mirror of
https://github.com/status-im/status-keycard.git
synced 2025-02-11 21:16:30 +00:00
remove plain data signing, closes #15
This commit is contained in:
parent
e78397c198
commit
bc0cb02eca
@ -7,6 +7,7 @@ compared to the previous released version. This is version 2.0 of the specs (unr
|
||||
|
||||
### Changes since 1.2
|
||||
* **BREAKING** Removed assisted key derivation
|
||||
* **BREAKING** Removed plain data signing, now only 32-byte long hashes can be signed
|
||||
* Added internal key generation
|
||||
|
||||
## Overview
|
||||
@ -88,7 +89,7 @@ When the applet is in pre-initializated state, it only returns the ECC public ke
|
||||
* P1 = 0x00
|
||||
* P2 = 0x00
|
||||
* Data = EC public key (LV encoded) | IV | encrypted payload
|
||||
* Response SW = 0x9000 on success, 0x6D00 if the applet is already initialized
|
||||
* Response SW = 0x9000 on success, 0x6D00 if the applet is already initialized, 0x6A80 if the data is invalid
|
||||
|
||||
This command is only available when the applet is in pre-initialized state and successful execution brings the applet in
|
||||
the initialized state. This command is needed to allow securely storing secrets on the applet at a different moment and
|
||||
@ -309,23 +310,14 @@ had been performed.
|
||||
|
||||
* CLA = 0x80
|
||||
* INS = 0xC0
|
||||
* P1 = data type
|
||||
* P2 = segment flag
|
||||
* Data = the data to sign
|
||||
* Response = if P2 indicates last segment, the public key and the signature are returned
|
||||
* Response SW = 0x9000 on success, 0x6A86 if P2 is invalid
|
||||
* P1 = 0x00
|
||||
* P2 = 0x00
|
||||
* Data = the hash to sign
|
||||
* Response = public key and the signature
|
||||
* Response SW = 0x9000 on success, 0x6A80 if the data is not 32-byte long
|
||||
* Preconditions: Secure Channel must be opened, user PIN must be verified (or a PIN-less key must be active), a valid
|
||||
keypair must be loaded
|
||||
|
||||
P1:
|
||||
* 0x00 = transaction data
|
||||
* 0x01 = precomputed hash
|
||||
|
||||
P2:
|
||||
* bit 0 = if 1 first block, if 0 other block
|
||||
* bit 1-6 = reserved
|
||||
* bit 7 = if 0 more blocks, if 1 last block
|
||||
|
||||
Response Data format:
|
||||
- Tag 0xA0 = signature template
|
||||
- Tag 0x80 = ECC public key component
|
||||
@ -333,26 +325,12 @@ Response Data format:
|
||||
- Tag 0x02 = R value
|
||||
- Tag 0x02 = S value
|
||||
|
||||
Used to sign transactions. Since the maximum short APDU size is 255 bytes the transaction must be segmented before
|
||||
being sent if it is larger than that. The overhead from the Secure Channel must be also accounted for. When the last
|
||||
segment is sent, the card returns the calculated signature. The signature is an ECDSA signature calculated over the
|
||||
SHA-256 hash of the sent data or directly over the provided hash if P1 = 0x01.
|
||||
|
||||
The P2 parameter is used to manage the signing session and is treated as a bitmask. The rightmost bit indicates whether
|
||||
this block is the first one (1) or not (0). On the first block the card resets the signature state. The leftmost bit
|
||||
indicates whether this is the last block (1) or not (0). On the last block, the card generates and sends the signatures
|
||||
to the client.
|
||||
|
||||
For example, if a signing session spans over 3 segments, the value of P2 will be respectively 0x01, 0x00, 0x80. If
|
||||
the signing session is composed of a single session P2 will have the value of 0x81.
|
||||
|
||||
After a signature is generated, the next SIGN command must have the rightmost bit of P2 set, otherwise 0x6A86 will
|
||||
be returned.
|
||||
|
||||
This segmentation scheme allows resuming signature sessions if other commands must be sent in between and at
|
||||
the same time avoid generating signatures over partial data, since both the first and the last block are marked.
|
||||
|
||||
On applet selection any pending signing session is aborted.
|
||||
Returns the ECDSA signature of the hash. The hash can be calculated using any algorithm, but must be 32-bytes long. The
|
||||
signature is returned in a signature template, containing the public key associated to the signature and the signature
|
||||
itself. For usage on the blockchain, you will need to calculate the recovery ID in addition to extracting R and S.
|
||||
To calculate the recovery ID you need to apply the same algorithm used for public key recovery from a transaction starting
|
||||
with a recovery ID of 0. If the public key matches the one returned in the template, then you have found the recovery ID,
|
||||
otherwise you try again by incrementing the recovery ID.
|
||||
|
||||
### SET PINLESS PATH
|
||||
|
||||
|
@ -47,12 +47,6 @@ public class WalletApplet extends Applet {
|
||||
static final byte LOAD_KEY_P1_EXT_EC = 0x02;
|
||||
static final byte LOAD_KEY_P1_SEED = 0x03;
|
||||
|
||||
static final byte SIGN_P1_DATA = 0x00;
|
||||
static final byte SIGN_P1_PRECOMPUTED_HASH = 0x01;
|
||||
|
||||
static final byte SIGN_P2_FIRST_BLOCK_MASK = 0x01;
|
||||
static final byte SIGN_P2_LAST_BLOCK_MASK = (byte) 0x80;
|
||||
|
||||
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;
|
||||
@ -110,7 +104,6 @@ public class WalletApplet extends Applet {
|
||||
private short pinlessPathLen;
|
||||
|
||||
private Signature signature;
|
||||
private boolean signInProgress;
|
||||
|
||||
private byte[] keyUID;
|
||||
|
||||
@ -278,11 +271,7 @@ public class WalletApplet extends Applet {
|
||||
} else if (apduBuffer[ISO7816.OFFSET_INS] == INS_INIT) {
|
||||
secureChannel.oneShotDecrypt(apduBuffer);
|
||||
|
||||
if (apduBuffer[ISO7816.OFFSET_LC] != (byte)(PIN_LENGTH + PUK_LENGTH + SecureChannel.SC_SECRET_LENGTH)) {
|
||||
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
|
||||
}
|
||||
|
||||
if (!allDigits(apduBuffer, ISO7816.OFFSET_CDATA, (short)(PIN_LENGTH + PUK_LENGTH))) {
|
||||
if ((apduBuffer[ISO7816.OFFSET_LC] != (byte)(PIN_LENGTH + PUK_LENGTH + SecureChannel.SC_SECRET_LENGTH)) || !allDigits(apduBuffer, ISO7816.OFFSET_CDATA, (short)(PIN_LENGTH + PUK_LENGTH))) {
|
||||
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
|
||||
}
|
||||
|
||||
@ -329,7 +318,6 @@ public class WalletApplet extends Applet {
|
||||
* @param apdu the JCRE-owned APDU object.
|
||||
*/
|
||||
private void selectApplet(APDU apdu) {
|
||||
signInProgress = false;
|
||||
pin.reset();
|
||||
puk.reset();
|
||||
secureChannel.reset();
|
||||
@ -598,7 +586,6 @@ public class WalletApplet extends Applet {
|
||||
* manipulation has happened to be sure that the state is always consistent.
|
||||
*/
|
||||
private void resetKeyStatus(boolean toParent) {
|
||||
signInProgress = false;
|
||||
parentValid = false;
|
||||
keyPathLen = toParent ? (short) (keyPathLen - 4) : 0;
|
||||
}
|
||||
@ -743,8 +730,6 @@ public class WalletApplet extends Applet {
|
||||
resetKeys(fromParent, apduBuffer, chainEnd);
|
||||
}
|
||||
|
||||
signInProgress = false;
|
||||
|
||||
for (short i = ISO7816.OFFSET_CDATA; i < chainEnd; i += 4) {
|
||||
JCSystem.beginTransaction();
|
||||
|
||||
@ -902,7 +887,6 @@ public class WalletApplet extends Applet {
|
||||
pinlessPathLen = 0;
|
||||
parentValid = false;
|
||||
isExtended = false;
|
||||
signInProgress = false;
|
||||
privateKey.clearKey();
|
||||
publicKey.clearKey();
|
||||
masterPrivate.clearKey();
|
||||
@ -960,40 +944,26 @@ public class WalletApplet extends Applet {
|
||||
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
||||
}
|
||||
|
||||
if ((apduBuffer[ISO7816.OFFSET_P2] & SIGN_P2_FIRST_BLOCK_MASK) == SIGN_P2_FIRST_BLOCK_MASK) {
|
||||
signInProgress = true;
|
||||
signature.init(privateKey, Signature.MODE_SIGN);
|
||||
} else if (!signInProgress) {
|
||||
ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
|
||||
if (len != MessageDigest.LENGTH_SHA_256) {
|
||||
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
|
||||
}
|
||||
|
||||
if ((apduBuffer[ISO7816.OFFSET_P2] & SIGN_P2_LAST_BLOCK_MASK) == SIGN_P2_LAST_BLOCK_MASK) {
|
||||
signInProgress = false;
|
||||
signature.init(privateKey, Signature.MODE_SIGN);
|
||||
|
||||
apduBuffer[SecureChannel.SC_OUT_OFFSET] = TLV_SIGNATURE_TEMPLATE;
|
||||
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 3)] = TLV_PUB_KEY;
|
||||
short outLen = apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 4)] = (byte) publicKey.getW(apduBuffer, (short) (SecureChannel.SC_OUT_OFFSET + 5));
|
||||
apduBuffer[SecureChannel.SC_OUT_OFFSET] = TLV_SIGNATURE_TEMPLATE;
|
||||
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 3)] = TLV_PUB_KEY;
|
||||
short outLen = apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 4)] = (byte) publicKey.getW(apduBuffer, (short) (SecureChannel.SC_OUT_OFFSET + 5));
|
||||
|
||||
outLen += 5;
|
||||
short sigOff = (short) (SecureChannel.SC_OUT_OFFSET + outLen);
|
||||
outLen += 5;
|
||||
short sigOff = (short) (SecureChannel.SC_OUT_OFFSET + outLen);
|
||||
|
||||
if ((apduBuffer[ISO7816.OFFSET_P1]) == SIGN_P1_DATA) {
|
||||
outLen += signature.sign(apduBuffer, ISO7816.OFFSET_CDATA, len, apduBuffer, sigOff);
|
||||
} else if ((apduBuffer[ISO7816.OFFSET_P1]) == SIGN_P1_PRECOMPUTED_HASH) {
|
||||
outLen += signature.signPreComputedHash(apduBuffer, ISO7816.OFFSET_CDATA, len, apduBuffer, sigOff);
|
||||
} else {
|
||||
ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
|
||||
}
|
||||
outLen += signature.signPreComputedHash(apduBuffer, ISO7816.OFFSET_CDATA, len, apduBuffer, sigOff);
|
||||
outLen += crypto.fixS(apduBuffer, sigOff);
|
||||
|
||||
outLen += crypto.fixS(apduBuffer, sigOff);
|
||||
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 1)] = (byte) 0x81;
|
||||
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 2)] = (byte) (outLen - 3);
|
||||
|
||||
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 1)] = (byte) 0x81;
|
||||
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 2)] = (byte) (outLen - 3);
|
||||
|
||||
secureChannel.respond(apdu, outLen, ISO7816.SW_NO_ERROR);
|
||||
} else {
|
||||
signature.update(apduBuffer, ISO7816.OFFSET_CDATA, len);
|
||||
}
|
||||
secureChannel.respond(apdu, outLen, ISO7816.SW_NO_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,21 +394,14 @@ public class WalletAppletCommandSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* generated and thus returned. When signing a precomputed hash it must be done in a single block, so isFirst and
|
||||
* isLast will always be true at the same time.
|
||||
* Sends a SIGN APDU. This signs a precomputed hash so the input must be exactly 32-bytes long.
|
||||
*
|
||||
* @param data the data to sign
|
||||
* @param dataType the P1 parameter
|
||||
* @param isFirst whether this is the first block of the command or not
|
||||
* @param isLast whether this is the last block of the command or not
|
||||
* @return the raw card response
|
||||
* @throws CardException communication error
|
||||
*/
|
||||
public ResponseAPDU sign(byte[] data, byte dataType, boolean isFirst, boolean isLast) throws CardException {
|
||||
byte p2 = (byte) ((isFirst ? 0x01 : 0x00) | (isLast ? 0x80 : 0x00));
|
||||
CommandAPDU sign = secureChannel.protectedCommand(0x80, WalletApplet.INS_SIGN, dataType, p2, data);
|
||||
public ResponseAPDU sign(byte[] data) throws CardException {
|
||||
CommandAPDU sign = secureChannel.protectedCommand(0x80, WalletApplet.INS_SIGN, 0x00, 0x00, data);
|
||||
return secureChannel.transmit(apduChannel, sign);
|
||||
}
|
||||
|
||||
|
@ -793,13 +793,13 @@ public class WalletAppletTest {
|
||||
byte[] hash = sha256(data);
|
||||
|
||||
// Security condition violation: SecureChannel not open
|
||||
ResponseAPDU response = cmdSet.sign(hash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH,true, true);
|
||||
ResponseAPDU response = cmdSet.sign(hash);
|
||||
assertEquals(0x6985, response.getSW());
|
||||
|
||||
cmdSet.autoOpenSecureChannel();
|
||||
|
||||
// Security condition violation: PIN not verified
|
||||
response = cmdSet.sign(hash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH,true,true);
|
||||
response = cmdSet.sign(hash);
|
||||
assertEquals(0x6985, response.getSW());
|
||||
|
||||
response = cmdSet.verifyPIN("000000");
|
||||
@ -812,15 +812,12 @@ public class WalletAppletTest {
|
||||
response = cmdSet.loadKey(keyPair);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
|
||||
// Wrong P2: no active signing session but first block bit not set
|
||||
response = cmdSet.sign(hash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH,false, false);
|
||||
assertEquals(0x6A86, response.getSW());
|
||||
|
||||
response = cmdSet.sign(hash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH,false, true);
|
||||
assertEquals(0x6A86, response.getSW());
|
||||
// Wrong Data length
|
||||
response = cmdSet.sign(data);
|
||||
assertEquals(0x6A80, response.getSW());
|
||||
|
||||
// Correctly sign a precomputed hash
|
||||
response = cmdSet.sign(hash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH,true, true);
|
||||
response = cmdSet.sign(hash);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
byte[] sig = response.getData();
|
||||
byte[] keyData = extractPublicKeyFromSignature(sig);
|
||||
@ -869,15 +866,15 @@ public class WalletAppletTest {
|
||||
|
||||
// Verify that only PINless path can be used without PIN
|
||||
resetAndSelectAndOpenSC();
|
||||
response = cmdSet.sign(hash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH,true, true);
|
||||
response = cmdSet.sign(hash);
|
||||
assertEquals(0x6985, response.getSW());
|
||||
response = cmdSet.deriveKey(new byte[] {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01}, WalletApplet.DERIVE_P1_SOURCE_MASTER);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
response = cmdSet.sign(hash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH,true, true);
|
||||
response = cmdSet.sign(hash);
|
||||
assertEquals(0x6985, response.getSW());
|
||||
response = cmdSet.deriveKey(new byte[] {0x00, 0x00, 0x00, 0x02}, WalletApplet.DERIVE_P1_SOURCE_CURRENT);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
response = cmdSet.sign(hash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH,true, true);
|
||||
response = cmdSet.sign(hash);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
|
||||
// Verify changing path
|
||||
@ -886,12 +883,12 @@ public class WalletAppletTest {
|
||||
response = cmdSet.setPinlessPath(new byte[] {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01});
|
||||
assertEquals(0x9000, response.getSW());
|
||||
resetAndSelectAndOpenSC();
|
||||
response = cmdSet.sign(hash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH,true, true);
|
||||
response = cmdSet.sign(hash);
|
||||
assertEquals(0x6985, response.getSW());
|
||||
assertEquals(0x6985, response.getSW());
|
||||
response = cmdSet.deriveKey(new byte[] {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01}, WalletApplet.DERIVE_P1_SOURCE_MASTER);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
response = cmdSet.sign(hash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH,true, true);
|
||||
response = cmdSet.sign(hash);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
|
||||
// Reset
|
||||
@ -900,7 +897,7 @@ public class WalletAppletTest {
|
||||
response = cmdSet.setPinlessPath(new byte[] {});
|
||||
assertEquals(0x9000, response.getSW());
|
||||
resetAndSelectAndOpenSC();
|
||||
response = cmdSet.sign(hash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH,true, true);
|
||||
response = cmdSet.sign(hash);
|
||||
assertEquals(0x6985, response.getSW());
|
||||
response = cmdSet.deriveKey(new byte[] {0x00, 0x00, 0x00, 0x02}, WalletApplet.DERIVE_P1_SOURCE_MASTER);
|
||||
assertEquals(0x6985, response.getSW());
|
||||
@ -987,105 +984,6 @@ public class WalletAppletTest {
|
||||
assertEquals(0x6985, response.getSW());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("SIGN data (unused for the current scenario)")
|
||||
@Tag("manual")
|
||||
void signDataTest() throws Exception {
|
||||
Random r = new Random();
|
||||
byte[] data = new byte[SecureChannelSession.PAYLOAD_MAX_SIZE];
|
||||
byte[] smallData = Arrays.copyOf(data, 20);
|
||||
r.nextBytes(data);
|
||||
|
||||
cmdSet.autoOpenSecureChannel();
|
||||
|
||||
ResponseAPDU response = cmdSet.verifyPIN("000000");
|
||||
assertEquals(0x9000, response.getSW());
|
||||
|
||||
KeyPair keyPair = keypairGenerator().generateKeyPair();
|
||||
Signature signature = Signature.getInstance("SHA256withECDSA", "BC");
|
||||
signature.initVerify(keyPair.getPublic());
|
||||
|
||||
response = cmdSet.loadKey(keyPair);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
|
||||
// Wrong P2: no active signing session but first block bit not set
|
||||
response = cmdSet.sign(data, WalletApplet.SIGN_P1_DATA,false, false);
|
||||
assertEquals(0x6A86, response.getSW());
|
||||
|
||||
response = cmdSet.sign(data, WalletApplet.SIGN_P1_DATA,false, true);
|
||||
assertEquals(0x6A86, response.getSW());
|
||||
|
||||
// Correctly sign 1 block (P2: 0x81)
|
||||
response = cmdSet.sign(smallData, WalletApplet.SIGN_P1_DATA,true, true);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
byte[] sig = extractSignature(response.getData());
|
||||
signature.update(smallData);
|
||||
assertTrue(signature.verify(sig));
|
||||
|
||||
// Correctly sign 2 blocks (P2: 0x01, 0x81)
|
||||
response = cmdSet.sign(data, WalletApplet.SIGN_P1_DATA,true, false);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
response = cmdSet.sign(smallData, WalletApplet.SIGN_P1_DATA,false, true);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
sig = extractSignature(response.getData());
|
||||
signature.update(data);
|
||||
signature.update(smallData);
|
||||
assertTrue(signature.verify(sig));
|
||||
|
||||
// Correctly sign 3 blocks (P2: 0x01, 0x00, 0x80)
|
||||
response = cmdSet.sign(data, WalletApplet.SIGN_P1_DATA,true, false);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
response = cmdSet.sign(data, WalletApplet.SIGN_P1_DATA,false, false);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
response = cmdSet.sign(smallData, WalletApplet.SIGN_P1_DATA,false, true);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
sig = extractSignature(response.getData());
|
||||
signature.update(data);
|
||||
signature.update(data);
|
||||
signature.update(smallData);
|
||||
assertTrue(signature.verify(sig));
|
||||
|
||||
// Re-start signing session by sending new first block
|
||||
response = cmdSet.sign(data, WalletApplet.SIGN_P1_DATA,true, false);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
response = cmdSet.sign(smallData, WalletApplet.SIGN_P1_DATA,true, true);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
sig = extractSignature(response.getData());
|
||||
signature.update(smallData);
|
||||
assertTrue(signature.verify(sig));
|
||||
|
||||
// Abort signing session by loading new keys
|
||||
response = cmdSet.sign(data, WalletApplet.SIGN_P1_DATA,true, false);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
keyPair = keypairGenerator().generateKeyPair();
|
||||
signature.initVerify(keyPair.getPublic());
|
||||
response = cmdSet.loadKey(keyPair);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
response = cmdSet.sign(smallData, WalletApplet.SIGN_P1_DATA,false, true);
|
||||
assertEquals(0x6A86, response.getSW());
|
||||
|
||||
// Signing session is aborted on reselection
|
||||
response = cmdSet.sign(data, WalletApplet.SIGN_P1_DATA,true, false);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
resetAndSelectAndOpenSC();
|
||||
response = cmdSet.verifyPIN("000000");
|
||||
assertEquals(0x9000, response.getSW());
|
||||
response = cmdSet.sign(smallData, WalletApplet.SIGN_P1_DATA,false, true);
|
||||
assertEquals(0x6A86, response.getSW());
|
||||
|
||||
// Signing session can be resumed if other commands are sent
|
||||
response = cmdSet.sign(data, WalletApplet.SIGN_P1_DATA,true, false);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
response = cmdSet.changePIN(WalletApplet.CHANGE_PIN_P1_USER_PIN, "000000");
|
||||
assertEquals(0x9000, response.getSW());
|
||||
response = cmdSet.sign(smallData, WalletApplet.SIGN_P1_DATA,false, true);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
sig = extractSignature(response.getData());
|
||||
signature.update(data);
|
||||
signature.update(smallData);
|
||||
assertTrue(signature.verify(sig));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sign actual Ethereum transaction")
|
||||
@Tag("manual")
|
||||
@ -1263,7 +1161,7 @@ public class WalletAppletTest {
|
||||
DeterministicKey key = deriveKey(keyPair, chainCode, path);
|
||||
|
||||
byte[] hash = Hash.sha3(new byte[8]);
|
||||
ResponseAPDU resp = cmdSet.sign(hash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH, true, true);
|
||||
ResponseAPDU resp = cmdSet.sign(hash);
|
||||
assertEquals(0x9000, resp.getSW());
|
||||
byte[] sig = resp.getData();
|
||||
byte[] publicKey = extractPublicKeyFromSignature(sig);
|
||||
@ -1347,7 +1245,7 @@ public class WalletAppletTest {
|
||||
private Sign.SignatureData signMessage(byte[] message) throws Exception {
|
||||
byte[] messageHash = Hash.sha3(message);
|
||||
|
||||
ResponseAPDU response = cmdSet.sign(messageHash, WalletApplet.SIGN_P1_PRECOMPUTED_HASH,true, true);
|
||||
ResponseAPDU response = cmdSet.sign(messageHash);
|
||||
assertEquals(0x9000, response.getSW());
|
||||
byte[] respData = response.getData();
|
||||
byte[] rawSig = extractSignature(respData);
|
||||
|
Loading…
x
Reference in New Issue
Block a user