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@@ -54,7 +54,7 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeLis
private static final byte INS_PROVISION_RKP_ADDITIONAL_CERT_CHAIN_CMD =
INS_KEYMINT_PROVIDER_APDU_START + 7;
private static final byte INS_SET_BOOT_ENDED_CMD =
INS_KEYMINT_PROVIDER_APDU_START + 8;
INS_KEYMINT_PROVIDER_APDU_START + 8; //unused
private static final byte INS_SE_FACTORY_PROVISIONING_LOCK_CMD = INS_KEYMINT_PROVIDER_APDU_START + 9;
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;
Expand DownExpand Up@@ -122,10 +122,6 @@ public void process(APDU apdu) {
processSetBootParamsCmd(apdu);
break;

case INS_SET_BOOT_ENDED_CMD:
processSetBootEndedCmd(apdu);
break;

case INS_PROVISION_RKP_DEVICE_UNIQUE_KEYPAIR_CMD:
processProvisionRkpDeviceUniqueKeyPair(apdu);
break;
Expand DownExpand Up@@ -214,14 +210,13 @@ private boolean isCommandAllowed(short apduIns) {
break;

case INS_SET_BOOT_PARAMS_CMD:
case INS_SET_BOOT_ENDED_CMD:
case INS_GET_PROVISION_STATUS_CMD:
break;

default:
// Allow other commands only if provision is completed.
if (!isProvisioningComplete()) {
result = false;
result = false;
}
}
return result;
Expand DownExpand Up@@ -512,23 +507,13 @@ private void processGetProvisionStatusCmd(APDU apdu) {
sendOutgoing(apdu, resp);
}

private void processSetBootEndedCmd(APDU apdu) {
if (seProvider.isBootSignalEventSupported()
&& (!seProvider.isDeviceRebooted())) {
ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
}
//set the flag to mark boot ended
kmDataStore.setBootEndedStatus(true);
seProvider.clearDeviceBooted(false);
sendError(apdu, KMError.OK);
}

private void processSetBootParamsCmd(APDU apdu) {
if (seProvider.isBootSignalEventSupported()
&& (!seProvider.isDeviceRebooted())) {
ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
}

// clear the device reboot status
kmDataStore.clearDeviceBootStatus();
short argsProto = KMArray.instance((short) 5);
byte[] scratchPad = apdu.getBuffer();
// Array of 4 expected arguments
Expand DownExpand Up@@ -580,6 +565,8 @@ private void processSetBootParamsCmd(APDU apdu) {
kmDataStore.createComputedHmacKey(scratchPad, (short) 0, KMKeymintDataStore.COMPUTED_HMAC_KEY_SIZE);

super.reboot();
kmDataStore.setDeviceBootStatus(KMKeymintDataStore.SET_BOOT_PARAMS_SUCCESS);
seProvider.clearDeviceBooted(false);
sendError(apdu, KMError.OK);
}

Expand DownExpand Up@@ -660,9 +647,13 @@ public Element onSave() {
private short validateApdu(APDU apdu) {
// Read the apdu header and buffer.
byte[] apduBuffer = apdu.getBuffer();
byte apduClass = apduBuffer[ISO7816.OFFSET_CLA];
short P1P2 = Util.getShort(apduBuffer, ISO7816.OFFSET_P1);

// Validate CLA
if (!apdu.isValidCLA()) {
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
}

// Validate P1P2.
if (P1P2 != KMKeymasterApplet.KM_HAL_VERSION) {
sendError(apdu, KMError.INVALID_P1P2);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,29 +43,14 @@ public class KMJCardSimApplet extends KMKeymasterApplet {
private static final byte INS_PROVISION_RKP_ADDITIONAL_CERT_CHAIN_CMD =
INS_KEYMINT_PROVIDER_APDU_START + 7;
private static final byte INS_SET_BOOT_ENDED_CMD =
INS_KEYMINT_PROVIDER_APDU_START + 8;
INS_KEYMINT_PROVIDER_APDU_START + 8; //unused
private static final byte INS_SE_FACTORY_PROVISIONING_LOCK_CMD = INS_KEYMINT_PROVIDER_APDU_START + 9;
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 short NOT_PROVISIONED = 0x0000;
private static final short PROVISION_STATUS_ATTESTATION_KEY = 0x0001;
private static final short PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x0002;
private static final short PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x0004;
private static final short PROVISION_STATUS_ATTEST_IDS = 0x0008;
private static final short PROVISION_STATUS_PRESHARED_SECRET = 0x0010;
private static final short PROVISION_STATUS_PROVISIONING_LOCKED = 0x0020;
private static final short PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR = 0x0040;
private static final short PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = 0x0080;
private static final short PROVISION_STATUS_SE_LOCKED = 0x0100;
private static final short PROVISION_STATUS_OEM_PUBLIC_KEY = 0x0200;

public static final short SHARED_SECRET_KEY_SIZE = 32;

// Package version.
Expand DownExpand Up@@ -125,10 +110,6 @@ public void process(APDU apdu) {
processSetBootParamsCmd(apdu);
break;

case INS_SET_BOOT_ENDED_CMD:
processSetBootEndedCmd(apdu);
break;

case INS_PROVISION_RKP_DEVICE_UNIQUE_KEYPAIR_CMD:
processProvisionRkpDeviceUniqueKeyPair(apdu);
break;
Expand DownExpand Up@@ -217,14 +198,13 @@ private boolean isCommandAllowed(short apduIns) {
break;

case INS_SET_BOOT_PARAMS_CMD:
case INS_SET_BOOT_ENDED_CMD:
case INS_GET_PROVISION_STATUS_CMD:
break;

default:
// Allow other commands only if provision is completed.
if (!isProvisioningComplete()) {
result = false;
result = false;
}
}
return result;
Expand DownExpand Up@@ -515,23 +495,13 @@ private void processGetProvisionStatusCmd(APDU apdu) {
sendOutgoing(apdu, resp);
}

private void processSetBootEndedCmd(APDU apdu) {
if (seProvider.isBootSignalEventSupported()
&& (!seProvider.isDeviceRebooted())) {
ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
}
//set the flag to mark boot ended
kmDataStore.setBootEndedStatus(true);
seProvider.clearDeviceBooted(false);
sendError(apdu, KMError.OK);
}

private void processSetBootParamsCmd(APDU apdu) {
if (seProvider.isBootSignalEventSupported()
&& (!seProvider.isDeviceRebooted())) {
ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
}

// clear the device reboot status
kmDataStore.clearDeviceBootStatus();
short argsProto = KMArray.instance((short) 5);
byte[] scratchPad = apdu.getBuffer();
// Array of 4 expected arguments
Expand DownExpand Up@@ -583,12 +553,14 @@ private void processSetBootParamsCmd(APDU apdu) {
kmDataStore.createComputedHmacKey(scratchPad, (short) 0, KMKeymintDataStore.COMPUTED_HMAC_KEY_SIZE);

super.reboot();
kmDataStore.setDeviceBootStatus(KMKeymintDataStore.SET_BOOT_PARAMS_SUCCESS);
seProvider.clearDeviceBooted(false);
sendError(apdu, KMError.OK);
}

private boolean isProvisioningComplete() {
short dInex = repository.allocReclaimableMemory((short)2);
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;
Expand All@@ -605,9 +577,15 @@ private boolean isProvisioningComplete() {
private short validateApdu(APDU apdu) {
// Read the apdu header and buffer.
byte[] apduBuffer = apdu.getBuffer();
byte apduClass = apduBuffer[ISO7816.OFFSET_CLA];
short apduClass = (short) (apduBuffer[ISO7816.OFFSET_CLA] & 0x00FF);
short P1P2 = Util.getShort(apduBuffer, ISO7816.OFFSET_P1);

// Validate CLA.
if (((apduClass & 0x00E0) == 0x0020) ||
(apduClass == 0x00FF)) {
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
}

// Validate P1P2.
if (P1P2 != KMKeymasterApplet.KM_HAL_VERSION) {
sendError(apdu, KMError.INVALID_P1P2);
Expand Down
40 changes: 31 additions & 9 deletions Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,7 +48,6 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe
public static final short VERIFIED_BOOT_HASH_SIZE = 32;
public static final short BOOT_PATCH_LVL_SIZE = 4;

protected static final byte CLA_ISO7816_NO_SM_NO_CHAN = (byte) 0x80;
protected static final short KM_HAL_VERSION = (short) 0x5000;
private static final short MAX_AUTH_DATA_SIZE = (short) 512;
private static final short DERIVE_KEY_INPUT_SIZE = (short) 256;
Expand DownExpand Up@@ -457,6 +456,9 @@ public void process(APDU apdu) {
}
byte[] apduBuffer = apdu.getBuffer();
byte apduIns = apduBuffer[ISO7816.OFFSET_INS];
if (!isKeymintReady(apduIns)) {
ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
}
switch (apduIns) {
case INS_INIT_STRONGBOX_CMD:
processInitStrongBoxCmd(apdu);
Expand DownExpand Up@@ -562,6 +564,28 @@ public void process(APDU apdu) {
}
}

//After every device boot, the Keymaster becomes ready to execute all the commands only after
// 1. boot parameters are set,
// 2. system properties are set and
// 3. computed the shared secret successfully.
private boolean isKeymintReady(byte apduIns) {
if(kmDataStore.isDeviceReady()) {
return true;
}
// Below commands are allowed even if the Keymaster is not ready.
switch (apduIns) {
case INS_GET_HW_INFO_CMD:
case INS_ADD_RNG_ENTROPY_CMD:
case INS_GET_HMAC_SHARING_PARAM_CMD:
case INS_COMPUTE_SHARED_HMAC_CMD:
case INS_INIT_STRONGBOX_CMD:
return true;
default:
break;
}
return false;
}

private void generateUniqueOperationHandle(byte[] buf, short offset, short len) {
do {
seProvider.newRandomNumber(buf, offset, len);
Expand All@@ -579,6 +603,7 @@ private void freeOperations() {

private void processEarlyBootEndedCmd(APDU apdu) {
kmDataStore.setEarlyBootEndedStatus(true);
sendError(apdu, KMError.OK);
}

private short deviceLockedCmd(APDU apdu){
Expand DownExpand Up@@ -1015,6 +1040,7 @@ private void processComputeSharedHmacCmd(APDU apdu) {
(short) sharingCheck.length,
scratchPad,
keyLen);
kmDataStore.setDeviceBootStatus(KMKeymintDataStore.NEGOTIATED_SHARED_SECRET_SUCCESS);
// verification signature blob - 32 bytes
//tmpVariables[1]
short signature = KMByteBlob.instance(scratchPad, keyLen, signLen);
Expand DownExpand Up@@ -2570,19 +2596,16 @@ private void authorizeAndBeginOperation(KMOperationState op, byte[] scratchPad)
authorizeDeviceUnlock(scratchPad);
authorizeKeyUsageForCount(scratchPad);

KMTag.assertAbsence(data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY,
KMError.INVALID_KEY_BLOB);

//Validate early boot
//VTS expects error code EARLY_BOOT_ONLY during begin operation if eary boot ended tag is present
if (kmDataStore.getEarlyBootEndedStatus()) {
KMTag.assertAbsence(data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY,
KMError.EARLY_BOOT_ENDED);
}

//Validate bootloader only
if (kmDataStore.getBootEndedStatus()) {
KMTag.assertAbsence(data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY,
KMError.INVALID_KEY_BLOB);
}

// Authorize Caller Nonce - if caller nonce absent in key char and nonce present in
// key params then fail if it is not a Decrypt operation
data[IV] = KMType.INVALID_VALUE;
Expand DownExpand Up@@ -3422,12 +3445,11 @@ private void processInitStrongBoxCmd(APDU apdu) {
setOsVersion(osVersion);
setOsPatchLevel(osPatchLevel);
setVendorPatchLevel(vendorPatchLevel);
kmDataStore.setDeviceBootStatus(KMKeymintDataStore.SET_SYSTEM_PROPERTIES_SUCCESS);
}

public void reboot() {
kmDataStore.clearHmacNonce();
//flag to maintain the boot state
kmDataStore.setBootEndedStatus(false);
//flag to maintain early boot ended state
kmDataStore.setEarlyBootEndedStatus(false);
//Clear all the operation state.
Expand Down
Loading