From 7655d9163ae00034929af07565db312c6fb6680e Mon Sep 17 00:00:00 2001 From: subrahmanyaman Date: Thu, 3 Nov 2022 06:33:09 +0000 Subject: [PATCH 1/7] NVM optimiztion --- .../keymaster/KMAttestationCertImpl.java | 635 ++++++++---------- .../keymaster/KMAttestationCertImpl.java | 556 ++++++++------- .../javacard/keymaster/KMAsn1Parser.java | 50 +- 3 files changed, 589 insertions(+), 652 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 45e354db..79369307 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -120,16 +120,6 @@ public class KMAttestationCertImpl implements KMAttestationCert { KMType.KEYSIZE, KMType.ALGORITHM, KMType.PURPOSE }; - // Validity is not fixed field - // Subject is a fixed field with only CN= Android Keystore Key - same for all the keys - private static final byte[] X509Subject = { - 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x41, 0x6e, - 0x64, - 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4B, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x4B, - 0x65, - 0x79 - }; - private static final byte keyUsageSign = (byte) 0x80; // 0 bit private static final byte keyUsageKeyEncipher = (byte) 0x20; // 2nd- bit private static final byte keyUsageDataEncipher = (byte) 0x10; // 3rd- bit @@ -139,48 +129,53 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static final short KEYMINT_VERSION = 200; private static final short ATTESTATION_VERSION = 200; private static final byte[] pubExponent = {0x01, 0x00, 0x01}; - private static final byte SERIAL_NUM = (byte) 0x01; private static final byte X509_VERSION = (byte) 0x02; - private static short certStart; - private static short certLength; - private static short tbsStart; - private static short tbsLength; - private static byte[] stack; - private static short stackPtr; - private static short bufStart; - private static short bufLength; - - private static short uniqueId; - private static short attChallenge; - private static short notBefore; - - private static short notAfter; - private static short pubKey; - private static short[] swParams; - private static short swParamsIndex; - private static short[] hwParams; - private static short hwParamsIndex; - private static byte keyUsage; - private static byte unusedBits; + // Buffer indexes in transient array + private static final short NUM_INDEX_ENTRIES = 21; + private static final byte CERT_START = (byte) 0; + private static final byte CERT_LENGTH = (byte) 1; + private static final byte TBS_START = (byte) 2; + private static final byte TBS_LENGTH = (byte) 3; + private static final byte BUF_START = (byte) 4; + private static final byte BUF_LENGTH = (byte) 5; + private static final byte SW_PARAM_INDEX = (byte) 6; + private static final byte HW_PARAM_INDEX = (byte) 7; + // Data indexes in transient array + private static final byte STACK_PTR = (byte) 8; + private static final byte UNIQUE_ID = (byte) 9; + private static final byte ATT_CHALLENGE = (byte) 10; + private static final byte NOT_BEFORE = (byte) 11; + private static final byte NOT_AFTER = (byte) 12; + private static final byte PUB_KEY = (byte) 13; + private static final byte VERIFIED_BOOT_KEY = (byte) 14; + private static final byte VERIFIED_HASH = (byte) 15; + private static final byte ISSUER = (byte) 16; + private static final byte SUBJECT_NAME = (byte) 17; + private static final byte SERIAL_NUMBER = (byte) 18; + private static final byte CERT_ATT_KEY_SECRET = (byte) 19; + private static final byte CERT_ATT_KEY_RSA_PUB_MOD = (byte) 20; + // State indexes in transient array + private static final short NUM_STATE_ENTRIES = 7; + private static final byte KEY_USAGE = (byte) 0; + private static final byte UNUSED_BITS = (byte) 1; + private static final byte DEVICE_LOCKED = (byte) 2; + private static final byte VERIFIED_STATE = (byte) 3; + private static final byte CERT_MODE = (byte) 4; + private static final byte RSA_CERT = (byte) 5; + private static final byte CERT_RSA_SIGN = (byte) 6; + private static KMAttestationCert inst; private static KMSEProvider seProvider; - private static boolean rsaCert; - private static byte deviceLocked; - private static short verifiedBootKey; - private static byte verifiedState; - private static short verifiedHash; - private static short issuer; - private static short subjectName; - private static short signPriv; - private static short serialNum; - - private static byte certMode; - private static short certAttestKeySecret; - private static short certAttestKeyRsaPubModulus; - private static boolean certRsaSign; + + private static short[] indexes; + private static byte[] states; + + private static byte[] stack; + private static short[] swParams; + private static short[] hwParams; + private static final byte SERIAL_NUM_MAX_LEN = 20; - private static final byte SUBJECT_NAME_MAX_LEN = 32; private KMAttestationCertImpl() { } @@ -188,89 +183,74 @@ private KMAttestationCertImpl() { public static KMAttestationCert instance(boolean rsaCert, KMSEProvider provider) { if (inst == null) { inst = new KMAttestationCertImpl(); - seProvider = provider; - } - init(); - KMAttestationCertImpl.rsaCert = rsaCert; + seProvider = provider; + + // Allocate transient memory + indexes = JCSystem.makeTransientShortArray(NUM_INDEX_ENTRIES, JCSystem.CLEAR_ON_RESET); + states = JCSystem.makeTransientByteArray(NUM_STATE_ENTRIES, JCSystem.CLEAR_ON_RESET); + swParams = JCSystem.makeTransientShortArray(MAX_PARAMS, JCSystem.CLEAR_ON_RESET); + hwParams = JCSystem.makeTransientShortArray(MAX_PARAMS, JCSystem.CLEAR_ON_RESET); + } + init(rsaCert); return inst; } - private static void init() { - stack = null; - stackPtr = 0; - certStart = 0; - certLength = 0; - bufStart = 0; - bufLength = 0; - tbsLength = 0; - if (swParams == null) { - swParams = JCSystem.makeTransientShortArray((short) MAX_PARAMS, JCSystem.CLEAR_ON_RESET); - } - if (hwParams == null) { - hwParams = JCSystem.makeTransientShortArray((short) MAX_PARAMS, JCSystem.CLEAR_ON_RESET); + private static void init(boolean rsaCert) { + for (short i = 0; i < NUM_INDEX_ENTRIES; i++) { + indexes[i] = 0; } - - swParamsIndex = 0; - hwParamsIndex = 0; - keyUsage = 0; - unusedBits = 8; - attChallenge = 0; - notBefore = 0; - notAfter = 0; - pubKey = 0; - uniqueId = 0; - verifiedBootKey = 0; - verifiedHash = 0; - verifiedState = 0; - rsaCert = true; - deviceLocked = 0; - signPriv = 0; - certMode = KMType.NO_CERT; - certAttestKeySecret = KMType.INVALID_VALUE; - certRsaSign = true; - issuer = KMType.INVALID_VALUE; - subjectName = KMType.INVALID_VALUE; - serialNum = KMType.INVALID_VALUE; + Util.arrayFillNonAtomic(states, (short) 0, NUM_STATE_ENTRIES, (byte) 0); + stack = null; + states[CERT_MODE] = KMType.NO_CERT; + states[UNUSED_BITS] = 8; + states[RSA_CERT] = rsaCert ? (byte) 1 : (byte) 0; + states[CERT_RSA_SIGN] = 1; + indexes[CERT_ATT_KEY_SECRET] = KMType.INVALID_VALUE; + indexes[CERT_ATT_KEY_RSA_PUB_MOD] = KMType.INVALID_VALUE; + indexes[ISSUER] = KMType.INVALID_VALUE; + indexes[SUBJECT_NAME] = KMType.INVALID_VALUE; + indexes[SERIAL_NUMBER] = KMType.INVALID_VALUE; } @Override public KMAttestationCert verifiedBootHash(short obj) { - verifiedHash = obj; + indexes[VERIFIED_HASH] = obj; return this; } @Override public KMAttestationCert verifiedBootKey(short obj) { - verifiedBootKey = obj; + indexes[VERIFIED_BOOT_KEY] = obj; return this; } @Override public KMAttestationCert verifiedBootState(byte val) { - verifiedState = val; + states[VERIFIED_STATE] = val; return this; } private KMAttestationCert uniqueId(short obj) { - uniqueId = obj; + indexes[UNIQUE_ID] = obj; return this; } @Override public KMAttestationCert notBefore(short obj, boolean derEncoded, byte[] scratchpad) { - if(!derEncoded) { + if (!derEncoded) { // convert milliseconds to UTC date - notBefore = KMUtils.convertToDate(obj, scratchpad, true); - }else{ - notBefore = KMByteBlob.instance(KMByteBlob.cast(obj).getBuffer(), + indexes[NOT_BEFORE] = KMUtils.convertToDate(obj, scratchpad, true); + } else { + indexes[NOT_BEFORE] = KMByteBlob.instance(KMByteBlob.cast(obj).getBuffer(), KMByteBlob.cast(obj).getStartOff(), KMByteBlob.cast(obj).length()); } return this; } @Override - public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, byte[] scratchPad) { - if(!derEncoded) { + public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, + byte[] scratchPad) { + if (!derEncoded) { if (usageExpiryTimeObj != KMType.INVALID_VALUE) { // compare if the expiry time is greater then 2050 then use generalized // time format else use utc time format. @@ -282,14 +262,12 @@ public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, usageExpiryTimeObj = KMUtils .convertToDate(usageExpiryTimeObj, scratchPad, true); } - notAfter = usageExpiryTimeObj; + indexes[NOT_AFTER] = usageExpiryTimeObj; } else { //notAfter = certExpirtyTimeObj; } - }else{ - notAfter = KMByteBlob.instance(KMByteBlob.cast(usageExpiryTimeObj).getBuffer(), - KMByteBlob.cast(usageExpiryTimeObj).getStartOff(), - KMByteBlob.cast(usageExpiryTimeObj).length()); + } else { + indexes[NOT_AFTER] = usageExpiryTimeObj; } return this; } @@ -297,33 +275,33 @@ public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, @Override public KMAttestationCert deviceLocked(boolean val) { if (val) { - deviceLocked = (byte) 0xFF; + states[DEVICE_LOCKED] = (byte) 0xFF; } else { - deviceLocked = 0; + states[DEVICE_LOCKED] = 0; } return this; } @Override public KMAttestationCert publicKey(short obj) { - pubKey = obj; + indexes[PUB_KEY] = obj; return this; } @Override public KMAttestationCert attestationChallenge(short obj) { - attChallenge = obj; + indexes[ATT_CHALLENGE] = obj; return this; } @Override public KMAttestationCert extensionTag(short tag, boolean hwEnforced) { if (hwEnforced) { - hwParams[hwParamsIndex] = tag; - hwParamsIndex++; + hwParams[indexes[HW_PARAM_INDEX]] = tag; + indexes[HW_PARAM_INDEX]++; } else { - swParams[swParamsIndex] = tag; - swParamsIndex++; + swParams[indexes[SW_PARAM_INDEX]] = tag; + indexes[SW_PARAM_INDEX]++; } if (KMTag.getKey(tag) == KMType.PURPOSE) { createKeyUsage(tag); @@ -333,7 +311,7 @@ public KMAttestationCert extensionTag(short tag, boolean hwEnforced) { @Override public KMAttestationCert issuer(short obj) { - issuer = obj; + indexes[ISSUER] = obj; return this; } @@ -342,29 +320,28 @@ private void createKeyUsage(short tag) { byte index = 0; while (index < len) { if (KMEnumArrayTag.cast(tag).get(index) == KMType.SIGN) { - keyUsage = (byte) (keyUsage | keyUsageSign); + states[KEY_USAGE] = (byte) (states[KEY_USAGE] | keyUsageSign); } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.WRAP_KEY) { - keyUsage = (byte) (keyUsage | keyUsageKeyEncipher); + states[KEY_USAGE] = (byte) (states[KEY_USAGE] | keyUsageKeyEncipher); } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.DECRYPT) { - keyUsage = (byte) (keyUsage | keyUsageDataEncipher); - } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.AGREE_KEY){ - keyUsage = (byte) (keyUsage | keyUsageKeyAgreement); - }else if (KMEnumArrayTag.cast(tag).get(index) == KMType.ATTEST_KEY){ - keyUsage = (byte) (keyUsage | keyUsageCertSign); + states[KEY_USAGE] = (byte) (states[KEY_USAGE] | keyUsageDataEncipher); + } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.AGREE_KEY) { + states[KEY_USAGE] = (byte) (states[KEY_USAGE] | keyUsageKeyAgreement); + } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.ATTEST_KEY) { + states[KEY_USAGE] = (byte) (states[KEY_USAGE] | keyUsageCertSign); } index++; } - index = keyUsage; + index = states[KEY_USAGE]; while (index != 0) { index = (byte) (index << 1); - unusedBits--; + states[UNUSED_BITS]--; } } -//TODO Serial number, X509Version needa to be passed as parameter private static void pushTbsCert(boolean rsaCert, boolean rsa) { - short last = stackPtr; - if(certMode == KMType.ATTESTATION_CERT) { + short last = indexes[STACK_PTR]; + if(states[CERT_MODE] == KMType.ATTESTATION_CERT) { pushExtensions(); } // subject public key info @@ -374,63 +351,64 @@ private static void pushTbsCert(boolean rsaCert, boolean rsa) { pushEccSubjectKeyInfo(); } // subject - pushBytes(KMByteBlob.cast(subjectName).getBuffer(), KMByteBlob.cast(subjectName).getStartOff(), - KMByteBlob.cast(subjectName).length()); + pushBytes(KMByteBlob.cast(indexes[SUBJECT_NAME]).getBuffer(), KMByteBlob.cast(indexes[SUBJECT_NAME]).getStartOff(), + KMByteBlob.cast(indexes[SUBJECT_NAME]).length()); pushValidity(); // issuer - der encoded pushBytes( - KMByteBlob.cast(issuer).getBuffer(), - KMByteBlob.cast(issuer).getStartOff(), - KMByteBlob.cast(issuer).length()); + KMByteBlob.cast(indexes[ISSUER]).getBuffer(), + KMByteBlob.cast(indexes[ISSUER]).getStartOff(), + KMByteBlob.cast(indexes[ISSUER]).length()); // Algorithm Id - if(rsa) { + if (rsa) { pushAlgorithmId(X509RsaSignAlgIdentifier); - }else{ + } else { pushAlgorithmId(X509EcdsaSignAlgIdentifier); } // Serial Number - pushBytes(KMByteBlob.cast(serialNum).getBuffer(), KMByteBlob.cast(serialNum).getStartOff(), - KMByteBlob.cast(serialNum).length()); - pushIntegerHeader(KMByteBlob.cast(serialNum).length()); + pushBytes(KMByteBlob.cast(indexes[SERIAL_NUMBER]).getBuffer(), KMByteBlob.cast(indexes[SERIAL_NUMBER]).getStartOff(), + KMByteBlob.cast(indexes[SERIAL_NUMBER]).length()); + pushIntegerHeader(KMByteBlob.cast(indexes[SERIAL_NUMBER]).length()); // Version pushByte(X509_VERSION); pushIntegerHeader((short) 1); pushByte((byte) 0x03); pushByte((byte) 0xA0); // Finally sequence header. - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushExtensions() { - short last = stackPtr; - if (keyUsage != 0) { - pushKeyUsage(keyUsage, unusedBits); + short last = indexes[STACK_PTR]; + // Push KeyUsage extension + if (states[KEY_USAGE] != 0) { + pushKeyUsage(states[KEY_USAGE], states[UNUSED_BITS]); } pushKeyDescription(); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); // Extensions have explicit tag of [3] - pushLength((short) (last - stackPtr)); + pushLength((short) (last - indexes[STACK_PTR])); pushByte((byte) 0xA3); } // Time SEQUENCE{UTCTime, UTC or Generalized Time) private static void pushValidity() { - short last = stackPtr; - if (notAfter != 0) { + short last = indexes[STACK_PTR]; + if (indexes[NOT_AFTER] != 0) { pushBytes( - KMByteBlob.cast(notAfter).getBuffer(), - KMByteBlob.cast(notAfter).getStartOff(), - KMByteBlob.cast(notAfter).length()); + KMByteBlob.cast(indexes[NOT_AFTER]).getBuffer(), + KMByteBlob.cast(indexes[NOT_AFTER]).getStartOff(), + KMByteBlob.cast(indexes[NOT_AFTER]).length()); } else { KMException.throwIt(KMError.INVALID_DATA); } - pushTimeHeader(KMByteBlob.cast(notAfter).length()); + pushTimeHeader(KMByteBlob.cast(indexes[NOT_AFTER]).length()); pushBytes( - KMByteBlob.cast(notBefore).getBuffer(), - KMByteBlob.cast(notBefore).getStartOff(), - KMByteBlob.cast(notBefore).length()); - pushTimeHeader(KMByteBlob.cast(notBefore).length()); - pushSequenceHeader((short) (last - stackPtr)); + KMByteBlob.cast(indexes[NOT_BEFORE]).getBuffer(), + KMByteBlob.cast(indexes[NOT_BEFORE]).getStartOff(), + KMByteBlob.cast(indexes[NOT_BEFORE]).length()); + pushTimeHeader(KMByteBlob.cast(indexes[NOT_BEFORE]).length()); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushTimeHeader(short len) { @@ -449,51 +427,51 @@ private static void pushTimeHeader(short len) { // exponent // as positive integer} private static void pushRsaSubjectKeyInfo() { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushBytes(pubExponent, (short) 0, (short) pubExponent.length); pushIntegerHeader((short) pubExponent.length); pushBytes( - KMByteBlob.cast(pubKey).getBuffer(), - KMByteBlob.cast(pubKey).getStartOff(), - KMByteBlob.cast(pubKey).length()); + KMByteBlob.cast(indexes[PUB_KEY]).getBuffer(), + KMByteBlob.cast(indexes[PUB_KEY]).getStartOff(), + KMByteBlob.cast(indexes[PUB_KEY]).length()); // encode modulus as positive if the MSB is 1. - if (KMByteBlob.cast(pubKey).get((short) 0) < 0) { + if (KMByteBlob.cast(indexes[PUB_KEY]).get((short) 0) < 0) { pushByte((byte) 0x00); - pushIntegerHeader((short) (KMByteBlob.cast(pubKey).length() + 1)); + pushIntegerHeader((short) (KMByteBlob.cast(indexes[PUB_KEY]).length() + 1)); } else { - pushIntegerHeader(KMByteBlob.cast(pubKey).length()); + pushIntegerHeader(KMByteBlob.cast(indexes[PUB_KEY]).length()); } - pushSequenceHeader((short) (last - stackPtr)); - pushBitStringHeader((byte) 0x00, (short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); + pushBitStringHeader((byte) 0x00, (short) (last - indexes[STACK_PTR])); pushRsaEncryption(); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } // SEQUENCE{SEQUENCE{ecPubKey, prime256v1}, bitString{pubKey}} private static void pushEccSubjectKeyInfo() { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushBytes( - KMByteBlob.cast(pubKey).getBuffer(), - KMByteBlob.cast(pubKey).getStartOff(), - KMByteBlob.cast(pubKey).length()); - pushBitStringHeader((byte) 0x00, KMByteBlob.cast(pubKey).length()); + KMByteBlob.cast(indexes[PUB_KEY]).getBuffer(), + KMByteBlob.cast(indexes[PUB_KEY]).getStartOff(), + KMByteBlob.cast(indexes[PUB_KEY]).length()); + pushBitStringHeader((byte) 0x00, KMByteBlob.cast(indexes[PUB_KEY]).length()); pushEcDsa(); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushEcDsa() { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushBytes(prime256v1, (short) 0, (short) prime256v1.length); pushBytes(eccPubKey, (short) 0, (short) eccPubKey.length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushRsaEncryption() { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushNullHeader(); pushBytes(rsaEncryption, (short) 0, (short) rsaEncryption.length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } // KeyDescription ::= SEQUENCE { @@ -507,45 +485,45 @@ private static void pushRsaEncryption() { // hardwareEnforced AuthorizationList, # See below // } private static void pushKeyDescription() { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushHWParams(); pushSWParams(); - if (uniqueId != 0) { + if (indexes[UNIQUE_ID] != 0) { pushOctetString( - KMByteBlob.cast(uniqueId).getBuffer(), - KMByteBlob.cast(uniqueId).getStartOff(), - KMByteBlob.cast(uniqueId).length()); + KMByteBlob.cast(indexes[UNIQUE_ID]).getBuffer(), + KMByteBlob.cast(indexes[UNIQUE_ID]).getStartOff(), + KMByteBlob.cast(indexes[UNIQUE_ID]).length()); } else { pushOctetStringHeader((short) 0); } pushOctetString( - KMByteBlob.cast(attChallenge).getBuffer(), - KMByteBlob.cast(attChallenge).getStartOff(), - KMByteBlob.cast(attChallenge).length()); + KMByteBlob.cast(indexes[ATT_CHALLENGE]).getBuffer(), + KMByteBlob.cast(indexes[ATT_CHALLENGE]).getStartOff(), + KMByteBlob.cast(indexes[ATT_CHALLENGE]).length()); pushEnumerated(KMType.STRONGBOX); pushShort(KEYMINT_VERSION); pushIntegerHeader((short) 2); pushEnumerated(KMType.STRONGBOX); pushShort(ATTESTATION_VERSION); pushIntegerHeader((short) 2); - pushSequenceHeader((short) (last - stackPtr)); - pushOctetStringHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); + pushOctetStringHeader((short) (last - indexes[STACK_PTR])); pushBytes(androidExtn, (short) 0, (short) androidExtn.length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushSWParams() { - short last = stackPtr; + short last = indexes[STACK_PTR]; byte index = 0; short length = (short) swTagIds.length; do { - pushParams(swParams, swParamsIndex, swTagIds[index]); + pushParams(swParams, indexes[SW_PARAM_INDEX], swTagIds[index]); } while (++index < length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushHWParams() { - short last = stackPtr; + short last = indexes[STACK_PTR]; byte index = 0; short length = (short) hwTagIds.length; do { @@ -553,11 +531,11 @@ private static void pushHWParams() { pushRoT(); continue; } - if (pushParams(hwParams, hwParamsIndex, hwTagIds[index])) { + if (pushParams(hwParams, indexes[HW_PARAM_INDEX], hwTagIds[index])) { continue; } } while (++index < length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static boolean pushParams(short[] params, short len, short tagId) { @@ -609,7 +587,7 @@ private static void pushTag(short tag) { break; case KMType.UINT_ARRAY_TAG: case KMType.ULONG_ARRAY_TAG: - // According to keymaster hal only one user secure id is used but this conflicts with + // According to KeyMint hal only one user secure id is used but this conflicts with // tag type which is ULONG-REP. Currently this is encoded as SET OF INTEGERS val = KMIntegerArrayTag.cast(tag).getValues(); pushIntegerArrayTag(tagId, val); @@ -637,26 +615,26 @@ private static void pushTag(short tag) { // Failed (3), // } private static void pushRoT() { - short last = stackPtr; + short last = indexes[STACK_PTR]; // verified boot hash pushOctetString( - KMByteBlob.cast(verifiedHash).getBuffer(), - KMByteBlob.cast(verifiedHash).getStartOff(), - KMByteBlob.cast(verifiedHash).length()); + KMByteBlob.cast(indexes[VERIFIED_HASH]).getBuffer(), + KMByteBlob.cast(indexes[VERIFIED_HASH]).getStartOff(), + KMByteBlob.cast(indexes[VERIFIED_HASH]).length()); - pushEnumerated(verifiedState); + pushEnumerated(states[VERIFIED_STATE]); - pushBoolean(deviceLocked); + pushBoolean(states[DEVICE_LOCKED]); // verified boot Key pushOctetString( - KMByteBlob.cast(verifiedBootKey).getBuffer(), - KMByteBlob.cast(verifiedBootKey).getStartOff(), - KMByteBlob.cast(verifiedBootKey).length()); + KMByteBlob.cast(indexes[VERIFIED_BOOT_KEY]).getBuffer(), + KMByteBlob.cast(indexes[VERIFIED_BOOT_KEY]).getStartOff(), + KMByteBlob.cast(indexes[VERIFIED_BOOT_KEY]).length()); // Finally sequence header - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); // ... and tag Id - pushTagIdHeader(KMType.ROOT_OF_TRUST, (short) (last - stackPtr)); + pushTagIdHeader(KMType.ROOT_OF_TRUST, (short) (last - indexes[STACK_PTR])); } private static void pushOctetString(byte[] buf, short start, short len) { @@ -677,21 +655,21 @@ private static void pushBooleanHeader(short len) { // Only SET of INTEGERS supported are padding, digest, purpose and blockmode // All of these are enum array tags i.e. byte long values private static void pushEnumArrayTag(short tagId, byte[] buf, short start, short len) { - short last = stackPtr; + short last = indexes[STACK_PTR]; short index = 0; while (index < len) { pushByte(buf[(short) (start + index)]); pushIntegerHeader((short) 1); index++; } - pushSetHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushSetHeader((short) (last - indexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - indexes[STACK_PTR])); } // Only SET of INTEGERS supported are padding, digest, purpose and blockmode // All of these are enum array tags i.e. byte long values private static void pushIntegerArrayTag(short tagId, short arr) { - short last = stackPtr; + short last = indexes[STACK_PTR]; short index = 0; short len = KMArray.cast(arr).length(); short ptr; @@ -703,8 +681,8 @@ private static void pushIntegerArrayTag(short tagId, short arr) { KMInteger.cast(ptr).length()); index++; } - pushSetHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushSetHeader((short) (last - indexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - indexes[STACK_PTR])); } private static void pushSetHeader(short len) { @@ -713,9 +691,9 @@ private static void pushSetHeader(short len) { } private static void pushEnumerated(byte val) { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushByte(val); - pushEnumeratedHeader((short) (last - stackPtr)); + pushEnumeratedHeader((short) (last - indexes[STACK_PTR])); } private static void pushEnumeratedHeader(short len) { @@ -724,9 +702,9 @@ private static void pushEnumeratedHeader(short len) { } private static void pushBoolTag(short tagId) { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushNullHeader(); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushTagIdHeader(tagId, (short) (last - indexes[STACK_PTR])); } private static void pushNullHeader() { @@ -735,23 +713,22 @@ private static void pushNullHeader() { } private static void pushEnumTag(short tagId, byte val) { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushByte(val); - pushIntegerHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushIntegerHeader((short) (last - indexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - indexes[STACK_PTR])); } private static void pushIntegerTag(short tagId, byte[] buf, short start, short len) { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushInteger(buf, start, len); - // pushIntegerHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushTagIdHeader(tagId, (short) (last - indexes[STACK_PTR])); } // Ignore leading zeros. Only Unsigned Integers are required hence if MSB is set then add 0x00 // as most significant byte. private static void pushInteger(byte[] buf, short start, short len) { - short last = stackPtr; + short last = indexes[STACK_PTR]; byte index = 0; while (index < (byte) len) { if (buf[(short) (start + index)] != 0) { @@ -767,15 +744,15 @@ private static void pushInteger(byte[] buf, short start, short len) { pushByte((byte) 0x00); // always unsigned int } } - pushIntegerHeader((short) (last - stackPtr)); + pushIntegerHeader((short) (last - indexes[STACK_PTR])); } // Bytes Tag is a octet string and tag id is added explicitly private static void pushBytesTag(short tagId, byte[] buf, short start, short len) { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushBytes(buf, start, len); - pushOctetStringHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushOctetStringHeader((short) (last - indexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - indexes[STACK_PTR])); } // tag id <= 30 ---> 0xA0 | {tagId} @@ -798,12 +775,12 @@ private static void pushTagIdHeader(short tagId, short len) { // SEQUENCE {ObjId, OCTET STRING{BIT STRING{keyUsage}}} private static void pushKeyUsage(byte keyUsage, byte unusedBits) { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushByte(keyUsage); - pushBitStringHeader(unusedBits, (short) (last - stackPtr)); - pushOctetStringHeader((short) (last - stackPtr)); + pushBitStringHeader(unusedBits, (short) (last - indexes[STACK_PTR])); + pushOctetStringHeader((short) (last - indexes[STACK_PTR])); pushBytes(keyUsageExtn, (short) 0, (short) keyUsageExtn.length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushAlgorithmId(byte[] algId) { @@ -845,24 +822,24 @@ private static void pushLength(short len) { private static void pushShort(short val) { decrementStackPtr((short) 2); - Util.setShort(stack, stackPtr, val); + Util.setShort(stack, indexes[STACK_PTR], val); } private static void pushByte(byte val) { decrementStackPtr((short) 1); - stack[stackPtr] = val; + stack[indexes[STACK_PTR]] = val; } private static void pushBytes(byte[] buf, short start, short len) { decrementStackPtr(len); if (buf != null) { - Util.arrayCopyNonAtomic(buf, start, stack, stackPtr, len); + Util.arrayCopyNonAtomic(buf, start, stack, indexes[STACK_PTR], len); } } private static void decrementStackPtr(short cnt) { - stackPtr = (short) (stackPtr - cnt); - if (bufStart > stackPtr) { + indexes[STACK_PTR] = (short) (indexes[STACK_PTR] - cnt); + if (indexes[BUF_START] > indexes[STACK_PTR]) { KMException.throwIt(KMError.UNKNOWN_ERROR); } } @@ -870,101 +847,86 @@ private static void decrementStackPtr(short cnt) { @Override public KMAttestationCert buffer(byte[] buf, short start, short maxLen) { stack = buf; - bufStart = start; - bufLength = maxLen; - stackPtr = (short) (bufStart + bufLength); + indexes[BUF_START] = start; + indexes[BUF_LENGTH] = maxLen; + indexes[STACK_PTR] = (short) (indexes[BUF_START] + indexes[BUF_LENGTH]); return this; } @Override public short getCertStart() { - return certStart; + return indexes[CERT_START]; } @Override public short getCertLength() { - return certLength; - } - -public void build(short attSecret, short attMod, boolean rsaSign, boolean fakeCert) { - stackPtr = (short)(bufStart + bufLength); - short last = stackPtr; - short sigLen = 0; - if(fakeCert){ - rsaSign = true; - pushByte((byte)0); - sigLen = 1; - } - // Push placeholder signature Bit string header - // This will potentially change at the end - else if (rsaSign) { - decrementStackPtr(RSA_SIG_LEN); - } else { - decrementStackPtr(ECDSA_MAX_SIG_LEN); - } - short signatureOffset = stackPtr; - pushBitStringHeader((byte) 0, (short) (last - stackPtr)); - if (rsaSign) { - pushAlgorithmId(X509RsaSignAlgIdentifier); - } else { - pushAlgorithmId(X509EcdsaSignAlgIdentifier); - } - tbsLength = stackPtr; - pushTbsCert(rsaCert, rsaSign); - tbsStart = stackPtr; - tbsLength = (short) (tbsLength - tbsStart); - if(attSecret != KMType.INVALID_VALUE){ - // Sign with the attestation key - // The pubKey is the modulus. - if (rsaSign) { - sigLen = seProvider - .rsaSign256Pkcs1( - KMByteBlob.cast(attSecret).getBuffer(), - KMByteBlob.cast(attSecret).getStartOff(), - KMByteBlob.cast(attSecret).length(), - KMByteBlob.cast(attMod).getBuffer(), - KMByteBlob.cast(attMod).getStartOff(), - KMByteBlob.cast(attMod).length(), - stack, - tbsStart, - tbsLength, - stack, - signatureOffset); - if(sigLen > RSA_SIG_LEN) KMException.throwIt(KMError.UNKNOWN_ERROR); - } else { - sigLen = seProvider - .ecSign256( - KMByteBlob.cast(attSecret).getBuffer(), - KMByteBlob.cast(attSecret).getStartOff(), - KMByteBlob.cast(attSecret).length(), - stack, - tbsStart, - tbsLength, - stack, - signatureOffset); - if (sigLen > ECDSA_MAX_SIG_LEN) KMException.throwIt(KMError.UNKNOWN_ERROR); - } - // Adjust signature length - stackPtr = signatureOffset; - pushBitStringHeader((byte) 0, sigLen); - }else if(!fakeCert){ // no attestation key provisioned in the factory - KMException.throwIt(KMError.ATTESTATION_KEYS_NOT_PROVISIONED); - } - last = (short)(signatureOffset+sigLen); - // Add certificate sequence header - stackPtr = tbsStart; - pushSequenceHeader((short) (last - stackPtr)); - certStart = stackPtr; - certLength = (short)(last - certStart); - //print(stack, getCertStart(), getCertLength()); - } - - @Override - public void build() { - if(certMode == KMType.FAKE_CERT) { + return indexes[CERT_LENGTH]; + } + + public void build(short attSecret, short attMod, boolean rsaSign, boolean fakeCert) { + indexes[STACK_PTR] = (short) (indexes[BUF_START] + indexes[BUF_LENGTH]); + short last = indexes[STACK_PTR]; + short sigLen = 0; + if (fakeCert) { + rsaSign = true; + pushByte((byte) 0); + sigLen = 1; + } + // Push placeholder signature Bit string header + // This will potentially change at the end + else if (rsaSign) { + decrementStackPtr(RSA_SIG_LEN); + } else { + decrementStackPtr(ECDSA_MAX_SIG_LEN); + } + short signatureOffset = indexes[STACK_PTR]; + pushBitStringHeader((byte) 0, (short) (last - indexes[STACK_PTR])); + if (rsaSign) { + pushAlgorithmId(X509RsaSignAlgIdentifier); + } else { + pushAlgorithmId(X509EcdsaSignAlgIdentifier); + } + indexes[TBS_LENGTH] = indexes[STACK_PTR]; + pushTbsCert((states[RSA_CERT] == 0 ? false : true), rsaSign); + indexes[TBS_START] = indexes[STACK_PTR]; + indexes[TBS_LENGTH] = (short) (indexes[TBS_LENGTH] - indexes[TBS_START]); + if (attSecret != KMType.INVALID_VALUE) { + // Sign with the attestation key + // The pubKey is the modulus. + if (rsaSign) { + sigLen = seProvider.rsaSign256Pkcs1(KMByteBlob.cast(attSecret).getBuffer(), + KMByteBlob.cast(attSecret).getStartOff(), KMByteBlob.cast(attSecret).length(), + KMByteBlob.cast(attMod).getBuffer(), KMByteBlob.cast(attMod).getStartOff(), + KMByteBlob.cast(attMod).length(), stack, indexes[TBS_START], indexes[TBS_LENGTH], stack, signatureOffset); + if (sigLen > RSA_SIG_LEN) + KMException.throwIt(KMError.UNKNOWN_ERROR); + } else { + sigLen = seProvider.ecSign256(KMByteBlob.cast(attSecret).getBuffer(), KMByteBlob.cast(attSecret).getStartOff(), + KMByteBlob.cast(attSecret).length(), stack, indexes[TBS_START], indexes[TBS_LENGTH], stack, + signatureOffset); + if (sigLen > ECDSA_MAX_SIG_LEN) + KMException.throwIt(KMError.UNKNOWN_ERROR); + } + // Adjust signature length + indexes[STACK_PTR] = signatureOffset; + pushBitStringHeader((byte) 0, sigLen); + } else if (!fakeCert) { // No attestation key provisioned in the factory + KMException.throwIt(KMError.ATTESTATION_KEYS_NOT_PROVISIONED); + } + last = (short) (signatureOffset + sigLen); + // Add certificate sequence header + indexes[STACK_PTR] = indexes[TBS_START]; + pushSequenceHeader((short) (last - indexes[STACK_PTR])); + indexes[CERT_START] = indexes[STACK_PTR]; + indexes[CERT_LENGTH] = (short) (last - indexes[CERT_START]); + } + + @Override + public void build() { + if(states[CERT_MODE] == KMType.FAKE_CERT) { build(KMType.INVALID_VALUE, KMType.INVALID_VALUE, true, true); - }else { - build(certAttestKeySecret, certAttestKeyRsaPubModulus, certRsaSign, false); + } else { + build(indexes[CERT_ATT_KEY_SECRET], indexes[CERT_ATT_KEY_RSA_PUB_MOD], (states[CERT_RSA_SIGN] == 0 ? false: true), false); } } @@ -1013,50 +975,43 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, } @Override - public boolean serialNumber(short number){ + public boolean serialNumber(short number) { + // https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.2 short length = KMByteBlob.cast(number).length(); - if(length > SERIAL_NUM_MAX_LEN){ + if(length > SERIAL_NUM_MAX_LEN) { return false; } - byte msb = KMByteBlob.cast(number).get((short)0); - if(msb < 0 && length > (SERIAL_NUM_MAX_LEN -1)){ + // The serial number Must be a positive integer. + byte msb = KMByteBlob.cast(number).get((short) 0); + if(msb < 0 && length > (SERIAL_NUM_MAX_LEN -1)) { return false; } - serialNum = number; + indexes[SERIAL_NUMBER] = number; return true; } @Override - public boolean subjectName(short sub){ - /* - short length = KMByteBlob.cast(sub).length(); - if(length > SUBJECT_NAME_MAX_LEN){ - return false; - } - Util.arrayCopyNonAtomic(KMByteBlob.cast(sub).getBuffer(), KMByteBlob.cast(sub).getStartOff(), - subjectName,(short)0,length); - subjectLen = length; - */ + public boolean subjectName(short sub) { if(sub == KMType.INVALID_VALUE || KMByteBlob.cast(sub).length() == 0) return false; - subjectName = sub; + indexes[SUBJECT_NAME] = sub; return true; } - + @Override - public KMAttestationCert ecAttestKey(short attestKey, byte mode){ - certMode = mode; - certAttestKeySecret = attestKey; - certAttestKeyRsaPubModulus = KMType.INVALID_VALUE; - certRsaSign = false; + public KMAttestationCert ecAttestKey(short attestKey, byte mode) { + states[CERT_MODE] = mode; + indexes[CERT_ATT_KEY_SECRET] = attestKey; + indexes[CERT_ATT_KEY_RSA_PUB_MOD] = KMType.INVALID_VALUE; + states[CERT_RSA_SIGN] = 0; return this; } @Override - public KMAttestationCert rsaAttestKey(short attestPrivExp, short attestMod, byte mode){ - certMode = mode; - certAttestKeySecret = attestPrivExp; - certAttestKeyRsaPubModulus = attestMod; - certRsaSign = true; + public KMAttestationCert rsaAttestKey(short attestPrivExp, short attestMod, byte mode) { + states[CERT_MODE] = mode; + indexes[CERT_ATT_KEY_SECRET] = attestPrivExp; + indexes[CERT_ATT_KEY_RSA_PUB_MOD] = attestMod; + states[CERT_RSA_SIGN] = 1; return this; } diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index df078971..45a88dcd 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -18,7 +18,6 @@ import com.android.javacard.seprovider.KMAESKey; import com.android.javacard.seprovider.KMAttestationCert; import com.android.javacard.seprovider.KMException; -import com.android.javacard.seprovider.KMJCardSimulator; import com.android.javacard.seprovider.KMMasterKey; import com.android.javacard.seprovider.KMSEProvider; import javacard.framework.JCSystem; @@ -110,7 +109,7 @@ public class KMAttestationCertImpl implements KMAttestationCert { KMType.ATTESTATION_ID_SERIAL, KMType.ATTESTATION_ID_PRODUCT, KMType.ATTESTATION_ID_DEVICE, KMType.ATTESTATION_ID_BRAND, KMType.OS_PATCH_LEVEL, KMType.OS_VERSION, KMType.ROOT_OF_TRUST, - KMType.ORIGIN, KMType.UNLOCKED_DEVICE_REQUIRED, + KMType.ORIGIN, KMType.UNLOCKED_DEVICE_REQUIRED, KMType.TRUSTED_CONFIRMATION_REQUIRED, KMType.AUTH_TIMEOUT, KMType.USER_AUTH_TYPE, KMType.NO_AUTH_REQUIRED, KMType.EARLY_BOOT_ONLY, @@ -120,16 +119,6 @@ public class KMAttestationCertImpl implements KMAttestationCert { KMType.KEYSIZE, KMType.ALGORITHM, KMType.PURPOSE }; - // Validity is not fixed field - // Subject is a fixed field with only CN= Android Keystore Key - same for all the keys - private static final byte[] X509Subject = { - 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x14, 0x41, 0x6e, - 0x64, - 0x72, 0x6f, 0x69, 0x64, 0x20, 0x4B, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x4B, - 0x65, - 0x79 - }; - private static final byte keyUsageSign = (byte) 0x80; // 0 bit private static final byte keyUsageKeyEncipher = (byte) 0x20; // 2nd- bit private static final byte keyUsageDataEncipher = (byte) 0x10; // 3rd- bit @@ -142,45 +131,51 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static final byte SERIAL_NUM = (byte) 0x01; private static final byte X509_VERSION = (byte) 0x02; - private static short certStart; - private static short certLength; - private static short tbsStart; - private static short tbsLength; - private static byte[] stack; - private static short stackPtr; - private static short bufStart; - private static short bufLength; + // Buffer indexes in transient array + private static final short NUM_INDEX_ENTRIES = 21; + private static final byte CERT_START = (byte) 0; + private static final byte CERT_LENGTH = (byte) 1; + private static final byte TBS_START = (byte) 2; + private static final byte TBS_LENGTH = (byte) 3; + private static final byte BUF_START = (byte) 4; + private static final byte BUF_LENGTH = (byte) 5; + private static final byte SW_PARAM_INDEX = (byte) 6; + private static final byte HW_PARAM_INDEX = (byte) 7; + // Data indexes in transient array + private static final byte STACK_PTR = (byte) 8; + private static final byte UNIQUE_ID = (byte) 9; + private static final byte ATT_CHALLENGE = (byte) 10; + private static final byte NOT_BEFORE = (byte) 11; + private static final byte NOT_AFTER = (byte) 12; + private static final byte PUB_KEY = (byte) 13; + private static final byte VERIFIED_BOOT_KEY = (byte) 14; + private static final byte VERIFIED_HASH = (byte) 15; + private static final byte ISSUER = (byte) 16; + private static final byte SUBJECT_NAME = (byte) 17; + private static final byte SERIAL_NUMBER = (byte) 18; + private static final byte CERT_ATT_KEY_SECRET = (byte) 19; + private static final byte CERT_ATT_KEY_RSA_PUB_MOD = (byte) 20; + // State indexes in transient array + private static final short NUM_STATE_ENTRIES = 7; + private static final byte KEY_USAGE = (byte) 0; + private static final byte UNUSED_BITS = (byte) 1; + private static final byte DEVICE_LOCKED = (byte) 2; + private static final byte VERIFIED_STATE = (byte) 3; + private static final byte CERT_MODE = (byte) 4; + private static final byte RSA_CERT = (byte) 5; + private static final byte CERT_RSA_SIGN = (byte) 6; + + private static KMAttestationCert inst; + private static KMSEProvider seProvider; - private static short uniqueId; - private static short attChallenge; - private static short notBefore; + private static short[] indexes; + private static byte[] states; - private static short notAfter; - private static short pubKey; + private static byte[] stack; private static short[] swParams; - private static short swParamsIndex; private static short[] hwParams; - private static short hwParamsIndex; - private static byte keyUsage; - private static byte unusedBits; - private static KMAttestationCert inst; - private static KMSEProvider seProvider; - private static boolean rsaCert; - private static byte deviceLocked; - private static short verifiedBootKey; - private static byte verifiedState; - private static short verifiedHash; - private static short issuer; - private static short subjectName; - private static short signPriv; - private static short serialNum; - - private static byte certMode; - private static short certAttestKeySecret; - private static short certAttestKeyRsaPubModulus; - private static boolean certRsaSign; + private static final byte SERIAL_NUM_MAX_LEN = 20; - private static final byte SUBJECT_NAME_MAX_LEN = 32; private KMAttestationCertImpl() { } @@ -189,88 +184,73 @@ public static KMAttestationCert instance(boolean rsaCert, KMSEProvider provider) if (inst == null) { inst = new KMAttestationCertImpl(); seProvider = provider; + + // Allocate transient memory + indexes = JCSystem.makeTransientShortArray(NUM_INDEX_ENTRIES, JCSystem.CLEAR_ON_RESET); + states = JCSystem.makeTransientByteArray(NUM_STATE_ENTRIES, JCSystem.CLEAR_ON_RESET); + swParams = JCSystem.makeTransientShortArray(MAX_PARAMS, JCSystem.CLEAR_ON_RESET); + hwParams = JCSystem.makeTransientShortArray(MAX_PARAMS, JCSystem.CLEAR_ON_RESET); } - init(); - KMAttestationCertImpl.rsaCert = rsaCert; + init(rsaCert); return inst; } - private static void init() { - stack = null; - stackPtr = 0; - certStart = 0; - certLength = 0; - bufStart = 0; - bufLength = 0; - tbsLength = 0; - if (swParams == null) { - swParams = JCSystem.makeTransientShortArray((short) MAX_PARAMS, JCSystem.CLEAR_ON_RESET); + private static void init(boolean rsaCert) { + for (short i = 0; i < NUM_INDEX_ENTRIES; i++) { + indexes[i] = 0; } - if (hwParams == null) { - hwParams = JCSystem.makeTransientShortArray((short) MAX_PARAMS, JCSystem.CLEAR_ON_RESET); - } - - swParamsIndex = 0; - hwParamsIndex = 0; - keyUsage = 0; - unusedBits = 8; - attChallenge = 0; - notBefore = 0; - notAfter = 0; - pubKey = 0; - uniqueId = 0; - verifiedBootKey = 0; - verifiedHash = 0; - verifiedState = 0; - rsaCert = true; - deviceLocked = 0; - signPriv = 0; - certMode = KMType.NO_CERT; - certAttestKeySecret = KMType.INVALID_VALUE; - certRsaSign = true; - issuer = KMType.INVALID_VALUE; - subjectName = KMType.INVALID_VALUE; - serialNum = KMType.INVALID_VALUE; + Util.arrayFillNonAtomic(states, (short) 0, NUM_STATE_ENTRIES, (byte) 0); + stack = null; + states[CERT_MODE] = KMType.NO_CERT; + states[UNUSED_BITS] = 8; + states[RSA_CERT] = rsaCert ? (byte) 1 : (byte) 0; + states[CERT_RSA_SIGN] = 1; + indexes[CERT_ATT_KEY_SECRET] = KMType.INVALID_VALUE; + indexes[CERT_ATT_KEY_RSA_PUB_MOD] = KMType.INVALID_VALUE; + indexes[ISSUER] = KMType.INVALID_VALUE; + indexes[SUBJECT_NAME] = KMType.INVALID_VALUE; + indexes[SERIAL_NUMBER] = KMType.INVALID_VALUE; } @Override public KMAttestationCert verifiedBootHash(short obj) { - verifiedHash = obj; + indexes[VERIFIED_HASH] = obj; return this; } @Override public KMAttestationCert verifiedBootKey(short obj) { - verifiedBootKey = obj; + indexes[VERIFIED_BOOT_KEY] = obj; return this; } @Override public KMAttestationCert verifiedBootState(byte val) { - verifiedState = val; + states[VERIFIED_STATE] = val; return this; } private KMAttestationCert uniqueId(short obj) { - uniqueId = obj; + indexes[UNIQUE_ID] = obj; return this; } @Override public KMAttestationCert notBefore(short obj, boolean derEncoded, byte[] scratchpad) { - if(!derEncoded) { + if (!derEncoded) { // convert milliseconds to UTC date - notBefore = KMUtils.convertToDate(obj, scratchpad, true); - }else{ - notBefore = KMByteBlob.instance(KMByteBlob.cast(obj).getBuffer(), + indexes[NOT_BEFORE] = KMUtils.convertToDate(obj, scratchpad, true); + } else { + indexes[NOT_BEFORE] = KMByteBlob.instance(KMByteBlob.cast(obj).getBuffer(), KMByteBlob.cast(obj).getStartOff(), KMByteBlob.cast(obj).length()); } return this; } @Override - public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, byte[] scratchPad) { - if(!derEncoded) { + public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, + byte[] scratchPad) { + if (!derEncoded) { if (usageExpiryTimeObj != KMType.INVALID_VALUE) { // compare if the expiry time is greater then 2050 then use generalized // time format else use utc time format. @@ -282,14 +262,12 @@ public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, usageExpiryTimeObj = KMUtils .convertToDate(usageExpiryTimeObj, scratchPad, true); } - notAfter = usageExpiryTimeObj; + indexes[NOT_AFTER] = usageExpiryTimeObj; } else { //notAfter = certExpirtyTimeObj; } - }else{ - notAfter = KMByteBlob.instance(KMByteBlob.cast(usageExpiryTimeObj).getBuffer(), - KMByteBlob.cast(usageExpiryTimeObj).getStartOff(), - KMByteBlob.cast(usageExpiryTimeObj).length()); + } else { + indexes[NOT_AFTER] = usageExpiryTimeObj; } return this; } @@ -297,33 +275,33 @@ public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, @Override public KMAttestationCert deviceLocked(boolean val) { if (val) { - deviceLocked = (byte) 0xFF; + states[DEVICE_LOCKED] = (byte) 0xFF; } else { - deviceLocked = 0; + states[DEVICE_LOCKED] = 0; } return this; } @Override public KMAttestationCert publicKey(short obj) { - pubKey = obj; + indexes[PUB_KEY] = obj; return this; } @Override public KMAttestationCert attestationChallenge(short obj) { - attChallenge = obj; + indexes[ATT_CHALLENGE] = obj; return this; } @Override public KMAttestationCert extensionTag(short tag, boolean hwEnforced) { if (hwEnforced) { - hwParams[hwParamsIndex] = tag; - hwParamsIndex++; + hwParams[indexes[HW_PARAM_INDEX]] = tag; + indexes[HW_PARAM_INDEX]++; } else { - swParams[swParamsIndex] = tag; - swParamsIndex++; + swParams[indexes[SW_PARAM_INDEX]] = tag; + indexes[SW_PARAM_INDEX]++; } if (KMTag.getKey(tag) == KMType.PURPOSE) { createKeyUsage(tag); @@ -333,7 +311,7 @@ public KMAttestationCert extensionTag(short tag, boolean hwEnforced) { @Override public KMAttestationCert issuer(short obj) { - issuer = obj; + indexes[ISSUER] = obj; return this; } @@ -342,31 +320,28 @@ private void createKeyUsage(short tag) { byte index = 0; while (index < len) { if (KMEnumArrayTag.cast(tag).get(index) == KMType.SIGN) { - keyUsage = (byte) (keyUsage | keyUsageSign); + states[KEY_USAGE] = (byte) (states[KEY_USAGE] | keyUsageSign); } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.WRAP_KEY) { - keyUsage = (byte) (keyUsage | keyUsageKeyEncipher); + states[KEY_USAGE] = (byte) (states[KEY_USAGE] | keyUsageKeyEncipher); } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.DECRYPT) { - keyUsage = (byte) (keyUsage | keyUsageDataEncipher); - } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.AGREE_KEY){ - keyUsage = (byte) (keyUsage | keyUsageKeyAgreement); - }else if (KMEnumArrayTag.cast(tag).get(index) == KMType.ATTEST_KEY){ - keyUsage = (byte) (keyUsage | keyUsageCertSign); + states[KEY_USAGE] = (byte) (states[KEY_USAGE] | keyUsageDataEncipher); + } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.AGREE_KEY) { + states[KEY_USAGE] = (byte) (states[KEY_USAGE] | keyUsageKeyAgreement); + } else if (KMEnumArrayTag.cast(tag).get(index) == KMType.ATTEST_KEY) { + states[KEY_USAGE] = (byte) (states[KEY_USAGE] | keyUsageCertSign); } index++; } - index = keyUsage; + index = states[KEY_USAGE]; while (index != 0) { index = (byte) (index << 1); - unusedBits--; + states[UNUSED_BITS]--; } } - //TODO Serial number, X509Version needa to be passed as parameter private static void pushTbsCert(boolean rsaCert, boolean rsa) { - short last = stackPtr; - if(certMode == KMType.ATTESTATION_CERT) { - pushExtensions(); - } + short last = indexes[STACK_PTR]; + pushExtensions(); // subject public key info if (rsaCert) { pushRsaSubjectKeyInfo(); @@ -374,63 +349,68 @@ private static void pushTbsCert(boolean rsaCert, boolean rsa) { pushEccSubjectKeyInfo(); } // subject - pushBytes(KMByteBlob.cast(subjectName).getBuffer(), KMByteBlob.cast(subjectName).getStartOff(), - KMByteBlob.cast(subjectName).length()); + pushBytes(KMByteBlob.cast(indexes[SUBJECT_NAME]).getBuffer(), + KMByteBlob.cast(indexes[SUBJECT_NAME]).getStartOff(), + KMByteBlob.cast(indexes[SUBJECT_NAME]).length()); pushValidity(); // issuer - der encoded pushBytes( - KMByteBlob.cast(issuer).getBuffer(), - KMByteBlob.cast(issuer).getStartOff(), - KMByteBlob.cast(issuer).length()); + KMByteBlob.cast(indexes[ISSUER]).getBuffer(), + KMByteBlob.cast(indexes[ISSUER]).getStartOff(), + KMByteBlob.cast(indexes[ISSUER]).length()); // Algorithm Id - if(rsa) { + if (rsa) { pushAlgorithmId(X509RsaSignAlgIdentifier); - }else{ + } else { pushAlgorithmId(X509EcdsaSignAlgIdentifier); } // Serial Number - pushBytes(KMByteBlob.cast(serialNum).getBuffer(), KMByteBlob.cast(serialNum).getStartOff(), - KMByteBlob.cast(serialNum).length()); - pushIntegerHeader(KMByteBlob.cast(serialNum).length()); + pushBytes(KMByteBlob.cast(indexes[SERIAL_NUMBER]).getBuffer(), + KMByteBlob.cast(indexes[SERIAL_NUMBER]).getStartOff(), + KMByteBlob.cast(indexes[SERIAL_NUMBER]).length()); + pushIntegerHeader(KMByteBlob.cast(indexes[SERIAL_NUMBER]).length()); // Version pushByte(X509_VERSION); pushIntegerHeader((short) 1); pushByte((byte) 0x03); pushByte((byte) 0xA0); // Finally sequence header. - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushExtensions() { - short last = stackPtr; - if (keyUsage != 0) { - pushKeyUsage(keyUsage, unusedBits); + short last = indexes[STACK_PTR]; + // Push KeyUsage extension + if (states[KEY_USAGE] != 0) { + pushKeyUsage(states[KEY_USAGE], states[UNUSED_BITS]); + } + if (states[CERT_MODE] == KMType.ATTESTATION_CERT) { + pushKeyDescription(); } - pushKeyDescription(); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); // Extensions have explicit tag of [3] - pushLength((short) (last - stackPtr)); + pushLength((short) (last - indexes[STACK_PTR])); pushByte((byte) 0xA3); } // Time SEQUENCE{UTCTime, UTC or Generalized Time) private static void pushValidity() { - short last = stackPtr; - if (notAfter != 0) { + short last = indexes[STACK_PTR]; + if (indexes[NOT_AFTER] != 0) { pushBytes( - KMByteBlob.cast(notAfter).getBuffer(), - KMByteBlob.cast(notAfter).getStartOff(), - KMByteBlob.cast(notAfter).length()); + KMByteBlob.cast(indexes[NOT_AFTER]).getBuffer(), + KMByteBlob.cast(indexes[NOT_AFTER]).getStartOff(), + KMByteBlob.cast(indexes[NOT_AFTER]).length()); } else { KMException.throwIt(KMError.INVALID_DATA); } - pushTimeHeader(KMByteBlob.cast(notAfter).length()); + pushTimeHeader(KMByteBlob.cast(indexes[NOT_AFTER]).length()); pushBytes( - KMByteBlob.cast(notBefore).getBuffer(), - KMByteBlob.cast(notBefore).getStartOff(), - KMByteBlob.cast(notBefore).length()); - pushTimeHeader(KMByteBlob.cast(notBefore).length()); - pushSequenceHeader((short) (last - stackPtr)); + KMByteBlob.cast(indexes[NOT_BEFORE]).getBuffer(), + KMByteBlob.cast(indexes[NOT_BEFORE]).getStartOff(), + KMByteBlob.cast(indexes[NOT_BEFORE]).length()); + pushTimeHeader(KMByteBlob.cast(indexes[NOT_BEFORE]).length()); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushTimeHeader(short len) { @@ -449,51 +429,51 @@ private static void pushTimeHeader(short len) { // exponent // as positive integer} private static void pushRsaSubjectKeyInfo() { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushBytes(pubExponent, (short) 0, (short) pubExponent.length); pushIntegerHeader((short) pubExponent.length); pushBytes( - KMByteBlob.cast(pubKey).getBuffer(), - KMByteBlob.cast(pubKey).getStartOff(), - KMByteBlob.cast(pubKey).length()); + KMByteBlob.cast(indexes[PUB_KEY]).getBuffer(), + KMByteBlob.cast(indexes[PUB_KEY]).getStartOff(), + KMByteBlob.cast(indexes[PUB_KEY]).length()); // encode modulus as positive if the MSB is 1. - if (KMByteBlob.cast(pubKey).get((short) 0) < 0) { + if (KMByteBlob.cast(indexes[PUB_KEY]).get((short) 0) < 0) { pushByte((byte) 0x00); - pushIntegerHeader((short) (KMByteBlob.cast(pubKey).length() + 1)); + pushIntegerHeader((short) (KMByteBlob.cast(indexes[PUB_KEY]).length() + 1)); } else { - pushIntegerHeader(KMByteBlob.cast(pubKey).length()); + pushIntegerHeader(KMByteBlob.cast(indexes[PUB_KEY]).length()); } - pushSequenceHeader((short) (last - stackPtr)); - pushBitStringHeader((byte) 0x00, (short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); + pushBitStringHeader((byte) 0x00, (short) (last - indexes[STACK_PTR])); pushRsaEncryption(); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } // SEQUENCE{SEQUENCE{ecPubKey, prime256v1}, bitString{pubKey}} private static void pushEccSubjectKeyInfo() { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushBytes( - KMByteBlob.cast(pubKey).getBuffer(), - KMByteBlob.cast(pubKey).getStartOff(), - KMByteBlob.cast(pubKey).length()); - pushBitStringHeader((byte) 0x00, KMByteBlob.cast(pubKey).length()); + KMByteBlob.cast(indexes[PUB_KEY]).getBuffer(), + KMByteBlob.cast(indexes[PUB_KEY]).getStartOff(), + KMByteBlob.cast(indexes[PUB_KEY]).length()); + pushBitStringHeader((byte) 0x00, KMByteBlob.cast(indexes[PUB_KEY]).length()); pushEcDsa(); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushEcDsa() { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushBytes(prime256v1, (short) 0, (short) prime256v1.length); pushBytes(eccPubKey, (short) 0, (short) eccPubKey.length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushRsaEncryption() { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushNullHeader(); pushBytes(rsaEncryption, (short) 0, (short) rsaEncryption.length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } // KeyDescription ::= SEQUENCE { @@ -507,45 +487,45 @@ private static void pushRsaEncryption() { // hardwareEnforced AuthorizationList, # See below // } private static void pushKeyDescription() { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushHWParams(); pushSWParams(); - if (uniqueId != 0) { + if (indexes[UNIQUE_ID] != 0) { pushOctetString( - KMByteBlob.cast(uniqueId).getBuffer(), - KMByteBlob.cast(uniqueId).getStartOff(), - KMByteBlob.cast(uniqueId).length()); + KMByteBlob.cast(indexes[UNIQUE_ID]).getBuffer(), + KMByteBlob.cast(indexes[UNIQUE_ID]).getStartOff(), + KMByteBlob.cast(indexes[UNIQUE_ID]).length()); } else { pushOctetStringHeader((short) 0); } pushOctetString( - KMByteBlob.cast(attChallenge).getBuffer(), - KMByteBlob.cast(attChallenge).getStartOff(), - KMByteBlob.cast(attChallenge).length()); + KMByteBlob.cast(indexes[ATT_CHALLENGE]).getBuffer(), + KMByteBlob.cast(indexes[ATT_CHALLENGE]).getStartOff(), + KMByteBlob.cast(indexes[ATT_CHALLENGE]).length()); pushEnumerated(KMType.STRONGBOX); pushShort(KEYMINT_VERSION); pushIntegerHeader((short) 2); pushEnumerated(KMType.STRONGBOX); pushShort(ATTESTATION_VERSION); pushIntegerHeader((short) 2); - pushSequenceHeader((short) (last - stackPtr)); - pushOctetStringHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); + pushOctetStringHeader((short) (last - indexes[STACK_PTR])); pushBytes(androidExtn, (short) 0, (short) androidExtn.length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushSWParams() { - short last = stackPtr; + short last = indexes[STACK_PTR]; byte index = 0; short length = (short) swTagIds.length; do { - pushParams(swParams, swParamsIndex, swTagIds[index]); + pushParams(swParams, indexes[SW_PARAM_INDEX], swTagIds[index]); } while (++index < length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushHWParams() { - short last = stackPtr; + short last = indexes[STACK_PTR]; byte index = 0; short length = (short) hwTagIds.length; do { @@ -553,11 +533,11 @@ private static void pushHWParams() { pushRoT(); continue; } - if (pushParams(hwParams, hwParamsIndex, hwTagIds[index])) { + if (pushParams(hwParams, indexes[HW_PARAM_INDEX], hwTagIds[index])) { continue; } } while (++index < length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static boolean pushParams(short[] params, short len, short tagId) { @@ -609,7 +589,7 @@ private static void pushTag(short tag) { break; case KMType.UINT_ARRAY_TAG: case KMType.ULONG_ARRAY_TAG: - // According to keymaster hal only one user secure id is used but this conflicts with + // According to KeyMint hal only one user secure id is used but this conflicts with // tag type which is ULONG-REP. Currently this is encoded as SET OF INTEGERS val = KMIntegerArrayTag.cast(tag).getValues(); pushIntegerArrayTag(tagId, val); @@ -637,26 +617,26 @@ private static void pushTag(short tag) { // Failed (3), // } private static void pushRoT() { - short last = stackPtr; + short last = indexes[STACK_PTR]; // verified boot hash pushOctetString( - KMByteBlob.cast(verifiedHash).getBuffer(), - KMByteBlob.cast(verifiedHash).getStartOff(), - KMByteBlob.cast(verifiedHash).length()); + KMByteBlob.cast(indexes[VERIFIED_HASH]).getBuffer(), + KMByteBlob.cast(indexes[VERIFIED_HASH]).getStartOff(), + KMByteBlob.cast(indexes[VERIFIED_HASH]).length()); - pushEnumerated(verifiedState); + pushEnumerated(states[VERIFIED_STATE]); - pushBoolean(deviceLocked); + pushBoolean(states[DEVICE_LOCKED]); // verified boot Key pushOctetString( - KMByteBlob.cast(verifiedBootKey).getBuffer(), - KMByteBlob.cast(verifiedBootKey).getStartOff(), - KMByteBlob.cast(verifiedBootKey).length()); + KMByteBlob.cast(indexes[VERIFIED_BOOT_KEY]).getBuffer(), + KMByteBlob.cast(indexes[VERIFIED_BOOT_KEY]).getStartOff(), + KMByteBlob.cast(indexes[VERIFIED_BOOT_KEY]).length()); // Finally sequence header - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); // ... and tag Id - pushTagIdHeader(KMType.ROOT_OF_TRUST, (short) (last - stackPtr)); + pushTagIdHeader(KMType.ROOT_OF_TRUST, (short) (last - indexes[STACK_PTR])); } private static void pushOctetString(byte[] buf, short start, short len) { @@ -677,21 +657,21 @@ private static void pushBooleanHeader(short len) { // Only SET of INTEGERS supported are padding, digest, purpose and blockmode // All of these are enum array tags i.e. byte long values private static void pushEnumArrayTag(short tagId, byte[] buf, short start, short len) { - short last = stackPtr; + short last = indexes[STACK_PTR]; short index = 0; while (index < len) { pushByte(buf[(short) (start + index)]); pushIntegerHeader((short) 1); index++; } - pushSetHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushSetHeader((short) (last - indexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - indexes[STACK_PTR])); } // Only SET of INTEGERS supported are padding, digest, purpose and blockmode // All of these are enum array tags i.e. byte long values private static void pushIntegerArrayTag(short tagId, short arr) { - short last = stackPtr; + short last = indexes[STACK_PTR]; short index = 0; short len = KMArray.cast(arr).length(); short ptr; @@ -703,8 +683,8 @@ private static void pushIntegerArrayTag(short tagId, short arr) { KMInteger.cast(ptr).length()); index++; } - pushSetHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushSetHeader((short) (last - indexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - indexes[STACK_PTR])); } private static void pushSetHeader(short len) { @@ -713,9 +693,9 @@ private static void pushSetHeader(short len) { } private static void pushEnumerated(byte val) { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushByte(val); - pushEnumeratedHeader((short) (last - stackPtr)); + pushEnumeratedHeader((short) (last - indexes[STACK_PTR])); } private static void pushEnumeratedHeader(short len) { @@ -724,9 +704,9 @@ private static void pushEnumeratedHeader(short len) { } private static void pushBoolTag(short tagId) { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushNullHeader(); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushTagIdHeader(tagId, (short) (last - indexes[STACK_PTR])); } private static void pushNullHeader() { @@ -735,23 +715,22 @@ private static void pushNullHeader() { } private static void pushEnumTag(short tagId, byte val) { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushByte(val); - pushIntegerHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushIntegerHeader((short) (last - indexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - indexes[STACK_PTR])); } private static void pushIntegerTag(short tagId, byte[] buf, short start, short len) { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushInteger(buf, start, len); - // pushIntegerHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushTagIdHeader(tagId, (short) (last - indexes[STACK_PTR])); } // Ignore leading zeros. Only Unsigned Integers are required hence if MSB is set then add 0x00 // as most significant byte. private static void pushInteger(byte[] buf, short start, short len) { - short last = stackPtr; + short last = indexes[STACK_PTR]; byte index = 0; while (index < (byte) len) { if (buf[(short) (start + index)] != 0) { @@ -767,15 +746,15 @@ private static void pushInteger(byte[] buf, short start, short len) { pushByte((byte) 0x00); // always unsigned int } } - pushIntegerHeader((short) (last - stackPtr)); + pushIntegerHeader((short) (last - indexes[STACK_PTR])); } // Bytes Tag is a octet string and tag id is added explicitly private static void pushBytesTag(short tagId, byte[] buf, short start, short len) { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushBytes(buf, start, len); - pushOctetStringHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushOctetStringHeader((short) (last - indexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - indexes[STACK_PTR])); } // tag id <= 30 ---> 0xA0 | {tagId} @@ -798,12 +777,12 @@ private static void pushTagIdHeader(short tagId, short len) { // SEQUENCE {ObjId, OCTET STRING{BIT STRING{keyUsage}}} private static void pushKeyUsage(byte keyUsage, byte unusedBits) { - short last = stackPtr; + short last = indexes[STACK_PTR]; pushByte(keyUsage); - pushBitStringHeader(unusedBits, (short) (last - stackPtr)); - pushOctetStringHeader((short) (last - stackPtr)); + pushBitStringHeader(unusedBits, (short) (last - indexes[STACK_PTR])); + pushOctetStringHeader((short) (last - indexes[STACK_PTR])); pushBytes(keyUsageExtn, (short) 0, (short) keyUsageExtn.length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - indexes[STACK_PTR])); } private static void pushAlgorithmId(byte[] algId) { @@ -845,24 +824,24 @@ private static void pushLength(short len) { private static void pushShort(short val) { decrementStackPtr((short) 2); - Util.setShort(stack, stackPtr, val); + Util.setShort(stack, indexes[STACK_PTR], val); } private static void pushByte(byte val) { decrementStackPtr((short) 1); - stack[stackPtr] = val; + stack[indexes[STACK_PTR]] = val; } private static void pushBytes(byte[] buf, short start, short len) { decrementStackPtr(len); if (buf != null) { - Util.arrayCopyNonAtomic(buf, start, stack, stackPtr, len); + Util.arrayCopyNonAtomic(buf, start, stack, indexes[STACK_PTR], len); } } private static void decrementStackPtr(short cnt) { - stackPtr = (short) (stackPtr - cnt); - if (bufStart > stackPtr) { + indexes[STACK_PTR] = (short) (indexes[STACK_PTR] - cnt); + if (indexes[BUF_START] > indexes[STACK_PTR]) { KMException.throwIt(KMError.UNKNOWN_ERROR); } } @@ -870,29 +849,29 @@ private static void decrementStackPtr(short cnt) { @Override public KMAttestationCert buffer(byte[] buf, short start, short maxLen) { stack = buf; - bufStart = start; - bufLength = maxLen; - stackPtr = (short) (bufStart + bufLength); + indexes[BUF_START] = start; + indexes[BUF_LENGTH] = maxLen; + indexes[STACK_PTR] = (short) (indexes[BUF_START] + indexes[BUF_LENGTH]); return this; } @Override public short getCertStart() { - return certStart; + return indexes[CERT_START]; } @Override public short getCertLength() { - return certLength; + return indexes[CERT_LENGTH]; } public void build(short attSecret, short attMod, boolean rsaSign, boolean fakeCert) { - stackPtr = (short)(bufStart + bufLength); - short last = stackPtr; + indexes[STACK_PTR] = (short) (indexes[BUF_START] + indexes[BUF_LENGTH]); + short last = indexes[STACK_PTR]; short sigLen = 0; - if(fakeCert){ + if (fakeCert) { rsaSign = true; - pushByte((byte)0); + pushByte((byte) 0); sigLen = 1; } // Push placeholder signature Bit string header @@ -902,18 +881,18 @@ else if (rsaSign) { } else { decrementStackPtr(ECDSA_MAX_SIG_LEN); } - short signatureOffset = stackPtr; - pushBitStringHeader((byte) 0, (short) (last - stackPtr)); + short signatureOffset = indexes[STACK_PTR]; + pushBitStringHeader((byte) 0, (short) (last - indexes[STACK_PTR])); if (rsaSign) { pushAlgorithmId(X509RsaSignAlgIdentifier); } else { pushAlgorithmId(X509EcdsaSignAlgIdentifier); } - tbsLength = stackPtr; - pushTbsCert(rsaCert, rsaSign); - tbsStart = stackPtr; - tbsLength = (short) (tbsLength - tbsStart); - if(attSecret != KMType.INVALID_VALUE){ + indexes[TBS_LENGTH] = indexes[STACK_PTR]; + pushTbsCert((states[RSA_CERT] == 0 ? false : true), rsaSign); + indexes[TBS_START] = indexes[STACK_PTR]; + indexes[TBS_LENGTH] = (short) (indexes[TBS_LENGTH] - indexes[TBS_START]); + if (attSecret != KMType.INVALID_VALUE) { // Sign with the attestation key // The pubKey is the modulus. if (rsaSign) { @@ -926,11 +905,13 @@ else if (rsaSign) { KMByteBlob.cast(attMod).getStartOff(), KMByteBlob.cast(attMod).length(), stack, - tbsStart, - tbsLength, + indexes[TBS_START], + indexes[TBS_LENGTH], stack, signatureOffset); - if(sigLen > RSA_SIG_LEN) KMException.throwIt(KMError.UNKNOWN_ERROR); + if (sigLen > RSA_SIG_LEN) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } } else { sigLen = seProvider .ecSign256( @@ -938,33 +919,35 @@ else if (rsaSign) { KMByteBlob.cast(attSecret).getStartOff(), KMByteBlob.cast(attSecret).length(), stack, - tbsStart, - tbsLength, + indexes[TBS_START], + indexes[TBS_LENGTH], stack, signatureOffset); - if (sigLen > ECDSA_MAX_SIG_LEN) KMException.throwIt(KMError.UNKNOWN_ERROR); + if (sigLen > ECDSA_MAX_SIG_LEN) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } } // Adjust signature length - stackPtr = signatureOffset; + indexes[STACK_PTR] = signatureOffset; pushBitStringHeader((byte) 0, sigLen); - }else if(!fakeCert){ // no attestation key provisioned in the factory + } else if (!fakeCert) { // No attestation key provisioned in the factory KMException.throwIt(KMError.ATTESTATION_KEYS_NOT_PROVISIONED); } - last = (short)(signatureOffset+sigLen); + last = (short) (signatureOffset + sigLen); // Add certificate sequence header - stackPtr = tbsStart; - pushSequenceHeader((short) (last - stackPtr)); - certStart = stackPtr; - certLength = (short)(last - certStart); - //print(stack, getCertStart(), getCertLength()); + indexes[STACK_PTR] = indexes[TBS_START]; + pushSequenceHeader((short) (last - indexes[STACK_PTR])); + indexes[CERT_START] = indexes[STACK_PTR]; + indexes[CERT_LENGTH] = (short) (last - indexes[CERT_START]); } @Override public void build() { - if(certMode == KMType.FAKE_CERT) { + if (states[CERT_MODE] == KMType.FAKE_CERT) { build(KMType.INVALID_VALUE, KMType.INVALID_VALUE, true, true); - }else { - build(certAttestKeySecret, certAttestKeyRsaPubModulus, certRsaSign, false); + } else { + build(indexes[CERT_ATT_KEY_SECRET], indexes[CERT_ATT_KEY_RSA_PUB_MOD], + (states[CERT_RSA_SIGN] == 0 ? false : true), false); } } @@ -1013,59 +996,54 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, } @Override - public boolean serialNumber(short number){ + public boolean serialNumber(short number) { + // https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.2 short length = KMByteBlob.cast(number).length(); - if(length > SERIAL_NUM_MAX_LEN){ + if (length > SERIAL_NUM_MAX_LEN) { return false; } - byte msb = KMByteBlob.cast(number).get((short)0); - if(msb < 0 && length > (SERIAL_NUM_MAX_LEN -1)){ + // The serial number Must be a positive integer. + byte msb = KMByteBlob.cast(number).get((short) 0); + if (msb < 0 && length > (SERIAL_NUM_MAX_LEN - 1)) { return false; } - serialNum = number; + indexes[SERIAL_NUMBER] = number; return true; } @Override - public boolean subjectName(short sub){ - /* - short length = KMByteBlob.cast(sub).length(); - if(length > SUBJECT_NAME_MAX_LEN){ + public boolean subjectName(short sub) { + if (sub == KMType.INVALID_VALUE || KMByteBlob.cast(sub).length() == 0) { return false; } - Util.arrayCopyNonAtomic(KMByteBlob.cast(sub).getBuffer(), KMByteBlob.cast(sub).getStartOff(), - subjectName,(short)0,length); - subjectLen = length; - */ - if(sub == KMType.INVALID_VALUE || KMByteBlob.cast(sub).length() == 0) return false; - subjectName = sub; + indexes[SUBJECT_NAME] = sub; return true; } @Override - public KMAttestationCert ecAttestKey(short attestKey, byte mode){ - certMode = mode; - certAttestKeySecret = attestKey; - certAttestKeyRsaPubModulus = KMType.INVALID_VALUE; - certRsaSign = false; + public KMAttestationCert ecAttestKey(short attestKey, byte mode) { + states[CERT_MODE] = mode; + indexes[CERT_ATT_KEY_SECRET] = attestKey; + indexes[CERT_ATT_KEY_RSA_PUB_MOD] = KMType.INVALID_VALUE; + states[CERT_RSA_SIGN] = 0; return this; } @Override - public KMAttestationCert rsaAttestKey(short attestPrivExp, short attestMod, byte mode){ - certMode = mode; - certAttestKeySecret = attestPrivExp; - certAttestKeyRsaPubModulus = attestMod; - certRsaSign = true; + public KMAttestationCert rsaAttestKey(short attestPrivExp, short attestMod, byte mode) { + states[CERT_MODE] = mode; + indexes[CERT_ATT_KEY_SECRET] = attestPrivExp; + indexes[CERT_ATT_KEY_RSA_PUB_MOD] = attestMod; + states[CERT_RSA_SIGN] = 1; return this; } - private void print(byte[] buf, short start, short length){ + private void print(byte[] buf, short start, short length) { StringBuilder sb = new StringBuilder(length * 2); - for(short i = start; i < (start+length); i ++){ + for (short i = start; i < (start + length); i++) { sb.append(String.format("%02x", buf[i])); } - System.out.println( sb.toString()); + System.out.println(sb.toString()); } } diff --git a/Applet/src/com/android/javacard/keymaster/KMAsn1Parser.java b/Applet/src/com/android/javacard/keymaster/KMAsn1Parser.java index be6590e3..dff22dee 100644 --- a/Applet/src/com/android/javacard/keymaster/KMAsn1Parser.java +++ b/Applet/src/com/android/javacard/keymaster/KMAsn1Parser.java @@ -1,6 +1,8 @@ package com.android.javacard.keymaster; import com.android.javacard.seprovider.KMException; + +import javacard.framework.JCSystem; import javacard.framework.Util; public class KMAsn1Parser { @@ -19,6 +21,9 @@ public class KMAsn1Parser { public static final byte ASN1_UNIVERSAL_STRING = 0x1C; public static final byte ASN1_BMP_STRING = 0x1E; public static final byte IA5_STRING = 0x16; + private static final byte DATA_START_OFFSET = 0; + private static final byte DATA_LENGTH_OFFSET = 1; + private static final byte DATA_CURSOR_OFFSET = 2; public static final byte[] EC_CURVE = { 0x06,0x08,0x2a,(byte)0x86,0x48,(byte)0xce,0x3d,0x03, @@ -87,14 +92,13 @@ public class KMAsn1Parser { (byte) 0x80 /* 1-128 pseudonym */ }; private byte[] data; - private short start; - private short length; - private short cur; + private short[] dataInfo; private static KMAsn1Parser inst; - private KMAsn1Parser(){ - start = 0; - length = 0; - cur = 0; + private KMAsn1Parser() { + dataInfo = JCSystem.makeTransientShortArray((short) 3, JCSystem.CLEAR_ON_RESET); + dataInfo[DATA_START_OFFSET] = 0; + dataInfo[DATA_LENGTH_OFFSET] = 0; + dataInfo[DATA_CURSOR_OFFSET] = 0; } public short decodeRsa(short blob){ @@ -124,7 +128,7 @@ SET SIZE (1..MAX) OF AttributeTypeAndValue public void validateDerSubject(short blob) { init(blob); header(ASN1_SEQUENCE); - while (cur < ((short) (start + length))) { + while (dataInfo[DATA_CURSOR_OFFSET] < ((short) (dataInfo[DATA_START_OFFSET] + dataInfo[DATA_LENGTH_OFFSET]))) { header(ASN1_SET); header(ASN1_SEQUENCE); // Parse and validate OBJECT-IDENTIFIER and Value fields @@ -265,20 +269,20 @@ public short decodeEcPrivateKey(short version){ return resp; } private void validateTag0IfPresent(){ - if(data[cur] != ASN1_A0_TAG) return;; + if(data[dataInfo[DATA_CURSOR_OFFSET]] != ASN1_A0_TAG) return;; short len = header(ASN1_A0_TAG); if(len != EC_CURVE.length) KMException.throwIt(KMError.UNKNOWN_ERROR); - if(Util.arrayCompare(data, cur, EC_CURVE, (short)0, len) != 0) KMException.throwIt(KMError.UNKNOWN_ERROR); + if(Util.arrayCompare(data, dataInfo[DATA_CURSOR_OFFSET], EC_CURVE, (short)0, len) != 0) KMException.throwIt(KMError.UNKNOWN_ERROR); incrementCursor(len); } private void validateAttributeTypeAndValue() { // First byte should be OBJECT_IDENTIFIER, otherwise it is not well-formed DER Subject. - if (data[cur] != OBJECT_IDENTIFIER) { + if (data[dataInfo[DATA_CURSOR_OFFSET]] != OBJECT_IDENTIFIER) { KMException.throwIt(KMError.UNKNOWN_ERROR); } // Check if the OID matches the email address - if ((Util.arrayCompare(data, cur, EMAIL_ADDRESS_OID, (short) 0, + if ((Util.arrayCompare(data, dataInfo[DATA_CURSOR_OFFSET], EMAIL_ADDRESS_OID, (short) 0, (short) EMAIL_ADDRESS_OID.length) == 0)) { incrementCursor((short) EMAIL_ADDRESS_OID.length); // Validate the length of the attribute value. @@ -294,8 +298,8 @@ private void validateAttributeTypeAndValue() { } // Check other OIDs. for (short i = 0; i < (short) attributeOIds.length; i++) { - if ((Util.arrayCompare(data, cur, COMMON_OID, (short) 0, (short) COMMON_OID.length) == 0) && - (attributeOIds[i] == data[(short) (cur + COMMON_OID.length)])) { + if ((Util.arrayCompare(data, dataInfo[DATA_CURSOR_OFFSET], COMMON_OID, (short) 0, (short) COMMON_OID.length) == 0) && + (attributeOIds[i] == data[(short) (dataInfo[DATA_CURSOR_OFFSET] + COMMON_OID.length)])) { incrementCursor((short) (COMMON_OID.length + 1)); // Validate the length of the attribute value. short tag = getByte(); @@ -328,26 +332,26 @@ private short header(short tag){ } private byte getByte(){ - byte d = data[cur]; + byte d = data[dataInfo[DATA_CURSOR_OFFSET]]; incrementCursor((short)1); return d; } private short getShort(){ - short d = Util.getShort(data, cur); + short d = Util.getShort(data, dataInfo[DATA_CURSOR_OFFSET]); incrementCursor((short)2); return d; } private void getBytes(short blob){ short len = KMByteBlob.cast(blob).length(); - Util.arrayCopyNonAtomic(data, cur, KMByteBlob.cast(blob).getBuffer(), + Util.arrayCopyNonAtomic(data, dataInfo[DATA_CURSOR_OFFSET], KMByteBlob.cast(blob).getBuffer(), KMByteBlob.cast(blob).getStartOff(), len); incrementCursor(len); } private void getBytes(byte[] buffer, short offset, short len) { - Util.arrayCopyNonAtomic(data, cur, buffer, offset, len); + Util.arrayCopyNonAtomic(data, dataInfo[DATA_CURSOR_OFFSET], buffer, offset, len); incrementCursor(len); } @@ -369,13 +373,13 @@ public static KMAsn1Parser instance() { public void init(short blob) { data = KMByteBlob.cast(blob).getBuffer(); - start = KMByteBlob.cast(blob).getStartOff(); - length = KMByteBlob.cast(blob).length(); - cur = start; + dataInfo[DATA_START_OFFSET] = KMByteBlob.cast(blob).getStartOff(); + dataInfo[DATA_LENGTH_OFFSET] = KMByteBlob.cast(blob).length(); + dataInfo[DATA_CURSOR_OFFSET] = dataInfo[DATA_START_OFFSET]; } public void incrementCursor(short n){ - cur += n; - if(cur > ((short)(start+length))) KMException.throwIt(KMError.UNKNOWN_ERROR); + dataInfo[DATA_CURSOR_OFFSET] += n; + if(dataInfo[DATA_CURSOR_OFFSET] > ((short)(dataInfo[DATA_START_OFFSET]+ dataInfo[DATA_LENGTH_OFFSET]))) KMException.throwIt(KMError.UNKNOWN_ERROR); } } From ae8e69d6b2e4d0dccd97ec911ba87c1c02c0f6c0 Mon Sep 17 00:00:00 2001 From: subrahmanyaman Date: Thu, 3 Nov 2022 06:42:18 +0000 Subject: [PATCH 2/7] Add keyusage extension in self signed certificate --- .../android/javacard/keymaster/KMAttestationCertImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 79369307..83647056 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -341,9 +341,7 @@ private void createKeyUsage(short tag) { private static void pushTbsCert(boolean rsaCert, boolean rsa) { short last = indexes[STACK_PTR]; - if(states[CERT_MODE] == KMType.ATTESTATION_CERT) { - pushExtensions(); - } + pushExtensions(); // subject public key info if (rsaCert) { pushRsaSubjectKeyInfo(); @@ -384,7 +382,9 @@ private static void pushExtensions() { if (states[KEY_USAGE] != 0) { pushKeyUsage(states[KEY_USAGE], states[UNUSED_BITS]); } - pushKeyDescription(); + if (states[CERT_MODE] == KMType.ATTESTATION_CERT) { + pushKeyDescription(); + } pushSequenceHeader((short) (last - indexes[STACK_PTR])); // Extensions have explicit tag of [3] pushLength((short) (last - indexes[STACK_PTR])); From 76d33f8c553ed69a1133d0113df4eeafcaf23b3f Mon Sep 17 00:00:00 2001 From: subrahmanyaman Date: Thu, 3 Nov 2022 06:48:06 +0000 Subject: [PATCH 3/7] Unwrapping params should have SH256 and RSA_OAEP as digest and padding --- .../android/javacard/keymaster/KMKeymasterApplet.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index da8aa4b7..fcf526ef 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -1358,6 +1358,15 @@ private void validateWrappingKeyBlob(){ if (!KMEnumArrayTag.contains(KMType.PURPOSE, KMType.WRAP_KEY, data[HW_PARAMETERS])) { KMException.throwIt((KMError.INCOMPATIBLE_PURPOSE)); } + + // Check that the digest and padding mode specified in unwrapping parameters are SHA2_256 + // and RSA_OAEP respectively. + if (!KMEnumArrayTag.contains(KMType.DIGEST, KMType.SHA2_256, data[KEY_PARAMETERS])) { + KMException.throwIt(KMError.INCOMPATIBLE_DIGEST); + } + if (!KMEnumArrayTag.contains(KMType.PADDING, KMType.RSA_OAEP, data[KEY_PARAMETERS])) { + KMException.throwIt(KMError.INCOMPATIBLE_PADDING_MODE); + } } private short decryptTransportKey(short privExp, short modulus, short transportKey, byte[] scratchPad){ From 49c4623aef97bdf2cdc72562cb1c4c48bbc53b60 Mon Sep 17 00:00:00 2001 From: subrahmanyaman Date: Thu, 3 Nov 2022 19:10:56 +0000 Subject: [PATCH 4/7] Removed getter and setter in provider --- .../keymaster/KMAttestationCertImpl.java | 4 +- .../android/javacard/seprovider/KMAESKey.java | 14 +---- .../seprovider/KMAndroidSEProvider.java | 56 ++++++++++--------- .../seprovider/KMECDeviceUniqueKey.java | 22 +------- .../javacard/seprovider/KMECPrivateKey.java | 16 +----- .../javacard/seprovider/KMException.java | 8 --- .../javacard/seprovider/KMHmacKey.java | 18 +----- .../javacard/seprovider/KMKeyObject.java | 17 +----- .../javacard/seprovider/KMPoolManager.java | 5 +- 9 files changed, 41 insertions(+), 119 deletions(-) diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 45e354db..34d04133 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -992,8 +992,8 @@ public KMAttestationCert makeUniqueId(byte[] scratchPad, short scratchPadOff, //Get the key data from the master key KMAESKey aesKey = (KMAESKey) masterKey; - short mKeyData = KMByteBlob.instance((short) (aesKey.getKeySizeBits() / 8)); - aesKey.getKey( + short mKeyData = KMByteBlob.instance((short) (aesKey.aesKey.getSize() / 8)); + aesKey.aesKey.getKey( KMByteBlob.cast(mKeyData).getBuffer(), /* Key */ KMByteBlob.cast(mKeyData).getStartOff()); /* Key start*/ timeOffset = KMByteBlob.instance((short) 32); diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java index 0c3172c2..d1ea05be 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAESKey.java @@ -21,24 +21,12 @@ public class KMAESKey implements KMMasterKey { - private AESKey aesKey; + public AESKey aesKey; public KMAESKey(AESKey key) { aesKey = key; } - public void setKey(byte[] keyData, short kOff) { - aesKey.setKey(keyData, kOff); - } - - public byte getKey(byte[] keyData, short kOff) { - return aesKey.getKey(keyData, kOff); - } - - public short getKeySizeBits() { - return aesKey.getSize(); - } - public static void onSave(Element element, KMAESKey kmKey) { element.write(kmKey.aesKey); } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index ddd45ae8..4142494e 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java @@ -427,7 +427,7 @@ public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelSta short keyOutLen = n * 16; //Convert Hmackey to AES Key as the algorithm is ALG_AES_CMAC_128. KMHmacKey hmacKey = ((KMHmacKey) preSharedKey); - hmacKey.getKey(tmpArray, (short) 0); + hmacKey.hmacKey.getKey(tmpArray, (short) 0); aesKeys[KEYSIZE_256_OFFSET].setKey(tmpArray, (short) 0); //Initialize the key derivation function. kdf.init(aesKeys[KEYSIZE_256_OFFSET], Signature.MODE_SIGN); @@ -473,11 +473,11 @@ public short hmacSign(byte[] keyBuf, short keyStart, short keyLength, @Override public short hmacSign(Object key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart) { - if(!(key instanceof KMHmacKey)) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - KMHmacKey hmacKey = (KMHmacKey) key; - return hmacSign(hmacKey.getKey(), data, dataStart, dataLength, mac, macStart); + if(!(key instanceof KMHmacKey)) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } + KMHmacKey hmacKey = (KMHmacKey) key; + return hmacSign(hmacKey.hmacKey, data, dataStart, dataLength, mac, macStart); } @Override @@ -485,8 +485,8 @@ public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart, short dataLength, byte[] signature, short signatureStart) { try { KMAESKey aesKey = (KMAESKey) masterkey; - short keyLen = (short) (aesKey.getKeySizeBits() / 8); - aesKey.getKey(tmpArray, (short) 0); + short keyLen = (short) (aesKey.aesKey.getSize() / 8); + aesKey.aesKey.getKey(tmpArray, (short) 0); return hmacSign(tmpArray, (short) 0, keyLen, data, dataStart, dataLength, signature, signatureStart); } finally { @@ -498,7 +498,7 @@ public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart, 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); + hmacSignature.init(hmacKey.hmacKey, Signature.MODE_VERIFY); return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, macLength); } @@ -602,7 +602,7 @@ public KMOperation createSymmetricCipher(short alg, short purpose, short macLeng } // Get the KeyObject from the operation and update the key with the secret key material. KMKeyObject keyObj = operation.getKeyObject(); - Key key = (Key)keyObj.getKeyObjectInstance(); + Key key = (Key)keyObj.keyObjectInst; switch (secretLength) { case 32: case 16: @@ -634,7 +634,7 @@ public KMOperation createHmacSignerVerifier(short purpose, short digest, } // Get the KeyObject from the operation and update the key with the secret key material. KMKeyObject keyObj = operation.getKeyObject(); - HMACKey key = (HMACKey)keyObj.getKeyObjectInstance(); + HMACKey key = (HMACKey)keyObj.keyObjectInst; key.setKey(secret, secretStart, secretLength); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); return operation; @@ -649,7 +649,7 @@ private KMOperation createHmacSignerVerifier(short purpose, short digest, HMACKe KMType.HMAC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, (short)0, isTrustedConf); // Get the KeyObject from the operation and update the key with the secret key material. KMKeyObject keyObj = operation.getKeyObject(); - HMACKey key = (HMACKey)keyObj.getKeyObjectInstance(); + HMACKey key = (HMACKey)keyObj.keyObjectInst; short len = hmacKey.getKey(tmpArray, (short) 0); key.setKey(tmpArray, (short) 0, len); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); @@ -716,8 +716,8 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg, byte digest, b switch (interfaceType) { case KMDataStoreConstants.INTERFACE_TYPE_MASTER_KEY: KMAESKey aesKey = (KMAESKey) key; - keyLen = (short) (aesKey.getKeySizeBits() / 8); - aesKey.getKey(tmpArray, (short) 0); + keyLen = (short) (aesKey.aesKey.getSize() / 8); + aesKey.aesKey.getKey(tmpArray, (short) 0); break; default: @@ -743,7 +743,7 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg, byte digest, b @Override public KMOperation initTrustedConfirmationSymmetricOperation(KMComputedHmacKey computedHmacKey) { KMHmacKey key = (KMHmacKey) computedHmacKey; - return createHmacSignerVerifier(KMType.VERIFY, KMType.SHA2_256, key.getKey(), true); + return createHmacSignerVerifier(KMType.VERIFY, KMType.SHA2_256, key.hmacKey, true); } public KMOperation createRsaSigner(short digest, short padding, byte[] secret, @@ -754,7 +754,7 @@ public KMOperation createRsaSigner(short digest, short padding, byte[] secret, KMType.INVALID_VALUE, KMType.INVALID_VALUE, secretLength, false); // Get the KeyObject from the operation and update the key with the secret key material. KMKeyObject keyObj = operation.getKeyObject(); - RSAPrivateKey key = (RSAPrivateKey)((KeyPair)(keyObj.getKeyObjectInstance())).getPrivate(); + RSAPrivateKey key = (RSAPrivateKey)((KeyPair)(keyObj.keyObjectInst)).getPrivate(); key.setExponent(secret, secretStart, secretLength); key.setModulus(modBuffer, modOff, modLength); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); @@ -769,7 +769,7 @@ public KMOperation createRsaDecipher(short padding, short mgfDigest, byte[] secr KMType.INVALID_VALUE, KMType.INVALID_VALUE, secretLength, false); // Get the KeyObject from the operation and update the key with the secret key material. KMKeyObject keyObj = operation.getKeyObject(); - RSAPrivateKey key = (RSAPrivateKey) ((KeyPair)(keyObj.getKeyObjectInstance())).getPrivate(); + RSAPrivateKey key = (RSAPrivateKey) ((KeyPair)(keyObj.keyObjectInst)).getPrivate(); key.setExponent(secret, secretStart, secretLength); key.setModulus(modBuffer, modOff, modLength); ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, null, (short) 0, (short) 0); @@ -783,7 +783,7 @@ public KMOperation createEcSigner(short digest, byte[] secret, .getOperationImpl(KMType.SIGN, alg, KMType.EC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, secretLength, false); KMKeyObject keyObj = operation.getKeyObject(); - ECPrivateKey key = (ECPrivateKey) ((KeyPair)(keyObj.getKeyObjectInstance())).getPrivate(); + ECPrivateKey key = (ECPrivateKey) ((KeyPair)(keyObj.keyObjectInst)).getPrivate(); key.setS(secret, secretStart, secretLength); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); return operation; @@ -795,7 +795,7 @@ public KMOperation createKeyAgreement(byte[] secret, short secretStart, .getOperationImpl(KMType.AGREE_KEY, KeyAgreement.ALG_EC_SVDP_DH_PLAIN, KMType.EC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, (short)0, false); KMKeyObject keyObj = operation.getKeyObject(); - ECPrivateKey key = (ECPrivateKey) ((KeyPair)(keyObj.getKeyObjectInstance())).getPrivate(); + ECPrivateKey key = (ECPrivateKey) ((KeyPair)(keyObj.keyObjectInst)).getPrivate(); key.setS(secret, secretStart, secretLength); ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, null, (short) 0, (short) 0); return operation; @@ -864,7 +864,7 @@ public KMMasterKey createMasterKey(KMMasterKey masterKey, short keySizeBits) { masterKey = new KMAESKey(key); short keyLen = (short) (keySizeBits / 8); getTrueRandomNumber(tmpArray, (short) 0, keyLen); - ((KMAESKey)masterKey).setKey(tmpArray, (short) 0); + ((KMAESKey)masterKey).aesKey.setKey(tmpArray, (short) 0); } return (KMMasterKey) masterKey; } finally { @@ -883,7 +883,7 @@ public KMPreSharedKey createPreSharedKey(KMPreSharedKey preSharedKey, byte[] key false); preSharedKey = new KMHmacKey(key); } - ((KMHmacKey)preSharedKey).setKey(keyData, offset, length); + ((KMHmacKey)preSharedKey).hmacKey.setKey(keyData, offset, length); return (KMPreSharedKey) preSharedKey; } @@ -897,7 +897,7 @@ public KMComputedHmacKey createComputedHmacKey(KMComputedHmacKey computedHmacKey false); computedHmacKey = new KMHmacKey(key); } - ((KMHmacKey)computedHmacKey).setKey(keyData, offset, length); + ((KMHmacKey)computedHmacKey).hmacKey.setKey(keyData, offset, length); return (KMComputedHmacKey) computedHmacKey; } @@ -933,7 +933,7 @@ public short ecSign256(KMAttestationKey ecPrivKey, byte[] inputDataBuf, short in signer = Signature.OneShot.open(MessageDigest.ALG_SHA_256, Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL); - signer.init(((KMECPrivateKey) ecPrivKey).getPrivateKey(), Signature.MODE_SIGN); + signer.init(((KMECPrivateKey) ecPrivKey).ecKeyPair.getPrivate(), Signature.MODE_SIGN); return signer.sign(inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); } finally { @@ -1071,7 +1071,7 @@ public short ecSign256(KMDeviceUniqueKeyPair ecPrivKey, byte[] inputDataBuf, try { signer = Signature.OneShot.open(MessageDigest.ALG_SHA_256, Signature.SIG_CIPHER_ECDSA, Cipher.PAD_NULL); - signer.init(((KMECDeviceUniqueKey) ecPrivKey).getPrivateKey(), Signature.MODE_SIGN); + signer.init(((KMECDeviceUniqueKey) ecPrivKey).ecKeyPair.getPrivate(), Signature.MODE_SIGN); return signer.sign(inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); } finally { @@ -1090,8 +1090,10 @@ public KMDeviceUniqueKeyPair createRkpDeviceUniqueKeyPair(KMDeviceUniqueKeyPair poolMgr.initECKey(ecKeyPair); key = new KMECDeviceUniqueKey(ecKeyPair); } - ((KMECDeviceUniqueKey) key).setS(privKey, privKeyOff, privKeyLen); - ((KMECDeviceUniqueKey) key).setW(pubKey, pubKeyOff, pubKeyLen); + ECPrivateKey ecKeyPair = (ECPrivateKey) ((KMECDeviceUniqueKey) key).ecKeyPair.getPrivate(); + ECPublicKey ecPublicKey = (ECPublicKey) ((KMECDeviceUniqueKey) key).ecKeyPair.getPublic(); + ecKeyPair.setS(privKey, privKeyOff, privKeyLen); + ecPublicKey.setW(pubKey, pubKeyOff, pubKeyLen); return (KMDeviceUniqueKeyPair) key; } @@ -1103,7 +1105,7 @@ public KMRkpMacKey createRkpMacKey(KMRkpMacKey rkpMacKey, byte[] keyData, false); rkpMacKey = new KMHmacKey(key); } - ((KMHmacKey) rkpMacKey).setKey(keyData, offset, length); + ((KMHmacKey) rkpMacKey).hmacKey.setKey(keyData, offset, length); return rkpMacKey; } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java index 1c512a5c..41df6f48 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECDeviceUniqueKey.java @@ -22,11 +22,11 @@ public class KMECDeviceUniqueKey implements KMDeviceUniqueKeyPair { - private KeyPair ecKeyPair; + public KeyPair ecKeyPair; @Override public short getPublicKey(byte[] buf, short offset) { - ECPublicKey publicKey = getPublicKey(); + ECPublicKey publicKey = (ECPublicKey) ecKeyPair.getPublic(); return publicKey.getW(buf, offset); } @@ -34,24 +34,6 @@ public KMECDeviceUniqueKey(KeyPair ecPair) { ecKeyPair = ecPair; } - public void setS(byte[] buffer, short offset, short length) { - ECPrivateKey ecPriv = (ECPrivateKey) ecKeyPair.getPrivate(); - ecPriv.setS(buffer, offset, length); - } - - public void setW(byte[] buffer, short offset, short length) { - ECPublicKey ecPublicKey = (ECPublicKey) ecKeyPair.getPublic(); - ecPublicKey.setW(buffer, offset, length); - } - - public ECPrivateKey getPrivateKey() { - return (ECPrivateKey) ecKeyPair.getPrivate(); - } - - public ECPublicKey getPublicKey() { - return (ECPublicKey) ecKeyPair.getPublic(); - } - public static void onSave(Element element, KMECDeviceUniqueKey kmKey) { element.write(kmKey.ecKeyPair); } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java index 0f9a7f8a..1ce36ee9 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMECPrivateKey.java @@ -23,26 +23,12 @@ public class KMECPrivateKey implements KMAttestationKey { - private KeyPair ecKeyPair; + public KeyPair ecKeyPair; public KMECPrivateKey(KeyPair ecPair) { ecKeyPair = ecPair; } - public void setS(byte[] buffer, short offset, short length) { - ECPrivateKey ecPriv = (ECPrivateKey) ecKeyPair.getPrivate(); - ecPriv.setS(buffer, offset, length); - } - - public short getS(byte[] buffer, short offset) { - ECPrivateKey ecPriv = (ECPrivateKey) ecKeyPair.getPrivate(); - return ecPriv.getS(buffer, offset); - } - - public ECPrivateKey getPrivateKey() { - return (ECPrivateKey) ecKeyPair.getPrivate(); - } - public static void onSave(Element element, KMECPrivateKey kmKey) { element.write(kmKey.ecKeyPair); } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMException.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMException.java index c0b2431f..740b07a6 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMException.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMException.java @@ -42,14 +42,6 @@ public static void throwIt(short e) { reason[0] = e; throw exception; } -/* - public static KMException instance() { - if (exception == null) { - exception = new KMException(); - } - return exception; - } -*/ } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java index bd4523a7..cbb17e07 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java @@ -21,28 +21,12 @@ public class KMHmacKey implements KMPreSharedKey, KMComputedHmacKey, KMRkpMacKey { - private HMACKey hmacKey; + public HMACKey hmacKey; public KMHmacKey(HMACKey key) { hmacKey = key; } - public void setKey(byte[] keyData, short kOff, short length) { - hmacKey.setKey(keyData, kOff, length); - } - - public byte getKey(byte[] keyData, short kOff) { - return hmacKey.getKey(keyData, kOff); - } - - public HMACKey getKey() { - return hmacKey; - } - - public short getKeySizeBits() { - return hmacKey.getSize(); - } - public static void onSave(Element element, KMHmacKey kmKey) { element.write(kmKey.hmacKey); } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java index 03f54ecc..26edaa27 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java @@ -1,19 +1,6 @@ package com.android.javacard.seprovider; public class KMKeyObject { - private byte algorithm; - private Object keyObjectInst; - - public void setKeyObjectData(byte alg, Object keyObject) { - algorithm = alg; - keyObjectInst = keyObject; - } - - public byte getAlgorithm() { - return this.algorithm; - } - - public Object getKeyObjectInstance() { - return keyObjectInst; - } + public byte algorithm; + public Object keyObjectInst; } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java index 7643e061..1a00886b 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java @@ -339,7 +339,8 @@ private KMKeyObject createKeyObjectInstance(byte alg) { KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); } KMKeyObject ptr = new KMKeyObject(); - ptr.setKeyObjectData(alg, keyObject); + ptr.algorithm = alg; + ptr.keyObjectInst = keyObject; return ptr; } @@ -529,7 +530,7 @@ public KMKeyObject getKeyObjectFromPool(short alg, short secretLength, short max break; } keyObject = (KMKeyObject) keysPool[index]; - if (algo == keyObject.getAlgorithm()) { + if (algo == keyObject.algorithm) { // Check if the Object instance is not busy and free to use. if (!isResourceBusy(keyObject, RESOURCE_TYPE_KEY)) { break; From d0284099857fdf96ecc93480769c9f2c2cbaf938 Mon Sep 17 00:00:00 2001 From: subrahmanyaman Date: Tue, 15 Nov 2022 05:41:13 +0000 Subject: [PATCH 5/7] Fixed the issue with one of the wychproof test vectors for RSA OAEP --- .../seprovider/KMRsaOAEPEncoding.java | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsaOAEPEncoding.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsaOAEPEncoding.java index 901e93f2..34f46321 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsaOAEPEncoding.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMRsaOAEPEncoding.java @@ -125,10 +125,8 @@ public short doFinal(byte[] inBuff, short inOffset, short inLength, if (len != 256 || outBuff[0] != 0) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } - inBuff = outBuff; - inOffset = (short) (outOffset + 1); - return rsaOAEPDecode(inBuff, inOffset, (short) (len - 1), outBuff, - outOffset); + Util.arrayCopyNonAtomic(outBuff, (short) (outOffset + 1), outBuff, (short) 0, (short) (len -1)); + return rsaOAEPDecode(outBuff, (short) 0, (short) (len - 1)); } @@ -177,7 +175,7 @@ private void I2OS(short i, byte[] out, short offset) { } private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, - short encodedMsgLen, byte[] msg, short offset) { + short encodedMsgLen) { MessageDigest.OneShot md = null; byte[] tmpArray = KMAndroidSEProvider.getInstance().tmpArray; @@ -232,22 +230,26 @@ private short rsaOAEPDecode(byte[] encodedMsg, short encodedMsgOff, // encoding parameters is calculated and then copied from the // starting of the block and a variable length of 0's are // appended to the end of the hash till the 0x01 byte. - short start = 0; + short start = (short) (encodedMsgOff + encodedMsgLen); for (short i = (short) (encodedMsgOff + 2 * hLen); i < (short) (encodedMsgOff + encodedMsgLen); i++) { - if (i == (short) ((encodedMsgOff + encodedMsgLen) - 1)) { - // Bad Padding. - CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); - } - if (encodedMsg[i] != 0) { + if ((encodedMsg[i] != 0)) { start = i; break; } } - // Copy the message - Util.arrayCopyNonAtomic(encodedMsg, (short) (start + 1), msg, offset, - (short) (encodedMsgLen - ((start - encodedMsgOff) + 1))); - return (short) (encodedMsgLen - ((start - encodedMsgOff) + 1)); + if ((start >= (short)(encodedMsgOff + encodedMsgLen)) || + (encodedMsg[start] != 0x01)) { + // Bad Padding. + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + start++; // Message starting pos. + if (start < (short)(encodedMsgOff + encodedMsgLen)) { + // Copy the message + Util.arrayCopyNonAtomic(encodedMsg, start, encodedMsg, encodedMsgOff, + (short) (encodedMsgLen - (start - encodedMsgOff))); + } + return (short) (encodedMsgLen - (start - encodedMsgOff)); } finally { if (md != null) { From 2f2879e7989ce8a7f045140ea1a67f507c423d2d Mon Sep 17 00:00:00 2001 From: subrahmanyaman Date: Tue, 15 Nov 2022 05:43:38 +0000 Subject: [PATCH 6/7] Correction in the calcuclation of RSA KeySize in importKey --- .../src/com/android/javacard/keymaster/KMKeymasterApplet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index da8aa4b7..f03dc7fb 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -3542,7 +3542,7 @@ private void importRSAKey(byte[] scratchPad) { // check the keysize tag if present in key parameters. short keysize = KMIntegerTag.getShortValue(KMType.UINT_TAG, KMType.KEYSIZE, data[KEY_PARAMETERS]); - short kSize = (short) (KMByteBlob.length(data[SECRET]) * 8); + short kSize = (short) (KMByteBlob.length(data[PUB_KEY]) * 8); if (keysize != KMType.INVALID_VALUE) { if (keysize != 2048 || (keysize != kSize)) { KMException.throwIt(KMError.IMPORT_PARAMETER_MISMATCH); From f039c744a6b4a4a47785f28a3468bf8e4f4e1b02 Mon Sep 17 00:00:00 2001 From: subrahmanyaman Date: Thu, 24 Nov 2022 03:07:02 +0000 Subject: [PATCH 7/7] Fixed the Functional Test in importWrappedKey --- .../android/javacard/test/KMFunctionalTest.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java index 43f8e132..f420b8f4 100644 --- a/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java +++ b/Applet/JCardSimProvider/test/com/android/javacard/test/KMFunctionalTest.java @@ -2359,7 +2359,20 @@ public ResponseAPDU importWrappedKey() { (short) wrappingKeyBlob.length)); // Wrapping Key KeyBlob KMArray.cast(arr).add((short) 2, KMByteBlob.instance(maskingKey, (short) 0, (short) maskingKey.length)); // Masking Key - KMArray.cast(arr).add((short) 3, nullParams); // unwrapping params + // RSA OAEP Padding + short paddingBlob = KMByteBlob.instance((short) 1); + KMByteBlob.cast(paddingBlob).add((short) 0, KMType.RSA_OAEP); + short padding = KMEnumArrayTag.instance(KMType.PADDING, paddingBlob); + // Unwrapping params should have Digest: SHA256 and padding as RSA_OAEP + short unwrappingParamsArr = KMArray.instance((short) 2); + // SHA256 digest + short digestBlob = KMByteBlob.instance((short) 1); + KMByteBlob.cast(digestBlob).add((short) 0, KMType.SHA2_256); + short digest = KMEnumArrayTag.instance(KMType.DIGEST, digestBlob); + KMArray.cast(unwrappingParamsArr).add((short) 0, padding); + KMArray.cast(unwrappingParamsArr).add((short) 1, digest); + short unwrappingParams = KMKeyParameters.instance(unwrappingParamsArr); + KMArray.cast(arr).add((short) 3, unwrappingParams); // unwrapping params CommandAPDU apdu = KMTestUtils.encodeApdu(encoder, (byte) INS_BEGIN_IMPORT_WRAPPED_KEY_CMD, arr); ResponseAPDU response = simulator.transmitCommand(apdu);