diff --git a/src/main/java/im/status/keycard/KeycardApplet.java b/src/main/java/im/status/keycard/KeycardApplet.java index d23cc51..8fdfa9e 100644 --- a/src/main/java/im/status/keycard/KeycardApplet.java +++ b/src/main/java/im/status/keycard/KeycardApplet.java @@ -113,6 +113,9 @@ public class KeycardApplet extends Applet { private ECPrivateKey privateKey; private byte[] chainCode; + private ECPublicKey pinlessPublicKey; + private ECPrivateKey pinlessPrivateKey; + private byte[] keyPath; private short keyPathLen; @@ -171,6 +174,9 @@ public class KeycardApplet extends Applet { publicKey = (ECPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, SECP256k1.SECP256K1_KEY_SIZE, false); privateKey = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, SECP256k1.SECP256K1_KEY_SIZE, false); + pinlessPublicKey = (ECPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, SECP256k1.SECP256K1_KEY_SIZE, false); + pinlessPrivateKey = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, SECP256k1.SECP256K1_KEY_SIZE, false); + masterChainCode = new byte[CHAIN_CODE_SIZE]; parentChainCode = new byte[CHAIN_CODE_SIZE]; chainCode = new byte[CHAIN_CODE_SIZE]; @@ -646,6 +652,7 @@ public class KeycardApplet extends Applet { break; } + pinlessPathLen = 0; generateKeyUIDAndRespond(apdu, apduBuffer); } @@ -1030,6 +1037,8 @@ public class KeycardApplet extends Applet { masterPublic.clearKey(); parentPrivateKey.clearKey(); parentPublicKey.clearKey(); + pinlessPrivateKey.clearKey(); + pinlessPublicKey.clearKey(); resetCurveParameters(); Util.arrayFillNonAtomic(chainCode, (short) 0, (short) chainCode.length, (byte) 0); Util.arrayFillNonAtomic(parentChainCode, (short) 0, (short) parentChainCode.length, (byte) 0); @@ -1057,6 +1066,7 @@ public class KeycardApplet extends Applet { crypto.random.generateData(apduBuffer, ISO7816.OFFSET_CDATA, BIP39_SEED_SIZE); loadSeed(apduBuffer); + pinlessPathLen = 0; generateKeyUIDAndRespond(apdu, apduBuffer); } @@ -1094,6 +1104,7 @@ public class KeycardApplet extends Applet { break; case DUPLICATE_KEY_P1_IMPORT: importDuplicate(apduBuffer); + pinlessPathLen = 0; generateKeyUIDAndRespond(apdu, apduBuffer); break; default: @@ -1231,6 +1242,14 @@ public class KeycardApplet extends Applet { JCSystem.beginTransaction(); pinlessPathLen = len; Util.arrayCopy(apduBuffer, ISO7816.OFFSET_CDATA, pinlessPath, (short) 0, len); + + if (pinlessPathLen > 0) { + doDerive(apduBuffer, len, DERIVE_P1_SOURCE_MASTER, false); + pinlessPrivateKey.setS(derivationOutput, (short) 0, Crypto.KEY_SECRET_SIZE); + secp256k1.derivePublicKey(pinlessPrivateKey, apduBuffer, (short) 0); + pinlessPublicKey.setW(apduBuffer, (short) 0, Crypto.KEY_PUB_SIZE); + } + JCSystem.commitTransaction(); } @@ -1379,5 +1398,8 @@ public class KeycardApplet extends Applet { secp256k1.setCurveParameters(publicKey); secp256k1.setCurveParameters(privateKey); + + secp256k1.setCurveParameters(pinlessPrivateKey); + secp256k1.setCurveParameters(pinlessPublicKey); } } diff --git a/src/main/java/im/status/keycard/SECP256k1.java b/src/main/java/im/status/keycard/SECP256k1.java index 1a9bbc2..ad33bba 100644 --- a/src/main/java/im/status/keycard/SECP256k1.java +++ b/src/main/java/im/status/keycard/SECP256k1.java @@ -55,7 +55,7 @@ public class SECP256k1 { private KeyAgreement ecPointMultiplier; private Crypto crypto; - private ECPrivateKey tmpECPrivateKey; + ECPrivateKey tmpECPrivateKey; /** * Allocates objects needed by this class. Must be invoked during the applet installation exactly 1 time. diff --git a/src/test/java/im/status/keycard/KeycardTest.java b/src/test/java/im/status/keycard/KeycardTest.java index f0e5a61..e328b97 100644 --- a/src/test/java/im/status/keycard/KeycardTest.java +++ b/src/test/java/im/status/keycard/KeycardTest.java @@ -1082,12 +1082,19 @@ public class KeycardTest { resetAndSelectAndOpenSC(); response = cmdSet.sign(hash); assertEquals(0x6985, response.getSw()); + + if (cmdSet.getApplicationInfo().hasCredentialsManagementCapability()) { + response = cmdSet.verifyPIN("000000"); + assertEquals(0x9000, response.getSw()); + } + response = cmdSet.deriveKey(new byte[] {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01}, KeycardApplet.DERIVE_P1_SOURCE_MASTER); assertEquals(0x9000, response.getSw()); - response = cmdSet.sign(hash); - assertEquals(0x6985, response.getSw()); response = cmdSet.deriveKey(new byte[] {0x00, 0x00, 0x00, 0x02}, KeycardApplet.DERIVE_P1_SOURCE_CURRENT); assertEquals(0x9000, response.getSw()); + + resetAndSelectAndOpenSC(); + response = cmdSet.sign(hash); assertEquals(0x9000, response.getSw()); @@ -1102,8 +1109,16 @@ public class KeycardTest { resetAndSelectAndOpenSC(); response = cmdSet.sign(hash); assertEquals(0x6985, response.getSw()); + + + if (cmdSet.getApplicationInfo().hasCredentialsManagementCapability()) { + response = cmdSet.verifyPIN("000000"); + assertEquals(0x9000, response.getSw()); + } + response = cmdSet.deriveKey(new byte[] {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01}, KeycardApplet.DERIVE_P1_SOURCE_MASTER); assertEquals(0x9000, response.getSw()); + resetAndSelectAndOpenSC(); response = cmdSet.sign(hash); assertEquals(0x9000, response.getSw());