From d380672e43a6656b39ed2aeb7e30ee478ac51405 Mon Sep 17 00:00:00 2001 From: "avinash.hedage" Date: Mon, 21 Feb 2022 05:45:09 +0000 Subject: [PATCH 1/3] ST review comment fixes --- .../javacard/kmapplet/KMRkpDataStoreImpl.java | 30 +- .../seprovider/KMAndroidSEProvider.java | 86 +++- .../javacard/seprovider/KMHmacKey.java | 3 +- .../javacard/seprovider/KMPoolManager.java | 50 +- .../android/javacard/seprovider/KMType.java | 1 - .../kmdevice/KMAttestationCertImpl.java | 463 +++++++++--------- .../com/android/javacard/kmdevice/KMCose.java | 72 ++- .../javacard/kmdevice/KMCoseHeaders.java | 19 +- .../android/javacard/kmdevice/KMCoseKey.java | 27 +- .../kmdevice/KMCosePairByteBlobTag.java | 33 +- .../javacard/kmdevice/KMCosePairTagType.java | 10 +- .../kmdevice/KMDataStoreConstants.java | 4 +- .../com/android/javacard/kmdevice/KMEnum.java | 46 +- .../javacard/kmdevice/KMEnumArrayTag.java | 135 +---- .../android/javacard/kmdevice/KMEnumTag.java | 26 +- .../javacard/kmdevice/KMKeymasterDevice.java | 48 +- .../javacard/kmdevice/KMKeymintDevice.java | 26 +- .../javacard/kmdevice/KMPKCS8Decoder.java | 39 +- .../javacard/kmdevice/KMRkpDataStore.java | 7 + .../javacard/kmdevice/KMRkpMacKey.java | 6 + .../javacard/kmdevice/KMSEProvider.java | 34 +- .../RemotelyProvisionedComponentDevice.java | 224 ++++----- 22 files changed, 696 insertions(+), 693 deletions(-) create mode 100644 Applet/src/com/android/javacard/kmdevice/KMRkpMacKey.java diff --git a/Applet/AndroidSEApplet/src/com/android/javacard/kmapplet/KMRkpDataStoreImpl.java b/Applet/AndroidSEApplet/src/com/android/javacard/kmapplet/KMRkpDataStoreImpl.java index e1d4d275..6a46efe9 100644 --- a/Applet/AndroidSEApplet/src/com/android/javacard/kmapplet/KMRkpDataStoreImpl.java +++ b/Applet/AndroidSEApplet/src/com/android/javacard/kmapplet/KMRkpDataStoreImpl.java @@ -21,8 +21,10 @@ import com.android.javacard.kmdevice.KMError; import com.android.javacard.kmdevice.KMException; import com.android.javacard.kmdevice.KMRkpDataStore; +import com.android.javacard.kmdevice.KMRkpMacKey; import com.android.javacard.kmdevice.KMPreSharedKey; import com.android.javacard.kmdevice.KMSEProvider; +import com.android.javacard.kmdevice.KMComputedHmacKey; import com.android.javacard.kmdevice.KMDataStoreConstants; import com.android.javacard.kmdevice.KMType; @@ -36,6 +38,7 @@ public class KMRkpDataStoreImpl implements KMRkpDataStore { private KMDeviceUniqueKey deviceUniqueKey; private KMDeviceUniqueKey testDeviceUniqueKey; private KMSEProvider seProvider; + private KMRkpMacKey rkpMacKey; public KMRkpDataStoreImpl(KMSEProvider provider) { @@ -67,6 +70,9 @@ public void storeData(byte storeDataIndex, byte[] data, short offset, short leng case KMDataStoreConstants.BOOT_CERT_CHAIN: persistBootCertificateChain(data, offset, length); break; + case KMDataStoreConstants.RKP_MAC_KEY: + persistRkpMacKey(data, offset, length); + break; } } @@ -100,6 +106,13 @@ private void persistBootCertificateChain(byte[] buf, short offset, short len) { Util.arrayCopy(buf, offset, bcc, (short) 2, len); } + private void persistRkpMacKey(byte[] keydata, short offset, short length) { + if (rkpMacKey == null) { + rkpMacKey = seProvider.createRkpMacKey(rkpMacKey, keydata, offset, length); + } else { + seProvider.createRkpMacKey(rkpMacKey, keydata, offset, length); + } + } @Override public void createDeviceUniqueKey(boolean testMode, byte[] pubKey, short pubKeyOff, @@ -154,6 +167,7 @@ public void onSave(Element ele) { ele.write(bcc); // Key Object seProvider.onSave(ele, KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY, deviceUniqueKey); + seProvider.onSave(ele, KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY, rkpMacKey); } @Override @@ -161,12 +175,15 @@ public void onRestore(Element ele, short oldVersion, short currentVersion) { additionalCertData = (byte[]) ele.readObject(); bcc = (byte[]) ele.readObject(); deviceUniqueKey = (KMDeviceUniqueKey) seProvider.onResore(ele); + rkpMacKey = (KMRkpMacKey) seProvider.onResore(ele); } @Override public short getBackupPrimitiveByteCount() { - return seProvider.getBackupPrimitiveByteCount( - KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY); + return (short)(seProvider.getBackupPrimitiveByteCount( + KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY) + + seProvider.getBackupPrimitiveByteCount( + KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY)); } @Override @@ -174,7 +191,9 @@ public short getBackupObjectCount() { // AdditionalCertificateChain - 1 // BCC - 1 return (short) (2 + seProvider.getBackupObjectCount( - KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY)); + KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY) + + seProvider.getBackupObjectCount( + KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY)); } @Override @@ -189,5 +208,10 @@ public byte[] getData(byte dataStoreId) { } return null; } + + @Override + public KMRkpMacKey getRkpMacacKey() { + return rkpMacKey; + } } diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index 9c554dde..4d7e9d5e 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMAndroidSEProvider.java @@ -26,6 +26,7 @@ import com.android.javacard.kmdevice.KMMasterKey; import com.android.javacard.kmdevice.KMOperation; import com.android.javacard.kmdevice.KMPreSharedKey; +import com.android.javacard.kmdevice.KMRkpMacKey; import com.android.javacard.kmdevice.KMSEProvider; import javacard.framework.ISO7816; @@ -516,43 +517,45 @@ public HMACKey cmacKdf(KMPreSharedKey preSharedKey, byte[] label, short labelSta final byte n = 2; // hardcoded // [L] 256 bits - hardcoded 32 bits as per // reference impl in keymaster. - final byte[] L = { - 0, 0, 1, 0 - }; - // byte - final byte[] zero = { - 0 - }; + short zeroIndex = 0; + short LIndex = 1; + short bufIndex = 5; + short keyIndex = 9; + //1st byte in tempArray is reserved for zero + //next 4 bytes in tempArray is reserved for L + tmpArray[0] = 0; + tmpArray[1] = 0; + tmpArray[2] = 0; + tmpArray[3] = 1; + tmpArray[4] = 0; + // [i] counter - 32 bits short iBufLen = 4; 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); - aesKeys[KEYSIZE_256_OFFSET].setKey(tmpArray, (short) 0); + hmacKey.getKey(tmpArray, keyIndex); + aesKeys[KEYSIZE_256_OFFSET].setKey(tmpArray, (short) keyIndex); //Initialize the key derivation function. kdf.init(aesKeys[KEYSIZE_256_OFFSET], Signature.MODE_SIGN); //Clear the tmpArray buffer. - Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0); - - Util.arrayFillNonAtomic(tmpArray, (short) 0, iBufLen, (byte) 0); - Util.arrayFillNonAtomic(tmpArray, (short) iBufLen, keyOutLen, (byte) 0); + Util.arrayFillNonAtomic(tmpArray, keyIndex, (short) 256, (byte) 0); byte i = 1; short pos = 0; while (i <= n) { - tmpArray[3] = i; + tmpArray[(short)(bufIndex + 3)] = i; // 4 bytes of iBuf with counter in it - kdf.update(tmpArray, (short) 0, (short) iBufLen); - kdf.update(label, labelStart, (short) labelLen); // label - kdf.update(zero, (short) 0, (short) 1); // 1 byte of 0x00 + kdf.update(tmpArray, bufIndex, iBufLen); + kdf.update(label, labelStart, labelLen); // label + kdf.update(tmpArray, zeroIndex, (short) 1); // 1 byte of 0x00 kdf.update(context, contextStart, contextLength); // context // 4 bytes of L - signature of 16 bytes - pos = kdf.sign(L, (short) 0, (short) 4, tmpArray, - (short) (iBufLen + pos)); + pos = kdf.sign(tmpArray, LIndex, (short) 4, tmpArray, + (short) (keyIndex + pos)); i++; } - return createHMACKey(tmpArray, (short) iBufLen, (short) keyOutLen); + return createHMACKey(tmpArray, keyIndex, keyOutLen); } finally { clean(); } @@ -570,6 +573,16 @@ public short hmacSign(byte[] keyBuf, short keyStart, short keyLength, HMACKey key = createHMACKey(keyBuf, keyStart, keyLength); return hmacSign(key, data, dataStart, dataLength, mac, macStart); } + + @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); + } @Override public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart, @@ -587,8 +600,11 @@ public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart, } @Override - public boolean hmacVerify(KMComputedHmacKey key, byte[] data, short dataStart, + public boolean hmacVerify(Object key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart, short macLength) { + if(!(key instanceof KMHmacKey)) { + KMException.throwIt(KMError.INVALID_ARGUMENT); + } KMHmacKey hmacKey = (KMHmacKey) key; hmacSignature.init(hmacKey.getKey(), Signature.MODE_VERIFY); return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, @@ -918,6 +934,18 @@ public KMComputedHmacKey createComputedHmacKey(KMComputedHmacKey computedHmacKey return (KMComputedHmacKey) computedHmacKey; } + @Override + public KMRkpMacKey createRkpMacKey(KMRkpMacKey rkpMacKey, byte[] keyData, + short offset, short length) { + if (rkpMacKey == null) { + HMACKey key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short) (length * 8), + false); + rkpMacKey = new KMHmacKey(key); + } + ((KMHmacKey) rkpMacKey).setKey(keyData, offset, length); + return rkpMacKey; + } + @Override public short ecSign256(byte[] secret, short secretStart, short secretLength, byte[] inputDataBuf, short inputDataStart, short inputDataLength, @@ -1048,22 +1076,22 @@ private short hkdfExpand(byte[] prk, short prkOff, short prkLen, byte[] info, sh CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } HMACKey hmacKey = createHMACKey(prk, prkOff, prkLen); - Util.arrayFill(tmpArray, (short) 0, (short) 32, (byte) 0); - byte[] cnt = {(byte) 0}; + //first byte in tmpArray will be used for count. + Util.arrayFill(tmpArray, (short) 0, (short) 33, (byte) 0); short bytesCopied = 0; short len = 0; for (short i = 0; i < n; i++) { - cnt[0]++; + tmpArray[0]++; hmacSignature.init(hmacKey, Signature.MODE_SIGN); if (i != 0) { - hmacSignature.update(tmpArray, (short) 0, (short) 32); + hmacSignature.update(tmpArray, (short) 1, (short) 32); } hmacSignature.update(info, infoOff, infoLen); - len = hmacSignature.sign(cnt, (short) 0, (short) 1, tmpArray, (short) 0); + len = hmacSignature.sign(tmpArray, (short) 0, (short) 1, tmpArray, (short) 1); if ((short) (bytesCopied + len) > outLen) { len = (short) (outLen - bytesCopied); } - Util.arrayCopyNonAtomic(tmpArray, (short) 0, out, (short) (outOff + bytesCopied), len); + Util.arrayCopyNonAtomic(tmpArray, (short) 1, out, (short) (outOff + bytesCopied), len); bytesCopied += len; } return outLen; @@ -1212,6 +1240,8 @@ public short getBackupPrimitiveByteCount(byte interfaceType) { return KMECPrivateKey.getBackupPrimitiveByteCount(); case KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY: return KMECDeviceUniqueKey.getBackupPrimitiveByteCount(); + case KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY: + return KMHmacKey.getBackupPrimitiveByteCount(); default: ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } @@ -1231,6 +1261,8 @@ public short getBackupObjectCount(byte interfaceType) { return KMECPrivateKey.getBackupObjectCount(); case KMDataStoreConstants.INTERFACE_TYPE_DEVICE_UNIQUE_KEY: return KMECDeviceUniqueKey.getBackupObjectCount(); + case KMDataStoreConstants.INTERFACE_TYPE_RKP_MAC_KEY: + return KMHmacKey.getBackupObjectCount(); default: ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMHmacKey.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMHmacKey.java index 791129e2..567d0b4c 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMHmacKey.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMHmacKey.java @@ -19,10 +19,11 @@ import com.android.javacard.kmdevice.KMComputedHmacKey; import com.android.javacard.kmdevice.KMPreSharedKey; +import com.android.javacard.kmdevice.KMRkpMacKey; import javacard.security.HMACKey; -public class KMHmacKey implements KMPreSharedKey, KMComputedHmacKey { +public class KMHmacKey implements KMPreSharedKey, KMComputedHmacKey, KMRkpMacKey { private HMACKey hmacKey; diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMPoolManager.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMPoolManager.java index a9fd7008..1df02e92 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMPoolManager.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMPoolManager.java @@ -42,29 +42,9 @@ public class KMPoolManager { // Hmac signer pool which is used to support TRUSTED_CONFIRMATION_REQUIRED tag. private Object[] hmacSignOperationPool; - final byte[] CIPHER_ALGS = { - Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, - Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, - Cipher.ALG_DES_CBC_NOPAD, - Cipher.ALG_DES_ECB_NOPAD, - Cipher.ALG_AES_CTR, - Cipher.ALG_RSA_PKCS1, - KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1, - KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA256, - Cipher.ALG_RSA_NOPAD, - AEADCipher.ALG_AES_GCM}; - - final byte[] SIG_ALGS = { - Signature.ALG_RSA_SHA_256_PKCS1, - Signature.ALG_RSA_SHA_256_PKCS1_PSS, - Signature.ALG_ECDSA_SHA_256, - Signature.ALG_HMAC_SHA_256, - KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD, - KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST, - KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST}; - - final byte[] KEY_AGREE_ALGS = {KeyAgreement.ALG_EC_SVDP_DH_PLAIN}; - + private static byte[] CIPHER_ALGS; + private static byte[] SIG_ALGS; + private static byte[] KEY_AGREE_ALGS; private static KMPoolManager poolManager; @@ -76,6 +56,7 @@ public static KMPoolManager getInstance() { } private KMPoolManager() { + initStatics(); cipherPool = new Object[(short) (CIPHER_ALGS.length * 4)]; // Extra 4 algorithms are used to support TRUSTED_CONFIRMATION_REQUIRED feature. signerPool = new Object[(short) ((SIG_ALGS.length * 4) + 4)]; @@ -90,6 +71,29 @@ private KMPoolManager() { initializeKeyAgreementPool(); } + private void initStatics() { + CIPHER_ALGS = new byte[]{ + Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, + Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, + Cipher.ALG_DES_CBC_NOPAD, + Cipher.ALG_DES_ECB_NOPAD, + Cipher.ALG_AES_CTR, + Cipher.ALG_RSA_PKCS1, + KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1, + KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA256, + Cipher.ALG_RSA_NOPAD, + AEADCipher.ALG_AES_GCM}; + SIG_ALGS = new byte[]{ + Signature.ALG_RSA_SHA_256_PKCS1, + Signature.ALG_RSA_SHA_256_PKCS1_PSS, + Signature.ALG_ECDSA_SHA_256, + Signature.ALG_HMAC_SHA_256, + KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD, + KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST, + KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST}; + KEY_AGREE_ALGS = new byte[]{KeyAgreement.ALG_EC_SVDP_DH_PLAIN}; + } + private void initializeOperationPool() { short index = 0; while (index < MAX_OPERATION_INSTANCES) { diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMType.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMType.java index 0bfc0b1a..26b23d83 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMType.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMType.java @@ -231,7 +231,6 @@ public abstract class KMType { public static final short ORIGINATION_EXPIRE_DATETIME = 0x0191; public static final short USAGE_EXPIRE_DATETIME = 0x0192; public static final short CREATION_DATETIME = 0x02BD; - ; public static final short CERTIFICATE_NOT_BEFORE = 0x03F0; public static final short CERTIFICATE_NOT_AFTER = 0x03F1; // Integer Array Tags - ULONG_REP and UINT_REP. diff --git a/Applet/src/com/android/javacard/kmdevice/KMAttestationCertImpl.java b/Applet/src/com/android/javacard/kmdevice/KMAttestationCertImpl.java index 25640a62..e490b6bd 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMAttestationCertImpl.java +++ b/Applet/src/com/android/javacard/kmdevice/KMAttestationCertImpl.java @@ -68,45 +68,54 @@ public class KMAttestationCertImpl implements KMAttestationCert { private static byte[] pubExponent; 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; + + // indexes in transient array indexes + 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; + +//indexes in transient array dataIndexes + private static final byte STACK_PTR = (byte) 0; + private static final byte UNIQUE_ID = (byte) 1; + private static final byte ATT_CHALLENGE = (byte) 2; + private static final byte NOT_BEFORE = (byte) 3; + private static final byte NOT_AFTER = (byte) 4; + private static final byte PUB_KEY = (byte) 5; + private static final byte VERIFIED_BOOT_KEY = (byte) 6; + private static final byte VERIFIED_HASH = (byte) 7; + private static final byte ISSUER = (byte) 8; + private static final byte SUBJECT_NAME = (byte) 9; + private static final byte SIGN_PRIV = (byte) 10; + private static final byte SERIAL_NUMBER = (byte) 11; + private static final byte CERT_ATT_KEY_SECRET = (byte) 12; + private static final byte CERT_ATT_KEY_RSA_PUB_MOD = (byte) 13; + +//indexes in transient array stateIndexes + 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 short []indexes; + private static short []dataIndexes; + private static byte []stateIndexes; + 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[] swParams; 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 KMAttestationKey factoryAttestKey; - private static boolean certRsaSign; private static final byte SERIAL_NUM_MAX_LEN = 20; private static final byte SUBJECT_NAME_MAX_LEN = 32; @@ -194,69 +203,60 @@ public static KMAttestationCert instance(boolean rsaCert, KMSEProvider provider) seProvider = provider; } init(); - KMAttestationCertImpl.rsaCert = rsaCert; + KMAttestationCertImpl.stateIndexes[RSA_CERT] = (byte)((rsaCert == true)? 1: 0); return inst; } private static void init() { - stack = null; - stackPtr = 0; - certStart = 0; - certLength = 0; - bufStart = 0; - bufLength = 0; - tbsLength = 0; + + indexes = JCSystem.makeTransientShortArray((short) 8, JCSystem.CLEAR_ON_RESET); + for (short i=0; i<8; i++ ) { + indexes[i] = 0; + } + dataIndexes = JCSystem.makeTransientShortArray((short) 14, JCSystem.CLEAR_ON_RESET); + for (short i = 0; i < 14; i++ ) { + dataIndexes[i] = 0; + } + stateIndexes = JCSystem.makeTransientByteArray((short) 7, JCSystem.CLEAR_ON_RESET); + Util.arrayFillNonAtomic(stateIndexes, (short) 0, (short) 5, (byte) 0); + stateIndexes[CERT_MODE] = KMType.NO_CERT; + stack = null; 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); } - - 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; + stateIndexes[UNUSED_BITS] = 8; + stateIndexes[RSA_CERT] = 1; + dataIndexes[CERT_ATT_KEY_SECRET] = KMType.INVALID_VALUE; + stateIndexes[CERT_RSA_SIGN] = 1; + dataIndexes[ISSUER] = KMType.INVALID_VALUE; + dataIndexes[SUBJECT_NAME] = KMType.INVALID_VALUE; + dataIndexes[SERIAL_NUMBER] = KMType.INVALID_VALUE; factoryAttestKey = null; } @Override public KMAttestationCert verifiedBootHash(short obj) { - verifiedHash = obj; + dataIndexes[VERIFIED_HASH] = obj; return this; } @Override public KMAttestationCert verifiedBootKey(short obj) { - verifiedBootKey = obj; + dataIndexes[VERIFIED_BOOT_KEY] = obj; return this; } @Override public KMAttestationCert verifiedBootState(byte val) { - verifiedState = val; + stateIndexes[VERIFIED_STATE] = val; return this; } private KMAttestationCert uniqueId(short obj) { - uniqueId = obj; + dataIndexes[UNIQUE_ID] = obj; return this; } @@ -264,9 +264,9 @@ private KMAttestationCert uniqueId(short obj) { public KMAttestationCert notBefore(short obj, boolean derEncoded, byte[] scratchpad) { if (!derEncoded) { // convert milliseconds to UTC date - notBefore = KMUtils.convertToDate(obj, scratchpad, true); + dataIndexes[NOT_BEFORE] = KMUtils.convertToDate(obj, scratchpad, true); } else { - notBefore = KMByteBlob.instance(KMByteBlob.getBuffer(obj), + dataIndexes[NOT_BEFORE] = KMByteBlob.instance(KMByteBlob.getBuffer(obj), KMByteBlob.getStartOff(obj), KMByteBlob.length(obj)); } return this; @@ -287,7 +287,7 @@ public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, usageExpiryTimeObj = KMUtils .convertToDate(usageExpiryTimeObj, scratchPad, true); } - notAfter = usageExpiryTimeObj; + dataIndexes[NOT_AFTER] = usageExpiryTimeObj; } else { //notAfter = certExpirtyTimeObj; } @@ -295,7 +295,7 @@ public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, // notAfter = KMKeymasterApplet.instance(KMKeymasterApplet.cast(usageExpiryTimeObj).getBuffer(), // KMKeymasterApplet.cast(usageExpiryTimeObj).getStartOff(), // KMKeymasterApplet.cast(usageExpiryTimeObj).length()); - notAfter = usageExpiryTimeObj; + dataIndexes[NOT_AFTER] = usageExpiryTimeObj; } return this; } @@ -303,33 +303,33 @@ public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, @Override public KMAttestationCert deviceLocked(boolean val) { if (val) { - deviceLocked = (byte) 0xFF; + stateIndexes[DEVICE_LOCKED] = (byte) 0xFF; } else { - deviceLocked = 0; + stateIndexes[DEVICE_LOCKED] = 0; } return this; } @Override public KMAttestationCert publicKey(short obj) { - pubKey = obj; + dataIndexes[PUB_KEY] = obj; return this; } @Override public KMAttestationCert attestationChallenge(short obj) { - attChallenge = obj; + dataIndexes[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.getKMTagKey(tag) == KMType.PURPOSE) { createKeyUsage(tag); @@ -339,7 +339,7 @@ public KMAttestationCert extensionTag(short tag, boolean hwEnforced) { @Override public KMAttestationCert issuer(short obj) { - issuer = obj; + dataIndexes[ISSUER] = obj; return this; } @@ -348,29 +348,29 @@ private void createKeyUsage(short tag) { byte index = 0; while (index < len) { if (KMEnumArrayTag.get(tag, index) == KMType.SIGN) { - keyUsage = (byte) (keyUsage | keyUsageSign); + stateIndexes[KEY_USAGE] = (byte) (stateIndexes[KEY_USAGE] | keyUsageSign); } else if (KMEnumArrayTag.get(tag, index) == KMType.WRAP_KEY) { - keyUsage = (byte) (keyUsage | keyUsageKeyEncipher); + stateIndexes[KEY_USAGE] = (byte) (stateIndexes[KEY_USAGE] | keyUsageKeyEncipher); } else if (KMEnumArrayTag.get(tag, index) == KMType.DECRYPT) { - keyUsage = (byte) (keyUsage | keyUsageDataEncipher); + stateIndexes[KEY_USAGE] = (byte) (stateIndexes[KEY_USAGE] | keyUsageDataEncipher); } else if (KMEnumArrayTag.get(tag, index) == KMType.AGREE_KEY) { - keyUsage = (byte) (keyUsage | keyUsageKeyAgreement); + stateIndexes[KEY_USAGE] = (byte) (stateIndexes[KEY_USAGE] | keyUsageKeyAgreement); } else if (KMEnumArrayTag.get(tag, index) == KMType.ATTEST_KEY) { - keyUsage = (byte) (keyUsage | keyUsageCertSign); + stateIndexes[KEY_USAGE] = (byte) (stateIndexes[KEY_USAGE] | keyUsageCertSign); } index++; } - index = keyUsage; + index = stateIndexes[KEY_USAGE]; while (index != 0) { index = (byte) (index << 1); - unusedBits--; + stateIndexes[UNUSED_BITS]--; } } //TODO Serial number, X509Version needa to be passed as parameter private void pushTbsCert(boolean rsaCert, boolean rsa) { - short last = stackPtr; - if (certMode == KMType.ATTESTATION_CERT || certMode == KMType.FACTORY_PROVISIONED_ATTEST_CERT) { + short last = dataIndexes[STACK_PTR]; + if (stateIndexes[CERT_MODE] == KMType.ATTESTATION_CERT || stateIndexes[CERT_MODE] == KMType.FACTORY_PROVISIONED_ATTEST_CERT) { pushExtensions(); } // subject public key info @@ -380,14 +380,14 @@ private void pushTbsCert(boolean rsaCert, boolean rsa) { pushEccSubjectKeyInfo(); } // subject - pushBytes(KMByteBlob.getBuffer(subjectName), KMByteBlob.getStartOff(subjectName), - KMByteBlob.length(subjectName)); + pushBytes(KMByteBlob.getBuffer(dataIndexes[SUBJECT_NAME]), KMByteBlob.getStartOff(dataIndexes[SUBJECT_NAME]), + KMByteBlob.length(dataIndexes[SUBJECT_NAME])); pushValidity(); // issuer - der encoded pushBytes( - KMByteBlob.getBuffer(issuer), - KMByteBlob.getStartOff(issuer), - KMByteBlob.length(issuer)); + KMByteBlob.getBuffer(dataIndexes[ISSUER]), + KMByteBlob.getStartOff(dataIndexes[ISSUER]), + KMByteBlob.length(dataIndexes[ISSUER])); // Algorithm Id if (rsa) { pushAlgorithmId(X509RsaSignAlgIdentifier); @@ -395,48 +395,48 @@ private void pushTbsCert(boolean rsaCert, boolean rsa) { pushAlgorithmId(X509EcdsaSignAlgIdentifier); } // Serial Number - pushBytes(KMByteBlob.getBuffer(serialNum), KMByteBlob.getStartOff(serialNum), - KMByteBlob.length(serialNum)); - pushIntegerHeader(KMByteBlob.length(serialNum)); + pushBytes(KMByteBlob.getBuffer(dataIndexes[SERIAL_NUMBER]), KMByteBlob.getStartOff(dataIndexes[SERIAL_NUMBER]), + KMByteBlob.length(dataIndexes[SERIAL_NUMBER])); + pushIntegerHeader(KMByteBlob.length(dataIndexes[SERIAL_NUMBER])); // Version pushByte(X509_VERSION); pushIntegerHeader((short) 1); pushByte((byte) 0x03); pushByte((byte) 0xA0); // Finally sequence header. - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); } private void pushExtensions() { - short last = stackPtr; - if (keyUsage != 0) { - pushKeyUsage(keyUsage, unusedBits); + short last = dataIndexes[STACK_PTR]; + if (stateIndexes[KEY_USAGE] != 0) { + pushKeyUsage(stateIndexes[KEY_USAGE], stateIndexes[UNUSED_BITS]); } pushKeyDescription(); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); // Extensions have explicit tag of [3] - pushLength((short) (last - stackPtr)); + pushLength((short) (last - dataIndexes[STACK_PTR])); pushByte((byte) 0xA3); } // Time SEQUENCE{UTCTime, UTC or Generalized Time) private void pushValidity() { - short last = stackPtr; - if (notAfter != 0) { + short last = dataIndexes[STACK_PTR]; + if (dataIndexes[NOT_AFTER] != 0) { pushBytes( - KMByteBlob.getBuffer(notAfter), - KMByteBlob.getStartOff(notAfter), - KMByteBlob.length(notAfter)); + KMByteBlob.getBuffer(dataIndexes[NOT_AFTER]), + KMByteBlob.getStartOff(dataIndexes[NOT_AFTER]), + KMByteBlob.length(dataIndexes[NOT_AFTER])); } else { KMException.throwIt(KMError.INVALID_DATA); } - pushTimeHeader(KMByteBlob.length(notAfter)); + pushTimeHeader(KMByteBlob.length(dataIndexes[NOT_AFTER])); pushBytes( - KMByteBlob.getBuffer(notBefore), - KMByteBlob.getStartOff(notBefore), - KMByteBlob.length(notBefore)); - pushTimeHeader(KMByteBlob.length(notBefore)); - pushSequenceHeader((short) (last - stackPtr)); + KMByteBlob.getBuffer(dataIndexes[NOT_BEFORE]), + KMByteBlob.getStartOff(dataIndexes[NOT_BEFORE]), + KMByteBlob.length(dataIndexes[NOT_BEFORE])); + pushTimeHeader(KMByteBlob.length(dataIndexes[NOT_BEFORE])); + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); } private static void pushTimeHeader(short len) { @@ -455,51 +455,51 @@ private static void pushTimeHeader(short len) { // exponent // as positive integer} private void pushRsaSubjectKeyInfo() { - short last = stackPtr; + short last = dataIndexes[STACK_PTR]; pushBytes(pubExponent, (short) 0, (short) pubExponent.length); pushIntegerHeader((short) pubExponent.length); pushBytes( - KMByteBlob.getBuffer(pubKey), - KMByteBlob.getStartOff(pubKey), - KMByteBlob.length(pubKey)); + KMByteBlob.getBuffer(dataIndexes[PUB_KEY]), + KMByteBlob.getStartOff(dataIndexes[PUB_KEY]), + KMByteBlob.length(dataIndexes[PUB_KEY])); // encode modulus as positive if the MSB is 1. - if (KMByteBlob.get(pubKey, (short) 0) < 0) { + if (KMByteBlob.get(dataIndexes[PUB_KEY], (short) 0) < 0) { pushByte((byte) 0x00); - pushIntegerHeader((short) (KMByteBlob.length(pubKey) + 1)); + pushIntegerHeader((short) (KMByteBlob.length(dataIndexes[PUB_KEY]) + 1)); } else { - pushIntegerHeader(KMByteBlob.length(pubKey)); + pushIntegerHeader(KMByteBlob.length(dataIndexes[PUB_KEY])); } - pushSequenceHeader((short) (last - stackPtr)); - pushBitStringHeader((byte) 0x00, (short) (last - stackPtr)); + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); + pushBitStringHeader((byte) 0x00, (short) (last - dataIndexes[STACK_PTR])); pushRsaEncryption(); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); } // SEQUENCE{SEQUENCE{ecPubKey, prime256v1}, bitString{pubKey}} private void pushEccSubjectKeyInfo() { - short last = stackPtr; + short last = dataIndexes[STACK_PTR]; pushBytes( - KMByteBlob.getBuffer(pubKey), - KMByteBlob.getStartOff(pubKey), - KMByteBlob.length(pubKey)); - pushBitStringHeader((byte) 0x00, KMByteBlob.length(pubKey)); + KMByteBlob.getBuffer(dataIndexes[PUB_KEY]), + KMByteBlob.getStartOff(dataIndexes[PUB_KEY]), + KMByteBlob.length(dataIndexes[PUB_KEY])); + pushBitStringHeader((byte) 0x00, KMByteBlob.length(dataIndexes[PUB_KEY])); pushEcDsa(); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); } private static void pushEcDsa() { - short last = stackPtr; + short last = dataIndexes[STACK_PTR]; pushBytes(prime256v1, (short) 0, (short) prime256v1.length); pushBytes(eccPubKey, (short) 0, (short) eccPubKey.length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); } private static void pushRsaEncryption() { - short last = stackPtr; + short last = dataIndexes[STACK_PTR]; pushNullHeader(); pushBytes(rsaEncryption, (short) 0, (short) rsaEncryption.length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); } // KeyDescription ::= SEQUENCE { @@ -513,45 +513,45 @@ private static void pushRsaEncryption() { // hardwareEnforced AuthorizationList, # See below // } private void pushKeyDescription() { - short last = stackPtr; + short last = dataIndexes[STACK_PTR]; pushHWParams(); pushSWParams(); - if (uniqueId != 0) { + if (dataIndexes[UNIQUE_ID] != 0) { pushOctetString( - KMByteBlob.getBuffer(uniqueId), - KMByteBlob.getStartOff(uniqueId), - KMByteBlob.length(uniqueId)); + KMByteBlob.getBuffer(dataIndexes[UNIQUE_ID]), + KMByteBlob.getStartOff(dataIndexes[UNIQUE_ID]), + KMByteBlob.length(dataIndexes[UNIQUE_ID])); } else { pushOctetStringHeader((short) 0); } pushOctetString( - KMByteBlob.getBuffer(attChallenge), - KMByteBlob.getStartOff(attChallenge), - KMByteBlob.length(attChallenge)); + KMByteBlob.getBuffer(dataIndexes[ATT_CHALLENGE]), + KMByteBlob.getStartOff(dataIndexes[ATT_CHALLENGE]), + KMByteBlob.length(dataIndexes[ATT_CHALLENGE])); pushEnumerated(KMType.STRONGBOX); pushByte(KEYMASTER_VERSION); pushIntegerHeader((short) 1); pushEnumerated(KMType.STRONGBOX); pushByte(ATTESTATION_VERSION); pushIntegerHeader((short) 1); - pushSequenceHeader((short) (last - stackPtr)); - pushOctetStringHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); + pushOctetStringHeader((short) (last - dataIndexes[STACK_PTR])); pushBytes(androidExtn, (short) 0, (short) androidExtn.length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); } private void pushSWParams() { - short last = stackPtr; + short last = dataIndexes[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 - dataIndexes[STACK_PTR])); } private void pushHWParams() { - short last = stackPtr; + short last = dataIndexes[STACK_PTR]; byte index = 0; short length = (short) hwTagIds.length; do { @@ -559,11 +559,11 @@ private 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 - dataIndexes[STACK_PTR])); } private boolean pushParams(short[] params, short len, short tagId) { @@ -643,26 +643,26 @@ private void pushTag(short tag) { // Failed (3), // } private void pushRoT() { - short last = stackPtr; + short last = dataIndexes[STACK_PTR]; // verified boot hash pushOctetString( - KMByteBlob.getBuffer(verifiedHash), - KMByteBlob.getStartOff(verifiedHash), - KMByteBlob.length(verifiedHash)); + KMByteBlob.getBuffer(dataIndexes[VERIFIED_HASH]), + KMByteBlob.getStartOff(dataIndexes[VERIFIED_HASH]), + KMByteBlob.length(dataIndexes[VERIFIED_HASH])); - pushEnumerated(verifiedState); + pushEnumerated(stateIndexes[VERIFIED_STATE]); - pushBoolean(deviceLocked); + pushBoolean(stateIndexes[DEVICE_LOCKED]); // verified boot Key pushOctetString( - KMByteBlob.getBuffer(verifiedBootKey), - KMByteBlob.getStartOff(verifiedBootKey), - KMByteBlob.length(verifiedBootKey)); + KMByteBlob.getBuffer(dataIndexes[VERIFIED_BOOT_KEY]), + KMByteBlob.getStartOff(dataIndexes[VERIFIED_BOOT_KEY]), + KMByteBlob.length(dataIndexes[VERIFIED_BOOT_KEY])); // Finally sequence header - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); // ... and tag Id - pushTagIdHeader(KMType.ROOT_OF_TRUST, (short) (last - stackPtr)); + pushTagIdHeader(KMType.ROOT_OF_TRUST, (short) (last - dataIndexes[STACK_PTR])); } private static void pushOctetString(byte[] buf, short start, short len) { @@ -683,21 +683,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 = dataIndexes[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 - dataIndexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - dataIndexes[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 void pushIntegerArrayTag(short tagId, short arr) { - short last = stackPtr; + short last = dataIndexes[STACK_PTR]; short index = 0; short len = KMArray.length(arr); short ptr; @@ -709,8 +709,8 @@ private void pushIntegerArrayTag(short tagId, short arr) { KMInteger.length(ptr)); index++; } - pushSetHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushSetHeader((short) (last - dataIndexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - dataIndexes[STACK_PTR])); } private static void pushSetHeader(short len) { @@ -719,9 +719,9 @@ private static void pushSetHeader(short len) { } private static void pushEnumerated(byte val) { - short last = stackPtr; + short last = dataIndexes[STACK_PTR]; pushByte(val); - pushEnumeratedHeader((short) (last - stackPtr)); + pushEnumeratedHeader((short) (last - dataIndexes[STACK_PTR])); } private static void pushEnumeratedHeader(short len) { @@ -730,9 +730,9 @@ private static void pushEnumeratedHeader(short len) { } private static void pushBoolTag(short tagId) { - short last = stackPtr; + short last = dataIndexes[STACK_PTR]; pushNullHeader(); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushTagIdHeader(tagId, (short) (last - dataIndexes[STACK_PTR])); } private static void pushNullHeader() { @@ -741,23 +741,23 @@ private static void pushNullHeader() { } private static void pushEnumTag(short tagId, byte val) { - short last = stackPtr; + short last = dataIndexes[STACK_PTR]; pushByte(val); - pushIntegerHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushIntegerHeader((short) (last - dataIndexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - dataIndexes[STACK_PTR])); } private static void pushIntegerTag(short tagId, byte[] buf, short start, short len) { - short last = stackPtr; + short last = dataIndexes[STACK_PTR]; pushInteger(buf, start, len); - // pushIntegerHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + // pushIntegerHeader((short) (last - dataIndexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - dataIndexes[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 = dataIndexes[STACK_PTR]; byte index = 0; while (index < (byte) len) { if (buf[(short) (start + index)] != 0) { @@ -773,15 +773,15 @@ private static void pushInteger(byte[] buf, short start, short len) { pushByte((byte) 0x00); // always unsigned int } } - pushIntegerHeader((short) (last - stackPtr)); + pushIntegerHeader((short) (last - dataIndexes[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 = dataIndexes[STACK_PTR]; pushBytes(buf, start, len); - pushOctetStringHeader((short) (last - stackPtr)); - pushTagIdHeader(tagId, (short) (last - stackPtr)); + pushOctetStringHeader((short) (last - dataIndexes[STACK_PTR])); + pushTagIdHeader(tagId, (short) (last - dataIndexes[STACK_PTR])); } // tag id <= 30 ---> 0xA0 | {tagId} @@ -804,12 +804,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 = dataIndexes[STACK_PTR]; pushByte(keyUsage); - pushBitStringHeader(unusedBits, (short) (last - stackPtr)); - pushOctetStringHeader((short) (last - stackPtr)); + pushBitStringHeader(unusedBits, (short) (last - dataIndexes[STACK_PTR])); + pushOctetStringHeader((short) (last - dataIndexes[STACK_PTR])); pushBytes(keyUsageExtn, (short) 0, (short) keyUsageExtn.length); - pushSequenceHeader((short) (last - stackPtr)); + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); } private static void pushAlgorithmId(byte[] algId) { @@ -851,24 +851,24 @@ private static void pushLength(short len) { private static void pushShort(short val) { decrementStackPtr((short) 2); - Util.setShort(stack, stackPtr, val); + Util.setShort(stack, dataIndexes[STACK_PTR], val); } private static void pushByte(byte val) { decrementStackPtr((short) 1); - stack[stackPtr] = val; + stack[dataIndexes[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, dataIndexes[STACK_PTR], len); } } private static void decrementStackPtr(short cnt) { - stackPtr = (short) (stackPtr - cnt); - if (bufStart > stackPtr) { + dataIndexes[STACK_PTR] = (short) (dataIndexes[STACK_PTR] - cnt); + if (indexes[BUF_START] > dataIndexes[STACK_PTR]) { KMException.throwIt(KMError.UNKNOWN_ERROR); } } @@ -876,27 +876,27 @@ 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; + dataIndexes[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(KMAttestationKey factoryAttestKey, short attSecret, short attMod, boolean rsaSign, boolean fakeCert) { - stackPtr = (short) (bufStart + bufLength); - short last = stackPtr; + dataIndexes[STACK_PTR] = (short) (indexes[BUF_START] + indexes[BUF_LENGTH]); + short last = dataIndexes[STACK_PTR]; short sigLen = 0; if (fakeCert) { rsaSign = true; @@ -910,17 +910,18 @@ else if (rsaSign) { } else { decrementStackPtr(ECDSA_MAX_SIG_LEN); } - short signatureOffset = stackPtr; - pushBitStringHeader((byte) 0, (short) (last - stackPtr)); + short signatureOffset = dataIndexes[STACK_PTR]; + pushBitStringHeader((byte) 0, (short) (last - dataIndexes[STACK_PTR])); if (rsaSign) { pushAlgorithmId(X509RsaSignAlgIdentifier); } else { pushAlgorithmId(X509EcdsaSignAlgIdentifier); } - tbsLength = stackPtr; - pushTbsCert(rsaCert, rsaSign); - tbsStart = stackPtr; - tbsLength = (short) (tbsLength - tbsStart); + indexes[TBS_LENGTH] = dataIndexes[STACK_PTR]; + + pushTbsCert((stateIndexes[RSA_CERT] == 0 ? false: true), rsaSign); + indexes[TBS_START] = dataIndexes[STACK_PTR]; + indexes[TBS_LENGTH] = (short) (indexes[TBS_LENGTH] - indexes[TBS_START]); if (attSecret != KMType.INVALID_VALUE || factoryAttestKey != null) { // Sign with the attestation key // The pubKey is the modulus. @@ -934,8 +935,8 @@ else if (rsaSign) { KMByteBlob.getStartOff(attMod), KMByteBlob.length(attMod), stack, - tbsStart, - tbsLength, + indexes[TBS_START], + indexes[TBS_LENGTH], stack, signatureOffset); if (sigLen > RSA_SIG_LEN) { @@ -946,8 +947,8 @@ else if (rsaSign) { .ecSign256( factoryAttestKey, stack, - tbsStart, - tbsLength, + indexes[TBS_START], + indexes[TBS_LENGTH], stack, signatureOffset); if (sigLen > ECDSA_MAX_SIG_LEN) { @@ -960,8 +961,8 @@ else if (rsaSign) { KMByteBlob.getStartOff(attSecret), KMByteBlob.length(attSecret), stack, - tbsStart, - tbsLength, + indexes[TBS_START], + indexes[TBS_LENGTH], stack, signatureOffset); if (sigLen > ECDSA_MAX_SIG_LEN) { @@ -969,28 +970,28 @@ else if (rsaSign) { } } // Adjust signature length - stackPtr = signatureOffset; + dataIndexes[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 - stackPtr = tbsStart; - pushSequenceHeader((short) (last - stackPtr)); - certStart = stackPtr; - certLength = (short) (last - certStart); + dataIndexes[STACK_PTR] = indexes[TBS_START]; + pushSequenceHeader((short) (last - dataIndexes[STACK_PTR])); + indexes[CERT_START] = dataIndexes[STACK_PTR]; + indexes[CERT_LENGTH] = (short) (last - indexes[CERT_START]); } @Override public void build() { - if (certMode == KMType.FAKE_CERT) { + if (stateIndexes[CERT_MODE] == KMType.FAKE_CERT) { build(null, KMType.INVALID_VALUE, KMType.INVALID_VALUE, true, true); - } else if (certMode == KMType.FACTORY_PROVISIONED_ATTEST_CERT) { + } else if (stateIndexes[CERT_MODE] == KMType.FACTORY_PROVISIONED_ATTEST_CERT) { build(factoryAttestKey, KMType.INVALID_VALUE, KMType.INVALID_VALUE, false, false); } else { - build(null, certAttestKeySecret, certAttestKeyRsaPubModulus, certRsaSign, false); + build(null, dataIndexes[CERT_ATT_KEY_SECRET], dataIndexes[CERT_ATT_KEY_RSA_PUB_MOD], (stateIndexes[CERT_RSA_SIGN] == 0 ? false: true), false); } } @@ -1048,7 +1049,7 @@ public boolean serialNumber(short number) { if (msb < 0 && length > (SERIAL_NUM_MAX_LEN - 1)) { return false; } - serialNum = number; + dataIndexes[SERIAL_NUMBER] = number; return true; } @@ -1066,30 +1067,30 @@ public boolean subjectName(short sub) { if (sub == KMType.INVALID_VALUE || KMByteBlob.length(sub) == 0) { return false; } - subjectName = sub; + dataIndexes[SUBJECT_NAME] = sub; return true; } @Override public KMAttestationCert ecAttestKey(short attestKey, byte mode) { - certMode = mode; - certAttestKeySecret = attestKey; - certAttestKeyRsaPubModulus = KMType.INVALID_VALUE; - certRsaSign = false; + stateIndexes[CERT_MODE] = mode; + dataIndexes[CERT_ATT_KEY_SECRET] = attestKey; + dataIndexes[CERT_ATT_KEY_RSA_PUB_MOD] = KMType.INVALID_VALUE; + stateIndexes[CERT_RSA_SIGN] = 0; return this; } @Override public KMAttestationCert rsaAttestKey(short attestPrivExp, short attestMod, byte mode) { - certMode = mode; - certAttestKeySecret = attestPrivExp; - certAttestKeyRsaPubModulus = attestMod; - certRsaSign = true; + stateIndexes[CERT_MODE] = mode; + dataIndexes[CERT_ATT_KEY_SECRET] = attestPrivExp; + dataIndexes[CERT_ATT_KEY_RSA_PUB_MOD] = attestMod; + stateIndexes[CERT_RSA_SIGN] = 1; return this; } public KMAttestationCert factoryAttestKey(KMAttestationKey key, byte mode) { - certMode = mode; + stateIndexes[CERT_MODE] = mode; factoryAttestKey = key; return this; } diff --git a/Applet/src/com/android/javacard/kmdevice/KMCose.java b/Applet/src/com/android/javacard/kmdevice/KMCose.java index e9e05d0e..a568a1c1 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMCose.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCose.java @@ -282,11 +282,11 @@ public short constructCoseSign1(short protectedHeader, short unProtectedHeader, * @param includeTestMode flag which indicates if TEST_COSE_KEY should be included or not. * @return instance of KMArray. */ - private short handleCosePairTags(short[] tags, boolean includeTestMode) { + private short handleCosePairTags(short[] tags, short tagLen, boolean includeTestMode) { short index = 0; // var is used to calculate the length of the array. short var = 0; - while (index < tags.length) { + while (index < tagLen) { if (tags[(short) (index + 1)] != KMType.INVALID_VALUE) { tags[(short) (index + 2)] = buildCosePairTag((byte) tags[index], tags[(short) (index + 1)]); @@ -299,7 +299,7 @@ private short handleCosePairTags(short[] tags, boolean includeTestMode) { index = 0; // var is used to index the array. var = 0; - while (index < tags.length) { + while (index < tagLen) { if (tags[(short) (index + 2)] != KMType.INVALID_VALUE) { KMArray.add(arrPtr, var++, tags[(short) (index + 2)]); } @@ -339,14 +339,21 @@ public short constructCoseCertPayload(short issuer, short subject, short subPubl * @param ephemeralKey instance of KMCoseKey. * @return instance of KMCoseHeaders. */ - public short constructHeaders(short alg, short keyId, short iv, short ephemeralKey) { - short[] coseHeaderTags = { - KMCose.COSE_LABEL_ALGORITHM, alg, KMType.INVALID_VALUE, - KMCose.COSE_LABEL_KEYID, keyId, KMType.INVALID_VALUE, - KMCose.COSE_LABEL_IV, iv, KMType.INVALID_VALUE, - KMCose.COSE_LABEL_COSE_KEY, ephemeralKey, KMType.INVALID_VALUE - }; - short ptr = handleCosePairTags(coseHeaderTags, false); + public short constructHeaders(short []buff, short alg, short keyId, short iv, short ephemeralKey) { + + buff[0]= KMCose.COSE_LABEL_ALGORITHM; + buff[1]= alg; + buff[2]= KMType.INVALID_VALUE; + buff[3]= KMCose.COSE_LABEL_KEYID; + buff[4]= keyId; + buff[5]= KMType.INVALID_VALUE; + buff[6]= KMCose.COSE_LABEL_IV; + buff[7]= iv; + buff[8]= KMType.INVALID_VALUE; + buff[9]= KMCose.COSE_LABEL_COSE_KEY; + buff[10]= ephemeralKey; + buff[11]= KMType.INVALID_VALUE; + short ptr = handleCosePairTags(buff, (short)12, false); ptr = KMCoseHeaders.instance(ptr); KMCoseHeaders.cast(ptr).canonicalize(); return ptr; @@ -483,7 +490,7 @@ public short buildCosePairTag(byte key, short valuePtr) { * @param testMode Represents if key is used in test mode or production mode. * @return Instance of the CoseKey structure. */ - public short constructCoseKey(short keyType, short keyId, short keyAlg, short keyOps, + public short constructCoseKey(short []buff, short keyType, short keyId, short keyAlg, short keyOps, short curve, byte[] pubKey, short pubKeyOff, short pubKeyLen, short privKeyPtr, boolean testMode) { if (pubKey[pubKeyOff] == 0x04) { // uncompressed format @@ -493,7 +500,7 @@ public short constructCoseKey(short keyType, short keyId, short keyAlg, short ke pubKeyLen = (short) (pubKeyLen / 2); short xPtr = KMByteBlob.instance(pubKey, pubKeyOff, pubKeyLen); short yPtr = KMByteBlob.instance(pubKey, (short) (pubKeyOff + pubKeyLen), pubKeyLen); - short coseKey = constructCoseKey(keyType, keyId, keyAlg, keyOps, curve, xPtr, yPtr, privKeyPtr, + short coseKey = constructCoseKey(buff, keyType, keyId, keyAlg, keyOps, curve, xPtr, yPtr, privKeyPtr, testMode); KMCoseKey.cast(coseKey).canonicalize(); return coseKey; @@ -514,19 +521,34 @@ public short constructCoseKey(short keyType, short keyId, short keyAlg, short ke * @param includeTestKey flag which identifies whether to construct test key or production key. * @return instance of the KMCoseKey object. */ - public short constructCoseKey(short keyType, short keyId, short keyAlg, short keyOps, short curve, + public short constructCoseKey(short []buff, short keyType, short keyId, short keyAlg, short keyOps, short curve, short pubX, short pubY, short priv, boolean includeTestKey) { - short[] coseKeyTags = { - KMCose.COSE_KEY_KEY_TYPE, keyType, KMType.INVALID_VALUE, - KMCose.COSE_KEY_KEY_ID, keyId, KMType.INVALID_VALUE, - KMCose.COSE_KEY_ALGORITHM, keyAlg, KMType.INVALID_VALUE, - KMCose.COSE_KEY_KEY_OPS, keyOps, KMType.INVALID_VALUE, - KMCose.COSE_KEY_CURVE, curve, KMType.INVALID_VALUE, - KMCose.COSE_KEY_PUBKEY_X, pubX, KMType.INVALID_VALUE, - KMCose.COSE_KEY_PUBKEY_Y, pubY, KMType.INVALID_VALUE, - KMCose.COSE_KEY_PRIV_KEY, priv, KMType.INVALID_VALUE - }; - short arrPtr = handleCosePairTags(coseKeyTags, includeTestKey); + buff[0] = KMCose.COSE_KEY_KEY_TYPE; + buff[1] = keyType; + buff[2] = KMType.INVALID_VALUE; + buff[3] = KMCose.COSE_KEY_KEY_ID; + buff[4] = keyId; + buff[5] = KMType.INVALID_VALUE; + buff[6] = KMCose.COSE_KEY_ALGORITHM; + buff[7] = keyAlg; + buff[8] = KMType.INVALID_VALUE; + buff[9] = KMCose.COSE_KEY_KEY_OPS; + buff[10] = keyOps; + buff[11] = KMType.INVALID_VALUE; + buff[12] = KMCose.COSE_KEY_CURVE; + buff[13] = curve; + buff[14] = KMType.INVALID_VALUE; + buff[15] = KMCose.COSE_KEY_PUBKEY_X; + buff[16] = pubX; + buff[17] = KMType.INVALID_VALUE; + buff[18] = KMCose.COSE_KEY_PUBKEY_Y; + buff[19] = pubY; + buff[20] = KMType.INVALID_VALUE; + buff[21] = KMCose.COSE_KEY_PRIV_KEY; + buff[22] = priv; + buff[23] = KMType.INVALID_VALUE; + + short arrPtr = handleCosePairTags(buff, (short)24, includeTestKey); if (includeTestKey) { short testKey = KMCosePairSimpleValueTag.instance(KMNInteger.uint_32(KMCose.COSE_TEST_KEY, (short) 0), diff --git a/Applet/src/com/android/javacard/kmdevice/KMCoseHeaders.java b/Applet/src/com/android/javacard/kmdevice/KMCoseHeaders.java index a1c2a653..5db5a7c6 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMCoseHeaders.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCoseHeaders.java @@ -151,20 +151,23 @@ public short getAlgorithm() { return getValueType(KMCose.COSE_LABEL_ALGORITHM); } - public boolean isDataValid(short alg, short keyIdPtr) { - short[] headerTags = { - KMCose.COSE_LABEL_ALGORITHM, alg, - KMCose.COSE_LABEL_KEYID, keyIdPtr, - }; + public boolean isDataValid(short []buff, short alg, short keyIdPtr) { + + short bufLen = 4; + buff[0] = KMCose.COSE_LABEL_ALGORITHM; + buff[1] = alg; + buff[2] = KMCose.COSE_LABEL_KEYID; + buff[3] = keyIdPtr; + boolean valid = false; short value; short ptr; short tagIndex = 0; - while (tagIndex < headerTags.length) { - value = headerTags[(short) (tagIndex + 1)]; + while (tagIndex < bufLen) { + value = buff[(short) (tagIndex + 1)]; if (value != KMType.INVALID_VALUE) { valid = false; - ptr = getValueType(headerTags[tagIndex]); + ptr = getValueType(buff[tagIndex]); switch (KMType.getKMType(ptr)) { case KMType.BYTE_BLOB_TYPE: if ((KMByteBlob.length(value) == KMByteBlob.length(ptr)) && diff --git a/Applet/src/com/android/javacard/kmdevice/KMCoseKey.java b/Applet/src/com/android/javacard/kmdevice/KMCoseKey.java index 97f73bf3..4c5bf941 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMCoseKey.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCoseKey.java @@ -181,24 +181,29 @@ public boolean isTestKey() { * @param curve value of the curve. * @return true if valid, otherwise false. */ - public boolean isDataValid(short keyType, short keyIdPtr, short keyAlg, short keyOps, + public boolean isDataValid(short []buff, short keyType, short keyIdPtr, short keyAlg, short keyOps, short curve) { - short[] coseKeyTags = { - KMCose.COSE_KEY_KEY_TYPE, keyType, - KMCose.COSE_KEY_KEY_ID, keyIdPtr, - KMCose.COSE_KEY_ALGORITHM, keyAlg, - KMCose.COSE_KEY_KEY_OPS, keyOps, - KMCose.COSE_KEY_CURVE, curve, - }; + short buffLen = 10; + buff[0] = KMCose.COSE_KEY_KEY_TYPE; + buff[1] = keyType; + buff[2] = KMCose.COSE_KEY_KEY_ID; + buff[3] = keyIdPtr; + buff[4] = KMCose.COSE_KEY_ALGORITHM; + buff[5] = keyAlg; + buff[6] = KMCose.COSE_KEY_KEY_OPS; + buff[7] = keyOps; + buff[8] = KMCose.COSE_KEY_CURVE; + buff[9] = curve; + boolean valid = false; short ptr; short tagIndex = 0; short value; - while (tagIndex < coseKeyTags.length) { - value = coseKeyTags[(short) (tagIndex + 1)]; + while (tagIndex < buffLen) { + value = buff[(short) (tagIndex + 1)]; if (value != KMType.INVALID_VALUE) { valid = false; - ptr = getValueType(coseKeyTags[tagIndex], KMType.INVALID_VALUE); + ptr = getValueType(buff[tagIndex], KMType.INVALID_VALUE); switch (KMType.getKMType(ptr)) { case KMType.BYTE_BLOB_TYPE: if ((KMByteBlob.length(value) == KMByteBlob.length(ptr)) && diff --git a/Applet/src/com/android/javacard/kmdevice/KMCosePairByteBlobTag.java b/Applet/src/com/android/javacard/kmdevice/KMCosePairByteBlobTag.java index d53de1dc..bf2e66d9 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMCosePairByteBlobTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCosePairByteBlobTag.java @@ -29,11 +29,24 @@ public class KMCosePairByteBlobTag extends KMCosePairTagType { private static KMCosePairByteBlobTag prototype; - public static Object[] keys; + private static Object[] keys; private KMCosePairByteBlobTag() { } - + + public static void initStatics() { + keys = new Object[]{ + (Object) new byte[]{(byte) 0, (byte) 0, (byte) 0, KMCose.COSE_KEY_PUBKEY_X}, + (Object) new byte[]{(byte) 0, (byte) 0, (byte) 0, KMCose.COSE_KEY_PUBKEY_Y}, + (Object) new byte[]{(byte) 0, (byte) 0, (byte) 0, KMCose.COSE_KEY_PRIV_KEY}, + (Object) new byte[]{(byte) 0, (byte) 0, (byte) 0, KMCose.COSE_LABEL_IV}, + (Object) new byte[]{(byte) 0, (byte) 0, (byte) 0, KMCose.COSE_LABEL_KEYID}, + (Object) new byte[]{(byte) 0, (byte) 0, (byte) 0, KMCose.COSE_KEY_KEY_ID}, + (Object) KMCose.SUBJECT_PUBLIC_KEY, + (Object) KMCose.KEY_USAGE + }; + } + private static KMCosePairByteBlobTag proto(short ptr) { if (prototype == null) { prototype = new KMCosePairByteBlobTag(); @@ -94,23 +107,7 @@ public short getValuePtr() { (short) (instanceTable[KM_COSE_KEY_BYTE_BLOB_VAL_OFFSET] + TLV_HEADER_SIZE + 4)); } - private static void createKeys() { - if (keys == null) { - keys = new Object[]{ - (Object) new byte[]{(byte) 0, (byte) 0, (byte) 0, KMCose.COSE_KEY_PUBKEY_X}, - (Object) new byte[]{(byte) 0, (byte) 0, (byte) 0, KMCose.COSE_KEY_PUBKEY_Y}, - (Object) new byte[]{(byte) 0, (byte) 0, (byte) 0, KMCose.COSE_KEY_PRIV_KEY}, - (Object) new byte[]{(byte) 0, (byte) 0, (byte) 0, KMCose.COSE_LABEL_IV}, - (Object) new byte[]{(byte) 0, (byte) 0, (byte) 0, KMCose.COSE_LABEL_KEYID}, - (Object) new byte[]{(byte) 0, (byte) 0, (byte) 0, KMCose.COSE_KEY_KEY_ID}, - (Object) KMCose.SUBJECT_PUBLIC_KEY, - (Object) KMCose.KEY_USAGE - }; - } - } - public static boolean isKeyValueValid(short keyPtr) { - createKeys(); short type = KMType.getKMType(keyPtr); short offset = 0; if (type == INTEGER_TYPE) { diff --git a/Applet/src/com/android/javacard/kmdevice/KMCosePairTagType.java b/Applet/src/com/android/javacard/kmdevice/KMCosePairTagType.java index 9cde1468..ab303adb 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMCosePairTagType.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCosePairTagType.java @@ -41,9 +41,8 @@ public abstract class KMCosePairTagType extends KMType { */ public static Object[] allowedKeyPairs; - private static void createAllowedKeyPairs() { - if (allowedKeyPairs == null) { - allowedKeyPairs = + public static void initStatics() { + allowedKeyPairs = new Object[]{ // Key type (Object) new byte[]{0, 0, 0, KMCose.COSE_KEY_KEY_TYPE}, @@ -68,10 +67,8 @@ private static void createAllowedKeyPairs() { // Test Key KMCose.COSE_TEST_KEY, (Object) new byte[]{KMSimpleValue.NULL}, }; - } } - - + /** * Validates the key and the values corresponding to key. * @@ -86,7 +83,6 @@ public static boolean isKeyPairValid(byte[] key, short keyOff, short keyLen, sho short valueIdx; byte[] values; boolean valid = false; - createAllowedKeyPairs(); while (index < allowedKeyPairs.length) { valueIdx = 0; if (isEqual((byte[]) allowedKeyPairs[index], (short) 0, diff --git a/Applet/src/com/android/javacard/kmdevice/KMDataStoreConstants.java b/Applet/src/com/android/javacard/kmdevice/KMDataStoreConstants.java index dece7cae..59bd7954 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMDataStoreConstants.java +++ b/Applet/src/com/android/javacard/kmdevice/KMDataStoreConstants.java @@ -52,6 +52,7 @@ public class KMDataStoreConstants { public static final byte AUTH_TAG_8 = 32; public static final byte ADDITIONAL_CERT_CHAIN = 33; public static final byte BOOT_CERT_CHAIN = 34; + public static final byte RKP_MAC_KEY = 35; //certificate data constants. public static final byte CERTIFICATE_CHAIN = 0; @@ -64,6 +65,5 @@ public class KMDataStoreConstants { public static final byte INTERFACE_TYPE_DEVICE_UNIQUE_KEY = 0x03; public static final byte INTERFACE_TYPE_MASTER_KEY = 0x04; public static final byte INTERFACE_TYPE_PRE_SHARED_KEY = 0x05; - - + public static final byte INTERFACE_TYPE_RKP_MAC_KEY = 0x06; } diff --git a/Applet/src/com/android/javacard/kmdevice/KMEnum.java b/Applet/src/com/android/javacard/kmdevice/KMEnum.java index d051f991..5a42a2c0 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMEnum.java +++ b/Applet/src/com/android/javacard/kmdevice/KMEnum.java @@ -32,7 +32,7 @@ public class KMEnum extends KMType { // The allowed enum types. private static short[] types; - private static Object[] enums = null; + private static Object[] enums ; private KMEnum() { } @@ -49,6 +49,24 @@ public static void initStatics() { ECCURVE, RULE }; + enums = new Object[]{ + new byte[]{SOFTWARE, TRUSTED_ENVIRONMENT, STRONGBOX}, + new byte[]{X509, PKCS8, RAW}, + new byte[]{ + DERIVATION_NONE, + RFC5869_SHA256, + ISO18033_2_KDF1_SHA1, + ISO18033_2_KDF1_SHA256, + ISO18033_2_KDF2_SHA1, + ISO18033_2_KDF2_SHA256 + }, + new byte[]{SELF_SIGNED_BOOT, VERIFIED_BOOT, UNVERIFIED_BOOT, FAILED_BOOT}, + new byte[]{DEVICE_LOCKED_TRUE, DEVICE_LOCKED_FALSE}, + new byte[]{USER_AUTH_NONE, PASSWORD, FINGERPRINT, BOTH}, + new byte[]{ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, ATTEST_KEY, AGREE_KEY}, + new byte[]{P_224, P_256, P_384, P_521}, + new byte[]{IGNORE_INVALID_TAGS, FAIL_ON_INVALID_TAGS} + }; } private static KMEnum proto(short ptr) { @@ -101,31 +119,6 @@ public static short instance(short enumType, byte val) { return ptr; } - private static void create() { - // The allowed enum values to corresponding enum types in the types array. - if (enums == null) { - enums = - new Object[]{ - new byte[]{SOFTWARE, TRUSTED_ENVIRONMENT, STRONGBOX}, - new byte[]{X509, PKCS8, RAW}, - new byte[]{ - DERIVATION_NONE, - RFC5869_SHA256, - ISO18033_2_KDF1_SHA1, - ISO18033_2_KDF1_SHA256, - ISO18033_2_KDF2_SHA1, - ISO18033_2_KDF2_SHA256 - }, - new byte[]{SELF_SIGNED_BOOT, VERIFIED_BOOT, UNVERIFIED_BOOT, FAILED_BOOT}, - new byte[]{DEVICE_LOCKED_TRUE, DEVICE_LOCKED_FALSE}, - new byte[]{USER_AUTH_NONE, PASSWORD, FINGERPRINT, BOTH}, - new byte[]{ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, ATTEST_KEY, AGREE_KEY}, - new byte[]{P_224, P_256, P_384, P_521}, - new byte[]{IGNORE_INVALID_TAGS, FAIL_ON_INVALID_TAGS} - }; - } - } - public void setVal(byte val) { heap[(short) (KMType.instanceTable[KM_ENUM_OFFSET] + TLV_HEADER_SIZE + 2)] = val; } @@ -144,7 +137,6 @@ public short getEnumType() { // isValidTag enumeration keys and values. private static boolean validateEnum(short key, byte value) { - create(); byte[] vals; short enumInd; // check if key exists diff --git a/Applet/src/com/android/javacard/kmdevice/KMEnumArrayTag.java b/Applet/src/com/android/javacard/kmdevice/KMEnumArrayTag.java index 3a8713cc..e4b77b0b 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMEnumArrayTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMEnumArrayTag.java @@ -32,10 +32,20 @@ public class KMEnumArrayTag extends KMTag { private static short[] tags; // Tag Values. - private static Object[] enums = null; + private static Object[] enums; public static void initStatics() { tags = new short[]{PURPOSE, BLOCK_MODE, DIGEST, PADDING, RSA_OAEP_MGF_DIGEST}; + enums = new Object[]{ + new byte[]{ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, ATTEST_KEY, AGREE_KEY}, + new byte[]{ECB, CBC, CTR, GCM}, + new byte[]{DIGEST_NONE, MD5, SHA1, SHA2_224, SHA2_256, SHA2_384, SHA2_512}, + new byte[]{ + PADDING_NONE, RSA_OAEP, RSA_PSS, RSA_PKCS1_1_5_ENCRYPT, RSA_PKCS1_1_5_SIGN, PKCS7 + }, + new byte[]{DIGEST_NONE, MD5, SHA1, SHA2_224, SHA2_256, SHA2_384, SHA2_512}, + + }; } private KMEnumArrayTag() { @@ -128,25 +138,7 @@ public short length() { return KMByteBlob.length(blobPtr); } - public static void create() { - if (enums == null) { - // allowed tag values. - enums = - new Object[]{ - new byte[]{ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, ATTEST_KEY, AGREE_KEY}, - new byte[]{ECB, CBC, CTR, GCM}, - new byte[]{DIGEST_NONE, MD5, SHA1, SHA2_224, SHA2_256, SHA2_384, SHA2_512}, - new byte[]{ - PADDING_NONE, RSA_OAEP, RSA_PSS, RSA_PKCS1_1_5_ENCRYPT, RSA_PKCS1_1_5_SIGN, PKCS7 - }, - new byte[]{DIGEST_NONE, MD5, SHA1, SHA2_224, SHA2_256, SHA2_384, SHA2_512}, - - }; - } - } - private static byte[] getAllowedEnumValues(short key) { - create(); short index = (short) tags.length; while (--index >= 0) { if (tags[index] == key) { @@ -202,111 +194,6 @@ public boolean contains(short tagValue) { return false; } - public boolean isValidDigests(byte alg) { - short index = 0; - short digest; - while (index < length()) { - digest = get(index); - switch (alg) { - case KMType.EC: - case KMType.RSA: - if (digest != KMType.DIGEST_NONE && digest != KMType.SHA2_256 && digest != KMType.SHA1) { - return false; - } - break; - case KMType.HMAC: - if (digest != KMType.SHA2_256) { - return false; - } - break; - case KMType.AES: - case KMType.DES: - if (digest != KMType.DIGEST_NONE) { - return false; - } - break; - default: - return false; - } - index++; - } - return true; - } - - public boolean isValidPaddingModes(byte alg) { - short index = 0; - short padding; - while (index < length()) { - padding = get(index); - switch (alg) { - case KMType.RSA: - if (padding != KMType.RSA_OAEP - && padding != KMType.PADDING_NONE - && padding != KMType.RSA_PKCS1_1_5_SIGN - && padding != KMType.RSA_PKCS1_1_5_ENCRYPT - && padding != KMType.RSA_PSS) { - return false; - } - break; - case KMType.AES: - case KMType.DES: - if (padding != KMType.PKCS7 && padding != KMType.PADDING_NONE) { - return false; - } - break; - case KMType.EC: - case KMType.HMAC: - if (padding != PADDING_NONE) { - return false; - } - break; - default: - return false; - } - index++; - } - return true; - } - - public boolean isValidPurpose(byte alg) { - short index = 0; - short purpose; - while (index < length()) { - purpose = get(index); - switch (purpose) { - case KMType.DECRYPT: - case KMType.ENCRYPT: - if (alg != KMType.RSA && alg != KMType.AES && alg != KMType.DES) { - return false; - } - break; - case KMType.SIGN: - case KMType.VERIFY: - if (alg != KMType.HMAC && alg != KMType.RSA && alg != KMType.EC) { - return false; - } - break; - case KMType.WRAP_KEY: - if (alg != KMType.RSA) { - return false; - } - break; - default: - return false; - } - index++; - } - return true; - } - - public boolean isValidBlockMode(byte alg) { - if (alg == KMType.AES || alg == KMType.DES) { - return true; - } else { - return false; - } - } - public static short get(short bPtr, short index) { return KMEnumArrayTag.cast(bPtr).get(index); } diff --git a/Applet/src/com/android/javacard/kmdevice/KMEnumTag.java b/Applet/src/com/android/javacard/kmdevice/KMEnumTag.java index 38a53229..acfaaf9d 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMEnumTag.java +++ b/Applet/src/com/android/javacard/kmdevice/KMEnumTag.java @@ -32,12 +32,20 @@ public class KMEnumTag extends KMTag { // The allowed tag keys of type enum tag. private static short[] tags; - private static Object[] enums = null; + private static Object[] enums; public static void initStatics() { tags = new short[]{ ALGORITHM, ECCURVE, BLOB_USAGE_REQ, USER_AUTH_TYPE, ORIGIN, HARDWARE_TYPE }; + enums = new Object[]{ + new byte[]{RSA, DES, EC, AES, HMAC}, + new byte[]{P_224, P_256, P_384, P_521, CURVE_25519}, + new byte[]{STANDALONE, REQUIRES_FILE_SYSTEM}, + new byte[]{USER_AUTH_NONE, PASSWORD, FINGERPRINT, BOTH, ANY}, + new byte[]{GENERATED, DERIVED, IMPORTED, UNKNOWN, SECURELY_IMPORTED}, + new byte[]{SOFTWARE, TRUSTED_ENVIRONMENT, STRONGBOX} + }; } private KMEnumTag() { @@ -102,24 +110,8 @@ public byte getValue() { return heap[(short) (KMType.instanceTable[KM_ENUM_TAG_OFFSET] + TLV_HEADER_SIZE + 4)]; } - public static void create() { - if (enums == null) { - // enum tag values. - enums = - new Object[]{ - new byte[]{RSA, DES, EC, AES, HMAC}, - new byte[]{P_224, P_256, P_384, P_521, CURVE_25519}, - new byte[]{STANDALONE, REQUIRES_FILE_SYSTEM}, - new byte[]{USER_AUTH_NONE, PASSWORD, FINGERPRINT, BOTH, ANY}, - new byte[]{GENERATED, DERIVED, IMPORTED, UNKNOWN, SECURELY_IMPORTED}, - new byte[]{SOFTWARE, TRUSTED_ENVIRONMENT, STRONGBOX} - }; - } - } - // isValidTag enumeration keys and values. private static boolean validateEnum(short key, byte value) { - create(); byte[] vals; short enumInd; // check if key exists diff --git a/Applet/src/com/android/javacard/kmdevice/KMKeymasterDevice.java b/Applet/src/com/android/javacard/kmdevice/KMKeymasterDevice.java index e25d05a1..1e5b43fd 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMKeymasterDevice.java +++ b/Applet/src/com/android/javacard/kmdevice/KMKeymasterDevice.java @@ -118,7 +118,7 @@ public class KMKeymasterDevice { private static final byte AUTH_DATA = 5; private static final byte AUTH_TAG = 6; private static final byte NONCE = 7; - private static final byte KEY_BLOB = 8; + protected static final byte KEY_BLOB = 8; private static final byte AUTH_DATA_LENGTH = 9; protected static final byte SECRET = 10; private static final byte ROT = 11; @@ -126,9 +126,9 @@ public class KMKeymasterDevice { private static final byte RSA_PUB_EXPONENT = 13; private static final byte APP_ID = 14; private static final byte APP_DATA = 15; - private static final byte PUB_KEY = 16; + protected static final byte PUB_KEY = 16; private static final byte IMPORTED_KEY_BLOB = 17; - private static final byte ORIGIN = 18; + protected static final byte ORIGIN = 18; private static final byte NOT_USED = 19; private static final byte MASKING_KEY = 20; private static final byte HMAC_SHARING_PARAMS = 21; @@ -170,6 +170,10 @@ public class KMKeymasterDevice { private static byte[] JAVACARD_KEYMASTER_DEVICE; private static byte[] GOOGLE; private static byte[] X509Subject; + + private static byte[] dec319999Ms ; + private static byte[] dec319999; + private static byte[] jan01970; private static short[] ATTEST_ID_TAGS; private static final byte SERIAL_NUM = (byte) 0x01; @@ -295,6 +299,17 @@ public static void initStatics() { KMType.ATTESTATION_ID_PRODUCT, KMType.ATTESTATION_ID_SERIAL }; + + dec319999Ms = new byte[]{(byte)0, (byte)0, (byte)0xE6, (byte)0x77, + (byte)0xD2, (byte)0x1F, (byte)0xD8, (byte)0x18}; + + dec319999 = new byte[]{ + 0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, + 0x39, 0x35, 0x39, 0x5a,}; + + jan01970 = new byte[]{ + 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x5a,}; } private static void initKMDeviceStatics() { @@ -314,6 +329,8 @@ private static void initKMDeviceStatics() { KMPKCS8Decoder.initStatics(); KMEnumArrayTag.initStatics(); KMIntegerArrayTag.initStatics(); + KMCosePairByteBlobTag.initStatics(); + KMCosePairTagType.initStatics(); } public void clean() { @@ -3880,7 +3897,7 @@ public void validateECKeys() { } } - private void generateECKeys(byte[] scratchPad) { + protected void generateECKeys(byte[] scratchPad) { validateECKeys(); short[] lengths = tmpVariables; seProvider.createAsymmetricKey(KMType.EC, scratchPad, (short) 0, (short) 128, scratchPad, @@ -3915,7 +3932,7 @@ private void validateHmacKey() { // check whether digest sizes are greater then or equal to min mac length. // Only SHA256 digest must be supported. - if (KMEnumArrayTag.contains(KMType.DIGEST, KMType.DIGEST_NONE, data[KEY_PARAMETERS])) { + if (!KMEnumArrayTag.contains(KMType.DIGEST, KMType.SHA2_256, data[KEY_PARAMETERS])) { KMException.throwIt(KMError.UNSUPPORTED_DIGEST); } // Read Minimum Mac length @@ -3994,7 +4011,7 @@ protected short getBootPatchLevel(byte[] scratchPad) { return KMInteger.uint_32(scratchPad, (short) 0); } - private void makeKeyCharacteristics(byte[] scratchPad) { + protected void makeKeyCharacteristics(byte[] scratchPad) { data[KEY_CHARACTERISTICS] = makeKeyCharacteristics( data[KEY_PARAMETERS], @@ -4010,7 +4027,7 @@ private void makeKeyCharacteristics(byte[] scratchPad) { data[HW_PARAMETERS] = getHardwareParamters(data[SB_PARAMETERS], data[TEE_PARAMETERS]); } - private void createEncryptedKeyBlob(byte[] scratchPad) { + protected void createEncryptedKeyBlob(byte[] scratchPad) { // make root of trust blob data[ROT] = readROT(scratchPad); if (data[ROT] == KMType.INVALID_VALUE) { @@ -4265,23 +4282,6 @@ public void powerReset() { resetWrappingKey(); } - public void generateRkpKey(byte[] scratchPad, short keyParams) { - data[KEY_PARAMETERS] = keyParams; - generateECKeys(scratchPad); - // create key blob - data[ORIGIN] = KMType.GENERATED; - makeKeyCharacteristics(scratchPad); - createEncryptedKeyBlob(scratchPad); - } - - public static short getPubKey() { - return data[PUB_KEY]; - } - - public static short getPivateKey() { - return data[KEY_BLOB]; - } - /** * Encodes the object to the provided apdu buffer. * diff --git a/Applet/src/com/android/javacard/kmdevice/KMKeymintDevice.java b/Applet/src/com/android/javacard/kmdevice/KMKeymintDevice.java index 48aa33ff..248c532d 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMKeymintDevice.java +++ b/Applet/src/com/android/javacard/kmdevice/KMKeymintDevice.java @@ -452,7 +452,7 @@ public short generateBcc(boolean testMode, byte[] scratchPad) { } KMDeviceUniqueKey deviceUniqueKey = rkpDataStoreInst.getDeviceUniqueKey(testMode); short temp = deviceUniqueKey.getPublicKey(scratchPad, (short) 0); - short coseKey = kmCoseInst.constructCoseKey(KMInteger.uint_8(KMCose.COSE_KEY_TYPE_EC2), + short coseKey = kmCoseInst.constructCoseKey(rkp.rkpTmpVariables, KMInteger.uint_8(KMCose.COSE_KEY_TYPE_EC2), KMType.INVALID_VALUE, KMNInteger.uint_8(KMCose.COSE_ALG_ES256), KMInteger.uint_8(KMCose.COSE_KEY_OP_VERIFY), KMInteger.uint_8(KMCose.COSE_ECCURVE_256), scratchPad, (short) 0, temp, @@ -478,7 +478,7 @@ public short generateBcc(boolean testMode, byte[] scratchPad) { payload = KMByteBlob.instance(scratchPad, (short) 0, temp); // protected header - short protectedHeader = kmCoseInst.constructHeaders(KMNInteger.uint_8(KMCose.COSE_ALG_ES256), + short protectedHeader = kmCoseInst.constructHeaders(rkp.rkpTmpVariables, KMNInteger.uint_8(KMCose.COSE_ALG_ES256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE); // temp temporarily holds the length of encoded headers. @@ -540,7 +540,7 @@ public short validateCertChain(boolean validateEekRoot, byte expCertAlg, ptr2 = KMArray.get(ptr1, KMCose.COSE_SIGN1_PROTECTED_PARAMS_OFFSET); ptr2 = decoder.decode(coseHeadersExp, KMByteBlob.getBuffer(ptr2), KMByteBlob.getStartOff(ptr2), KMByteBlob.length(ptr2)); - if (!KMCoseHeaders.cast(ptr2).isDataValid(alg, KMType.INVALID_VALUE)) { + if (!KMCoseHeaders.cast(ptr2).isDataValid(rkp.rkpTmpVariables, alg, KMType.INVALID_VALUE)) { KMException.throwIt(KMError.STATUS_FAILED); } @@ -551,7 +551,7 @@ public short validateCertChain(boolean validateEekRoot, byte expCertAlg, if ((index == (short) (len - 1)) && len > 1) { alg = expLeafCertAlg; } - if (!KMCoseKey.cast(ptr2).isDataValid(KMCose.COSE_KEY_TYPE_EC2, KMType.INVALID_VALUE, alg, + if (!KMCoseKey.cast(ptr2).isDataValid(rkp.rkpTmpVariables, KMCose.COSE_KEY_TYPE_EC2, KMType.INVALID_VALUE, alg, KMType.INVALID_VALUE, KMCose.COSE_ECCURVE_256)) { KMException.throwIt(KMError.STATUS_FAILED); } @@ -620,4 +620,22 @@ public void validateEarlyBoot(short Params, byte inst, byte[] sPad, short sPadOf super.validateEarlyBoot(Params, inst, sPad, sPadOff, errorCode); } } + + public void generateRkpKey(byte[] scratchPad, short keyParams) { + data[KEY_PARAMETERS] = keyParams; + generateECKeys(scratchPad); + // create key blob + data[ORIGIN] = KMType.GENERATED; + makeKeyCharacteristics(scratchPad); + createEncryptedKeyBlob(scratchPad); + } + + public static short getPubKey() { + return data[PUB_KEY]; + } + + public static short getPivateKey() { + return data[KEY_BLOB]; + } + } diff --git a/Applet/src/com/android/javacard/kmdevice/KMPKCS8Decoder.java b/Applet/src/com/android/javacard/kmdevice/KMPKCS8Decoder.java index 72e07fea..576cac25 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMPKCS8Decoder.java +++ b/Applet/src/com/android/javacard/kmdevice/KMPKCS8Decoder.java @@ -1,5 +1,6 @@ package com.android.javacard.kmdevice; +import javacard.framework.JCSystem; import javacard.framework.Util; public class KMPKCS8Decoder { @@ -10,19 +11,22 @@ public class KMPKCS8Decoder { public static final byte ASN1_A0_TAG = (byte) 0xA0; public static final byte ASN1_A1_TAG = (byte) 0xA1; public static final byte ASN1_BIT_STRING = 0x03; + private static final short START_INDEX = 0; + private static final short LENGTH_INDEX = 1; + private static final short CURR_INDEX =2; + public static byte[] EC_CURVE; public static byte[] RSA_ALGORITHM; public static byte[] EC_ALGORITHM; private byte[] data; - private short start; - private short length; - private short cur; + private short[] dataIndex; private static KMPKCS8Decoder inst; private KMPKCS8Decoder() { - start = 0; - length = 0; - cur = 0; + dataIndex = JCSystem.makeTransientShortArray((short)3, JCSystem.CLEAR_ON_RESET); + for(short i=0; i<3; i++) { + dataIndex[i] = 0; + } } public static void initStatics() { @@ -205,15 +209,14 @@ public short decodeEcPrivateKey(short version) { } private void validateTag0IfPresent() { - if (data[cur] != ASN1_A0_TAG) { + if (data[dataIndex[CURR_INDEX]] != 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) { + if (Util.arrayCompare(data, dataIndex[CURR_INDEX], EC_CURVE, (short) 0, len) != 0) { KMException.throwIt(KMError.UNKNOWN_ERROR); } incrementCursor(len); @@ -228,26 +231,26 @@ private short header(short tag) { } private byte getByte() { - byte d = data[cur]; + byte d = data[dataIndex[CURR_INDEX]]; incrementCursor((short) 1); return d; } private short getShort() { - short d = Util.getShort(data, cur); + short d = Util.getShort(data, dataIndex[CURR_INDEX]); incrementCursor((short) 2); return d; } private void getBytes(short blob) { short len = KMByteBlob.length(blob); - Util.arrayCopyNonAtomic(data, cur, KMByteBlob.getBuffer(blob), + Util.arrayCopyNonAtomic(data, dataIndex[CURR_INDEX], KMByteBlob.getBuffer(blob), KMByteBlob.getStartOff(blob), len); incrementCursor(len); } private void getBytes(byte[] buffer, short offset, short len) { - Util.arrayCopyNonAtomic(data, cur, buffer, offset, len); + Util.arrayCopyNonAtomic(data, dataIndex[CURR_INDEX], buffer, offset, len); incrementCursor(len); } @@ -276,14 +279,14 @@ public static KMPKCS8Decoder instance() { public void init(short blob) { data = KMByteBlob.getBuffer(blob); - start = KMByteBlob.getStartOff(blob); - length = KMByteBlob.length(blob); - cur = start; + dataIndex[START_INDEX] = KMByteBlob.getStartOff(blob); + dataIndex[LENGTH_INDEX] = KMByteBlob.length(blob); + dataIndex[CURR_INDEX] = dataIndex[START_INDEX]; } public void incrementCursor(short n) { - cur += n; - if (cur > ((short) (start + length))) { + dataIndex[CURR_INDEX] = (short) (dataIndex[CURR_INDEX] + n); + if (dataIndex[CURR_INDEX] > ((short) (dataIndex[START_INDEX] + dataIndex[LENGTH_INDEX]))) { KMException.throwIt(KMError.UNKNOWN_ERROR); } } diff --git a/Applet/src/com/android/javacard/kmdevice/KMRkpDataStore.java b/Applet/src/com/android/javacard/kmdevice/KMRkpDataStore.java index bb7023b4..445debff 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMRkpDataStore.java +++ b/Applet/src/com/android/javacard/kmdevice/KMRkpDataStore.java @@ -61,4 +61,11 @@ void createDeviceUniqueKey(boolean testMode, byte[] pubKey, short pubKeyOff, sho * @return KMDeviceUniqueKey instance */ KMDeviceUniqueKey getDeviceUniqueKey(boolean testMode); + + /** + * Returns the persisted RKP mac key. + * + * @return KMRkpMacKey instance. + */ + KMRkpMacKey getRkpMacacKey(); } diff --git a/Applet/src/com/android/javacard/kmdevice/KMRkpMacKey.java b/Applet/src/com/android/javacard/kmdevice/KMRkpMacKey.java new file mode 100644 index 00000000..e40506a2 --- /dev/null +++ b/Applet/src/com/android/javacard/kmdevice/KMRkpMacKey.java @@ -0,0 +1,6 @@ +package com.android.javacard.kmdevice; + + +public interface KMRkpMacKey { + +} diff --git a/Applet/src/com/android/javacard/kmdevice/KMSEProvider.java b/Applet/src/com/android/javacard/kmdevice/KMSEProvider.java index 03dfcd50..8b42e497 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMSEProvider.java +++ b/Applet/src/com/android/javacard/kmdevice/KMSEProvider.java @@ -275,6 +275,25 @@ short hmacSign( short dataLength, byte[] signature, short signatureStart); + + /** + * This is a oneshot operation that signs the data using hmac algorithm. + * + * @param hmacKey is the KMHmacKey. + * @param data is the buffer containing data to be signed. + * @param dataStart is the start of the data. + * @param dataLength is the length of the data. + * @param signature is the output signature buffer + * @param signatureStart is the start of the signature + * @return length of the signature buffer in bytes. + */ + short hmacSign( + Object hmacKey, + byte[] data, + short dataStart, + short dataLength, + byte[] signature, + short signatureStart); /** * This is a oneshot operation that signs the data using hmac algorithm. This is used to derive @@ -299,7 +318,7 @@ short hmacKDF( /** * This is a oneshot operation that verifies the signature using hmac algorithm. * - * @param hmacKey is the computed hmac key. + * @param hmacKey is the KMHmacKey key. * @param data is the buffer containing data. * @param dataStart is the start of the data. * @param dataLength is the length of the data. @@ -309,7 +328,7 @@ short hmacKDF( * @return true if the signature matches. */ boolean hmacVerify( - KMComputedHmacKey hmacKey, + Object hmacKey, byte[] data, short dataStart, short dataLength, @@ -584,6 +603,17 @@ KMOperation initAsymmetricOperation( */ KMComputedHmacKey createComputedHmacKey(KMComputedHmacKey createComputedHmacKey, byte[] keyData, short offset, short length); + + /** + * This function creates an HMACKey and initializes the key with the provided input key data. + * + * @param keyData buffer containing the key data. + * @param offset start of the buffer. + * @param length length of the buffer. + * @return An instance of the KMRkpMacKey. + */ + KMRkpMacKey createRkpMacKey(KMRkpMacKey createComputedHmacKey, byte[] keyData, + short offset, short length); /** * This function generates an AES Key of keySizeBits, which is used as an master key. This diff --git a/Applet/src/com/android/javacard/kmdevice/RemotelyProvisionedComponentDevice.java b/Applet/src/com/android/javacard/kmdevice/RemotelyProvisionedComponentDevice.java index 1f2031a5..d765f29f 100644 --- a/Applet/src/com/android/javacard/kmdevice/RemotelyProvisionedComponentDevice.java +++ b/Applet/src/com/android/javacard/kmdevice/RemotelyProvisionedComponentDevice.java @@ -43,6 +43,10 @@ public class RemotelyProvisionedComponentDevice { private static final byte BOOT_PATCH_LEVEL_ID = 0x02; private static final byte VENDOR_PATCH_LEVEL_ID = 0x03; public static final short MAX_COSE_BUF_SIZE = (short) 1024; + + //RKP mac key size + private static final short RKP_MAC_KEY_SIZE = 32; + // Device Info labels public static byte[] BRAND; public static byte[] MANUFACTURER; @@ -119,13 +123,13 @@ public class RemotelyProvisionedComponentDevice { private KMSEProvider seProvider; private Object[] operation; private short[] dataIndex; - private Object[] authorizedEekRoots; + private static Object[] authorizedEekRoots; private KMKeymintDevice KMAppletInst; private KMDataStore storeDataInst; private KMRkpDataStore rkpStoreDataInst; private KMBootDataStore bootParamsProv; private KMCose kmCoseInst; - private short[] deviceIds; + public short[] rkpTmpVariables; public RemotelyProvisionedComponentDevice(KMKeymintDevice KMApplet, KMEncoder encoder, KMDecoder decoder, @@ -141,12 +145,16 @@ public RemotelyProvisionedComponentDevice(KMKeymintDevice KMApplet, KMEncoder en storeDataInst = storeData; rkpStoreDataInst = rkpStore; bootParamsProv = bootParamsProvider; - deviceIds = JCSystem.makeTransientShortArray((short) 30, JCSystem.CLEAR_ON_RESET); + rkpTmpVariables = JCSystem.makeTransientShortArray((short) 32, JCSystem.CLEAR_ON_RESET); data = JCSystem.makeTransientByteArray(DATA_SIZE, JCSystem.CLEAR_ON_RESET); operation = JCSystem.makeTransientObjectArray((short) 1, JCSystem.CLEAR_ON_RESET); dataIndex = JCSystem.makeTransientShortArray((short) 1, JCSystem.CLEAR_ON_RESET); operation[0] = null; - createAuthorizedEEKRoot(); + // Initialize RKP mac key + short offset = repository.alloc((short) RKP_MAC_KEY_SIZE); + byte[] buffer = repository.getHeap(); + seProvider.getTrueRandomNumber(buffer, offset, RKP_MAC_KEY_SIZE); + rkpStoreDataInst.storeData(KMDataStoreConstants.RKP_MAC_KEY, buffer, offset, RKP_MAC_KEY_SIZE); kmCoseInst = KMCose.getInstance(); } @@ -195,30 +203,24 @@ public static void initStatics() { 0x78}; ATTEST_ID_LOCKED = new byte[]{0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64}; ATTEST_ID_OPEN = new byte[]{0x6f, 0x70, 0x65, 0x6e}; - } - - private void createAuthorizedEEKRoot() { - if (authorizedEekRoots == null) { - authorizedEekRoots = - new Object[] - { - new byte[]{ - 0x04, - (byte) 0xf7, (byte) 0x14, (byte) 0x8a, (byte) 0xdb, (byte) 0x97, (byte) 0xf4, - (byte) 0xcc, (byte) 0x53, (byte) 0xef, (byte) 0xd2, (byte) 0x64, (byte) 0x11, - (byte) 0xc4, (byte) 0xe3, (byte) 0x75, (byte) 0x1f, (byte) 0x66, (byte) 0x1f, - (byte) 0xa4, (byte) 0x71, (byte) 0x0c, (byte) 0x6c, (byte) 0xcf, (byte) 0xfa, - (byte) 0x09, (byte) 0x46, (byte) 0x80, (byte) 0x74, (byte) 0x87, (byte) 0x54, - (byte) 0xf2, (byte) 0xad, - (byte) 0x5e, (byte) 0x7f, (byte) 0x5b, (byte) 0xf6, (byte) 0xec, (byte) 0xe4, - (byte) 0xf6, (byte) 0x19, (byte) 0xcc, (byte) 0xff, (byte) 0x13, (byte) 0x37, - (byte) 0xfd, (byte) 0x0f, (byte) 0xa1, (byte) 0xc8, (byte) 0x93, (byte) 0xdb, - (byte) 0x18, (byte) 0x06, (byte) 0x76, (byte) 0xc4, (byte) 0x5d, (byte) 0xe6, - (byte) 0xd7, (byte) 0x6a, (byte) 0x77, (byte) 0x86, (byte) 0xc3, (byte) 0x2d, - (byte) 0xaf, (byte) 0x8f - }, - }; - } + authorizedEekRoots = new Object[] + { + new byte[]{ + 0x04, + (byte) 0xf7, (byte) 0x14, (byte) 0x8a, (byte) 0xdb, (byte) 0x97, (byte) 0xf4, + (byte) 0xcc, (byte) 0x53, (byte) 0xef, (byte) 0xd2, (byte) 0x64, (byte) 0x11, + (byte) 0xc4, (byte) 0xe3, (byte) 0x75, (byte) 0x1f, (byte) 0x66, (byte) 0x1f, + (byte) 0xa4, (byte) 0x71, (byte) 0x0c, (byte) 0x6c, (byte) 0xcf, (byte) 0xfa, + (byte) 0x09, (byte) 0x46, (byte) 0x80, (byte) 0x74, (byte) 0x87, (byte) 0x54, + (byte) 0xf2, (byte) 0xad, + (byte) 0x5e, (byte) 0x7f, (byte) 0x5b, (byte) 0xf6, (byte) 0xec, (byte) 0xe4, + (byte) 0xf6, (byte) 0x19, (byte) 0xcc, (byte) 0xff, (byte) 0x13, (byte) 0x37, + (byte) 0xfd, (byte) 0x0f, (byte) 0xa1, (byte) 0xc8, (byte) 0x93, (byte) 0xdb, + (byte) 0x18, (byte) 0x06, (byte) 0x76, (byte) 0xc4, (byte) 0x5d, (byte) 0xe6, + (byte) 0xd7, (byte) 0x6a, (byte) 0x77, (byte) 0x86, (byte) 0xc3, (byte) 0x2d, + (byte) 0xaf, (byte) 0x8f + }, + }; } private void initializeDataTable() { @@ -291,13 +293,13 @@ public void processGenerateRkpKey(APDU apdu) { boolean testMode = (KMSimpleValue.TRUE == KMSimpleValue.getValue(KMArray.get(arr, (short) 0))); KMAppletInst.generateRkpKey(scratchPad, getEcAttestKeyParameters()); - short pubKey = KMKeymasterDevice.getPubKey(); + short pubKey = KMKeymintDevice.getPubKey(); short coseMac0 = constructCoseMacForRkpKey(testMode, scratchPad, pubKey); // Encode the COSE_MAC0 object arr = KMArray.instance((short) 3); KMArray.add(arr, (short) 0, KMInteger.uint_16(KMError.OK)); KMArray.add(arr, (short) 1, coseMac0); - KMArray.add(arr, (short) 2, KMKeymasterDevice.getPivateKey()); + KMArray.add(arr, (short) 2, KMKeymintDevice.getPivateKey()); KMAppletInst.sendOutgoing(apdu, arr); } @@ -466,9 +468,9 @@ public void processFinishSendData(APDU apdu) throws Exception { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } // PubKeysToSignMac - byte[] empty = {}; + short empty = repository.alloc((short)0) ; short len = - ((KMOperation) operation[0]).sign(empty, (short) 0, + ((KMOperation) operation[0]).sign(repository.getHeap(), empty, (short) 0, scratchPad, (short) 0); // release operation releaseOperation(); @@ -591,9 +593,9 @@ private boolean isAdditionalCertificateChainPresent() { private short processFinalData(byte[] scratchPad) { // Call finish on AES GCM Cipher - byte[] empty = {}; + short empty = repository.alloc((short)0); short len = - ((KMOperation) operation[0]).finish(empty, (short) 0, (short) 0, scratchPad, (short) 0); + ((KMOperation) operation[0]).finish(repository.getHeap(), (short) empty, (short) 0, scratchPad, (short) 0); return len; } @@ -610,35 +612,6 @@ private void updateOutputProcessingState(byte state) { data[dataEntryIndex] = state; } - - private short getHmacKey(boolean testMode, byte[] scratchPad) { - short macKey = KMByteBlob.instance(MAC_KEY_SIZE); - Util.arrayFillNonAtomic(KMByteBlob.getBuffer(macKey), - KMByteBlob.getStartOff(macKey), MAC_KEY_SIZE, (byte) 0); - if (!testMode) { - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) (2 * MAC_KEY_SIZE), (byte) 0); - short len = - seProvider.hkdf( - scratchPad, //ikm - (short) 0, // ikm offset - MAC_KEY_SIZE, // ikm size - scratchPad, // salt - MAC_KEY_SIZE, // salt offset - MAC_KEY_SIZE, // salt length - KMCose.MAC_DERIVE_KEY_CTX, - (short) 0, - (short) KMCose.MAC_DERIVE_KEY_CTX.length, - KMByteBlob.getBuffer(macKey), - KMByteBlob.getStartOff(macKey), - MAC_KEY_SIZE - ); - if (len != MAC_KEY_SIZE) { - KMException.throwIt(KMError.INVALID_MAC_LENGTH); - } - } - return macKey; - } - /** * Validates the CoseMac message and extracts the CoseKey from it. * @@ -652,15 +625,13 @@ private short validateAndExtractPublicKey(short coseMacPtr, byte[] scratchPad) { short coseHeadersExp = KMCoseHeaders.exp(); // Exp for coseky short coseKeyExp = KMCoseKey.exp(); - // Get the mackey. - short macKey = getHmacKey(testMode, scratchPad); // validate protected Headers short ptr = KMArray.get(coseMacPtr, KMCose.COSE_MAC0_PROTECTED_PARAMS_OFFSET); ptr = decoder.decode(coseHeadersExp, KMByteBlob.getBuffer(ptr), KMByteBlob.getStartOff(ptr), KMByteBlob.length(ptr)); - if (!KMCoseHeaders.cast(ptr).isDataValid(KMCose.COSE_ALG_HMAC_256, KMType.INVALID_VALUE)) { + if (!KMCoseHeaders.cast(ptr).isDataValid(rkpTmpVariables, KMCose.COSE_ALG_HMAC_256, KMType.INVALID_VALUE)) { KMException.throwIt(KMError.STATUS_FAILED); } @@ -669,7 +640,7 @@ private short validateAndExtractPublicKey(short coseMacPtr, byte[] scratchPad) { ptr = decoder.decode(coseKeyExp, KMByteBlob.getBuffer(ptr), KMByteBlob.getStartOff(ptr), KMByteBlob.length(ptr)); - if (!KMCoseKey.cast(ptr).isDataValid(KMCose.COSE_KEY_TYPE_EC2, KMType.INVALID_VALUE, + if (!KMCoseKey.cast(ptr).isDataValid(rkpTmpVariables, KMCose.COSE_KEY_TYPE_EC2, KMType.INVALID_VALUE, KMCose.COSE_ALG_ES256, KMType.INVALID_VALUE, KMCose.COSE_ECCURVE_256)) { KMException.throwIt(KMError.STATUS_FAILED); } @@ -690,9 +661,7 @@ private short validateAndExtractPublicKey(short coseMacPtr, byte[] scratchPad) { short encodedLen = KMAppletInst.encodeToApduBuffer(macStructure, scratchPad, (short) 0, MAX_COSE_BUF_SIZE); - short hmacLen = seProvider.hmacSign(KMByteBlob.getBuffer(macKey), - KMByteBlob.getStartOff(macKey), - (short) 32, scratchPad, (short) 0, encodedLen, scratchPad, encodedLen); + short hmacLen = rkpHmacSign(testMode, scratchPad, (short) 0, encodedLen, scratchPad, encodedLen); if (hmacLen != KMByteBlob.length(KMArray.get(coseMacPtr, KMCose.COSE_MAC0_TAG_OFFSET))) { KMException.throwIt(KMError.STATUS_INVALID_MAC); @@ -707,6 +676,19 @@ private short validateAndExtractPublicKey(short coseMacPtr, byte[] scratchPad) { return ptr; } + private short rkpHmacSign(boolean testMode, byte[] data, short dataStart, short dataLength, byte[] signature, + short signatureStart) { + short result; + if(testMode) { + short macKey = KMByteBlob.instance(MAC_KEY_SIZE); + Util.arrayFillNonAtomic(KMByteBlob.getBuffer(macKey), + KMByteBlob.getStartOff(macKey), MAC_KEY_SIZE, (byte) 0); + result = seProvider.hmacSign(KMByteBlob.getBuffer(macKey), KMByteBlob.getStartOff(macKey), MAC_KEY_SIZE, data, dataStart, dataLength, signature, signatureStart); + } else { + result = seProvider.hmacSign(rkpStoreDataInst.getRkpMacacKey(), data, dataStart, dataLength, signature, signatureStart); + } + return result; + } /** * This function validates the EEK Chain and extracts the leaf public key, which is used to @@ -769,7 +751,7 @@ private void constructPartialPubKeysToSignMac(byte[] scratchPad, short arrayLeng short encodedCoseKeysLen) { short ptr; short len; - short headerPtr = kmCoseInst.constructHeaders( + short headerPtr = kmCoseInst.constructHeaders(rkpTmpVariables, KMInteger.uint_8(KMCose.COSE_ALG_HMAC_256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, @@ -825,7 +807,7 @@ private short createSignedMac(KMDeviceUniqueKey deviceUniqueKey, byte[] scratchP aad = KMByteBlob.instance(scratchPad, (short) 0, aad); /* construct protected header */ - short protectedHeaders = kmCoseInst.constructHeaders( + short protectedHeaders = kmCoseInst.constructHeaders(rkpTmpVariables, KMNInteger.uint_8(KMCose.COSE_ALG_ES256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, @@ -865,7 +847,8 @@ private short createSignedMac(KMDeviceUniqueKey deviceUniqueKey, byte[] scratchP private KMDeviceUniqueKey createDeviceUniqueKey(boolean testMode, byte[] scratchPad) { KMDeviceUniqueKey deviceUniqueKey; - short[] lengths = {0, 0}; + rkpTmpVariables[0] = 0; + rkpTmpVariables[1] = 0; if (testMode) { seProvider.createAsymmetricKey( KMType.EC, @@ -875,9 +858,9 @@ private KMDeviceUniqueKey createDeviceUniqueKey(boolean testMode, byte[] scratch scratchPad, (short) 128, (short) 128, - lengths); - rkpStoreDataInst.createDeviceUniqueKey(true, scratchPad, (short) 128, lengths[1], - scratchPad, (short) 0, lengths[0]); + rkpTmpVariables); + rkpStoreDataInst.createDeviceUniqueKey(true, scratchPad, (short) 128, rkpTmpVariables[1], + scratchPad, (short) 0, rkpTmpVariables[0]); deviceUniqueKey = rkpStoreDataInst.getDeviceUniqueKey(true); } else { @@ -900,36 +883,40 @@ private KMDeviceUniqueKey createDeviceUniqueKey(boolean testMode, byte[] scratch */ private short createDeviceInfo(byte[] scratchpad) { // Device Info Key Value pairs. - for (short i = 0; i < 30; i++) { - deviceIds[i] = KMType.INVALID_VALUE; + for (short i = 0; i < 32; i++) { + rkpTmpVariables[i] = KMType.INVALID_VALUE; } - short[] out = {0/* index */, 0 /* length */}; - updateItem(deviceIds, out, BRAND, getAttestationId(KMType.ATTESTATION_ID_BRAND, scratchpad)); - updateItem(deviceIds, out, MANUFACTURER, + short dataOffset = 2; + rkpTmpVariables[0] = dataOffset; + rkpTmpVariables[1] = 0; + short metaOffset = 0; + // first 2 shorts in the rkpTmpVariables will be used for lenth and index + updateItem(rkpTmpVariables, metaOffset, BRAND, getAttestationId(KMType.ATTESTATION_ID_BRAND, scratchpad)); + updateItem(rkpTmpVariables, metaOffset, MANUFACTURER, getAttestationId(KMType.ATTESTATION_ID_MANUFACTURER, scratchpad)); - updateItem(deviceIds, out, PRODUCT, + updateItem(rkpTmpVariables, metaOffset, PRODUCT, getAttestationId(KMType.ATTESTATION_ID_PRODUCT, scratchpad)); - updateItem(deviceIds, out, MODEL, getAttestationId(KMType.ATTESTATION_ID_MODEL, scratchpad)); - updateItem(deviceIds, out, VB_STATE, getVbState()); - updateItem(deviceIds, out, BOOTLOADER_STATE, getBootloaderState()); - updateItem(deviceIds, out, VB_META_DIGEST, getVerifiedBootHash(scratchpad)); - updateItem(deviceIds, out, OS_VERSION, getBootParams(OS_VERSION_ID, scratchpad)); - updateItem(deviceIds, out, SYSTEM_PATCH_LEVEL, + updateItem(rkpTmpVariables, metaOffset, MODEL, getAttestationId(KMType.ATTESTATION_ID_MODEL, scratchpad)); + updateItem(rkpTmpVariables, metaOffset, VB_STATE, getVbState()); + updateItem(rkpTmpVariables, metaOffset, BOOTLOADER_STATE, getBootloaderState()); + updateItem(rkpTmpVariables, metaOffset, VB_META_DIGEST, getVerifiedBootHash(scratchpad)); + updateItem(rkpTmpVariables, metaOffset, OS_VERSION, getBootParams(OS_VERSION_ID, scratchpad)); + updateItem(rkpTmpVariables, metaOffset, SYSTEM_PATCH_LEVEL, getBootParams(SYSTEM_PATCH_LEVEL_ID, scratchpad)); - updateItem(deviceIds, out, BOOT_PATCH_LEVEL, getBootParams(BOOT_PATCH_LEVEL_ID, scratchpad)); - updateItem(deviceIds, out, VENDOR_PATCH_LEVEL, + updateItem(rkpTmpVariables, metaOffset, BOOT_PATCH_LEVEL, getBootParams(BOOT_PATCH_LEVEL_ID, scratchpad)); + updateItem(rkpTmpVariables, metaOffset, VENDOR_PATCH_LEVEL, getBootParams(VENDOR_PATCH_LEVEL_ID, scratchpad)); - updateItem(deviceIds, out, DEVICE_INFO_VERSION, KMInteger.uint_8(DI_SCHEMA_VERSION)); - updateItem(deviceIds, out, SECURITY_LEVEL, + updateItem(rkpTmpVariables, metaOffset, DEVICE_INFO_VERSION, KMInteger.uint_8(DI_SCHEMA_VERSION)); + updateItem(rkpTmpVariables, metaOffset, SECURITY_LEVEL, KMTextString.instance(DI_SECURITY_LEVEL, (short) 0, (short) DI_SECURITY_LEVEL.length)); //TODO Add attest_id_state // Create device info map. - short map = KMMap.instance(out[1]); + short map = KMMap.instance(rkpTmpVariables[1]); short mapIndex = 0; - short index = 0; - while (index < (short) deviceIds.length) { - if (deviceIds[index] != KMType.INVALID_VALUE) { - KMMap.add(map, mapIndex++, deviceIds[index], deviceIds[(short) (index + 1)]); + short index = 2; + while (index < (short) 32) { + if (rkpTmpVariables[index] != KMType.INVALID_VALUE) { + KMMap.add(map, mapIndex++, rkpTmpVariables[index], rkpTmpVariables[(short) (index + 1)]); } index += 2; } @@ -948,12 +935,12 @@ private short createDeviceInfo(byte[] scratchpad) { * @param item Key info to be updated. * @param value value to be updated. */ - private void updateItem(short[] deviceIds, short[] meta, byte[] item, short value) { + private void updateItem(short[] deviceIds, short metaOffset, byte[] item, short value) { if (KMType.INVALID_VALUE != value) { - deviceIds[meta[0]++] = + deviceIds[deviceIds[metaOffset]++] = KMTextString.instance(item, (short) 0, (short) item.length); - deviceIds[meta[0]++] = value; - meta[1]++; + deviceIds[deviceIds[metaOffset]++] = value; + deviceIds[(short)(metaOffset+1)]++; } } @@ -1122,7 +1109,8 @@ private short ecdhHkdfDeriveKey(byte[] privKeyA, short privKeyAOff, short privKe // data table for later usage. private short generateEphemeralEcKey(byte[] scratchPad) { // Generate ephemeral ec key. - short[] lengths = {0/* Private key Length*/, 0 /* Public key length*/}; + rkpTmpVariables[0] = 0; + rkpTmpVariables[1] = 0; seProvider.createAsymmetricKey( KMType.EC, scratchPad, @@ -1131,18 +1119,18 @@ private short generateEphemeralEcKey(byte[] scratchPad) { scratchPad, (short) 128, (short) 128, - lengths); + rkpTmpVariables); // Copy the ephemeral private key from scratch pad - short ptr = KMByteBlob.instance(lengths[0]); + short ptr = KMByteBlob.instance(rkpTmpVariables[0]); Util.arrayCopyNonAtomic( scratchPad, (short) 0, KMByteBlob.getBuffer(ptr), KMByteBlob.getStartOff(ptr), - lengths[0]); + rkpTmpVariables[0]); //Store ephemeral public key in data table for later usage. - short dataEntryIndex = createEntry(EPHEMERAL_PUB_KEY, lengths[1]); - Util.arrayCopyNonAtomic(scratchPad, (short) 128, data, dataEntryIndex, lengths[1]); + short dataEntryIndex = createEntry(EPHEMERAL_PUB_KEY, rkpTmpVariables[1]); + Util.arrayCopyNonAtomic(scratchPad, (short) 128, data, dataEntryIndex, rkpTmpVariables[1]); return ptr; } @@ -1210,7 +1198,7 @@ private void initAesGcmOperation(byte[] scratchPad, short nonce) { } private short processRecipientStructure(byte[] scratchPad) { - short protectedHeaderRecipient = kmCoseInst.constructHeaders( + short protectedHeaderRecipient = kmCoseInst.constructHeaders(rkpTmpVariables, KMNInteger.uint_8(KMCose.COSE_ALG_ECDH_ES_HKDF_256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, @@ -1225,7 +1213,7 @@ private short processRecipientStructure(byte[] scratchPad) { short pubKeyIndex = getEntry(EPHEMERAL_PUB_KEY); // prepare cosekey short coseKey = - kmCoseInst.constructCoseKey( + kmCoseInst.constructCoseKey(rkpTmpVariables, KMInteger.uint_8(KMCose.COSE_KEY_TYPE_EC2), KMType.INVALID_VALUE, KMNInteger.uint_8(KMCose.COSE_ALG_ES256), @@ -1240,7 +1228,7 @@ private short processRecipientStructure(byte[] scratchPad) { short keyIdentifierPtr = KMByteBlob .instance(data, getEntry(EEK_KEY_ID), getEntryLength(EEK_KEY_ID)); short unprotectedHeaderRecipient = - kmCoseInst.constructHeaders(KMType.INVALID_VALUE, keyIdentifierPtr, KMType.INVALID_VALUE, + kmCoseInst.constructHeaders(rkpTmpVariables, KMType.INVALID_VALUE, keyIdentifierPtr, KMType.INVALID_VALUE, coseKey); // Construct recipients structure. @@ -1315,7 +1303,7 @@ private short processBcc(byte[] scratchPad) { // AAD is the CoseEncrypt structure private void processAesGcmUpdateAad(byte[] scratchPad) { - short protectedHeader = kmCoseInst.constructHeaders( + short protectedHeader = kmCoseInst.constructHeaders(rkpTmpVariables, KMInteger.uint_8(KMCose.COSE_ALG_AES_GCM_256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, @@ -1361,7 +1349,7 @@ private short processSignedMac(byte[] scratchPad, short pubKeysToSignMac, short private short getCoseEncryptProtectedHeader(byte[] scratchPad) { // CoseEncrypt protected headers. - short protectedHeader = kmCoseInst.constructHeaders( + short protectedHeader = kmCoseInst.constructHeaders(rkpTmpVariables, KMInteger.uint_8(KMCose.COSE_ALG_AES_GCM_256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, @@ -1375,13 +1363,13 @@ private short getCoseEncryptProtectedHeader(byte[] scratchPad) { private short getCoseEncryptUnprotectedHeader(byte[] scratchPad, short nonce) { /* CoseEncrypt unprotected headers */ return kmCoseInst - .constructHeaders(KMType.INVALID_VALUE, KMType.INVALID_VALUE, nonce, KMType.INVALID_VALUE); + .constructHeaders(rkpTmpVariables, KMType.INVALID_VALUE, KMType.INVALID_VALUE, nonce, KMType.INVALID_VALUE); } private short constructCoseMacForRkpKey(boolean testMode, byte[] scratchPad, short pubKey) { // prepare cosekey short coseKey = - kmCoseInst.constructCoseKey( + kmCoseInst.constructCoseKey(rkpTmpVariables, KMInteger.uint_8(KMCose.COSE_KEY_TYPE_EC2), KMType.INVALID_VALUE, KMNInteger.uint_8(KMCose.COSE_ALG_ES256), @@ -1396,10 +1384,8 @@ private short constructCoseMacForRkpKey(boolean testMode, byte[] scratchPad, sho short len = KMAppletInst .encodeToApduBuffer(coseKey, scratchPad, (short) 0, MAX_COSE_BUF_SIZE); short payload = KMByteBlob.instance(scratchPad, (short) 0, len); - // Get the mackey. - short macKey = getHmacKey(testMode, scratchPad); // Prepare protected header, which is required to construct the COSE_MAC0 - short headerPtr = kmCoseInst.constructHeaders( + short headerPtr = kmCoseInst.constructHeaders(rkpTmpVariables, KMInteger.uint_8(KMCose.COSE_ALG_HMAC_256), KMType.INVALID_VALUE, KMType.INVALID_VALUE, @@ -1416,9 +1402,7 @@ private short constructCoseMacForRkpKey(boolean testMode, byte[] scratchPad, sho len = KMAppletInst.encodeToApduBuffer(macStructure, scratchPad, (short) 0, MAX_COSE_BUF_SIZE); // HMAC Sign. - short hmacLen = seProvider - .hmacSign(KMByteBlob.getBuffer(macKey), KMByteBlob.getStartOff(macKey), - (short) 32, scratchPad, (short) 0, len, scratchPad, len); + short hmacLen = rkpHmacSign(testMode, scratchPad, (short) 0, len, scratchPad, len); // Create COSE_MAC0 object short coseMac0 = kmCoseInst From c7621824540432b824691d04ef9617c19f51ac76 Mon Sep 17 00:00:00 2001 From: "avinash.hedage" Date: Tue, 22 Feb 2022 05:01:41 +0000 Subject: [PATCH 2/3] temparal counter update, date update in ASN.1 time encoding and optimised cose key and header creation --- .../kmdevice/KMAttestationCertImpl.java | 4 +- .../com/android/javacard/kmdevice/KMCose.java | 86 ++++++++----------- .../javacard/kmdevice/KMKeymasterDevice.java | 3 +- .../android/javacard/kmdevice/KMUtils.java | 17 ++-- 4 files changed, 50 insertions(+), 60 deletions(-) diff --git a/Applet/src/com/android/javacard/kmdevice/KMAttestationCertImpl.java b/Applet/src/com/android/javacard/kmdevice/KMAttestationCertImpl.java index e490b6bd..fafc3644 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMAttestationCertImpl.java +++ b/Applet/src/com/android/javacard/kmdevice/KMAttestationCertImpl.java @@ -277,9 +277,9 @@ public KMAttestationCert notAfter(short usageExpiryTimeObj, boolean derEncoded, byte[] scratchPad) { if (!derEncoded) { if (usageExpiryTimeObj != KMType.INVALID_VALUE) { - // compare if the expiry time is greater then 2051 then use generalized + // compare if the expiry time is greater then 2050 then use generalized // time format else use utc time format. - short tmpVar = KMInteger.uint_64(KMUtils.firstJan2051, (short) 0); + short tmpVar = KMInteger.uint_64(KMUtils.firstJan2050, (short) 0); if (KMInteger.compare(usageExpiryTimeObj, tmpVar) >= 0) { usageExpiryTimeObj = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad, false); diff --git a/Applet/src/com/android/javacard/kmdevice/KMCose.java b/Applet/src/com/android/javacard/kmdevice/KMCose.java index a568a1c1..f8746d54 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMCose.java +++ b/Applet/src/com/android/javacard/kmdevice/KMCose.java @@ -95,6 +95,8 @@ public class KMCose { public static byte[] MAC_CONTEXT; // MAC0 public static byte[] SIGNATURE1_CONTEXT; // Signature1 public static byte[] ENCRYPT_CONTEXT; // Encrypt + public static short[] coseKeyConst; + public static short[] coseHeaderConst; //Empty strings public static byte[] EMPTY_MAC_KEY; // "Empty MAC key" @@ -147,7 +149,9 @@ public static void initStatics() { {0x4B, 0x65, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x4D, 0x41, 0x43, 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x20, 0x6B, 0x65, 0x79, 0x73}; // "Key to MAC public keys" - + coseKeyConst = new short[]{KMCose.COSE_KEY_KEY_TYPE, KMCose.COSE_KEY_KEY_ID, KMCose.COSE_KEY_ALGORITHM, KMCose.COSE_KEY_KEY_OPS, + KMCose.COSE_KEY_CURVE, KMCose.COSE_KEY_PUBKEY_X, KMCose.COSE_KEY_PUBKEY_Y, KMCose.COSE_KEY_PRIV_KEY}; + coseHeaderConst = new short[]{KMCose.COSE_LABEL_ALGORITHM, KMCose.COSE_LABEL_KEYID, KMCose.COSE_LABEL_IV, KMCose.COSE_LABEL_COSE_KEY}; } public static KMCose getInstance() { @@ -282,17 +286,17 @@ public short constructCoseSign1(short protectedHeader, short unProtectedHeader, * @param includeTestMode flag which indicates if TEST_COSE_KEY should be included or not. * @return instance of KMArray. */ - private short handleCosePairTags(short[] tags, short tagLen, boolean includeTestMode) { + private short handleCosePairTags(short[] tag, short[] keyValues, short valueIndex, boolean includeTestMode) { short index = 0; - // var is used to calculate the length of the array. short var = 0; + short tagLen = (short) tag.length; + // var is used to calculate the length of the array. while (index < tagLen) { - if (tags[(short) (index + 1)] != KMType.INVALID_VALUE) { - tags[(short) (index + 2)] = - buildCosePairTag((byte) tags[index], tags[(short) (index + 1)]); - var++; + if (keyValues[index] != KMType.INVALID_VALUE) { + keyValues[(short)(index + valueIndex)] = buildCosePairTag((byte) tag[index], keyValues[index]); + var++; } - index += 3; + index++; } var += includeTestMode ? 1 : 0; short arrPtr = KMArray.instance(var); @@ -300,10 +304,10 @@ private short handleCosePairTags(short[] tags, short tagLen, boolean includeTest // var is used to index the array. var = 0; while (index < tagLen) { - if (tags[(short) (index + 2)] != KMType.INVALID_VALUE) { - KMArray.add(arrPtr, var++, tags[(short) (index + 2)]); + if (keyValues[(short)(index + valueIndex)] != KMType.INVALID_VALUE) { + KMArray.add(arrPtr, var++, keyValues[(short)(index + valueIndex)]); } - index += 3; + index++; } return arrPtr; } @@ -341,19 +345,14 @@ public short constructCoseCertPayload(short issuer, short subject, short subPubl */ public short constructHeaders(short []buff, short alg, short keyId, short iv, short ephemeralKey) { - buff[0]= KMCose.COSE_LABEL_ALGORITHM; - buff[1]= alg; - buff[2]= KMType.INVALID_VALUE; - buff[3]= KMCose.COSE_LABEL_KEYID; - buff[4]= keyId; - buff[5]= KMType.INVALID_VALUE; - buff[6]= KMCose.COSE_LABEL_IV; - buff[7]= iv; - buff[8]= KMType.INVALID_VALUE; - buff[9]= KMCose.COSE_LABEL_COSE_KEY; - buff[10]= ephemeralKey; - buff[11]= KMType.INVALID_VALUE; - short ptr = handleCosePairTags(buff, (short)12, false); + buff[0]= alg; + buff[1]= keyId; + buff[2]= iv; + buff[3]= ephemeralKey; + for(short i = 4; i < 8; i++) { + buff[i] = KMType.INVALID_VALUE; + } + short ptr = handleCosePairTags(coseHeaderConst, buff, (short)4, false); ptr = KMCoseHeaders.instance(ptr); KMCoseHeaders.cast(ptr).canonicalize(); return ptr; @@ -523,32 +522,19 @@ public short constructCoseKey(short []buff, short keyType, short keyId, short ke */ public short constructCoseKey(short []buff, short keyType, short keyId, short keyAlg, short keyOps, short curve, short pubX, short pubY, short priv, boolean includeTestKey) { - buff[0] = KMCose.COSE_KEY_KEY_TYPE; - buff[1] = keyType; - buff[2] = KMType.INVALID_VALUE; - buff[3] = KMCose.COSE_KEY_KEY_ID; - buff[4] = keyId; - buff[5] = KMType.INVALID_VALUE; - buff[6] = KMCose.COSE_KEY_ALGORITHM; - buff[7] = keyAlg; - buff[8] = KMType.INVALID_VALUE; - buff[9] = KMCose.COSE_KEY_KEY_OPS; - buff[10] = keyOps; - buff[11] = KMType.INVALID_VALUE; - buff[12] = KMCose.COSE_KEY_CURVE; - buff[13] = curve; - buff[14] = KMType.INVALID_VALUE; - buff[15] = KMCose.COSE_KEY_PUBKEY_X; - buff[16] = pubX; - buff[17] = KMType.INVALID_VALUE; - buff[18] = KMCose.COSE_KEY_PUBKEY_Y; - buff[19] = pubY; - buff[20] = KMType.INVALID_VALUE; - buff[21] = KMCose.COSE_KEY_PRIV_KEY; - buff[22] = priv; - buff[23] = KMType.INVALID_VALUE; - - short arrPtr = handleCosePairTags(buff, (short)24, includeTestKey); + short valueIndex = 8; + buff[0] = keyType; + buff[1] = keyId; + buff[2] = keyAlg; + buff[3] = keyOps; + buff[4] = curve; + buff[5] = pubX; + buff[6] = pubY; + buff[7] = priv; + for (short i = valueIndex; i < 16; i++) { + buff[i] = KMType.INVALID_VALUE; + } + short arrPtr = handleCosePairTags(coseKeyConst, buff, valueIndex, includeTestKey); if (includeTestKey) { short testKey = KMCosePairSimpleValueTag.instance(KMNInteger.uint_32(KMCose.COSE_TEST_KEY, (short) 0), diff --git a/Applet/src/com/android/javacard/kmdevice/KMKeymasterDevice.java b/Applet/src/com/android/javacard/kmdevice/KMKeymasterDevice.java index 1e5b43fd..e55ab0b2 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMKeymasterDevice.java +++ b/Applet/src/com/android/javacard/kmdevice/KMKeymasterDevice.java @@ -588,10 +588,11 @@ private void processEarlyBootEndedCmd(APDU apdu) { private short deviceLockedCmd(APDU apdu) { short cmd = KMArray.instance((short) 2); + short ptr = getKMVerificationTokenExp(); // passwordOnly KMArray.add(cmd, (short) 0, KMInteger.exp()); // verification token - KMArray.add(cmd, (short) 1, getKMVerificationTokenExp()); + KMArray.add(cmd, (short) 1, ptr); return receiveIncoming(apdu, cmd); } diff --git a/Applet/src/com/android/javacard/kmdevice/KMUtils.java b/Applet/src/com/android/javacard/kmdevice/KMUtils.java index 62677a35..e79e3dd5 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMUtils.java +++ b/Applet/src/com/android/javacard/kmdevice/KMUtils.java @@ -25,12 +25,13 @@ public class KMUtils { public static byte[] oneHourMsec; // 3600000 msec public static byte[] oneDayMsec; // 86400000 msec public static byte[] oneMonthMsec; // 2629746000 msec + public static byte[] thirtyDaysMsec; //2592000000 msec public static byte[] leapYearMsec; //31622400000; public static byte[] yearMsec; //31536000000 //Leap year(366) + 3 * 365 public static byte[] fourYrsMsec;//126230400000 public static byte[] firstJan2020; // 1577836800000 msec - public static byte[] firstJan2051; // 2556144000000 + public static byte[] firstJan2050; // 2524608000 // msec public static byte[] febMonthLeapMSec; //2505600000 public static byte[] febMonthMsec; //2419200000 @@ -53,6 +54,8 @@ public static void initStatics() { 0, 0, 0, 0, 0x05, 0x26, 0x5C, 0x00}; // 86400000 msec oneMonthMsec = new byte[]{ 0, 0, 0, 0, (byte) 0x9C, (byte) 0xBE, (byte) 0xBD, 0x50}; // 2629746000 msec + thirtyDaysMsec = new byte[]{ + 0, 0, 0, 0, (byte) 0x9A, (byte) 0x7E, (byte) 0xC8, 0}; // 2592000000 msec leapYearMsec = new byte[]{ 0, 0, 0, 0x07, (byte) 0x5C, (byte) 0xD7, (byte) 0x88, 0x00}; //31622400000; yearMsec = new byte[]{ @@ -62,8 +65,8 @@ public static void initStatics() { 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00};//126230400000 firstJan2020 = new byte[]{ 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte) 0xE8, 0x00}; // 1577836800000 msec - firstJan2051 = new byte[]{ - 0, 0, 0x02, 0x53, 0x26, (byte) 0x0E, (byte) 0x1C, 0x00}; // 2556144000000 + firstJan2050 = new byte[]{ + 0, 0, 0, 0, (byte) 0x96, 0x7A, (byte) 0x76, 0x00}; // 2524608000 // msec febMonthLeapMSec = new byte[]{ 0, 0, 0, 0, (byte) 0x95, 0x58, 0x6C, 0x00}; //2505600000 @@ -99,12 +102,12 @@ public static short convertToDate(short time, byte[] scratchPad, KMException.throwIt(KMError.INVALID_ARGUMENT); } if (utcFlag - && KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, + && KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2050, (short) 0, (short) 8) >= 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2051, (short) 0, + if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2050, (short) 0, (short) 8) < 0) { Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, (short) 8); @@ -113,7 +116,7 @@ public static short convertToDate(short time, byte[] scratchPad, (short) 8); } else { from2020 = false; - Util.arrayCopyNonAtomic(firstJan2051, (short) 0, scratchPad, (short) 8, + Util.arrayCopyNonAtomic(firstJan2050, (short) 0, scratchPad, (short) 8, (short) 8); subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, @@ -412,7 +415,7 @@ public static short countTemporalCount(byte[] bufTime, short timeOff, scratchPad, (short) (offset + 8 - timeLen), timeLen); - Util.arrayCopyNonAtomic(oneMonthMsec, (short) 0, scratchPad, (short) (offset + 8), + Util.arrayCopyNonAtomic(thirtyDaysMsec, (short) 0, scratchPad, (short) (offset + 8), (short) 8); return divide(scratchPad, (short) 0, (short) 8, (short) 16); } From 9ed09fd5f3a6475094202e5d4d48fafd3994a65d Mon Sep 17 00:00:00 2001 From: "avinash.hedage" Date: Fri, 25 Feb 2022 11:08:45 +0000 Subject: [PATCH 3/3] added attest id state in RKP device info, updated cose sign in provision tool --- .../javacard/kmapplet/KMAndroidSEApplet.java | 15 ++---------- .../seprovider/KMKeymasterProvision.java | 12 ++++++++++ .../android/javacard/kmdevice/KMUtils.java | 4 ++-- .../RemotelyProvisionedComponentDevice.java | 15 ++++++++++++ .../keymint/src/cppcose/cppcose.cpp | 23 ++++++++++++++++++- 5 files changed, 53 insertions(+), 16 deletions(-) diff --git a/Applet/AndroidSEApplet/src/com/android/javacard/kmapplet/KMAndroidSEApplet.java b/Applet/AndroidSEApplet/src/com/android/javacard/kmapplet/KMAndroidSEApplet.java index 0338b004..acfe554c 100644 --- a/Applet/AndroidSEApplet/src/com/android/javacard/kmapplet/KMAndroidSEApplet.java +++ b/Applet/AndroidSEApplet/src/com/android/javacard/kmapplet/KMAndroidSEApplet.java @@ -158,18 +158,7 @@ public static void install(byte[] bArray, short bOffset, byte bLength) { } new KMAndroidSEApplet(kmDevice).register(bArray, (short) (bOffset + 1), bArray[bOffset]); } - - private boolean isProvisionLocked() { - short offset = repositoryInst.alloc((short) 1); - short len = kmDataStore.getData(KMDataStoreConstants.PROVISIONED_LOCKED, - repositoryInst.getHeap(), offset); - if (len == 0) { - return false; - } - return ((byte[]) repositoryInst.getHeap())[offset] == 0x01; - } - - + @Override public void process(APDU apdu) { try { @@ -184,7 +173,7 @@ public void process(APDU apdu) { kmDeviceInst.powerReset(); } - if (isProvisionLocked()) { + if (seProvisionInst.isProvisionLocked()) { switch (apduIns) { case INS_SET_BOOT_PARAMS_CMD: processSetBootParamsCmd(apdu); diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMKeymasterProvision.java b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMKeymasterProvision.java index 77ada381..b2117fe4 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMKeymasterProvision.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/seprovider/KMKeymasterProvision.java @@ -253,6 +253,18 @@ public void processLockProvisioningCmd(APDU apdu) { kmDeviceInst.sendError(apdu, KMError.OK); } + public boolean isProvisionLocked() { + short offset = kmRepositroyInst.allocReclaimableMemory((short) 1); + short len = kmStoreDataInst.getData(KMDataStoreConstants.PROVISIONED_LOCKED, + kmRepositroyInst.getHeap(), offset); + if (len == 0) { + return false; + } + boolean res = ((byte[]) kmRepositroyInst.getHeap())[offset] == 0x01; + kmRepositroyInst.reclaimMemory((short)1); + return res; + } + public void processProvisionDeviceUniqueKey(APDU apdu) { kmDeviceInst.sendError(apdu, KMError.CMD_NOT_ALLOWED); } diff --git a/Applet/src/com/android/javacard/kmdevice/KMUtils.java b/Applet/src/com/android/javacard/kmdevice/KMUtils.java index e79e3dd5..6aff7867 100644 --- a/Applet/src/com/android/javacard/kmdevice/KMUtils.java +++ b/Applet/src/com/android/javacard/kmdevice/KMUtils.java @@ -31,7 +31,7 @@ public class KMUtils { //Leap year(366) + 3 * 365 public static byte[] fourYrsMsec;//126230400000 public static byte[] firstJan2020; // 1577836800000 msec - public static byte[] firstJan2050; // 2524608000 + public static byte[] firstJan2050; // 2524608000000 msec // msec public static byte[] febMonthLeapMSec; //2505600000 public static byte[] febMonthMsec; //2419200000 @@ -66,7 +66,7 @@ public static void initStatics() { firstJan2020 = new byte[]{ 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte) 0xE8, 0x00}; // 1577836800000 msec firstJan2050 = new byte[]{ - 0, 0, 0, 0, (byte) 0x96, 0x7A, (byte) 0x76, 0x00}; // 2524608000 + 0, 0, 0x02, 0x4b, (byte) 0xCE, 0x5C, (byte)0xF0, 0x00}; //2524608000000 // msec febMonthLeapMSec = new byte[]{ 0, 0, 0, 0, (byte) 0x95, 0x58, 0x6C, 0x00}; //2505600000 diff --git a/Applet/src/com/android/javacard/kmdevice/RemotelyProvisionedComponentDevice.java b/Applet/src/com/android/javacard/kmdevice/RemotelyProvisionedComponentDevice.java index d765f29f..a8e883f2 100644 --- a/Applet/src/com/android/javacard/kmdevice/RemotelyProvisionedComponentDevice.java +++ b/Applet/src/com/android/javacard/kmdevice/RemotelyProvisionedComponentDevice.java @@ -909,6 +909,9 @@ private short createDeviceInfo(byte[] scratchpad) { updateItem(rkpTmpVariables, metaOffset, DEVICE_INFO_VERSION, KMInteger.uint_8(DI_SCHEMA_VERSION)); updateItem(rkpTmpVariables, metaOffset, SECURITY_LEVEL, KMTextString.instance(DI_SECURITY_LEVEL, (short) 0, (short) DI_SECURITY_LEVEL.length)); + byte[] attestIdState = isKMProvisionLocked() ? ATTEST_ID_LOCKED : ATTEST_ID_OPEN; + updateItem(rkpTmpVariables, metaOffset, ATTEST_ID_STATE, + KMTextString.instance(attestIdState, (short) 0, (short) attestIdState.length)); //TODO Add attest_id_state // Create device info map. short map = KMMap.instance(rkpTmpVariables[1]); @@ -1506,5 +1509,17 @@ public short encodeES256CoseSignSignature(byte[] input, short offset, short len, } return length; } + + private boolean isKMProvisionLocked() { + short offset = repository.allocReclaimableMemory((short) 1); + short len = storeDataInst.getData(KMDataStoreConstants.PROVISIONED_LOCKED, + repository.getHeap(), offset); + if (len == 0) { + return false; + } + boolean res = ((byte[]) repository.getHeap())[offset] == 0x01; + repository.reclaimMemory((short)1); + return res; + } } diff --git a/ProvisioningTool/keymint/src/cppcose/cppcose.cpp b/ProvisioningTool/keymint/src/cppcose/cppcose.cpp index e0c5aaab..29bb2015 100644 --- a/ProvisioningTool/keymint/src/cppcose/cppcose.cpp +++ b/ProvisioningTool/keymint/src/cppcose/cppcose.cpp @@ -27,9 +27,30 @@ #include #include #include +#include namespace cppcose { +ErrMsgOr ecdsaDerSignatureToCose(const bytevec& ecdsaSignature) { + const unsigned char* p = ecdsaSignature.data(); + ECDSA_SIG *sig = d2i_ECDSA_SIG(nullptr, &p, ecdsaSignature.size()); + if (sig == nullptr) { + return "Error decoding DER signature"; + } + + bytevec ecdsaCoseSignature(64, 0); + if (BN_bn2binpad(ECDSA_SIG_get0_r(sig), ecdsaCoseSignature.data(), 32) != 32) { + ECDSA_SIG_free(sig); + return "Error encoding r"; + } + if (BN_bn2binpad(ECDSA_SIG_get0_s(sig), ecdsaCoseSignature.data() + 32, 32) != 32) { + ECDSA_SIG_free(sig); + return "Error encoding s"; + } + ECDSA_SIG_free(sig); + return ecdsaCoseSignature; +} + ErrMsgOr ECDSA_sign(const bytevec& key, bytevec& input) { EVP_PKEY_CTX* pkeyCtx = NULL; EVP_MD_CTX_Ptr digestCtx(EVP_MD_CTX_new()); @@ -132,7 +153,7 @@ ErrMsgOr createCoseSign1Signature(const bytevec& key, const bytevec& pr .encode(); auto signature = ECDSA_sign(key, signatureInput); if (!signature) return "Signing failed"; - return signature; + return ecdsaDerSignatureToCose(*signature); } ErrMsgOr constructCoseSign1(const bytevec& key, cppbor::Map protectedParams,