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
83 changes: 59 additions & 24 deletions Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe
private static final byte INS_OEM_LOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD + 6; //0x06
private static final byte INS_GET_PROVISION_STATUS_CMD = INS_BEGIN_KM_CMD + 7; //0x07
private static final byte INS_SET_VERSION_PATCHLEVEL_CMD = INS_BEGIN_KM_CMD + 8; //0x08
private static final byte INS_SET_BOOT_ENDED_CMD = INS_BEGIN_KM_CMD + 9; //0x09
private static final byte INS_SET_BOOT_ENDED_CMD = INS_BEGIN_KM_CMD + 9; //0x09 // Unused
private static final byte INS_SE_FACTORY_LOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD + 10; //0x0A
private static final byte INS_PROVISION_OEM_ROOT_PUBLIC_KEY_CMD = INS_BEGIN_KM_CMD + 11; //0x0B
private static final byte INS_OEM_UNLOCK_PROVISIONING_CMD = INS_BEGIN_KM_CMD + 12; //0x0C
Expand Down Expand Up @@ -237,6 +237,17 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe
public static final short KEYBLOB_CURRENT_VERSION = 1;
// KeyBlob Verion 1 constant.
public static final short KEYBLOB_VERSION_0 = 0;
// Device boot states. Applet starts executing the
// core commands once all the states are set. The commands
// that are allowed irrespective of these states are:
// All the provision commands
// INS_GET_HW_INFO_CMD
// INS_ADD_RNG_ENTROPY_CMD
// INS_COMPUTE_SHARED_HMAC_CMD
// INS_GET_HMAC_SHARING_PARAM_CMD
public static final byte SET_BOOT_PARAMS_SUCCESS = 0x01;
public static final byte SET_SYSTEM_PROPERTIES_SUCCESS = 0x02;
public static final byte NEGOTIATED_SHARED_SECRET_SUCCESS = 0x04;

// Keymaster Applet attributes
protected static byte keymasterState = ILLEGAL_STATE;
Expand Down Expand Up @@ -485,23 +496,15 @@ public void process(APDU apdu) {
&& (!seProvider.isDeviceRebooted())) {
ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
}
// clear the device reboot status
repository.setDeviceBootStatus((byte) 0x00);
processSetBootParamsCmd(apdu);
//set the flag to mark boot started
repository.setDeviceBootStatus(SET_BOOT_PARAMS_SUCCESS);
seProvider.clearDeviceBooted(false);

sendError(apdu, KMError.OK);
return;

case INS_SET_BOOT_ENDED_CMD:
if (seProvider.isBootSignalEventSupported()
&& (keymasterState == KMKeymasterApplet.ACTIVE_STATE)
&& (!seProvider.isDeviceRebooted())) {
ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
}
//set the flag to mark boot ended
repository.setBootEndedStatus(true);

seProvider.clearDeviceBooted(false);
sendError(apdu, KMError.OK);
return;

case INS_GET_PROVISION_STATUS_CMD:
processGetProvisionStatusCmd(apdu);
Expand All @@ -512,6 +515,10 @@ public void process(APDU apdu) {
if ((keymasterState == KMKeymasterApplet.ACTIVE_STATE)
|| ((keymasterState == KMKeymasterApplet.IN_PROVISION_STATE)
&& isProvisioningComplete())) {

if (!isKeymasterReady(apduIns)) {
KMException.throwIt(KMError.UNKNOWN_ERROR);
}
switch (apduIns) {
case INS_GENERATE_KEY_CMD:
processGenerateKey(apdu);
Expand Down Expand Up @@ -619,6 +626,39 @@ && isProvisioningComplete())) {
}
}

// 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 isKeymasterReady(byte apduIns) {
byte deviceBootStatus =
(SET_BOOT_PARAMS_SUCCESS | SET_SYSTEM_PROPERTIES_SUCCESS |
NEGOTIATED_SHARED_SECRET_SUCCESS);
if (repository.getDeviceBootStatus() == deviceBootStatus) {
// Keymaster is ready to execute all the commands.
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_SET_VERSION_PATCHLEVEL_CMD:
case INS_OEM_UNLOCK_PROVISIONING_CMD:
return true;
default:
break;
}
return false;
}

private void setDeviceBootStatus(byte deviceRebootStatus) {
byte status = repository.getDeviceBootStatus();
status |= deviceRebootStatus;
repository.setDeviceBootStatus(status);
}

private void generateUniqueOperationHandle(byte[] buf, short offset, short len) {
do {
seProvider.newRandomNumber(buf, offset, len);
Expand Down Expand Up @@ -854,6 +894,7 @@ private void processSetVersionAndPatchLevels(APDU apdu) {
KMInteger.cast(tmpVariables[2]).getStartOff(),
KMInteger.cast(tmpVariables[2]).length());

setDeviceBootStatus(SET_SYSTEM_PROPERTIES_SUCCESS);
sendError(apdu, KMError.OK);
}

Expand Down Expand Up @@ -1337,6 +1378,7 @@ private void processComputeSharedHmacCmd(APDU apdu) {
(short) sharingCheck.length,
scratchPad,
tmpVariables[6]);
setDeviceBootStatus(NEGOTIATED_SHARED_SECRET_SUCCESS);
// verification signature blob - 32 bytes
tmpVariables[1] = KMByteBlob.instance(scratchPad, tmpVariables[6], tmpVariables[5]);
// prepare the response
Expand Down Expand Up @@ -1682,7 +1724,7 @@ private void processAttestKeyCmd(APDU apdu) {
addTags(
KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getSoftwareEnforced(), false, cert);

cert.deviceLocked(repository.getBootLoaderLock());
cert.deviceLocked(repository.getBootDeviceLocked());
cert.issuer(getProvisionedCertificateData(KMSEProvider.CERTIFICATE_ISSUER));
cert.publicKey(data[PUB_KEY]);
cert.verifiedBootHash(repository.getVerifiedBootHash());
Expand Down Expand Up @@ -2775,7 +2817,7 @@ private void authorizeAndBeginOperation(KMOperationState op, byte[] scratchPad)
//Validate bootloader only
tmpVariables[0] =
KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, data[HW_PARAMETERS]);
if (tmpVariables[0] != KMType.INVALID_VALUE && repository.getBootEndedStatus()) {
if (tmpVariables[0] != KMType.INVALID_VALUE) {
KMException.throwIt(KMError.INVALID_KEY_BLOB);
}

Expand Down Expand Up @@ -3674,11 +3716,7 @@ private void processSetBootParamsCmd(APDU apdu) {
repository.setBootState(enumVal);

enumVal = KMEnum.cast(tmpVariables[4]).getVal();
repository.setBootloaderLocked(enumVal == KMType.DEVICE_LOCKED_TRUE);

// Clear Android system properties expect boot patch level as it is
// already set.
repository.clearAndroidSystemProperties();
repository.setBootDeviceLocked(enumVal == KMType.DEVICE_LOCKED_TRUE);

// Clear the Computed SharedHmac and Hmac nonce from persistent memory.
Util.arrayFillNonAtomic(scratchPad, (short) 0, KMRepository.COMPUTED_HMAC_KEY_SIZE, (byte) 0);
Expand All @@ -3692,9 +3730,6 @@ private void processSetBootParamsCmd(APDU apdu) {
seProvider.newRandomNumber(scratchPad, (short) 0, KMRepository.HMAC_SEED_NONCE_SIZE);
repository.initHmacNonce(scratchPad, (short) 0, KMRepository.HMAC_SEED_NONCE_SIZE);

//flag to maintain the boot state
repository.setBootEndedStatus(false);

//flag to maintain early boot ended state
repository.setEarlyBootEndedStatus(false);

Expand Down
32 changes: 14 additions & 18 deletions Applet/src/com/android/javacard/keymaster/KMRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public class KMRepository implements KMUpgradable {
public static final byte DEVICE_LOCKED_PASSWORD_ONLY = 22;
// Total 8 auth tags, so the next offset is AUTH_TAG_1 + 8
public static final byte AUTH_TAG_1 = 23;
public static final byte BOOT_ENDED_STATUS = 31;
public static final byte DEVICE_STATUS = 31;
public static final byte EARLY_BOOT_ENDED_STATUS = 32;

// Data Item sizes
Expand All @@ -94,7 +94,7 @@ public class KMRepository implements KMUpgradable {
public static final short AUTH_TAG_LENGTH = 16;
public static final short AUTH_TAG_COUNTER_SIZE = 4;
public static final short AUTH_TAG_ENTRY_SIZE = (AUTH_TAG_LENGTH + AUTH_TAG_COUNTER_SIZE + 1);
public static final short BOOT_ENDED_FLAG_SIZE = 1;
public static final short DEVICE_STATUS_FLAG_SIZE = 1;
public static final short EARLY_BOOT_ENDED_FLAG_SIZE = 1;
private static final byte[] zero = {0, 0, 0, 0, 0, 0, 0, 0};

Expand Down Expand Up @@ -698,7 +698,7 @@ public short getVerifiedBootHash() {
return blob;
}

public boolean getBootLoaderLock() {
public boolean getBootDeviceLocked() {
short blob = readData(BOOT_DEVICE_LOCKED_STATUS);
if (blob == KMType.INVALID_VALUE) {
KMException.throwIt(KMError.INVALID_DATA);
Expand Down Expand Up @@ -770,7 +770,7 @@ public void clearAndroidSystemProperties() {
// boot parameters.
}

public void setBootloaderLocked(boolean flag) {
public void setBootDeviceLocked(boolean flag) {
short start = alloc(BOOT_DEVICE_LOCK_FLAG_SIZE);
if (flag) {
(getHeap())[start] = (byte) 0x01;
Expand Down Expand Up @@ -975,24 +975,20 @@ public short getBackupObjectCount() {
return (short) 1;
}

public boolean getBootEndedStatus() {
short blob = readData(BOOT_ENDED_STATUS);
public byte getDeviceBootStatus() {
short blob = readData(DEVICE_STATUS);
if (blob == KMType.INVALID_VALUE) {
KMException.throwIt(KMError.INVALID_DATA);
}
return (byte) ((getHeap())[KMByteBlob.cast(blob).getStartOff()]) == 0x01;
return (byte) ((getHeap())[KMByteBlob.cast(blob).getStartOff()]);
}

public void setBootEndedStatus(boolean flag) {
short start = alloc(BOOT_ENDED_STATUS);
if (flag) {
(getHeap())[start] = (byte) 0x01;
} else {
(getHeap())[start] = (byte) 0x00;
}
writeDataEntry(BOOT_ENDED_STATUS, getHeap(), start, BOOT_ENDED_FLAG_SIZE);

public void setDeviceBootStatus(byte deviceStatus) {
short start = alloc(DEVICE_STATUS_FLAG_SIZE);
(getHeap())[start] = deviceStatus;
writeDataEntry(DEVICE_STATUS, getHeap(), start, DEVICE_STATUS_FLAG_SIZE);
}

public boolean getEarlyBootEndedStatus() {
short blob = readData(EARLY_BOOT_ENDED_STATUS);
if (blob == KMType.INVALID_VALUE) {
Expand All @@ -1002,7 +998,7 @@ public boolean getEarlyBootEndedStatus() {
}

public void setEarlyBootEndedStatus(boolean flag) {
short start = alloc(EARLY_BOOT_ENDED_STATUS);
short start = alloc(EARLY_BOOT_ENDED_FLAG_SIZE);
if (flag) {
(getHeap())[start] = (byte) 0x01;
} else {
Expand Down