add remove key command
This commit is contained in:
parent
3c5fd3bfca
commit
6a0ca5e260
|
@ -104,8 +104,8 @@ if P1 = 0x00:
|
|||
- Tag 0xA3 = Application Status Template
|
||||
- Tag 0x02 = PIN retry count (1 byte)
|
||||
- Tag 0x02 = PUK retry count (1 byte)
|
||||
- Tag 0x01 = 0 if key is not initialized, 1 otherwise
|
||||
- Tag 0x01 = 1 if public key derivation is supported, 0 otherwise
|
||||
- Tag 0x01 = 0xff if key is initialized, 0 otherwise
|
||||
- Tag 0x01 = 0xff if public key derivation is supported, 0 otherwise
|
||||
|
||||
if P1 = 0x01
|
||||
- a sequence of 32-bit numbers indicating the current key path. Empty if master key is selected.
|
||||
|
@ -255,6 +255,18 @@ Used to generate a mnemonic according to the algorithm specified in [BIP39](http
|
|||
The returned data is a list of 16-byte integers which should be used as indexes in a wordlist to generate the
|
||||
human-readable mnemonic. Each integer can have a value from 0 to 2047.
|
||||
|
||||
### REMOVE KEY
|
||||
|
||||
* CLA = 0x80
|
||||
* INS = 0xD3
|
||||
* P1 = 0x00
|
||||
* P2 = 0x00
|
||||
* Response SW = 0x9000 on success.
|
||||
* Preconditions: Secure Channel must be opened, user PIN must be verified
|
||||
|
||||
Removes the key from the card, bringing it back to an uninitialized state. No signing operation is possible after this
|
||||
command until a new LOAD KEY command is performed.
|
||||
|
||||
### SIGN
|
||||
|
||||
* CLA = 0x80
|
||||
|
|
|
@ -16,6 +16,7 @@ public class WalletApplet extends Applet {
|
|||
static final byte INS_LOAD_KEY = (byte) 0xD0;
|
||||
static final byte INS_DERIVE_KEY = (byte) 0xD1;
|
||||
static final byte INS_GENERATE_MNEMONIC = (byte) 0xD2;
|
||||
static final byte INS_REMOVE_KEY = (byte) 0xD3;
|
||||
static final byte INS_SIGN = (byte) 0xC0;
|
||||
static final byte INS_SET_PINLESS_PATH = (byte) 0xC1;
|
||||
static final byte INS_EXPORT_KEY = (byte) 0xC2;
|
||||
|
@ -160,15 +161,7 @@ public class WalletApplet extends Applet {
|
|||
keyPath = new byte[KEY_PATH_MAX_DEPTH * 4];
|
||||
pinlessPath = new byte[KEY_PATH_MAX_DEPTH * 4];
|
||||
|
||||
secp256k1.setCurveParameters(masterPublic);
|
||||
secp256k1.setCurveParameters(masterPrivate);
|
||||
|
||||
secp256k1.setCurveParameters(parentPublicKey);
|
||||
secp256k1.setCurveParameters(parentPrivateKey);
|
||||
parentValid = false;
|
||||
|
||||
secp256k1.setCurveParameters(publicKey);
|
||||
secp256k1.setCurveParameters(privateKey);
|
||||
resetCurveParameters();
|
||||
|
||||
signature = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false);
|
||||
|
||||
|
@ -239,6 +232,9 @@ public class WalletApplet extends Applet {
|
|||
case INS_GENERATE_MNEMONIC:
|
||||
generateMnemonic(apdu);
|
||||
break;
|
||||
case INS_REMOVE_KEY:
|
||||
removeKey(apdu);
|
||||
break;
|
||||
case INS_SIGN:
|
||||
sign(apdu);
|
||||
break;
|
||||
|
@ -832,6 +828,34 @@ public class WalletApplet extends Applet {
|
|||
return (short) ((short)((short) 0x4000 >>> (short) (amount - 1)) | tmp);
|
||||
}
|
||||
|
||||
private void removeKey(APDU apdu) {
|
||||
byte[] apduBuffer = apdu.getBuffer();
|
||||
secureChannel.preprocessAPDU(apduBuffer);
|
||||
|
||||
if (!pin.isValidated()) {
|
||||
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
||||
}
|
||||
|
||||
keyPathLen = 0;
|
||||
pinlessPathLen = 0;
|
||||
parentValid = false;
|
||||
isExtended = false;
|
||||
signInProgress = false;
|
||||
expectPublicKey = false;
|
||||
privateKey.clearKey();
|
||||
publicKey.clearKey();
|
||||
masterPrivate.clearKey();
|
||||
masterPublic.clearKey();
|
||||
parentPrivateKey.clearKey();
|
||||
parentPublicKey.clearKey();
|
||||
resetCurveParameters();
|
||||
Util.arrayFillNonAtomic(chainCode, (short) 0, (short) chainCode.length, (byte) 0);
|
||||
Util.arrayFillNonAtomic(parentChainCode, (short) 0, (short) parentChainCode.length, (byte) 0);
|
||||
Util.arrayFillNonAtomic(masterChainCode, (short) 0, (short) masterChainCode.length, (byte) 0);
|
||||
Util.arrayFillNonAtomic(keyPath, (short) 0, (short) keyPath.length, (byte) 0);
|
||||
Util.arrayFillNonAtomic(pinlessPath, (short) 0, (short) pinlessPath.length, (byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the SIGN command. Requires a secure channel to open and either the PIN to be verified or the PIN-less key
|
||||
* path to be the current key path. This command supports signing data using SHA-256 with possible segmentation over
|
||||
|
@ -927,7 +951,7 @@ public class WalletApplet extends Applet {
|
|||
byte[] apduBuffer = apdu.getBuffer();
|
||||
secureChannel.preprocessAPDU(apduBuffer);
|
||||
|
||||
if (!pin.isValidated()) {
|
||||
if (!pin.isValidated() || !privateKey.isInitialized()) {
|
||||
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
||||
}
|
||||
|
||||
|
@ -1014,4 +1038,18 @@ public class WalletApplet extends Applet {
|
|||
private boolean isPinless() {
|
||||
return (pinlessPathLen > 0) && (pinlessPathLen == keyPathLen) && (Util.arrayCompare(keyPath, (short) 0, pinlessPath, (short) 0, keyPathLen) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set curve parameters to cleared keys
|
||||
*/
|
||||
private void resetCurveParameters() {
|
||||
secp256k1.setCurveParameters(masterPublic);
|
||||
secp256k1.setCurveParameters(masterPrivate);
|
||||
|
||||
secp256k1.setCurveParameters(parentPublicKey);
|
||||
secp256k1.setCurveParameters(parentPrivateKey);
|
||||
|
||||
secp256k1.setCurveParameters(publicKey);
|
||||
secp256k1.setCurveParameters(privateKey);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,6 +138,19 @@ public class WalletAppletCommandSet {
|
|||
return data[data.length - 1] != 0x00;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a GET STATUS APDU to retrieve the APPLICATION STATUS template and reads the byte indicating key initialization
|
||||
* status
|
||||
*
|
||||
* @return whether public key derivation is supported or not
|
||||
* @throws CardException communication error
|
||||
*/
|
||||
public boolean getKeyInitializationStatus() throws CardException {
|
||||
ResponseAPDU resp = getStatus(WalletApplet.GET_STATUS_P1_APPLICATION);
|
||||
byte[] data = resp.getData();
|
||||
return data[data.length - 4] != 0x00;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a VERIFY PIN APDU. The raw bytes of the given string are encrypted using the secure channel and used as APDU
|
||||
* data.
|
||||
|
@ -355,6 +368,17 @@ public class WalletAppletCommandSet {
|
|||
return secureChannel.transmit(apduChannel, generateMnemonic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a REMOVE KEY APDU.
|
||||
*
|
||||
* @return the raw card response
|
||||
* @throws CardException communication error
|
||||
*/
|
||||
public ResponseAPDU removeKey() throws CardException {
|
||||
CommandAPDU removeKey = secureChannel.protectedCommand(0x80, WalletApplet.INS_REMOVE_KEY, 0, 0, new byte[0]);
|
||||
return secureChannel.transmit(apduChannel, removeKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a SIGN APDU. The dataType is P1 as defined in the applet. The isFirst and isLast arguments are used to form
|
||||
* the P2 parameter. The data is the data to sign, or part of it. Only when sending the last block a signature is
|
||||
|
|
|
@ -550,6 +550,36 @@ public class WalletAppletTest {
|
|||
assertMnemonic(24, response.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("REMOVE KEY command")
|
||||
void removeKeyTest() throws Exception {
|
||||
KeyPairGenerator g = keypairGenerator();
|
||||
KeyPair keyPair = g.generateKeyPair();
|
||||
|
||||
// Security condition violation: SecureChannel not open
|
||||
ResponseAPDU response = cmdSet.removeKey();
|
||||
assertEquals(0x6985, response.getSW());
|
||||
cmdSet.autoOpenSecureChannel();
|
||||
|
||||
// Security condition violation: PIN not verified
|
||||
response = cmdSet.removeKey();
|
||||
assertEquals(0x6985, response.getSW());
|
||||
|
||||
response = cmdSet.verifyPIN("000000");
|
||||
assertEquals(0x9000, response.getSW());
|
||||
|
||||
response = cmdSet.loadKey(keyPair);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
|
||||
assertTrue(cmdSet.getKeyInitializationStatus());
|
||||
|
||||
// Good case
|
||||
response = cmdSet.removeKey();
|
||||
assertEquals(0x9000, response.getSW());
|
||||
|
||||
assertFalse(cmdSet.getKeyInitializationStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("DERIVE KEY command")
|
||||
void deriveKeyTest() throws Exception {
|
||||
|
|
Loading…
Reference in New Issue