From b1be261ea1acbf1d81d37eb79ed9fed8f4d27d52 Mon Sep 17 00:00:00 2001 From: Michele Balistreri Date: Tue, 15 Oct 2019 14:55:48 +0300 Subject: [PATCH] remove DUPLICATE KEY command --- .../status/keycard/applet/CardDuplicator.java | 141 ------------------ .../keycard/applet/DuplicatorCallback.java | 24 --- .../keycard/applet/KeycardCommandSet.java | 52 ------- 3 files changed, 217 deletions(-) delete mode 100644 lib/src/main/java/im/status/keycard/applet/CardDuplicator.java delete mode 100644 lib/src/main/java/im/status/keycard/applet/DuplicatorCallback.java diff --git a/lib/src/main/java/im/status/keycard/applet/CardDuplicator.java b/lib/src/main/java/im/status/keycard/applet/CardDuplicator.java deleted file mode 100644 index 1c3b392..0000000 --- a/lib/src/main/java/im/status/keycard/applet/CardDuplicator.java +++ /dev/null @@ -1,141 +0,0 @@ -package im.status.keycard.applet; - -import im.status.keycard.io.APDUException; -import im.status.keycard.io.CardChannel; -import im.status.keycard.io.WrongPINException; - -import java.io.IOException; -import java.security.SecureRandom; -import java.util.HashSet; - -/** - * Class helping with the card duplication process. Depending on the client's role, only some of the methods are relevant. - */ -public class CardDuplicator { - private byte[] secret; - private KeycardCommandSet cmdSet; - private DuplicatorCallback cb; - - private HashSet startedDuplication; - private HashSet addedEntropy; - private HashSet finishedDuplication; - - /** - * Creates a CardDuplicator object. Regardless of the role of the client, this object must be kept and used for the - * entire duplication session. It cannot be reused for multiple sessions. - * - * @param cmdSet the CommandSet to use - * @param cb the callback object for backups. This is needed only on the client performing steps requiring pairing - * and authentication. Clients which only add entropy should pass null - */ - public CardDuplicator(KeycardCommandSet cmdSet, DuplicatorCallback cb) { - this.cmdSet = cmdSet; - this.cb = cb; - this.startedDuplication = new HashSet<>(); - this.addedEntropy = new HashSet<>(); - this.finishedDuplication = new HashSet<>(); - - this.secret = new byte[32]; - SecureRandom random = new SecureRandom(); - random.nextBytes(this.secret); - } - - /** - * Creates a CardDuplicator object. Only suitable for clients performing the role of adding entropy. - * - * @param channel the APDU channel - */ - public CardDuplicator(CardChannel channel) { - this(new KeycardCommandSet(channel), null); - } - - private ApplicationInfo selectAndCheck(HashSet processed) throws APDUException, IOException { - ApplicationInfo appInfo = new ApplicationInfo(cmdSet.select().checkOK().getData()); - - if (!processed.add(appInfo.getInstanceUID())) { - throw new IllegalStateException("The requested action has been already performed on this card"); - } - - return appInfo; - } - - private void preamble(HashSet processed) throws IOException, APDUException { - ApplicationInfo appInfo = selectAndCheck(processed); - - Pairing pairing = cb.getPairing(appInfo); - - if (pairing == null) { - throw new APDUException("The given card is not paired"); - } - - cmdSet.setPairing(pairing); - cmdSet.autoOpenSecureChannel(); - ApplicationStatus appStatus = new ApplicationStatus(cmdSet.getStatus(KeycardCommandSet.GET_STATUS_P1_APPLICATION).checkOK().getData()); - int remainingAttempts = appStatus.getPINRetryCount(); - - while(remainingAttempts > 0) { - try { - cmdSet.verifyPIN(cb.getPIN(appInfo, remainingAttempts)).checkAuthOK(); - break; - } catch(WrongPINException e) { - remainingAttempts = e.getRetryAttempts(); - } - } - - if (remainingAttempts <= 0) { - throw new APDUException("Card blocked"); - } - } - - /** - * Starts duplication session. Must be used on all cards taking part of in the duplication process. - * - * @param clientCount the number of clients which will be adding entropy for the key, including this one - * - * @throws IOException communication error - * @throws APDUException unexpected card response - * @throws IllegalStateException this card has already been used - */ - public void startDuplication(int clientCount) throws IOException, APDUException, IllegalStateException { - preamble(startedDuplication); - cmdSet.duplicateKeyStart(clientCount, secret).checkOK(); - } - - /** - * Exports key. Must be used on the card designated as the source for the duplication. - * - * @throws IOException communication error - * @throws APDUException unexpected card response - */ - public byte[] exportKey() throws IOException, APDUException, IllegalStateException { - preamble(finishedDuplication); - return cmdSet.duplicateKeyExport().checkOK().getData(); - } - - /** - * Imports key. Must be used on all cards designated as the target for the duplication. - * - * @param key the key to import - * @return the key UID - * @throws IOException communication error - * @throws APDUException unexpected card response - * @throws IllegalStateException this card has already been used - */ - public byte[] importKey(byte[] key) throws IOException, APDUException, IllegalStateException { - preamble(finishedDuplication); - return cmdSet.duplicateKeyImport(key).checkOK().getData(); - } - - /** - * Adds entropy. Must be used on all cards taking part in the backup process. Each client taking part must use this - * exactly once, except for the client which started the backup. - * - * @throws IOException communication error - * @throws APDUException unexpected card response - * @throws IllegalStateException this card has already been used - */ - public void addEntropy() throws IOException, APDUException, IllegalStateException { - selectAndCheck(addedEntropy); - cmdSet.duplicateKeyAddEntropy(secret).checkOK(); - } -} diff --git a/lib/src/main/java/im/status/keycard/applet/DuplicatorCallback.java b/lib/src/main/java/im/status/keycard/applet/DuplicatorCallback.java deleted file mode 100644 index 170225b..0000000 --- a/lib/src/main/java/im/status/keycard/applet/DuplicatorCallback.java +++ /dev/null @@ -1,24 +0,0 @@ -package im.status.keycard.applet; - -/** - * Callback interface for duplication procedure. - */ -public interface DuplicatorCallback { - /** - * Must return the pairing for the current card, represented by the applicationInfo parameter. If no pairing - * could be found, null must be returned. - * - * @param applicationInfo the application info template of the currently inserted card - * @return the pairing info or null - */ - Pairing getPairing(ApplicationInfo applicationInfo); - - /** - * Must return the PIN for the current card. This method can prompt the user or return a cached value. - * - * @param applicationInfo the application info template of the currently inserted card - * @param remainingAttempts the number of remaining PIN attempts - * @return the PIN - */ - String getPIN(ApplicationInfo applicationInfo, int remainingAttempts); -} diff --git a/lib/src/main/java/im/status/keycard/applet/KeycardCommandSet.java b/lib/src/main/java/im/status/keycard/applet/KeycardCommandSet.java index 12ea022..88f9dd3 100644 --- a/lib/src/main/java/im/status/keycard/applet/KeycardCommandSet.java +++ b/lib/src/main/java/im/status/keycard/applet/KeycardCommandSet.java @@ -28,7 +28,6 @@ public class KeycardCommandSet { static final byte INS_GENERATE_MNEMONIC = (byte) 0xD2; static final byte INS_REMOVE_KEY = (byte) 0xD3; static final byte INS_GENERATE_KEY = (byte) 0xD4; - static final byte INS_DUPLICATE_KEY = (byte) 0xD5; static final byte INS_SIGN = (byte) 0xC0; static final byte INS_SET_PINLESS_PATH = (byte) 0xC1; static final byte INS_EXPORT_KEY = (byte) 0xC2; @@ -488,57 +487,6 @@ public class KeycardCommandSet { return secureChannel.transmit(apduChannel, generateKey); } - /** - * Sends a DUPLICATE KEY APDU. The P1 is set to 00, P2 to the entropy count and the data is the first entropy piece. - * This starts a duplication session. Requires an open Secure Channel and authenticated PIN. - * - * @param entropyCount the number of entropy pieces to expect, including the one in this APDU - * @param firstEntropy a random 32-byte number - * @return the raw card response - * @throws IOException communication error - */ - public APDUResponse duplicateKeyStart(int entropyCount, byte[] firstEntropy) throws IOException { - APDUCommand duplicateKeyStart = secureChannel.protectedCommand(0x80, INS_DUPLICATE_KEY, DUPLICATE_KEY_P1_START, entropyCount, firstEntropy); - return secureChannel.transmit(apduChannel, duplicateKeyStart); - } - - /** - * Sends a DUPLICATE KEY APDU. The P1 is set to 01 and the data is the entropy. This adds entropy and does not require - * a Secure Channel or authenticated PIN. - * - * @param entropy a random 32-byte number - * @return the raw card response - * @throws IOException communication error - */ - public APDUResponse duplicateKeyAddEntropy(byte[] entropy) throws IOException { - APDUCommand duplicateKeyAddEntropy = new APDUCommand(0x80, INS_DUPLICATE_KEY, DUPLICATE_KEY_P1_ADD_ENTROPY, 0, secureChannel.oneShotEncrypt(entropy)); - return apduChannel.send(duplicateKeyAddEntropy); - } - - /** - * Sends a DUPLICATE KEY APDU. The P1 is set to 02. This exports the encrypted master key including chaining code. - * - * @return the raw card response - * @throws IOException communication error - */ - public APDUResponse duplicateKeyExport() throws IOException { - APDUCommand duplicateKeyExport = secureChannel.protectedCommand(0x80, INS_DUPLICATE_KEY, DUPLICATE_KEY_P1_EXPORT, 0, new byte[0]); - return secureChannel.transmit(apduChannel, duplicateKeyExport); - } - - /** - * Sends a DUPLICATE KEY APDU. The P1 is set to 03. This imports an encrypted master key including chaining code. The - * response data contains the key UID of the imported key. - * - * @param key the key, exported from another card in the same duplication session. - * @return the raw card response - * @throws IOException communication error - */ - public APDUResponse duplicateKeyImport(byte[] key) throws IOException { - APDUCommand duplicateKeyImport = secureChannel.protectedCommand(0x80, INS_DUPLICATE_KEY, DUPLICATE_KEY_P1_IMPORT, 0, key); - return secureChannel.transmit(apduChannel, duplicateKeyImport); - } - /** * Sends a SIGN APDU. This signs a precomputed hash that must be exactly 32-bytes long. *