diff options
3 files changed, 108 insertions, 43 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/BaseJavacardDevice.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/BaseJavacardDevice.java index f81d234b3..796b4e1f3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/BaseJavacardDevice.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/BaseJavacardDevice.java @@ -393,26 +393,6 @@ public class BaseJavacardDevice implements JavacardDevice {          Arrays.fill(dataToSend, (byte) 0);      } - -    /** -     * Return the key id from application specific data stored on tag, or null -     * if it doesn't exist. -     * -     * @param idx Index of the key to return the fingerprint from. -     * @return The long key id of the requested key, or null if not found. -     */ -    public Long nfcGetKeyId(int idx) throws IOException { -        byte[] fp = getMasterKeyFingerprint(idx); -        if (fp == null) { -            return null; -        } -        ByteBuffer buf = ByteBuffer.wrap(fp); -        // skip first 12 bytes of the fingerprint -        buf.position(12); -        // the last eight bytes are the key id (big endian, which is default order in ByteBuffer) -        return buf.getLong(); -    } -      /**       * Return fingerprints of all keys from application specific data stored       * on tag, or null if data not available. diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/UsbConnectionManager.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/UsbConnectionManager.java index 9dd3bc028..6b049159a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/UsbConnectionManager.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/UsbConnectionManager.java @@ -80,13 +80,14 @@ public class UsbConnectionManager {                          false);                  Log.d(LOG_TAG, "ACTION_USB_PERMISSION: " + permission + " Device: " + deviceName); -                interceptIntent(intent); +                if (permission) { +                    interceptIntent(intent); +                }                  context.unregisterReceiver(mUsbReceiver);              }          }      }; -    private Handler handler = new Handler(Looper.getMainLooper());      public UsbConnectionManager(final Activity activity, final OnDiscoveredUsbDeviceListener listener) {          this.mActivity = activity; @@ -98,7 +99,7 @@ public class UsbConnectionManager {      private static UsbDevice getDevice(UsbManager manager) {          HashMap<String, UsbDevice> deviceList = manager.getDeviceList();          for (UsbDevice device : deviceList.values()) { -            if (device.getVendorId() == 0x1050 && device.getProductId() == 0x0112) { +            if (device.getVendorId() == 0x1050 && (device.getProductId() == 0x0112 || device.getProductId() == 0x0115)) {                  return device;              }          } @@ -139,9 +140,11 @@ public class UsbConnectionManager {      public void onDestroy() {          mStopped.set(true); +        mRunning.release();          try {              mActivity.unregisterReceiver(mUsbReceiver);          } catch (IllegalArgumentException ignore) {          } +        mActivity = null;      }  } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/UsbTransport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/UsbTransport.java index f2af34c39..07697f11e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/UsbTransport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/UsbTransport.java @@ -11,10 +11,14 @@ import android.support.annotation.Nullable;  import android.util.Pair;  import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder;  public class UsbTransport implements Transport {      private static final int CLASS_SMARTCARD = 11; -    private static final int TIMEOUT = 1000; // 1 s +    private static final int TIMEOUT = 20 * 1000; // 2 s      private final UsbManager mUsbManager;      private final UsbDevice mUsbDevice; @@ -22,7 +26,7 @@ public class UsbTransport implements Transport {      private final UsbEndpoint mBulkIn;      private final UsbEndpoint mBulkOut;      private final UsbDeviceConnection mConnection; -    private byte counter = 0; +    private byte mCounter = 0;      public UsbTransport(final UsbDevice usbDevice, final UsbManager usbManager) throws TransportIoException {          mUsbDevice = usbDevice; @@ -40,17 +44,60 @@ public class UsbTransport implements Transport {          mConnection.claimInterface(mUsbInterface, true);          // check result +        powerOn(); + +        setTimings(); +    } + +    private void setTimings()  throws TransportIoException { +        byte[] data = { +                0x6C, +                0x00, 0x00, 0x00, 0x00, +                0x00, +                mCounter++, +                0x00, 0x00, 0x00 +        }; +        sendRaw(data); +        data = receive(); + +        data[0] = 0x61; +        data[1] = 0x04; +        data[2] = data[3] = data[4] = 0x00; +        data[5] = 0x00; +        data[6] = mCounter++; +        data[7] = 0x00; +        data[8] = data[9] = 0x00; + +        data[13] = 1; + +        sendRaw(data); +        receive(); +    } + +    private void powerOff() throws TransportIoException { +        final byte[] iccPowerOff = { +                0x63, +                0x00, 0x00, 0x00, 0x00, +                0x00, +                mCounter++, +                0x00, +                0x00, 0x00 +        }; +        sendRaw(iccPowerOff); +        receive(); +    } + +    void powerOn() throws TransportIoException {          final byte[] iccPowerOn = {                  0x62,                  0x00, 0x00, 0x00, 0x00,                  0x00, -                counter++, -                0x03, +                mCounter++, +                0x00,                  0x00, 0x00          };          sendRaw(iccPowerOn); -        receiveRaw(); -        // Check result +        receive();      }      /** @@ -101,27 +148,58 @@ public class UsbTransport implements Transport {      }      @Override -    public byte[] sendAndReceive(final byte[] data) throws TransportIoException { +    public byte[] sendAndReceive(byte[] data) throws TransportIoException {          send(data); -        return receive(); +        byte[] bytes; +        do { +            bytes = receive(); +        } while (isXfrBlockNotReady(bytes)); + +        checkXfrBlockResult(bytes); +        return Arrays.copyOfRange(bytes, 10, bytes.length);      } -    public void send(final byte[] d) throws TransportIoException { +    public void send(byte[] d) throws TransportIoException {          int l = d.length;          byte[] data = Arrays.concatenate(new byte[]{                          0x6f,                          (byte) l, (byte) (l >> 8), (byte) (l >> 16), (byte) (l >> 24),                          0x00, -                        counter++, -                        0x01, +                        mCounter++, +                        0x00,                          0x00, 0x00},                  d); -        sendRaw(data); + +        int send = 0; +        while (send < data.length) { +            final int len = Math.min(mBulkIn.getMaxPacketSize(), data.length - send); +            sendRaw(Arrays.copyOfRange(data, send, send + len)); +            send += len; +        }      }      public byte[] receive() throws TransportIoException { -        final byte[] bytes = receiveRaw(); -        return Arrays.copyOfRange(bytes, 10, bytes.length); +        byte[] buffer = new byte[mBulkIn.getMaxPacketSize()]; +        byte[] result = null; +        int readBytes = 0, totalBytes = 0; + +        do { +            int res = mConnection.bulkTransfer(mBulkIn, buffer, buffer.length, TIMEOUT); +            if (res < 0) { +                throw new TransportIoException("USB error, failed to receive response " + res); +            } +            if (result == null) { +                if (res < 10) { +                    throw new TransportIoException("USB error, failed to receive ccid header"); +                } +                totalBytes = ByteBuffer.wrap(buffer, 1, 4).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().get() + 10; +                result = new byte[totalBytes]; +            } +            System.arraycopy(buffer, 0, result, readBytes, res); +            readBytes += res; +        } while (readBytes < totalBytes); + +        return result;      }      private void sendRaw(final byte[] data) throws TransportIoException { @@ -131,14 +209,18 @@ public class UsbTransport implements Transport {          }      } -    private byte[] receiveRaw() throws TransportIoException { -        byte[] buffer = new byte[1024]; +    private byte getStatus(byte[] bytes) { +        return (byte) ((bytes[7] >> 6) & 0x03); +    } -        int res = mConnection.bulkTransfer(mBulkIn, buffer, buffer.length, TIMEOUT); -        if (res < 0) { -            throw new TransportIoException("USB error, failed to receive response " + res); +    private void checkXfrBlockResult(byte[] bytes) throws TransportIoException { +        final byte status = getStatus(bytes); +        if (status != 0) { +            throw new TransportIoException("CCID error, status " + status + " error code: " + Hex.toHexString(bytes, 8, 1));          } +    } -        return Arrays.copyOfRange(buffer, 0, res); +    private boolean isXfrBlockNotReady(byte[] bytes) { +        return getStatus(bytes) == 2;      }  }  | 
