From b90e22c6fe069425149699ad3bcf66dc2ca492dc Mon Sep 17 00:00:00 2001 From: "avinash.hedage" Date: Fri, 3 Jun 2022 11:08:55 +0000 Subject: [PATCH 1/3] updated bug fixes in RMA support --- .../javacard/keymaster/KMAndroidSEApplet.java | 99 ++++++++----------- .../javacard/seprovider/KMSEProvider.java | 1 - .../javacard/keymaster/KMJCardSimApplet.java | 90 +++++++---------- .../keymaster/KMKeymintDataStore.java | 29 +++--- ProvisioningTool/src/provision.cpp | 20 ++-- 5 files changed, 104 insertions(+), 135 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index 8fb66a7f..3f557d0d 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -65,17 +65,17 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeLis public static final byte BOOT_HASH_MAX_SIZE = 32; // Provision reporting status - private static final byte NOT_PROVISIONED = 0x00; - private static final byte PROVISION_STATUS_ATTESTATION_KEY = 0x01; // unused in keymint - private static final byte PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02; // unused in keymint - private static final byte PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04; // unused in keymint - 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_KEYPAIR = 0x40; - private static final byte PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = (byte) 0x80; - private static final byte PROVISION_STATUS_SE_LOCKED = 0x01; - private static final byte PROVISION_STATUS_OEM_PUBLIC_KEY = 0x02; + 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; @@ -206,7 +206,7 @@ private boolean isCommandAllowed(short apduIns) { break; case INS_SE_FACTORY_PROVISIONING_LOCK_CMD: - if(!isSeFactoryProvisioningComplete()) { + if(isSeFactoryProvisioningLocked() || !isSeFactoryProvisioningComplete()) { result = false; } break; @@ -216,7 +216,7 @@ private boolean isCommandAllowed(short apduIns) { // 1. All the necessary provisioning commands are succcessfully executed // 2. SE provision is locked // 3. OEM Root Public is provisioned. - if (!(isProvisioningComplete() && isSeFactoryProvisioningLocked())) { + if (kmDataStore.isProvisionLocked() || !(isProvisioningComplete() && isSeFactoryProvisioningLocked())) { result = false; } break; @@ -243,44 +243,48 @@ private boolean isCommandAllowed(short apduIns) { } private boolean isSeFactoryProvisioningLocked() { - short dInex = repository.allocReclaimableMemory((short)1); - 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; - if ((0 != (data[dInex] & PROVISION_STATUS_SE_LOCKED))) { + if ((0 != (pStatus & PROVISION_STATUS_SE_LOCKED))) { result = true; } - repository.reclaimMemory((short)1); + repository.reclaimMemory((short)2); return result; } private boolean isSeFactoryProvisioningComplete() { - short dIndex = repository.allocReclaimableMemory((short)1); + 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 != (data[dIndex] & INS_PROVISION_RKP_DEVICE_UNIQUE_KEYPAIR_CMD)) - && (0 != ((data[dIndex] & INS_PROVISION_RKP_ADDITIONAL_CERT_CHAIN_CMD)))) { - result = true; + if ((0 != (pStatus & PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR)) + && (0 != ((pStatus & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN)))) { + result = true; } - repository.reclaimMemory((short)1); + repository.reclaimMemory((short)2); return result; } private void processOEMUnlockProvisionCmd(APDU apdu) { - handleOEMLockUnlockCmd(OEM_UNLOCK_PROVISION_VERIFICATION_LABEL, apdu); + authenticateOEM(OEM_UNLOCK_PROVISION_VERIFICATION_LABEL, apdu); + kmDataStore.setProvisionLock(false); kmDataStore.unlockProvision(PROVISION_STATUS_PROVISIONING_LOCKED); sendError(apdu, KMError.OK); } private void processOEMLockProvisionCmd(APDU apdu) { - handleOEMLockUnlockCmd(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); sendError(apdu, KMError.OK); } - private void handleOEMLockUnlockCmd(byte[] plainMsg, APDU apdu) { + private void authenticateOEM(byte[] plainMsg, APDU apdu) { tmpVariables[0] = KMArray.instance((short) 1); KMArray.cast(tmpVariables[0]).add((short) 0, KMByteBlob.exp()); @@ -519,7 +523,7 @@ private void processGetProvisionStatusCmd(APDU apdu) { 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_8(scratchpad[0])); + KMArray.cast(resp).add((short) 1, KMInteger.instance(scratchpad, (short)0, (short)2)); sendOutgoing(apdu, resp); } @@ -586,53 +590,30 @@ private void processSetBootParamsCmd(APDU apdu) { enumVal = KMEnum.cast(bootParam).getVal(); kmDataStore.setDeviceLocked(enumVal == KMType.DEVICE_LOCKED_TRUE); - // Clear the Computed SharedHmac and Hmac nonce from persistent memory. Util.arrayFillNonAtomic(scratchPad, (short) 0, KMKeymintDataStore.COMPUTED_HMAC_KEY_SIZE, (byte) 0); kmDataStore.createComputedHmacKey(scratchPad, (short) 0, KMKeymintDataStore.COMPUTED_HMAC_KEY_SIZE); - + super.reboot(); sendError(apdu, KMError.OK); } private boolean isProvisioningComplete() { - short dInex = repository.allocReclaimableMemory((short)1); - 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; - if (kmDataStore.isProvisionLocked() || ((0 != (data[dInex] & PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR)) - && (0 != (data[dInex] & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN)) - && (0 != (data[dInex] & PROVISION_STATUS_PRESHARED_SECRET)) - && (0 != (data[dInex] & PROVISION_STATUS_ATTEST_IDS)))) { + 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; } - repository.reclaimMemory((short)1); + repository.reclaimMemory((short)2); return result; } - private boolean isOemProvisionComplete() { - short dInex = repository.allocReclaimableMemory((short)1); - byte data[] = repository.getHeap(); - kmDataStore.getProvisionStatus(data, dInex); - boolean result = false; - if ((0 != (data[dInex] & PROVISION_STATUS_OEM_PUBLIC_KEY)) - && (0 != (data[dInex] & PROVISION_STATUS_SE_LOCKED))) { - result = true; - } - repository.reclaimMemory((short)1); - return result; - } - - private void processLockProvisioningCmd(APDU apdu) { - if (isProvisioningComplete()) { - kmDataStore.setProvisionLocked(); - kmDataStore.setProvisionStatus(PROVISION_STATUS_PROVISIONING_LOCKED); - sendError(apdu, KMError.OK); - } else { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - } - @Override public void onCleanup() { } @@ -704,5 +685,5 @@ private short validateApdu(APDU apdu) { } return apduBuffer[ISO7816.OFFSET_INS]; } -} +} diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java index d641e4c6..d77f2167 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java @@ -698,7 +698,6 @@ KMDeviceUniqueKeyPair createRkpDeviceUniqueKeyPair(KMDeviceUniqueKeyPair key, short messageDigest256(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, short outOffset); - /** * This function generates a HMAC key from the provided key buffers. * diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java index 904a44ae..66f80148 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java @@ -54,17 +54,17 @@ public class KMJCardSimApplet extends KMKeymasterApplet { public static final byte BOOT_HASH_MAX_SIZE = 32; // Provision reporting status - private static final byte NOT_PROVISIONED = 0x00; - private static final byte PROVISION_STATUS_ATTESTATION_KEY = 0x01; // unused in keymint - private static final byte PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x02; // unused in keymint - private static final byte PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04; // unused in keymint - 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_KEYPAIR = 0x40; - private static final byte PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = (byte) 0x80; - private static final byte PROVISION_STATUS_SE_LOCKED = 0x01; - private static final byte PROVISION_STATUS_OEM_PUBLIC_KEY = 0x02; + 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; @@ -194,7 +194,7 @@ private boolean isCommandAllowed(short apduIns) { break; case INS_SE_FACTORY_PROVISIONING_LOCK_CMD: - if(!isSeFactoryProvisioningComplete()) { + if(isSeFactoryProvisioningLocked() || !isSeFactoryProvisioningComplete()) { result = false; } break; @@ -204,7 +204,7 @@ private boolean isCommandAllowed(short apduIns) { // 1. All the necessary provisioning commands are succcessfully executed // 2. SE provision is locked // 3. OEM Root Public is provisioned. - if (!(isProvisioningComplete() && isSeFactoryProvisioningLocked())) { + if (kmDataStore.isProvisionLocked() || !(isProvisioningComplete() && isSeFactoryProvisioningLocked())) { result = false; } break; @@ -231,44 +231,48 @@ private boolean isCommandAllowed(short apduIns) { } private boolean isSeFactoryProvisioningLocked() { - short dInex = repository.allocReclaimableMemory((short)1); + short dInex = repository.allocReclaimableMemory((short)2); byte data[] = repository.getHeap(); kmDataStore.getProvisionStatus(data, dInex); + short pStatus = Util.getShort(data, dInex); boolean result = false; - if ((0 != (data[dInex] & PROVISION_STATUS_SE_LOCKED))) { + if ((0 != (pStatus & PROVISION_STATUS_SE_LOCKED))) { result = true; } - repository.reclaimMemory((short)1); + repository.reclaimMemory((short)2); return result; } private boolean isSeFactoryProvisioningComplete() { - short dIndex = repository.allocReclaimableMemory((short)1); + 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 != (data[dIndex] & INS_PROVISION_RKP_DEVICE_UNIQUE_KEYPAIR_CMD)) - && (0 != ((data[dIndex] & INS_PROVISION_RKP_ADDITIONAL_CERT_CHAIN_CMD)))) { - result = true; + if ((0 != (pStatus & PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR)) + && (0 != ((pStatus & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN)))) { + result = true; } - repository.reclaimMemory((short)1); + repository.reclaimMemory((short)2); return result; } private void processOEMUnlockProvisionCmd(APDU apdu) { - handleOEMLockUnlockCmd(OEM_UNLOCK_PROVISION_VERIFICATION_LABEL, apdu); + authenticateOEM(OEM_UNLOCK_PROVISION_VERIFICATION_LABEL, apdu); + kmDataStore.setProvisionLock(false); kmDataStore.unlockProvision(PROVISION_STATUS_PROVISIONING_LOCKED); sendError(apdu, KMError.OK); } private void processOEMLockProvisionCmd(APDU apdu) { - handleOEMLockUnlockCmd(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); sendError(apdu, KMError.OK); } - private void handleOEMLockUnlockCmd(byte[] plainMsg, APDU apdu) { + private void authenticateOEM(byte[] plainMsg, APDU apdu) { tmpVariables[0] = KMArray.instance((short) 1); KMArray.cast(tmpVariables[0]).add((short) 0, KMByteBlob.exp()); @@ -507,7 +511,7 @@ private void processGetProvisionStatusCmd(APDU apdu) { 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_8(scratchpad[0])); + KMArray.cast(resp).add((short) 1, KMInteger.instance(scratchpad, (short)0, (short)2)); sendOutgoing(apdu, resp); } @@ -583,43 +587,21 @@ private void processSetBootParamsCmd(APDU apdu) { } private boolean isProvisioningComplete() { - short dInex = repository.allocReclaimableMemory((short)1); - byte data[] = repository.getHeap(); - kmDataStore.getProvisionStatus(data, dInex); - boolean result = false; - if (kmDataStore.isProvisionLocked() || ((0 != (data[dInex] & PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR)) - && (0 != (data[dInex] & PROVISION_STATUS_ADDITIONAL_CERT_CHAIN)) - && (0 != (data[dInex] & PROVISION_STATUS_PRESHARED_SECRET)) - && (0 != (data[dInex] & PROVISION_STATUS_ATTEST_IDS)))) { - result = true; - } - repository.reclaimMemory((short)1); - return result; - } - - private boolean isOemProvisionComplete() { - short dInex = repository.allocReclaimableMemory((short)1); + short dInex = repository.allocReclaimableMemory((short)2); byte data[] = repository.getHeap(); kmDataStore.getProvisionStatus(data, dInex); + short pStatus = Util.getShort(data, dInex); boolean result = false; - if ((0 != (data[dInex] & PROVISION_STATUS_OEM_PUBLIC_KEY)) - && (0 != (data[dInex] & PROVISION_STATUS_SE_LOCKED))) { + 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; } - repository.reclaimMemory((short)1); + repository.reclaimMemory((short)2); return result; } - private void processLockProvisioningCmd(APDU apdu) { - if (isProvisioningComplete()) { - kmDataStore.setProvisionLocked(); - kmDataStore.setProvisionStatus(PROVISION_STATUS_PROVISIONING_LOCKED); - sendError(apdu, KMError.OK); - } else { - ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED); - } - } - private short validateApdu(APDU apdu) { // Read the apdu header and buffer. byte[] apduBuffer = apdu.getBuffer(); diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java b/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java index 0d50284f..570648ad 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java @@ -462,7 +462,6 @@ public void persistAdditionalCertChain(byte[] buf, short offset, short len) { Util.arrayCopyNonAtomic(buf, offset, additionalCertChain, (short) 2, len); JCSystem.commitTransaction(); - } public short getAdditionalCertChainLength() { @@ -749,8 +748,8 @@ 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 void setProvisionLock(boolean lockValue) { + writeBoolean(PROVISIONED_LOCKED, lockValue); } public boolean isProvisionLocked() { @@ -763,25 +762,28 @@ public boolean isProvisionLocked() { return false; } - public void setProvisionStatus(byte provisionStatus) { - short offset = repository.alloc((short) 1); + public void setProvisionStatus(short provisionStatus) { + short offset = repository.alloc((short) 2); byte[] buf = repository.getHeap(); getProvisionStatus(buf, offset); - buf[offset] |= provisionStatus; - writeDataEntry(PROVISIONED_STATUS, buf, offset, (short) 1); + provisionStatus |= Util.getShort(buf, offset); + Util.setShort(buf, offset, provisionStatus); + writeDataEntry(PROVISIONED_STATUS, buf, offset, (short) 2); } public void getProvisionStatus(byte[] scratchpad, short offset) { - scratchpad[offset] = 0; + Util.setShort(scratchpad, offset, (short)0); readDataEntry(PROVISIONED_STATUS, scratchpad, offset); } - public void unlockProvision(byte unlockOffset) { - short offset = repository.alloc((short) 1); + public void unlockProvision(short unlockOffset) { + short offset = repository.alloc((short) 2); byte[] buf = repository.getHeap(); getProvisionStatus(buf, offset); - buf[offset] &= ~unlockOffset; - writeDataEntry(PROVISIONED_STATUS, buf, offset, (short) 1); + short temp = Util.getShort(buf, offset); + temp &= ~unlockOffset; + Util.setShort(buf, offset, temp); + writeDataEntry(PROVISIONED_STATUS, buf, offset, (short) 2); } public void persistOEMRootPublicKey(byte[] inBuff, short inOffset, short inLength) { @@ -795,6 +797,9 @@ public void persistOEMRootPublicKey(byte[] inBuff, short inOffset, short inLengt } public byte[] getOEMRootPublicKey() { + if(oemRootPublicKey == null) { + KMException.throwIt(KMError.INVALID_DATA); + } return oemRootPublicKey; } diff --git a/ProvisioningTool/src/provision.cpp b/ProvisioningTool/src/provision.cpp index 4587a808..6284f686 100644 --- a/ProvisioningTool/src/provision.cpp +++ b/ProvisioningTool/src/provision.cpp @@ -30,15 +30,17 @@ #define SE_POWER_RESET_STATUS_FLAG (1 << 30) // TODO keymint provision status enum ProvisionStatus { - NOT_PROVISIONED = 0x00, - PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x04, - PROVISION_STATUS_ATTEST_IDS = 0x08, - PROVISION_STATUS_PRESHARED_SECRET = 0x10, - PROVISION_STATUS_PROVISIONING_LOCKED = 0x20, - PROVISION_STATUS_DEVICE_UNIQUE_KEY = 0x40, - PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = 0x80, - PROVISION_STATUS_SE_LOCKED = 0x01, - PROVISION_STATUS_OEM_PUBLIC_KEY = 0x02 + NOT_PROVISIONED = 0x0000, + PROVISION_STATUS_ATTESTATION_KEY = 0x0001, + PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x0002, + PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x0004, + PROVISION_STATUS_ATTEST_IDS = 0x0008, + PROVISION_STATUS_PRESHARED_SECRET = 0x0010, + PROVISION_STATUS_PROVISIONING_LOCKED = 0x0020, + PROVISION_STATUS_DEVICE_UNIQUE_KEY = 0x0040, + PROVISION_STATUS_ADDITIONAL_CERT_CHAIN = 0x0080, + PROVISION_STATUS_SE_LOCKED = 0x0100, + PROVISION_STATUS_OEM_PUBLIC_KEY = 0x0200 }; // TODO keymint provision status and lock From 7dda70169c74bb822dd5b92ab468e73b4cba9000 Mon Sep 17 00:00:00 2001 From: "avinash.hedage" Date: Fri, 3 Jun 2022 20:06:37 +0000 Subject: [PATCH 2/3] updated bug fixes and provision status in RMA support --- .../javacard/keymaster/KMAndroidSEApplet.java | 15 ----------- .../javacard/keymaster/KMKeymasterApplet.java | 13 ++++++++++ .../keymaster/KMKeymintDataStore.java | 26 +++++++++++++++++++ 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index 3f557d0d..adb18e05 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -59,24 +59,9 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeLis 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. diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 462c42df..74d66f0f 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -266,6 +266,19 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe // Minimum HMAC length in bits public static final short MIN_HMAC_LENGTH_BITS = 64; + // Provision reporting status + public static final short NOT_PROVISIONED = 0x0000; + public static final short PROVISION_STATUS_ATTESTATION_KEY = 0x0001; + public static final short PROVISION_STATUS_ATTESTATION_CERT_CHAIN = 0x0002; + public static final short PROVISION_STATUS_ATTESTATION_CERT_PARAMS = 0x0004; + public static final short PROVISION_STATUS_ATTEST_IDS = 0x0008; + public static final short PROVISION_STATUS_PRESHARED_SECRET = 0x0010; + public static final short PROVISION_STATUS_PROVISIONING_LOCKED = 0x0020; + public static final short PROVISION_STATUS_DEVICE_UNIQUE_KEYPAIR = 0x0040; + 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; + protected static RemotelyProvisionedComponentDevice rkp; protected static KMEncoder encoder; protected static KMDecoder decoder; diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java b/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java index 570648ad..3d6760ec 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymintDataStore.java @@ -866,8 +866,34 @@ public void onRestore(Element element, short oldVersion, short currentVersion) { 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 == 0x0100 && currentVersion == 0x0200) { + handleProvisionStatusUpgrade(); + } + } + + void handleProvisionStatusUpgrade( ){ + short dInex = repository.allocReclaimableMemory((short)2); + byte data[] = repository.getHeap(); + getProvisionStatus(data, dInex); + short newStatus = (short)( data[dInex] & 0x00ff); + if( KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED + == (newStatus & KMKeymasterApplet.PROVISION_STATUS_PROVISIONING_LOCKED)) { + newStatus |= 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 From f778194b8017aa8adf5afe655804bbb337bc52a3 Mon Sep 17 00:00:00 2001 From: "avinash.hedage" Date: Sun, 5 Jun 2022 17:45:06 +0000 Subject: [PATCH 3/3] Updated NVM optimization changes --- .../javacard/keymaster/KMAndroidSEApplet.java | 2 +- .../seprovider/KMAndroidSEProvider.java | 30 ++++++++----------- .../android/javacard/keymaster/KMCose.java | 14 ++++----- .../javacard/keymaster/KMCoseHeaders.java | 8 ++--- .../android/javacard/keymaster/KMCoseKey.java | 22 +++++++------- .../RemotelyProvisionedComponentDevice.java | 4 +-- 6 files changed, 38 insertions(+), 42 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index adb18e05..115abe41 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -123,7 +123,7 @@ public void process(APDU apdu) { break; case INS_SET_BOOT_ENDED_CMD: - processSetBootEndedCmd(apdu); + processSetBootEndedCmd(apdu); break; case INS_PROVISION_RKP_DEVICE_UNIQUE_KEYPAIR_CMD: diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index 86c3e7c7..e5ede6e9 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java @@ -52,6 +52,8 @@ public class KMAndroidSEProvider implements KMSEProvider { public static final byte POWER_RESET_FALSE = (byte) 0xAA; public static final byte POWER_RESET_TRUE = (byte) 0x00; private static final short COMPUTED_HMAC_KEY_SIZE = 32; + private static byte[] CMAC_KDF_CONSTANT_L; + private static byte[] CMAC_KDF_CONSTANT_ZERO; private static KeyAgreement keyAgreement; @@ -88,6 +90,7 @@ public static KMAndroidSEProvider getInstance() { } public KMAndroidSEProvider() { + initStatics(); // Re-usable AES,DES and HMAC keys in persisted memory. aesKeys = new AESKey[2]; aesKeys[KEYSIZE_128_OFFSET] = (AESKey) KeyBuilder.buildKey( @@ -120,6 +123,12 @@ public KMAndroidSEProvider() { JCSystem.CLEAR_ON_RESET); resetFlag[0] = (byte) POWER_RESET_FALSE; } + + void initStatics() { + CMAC_KDF_CONSTANT_L = new byte[] { + 0x00, 0x00, 0x01, 0x00 }; + CMAC_KDF_CONSTANT_ZERO = new byte[] {0x00}; + } public void clean() { Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0); @@ -401,23 +410,10 @@ public boolean aesGCMDecrypt(byte[] aesKey, short aesKeyStart, public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelStart, short labelLen, byte[] context, short contextStart, short contextLength) { - try { + try { // This is hardcoded to requirement - 32 byte output with two concatenated // 16 bytes K1 and K2. final byte n = 2; // hardcoded - // [L] 256 bits - hardcoded 32 bits as per - // reference impl in keymaster. - short zeroIndex = 0; - short LIndex = 1; - short bufIndex = 5; - short keyIndex = 9; - //1st byte in tempArray is reserved for zero - //next 4 bytes in tempArray is reserved for L - tmpArray[0] = 0; - tmpArray[1] = 0; - tmpArray[2] = 0; - tmpArray[3] = 1; - tmpArray[4] = 0; // [i] counter - 32 bits short iBufLen = 4; @@ -439,12 +435,12 @@ public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelSta while (i <= n) { tmpArray[3] = i; // 4 bytes of iBuf with counter in it - kdf.update(tmpArray, bufIndex, iBufLen); + kdf.update(tmpArray, (short) 0, (short) iBufLen); kdf.update(label, labelStart, (short) labelLen); // label - kdf.update(tmpArray, zeroIndex, (short) 1); // 1 byte of 0x00 + kdf.update(CMAC_KDF_CONSTANT_ZERO, (short) 0, (short) CMAC_KDF_CONSTANT_ZERO.length); // 1 byte of 0x00 kdf.update(context, contextStart, contextLength); // context // 4 bytes of L - signature of 16 bytes - pos = kdf.sign(tmpArray, LIndex, (short) 4, tmpArray, + pos = kdf.sign(CMAC_KDF_CONSTANT_L, (short) 0, (short) CMAC_KDF_CONSTANT_L.length, tmpArray, (short) (iBufLen + pos)); i++; } diff --git a/Applet/src/com/android/javacard/keymaster/KMCose.java b/Applet/src/com/android/javacard/keymaster/KMCose.java index 94648ca2..ca72db64 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCose.java +++ b/Applet/src/com/android/javacard/keymaster/KMCose.java @@ -305,13 +305,13 @@ public static short constructCoseCertPayload(short issuer, short subject, short * @return instance of KMCoseHeaders. */ public static short constructHeaders(short []buff, short alg, short keyId, short iv, short ephemeralKey) { - buff[0]= alg; - buff[1]= keyId; - buff[2]= iv; - buff[3]= ephemeralKey; - for(short i = 4; i < 8; i++) { + buff[0]= alg; + buff[1]= keyId; + buff[2]= iv; + buff[3]= ephemeralKey; + for(short i = 4; i < 8; i++) { buff[i] = KMType.INVALID_VALUE; - } + } short ptr = handleCosePairTags(coseHeaderConst, buff, (short)4, false); ptr = KMCoseHeaders.instance(ptr); KMCoseHeaders.cast(ptr).canonicalize(); @@ -490,7 +490,7 @@ public static short constructCoseKey(short []buff, short keyType, short keyId, s buff[6] = pubY; buff[7] = priv; for (short i = valueIndex; i < 16; i++) { - buff[i] = KMType.INVALID_VALUE; + buff[i] = KMType.INVALID_VALUE; } short arrPtr = handleCosePairTags(coseKeyConst, buff, valueIndex, includeTestKey); if (includeTestKey) { diff --git a/Applet/src/com/android/javacard/keymaster/KMCoseHeaders.java b/Applet/src/com/android/javacard/keymaster/KMCoseHeaders.java index d02a3975..e8939f1e 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCoseHeaders.java +++ b/Applet/src/com/android/javacard/keymaster/KMCoseHeaders.java @@ -154,10 +154,10 @@ public short getAlgorithm() { public boolean isDataValid(short []buff, short alg, short keyIdPtr) { short bufLen = 4; - buff[0] = KMCose.COSE_LABEL_ALGORITHM; - buff[1] = alg; - buff[2] = KMCose.COSE_LABEL_KEYID; - buff[3] = keyIdPtr; + buff[0] = KMCose.COSE_LABEL_ALGORITHM; + buff[1] = alg; + buff[2] = KMCose.COSE_LABEL_KEYID; + buff[3] = keyIdPtr; boolean valid = false; short value; short ptr; diff --git a/Applet/src/com/android/javacard/keymaster/KMCoseKey.java b/Applet/src/com/android/javacard/keymaster/KMCoseKey.java index 53a14c34..a39d3225 100644 --- a/Applet/src/com/android/javacard/keymaster/KMCoseKey.java +++ b/Applet/src/com/android/javacard/keymaster/KMCoseKey.java @@ -180,17 +180,17 @@ public boolean isTestKey() { * @return true if valid, otherwise false. */ public boolean isDataValid(short []buff, short keyType, short keyIdPtr, short keyAlg, short keyOps, short curve) { - short buffLen = 10; - buff[0] = KMCose.COSE_KEY_KEY_TYPE; - buff[1] = keyType; - buff[2] = KMCose.COSE_KEY_KEY_ID; - buff[3] = keyIdPtr; - buff[4] = KMCose.COSE_KEY_ALGORITHM; - buff[5] = keyAlg; - buff[6] = KMCose.COSE_KEY_KEY_OPS; - buff[7] = keyOps; - buff[8] = KMCose.COSE_KEY_CURVE; - buff[9] = curve; + short buffLen = 10; + buff[0] = KMCose.COSE_KEY_KEY_TYPE; + buff[1] = keyType; + buff[2] = KMCose.COSE_KEY_KEY_ID; + buff[3] = keyIdPtr; + buff[4] = KMCose.COSE_KEY_ALGORITHM; + buff[5] = keyAlg; + buff[6] = KMCose.COSE_KEY_KEY_OPS; + buff[7] = keyOps; + buff[8] = KMCose.COSE_KEY_CURVE; + buff[9] = curve; boolean valid = false; short ptr; short tagIndex = 0; diff --git a/Applet/src/com/android/javacard/keymaster/RemotelyProvisionedComponentDevice.java b/Applet/src/com/android/javacard/keymaster/RemotelyProvisionedComponentDevice.java index 282a480b..12dc4b83 100644 --- a/Applet/src/com/android/javacard/keymaster/RemotelyProvisionedComponentDevice.java +++ b/Applet/src/com/android/javacard/keymaster/RemotelyProvisionedComponentDevice.java @@ -1059,8 +1059,8 @@ private short ecdhHkdfDeriveKey(byte[] privKeyA, short privKeyAOff, short privKe // data table for later usage. private short generateEphemeralEcKey(byte[] scratchPad) { // Generate ephemeral ec key. - rkpTmpVariables[0] = 0; - rkpTmpVariables[1] = 0; + rkpTmpVariables[0] = 0; + rkpTmpVariables[1] = 0; seProvider.createAsymmetricKey( KMType.EC, scratchPad,