diff --git a/APPLICATION.MD b/APPLICATION.MD index 3026235..9266e7b 100644 --- a/APPLICATION.MD +++ b/APPLICATION.MD @@ -439,7 +439,9 @@ private key (P2=0x00) can be exported if and only if the requested key path is i The P1 parameter indicates how to the derive the desired key. P1 = 0x00 indicates that the current key must be exported, and no derivation will be performed. P1 = 0x01 derives the path given in the data field without changing the current -path of the card. P1 = 0x02 derives the path but also changes the current path of the card. +path of the card. P1 = 0x02 derives the path but also changes the current path of the card. The source for derivation +can be set by OR'ing P1 with the constants defined in the DERIVE KEY command. This allows deriving from master, parent +or current. If the private key is being exported, the card could omit exporting the public key for performance reason. The public key can then be calculate off-card if needed. \ No newline at end of file diff --git a/build.gradle b/build.gradle index 8d6915e..4cc12b1 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ dependencies { testCompile('org.web3j:core:2.3.1') testCompile('org.bitcoinj:bitcoinj-core:0.14.5') testCompile("org.bouncycastle:bcprov-jdk15on:1.58") - testCompile("com.github.status-im:hardwallet-lite-sdk:75d9f54") + testCompile("com.github.status-im:hardwallet-lite-sdk:482e32c") testCompile("org.junit.jupiter:junit-jupiter-api:5.1.1") testRuntime("org.junit.jupiter:junit-jupiter-engine:5.1.1") } diff --git a/src/main/java/im/status/wallet/WalletApplet.java b/src/main/java/im/status/wallet/WalletApplet.java index b755805..9d15ace 100644 --- a/src/main/java/im/status/wallet/WalletApplet.java +++ b/src/main/java/im/status/wallet/WalletApplet.java @@ -52,6 +52,7 @@ public class WalletApplet extends Applet { static final byte DERIVE_P1_SOURCE_MASTER = (byte) 0x00; static final byte DERIVE_P1_SOURCE_PARENT = (byte) 0x40; static final byte DERIVE_P1_SOURCE_CURRENT = (byte) 0x80; + static final byte DERIVE_P1_SOURCE_MASK = (byte) 0xC0; static final byte GENERATE_MNEMONIC_P1_CS_MIN = 4; static final byte GENERATE_MNEMONIC_P1_CS_MAX = 8; @@ -1233,25 +1234,26 @@ public class WalletApplet extends Applet { return; } - byte[] exportPath; - short exportPathOff; - short exportPathLen; + byte[] exportPath = keyPath; + short exportPathOff = (short) 0; + short exportPathLen = keyPathLen; + boolean derive = false; boolean makeCurrent = false; + byte derivationSource = (byte) (apduBuffer[ISO7816.OFFSET_P1] & DERIVE_P1_SOURCE_MASK); - switch (apduBuffer[ISO7816.OFFSET_P1]) { + switch ((byte) (apduBuffer[ISO7816.OFFSET_P1] & ~DERIVE_P1_SOURCE_MASK)) { case EXPORT_KEY_P1_CURRENT: - exportPath = keyPath; - exportPathOff = (short) 0; - exportPathLen = keyPathLen; break; case EXPORT_KEY_P1_DERIVE_AND_MAKE_CURRENT: makeCurrent = true; case EXPORT_KEY_P1_DERIVE: derive = true; - exportPath = apduBuffer; - exportPathOff = ISO7816.OFFSET_CDATA; - exportPathLen = dataLen; + if (derivationSource == DERIVE_P1_SOURCE_MASTER) { + exportPath = apduBuffer; + exportPathOff = ISO7816.OFFSET_CDATA; + exportPathLen = dataLen; + } break; default: ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); @@ -1263,7 +1265,7 @@ public class WalletApplet extends Applet { } if (derive) { - doDerive(apduBuffer, dataLen, DERIVE_P1_SOURCE_MASTER, makeCurrent); + doDerive(apduBuffer, dataLen, derivationSource, makeCurrent); } short off = SecureChannel.SC_OUT_OFFSET; diff --git a/src/test/java/im/status/wallet/WalletAppletTest.java b/src/test/java/im/status/wallet/WalletAppletTest.java index 53f2e72..3c3bae6 100644 --- a/src/test/java/im/status/wallet/WalletAppletTest.java +++ b/src/test/java/im/status/wallet/WalletAppletTest.java @@ -981,13 +981,13 @@ public class WalletAppletTest { verifyExportedKey(keyTemplate, keyPair, chainCode, new int[] { 0x8000002b, 0x8000003c, 0x8000062d, 0x00000000 }, true, false); // Derive & Make current - response = cmdSet.exportKey(new byte[] {(byte) 0x80, 0x00, 0x00, 0x2B, (byte) 0x80, 0x00, 0x00, 0x3C, (byte) 0x80, 0x00, 0x06, 0x2D, (byte) 0x00, 0x00, 0x00, 0x00, (byte) 0x00, 0x00, 0x00, 0x00}, true,false); + response = cmdSet.exportKey(new byte[] {(byte) 0x80, 0x00, 0x00, 0x2B, (byte) 0x80, 0x00, 0x00, 0x3C, (byte) 0x80, 0x00, 0x06, 0x2D, (byte) 0x00, 0x00, 0x00, 0x00, (byte) 0x00, 0x00, 0x00, 0x00}, WalletApplet.DERIVE_P1_SOURCE_MASTER,true,false); assertEquals(0x9000, response.getSW()); keyTemplate = response.getData(); verifyExportedKey(keyTemplate, keyPair, chainCode, new int[] { 0x8000002b, 0x8000003c, 0x8000062d, 0x00000000, 0x00000000 }, false, false); // Derive without making current - response = cmdSet.exportKey(new byte[] {(byte) 0x80, 0x00, 0x00, 0x2B, (byte) 0x80, 0x00, 0x00, 0x3C, (byte) 0x80, 0x00, 0x06, 0x2D, (byte) 0x00, 0x00, 0x00, 0x00, (byte) 0x00, 0x00, 0x00, 0x01}, false,false); + response = cmdSet.exportKey(new byte[] {(byte) 0x00, 0x00, 0x00, 0x01}, WalletApplet.DERIVE_P1_SOURCE_PARENT, false,false); assertEquals(0x9000, response.getSW()); keyTemplate = response.getData(); verifyExportedKey(keyTemplate, keyPair, chainCode, new int[] { 0x8000002b, 0x8000003c, 0x8000062d, 0x00000000, 0x00000001 }, false, true); @@ -1002,7 +1002,7 @@ public class WalletAppletTest { verifyExportedKey(keyTemplate, keyPair, chainCode, new int[] { 0x8000002b, 0x8000003c, 0x8000062d, 0x00000000, 0x00000000 }, false, false); // Reset - response = cmdSet.deriveKey(new byte[] {}, WalletApplet.DERIVE_P1_SOURCE_MASTER); + response = cmdSet.deriveKey(new byte[0], WalletApplet.DERIVE_P1_SOURCE_MASTER); assertEquals(0x9000, response.getSW()); }