diff options
Diffstat (limited to 'keystore/java/android/security/KeyPairGeneratorSpec.java')
-rw-r--r-- | keystore/java/android/security/KeyPairGeneratorSpec.java | 192 |
1 files changed, 183 insertions, 9 deletions
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); } } } |