Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeLis
private static final byte INS_LOCK_PROVISIONING_CMD = INS_KEYMINT_PROVIDER_APDU_START + 3;
private static final byte INS_GET_PROVISION_STATUS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 4;
private static final byte INS_SET_BOOT_PARAMS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 5;
private static final byte INS_PROVISION_RKP_UNIQUE_DEVICE_KEYPAIR_CMD =
private static final byte INS_PROVISION_RKP_DEVICE_UNIQUE_KEYPAIR_CMD =
INS_KEYMINT_PROVIDER_APDU_START + 6;
private static final byte INS_PROVISION_RKP_ADDITIONAL_CERT_CHAIN_CMD =
INS_KEYMINT_PROVIDER_APDU_START + 7;
Expand All @@ -68,7 +68,7 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeLis
private static final byte PROVISION_STATUS_ATTEST_IDS = 0x08;
private static final byte PROVISION_STATUS_PRESHARED_SECRET = 0x10;
private static final byte PROVISION_STATUS_PROVISIONING_LOCKED = 0x20;
private static final byte PROVISION_STATUS_UNIQUE_DEVICE_KEYPAIR = 0x40;
private static final byte PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR = 0x40;
private static final byte PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = (byte) 0x80;

public static final short SHARED_SECRET_KEY_SIZE = 32;
Expand Down Expand Up @@ -159,12 +159,12 @@ public void process(APDU apdu) {
processSetBootParamsCmd(apdu);
break;

case INS_PROVISION_RKP_UNIQUE_DEVICE_KEYPAIR_CMD:
processProvisionDeviceUniqueKeyPair(apdu);
case INS_PROVISION_RKP_DEVICE_UNIQUE_KEYPAIR_CMD:
processProvisionRkpDeviceUniqueKeyPair(apdu);
break;

case INS_PROVISION_RKP_ADDITIONAL_CERT_CHAIN_CMD:
processProvisionAdditionalCertChain(apdu);
processProvisionRkpAdditionalCertChain(apdu);
break;

default:
Expand All @@ -189,7 +189,7 @@ public void process(APDU apdu) {
}
}

private static void processProvisionDeviceUniqueKeyPair(APDU apdu) {
private static void processProvisionRkpDeviceUniqueKeyPair(APDU apdu) {
// Re-purpose the apdu buffer as scratch pad.
byte[] scratchPad = apdu.getBuffer();
short arr = KMArray.instance((short) 1);
Expand All @@ -201,17 +201,17 @@ private static void processProvisionDeviceUniqueKeyPair(APDU apdu) {
short pubKeyLen = KMCoseKey.cast(coseKey).getEcdsa256PublicKey(scratchPad, (short) 0);
short privKeyLen = KMCoseKey.cast(coseKey).getPrivateKey(scratchPad, pubKeyLen);
//Store the Device unique Key.
kmDataStore.createDeviceUniqueKeyPair(scratchPad, (short) 0, pubKeyLen, scratchPad,
kmDataStore.createRkpDeviceUniqueKeyPair(scratchPad, (short) 0, pubKeyLen, scratchPad,
pubKeyLen, privKeyLen);
short bcc = generateBcc(false, scratchPad);
short len = KMKeymasterApplet.encodeToApduBuffer(bcc, scratchPad, (short) 0,
MAX_COSE_BUF_SIZE);
kmDataStore.persistBootCertificateChain(scratchPad, (short) 0, len);
kmDataStore.setProvisionStatus(PROVISION_STATUS_UNIQUE_DEVICE_KEYPAIR);
kmDataStore.setProvisionStatus(PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR);
sendError(apdu, KMError.OK);
}

private static void processProvisionAdditionalCertChain(APDU apdu) {
private static void processProvisionRkpAdditionalCertChain(APDU apdu) {
// Prepare the expression to decode
short headers = KMCoseHeaders.exp();
short arrInst = KMArray.instance((short) 4);
Expand Down Expand Up @@ -244,7 +244,7 @@ private static void processProvisionAdditionalCertChain(APDU apdu) {
srcBuffer, null);
// Compare the DK_Pub.
short pubKeyLen = KMCoseKey.cast(leafCoseKey).getEcdsa256PublicKey(srcBuffer, (short) 0);
KMDeviceUniqueKeyPair uniqueKey = kmDataStore.getDeviceUniqueKeyPair(false);
KMDeviceUniqueKeyPair uniqueKey = kmDataStore.getRkpDeviceUniqueKeyPair(false);
if (uniqueKey == null) {
KMException.throwIt(KMError.STATUS_FAILED);
}
Expand Down Expand Up @@ -408,7 +408,7 @@ private boolean isProvisioningComplete() {
byte data[] = repository.getHeap();
kmDataStore.getProvisionStatus(data, dInex);
boolean result = false;
if ((0 != (data[dInex] & PROVISION_STATUS_UNIQUE_DEVICE_KEYPAIR))
if ((0 != (data[dInex] & PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR))
&& (0 != (data[dInex] & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN))
&& (0 != (data[dInex] & PROVISION_STATUS_PRESHARED_SECRET))) {
result = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1108,7 +1108,7 @@ public short ecSign256(KMDeviceUniqueKeyPair ecPrivKey, byte[] inputDataBuf,
}

@Override
public KMDeviceUniqueKeyPair createDeviceUniqueKeyPair(KMDeviceUniqueKeyPair key,
public KMDeviceUniqueKeyPair createRkpDeviceUniqueKeyPair(KMDeviceUniqueKeyPair key,
byte[] pubKey, short pubKeyOff, short pubKeyLen, byte[] privKey,
short privKeyOff, short privKeyLen) {
if (key == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package com.android.javacard.seprovider;

public interface KMDeviceUniqueKey {
public interface KMDeviceUniqueKeyPair {

short getPublicKey(byte[] buf, short offset);
}
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ KMOperation initAsymmetricOperation(
* @param privKeyLen private key buffer length.
* @return instance of KMDeviceUniqueKey.
*/
KMDeviceUniqueKeyPair createDeviceUniqueKeyPair(KMDeviceUniqueKeyPair key,
KMDeviceUniqueKeyPair createRkpDeviceUniqueKeyPair(KMDeviceUniqueKeyPair key,
byte[] pubKey, short pubKeyOff, short pubKeyLen,
byte[] privKey, short privKeyOff, short privKeyLen);

Expand Down
99 changes: 80 additions & 19 deletions Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ public void process(APDU apdu) {
case INS_GENERATE_KEY_CMD:
processGenerateKey(apdu);
break;
case INS_ATTEST_KEY_CMD:
processAttestKeyCmd(apdu);
break;
case INS_IMPORT_KEY_CMD:
processImportKeyCmd(apdu);
break;
Expand Down Expand Up @@ -1283,16 +1286,17 @@ private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyPara

// Add Tags
addTags(hwParameters, true, cert);
addTags(swParameters, false, cert);
short swParams = KMKeyParameters.makeKeystoreEnforced(data[KEY_PARAMETERS], scratchPad);
addTags(swParams, false, cert);
// Add Device Boot locked status
cert.deviceLocked(kmDataStore.isDeviceBootLocked());
// VB data
cert.verifiedBootHash(getVerifiedBootHash(scratchPad));
cert.verifiedBootKey(getBootKey(scratchPad));
cert.verifiedBootState((byte) kmDataStore.getBootState());

// TODO remove the following line
makeKeyCharacteristics(scratchPad);
data[SECRET] = privKey;
data[KEY_BLOB] = origBlob;
return cert;
}

Expand Down Expand Up @@ -3294,13 +3298,9 @@ protected void setVendorPatchLevel(short patch){

private short generateKeyCmd(APDU apdu){
short params = KMKeyParameters.expAny();
short blob = KMByteBlob.exp();
// Array of expected arguments
short cmd = KMArray.instance((short) 4);
short cmd = KMArray.instance((short) 1);
KMArray.cast(cmd).add((short) 0, params); //key params
KMArray.cast(cmd).add((short) 1, blob); //attest key
KMArray.cast(cmd).add((short) 2, params); //attest key params
KMArray.cast(cmd).add((short) 3, blob); //issuer
return receiveIncoming(apdu, cmd);
}

Expand All @@ -3310,10 +3310,6 @@ private void processGenerateKey(APDU apdu) {
// Re-purpose the apdu buffer as scratch pad.
byte[] scratchPad = apdu.getBuffer();
data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 0);
data[ATTEST_KEY_BLOB] = KMArray.cast(cmd).get((short) 1);
data[ATTEST_KEY_PARAMS] = KMArray.cast(cmd).get((short) 2);
data[ATTEST_KEY_ISSUER] = KMArray.cast(cmd).get((short) 3);
data[CERTIFICATE] = KMArray.instance((short)0); //by default the cert is empty.
// ROLLBACK_RESISTANCE not supported.
KMTag.assertAbsence(data[KEY_PARAMETERS], KMType.BOOL_TAG,KMType.ROLLBACK_RESISTANCE, KMError.ROLLBACK_RESISTANCE_UNAVAILABLE);

Expand Down Expand Up @@ -3359,22 +3355,84 @@ private void processGenerateKey(APDU apdu) {
// create key blob and associated attestation.
data[ORIGIN] = KMType.GENERATED;
makeKeyCharacteristics(scratchPad);
generateAttestation(data[ATTEST_KEY_BLOB], data[ATTEST_KEY_PARAMS],scratchPad);
createEncryptedKeyBlob(scratchPad);
// Remove custom tags from key characteristics
short teeParams = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced();
if(teeParams != KMType.INVALID_VALUE) {
KMKeyParameters.cast(teeParams).deleteCustomTags();
}
// prepare the response
short resp = KMArray.instance((short) 4);
short resp = KMArray.instance((short) 3);
KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
KMArray.cast(resp).add((short) 1, data[KEY_BLOB]);
KMArray.cast(resp).add((short) 2, data[KEY_CHARACTERISTICS]);
KMArray.cast(resp).add((short) 3, data[CERTIFICATE]);
sendOutgoing(apdu, resp);
}

private short generateAttestKeyCmd(APDU apdu) {
short params = KMKeyParameters.expAny();
short blob = KMByteBlob.exp();
// Array of expected arguments
short cmd = KMArray.instance((short) 5);
KMArray.cast(cmd).add((short) 0, blob); // key blob
KMArray.cast(cmd).add((short) 1, params); // keyparamters to be attested.
KMArray.cast(cmd).add((short) 2, blob); // attest key blob
KMArray.cast(cmd).add((short) 3, params); // attest key params
KMArray.cast(cmd).add((short) 4, blob); // attest issuer

return receiveIncoming(apdu, cmd);
}

public void getAttestKeyInputParameters(short arrPtr, short[] data, byte keyBlobOff,
byte keyParametersOff,
byte attestKeyBlobOff, byte attestKeyParamsOff, byte attestKeyIssuerOff) {
data[keyBlobOff] = KMArray.cast(arrPtr).get((short) 0);
data[keyParametersOff] = KMArray.cast(arrPtr).get((short) 1);
data[attestKeyBlobOff] = KMType.INVALID_VALUE;
data[attestKeyParamsOff] = KMType.INVALID_VALUE;
data[attestKeyIssuerOff] = KMType.INVALID_VALUE;
}

private void processAttestKeyCmd(APDU apdu) {
// Receive the incoming request fully from the master into buffer.
short cmd = generateAttestKeyCmd(apdu);
// Re-purpose the apdu buffer as scratch pad.
byte[] scratchPad = apdu.getBuffer();
data[KEY_BLOB] = KMArray.cast(cmd).get((short) 0);
data[KEY_PARAMETERS] = KMArray.cast(cmd).get((short) 1);
data[ATTEST_KEY_BLOB] = KMArray.cast(cmd).get((short) 2);
data[ATTEST_KEY_PARAMS] = KMArray.cast(cmd).get((short) 3);
data[ATTEST_KEY_ISSUER] = KMArray.cast(cmd).get((short) 4);

data[CERTIFICATE] = KMArray.instance((short) 0); //by default the cert is empty.

// Check for app id and app data.
data[APP_ID] =
KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, data[KEY_PARAMETERS]);
data[APP_DATA] =
KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_DATA, data[KEY_PARAMETERS]);
if (data[APP_ID] != KMTag.INVALID_VALUE) {
data[APP_ID] = KMByteTag.cast(data[APP_ID]).getValue();
}
if (data[APP_DATA] != KMTag.INVALID_VALUE) {
data[APP_DATA] = KMByteTag.cast(data[APP_DATA]).getValue();
}
// parse key blob
parseEncryptedKeyBlob(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad);
// The key which is being attested should be asymmetric i.e. RSA or EC
short alg = KMEnumTag.getValue(KMType.ALGORITHM, data[HW_PARAMETERS]);
if (alg != KMType.RSA && alg != KMType.EC) {
KMException.throwIt(KMError.INCOMPATIBLE_ALGORITHM);
}
// Build certificate
generateAttestation(data[ATTEST_KEY_BLOB], data[ATTEST_KEY_PARAMS], scratchPad);

short resp = KMArray.instance((short) 2);
KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK));
KMArray.cast(resp).add((short) 1, data[CERTIFICATE]);
sendOutgoing(apdu, resp);
}

private short getAttestationMode(short attKeyBlob, short attChallenge){
short alg = KMKeyParameters.findTag(KMType.ENUM_TAG, KMType.ALGORITHM, data[KEY_PARAMETERS]);
short mode = KMType.NO_CERT;
Expand Down Expand Up @@ -3419,7 +3477,7 @@ private void generateAttestation(short attKeyBlob, short attKeyParam, byte[] sc

switch (mode){
case KMType.ATTESTATION_CERT:
cert = makeAttestationCert(attKeyBlob,attKeyParam, attChallenge, data[ATTEST_KEY_ISSUER],data[HW_PARAMETERS],
cert = makeAttestationCert(attKeyBlob, attKeyParam, attChallenge, data[ATTEST_KEY_ISSUER],data[HW_PARAMETERS],
data[SW_PARAMETERS], scratchPad);
break;
case KMType.SELF_SIGNED_CERT:
Expand Down Expand Up @@ -3838,7 +3896,7 @@ private static void makeAuthData(byte[] scratchPad) {
KMArray.cast(params).add((short) 2, data[PUB_KEY]);
}

short authIndex = repository.alloc(MAX_AUTH_DATA_SIZE);
short authIndex = repository.allocReclaimableMemory(MAX_AUTH_DATA_SIZE);
short index = 0;
short len = 0;
short paramsLen = KMArray.cast(params).length();
Expand All @@ -3855,7 +3913,10 @@ private static void makeAuthData(byte[] scratchPad) {
}
index++;
}
data[AUTH_DATA] = authIndex;
short authDataIndex = repository.alloc(len);
Util.arrayCopyNonAtomic(repository.getHeap(), authIndex, repository.getHeap(), authDataIndex, len);
repository.reclaimMemory(MAX_AUTH_DATA_SIZE);
data[AUTH_DATA] = authDataIndex;
data[AUTH_DATA_LENGTH] = len;
}

Expand Down Expand Up @@ -4055,7 +4116,7 @@ public static short generateBcc(boolean testMode, byte[] scratchPad) {
if (!testMode && kmDataStore.isProvisionLocked()) {
KMException.throwIt(KMError.STATUS_FAILED);
}
KMDeviceUniqueKeyPair deviceUniqueKey = kmDataStore.getDeviceUniqueKeyPair(testMode);
KMDeviceUniqueKeyPair deviceUniqueKey = kmDataStore.getRkpDeviceUniqueKeyPair(testMode);
short temp = deviceUniqueKey.getPublicKey(scratchPad, (short) 0);
short coseKey =
KMCose.constructCoseKey(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -530,35 +530,35 @@ public KMComputedHmacKey getComputedHmacKey() {
return computedHmacKey;
}

public KMDeviceUniqueKeyPair createTestDeviceUniqueKeyPair(byte[] pubKey, short pubKeyOff, short pubKeyLen,
public KMDeviceUniqueKeyPair createRkpTestDeviceUniqueKeyPair(byte[] pubKey, short pubKeyOff, short pubKeyLen,
byte[] privKey, short privKeyOff, short privKeyLen) {
if (testDeviceUniqueKeyPair == null) {
testDeviceUniqueKeyPair = seProvider.createDeviceUniqueKeyPair(testDeviceUniqueKeyPair, pubKey, pubKeyOff,
testDeviceUniqueKeyPair = seProvider.createRkpDeviceUniqueKeyPair(testDeviceUniqueKeyPair, pubKey, pubKeyOff,
pubKeyLen, privKey,
privKeyOff, privKeyLen);
} else {
seProvider.createDeviceUniqueKeyPair(testDeviceUniqueKeyPair, pubKey, pubKeyOff, pubKeyLen, privKey,
seProvider.createRkpDeviceUniqueKeyPair(testDeviceUniqueKeyPair, pubKey, pubKeyOff, pubKeyLen, privKey,
privKeyOff,
privKeyLen);
}
return testDeviceUniqueKeyPair;
}

public KMDeviceUniqueKeyPair createDeviceUniqueKeyPair(byte[] pubKey, short pubKeyOff, short pubKeyLen,
public KMDeviceUniqueKeyPair createRkpDeviceUniqueKeyPair(byte[] pubKey, short pubKeyOff, short pubKeyLen,
byte[] privKey, short privKeyOff,
short privKeyLen) {
if (deviceUniqueKeyPair == null) {
deviceUniqueKeyPair = seProvider.createDeviceUniqueKeyPair(deviceUniqueKeyPair, pubKey, pubKeyOff,
deviceUniqueKeyPair = seProvider.createRkpDeviceUniqueKeyPair(deviceUniqueKeyPair, pubKey, pubKeyOff,
pubKeyLen, privKey,
privKeyOff, privKeyLen);
} else {
seProvider.createDeviceUniqueKeyPair(deviceUniqueKeyPair, pubKey, pubKeyOff, pubKeyLen, privKey,
seProvider.createRkpDeviceUniqueKeyPair(deviceUniqueKeyPair, pubKey, pubKeyOff, pubKeyLen, privKey,
privKeyOff, privKeyLen);
}
return deviceUniqueKeyPair;
}

public KMDeviceUniqueKeyPair getDeviceUniqueKeyPair(boolean testMode) {
public KMDeviceUniqueKeyPair getRkpDeviceUniqueKeyPair(boolean testMode) {
return ((KMDeviceUniqueKeyPair) (testMode ? testDeviceUniqueKeyPair : deviceUniqueKeyPair));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
*/
public class KMRepository {

public static final short HEAP_SIZE = 15000;
public static final short HEAP_SIZE = 10000;

// Class Attributes
private byte[] heap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -813,10 +813,10 @@ private KMDeviceUniqueKeyPair createDeviceUniqueKeyPair(boolean testMode, byte[]
(short) 128,
lengths);
deviceUniqueKeyPair =
storeDataInst.createTestDeviceUniqueKeyPair(scratchPad, (short) 128, lengths[1],
storeDataInst.createRkpTestDeviceUniqueKeyPair(scratchPad, (short) 128, lengths[1],
scratchPad, (short) 0, lengths[0]);
} else {
deviceUniqueKeyPair = storeDataInst.getDeviceUniqueKeyPair(false);
deviceUniqueKeyPair = storeDataInst.getRkpDeviceUniqueKeyPair(false);
}
return deviceUniqueKeyPair;
}
Expand Down
Loading