Merge "Add KeyPairGenerator.EC backed by Android KeyStore."

This commit is contained in:
Alex Klyubin
2015-01-16 16:44:06 +00:00
committed by Gerrit Code Review
4 changed files with 140 additions and 90 deletions

View File

@@ -50,10 +50,50 @@ import java.security.spec.X509EncodedKeySpec;
* *
* {@hide} * {@hide}
*/ */
public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
public static class RSA extends AndroidKeyPairGenerator {
public RSA() {
super("RSA");
}
}
public static class EC extends AndroidKeyPairGenerator {
public EC() {
super("EC");
}
}
/*
* These must be kept in sync with system/security/keystore/defaults.h
*/
/* 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 String mAlgorithm;
private android.security.KeyStore mKeyStore; private android.security.KeyStore mKeyStore;
private KeyPairGeneratorSpec mSpec; private KeyPairGeneratorSpec mSpec;
private String mKeyAlgorithm;
private int mKeyType;
private int mKeySize;
protected AndroidKeyPairGenerator(String algorithm) {
mAlgorithm = algorithm;
}
public String getAlgorithm() {
return mAlgorithm;
}
/** /**
* Generate a KeyPair which is backed by the Android keystore service. You * Generate a KeyPair which is backed by the Android keystore service. You
@@ -88,12 +128,11 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
Credentials.deleteAllTypesForAlias(mKeyStore, alias); Credentials.deleteAllTypesForAlias(mKeyStore, alias);
final int keyType = KeyStore.getKeyTypeForAlgorithm(mSpec.getKeyType()); byte[][] args = getArgsForKeyType(mKeyType, mSpec.getAlgorithmParameterSpec());
byte[][] args = getArgsForKeyType(keyType, mSpec.getAlgorithmParameterSpec());
final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias; final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, keyType, if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, mKeyType, mKeySize,
mSpec.getKeySize(), mSpec.getFlags(), args)) { mSpec.getFlags(), args)) {
throw new IllegalStateException("could not generate key in keystore"); throw new IllegalStateException("could not generate key in keystore");
} }
@@ -109,7 +148,7 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
final PublicKey pubKey; final PublicKey pubKey;
try { try {
final KeyFactory keyFact = KeyFactory.getInstance(mSpec.getKeyType()); final KeyFactory keyFact = KeyFactory.getInstance(mKeyAlgorithm);
pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes)); pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("Can't instantiate key generator", e); throw new IllegalStateException("Can't instantiate key generator", e);
@@ -117,18 +156,9 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
throw new IllegalStateException("keystore returned invalid key encoding", e); throw new IllegalStateException("keystore returned invalid key encoding", e);
} }
final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
certGen.setPublicKey(pubKey);
certGen.setSerialNumber(mSpec.getSerialNumber());
certGen.setSubjectDN(mSpec.getSubjectDN());
certGen.setIssuerDN(mSpec.getSubjectDN());
certGen.setNotBefore(mSpec.getStartDate());
certGen.setNotAfter(mSpec.getEndDate());
certGen.setSignatureAlgorithm(getDefaultSignatureAlgorithmForKeyType(mSpec.getKeyType()));
final X509Certificate cert; final X509Certificate cert;
try { try {
cert = certGen.generate(privKey); cert = generateCertificate(privKey, pubKey);
} catch (Exception e) { } catch (Exception e) {
Credentials.deleteAllTypesForAlias(mKeyStore, alias); Credentials.deleteAllTypesForAlias(mKeyStore, alias);
throw new IllegalStateException("Can't generate certificate", e); throw new IllegalStateException("Can't generate certificate", e);
@@ -151,13 +181,78 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
return new KeyPair(pubKey, privKey); return new KeyPair(pubKey, privKey);
} }
private static String getDefaultSignatureAlgorithmForKeyType(String keyType) { @SuppressWarnings("deprecation")
if ("RSA".equalsIgnoreCase(keyType)) { private X509Certificate generateCertificate(PrivateKey privateKey, PublicKey publicKey)
throws Exception {
final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
certGen.setPublicKey(publicKey);
certGen.setSerialNumber(mSpec.getSerialNumber());
certGen.setSubjectDN(mSpec.getSubjectDN());
certGen.setIssuerDN(mSpec.getSubjectDN());
certGen.setNotBefore(mSpec.getStartDate());
certGen.setNotAfter(mSpec.getEndDate());
certGen.setSignatureAlgorithm(getDefaultSignatureAlgorithmForKeyAlgorithm(mKeyAlgorithm));
return certGen.generate(privateKey);
}
private String getKeyAlgorithm(KeyPairGeneratorSpec spec) {
String result = spec.getKeyType();
if (result != null) {
return result;
}
return getAlgorithm();
}
private static int getDefaultKeySize(int keyType) {
if (keyType == NativeCrypto.EVP_PKEY_EC) {
return EC_DEFAULT_KEY_SIZE;
} else if (keyType == NativeCrypto.EVP_PKEY_RSA) {
return RSA_DEFAULT_KEY_SIZE;
}
return -1;
}
private static void checkValidKeySize(String keyAlgorithm, int keyType, int keySize)
throws InvalidAlgorithmParameterException {
if (keyType == NativeCrypto.EVP_PKEY_EC) {
if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) {
throw new InvalidAlgorithmParameterException("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 InvalidAlgorithmParameterException("RSA keys must be >= "
+ RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
}
} else {
throw new InvalidAlgorithmParameterException(
"Unsupported key algorithm: " + keyAlgorithm);
}
}
private static void checkCorrectParametersSpec(int keyType, int keySize,
AlgorithmParameterSpec spec) throws InvalidAlgorithmParameterException {
if (keyType == NativeCrypto.EVP_PKEY_RSA && spec != null) {
if (spec instanceof RSAKeyGenParameterSpec) {
RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec;
if (keySize != -1 && keySize != rsaSpec.getKeysize()) {
throw new InvalidAlgorithmParameterException("RSA key size must match: "
+ keySize + " vs " + rsaSpec.getKeysize());
}
} else {
throw new InvalidAlgorithmParameterException(
"RSA may only use RSAKeyGenParameterSpec");
}
}
}
private static String getDefaultSignatureAlgorithmForKeyAlgorithm(String algorithm) {
if ("RSA".equalsIgnoreCase(algorithm)) {
return "sha256WithRSA"; return "sha256WithRSA";
} else if ("EC".equalsIgnoreCase(keyType)) { } else if ("EC".equalsIgnoreCase(algorithm)) {
return "sha256WithECDSA"; return "sha256WithECDSA";
} else { } else {
throw new IllegalArgumentException("Unsupported key type " + keyType); throw new IllegalArgumentException("Unsupported key type " + algorithm);
} }
} }
@@ -190,7 +285,26 @@ public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
} }
KeyPairGeneratorSpec spec = (KeyPairGeneratorSpec) params; KeyPairGeneratorSpec spec = (KeyPairGeneratorSpec) params;
String keyAlgorithm = getKeyAlgorithm(spec);
int keyType = KeyStore.getKeyTypeForAlgorithm(keyAlgorithm);
if (keyType == -1) {
throw new InvalidAlgorithmParameterException(
"Unsupported key algorithm: " + keyAlgorithm);
}
int keySize = spec.getKeySize();
if (keySize == -1) {
keySize = getDefaultKeySize(keyType);
if (keySize == -1) {
throw new InvalidAlgorithmParameterException(
"Unsupported key algorithm: " + keyAlgorithm);
}
}
checkCorrectParametersSpec(keyType, keySize, spec.getAlgorithmParameterSpec());
checkValidKeySize(keyAlgorithm, keyType, keySize);
mKeyAlgorithm = keyAlgorithm;
mKeyType = keyType;
mKeySize = keySize;
mSpec = spec; mSpec = spec;
mKeyStore = android.security.KeyStore.getInstance(); mKeyStore = android.security.KeyStore.getInstance();
} }

View File

@@ -33,6 +33,7 @@ public class AndroidKeyStoreProvider extends Provider {
put("KeyStore." + AndroidKeyStore.NAME, AndroidKeyStore.class.getName()); put("KeyStore." + AndroidKeyStore.NAME, AndroidKeyStore.class.getName());
// java.security.KeyPairGenerator // java.security.KeyPairGenerator
put("KeyPairGenerator.RSA", AndroidKeyPairGenerator.class.getName()); put("KeyPairGenerator.EC", AndroidKeyPairGenerator.EC.class.getName());
put("KeyPairGenerator.RSA", AndroidKeyPairGenerator.RSA.class.getName());
} }
} }

View File

@@ -16,8 +16,6 @@
package android.security; package android.security;
import com.android.org.conscrypt.NativeCrypto;
import android.content.Context; import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;
@@ -26,7 +24,6 @@ import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.spec.AlgorithmParameterSpec; import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.Date; import java.util.Date;
import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500Principal;
@@ -54,19 +51,6 @@ import javax.security.auth.x500.X500Principal;
* certificate signed by a real Certificate Authority. * certificate signed by a real Certificate Authority.
*/ */
public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/*
* These must be kept in sync with system/security/keystore/defaults.h
*/
/* 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 Context mContext;
@@ -139,13 +123,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
throw new IllegalArgumentException("endDate < startDate"); 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; mContext = context;
mKeystoreAlias = keyStoreAlias; mKeystoreAlias = keyStoreAlias;
mKeyType = keyType; mKeyType = keyType;
@@ -158,46 +135,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
mFlags = flags; mFlags = flags;
} }
private static int getDefaultKeySizeForType(int keyType) {
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_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_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. * Gets the Android context used for operations with this instance.
*/ */
@@ -311,7 +248,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
private String mKeystoreAlias; private String mKeystoreAlias;
private String mKeyType = "RSA"; private String mKeyType;
private int mKeySize = -1; private int mKeySize = -1;
@@ -360,9 +297,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
if (keyType == null) { if (keyType == null) {
throw new NullPointerException("keyType == null"); throw new NullPointerException("keyType == null");
} else { } else {
try { if (KeyStore.getKeyTypeForAlgorithm(keyType) == -1) {
KeyStore.getKeyTypeForAlgorithm(keyType);
} catch (IllegalArgumentException e) {
throw new NoSuchAlgorithmException("Unsupported key type: " + keyType); throw new NoSuchAlgorithmException("Unsupported key type: " + keyType);
} }
} }

View File

@@ -68,13 +68,13 @@ public class KeyStore {
return new KeyStore(keystore); return new KeyStore(keystore);
} }
static int getKeyTypeForAlgorithm(String keyType) throws IllegalArgumentException { static int getKeyTypeForAlgorithm(String keyType) {
if ("RSA".equalsIgnoreCase(keyType)) { if ("RSA".equalsIgnoreCase(keyType)) {
return NativeCrypto.EVP_PKEY_RSA; return NativeCrypto.EVP_PKEY_RSA;
} else if ("EC".equalsIgnoreCase(keyType)) { } else if ("EC".equalsIgnoreCase(keyType)) {
return NativeCrypto.EVP_PKEY_EC; return NativeCrypto.EVP_PKEY_EC;
} else { } else {
throw new IllegalArgumentException("Unsupported key type: " + keyType); return -1;
} }
} }