From 1a45800fa4bf164b04a44c3b997a964f662bd30b Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Thu, 21 Apr 2022 01:09:14 +0000 Subject: [PATCH 1/6] Fixed the issue in removing custom tags --- .../javacard/keymaster/KMAndroidSEApplet.java | 6 ++ .../android/javacard/keymaster/KMUtils.java | 6 +- .../javacard/keymaster/KMJCardSimApplet.java | 6 ++ .../android/javacard/keymaster/KMUtils.java | 6 +- .../javacard/keymaster/KMKeymasterApplet.java | 63 ++++++++++--------- 5 files changed, 57 insertions(+), 30 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index d024fb83..1987d576 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -159,6 +159,12 @@ public void process(APDU apdu) { processSetBootParamsCmd(apdu); break; + case INS_SET_BOOT_ENDED_CMD: + //set the flag to mark boot ended + kmDataStore.setBootEndedStatus(true); + sendError(apdu, KMError.OK); + break; + case INS_PROVISION_RKP_DEVICE_UNIQUE_KEYPAIR_CMD: processProvisionRkpDeviceUniqueKeyPair(apdu); break; diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java index a2fc8eab..6c4e6d1b 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -352,8 +352,12 @@ public static void add(byte[] buf, short op1, short op2, short result) { byte index = 7; byte carry = 0; short tmp; + short val1 = 0; + short val2 = 0; while (index >= 0) { - tmp = (short) (buf[(short) (op1 + index)] + buf[(short) (op2 + index)] + carry); + val1 = (short) (buf[(short) (op1 + index)] & 0x00FF); + val2 = (short) (buf[(short) (op2 + index)] & 0x00FF); + tmp = (short) (val1 + val2 + carry); carry = 0; if (tmp > 255) { carry = 1; // max unsigned byte value is 255 diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java index 2271d0a5..12ba75ba 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMJCardSimApplet.java @@ -143,6 +143,12 @@ public void process(APDU apdu) { processSetBootParamsCmd(apdu); break; + case INS_SET_BOOT_ENDED_CMD: + //set the flag to mark boot ended + kmDataStore.setBootEndedStatus(true); + sendError(apdu, KMError.OK); + break; + case INS_PROVISION_RKP_DEVICE_UNIQUE_KEYPAIR_CMD: processProvisionRkpDeviceUniqueKeyPair(apdu); break; diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java index a2fc8eab..6c4e6d1b 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -352,8 +352,12 @@ public static void add(byte[] buf, short op1, short op2, short result) { byte index = 7; byte carry = 0; short tmp; + short val1 = 0; + short val2 = 0; while (index >= 0) { - tmp = (short) (buf[(short) (op1 + index)] + buf[(short) (op2 + index)] + carry); + val1 = (short) (buf[(short) (op1 + index)] & 0x00FF); + val2 = (short) (buf[(short) (op2 + index)] & 0x00FF); + tmp = (short) (val1 + val2 + carry); carry = 0; if (tmp > 255) { carry = 1; // max unsigned byte value is 255 diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index c4632d39..64b81ea6 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -652,11 +652,23 @@ public void sendOutgoing(APDU apdu, KMAttestationCert cert, short certStart, sho // reclaim the unused memory in the certificate. repository.reclaimMemory((short) (bufferStart - certStart)); } + // Reserve space of MAX_KEY_CHARS_SIZE to encode KeyCharacteristics + short prevReclaimIndex = repository.getHeapReclaimIndex(); + short keyCharsIndex = repository.allocReclaimableMemory(MAX_KEY_CHARS_SIZE); + + // Encode keyblob at the end of the buffer before KEY_CHARACTERISTICS + short keyBlobLen = encodeKeyBlob(keyblob); + short keyBlobStart = repository.getHeapReclaimIndex(); // Encode KeyCharacteristics at the end of heap just before data[CERTIFICATE] - encodeKeyCharacteristics(keyChars); - // and encode it to the end of the buffer before KEY_CHARACTERISTICS - encodeKeyBlob(keyblob); + // in the reserved space of MAX_KEY_CHARS_SIZE + short keyCharsLen = encodeKeyCharacteristics(keyCharsIndex, prevReclaimIndex, keyChars); + + // Adjust the keyblob buffer before KeyChars and reclaim the memory + short newKeyBlobStart = (short) (keyBlobStart + (MAX_KEY_CHARS_SIZE - keyCharsLen)); + Util.arrayCopyNonAtomic(buffer, keyBlobStart, buffer, newKeyBlobStart, keyBlobLen); + repository.reclaimMemory((short) (newKeyBlobStart - keyBlobStart)); + // Write Array header and ErrorCode before data[KEY_BLOB] short bufferStartOffset = repository.allocReclaimableMemory((short) 2); Util.setShort(buffer, bufferStartOffset, (short) 0x8400); @@ -3048,11 +3060,6 @@ private void importKey(APDU apdu, short keyFmt, byte[] scratchPad) { makeKeyCharacteristics( scratchPad); KMAttestationCert cert = generateAttestation(data[ATTEST_KEY_BLOB], data[ATTEST_KEY_PARAMS],scratchPad); createEncryptedKeyBlob(scratchPad); - // Remove custom tags from key characteristics - short teeParams = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); - if(teeParams != KMType.INVALID_VALUE) { - KMKeyParameters.cast(teeParams).deleteCustomTags(); - } sendOutgoing(apdu, cert, data[CERTIFICATE], data[KEY_BLOB], data[KEY_CHARACTERISTICS]); } @@ -3496,11 +3503,6 @@ private void processGenerateKey(APDU apdu) { // construct the certificate and place the encoded data in data[CERTIFICATE] KMAttestationCert cert = generateAttestation(data[ATTEST_KEY_BLOB], data[ATTEST_KEY_PARAMS], scratchPad); createEncryptedKeyBlob(scratchPad); - // Remove custom tags from key characteristics - short teeParams = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); - if(teeParams != KMType.INVALID_VALUE) { - KMKeyParameters.cast(teeParams).deleteCustomTags(); - } sendOutgoing(apdu, cert, data[CERTIFICATE], data[KEY_BLOB], data[KEY_CHARACTERISTICS]); } @@ -3841,34 +3843,39 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { } // Encodes KeyCharacteristics at the end of the heap - private void encodeKeyCharacteristics(short keyChars) { + // and return the length of encoded KeyChars. + private short encodeKeyCharacteristics(short startOffset, short prevReclaimIndex, short keyChars) { + // Remove custom tags from key characteristics + short teeParams = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); + if(teeParams != KMType.INVALID_VALUE) { + KMKeyParameters.cast(teeParams).deleteCustomTags(); + } byte[] buffer = repository.getHeap(); - short prevReclaimIndex = repository.getHeapReclaimIndex(); - short ptr = repository.allocReclaimableMemory(MAX_KEY_CHARS_SIZE); - short len = encoder.encode(keyChars, buffer, ptr, prevReclaimIndex, MAX_KEY_CHARS_SIZE); + short len = encoder.encode(keyChars, buffer, startOffset, prevReclaimIndex, MAX_KEY_CHARS_SIZE); // shift the encoded KeyCharacteristics data towards the right till the data[CERTIFICATE] offset. - Util.arrayCopyNonAtomic(buffer, ptr, buffer, (short) (ptr + (MAX_KEY_CHARS_SIZE - len)), len); - // Reclaim the unused memory. - repository.reclaimMemory((short) (MAX_KEY_CHARS_SIZE - len)); + Util.arrayCopyNonAtomic(buffer, startOffset, buffer, (short) (startOffset + (MAX_KEY_CHARS_SIZE - len)), len); + return len; } // Encodes KeyBlob at the end of the heap - private void encodeKeyBlob(short keyBlobPtr) { + // and returns the length of the encoded keyblob + private short encodeKeyBlob(short keyBlobPtr) { // allocate reclaimable memory. byte[] buffer = repository.getHeap(); short prevReclaimIndex = repository.getHeapReclaimIndex(); short top = repository.allocReclaimableMemory(MAX_KEYBLOB_SIZE); - short keyBlob = encoder.encode(keyBlobPtr, buffer, top, prevReclaimIndex, MAX_KEYBLOB_SIZE); + short keyBlobLen = encoder.encode(keyBlobPtr, buffer, top, prevReclaimIndex, MAX_KEYBLOB_SIZE); Util.arrayCopyNonAtomic(repository.getHeap(), top, repository.getHeap(), - (short) (top + MAX_KEYBLOB_SIZE - keyBlob), keyBlob); - short newTop = (short) (top + MAX_KEYBLOB_SIZE - keyBlob); - // Encode the KeyBlob array inside a ByteString. Get the length of - // the ByteString header. - short encodedBytesLength = encoder.getEncodedBytesLength(keyBlob); + (short) (top + MAX_KEYBLOB_SIZE - keyBlobLen), keyBlobLen); + short newTop = (short) (top + MAX_KEYBLOB_SIZE - keyBlobLen); + // Encode the KeyBlob array inside a ByteBlob. Get the length of + // the ByteBlob header. + short encodedBytesLength = encoder.getEncodedBytesLength(keyBlobLen); newTop -= encodedBytesLength; - encoder.encodeByteBlobHeader(keyBlob, buffer, newTop, encodedBytesLength); + encoder.encodeByteBlobHeader(keyBlobLen, buffer, newTop, encodedBytesLength); // Reclaim unused memory. repository.reclaimMemory((short) (newTop - top)); + return (short) (keyBlobLen + encodedBytesLength); } private short readKeyBlobVersion(short keyBlob) { From 154c9493b6824afa24c4ea6706fb9351e1e7ee2c Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Thu, 21 Apr 2022 16:04:59 +0000 Subject: [PATCH 2/6] customtags change --- .../javacard/keymaster/KMAndroidSEApplet.java | 1 + .../javacard/seprovider/KMJCardSimulator.java | 6 +- .../javacard/keymaster/KMKeyParameters.java | 70 ++++++----- .../javacard/keymaster/KMKeymasterApplet.java | 119 ++++++++---------- .../android/javacard/keymaster/KMType.java | 8 ++ 5 files changed, 105 insertions(+), 99 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index 1987d576..45822390 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -97,6 +97,7 @@ public static void install(byte[] bArray, short bOffset, byte bLength) { @Override public void process(APDU apdu) { try { + resetData(); // If this is select applet apdu which is selecting this applet then return if (apdu.isISOInterindustryCLA()) { if (selectingApplet()) { diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java index 31ca6519..ee5a8d4d 100644 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java +++ b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java @@ -621,8 +621,10 @@ public short hmacSign(Object key, byte[] data, short dataStart, short dataLength @Override public boolean hmacVerify(KMComputedHmacKey key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart, short macLength) { - KMHmacKey hmacKey = (KMHmacKey) key; - hmacSignature.init(hmacKey.getKey(), Signature.MODE_VERIFY); + //KMHmacKey hmacKey = (KMHmacKey) key; + byte[] keyBuf = new byte[32]; + HMACKey hmacKey = createHMACKey(keyBuf, (short) 0, (short) keyBuf.length); + hmacSignature.init(hmacKey, Signature.MODE_VERIFY); return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, macLength); } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java index 9b2e4dad..d1ea64ba 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java @@ -46,37 +46,43 @@ private static KMKeyParameters proto(short ptr) { } public static short exp() { - short arrPtr = KMArray.instance((short) 11); - KMArray arr = KMArray.cast(arrPtr); - arr.add((short) 0, KMEnum.instance(KMType.RULE, KMType.FAIL_ON_INVALID_TAGS)); - arr.add((short) 1, KMIntegerTag.exp(UINT_TAG)); - arr.add((short) 2, KMIntegerArrayTag.exp(UINT_ARRAY_TAG)); - arr.add((short) 3, KMIntegerTag.exp(ULONG_TAG)); - arr.add((short) 4, KMIntegerTag.exp(DATE_TAG)); - arr.add((short) 5, KMIntegerArrayTag.exp(ULONG_ARRAY_TAG)); - arr.add((short) 6, KMEnumTag.exp()); - arr.add((short) 7, KMEnumArrayTag.exp()); - arr.add((short) 8, KMByteTag.exp()); - arr.add((short) 9, KMBoolTag.exp()); - arr.add((short) 10, KMBignumTag.exp()); - return instance(arrPtr); + if (KMType.keyParamExp[0] == KMType.INVALID_VALUE) { + short arrPtr = KMArray.instance((short) 11); + KMArray arr = KMArray.cast(arrPtr); + arr.add((short) 0, KMEnum.instance(KMType.RULE, KMType.FAIL_ON_INVALID_TAGS)); + arr.add((short) 1, KMIntegerTag.exp(UINT_TAG)); + arr.add((short) 2, KMIntegerArrayTag.exp(UINT_ARRAY_TAG)); + arr.add((short) 3, KMIntegerTag.exp(ULONG_TAG)); + arr.add((short) 4, KMIntegerTag.exp(DATE_TAG)); + arr.add((short) 5, KMIntegerArrayTag.exp(ULONG_ARRAY_TAG)); + arr.add((short) 6, KMEnumTag.exp()); + arr.add((short) 7, KMEnumArrayTag.exp()); + arr.add((short) 8, KMByteTag.exp()); + arr.add((short) 9, KMBoolTag.exp()); + arr.add((short) 10, KMBignumTag.exp()); + KMType.keyParamExp[0] = instance(arrPtr); + } + return KMType.keyParamExp[0]; } public static short expAny() { - short arrPtr = KMArray.instance((short) 11); - KMArray arr = KMArray.cast(arrPtr); - arr.add((short) 0, KMEnum.instance(KMType.RULE, KMType.IGNORE_INVALID_TAGS)); - arr.add((short) 1, KMIntegerTag.exp(UINT_TAG)); - arr.add((short) 2, KMIntegerArrayTag.exp(UINT_ARRAY_TAG)); - arr.add((short) 3, KMIntegerTag.exp(ULONG_TAG)); - arr.add((short) 4, KMIntegerTag.exp(DATE_TAG)); - arr.add((short) 5, KMIntegerArrayTag.exp(ULONG_ARRAY_TAG)); - arr.add((short) 6, KMEnumTag.exp()); - arr.add((short) 7, KMEnumArrayTag.exp()); - arr.add((short) 8, KMByteTag.exp()); - arr.add((short) 9, KMBoolTag.exp()); - arr.add((short) 10, KMBignumTag.exp()); - return instance(arrPtr); + if (KMType.keyParamExp[1] == KMType.INVALID_VALUE) { + short arrPtr = KMArray.instance((short) 11); + KMArray arr = KMArray.cast(arrPtr); + arr.add((short) 0, KMEnum.instance(KMType.RULE, KMType.IGNORE_INVALID_TAGS)); + arr.add((short) 1, KMIntegerTag.exp(UINT_TAG)); + arr.add((short) 2, KMIntegerArrayTag.exp(UINT_ARRAY_TAG)); + arr.add((short) 3, KMIntegerTag.exp(ULONG_TAG)); + arr.add((short) 4, KMIntegerTag.exp(DATE_TAG)); + arr.add((short) 5, KMIntegerArrayTag.exp(ULONG_ARRAY_TAG)); + arr.add((short) 6, KMEnumTag.exp()); + arr.add((short) 7, KMEnumArrayTag.exp()); + arr.add((short) 8, KMByteTag.exp()); + arr.add((short) 9, KMBoolTag.exp()); + arr.add((short) 10, KMBignumTag.exp()); + KMType.keyParamExp[1] = instance(arrPtr); + } + return KMType.keyParamExp[1]; } public static short instance(short vals) { @@ -393,9 +399,6 @@ public static short makeTeeEnforced(short keyParamsPtr, byte[] scratchPad) { } index++; } - // Add custom tags at the end of the array. So it becomes easy to - // delete them when sending key characteristics back to HAL. - arrInd = addCustomTags(keyParamsPtr, scratchPad, arrInd); return createKeyParameters(scratchPad, (short) (arrInd / 2)); } @@ -471,9 +474,10 @@ public static short createKeyParameters(byte[] ptrArr, short len) { return KMKeyParameters.instance(arrPtr); } - public static short addCustomTags(short keyParams, byte[] scratchPad, short offset) { + public static short makeCustomTags(short keyParams, byte[] scratchPad) { short index = 0; short tagPtr; + short offset = 0; short len = (short) customTags.length; short tagType; while (index < len) { @@ -493,7 +497,7 @@ public static short addCustomTags(short keyParams, byte[] scratchPad, short offs } index += 2; } - return offset; + return createKeyParameters(scratchPad, (short) (offset / 2)); } public void deleteCustomTags() { diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 64b81ea6..fcb6d2ae 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -191,6 +191,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final byte SB_PARAMETERS = 35; public static final byte CONFIRMATION_TOKEN = 36; public static final byte KEY_BLOB_VERSION_DATA_OFFSET = 37; + public static final byte CUSTOM_TAGS = 38; // Constant // AddRngEntropy @@ -202,7 +203,8 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final byte KEY_BLOB_NONCE = 2; public static final byte KEY_BLOB_AUTH_TAG = 3; public static final byte KEY_BLOB_PARAMS = 4; - public static final byte KEY_BLOB_PUB_KEY = 5; + public static final byte KEY_BLOB_CUSTOM_TAGS = 5; + public static final byte KEY_BLOB_PUB_KEY = 6; // AES GCM constants public static final byte AES_GCM_AUTH_TAG_LENGTH = 16; public static final byte AES_GCM_NONCE_LENGTH = 12; @@ -217,8 +219,8 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe // KeyBlob (structure, encryption algorithm etc). public static final short KEYBLOB_CURRENT_VERSION = 1; // KeyBlob array size constants. - public static final byte SYM_KEY_BLOB_SIZE_V1 = 5; - public static final byte ASYM_KEY_BLOB_SIZE_V1 = 6; + public static final byte SYM_KEY_BLOB_SIZE_V1 = 6; + public static final byte ASYM_KEY_BLOB_SIZE_V1 = 7; public static final byte SYM_KEY_BLOB_SIZE_V0 = 4; public static final byte ASYM_KEY_BLOB_SIZE_V0 = 5; // Key type constants @@ -397,7 +399,6 @@ protected short mapCryptoErrorToKMError(short reason) { @Override public void process(APDU apdu) { try { - resetData(); repository.onProcess(); // If this is select applet apdu which is selecting this applet then return if (apdu.isISOInterindustryCLA()) { @@ -594,6 +595,7 @@ protected void resetData() { tmpVariables[index] = KMType.INVALID_VALUE; index++; } + KMType.resetData(); } /** @@ -652,23 +654,11 @@ public void sendOutgoing(APDU apdu, KMAttestationCert cert, short certStart, sho // reclaim the unused memory in the certificate. repository.reclaimMemory((short) (bufferStart - certStart)); } - // Reserve space of MAX_KEY_CHARS_SIZE to encode KeyCharacteristics - short prevReclaimIndex = repository.getHeapReclaimIndex(); - short keyCharsIndex = repository.allocReclaimableMemory(MAX_KEY_CHARS_SIZE); - - // Encode keyblob at the end of the buffer before KEY_CHARACTERISTICS - short keyBlobLen = encodeKeyBlob(keyblob); - short keyBlobStart = repository.getHeapReclaimIndex(); // Encode KeyCharacteristics at the end of heap just before data[CERTIFICATE] - // in the reserved space of MAX_KEY_CHARS_SIZE - short keyCharsLen = encodeKeyCharacteristics(keyCharsIndex, prevReclaimIndex, keyChars); - - // Adjust the keyblob buffer before KeyChars and reclaim the memory - short newKeyBlobStart = (short) (keyBlobStart + (MAX_KEY_CHARS_SIZE - keyCharsLen)); - Util.arrayCopyNonAtomic(buffer, keyBlobStart, buffer, newKeyBlobStart, keyBlobLen); - repository.reclaimMemory((short) (newKeyBlobStart - keyBlobStart)); - + encodeKeyCharacteristics(keyChars); + // and encode it to the end of the buffer before KEY_CHARACTERISTICS + encodeKeyBlob(keyblob); // Write Array header and ErrorCode before data[KEY_BLOB] short bufferStartOffset = repository.allocReclaimableMemory((short) 2); Util.setShort(buffer, bufferStartOffset, (short) 0x8400); @@ -779,11 +769,6 @@ private void processGetKeyCharacteristicsCmd(APDU apdu) { if (isKeyUpgradeRequired(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad)) { KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE); } - // Remove custom tags from key characteristics - short teeParams = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); - if(teeParams != KMType.INVALID_VALUE) { - KMKeyParameters.cast(teeParams).deleteCustomTags(); - } // make response. short resp = KMArray.instance((short) 2); KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); @@ -816,6 +801,7 @@ private short createKeyBlobExp(short version) { short keyBlob = KMType.INVALID_VALUE; short byteBlobExp = KMByteBlob.exp(); short keyChar = KMKeyCharacteristics.exp(); + short keyParam = KMKeyParameters.exp(); switch(version) { case (short) 0: // Old KeyBlob has a maximum of 5 elements. @@ -833,6 +819,7 @@ private short createKeyBlobExp(short version) { KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_AUTH_TAG, byteBlobExp); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_NONCE, byteBlobExp); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_PARAMS, keyChar); + KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_CUSTOM_TAGS, keyParam); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_PUB_KEY, byteBlobExp); break; default: @@ -1365,6 +1352,7 @@ private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyPara short privKey = data[SECRET]; short hwParams = data[HW_PARAMETERS]; short keyChars = data[KEY_CHARACTERISTICS]; + short customTags = data[CUSTOM_TAGS]; // Check if key requires upgrade for attestKeyBlob. The KeyBlob is parsed inside // isKeyUpgradeRequired function itself. if (isKeyUpgradeRequired(attKeyBlob, appId, appData, scratchPad)) { @@ -1412,6 +1400,7 @@ private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyPara data[KEY_BLOB] = origBlob; data[HW_PARAMETERS] = hwParams; data[KEY_CHARACTERISTICS] = keyChars; + data[CUSTOM_TAGS] = customTags; data[SW_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getKeystoreEnforced(); data[TEE_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); data[SB_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getStrongboxEnforced(); @@ -3506,20 +3495,6 @@ private void processGenerateKey(APDU apdu) { sendOutgoing(apdu, cert, data[CERTIFICATE], data[KEY_BLOB], data[KEY_CHARACTERISTICS]); } - private short generateAttestKeyCmd(APDU apdu) { - short params = KMKeyParameters.expAny(); - short blob = KMByteBlob.exp(); - // Array of expected arguments - short cmd = KMArray.instance((short) 6); - KMArray.cast(cmd).add((short) 0, blob); // key blob - KMArray.cast(cmd).add((short) 1, params); // keyparamters to be attested. - KMArray.cast(cmd).add((short) 2, blob); // attest key blob - KMArray.cast(cmd).add((short) 3, params); // attest key params - KMArray.cast(cmd).add((short) 4, blob); // attest issuer - KMArray.cast(cmd).add((short) 5, blob); // keyparams mac. - - return receiveIncoming(apdu, cmd); - } private short getApplicationId(short params) { short appId = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, params); @@ -3781,7 +3756,7 @@ protected static short getBootPatchLevel(byte[] scratchPad){ // KeyBlob's KeyCharacteristics. // 2. Re-create KeyBlob's KeyCharacteristics from HW_PARAMS to make sure we don't miss // anything which happens in these functions makeSbEnforced and makeTeeEnforced in - // the future. Like validations, addition of custom tags e.t.c. + // the future. Like validations. // 3. No need to create Keystore Enforced list here as it is not required to be included in // the KeyBlob's KeyCharacteristics. // 4. No need to create KeyCharacteristics as upgradeKey does not require to return any @@ -3795,6 +3770,20 @@ private static void upgradeKeyBlobKeyCharacteristics(short hwParams, byte[] scra hwParams, (byte) data[ORIGIN], osVersion, osPatch, vendorPatch, bootPatch, scratchPad); data[TEE_PARAMETERS] = KMKeyParameters.makeTeeEnforced(hwParams, scratchPad); data[HW_PARAMETERS] = KMKeyParameters.makeHwEnforced(data[SB_PARAMETERS], data[TEE_PARAMETERS]); + + // Create custom tags from tee params and remove the custom tags from old Keyblob keychars. + short version = KMInteger.cast(data[KEY_BLOB_VERSION_DATA_OFFSET]).getShort(); + switch (version) { + case 0: + if (data[TEE_PARAMETERS] != KMType.INVALID_VALUE) { + data[CUSTOM_TAGS] = KMKeyParameters.makeCustomTags(data[TEE_PARAMETERS], scratchPad); + KMKeyParameters.cast(data[TEE_PARAMETERS]).deleteCustomTags(); + } + break; + + default: + break; + } } private static void makeKeyCharacteristics(byte[] scratchPad) { @@ -3811,6 +3800,8 @@ private static void makeKeyCharacteristics(byte[] scratchPad) { KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).setStrongboxEnforced(data[SB_PARAMETERS]); KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).setKeystoreEnforced(data[SW_PARAMETERS]); KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).setTeeEnforced(data[TEE_PARAMETERS]); + // Add custom tags + data[CUSTOM_TAGS] = KMKeyParameters.makeCustomTags(data[KEY_PARAMETERS], scratchPad); } private static void createEncryptedKeyBlob(byte[] scratchPad) { @@ -3832,6 +3823,7 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_AUTH_TAG, data[AUTH_TAG]); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_NONCE, data[NONCE]); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_VERSION_OFFSET, data[KEY_BLOB_VERSION_DATA_OFFSET]); + KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_CUSTOM_TAGS, data[CUSTOM_TAGS]); short tempChar = KMKeyCharacteristics.instance(); short emptyParam = KMArray.instance((short) 0); @@ -3843,39 +3835,34 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { } // Encodes KeyCharacteristics at the end of the heap - // and return the length of encoded KeyChars. - private short encodeKeyCharacteristics(short startOffset, short prevReclaimIndex, short keyChars) { - // Remove custom tags from key characteristics - short teeParams = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); - if(teeParams != KMType.INVALID_VALUE) { - KMKeyParameters.cast(teeParams).deleteCustomTags(); - } + private void encodeKeyCharacteristics(short keyChars) { byte[] buffer = repository.getHeap(); - short len = encoder.encode(keyChars, buffer, startOffset, prevReclaimIndex, MAX_KEY_CHARS_SIZE); + short prevReclaimIndex = repository.getHeapReclaimIndex(); + short ptr = repository.allocReclaimableMemory(MAX_KEY_CHARS_SIZE); + short len = encoder.encode(keyChars, buffer, ptr, prevReclaimIndex, MAX_KEY_CHARS_SIZE); // shift the encoded KeyCharacteristics data towards the right till the data[CERTIFICATE] offset. - Util.arrayCopyNonAtomic(buffer, startOffset, buffer, (short) (startOffset + (MAX_KEY_CHARS_SIZE - len)), len); - return len; + Util.arrayCopyNonAtomic(buffer, ptr, buffer, (short) (ptr + (MAX_KEY_CHARS_SIZE - len)), len); + // Reclaim the unused memory. + repository.reclaimMemory((short) (MAX_KEY_CHARS_SIZE - len)); } // Encodes KeyBlob at the end of the heap - // and returns the length of the encoded keyblob - private short encodeKeyBlob(short keyBlobPtr) { + private void encodeKeyBlob(short keyBlobPtr) { // allocate reclaimable memory. byte[] buffer = repository.getHeap(); short prevReclaimIndex = repository.getHeapReclaimIndex(); short top = repository.allocReclaimableMemory(MAX_KEYBLOB_SIZE); - short keyBlobLen = encoder.encode(keyBlobPtr, buffer, top, prevReclaimIndex, MAX_KEYBLOB_SIZE); + short keyBlob = encoder.encode(keyBlobPtr, buffer, top, prevReclaimIndex, MAX_KEYBLOB_SIZE); Util.arrayCopyNonAtomic(repository.getHeap(), top, repository.getHeap(), - (short) (top + MAX_KEYBLOB_SIZE - keyBlobLen), keyBlobLen); - short newTop = (short) (top + MAX_KEYBLOB_SIZE - keyBlobLen); - // Encode the KeyBlob array inside a ByteBlob. Get the length of - // the ByteBlob header. - short encodedBytesLength = encoder.getEncodedBytesLength(keyBlobLen); + (short) (top + MAX_KEYBLOB_SIZE - keyBlob), keyBlob); + short newTop = (short) (top + MAX_KEYBLOB_SIZE - keyBlob); + // Encode the KeyBlob array inside a ByteString. Get the length of + // the ByteString header. + short encodedBytesLength = encoder.getEncodedBytesLength(keyBlob); newTop -= encodedBytesLength; - encoder.encodeByteBlobHeader(keyBlobLen, buffer, newTop, encodedBytesLength); + encoder.encodeByteBlobHeader(keyBlob, buffer, newTop, encodedBytesLength); // Reclaim unused memory. repository.reclaimMemory((short) (newTop - top)); - return (short) (keyBlobLen + encodedBytesLength); } private short readKeyBlobVersion(short keyBlob) { @@ -3914,6 +3901,7 @@ private void readKeyBlobParams(short version, short parsedKeyBlob) { if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V0) { data[PUB_KEY] = KMArray.cast(parsedKeyBlob).get((short) 4); } + data[KEY_BLOB_VERSION_DATA_OFFSET] = KMInteger.uint_8((byte) 0); break; case (short) 1: data[SECRET] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_SECRET); @@ -3922,6 +3910,8 @@ private void readKeyBlobParams(short version, short parsedKeyBlob) { data[KEY_CHARACTERISTICS] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_PARAMS); data[KEY_BLOB_VERSION_DATA_OFFSET] = KMArray.cast(parsedKeyBlob).get( KEY_BLOB_VERSION_OFFSET); + data[CUSTOM_TAGS] = KMArray.cast(parsedKeyBlob).get( + KEY_BLOB_CUSTOM_TAGS); data[PUB_KEY] = KMType.INVALID_VALUE; if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V1) { data[PUB_KEY] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_PUB_KEY); @@ -4062,7 +4052,7 @@ private static byte getKeyType(short hardwareParams) { } private static void makeAuthData(short version, byte[] scratchPad) { - // For KeyBlob V1: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS, VERSION and PUB_KEY. + // For KeyBlob V1: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS, CUSTOM_TAGS, VERSION and PUB_KEY. // For KeyBlob V0: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS and PUB_KEY. // VERSION is included only for KeyBlobs having version >= 1. // PUB_KEY is included for only ASYMMETRIC KeyBlobs. @@ -4087,14 +4077,15 @@ private static void makeAuthData(short version, byte[] scratchPad) { } break; case (short) 1: - numParams = 3; + numParams = 4; Util.setShort(scratchPad, (short) 0, KMKeyParameters.cast(data[HW_PARAMETERS]).getVals()); Util.setShort(scratchPad, (short) 2, KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals()); - Util.setShort(scratchPad, (short) 4, data[KEY_BLOB_VERSION_DATA_OFFSET]); + Util.setShort(scratchPad, (short) 4, KMKeyParameters.cast(data[CUSTOM_TAGS]).getVals()); + Util.setShort(scratchPad, (short) 6, data[KEY_BLOB_VERSION_DATA_OFFSET]); // For Asymmetric Keys include the PUB_KEY. if (keyType == ASYM_KEY_TYPE) { - numParams = 4; - Util.setShort(scratchPad, (short) 6, data[PUB_KEY]); + numParams = 5; + Util.setShort(scratchPad, (short) 8, data[PUB_KEY]); } break; default: diff --git a/Applet/src/com/android/javacard/keymaster/KMType.java b/Applet/src/com/android/javacard/keymaster/KMType.java index 95806ad3..891de5b6 100644 --- a/Applet/src/com/android/javacard/keymaster/KMType.java +++ b/Applet/src/com/android/javacard/keymaster/KMType.java @@ -364,6 +364,8 @@ public abstract class KMType { public static final short MAX_SUBJECT_DER_LEN = 1095; + protected static short[] keyParamExp; + protected static KMRepository repository; protected static byte[] heap; // Instance table @@ -372,6 +374,7 @@ public abstract class KMType { public static void initialize() { instanceTable = JCSystem.makeTransientShortArray(INSTANCE_TABLE_SIZE, JCSystem.CLEAR_ON_RESET); + keyParamExp = JCSystem.makeTransientShortArray((short) 2, JCSystem.CLEAR_ON_RESET); KMType.repository = KMRepository.instance(); KMType.heap = repository.getHeap(); } @@ -404,5 +407,10 @@ protected static short exp(byte type) { Util.setShort(heap, (short) (ptr + 1), INVALID_VALUE); return ptr; } + + protected static void resetData() { + keyParamExp[0] = KMType.INVALID_VALUE; + keyParamExp[1] = KMType.INVALID_VALUE; + } } From 971e5926fe607857c18a7978ac925a8f4e6589fd Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Fri, 22 Apr 2022 01:22:01 +0000 Subject: [PATCH 3/6] Custom tags moved to KeyBlob from KeyChars --- .../javacard/keymaster/KMAndroidSEApplet.java | 1 - .../javacard/keymaster/KMKeyParameters.java | 123 +++++------------- .../javacard/keymaster/KMKeymasterApplet.java | 98 +++++++++++--- .../android/javacard/keymaster/KMType.java | 11 +- 4 files changed, 113 insertions(+), 120 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index 45822390..1987d576 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -97,7 +97,6 @@ public static void install(byte[] bArray, short bOffset, byte bLength) { @Override public void process(APDU apdu) { try { - resetData(); // If this is select applet apdu which is selecting this applet then return if (apdu.isISOInterindustryCLA()) { if (selectingApplet()) { diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java index d1ea64ba..89805dc7 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java @@ -46,43 +46,37 @@ private static KMKeyParameters proto(short ptr) { } public static short exp() { - if (KMType.keyParamExp[0] == KMType.INVALID_VALUE) { - short arrPtr = KMArray.instance((short) 11); - KMArray arr = KMArray.cast(arrPtr); - arr.add((short) 0, KMEnum.instance(KMType.RULE, KMType.FAIL_ON_INVALID_TAGS)); - arr.add((short) 1, KMIntegerTag.exp(UINT_TAG)); - arr.add((short) 2, KMIntegerArrayTag.exp(UINT_ARRAY_TAG)); - arr.add((short) 3, KMIntegerTag.exp(ULONG_TAG)); - arr.add((short) 4, KMIntegerTag.exp(DATE_TAG)); - arr.add((short) 5, KMIntegerArrayTag.exp(ULONG_ARRAY_TAG)); - arr.add((short) 6, KMEnumTag.exp()); - arr.add((short) 7, KMEnumArrayTag.exp()); - arr.add((short) 8, KMByteTag.exp()); - arr.add((short) 9, KMBoolTag.exp()); - arr.add((short) 10, KMBignumTag.exp()); - KMType.keyParamExp[0] = instance(arrPtr); - } - return KMType.keyParamExp[0]; + short arrPtr = KMArray.instance((short) 11); + KMArray arr = KMArray.cast(arrPtr); + arr.add((short) 0, KMEnum.instance(KMType.RULE, KMType.FAIL_ON_INVALID_TAGS)); + arr.add((short) 1, KMIntegerTag.exp(UINT_TAG)); + arr.add((short) 2, KMIntegerArrayTag.exp(UINT_ARRAY_TAG)); + arr.add((short) 3, KMIntegerTag.exp(ULONG_TAG)); + arr.add((short) 4, KMIntegerTag.exp(DATE_TAG)); + arr.add((short) 5, KMIntegerArrayTag.exp(ULONG_ARRAY_TAG)); + arr.add((short) 6, KMEnumTag.exp()); + arr.add((short) 7, KMEnumArrayTag.exp()); + arr.add((short) 8, KMByteTag.exp()); + arr.add((short) 9, KMBoolTag.exp()); + arr.add((short) 10, KMBignumTag.exp()); + return instance(arrPtr); } public static short expAny() { - if (KMType.keyParamExp[1] == KMType.INVALID_VALUE) { - short arrPtr = KMArray.instance((short) 11); - KMArray arr = KMArray.cast(arrPtr); - arr.add((short) 0, KMEnum.instance(KMType.RULE, KMType.IGNORE_INVALID_TAGS)); - arr.add((short) 1, KMIntegerTag.exp(UINT_TAG)); - arr.add((short) 2, KMIntegerArrayTag.exp(UINT_ARRAY_TAG)); - arr.add((short) 3, KMIntegerTag.exp(ULONG_TAG)); - arr.add((short) 4, KMIntegerTag.exp(DATE_TAG)); - arr.add((short) 5, KMIntegerArrayTag.exp(ULONG_ARRAY_TAG)); - arr.add((short) 6, KMEnumTag.exp()); - arr.add((short) 7, KMEnumArrayTag.exp()); - arr.add((short) 8, KMByteTag.exp()); - arr.add((short) 9, KMBoolTag.exp()); - arr.add((short) 10, KMBignumTag.exp()); - KMType.keyParamExp[1] = instance(arrPtr); - } - return KMType.keyParamExp[1]; + short arrPtr = KMArray.instance((short) 11); + KMArray arr = KMArray.cast(arrPtr); + arr.add((short) 0, KMEnum.instance(KMType.RULE, KMType.IGNORE_INVALID_TAGS)); + arr.add((short) 1, KMIntegerTag.exp(UINT_TAG)); + arr.add((short) 2, KMIntegerArrayTag.exp(UINT_ARRAY_TAG)); + arr.add((short) 3, KMIntegerTag.exp(ULONG_TAG)); + arr.add((short) 4, KMIntegerTag.exp(DATE_TAG)); + arr.add((short) 5, KMIntegerArrayTag.exp(ULONG_ARRAY_TAG)); + arr.add((short) 6, KMEnumTag.exp()); + arr.add((short) 7, KMEnumArrayTag.exp()); + arr.add((short) 8, KMByteTag.exp()); + arr.add((short) 9, KMBoolTag.exp()); + arr.add((short) 10, KMBignumTag.exp()); + return instance(arrPtr); } public static short instance(short vals) { @@ -241,64 +235,6 @@ public static short makeSbEnforced(short keyParamsPtr, byte origin, return createKeyParameters(scratchPad, (short) (arrInd / 2)); } - public static short makeSbEnforced(short keyParamsPtr, byte[] scratchPad) { - final short[] hwEnforcedTagArr = { - // HW Enforced - KMType.ENUM_TAG, KMType.ORIGIN, - KMType.UINT_TAG, KMType.OS_VERSION, - KMType.UINT_TAG, KMType.OS_PATCH_LEVEL, - KMType.UINT_TAG, KMType.VENDOR_PATCH_LEVEL, - KMType.UINT_TAG, KMType.BOOT_PATCH_LEVEL, - KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, - KMType.ENUM_TAG, KMType.ALGORITHM, - KMType.UINT_TAG, KMType.KEYSIZE, - KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, - KMType.ENUM_TAG, KMType.BLOB_USAGE_REQ, - KMType.ENUM_ARRAY_TAG, KMType.DIGEST, - KMType.ENUM_ARRAY_TAG, KMType.PADDING, - KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, - KMType.ENUM_ARRAY_TAG, KMType.RSA_OAEP_MGF_DIGEST, - KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, - KMType.BOOL_TAG, KMType.CALLER_NONCE, - KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, - KMType.ENUM_TAG, KMType.ECCURVE, - KMType.BOOL_TAG, KMType.INCLUDE_UNIQUE_ID, - KMType.BOOL_TAG, KMType.ROLLBACK_RESISTANCE, - KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, - KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, - KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, - KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, - }; - byte index = 0; - short tagInd; - short arrInd = 0; - short tagPtr; - short tagKey; - short tagType; - short arrPtr = KMKeyParameters.cast(keyParamsPtr).getVals(); - short len = KMArray.cast(arrPtr).length(); - while (index < len) { - tagInd = 0; - tagPtr = KMArray.cast(arrPtr).get(index); - tagKey = KMTag.getKey(tagPtr); - tagType = KMTag.getTagType(tagPtr); - if (!isValidTag(tagType, tagKey)) { - KMException.throwIt(KMError.INVALID_KEY_BLOB); - } - while (tagInd < (short) hwEnforcedTagArr.length) { - if ((hwEnforcedTagArr[tagInd] == tagType) - && (hwEnforcedTagArr[(short) (tagInd + 1)] == tagKey)) { - Util.setShort(scratchPad, arrInd, tagPtr); - arrInd += 2; - break; - } - tagInd += 2; - } - index++; - } - return createKeyParameters(scratchPad, (short) (arrInd / 2)); - } - public static short makeHwEnforced(short sb, short tee){ short len = KMKeyParameters.cast(sb).length(); len += KMKeyParameters.cast(tee).length(); @@ -334,7 +270,8 @@ public static short makeKeystoreEnforced(short keyParamsPtr, byte[] scratchPad) KMType.UINT_TAG, KMType.USERID, KMType.DATE_TAG, KMType.CREATION_DATETIME, KMType.UINT_TAG, KMType.USAGE_COUNT_LIMIT, - KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY + KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY, + KMType.UINT_TAG, KMType.MAX_BOOT_LEVEL, }; byte index = 0; short tagInd; diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index fcb6d2ae..62436edf 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -217,10 +217,12 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe // the KeyBlobs if it is changed. please increment this // version number whenever you change anything related to // KeyBlob (structure, encryption algorithm etc). - public static final short KEYBLOB_CURRENT_VERSION = 1; + public static final short KEYBLOB_CURRENT_VERSION = 2; // KeyBlob array size constants. - public static final byte SYM_KEY_BLOB_SIZE_V1 = 6; - public static final byte ASYM_KEY_BLOB_SIZE_V1 = 7; + public static final byte SYM_KEY_BLOB_SIZE_V2 = 6; + public static final byte ASYM_KEY_BLOB_SIZE_V2 = 7; + public static final byte SYM_KEY_BLOB_SIZE_V1 = 5; + public static final byte ASYM_KEY_BLOB_SIZE_V1 = 6; public static final byte SYM_KEY_BLOB_SIZE_V0 = 4; public static final byte ASYM_KEY_BLOB_SIZE_V0 = 5; // Key type constants @@ -399,6 +401,7 @@ protected short mapCryptoErrorToKMError(short reason) { @Override public void process(APDU apdu) { try { + resetData(); repository.onProcess(); // If this is select applet apdu which is selecting this applet then return if (apdu.isISOInterindustryCLA()) { @@ -595,7 +598,6 @@ protected void resetData() { tmpVariables[index] = KMType.INVALID_VALUE; index++; } - KMType.resetData(); } /** @@ -814,6 +816,15 @@ private short createKeyBlobExp(short version) { break; case (short) 1: keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V1); + KMArray.cast(keyBlob).add((short) 0, KMInteger.exp()); + KMArray.cast(keyBlob).add((short) 1, byteBlobExp); + KMArray.cast(keyBlob).add((short) 2, byteBlobExp); + KMArray.cast(keyBlob).add((short) 3, byteBlobExp); + KMArray.cast(keyBlob).add((short) 4, keyChar); + KMArray.cast(keyBlob).add((short) 5, byteBlobExp); + break; + case (short) 2: + keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V2); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_VERSION_OFFSET, KMInteger.exp()); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_SECRET, byteBlobExp); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_AUTH_TAG, byteBlobExp); @@ -832,10 +843,10 @@ private static short createKeyBlobInstance(byte keyType) { short arrayLen = 0; switch (keyType) { case ASYM_KEY_TYPE: - arrayLen = ASYM_KEY_BLOB_SIZE_V1; + arrayLen = ASYM_KEY_BLOB_SIZE_V2; break; case SYM_KEY_TYPE: - arrayLen = SYM_KEY_BLOB_SIZE_V1; + arrayLen = SYM_KEY_BLOB_SIZE_V2; break; default: KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); @@ -1056,11 +1067,11 @@ private void processUpgradeKeyCmd(APDU apdu) { byte keyType = getKeyType(data[HW_PARAMETERS]); switch (keyType) { case ASYM_KEY_TYPE: - data[KEY_BLOB] = KMArray.instance(ASYM_KEY_BLOB_SIZE_V1); + data[KEY_BLOB] = KMArray.instance(ASYM_KEY_BLOB_SIZE_V2); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]); break; case SYM_KEY_TYPE: - data[KEY_BLOB] = KMArray.instance(SYM_KEY_BLOB_SIZE_V1); + data[KEY_BLOB] = KMArray.instance(SYM_KEY_BLOB_SIZE_V2); break; default: KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); @@ -2833,7 +2844,7 @@ private void authorizeUserSecureIdAuthTimeout(KMOperationState op, byte[] scratc } authTimeoutTagPtr = - KMKeyParameters.findTag(KMType.ULONG_TAG, KMType.AUTH_TIMEOUT_MILLIS, data[HW_PARAMETERS]); + KMKeyParameters.findTag(KMType.ULONG_TAG, KMType.AUTH_TIMEOUT_MILLIS, data[CUSTOM_TAGS]); if (authTimeoutTagPtr == KMType.INVALID_VALUE) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } @@ -3775,8 +3786,8 @@ private static void upgradeKeyBlobKeyCharacteristics(short hwParams, byte[] scra short version = KMInteger.cast(data[KEY_BLOB_VERSION_DATA_OFFSET]).getShort(); switch (version) { case 0: + case 1: if (data[TEE_PARAMETERS] != KMType.INVALID_VALUE) { - data[CUSTOM_TAGS] = KMKeyParameters.makeCustomTags(data[TEE_PARAMETERS], scratchPad); KMKeyParameters.cast(data[TEE_PARAMETERS]).deleteCustomTags(); } break; @@ -3800,8 +3811,6 @@ private static void makeKeyCharacteristics(byte[] scratchPad) { KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).setStrongboxEnforced(data[SB_PARAMETERS]); KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).setKeystoreEnforced(data[SW_PARAMETERS]); KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).setTeeEnforced(data[TEE_PARAMETERS]); - // Add custom tags - data[CUSTOM_TAGS] = KMKeyParameters.makeCustomTags(data[KEY_PARAMETERS], scratchPad); } private static void createEncryptedKeyBlob(byte[] scratchPad) { @@ -3814,6 +3823,8 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { data[HIDDEN_PARAMETERS] = KMKeyParameters.makeHidden(data[KEY_PARAMETERS], data[ROT], scratchPad); data[KEY_BLOB_VERSION_DATA_OFFSET] = KMInteger.uint_16(KEYBLOB_CURRENT_VERSION); + // create custom tags + data[CUSTOM_TAGS] = KMKeyParameters.makeCustomTags(data[HW_PARAMETERS], scratchPad); // make authorization data makeAuthData(KEYBLOB_CURRENT_VERSION, scratchPad); // encrypt the secret and cryptographically attach that to authorization data @@ -3901,9 +3912,24 @@ private void readKeyBlobParams(short version, short parsedKeyBlob) { if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V0) { data[PUB_KEY] = KMArray.cast(parsedKeyBlob).get((short) 4); } + // Set the data[KEY_BLOB_VERSION_DATA_OFFSET] with integer value of 0 so + // that it will used at later point of time. data[KEY_BLOB_VERSION_DATA_OFFSET] = KMInteger.uint_8((byte) 0); break; case (short) 1: + data[SECRET] = KMArray.cast(parsedKeyBlob).get((short) 0); + data[NONCE]= KMArray.cast(parsedKeyBlob).get((short) 1); + data[AUTH_TAG] = KMArray.cast(parsedKeyBlob).get((short) 2); + data[KEY_CHARACTERISTICS] = KMArray.cast(parsedKeyBlob).get((short) 3); + data[KEY_BLOB_VERSION_DATA_OFFSET] = KMArray.cast(parsedKeyBlob).get( + (short) 4); + data[CUSTOM_TAGS] = KMType.INVALID_VALUE; + data[PUB_KEY] = KMType.INVALID_VALUE; + if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V1) { + data[PUB_KEY] = KMArray.cast(parsedKeyBlob).get((short) 5); + } + break; + case (short) 2: data[SECRET] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_SECRET); data[NONCE]= KMArray.cast(parsedKeyBlob).get(KEY_BLOB_NONCE); data[AUTH_TAG] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_AUTH_TAG); @@ -3913,7 +3939,7 @@ private void readKeyBlobParams(short version, short parsedKeyBlob) { data[CUSTOM_TAGS] = KMArray.cast(parsedKeyBlob).get( KEY_BLOB_CUSTOM_TAGS); data[PUB_KEY] = KMType.INVALID_VALUE; - if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V1) { + if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V2) { data[PUB_KEY] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_PUB_KEY); } break; @@ -3928,7 +3954,20 @@ private void decodeKeyBlob(short version, short keyBlob) { KMByteBlob.cast(keyBlob).getBuffer(), KMByteBlob.cast(keyBlob).getStartOff(), KMByteBlob.cast(keyBlob).length()); - short minArraySize = (version > 0) ? SYM_KEY_BLOB_SIZE_V1 : (short) 4; + short minArraySize = 0; + switch(version) { + case 0: + minArraySize = (short) 4; + break; + case 1: + minArraySize = (short) 5; + break; + case 2: + minArraySize = SYM_KEY_BLOB_SIZE_V2; + break; + default: + KMException.throwIt(KMError.INVALID_KEY_BLOB); + }; // KeyBlob size should not be less than the minimum KeyBlob size. if (KMArray.cast(parsedBlob).length() < minArraySize) { KMException.throwIt(KMError.INVALID_KEY_BLOB); @@ -3947,7 +3986,20 @@ private void processDecryptSecret(short version, short appId, short appData, byt makeAuthData(version, scratchPad); // Decrypt Secret and verify auth tag decryptSecret(scratchPad); - short keyBlobSecretOff = (version > 0) ? KEY_BLOB_SECRET : (short) 0; + short keyBlobSecretOff = 0; + switch(version) { + case 0: + keyBlobSecretOff = (short) 0; + break; + case 1: + keyBlobSecretOff = (short) 1; + break; + case 2: + keyBlobSecretOff = KEY_BLOB_SECRET; + break; + default: + KMException.throwIt(KMError.INVALID_KEY_BLOB); + }; KMArray.cast(data[KEY_BLOB]).add(keyBlobSecretOff, data[SECRET]); } @@ -4052,13 +4104,14 @@ private static byte getKeyType(short hardwareParams) { } private static void makeAuthData(short version, byte[] scratchPad) { - // For KeyBlob V1: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS, CUSTOM_TAGS, VERSION and PUB_KEY. + // For KeyBlob V2: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS, CUSTOM_TAGS, VERSION and PUB_KEY. + // For KeyBlob V1: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS, VERSION and PUB_KEY. // For KeyBlob V0: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS and PUB_KEY. // VERSION is included only for KeyBlobs having version >= 1. // PUB_KEY is included for only ASYMMETRIC KeyBlobs. short index = 0; short numParams = 0; - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 8, (byte) 0); + Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 10, (byte) 0); byte keyType = getKeyType(data[HW_PARAMETERS]); // Copy the relevant parameters in the scratchPad in the order // 1. HW_PARAMETERS @@ -4077,6 +4130,17 @@ private static void makeAuthData(short version, byte[] scratchPad) { } break; case (short) 1: + numParams = 3; + Util.setShort(scratchPad, (short) 0, KMKeyParameters.cast(data[HW_PARAMETERS]).getVals()); + Util.setShort(scratchPad, (short) 2, KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals()); + Util.setShort(scratchPad, (short) 4, data[KEY_BLOB_VERSION_DATA_OFFSET]); + // For Asymmetric Keys include the PUB_KEY. + if (keyType == ASYM_KEY_TYPE) { + numParams = 4; + Util.setShort(scratchPad, (short) 6, data[PUB_KEY]); + } + break; + case (short) 2: numParams = 4; Util.setShort(scratchPad, (short) 0, KMKeyParameters.cast(data[HW_PARAMETERS]).getVals()); Util.setShort(scratchPad, (short) 2, KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals()); diff --git a/Applet/src/com/android/javacard/keymaster/KMType.java b/Applet/src/com/android/javacard/keymaster/KMType.java index 891de5b6..26eda3d3 100644 --- a/Applet/src/com/android/javacard/keymaster/KMType.java +++ b/Applet/src/com/android/javacard/keymaster/KMType.java @@ -247,6 +247,8 @@ public abstract class KMType { public static final short NO_AUTH_REQUIRED = (short) 0x01F7; // Allow While On Body public static final short ALLOW_WHILE_ON_BODY = (short) 0x01FA; + // Max Boot Level + public static final short MAX_BOOT_LEVEL = (short) 0x03F2; // Trusted User Presence Required public static final short TRUSTED_USER_PRESENCE_REQUIRED = (short) 0x01FB; // Trusted Confirmation Required @@ -364,8 +366,6 @@ public abstract class KMType { public static final short MAX_SUBJECT_DER_LEN = 1095; - protected static short[] keyParamExp; - protected static KMRepository repository; protected static byte[] heap; // Instance table @@ -374,7 +374,6 @@ public abstract class KMType { public static void initialize() { instanceTable = JCSystem.makeTransientShortArray(INSTANCE_TABLE_SIZE, JCSystem.CLEAR_ON_RESET); - keyParamExp = JCSystem.makeTransientShortArray((short) 2, JCSystem.CLEAR_ON_RESET); KMType.repository = KMRepository.instance(); KMType.heap = repository.getHeap(); } @@ -407,10 +406,4 @@ protected static short exp(byte type) { Util.setShort(heap, (short) (ptr + 1), INVALID_VALUE); return ptr; } - - protected static void resetData() { - keyParamExp[0] = KMType.INVALID_VALUE; - keyParamExp[1] = KMType.INVALID_VALUE; - } - } From 19281fba12b10fb68556d3bc693821ecfbc93b80 Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Fri, 22 Apr 2022 01:26:29 +0000 Subject: [PATCH 4/6] Updated KMJCardSimulator hmacVerify --- .../com/android/javacard/seprovider/KMJCardSimulator.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java index ee5a8d4d..937fb349 100644 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java +++ b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java @@ -621,11 +621,9 @@ public short hmacSign(Object key, byte[] data, short dataStart, short dataLength @Override public boolean hmacVerify(KMComputedHmacKey key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart, short macLength) { - //KMHmacKey hmacKey = (KMHmacKey) key; - byte[] keyBuf = new byte[32]; - HMACKey hmacKey = createHMACKey(keyBuf, (short) 0, (short) keyBuf.length); - hmacSignature.init(hmacKey, Signature.MODE_VERIFY); - return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, macLength); + KMHmacKey hmacKey = (KMHmacKey) key; + hmacSignature.init(hmacKey.getKey(), Signature.MODE_VERIFY); + return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, macLength); } @Override From d0aab6af351849c4d121fe3bf39d1520a67fd9f2 Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Fri, 22 Apr 2022 01:34:05 +0000 Subject: [PATCH 5/6] Updated upgradeKeyChars function --- .../javacard/keymaster/KMKeymasterApplet.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 62436edf..bd269dc1 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -3781,20 +3781,6 @@ private static void upgradeKeyBlobKeyCharacteristics(short hwParams, byte[] scra hwParams, (byte) data[ORIGIN], osVersion, osPatch, vendorPatch, bootPatch, scratchPad); data[TEE_PARAMETERS] = KMKeyParameters.makeTeeEnforced(hwParams, scratchPad); data[HW_PARAMETERS] = KMKeyParameters.makeHwEnforced(data[SB_PARAMETERS], data[TEE_PARAMETERS]); - - // Create custom tags from tee params and remove the custom tags from old Keyblob keychars. - short version = KMInteger.cast(data[KEY_BLOB_VERSION_DATA_OFFSET]).getShort(); - switch (version) { - case 0: - case 1: - if (data[TEE_PARAMETERS] != KMType.INVALID_VALUE) { - KMKeyParameters.cast(data[TEE_PARAMETERS]).deleteCustomTags(); - } - break; - - default: - break; - } } private static void makeKeyCharacteristics(byte[] scratchPad) { From 1fff08ae92c997c0a335c58477a339c488878cb0 Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Tue, 26 Apr 2022 17:30:54 +0000 Subject: [PATCH 6/6] Added Comments --- .../javacard/keymaster/KMKeymasterApplet.java | 71 +++++++++++-------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index bd269dc1..a14933e3 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -808,20 +808,20 @@ private short createKeyBlobExp(short version) { case (short) 0: // Old KeyBlob has a maximum of 5 elements. keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V0); - KMArray.cast(keyBlob).add((short) 0, byteBlobExp); - KMArray.cast(keyBlob).add((short) 1, byteBlobExp); - KMArray.cast(keyBlob).add((short) 2, byteBlobExp); - KMArray.cast(keyBlob).add((short) 3, keyChar); - KMArray.cast(keyBlob).add((short) 4, byteBlobExp); + KMArray.cast(keyBlob).add((short) 0, byteBlobExp);// Secret + KMArray.cast(keyBlob).add((short) 1, byteBlobExp);// Nonce + KMArray.cast(keyBlob).add((short) 2, byteBlobExp);// AuthTag + KMArray.cast(keyBlob).add((short) 3, keyChar);// KeyChars + KMArray.cast(keyBlob).add((short) 4, byteBlobExp);// PubKey break; case (short) 1: keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V1); - KMArray.cast(keyBlob).add((short) 0, KMInteger.exp()); - KMArray.cast(keyBlob).add((short) 1, byteBlobExp); - KMArray.cast(keyBlob).add((short) 2, byteBlobExp); - KMArray.cast(keyBlob).add((short) 3, byteBlobExp); - KMArray.cast(keyBlob).add((short) 4, keyChar); - KMArray.cast(keyBlob).add((short) 5, byteBlobExp); + KMArray.cast(keyBlob).add((short) 0, KMInteger.exp());// Version + KMArray.cast(keyBlob).add((short) 1, byteBlobExp);// Secret + KMArray.cast(keyBlob).add((short) 2, byteBlobExp);// Nonce + KMArray.cast(keyBlob).add((short) 3, byteBlobExp);// AuthTag + KMArray.cast(keyBlob).add((short) 4, keyChar);// KeyChars + KMArray.cast(keyBlob).add((short) 5, byteBlobExp);// PubKey break; case (short) 2: keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V2); @@ -3031,9 +3031,6 @@ private void validateImportKey(short params, short keyFmt){ } private void importKey(APDU apdu, short keyFmt, byte[] scratchPad) { - // Take backup of the KeyParams before they get updated. The original - // key params are required to generate MAC in macKeyParams() function. - short keyParams = data[KEY_PARAMETERS]; validateImportKey(data[KEY_PARAMETERS], keyFmt); // Check algorithm and dispatch to appropriate handler. short alg = KMEnumTag.getValue(KMType.ALGORITHM, data[KEY_PARAMETERS]); @@ -3943,10 +3940,10 @@ private void decodeKeyBlob(short version, short keyBlob) { short minArraySize = 0; switch(version) { case 0: - minArraySize = (short) 4; + minArraySize = SYM_KEY_BLOB_SIZE_V0; break; case 1: - minArraySize = (short) 5; + minArraySize = SYM_KEY_BLOB_SIZE_V1; break; case 2: minArraySize = SYM_KEY_BLOB_SIZE_V2; @@ -3975,12 +3972,39 @@ private void processDecryptSecret(short version, short appId, short appData, byt short keyBlobSecretOff = 0; switch(version) { case 0: + // V0 KeyBlob + // KEY_BLOB = [ + // SECRET, + // NONCE, + // AUTH_TAG, + // KEY_CHARACTERISTICS, + // PUBKEY + // ] keyBlobSecretOff = (short) 0; break; case 1: + // V1 KeyBlob + // KEY_BLOB = [ + // VERSION, + // SECRET, + // NONCE, + // AUTH_TAG, + // KEY_CHARACTERISTICS, + // PUBKEY + // ] keyBlobSecretOff = (short) 1; break; case 2: + // V2 KeyBlob + // KEY_BLOB = [ + // VERSION, + // SECRET, + // NONCE, + // AUTH_TAG, + // KEY_CHARACTERISTICS, + // CUSTOM_TAGS, + // PUBKEY + // ] keyBlobSecretOff = KEY_BLOB_SECRET; break; default: @@ -4216,21 +4240,6 @@ private short addIntegers(short authTime, short timeStamp, byte[] scratchPad) { return KMInteger.uint_64(scratchPad, (short) 16); } - private void add(byte[] buf, short op1, short op2, short result) { - byte index = 7; - byte carry = 0; - short tmp; - while (index >= 0) { - tmp = (short) (buf[(short) (op1 + index)] + buf[(short) (op2 + index)] + carry); - carry = 0; - if (tmp > 255) { - carry = 1; // max unsigned byte value is 255 - } - buf[(short) (result + index)] = (byte) (tmp & (byte) 0xFF); - index--; - } - } - public void powerReset() { //TODO handle power reset signal. releaseAllOperations();