add support for derivation in sign

This commit is contained in:
Michele Balistreri 2019-03-29 14:55:59 +03:00
parent 12481c6f94
commit 5bc5e23272
1 changed files with 63 additions and 26 deletions

View File

@ -807,17 +807,18 @@ public class KeycardApplet extends Applet {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
doDerive(apduBuffer, len, apduBuffer[ISO7816.OFFSET_P1], true);
doDerive(apduBuffer, (short) 0, len, apduBuffer[ISO7816.OFFSET_P1], true);
}
/**
* Internal derivation function, called by DERIVE KEY and EXPORT KEY
* @param apduBuffer the APDU buffer
* @param len the APDU len
* @param off the offset in the APDU buffer relative to the data field
* @param len the len of the path
* @param source derivation source
* @param makeCurrent whether the results should be saved or not
*/
private void doDerive(byte[] apduBuffer, short len, byte source, boolean makeCurrent) {
private void doDerive(byte[] apduBuffer, short off, short len, byte source, boolean makeCurrent) {
if (!isExtended) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
@ -876,7 +877,8 @@ public class KeycardApplet extends Applet {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
}
short scratchOff = (short) (ISO7816.OFFSET_CDATA + len);
short pathOff = (short) (ISO7816.OFFSET_CDATA + off);
short scratchOff = (short) (pathOff + len);
short dataOff = (short) (scratchOff + Crypto.KEY_DERIVATION_SCRATCH_SIZE);
short pubKeyOff = (short) (dataOff + sourcePriv.getS(apduBuffer, dataOff));
@ -888,8 +890,8 @@ public class KeycardApplet extends Applet {
apduBuffer[pubKeyOff] = 0;
}
for (short i = ISO7816.OFFSET_CDATA; i < scratchOff; i += 4) {
if (i > ISO7816.OFFSET_CDATA) {
for (short i = pathOff; i < scratchOff; i += 4) {
if (i > pathOff) {
Util.arrayCopyNonAtomic(derivationOutput, (short) 0, apduBuffer, dataOff, (short) (Crypto.KEY_SECRET_SIZE + CHAIN_CODE_SIZE));
if (!crypto.bip32IsHardened(apduBuffer, i)) {
@ -1198,7 +1200,41 @@ public class KeycardApplet extends Applet {
*/
private void sign(APDU apdu) {
byte[] apduBuffer = apdu.getBuffer();
boolean usePinless = apduBuffer[ISO7816.OFFSET_P1] == SIGN_P1_PINLESS;
boolean usePinless = false;
boolean derive = false;
boolean makeCurrent = false;
ECPrivateKey signingKey;
ECPublicKey outputKey;
switch((byte) (apduBuffer[ISO7816.OFFSET_P1] & ~DERIVE_P1_SOURCE_MASK)) {
case SIGN_P1_CURRENT_KEY:
signingKey = privateKey;
outputKey = publicKey;
break;
case SIGN_P1_DERIVE:
signingKey = secp256k1.tmpECPrivateKey;
outputKey = null;
derive = true;
break;
case SIGN_P1_DERIVE_AND_MAKE_CURRENT:
signingKey = privateKey;
outputKey = publicKey;
derive = true;
makeCurrent = true;
break;
case SIGN_P1_PINLESS:
if (pinlessPathLen == 0) {
ISOException.throwIt(SW_REFERENCED_DATA_NOT_FOUND);
}
usePinless = true;
signingKey = pinlessPrivateKey;
outputKey = pinlessPublicKey;
break;
default:
ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
return;
}
short len;
@ -1212,35 +1248,36 @@ public class KeycardApplet extends Applet {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
if (len != MessageDigest.LENGTH_SHA_256) {
if (derive) {
short pathLen = (short) (len - MessageDigest.LENGTH_SHA_256);
if (pathLen <= 0) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
}
ECPrivateKey signingKey;
ECPublicKey outputKey;
if (usePinless) {
if (pinlessPathLen == 0) {
ISOException.throwIt(SW_REFERENCED_DATA_NOT_FOUND);
}
signingKey = pinlessPrivateKey;
outputKey = pinlessPublicKey;
doDerive(apduBuffer, MessageDigest.LENGTH_SHA_256, pathLen, apduBuffer[ISO7816.OFFSET_P1], makeCurrent);
} else {
signingKey = privateKey;
outputKey = publicKey;
if (len != MessageDigest.LENGTH_SHA_256) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
}
}
signature.init(signingKey, 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) outputKey.getW(apduBuffer, (short) (SecureChannel.SC_OUT_OFFSET + 5));
short outLen = apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 4)] = Crypto.KEY_PUB_SIZE;
if (outputKey != null) {
outputKey.getW(apduBuffer, (short) (SecureChannel.SC_OUT_OFFSET + 5));
} else {
secp256k1.derivePublicKey(derivationOutput, (short) 0, apduBuffer, (short) (SecureChannel.SC_OUT_OFFSET + 5));
}
outLen += 5;
short sigOff = (short) (SecureChannel.SC_OUT_OFFSET + outLen);
outLen += signature.signPreComputedHash(apduBuffer, ISO7816.OFFSET_CDATA, len, apduBuffer, sigOff);
signature.init(signingKey, Signature.MODE_SIGN);
outLen += signature.signPreComputedHash(apduBuffer, ISO7816.OFFSET_CDATA, MessageDigest.LENGTH_SHA_256, apduBuffer, sigOff);
outLen += crypto.fixS(apduBuffer, sigOff);
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 1)] = (byte) 0x81;
@ -1274,7 +1311,7 @@ public class KeycardApplet extends Applet {
Util.arrayCopy(apduBuffer, ISO7816.OFFSET_CDATA, pinlessPath, (short) 0, len);
if (pinlessPathLen > 0) {
doDerive(apduBuffer, len, DERIVE_P1_SOURCE_MASTER, false);
doDerive(apduBuffer, (short) 0, len, DERIVE_P1_SOURCE_MASTER, false);
pinlessPrivateKey.setS(derivationOutput, (short) 0, Crypto.KEY_SECRET_SIZE);
secp256k1.derivePublicKey(pinlessPrivateKey, apduBuffer, (short) 0);
pinlessPublicKey.setW(apduBuffer, (short) 0, Crypto.KEY_PUB_SIZE);
@ -1341,7 +1378,7 @@ public class KeycardApplet extends Applet {
}
if (derive) {
doDerive(apduBuffer, dataLen, derivationSource, makeCurrent);
doDerive(apduBuffer, (short) 0, dataLen, derivationSource, makeCurrent);
}
short off = SecureChannel.SC_OUT_OFFSET;