begin converting to multiple ops per request
authorEugene Crosser <crosser@average.org>
Fri, 10 May 2013 09:07:28 +0000 (13:07 +0400)
committerEugene Crosser <crosser@average.org>
Fri, 10 May 2013 09:07:28 +0000 (13:07 +0400)
AndroidManifest.xml
res/values/strings.xml
res/values/styles.xml
src/org/average/nfcauthcr/Enroll.java
src/org/average/nfcauthcr/NfcCRdispatch.java
src/org/average/nfcauthcr/QueryCrToken.java [new file with mode: 0644]
src/org/average/nfcauthcr/TagEvent.java [deleted file]
src/org/average/nfcauthcr/YkNeo.java

index e9e69e02bebd986c4cb7649a940f57bfd0b78159..97bd259ee0b122fbb051dbaed7ea304234281a89 100644 (file)
                        </intent-filter>
                </activity>
 
-               <activity android:name=".TagEvent"
-                         android:label="@string/app_name">
+               <activity android:name=".QueryCrToken"
+                         android:label="@string/app_name"
+                         android:theme="@style/TransparentDialog">>
+                       <intent-filter>
+                               <action android:name="org.openintents.action.CHALLENGE_FOR_RESPONSE" />
+                               <category android:name="android.intent.category.DEFAULT" />
+                       </intent-filter>
                </activity>
 
        </application>
index aadb0f439587139504b70d83cbe228a18de50f9f..15a4fc0516117c13ebf9fbce791edbb3ab6e958f 100644 (file)
@@ -8,8 +8,8 @@
        <string name="need_slot">You must select which slot to use</string>
        <string name="enrollresult">Enrollment result:</string>
        <string name="enroll_success">Token successfully bound to the device</string>
-       <string name="challenging">Ready to send challenge</string>
-       <string name="swipe">Please touch the back of the phone with the NFC token to enroll it</string>
+       <string name="challenging">Ready to communicate</string>
+       <string name="swipe">Please touch the back of the phone with the NFC token</string>
        <string name="no_nfc">Cannot reach the NFC adapter</string>
        <string name="nfc_disabled">Need to enable NFC in Settings</string>
        <string name="tag_lost">Communitation with the tag lost</string>
index d48e9753605dc159a4e34db2ed23757bb038fe27..3855bba5be25bd1467d92459b2ad94d18bdd4ca6 100644 (file)
@@ -1,7 +1,15 @@
 <resources>
-    <style name="AppBaseTheme" parent="android:Theme.Light">
-    </style>
+       <style name="AppBaseTheme" parent="android:Theme.Light">
+       </style>
 
-    <style name="AppTheme" parent="AppBaseTheme">
-    </style>
+       <style name="AppTheme" parent="AppBaseTheme">
+       </style>
+
+       <style name="TransparentDialog" parent="@android:style/Theme.Dialog">
+               <item name="android:windowIsTranslucent">true</item>
+               <item name="android:windowBackground">@android:color/transparent</item>
+               <item name="android:windowContentOverlay">@null</item>
+               <item name="android:windowNoTitle">true</item>
+               <item name="android:backgroundDimEnabled">false</item>
+       </style>
 </resources>
index 6c104c4ad9513ad22574924fccd89f824a17d033..96fa3147b7ac79c8c8e44d0386a2c925959bd3fc 100644 (file)
@@ -12,10 +12,9 @@ import android.content.SharedPreferences.Editor;
 import android.content.DialogInterface;
 import android.util.Log;
 import android.view.View;
-import android.widget.TextView;
 import android.widget.RadioButton;
 
-import org.average.nfcauthcr.TagEvent;
+import org.average.nfcauthcr.QueryCrToken;
 
 public class Enroll extends Activity {
 
@@ -49,17 +48,6 @@ public class Enroll extends Activity {
                if (btn != null) btn.setChecked(true);
        }
 
-       @Override
-       protected void onPause() {
-               super.onPause();
-       }
-
-       @Override
-       protected void onStop() {
-               super.onStop();
-               Log.v(TAG, "Stop requested");
-       }
-
        public void onSlotSelectionClicked(View view) {
                Log.v(TAG, "Radio Button selected");
                if (! ((RadioButton) view).isChecked()) return;
@@ -123,8 +111,7 @@ public class Enroll extends Activity {
                byte[] challenge = new byte[63];
                rng.nextBytes(challenge);
                Log.v(TAG, "Random challenge: " + hex(challenge));
-               Intent crIntent = new Intent(this, TagEvent.class);
-               crIntent.putExtra("yubikey_neo_slot", slot);
+               Intent crIntent = new Intent(this, QueryCrToken.class);
                crIntent.putExtra("challenge", challenge);
                waitingForResult = true;
                this.startActivityForResult(crIntent, 0);
index bfacfa988a257a214ee0c09fcec052069e7762bf..25198beff5fdf39e9b1819d673d8822bbe688cc7 100644 (file)
@@ -1,5 +1,8 @@
 package org.average.nfcauthcr;
 
+import java.io.IOException;
+import java.util.ArrayList;
+
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Intent;
@@ -20,30 +23,39 @@ public class NfcCRdispatch {
 
        private Activity activity = null;
        private PendingIntent tagIntent = null;
-       private byte[] challenge;
+       private ArrayList<String> challenge;
 
        NfcCRdispatch(Activity activity) {
                Log.v(TAG, "new NfcCRdispatch, activity=" + activity);
                this.activity = activity;
        }
 
-       public byte[] onNewIntent(Intent intent) {
+       public ArrayList<String> onNewIntent(Intent intent) {
                Log.v(TAG, "NFC Intent arrived");
                Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
                if (tag == null) return null;
                IsoDep isoTag = IsoDep.get(tag);
                try {
                        int slot = intent.getIntExtra("yubikey_neo_slot", -1);
+                       isoTag.connect();
                        return YkNeo.doChalResp(isoTag, slot, challenge);
+               } catch (TagLostException e) {
+                       Log.v(TAG, e.getMessage());
+                       Toast.makeText(activity, e.getMessage(),
+                                       Toast.LENGTH_LONG).show();
+               } catch (IOException e) {
+                       Log.v(TAG, e.getMessage());
+                       Toast.makeText(activity, e.getMessage(),
+                                       Toast.LENGTH_LONG).show();
                } catch (CRException e) {
                        Log.v(TAG, e.getMessage());
                        Toast.makeText(activity, e.getMessage(),
                                        Toast.LENGTH_LONG).show();
-                       return null;
                }
+               return null;
        }
 
-       public void onResume(byte[] challenge) {
+       public void onResume(ArrayList<String> challenge) {
                this.challenge = challenge;
                Intent intent = activity.getIntent();
                intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
diff --git a/src/org/average/nfcauthcr/QueryCrToken.java b/src/org/average/nfcauthcr/QueryCrToken.java
new file mode 100644 (file)
index 0000000..903aefb
--- /dev/null
@@ -0,0 +1,87 @@
+package org.average.nfcauthcr;
+
+import java.util.ArrayList;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.PendingIntent;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.nfc.NfcAdapter;
+import android.nfc.Tag;
+import android.nfc.TagLostException;
+import android.nfc.tech.IsoDep;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.widget.Toast;
+
+import org.average.nfcauthcr.NfcCRdispatch;
+
+public class QueryCrToken extends Activity {
+
+       private final String TAG = getClass().getName();
+
+       private NfcCRdispatch dispatch = new NfcCRdispatch((Activity)this);
+       private SharedPreferences prefs;
+
+       @Override
+       protected void onCreate(Bundle savedInstanceState) {
+               super.onCreate(savedInstanceState);
+               Log.v(TAG, "onCreate get prefs");
+               prefs = PreferenceManager.getDefaultSharedPreferences(this);
+       }
+
+       @Override
+       protected void onResume() {
+               super.onResume();
+               Log.v(TAG, "Starting the work");
+
+               new AlertDialog.Builder(this)
+                       .setTitle(R.string.challenging)
+                       .setMessage(R.string.swipe)
+                       .setOnCancelListener(
+                               new DialogInterface.OnCancelListener() {
+                               public void onCancel(DialogInterface dialog) {
+                                       Log.v(TAG, "Cancel");
+                                       finish();
+                               }
+                       })
+                       .create().show();
+
+               Intent intent = getIntent();
+               ArrayList<String> challenge =
+                               intent.getStringArrayListExtra("challenge");
+               int slot = prefs.getInt("slot_number", -1);
+               intent.putExtra("yubikey_neo_slot", slot);
+               setResult(RESULT_CANCELED);
+               if (challenge != null) {
+                       dispatch.onResume(challenge);
+               } else {
+                       Log.e(TAG, "Challenge missing in the Intent");
+                       finish();
+               }
+       }
+
+       @Override
+       protected void onPause() {
+               super.onPause();
+               Log.v(TAG, "Finished the work");
+
+               dispatch.onPause();
+       }
+
+       public void onNewIntent(Intent newintent) {
+               Log.v(TAG, "NFC Intent arrived");
+
+               ArrayList<String> response = dispatch.onNewIntent(newintent);
+               if (response != null) {
+                       Intent masterintent = getIntent();
+                       masterintent.putExtra("response", response);
+                       setResult(RESULT_OK, masterintent);
+                       finish();
+               }
+       }
+}
diff --git a/src/org/average/nfcauthcr/TagEvent.java b/src/org/average/nfcauthcr/TagEvent.java
deleted file mode 100644 (file)
index febfa63..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.average.nfcauthcr;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.PendingIntent;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.nfc.NfcAdapter;
-import android.nfc.Tag;
-import android.nfc.TagLostException;
-import android.nfc.tech.IsoDep;
-import android.util.Log;
-import android.widget.Toast;
-
-import org.average.nfcauthcr.NfcCRdispatch;
-
-public class TagEvent extends Activity {
-
-       private final String TAG = getClass().getName();
-
-       private NfcCRdispatch dispatch = new NfcCRdispatch((Activity)this);
-
-       @Override
-       protected void onResume() {
-               super.onResume();
-               Log.v(TAG, "Starting the work");
-
-               new AlertDialog.Builder(this)
-                       .setTitle(R.string.challenging)
-                       .setMessage(R.string.swipe)
-                       .setOnCancelListener(
-                               new DialogInterface.OnCancelListener() {
-                               public void onCancel(DialogInterface dialog) {
-                                       Log.v(TAG, "Cancel");
-                                       finish();
-                               }
-                       })
-                       .create().show();
-
-               Intent intent = getIntent();
-               setResult(RESULT_CANCELED);
-               byte[] challenge = intent.getByteArrayExtra("challenge");
-               dispatch.onResume(challenge);
-       }
-
-       @Override
-       protected void onPause() {
-               super.onPause();
-               Log.v(TAG, "Finished the work");
-
-               dispatch.onPause();
-       }
-
-       public void onNewIntent(Intent newintent) {
-               Log.v(TAG, "NFC Intent arrived");
-
-               byte[] response = dispatch.onNewIntent(newintent);
-               if (response != null) {
-                       Intent masterintent = getIntent();
-                       masterintent.putExtra("response", response);
-                       setResult(RESULT_OK, masterintent);
-                       finish();
-               }
-       }
-}
index 39c760b795ad4d887ff48d2d3e0865444ee6c1c9..9c19135b23194dfb5afbf2948445c4892a8f1be2 100644 (file)
 package org.average.nfcauthcr;
 
-import java.lang.String;
 import java.io.IOException;
+import java.lang.String;
+import java.util.ArrayList;
 import java.util.Arrays;
 
 import android.nfc.NfcAdapter;
 import android.nfc.Tag;
-import android.nfc.TagLostException;
 import android.nfc.tech.IsoDep;
 
 import org.average.nfcauthcr.CRException;
 
 public class YkNeo {
 
-       // This is a CCID APDU, ISO 7816-4.
-       // 00 A4 04 00 xx AID - GlobalPlatform - SELECT
-       // Lc, send data = 07: A0 00 00 05 27 20 01
-       // Le, recv data = 00
+       // http://forum.yubico.com/viewtopic.php?\
+       //              f=26&t=1053&sid=2a11c0f97306e4b699bf67502b7a754a
+       // CCID APDU, ISO 7816-4.
+
+       // Start with Select APDU:
+       // CLA INS P1 P2 Lc AID Le
+       //  00  A4 04 00                - GlobalPlatform - Application Select
+       // Lc = 07
+       //   A0 00 00 05 27
+       //      Yubico's RID (Registered application provider IDentifier)
+       //   20 01
+       //      PIX (Proprietary application Identifier eXtension)
+       //      for the Yubikey2 applet
+       // Le = 00
        private static final byte[] selectApdu =
                {0x00, (byte) 0xA4, 0x04, 0x00, 0x07, (byte) 0xA0,
                 0x00, 0x00, 0x05, 0x27, 0x20, 0x01, 0x00};
 
+       // Application APDUs:
+       // CLA INS P1 P2
+       //  00  01 YK 00
+       //   YK is the one-byte command&slot code as in the USB interface
+       //   Lc + data bytes follow
+       //   Le is optional
        private static final byte SLOT_CHAL_HMAC1 = 0x30;
        private static final byte SLOT_CHAL_HMAC2 = 0x38;
 
-       public static byte[] doChalResp(IsoDep isoTag, int slot,
-                                       byte[] challenge) throws CRException {
-               try {
-                       isoTag.connect();
-                       byte[] resp = isoTag.transceive(selectApdu);
-                       int length = resp.length;
-                       if (resp[length - 2] != (byte)0x90 ||
-                           resp[length - 1] != 0x00) {
-                               throw new CRException(String.format(
-                               "NFC select error code: %02x:%02x",
-                               resp[length - 2], resp[length - 1]));
-                       }
-                       byte[] crApdu = new byte[69];
-                       crApdu[0] = 0x00; // CLA
-                       crApdu[1] = 0x01; // INS
-                       switch (slot) {
-                       case 1: crApdu[2] = SLOT_CHAL_HMAC1; break; // P1
-                       case 2: crApdu[2] = SLOT_CHAL_HMAC2; break; // P1
-                       }
-                       crApdu[3] = 0x00; // P2
-                       crApdu[4] = 63;   // Lc
-                       System.arraycopy(challenge, 0, crApdu, 5,
-                                               challenge.length); // Payload
-                       crApdu[crApdu.length-1] = 22; // Le
-                       resp = isoTag.transceive(crApdu);
-                       length = resp.length;
-                       if (resp[length - 2] != (byte)0x90 ||
-                           resp[length - 1] != 0x00) {
-                               throw new CRException(String.format(
-                               "NFC CR error code: %02x:%02x",
-                               resp[length - 2], resp[length - 1]));
-                       }
-                       if (length != 22) {
-                               throw new CRException(String.format(
-                               "NFC wrong response size: got %d, need 20",
-                               length-2));
-                       }
-                       return Arrays.copyOf(resp, length-2);
-               } catch (TagLostException e) {
-                       throw new CRException("NFC connection lost", e);
-               } catch (IOException e) {
-                       throw new CRException("NFC I/O: " + e.getMessage(), e);
+       public static ArrayList<String> doChalResp(IsoDep isoTag, int slot,
+                                       ArrayList<String> cset)
+                       throws IOException, CRException {
+               byte[] challenge = unhex(cset.get(0));
+               if (challenge.length > 127) {
+                       throw new CRException(String.format(
+                       "NFC challenge size too big: %d",
+                       challenge.length));
+               }
+               if (slot != 1 && slot != 2) {
+                       throw new CRException(String.format(
+                       "NFC Yubikey slot is %d, can be 1 or 2",
+                       slot));
+               }
+               byte[] resp = isoTag.transceive(selectApdu);
+               int length = resp.length;
+               if (resp[length - 2] != (byte)0x90 ||
+                   resp[length - 1] != 0x00) {
+                       throw new CRException(String.format(
+                       "NFC select error code: %02x:%02x",
+                       resp[length - 2], resp[length - 1]));
+               }
+               byte[] crApdu = new byte[6+challenge.length];
+               crApdu[0] = 0x00; // CLA
+               crApdu[1] = 0x01; // INS
+               switch (slot) {
+               case 1: crApdu[2] = SLOT_CHAL_HMAC1; break; // P1
+               case 2: crApdu[2] = SLOT_CHAL_HMAC2; break; // P1
+               }
+               crApdu[3] = 0x00; // P2
+               crApdu[4] = (byte)challenge.length; // Lc
+               System.arraycopy(challenge, 0, crApdu, 5,
+                                       challenge.length); // Payload
+               crApdu[5+challenge.length] = 22; // Le
+               resp = isoTag.transceive(crApdu);
+               length = resp.length;
+               if (resp[length - 2] != (byte)0x90 ||
+                   resp[length - 1] != 0x00) {
+                       throw new CRException(String.format(
+                       "NFC CR error code: %02x:%02x",
+                       resp[length - 2], resp[length - 1]));
+               }
+               if (length <= 2) {
+                       throw new CRException(String.format(
+                       "NFC wrong response size: only %d bytes",
+                       length-2));
+               }
+               ArrayList<String> rset = new ArrayList<String>();
+               rset.add(hex(Arrays.copyOf(resp, length-2)));
+               return rset;
+       }
+
+       private static String hex(byte[] a) {
+               StringBuilder sb = new StringBuilder();
+               if (a == null) return "<null>";
+               for (byte b: a) sb.append(String.format("%02x", b&0xff));
+               return sb.toString();
+       }
+
+       private static byte[] unhex(String s) {
+               int len = s.length();
+               if ((len % 2) != 0) return null;
+               byte[] b = new byte[len / 2];
+               for (int i = 0; i < len; i += 2) {
+                       b[i / 2] = (byte)Integer.parseInt(
+                                               s.substring(i,i+2), 16);
                }
+               return b;
        }
 }