summaryrefslogtreecommitdiffstats
path: root/keystore/tests/src/android/security
diff options
context:
space:
mode:
authorAlex Klyubin <klyubin@google.com>2015-06-09 13:25:20 -0700
committerAlex Klyubin <klyubin@google.com>2015-06-10 14:50:55 -0700
commit4a0ff7ca984d29bd34b02e54441957cad65e8b53 (patch)
tree02e9eafdb05f423aa757bc2c94ad7ca6c323eae8 /keystore/tests/src/android/security
parentf22030d1c59aca4f9ad2af7d4c4d646b0b619f27 (diff)
downloadframeworks_base-4a0ff7ca984d29bd34b02e54441957cad65e8b53.zip
frameworks_base-4a0ff7ca984d29bd34b02e54441957cad65e8b53.tar.gz
frameworks_base-4a0ff7ca984d29bd34b02e54441957cad65e8b53.tar.bz2
Android Keystore keys are no longer backed by Conscrypt.
This switches Android Keystore asymmetric keys from being backed by Conscrypt (via keystore-engine which is an OpenSSL/BoringSSL ENGINE which talks to keystore via the old KeyStore API) to being backed by the AndroidKeyStore Provider which talks to keystore via the new KeyStore API. In effect, this switches asymmetric crypto offered by Android Keystore from old Keystore API to new KeyStore API, enabling all the new features such as enforcement of authorizations on key use. Some algorithms offered by Android Keystore, such as RSA with OAEP or PSS padding schemes, are not supported by other providers. This complicates matters because Android Keystore only supports public key operations if the corresponding private key is in the keystore. Thus, Android Keystore can only offer these operations for its own public keys only. This requires AndroidKeyStore to use its own subclasses of PublicKey everywhere. The ugliest place is where it needs to return its own subclass of X509Certificate only to be able to return its own subclass of PublicKey from Certificate.getPublicKey(). Bug: 18088752 Bug: 19284418 Bug: 20912868 Change-Id: Id234f9ab9ff72d353ca1ff66768bd3d46da50d64
Diffstat (limited to 'keystore/tests/src/android/security')
-rw-r--r--keystore/tests/src/android/security/KeyStoreTest.java5
-rw-r--r--keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java56
-rw-r--r--keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java67
3 files changed, 72 insertions, 56 deletions
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 44fb826..0b60c62 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -20,7 +20,6 @@ import android.app.Activity;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
-import android.os.ServiceManager;
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
@@ -34,13 +33,9 @@ import android.test.suitebuilder.annotation.MediumTest;
import com.android.org.conscrypt.NativeConstants;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
-import java.util.Date;
import java.util.HashSet;
import java.security.spec.RSAKeyGenParameterSpec;
-import android.util.Log;
-import android.util.Base64;
-
/**
* Junit / Instrumentation test case for KeyStore class
*
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
index 8488acd..e5c15c5 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
@@ -26,17 +26,21 @@ import android.test.AndroidTestCase;
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.security.interfaces.ECKey;
import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.text.SimpleDateFormat;
+import java.util.Arrays;
import java.util.Date;
import javax.security.auth.x500.X500Principal;
@@ -158,6 +162,26 @@ public class AndroidKeyPairGeneratorTest extends AndroidTestCase {
}
public void testKeyPairGenerator_GenerateKeyPair_EC_Unencrypted_Success() throws Exception {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
+ generator.initialize(new KeyGenParameterSpec.Builder(
+ TEST_ALIAS_1,
+ KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
+ .setCertificateSubject(TEST_DN_1)
+ .setCertificateSerialNumber(TEST_SERIAL_1)
+ .setCertificateNotBefore(NOW)
+ .setCertificateNotAfter(NOW_PLUS_10_YEARS)
+ .setDigests(KeyProperties.DIGEST_SHA256)
+ .build());
+
+ final KeyPair pair = generator.generateKeyPair();
+ assertNotNull("The KeyPair returned should not be null", pair);
+
+ assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 256, null, TEST_DN_1, TEST_SERIAL_1, NOW,
+ NOW_PLUS_10_YEARS);
+ }
+
+ public void testKeyPairGenerator_Legacy_GenerateKeyPair_EC_Unencrypted_Success()
+ throws Exception {
mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
.setAlias(TEST_ALIAS_1)
.setKeyType("EC")
@@ -328,19 +352,40 @@ public class AndroidKeyPairGeneratorTest extends AndroidTestCase {
assertNotNull("The PrivateKey for the KeyPair should be not null", privKey);
assertEquals(keyType, privKey.getAlgorithm());
+ if ("EC".equalsIgnoreCase(keyType)) {
+ assertTrue("EC private key must be instanceof ECKey: " + privKey.getClass().getName(),
+ privKey instanceof ECKey);
+ assertEquals("Private and public key must have the same EC parameters",
+ ((ECKey) pubKey).getParams(), ((ECKey) privKey).getParams());
+ } else if ("RSA".equalsIgnoreCase(keyType)) {
+ assertTrue("RSA private key must be instance of RSAKey: "
+ + privKey.getClass().getName(),
+ privKey instanceof RSAKey);
+ assertEquals("Private and public key must have the same RSA modulus",
+ ((RSAKey) pubKey).getModulus(), ((RSAKey) privKey).getModulus());
+ }
+
final byte[] userCertBytes = mAndroidKeyStore.get(Credentials.USER_CERTIFICATE + alias);
assertNotNull("The user certificate should exist for the generated entry", userCertBytes);
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
- final Certificate userCert = cf
- .generateCertificate(new ByteArrayInputStream(userCertBytes));
+ final Certificate userCert =
+ cf.generateCertificate(new ByteArrayInputStream(userCertBytes));
assertTrue("Certificate should be in X.509 format", userCert instanceof X509Certificate);
final X509Certificate x509userCert = (X509Certificate) userCert;
+ assertEquals(
+ "Public key used to sign certificate should have the same algorithm as in KeyPair",
+ pubKey.getAlgorithm(), x509userCert.getPublicKey().getAlgorithm());
+
assertEquals("PublicKey used to sign certificate should match one returned in KeyPair",
- pubKey, x509userCert.getPublicKey());
+ pubKey,
+ AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
+ Credentials.USER_PRIVATE_KEY + alias,
+ x509userCert.getPublicKey().getAlgorithm(),
+ x509userCert.getPublicKey().getEncoded()));
assertEquals("The Subject DN should be the one passed into the params", dn,
x509userCert.getSubjectDN());
@@ -357,7 +402,10 @@ public class AndroidKeyPairGeneratorTest extends AndroidTestCase {
assertDateEquals("The notAfter date should be the one passed into the params", end,
x509userCert.getNotAfter());
+ // Assert that the cert's signature verifies using the public key from generated KeyPair
x509userCert.verify(pubKey);
+ // Assert that the cert's signature verifies using the public key from the cert itself.
+ x509userCert.verify(x509userCert.getPublicKey());
final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias);
assertNull("A list of CA certificates should not exist for the generated entry", caCerts);
@@ -368,6 +416,8 @@ public class AndroidKeyPairGeneratorTest extends AndroidTestCase {
final byte[] pubKeyBytes = exportResult.exportData;
assertNotNull("The keystore should return the public key for the generated key",
pubKeyBytes);
+ assertTrue("Public key X.509 format should be as expected",
+ Arrays.equals(pubKey.getEncoded(), pubKeyBytes));
}
private static void assertDateEquals(String message, Date date1, Date date2) throws Exception {
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
index 336fa40..c3b731b 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
@@ -19,38 +19,31 @@ package android.security.keystore;
import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
import com.android.org.conscrypt.NativeConstants;
-import com.android.org.conscrypt.OpenSSLEngine;
import android.security.Credentials;
import android.security.KeyStore;
import android.security.KeyStoreParameter;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeymasterDefs;
import android.test.AndroidTestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.math.BigInteger;
-import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
+import java.security.KeyPair;
import java.security.KeyStore.Entry;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStore.TrustedCertificateEntry;
import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import java.security.interfaces.ECPrivateKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.spec.InvalidKeySpecException;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.RSAKey;
import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
@@ -1203,14 +1196,14 @@ public class AndroidKeyStoreTest extends AndroidTestCase {
private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, PrivateKey expectedKey,
Certificate expectedCert, Collection<Certificate> expectedChain) throws Exception {
- if (expectedKey instanceof ECPrivateKey) {
+ if (expectedKey instanceof ECKey) {
assertEquals("Returned PrivateKey should be what we inserted",
- ((ECPrivateKey) expectedKey).getParams().getCurve(),
- ((ECPublicKey) keyEntry.getCertificate().getPublicKey()).getParams().getCurve());
- } else if (expectedKey instanceof RSAPrivateKey) {
+ ((ECKey) expectedKey).getParams().getCurve(),
+ ((ECKey) keyEntry.getCertificate().getPublicKey()).getParams().getCurve());
+ } else if (expectedKey instanceof RSAKey) {
assertEquals("Returned PrivateKey should be what we inserted",
- ((RSAPrivateKey) expectedKey).getModulus(),
- ((RSAPrivateKey) keyEntry.getPrivateKey()).getModulus());
+ ((RSAKey) expectedKey).getModulus(),
+ ((RSAKey) keyEntry.getPrivateKey()).getModulus());
}
assertEquals("Returned Certificate should be what we inserted", expectedCert,
@@ -1263,15 +1256,14 @@ public class AndroidKeyStoreTest extends AndroidTestCase {
Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
assertNotNull("Key should exist", key);
- assertTrue("Should be a RSAPrivateKey", key instanceof RSAPrivateKey);
-
- RSAPrivateKey actualKey = (RSAPrivateKey) key;
+ assertTrue("Should be a PrivateKey", key instanceof PrivateKey);
+ assertTrue("Should be a RSAKey", key instanceof RSAKey);
KeyFactory keyFact = KeyFactory.getInstance("RSA");
PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
assertEquals("Inserted key should be same as retrieved key",
- ((RSAPrivateKey) expectedKey).getModulus(), actualKey.getModulus());
+ ((RSAKey) expectedKey).getModulus(), ((RSAKey) key).getModulus());
}
public void testKeyStore_GetKey_NoPassword_Unencrypted_Success() throws Exception {
@@ -1287,15 +1279,14 @@ public class AndroidKeyStoreTest extends AndroidTestCase {
Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
assertNotNull("Key should exist", key);
- assertTrue("Should be a RSAPrivateKey", key instanceof RSAPrivateKey);
-
- RSAPrivateKey actualKey = (RSAPrivateKey) key;
+ assertTrue("Should be a PrivateKey", key instanceof PrivateKey);
+ assertTrue("Should be a RSAKey", key instanceof RSAKey);
KeyFactory keyFact = KeyFactory.getInstance("RSA");
PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
assertEquals("Inserted key should be same as retrieved key",
- ((RSAPrivateKey) expectedKey).getModulus(), actualKey.getModulus());
+ ((RSAKey) expectedKey).getModulus(), ((RSAKey) key).getModulus());
}
public void testKeyStore_GetKey_Certificate_Encrypted_Failure() throws Exception {
@@ -1926,31 +1917,11 @@ public class AndroidKeyStoreTest extends AndroidTestCase {
Date notAfter) throws Exception {
final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
- final PrivateKey privKey;
- final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
- try {
- privKey = engine.getPrivateKeyById(privateKeyAlias);
- } catch (InvalidKeyException e) {
- throw new RuntimeException("Can't get key", e);
- }
-
- ExportResult exportResult =
- keyStore.exportKey(privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
- assertEquals(KeyStore.NO_ERROR, exportResult.resultCode);
- final byte[] pubKeyBytes = exportResult.exportData;
-
- final PublicKey pubKey;
- try {
- final KeyFactory keyFact = KeyFactory.getInstance("RSA");
- pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException("Can't instantiate RSA key generator", e);
- } catch (InvalidKeySpecException e) {
- throw new IllegalStateException("keystore returned invalid key encoding", e);
- }
+ KeyPair keyPair = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
+ keyStore, privateKeyAlias);
final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
- certGen.setPublicKey(pubKey);
+ certGen.setPublicKey(keyPair.getPublic());
certGen.setSerialNumber(serialNumber);
certGen.setSubjectDN(subjectDN);
certGen.setIssuerDN(subjectDN);
@@ -1958,7 +1929,7 @@ public class AndroidKeyStoreTest extends AndroidTestCase {
certGen.setNotAfter(notAfter);
certGen.setSignatureAlgorithm("sha1WithRSA");
- final X509Certificate cert = certGen.generate(privKey);
+ final X509Certificate cert = certGen.generate(keyPair.getPrivate());
return cert;
}