diff options
author | Kenny Root <kroot@google.com> | 2012-08-20 10:48:46 -0700 |
---|---|---|
committer | Kenny Root <kroot@google.com> | 2012-08-22 08:52:55 -0700 |
commit | db026710ec0adcf7f72dfb24c65d38a882ee26d8 (patch) | |
tree | cff080fbecd17c5d6e6a60a7bc2adccbd6761b20 /keystore/tests | |
parent | e29df16cb57b69995df597e8a6d95d986c1c43fc (diff) | |
download | frameworks_base-db026710ec0adcf7f72dfb24c65d38a882ee26d8.zip frameworks_base-db026710ec0adcf7f72dfb24c65d38a882ee26d8.tar.gz frameworks_base-db026710ec0adcf7f72dfb24c65d38a882ee26d8.tar.bz2 |
Add KeyPairGenerator for Android keystore
This allows end-users to generate keys in the keystore without the
private part of the key ever needing to leave the device. The generation
process also generates a self-signed certificate.
Change-Id: I114ffb8e0cbe3b1edaae7e69e8aa578cb835efc9
Diffstat (limited to 'keystore/tests')
-rw-r--r-- | keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java | 118 | ||||
-rw-r--r-- | keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java | 180 |
2 files changed, 298 insertions, 0 deletions
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java new file mode 100644 index 0000000..e6a3750 --- /dev/null +++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +import android.test.AndroidTestCase; + +import java.math.BigInteger; +import java.util.Date; + +import javax.security.auth.x500.X500Principal; + +public class AndroidKeyPairGeneratorSpecTest extends AndroidTestCase { + private static final String TEST_ALIAS_1 = "test1"; + + private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1"); + + private static final long NOW_MILLIS = System.currentTimeMillis(); + + private static final BigInteger SERIAL_1 = BigInteger.ONE; + + /* We have to round this off because X509v3 doesn't store milliseconds. */ + private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L)); + + @SuppressWarnings("deprecation") + private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1); + + public void testConstructor_Success() throws Exception { + AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec(getContext(), + TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW, NOW_PLUS_10_YEARS); + + assertEquals("Context should be the one specified", getContext(), spec.getContext()); + + assertEquals("Alias should be the one specified", TEST_ALIAS_1, spec.getKeystoreAlias()); + + assertEquals("subjectDN should be the one specified", TEST_DN_1, spec.getSubjectDN()); + + assertEquals("startDate should be the one specified", NOW, spec.getStartDate()); + + assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate()); + } + + public void testConstructor_NullContext_Failure() throws Exception { + try { + new AndroidKeyPairGeneratorSpec(null, TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW, + NOW_PLUS_10_YEARS); + fail("Should throw IllegalArgumentException when context is null"); + } catch (IllegalArgumentException success) { + } + } + + public void testConstructor_NullKeystoreAlias_Failure() throws Exception { + try { + new AndroidKeyPairGeneratorSpec(getContext(), null, TEST_DN_1, SERIAL_1, NOW, + NOW_PLUS_10_YEARS); + fail("Should throw IllegalArgumentException when keystoreAlias is null"); + } catch (IllegalArgumentException success) { + } + } + + public void testConstructor_NullSubjectDN_Failure() throws Exception { + try { + new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, null, SERIAL_1, NOW, + NOW_PLUS_10_YEARS); + fail("Should throw IllegalArgumentException when subjectDN is null"); + } catch (IllegalArgumentException success) { + } + } + + public void testConstructor_NullSerial_Failure() throws Exception { + try { + new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, null, NOW, + NOW_PLUS_10_YEARS); + fail("Should throw IllegalArgumentException when startDate is null"); + } catch (IllegalArgumentException success) { + } + } + + public void testConstructor_NullStartDate_Failure() throws Exception { + try { + new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, null, + NOW_PLUS_10_YEARS); + fail("Should throw IllegalArgumentException when startDate is null"); + } catch (IllegalArgumentException success) { + } + } + + public void testConstructor_NullEndDate_Failure() throws Exception { + try { + new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW, + null); + fail("Should throw IllegalArgumentException when keystoreAlias is null"); + } catch (IllegalArgumentException success) { + } + } + + public void testConstructor_EndBeforeStart_Failure() throws Exception { + try { + new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, + NOW_PLUS_10_YEARS, NOW); + fail("Should throw IllegalArgumentException when end is before start"); + } catch (IllegalArgumentException success) { + } + } +} diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java new file mode 100644 index 0000000..d108caa --- /dev/null +++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +import android.test.AndroidTestCase; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.security.KeyPair; +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.util.Date; + +import javax.security.auth.x500.X500Principal; + +public class AndroidKeyPairGeneratorTest extends AndroidTestCase { + private android.security.KeyStore mAndroidKeyStore; + + private java.security.KeyPairGenerator mGenerator; + + private static final String TEST_ALIAS_1 = "test1"; + + private static final String TEST_ALIAS_2 = "test2"; + + private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1"); + + private static final X500Principal TEST_DN_2 = new X500Principal("CN=test2"); + + private static final BigInteger TEST_SERIAL_1 = BigInteger.ONE; + + private static final BigInteger TEST_SERIAL_2 = BigInteger.valueOf(2L); + + private static final long NOW_MILLIS = System.currentTimeMillis(); + + /* We have to round this off because X509v3 doesn't store milliseconds. */ + private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L)); + + @SuppressWarnings("deprecation") + private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1); + + @Override + protected void setUp() throws Exception { + mAndroidKeyStore = android.security.KeyStore.getInstance(); + + assertTrue(mAndroidKeyStore.reset()); + + assertEquals(android.security.KeyStore.State.UNINITIALIZED, mAndroidKeyStore.state()); + + assertTrue(mAndroidKeyStore.password("1111")); + + assertEquals(android.security.KeyStore.State.UNLOCKED, mAndroidKeyStore.state()); + + assertEquals(0, mAndroidKeyStore.saw("").length); + + mGenerator = java.security.KeyPairGenerator.getInstance(AndroidKeyPairGenerator.NAME); + } + + public void testKeyPairGenerator_Initialize_Params_Success() throws Exception { + mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, + TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS)); + } + + public void testKeyPairGenerator_Initialize_KeySize_Failure() throws Exception { + try { + mGenerator.initialize(1024); + fail("KeyPairGenerator should not support setting the key size"); + } catch (IllegalArgumentException success) { + } + } + + public void testKeyPairGenerator_Initialize_KeySizeAndSecureRandom_Failure() throws Exception { + try { + mGenerator.initialize(1024, new SecureRandom()); + fail("KeyPairGenerator should not support setting the key size"); + } catch (IllegalArgumentException success) { + } + } + + public void testKeyPairGenerator_Initialize_ParamsAndSecureRandom_Failure() throws Exception { + mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, + TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS), new SecureRandom()); + } + + public void testKeyPairGenerator_GenerateKeyPair_Success() throws Exception { + mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, + TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS)); + + final KeyPair pair = mGenerator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair); + + assertKeyPairCorrect(pair, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS); + } + + public void testKeyPairGenerator_GenerateKeyPair_Replaced_Success() throws Exception { + // Generate the first key + { + mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, + TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS)); + final KeyPair pair1 = mGenerator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair1); + assertKeyPairCorrect(pair1, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW, + NOW_PLUS_10_YEARS); + } + + // Replace the original key + { + mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_2, + TEST_DN_2, TEST_SERIAL_2, NOW, NOW_PLUS_10_YEARS)); + final KeyPair pair2 = mGenerator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair2); + assertKeyPairCorrect(pair2, TEST_ALIAS_2, TEST_DN_2, TEST_SERIAL_2, NOW, + NOW_PLUS_10_YEARS); + } + } + + private void assertKeyPairCorrect(KeyPair pair, String alias, X500Principal dn, + BigInteger serial, Date start, Date end) throws Exception { + final PublicKey pubKey = pair.getPublic(); + assertNotNull("The PublicKey for the KeyPair should be not null", pubKey); + + final PrivateKey privKey = pair.getPrivate(); + assertNotNull("The PrivateKey for the KeyPair should be not null", privKey); + + 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)); + + assertTrue("Certificate should be in X.509 format", userCert instanceof X509Certificate); + + final X509Certificate x509userCert = (X509Certificate) userCert; + + assertEquals("PublicKey used to sign certificate should match one returned in KeyPair", + pubKey, x509userCert.getPublicKey()); + + assertEquals("The Subject DN should be the one passed into the params", dn, + x509userCert.getSubjectDN()); + + assertEquals("The Issuer DN should be the same as the Subject DN", dn, + x509userCert.getIssuerDN()); + + assertEquals("The Serial should be the one passed into the params", serial, + x509userCert.getSerialNumber()); + + assertEquals("The notBefore date should be the one passed into the params", start, + x509userCert.getNotBefore()); + + assertEquals("The notAfter date should be the one passed into the params", end, + x509userCert.getNotAfter()); + + x509userCert.verify(pubKey); + + final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias); + assertNull("A list of CA certificates should not exist for the generated entry", caCerts); + + final byte[] pubKeyBytes = mAndroidKeyStore.getPubkey(Credentials.USER_PRIVATE_KEY + alias); + assertNotNull("The keystore should return the public key for the generated key", + pubKeyBytes); + } +} |