Skip to content
This repository was archived by the owner on May 24, 2026. It is now read-only.
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 numberDiff line numberDiff line change
Expand Up@@ -59,24 +59,9 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeLis
private static final byte INS_PROVISION_OEM_ROOT_PUBLIC_KEY_CMD = INS_KEYMINT_PROVIDER_APDU_START + 10;
private static final byte INS_OEM_UNLOCK_PROVISIONING_CMD = INS_KEYMINT_PROVIDER_APDU_START + 11;


private static final byte INS_KEYMINT_PROVIDER_APDU_END = 0x1F;
public static final byte BOOT_KEY_MAX_SIZE = 32;
public static final byte BOOT_HASH_MAX_SIZE = 32;

// Provision reporting status
private static final byte NOT_PROVISIONED = 0x00;
private static final byte PROVISION_STATUS_ATTESTATION_KEY = 0x01; // unused in keymint
private static final byte PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02; // unused in keymint
private static final byte PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04; // unused in keymint
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_DEVICE_UNIQUE_KEYPAIR = 0x40;
private static final byte PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = (byte) 0x80;
private static final byte PROVISION_STATUS_SE_LOCKED = 0x01;
private static final byte PROVISION_STATUS_OEM_PUBLIC_KEY = 0x02;

public static final short SHARED_SECRET_KEY_SIZE = 32;

// Package version.
Expand DownExpand Up@@ -138,7 +123,7 @@ public void process(APDU apdu) {
break;

case INS_SET_BOOT_ENDED_CMD:
processSetBootEndedCmd(apdu);
processSetBootEndedCmd(apdu);
break;

case INS_PROVISION_RKP_DEVICE_UNIQUE_KEYPAIR_CMD:
Expand DownExpand Up@@ -206,7 +191,7 @@ private boolean isCommandAllowed(short apduIns) {
break;

case INS_SE_FACTORY_PROVISIONING_LOCK_CMD:
if(!isSeFactoryProvisioningComplete()) {
if(isSeFactoryProvisioningLocked() || !isSeFactoryProvisioningComplete()) {
result = false;
}
break;
Expand All@@ -216,7 +201,7 @@ private boolean isCommandAllowed(short apduIns) {
// 1. All the necessary provisioning commands are succcessfully executed
// 2. SE provision is locked
// 3. OEM Root Public is provisioned.
if (!(isProvisioningComplete() && isSeFactoryProvisioningLocked())) {
if (kmDataStore.isProvisionLocked() || !(isProvisioningComplete() && isSeFactoryProvisioningLocked())) {
result = false;
}
break;
Expand All@@ -243,44 +228,48 @@ private boolean isCommandAllowed(short apduIns) {
}

private boolean isSeFactoryProvisioningLocked() {
short dInex = repository.allocReclaimableMemory((short)1);
byte data[] = repository.getHeap();
short dInex = repository.allocReclaimableMemory((short)2);
byte data[] = repository.getHeap();
kmDataStore.getProvisionStatus(data, dInex);
short pStatus = Util.getShort(data, dInex);
boolean result = false;
if ((0 != (data[dInex] & PROVISION_STATUS_SE_LOCKED))) {
if ((0 != (pStatus & PROVISION_STATUS_SE_LOCKED))) {
result = true;
}
repository.reclaimMemory((short)1);
repository.reclaimMemory((short)2);
return result;
}

private boolean isSeFactoryProvisioningComplete() {
short dIndex = repository.allocReclaimableMemory((short)1);
short dIndex = repository.allocReclaimableMemory((short)2);
byte data[] = repository.getHeap();
kmDataStore.getProvisionStatus(data, dIndex);
short pStatus = Util.getShort(data, dIndex);
boolean result = false;
if ((0 != (data[dIndex] & INS_PROVISION_RKP_DEVICE_UNIQUE_KEYPAIR_CMD))
&& (0 != ((data[dIndex] & INS_PROVISION_RKP_ADDITIONAL_CERT_CHAIN_CMD)))) {
result = true;
if ((0 != (pStatus & PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR))
&& (0 != ((pStatus & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN)))) {
result = true;
}
repository.reclaimMemory((short)1);
repository.reclaimMemory((short)2);
return result;
}

private void processOEMUnlockProvisionCmd(APDU apdu) {
handleOEMLockUnlockCmd(OEM_UNLOCK_PROVISION_VERIFICATION_LABEL, apdu);
authenticateOEM(OEM_UNLOCK_PROVISION_VERIFICATION_LABEL, apdu);
kmDataStore.setProvisionLock(false);
kmDataStore.unlockProvision(PROVISION_STATUS_PROVISIONING_LOCKED);
sendError(apdu, KMError.OK);
}

private void processOEMLockProvisionCmd(APDU apdu) {
handleOEMLockUnlockCmd(OEM_LOCK_PROVISION_VERIFICATION_LABEL, apdu);
authenticateOEM(OEM_LOCK_PROVISION_VERIFICATION_LABEL, apdu);
// Enable the lock bit in provision status.
kmDataStore.setProvisionLock(true);
kmDataStore.setProvisionStatus(PROVISION_STATUS_PROVISIONING_LOCKED);
sendError(apdu, KMError.OK);
}

private void handleOEMLockUnlockCmd(byte[] plainMsg, APDU apdu) {
private void authenticateOEM(byte[] plainMsg, APDU apdu) {

tmpVariables[0] = KMArray.instance((short) 1);
KMArray.cast(tmpVariables[0]).add((short) 0, KMByteBlob.exp());
Expand DownExpand Up@@ -519,7 +508,7 @@ private void processGetProvisionStatusCmd(APDU apdu) {
kmDataStore.getProvisionStatus(scratchpad, (short) 0);
short resp = KMArray.instance((short) 2);
KMArray.cast(resp).add((short) 0, buildErrorStatus(KMError.OK));
KMArray.cast(resp).add((short) 1, KMInteger.uint_8(scratchpad[0]));
KMArray.cast(resp).add((short) 1, KMInteger.instance(scratchpad, (short)0, (short)2));
sendOutgoing(apdu, resp);
}

Expand DownExpand Up@@ -586,53 +575,30 @@ private void processSetBootParamsCmd(APDU apdu) {
enumVal = KMEnum.cast(bootParam).getVal();
kmDataStore.setDeviceLocked(enumVal == KMType.DEVICE_LOCKED_TRUE);


// Clear the Computed SharedHmac and Hmac nonce from persistent memory.
Util.arrayFillNonAtomic(scratchPad, (short) 0, KMKeymintDataStore.COMPUTED_HMAC_KEY_SIZE, (byte) 0);
kmDataStore.createComputedHmacKey(scratchPad, (short) 0, KMKeymintDataStore.COMPUTED_HMAC_KEY_SIZE);

super.reboot();
sendError(apdu, KMError.OK);
}

private boolean isProvisioningComplete() {
short dInex = repository.allocReclaimableMemory((short)1);
byte data[] = repository.getHeap();
kmDataStore.getProvisionStatus(data, dInex);
boolean result = false;
if (kmDataStore.isProvisionLocked() || ((0 != (data[dInex] & PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR))
&& (0 != (data[dInex] & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN))
&& (0 != (data[dInex] & PROVISION_STATUS_PRESHARED_SECRET))
&& (0 != (data[dInex] & PROVISION_STATUS_ATTEST_IDS)))) {
result = true;
}
repository.reclaimMemory((short)1);
return result;
}

private boolean isOemProvisionComplete() {
short dInex = repository.allocReclaimableMemory((short)1);
byte data[] = repository.getHeap();
short dInex = repository.allocReclaimableMemory((short)2);
byte data[] = repository.getHeap();
kmDataStore.getProvisionStatus(data, dInex);
short pStatus = Util.getShort(data, dInex);
boolean result = false;
if ((0 != (data[dInex] & PROVISION_STATUS_OEM_PUBLIC_KEY))
&& (0 != (data[dInex] & PROVISION_STATUS_SE_LOCKED))) {
if (kmDataStore.isProvisionLocked() || ((0 != (pStatus & PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR))
&& (0 != (pStatus & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN))
&& (0 != (pStatus & PROVISION_STATUS_PRESHARED_SECRET))
&& (0 != (pStatus & PROVISION_STATUS_ATTEST_IDS)))) {
result = true;
}
repository.reclaimMemory((short)1);
repository.reclaimMemory((short)2);
return result;
}

private void processLockProvisioningCmd(APDU apdu) {
if (isProvisioningComplete()) {
kmDataStore.setProvisionLocked();
kmDataStore.setProvisionStatus(PROVISION_STATUS_PROVISIONING_LOCKED);
sendError(apdu, KMError.OK);
} else {
ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
}
}

@Override
public void onCleanup() {
}
Expand DownExpand Up@@ -704,5 +670,5 @@ private short validateApdu(APDU apdu) {
}
return apduBuffer[ISO7816.OFFSET_INS];
}
}

}
Original file line numberDiff line numberDiff line change
Expand Up@@ -52,6 +52,8 @@ public class KMAndroidSEProvider implements KMSEProvider {
public static final byte POWER_RESET_FALSE = (byte) 0xAA;
public static final byte POWER_RESET_TRUE = (byte) 0x00;
private static final short COMPUTED_HMAC_KEY_SIZE = 32;
private static byte[] CMAC_KDF_CONSTANT_L;
private static byte[] CMAC_KDF_CONSTANT_ZERO;

private static KeyAgreement keyAgreement;

Expand DownExpand Up@@ -88,6 +90,7 @@ public static KMAndroidSEProvider getInstance() {
}

public KMAndroidSEProvider() {
initStatics();
// Re-usable AES,DES and HMAC keys in persisted memory.
aesKeys = new AESKey[2];
aesKeys[KEYSIZE_128_OFFSET] = (AESKey) KeyBuilder.buildKey(
Expand DownExpand Up@@ -120,6 +123,12 @@ public KMAndroidSEProvider() {
JCSystem.CLEAR_ON_RESET);
resetFlag[0] = (byte) POWER_RESET_FALSE;
}

void initStatics() {
CMAC_KDF_CONSTANT_L = new byte[] {
0x00, 0x00, 0x01, 0x00 };
CMAC_KDF_CONSTANT_ZERO = new byte[] {0x00};
}

public void clean() {
Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0);
Expand DownExpand Up@@ -401,23 +410,10 @@ public boolean aesGCMDecrypt(byte[] aesKey, short aesKeyStart,
public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelStart,
short labelLen,
byte[] context, short contextStart, short contextLength) {
try {
try {
// This is hardcoded to requirement - 32 byte output with two concatenated
// 16 bytes K1 and K2.
final byte n = 2; // hardcoded
// [L] 256 bits - hardcoded 32 bits as per
// reference impl in keymaster.
short zeroIndex = 0;
short LIndex = 1;
short bufIndex = 5;
short keyIndex = 9;
//1st byte in tempArray is reserved for zero
//next 4 bytes in tempArray is reserved for L
tmpArray[0] = 0;
tmpArray[1] = 0;
tmpArray[2] = 0;
tmpArray[3] = 1;
tmpArray[4] = 0;

// [i] counter - 32 bits
short iBufLen = 4;
Expand All@@ -439,12 +435,12 @@ public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelSta
while (i <= n) {
tmpArray[3] = i;
// 4 bytes of iBuf with counter in it
kdf.update(tmpArray, bufIndex, iBufLen);
kdf.update(tmpArray, (short) 0, (short) iBufLen);
kdf.update(label, labelStart, (short) labelLen); // label
kdf.update(tmpArray, zeroIndex, (short) 1); // 1 byte of 0x00
kdf.update(CMAC_KDF_CONSTANT_ZERO, (short) 0, (short) CMAC_KDF_CONSTANT_ZERO.length); // 1 byte of 0x00
kdf.update(context, contextStart, contextLength); // context
// 4 bytes of L - signature of 16 bytes
pos = kdf.sign(tmpArray, LIndex, (short) 4, tmpArray,
pos = kdf.sign(CMAC_KDF_CONSTANT_L, (short) 0, (short) CMAC_KDF_CONSTANT_L.length, tmpArray,
(short) (iBufLen + pos));
i++;
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -698,7 +698,6 @@ KMDeviceUniqueKeyPair createRkpDeviceUniqueKeyPair(KMDeviceUniqueKeyPair key,
short messageDigest256(byte[] inBuff, short inOffset, short inLength, byte[] outBuff,
short outOffset);


/**
* This function generates a HMAC key from the provided key buffers.
*
Expand Down
Loading