diff options
Diffstat (limited to 'keystore')
6 files changed, 65 insertions, 145 deletions
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<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests); - result.retainAll(authorizedKeymasterKeyDigests); - return result; - } + Set<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests); + result.retainAll(authorizedKeymasterKeyDigests); + return result; } } diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java index 94ed8b4..56cc44c 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java @@ -18,16 +18,11 @@ package android.security.keystore; import android.annotation.NonNull; import android.annotation.Nullable; -import android.os.IBinder; import android.security.KeyStore; -import android.security.KeyStoreException; import android.security.keymaster.KeyCharacteristics; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; -import libcore.util.EmptyArray; - -import java.io.ByteArrayOutputStream; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -103,91 +98,6 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase protected final int getAdditionalEntropyAmountForFinish() { return 0; } - - @Override - @NonNull - protected KeyStoreCryptoOperationStreamer createMainDataStreamer( - KeyStore keyStore, IBinder operationToken) { - if (isEncrypting()) { - // KeyStore's RSA encryption without padding expects the input to be of the same - // length as the modulus. We thus have to buffer all input to pad it with leading - // zeros. - return new ZeroPaddingEncryptionStreamer( - super.createMainDataStreamer(keyStore, operationToken), - getModulusSizeBytes()); - } else { - return super.createMainDataStreamer(keyStore, operationToken); - } - } - - /** - * Streamer which buffers all plaintext input, then pads it with leading zeros to match - * modulus size, and then sends it into KeyStore to obtain ciphertext. - */ - private static class ZeroPaddingEncryptionStreamer - implements KeyStoreCryptoOperationStreamer { - - private final KeyStoreCryptoOperationStreamer mDelegate; - private final int mModulusSizeBytes; - private final ByteArrayOutputStream mInputBuffer = new ByteArrayOutputStream(); - private long mConsumedInputSizeBytes; - - private ZeroPaddingEncryptionStreamer( - KeyStoreCryptoOperationStreamer delegate, - int modulusSizeBytes) { - mDelegate = delegate; - mModulusSizeBytes = modulusSizeBytes; - } - - @Override - public byte[] update(byte[] input, int inputOffset, int inputLength) - throws KeyStoreException { - if (inputLength > 0) { - mInputBuffer.write(input, inputOffset, inputLength); - mConsumedInputSizeBytes += inputLength; - } - return EmptyArray.BYTE; - } - - @Override - public byte[] doFinal(byte[] input, int inputOffset, int inputLength, - byte[] signature, byte[] additionalEntropy) throws KeyStoreException { - if (inputLength > 0) { - mConsumedInputSizeBytes += inputLength; - mInputBuffer.write(input, inputOffset, inputLength); - } - byte[] bufferedInput = mInputBuffer.toByteArray(); - mInputBuffer.reset(); - byte[] paddedInput; - if (bufferedInput.length < mModulusSizeBytes) { - // Pad input with leading zeros - paddedInput = new byte[mModulusSizeBytes]; - System.arraycopy( - bufferedInput, 0, - paddedInput, - paddedInput.length - bufferedInput.length, - bufferedInput.length); - } else { - // RI throws BadPaddingException in this scenario. INVALID_ARGUMENT below will - // be translated into BadPaddingException. - throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_ARGUMENT, - "Message size (" + bufferedInput.length + " bytes) must be smaller than" - + " modulus (" + mModulusSizeBytes + " bytes)"); - } - return mDelegate.doFinal(paddedInput, 0, paddedInput.length, signature, - additionalEntropy); - } - - @Override - public long getConsumedInputSizeBytes() { - return mConsumedInputSizeBytes; - } - - @Override - public long getProducedOutputSizeBytes() { - return mDelegate.getProducedOutputSizeBytes(); - } - } } /** 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; * * <p>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: * <ul> * <li>{@link KeyProperties#PURPOSE_SIGN},</li> * <li>operation without requiring the user to be authenticated (see * {@link Builder#setUserAuthenticationRequired(boolean)}),</li> * <li>signing/origination at this moment in time (see {@link Builder#setKeyValidityStart(Date)} * and {@link Builder#setKeyValidityForOriginationEnd(Date)}),</li> - * <li>suitable digest or {@link KeyProperties#DIGEST_NONE},</li> - * <li>(RSA keys only) padding scheme {@link KeyProperties#SIGNATURE_PADDING_RSA_PKCS1} or - * {@link KeyProperties#ENCRYPTION_PADDING_NONE}.</li> + * <li>suitable digest,</li> + * <li>(RSA keys only) padding scheme {@link KeyProperties#SIGNATURE_PADDING_RSA_PKCS1}.</li> * </ul> * * <p>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 { * * <p>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. - * - * <p><b>NOTE</b>: 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. - * - * <p><b>NOTE</b>: 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 { * * <p>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. * |
