From 289ba686fe430b827ac47a72225a90272a868567 Mon Sep 17 00:00:00 2001 From: "avinash.hedage" Date: Thu, 23 Dec 2021 07:10:36 +0000 Subject: [PATCH] Trusted confirmation tag, boot loader only, early boot only and Computed HMAC key changes --- .../javacard/keymaster/KMAndroidSEApplet.java | 17 +- .../seprovider/KMAndroidSEProvider.java | 103 ++++++++-- .../seprovider/KMComputedHmacKey.java | 5 + .../javacard/seprovider/KMHmacKey.java | 8 +- .../javacard/seprovider/KMOperationImpl.java | 19 ++ .../javacard/seprovider/KMPoolManager.java | 42 +++- .../javacard/seprovider/KMSEProvider.java | 42 +++- .../android/javacard/keymaster/KMError.java | 1 + .../javacard/keymaster/KMKeyParameters.java | 10 +- .../javacard/keymaster/KMKeymasterApplet.java | 193 +++++++++++------- .../javacard/keymaster/KMOperationState.java | 40 ++-- .../javacard/keymaster/KMRepository.java | 27 +-- 12 files changed, 365 insertions(+), 142 deletions(-) create mode 100644 Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMComputedHmacKey.java diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java index 8da8b8ed..4505f8d7 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAndroidSEApplet.java @@ -47,6 +47,8 @@ public class KMAndroidSEApplet extends KMKeymasterApplet implements OnUpgradeLis INS_KEYMINT_PROVIDER_APDU_START + 6; private static final byte INS_PROVISION_ADDITIONAL_CERT_CHAIN_CMD = INS_KEYMINT_PROVIDER_APDU_START + 7; + private static final byte INS_SET_BOOT_ENDED_CMD = + INS_KEYMINT_PROVIDER_APDU_START + 8; private static final byte INS_KEYMINT_PROVIDER_APDU_END = 0x1F; public static final byte BOOT_KEY_MAX_SIZE = 32; @@ -100,6 +102,13 @@ public void process(APDU apdu) { case INS_SET_BOOT_PARAMS_CMD: processSetBootParamsCmd(apdu); break; + + case INS_SET_BOOT_ENDED_CMD: + //set the flag to mark boot ended + repository.setBootEndedStatus(true); + sendError(apdu, KMError.OK); + break; + default: super.process(apdu); break; @@ -308,7 +317,8 @@ private void processGetProvisionStatusCmd(APDU apdu) { private void processSetBootParamsCmd(APDU apdu) { short argsProto = KMArray.instance((short) 5); - + + byte[] scratchPad = apdu.getBuffer(); // Array of 4 expected arguments // Argument 0 Boot Patch level KMArray.cast(argsProto).add((short) 0, KMInteger.exp()); @@ -353,6 +363,11 @@ private void processSetBootParamsCmd(APDU apdu) { enumVal = KMEnum.cast(bootParam).getVal(); ((KMAndroidSEProvider) seProvider).setDeviceLocked(enumVal == KMType.DEVICE_LOCKED_TRUE); + + // Clear the Computed SharedHmac and Hmac nonce from persistent memory. + Util.arrayFillNonAtomic(scratchPad, (short) 0, KMRepository.COMPUTED_HMAC_KEY_SIZE, (byte) 0); + seProvider.createComputedHmacKey(scratchPad, (short) 0, KMRepository.COMPUTED_HMAC_KEY_SIZE); + super.reboot(); sendError(apdu, KMError.OK); } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java index aaf93834..30860f50 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMAndroidSEProvider.java @@ -65,6 +65,7 @@ public class KMAndroidSEProvider implements KMSEProvider { public static final short SHARED_SECRET_KEY_SIZE = 32; public static final byte POWER_RESET_FALSE = (byte) 0xAA; public static final byte POWER_RESET_TRUE = (byte) 0x00; + private static final short COMPUTED_HMAC_KEY_SIZE = 32; private static KeyAgreement keyAgreement; @@ -117,6 +118,7 @@ public class KMAndroidSEProvider implements KMSEProvider { private KMECDeviceUniqueKey testKey; private KMECDeviceUniqueKey deviceUniqueKey; private KMHmacKey preSharedKey; + private KMHmacKey computedHmacKey; private byte[] additionalCertChain; private byte[] bcc; private boolean isProvisionLocked; @@ -167,6 +169,8 @@ public KMAndroidSEProvider() { createAttestationKey(tmpArray, (short) 0, (short) 32); // Pre-shared secret key length is 32 bytes. createPresharedKey(tmpArray, (short) 0, (short) SHARED_SECRET_KEY_SIZE); + // Initialize the Computed Hmac Key object. + createComputedHmacKey(tmpArray, (short)0, (short) 32); } androidSEProvider = this; resetFlag = JCSystem.makeTransientByteArray((short) 1, @@ -593,13 +597,6 @@ public short hmacSign(HMACKey key, byte[] data, short dataStart, return hmacSignature.sign(data, dataStart, dataLength, mac, macStart); } - public boolean hmacVerify(HMACKey key, byte[] data, short dataStart, - short dataLength, byte[] mac, short macStart, short macLength) { - hmacSignature.init(key, Signature.MODE_VERIFY); - return hmacSignature.verify(data, dataStart, dataLength, mac, macStart, - macLength); - } - @Override public short hmacSign(byte[] keyBuf, short keyStart, short keyLength, byte[] data, short dataStart, short dataLength, byte[] mac, short macStart) { @@ -623,12 +620,12 @@ public short hmacKDF(KMMasterKey masterkey, byte[] data, short dataStart, } @Override - public boolean hmacVerify(byte[] keyBuf, short keyStart, short keyLength, - byte[] data, short dataStart, short dataLength, byte[] mac, - short macStart, short macLength) { - HMACKey key = createHMACKey(keyBuf, keyStart, keyLength); - return hmacVerify(key, data, dataStart, dataLength, mac, macStart, - macLength); + 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); } @Override @@ -739,7 +736,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); + poolMgr.getOperationImpl(purpose, cipherAlg, alg, padding, blockMode, macLength, false); ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, ivBuffer, ivStart, ivLength); return operation; } @@ -751,11 +748,23 @@ 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); + KMType.HMAC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, false); HMACKey key = createHMACKey(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) { + 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); + + ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); + return operation; + } @Override public KMOperation initSymmetricOperation(byte purpose, byte alg, @@ -781,12 +790,18 @@ public KMOperation initSymmetricOperation(byte purpose, byte alg, return opr; } + @Override + public KMOperation initTrustedConfirmationSymmetricOperation(KMComputedHmacKey computedHmacKey) { + KMHmacKey key = (KMHmacKey) computedHmacKey; + return createHmacSignerVerifier(KMType.VERIFY, KMType.SHA2_256, key.getKey(), true); + } + public KMOperation createRsaSigner(short digest, short padding, byte[] secret, short secretStart, short secretLength, byte[] modBuffer, short modOff, 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); + KMType.INVALID_VALUE, KMType.INVALID_VALUE, false); RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); key.setExponent(secret, secretStart, secretLength); key.setModulus(modBuffer, modOff, modLength); @@ -799,7 +814,7 @@ 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); + KMType.INVALID_VALUE, KMType.INVALID_VALUE, false); RSAPrivateKey key = (RSAPrivateKey) rsaKeyPair.getPrivate(); key.setExponent(secret, secretStart, secretLength); key.setModulus(modBuffer, modOff, modLength); @@ -814,7 +829,7 @@ public KMOperation createEcSigner(short digest, byte[] secret, key.setS(secret, secretStart, secretLength); KMOperation operation = poolMgr .getOperationImpl(KMType.SIGN, alg, KMType.EC, KMType.INVALID_VALUE, - KMType.INVALID_VALUE, KMType.INVALID_VALUE); + KMType.INVALID_VALUE, KMType.INVALID_VALUE, false); ((KMOperationImpl) operation).init(key, digest, null, (short) 0, (short) 0); return operation; } @@ -825,7 +840,7 @@ public KMOperation createKeyAgreement(byte[] secret, short secretStart, 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); + KMType.EC, KMType.INVALID_VALUE, KMType.INVALID_VALUE, KMType.INVALID_VALUE, false); ((KMOperationImpl) operation).init(key, KMType.INVALID_VALUE, null, (short) 0, (short) 0); return operation; } @@ -1001,6 +1016,20 @@ public KMPreSharedKey createPresharedKey(byte[] keyData, short offset, short len return (KMPreSharedKey) preSharedKey; } + @Override + public KMComputedHmacKey createComputedHmacKey(byte[] keyData, short offset, short length) { + if (length != COMPUTED_HMAC_KEY_SIZE) { + CryptoException.throwIt(CryptoException.ILLEGAL_VALUE); + } + if (computedHmacKey == null) { + HMACKey key = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short) (length * 8), + false); + computedHmacKey = new KMHmacKey(key); + } + computedHmacKey.setKey(keyData, offset, length); + return (KMComputedHmacKey) computedHmacKey; + } + @Override public KMMasterKey getMasterKey() { return (KMMasterKey) masterKey; @@ -1486,4 +1515,40 @@ public void setProvisionLocked(boolean locked) { public boolean isProvisionLocked() { return isProvisionLocked; } + + @Override + public short messageDigest256(byte[] inBuff, short inOffset, + short inLength, byte[] outBuff, short outOffset) { + MessageDigest.OneShot mDigest = null; + short len = 0; + try { + mDigest = MessageDigest.OneShot.open(MessageDigest.ALG_SHA_256); + len = mDigest.doFinal(inBuff, inOffset, inLength, outBuff, outOffset); + } finally { + if (mDigest != null) { + mDigest.close(); + mDigest = null; + } + } + return len; + } + + @Override + public KMComputedHmacKey getComputedHmacKey() { + return computedHmacKey; + } + + private byte mapPurpose(short purpose) { + switch (purpose) { + case KMType.ENCRYPT: + return Cipher.MODE_ENCRYPT; + case KMType.DECRYPT: + return Cipher.MODE_DECRYPT; + case KMType.SIGN: + return Signature.MODE_SIGN; + case KMType.VERIFY: + return Signature.MODE_VERIFY; + } + return -1; + } } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMComputedHmacKey.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMComputedHmacKey.java new file mode 100644 index 00000000..3b0aa405 --- /dev/null +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMComputedHmacKey.java @@ -0,0 +1,5 @@ +package com.android.javacard.seprovider; + + +public interface KMComputedHmacKey { +} diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java index 2eaeeeb9..a863bf88 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMHmacKey.java @@ -19,7 +19,7 @@ import javacard.security.HMACKey; -public class KMHmacKey implements KMPreSharedKey { +public class KMHmacKey implements KMPreSharedKey, KMComputedHmacKey { private HMACKey hmacKey; @@ -34,7 +34,11 @@ public void setKey(byte[] keyData, short kOff, short length) { public byte getKey(byte[] keyData, short kOff) { return hmacKey.getKey(keyData, kOff); } - + + public HMACKey getKey() { + return hmacKey; + } + public short getKeySizeBits() { return hmacKey.getSize(); } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java index 2c447fd4..baa8a0f9 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMOperationImpl.java @@ -35,6 +35,7 @@ public class KMOperationImpl implements KMOperation { private static final short PURPOSE_OFFSET = 0x02; private static final short BLOCK_MODE_OFFSET = 0x03; private static final short MAC_LENGTH_OFFSET = 0x04; + private final byte[] EMPTY = {}; //This will hold the length of the buffer stored inside the //Java Card after the GCM update operation. private static final short AES_GCM_UPDATE_LEN_OFFSET = 0x05; @@ -340,6 +341,24 @@ public boolean verify(byte[] inputDataBuf, short inputDataStart, @Override 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 ((parameters[PURPOSE_OFFSET] == KMType.SIGN || parameters[PURPOSE_OFFSET] == KMType.VERIFY) && + (((Signature) operationInst[0]).getAlgorithm() == Signature.ALG_HMAC_SHA_256)) { + Signature signer = (Signature) operationInst[0]; + try { + if (parameters[PURPOSE_OFFSET] == KMType.SIGN) { + signer.sign(EMPTY, (short) 0, (short) 0, EMPTY, (short) 0); + } else { + signer.verify(EMPTY, (short) 0, (short) 0, EMPTY, (short) 0, (short) 0); + } + } catch(Exception e) { + // Ignore. + } + } + } reset(); } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java index 1606ce4e..e3baf610 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMPoolManager.java @@ -26,6 +26,7 @@ public class KMPoolManager { public static final short MAX_OPERATION_INSTANCES = 4; + private static final short HMAC_MAX_OPERATION_INSTANCES = 8; // Cipher pool private Object[] cipherPool; // Signature pool @@ -34,6 +35,8 @@ public class KMPoolManager { private Object[] keyAgreementPool; // KMOperationImpl pool private Object[] operationPool; + // Hmac signer pool which is used to support TRUSTED_CONFIRMATION_REQUIRED tag. + private Object[] hmacSignOperationPool; final byte[] CIPHER_ALGS = { Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, @@ -70,11 +73,14 @@ public static KMPoolManager getInstance() { private KMPoolManager() { cipherPool = new Object[(short) (CIPHER_ALGS.length * 4)]; - signerPool = new Object[(short) (SIG_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)]; operationPool = new Object[4]; + hmacSignOperationPool = new Object[4]; /* Initialize pools */ initializeOperationPool(); + initializeHmacSignOperationPool(); initializeSignerPool(); initializeCipherPool(); initializeKeyAgreementPool(); @@ -88,6 +94,14 @@ private void initializeOperationPool() { } } + private void initializeHmacSignOperationPool() { + short index = 0; + while (index < MAX_OPERATION_INSTANCES) { + hmacSignOperationPool[index] = new KMOperationImpl(); + index++; + } + } + // Create a signature instance of each algorithm once. private void initializeSignerPool() { short index = 0; @@ -181,11 +195,17 @@ private Cipher getCipherInstance(byte alg) { * * @return instance of the available resource or null if no resource is available. */ - public KMOperation getResourceFromOperationPool() { + public KMOperation getResourceFromOperationPool(boolean isTrustedConfOpr) { short index = 0; KMOperationImpl impl; - while (index < operationPool.length) { - impl = (KMOperationImpl) operationPool[index]; + Object[] oprPool; + if(isTrustedConfOpr) { + oprPool = hmacSignOperationPool; + } else { + oprPool = operationPool; + } + while (index < oprPool.length) { + impl = (KMOperationImpl) oprPool[index]; // Mode is always set. so compare using mode value. if (impl.getPurpose() == KMType.INVALID_VALUE) { return impl; @@ -217,7 +237,8 @@ private byte getAlgorithm(short purpose, Object object) { private boolean isResourceBusy(Object obj) { short index = 0; while (index < MAX_OPERATION_INSTANCES) { - if (((KMOperationImpl) operationPool[index]).isResourceMatches(obj)) { + if (((KMOperationImpl) operationPool[index]).isResourceMatches(obj) + || ((KMOperationImpl) hmacSignOperationPool[index]).isResourceMatches(obj)) { return true; } index++; @@ -256,19 +277,23 @@ private void reserveOperation(KMOperation operation, short purpose, short strong public KMOperation getOperationImpl(short purpose, short alg, short strongboxAlgType, short padding, - short blockMode, short macLength) { + short blockMode, short macLength, boolean isTrustedConfOpr) { KMOperation operation; // Throw exception if no resource from operation pool is available. - if (null == (operation = getResourceFromOperationPool())) { + if (null == (operation = getResourceFromOperationPool(isTrustedConfOpr))) { KMException.throwIt(KMError.TOO_MANY_OPERATIONS); } // Get one of the pool instances (cipher / signer / keyAgreement) based on purpose. Object[] pool = getCryptoPoolInstance(purpose); short index = 0; short usageCount = 0; + short maxOperations = MAX_OPERATION_INSTANCES; + if (Signature.ALG_HMAC_SHA_256 == alg) { + maxOperations = HMAC_MAX_OPERATION_INSTANCES; + } while (index < pool.length) { - if (usageCount >= MAX_OPERATION_INSTANCES) { + if (usageCount >= maxOperations) { KMException.throwIt(KMError.TOO_MANY_OPERATIONS); } if (pool[index] == null) { @@ -298,6 +323,7 @@ public void powerReset() { short index = 0; while (index < operationPool.length) { ((KMOperationImpl) operationPool[index]).abort(); + ((KMOperationImpl) hmacSignOperationPool[index]).abort(); index++; } } diff --git a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java index 0c3051d1..18932ee5 100644 --- a/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java +++ b/Applet/AndroidSEProviderLib/src/com/android/javacard/seprovider/KMSEProvider.java @@ -63,6 +63,14 @@ void createAsymmetricKey( short pubModMaxLength, short[] lengths); + /** + * Initializes the trusted confirmation operation. + * + * @param computedHmacKey Instance of the computed Hmac key. + * @return instance of KMOperation. + */ + KMOperation initTrustedConfirmationSymmetricOperation(KMComputedHmacKey computedHmacKey); + /** * Verify that the imported key is valid. If the algorithm and/or keysize are not supported then * it should throw a CryptoException. @@ -301,9 +309,7 @@ short hmacKDF( * @return true if the signature matches. */ boolean hmacVerify( - byte[] keyBuf, - short keyStart, - short keyLength, + KMComputedHmacKey hmacKey, byte[] data, short dataStart, short dataLength, @@ -576,6 +582,16 @@ KMOperation initAsymmetricOperation( */ KMMasterKey createMasterKey(short keySizeBits); + /** + * This function creates an HMACKey and initializes the key with the provided input key data. + * + * @param keyData buffer containing the key data. + * @param offset start of the buffer. + * @param length length of the buffer. + * @return An instance of the KMComputedHmacKey. + */ + KMComputedHmacKey createComputedHmacKey(byte[] keyData, short offset, short length); + /** * Returns the master key. * @@ -697,6 +713,26 @@ KMDeviceUniqueKey createDeviceUniqueKey(boolean testMode, */ byte[] getBootCertificateChain(); + /** + * Returns the computed Hmac key. + * + * @return Instance of the computed hmac key. + */ + KMComputedHmacKey getComputedHmacKey(); + + /** + * This is a one-shot operation the does digest of the input mesage. + * + * @param inBuff input buffer to be digested. + * @param inOffset start offset of the input buffer. + * @param inLength length of the input buffer. + * @param outBuff is the output buffer that contains the digested data. + * @param outOffset start offset of the digested output buffer. + * @return length of the digested data. + */ + short messageDigest256(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, + short outOffset); + public boolean isProvisionLocked(); diff --git a/Applet/src/com/android/javacard/keymaster/KMError.java b/Applet/src/com/android/javacard/keymaster/KMError.java index 992d804a..52398824 100644 --- a/Applet/src/com/android/javacard/keymaster/KMError.java +++ b/Applet/src/com/android/javacard/keymaster/KMError.java @@ -71,6 +71,7 @@ public class KMError { public static final short CANNOT_ATTEST_IDS = 66; public static final short ROLLBACK_RESISTANCE_UNAVAILABLE = 67; + public static final short NO_USER_CONFIRMATION = 71; public static final short DEVICE_LOCKED = 72; public static final short EARLY_BOOT_ENDED = 73; public static final short ATTESTATION_KEYS_NOT_PROVISIONED =74; diff --git a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java index 7fd115ca..d4cbc323 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeyParameters.java @@ -134,9 +134,7 @@ public short findTag(short tagType, short tagKey) { public static boolean hasUnsupportedTags(short keyParamsPtr) { final short[] tagArr = { // Unsupported tags. - KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, KMType.BOOL_TAG, KMType.TRUSTED_USER_PRESENCE_REQUIRED, - KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY, KMType.UINT_TAG, KMType.MIN_SEC_BETWEEN_OPS }; byte index = 0; @@ -188,7 +186,9 @@ public static short makeSbEnforced(short keyParamsPtr, byte origin, KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, KMType.BOOL_TAG, KMType.RESET_SINCE_ID_ROTATION, KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, + KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, KMType.UINT_TAG, KMType.MAX_USES_PER_BOOT, + KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, }; byte index = 0; short tagInd; @@ -263,6 +263,8 @@ public static short makeSbEnforced(short keyParamsPtr, byte[] scratchPad) { KMType.BOOL_TAG, KMType.UNLOCKED_DEVICE_REQUIRED, KMType.BOOL_TAG, KMType.RESET_SINCE_ID_ROTATION, 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; @@ -328,7 +330,8 @@ public static short makeKeystoreEnforced(short keyParamsPtr, byte[] scratchPad) KMType.DATE_TAG, KMType.USAGE_EXPIRE_DATETIME, KMType.UINT_TAG, KMType.USERID, KMType.DATE_TAG, KMType.CREATION_DATETIME, - KMType.UINT_TAG, KMType.USAGE_COUNT_LIMIT + KMType.UINT_TAG, KMType.USAGE_COUNT_LIMIT, + KMType.BOOL_TAG, KMType.ALLOW_WHILE_ON_BODY }; byte index = 0; short tagInd; @@ -438,7 +441,6 @@ public static boolean isValidTag(short tagType, short tagKey) { KMType.BYTES_TAG, KMType.ASSOCIATED_DATA, KMType.BYTES_TAG, KMType.UNIQUE_ID, KMType.UINT_TAG, KMType.MAC_LENGTH, - KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY }; short index = 0; if (tagKey == KMType.INVALID_TAG) { diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 04c947ba..15ebae13 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -17,8 +17,10 @@ package com.android.javacard.keymaster; import com.android.javacard.seprovider.KMAttestationCert; +import com.android.javacard.seprovider.KMComputedHmacKey; import com.android.javacard.seprovider.KMDeviceUniqueKey; import com.android.javacard.seprovider.KMException; +import com.android.javacard.seprovider.KMHmacKey; import com.android.javacard.seprovider.KMSEProvider; import javacard.framework.APDU; import javacard.framework.Applet; @@ -28,6 +30,8 @@ import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.CryptoException; +import javacard.security.HMACKey; +import javacard.security.KeyBuilder; import javacardx.apdu.ExtendedLength; /** @@ -98,6 +102,13 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe 0x6E }; + // "confirmation token" + public static final byte[] confirmationToken = { + 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x6F, + 0x6B, + 0x65, 0x6E + }; + public static final short MAX_COSE_BUF_SIZE = (short) 1024; // Top 32 commands are reserved for provisioning. private static final byte KEYMINT_CMD_APDU_START = 0x20; @@ -181,6 +192,7 @@ public class KMKeymasterApplet extends Applet implements AppletEvent, ExtendedLe public static final byte PLAIN_SECRET = 33; public static final byte TEE_PARAMETERS = 34; public static final byte SB_PARAMETERS = 35; + public static final byte CONFIRMATION_TOKEN = 36; // Constant // AddRngEntropy @@ -494,7 +506,6 @@ public void process(APDU apdu) { resetWrappingKey(); sendError(apdu, mapCryptoErrorToKMError(e.getReason())); } catch (Exception e) { - sendError(apdu, KMError.GENERIC_UNKNOWN_ERROR); freeOperations(); resetWrappingKey(); sendError(apdu, KMError.GENERIC_UNKNOWN_ERROR); @@ -869,9 +880,9 @@ private void processComputeSharedHmacCmd(APDU apdu) { bufferIndex, scratchPad, (short) 0); - // persist the computed hmac key. - repository.initComputedHmac(scratchPad, (short) 0, keyLen); + // persist the computed hmac key. + seProvider.createComputedHmacKey(scratchPad, (short) 0, keyLen); // Generate sharingKey verification signature and store that in scratch pad. //tmpVariables[5] short signLen = @@ -961,6 +972,7 @@ private void processUpgradeKeyCmd(APDU apdu) { if (isKeyUpgradeRequired) { // copy origin data[ORIGIN] = KMEnumTag.getValue(KMType.ORIGIN, data[HW_PARAMETERS]); + makeKeyCharacteristics(scratchPad); // create new key blob with current os version etc. createEncryptedKeyBlob(scratchPad); } else { @@ -1673,7 +1685,7 @@ private void processAbortOperationCmd(APDU apdu) { } private short finishOperationCmd(APDU apdu){ - short cmd = KMArray.instance((short) 5); + short cmd = KMArray.instance((short) 6); KMArray.cast(cmd).add((short) 0, KMInteger.exp());//op handle KMArray.cast(cmd).add((short) 1, KMByteBlob.exp());// input data KMArray.cast(cmd).add((short) 2, KMByteBlob.exp()); // signature @@ -1681,6 +1693,7 @@ private short finishOperationCmd(APDU apdu){ KMArray.cast(cmd).add((short) 3, authToken); // auth token short verToken = KMVerificationToken.exp(); KMArray.cast(cmd).add((short) 4, verToken); // time stamp token + KMArray.cast(cmd).add((short) 5, KMByteBlob.exp()); //confirmation token return receiveIncoming(apdu, cmd); } @@ -1692,6 +1705,7 @@ private void processFinishOperationCmd(APDU apdu) { data[SIGNATURE] = KMArray.cast(cmd).get((short) 2); data[HW_TOKEN] = KMArray.cast(cmd).get((short) 3); data[VERIFICATION_TOKEN] = KMArray.cast(cmd).get((short) 4); + data[CONFIRMATION_TOKEN] = KMArray.cast(cmd).get((short) 5); // Check Operation Handle KMOperationState op = findOperation(data[OP_HANDLE]); if (op == null) { @@ -1701,6 +1715,7 @@ private void processFinishOperationCmd(APDU apdu) { authorizeUpdateFinishOperation(op, scratchPad); switch (op.getPurpose()) { case KMType.SIGN: + finishTrustedConfirmationOperation(op); case KMType.VERIFY: finishSigningVerifyingOperation(op, scratchPad); break; @@ -2041,11 +2056,9 @@ private boolean verifyVerificationTokenMacInBigEndian(short verToken, byte[] scr len += 4; // hmac the data ptr = KMVerificationToken.cast(verToken).getMac(); - short key = repository.getComputedHmacKey(); + return seProvider.hmacVerify( - KMByteBlob.cast(key).getBuffer(), - KMByteBlob.cast(key).getStartOff(), - KMByteBlob.cast(key).length(), + seProvider.getComputedHmacKey(), scratchPad, (short) 0, len, @@ -2107,6 +2120,9 @@ private void processUpdateOperationCmd(APDU apdu) { KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), KMByteBlob.cast(data[INPUT_DATA]).length()); + // update trusted confirmation operation + updateTrustedConfirmationOperation(op); + data[OUTPUT_DATA] = KMType.INVALID_VALUE; } else if (op.getPurpose() == KMType.ENCRYPT || op.getPurpose() == KMType.DECRYPT) { // Update for encrypt/decrypt using RSA will not be supported because to do this op state @@ -2255,7 +2271,6 @@ private void processBeginOperationCmd(APDU apdu) { } // Parse the encrypted blob and decrypt it. parseEncryptedKeyBlob(data[KEY_BLOB], data[APP_ID], data[APP_DATA], scratchPad); - KMTag.assertAbsence(data[SB_PARAMETERS],KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, KMError.EARLY_BOOT_ENDED); KMTag.assertPresence(data[SB_PARAMETERS],KMType.ENUM_TAG,KMType.ALGORITHM,KMError.UNSUPPORTED_ALGORITHM); short algorithm = KMEnumTag.getValue(KMType.ALGORITHM,data[SB_PARAMETERS]); // If Blob usage tag is present in key characteristics then it should be standalone. @@ -2286,6 +2301,7 @@ private void processBeginOperationCmd(APDU apdu) { authorizeAndBeginOperation(op, scratchPad); switch (op.getPurpose()) { case KMType.SIGN: + beginTrustedConfirmationOperation(op); case KMType.VERIFY: beginSignVerifyOperation(op); break; @@ -2605,7 +2621,13 @@ private void authorizeAndBeginOperation(KMOperationState op, byte[] scratchPad) KMTag.assertAbsence(data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, KMError.INVALID_KEY_BLOB); } - + + //Validate bootloader only + if (repository.getBootEndedStatus()) { + KMTag.assertAbsence(data[HW_PARAMETERS], KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, + KMError.INVALID_KEY_BLOB); + } + // Authorize Caller Nonce - if caller nonce absent in key char and nonce present in // key params then fail if it is not a Decrypt operation data[IV] = KMType.INVALID_VALUE; @@ -2741,6 +2763,22 @@ private void beginCipherOperation(KMOperationState op) { } } + private void beginTrustedConfirmationOperation(KMOperationState op) { + // Check for trusted confirmation - if required then set the signer in op state. + if (KMKeyParameters.findTag(KMType.BOOL_TAG, KMType.TRUSTED_CONFIRMATION_REQUIRED, + data[HW_PARAMETERS]) != KMType.INVALID_VALUE) { + + op.setTrustedConfirmationSigner( + seProvider.initTrustedConfirmationSymmetricOperation(seProvider.getComputedHmacKey())); + + op.getTrustedConfirmationSigner().update( + confirmationToken, + (short) 0, + (short) confirmationToken.length); + } + + } + private void beginSignVerifyOperation(KMOperationState op) { switch (op.getAlgorithm()) { case KMType.RSA: @@ -2949,11 +2987,9 @@ private boolean verifyHwTokenMacInBigEndian(short hwToken, byte[] scratchPad) { len += 8; ptr = KMHardwareAuthToken.cast(hwToken).getMac(); - short key = repository.getComputedHmacKey(); + return seProvider.hmacVerify( - KMByteBlob.cast(key).getBuffer(), - KMByteBlob.cast(key).getStartOff(), - KMByteBlob.cast(key).length(), + seProvider.getComputedHmacKey(), scratchPad, (short) 0, len, @@ -2992,11 +3028,9 @@ private boolean verifyHwTokenMacInLittleEndian(short hwToken, byte[] scratchPad) len += 8; ptr = KMHardwareAuthToken.cast(hwToken).getMac(); - short key = repository.getComputedHmacKey(); + return seProvider.hmacVerify( - KMByteBlob.cast(key).getBuffer(), - KMByteBlob.cast(key).getStartOff(), - KMByteBlob.cast(key).length(), + seProvider.getComputedHmacKey(), scratchPad, (short) 0, len, @@ -3054,8 +3088,7 @@ private void validateImportKey(short params, short keyFmt){ // As per specification, Early boot keys may not be imported at all, if Tag::EARLY_BOOT_ONLY is // provided to IKeyMintDevice::importKey KMTag.assertAbsence(params, KMType.BOOL_TAG, KMType.EARLY_BOOT_ONLY, KMError.EARLY_BOOT_ENDED); - // Importing Bootloader only keys not supported. - KMTag.assertAbsence(params, KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, KMError.INVALID_KEY_BLOB); + // Algorithm must be present KMTag.assertPresence(params, KMType.ENUM_TAG, KMType.ALGORITHM, KMError.INVALID_ARGUMENT); short alg = KMEnumTag.getValue(KMType.ALGORITHM, params); @@ -3409,17 +3442,17 @@ private void processInitStrongBoxCmd(APDU apdu) { } public void reboot() { - // Clear the Computed SharedHmac and Hmac nonce from persistent memory. - repository.clearComputedHmac(); repository.clearHmacNonce(); + //flag to maintain the boot state + repository.setBootEndedStatus(false); + //flag to maintain early boot ended state + repository.setEarlyBootEndedStatus(false); //Clear all the operation state. releaseAllOperations(); // Hmac is cleared, so generate a new Hmac nonce. initHmacNonceAndSeed(); // Clear all auth tags. repository.removeAllAuthTags(); - // clear early boot ended status. - repository.setEarlyBootEndedStatus(false); } protected void initSystemBootParams(short osVersion, @@ -3477,8 +3510,7 @@ private void processGenerateKey(APDU apdu) { data[CERTIFICATE] = KMArray.instance((short)0); //by default the cert is empty. // ROLLBACK_RESISTANCE not supported. KMTag.assertAbsence(data[KEY_PARAMETERS], KMType.BOOL_TAG,KMType.ROLLBACK_RESISTANCE, KMError.ROLLBACK_RESISTANCE_UNAVAILABLE); - // BOOTLOADER_ONLY keys not supported. - KMTag.assertAbsence(data[KEY_PARAMETERS], KMType.BOOL_TAG, KMType.BOOTLOADER_ONLY, KMError.INVALID_KEY_BLOB); + // As per specification Early boot keys may be created after early boot ended. // Algorithm must be present KMTag.assertPresence(data[KEY_PARAMETERS], KMType.ENUM_TAG, KMType.ALGORITHM, KMError.INVALID_ARGUMENT); @@ -4009,31 +4041,36 @@ private static void encryptSecret(byte[] scratchPad) { } private static void makeAuthData(byte[] scratchPad) { - short len = - addPtrToAAD(KMKeyParameters.cast(data[HW_PARAMETERS]).getVals(), scratchPad, (short) 0); - len += - addPtrToAAD( - KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals(), scratchPad, len); - short authData; + short arrayLen = 2; if (KMArray.cast(data[KEY_BLOB]).length() == 5) { - authData = KMArray.instance((short) (len + 1)); - } else { - authData = KMArray.instance(len); + arrayLen = 3; } - // convert scratch pad to KMArray + short params = KMArray.instance((short) arrayLen); + KMArray.cast(params).add((short) 0, KMKeyParameters.cast(data[HW_PARAMETERS]).getVals()); + // KMArray.cast(params).add((short) 1, KMKeyParameters.cast(data[SW_PARAMETERS]).getVals()); + KMArray.cast(params).add((short) 1, KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals()); + if (3 == arrayLen) { + KMArray.cast(params).add((short) 2, data[PUB_KEY]); + } + + short authIndex = repository.alloc(MAX_AUTH_DATA_SIZE); short index = 0; - short objPtr; - while (index < len) { - objPtr = Util.getShort(scratchPad, (short) (index * 2)); - KMArray.cast(authData).add(index, objPtr); + short len = 0; + short paramsLen = KMArray.cast(params).length(); + Util.arrayFillNonAtomic(repository.getHeap(), authIndex, (short) MAX_AUTH_DATA_SIZE, (byte) 0); + while (index < paramsLen) { + short tag = KMArray.cast(params).get(index); + len = encoder.encode(tag, repository.getHeap(), (short) (authIndex + 32)); + Util.arrayCopyNonAtomic(repository.getHeap(), (short) authIndex, repository.getHeap(), + (short) (authIndex + len + 32), (short) 32); + len = seProvider.messageDigest256(repository.getHeap(), + (short) (authIndex + 32), (short) (len + 32), repository.getHeap(), (short) authIndex); + if (len != 32) { + KMException.throwIt(KMError.UNKNOWN_ERROR); + } index++; } - //TODO change the code below - implicitly adds the pub key. - if (KMArray.cast(data[KEY_BLOB]).length() == 5) { - KMArray.cast(authData).add(index, data[PUB_KEY]); - } - data[AUTH_DATA] = repository.alloc(MAX_AUTH_DATA_SIZE); - len = encoder.encode(authData, repository.getHeap(), data[AUTH_DATA]); + data[AUTH_DATA] = authIndex; data[AUTH_DATA_LENGTH] = len; } @@ -4052,45 +4089,24 @@ private static short addPtrToAAD(short dataArrPtr, byte[] aadBuf, short offset) } private static short deriveKey(byte[] scratchPad) { - short hiddenParams = KMKeyParameters.cast(data[HIDDEN_PARAMETERS]).getVals(); - short derivationData = repository.alloc(DERIVE_KEY_INPUT_SIZE); - // generate derivation material from hidden parameters - short len = encoder.encode(hiddenParams, repository.getHeap(), derivationData); - if (DERIVE_KEY_INPUT_SIZE > len) { - short start = (short)(derivationData+len); - len = (short)(DERIVE_KEY_INPUT_SIZE - len); - // Copy KeyCharacteristics in the remaining space of DERIVE_KEY_INPUT_SIZE - // if the data[AUTH_DATA] length is less then DERIVE_KEY_INPUT_SIZE - len - // then add complete key characteristics. - if(data[AUTH_DATA_LENGTH] < len){ - len = data[AUTH_DATA_LENGTH]; - } - Util.arrayCopyNonAtomic(repository.getHeap(), data[AUTH_DATA], - repository.getHeap(), start, len); - } // KeyDerivation: - // 1. Do HMAC Sign, with below input parameters. - // Key - 128 bit master key - // Input data - HIDDEN_PARAMETERS + KeyCharacateristics - // - Truncate beyond 256 bytes. + // 1. Do HMAC Sign, Auth data. // 2. HMAC Sign generates an output of 32 bytes length. - // Consume only first 16 bytes as derived key. + // Consume only first 16 bytes as derived key. // Hmac sign. - short signLen = seProvider.hmacKDF( + short len = seProvider.hmacKDF( seProvider.getMasterKey(), repository.getHeap(), - derivationData, - DERIVE_KEY_INPUT_SIZE, + data[AUTH_DATA], + data[AUTH_DATA_LENGTH], scratchPad, (short) 0); - if (signLen < 16) { + if (len < 16) { KMException.throwIt(KMError.UNKNOWN_ERROR); } - signLen = 16; - // store the derived secret in data dictionary - data[DERIVED_KEY] = KMByteBlob.instance(scratchPad, (short)0, signLen); - //TODO do we need to return this len? - return signLen; + len = 16; + data[DERIVED_KEY] = KMByteBlob.instance(scratchPad, (short)0, len); + return len; } public static void sendError(APDU apdu, short err) { @@ -4341,4 +4357,29 @@ public static short generateBcc(boolean testMode, byte[] scratchPad) { KMArray.cast(bcc).add((short) 1, coseSign1); return bcc; } + + private void updateTrustedConfirmationOperation(KMOperationState op) { + if (op.isTrustedConfirmationRequired()) { + op.getTrustedConfirmationSigner().update(KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), + KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), KMByteBlob.cast(data[INPUT_DATA]).length()); + } + } + + private void finishTrustedConfirmationOperation(KMOperationState op) { + // Perform trusted confirmation if required + if (op.isTrustedConfirmationRequired()) { + if (0 == KMByteBlob.cast(data[CONFIRMATION_TOKEN]).length()) { + KMException.throwIt(KMError.NO_USER_CONFIRMATION); + } + + boolean verified = op.getTrustedConfirmationSigner().verify(KMByteBlob.cast(data[INPUT_DATA]).getBuffer(), + KMByteBlob.cast(data[INPUT_DATA]).getStartOff(), KMByteBlob.cast(data[INPUT_DATA]).length(), + KMByteBlob.cast(data[CONFIRMATION_TOKEN]).getBuffer(), + KMByteBlob.cast(data[CONFIRMATION_TOKEN]).getStartOff(), + KMByteBlob.cast(data[CONFIRMATION_TOKEN]).length()); + if (!verified) { + KMException.throwIt(KMError.NO_USER_CONFIRMATION); + } + } + } } diff --git a/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/src/com/android/javacard/keymaster/KMOperationState.java index 99715232..83370b8e 100644 --- a/Applet/src/com/android/javacard/keymaster/KMOperationState.java +++ b/Applet/src/com/android/javacard/keymaster/KMOperationState.java @@ -48,6 +48,8 @@ public class KMOperationState { // First two bytes are reserved to store number of secure ids. So total 42 bytes. public static final byte USER_SECURE_IDS_SIZE = 42; + private static final byte OPERATION = 0; + private static final byte HMAC_SIGNER_OPERATION = 1; // Flag masks private static final short AUTH_PER_OP_REQD = 1; private static final short SECURE_USER_ID_REQD = 2; @@ -61,14 +63,14 @@ public class KMOperationState { private byte[] authTime; private byte[] userSecureIds; private short[] data; - private Object[] operation; + private Object[] operations; public KMOperationState() { opHandle = JCSystem.makeTransientByteArray(OPERATION_HANDLE_SIZE, JCSystem.CLEAR_ON_RESET); authTime = JCSystem.makeTransientByteArray(AUTH_TIME_SIZE, JCSystem.CLEAR_ON_RESET); data = JCSystem.makeTransientShortArray(DATA_SIZE, JCSystem.CLEAR_ON_RESET); - operation = JCSystem.makeTransientObjectArray((short) 1, JCSystem.CLEAR_ON_RESET); + operations = JCSystem.makeTransientObjectArray((short) 2, JCSystem.CLEAR_ON_RESET); userSecureIds = JCSystem.makeTransientByteArray(USER_SECURE_IDS_SIZE, JCSystem.CLEAR_ON_RESET); reset(); } @@ -81,16 +83,18 @@ public void reset() { } Util.arrayFillNonAtomic(opHandle, (short) 0, OPERATION_HANDLE_SIZE, (byte) 0); Util.arrayFillNonAtomic(authTime, (short) 0, AUTH_TIME_SIZE, (byte) 0); - - if (null != operation[0]) { - ((KMOperation) operation[0]).abort(); - } - - operation[0] = null; + + if(null != operations[OPERATION]) + ((KMOperation)operations[OPERATION]).abort(); + operations[OPERATION] = null; + + if(null != operations[HMAC_SIGNER_OPERATION]) + ((KMOperation)operations[HMAC_SIGNER_OPERATION]).abort(); + operations[HMAC_SIGNER_OPERATION] = null; } - public short compare(byte[] handle, short start, short len) { - return Util.arrayCompare(handle, start, opHandle, (short) 0, (short) opHandle.length); + public short compare(byte[] handle, short start, short len){ + return Util.arrayCompare(handle, start, opHandle, (short)0, (short)opHandle.length); } public void setKeySize(short keySize) { @@ -118,11 +122,11 @@ public void setPurpose(short purpose) { } public void setOperation(KMOperation op) { - operation[0] = op; + operations[OPERATION] = op; } public KMOperation getOperation() { - return (KMOperation) operation[0]; + return (KMOperation) operations[OPERATION]; } public boolean isAuthPerOperationReqd() { @@ -312,4 +316,16 @@ public byte getBufferingMode() { } return KMType.BUF_NONE; } + + public void setTrustedConfirmationSigner(KMOperation hmacSignerOp) { + operations[HMAC_SIGNER_OPERATION] = hmacSignerOp; + } + + public KMOperation getTrustedConfirmationSigner() { + return (KMOperation)operations[HMAC_SIGNER_OPERATION]; + } + + public boolean isTrustedConfirmationRequired() { + return operations[HMAC_SIGNER_OPERATION] != null; + } } diff --git a/Applet/src/com/android/javacard/keymaster/KMRepository.java b/Applet/src/com/android/javacard/keymaster/KMRepository.java index b4158b9c..03791210 100644 --- a/Applet/src/com/android/javacard/keymaster/KMRepository.java +++ b/Applet/src/com/android/javacard/keymaster/KMRepository.java @@ -53,9 +53,9 @@ public class KMRepository implements KMUpgradable { public static final byte DEVICE_LOCKED_PASSWORD_ONLY = 7; // Total 8 auth tags, so the next offset is AUTH_TAG_1 + 8 public static final byte AUTH_TAG_1 = 8; + public static final byte BOOT_ENDED_FLAG = 15; public static final byte EARLY_BOOT_ENDED_FLAG = 16; - - + // Data Item sizes public static final short HMAC_SEED_NONCE_SIZE = 32; public static final short COMPUTED_HMAC_KEY_SIZE = 32; @@ -96,13 +96,6 @@ public KMRepository(boolean isUpgrading) { repository = this; } - public void initComputedHmac(byte[] key, short start, short len) { - if (len != COMPUTED_HMAC_KEY_SIZE) { - KMException.throwIt(KMError.INVALID_INPUT_LENGTH); - } - writeDataEntry(COMPUTED_HMAC_KEY, key, start, len); - } - public void initHmacNonce(byte[] nonce, short offset, short len) { if (len != HMAC_SEED_NONCE_SIZE) { KMException.throwIt(KMError.INVALID_INPUT_LENGTH); @@ -114,10 +107,6 @@ public void clearHmacNonce() { clearDataEntry(HMAC_NONCE); } - public void clearComputedHmac() { - clearDataEntry(COMPUTED_HMAC_KEY); - } - public void onUninstall() { // Javacard Runtime environment cleans up the data. @@ -253,10 +242,6 @@ public short getHmacNonce() { return readData(HMAC_NONCE); } - public short getComputedHmacKey() { - return readData(COMPUTED_HMAC_KEY); - } - public short readData(short id) { short len = dataLength(id); if (len != 0) { @@ -319,6 +304,10 @@ public boolean getEarlyBootEndedStatus() { return readBoolean(EARLY_BOOT_ENDED_FLAG); } + public boolean getBootEndedStatus() { + return readBoolean(BOOT_ENDED_FLAG); + } + public short getDeviceTimeStamp() { short blob = readData(DEVICE_LOCKED_TIME); if (blob != KMType.INVALID_VALUE) { @@ -371,6 +360,10 @@ public void setDeviceLockTimestamp(byte[] buf, short start, short len) { public void setEarlyBootEndedStatus(boolean flag) { writeBoolean(EARLY_BOOT_ENDED_FLAG, flag); } + + public void setBootEndedStatus(boolean flag) { + writeBoolean(BOOT_ENDED_FLAG, flag); + } public void clearDeviceLockTimeStamp() { clearDataEntry(DEVICE_LOCKED_TIME);