fix situation where the card would get stuck in waiting for public key status
This commit is contained in:
parent
24352fb0bc
commit
c062e53a6e
|
@ -279,6 +279,7 @@ public class WalletApplet extends Applet {
|
|||
}
|
||||
|
||||
signInProgress = false;
|
||||
expectPublicKey = false;
|
||||
}
|
||||
|
||||
private void loadKeyPair(byte[] apduBuffer, boolean newExtended) {
|
||||
|
@ -500,7 +501,7 @@ public class WalletApplet extends Applet {
|
|||
private void sign(APDU apdu) {
|
||||
apdu.setIncomingAndReceive();
|
||||
|
||||
if (!(secureChannel.isOpen() && pin.isValidated() && privateKey.isInitialized())) {
|
||||
if (!(secureChannel.isOpen() && pin.isValidated() && privateKey.isInitialized() && !expectPublicKey)) {
|
||||
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,12 @@ public class WalletAppletCommandSet {
|
|||
return apduChannel.transmit(getStatus);
|
||||
}
|
||||
|
||||
public boolean getPublicKeyDerivationSupport() throws CardException {
|
||||
ResponseAPDU resp = getStatus();
|
||||
byte[] data = secureChannel.decryptAPDU(resp.getData());
|
||||
return data[data.length - 1] == 1;
|
||||
}
|
||||
|
||||
public ResponseAPDU verifyPIN(String pin) throws CardException {
|
||||
CommandAPDU verifyPIN = new CommandAPDU(0x80, WalletApplet.INS_VERIFY_PIN, 0, 0, secureChannel.encryptAPDU(pin.getBytes()));
|
||||
return apduChannel.transmit(verifyPIN);
|
||||
|
|
|
@ -282,6 +282,8 @@ public class WalletAppletTest {
|
|||
|
||||
cmdSet.openSecureChannel();
|
||||
|
||||
int publicKeyDerivationSW = cmdSet.getPublicKeyDerivationSupport() ? 0x9000 : 0x6a81;
|
||||
|
||||
// Security condition violation: PIN not verified
|
||||
response = cmdSet.loadKey(keyPair);
|
||||
assertEquals(0x6985, response.getSW());
|
||||
|
@ -320,13 +322,13 @@ public class WalletAppletTest {
|
|||
|
||||
// Check omitted public key
|
||||
response = cmdSet.loadKey(keyPair, true, null);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
assertEquals(publicKeyDerivationSW, response.getSW());
|
||||
response = cmdSet.loadKey(keyPair, true, chainCode);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
assertEquals(publicKeyDerivationSW, response.getSW());
|
||||
|
||||
// Check seed load
|
||||
response = cmdSet.loadKey(keyPair.getPrivate(), chainCode);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
assertEquals(publicKeyDerivationSW, response.getSW());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -374,6 +376,7 @@ public class WalletAppletTest {
|
|||
assertEquals(0x6985, response.getSW());
|
||||
|
||||
cmdSet.openSecureChannel();
|
||||
boolean autonomousDerivation = cmdSet.getPublicKeyDerivationSupport();
|
||||
|
||||
// Security condition violation: PIN is not verified
|
||||
response = cmdSet.deriveKey(new byte[] {0x00, 0x00, 0x00, 0x00});
|
||||
|
@ -410,6 +413,8 @@ public class WalletAppletTest {
|
|||
response = cmdSet.deriveKey(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, true, true, false);
|
||||
assertEquals(0x6A80, response.getSW());
|
||||
|
||||
|
||||
if (autonomousDerivation) {
|
||||
// Correct
|
||||
response = cmdSet.deriveKey(new byte[]{0x00, 0x00, 0x00, 0x01});
|
||||
assertEquals(0x9000, response.getSW());
|
||||
|
@ -433,6 +438,10 @@ public class WalletAppletTest {
|
|||
response = cmdSet.deriveKey(new byte[]{0x00, 0x00, 0x00, 0x02}, false, false, false);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
verifyKeyDerivation(keyPair, chainCode, new int[]{1, 0x80000000, 2});
|
||||
} else {
|
||||
response = cmdSet.deriveKey(new byte[]{0x00, 0x00, 0x00, 0x01});
|
||||
assertEquals(0x6a81, response.getSW());
|
||||
}
|
||||
|
||||
// Assisted derivation
|
||||
response = cmdSet.deriveKey(new byte[] {0x00, 0x00, 0x00, 0x01}, true, true, false);
|
||||
|
@ -452,9 +461,21 @@ public class WalletAppletTest {
|
|||
assertEquals(0x9000, response.getSW());
|
||||
response = cmdSet.deriveKey(new byte[] {0x00, 0x00, 0x00, 0x02}, false, true, false);
|
||||
assertEquals(0x6a86, response.getSW());
|
||||
|
||||
// Reset master key
|
||||
response = cmdSet.deriveKey(new byte[0]);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
verifyKeyDerivation(keyPair, chainCode, new int[0]);
|
||||
|
||||
// Try to sign before load public key, then resume loading public key
|
||||
response = cmdSet.deriveKey(new byte[] {0x00, 0x00, 0x00, 0x02}, false, true, false);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
byte[] key = derivePublicKey(secureChannel.decryptAPDU(response.getData()));
|
||||
response = cmdSet.sign(sha256("test".getBytes()), WalletApplet.SIGN_P1_PRECOMPUTED_HASH, true, true);
|
||||
assertEquals(0x6985, response.getSW());
|
||||
response = cmdSet.deriveKey(key, false, true, true);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
verifyKeyDerivation(keyPair, chainCode, new int[] { 2 });
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -732,13 +753,14 @@ public class WalletAppletTest {
|
|||
private byte[] derivePublicKey(byte[] data) {
|
||||
byte[] pubKey = Arrays.copyOfRange(data, 3, 4 + data[3]);
|
||||
byte[] signature = Arrays.copyOfRange(data, 4 + data[3], data.length);
|
||||
byte[] hash = sha256("STATUS KEY DERIVATION".getBytes());
|
||||
|
||||
pubKey[0] = 0x02;
|
||||
ECKey candidate = ECKey.fromPublicOnly(pubKey);
|
||||
if (!candidate.verify(WalletApplet.ASSISTED_DERIVATION_HASH, signature)) {
|
||||
if (!candidate.verify(hash, signature)) {
|
||||
pubKey[0] = 0x03;
|
||||
candidate = ECKey.fromPublicOnly(pubKey);
|
||||
assertTrue(candidate.verify(WalletApplet.ASSISTED_DERIVATION_HASH, signature));
|
||||
assertTrue(candidate.verify(hash, signature));
|
||||
}
|
||||
|
||||
return candidate.decompress().getPubKey();
|
||||
|
|
Loading…
Reference in New Issue