aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikita Mikhailov <nikita.s.mikhailov@gmail.com>2016-04-06 01:33:01 +0600
committerNikita Mikhailov <nikita.s.mikhailov@gmail.com>2016-04-14 22:48:01 +0600
commit79a0918072e2b4a01f328cb8d8d2a0a8761394f6 (patch)
treee5de1a9758679129cc2f41e6a933b2b04e5cbe9d
parent3d538d885e0ed52640ea72d538fe1752a5ffe1f2 (diff)
downloadopen-keychain-79a0918072e2b4a01f328cb8d8d2a0a8761394f6.tar.gz
open-keychain-79a0918072e2b4a01f328cb8d8d2a0a8761394f6.tar.bz2
open-keychain-79a0918072e2b4a01f328cb8d8d2a0a8761394f6.zip
OTG: Fix usb transport
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/BaseJavacardDevice.java20
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/UsbConnectionManager.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/javacard/UsbTransport.java122
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;
}
}