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 @@ -28,14 +28,15 @@
import javacard.framework.APDU;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.JCSystem;
import javacard.framework.Util;
import javacard.security.CryptoException;

public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeListener {
// Magic number version
private static final byte KM_MAGIC_NUMBER = (byte) 0x82;
// MSB byte is for Major version and LSB byte is for Minor version.
private static final short KM_APPLET_PACKAGE_VERSION = 0x0300;
public static final short KM_APPLET_PACKAGE_VERSION = 0x0300;

private static final byte KM_BEGIN_STATE = 0x00;
private static final byte ILLEGAL_STATE = KM_BEGIN_STATE + 1;
Expand All @@ -58,6 +59,7 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeLis
INS_KEYMINT_PROVIDER_APDU_START + 13;
private static final byte INS_PROVISION_RKP_ADDITIONAL_CERT_CHAIN_CMD =
INS_KEYMINT_PROVIDER_APDU_START + 14;
private static final byte INS_PROVISION_SECURE_BOOT_MODE_CMD = INS_KEYMINT_PROVIDER_APDU_START + 15;

private static final byte INS_KEYMINT_PROVIDER_APDU_END = 0x1F;
public static final byte BOOT_KEY_MAX_SIZE = 32;
Expand Down Expand Up @@ -154,6 +156,10 @@ public void process(APDU apdu) {
case INS_OEM_UNLOCK_PROVISIONING_CMD:
processOEMUnlockProvisionCmd(apdu);
break;

case INS_PROVISION_SECURE_BOOT_MODE_CMD:
processSecureBootCmd(apdu);
break;

default:
super.process(apdu);
Expand All @@ -180,6 +186,7 @@ private boolean isCommandAllowed(short apduIns) {
switch(apduIns) {
case INS_PROVISION_ATTEST_IDS_CMD:
case INS_PROVISION_PRESHARED_SECRET_CMD:
case INS_PROVISION_SECURE_BOOT_MODE_CMD:
case INS_PROVISION_OEM_ROOT_PUBLIC_KEY_CMD:
if(kmDataStore.isProvisionLocked()) {
result = false;
Expand Down Expand Up @@ -245,6 +252,22 @@ private boolean isSeFactoryProvisioningComplete() {
return false;
}

private void processSecureBootCmd(APDU apdu) {
short argsProto = KMArray.instance((short) 1);
KMArray.cast(argsProto).add((short) 0, KMInteger.exp());
short args = receiveIncoming(apdu, argsProto);
short val = KMInteger.cast(KMArray.cast(args).get((short) 0)).getShort();
if (val != 1 && val != 0) {
KMException.throwIt(KMError.INVALID_ARGUMENT);
}
// Store secure boot mode value.
JCSystem.beginTransaction();
kmDataStore.secureBootMode = (byte) val;
JCSystem.commitTransaction();
kmDataStore.setProvisionStatus(PROVISION_STATUS_SECURE_BOOT_MODE);
sendResponse(apdu, KMError.OK);
}

private void processOEMUnlockProvisionCmd(APDU apdu) {
authenticateOEM(OEM_UNLOCK_PROVISION_VERIFICATION_LABEL, apdu);
kmDataStore.unlockProvision();
Expand Down Expand Up @@ -505,7 +528,8 @@ private void processGetProvisionStatusCmd(APDU apdu) {
private boolean isProvisioningComplete() {
short pStatus = kmDataStore.getProvisionStatus();
short pCompleteStatus = PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR | PROVISION_STATUS_ADDITIONAL_CERT_CHAIN |
PROVISION_STATUS_PRESHARED_SECRET | PROVISION_STATUS_ATTEST_IDS | PROVISION_STATUS_OEM_PUBLIC_KEY;
PROVISION_STATUS_PRESHARED_SECRET | PROVISION_STATUS_ATTEST_IDS | PROVISION_STATUS_OEM_PUBLIC_KEY |
PROVISION_STATUS_SECURE_BOOT_MODE;
if (kmDataStore.isProvisionLocked() || (pCompleteStatus == (pStatus & pCompleteStatus))) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import javacard.framework.APDU;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.JCSystem;
import javacard.framework.Util;
import javacard.security.CryptoException;

Expand All @@ -47,6 +48,7 @@ public class KMJCardSimApplet extends KMKeymasterApplet {
INS_KEYMINT_PROVIDER_APDU_START + 13;
private static final byte INS_PROVISION_RKP_ADDITIONAL_CERT_CHAIN_CMD =
INS_KEYMINT_PROVIDER_APDU_START + 14;
private static final byte INS_PROVISION_SECURE_BOOT_MODE_CMD = INS_KEYMINT_PROVIDER_APDU_START + 15;

private static final byte INS_KEYMINT_PROVIDER_APDU_END = 0x1F;
public static final byte BOOT_KEY_MAX_SIZE = 32;
Expand Down Expand Up @@ -146,6 +148,10 @@ public void process(APDU apdu) {
case INS_OEM_UNLOCK_PROVISIONING_CMD:
processOEMUnlockProvisionCmd(apdu);
break;

case INS_PROVISION_SECURE_BOOT_MODE_CMD:
processSecureBootCmd(apdu);
break;

default:
super.process(apdu);
Expand All @@ -172,6 +178,7 @@ private boolean isCommandAllowed(short apduIns) {
switch(apduIns) {
case INS_PROVISION_ATTEST_IDS_CMD:
case INS_PROVISION_PRESHARED_SECRET_CMD:
case INS_PROVISION_SECURE_BOOT_MODE_CMD:
case INS_PROVISION_OEM_ROOT_PUBLIC_KEY_CMD:
if(kmDataStore.isProvisionLocked()) {
result = false;
Expand Down Expand Up @@ -238,6 +245,22 @@ private boolean isSeFactoryProvisioningComplete() {
return false;
}

private void processSecureBootCmd(APDU apdu) {
short argsProto = KMArray.instance((short) 1);
KMArray.cast(argsProto).add((short) 0, KMInteger.exp());
short args = receiveIncoming(apdu, argsProto);
short val = KMInteger.cast(KMArray.cast(args).get((short) 0)).getShort();
if (val != 1 && val != 0) {
KMException.throwIt(KMError.INVALID_ARGUMENT);
}
// Store secure boot mode value.
JCSystem.beginTransaction();
kmDataStore.secureBootMode = (byte) val;
JCSystem.commitTransaction();
kmDataStore.setProvisionStatus(PROVISION_STATUS_SECURE_BOOT_MODE);
sendResponse(apdu, KMError.OK);
}

private void processOEMUnlockProvisionCmd(APDU apdu) {
authenticateOEM(OEM_UNLOCK_PROVISION_VERIFICATION_LABEL, apdu);
kmDataStore.unlockProvision();
Expand Down Expand Up @@ -561,7 +584,8 @@ private void processSetBootParamsCmd(APDU apdu) {
private boolean isProvisioningComplete() {
short pStatus = kmDataStore.getProvisionStatus();
short pCompleteStatus = PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR | PROVISION_STATUS_ADDITIONAL_CERT_CHAIN |
PROVISION_STATUS_PRESHARED_SECRET | PROVISION_STATUS_ATTEST_IDS | PROVISION_STATUS_OEM_PUBLIC_KEY;
PROVISION_STATUS_PRESHARED_SECRET | PROVISION_STATUS_ATTEST_IDS | PROVISION_STATUS_OEM_PUBLIC_KEY |
PROVISION_STATUS_SECURE_BOOT_MODE;
if (kmDataStore.isProvisionLocked() || (pCompleteStatus == (pStatus & pCompleteStatus))) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1510,6 +1510,8 @@ public void testVerifyOemUnLockAfterOemLockSuccess() {
KMProvision.provisionSeLocked(simulator, decoder)));
Assert.assertEquals(KMError.OK, KMTestUtils.decodeError(decoder,
KMProvision.provisionSharedSecret(simulator, encoder, decoder)));
Assert.assertEquals(KMError.OK, KMTestUtils.decodeError(decoder,
KMProvision.provisionSecureBootMode(simulator, encoder, decoder)));
Assert.assertEquals(KMError.OK, KMTestUtils.decodeError(decoder,
KMProvision.provisionAttestIds(simulator, encoder, decoder)));
Assert.assertEquals(KMError.OK, KMTestUtils.decodeError(decoder,
Expand Down Expand Up @@ -1611,6 +1613,8 @@ public void testVerifyOemProvisionAfterOemLockFailure() {
KMProvision.provisionSeLocked(simulator, decoder)));
Assert.assertEquals(KMError.OK, KMTestUtils.decodeError(decoder,
KMProvision.provisionSharedSecret(simulator, encoder, decoder)));
Assert.assertEquals(KMError.OK, KMTestUtils.decodeError(decoder,
KMProvision.provisionSecureBootMode(simulator, encoder, decoder)));
Assert.assertEquals(KMError.OK, KMTestUtils.decodeError(decoder,
KMProvision.provisionAttestIds(simulator, encoder, decoder)));
Assert.assertEquals(KMError.OK, KMTestUtils.decodeError(decoder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,22 @@ public class KMProvision {

// Provision Instructions
private static final byte INS_KEYMINT_PROVIDER_APDU_START = 0x00;
private static final byte INS_PROVISION_ATTEST_IDS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 1;
private static final byte INS_PROVISION_ATTEST_IDS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 3;
private static final byte INS_PROVISION_PRESHARED_SECRET_CMD =
INS_KEYMINT_PROVIDER_APDU_START + 2;
private static final byte INS_OEM_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;
INS_KEYMINT_PROVIDER_APDU_START + 4;
private static final byte INS_SET_BOOT_PARAMS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 5; // Unused
private static final byte INS_OEM_LOCK_PROVISIONING_CMD = INS_KEYMINT_PROVIDER_APDU_START + 6;
private static final byte INS_GET_PROVISION_STATUS_CMD = INS_KEYMINT_PROVIDER_APDU_START + 7;
//0x08 was reserved for INS_INIT_STRONGBOX_CMD
//0x09 was reserved for INS_SET_BOOT_ENDED_CMD earlier. it is unused now.
private static final byte INS_SE_FACTORY_PROVISIONING_LOCK_CMD = INS_KEYMINT_PROVIDER_APDU_START + 10;
private static final byte INS_PROVISION_OEM_ROOT_PUBLIC_KEY_CMD = INS_KEYMINT_PROVIDER_APDU_START + 11;
private static final byte INS_OEM_UNLOCK_PROVISIONING_CMD = INS_KEYMINT_PROVIDER_APDU_START + 12;
private static final byte INS_PROVISION_RKP_DEVICE_UNIQUE_KEYPAIR_CMD =
INS_KEYMINT_PROVIDER_APDU_START + 6;
INS_KEYMINT_PROVIDER_APDU_START + 13;
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; //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;
INS_KEYMINT_PROVIDER_APDU_START + 14;
private static final byte INS_PROVISION_SECURE_BOOT_MODE_CMD = INS_KEYMINT_PROVIDER_APDU_START + 15;
// Top 32 commands are reserved for provisioning.
private static final byte INS_END_KM_PROVISION_CMD = 0x20;

Expand Down Expand Up @@ -303,6 +302,17 @@ public static ResponseAPDU provisionOEMRootPublicKey(CardSimulator simulator, KM
return simulator.transmitCommand(apdu);
}

public static ResponseAPDU provisionSecureBootMode(CardSimulator simulator, KMEncoder encoder,
KMDecoder decoder) {
short arrPtr = KMArray.instance((short) 1);
KMArray.cast(arrPtr).add((short) 0, KMInteger.uint_8((byte) 0));

CommandAPDU apdu = KMTestUtils.encodeApdu(encoder, (byte) INS_PROVISION_SECURE_BOOT_MODE_CMD,
arrPtr);
// print(commandAPDU.getBytes());
return simulator.transmitCommand(apdu);
}

public static ResponseAPDU provisionSharedSecret(CardSimulator simulator, KMEncoder encoder,
KMDecoder decoder) {
byte[] sharedKeySecret = {
Expand Down Expand Up @@ -471,6 +481,8 @@ public static void provisionCmd(CardSimulator simulator,
provisionSeLocked(simulator, decoder)));
Assert.assertEquals(KMError.OK, KMTestUtils.decodeError(decoder,
provisionSharedSecret(simulator, encoder, decoder)));
Assert.assertEquals(KMError.OK, KMTestUtils.decodeError(decoder,
provisionSecureBootMode(simulator, encoder, decoder)));
Assert.assertEquals(KMError.OK, KMTestUtils.decodeError(decoder,
provisionAttestIds(simulator, encoder, decoder)));
Assert.assertEquals(KMError.OK, KMTestUtils.decodeError(decoder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe
private static final byte INS_END_KM_CMD = 0x7F;
// Instruction values from 0xCD to 0xFF are completely reserved for Vendors to use and
// will never be used by the base line code in future.
private static final byte INS_KM_VENDOR_START_CMD = 0xCD;
private static final byte INS_KM_VENDOR_END_CMD = 0xFF;
private static final byte INS_KM_VENDOR_START_CMD = (byte) 0xCD;
private static final byte INS_KM_VENDOR_END_CMD = (byte) 0xFF;

// Data Dictionary items
public static final byte DATA_ARRAY_SIZE = 40;
Expand Down Expand Up @@ -289,6 +289,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe
public static final short PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = 0x0080;
public static final short PROVISION_STATUS_SE_LOCKED = 0x0100;
public static final short PROVISION_STATUS_OEM_PUBLIC_KEY = 0x0200;
public static final short PROVISION_STATUS_SECURE_BOOT_MODE = 0x0400;

protected static RemotelyProvisionedComponentDevice rkp;
protected static KMEncoder encoder;
Expand Down
30 changes: 26 additions & 4 deletions Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public class KMKeymintDataStore implements KMUpgradable {

// Data table configuration
public static final short KM_APPLET_PACKAGE_VERSION_1 = 0x0100;
public static final short KM_APPLET_PACKAGE_VERSION_2 = 0x0200;
public static final short KM_APPLET_PACKAGE_VERSION_3 = 0x0300;
public static final short OLD_DATA_INDEX_SIZE = 19;
public static final short DATA_INDEX_SIZE = 17;
public static final short DATA_INDEX_ENTRY_SIZE = 4;
Expand Down Expand Up @@ -106,6 +108,8 @@ public class KMKeymintDataStore implements KMUpgradable {
// Challenge for Root of trust
private byte[] challenge;

// Secure Boot Mode
public byte secureBootMode;

private short dataIndex;
private byte[] dataTable;
Expand Down Expand Up @@ -886,6 +890,7 @@ public byte[] getOEMRootPublicKey() {
public void onSave(Element element) {
// Prmitives
element.write(provisionStatus);
element.write(secureBootMode);
// Objects
element.write(attIdBrand);
element.write(attIdDevice);
Expand All @@ -912,8 +917,17 @@ public void onRestore(Element element, short oldVersion, short currentVersion) {
// 1.0 to 3.0 Upgrade happens here.
handlePreviousVersionUpgrade(element);
return;
} else if (oldVersion == KM_APPLET_PACKAGE_VERSION_2) {
handleUpgrade(element, oldVersion);
JCSystem.beginTransaction();
// While upgrading Secure Boot Mode flag from 2.0 to 3.0, implementations
// have to update the secureBootMode with the correct input.
secureBootMode = 0;
provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SECURE_BOOT_MODE;
JCSystem.commitTransaction();
return;
}
handleUpgrade(element);
handleUpgrade(element, oldVersion);
}

private void handlePreviousVersionUpgrade(Element element) {
Expand Down Expand Up @@ -950,9 +964,12 @@ private void handlePreviousVersionUpgrade(Element element) {
handleProvisionStatusUpgrade(oldDataTable, oldDataIndex);
}

private void handleUpgrade(Element element) {
private void handleUpgrade(Element element, short oldVersion) {
// Read Primitives
provisionStatus = element.readShort();
if (oldVersion >= KM_APPLET_PACKAGE_VERSION_3) {
secureBootMode = element.readByte();
}
// Read Objects
attIdBrand = (byte[]) element.readObject();
attIdDevice = (byte[]) element.readObject();
Expand Down Expand Up @@ -984,9 +1001,13 @@ void handleProvisionStatusUpgrade(byte[] dataTable, short dataTableIndex){
short pStatus = (short)( data[dInex] & 0x00ff);
if( KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED
== (pStatus & KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED)) {
pStatus |= KMKeymasterApplet.PROVISION_STATUS_SE_LOCKED;
pStatus |= KMKeymasterApplet.PROVISION_STATUS_SE_LOCKED
| KMKeymasterApplet.PROVISION_STATUS_SECURE_BOOT_MODE;
}
JCSystem.beginTransaction();
// While upgrading Secure Boot Mode flag from 1.0 to 3.0, implementations
// have to update the secureBootMode with the correct input.
secureBootMode = 0;
provisionStatus = pStatus;
JCSystem.commitTransaction();
repository.reclaimMemory((short)2);
Expand All @@ -995,7 +1016,8 @@ void handleProvisionStatusUpgrade(byte[] dataTable, short dataTableIndex){
@Override
public short getBackupPrimitiveByteCount() {
// provisionStatus - 2 bytes
return (short) (2 +
// secureBootMode - 1 byte
return (short) (3 +
seProvider.getBackupPrimitiveByteCount(KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY) +
seProvider.getBackupPrimitiveByteCount(KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY) +
seProvider.getBackupPrimitiveByteCount( KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY_PAIR) +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ private short createDeviceInfo(byte[] scratchpad) {
updateItem(rkpTmpVariables, metaOffset, DEVICE_INFO_VERSION, KMInteger.uint_8(DI_SCHEMA_VERSION));
updateItem(rkpTmpVariables, metaOffset, SECURITY_LEVEL,
KMTextString.instance(DI_SECURITY_LEVEL, (short) 0, (short) DI_SECURITY_LEVEL.length));
updateItem(rkpTmpVariables, metaOffset, FUSED, KMInteger.uint_8((byte) 0));
updateItem(rkpTmpVariables, metaOffset, FUSED, KMInteger.uint_8((byte) storeDataInst.secureBootMode));
// Create device info map.
short map = KMMap.instance(rkpTmpVariables[1]);
short mapIndex = 0;
Expand Down
2 changes: 2 additions & 0 deletions ProvisioningTool/include/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ constexpr char kLockProvision[] = "lock_provision";
constexpr char kOEMRootKey[] = "oem_root_key";
constexpr char kSeFactoryProvisionLock[] = "se_factory_lock";
constexpr char kUnLockProvision[] = "unlock_provision";
constexpr char kSecureBootMode[] = "secure_boot_mode";

// Instruction constatnts
constexpr int kAttestationIdsCmd = INS_BEGIN_KM_CMD + 3;
Expand All @@ -111,6 +112,7 @@ constexpr int kOemRootPublicKeyCmd = INS_BEGIN_KM_CMD + 11;
constexpr int kOemUnLockProvisionCmd = INS_BEGIN_KM_CMD + 12;
constexpr int kDeviceUniqueKeyCmd = INS_BEGIN_KM_CMD + 13;
constexpr int kAdditionalCertChainCmd = INS_BEGIN_KM_CMD + 14;
constexpr int kSecureBootModeCmd = INS_BEGIN_KM_CMD + 15;



3 changes: 2 additions & 1 deletion ProvisioningTool/sample_json_keymint_cf.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@
"test_resources/intermediate_key.der"
]
},
"oem_root_key": "test_resources/oem_root_key.der"
"oem_root_key": "test_resources/oem_root_key.der",
"secure_boot_mode": 0
}
4 changes: 3 additions & 1 deletion ProvisioningTool/sample_json_keymint_gf.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@
"test_resources/ca_key.der",
"test_resources/intermediate_key.der"
]
}
},
"oem_root_key": "test_resources/oem_root_key.der",
"secure_boot_mode": 0
}
Loading