From c2ca440c8837456af9c077a218796684183822fc Mon Sep 17 00:00:00 2001 From: Nikita Mikhailov Date: Sat, 14 May 2016 15:35:36 +0600 Subject: [PATCH] SecurityToken: use CommandAPDU instead of raw strings --- .../keychain/securitytoken/CardException.java | 9 + .../keychain/securitytoken/NfcTransport.java | 6 +- .../securitytoken/SecurityTokenHelper.java | 336 ++++++------------ .../keychain/securitytoken/Transport.java | 5 +- .../securitytoken/usb/UsbTransport.java | 7 +- 5 files changed, 135 insertions(+), 228 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/CardException.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/CardException.java index 905deca90..6a011ff0b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/CardException.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/CardException.java @@ -27,6 +27,15 @@ public class CardException extends IOException { mResponseCode = responseCode; } + public CardException(String detailMessage, int responseCode) { + super(detailMessage); + mResponseCode = (short) responseCode; + } + + public CardException(String s) { + this(s, -1); + } + public short getResponseCode() { return mResponseCode; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/NfcTransport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/NfcTransport.java index ba36ebdf0..61cfd1d24 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/NfcTransport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/NfcTransport.java @@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain.securitytoken; import android.nfc.Tag; +import org.sufficientlysecure.keychain.securitytoken.smartcardio.CommandAPDU; +import org.sufficientlysecure.keychain.securitytoken.smartcardio.ResponseAPDU; import org.sufficientlysecure.keychain.ui.base.BaseSecurityTokenActivity; import java.io.IOException; @@ -43,8 +45,8 @@ public class NfcTransport implements Transport { * @throws IOException */ @Override - public byte[] transceive(final byte[] data) throws IOException { - return mIsoCard.transceive(data); + public ResponseAPDU transceive(final CommandAPDU data) throws IOException { + return new ResponseAPDU(mIsoCard.transceive(data.getBytes())); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenHelper.java index 0b81c9fbb..0232c36a8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/SecurityTokenHelper.java @@ -30,6 +30,8 @@ import org.bouncycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.securitytoken.smartcardio.CommandAPDU; +import org.sufficientlysecure.keychain.securitytoken.smartcardio.ResponseAPDU; import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; @@ -47,7 +49,14 @@ import nordpol.Apdu; * For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf */ public class SecurityTokenHelper { - private static final int MAX_APDU_DATAFIELD_SIZE = 254 * 500; + private static final int MAX_APDU_NC = 255; + private static final int MAX_APDU_NC_EXT = 65535; + + private static final int MAX_APDU_NE = 256; + private static final int MAX_APDU_NE_EXT = 65536; + + private static final int APDU_SW_SUCCESS = 0x9000; + // Fidesmo constants private static final String FIDESMO_APPS_AID_PREFIX = "A000000617"; @@ -72,16 +81,9 @@ public class SecurityTokenHelper { return new String(Hex.encode(raw)); } - private String getHolderName(String name) { + private String getHolderName(byte[] name) { try { - String slength; - int ilength; - name = name.substring(6); - slength = name.substring(0, 2); - ilength = Integer.parseInt(slength, 16) * 2; - name = name.substring(2, ilength + 2); - name = (new String(Hex.decode(name))).replace('<', ' '); - return name; + return (new String(name, 4, name[3])).replace('<', ' '); } catch (IndexOutOfBoundsException e) { // try-catch for https://github.com/FluffyKaon/OpenPGP-Card // Note: This should not happen, but happens with @@ -153,23 +155,12 @@ public class SecurityTokenHelper { mTransport.connect(); // Connect on smartcard layer - - // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. - // See specification, page 51 - String accepted = "9000"; - // Command APDU (page 51) for SELECT FILE command (page 29) - String opening = - "00" // CLA - + "A4" // INS - + "04" // P1 - + "00" // P2 - + "06" // Lc (number of bytes) - + "D27600012401" // Data (6 bytes) - + "00"; // Le - String response = communicate(opening); // activate connection - if (!response.endsWith(accepted)) { - throw new CardException("Initialization failed!", parseCardStatus(response)); + CommandAPDU select = new CommandAPDU(0x00, 0xA4, 0x04, 0x00, Hex.decode("D27600012401")); + ResponseAPDU response = communicate(select); // activate connection + + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Initialization failed!", response.getSW()); } byte[] pwStatusBytes = getPwStatusBytes(); @@ -179,24 +170,6 @@ public class SecurityTokenHelper { mPw3Validated = false; } - /** - * Parses out the status word from a JavaCard response string. - * - * @param response A hex string with the response from the card - * @return A short indicating the SW1/SW2, or 0 if a status could not be determined. - */ - private short parseCardStatus(String response) { - if (response.length() < 4) { - return 0; // invalid input - } - - try { - return Short.parseShort(response.substring(response.length() - 4), 16); - } catch (NumberFormatException e) { - return 0; - } - } - /** * Modifies the user's PW1 or PW3. Before sending, the new PIN will be validated for * conformance to the token's requirements for key length. @@ -230,16 +203,11 @@ public class SecurityTokenHelper { } // Command APDU for CHANGE REFERENCE DATA command (page 32) - String changeReferenceDataApdu = "00" // CLA - + "24" // INS - + "00" // P1 - + String.format("%02x", pw) // P2 - + String.format("%02x", pin.length + newPin.length) // Lc - + getHex(pin) - + getHex(newPin); - String response = communicate(changeReferenceDataApdu); // change PIN - if (!response.equals("9000")) { - throw new CardException("Failed to change PIN", parseCardStatus(response)); + CommandAPDU changePin = new CommandAPDU(0x00, 0x24, 0x00, pw, Arrays.concatenate(pin, newPin)); + ResponseAPDU response = communicate(changePin); + + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Failed to change PIN", response.getSW()); } } @@ -254,43 +222,20 @@ public class SecurityTokenHelper { verifyPin(0x82); // (Verify PW1 with mode 82 for decryption) } - int offset = 2; // Skip first byte TODO: why? - String response = "", status = ""; - boolean shouldPad = true; - // Transmit - while (offset < encryptedSessionKey.length) { - boolean isLastCommand = MAX_APDU_DATAFIELD_SIZE >= encryptedSessionKey.length - offset; - String cla = isLastCommand ? "00" : "10"; - - int len = Math.min(MAX_APDU_DATAFIELD_SIZE, encryptedSessionKey.length - offset + (shouldPad ? 1 : 0)); - String command = cla + "2a8086" - + Hex.toHexString(new byte[]{(byte) ((len >> 16) & 0xFF), (byte) ((len >> 8) & 0xFF), (byte) (len & 0xFF)}) - + (shouldPad ? "00": "") - + Hex.toHexString(encryptedSessionKey, offset, len - (shouldPad ? 1 : 0)) + "0000"; - shouldPad = false; - response = communicate(command); - status = response.substring(response.length() - 4); - - if (!isLastCommand && !response.endsWith("9000")) { - throw new CardException("Deciphering with Security token failed on transmit", parseCardStatus(response)); - } - - offset += MAX_APDU_DATAFIELD_SIZE; + byte[] data = Arrays.copyOfRange(encryptedSessionKey, 2, encryptedSessionKey.length); + if (data[0] != 0) { + data = Arrays.prepend(data, (byte) 0x00); } - // Receive - String result = getDataField(response); - while (response.endsWith("61")) { - response = communicate("00C00000" + status.substring(2)); - status = response.substring(response.length() - 4); - result += getDataField(response); - } - if (!status.equals("9000")) { - throw new CardException("Deciphering with Security token failed on receive", parseCardStatus(response)); + CommandAPDU command = new CommandAPDU(0x00, 0x2A, 0x80, 0x86, data, MAX_APDU_NE_EXT); + ResponseAPDU response = communicate(command); + + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Deciphering with Security token failed on receive", response.getSW()); } - return Hex.decode(result); + return response.getData(); } /** @@ -309,12 +254,9 @@ public class SecurityTokenHelper { pin = mPin.toStringUnsafe().getBytes(); } - // SW1/2 0x9000 is the generic "ok" response, which we expect most of the time. - // See specification, page 51 - String accepted = "9000"; - String response = tryPin(mode, pin); // login - if (!response.equals(accepted)) { - throw new CardException("Bad PIN!", parseCardStatus(response)); + ResponseAPDU response = tryPin(mode, pin);// login + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Bad PIN!", response.getSW()); } if (mode == 0x81) { @@ -347,16 +289,11 @@ public class SecurityTokenHelper { verifyPin(0x83); // (Verify PW3) } - String putDataApdu = "00" // CLA - + "DA" // INS - + String.format("%02x", (dataObject & 0xFF00) >> 8) // P1 - + String.format("%02x", dataObject & 0xFF) // P2 - + String.format("%02x", data.length) // Lc - + getHex(data); + CommandAPDU command = new CommandAPDU(0x00, 0xDA, (dataObject & 0xFF00) >> 8, dataObject & 0xFF, data); + ResponseAPDU response = communicate(command); // put data - String response = communicate(putDataApdu); // put data - if (!response.equals("9000")) { - throw new CardException("Failed to put data.", parseCardStatus(response)); + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Failed to put data.", response.getSW()); } } @@ -442,34 +379,18 @@ public class SecurityTokenHelper { currentKeyObject = crtSecretKey.getModulus().toByteArray(); System.arraycopy(currentKeyObject, currentKeyObject.length - 256, dataToSend, offset, 256); - String putKeyCommand = "10DB3FFF"; - String lastPutKeyCommand = "00DB3FFF"; - // Now we're ready to communicate with the token. - offset = 0; - String response; - while (offset < dataToSend.length) { - int dataRemaining = dataToSend.length - offset; - if (dataRemaining > 254) { - response = communicate( - putKeyCommand + "FE" + Hex.toHexString(dataToSend, offset, 254) - ); - offset += 254; - } else { - int length = dataToSend.length - offset; - response = communicate( - lastPutKeyCommand + String.format("%02x", length) - + Hex.toHexString(dataToSend, offset, length)); - offset += length; - } - if (!response.endsWith("9000")) { - throw new CardException("Key export to Security Token failed", parseCardStatus(response)); - } - } + CommandAPDU apdu = new CommandAPDU(0x00, 0xDB, 0x3F, 0xFF, dataToSend); // Clear array with secret data before we return. Arrays.fill(dataToSend, (byte) 0); + + ResponseAPDU response = communicate(apdu); + + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Key export to Security Token failed", response.getSW()); + } } /** @@ -479,25 +400,29 @@ public class SecurityTokenHelper { * @return The fingerprints of all subkeys in a contiguous byte array. */ public byte[] getFingerprints() throws IOException { - String data = "00CA006E00"; - byte[] buf = mTransport.transceive(Hex.decode(data)); + CommandAPDU apdu = new CommandAPDU(0x00, 0xCA, 0x00, 0x6E); + ResponseAPDU response = communicate(apdu); - Iso7816TLV[] tlvs = Iso7816TLV.readList(buf, true); - Iso7816TLV fptlv = null; + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Failed to get fingerprints", response.getSW()); + } - for (int i = 0; i < tlvs.length; i++) { - Log.d(Constants.TAG, "nfcGetFingerprints() Iso7816TLV tlv data:\n" + tlvs[i].prettyPrint()); + Iso7816TLV[] tlvList = Iso7816TLV.readList(response.getData(), true); + Iso7816TLV fingerPrintTlv = null; - Iso7816TLV tlv = Iso7816TLV.findRecursive(tlvs[i], 0xc5); - if (tlv != null) { - fptlv = tlv; + for (Iso7816TLV tlv : tlvList) { + Log.d(Constants.TAG, "nfcGetFingerprints() Iso7816TLV tlv data:\n" + tlv.prettyPrint()); + + Iso7816TLV matchingTlv = Iso7816TLV.findRecursive(tlv, 0xc5); + if (matchingTlv != null) { + fingerPrintTlv = matchingTlv; } } - if (fptlv == null) { + if (fingerPrintTlv == null) { return null; } - return fptlv.mV; + return fingerPrintTlv.mV; } /** @@ -506,18 +431,23 @@ public class SecurityTokenHelper { * @return Seven bytes in fixed format, plus 0x9000 status word at the end. */ private byte[] getPwStatusBytes() throws IOException { - String data = "00CA00C400"; - return mTransport.transceive(Hex.decode(data)); + return getData(0x00, 0xC4); } public byte[] getAid() throws IOException { - String info = "00CA004F00"; - return mTransport.transceive(Hex.decode(info)); + return getData(0x00, 0x4F); } public String getUserId() throws IOException { - String info = "00CA006500"; - return getHolderName(communicate(info)); + return getHolderName(getData(0x00, 0x65)); + } + + private byte[] getData(int p1, int p2) throws IOException { + ResponseAPDU response = communicate(new CommandAPDU(0x00, 0xCA, p1, p2)); + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Failed to get pw status bytes", response.getSW()); + } + return response.getData(); } /** @@ -532,7 +462,7 @@ public class SecurityTokenHelper { } // dsi, including Lc - String dsi; + byte[] dsi; Log.i(Constants.TAG, "Hash: " + hashAlgo); switch (hashAlgo) { @@ -540,86 +470,65 @@ public class SecurityTokenHelper { if (hash.length != 20) { throw new IOException("Bad hash length (" + hash.length + ", expected 10!"); } - dsi = "23" // Lc - + "3021" // Tag/Length of Sequence, the 0x21 includes all following 33 bytes + dsi = Arrays.concatenate(Hex.decode( + "3021" // Tag/Length of Sequence, the 0x21 includes all following 33 bytes + "3009" // Tag/Length of Sequence, the 0x09 are the following header bytes + "0605" + "2B0E03021A" // OID of SHA1 + "0500" // TLV coding of ZERO - + "0414" + getHex(hash); // 0x14 are 20 hash bytes + + "0414"), hash); // 0x14 are 20 hash bytes break; case HashAlgorithmTags.RIPEMD160: if (hash.length != 20) { throw new IOException("Bad hash length (" + hash.length + ", expected 20!"); } - dsi = "233021300906052B2403020105000414" + getHex(hash); + dsi = Arrays.concatenate(Hex.decode("3021300906052B2403020105000414"), hash); break; case HashAlgorithmTags.SHA224: if (hash.length != 28) { throw new IOException("Bad hash length (" + hash.length + ", expected 28!"); } - dsi = "2F302D300D06096086480165030402040500041C" + getHex(hash); + dsi = Arrays.concatenate(Hex.decode("302D300D06096086480165030402040500041C"), hash); break; case HashAlgorithmTags.SHA256: if (hash.length != 32) { throw new IOException("Bad hash length (" + hash.length + ", expected 32!"); } - dsi = "333031300D060960864801650304020105000420" + getHex(hash); + dsi = Arrays.concatenate(Hex.decode("3031300D060960864801650304020105000420"), hash); break; case HashAlgorithmTags.SHA384: if (hash.length != 48) { throw new IOException("Bad hash length (" + hash.length + ", expected 48!"); } - dsi = "433041300D060960864801650304020205000430" + getHex(hash); + dsi = Arrays.concatenate(Hex.decode("3041300D060960864801650304020205000430"), hash); break; case HashAlgorithmTags.SHA512: if (hash.length != 64) { throw new IOException("Bad hash length (" + hash.length + ", expected 64!"); } - dsi = "533051300D060960864801650304020305000440" + getHex(hash); + dsi = Arrays.concatenate(Hex.decode("3051300D060960864801650304020305000440"), hash); break; default: throw new IOException("Not supported hash algo!"); } // Command APDU for PERFORM SECURITY OPERATION: COMPUTE DIGITAL SIGNATURE (page 37) - String apdu = - "002A9E9A" // CLA, INS, P1, P2 - + "0000" - + dsi // digital signature input - + "0000"; // Le + CommandAPDU command = new CommandAPDU(0x00, 0x2A, 0x9E, 0x9A, dsi, MAX_APDU_NE_EXT); + ResponseAPDU response = communicate(command); - String response = communicate(apdu); - - if (response.length() < 4) { - throw new CardException("Bad response", (short) 0); + if (response.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Failed to sign", response.getSW()); } - // split up response into signature and status - String status = response.substring(response.length() - 4); - String signature = response.substring(0, response.length() - 4); - - // while we are getting 0x61 status codes, retrieve more data - while (status.substring(0, 2).equals("61")) { - Log.d(Constants.TAG, "requesting more data, status " + status); - // Send GET RESPONSE command - response = communicate("00C00000" + status.substring(2)); - status = response.substring(response.length() - 4); - signature += response.substring(0, response.length() - 4); - } - - Log.d(Constants.TAG, "final response:" + status); if (!mPw1ValidForMultipleSignatures) { mPw1ValidatedForSignature = false; } - if (!"9000".equals(status)) { - throw new CardException("Bad NFC response code: " + status, parseCardStatus(response)); - } + byte[] signature = response.getData(); // Make sure the signature we received is actually the expected number of bytes long! - if (signature.length() != 256 && signature.length() != 512 - && signature.length() != 768 && signature.length() != 1024) { - throw new IOException("Bad signature length! Expected 128/256/384/512 bytes, got " + signature.length() / 2); + if (signature.length != 128 && signature.length != 256 + && signature.length != 384 && signature.length != 512) { + throw new IOException("Bad signature length! Expected 128/256/384/512 bytes, got " + signature.length); } return Hex.decode(signature); @@ -628,8 +537,8 @@ public class SecurityTokenHelper { /** * Transceive data via NFC encoded as Hex */ - private String communicate(String apdu) throws IOException { - return getHex(mTransport.transceive(Hex.decode(apdu))); + private ResponseAPDU communicate(CommandAPDU apdu) throws IOException { + return mTransport.transceive(apdu); } public Transport getTransport() { @@ -645,9 +554,8 @@ public class SecurityTokenHelper { try { // By trying to select any apps that have the Fidesmo AID prefix we can // see if it is a Fidesmo device or not - byte[] mSelectResponse = mTransport.transceive(Apdu.select(FIDESMO_APPS_AID_PREFIX)); - // Compare the status returned by our select with the OK status code - return Apdu.hasStatus(mSelectResponse, Apdu.OK_APDU); + CommandAPDU apdu = new CommandAPDU(0x00, 0xA4, 0x04, 0x00, Hex.decode(FIDESMO_APPS_AID_PREFIX)); + return communicate(apdu).getSW() == APDU_SW_SUCCESS; } catch (IOException e) { Log.e(Constants.TAG, "Card communication failed!", e); } @@ -678,38 +586,19 @@ public class SecurityTokenHelper { verifyPin(0x83); // (Verify PW3 with mode 83) } - String generateKeyApdu = "0047800002" + String.format("%02x", slot) + "0000"; - String getResponseApdu = "00C00000"; + CommandAPDU apdu = new CommandAPDU(0x00, 0x47, 0x80, 0x00, new byte[]{(byte) slot, 0x00}, MAX_APDU_NE_EXT); + ResponseAPDU response = communicate(apdu); - String first = communicate(generateKeyApdu); - String second = communicate(getResponseApdu); - - if (!second.endsWith("9000")) { + if (response.getSW() != APDU_SW_SUCCESS) { throw new IOException("On-card key generation failed"); } - String publicKeyData = getDataField(first) + getDataField(second); - - Log.d(Constants.TAG, "Public Key Data Objects: " + publicKeyData); - - return Hex.decode(publicKeyData); + return response.getData(); } - private String getDataField(String output) { - return output.substring(0, output.length() - 4); - } - - private String tryPin(int mode, byte[] pin) throws IOException { + private ResponseAPDU tryPin(int mode, byte[] pin) throws IOException { // Command APDU for VERIFY command (page 32) - String login = - "00" // CLA - + "20" // INS - + "00" // P1 - + String.format("%02x", mode) // P2 - + String.format("%02x", pin.length) // Lc - + Hex.toHexString(pin); - - return communicate(login); + return communicate(new CommandAPDU(0x00, 0x20, 0x00, mode, pin)); } /** @@ -723,30 +612,33 @@ public class SecurityTokenHelper { // try wrong PIN 4 times until counter goes to C0 byte[] pin = "XXXXXX".getBytes(); for (int i = 0; i <= 4; i++) { - String response = tryPin(0x81, pin); - if (response.equals(accepted)) { // Should NOT accept! - throw new CardException("Should never happen, XXXXXX has been accepted!", parseCardStatus(response)); + ResponseAPDU response = tryPin(0x81, pin); + if (response.getSW() != APDU_SW_SUCCESS) { // Should NOT accept! + throw new CardException("Should never happen, XXXXXX has been accepted!", response.getSW()); } } // try wrong Admin PIN 4 times until counter goes to C0 byte[] adminPin = "XXXXXXXX".getBytes(); for (int i = 0; i <= 4; i++) { - String response = tryPin(0x83, adminPin); - if (response.equals(accepted)) { // Should NOT accept! - throw new CardException("Should never happen, XXXXXXXX has been accepted", parseCardStatus(response)); + ResponseAPDU response = tryPin(0x83, adminPin); + if (response.getSW() != APDU_SW_SUCCESS) { // Should NOT accept! + throw new CardException("Should never happen, XXXXXXXX has been accepted", response.getSW()); } } // reactivate token! - String reactivate1 = "00" + "e6" + "00" + "00"; - String reactivate2 = "00" + "44" + "00" + "00"; - String response1 = communicate(reactivate1); - String response2 = communicate(reactivate2); - if (!response1.equals(accepted) || !response2.equals(accepted)) { - throw new CardException("Reactivating failed!", parseCardStatus(response1)); - } + CommandAPDU reactivate1 = new CommandAPDU(0x00, 0xE6, 0x00, 0x00); + CommandAPDU reactivate2 = new CommandAPDU(0x00, 0x44, 0x00, 0x00); + ResponseAPDU response1 = communicate(reactivate1); + ResponseAPDU response2 = communicate(reactivate2); + if (response1.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Reactivating failed!", response1.getSW()); + } + if (response2.getSW() != APDU_SW_SUCCESS) { + throw new CardException("Reactivating failed!", response2.getSW()); + } } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/Transport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/Transport.java index 294eaa9ee..7c48b0c3a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/Transport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/Transport.java @@ -17,6 +17,9 @@ package org.sufficientlysecure.keychain.securitytoken; +import org.sufficientlysecure.keychain.securitytoken.smartcardio.CommandAPDU; +import org.sufficientlysecure.keychain.securitytoken.smartcardio.ResponseAPDU; + import java.io.IOException; /** @@ -29,7 +32,7 @@ public interface Transport { * @return received data * @throws IOException */ - byte[] transceive(byte[] data) throws IOException; + ResponseAPDU transceive(CommandAPDU data) throws IOException; /** * Disconnect and release connection 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 e1409f39e..d65bbedd3 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 @@ -29,8 +29,9 @@ import android.util.Pair; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.securitytoken.Transport; +import org.sufficientlysecure.keychain.securitytoken.smartcardio.CommandAPDU; +import org.sufficientlysecure.keychain.securitytoken.smartcardio.ResponseAPDU; import org.sufficientlysecure.keychain.securitytoken.usb.tpdu.T1TpduProtocol; -import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; @@ -230,8 +231,8 @@ public class UsbTransport implements Transport { * @throws UsbTransportException */ @Override - public byte[] transceive(byte[] data) throws UsbTransportException { - return mProtocol.transceive(data); + public ResponseAPDU transceive(CommandAPDU data) throws UsbTransportException { + return new ResponseAPDU(mProtocol.transceive(data.getBytes())); } @Override