mirror of
https://github.com/status-im/status-keycard.git
synced 2025-01-27 22:14:49 +00:00
make EXPORT KEY able to derive from other sources
This commit is contained in:
parent
98ffcda1b8
commit
d4e01ab21b
@ -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,
|
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
|
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
|
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.
|
key can then be calculate off-card if needed.
|
@ -42,7 +42,7 @@ dependencies {
|
|||||||
testCompile('org.web3j:core:2.3.1')
|
testCompile('org.web3j:core:2.3.1')
|
||||||
testCompile('org.bitcoinj:bitcoinj-core:0.14.5')
|
testCompile('org.bitcoinj:bitcoinj-core:0.14.5')
|
||||||
testCompile("org.bouncycastle:bcprov-jdk15on:1.58")
|
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")
|
testCompile("org.junit.jupiter:junit-jupiter-api:5.1.1")
|
||||||
testRuntime("org.junit.jupiter:junit-jupiter-engine:5.1.1")
|
testRuntime("org.junit.jupiter:junit-jupiter-engine:5.1.1")
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ public class WalletApplet extends Applet {
|
|||||||
static final byte DERIVE_P1_SOURCE_MASTER = (byte) 0x00;
|
static final byte DERIVE_P1_SOURCE_MASTER = (byte) 0x00;
|
||||||
static final byte DERIVE_P1_SOURCE_PARENT = (byte) 0x40;
|
static final byte DERIVE_P1_SOURCE_PARENT = (byte) 0x40;
|
||||||
static final byte DERIVE_P1_SOURCE_CURRENT = (byte) 0x80;
|
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_MIN = 4;
|
||||||
static final byte GENERATE_MNEMONIC_P1_CS_MAX = 8;
|
static final byte GENERATE_MNEMONIC_P1_CS_MAX = 8;
|
||||||
@ -1233,25 +1234,26 @@ public class WalletApplet extends Applet {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] exportPath;
|
byte[] exportPath = keyPath;
|
||||||
short exportPathOff;
|
short exportPathOff = (short) 0;
|
||||||
short exportPathLen;
|
short exportPathLen = keyPathLen;
|
||||||
|
|
||||||
boolean derive = false;
|
boolean derive = false;
|
||||||
boolean makeCurrent = 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:
|
case EXPORT_KEY_P1_CURRENT:
|
||||||
exportPath = keyPath;
|
|
||||||
exportPathOff = (short) 0;
|
|
||||||
exportPathLen = keyPathLen;
|
|
||||||
break;
|
break;
|
||||||
case EXPORT_KEY_P1_DERIVE_AND_MAKE_CURRENT:
|
case EXPORT_KEY_P1_DERIVE_AND_MAKE_CURRENT:
|
||||||
makeCurrent = true;
|
makeCurrent = true;
|
||||||
case EXPORT_KEY_P1_DERIVE:
|
case EXPORT_KEY_P1_DERIVE:
|
||||||
derive = true;
|
derive = true;
|
||||||
|
if (derivationSource == DERIVE_P1_SOURCE_MASTER) {
|
||||||
exportPath = apduBuffer;
|
exportPath = apduBuffer;
|
||||||
exportPathOff = ISO7816.OFFSET_CDATA;
|
exportPathOff = ISO7816.OFFSET_CDATA;
|
||||||
exportPathLen = dataLen;
|
exportPathLen = dataLen;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
|
ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
|
||||||
@ -1263,7 +1265,7 @@ public class WalletApplet extends Applet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (derive) {
|
if (derive) {
|
||||||
doDerive(apduBuffer, dataLen, DERIVE_P1_SOURCE_MASTER, makeCurrent);
|
doDerive(apduBuffer, dataLen, derivationSource, makeCurrent);
|
||||||
}
|
}
|
||||||
|
|
||||||
short off = SecureChannel.SC_OUT_OFFSET;
|
short off = SecureChannel.SC_OUT_OFFSET;
|
||||||
|
@ -981,13 +981,13 @@ public class WalletAppletTest {
|
|||||||
verifyExportedKey(keyTemplate, keyPair, chainCode, new int[] { 0x8000002b, 0x8000003c, 0x8000062d, 0x00000000 }, true, false);
|
verifyExportedKey(keyTemplate, keyPair, chainCode, new int[] { 0x8000002b, 0x8000003c, 0x8000062d, 0x00000000 }, true, false);
|
||||||
|
|
||||||
// Derive & Make current
|
// 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());
|
assertEquals(0x9000, response.getSW());
|
||||||
keyTemplate = response.getData();
|
keyTemplate = response.getData();
|
||||||
verifyExportedKey(keyTemplate, keyPair, chainCode, new int[] { 0x8000002b, 0x8000003c, 0x8000062d, 0x00000000, 0x00000000 }, false, false);
|
verifyExportedKey(keyTemplate, keyPair, chainCode, new int[] { 0x8000002b, 0x8000003c, 0x8000062d, 0x00000000, 0x00000000 }, false, false);
|
||||||
|
|
||||||
// Derive without making current
|
// 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());
|
assertEquals(0x9000, response.getSW());
|
||||||
keyTemplate = response.getData();
|
keyTemplate = response.getData();
|
||||||
verifyExportedKey(keyTemplate, keyPair, chainCode, new int[] { 0x8000002b, 0x8000003c, 0x8000062d, 0x00000000, 0x00000001 }, false, true);
|
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);
|
verifyExportedKey(keyTemplate, keyPair, chainCode, new int[] { 0x8000002b, 0x8000003c, 0x8000062d, 0x00000000, 0x00000000 }, false, false);
|
||||||
|
|
||||||
// Reset
|
// 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());
|
assertEquals(0x9000, response.getSW());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user