diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index ddaece5c..d21e25ab 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); + // 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) { 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,20 +614,27 @@ 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); + // 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); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); 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, isTrustedConf); - + 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; } @@ -769,8 +674,10 @@ 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); + // 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); key.setModulus(modBuffer, modOff, modLength); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); @@ -782,8 +689,10 @@ 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); + // 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); key.setModulus(modBuffer, modOff, modLength); ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, null, (short) 0, (short) 0); @@ -793,22 +702,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.getKeyObjectInstance())).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.getKeyObjectInstance())).getPrivate(); + key.setS(secret, secretStart, secretLength); ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, null, (short) 0, (short) 0); return operation; } @@ -884,19 +795,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 +1011,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..03f54ecc --- /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 getKeyObjectInstance() { + 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..9db4d0fb 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,24 +447,26 @@ public KMOperation getOperationImpl(short purpose, short alg, short strongboxAlg maxOperations = HMAC_MAX_OPERATION_INSTANCES; } + KMKeyObject keyObject = getKeyObjectFromPool(alg, secretLength, maxOperations); while (index < pool.length) { if (usageCount >= maxOperations) { KMException.throwIt(KMError.TOO_MANY_OPERATIONS); } 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]); + 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 +476,96 @@ public KMOperation getOperationImpl(short purpose, short alg, short strongboxAlg return operation; } + public KMKeyObject getKeyObjectFromPool(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) { + keyObject = createKeyObjectInstance(algo); + JCSystem.beginTransaction(); + keysPool[index] = keyObject; + 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. * diff --git a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java index 31ca6519..937fb349 100644 --- a/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java +++ b/Applet/JCardSimProviderLib/src/com/android/javacard/seprovider/KMJCardSimulator.java @@ -621,9 +621,9 @@ public short hmacSign(Object key, byte[] data, short dataStart, short dataLength @Override public boolean hmacVerify(KMComputedHmacKey key, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart, short macLength) { - KMHmacKey hmacKey = (KMHmacKey) key; - hmacSignature.init(hmacKey.getKey(), Signature.MODE_VERIFY); - return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, macLength); + KMHmacKey hmacKey = (KMHmacKey) key; + hmacSignature.init(hmacKey.getKey(), Signature.MODE_VERIFY); + return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, macLength); } @Override diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java index 9b2e4dad..89805dc7 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java @@ -235,64 +235,6 @@ public static short makeSbEnforced(short keyParamsPtr, byte origin, return createKeyParameters(scratchPad, (short) (arrInd / 2)); } - public static short makeSbEnforced(short keyParamsPtr, byte[] scratchPad) { - final short[] hwEnforcedTagArr = { - // HW Enforced - KMType.ENUM_TAG, KMType.ORIGIN, - KMType.UINT_TAG, KMType.OS_VERSION, - KMType.UINT_TAG, KMType.OS_PATCH_LEVEL, - KMType.UINT_TAG, KMType.VENDOR_PATCH_LEVEL, - KMType.UINT_TAG, KMType.BOOT_PATCH_LEVEL, - KMType.ENUM_ARRAY_TAG, KMType.PURPOSE, - KMType.ENUM_TAG, KMType.ALGORITHM, - KMType.UINT_TAG, KMType.KEYSIZE, - KMType.ULONG_TAG, KMType.RSA_PUBLIC_EXPONENT, - KMType.ENUM_TAG, KMType.BLOB_USAGE_REQ, - KMType.ENUM_ARRAY_TAG, KMType.DIGEST, - KMType.ENUM_ARRAY_TAG, KMType.PADDING, - KMType.ENUM_ARRAY_TAG, KMType.BLOCK_MODE, - KMType.ENUM_ARRAY_TAG, KMType.RSA_OAEP_MGF_DIGEST, - KMType.BOOL_TAG, KMType.NO_AUTH_REQUIRED, - KMType.BOOL_TAG, KMType.CALLER_NONCE, - KMType.UINT_TAG, KMType.MIN_MAC_LENGTH, - KMType.ENUM_TAG, KMType.ECCURVE, - KMType.BOOL_TAG, KMType.INCLUDE_UNIQUE_ID, - KMType.BOOL_TAG, KMType.ROLLBACK_RESISTANCE, - KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, - KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, - KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, - KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, - }; - byte index = 0; - short tagInd; - short arrInd = 0; - short tagPtr; - short tagKey; - short tagType; - short arrPtr = KMKeyParameters.cast(keyParamsPtr).getVals(); - short len = KMArray.cast(arrPtr).length(); - while (index < len) { - tagInd = 0; - tagPtr = KMArray.cast(arrPtr).get(index); - tagKey = KMTag.getKey(tagPtr); - tagType = KMTag.getTagType(tagPtr); - if (!isValidTag(tagType, tagKey)) { - KMException.throwIt(KMError.INVALID_KEY_BLOB); - } - while (tagInd < (short) hwEnforcedTagArr.length) { - if ((hwEnforcedTagArr[tagInd] == tagType) - && (hwEnforcedTagArr[(short) (tagInd + 1)] == tagKey)) { - Util.setShort(scratchPad, arrInd, tagPtr); - arrInd += 2; - break; - } - tagInd += 2; - } - index++; - } - return createKeyParameters(scratchPad, (short) (arrInd / 2)); - } - public static short makeHwEnforced(short sb, short tee){ short len = KMKeyParameters.cast(sb).length(); len += KMKeyParameters.cast(tee).length(); @@ -328,7 +270,8 @@ public static short makeKeystoreEnforced(short keyParamsPtr, byte[] scratchPad) KMType.UINT_TAG, KMType.USERID, KMType.DATE_TAG, KMType.CREATION_DATETIME, KMType.UINT_TAG, KMType.USAGE_COUNT_LIMIT, - KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY + KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY, + KMType.UINT_TAG, KMType.MAX_BOOT_LEVEL, }; byte index = 0; short tagInd; @@ -393,9 +336,6 @@ public static short makeTeeEnforced(short keyParamsPtr, byte[] scratchPad) { } index++; } - // Add custom tags at the end of the array. So it becomes easy to - // delete them when sending key characteristics back to HAL. - arrInd = addCustomTags(keyParamsPtr, scratchPad, arrInd); return createKeyParameters(scratchPad, (short) (arrInd / 2)); } @@ -471,9 +411,10 @@ public static short createKeyParameters(byte[] ptrArr, short len) { return KMKeyParameters.instance(arrPtr); } - public static short addCustomTags(short keyParams, byte[] scratchPad, short offset) { + public static short makeCustomTags(short keyParams, byte[] scratchPad) { short index = 0; short tagPtr; + short offset = 0; short len = (short) customTags.length; short tagType; while (index < len) { @@ -493,7 +434,7 @@ public static short addCustomTags(short keyParams, byte[] scratchPad, short offs } index += 2; } - return offset; + return createKeyParameters(scratchPad, (short) (offset / 2)); } public void deleteCustomTags() { diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 64b81ea6..a14933e3 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -191,6 +191,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final byte SB_PARAMETERS = 35; public static final byte CONFIRMATION_TOKEN = 36; public static final byte KEY_BLOB_VERSION_DATA_OFFSET = 37; + public static final byte CUSTOM_TAGS = 38; // Constant // AddRngEntropy @@ -202,7 +203,8 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final byte KEY_BLOB_NONCE = 2; public static final byte KEY_BLOB_AUTH_TAG = 3; public static final byte KEY_BLOB_PARAMS = 4; - public static final byte KEY_BLOB_PUB_KEY = 5; + public static final byte KEY_BLOB_CUSTOM_TAGS = 5; + public static final byte KEY_BLOB_PUB_KEY = 6; // AES GCM constants public static final byte AES_GCM_AUTH_TAG_LENGTH = 16; public static final byte AES_GCM_NONCE_LENGTH = 12; @@ -215,8 +217,10 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe // the KeyBlobs if it is changed. please increment this // version number whenever you change anything related to // KeyBlob (structure, encryption algorithm etc). - public static final short KEYBLOB_CURRENT_VERSION = 1; + public static final short KEYBLOB_CURRENT_VERSION = 2; // KeyBlob array size constants. + public static final byte SYM_KEY_BLOB_SIZE_V2 = 6; + public static final byte ASYM_KEY_BLOB_SIZE_V2 = 7; public static final byte SYM_KEY_BLOB_SIZE_V1 = 5; public static final byte ASYM_KEY_BLOB_SIZE_V1 = 6; public static final byte SYM_KEY_BLOB_SIZE_V0 = 4; @@ -652,23 +656,11 @@ public void sendOutgoing(APDU apdu, KMAttestationCert cert, short certStart, sho // reclaim the unused memory in the certificate. repository.reclaimMemory((short) (bufferStart - certStart)); } - // Reserve space of MAX_KEY_CHARS_SIZE to encode KeyCharacteristics - short prevReclaimIndex = repository.getHeapReclaimIndex(); - short keyCharsIndex = repository.allocReclaimableMemory(MAX_KEY_CHARS_SIZE); - - // Encode keyblob at the end of the buffer before KEY_CHARACTERISTICS - short keyBlobLen = encodeKeyBlob(keyblob); - short keyBlobStart = repository.getHeapReclaimIndex(); // Encode KeyCharacteristics at the end of heap just before data[CERTIFICATE] - // in the reserved space of MAX_KEY_CHARS_SIZE - short keyCharsLen = encodeKeyCharacteristics(keyCharsIndex, prevReclaimIndex, keyChars); - - // Adjust the keyblob buffer before KeyChars and reclaim the memory - short newKeyBlobStart = (short) (keyBlobStart + (MAX_KEY_CHARS_SIZE - keyCharsLen)); - Util.arrayCopyNonAtomic(buffer, keyBlobStart, buffer, newKeyBlobStart, keyBlobLen); - repository.reclaimMemory((short) (newKeyBlobStart - keyBlobStart)); - + encodeKeyCharacteristics(keyChars); + // and encode it to the end of the buffer before KEY_CHARACTERISTICS + encodeKeyBlob(keyblob); // Write Array header and ErrorCode before data[KEY_BLOB] short bufferStartOffset = repository.allocReclaimableMemory((short) 2); Util.setShort(buffer, bufferStartOffset, (short) 0x8400); @@ -779,11 +771,6 @@ private void processGetKeyCharacteristicsCmd(APDU apdu) { if (isKeyUpgradeRequired(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad)) { KMException.throwIt(KMError.KEY_REQUIRES_UPGRADE); } - // Remove custom tags from key characteristics - short teeParams = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); - if(teeParams != KMType.INVALID_VALUE) { - KMKeyParameters.cast(teeParams).deleteCustomTags(); - } // make response. short resp = KMArray.instance((short) 2); KMArray.cast(resp).add((short) 0, KMInteger.uint_16(KMError.OK)); @@ -816,23 +803,34 @@ private short createKeyBlobExp(short version) { short keyBlob = KMType.INVALID_VALUE; short byteBlobExp = KMByteBlob.exp(); short keyChar = KMKeyCharacteristics.exp(); + short keyParam = KMKeyParameters.exp(); switch(version) { case (short) 0: // Old KeyBlob has a maximum of 5 elements. 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());// 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); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_VERSION_OFFSET, KMInteger.exp()); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_SECRET, byteBlobExp); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_AUTH_TAG, byteBlobExp); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_NONCE, byteBlobExp); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_PARAMS, keyChar); + KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_CUSTOM_TAGS, keyParam); KMArray.cast(keyBlob).add(KMKeymasterApplet.KEY_BLOB_PUB_KEY, byteBlobExp); break; default: @@ -845,10 +843,10 @@ private static short createKeyBlobInstance(byte keyType) { short arrayLen = 0; switch (keyType) { case ASYM_KEY_TYPE: - arrayLen = ASYM_KEY_BLOB_SIZE_V1; + arrayLen = ASYM_KEY_BLOB_SIZE_V2; break; case SYM_KEY_TYPE: - arrayLen = SYM_KEY_BLOB_SIZE_V1; + arrayLen = SYM_KEY_BLOB_SIZE_V2; break; default: KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); @@ -1069,11 +1067,11 @@ private void processUpgradeKeyCmd(APDU apdu) { byte keyType = getKeyType(data[HW_PARAMETERS]); switch (keyType) { case ASYM_KEY_TYPE: - data[KEY_BLOB] = KMArray.instance(ASYM_KEY_BLOB_SIZE_V1); + data[KEY_BLOB] = KMArray.instance(ASYM_KEY_BLOB_SIZE_V2); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_PUB_KEY, data[PUB_KEY]); break; case SYM_KEY_TYPE: - data[KEY_BLOB] = KMArray.instance(SYM_KEY_BLOB_SIZE_V1); + data[KEY_BLOB] = KMArray.instance(SYM_KEY_BLOB_SIZE_V2); break; default: KMException.throwIt(KMError.UNSUPPORTED_ALGORITHM); @@ -1365,6 +1363,7 @@ private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyPara short privKey = data[SECRET]; short hwParams = data[HW_PARAMETERS]; short keyChars = data[KEY_CHARACTERISTICS]; + short customTags = data[CUSTOM_TAGS]; // Check if key requires upgrade for attestKeyBlob. The KeyBlob is parsed inside // isKeyUpgradeRequired function itself. if (isKeyUpgradeRequired(attKeyBlob, appId, appData, scratchPad)) { @@ -1412,6 +1411,7 @@ private KMAttestationCert makeAttestationCert(short attKeyBlob, short attKeyPara data[KEY_BLOB] = origBlob; data[HW_PARAMETERS] = hwParams; data[KEY_CHARACTERISTICS] = keyChars; + data[CUSTOM_TAGS] = customTags; data[SW_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getKeystoreEnforced(); data[TEE_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); data[SB_PARAMETERS] = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getStrongboxEnforced(); @@ -2844,7 +2844,7 @@ private void authorizeUserSecureIdAuthTimeout(KMOperationState op, byte[] scratc } authTimeoutTagPtr = - KMKeyParameters.findTag(KMType.ULONG_TAG, KMType.AUTH_TIMEOUT_MILLIS, data[HW_PARAMETERS]); + KMKeyParameters.findTag(KMType.ULONG_TAG, KMType.AUTH_TIMEOUT_MILLIS, data[CUSTOM_TAGS]); if (authTimeoutTagPtr == KMType.INVALID_VALUE) { KMException.throwIt(KMError.INVALID_KEY_BLOB); } @@ -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]); @@ -3506,20 +3503,6 @@ private void processGenerateKey(APDU apdu) { sendOutgoing(apdu, cert, data[CERTIFICATE], data[KEY_BLOB], data[KEY_CHARACTERISTICS]); } - private short generateAttestKeyCmd(APDU apdu) { - short params = KMKeyParameters.expAny(); - short blob = KMByteBlob.exp(); - // Array of expected arguments - short cmd = KMArray.instance((short) 6); - KMArray.cast(cmd).add((short) 0, blob); // key blob - KMArray.cast(cmd).add((short) 1, params); // keyparamters to be attested. - KMArray.cast(cmd).add((short) 2, blob); // attest key blob - KMArray.cast(cmd).add((short) 3, params); // attest key params - KMArray.cast(cmd).add((short) 4, blob); // attest issuer - KMArray.cast(cmd).add((short) 5, blob); // keyparams mac. - - return receiveIncoming(apdu, cmd); - } private short getApplicationId(short params) { short appId = KMKeyParameters.findTag(KMType.BYTES_TAG, KMType.APPLICATION_ID, params); @@ -3781,7 +3764,7 @@ protected static short getBootPatchLevel(byte[] scratchPad){ // KeyBlob's KeyCharacteristics. // 2. Re-create KeyBlob's KeyCharacteristics from HW_PARAMS to make sure we don't miss // anything which happens in these functions makeSbEnforced and makeTeeEnforced in - // the future. Like validations, addition of custom tags e.t.c. + // the future. Like validations. // 3. No need to create Keystore Enforced list here as it is not required to be included in // the KeyBlob's KeyCharacteristics. // 4. No need to create KeyCharacteristics as upgradeKey does not require to return any @@ -3823,6 +3806,8 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { data[HIDDEN_PARAMETERS] = KMKeyParameters.makeHidden(data[KEY_PARAMETERS], data[ROT], scratchPad); data[KEY_BLOB_VERSION_DATA_OFFSET] = KMInteger.uint_16(KEYBLOB_CURRENT_VERSION); + // create custom tags + data[CUSTOM_TAGS] = KMKeyParameters.makeCustomTags(data[HW_PARAMETERS], scratchPad); // make authorization data makeAuthData(KEYBLOB_CURRENT_VERSION, scratchPad); // encrypt the secret and cryptographically attach that to authorization data @@ -3832,6 +3817,7 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_AUTH_TAG, data[AUTH_TAG]); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_NONCE, data[NONCE]); KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_VERSION_OFFSET, data[KEY_BLOB_VERSION_DATA_OFFSET]); + KMArray.cast(data[KEY_BLOB]).add(KEY_BLOB_CUSTOM_TAGS, data[CUSTOM_TAGS]); short tempChar = KMKeyCharacteristics.instance(); short emptyParam = KMArray.instance((short) 0); @@ -3843,39 +3829,34 @@ private static void createEncryptedKeyBlob(byte[] scratchPad) { } // Encodes KeyCharacteristics at the end of the heap - // and return the length of encoded KeyChars. - private short encodeKeyCharacteristics(short startOffset, short prevReclaimIndex, short keyChars) { - // Remove custom tags from key characteristics - short teeParams = KMKeyCharacteristics.cast(data[KEY_CHARACTERISTICS]).getTeeEnforced(); - if(teeParams != KMType.INVALID_VALUE) { - KMKeyParameters.cast(teeParams).deleteCustomTags(); - } + private void encodeKeyCharacteristics(short keyChars) { byte[] buffer = repository.getHeap(); - short len = encoder.encode(keyChars, buffer, startOffset, prevReclaimIndex, MAX_KEY_CHARS_SIZE); + short prevReclaimIndex = repository.getHeapReclaimIndex(); + short ptr = repository.allocReclaimableMemory(MAX_KEY_CHARS_SIZE); + short len = encoder.encode(keyChars, buffer, ptr, prevReclaimIndex, MAX_KEY_CHARS_SIZE); // shift the encoded KeyCharacteristics data towards the right till the data[CERTIFICATE] offset. - Util.arrayCopyNonAtomic(buffer, startOffset, buffer, (short) (startOffset + (MAX_KEY_CHARS_SIZE - len)), len); - return len; + Util.arrayCopyNonAtomic(buffer, ptr, buffer, (short) (ptr + (MAX_KEY_CHARS_SIZE - len)), len); + // Reclaim the unused memory. + repository.reclaimMemory((short) (MAX_KEY_CHARS_SIZE - len)); } // Encodes KeyBlob at the end of the heap - // and returns the length of the encoded keyblob - private short encodeKeyBlob(short keyBlobPtr) { + private void encodeKeyBlob(short keyBlobPtr) { // allocate reclaimable memory. byte[] buffer = repository.getHeap(); short prevReclaimIndex = repository.getHeapReclaimIndex(); short top = repository.allocReclaimableMemory(MAX_KEYBLOB_SIZE); - short keyBlobLen = encoder.encode(keyBlobPtr, buffer, top, prevReclaimIndex, MAX_KEYBLOB_SIZE); + short keyBlob = encoder.encode(keyBlobPtr, buffer, top, prevReclaimIndex, MAX_KEYBLOB_SIZE); Util.arrayCopyNonAtomic(repository.getHeap(), top, repository.getHeap(), - (short) (top + MAX_KEYBLOB_SIZE - keyBlobLen), keyBlobLen); - short newTop = (short) (top + MAX_KEYBLOB_SIZE - keyBlobLen); - // Encode the KeyBlob array inside a ByteBlob. Get the length of - // the ByteBlob header. - short encodedBytesLength = encoder.getEncodedBytesLength(keyBlobLen); + (short) (top + MAX_KEYBLOB_SIZE - keyBlob), keyBlob); + short newTop = (short) (top + MAX_KEYBLOB_SIZE - keyBlob); + // Encode the KeyBlob array inside a ByteString. Get the length of + // the ByteString header. + short encodedBytesLength = encoder.getEncodedBytesLength(keyBlob); newTop -= encodedBytesLength; - encoder.encodeByteBlobHeader(keyBlobLen, buffer, newTop, encodedBytesLength); + encoder.encodeByteBlobHeader(keyBlob, buffer, newTop, encodedBytesLength); // Reclaim unused memory. repository.reclaimMemory((short) (newTop - top)); - return (short) (keyBlobLen + encodedBytesLength); } private short readKeyBlobVersion(short keyBlob) { @@ -3914,16 +3895,34 @@ private void readKeyBlobParams(short version, short parsedKeyBlob) { if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V0) { data[PUB_KEY] = KMArray.cast(parsedKeyBlob).get((short) 4); } + // Set the data[KEY_BLOB_VERSION_DATA_OFFSET] with integer value of 0 so + // that it will used at later point of time. + data[KEY_BLOB_VERSION_DATA_OFFSET] = KMInteger.uint_8((byte) 0); break; case (short) 1: + data[SECRET] = KMArray.cast(parsedKeyBlob).get((short) 0); + data[NONCE]= KMArray.cast(parsedKeyBlob).get((short) 1); + data[AUTH_TAG] = KMArray.cast(parsedKeyBlob).get((short) 2); + data[KEY_CHARACTERISTICS] = KMArray.cast(parsedKeyBlob).get((short) 3); + data[KEY_BLOB_VERSION_DATA_OFFSET] = KMArray.cast(parsedKeyBlob).get( + (short) 4); + data[CUSTOM_TAGS] = KMType.INVALID_VALUE; + data[PUB_KEY] = KMType.INVALID_VALUE; + if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V1) { + data[PUB_KEY] = KMArray.cast(parsedKeyBlob).get((short) 5); + } + break; + case (short) 2: data[SECRET] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_SECRET); data[NONCE]= KMArray.cast(parsedKeyBlob).get(KEY_BLOB_NONCE); data[AUTH_TAG] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_AUTH_TAG); data[KEY_CHARACTERISTICS] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_PARAMS); data[KEY_BLOB_VERSION_DATA_OFFSET] = KMArray.cast(parsedKeyBlob).get( KEY_BLOB_VERSION_OFFSET); + data[CUSTOM_TAGS] = KMArray.cast(parsedKeyBlob).get( + KEY_BLOB_CUSTOM_TAGS); data[PUB_KEY] = KMType.INVALID_VALUE; - if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V1) { + if (KMArray.cast(parsedKeyBlob).length() == ASYM_KEY_BLOB_SIZE_V2) { data[PUB_KEY] = KMArray.cast(parsedKeyBlob).get(KEY_BLOB_PUB_KEY); } break; @@ -3938,7 +3937,20 @@ private void decodeKeyBlob(short version, short keyBlob) { KMByteBlob.cast(keyBlob).getBuffer(), KMByteBlob.cast(keyBlob).getStartOff(), KMByteBlob.cast(keyBlob).length()); - short minArraySize = (version > 0) ? SYM_KEY_BLOB_SIZE_V1 : (short) 4; + short minArraySize = 0; + switch(version) { + case 0: + minArraySize = SYM_KEY_BLOB_SIZE_V0; + break; + case 1: + minArraySize = SYM_KEY_BLOB_SIZE_V1; + break; + case 2: + minArraySize = SYM_KEY_BLOB_SIZE_V2; + break; + default: + KMException.throwIt(KMError.INVALID_KEY_BLOB); + }; // KeyBlob size should not be less than the minimum KeyBlob size. if (KMArray.cast(parsedBlob).length() < minArraySize) { KMException.throwIt(KMError.INVALID_KEY_BLOB); @@ -3957,7 +3969,47 @@ private void processDecryptSecret(short version, short appId, short appData, byt makeAuthData(version, scratchPad); // Decrypt Secret and verify auth tag decryptSecret(scratchPad); - short keyBlobSecretOff = (version > 0) ? KEY_BLOB_SECRET : (short) 0; + short keyBlobSecretOff = 0; + switch(version) { + case 0: + // 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: + KMException.throwIt(KMError.INVALID_KEY_BLOB); + }; KMArray.cast(data[KEY_BLOB]).add(keyBlobSecretOff, data[SECRET]); } @@ -4062,13 +4114,14 @@ private static byte getKeyType(short hardwareParams) { } private static void makeAuthData(short version, byte[] scratchPad) { + // For KeyBlob V2: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS, CUSTOM_TAGS, VERSION and PUB_KEY. // For KeyBlob V1: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS, VERSION and PUB_KEY. // For KeyBlob V0: Auth Data includes HW_PARAMETERS, HIDDEN_PARAMETERS and PUB_KEY. // VERSION is included only for KeyBlobs having version >= 1. // PUB_KEY is included for only ASYMMETRIC KeyBlobs. short index = 0; short numParams = 0; - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 8, (byte) 0); + Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 10, (byte) 0); byte keyType = getKeyType(data[HW_PARAMETERS]); // Copy the relevant parameters in the scratchPad in the order // 1. HW_PARAMETERS @@ -4097,6 +4150,18 @@ private static void makeAuthData(short version, byte[] scratchPad) { Util.setShort(scratchPad, (short) 6, data[PUB_KEY]); } break; + case (short) 2: + numParams = 4; + Util.setShort(scratchPad, (short) 0, KMKeyParameters.cast(data[HW_PARAMETERS]).getVals()); + Util.setShort(scratchPad, (short) 2, KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals()); + Util.setShort(scratchPad, (short) 4, KMKeyParameters.cast(data[CUSTOM_TAGS]).getVals()); + Util.setShort(scratchPad, (short) 6, data[KEY_BLOB_VERSION_DATA_OFFSET]); + // For Asymmetric Keys include the PUB_KEY. + if (keyType == ASYM_KEY_TYPE) { + numParams = 5; + Util.setShort(scratchPad, (short) 8, data[PUB_KEY]); + } + break; default: KMException.throwIt(KMError.INVALID_KEY_BLOB); } @@ -4175,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(); diff --git a/Applet/src/com/android/javacard/keymaster/KMType.java b/Applet/src/com/android/javacard/keymaster/KMType.java index 95806ad3..26eda3d3 100644 --- a/Applet/src/com/android/javacard/keymaster/KMType.java +++ b/Applet/src/com/android/javacard/keymaster/KMType.java @@ -247,6 +247,8 @@ public abstract class KMType { public static final short NO_AUTH_REQUIRED = (short) 0x01F7; // Allow While On Body public static final short ALLOW_WHILE_ON_BODY = (short) 0x01FA; + // Max Boot Level + public static final short MAX_BOOT_LEVEL = (short) 0x03F2; // Trusted User Presence Required public static final short TRUSTED_USER_PRESENCE_REQUIRED = (short) 0x01FB; // Trusted Confirmation Required @@ -404,5 +406,4 @@ protected static short exp(byte type) { Util.setShort(heap, (short) (ptr + 1), INVALID_VALUE); return ptr; } - }