AndroidKeyPairGeneratorTest.java revision 1c219f619291ba818bc2542390a2988539d94ed0
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.security; 18 19import android.test.AndroidTestCase; 20 21import java.io.ByteArrayInputStream; 22import java.math.BigInteger; 23import java.security.KeyPair; 24import java.security.PrivateKey; 25import java.security.PublicKey; 26import java.security.SecureRandom; 27import java.security.cert.Certificate; 28import java.security.cert.CertificateFactory; 29import java.security.cert.X509Certificate; 30import java.text.SimpleDateFormat; 31import java.util.Date; 32 33import javax.security.auth.x500.X500Principal; 34 35public class AndroidKeyPairGeneratorTest extends AndroidTestCase { 36 private android.security.KeyStore mAndroidKeyStore; 37 38 private java.security.KeyPairGenerator mGenerator; 39 40 private static final String TEST_ALIAS_1 = "test1"; 41 42 private static final String TEST_ALIAS_2 = "test2"; 43 44 private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1"); 45 46 private static final X500Principal TEST_DN_2 = new X500Principal("CN=test2"); 47 48 private static final BigInteger TEST_SERIAL_1 = BigInteger.ONE; 49 50 private static final BigInteger TEST_SERIAL_2 = BigInteger.valueOf(2L); 51 52 private static final long NOW_MILLIS = System.currentTimeMillis(); 53 54 /* We have to round this off because X509v3 doesn't store milliseconds. */ 55 private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L)); 56 57 @SuppressWarnings("deprecation") 58 private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1); 59 60 @Override 61 protected void setUp() throws Exception { 62 mAndroidKeyStore = android.security.KeyStore.getInstance(); 63 64 assertTrue(mAndroidKeyStore.reset()); 65 66 assertFalse(mAndroidKeyStore.isUnlocked()); 67 68 mGenerator = java.security.KeyPairGenerator.getInstance("RSA", "AndroidKeyStore"); 69 } 70 71 private void setupPassword() { 72 assertTrue(mAndroidKeyStore.password("1111")); 73 assertTrue(mAndroidKeyStore.isUnlocked()); 74 75 String[] aliases = mAndroidKeyStore.saw(""); 76 assertNotNull(aliases); 77 assertEquals(0, aliases.length); 78 } 79 80 public void testKeyPairGenerator_Initialize_Params_Encrypted_Success() throws Exception { 81 setupPassword(); 82 83 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 84 .setAlias(TEST_ALIAS_1) 85 .setSubject(TEST_DN_1) 86 .setSerialNumber(TEST_SERIAL_1) 87 .setStartDate(NOW) 88 .setEndDate(NOW_PLUS_10_YEARS) 89 .setEncryptionRequired() 90 .build()); 91 } 92 93 public void testKeyPairGenerator_Initialize_KeySize_Encrypted_Failure() throws Exception { 94 setupPassword(); 95 96 try { 97 mGenerator.initialize(1024); 98 fail("KeyPairGenerator should not support setting the key size"); 99 } catch (IllegalArgumentException success) { 100 } 101 } 102 103 public void testKeyPairGenerator_Initialize_KeySizeAndSecureRandom_Encrypted_Failure() 104 throws Exception { 105 setupPassword(); 106 107 try { 108 mGenerator.initialize(1024, new SecureRandom()); 109 fail("KeyPairGenerator should not support setting the key size"); 110 } catch (IllegalArgumentException success) { 111 } 112 } 113 114 public void testKeyPairGenerator_Initialize_ParamsAndSecureRandom_Encrypted_Failure() 115 throws Exception { 116 setupPassword(); 117 118 mGenerator.initialize( 119 new KeyPairGeneratorSpec.Builder(getContext()) 120 .setAlias(TEST_ALIAS_1) 121 .setSubject(TEST_DN_1) 122 .setSerialNumber(TEST_SERIAL_1) 123 .setStartDate(NOW) 124 .setEndDate(NOW_PLUS_10_YEARS) 125 .setEncryptionRequired() 126 .build(), 127 new SecureRandom()); 128 } 129 130 public void testKeyPairGenerator_GenerateKeyPair_Encrypted_Success() throws Exception { 131 setupPassword(); 132 133 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 134 .setAlias(TEST_ALIAS_1) 135 .setSubject(TEST_DN_1) 136 .setSerialNumber(TEST_SERIAL_1) 137 .setStartDate(NOW) 138 .setEndDate(NOW_PLUS_10_YEARS) 139 .setEncryptionRequired() 140 .build()); 141 142 final KeyPair pair = mGenerator.generateKeyPair(); 143 assertNotNull("The KeyPair returned should not be null", pair); 144 145 assertKeyPairCorrect(pair, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS); 146 } 147 148 public void testKeyPairGenerator_GenerateKeyPair_Unencrypted_Success() throws Exception { 149 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 150 .setAlias(TEST_ALIAS_1) 151 .setSubject(TEST_DN_1) 152 .setSerialNumber(TEST_SERIAL_1) 153 .setStartDate(NOW) 154 .setEndDate(NOW_PLUS_10_YEARS) 155 .build()); 156 157 final KeyPair pair = mGenerator.generateKeyPair(); 158 assertNotNull("The KeyPair returned should not be null", pair); 159 160 assertKeyPairCorrect(pair, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS); 161 } 162 163 public void testKeyPairGenerator_GenerateKeyPair_Replaced_Success() throws Exception { 164 // Generate the first key 165 { 166 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 167 .setAlias(TEST_ALIAS_1) 168 .setSubject(TEST_DN_1) 169 .setSerialNumber(TEST_SERIAL_1) 170 .setStartDate(NOW) 171 .setEndDate(NOW_PLUS_10_YEARS) 172 .build()); 173 final KeyPair pair1 = mGenerator.generateKeyPair(); 174 assertNotNull("The KeyPair returned should not be null", pair1); 175 assertKeyPairCorrect(pair1, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW, 176 NOW_PLUS_10_YEARS); 177 } 178 179 // Replace the original key 180 { 181 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 182 .setAlias(TEST_ALIAS_2) 183 .setSubject(TEST_DN_2) 184 .setSerialNumber(TEST_SERIAL_2) 185 .setStartDate(NOW) 186 .setEndDate(NOW_PLUS_10_YEARS) 187 .build()); 188 final KeyPair pair2 = mGenerator.generateKeyPair(); 189 assertNotNull("The KeyPair returned should not be null", pair2); 190 assertKeyPairCorrect(pair2, TEST_ALIAS_2, TEST_DN_2, TEST_SERIAL_2, NOW, 191 NOW_PLUS_10_YEARS); 192 } 193 } 194 195 public void testKeyPairGenerator_GenerateKeyPair_Replaced_UnencryptedToEncrypted_Success() 196 throws Exception { 197 // Generate the first key 198 { 199 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 200 .setAlias(TEST_ALIAS_1) 201 .setSubject(TEST_DN_1) 202 .setSerialNumber(TEST_SERIAL_1) 203 .setStartDate(NOW) 204 .setEndDate(NOW_PLUS_10_YEARS) 205 .build()); 206 final KeyPair pair1 = mGenerator.generateKeyPair(); 207 assertNotNull("The KeyPair returned should not be null", pair1); 208 assertKeyPairCorrect(pair1, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW, 209 NOW_PLUS_10_YEARS); 210 } 211 212 // Attempt to replace previous key 213 { 214 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 215 .setAlias(TEST_ALIAS_1) 216 .setSubject(TEST_DN_2) 217 .setSerialNumber(TEST_SERIAL_2) 218 .setStartDate(NOW) 219 .setEndDate(NOW_PLUS_10_YEARS) 220 .setEncryptionRequired() 221 .build()); 222 try { 223 mGenerator.generateKeyPair(); 224 fail("Should not be able to generate encrypted key while not initialized"); 225 } catch (IllegalStateException expected) { 226 } 227 228 assertTrue(mAndroidKeyStore.password("1111")); 229 assertTrue(mAndroidKeyStore.isUnlocked()); 230 231 final KeyPair pair2 = mGenerator.generateKeyPair(); 232 assertNotNull("The KeyPair returned should not be null", pair2); 233 assertKeyPairCorrect(pair2, TEST_ALIAS_1, TEST_DN_2, TEST_SERIAL_2, NOW, 234 NOW_PLUS_10_YEARS); 235 } 236 } 237 238 private void assertKeyPairCorrect(KeyPair pair, String alias, X500Principal dn, 239 BigInteger serial, Date start, Date end) throws Exception { 240 final PublicKey pubKey = pair.getPublic(); 241 assertNotNull("The PublicKey for the KeyPair should be not null", pubKey); 242 243 final PrivateKey privKey = pair.getPrivate(); 244 assertNotNull("The PrivateKey for the KeyPair should be not null", privKey); 245 246 final byte[] userCertBytes = mAndroidKeyStore.get(Credentials.USER_CERTIFICATE + alias); 247 assertNotNull("The user certificate should exist for the generated entry", userCertBytes); 248 249 final CertificateFactory cf = CertificateFactory.getInstance("X.509"); 250 final Certificate userCert = cf 251 .generateCertificate(new ByteArrayInputStream(userCertBytes)); 252 253 assertTrue("Certificate should be in X.509 format", userCert instanceof X509Certificate); 254 255 final X509Certificate x509userCert = (X509Certificate) userCert; 256 257 assertEquals("PublicKey used to sign certificate should match one returned in KeyPair", 258 pubKey, x509userCert.getPublicKey()); 259 260 assertEquals("The Subject DN should be the one passed into the params", dn, 261 x509userCert.getSubjectDN()); 262 263 assertEquals("The Issuer DN should be the same as the Subject DN", dn, 264 x509userCert.getIssuerDN()); 265 266 assertEquals("The Serial should be the one passed into the params", serial, 267 x509userCert.getSerialNumber()); 268 269 assertDateEquals("The notBefore date should be the one passed into the params", start, 270 x509userCert.getNotBefore()); 271 272 assertDateEquals("The notAfter date should be the one passed into the params", end, 273 x509userCert.getNotAfter()); 274 275 x509userCert.verify(pubKey); 276 277 final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias); 278 assertNull("A list of CA certificates should not exist for the generated entry", caCerts); 279 280 final byte[] pubKeyBytes = mAndroidKeyStore.getPubkey(Credentials.USER_PRIVATE_KEY + alias); 281 assertNotNull("The keystore should return the public key for the generated key", 282 pubKeyBytes); 283 } 284 285 private static void assertDateEquals(String message, Date date1, Date date2) throws Exception { 286 SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss"); 287 288 String result1 = formatter.format(date1); 289 String result2 = formatter.format(date2); 290 291 assertEquals(message, result1, result2); 292 } 293} 294