add support for derivation in sign
This commit is contained in:
parent
12481c6f94
commit
5bc5e23272
|
@ -807,17 +807,18 @@ public class KeycardApplet extends Applet {
|
||||||
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
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
|
* Internal derivation function, called by DERIVE KEY and EXPORT KEY
|
||||||
* @param apduBuffer the APDU buffer
|
* @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 source derivation source
|
||||||
* @param makeCurrent whether the results should be saved or not
|
* @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) {
|
if (!isExtended) {
|
||||||
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
||||||
}
|
}
|
||||||
|
@ -876,7 +877,8 @@ public class KeycardApplet extends Applet {
|
||||||
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
|
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 dataOff = (short) (scratchOff + Crypto.KEY_DERIVATION_SCRATCH_SIZE);
|
||||||
|
|
||||||
short pubKeyOff = (short) (dataOff + sourcePriv.getS(apduBuffer, dataOff));
|
short pubKeyOff = (short) (dataOff + sourcePriv.getS(apduBuffer, dataOff));
|
||||||
|
@ -888,8 +890,8 @@ public class KeycardApplet extends Applet {
|
||||||
apduBuffer[pubKeyOff] = 0;
|
apduBuffer[pubKeyOff] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (short i = ISO7816.OFFSET_CDATA; i < scratchOff; i += 4) {
|
for (short i = pathOff; i < scratchOff; i += 4) {
|
||||||
if (i > ISO7816.OFFSET_CDATA) {
|
if (i > pathOff) {
|
||||||
Util.arrayCopyNonAtomic(derivationOutput, (short) 0, apduBuffer, dataOff, (short) (Crypto.KEY_SECRET_SIZE + CHAIN_CODE_SIZE));
|
Util.arrayCopyNonAtomic(derivationOutput, (short) 0, apduBuffer, dataOff, (short) (Crypto.KEY_SECRET_SIZE + CHAIN_CODE_SIZE));
|
||||||
|
|
||||||
if (!crypto.bip32IsHardened(apduBuffer, i)) {
|
if (!crypto.bip32IsHardened(apduBuffer, i)) {
|
||||||
|
@ -1198,7 +1200,41 @@ public class KeycardApplet extends Applet {
|
||||||
*/
|
*/
|
||||||
private void sign(APDU apdu) {
|
private void sign(APDU apdu) {
|
||||||
byte[] apduBuffer = apdu.getBuffer();
|
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;
|
short len;
|
||||||
|
|
||||||
|
@ -1212,35 +1248,36 @@ public class KeycardApplet extends Applet {
|
||||||
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
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);
|
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
ECPrivateKey signingKey;
|
doDerive(apduBuffer, MessageDigest.LENGTH_SHA_256, pathLen, apduBuffer[ISO7816.OFFSET_P1], makeCurrent);
|
||||||
ECPublicKey outputKey;
|
|
||||||
|
|
||||||
if (usePinless) {
|
|
||||||
if (pinlessPathLen == 0) {
|
|
||||||
ISOException.throwIt(SW_REFERENCED_DATA_NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
signingKey = pinlessPrivateKey;
|
|
||||||
outputKey = pinlessPublicKey;
|
|
||||||
} else {
|
} else {
|
||||||
signingKey = privateKey;
|
if (len != MessageDigest.LENGTH_SHA_256) {
|
||||||
outputKey = publicKey;
|
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signature.init(signingKey, Signature.MODE_SIGN);
|
|
||||||
|
|
||||||
apduBuffer[SecureChannel.SC_OUT_OFFSET] = TLV_SIGNATURE_TEMPLATE;
|
apduBuffer[SecureChannel.SC_OUT_OFFSET] = TLV_SIGNATURE_TEMPLATE;
|
||||||
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 3)] = TLV_PUB_KEY;
|
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;
|
outLen += 5;
|
||||||
short sigOff = (short) (SecureChannel.SC_OUT_OFFSET + outLen);
|
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);
|
outLen += crypto.fixS(apduBuffer, sigOff);
|
||||||
|
|
||||||
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 1)] = (byte) 0x81;
|
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);
|
Util.arrayCopy(apduBuffer, ISO7816.OFFSET_CDATA, pinlessPath, (short) 0, len);
|
||||||
|
|
||||||
if (pinlessPathLen > 0) {
|
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);
|
pinlessPrivateKey.setS(derivationOutput, (short) 0, Crypto.KEY_SECRET_SIZE);
|
||||||
secp256k1.derivePublicKey(pinlessPrivateKey, apduBuffer, (short) 0);
|
secp256k1.derivePublicKey(pinlessPrivateKey, apduBuffer, (short) 0);
|
||||||
pinlessPublicKey.setW(apduBuffer, (short) 0, Crypto.KEY_PUB_SIZE);
|
pinlessPublicKey.setW(apduBuffer, (short) 0, Crypto.KEY_PUB_SIZE);
|
||||||
|
@ -1341,7 +1378,7 @@ public class KeycardApplet extends Applet {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (derive) {
|
if (derive) {
|
||||||
doDerive(apduBuffer, dataLen, derivationSource, makeCurrent);
|
doDerive(apduBuffer, (short) 0, dataLen, derivationSource, makeCurrent);
|
||||||
}
|
}
|
||||||
|
|
||||||
short off = SecureChannel.SC_OUT_OFFSET;
|
short off = SecureChannel.SC_OUT_OFFSET;
|
||||||
|
|
Loading…
Reference in New Issue