From a2f438726de602c07f187d7cf2587f5ae4c6342d Mon Sep 17 00:00:00 2001 From: "avinash.hedage" Date: Mon, 20 Jun 2022 06:19:22 +0000 Subject: [PATCH 1/2] updated applet upgrade --- .../javacard/keymaster/KMAndroidSEApplet.java | 40 +--- .../keymaster/KMKeymintDataStore.java | 205 +++++++++--------- 2 files changed, 113 insertions(+), 132 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index 01fbcf3a..70d65026 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -35,7 +35,7 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeLis // 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 = 0x0200; + private static final short KM_APPLET_PACKAGE_VERSION = 0x0102; private static final byte KM_BEGIN_STATE = 0x00; private static final byte ILLEGAL_STATE = KM_BEGIN_STATE + 1; @@ -223,35 +223,26 @@ private boolean isCommandAllowed(short apduIns) { } private boolean isSeFactoryProvisioningLocked() { - short dInex = repository.allocReclaimableMemory((short)2); - byte data[] = repository.getHeap(); - kmDataStore.getProvisionStatus(data, dInex); - short pStatus = Util.getShort(data, dInex); + short pStatus = kmDataStore.getProvisionStatus(); boolean result = false; if ((0 != (pStatus & PROVISION_STATUS_SE_LOCKED))) { result = true; } - repository.reclaimMemory((short)2); return result; } private boolean isSeFactoryProvisioningComplete() { - short dIndex = repository.allocReclaimableMemory((short)2); - byte data[] = repository.getHeap(); - kmDataStore.getProvisionStatus(data, dIndex); - short pStatus = Util.getShort(data, dIndex); + short pStatus = kmDataStore.getProvisionStatus(); boolean result = false; if ((0 != (pStatus & PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR)) && (0 != ((pStatus & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN)))) { result = true; } - repository.reclaimMemory((short)2); return result; } private void processOEMUnlockProvisionCmd(APDU apdu) { authenticateOEM(OEM_UNLOCK_PROVISION_VERIFICATION_LABEL, apdu); - kmDataStore.setProvisionLock(false); kmDataStore.unlockProvision(PROVISION_STATUS_PROVISIONING_LOCKED); sendResponse(apdu, KMError.OK); } @@ -259,7 +250,6 @@ private void processOEMUnlockProvisionCmd(APDU apdu) { private void processOEMLockProvisionCmd(APDU apdu) { authenticateOEM(OEM_LOCK_PROVISION_VERIFICATION_LABEL, apdu); // Enable the lock bit in provision status. - kmDataStore.setProvisionLock(true); kmDataStore.setProvisionStatus(PROVISION_STATUS_PROVISIONING_LOCKED); sendResponse(apdu, KMError.OK); } @@ -500,7 +490,8 @@ private static short buildErrorStatus(short err) { private void processGetProvisionStatusCmd(APDU apdu) { byte[] scratchpad = apdu.getBuffer(); - kmDataStore.getProvisionStatus(scratchpad, (short) 0); + short pStatus = kmDataStore.getProvisionStatus(); + Util.setShort(scratchpad, (short)0, pStatus); short resp = KMArray.instance((short) 2); KMArray.cast(resp).add((short) 0, buildErrorStatus(KMError.OK)); KMArray.cast(resp).add((short) 1, KMInteger.instance(scratchpad, (short)0, (short)2)); @@ -571,10 +562,7 @@ private void processSetBootParamsCmd(APDU apdu) { } private boolean isProvisioningComplete() { - short dInex = repository.allocReclaimableMemory((short)2); - byte data[] = repository.getHeap(); - kmDataStore.getProvisionStatus(data, dInex); - short pStatus = Util.getShort(data, dInex); + short pStatus = kmDataStore.getProvisionStatus(); boolean result = false; if (kmDataStore.isProvisionLocked() || ((0 != (pStatus & PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR)) && (0 != (pStatus & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN)) @@ -582,7 +570,6 @@ private boolean isProvisioningComplete() { && (0 != (pStatus & PROVISION_STATUS_ATTEST_IDS)))) { result = true; } - repository.reclaimMemory((short)2); return result; } @@ -596,20 +583,9 @@ public void onConsolidate() { private boolean isUpgradeAllowed(short oldVersion) { boolean upgradeAllowed = false; - short oldMajorVersion = (short) ((oldVersion >> 8) & 0x00FF); - short oldMinorVersion = (short) (oldVersion & 0x00FF); - short currentMajorVersion = (short) (KM_APPLET_PACKAGE_VERSION >> 8 & 0x00FF); - short currentMinorVersion = (short) (KM_APPLET_PACKAGE_VERSION & 0x00FF); // Downgrade of the Applet is not allowed. - // Upgrade is not allowed to a next version which is not immediate. - if ((short) (currentMajorVersion - oldMajorVersion) == 1) { - if (currentMinorVersion == 0) { - upgradeAllowed = true; - } - } else if ((short) (currentMajorVersion - oldMajorVersion) == 0) { - if (currentMinorVersion >= oldMinorVersion) { - upgradeAllowed = true; - } + if (KM_APPLET_PACKAGE_VERSION >= oldVersion) { + upgradeAllowed = true; } return upgradeAllowed; } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java b/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java index a68cbbbd..5077ff3c 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java @@ -32,7 +32,8 @@ public class KMKeymintDataStore implements KMUpgradable { // Data table configuration - public static final short DATA_INDEX_SIZE = 19; + 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; public static final short DATA_INDEX_ENTRY_LENGTH = 0; public static final short DATA_INDEX_ENTRY_OFFSET = 2; @@ -40,22 +41,23 @@ public class KMKeymintDataStore implements KMUpgradable { //TODO reduced data table size from 2048 to 300. public static final short DATA_MEM_SIZE = 300; + // Old Data table offsets + private static final byte OLD_PROVISIONED_LOCKED = 17; + private static final byte OLD_PROVISIONED_STATUS = 18; + // Data table offsets - public static final byte COMPUTED_HMAC_KEY = 0; - public static final byte HMAC_NONCE = 1; - public static final byte BOOT_OS_VERSION = 2; - public static final byte BOOT_OS_PATCH_LEVEL = 3; - public static final byte VENDOR_PATCH_LEVEL = 4; - public static final byte DEVICE_LOCKED_TIME = 5; - public static final byte DEVICE_LOCKED = 6; - public static final byte DEVICE_LOCKED_PASSWORD_ONLY = 7; + public static final byte HMAC_NONCE = 0; + public static final byte BOOT_OS_VERSION = 1; + public static final byte BOOT_OS_PATCH_LEVEL = 2; + public static final byte VENDOR_PATCH_LEVEL = 3; + public static final byte DEVICE_LOCKED_TIME = 4; + public static final byte DEVICE_LOCKED = 5; + public static final byte DEVICE_LOCKED_PASSWORD_ONLY = 6; // Total 8 auth tags, so the next offset is AUTH_TAG_1 + 8 - public static final byte AUTH_TAG_1 = 8; + public static final byte AUTH_TAG_1 = 7; public static final byte DEVICE_STATUS_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; + public static final byte EARLY_BOOT_ENDED_FLAG = 16; // Data Item sizes public static final short HMAC_SEED_NONCE_SIZE = 32; @@ -104,8 +106,8 @@ public class KMKeymintDataStore implements KMUpgradable { private boolean deviceBootLocked; private short bootState; - private byte[] dataTable; private short dataIndex; + private byte[] dataTable; private KMSEProvider seProvider; private KMRepository repository; private byte[] additionalCertChain; @@ -117,29 +119,28 @@ public class KMKeymintDataStore implements KMUpgradable { private KMComputedHmacKey computedHmacKey; private KMRkpMacKey rkpMacKey; private byte[] oemRootPublicKey; + private short provisionStatus; public KMKeymintDataStore(KMSEProvider provider, KMRepository repo) { seProvider = provider; repository = repo; boolean isUpgrading = provider.isUpgrading(); - initDataTable(isUpgrading); + initDataTable(); //Initialize the device locked status if (!isUpgrading) { additionalCertChain = new byte[ADDITIONAL_CERT_CHAIN_MAX_SIZE]; bcc = new byte[BCC_MAX_SIZE]; oemRootPublicKey = new byte[65]; - setDeviceLock(false); - setDeviceLockPasswordOnly(false); } + setDeviceLockPasswordOnly(false); + setDeviceLock(false); } - private void initDataTable(boolean isUpgrading) { - if (!isUpgrading) { - if (dataTable == null) { - dataTable = new byte[DATA_MEM_SIZE]; - dataIndex = (short) (DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE); - } - } + private void initDataTable() { + if (dataTable == null) { + dataTable = new byte[DATA_MEM_SIZE]; + dataIndex = (short) (DATA_INDEX_SIZE * DATA_INDEX_ENTRY_SIZE); + } } private short dataAlloc(short length) { @@ -196,6 +197,20 @@ private short readDataEntry(short id, byte[] buf, short offset) { } return len; } + + private short readDataEntry(byte[] dataTable, short id, byte[] buf, short offset) { + id = (short) (id * DATA_INDEX_ENTRY_SIZE); + short len = Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_LENGTH)); + if (len != 0) { + Util.arrayCopyNonAtomic( + dataTable, + Util.getShort(dataTable, (short) (id + DATA_INDEX_ENTRY_OFFSET)), + buf, + offset, + len); + } + return len; + } private short dataLength(short id) { id = (short) (id * DATA_INDEX_ENTRY_SIZE); @@ -741,7 +756,7 @@ public short getVerifiedBootHash(byte[] buffer, short start) { } public short getBootKey(byte[] buffer, short start) { - if (verifiedHash == null) { + if (bootKey == null) { KMException.throwIt(KMError.INVALID_DATA); } Util.arrayCopyNonAtomic(bootKey, (short) 0, buffer, start, (short) bootKey.length); @@ -802,43 +817,24 @@ public void setBootPatchLevel(byte[] buffer, short start, short length) { } Util.arrayCopy(buffer, start, bootPatchLevel, (short) 0, (short) length); } - - public void setProvisionLock(boolean lockValue) { - writeBoolean(PROVISIONED_LOCKED, lockValue); - } public boolean isProvisionLocked() { - try { - return readBoolean(PROVISIONED_LOCKED); - } catch (KMException e) { - if (KMException.reason() != KMError.INVALID_DATA) - KMException.throwIt(KMException.reason()); + if (0 != (provisionStatus & KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED)) { + return true; } return false; } - public void setProvisionStatus(short provisionStatus) { - short offset = repository.alloc((short) 2); - byte[] buf = repository.getHeap(); - getProvisionStatus(buf, offset); - provisionStatus |= Util.getShort(buf, offset); - Util.setShort(buf, offset, provisionStatus); - writeDataEntry(PROVISIONED_STATUS, buf, offset, (short) 2); + public void setProvisionStatus(short pStatus) { + provisionStatus |= pStatus; } - public void getProvisionStatus(byte[] scratchpad, short offset) { - Util.setShort(scratchpad, offset, (short)0); - readDataEntry(PROVISIONED_STATUS, scratchpad, offset); + public short getProvisionStatus() { + return provisionStatus; } - + public void unlockProvision(short unlockOffset) { - short offset = repository.alloc((short) 2); - byte[] buf = repository.getHeap(); - getProvisionStatus(buf, offset); - short temp = Util.getShort(buf, offset); - temp &= ~unlockOffset; - Util.setShort(buf, offset, temp); - writeDataEntry(PROVISIONED_STATUS, buf, offset, (short) 2); + provisionStatus &= ~unlockOffset; } public void persistOEMRootPublicKey(byte[] inBuff, short inOffset, short inLength) { @@ -861,11 +857,8 @@ public byte[] getOEMRootPublicKey() { @Override public void onSave(Element element) { // Prmitives - element.write(dataIndex); - element.write(deviceBootLocked); - element.write(bootState); + element.write(provisionStatus); // Objects - element.write(dataTable); element.write(attIdBrand); element.write(attIdDevice); element.write(attIdProduct); @@ -874,17 +867,12 @@ public void onSave(Element element) { element.write(attIdMeId); element.write(attIdManufacturer); element.write(attIdModel); - element.write(verifiedHash); - element.write(bootKey); - element.write(bootPatchLevel); element.write(additionalCertChain); element.write(bcc); element.write(oemRootPublicKey); // Key Objects seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY, masterKey); - seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY, - computedHmacKey); seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY, preSharedKey); seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY_PAIR, deviceUniqueKeyPair); seProvider.onSave(element, KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY, rkpMacKey); @@ -892,12 +880,51 @@ public void onSave(Element element) { @Override public void onRestore(Element element, short oldVersion, short currentVersion) { - // Read Primitives - dataIndex = element.readShort(); - deviceBootLocked = element.readBoolean(); - bootState = element.readShort(); + if (oldVersion != currentVersion) { + handlePrevisionVersionUpgrade(element); + } else { + handleCurrentVersionUpgrade(element); + } + } + + private void handlePrevisionVersionUpgrade(Element element) { + // Read Primitives + //restore old data table index + short oldDataIndex = element.readShort(); + element.readBoolean(); // pop deviceBootLocked + element.readShort(); // pop bootState + + // Read Objects + //restore old data table + byte[] oldDataTable = (byte[]) element.readObject(); + + attIdBrand = (byte[]) element.readObject(); + attIdDevice = (byte[]) element.readObject(); + attIdProduct = (byte[]) element.readObject(); + attIdSerial = (byte[]) element.readObject(); + attIdImei = (byte[]) element.readObject(); + attIdMeId = (byte[]) element.readObject(); + attIdManufacturer = (byte[]) element.readObject(); + attIdModel = (byte[]) element.readObject(); + element.readObject(); // pop verifiedHash + element.readObject(); //pop bootKey + element.readObject(); // pop bootPatchLevel + additionalCertChain = (byte[]) element.readObject(); // + bcc = (byte[]) element.readObject(); + + // Read Key Objects + masterKey = (KMMasterKey) seProvider.onRestore(element); + seProvider.onRestore(element); // pop computedHmacKey + preSharedKey = (KMPreSharedKey) seProvider.onRestore(element); + deviceUniqueKeyPair = (KMDeviceUniqueKeyPair) seProvider.onRestore(element); + rkpMacKey = (KMRkpMacKey) seProvider.onRestore(element); + handleProvisionStatusUpgrade(oldDataTable, oldDataIndex); + } + + private void handleCurrentVersionUpgrade(Element element) { + // Read Primitives + provisionStatus = element.readShort(); // Read Objects - dataTable = (byte[]) element.readObject(); attIdBrand = (byte[]) element.readObject(); attIdDevice = (byte[]) element.readObject(); attIdProduct = (byte[]) element.readObject(); @@ -906,58 +933,38 @@ public void onRestore(Element element, short oldVersion, short currentVersion) { attIdMeId = (byte[]) element.readObject(); attIdManufacturer = (byte[]) element.readObject(); attIdModel = (byte[]) element.readObject(); - verifiedHash = (byte[]) element.readObject(); - bootKey = (byte[]) element.readObject(); - bootPatchLevel = (byte[]) element.readObject(); additionalCertChain = (byte[]) element.readObject(); bcc = (byte[]) element.readObject(); - //oemRootPublicKey has to be provisioned - if (oldVersion >= 0x0200) { - oemRootPublicKey = (byte[]) element.readObject(); - } + oemRootPublicKey = (byte[]) element.readObject(); // Read Key Objects masterKey = (KMMasterKey) seProvider.onRestore(element); - computedHmacKey = (KMComputedHmacKey) seProvider.onRestore(element); preSharedKey = (KMPreSharedKey) seProvider.onRestore(element); deviceUniqueKeyPair = (KMDeviceUniqueKeyPair) seProvider.onRestore(element); rkpMacKey = (KMRkpMacKey) seProvider.onRestore(element); - handleDataUpgrade(oldVersion, currentVersion); } - void handleDataUpgrade(short oldVersion, short currentVersion) { - if(oldVersion != currentVersion) { - handleProvisionStatusUpgrade(); - } + public void getProvisionStatus(byte[] dataTable, byte[] scratchpad, short offset) { + Util.setShort(scratchpad, offset, (short)0); + readDataEntry(dataTable, OLD_PROVISIONED_STATUS, scratchpad, offset); } - void handleProvisionStatusUpgrade(){ + void handleProvisionStatusUpgrade(byte[] dataTable, short dataTableIndex){ short dInex = repository.allocReclaimableMemory((short)2); byte data[] = repository.getHeap(); - getProvisionStatus(data, dInex); - short newStatus = (short)( data[dInex] & 0x00ff); + getProvisionStatus(dataTable, data, dInex); + provisionStatus = (short)( data[dInex] & 0x00ff); if( KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED - == (newStatus & KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED)) { - newStatus |= KMKeymasterApplet.PROVISION_STATUS_SE_LOCKED; + == (provisionStatus & KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED)) { + provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SE_LOCKED; } - Util.setShort(data, dInex, newStatus); - short pStatusOff = (short) (PROVISIONED_STATUS * DATA_INDEX_ENTRY_SIZE); - JCSystem.beginTransaction(); - Util.setShort(dataTable, (short) (pStatusOff + DATA_INDEX_ENTRY_OFFSET), (short)0); - Util.setShort(dataTable, (short) (pStatusOff + DATA_INDEX_ENTRY_LENGTH), (short)0); - JCSystem.commitTransaction(); - writeDataEntry(PROVISIONED_STATUS, data, dInex, (short) 2); repository.reclaimMemory((short)2); } @Override public short getBackupPrimitiveByteCount() { - // dataIndex - 2 bytes - // deviceLocked - 1 byte - // deviceState = 2 bytes - return (short) (5 + + // provisionStatus - 2 bytes + return (short) (2 + seProvider.getBackupPrimitiveByteCount(KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY) + - seProvider.getBackupPrimitiveByteCount( - KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY) + seProvider.getBackupPrimitiveByteCount(KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY) + seProvider.getBackupPrimitiveByteCount( KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY_PAIR) + seProvider.getBackupPrimitiveByteCount(KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY)); @@ -965,13 +972,11 @@ public short getBackupPrimitiveByteCount() { @Override public short getBackupObjectCount() { - // dataTable - 1 // AttestationIds - 8 - // bootParameters - 3 // AdditionalCertificateChain - 1 // BCC - 1 // oemRootPublicKey - 1 - return (short) (15 + + return (short) (11 + seProvider.getBackupObjectCount(KMDataStoreConstants.INTERFACE_TYPE_COMPUTED_HMAC_KEY) + seProvider.getBackupObjectCount(KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY) + seProvider.getBackupObjectCount(KMDataStoreConstants.INTERFACE_TYPE_PRE_SHARED_KEY) + From d76bc17dc6ec8f179a58722730215f85730105e8 Mon Sep 17 00:00:00 2001 From: "avinash.hedage" Date: Tue, 21 Jun 2022 04:28:53 +0000 Subject: [PATCH 2/2] Updated applet upgrade --- .../javacard/keymaster/KMAndroidSEApplet.java | 27 +++++----- .../javacard/keymaster/KMJCardSimApplet.java | 50 +++++++------------ .../keymaster/KMKeymintDataStore.java | 25 ++++++---- 3 files changed, 44 insertions(+), 58 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index 70d65026..99ca1ffd 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -35,7 +35,7 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeLis // 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 = 0x0102; + private static final short KM_APPLET_PACKAGE_VERSION = 0x0200; private static final byte KM_BEGIN_STATE = 0x00; private static final byte ILLEGAL_STATE = KM_BEGIN_STATE + 1; @@ -233,22 +233,21 @@ private boolean isSeFactoryProvisioningLocked() { private boolean isSeFactoryProvisioningComplete() { short pStatus = kmDataStore.getProvisionStatus(); - boolean result = false; - if ((0 != (pStatus & PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR)) - && (0 != ((pStatus & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN)))) { - result = true; + short seCompleteStatus = PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR | PROVISION_STATUS_ADDITIONAL_CERT_CHAIN; + if (seCompleteStatus == (pStatus & seCompleteStatus)) { + return true; } - return result; + return false; } private void processOEMUnlockProvisionCmd(APDU apdu) { authenticateOEM(OEM_UNLOCK_PROVISION_VERIFICATION_LABEL, apdu); - kmDataStore.unlockProvision(PROVISION_STATUS_PROVISIONING_LOCKED); + kmDataStore.unlockProvision(); sendResponse(apdu, KMError.OK); } private void processOEMLockProvisionCmd(APDU apdu) { - authenticateOEM(OEM_LOCK_PROVISION_VERIFICATION_LABEL, apdu); + authenticateOEM(OEM_LOCK_PROVISION_VERIFICATION_LABEL, apdu); // Enable the lock bit in provision status. kmDataStore.setProvisionStatus(PROVISION_STATUS_PROVISIONING_LOCKED); sendResponse(apdu, KMError.OK); @@ -563,14 +562,12 @@ private void processSetBootParamsCmd(APDU apdu) { private boolean isProvisioningComplete() { short pStatus = kmDataStore.getProvisionStatus(); - boolean result = false; - 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; + short pCompleteStatus = PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR | PROVISION_STATUS_ADDITIONAL_CERT_CHAIN | + PROVISION_STATUS_PRESHARED_SECRET | PROVISION_STATUS_ATTEST_IDS; + if (kmDataStore.isProvisionLocked() || (pCompleteStatus == (pStatus & pCompleteStatus))) { + return true; } - return result; + return false; } @Override diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java index bbfb6a04..cd665ef3 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java @@ -204,50 +204,39 @@ private boolean isCommandAllowed(short apduIns) { default: // Allow other commands only if provision is completed. if (!isProvisioningComplete()) { - result = false; + result = false; } } return result; } private boolean isSeFactoryProvisioningLocked() { - short dInex = repository.allocReclaimableMemory((short)2); - byte data[] = repository.getHeap(); - kmDataStore.getProvisionStatus(data, dInex); - short pStatus = Util.getShort(data, dInex); + short pStatus = kmDataStore.getProvisionStatus(); boolean result = false; if ((0 != (pStatus & PROVISION_STATUS_SE_LOCKED))) { result = true; } - repository.reclaimMemory((short)2); return result; } private boolean isSeFactoryProvisioningComplete() { - 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 != (pStatus & PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR)) - && (0 != ((pStatus & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN)))) { - result = true; + short pStatus = kmDataStore.getProvisionStatus(); + short seCompleteStatus = PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR | PROVISION_STATUS_ADDITIONAL_CERT_CHAIN; + if (seCompleteStatus == (pStatus & seCompleteStatus)) { + return true; } - repository.reclaimMemory((short)2); - return result; + return false; } private void processOEMUnlockProvisionCmd(APDU apdu) { authenticateOEM(OEM_UNLOCK_PROVISION_VERIFICATION_LABEL, apdu); - kmDataStore.setProvisionLock(false); - kmDataStore.unlockProvision(PROVISION_STATUS_PROVISIONING_LOCKED); + kmDataStore.unlockProvision(); sendResponse(apdu, KMError.OK); } private void processOEMLockProvisionCmd(APDU apdu) { - authenticateOEM(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); sendResponse(apdu, KMError.OK); } @@ -488,7 +477,8 @@ private static short buildErrorStatus(short err) { private void processGetProvisionStatusCmd(APDU apdu) { byte[] scratchpad = apdu.getBuffer(); - kmDataStore.getProvisionStatus(scratchpad, (short) 0); + short pStatus = kmDataStore.getProvisionStatus(); + Util.setShort(scratchpad, (short)0, pStatus); short resp = KMArray.instance((short) 2); KMArray.cast(resp).add((short) 0, buildErrorStatus(KMError.OK)); KMArray.cast(resp).add((short) 1, KMInteger.instance(scratchpad, (short)0, (short)2)); @@ -559,19 +549,13 @@ private void processSetBootParamsCmd(APDU apdu) { } private boolean isProvisioningComplete() { - short dInex = repository.allocReclaimableMemory((short)2); - byte data[] = repository.getHeap(); - kmDataStore.getProvisionStatus(data, dInex); - short pStatus = Util.getShort(data, dInex); - boolean result = false; - 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; + short pStatus = kmDataStore.getProvisionStatus(); + short pCompleteStatus = PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR | PROVISION_STATUS_ADDITIONAL_CERT_CHAIN | + PROVISION_STATUS_PRESHARED_SECRET | PROVISION_STATUS_ATTEST_IDS; + if (kmDataStore.isProvisionLocked() || (pCompleteStatus == (pStatus & pCompleteStatus))) { + return true; } - repository.reclaimMemory((short)2); - return result; + return false; } private short validateApdu(APDU apdu) { diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java b/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java index 5077ff3c..4380cb67 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java @@ -42,8 +42,7 @@ public class KMKeymintDataStore implements KMUpgradable { public static final short DATA_MEM_SIZE = 300; // Old Data table offsets - private static final byte OLD_PROVISIONED_LOCKED = 17; - private static final byte OLD_PROVISIONED_STATUS = 18; + private static final byte OLD_PROVISIONED_STATUS_OFFSET = 18; // Data table offsets public static final byte HMAC_NONCE = 0; @@ -350,9 +349,9 @@ public boolean isDeviceReady() { short offset = repository.allocReclaimableMemory(DEVICE_STATUS_FLAG_SIZE); byte[] buf = repository.getHeap(); getDeviceBootStatus(buf, offset); - if ((0 != (buf[offset] & SET_BOOT_PARAMS_SUCCESS)) - && (0 != (buf[offset] & SET_SYSTEM_PROPERTIES_SUCCESS)) - && (0 != (buf[offset] & NEGOTIATED_SHARED_SECRET_SUCCESS))) { + byte bootCompleteStatus = SET_BOOT_PARAMS_SUCCESS | SET_SYSTEM_PROPERTIES_SUCCESS | + SET_SYSTEM_PROPERTIES_SUCCESS; + if (bootCompleteStatus == (buf[offset] & bootCompleteStatus)) { result = true; } repository.reclaimMemory(DEVICE_STATUS_FLAG_SIZE); @@ -826,15 +825,19 @@ public boolean isProvisionLocked() { } public void setProvisionStatus(short pStatus) { + JCSystem.beginTransaction(); provisionStatus |= pStatus; + JCSystem.commitTransaction(); } public short getProvisionStatus() { return provisionStatus; } - public void unlockProvision(short unlockOffset) { - provisionStatus &= ~unlockOffset; + public void unlockProvision() { + JCSystem.beginTransaction(); + provisionStatus &= ~KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED; + JCSystem.commitTransaction(); } public void persistOEMRootPublicKey(byte[] inBuff, short inOffset, short inLength) { @@ -881,13 +884,13 @@ public void onSave(Element element) { @Override public void onRestore(Element element, short oldVersion, short currentVersion) { if (oldVersion != currentVersion) { - handlePrevisionVersionUpgrade(element); + handlePreviousVersionUpgrade(element); } else { handleCurrentVersionUpgrade(element); } } - private void handlePrevisionVersionUpgrade(Element element) { + private void handlePreviousVersionUpgrade(Element element) { // Read Primitives //restore old data table index short oldDataIndex = element.readShort(); @@ -945,18 +948,20 @@ private void handleCurrentVersionUpgrade(Element element) { public void getProvisionStatus(byte[] dataTable, byte[] scratchpad, short offset) { Util.setShort(scratchpad, offset, (short)0); - readDataEntry(dataTable, OLD_PROVISIONED_STATUS, scratchpad, offset); + readDataEntry(dataTable, OLD_PROVISIONED_STATUS_OFFSET, scratchpad, offset); } void handleProvisionStatusUpgrade(byte[] dataTable, short dataTableIndex){ short dInex = repository.allocReclaimableMemory((short)2); byte data[] = repository.getHeap(); getProvisionStatus(dataTable, data, dInex); + JCSystem.beginTransaction(); provisionStatus = (short)( data[dInex] & 0x00ff); if( KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED == (provisionStatus & KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED)) { provisionStatus |= KMKeymasterApplet.PROVISION_STATUS_SE_LOCKED; } + JCSystem.commitTransaction(); repository.reclaimMemory((short)2); }