From a017b9f25a1188eeff6f1b1f2da4111fbb147d16 Mon Sep 17 00:00:00 2001 From: Nikita Mikhailov Date: Mon, 9 May 2016 13:42:05 +0600 Subject: [PATCH] SecurityToken: fix ccid class header parsing --- .../securitytoken/usb/CcidTransceiver.java | 2 +- .../securitytoken/usb/UsbTransport.java | 40 +++++++++++---- .../usb/tpdu/{block => }/Block.java | 5 +- .../usb/tpdu/{block => }/IBlock.java | 3 +- .../usb/tpdu/{block => }/RBlock.java | 3 +- .../usb/tpdu/{block => }/SBlock.java | 2 +- .../usb/tpdu/T1TpduProtocol.java | 6 +-- .../usb/tpdu/block/BlockFactory.java | 51 ------------------- 8 files changed, 38 insertions(+), 74 deletions(-) rename OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/{block => }/Block.java (94%) rename OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/{block => }/IBlock.java (90%) rename OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/{block => }/RBlock.java (93%) rename OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/{block => }/SBlock.java (92%) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/usb/tpdu/block/BlockFactory.java 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; - } -}