From e4928a2912297751108c7045ce3343ec63edcc01 Mon Sep 17 00:00:00 2001 From: Alex Klyubin Date: Tue, 21 Jul 2015 13:38:48 -0700 Subject: Keymaster digest/padding NONE no longer means ANY. This adjusts the public API documentation to no longer say that digest/padding NONE means any digest/padding. This also changes the implementation of legacy key generation and import to explicitly list which digests/paddings the generated/imported key is authorized for. Previously, such keys were simply authorized for digest NONE and padding NONE. Bug: 22556114 Change-Id: Id02d9450a07de16ccb795b76b6de0006dd49dcca --- .../AndroidKeyStoreKeyPairGeneratorSpi.java | 66 ++++++++++------------ .../security/keystore/AndroidKeyStoreSpi.java | 33 ++++++++--- .../security/keystore/KeyGenParameterSpec.java | 12 ++-- .../android/security/keystore/KeyProperties.java | 6 -- .../android/security/keystore/KeyProtection.java | 3 +- 5 files changed, 65 insertions(+), 55 deletions(-) (limited to 'keystore') diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java index 6b36a58..79095f4 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -63,7 +63,6 @@ import java.security.spec.ECGenParameterSpec; import java.security.spec.RSAKeyGenParameterSpec; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -215,7 +214,14 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY); // Authorized to be used with any digest (including no digest). - specBuilder.setDigests(KeyProperties.DIGEST_NONE); + // MD5 was never offered for Android Keystore for ECDSA. + specBuilder.setDigests( + KeyProperties.DIGEST_NONE, + KeyProperties.DIGEST_SHA1, + KeyProperties.DIGEST_SHA224, + KeyProperties.DIGEST_SHA256, + KeyProperties.DIGEST_SHA384, + KeyProperties.DIGEST_SHA512); break; case KeymasterDefs.KM_ALGORITHM_RSA: specBuilder = new KeyGenParameterSpec.Builder( @@ -225,11 +231,23 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato | KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY); // Authorized to be used with any digest (including no digest). - specBuilder.setDigests(KeyProperties.DIGEST_NONE); + specBuilder.setDigests( + KeyProperties.DIGEST_NONE, + KeyProperties.DIGEST_MD5, + KeyProperties.DIGEST_SHA1, + KeyProperties.DIGEST_SHA224, + KeyProperties.DIGEST_SHA256, + KeyProperties.DIGEST_SHA384, + KeyProperties.DIGEST_SHA512); // Authorized to be used with any encryption and signature padding - // scheme (including no padding). + // schemes (including no padding). specBuilder.setEncryptionPaddings( - KeyProperties.ENCRYPTION_PADDING_NONE); + KeyProperties.ENCRYPTION_PADDING_NONE, + KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1, + KeyProperties.ENCRYPTION_PADDING_RSA_OAEP); + specBuilder.setSignaturePaddings( + KeyProperties.SIGNATURE_PADDING_RSA_PKCS1, + KeyProperties.SIGNATURE_PADDING_RSA_PSS); // Disable randomized encryption requirement to support encryption // padding NONE above. specBuilder.setRandomizedEncryptionRequired(false); @@ -724,27 +742,11 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs // to be authorized for PKCS#1 padding or padding NONE which means any padding. - boolean pkcs1SignaturePaddingSupported = false; - for (int keymasterPadding : KeyProperties.SignaturePadding.allToKeymaster( - spec.getSignaturePaddings())) { - if ((keymasterPadding == KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN) - || (keymasterPadding == KeymasterDefs.KM_PAD_NONE)) { - pkcs1SignaturePaddingSupported = true; - break; - } - } - if (!pkcs1SignaturePaddingSupported) { - // Keymaster doesn't distinguish between encryption padding NONE and signature - // padding NONE. In the Android Keystore API only encryption padding NONE is - // exposed. - for (int keymasterPadding : KeyProperties.EncryptionPadding.allToKeymaster( - spec.getEncryptionPaddings())) { - if (keymasterPadding == KeymasterDefs.KM_PAD_NONE) { - pkcs1SignaturePaddingSupported = true; - break; - } - } - } + boolean pkcs1SignaturePaddingSupported = + com.android.internal.util.ArrayUtils.contains( + KeyProperties.SignaturePadding.allToKeymaster( + spec.getSignaturePaddings()), + KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN); if (!pkcs1SignaturePaddingSupported) { // Key not authorized for PKCS#1 signature padding -- can't sign return null; @@ -803,14 +805,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato : KeyProperties.Digest.allToKeymaster(supportedSignatureDigests)) { supportedKeymasterSignatureDigests.add(keymasterDigest); } - if (authorizedKeymasterKeyDigests.contains(KeymasterDefs.KM_DIGEST_NONE)) { - // Key is authorized to be used with any digest - return supportedKeymasterSignatureDigests; - } else { - // Key is authorized to be used only with specific digests. - Set result = new HashSet(supportedKeymasterSignatureDigests); - result.retainAll(authorizedKeymasterKeyDigests); - return result; - } + Set result = new HashSet(supportedKeymasterSignatureDigests); + result.retainAll(authorizedKeymasterKeyDigests); + return result; } } diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java index 915d86f..d300a92 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java @@ -292,7 +292,14 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { new KeyProtection.Builder( KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY); // Authorized to be used with any digest (including no digest). - specBuilder.setDigests(KeyProperties.DIGEST_NONE); + // MD5 was never offered for Android Keystore for ECDSA. + specBuilder.setDigests( + KeyProperties.DIGEST_NONE, + KeyProperties.DIGEST_SHA1, + KeyProperties.DIGEST_SHA224, + KeyProperties.DIGEST_SHA256, + KeyProperties.DIGEST_SHA384, + KeyProperties.DIGEST_SHA512); } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { specBuilder = new KeyProtection.Builder( @@ -301,13 +308,25 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { | KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY); // Authorized to be used with any digest (including no digest). - specBuilder.setDigests(KeyProperties.DIGEST_NONE); - // Authorized to be used with any encryption and signature padding scheme (including no - // padding). + specBuilder.setDigests( + KeyProperties.DIGEST_NONE, + KeyProperties.DIGEST_MD5, + KeyProperties.DIGEST_SHA1, + KeyProperties.DIGEST_SHA224, + KeyProperties.DIGEST_SHA256, + KeyProperties.DIGEST_SHA384, + KeyProperties.DIGEST_SHA512); + // Authorized to be used with any encryption and signature padding + // schemes (including no padding). specBuilder.setEncryptionPaddings( - KeyProperties.ENCRYPTION_PADDING_NONE); - // Disable randomized encryption requirement to support encryption padding NONE - // above. + KeyProperties.ENCRYPTION_PADDING_NONE, + KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1, + KeyProperties.ENCRYPTION_PADDING_RSA_OAEP); + specBuilder.setSignaturePaddings( + KeyProperties.SIGNATURE_PADDING_RSA_PKCS1, + KeyProperties.SIGNATURE_PADDING_RSA_PSS); + // Disable randomized encryption requirement to support encryption + // padding NONE above. specBuilder.setRandomizedEncryptionRequired(false); } else { throw new KeyStoreException("Unsupported key algorithm: " + keyAlgorithm); diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index faaa1a6..7605231 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -65,17 +65,16 @@ import javax.security.auth.x500.X500Principal; * *

NOTE: If a private key is not authorized to sign the self-signed certificate, then the * certificate will be created with an invalid signature which will not verify. Such a certificate - * is still useful because it provides access to the public key. To generate a valid - * signature for the certificate the key needs to be authorized for all of the following: + * is still useful because it provides access to the public key. To generate a valid signature for + * the certificate the key needs to be authorized for all of the following: *

    *
  • {@link KeyProperties#PURPOSE_SIGN},
  • *
  • operation without requiring the user to be authenticated (see * {@link Builder#setUserAuthenticationRequired(boolean)}),
  • *
  • signing/origination at this moment in time (see {@link Builder#setKeyValidityStart(Date)} * and {@link Builder#setKeyValidityForOriginationEnd(Date)}),
  • - *
  • suitable digest or {@link KeyProperties#DIGEST_NONE},
  • - *
  • (RSA keys only) padding scheme {@link KeyProperties#SIGNATURE_PADDING_RSA_PKCS1} or - * {@link KeyProperties#ENCRYPTION_PADDING_NONE}.
  • + *
  • suitable digest,
  • + *
  • (RSA keys only) padding scheme {@link KeyProperties#SIGNATURE_PADDING_RSA_PKCS1}.
  • *
* *

NOTE: The key material of the generated symmetric and private keys is not accessible. The key @@ -668,7 +667,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { * *

For RSA private keys used by TLS/SSL servers to authenticate themselves to clients it * is usually necessary to authorize the use of no/any padding - * ({@link KeyProperties#ENCRYPTION_PADDING_NONE}). This is because RSA decryption is + * ({@link KeyProperties#ENCRYPTION_PADDING_NONE}) and/or PKCS#1 encryption padding + * ({@link KeyProperties#ENCRYPTION_PADDING_RSA_PKCS1}). This is because RSA decryption is * required by some cipher suites, and some stacks request decryption using no padding * whereas others request PKCS#1 padding. * diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java index 2b49297..d6b1cf1 100644 --- a/keystore/java/android/security/keystore/KeyProperties.java +++ b/keystore/java/android/security/keystore/KeyProperties.java @@ -364,9 +364,6 @@ public abstract class KeyProperties { /** * No encryption padding. - * - *

NOTE: If a key is authorized to be used with no padding, then it can be used with - * any padding scheme, both for encryption and signing. */ public static final String ENCRYPTION_PADDING_NONE = "NoPadding"; @@ -513,9 +510,6 @@ public abstract class KeyProperties { /** * No digest: sign/authenticate the raw message. - * - *

NOTE: If a key is authorized to be used with no digest, then it can be used with - * any digest. */ public static final String DIGEST_NONE = "NONE"; diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index ec0ef24..b71dc82 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -386,7 +386,8 @@ public final class KeyProtection implements ProtectionParameter { * *

For RSA private keys used by TLS/SSL servers to authenticate themselves to clients it * is usually necessary to authorize the use of no/any padding - * ({@link KeyProperties#ENCRYPTION_PADDING_NONE}). This is because RSA decryption is + * ({@link KeyProperties#ENCRYPTION_PADDING_NONE}) and/or PKCS#1 encryption padding + * ({@link KeyProperties#ENCRYPTION_PADDING_RSA_PKCS1}). This is because RSA decryption is * required by some cipher suites, and some stacks request decryption using no padding * whereas others request PKCS#1 padding. * -- cgit v1.1