diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/CcidTransceiver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/CcidTransceiver.java
index d43c373d7..acb1ca9f4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/CcidTransceiver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/CcidTransceiver.java
@@ -80,7 +80,7 @@ public class CcidTransceiver {
try {
atr = receiveRaw();
break;
- } catch (UsbTransportException e) {
+ } catch (Exception e) {
// Try more startTime
if (System.currentTimeMillis() - startTime > TIMEOUT) {
break;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/UsbTransport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/UsbTransport.java
index 037a23352..e1409f39e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/UsbTransport.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/UsbTransport.java
@@ -30,6 +30,7 @@ import android.util.Pair;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.securitytoken.Transport;
import org.sufficientlysecure.keychain.securitytoken.usb.tpdu.T1TpduProtocol;
+import org.sufficientlysecure.keychain.util.Iso7816TLV;
import org.sufficientlysecure.keychain.util.Log;
import java.io.IOException;
@@ -42,10 +43,9 @@ import java.nio.ByteOrder;
* Implements small subset of these features
*/
public class UsbTransport implements Transport {
- private static final int USB_CLASS_SMARTCARD = 11;
private static final int PROTOCOLS_OFFSET = 6;
private static final int FEATURES_OFFSET = 40;
- private static final int MASK_T1_PROTO = 2;
+ private static final short MASK_T1_PROTO = 2;
// dwFeatures Masks
private static final int MASK_TPDU = 0x10000;
@@ -77,7 +77,7 @@ public class UsbTransport implements Transport {
private static UsbInterface getSmartCardInterface(UsbDevice device) {
for (int i = 0; i < device.getInterfaceCount(); i++) {
UsbInterface anInterface = device.getInterface(i);
- if (anInterface.getInterfaceClass() == USB_CLASS_SMARTCARD) {
+ if (anInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CSCID) {
return anInterface;
}
}
@@ -180,13 +180,35 @@ public class UsbTransport implements Transport {
private void configureProtocol() throws UsbTransportException {
byte[] desc = mConnection.getRawDescriptors();
- if (desc.length < FEATURES_OFFSET + 4)
- throw new UsbTransportException("Can't access dwFeatures for protocol selection");
+ int dwProtocols = 0, dwFeatures = 0;
+ boolean hasCcidDescriptor = false;
- int dwProtocols = ByteBuffer.wrap(desc, FEATURES_OFFSET, 4).order(ByteOrder.LITTLE_ENDIAN)
- .asIntBuffer().get();
- int dwFeatures = ByteBuffer.wrap(desc, FEATURES_OFFSET, 4).order(ByteOrder.LITTLE_ENDIAN)
- .asIntBuffer().get();
+ ByteBuffer byteBuffer = ByteBuffer.wrap(desc).order(ByteOrder.LITTLE_ENDIAN);
+
+ while (byteBuffer.hasRemaining()) {
+ byteBuffer.mark();
+ byte len = byteBuffer.get(), type = byteBuffer.get();
+
+ if (type == 0x21 && len == 0x36) {
+ byteBuffer.reset();
+
+ byteBuffer.position(byteBuffer.position() + PROTOCOLS_OFFSET);
+ dwProtocols = byteBuffer.getInt();
+
+ byteBuffer.reset();
+
+ byteBuffer.position(byteBuffer.position() + FEATURES_OFFSET);
+ dwFeatures = byteBuffer.getInt();
+ hasCcidDescriptor = true;
+ break;
+ } else {
+ byteBuffer.position(byteBuffer.position() + len - 2);
+ }
+ }
+
+ if (!hasCcidDescriptor) {
+ throw new UsbTransportException("CCID descriptor not found");
+ }
if ((dwProtocols & MASK_T1_PROTO) == 0) {
throw new UsbTransportException("T=0 protocol is not supported");
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/Block.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/Block.java
similarity index 94%
rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/Block.java
rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/Block.java
index bfebd1934..1fe29b2a2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/Block.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/Block.java
@@ -15,12 +15,11 @@
* along with this program. If not, see .
*/
-package org.sufficientlysecure.keychain.securitytoken.usb.tpdu.block;
+package org.sufficientlysecure.keychain.securitytoken.usb.tpdu;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.securitytoken.usb.UsbTransportException;
-import org.sufficientlysecure.keychain.securitytoken.usb.tpdu.BlockChecksumType;
public class Block {
protected static final int MAX_PAYLOAD_LEN = 254;
@@ -78,7 +77,7 @@ public class Block {
}
public byte[] getEdc() {
- return Arrays.copyOfRange(mData, mData.length - mChecksumType.getLength(), mChecksumType.getLength());
+ return Arrays.copyOfRange(mData, mData.length - mChecksumType.getLength(), mData.length);
}
public BlockChecksumType getChecksumType() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/IBlock.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/IBlock.java
similarity index 90%
rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/IBlock.java
rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/IBlock.java
index e7e9f8b51..8caa54ae8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/IBlock.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/IBlock.java
@@ -15,10 +15,9 @@
* along with this program. If not, see .
*/
-package org.sufficientlysecure.keychain.securitytoken.usb.tpdu.block;
+package org.sufficientlysecure.keychain.securitytoken.usb.tpdu;
import org.sufficientlysecure.keychain.securitytoken.usb.UsbTransportException;
-import org.sufficientlysecure.keychain.securitytoken.usb.tpdu.BlockChecksumType;
public class IBlock extends Block {
private static final byte BIT_SEQUENCE = 6;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/RBlock.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/RBlock.java
similarity index 93%
rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/RBlock.java
rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/RBlock.java
index f0262257e..678b5e01e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/RBlock.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/RBlock.java
@@ -15,12 +15,11 @@
* along with this program. If not, see .
*/
-package org.sufficientlysecure.keychain.securitytoken.usb.tpdu.block;
+package org.sufficientlysecure.keychain.securitytoken.usb.tpdu;
import android.support.annotation.NonNull;
import org.sufficientlysecure.keychain.securitytoken.usb.UsbTransportException;
-import org.sufficientlysecure.keychain.securitytoken.usb.tpdu.BlockChecksumType;
public class RBlock extends Block {
private static final byte BIT_SEQUENCE = 5;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/SBlock.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/SBlock.java
similarity index 92%
rename from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/SBlock.java
rename to OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/SBlock.java
index 18a66f548..9bf3fdc9d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/SBlock.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/SBlock.java
@@ -15,7 +15,7 @@
* along with this program. If not, see .
*/
-package org.sufficientlysecure.keychain.securitytoken.usb.tpdu.block;
+package org.sufficientlysecure.keychain.securitytoken.usb.tpdu;
public class SBlock extends Block {
public SBlock(Block baseBlock) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/T1TpduProtocol.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/T1TpduProtocol.java
index 59e651a3f..fb86c8020 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/T1TpduProtocol.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/T1TpduProtocol.java
@@ -25,10 +25,6 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.securitytoken.usb.CcidTransceiver;
import org.sufficientlysecure.keychain.securitytoken.usb.UsbTransportException;
import org.sufficientlysecure.keychain.securitytoken.usb.CcidTransportProtocol;
-import org.sufficientlysecure.keychain.securitytoken.usb.tpdu.block.Block;
-import org.sufficientlysecure.keychain.securitytoken.usb.tpdu.block.IBlock;
-import org.sufficientlysecure.keychain.securitytoken.usb.tpdu.block.RBlock;
-import org.sufficientlysecure.keychain.securitytoken.usb.tpdu.block.SBlock;
import org.sufficientlysecure.keychain.util.Log;
public class T1TpduProtocol implements CcidTransportProtocol {
@@ -107,7 +103,7 @@ public class T1TpduProtocol implements CcidTransportProtocol {
byte[] responseApdu = responseBlock.getApdu();
while (((IBlock) responseBlock).getChaining()) {
- Block ackBlock = newRBlock(((IBlock) responseBlock).getSequence());
+ Block ackBlock = newRBlock((byte) (1 - ((IBlock) responseBlock).getSequence()));
mTransceiver.sendXfrBlock(ackBlock.getRawData());
responseBlock = getBlockFromResponse(mTransceiver.receive());
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/BlockFactory.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/BlockFactory.java
deleted file mode 100644
index c64f2315c..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/BlockFactory.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2016 Nikita Mikhailov
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.sufficientlysecure.keychain.securitytoken.usb.tpdu.block;
-
-import org.sufficientlysecure.keychain.securitytoken.usb.UsbTransportException;
-import org.sufficientlysecure.keychain.securitytoken.usb.tpdu.BlockChecksumType;
-
-public class BlockFactory {
- private BlockChecksumType mChecksumType = BlockChecksumType.LRC;
-
- public Block getBlockFromResponse(byte[] data) throws UsbTransportException {
- final Block baseBlock = new Block(mChecksumType, data);
-
- if ((baseBlock.getPcb() & 0b10000000) == 0b00000000) {
- return new IBlock(baseBlock);
- } else if ((baseBlock.getPcb() & 0b11000000) == 0b11000000) {
- return new SBlock(baseBlock);
- } else if ((baseBlock.getPcb() & 0b11000000) == 0b10000000) {
- return new RBlock(baseBlock);
- }
-
- throw new UsbTransportException("TPDU Unknown block type");
- }
-
- public IBlock newIBlock(byte sequence, boolean chaining, byte[] apdu) throws UsbTransportException {
- return new IBlock(mChecksumType, (byte) 0, sequence, chaining, apdu);
- }
-
- public RBlock newRBlock(byte sequence) throws UsbTransportException {
- return new RBlock(mChecksumType, (byte) 0, sequence);
- }
-
- public void setChecksumType(final BlockChecksumType checksumType) {
- mChecksumType = checksumType;
- }
-}