From 00698c83c6cd57fd5f23eacd0a4b5716ba311d5e Mon Sep 17 00:00:00 2001 From: Eran Messeri Date: Thu, 20 Apr 2023 18:09:01 +0100 Subject: [PATCH] Do not add the MGF Digest tag for upgraded keys If a key does not have the MGF_DIGEST tag in its key characteristics, do not include the MGF_DIGEST tag for it (even if the algorithm string specifies it). This fixes an issue with keys that were generated on Android 13, where the MGF_DIGEST tag was not propagated from the SPI layer. Such keys will not have the MGF_DIGEST tag and so it will not be added by the SPI layer even if the algorithm string specifies it. This maintains Android 13's (incorrect) behaviour of ignoring the MGF Digest specification, but is necessary to use those keys (otherwise KeyMint will error out on begin() due to an incompatible MGF digest specification). Bug: 278157584 Test: atest CtsKeystoreWycheproofTestCases:com.google.security.wycheproof.RsaOaepTest Merged-In: I0f1fa7983f9c771bec3196c6a617eb7044ac2e79 Change-Id: I6a4c15ca04aa78c2191d47394811ba9338ee7f0b --- .../AndroidKeyStoreCipherSpiBase.java | 42 +++++++++++++++---- .../AndroidKeyStoreRSACipherSpi.java | 28 ++++++++++--- 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java index 7571e44a7713d..d129891872811 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java @@ -24,6 +24,7 @@ import android.security.KeyStoreException; import android.security.KeyStoreOperation; import android.security.keymaster.KeymasterDefs; import android.security.keystore.KeyStoreCryptoOperation; +import android.system.keystore2.Authorization; import libcore.util.EmptyArray; @@ -119,6 +120,14 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor mCipher = null; } + private Authorization[] getKeyCharacteristics(Key key) { + if (!(key instanceof AndroidKeyStoreKey)) { + return new Authorization[] {}; + } + + return ((AndroidKeyStoreKey) key).getAuthorizations(); + } + @Override protected final void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { @@ -173,7 +182,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor init(opmode, key, random); initAlgorithmSpecificParameters(); try { - ensureKeystoreOperationInitialized(); + ensureKeystoreOperationInitialized(getKeyCharacteristics(key)); } catch (InvalidAlgorithmParameterException e) { throw new InvalidKeyException(e); } @@ -206,7 +215,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor try { init(opmode, key, random); initAlgorithmSpecificParameters(params); - ensureKeystoreOperationInitialized(); + ensureKeystoreOperationInitialized(getKeyCharacteristics(key)); success = true; } finally { if (!success) { @@ -236,7 +245,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor try { init(opmode, key, random); initAlgorithmSpecificParameters(params); - ensureKeystoreOperationInitialized(); + ensureKeystoreOperationInitialized(getKeyCharacteristics(key)); success = true; } finally { if (!success) { @@ -310,7 +319,8 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor mCachedException = null; } - private void ensureKeystoreOperationInitialized() throws InvalidKeyException, + private void ensureKeystoreOperationInitialized(Authorization[] keyCharacteristics) + throws InvalidKeyException, InvalidAlgorithmParameterException { if (mMainDataStreamer != null) { return; @@ -323,7 +333,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor } List parameters = new ArrayList<>(); - addAlgorithmSpecificParametersToBegin(parameters); + addAlgorithmSpecificParametersToBegin(parameters, keyCharacteristics); int purpose; if (mKeymasterPurposeOverride != -1) { @@ -404,7 +414,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor return null; } try { - ensureKeystoreOperationInitialized(); + ensureKeystoreOperationInitialized(getKeyCharacteristics(mKey)); } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { mCachedException = e; return null; @@ -520,7 +530,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor } try { - ensureKeystoreOperationInitialized(); + ensureKeystoreOperationInitialized(getKeyCharacteristics(mKey)); } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { mCachedException = e; return; @@ -597,7 +607,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor } try { - ensureKeystoreOperationInitialized(); + ensureKeystoreOperationInitialized(getKeyCharacteristics(mKey)); } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e); } @@ -1011,6 +1021,22 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor protected abstract void addAlgorithmSpecificParametersToBegin( @NonNull List parameters); + /** + * Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation, + * including the key characteristics. This is useful in case the parameters to {@code begin} + * depend on how the key was generated. + * The default implementation provided here simply ignores these key characteristics because + * they are not be needed for most engines. + * + * @param parameters keystore/keymaster arguments to be populated with algorithm-specific + * parameters. + * @param keyCharacteristics The key's characteristics. + */ + protected void addAlgorithmSpecificParametersToBegin( + @NonNull List parameters, Authorization[] keyCharacteristics) { + addAlgorithmSpecificParametersToBegin(parameters); + } + /** * Invoked to obtain algorithm-specific parameters from the result of the KeyStore's * {@code begin} operation. diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java index e9b66aafc2621..3bb2564807b64 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java @@ -288,16 +288,34 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase } } + private static boolean isMgfDigestTagPresentInKeyProperties( + Authorization[] keyCharacteristics) { + for (Authorization authorization : keyCharacteristics) { + if (authorization.keyParameter.tag == KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST) { + return true; + } + } + + return false; + } + @Override protected final void addAlgorithmSpecificParametersToBegin( - @NonNull List parameters) { - super.addAlgorithmSpecificParametersToBegin(parameters); + @NonNull List parameters, Authorization[] keyCharacteristics) { + super.addAlgorithmSpecificParametersToBegin(parameters, keyCharacteristics); parameters.add(KeyStore2ParameterUtils.makeEnum( KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest )); - parameters.add(KeyStore2ParameterUtils.makeEnum( - KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, mKeymasterMgf1Digest - )); + // Only add the KM_TAG_RSA_OAEP_MGF_DIGEST tag to begin() if the MGF Digest is + // present in the key properties. Keys generated prior to Android 14 did not have + // this tag (Keystore didn't add it) so specifying any MGF digest tag would cause + // a begin() operation (on an Android 14 device) to fail (with a key that was generated + // on Android 13 or below). + if (isMgfDigestTagPresentInKeyProperties(keyCharacteristics)) { + parameters.add(KeyStore2ParameterUtils.makeEnum( + KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, mKeymasterMgf1Digest + )); + } } @Override