diff --git a/APPLICATION.MD b/APPLICATION.MD index cf3bc5d..d8c5b4c 100644 --- a/APPLICATION.MD +++ b/APPLICATION.MD @@ -69,7 +69,6 @@ Response Data format: - Tag 0xC0 = PIN retry count (1 byte) - Tag 0xC1 = PUK retry count (1 byte) - Tag 0xC2 = 0 if key is not initialized, 1 otherwise - - Tag 0xC3 = 0 if public key derivation is not supported, 1 otherwise ### VERIFY PIN @@ -125,27 +124,24 @@ always returns 0x63C0, even if the PUK is inserted correctly. In this case the w * P1 = key type * P2 = 0x00 * Data = the key data -* Response SW = 0x9000 on success, 0x6A80 if the format is invalid, 0x6A86 if P1 is invalid, 0x6A81 if public key is - omitted and its derivation is not supported. +* Response SW = 0x9000 on success, 0x6A80 if the format is invalid, 0x6A86 if P1 is invalid * Preconditions: Secure Channel must be opened, user PIN must be verified P1: * 0x01 = ECC SECP256k1 keypair * 0x02 = ECC SECP256k1 extended keypair -* 0x03 = Binary seed as defined in [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) (if card -supports public key derivation) +* 0x03 = Binary seed as defined in [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) Data: If P1 is 0x01 or 0x02 - Tag 0xA1 = keypair template - - Tag 0x80 = ECC public key component (can be omitted if card supports public key derivation) + - Tag 0x80 = ECC public key component (can be omitted) - Tag 0x81 = ECC private key component - Tag 0x82 = chain code (if P1=0x02) If P1 is 0x03 a 64 byte sequence generated according to the BIP39 specifications is expected. The master key will be -generated according to the [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) specifications. Since -in this case the public key is not provided externally, the card must support public key derivation. +generated according to the [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) specifications. This command is used to load or replace the keypair used for signing on the card. This command always aborts open signing sessions, if any. Unless a DERIVE KEY is sent, a subsequent SIGN command will use this keypair for signature. @@ -156,21 +152,12 @@ signing sessions, if any. Unless a DERIVE KEY is sent, a subsequent SIGN command * INS = 0xD1 * P1 = 0x00 * P2 = 0x00 -* Data = key derivation template -* Response SW = 0x9000 on success, 0x6A80 if the format is invalid, 0x6A81 if public keys are omitted and their derivation - is not supported. +* Data = a sequence of 32-bit integers (most significant byte first). Empty if the master key must be used. +* Response SW = 0x9000 on success, 0x6A80 if the format is invalid * Preconditions: Secure Channel must be opened, user PIN must be verified, an extended keyset must be loaded -Data format: - -- Tag 0xA2 = key derivation template - - Tag 0xC0 = a sequence of 32-bit integers (most significant byte first). Empty if the master key must be used. - - Tag 0xC1 = derived public key (omitted if master or public key derivation is supported) - - Tag 0xC2 = parent public key (omitted if master or public key derivation is supported) - This command is used before a signing session to generated a private key according to the [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) -specifications. The generated key is used for all subsequent SIGN sessions. An empty 0x82 is used in order for SIGN to -use the master key instead. Omitting the 0x82 subtag entirely is not permitted. +specifications. The generated key is used for all subsequent SIGN sessions. ### GENERATE MNEMONIC diff --git a/src/main/java/im/status/wallet/WalletApplet.java b/src/main/java/im/status/wallet/WalletApplet.java index d9ee205..ee43748 100644 --- a/src/main/java/im/status/wallet/WalletApplet.java +++ b/src/main/java/im/status/wallet/WalletApplet.java @@ -43,16 +43,10 @@ public class WalletApplet extends Applet { static final byte TLV_PRIV_KEY = (byte) 0x81; static final byte TLV_CHAIN_CODE = (byte) 0x82; - static final byte TLV_KEY_DERIVATION_TEMPLATE = (byte) 0xA2; - static final byte TLV_DERIVATION_SEQUENCE = (byte) 0xC0; - static final byte TLV_DERIVED_PUB_KEY = (byte) 0xC1; - static final byte TLV_PARENT_PUB_KEY = (byte) 0xC2; - static final byte TLV_APPLICATION_STATUS_TEMPLATE = (byte) 0xA3; static final byte TLV_PIN_RETRY_COUNT = (byte) 0xC0; static final byte TLV_PUK_RETRY_COUNT = (byte) 0xC1; static final byte TLV_KEY_INITIALIZATION_STATUS = (byte) 0xC2; - static final byte TLV_PUBLIC_KEY_DERIVATION_SUPPORTED = (byte) 0xC3; private OwnerPIN pin; private OwnerPIN puk; @@ -168,7 +162,7 @@ public class WalletApplet extends Applet { byte[] apduBuffer = apdu.getBuffer(); apduBuffer[off++] = TLV_APPLICATION_STATUS_TEMPLATE; - apduBuffer[off++] = 12; + apduBuffer[off++] = 9; apduBuffer[off++] = TLV_PIN_RETRY_COUNT; apduBuffer[off++] = 1; apduBuffer[off++] = pin.getTriesRemaining(); @@ -178,9 +172,6 @@ public class WalletApplet extends Applet { apduBuffer[off++] = TLV_KEY_INITIALIZATION_STATUS; apduBuffer[off++] = 1; apduBuffer[off++] = privateKey.isInitialized() ? (byte) 0x01 : (byte) 0x00; - apduBuffer[off++] = TLV_PUBLIC_KEY_DERIVATION_SUPPORTED; - apduBuffer[off++] = 1; - apduBuffer[off++] = 1; //TODO: actually check if it is supported or totally remove if a fallback software implementation is a requirement short len = secureChannel.encryptAPDU(apduBuffer, (short) (off - SecureChannel.SC_OUT_OFFSET)); apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, len); diff --git a/src/test/java/im/status/wallet/WalletAppletTest.java b/src/test/java/im/status/wallet/WalletAppletTest.java index 64b9d66..5d2b36a 100644 --- a/src/test/java/im/status/wallet/WalletAppletTest.java +++ b/src/test/java/im/status/wallet/WalletAppletTest.java @@ -116,25 +116,24 @@ public class WalletAppletTest { cmdSet.openSecureChannel(); // Good case. Since the order of test execution is undefined, the test cannot know if the keys are initialized or not. - // Additionally, the public key derivation cannot also be known here. response = cmdSet.getStatus(); assertEquals(0x9000, response.getSW()); byte[] data = secureChannel.decryptAPDU(response.getData()); - assertTrue(Hex.toHexString(data).matches("a30cc00103c10105c2010[0-1]c3010[0-1]")); + assertTrue(Hex.toHexString(data).matches("a309c00103c10105c2010[0-1]")); response = cmdSet.verifyPIN("123456"); assertEquals(0x63C2, response.getSW()); response = cmdSet.getStatus(); assertEquals(0x9000, response.getSW()); data = secureChannel.decryptAPDU(response.getData()); - assertTrue(Hex.toHexString(data).matches("a30cc00102c10105c2010[0-1]c3010[0-1]")); + assertTrue(Hex.toHexString(data).matches("a309c00102c10105c2010[0-1]")); response = cmdSet.verifyPIN("000000"); assertEquals(0x9000, response.getSW()); response = cmdSet.getStatus(); assertEquals(0x9000, response.getSW()); data = secureChannel.decryptAPDU(response.getData()); - assertTrue(Hex.toHexString(data).matches("a30cc00103c10105c2010[0-1]c3010[0-1]")); + assertTrue(Hex.toHexString(data).matches("a309c00103c10105c2010[0-1]")); } @Test