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 @@ -68,11 +68,11 @@ 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_DEVICE_UNIQUE_KEY = 0x40;
private static final byte PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = (byte) 0x80;

public static final short SHARED_SECRET_KEY_SIZE = 32;

private static byte keymasterState = ILLEGAL_STATE;
private static byte provisionStatus = NOT_PROVISIONED;
// Package version.
protected short packageVersion;

Expand Down Expand Up @@ -108,7 +108,7 @@ public void process(APDU apdu) {
super.powerReset();
}

if (((KMAndroidSEProvider) seProvider).isProvisionLocked()) {
if (kmDataStore.isProvisionLocked()) {
switch (apduIns) {
case INS_SET_BOOT_PARAMS_CMD:
processSetBootParamsCmd(apdu);
Expand All @@ -118,7 +118,11 @@ public void process(APDU apdu) {
//set the flag to mark boot ended
kmDataStore.setBootEndedStatus(true);
sendError(apdu, KMError.OK);
break;
break;

case INS_GET_PROVISION_STATUS_CMD:
processGetProvisionStatusCmd(apdu);
break;

default:
super.process(apdu);
Expand All @@ -133,13 +137,13 @@ public void process(APDU apdu) {
switch (apduIns) {
case INS_PROVISION_ATTEST_IDS_CMD:
processProvisionAttestIdsCmd(apdu);
provisionStatus |= PROVISION_STATUS_ATTEST_IDS;
kmDataStore.setProvisionStatus(PROVISION_STATUS_ATTEST_IDS);
sendError(apdu, KMError.OK);
break;

case INS_PROVISION_PRESHARED_SECRET_CMD:
processProvisionPreSharedSecretCmd(apdu);
provisionStatus |= PROVISION_STATUS_PRESHARED_SECRET;
kmDataStore.setProvisionStatus(PROVISION_STATUS_PRESHARED_SECRET);
sendError(apdu, KMError.OK);
break;

Expand All @@ -152,7 +156,6 @@ public void process(APDU apdu) {
break;

case INS_SET_BOOT_PARAMS_CMD:

processSetBootParamsCmd(apdu);
break;

Expand All @@ -165,7 +168,12 @@ public void process(APDU apdu) {
break;

default:
super.process(apdu);
// Allow other commands only if provision is completed.
if (isProvisioningComplete(apdu.getBuffer())) {
super.process(apdu);
} else {
ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
}
break;
}
} catch (KMException exception) {
Expand Down Expand Up @@ -199,6 +207,7 @@ private static void processProvisionDeviceUniqueKey(APDU apdu) {
short len = KMKeymasterApplet.encodeToApduBuffer(bcc, scratchPad, (short) 0,
MAX_COSE_BUF_SIZE);
kmDataStore.persistBootCertificateChain(scratchPad, (short) 0, len);
kmDataStore.setProvisionStatus(PROVISION_STATUS_DEVICE_UNIQUE_KEY);
sendError(apdu, KMError.OK);
}

Expand Down Expand Up @@ -245,6 +254,7 @@ private static void processProvisionAdditionalCertChain(APDU apdu) {
KMException.throwIt(KMError.STATUS_FAILED);
}
kmDataStore.persistAdditionalCertChain(buffer, bufferStartOffset, bufferLength);
kmDataStore.setProvisionStatus(PROVISION_STATUS_ADDITIONAL_CERT_CHAIN);
//reclaim memory
repository.reclaimMemory(bufferLength);
sendError(apdu, KMError.OK);
Expand Down Expand Up @@ -328,9 +338,11 @@ private static short buildErrorStatus(short err) {
}

private void processGetProvisionStatusCmd(APDU apdu) {
byte[] scratchpad = apdu.getBuffer();
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_16(provisionStatus));
KMArray.cast(resp).add((short) 1, KMInteger.uint_8(scratchpad[0]));
sendOutgoing(apdu, resp);
}

Expand Down Expand Up @@ -390,10 +402,27 @@ private void processSetBootParamsCmd(APDU apdu) {
super.reboot();
sendError(apdu, KMError.OK);
}

private boolean isProvisioningComplete(byte[] scratchPad) {
kmDataStore.getProvisionStatus(scratchPad, (short) 0);
if ((0 != (scratchPad[0] & PROVISION_STATUS_DEVICE_UNIQUE_KEY))
&& (0 != (scratchPad[0] & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN))
&& (0 != (scratchPad[0] & PROVISION_STATUS_PRESHARED_SECRET))) {
return true;
} else {
return false;
}
}

private void processLockProvisioningCmd(APDU apdu) {
((KMAndroidSEProvider) seProvider).setProvisionLocked(true);
sendError(apdu, KMError.OK);
byte[] scratchPad = apdu.getBuffer();
if (isProvisioningComplete(scratchPad)) {
kmDataStore.setProvisionLocked();
kmDataStore.setProvisionStatus(PROVISION_STATUS_PROVISIONING_LOCKED);
sendError(apdu, KMError.OK);
} else {
ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
}
}

@Override
Expand Down Expand Up @@ -454,15 +483,6 @@ public Element onSave() {
return element;
}

private short computePrimitveDataSize() {
// provisionStatus + keymasterState
return (short) 2;
}

private short computeObjectCount() {
return (short) 0;
}

private short validateApdu(APDU apdu) {
// Read the apdu header and buffer.
byte[] apduBuffer = apdu.getBuffer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ public class KMAndroidSEProvider implements KMSEProvider {
// Entropy
private RandomData rng;

private boolean isProvisionLocked;

private static KMAndroidSEProvider androidSEProvider = null;

public static KMAndroidSEProvider getInstance() {
Expand Down Expand Up @@ -1134,17 +1132,7 @@ public KMRkpMacKey createRkpMacKey(KMRkpMacKey rkpMacKey, byte[] keyData,
((KMHmacKey) rkpMacKey).setKey(keyData, offset, length);
return rkpMacKey;
}

public void setProvisionLocked(boolean locked) {
JCSystem.beginTransaction();
isProvisionLocked = locked;
JCSystem.commitTransaction();
}

public boolean isProvisionLocked() {
return isProvisionLocked;
}

@Override
public short messageDigest256(byte[] inBuff, short inOffset,
short inLength, byte[] outBuff, short outOffset) {
Expand Down Expand Up @@ -1173,21 +1161,7 @@ public boolean isPowerReset() {
}
return flag;
}

private byte mapPurpose(short purpose) {
switch (purpose) {
case KMType.ENCRYPT:
return Cipher.MODE_ENCRYPT;
case KMType.DECRYPT:
return Cipher.MODE_DECRYPT;
case KMType.SIGN:
return Signature.MODE_SIGN;
case KMType.VERIFY:
return Signature.MODE_VERIFY;
}
return -1;
}


@Override
public void onSave(Element element, byte interfaceType, Object object) {
element.write(interfaceType);
Expand Down Expand Up @@ -1237,7 +1211,7 @@ public Object onResore(Element element) {
case KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY:
return KMECDeviceUniqueKey.onRestore((KeyPair) element.readObject());
case KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY:
return KMHmacKey.onRestore((HMACKey) element.readObject());
return KMHmacKey.onRestore((HMACKey) element.readObject());
default:
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
Expand All @@ -1246,23 +1220,30 @@ public Object onResore(Element element) {

@Override
public short getBackupPrimitiveByteCount(byte interfaceType) {
short primitiveCount = 1; // interface type
switch (interfaceType) {
case KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY:
return KMHmacKey.getBackupPrimitiveByteCount();
primitiveCount += KMHmacKey.getBackupPrimitiveByteCount();
break;
case KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY:
return KMAESKey.getBackupPrimitiveByteCount();
primitiveCount += KMAESKey.getBackupPrimitiveByteCount();
break;
case KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY:
return KMHmacKey.getBackupPrimitiveByteCount();
primitiveCount += KMHmacKey.getBackupPrimitiveByteCount();
break;
case KMDataStoreConstants.INTERFACE_TYPE_ATTESTATION_KEY:
return KMECPrivateKey.getBackupPrimitiveByteCount();
primitiveCount += KMECPrivateKey.getBackupPrimitiveByteCount();
break;
case KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY:
return KMECDeviceUniqueKey.getBackupPrimitiveByteCount();
primitiveCount += KMECDeviceUniqueKey.getBackupPrimitiveByteCount();
break;
case KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY:
return KMHmacKey.getBackupPrimitiveByteCount();
primitiveCount += KMHmacKey.getBackupPrimitiveByteCount();
break;
default:
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
return 0;
return primitiveCount;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -715,10 +715,4 @@ KMPreSharedKey createPreSharedKey(KMPreSharedKey presharedKey, byte[] key, short
KMRkpMacKey createRkpMacKey(KMRkpMacKey createComputedHmacKey, byte[] keyData,
short offset, short length);

/**
* Returns true if provision is locked.
*/
public boolean isProvisionLocked();


}
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,6 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe
protected static short[] data;
protected static byte[] wrappingKey;

public static void install(byte[] bArray, short bOffset, byte bLength) {
new KMAndroidSEApplet().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
}

/**
* Registers this applet.
Expand Down Expand Up @@ -4308,7 +4305,7 @@ public static short validateCertChain(boolean validateEekRoot, byte expCertAlg,


public static short generateBcc(boolean testMode, byte[] scratchPad) {
if (!testMode && seProvider.isProvisionLocked()) {
if (!testMode && kmDataStore.isProvisionLocked()) {
KMException.throwIt(KMError.STATUS_FAILED);
}
KMDeviceUniqueKey deviceUniqueKey = kmDataStore.getDeviceUniqueKey(testMode);
Expand Down
37 changes: 30 additions & 7 deletions Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
public class KMKeymintDataStore implements KMUpgradable {

// Data table configuration
public static final short DATA_INDEX_SIZE = 17;
public static final short DATA_INDEX_SIZE = 19;
public static final short DATA_INDEX_ENTRY_SIZE = 4;
public static final short DATA_INDEX_ENTRY_LENGTH = 0;
public static final short DATA_INDEX_ENTRY_OFFSET = 2;
Expand All @@ -53,6 +53,8 @@ public class KMKeymintDataStore implements KMUpgradable {
public static final byte AUTH_TAG_1 = 8;
public static final byte BOOT_ENDED_FLAG = 15;
public static final byte EARLY_BOOT_ENDED_FLAG = 16;
private static final byte PROVISIONED_LOCKED = 17;
private static final byte PROVISIONED_STATUS = 18;

// Data Item sizes
public static final short HMAC_SEED_NONCE_SIZE = 32;
Expand Down Expand Up @@ -746,7 +748,33 @@ public void setBootPatchLevel(byte[] buffer, short start, short length) {
Util.arrayCopyNonAtomic(buffer, start, bootPatchLevel, (short) 0, (short) length);
}

public void setProvisionLocked() {
writeBoolean(PROVISIONED_LOCKED, true);
}

public boolean isProvisionLocked() {
try {
return readBoolean(PROVISIONED_LOCKED);
} catch (KMException e) {
if (KMException.reason() != KMError.INVALID_DATA)
KMException.throwIt(KMException.reason());
}
return false;
}

public void setProvisionStatus(byte provisionStatus) {
short offset = repository.alloc((short) 1);
byte[] buf = repository.getHeap();
getProvisionStatus(buf, offset);
buf[offset] |= provisionStatus;
writeDataEntry(PROVISIONED_STATUS, buf, offset, (short) 1);
}

public void getProvisionStatus(byte[] scratchpad, short offset) {
scratchpad[offset] = 0;
readDataEntry(PROVISIONED_STATUS, scratchpad, offset);
}

@Override
public void onSave(Element element) {
// Prmitives
Expand All @@ -755,7 +783,6 @@ public void onSave(Element element) {
element.write(bootState);
// Objects
element.write(dataTable);
// element.write(certificateData);
element.write(attIdBrand);
element.write(attIdDevice);
element.write(attIdProduct);
Expand Down Expand Up @@ -786,7 +813,6 @@ public void onRestore(Element element) {
bootState = element.readShort();
// Read Objects
dataTable = (byte[]) element.readObject();
// certificateData = (byte[]) element.readObject();
attIdBrand = (byte[]) element.readObject();
attIdDevice = (byte[]) element.readObject();
attIdProduct = (byte[]) element.readObject();
Expand All @@ -810,13 +836,10 @@ public void onRestore(Element element) {

@Override
public short getBackupPrimitiveByteCount() {
// Magic Number - 1 byte
// Package Version - 2 bytes
// dataIndex - 2 bytes
// deviceLocked - 1 byte
// deviceState = 2 bytes
// interface types - 4 bytes
return (short) (12 +
return (short) (5 +
seProvider.getBackupPrimitiveByteCount(KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY) +
seProvider.getBackupPrimitiveByteCount(
KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY) +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ private short createDeviceInfo(byte[] scratchpad) {
updateItem(deviceIds, out, DEVICE_INFO_VERSION, KMInteger.uint_8(DI_SCHEMA_VERSION));
updateItem(deviceIds, out, SECURITY_LEVEL,
KMTextString.instance(DI_SECURITY_LEVEL, (short) 0, (short) DI_SECURITY_LEVEL.length));
byte[] attestIdState = seProvider.isProvisionLocked() ? ATTEST_ID_LOCKED : ATTEST_ID_OPEN;
byte[] attestIdState = storeDataInst.isProvisionLocked() ? ATTEST_ID_LOCKED : ATTEST_ID_OPEN;
updateItem(deviceIds, out, ATTEST_ID_STATE,
KMTextString.instance(attestIdState, (short) 0, (short) attestIdState.length));
// Create device info map.
Expand Down
Loading