From a94b62628d259ec0a9cbf5b25880715bf2e78eb9 Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Fri, 22 Apr 2022 06:24:02 +0000 Subject: [PATCH 1/3] key pool implementation --- .../seprovider/KMAndroidSEProvider.java | 171 ++---------- .../javacard/seprovider/KMKeyObject.java | 19 ++ .../javacard/seprovider/KMOperation.java | 2 + .../javacard/seprovider/KMOperationImpl.java | 67 +++-- .../javacard/seprovider/KMPoolManager.java | 264 +++++++++++++++++- .../javacard/seprovider/KMSEProvider.java | 15 +- 6 files changed, 349 insertions(+), 189 deletions(-) create mode 100644 Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index ddaece5c..23e80b29 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java @@ -41,20 +41,6 @@ public class KMAndroidSEProvider implements KMSEProvider { - // static final variables - // -------------------------------------------------------------- - // P-256 Curve Parameters - static byte[] secp256r1_P; - static byte[] secp256r1_A; - - static byte[] secp256r1_B; - static byte[] secp256r1_S; - - // Uncompressed form - static byte[] secp256r1_UCG; - static byte[] secp256r1_N; - static final short secp256r1_H = 1; - // -------------------------------------------------------------- public static final short AES_GCM_TAG_LENGTH = 16; public static final short AES_GCM_NONCE_LENGTH = 12; public static final byte KEYSIZE_128_OFFSET = 0x00; @@ -102,7 +88,6 @@ public static KMAndroidSEProvider getInstance() { } public KMAndroidSEProvider() { - initStatics(); // Re-usable AES,DES and HMAC keys in persisted memory. aesKeys = new AESKey[2]; aesKeys[KEYSIZE_128_OFFSET] = (AESKey) KeyBuilder.buildKey( @@ -116,8 +101,8 @@ public KMAndroidSEProvider() { rsaKeyPair = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); keyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN, false); - initECKey(ecKeyPair); poolMgr = KMPoolManager.getInstance(); + poolMgr.initECKey(ecKeyPair); //RsaOAEP Decipher rsaOaepDecipher = new KMRsaOAEPEncoding(KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1); @@ -136,95 +121,10 @@ public KMAndroidSEProvider() { resetFlag[0] = (byte) POWER_RESET_FALSE; } - public static void initStatics() { - secp256r1_P = new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, - (byte) 0x00, - (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, - (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF}; - - secp256r1_A = new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, - (byte) 0x00, - (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, - (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, - (byte) 0xFF, (byte) 0xFC}; - - secp256r1_B = new byte[]{(byte) 0x5A, (byte) 0xC6, (byte) 0x35, (byte) 0xD8, (byte) 0xAA, - (byte) 0x3A, - (byte) 0x93, (byte) 0xE7, (byte) 0xB3, (byte) 0xEB, (byte) 0xBD, (byte) 0x55, (byte) 0x76, - (byte) 0x98, - (byte) 0x86, (byte) 0xBC, (byte) 0x65, (byte) 0x1D, (byte) 0x06, (byte) 0xB0, (byte) 0xCC, - (byte) 0x53, - (byte) 0xB0, (byte) 0xF6, (byte) 0x3B, (byte) 0xCE, (byte) 0x3C, (byte) 0x3E, (byte) 0x27, - (byte) 0xD2, - (byte) 0x60, (byte) 0x4B}; - - secp256r1_S = new byte[]{(byte) 0xC4, (byte) 0x9D, (byte) 0x36, (byte) 0x08, (byte) 0x86, - (byte) 0xE7, - (byte) 0x04, (byte) 0x93, (byte) 0x6A, (byte) 0x66, (byte) 0x78, (byte) 0xE1, (byte) 0x13, - (byte) 0x9D, - (byte) 0x26, (byte) 0xB7, (byte) 0x81, (byte) 0x9F, (byte) 0x7E, (byte) 0x90}; - - // Uncompressed form - secp256r1_UCG = new byte[]{(byte) 0x04, (byte) 0x6B, (byte) 0x17, (byte) 0xD1, (byte) 0xF2, - (byte) 0xE1, - (byte) 0x2C, (byte) 0x42, (byte) 0x47, (byte) 0xF8, (byte) 0xBC, (byte) 0xE6, (byte) 0xE5, - (byte) 0x63, - (byte) 0xA4, (byte) 0x40, (byte) 0xF2, (byte) 0x77, (byte) 0x03, (byte) 0x7D, (byte) 0x81, - (byte) 0x2D, - (byte) 0xEB, (byte) 0x33, (byte) 0xA0, (byte) 0xF4, (byte) 0xA1, (byte) 0x39, (byte) 0x45, - (byte) 0xD8, - (byte) 0x98, (byte) 0xC2, (byte) 0x96, (byte) 0x4F, (byte) 0xE3, (byte) 0x42, (byte) 0xE2, - (byte) 0xFE, - (byte) 0x1A, (byte) 0x7F, (byte) 0x9B, (byte) 0x8E, (byte) 0xE7, (byte) 0xEB, (byte) 0x4A, - (byte) 0x7C, - (byte) 0x0F, (byte) 0x9E, (byte) 0x16, (byte) 0x2B, (byte) 0xCE, (byte) 0x33, (byte) 0x57, - (byte) 0x6B, - (byte) 0x31, (byte) 0x5E, (byte) 0xCE, (byte) 0xCB, (byte) 0xB6, (byte) 0x40, (byte) 0x68, - (byte) 0x37, - (byte) 0xBF, (byte) 0x51, (byte) 0xF5}; - - secp256r1_N = new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, - (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, - (byte) 0xFF, (byte) 0xFF, (byte) 0xBC, (byte) 0xE6, (byte) 0xFA, (byte) 0xAD, (byte) 0xA7, - (byte) 0x17, - (byte) 0x9E, (byte) 0x84, (byte) 0xF3, (byte) 0xB9, (byte) 0xCA, (byte) 0xC2, (byte) 0xFC, - (byte) 0x63, - (byte) 0x25, (byte) 0x51}; - } - public void clean() { Util.arrayFillNonAtomic(tmpArray, (short) 0, (short) 256, (byte) 0); } - private void initECKey(KeyPair ecKeyPair) { - ECPrivateKey privKey = (ECPrivateKey) ecKeyPair.getPrivate(); - ECPublicKey pubkey = (ECPublicKey) ecKeyPair.getPublic(); - pubkey.setFieldFP(secp256r1_P, (short) 0, (short) secp256r1_P.length); - pubkey.setA(secp256r1_A, (short) 0, (short) secp256r1_A.length); - pubkey.setB(secp256r1_B, (short) 0, (short) secp256r1_B.length); - pubkey.setG(secp256r1_UCG, (short) 0, (short) secp256r1_UCG.length); - pubkey.setK(secp256r1_H); - pubkey.setR(secp256r1_N, (short) 0, (short) secp256r1_N.length); - - privKey.setFieldFP(secp256r1_P, (short) 0, (short) secp256r1_P.length); - privKey.setA(secp256r1_A, (short) 0, (short) secp256r1_A.length); - privKey.setB(secp256r1_B, (short) 0, (short) secp256r1_B.length); - privKey.setG(secp256r1_UCG, (short) 0, (short) secp256r1_UCG.length); - privKey.setK(secp256r1_H); - privKey.setR(secp256r1_N, (short) 0, (short) secp256r1_N.length); - } - public AESKey createAESKey(short keysize) { try { newRandomNumber(tmpArray, (short) 0, (short) (keysize / 8)); @@ -684,27 +584,25 @@ private byte mapCipherAlg(byte alg, byte padding, byte blockmode, byte digest) { public KMOperation createSymmetricCipher(short alg, short purpose, short macLength, short blockMode, short padding, byte[] secret, short secretStart, short secretLength, byte[] ivBuffer, short ivStart, short ivLength) { - Key key = null; + + short cipherAlg = mapCipherAlg((byte) alg, (byte) padding, (byte) blockMode, (byte) 0); + KMOperation operation = + poolMgr.getOperationImpl(purpose, cipherAlg, alg, padding, blockMode, macLength, secretLength, false); + + KMKeyObject keyObj = operation.getKeyObject(); + Key key = (Key)keyObj.getKeyObject(); switch (secretLength) { case 32: - key = aesKeys[KEYSIZE_256_OFFSET]; - ((AESKey) key).setKey(secret, secretStart); - break; - case 16: - key = aesKeys[KEYSIZE_128_OFFSET]; + case 16: ((AESKey) key).setKey(secret, secretStart); break; case 24: - key = triDesKey; ((DESKey) key).setKey(secret, secretStart); break; default: CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); break; - } - short cipherAlg = mapCipherAlg((byte) alg, (byte) padding, (byte) blockMode, (byte) 0); - KMOperation operation = - poolMgr.getOperationImpl(purpose, cipherAlg, alg, padding, blockMode, macLength, false); + } ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, ivBuffer, ivStart, ivLength); return operation; } @@ -716,8 +614,10 @@ public KMOperation createHmacSignerVerifier(short purpose, short digest, } KMOperation operation = poolMgr.getOperationImpl(purpose, Signature.ALG_HMAC_SHA_256, - KMType.HMAC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, false); - HMACKey key = createHMACKey(secret, secretStart, secretLength); + KMType.HMAC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, (short)0, false); + KMKeyObject keyObj = operation.getKeyObject(); + HMACKey key = (HMACKey)keyObj.getKeyObject(); + key.setKey(secret, secretStart, secretLength); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); return operation; } @@ -728,7 +628,7 @@ private KMOperation createHmacSignerVerifier(short purpose, short digest, HMACKe } KMOperation operation = poolMgr.getOperationImpl(purpose, Signature.ALG_HMAC_SHA_256, - KMType.HMAC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, isTrustedConf); + KMType.HMAC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, (short)0, isTrustedConf); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); return operation; @@ -769,8 +669,9 @@ public KMOperation createRsaSigner(short digest, short padding, byte[] secret, short modLength) { byte alg = mapSignature256Alg(KMType.RSA, (byte) padding, (byte) digest); KMOperation operation = poolMgr.getOperationImpl(KMType.SIGN, alg, KMType.RSA, padding, - KMType.INVALID_VALUE, KMType.INVALID_VALUE, false); - RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); + KMType.INVALID_VALUE, KMType.INVALID_VALUE, secretLength, false); + KMKeyObject keyObj = operation.getKeyObject(); + RSAPrivateKey key = (RSAPrivateKey)((KeyPair)(keyObj.getKeyObject())).getPrivate(); key.setExponent(secret, secretStart, secretLength); key.setModulus(modBuffer, modOff, modLength); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); @@ -782,8 +683,9 @@ public KMOperation createRsaDecipher(short padding, short mgfDigest, byte[] secr short modLength) { byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0, (byte) mgfDigest); KMOperation operation = poolMgr.getOperationImpl(KMType.DECRYPT, cipherAlg, KMType.RSA, padding, - KMType.INVALID_VALUE, KMType.INVALID_VALUE, false); - RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); + KMType.INVALID_VALUE, KMType.INVALID_VALUE, secretLength, false); + KMKeyObject keyObj = operation.getKeyObject(); + RSAPrivateKey key = (RSAPrivateKey) ((KeyPair)(keyObj.getKeyObject())).getPrivate(); key.setExponent(secret, secretStart, secretLength); key.setModulus(modBuffer, modOff, modLength); ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, null, (short) 0, (short) 0); @@ -793,22 +695,24 @@ public KMOperation createRsaDecipher(short padding, short mgfDigest, byte[] secr public KMOperation createEcSigner(short digest, byte[] secret, short secretStart, short secretLength) { byte alg = mapSignature256Alg(KMType.EC, (byte) 0, (byte) digest); - ECPrivateKey key = (ECPrivateKey) ecKeyPair.getPrivate(); - key.setS(secret, secretStart, secretLength); KMOperation operation = poolMgr - .getOperationImpl(KMType.SIGN, alg, KMType.EC, KMType.INVALID_VALUE, - KMType.INVALID_VALUE, KMType.INVALID_VALUE, false); + .getOperationImpl(KMType.SIGN, alg, KMType.EC, KMType.INVALID_VALUE, + KMType.INVALID_VALUE, KMType.INVALID_VALUE, secretLength, false); + KMKeyObject keyObj = operation.getKeyObject(); + ECPrivateKey key = (ECPrivateKey) ((KeyPair)(keyObj.getKeyObject())).getPrivate(); + key.setS(secret, secretStart, secretLength); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); return operation; } public KMOperation createKeyAgreement(byte[] secret, short secretStart, short secretLength) { - ECPrivateKey key = (ECPrivateKey) ecKeyPair.getPrivate(); - key.setS(secret, secretStart, secretLength); KMOperation operation = poolMgr .getOperationImpl(KMType.AGREE_KEY, KeyAgreement.ALG_EC_SVDP_DH_PLAIN, - KMType.EC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, false); + KMType.EC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, (short)0, false); + KMKeyObject keyObj = operation.getKeyObject(); + ECPrivateKey key = (ECPrivateKey) ((KeyPair)(keyObj.getKeyObject())).getPrivate(); + key.setS(secret, secretStart, secretLength); ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, null, (short) 0, (short) 0); return operation; } @@ -884,19 +788,6 @@ public KMMasterKey createMasterKey(KMMasterKey masterKey, short keySizeBits) { } } - @Override - public KMAttestationKey createAttestationKey(KMAttestationKey attestationKey, byte[] keyData, short offset, - short length) { - if (attestationKey == null) { - // Strongbox supports only P-256 curve for EC key. - KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); - initECKey(ecKeyPair); - attestationKey = new KMECPrivateKey(ecKeyPair); - } - ((KMECPrivateKey) attestationKey).setS(keyData, offset, length); - return (KMAttestationKey) attestationKey; - } - @Override public KMPreSharedKey createPreSharedKey(KMPreSharedKey preSharedKey, byte[] keyData, short offset, short length) { short lengthInBits = (short) (length * 8); @@ -1113,7 +1004,7 @@ public KMDeviceUniqueKeyPair createRkpDeviceUniqueKeyPair(KMDeviceUniqueKeyPair short privKeyOff, short privKeyLen) { if (key == null) { KeyPair ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); - initECKey(ecKeyPair); + poolMgr.initECKey(ecKeyPair); key = new KMECDeviceUniqueKey(ecKeyPair); } ((KMECDeviceUniqueKey) key).setS(privKey, privKeyOff, privKeyLen); diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java new file mode 100644 index 00000000..ad5d1e5f --- /dev/null +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java @@ -0,0 +1,19 @@ +package com.android.javacard.seprovider; + +public class KMKeyObject { + private byte algorithm; + private Object keyObjectInst; + + public void setKeyObjectData(byte alg, Object keyObject) { + algorithm = alg; + keyObjectInst = keyObject; + } + + public byte getAlgorithm() { + return this.algorithm; + } + + public Object getKeyObject() { + return keyObjectInst; + } +} diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperation.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperation.java index b73d58d1..d824db2a 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperation.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperation.java @@ -51,4 +51,6 @@ boolean verify(byte[] inputDataBuf, short inputDataStart, short inputDataLength, // include the auth tag which is appended at the end of the encrypted data. For decryption this will be // size of the decrypted data only. short getAESGCMOutputSize(short dataSize, short macLength); + + KMKeyObject getKeyObject(); } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java index baa8a0f9..bbb8c675 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java @@ -15,9 +15,6 @@ */ package com.android.javacard.seprovider; -import com.android.javacard.seprovider.KMError; -import com.android.javacard.seprovider.KMException; -import com.android.javacard.seprovider.KMType; import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.KeyAgreement; @@ -46,7 +43,7 @@ public class KMOperationImpl implements KMOperation { public KMOperationImpl() { parameters = JCSystem.makeTransientShortArray(PARAMETERS_LENGTH, JCSystem.CLEAR_ON_RESET); - operationInst = JCSystem.makeTransientObjectArray((short) 1, JCSystem.CLEAR_ON_RESET); + operationInst = JCSystem.makeTransientObjectArray((short) 2, JCSystem.CLEAR_ON_RESET); reset(); } @@ -91,23 +88,32 @@ public void setAlgorithmType(short cipherAlg) { } public void setCipher(Cipher cipher) { - operationInst[0] = cipher; + operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO] = cipher; } public void setSignature(Signature signer) { - operationInst[0] = signer; + operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO] = signer; } public void setKeyAgreement(KeyAgreement keyAgreement) { - operationInst[0] = keyAgreement; + operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO] = keyAgreement; } - public boolean isResourceMatches(Object object) { - return operationInst[0] == object; + public boolean isResourceMatches(Object object, byte resourceType) { + return operationInst[resourceType] == object; } + public void setKeyObject(KMKeyObject keyObject) { + operationInst[KMPoolManager.RESOURCE_TYPE_KEY] = keyObject; + } + + public KMKeyObject getKeyObject() { + return (KMKeyObject) operationInst[KMPoolManager.RESOURCE_TYPE_KEY]; + } + private void reset() { - operationInst[0] = null; + operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO] = null; + operationInst[KMPoolManager.RESOURCE_TYPE_KEY] = null; parameters[MAC_LENGTH_OFFSET] = KMType.INVALID_VALUE; parameters[AES_GCM_UPDATE_LEN_OFFSET] = 0; parameters[BLOCK_MODE_OFFSET] = KMType.INVALID_VALUE; @@ -131,7 +137,7 @@ private byte mapPurpose(short purpose) { } private void initSymmetricCipher(Key key, byte[] ivBuffer, short ivStart, short ivLength) { - Cipher symmCipher = (Cipher) operationInst[0]; + Cipher symmCipher = (Cipher) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]; byte cipherAlg = symmCipher.getAlgorithm(); switch (cipherAlg) { case Cipher.ALG_AES_BLOCK_128_CBC_NOPAD: @@ -167,17 +173,19 @@ private void initRsa(Key key, short digest) { } else { mode = Signature.MODE_SIGN; } - ((Signature) operationInst[0]).init((PrivateKey) key, mode); + ((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]).init((PrivateKey) key, mode); } else { // RSA Cipher - ((Cipher) operationInst[0]).init((PrivateKey) key, mapPurpose(getPurpose())); + ((Cipher) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]). + init((PrivateKey) key, mapPurpose(getPurpose())); } } private void initEc(Key key) { if (KMType.AGREE_KEY == getPurpose()) { - ((KeyAgreement) operationInst[0]).init((PrivateKey) key); + ((KeyAgreement) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]).init((PrivateKey) key); } else { - ((Signature) operationInst[0]).init((PrivateKey) key, mapPurpose(getPurpose())); + ((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]) + .init((PrivateKey) key, mapPurpose(getPurpose())); } } @@ -188,7 +196,8 @@ public void init(Key key, short digest, byte[] buf, short start, short length) { initSymmetricCipher(key, buf, start, length); break; case KMType.HMAC: - ((Signature) operationInst[0]).init(key, mapPurpose(getPurpose())); + ((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]) + .init(key, mapPurpose(getPurpose())); break; case KMType.RSA: initRsa(key, digest); @@ -205,7 +214,8 @@ public void init(Key key, short digest, byte[] buf, short start, short length) { @Override public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] outputDataBuf, short outputDataStart) { - short len = ((Cipher) operationInst[0]).update(inputDataBuf, inputDataStart, inputDataLength, + short len = ((Cipher) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]) + .update(inputDataBuf, inputDataStart, inputDataLength, outputDataBuf, outputDataStart); if (parameters[ALG_TYPE_OFFSET] == KMType.AES && parameters[BLOCK_MODE_OFFSET] == KMType.GCM) { @@ -218,13 +228,15 @@ public short update(byte[] inputDataBuf, short inputDataStart, @Override public short update(byte[] inputDataBuf, short inputDataStart, short inputDataLength) { - ((Signature) operationInst[0]).update(inputDataBuf, inputDataStart, inputDataLength); + ((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]) + .update(inputDataBuf, inputDataStart, inputDataLength); return 0; } private short finishKeyAgreement(byte[] publicKey, short start, short len, byte[] output, short outputStart) { - return ((KeyAgreement) operationInst[0]).generateSecret(publicKey, start, len, + return ((KeyAgreement) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]) + .generateSecret(publicKey, start, len, output, outputStart); } @@ -234,7 +246,7 @@ private short finishCipher(byte[] inputDataBuf, short inputDataStart, short inpu short len = 0; try { byte[] tmpArray = KMAndroidSEProvider.getInstance().tmpArray; - Cipher cipher = (Cipher) operationInst[0]; + Cipher cipher = (Cipher) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]; short cipherAlg = parameters[ALG_TYPE_OFFSET]; short blockMode = parameters[BLOCK_MODE_OFFSET]; short mode = parameters[PURPOSE_OFFSET]; @@ -328,14 +340,16 @@ public short finish(byte[] inputDataBuf, short inputDataStart, short inputDataLe @Override public short sign(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] signBuf, short signStart) { - return ((Signature) operationInst[0]).sign(inputDataBuf, inputDataStart, inputDataLength, + return ((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]) + .sign(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart); } @Override public boolean verify(byte[] inputDataBuf, short inputDataStart, short inputDataLength, byte[] signBuf, short signStart, short signLength) { - return ((Signature) operationInst[0]).verify(inputDataBuf, inputDataStart, inputDataLength, + return ((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]) + .verify(inputDataBuf, inputDataStart, inputDataLength, signBuf, signStart, signLength); } @@ -344,10 +358,10 @@ public void abort() { // Few simulators does not reset the Hmac signer instance on init so as // a workaround to reset the hmac signer instance in case of abort/failure of the operation // the corresponding sign / verify function is called. - if (operationInst[0] != null) { + if (operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO] != null) { if ((parameters[PURPOSE_OFFSET] == KMType.SIGN || parameters[PURPOSE_OFFSET] == KMType.VERIFY) && - (((Signature) operationInst[0]).getAlgorithm() == Signature.ALG_HMAC_SHA_256)) { - Signature signer = (Signature) operationInst[0]; + (((Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]).getAlgorithm() == Signature.ALG_HMAC_SHA_256)) { + Signature signer = (Signature) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]; try { if (parameters[PURPOSE_OFFSET] == KMType.SIGN) { signer.sign(EMPTY, (short) 0, (short) 0, EMPTY, (short) 0); @@ -364,7 +378,8 @@ public void abort() { @Override public void updateAAD(byte[] dataBuf, short dataStart, short dataLength) { - ((AEADCipher) operationInst[0]).updateAAD(dataBuf, dataStart, dataLength); + ((AEADCipher) operationInst[KMPoolManager.RESOURCE_TYPE_CRYPTO]) + .updateAAD(dataBuf, dataStart, dataLength); } @Override diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java index e3baf610..57d164cb 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java @@ -15,7 +15,16 @@ */ package com.android.javacard.seprovider; import javacard.framework.JCSystem; +import javacard.security.AESKey; +import javacard.security.CryptoException; +import javacard.security.DESKey; +import javacard.security.ECPrivateKey; +import javacard.security.ECPublicKey; +import javacard.security.HMACKey; import javacard.security.KeyAgreement; +import javacard.security.KeyBuilder; +import javacard.security.KeyPair; +import javacard.security.SecretKey; import javacard.security.Signature; import javacardx.crypto.AEADCipher; import javacardx.crypto.Cipher; @@ -27,6 +36,26 @@ public class KMPoolManager { public static final short MAX_OPERATION_INSTANCES = 4; private static final short HMAC_MAX_OPERATION_INSTANCES = 8; + public static final byte AES_128 = 0x04; + public static final byte AES_256 = 0x05; + //Resource type constants + public static final byte RESOURCE_TYPE_CRYPTO = 0x00; + public static final byte RESOURCE_TYPE_KEY = 0x01; + // static final variables + // -------------------------------------------------------------- + // P-256 Curve Parameters + static byte[] secp256r1_P; + static byte[] secp256r1_A; + + static byte[] secp256r1_B; + static byte[] secp256r1_S; + + // Uncompressed form + static byte[] secp256r1_UCG; + static byte[] secp256r1_N; + static final short secp256r1_H = 1; + // -------------------------------------------------------------- + // Cipher pool private Object[] cipherPool; // Signature pool @@ -37,7 +66,18 @@ public class KMPoolManager { private Object[] operationPool; // Hmac signer pool which is used to support TRUSTED_CONFIRMATION_REQUIRED tag. private Object[] hmacSignOperationPool; - + + private Object[] keysPool; + + final byte[] KEY_ALGS = { + AES_128, + AES_256, + KMType.DES, + KMType.RSA, + KMType.EC, + KMType.HMAC, + }; + final byte[] CIPHER_ALGS = { Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, @@ -71,11 +111,81 @@ public static KMPoolManager getInstance() { return poolManager; } + public static void initStatics() { + secp256r1_P = new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, + (byte) 0x00, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF}; + + secp256r1_A = new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, + (byte) 0x00, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, (byte) 0xFC}; + + secp256r1_B = new byte[]{(byte) 0x5A, (byte) 0xC6, (byte) 0x35, (byte) 0xD8, (byte) 0xAA, + (byte) 0x3A, + (byte) 0x93, (byte) 0xE7, (byte) 0xB3, (byte) 0xEB, (byte) 0xBD, (byte) 0x55, (byte) 0x76, + (byte) 0x98, + (byte) 0x86, (byte) 0xBC, (byte) 0x65, (byte) 0x1D, (byte) 0x06, (byte) 0xB0, (byte) 0xCC, + (byte) 0x53, + (byte) 0xB0, (byte) 0xF6, (byte) 0x3B, (byte) 0xCE, (byte) 0x3C, (byte) 0x3E, (byte) 0x27, + (byte) 0xD2, + (byte) 0x60, (byte) 0x4B}; + + secp256r1_S = new byte[]{(byte) 0xC4, (byte) 0x9D, (byte) 0x36, (byte) 0x08, (byte) 0x86, + (byte) 0xE7, + (byte) 0x04, (byte) 0x93, (byte) 0x6A, (byte) 0x66, (byte) 0x78, (byte) 0xE1, (byte) 0x13, + (byte) 0x9D, + (byte) 0x26, (byte) 0xB7, (byte) 0x81, (byte) 0x9F, (byte) 0x7E, (byte) 0x90}; + + // Uncompressed form + secp256r1_UCG = new byte[]{(byte) 0x04, (byte) 0x6B, (byte) 0x17, (byte) 0xD1, (byte) 0xF2, + (byte) 0xE1, + (byte) 0x2C, (byte) 0x42, (byte) 0x47, (byte) 0xF8, (byte) 0xBC, (byte) 0xE6, (byte) 0xE5, + (byte) 0x63, + (byte) 0xA4, (byte) 0x40, (byte) 0xF2, (byte) 0x77, (byte) 0x03, (byte) 0x7D, (byte) 0x81, + (byte) 0x2D, + (byte) 0xEB, (byte) 0x33, (byte) 0xA0, (byte) 0xF4, (byte) 0xA1, (byte) 0x39, (byte) 0x45, + (byte) 0xD8, + (byte) 0x98, (byte) 0xC2, (byte) 0x96, (byte) 0x4F, (byte) 0xE3, (byte) 0x42, (byte) 0xE2, + (byte) 0xFE, + (byte) 0x1A, (byte) 0x7F, (byte) 0x9B, (byte) 0x8E, (byte) 0xE7, (byte) 0xEB, (byte) 0x4A, + (byte) 0x7C, + (byte) 0x0F, (byte) 0x9E, (byte) 0x16, (byte) 0x2B, (byte) 0xCE, (byte) 0x33, (byte) 0x57, + (byte) 0x6B, + (byte) 0x31, (byte) 0x5E, (byte) 0xCE, (byte) 0xCB, (byte) 0xB6, (byte) 0x40, (byte) 0x68, + (byte) 0x37, + (byte) 0xBF, (byte) 0x51, (byte) 0xF5}; + + secp256r1_N = new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, + (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xBC, (byte) 0xE6, (byte) 0xFA, (byte) 0xAD, (byte) 0xA7, + (byte) 0x17, + (byte) 0x9E, (byte) 0x84, (byte) 0xF3, (byte) 0xB9, (byte) 0xCA, (byte) 0xC2, (byte) 0xFC, + (byte) 0x63, + (byte) 0x25, (byte) 0x51}; + } + 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)]; keyAgreementPool = new Object[(short) (KEY_AGREE_ALGS.length * 4)]; + + keysPool = new Object[(short) ((KEY_ALGS.length * 4) + 4)]; operationPool = new Object[4]; hmacSignOperationPool = new Object[4]; /* Initialize pools */ @@ -84,8 +194,18 @@ private KMPoolManager() { initializeSignerPool(); initializeCipherPool(); initializeKeyAgreementPool(); + initializeKeysPool(); + } + private void initializeKeysPool() { + short index = 0; + while (index < KEY_ALGS.length) { + keysPool[index] = createKeyObjectInstance(KEY_ALGS[index]); + index++; + } + } + private void initializeOperationPool() { short index = 0; while (index < MAX_OPERATION_INSTANCES) { @@ -180,6 +300,40 @@ private Signature getSignatureInstance(byte alg) { return Signature.getInstance(alg, false); } } + + private KMKeyObject createKeyObjectInstance(byte alg) { + Object keyObject = null; + switch (alg) { + case AES_128: + keyObject = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_RESET, + KeyBuilder.LENGTH_AES_128, false); + break; + case AES_256: + keyObject = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_RESET, + KeyBuilder.LENGTH_AES_256, false); + break; + case KMType.DES: + keyObject = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES_TRANSIENT_RESET, + KeyBuilder.LENGTH_DES3_3KEY, false); + break; + case KMType.RSA: + keyObject = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_2048); + break; + case KMType.EC: + keyObject = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); + initECKey((KeyPair) keyObject); + break; + case KMType.HMAC: + keyObject = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC_TRANSIENT_RESET, + (short) 512, false); + break; + default: + KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); + } + KMKeyObject ptr = new KMKeyObject(); + ptr.setKeyObjectData(alg, keyObject); + return ptr; + } private Cipher getCipherInstance(byte alg) { if ((KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1 == alg) || @@ -234,11 +388,11 @@ private byte getAlgorithm(short purpose, Object object) { return 0; } - private boolean isResourceBusy(Object obj) { + private boolean isResourceBusy(Object obj, byte resourceType) { short index = 0; while (index < MAX_OPERATION_INSTANCES) { - if (((KMOperationImpl) operationPool[index]).isResourceMatches(obj) - || ((KMOperationImpl) hmacSignOperationPool[index]).isResourceMatches(obj)) { + if (((KMOperationImpl) operationPool[index]).isResourceMatches(obj, resourceType) + || ((KMOperationImpl) hmacSignOperationPool[index]).isResourceMatches(obj, resourceType)) { return true; } index++; @@ -265,19 +419,20 @@ private void setObject(short purpose, KMOperation operation, Object obj) { } private void reserveOperation(KMOperation operation, short purpose, short strongboxAlgType, - short padding, short blockMode, short macLength, Object obj) { + short padding, short blockMode, short macLength, Object obj, KMKeyObject keyObject) { ((KMOperationImpl) operation).setPurpose(purpose); ((KMOperationImpl) operation).setAlgorithmType(strongboxAlgType); ((KMOperationImpl) operation).setPaddingAlgorithm(padding); ((KMOperationImpl) operation).setBlockMode(blockMode); ((KMOperationImpl) operation).setMacLength(macLength); + ((KMOperationImpl) operation).setKeyObject(keyObject); setObject(purpose, operation, obj); } public KMOperation getOperationImpl(short purpose, short alg, short strongboxAlgType, short padding, - short blockMode, short macLength, boolean isTrustedConfOpr) { + short blockMode, short macLength, short secretLength, boolean isTrustedConfOpr) { KMOperation operation; // Throw exception if no resource from operation pool is available. if (null == (operation = getResourceFromOperationPool(isTrustedConfOpr))) { @@ -292,6 +447,7 @@ public KMOperation getOperationImpl(short purpose, short alg, short strongboxAlg maxOperations = HMAC_MAX_OPERATION_INSTANCES; } + KMKeyObject keyObject = reserveKeyObject(alg, secretLength, maxOperations); while (index < pool.length) { if (usageCount >= maxOperations) { KMException.throwIt(KMError.TOO_MANY_OPERATIONS); @@ -302,14 +458,14 @@ public KMOperation getOperationImpl(short purpose, short alg, short strongboxAlg pool[index] = createInstance(purpose, alg); JCSystem.commitTransaction(); reserveOperation(operation, purpose, strongboxAlgType, padding, blockMode, macLength, - pool[index]); + pool[index], keyObject); break; } if (alg == getAlgorithm(purpose, pool[index])) { // Check if the crypto instance is not busy and free to use. - if (!isResourceBusy(pool[index])) { + if (!isResourceBusy(pool[index], RESOURCE_TYPE_CRYPTO)) { reserveOperation(operation, purpose, strongboxAlgType, padding, blockMode, macLength, - pool[index]); + pool[index], keyObject); break; } usageCount++; @@ -319,6 +475,96 @@ public KMOperation getOperationImpl(short purpose, short alg, short strongboxAlg return operation; } + public KMKeyObject reserveKeyObject(short alg, short secretLength, short maxOperations) { + KMKeyObject keyObject = null; + byte algo = mapAlgorithm(alg, secretLength); + short index = 0; + short usageCount = 0; + while (index < keysPool.length) { + if (usageCount >= maxOperations) { + KMException.throwIt(KMError.TOO_MANY_OPERATIONS); + } + if (keysPool[index] == null) { + JCSystem.beginTransaction(); + keysPool[index] = createKeyObjectInstance(algo); + keyObject = (KMKeyObject) keysPool[index]; + JCSystem.commitTransaction(); + break; + } + keyObject = (KMKeyObject) keysPool[index]; + if (algo == keyObject.getAlgorithm()) { + // Check if the Object instance is not busy and free to use. + if (!isResourceBusy(keyObject, RESOURCE_TYPE_KEY)) { + break; + } + usageCount++; + } + index++; + } + return keyObject; + } + + private byte mapAlgorithm(short alg, short secretLength) { + byte algo = 0; + switch (alg) { + case Cipher.ALG_AES_BLOCK_128_CBC_NOPAD: + case Cipher.ALG_AES_BLOCK_128_ECB_NOPAD: + case Cipher.ALG_AES_CTR: + case AEADCipher.ALG_AES_GCM: + if (secretLength == 16) { + algo = AES_128; + } else if (secretLength == 32) { + algo = AES_256; + } else { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + break; + case Cipher.ALG_DES_CBC_NOPAD: + case Cipher.ALG_DES_ECB_NOPAD: + algo = KMType.DES; + break; + case Cipher.ALG_RSA_PKCS1: + case KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA1: + case KMRsaOAEPEncoding.ALG_RSA_PKCS1_OAEP_SHA256_MGF1_SHA256: + case Cipher.ALG_RSA_NOPAD: + case Signature.ALG_RSA_SHA_256_PKCS1: + case Signature.ALG_RSA_SHA_256_PKCS1_PSS: + case KMRsa2048NoDigestSignature.ALG_RSA_SIGN_NOPAD: + case KMRsa2048NoDigestSignature.ALG_RSA_PKCS1_NODIGEST: + algo = KMType.RSA; + break; + case Signature.ALG_ECDSA_SHA_256: + case KMEcdsa256NoDigestSignature.ALG_ECDSA_NODIGEST: + case KeyAgreement.ALG_EC_SVDP_DH_PLAIN: + algo = KMType.EC; + break; + case Signature.ALG_HMAC_SHA_256: + algo = KMType.HMAC; + break; + default: + KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); + } + return algo; + } + + public void initECKey(KeyPair ecKeyPair) { + ECPrivateKey privKey = (ECPrivateKey) ecKeyPair.getPrivate(); + ECPublicKey pubkey = (ECPublicKey) ecKeyPair.getPublic(); + pubkey.setFieldFP(secp256r1_P, (short) 0, (short) secp256r1_P.length); + pubkey.setA(secp256r1_A, (short) 0, (short) secp256r1_A.length); + pubkey.setB(secp256r1_B, (short) 0, (short) secp256r1_B.length); + pubkey.setG(secp256r1_UCG, (short) 0, (short) secp256r1_UCG.length); + pubkey.setK(secp256r1_H); + pubkey.setR(secp256r1_N, (short) 0, (short) secp256r1_N.length); + + privKey.setFieldFP(secp256r1_P, (short) 0, (short) secp256r1_P.length); + privKey.setA(secp256r1_A, (short) 0, (short) secp256r1_A.length); + privKey.setB(secp256r1_B, (short) 0, (short) secp256r1_B.length); + privKey.setG(secp256r1_UCG, (short) 0, (short) secp256r1_UCG.length); + privKey.setK(secp256r1_H); + privKey.setR(secp256r1_N, (short) 0, (short) secp256r1_N.length); + } + public void powerReset() { short index = 0; while (index < operationPool.length) { diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java index c4445114..515fe4b4 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java @@ -643,20 +643,7 @@ KMDeviceUniqueKeyPair createRkpDeviceUniqueKeyPair(KMDeviceUniqueKeyPair key, short messageDigest256(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, short outOffset); - /** - * This function creates an ECKey and initializes the ECPrivateKey with the provided input key - * data. The initialized Key is maintained by the SEProvider. This function should be called only - * while provisioning the attestation key. - * - * @param keyData buffer containing the ec private key. - * @param offset start of the buffer. - * @param length length of the buffer. - * @return An instance of KMAttestationKey. - */ - KMAttestationKey createAttestationKey(KMAttestationKey attestationKey, byte[] keyData, - short offset, - short length); - + /** * This function generates a HMAC key from the provided key buffers. * From 24d9d551e1984a67563a64a4083acbed1c587df3 Mon Sep 17 00:00:00 2001 From: "avinash.hedage" Date: Fri, 22 Apr 2022 14:50:37 +0000 Subject: [PATCH 2/3] key object pool changes --- .../javacard/seprovider/KMAndroidSEProvider.java | 12 ++++++------ .../com/android/javacard/seprovider/KMKeyObject.java | 2 +- .../android/javacard/seprovider/KMPoolManager.java | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index 23e80b29..d2fc4f48 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java @@ -590,7 +590,7 @@ public KMOperation createSymmetricCipher(short alg, short purpose, short macLeng poolMgr.getOperationImpl(purpose, cipherAlg, alg, padding, blockMode, macLength, secretLength, false); KMKeyObject keyObj = operation.getKeyObject(); - Key key = (Key)keyObj.getKeyObject(); + Key key = (Key)keyObj.getKeyObjectInstance(); switch (secretLength) { case 32: case 16: @@ -616,7 +616,7 @@ public KMOperation createHmacSignerVerifier(short purpose, short digest, poolMgr.getOperationImpl(purpose, Signature.ALG_HMAC_SHA_256, KMType.HMAC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, (short)0, false); KMKeyObject keyObj = operation.getKeyObject(); - HMACKey key = (HMACKey)keyObj.getKeyObject(); + HMACKey key = (HMACKey)keyObj.getKeyObjectInstance(); key.setKey(secret, secretStart, secretLength); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); return operation; @@ -671,7 +671,7 @@ public KMOperation createRsaSigner(short digest, short padding, byte[] secret, KMOperation operation = poolMgr.getOperationImpl(KMType.SIGN, alg, KMType.RSA, padding, KMType.INVALID_VALUE, KMType.INVALID_VALUE, secretLength, false); KMKeyObject keyObj = operation.getKeyObject(); - RSAPrivateKey key = (RSAPrivateKey)((KeyPair)(keyObj.getKeyObject())).getPrivate(); + RSAPrivateKey key = (RSAPrivateKey)((KeyPair)(keyObj.getKeyObjectInstance())).getPrivate(); key.setExponent(secret, secretStart, secretLength); key.setModulus(modBuffer, modOff, modLength); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); @@ -685,7 +685,7 @@ public KMOperation createRsaDecipher(short padding, short mgfDigest, byte[] secr KMOperation operation = poolMgr.getOperationImpl(KMType.DECRYPT, cipherAlg, KMType.RSA, padding, KMType.INVALID_VALUE, KMType.INVALID_VALUE, secretLength, false); KMKeyObject keyObj = operation.getKeyObject(); - RSAPrivateKey key = (RSAPrivateKey) ((KeyPair)(keyObj.getKeyObject())).getPrivate(); + RSAPrivateKey key = (RSAPrivateKey) ((KeyPair)(keyObj.getKeyObjectInstance())).getPrivate(); key.setExponent(secret, secretStart, secretLength); key.setModulus(modBuffer, modOff, modLength); ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, null, (short) 0, (short) 0); @@ -699,7 +699,7 @@ public KMOperation createEcSigner(short digest, byte[] secret, .getOperationImpl(KMType.SIGN, alg, KMType.EC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, secretLength, false); KMKeyObject keyObj = operation.getKeyObject(); - ECPrivateKey key = (ECPrivateKey) ((KeyPair)(keyObj.getKeyObject())).getPrivate(); + ECPrivateKey key = (ECPrivateKey) ((KeyPair)(keyObj.getKeyObjectInstance())).getPrivate(); key.setS(secret, secretStart, secretLength); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); return operation; @@ -711,7 +711,7 @@ public KMOperation createKeyAgreement(byte[] secret, short secretStart, .getOperationImpl(KMType.AGREE_KEY, KeyAgreement.ALG_EC_SVDP_DH_PLAIN, KMType.EC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, (short)0, false); KMKeyObject keyObj = operation.getKeyObject(); - ECPrivateKey key = (ECPrivateKey) ((KeyPair)(keyObj.getKeyObject())).getPrivate(); + ECPrivateKey key = (ECPrivateKey) ((KeyPair)(keyObj.getKeyObjectInstance())).getPrivate(); key.setS(secret, secretStart, secretLength); ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, null, (short) 0, (short) 0); return operation; diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java index ad5d1e5f..03f54ecc 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMKeyObject.java @@ -13,7 +13,7 @@ public byte getAlgorithm() { return this.algorithm; } - public Object getKeyObject() { + public Object getKeyObjectInstance() { return keyObjectInst; } } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java index 57d164cb..6e9ca210 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java @@ -447,7 +447,7 @@ public KMOperation getOperationImpl(short purpose, short alg, short strongboxAlg maxOperations = HMAC_MAX_OPERATION_INSTANCES; } - KMKeyObject keyObject = reserveKeyObject(alg, secretLength, maxOperations); + KMKeyObject keyObject = getKeyObjectFromPool(alg, secretLength, maxOperations); while (index < pool.length) { if (usageCount >= maxOperations) { KMException.throwIt(KMError.TOO_MANY_OPERATIONS); @@ -475,7 +475,7 @@ public KMOperation getOperationImpl(short purpose, short alg, short strongboxAlg return operation; } - public KMKeyObject reserveKeyObject(short alg, short secretLength, short maxOperations) { + public KMKeyObject getKeyObjectFromPool(short alg, short secretLength, short maxOperations) { KMKeyObject keyObject = null; byte algo = mapAlgorithm(alg, secretLength); short index = 0; From 100ea995c74e6ddedfbd8d3dd7d157578af52105 Mon Sep 17 00:00:00 2001 From: Subrahmanyaman Date: Tue, 26 Apr 2022 05:55:18 +0000 Subject: [PATCH 3/3] Addressed review comments --- .../seprovider/KMAndroidSEProvider.java | 15 ++-- .../javacard/seprovider/KMPoolManager.java | 7 +- .../javacard/keymaster/KMKeymasterApplet.java | 71 +++++++++++-------- 3 files changed, 55 insertions(+), 38 deletions(-) diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index d2fc4f48..d21e25ab 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java @@ -588,7 +588,7 @@ public KMOperation createSymmetricCipher(short alg, short purpose, short macLeng short cipherAlg = mapCipherAlg((byte) alg, (byte) padding, (byte) blockMode, (byte) 0); KMOperation operation = poolMgr.getOperationImpl(purpose, cipherAlg, alg, padding, blockMode, macLength, secretLength, false); - + // Get the KeyObject from the operation and update the key with the secret key material. KMKeyObject keyObj = operation.getKeyObject(); Key key = (Key)keyObj.getKeyObjectInstance(); switch (secretLength) { @@ -615,6 +615,7 @@ public KMOperation createHmacSignerVerifier(short purpose, short digest, KMOperation operation = poolMgr.getOperationImpl(purpose, Signature.ALG_HMAC_SHA_256, KMType.HMAC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, (short)0, false); + // Get the KeyObject from the operation and update the key with the secret key material. KMKeyObject keyObj = operation.getKeyObject(); HMACKey key = (HMACKey)keyObj.getKeyObjectInstance(); key.setKey(secret, secretStart, secretLength); @@ -622,14 +623,18 @@ public KMOperation createHmacSignerVerifier(short purpose, short digest, return operation; } - private KMOperation createHmacSignerVerifier(short purpose, short digest, HMACKey key, boolean isTrustedConf) { + private KMOperation createHmacSignerVerifier(short purpose, short digest, HMACKey hmacKey, boolean isTrustedConf) { if (digest != KMType.SHA2_256) { CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); } KMOperation operation = poolMgr.getOperationImpl(purpose, Signature.ALG_HMAC_SHA_256, KMType.HMAC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, (short)0, isTrustedConf); - + // Get the KeyObject from the operation and update the key with the secret key material. + KMKeyObject keyObj = operation.getKeyObject(); + HMACKey key = (HMACKey)keyObj.getKeyObject(); + short len = hmacKey.getKey(tmpArray, (short) 0); + key.setKey(tmpArray, (short) 0, len); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); return operation; } @@ -670,6 +675,7 @@ public KMOperation createRsaSigner(short digest, short padding, byte[] secret, byte alg = mapSignature256Alg(KMType.RSA, (byte) padding, (byte) digest); KMOperation operation = poolMgr.getOperationImpl(KMType.SIGN, alg, KMType.RSA, padding, KMType.INVALID_VALUE, KMType.INVALID_VALUE, secretLength, false); + // Get the KeyObject from the operation and update the key with the secret key material. KMKeyObject keyObj = operation.getKeyObject(); RSAPrivateKey key = (RSAPrivateKey)((KeyPair)(keyObj.getKeyObjectInstance())).getPrivate(); key.setExponent(secret, secretStart, secretLength); @@ -683,7 +689,8 @@ public KMOperation createRsaDecipher(short padding, short mgfDigest, byte[] secr short modLength) { byte cipherAlg = mapCipherAlg(KMType.RSA, (byte) padding, (byte) 0, (byte) mgfDigest); KMOperation operation = poolMgr.getOperationImpl(KMType.DECRYPT, cipherAlg, KMType.RSA, padding, - KMType.INVALID_VALUE, KMType.INVALID_VALUE, secretLength, false); + KMType.INVALID_VALUE, KMType.INVALID_VALUE, secretLength, false); + // Get the KeyObject from the operation and update the key with the secret key material. KMKeyObject keyObj = operation.getKeyObject(); RSAPrivateKey key = (RSAPrivateKey) ((KeyPair)(keyObj.getKeyObjectInstance())).getPrivate(); key.setExponent(secret, secretStart, secretLength); diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java index 6e9ca210..9db4d0fb 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java @@ -454,8 +454,9 @@ public KMOperation getOperationImpl(short purpose, short alg, short strongboxAlg } if (pool[index] == null) { // Create one of the instance (Cipher / Signer / KeyAgreement] based on purpose. + Object cipherObject = createInstance(purpose, alg); JCSystem.beginTransaction(); - pool[index] = createInstance(purpose, alg); + pool[index] = cipherObject; JCSystem.commitTransaction(); reserveOperation(operation, purpose, strongboxAlgType, padding, blockMode, macLength, pool[index], keyObject); @@ -485,9 +486,9 @@ public KMKeyObject getKeyObjectFromPool(short alg, short secretLength, short max KMException.throwIt(KMError.TOO_MANY_OPERATIONS); } if (keysPool[index] == null) { + keyObject = createKeyObjectInstance(algo); JCSystem.beginTransaction(); - keysPool[index] = createKeyObjectInstance(algo); - keyObject = (KMKeyObject) keysPool[index]; + keysPool[index] = keyObject; JCSystem.commitTransaction(); break; } diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index bd269dc1..a14933e3 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -808,20 +808,20 @@ private short createKeyBlobExp(short version) { case (short) 0: // Old KeyBlob has a maximum of 5 elements. keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V0); - KMArray.cast(keyBlob).add((short) 0, byteBlobExp); - KMArray.cast(keyBlob).add((short) 1, byteBlobExp); - KMArray.cast(keyBlob).add((short) 2, byteBlobExp); - KMArray.cast(keyBlob).add((short) 3, keyChar); - KMArray.cast(keyBlob).add((short) 4, byteBlobExp); + KMArray.cast(keyBlob).add((short) 0, byteBlobExp);// Secret + KMArray.cast(keyBlob).add((short) 1, byteBlobExp);// Nonce + KMArray.cast(keyBlob).add((short) 2, byteBlobExp);// AuthTag + KMArray.cast(keyBlob).add((short) 3, keyChar);// KeyChars + KMArray.cast(keyBlob).add((short) 4, byteBlobExp);// PubKey break; case (short) 1: keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V1); - KMArray.cast(keyBlob).add((short) 0, KMInteger.exp()); - KMArray.cast(keyBlob).add((short) 1, byteBlobExp); - KMArray.cast(keyBlob).add((short) 2, byteBlobExp); - KMArray.cast(keyBlob).add((short) 3, byteBlobExp); - KMArray.cast(keyBlob).add((short) 4, keyChar); - KMArray.cast(keyBlob).add((short) 5, byteBlobExp); + KMArray.cast(keyBlob).add((short) 0, KMInteger.exp());// Version + KMArray.cast(keyBlob).add((short) 1, byteBlobExp);// Secret + KMArray.cast(keyBlob).add((short) 2, byteBlobExp);// Nonce + KMArray.cast(keyBlob).add((short) 3, byteBlobExp);// AuthTag + KMArray.cast(keyBlob).add((short) 4, keyChar);// KeyChars + KMArray.cast(keyBlob).add((short) 5, byteBlobExp);// PubKey break; case (short) 2: keyBlob = KMArray.instance(ASYM_KEY_BLOB_SIZE_V2); @@ -3031,9 +3031,6 @@ private void validateImportKey(short params, short keyFmt){ } private void importKey(APDU apdu, short keyFmt, byte[] scratchPad) { - // Take backup of the KeyParams before they get updated. The original - // key params are required to generate MAC in macKeyParams() function. - short keyParams = data[KEY_PARAMETERS]; validateImportKey(data[KEY_PARAMETERS], keyFmt); // Check algorithm and dispatch to appropriate handler. short alg = KMEnumTag.getValue(KMType.ALGORITHM, data[KEY_PARAMETERS]); @@ -3943,10 +3940,10 @@ private void decodeKeyBlob(short version, short keyBlob) { short minArraySize = 0; switch(version) { case 0: - minArraySize = (short) 4; + minArraySize = SYM_KEY_BLOB_SIZE_V0; break; case 1: - minArraySize = (short) 5; + minArraySize = SYM_KEY_BLOB_SIZE_V1; break; case 2: minArraySize = SYM_KEY_BLOB_SIZE_V2; @@ -3975,12 +3972,39 @@ private void processDecryptSecret(short version, short appId, short appData, byt short keyBlobSecretOff = 0; switch(version) { case 0: + // V0 KeyBlob + // KEY_BLOB = [ + // SECRET, + // NONCE, + // AUTH_TAG, + // KEY_CHARACTERISTICS, + // PUBKEY + // ] keyBlobSecretOff = (short) 0; break; case 1: + // V1 KeyBlob + // KEY_BLOB = [ + // VERSION, + // SECRET, + // NONCE, + // AUTH_TAG, + // KEY_CHARACTERISTICS, + // PUBKEY + // ] keyBlobSecretOff = (short) 1; break; case 2: + // V2 KeyBlob + // KEY_BLOB = [ + // VERSION, + // SECRET, + // NONCE, + // AUTH_TAG, + // KEY_CHARACTERISTICS, + // CUSTOM_TAGS, + // PUBKEY + // ] keyBlobSecretOff = KEY_BLOB_SECRET; break; default: @@ -4216,21 +4240,6 @@ private short addIntegers(short authTime, short timeStamp, byte[] scratchPad) { return KMInteger.uint_64(scratchPad, (short) 16); } - private void add(byte[] buf, short op1, short op2, short result) { - byte index = 7; - byte carry = 0; - short tmp; - while (index >= 0) { - tmp = (short) (buf[(short) (op1 + index)] + buf[(short) (op2 + index)] + carry); - carry = 0; - if (tmp > 255) { - carry = 1; // max unsigned byte value is 255 - } - buf[(short) (result + index)] = (byte) (tmp & (byte) 0xFF); - index--; - } - } - public void powerReset() { //TODO handle power reset signal. releaseAllOperations();