diff options
author | Kenny Root <kroot@google.com> | 2013-08-16 14:03:29 -0700 |
---|---|---|
committer | Kenny Root <kroot@google.com> | 2013-09-03 00:53:04 -0700 |
commit | a39859889b7de0ad3190386cc732fa4bdcbe5504 (patch) | |
tree | a9efaea5421fe0ce48f088faf2324afb798d2ce1 /keystore/java | |
parent | 96661c42d0643c129fed60678aa0b8f99d32b456 (diff) | |
download | frameworks_base-a39859889b7de0ad3190386cc732fa4bdcbe5504.zip frameworks_base-a39859889b7de0ad3190386cc732fa4bdcbe5504.tar.gz frameworks_base-a39859889b7de0ad3190386cc732fa4bdcbe5504.tar.bz2 |
Add support for DSA and ECDSA key types
(cherry picked from commit f64386fc26efeb245fd90fabaa47b8c8bf9b4613)
Bug: 10600582
Change-Id: I88dfcc8ca602f55fad54bd8bf043aee460c0de24
Diffstat (limited to 'keystore/java')
-rw-r--r-- | keystore/java/android/security/AndroidKeyPairGenerator.java | 47 | ||||
-rw-r--r-- | keystore/java/android/security/KeyPairGeneratorSpec.java | 192 | ||||
-rw-r--r-- | keystore/java/android/security/KeyStore.java | 19 |
3 files changed, 243 insertions, 15 deletions
diff --git a/keystore/java/android/security/AndroidKeyPairGenerator.java b/keystore/java/android/security/AndroidKeyPairGenerator.java index 390e732..1ab0aeb 100644 --- a/keystore/java/android/security/AndroidKeyPairGenerator.java +++ b/keystore/java/android/security/AndroidKeyPairGenerator.java @@ -18,6 +18,7 @@ package android.security; import com.android.org.bouncycastle.x509.X509V3CertificateGenerator; +import com.android.org.conscrypt.NativeCrypto; import com.android.org.conscrypt.OpenSSLEngine; import java.security.InvalidAlgorithmParameterException; @@ -33,7 +34,10 @@ import java.security.SecureRandom; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.DSAParameterSpec; +import java.security.spec.ECParameterSpec; import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAKeyGenParameterSpec; import java.security.spec.X509EncodedKeySpec; /** @@ -87,8 +91,12 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { Credentials.deleteAllTypesForAlias(mKeyStore, alias); + final int keyType = KeyStore.getKeyTypeForAlgorithm(mSpec.getKeyType()); + byte[][] args = getArgsForKeyType(keyType, mSpec.getAlgorithmParameterSpec()); + final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias; - if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, mSpec.getFlags())) { + if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, keyType, + mSpec.getKeySize(), mSpec.getFlags(), args)) { throw new IllegalStateException("could not generate key in keystore"); } @@ -104,10 +112,10 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { final PublicKey pubKey; try { - final KeyFactory keyFact = KeyFactory.getInstance("RSA"); + final KeyFactory keyFact = KeyFactory.getInstance(mSpec.getKeyType()); pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes)); } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException("Can't instantiate RSA key generator", e); + throw new IllegalStateException("Can't instantiate key generator", e); } catch (InvalidKeySpecException e) { throw new IllegalStateException("keystore returned invalid key encoding", e); } @@ -119,7 +127,7 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { certGen.setIssuerDN(mSpec.getSubjectDN()); certGen.setNotBefore(mSpec.getStartDate()); certGen.setNotAfter(mSpec.getEndDate()); - certGen.setSignatureAlgorithm("sha1WithRSA"); + certGen.setSignatureAlgorithm(getDefaultSignatureAlgorithmForKeyType(mSpec.getKeyType())); final X509Certificate cert; try { @@ -146,6 +154,37 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { return new KeyPair(pubKey, privKey); } + private static String getDefaultSignatureAlgorithmForKeyType(String keyType) { + if ("RSA".equalsIgnoreCase(keyType)) { + return "sha256WithRSA"; + } else if ("DSA".equalsIgnoreCase(keyType)) { + return "sha1WithDSA"; + } else if ("EC".equalsIgnoreCase(keyType)) { + return "sha256WithECDSA"; + } else { + throw new IllegalArgumentException("Unsupported key type " + keyType); + } + } + + private static byte[][] getArgsForKeyType(int keyType, AlgorithmParameterSpec spec) { + switch (keyType) { + case NativeCrypto.EVP_PKEY_RSA: + if (spec instanceof RSAKeyGenParameterSpec) { + RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec; + return new byte[][] { rsaSpec.getPublicExponent().toByteArray() }; + } + break; + case NativeCrypto.EVP_PKEY_DSA: + if (spec instanceof DSAParameterSpec) { + DSAParameterSpec dsaSpec = (DSAParameterSpec) spec; + return new byte[][] { dsaSpec.getG().toByteArray(), + dsaSpec.getP().toByteArray(), dsaSpec.getQ().toByteArray() }; + } + break; + } + return null; + } + @Override public void initialize(int keysize, SecureRandom random) { throw new IllegalArgumentException("cannot specify keysize with AndroidKeyPairGenerator"); diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java index 59f89bc..da1abdc 100644 --- a/keystore/java/android/security/KeyPairGeneratorSpec.java +++ b/keystore/java/android/security/KeyPairGeneratorSpec.java @@ -16,13 +16,18 @@ package android.security; +import com.android.org.conscrypt.NativeCrypto; + import android.content.Context; import android.text.TextUtils; import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.DSAParameterSpec; +import java.security.spec.RSAKeyGenParameterSpec; import java.util.Date; import javax.security.auth.x500.X500Principal; @@ -50,10 +55,35 @@ import javax.security.auth.x500.X500Principal; * certificate signed by a real Certificate Authority. */ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { - private final String mKeystoreAlias; + /* + * These must be kept in sync with system/security/keystore/defaults.h + */ + + /* DSA */ + private static final int DSA_DEFAULT_KEY_SIZE = 1024; + private static final int DSA_MIN_KEY_SIZE = 512; + private static final int DSA_MAX_KEY_SIZE = 8192; + + /* EC */ + private static final int EC_DEFAULT_KEY_SIZE = 256; + private static final int EC_MIN_KEY_SIZE = 192; + private static final int EC_MAX_KEY_SIZE = 521; + + /* RSA */ + private static final int RSA_DEFAULT_KEY_SIZE = 2048; + private static final int RSA_MIN_KEY_SIZE = 512; + private static final int RSA_MAX_KEY_SIZE = 8192; private final Context mContext; + private final String mKeystoreAlias; + + private final String mKeyType; + + private final int mKeySize; + + private final AlgorithmParameterSpec mSpec; + private final X500Principal mSubjectDN; private final BigInteger mSerialNumber; @@ -84,6 +114,9 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * @param context Android context for the activity * @param keyStoreAlias name to use for the generated key in the Android * keystore + * @param keyType key algorithm to use (RSA, DSA, EC) + * @param keySize size of key to generate + * @param spec the underlying key type parameters * @param subjectDN X.509 v3 Subject Distinguished Name * @param serialNumber X509 v3 certificate serial number * @param startDate the start of the self-signed certificate validity period @@ -93,9 +126,9 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * {@code endDate} is before {@code startDate}. * @hide should be built with KeyPairGeneratorSpecBuilder */ - public KeyPairGeneratorSpec(Context context, String keyStoreAlias, - X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate, - int flags) { + public KeyPairGeneratorSpec(Context context, String keyStoreAlias, String keyType, int keySize, + AlgorithmParameterSpec spec, X500Principal subjectDN, BigInteger serialNumber, + Date startDate, Date endDate, int flags) { if (context == null) { throw new IllegalArgumentException("context == null"); } else if (TextUtils.isEmpty(keyStoreAlias)) { @@ -112,8 +145,18 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { throw new IllegalArgumentException("endDate < startDate"); } + final int keyTypeInt = KeyStore.getKeyTypeForAlgorithm(keyType); + if (keySize == -1) { + keySize = getDefaultKeySizeForType(keyTypeInt); + } + checkCorrectParametersSpec(keyTypeInt, keySize, spec); + checkValidKeySize(keyTypeInt, keySize); + mContext = context; mKeystoreAlias = keyStoreAlias; + mKeyType = keyType; + mKeySize = keySize; + mSpec = spec; mSubjectDN = subjectDN; mSerialNumber = serialNumber; mStartDate = startDate; @@ -121,6 +164,64 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mFlags = flags; } + private static int getDefaultKeySizeForType(int keyType) { + if (keyType == NativeCrypto.EVP_PKEY_DSA) { + return DSA_DEFAULT_KEY_SIZE; + } else if (keyType == NativeCrypto.EVP_PKEY_EC) { + return EC_DEFAULT_KEY_SIZE; + } else if (keyType == NativeCrypto.EVP_PKEY_RSA) { + return RSA_DEFAULT_KEY_SIZE; + } + throw new IllegalArgumentException("Invalid key type " + keyType); + } + + private static void checkValidKeySize(int keyType, int keySize) { + if (keyType == NativeCrypto.EVP_PKEY_DSA) { + if (keySize < DSA_MIN_KEY_SIZE || keySize > DSA_MAX_KEY_SIZE) { + throw new IllegalArgumentException("DSA keys must be >= " + DSA_MIN_KEY_SIZE + + " and <= " + DSA_MAX_KEY_SIZE); + } + } else if (keyType == NativeCrypto.EVP_PKEY_EC) { + if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) { + throw new IllegalArgumentException("EC keys must be >= " + EC_MIN_KEY_SIZE + + " and <= " + EC_MAX_KEY_SIZE); + } + } else if (keyType == NativeCrypto.EVP_PKEY_RSA) { + if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) { + throw new IllegalArgumentException("RSA keys must be >= " + RSA_MIN_KEY_SIZE + + " and <= " + RSA_MAX_KEY_SIZE); + } + } else { + throw new IllegalArgumentException("Invalid key type " + keyType); + } + } + + private static void checkCorrectParametersSpec(int keyType, int keySize, + AlgorithmParameterSpec spec) { + if (keyType == NativeCrypto.EVP_PKEY_DSA && spec != null) { + if (!(spec instanceof DSAParameterSpec)) { + throw new IllegalArgumentException("DSA keys must have DSAParameterSpec specified"); + } + } else if (keyType == NativeCrypto.EVP_PKEY_RSA && spec != null) { + if (spec instanceof RSAKeyGenParameterSpec) { + RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec; + if (keySize != -1 && keySize != rsaSpec.getKeysize()) { + throw new IllegalArgumentException("RSA key size must match: " + keySize + + " vs " + rsaSpec.getKeysize()); + } + } else { + throw new IllegalArgumentException("RSA may only use RSAKeyGenParameterSpec"); + } + } + } + + /** + * Gets the Android context used for operations with this instance. + */ + public Context getContext() { + return mContext; + } + /** * Returns the alias that will be used in the {@code java.security.KeyStore} * in conjunction with the {@code AndroidKeyStore}. @@ -130,10 +231,31 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { } /** - * Gets the Android context used for operations with this instance. + * Returns the key type (e.g., "RSA", "DSA", "EC") specified by this + * parameter. + * @hide */ - public Context getContext() { - return mContext; + public String getKeyType() { + return mKeyType; + } + + /** + * Returns the key size specified by this parameter. For instance, for RSA + * this will return the modulus size and for EC it will return the field + * size. + * @hide + */ + public int getKeySize() { + return mKeySize; + } + + /** + * Returns the {@link AlgorithmParameterSpec} that will be used for creation + * of the key pair. + * @hide + */ + public AlgorithmParameterSpec getAlgorithmParameterSpec() { + return mSpec; } /** @@ -209,6 +331,12 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private String mKeystoreAlias; + private String mKeyType = "RSA"; + + private int mKeySize = -1; + + private AlgorithmParameterSpec mSpec; + private X500Principal mSubjectDN; private BigInteger mSerialNumber; @@ -246,6 +374,52 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { } /** + * Sets the key type (e.g., RSA, DSA, EC) of the keypair to be created. + * @hide + */ + public Builder setKeyType(String keyType) throws NoSuchAlgorithmException { + if (keyType == null) { + throw new NullPointerException("keyType == null"); + } else { + try { + KeyStore.getKeyTypeForAlgorithm(keyType); + } catch (IllegalArgumentException e) { + throw new NoSuchAlgorithmException("Unsupported key type: " + keyType); + } + } + mKeyType = keyType; + return this; + } + + /** + * Sets the key size for the keypair to be created. For instance, for a + * key type of RSA this will set the modulus size and for a key type of + * EC it will select a curve with a matching field size. + * @hide + */ + public Builder setKeySize(int keySize) { + if (keySize < 0) { + throw new IllegalArgumentException("keySize < 0"); + } + mKeySize = keySize; + return this; + } + + /** + * Sets the underlying key type's parameters. This is required for DSA + * where you must set this to an instance of + * {@link java.security.spec.DSAParameterSpec}. + * @hide + */ + public Builder setAlgorithmParameterSpec(AlgorithmParameterSpec spec) { + if (spec == null) { + throw new NullPointerException("spec == null"); + } + mSpec = spec; + return this; + } + + /** * Sets the subject used for the self-signed certificate of the * generated key pair. */ @@ -311,8 +485,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * @return built instance of {@code KeyPairGeneratorSpec} */ public KeyPairGeneratorSpec build() { - return new KeyPairGeneratorSpec(mContext, mKeystoreAlias, mSubjectDN, - mSerialNumber, mStartDate, mEndDate, mFlags); + return new KeyPairGeneratorSpec(mContext, mKeystoreAlias, mKeyType, mKeySize, mSpec, + mSubjectDN, mSerialNumber, mStartDate, mEndDate, mFlags); } } } diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index fb5e039..9babb94 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -16,6 +16,8 @@ package android.security; +import com.android.org.conscrypt.NativeCrypto; + import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; @@ -64,6 +66,18 @@ public class KeyStore { return new KeyStore(keystore); } + static int getKeyTypeForAlgorithm(String keyType) throws IllegalArgumentException { + if ("RSA".equalsIgnoreCase(keyType)) { + return NativeCrypto.EVP_PKEY_RSA; + } else if ("DSA".equalsIgnoreCase(keyType)) { + return NativeCrypto.EVP_PKEY_DSA; + } else if ("EC".equalsIgnoreCase(keyType)) { + return NativeCrypto.EVP_PKEY_EC; + } else { + throw new IllegalArgumentException("Unsupported key type: " + keyType); + } + } + public State state() { final int ret; try { @@ -188,9 +202,10 @@ public class KeyStore { } } - public boolean generate(String key, int uid, int flags) { + public boolean generate(String key, int uid, int keyType, int keySize, int flags, + byte[][] args) { try { - return mBinder.generate(key, uid, flags) == NO_ERROR; + return mBinder.generate(key, uid, keyType, keySize, flags, args) == NO_ERROR; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return false; |