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.keystore; 18 19import android.security.Credentials; 20import android.security.KeyPairGeneratorSpec; 21import android.security.KeyStore; 22import android.security.keymaster.ExportResult; 23import android.security.keymaster.KeymasterDefs; 24import android.test.AndroidTestCase; 25 26import java.io.ByteArrayInputStream; 27import java.math.BigInteger; 28import java.security.KeyPair; 29import java.security.KeyPairGenerator; 30import java.security.PrivateKey; 31import java.security.PublicKey; 32import java.security.SecureRandom; 33import java.security.cert.Certificate; 34import java.security.cert.CertificateFactory; 35import java.security.cert.X509Certificate; 36import java.security.interfaces.ECKey; 37import java.security.interfaces.ECPublicKey; 38import java.security.interfaces.RSAKey; 39import java.security.interfaces.RSAPublicKey; 40import java.security.spec.AlgorithmParameterSpec; 41import java.security.spec.RSAKeyGenParameterSpec; 42import java.text.SimpleDateFormat; 43import java.util.Arrays; 44import java.util.Date; 45 46import javax.security.auth.x500.X500Principal; 47 48public class AndroidKeyPairGeneratorTest extends AndroidTestCase { 49 private android.security.KeyStore mAndroidKeyStore; 50 51 private java.security.KeyPairGenerator mGenerator; 52 53 private static final String TEST_ALIAS_1 = "test1"; 54 55 private static final String TEST_ALIAS_2 = "test2"; 56 57 private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1"); 58 59 private static final X500Principal TEST_DN_2 = new X500Principal("CN=test2"); 60 61 private static final BigInteger TEST_SERIAL_1 = BigInteger.ONE; 62 63 private static final BigInteger TEST_SERIAL_2 = BigInteger.valueOf(2L); 64 65 private static final long NOW_MILLIS = System.currentTimeMillis(); 66 67 /* We have to round this off because X509v3 doesn't store milliseconds. */ 68 private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L)); 69 70 @SuppressWarnings("deprecation") 71 private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1); 72 73 @Override 74 protected void setUp() throws Exception { 75 mAndroidKeyStore = android.security.KeyStore.getInstance(); 76 77 assertTrue(mAndroidKeyStore.reset()); 78 79 assertFalse(mAndroidKeyStore.isUnlocked()); 80 81 mGenerator = java.security.KeyPairGenerator.getInstance("RSA", "AndroidKeyStore"); 82 } 83 84 private void setupPassword() { 85 assertTrue(mAndroidKeyStore.onUserPasswordChanged("1111")); 86 assertTrue(mAndroidKeyStore.isUnlocked()); 87 88 String[] aliases = mAndroidKeyStore.list(""); 89 assertNotNull(aliases); 90 assertEquals(0, aliases.length); 91 } 92 93 public void testKeyPairGenerator_Initialize_Params_Encrypted_Success() throws Exception { 94 setupPassword(); 95 96 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 97 .setAlias(TEST_ALIAS_1) 98 .setSubject(TEST_DN_1) 99 .setSerialNumber(TEST_SERIAL_1) 100 .setStartDate(NOW) 101 .setEndDate(NOW_PLUS_10_YEARS) 102 .setEncryptionRequired() 103 .build()); 104 } 105 106 public void testKeyPairGenerator_Initialize_KeySize_Encrypted_Failure() throws Exception { 107 setupPassword(); 108 109 try { 110 mGenerator.initialize(1024); 111 fail("KeyPairGenerator should not support setting the key size"); 112 } catch (IllegalArgumentException success) { 113 } 114 } 115 116 public void testKeyPairGenerator_Initialize_KeySizeAndSecureRandom_Encrypted_Failure() 117 throws Exception { 118 setupPassword(); 119 120 try { 121 mGenerator.initialize(1024, new SecureRandom()); 122 fail("KeyPairGenerator should not support setting the key size"); 123 } catch (IllegalArgumentException success) { 124 } 125 } 126 127 public void testKeyPairGenerator_Initialize_ParamsAndSecureRandom_Encrypted_Failure() 128 throws Exception { 129 setupPassword(); 130 131 mGenerator.initialize( 132 new KeyPairGeneratorSpec.Builder(getContext()) 133 .setAlias(TEST_ALIAS_1) 134 .setKeyType("RSA") 135 .setKeySize(1024) 136 .setSubject(TEST_DN_1) 137 .setSerialNumber(TEST_SERIAL_1) 138 .setStartDate(NOW) 139 .setEndDate(NOW_PLUS_10_YEARS) 140 .setEncryptionRequired() 141 .build(), 142 new SecureRandom()); 143 } 144 145 public void testKeyPairGenerator_GenerateKeyPair_Encrypted_Success() throws Exception { 146 setupPassword(); 147 148 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 149 .setAlias(TEST_ALIAS_1) 150 .setSubject(TEST_DN_1) 151 .setSerialNumber(TEST_SERIAL_1) 152 .setStartDate(NOW) 153 .setEndDate(NOW_PLUS_10_YEARS) 154 .setEncryptionRequired() 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, "RSA", 2048, null, TEST_DN_1, TEST_SERIAL_1, NOW, 161 NOW_PLUS_10_YEARS); 162 } 163 164 public void testKeyPairGenerator_GenerateKeyPair_EC_Unencrypted_Success() throws Exception { 165 KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "AndroidKeyStore"); 166 generator.initialize(new KeyGenParameterSpec.Builder( 167 TEST_ALIAS_1, 168 KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) 169 .setCertificateSubject(TEST_DN_1) 170 .setCertificateSerialNumber(TEST_SERIAL_1) 171 .setCertificateNotBefore(NOW) 172 .setCertificateNotAfter(NOW_PLUS_10_YEARS) 173 .setDigests(KeyProperties.DIGEST_SHA256) 174 .build()); 175 176 final KeyPair pair = generator.generateKeyPair(); 177 assertNotNull("The KeyPair returned should not be null", pair); 178 179 assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 256, null, TEST_DN_1, TEST_SERIAL_1, NOW, 180 NOW_PLUS_10_YEARS); 181 } 182 183 public void testKeyPairGenerator_Legacy_GenerateKeyPair_EC_Unencrypted_Success() 184 throws Exception { 185 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 186 .setAlias(TEST_ALIAS_1) 187 .setKeyType("EC") 188 .setSubject(TEST_DN_1) 189 .setSerialNumber(TEST_SERIAL_1) 190 .setStartDate(NOW) 191 .setEndDate(NOW_PLUS_10_YEARS) 192 .build()); 193 194 final KeyPair pair = mGenerator.generateKeyPair(); 195 assertNotNull("The KeyPair returned should not be null", pair); 196 197 assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 256, null, TEST_DN_1, TEST_SERIAL_1, NOW, 198 NOW_PLUS_10_YEARS); 199 } 200 201 public void testKeyPairGenerator_GenerateKeyPair_EC_P521_Unencrypted_Success() throws Exception { 202 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 203 .setAlias(TEST_ALIAS_1) 204 .setKeyType("EC") 205 .setKeySize(521) 206 .setSubject(TEST_DN_1) 207 .setSerialNumber(TEST_SERIAL_1) 208 .setStartDate(NOW) 209 .setEndDate(NOW_PLUS_10_YEARS) 210 .build()); 211 212 final KeyPair pair = mGenerator.generateKeyPair(); 213 assertNotNull("The KeyPair returned should not be null", pair); 214 215 assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 521, null, TEST_DN_1, TEST_SERIAL_1, NOW, 216 NOW_PLUS_10_YEARS); 217 } 218 219 public void testKeyPairGenerator_GenerateKeyPair_RSA_Unencrypted_Success() throws Exception { 220 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 221 .setAlias(TEST_ALIAS_1) 222 .setSubject(TEST_DN_1) 223 .setSerialNumber(TEST_SERIAL_1) 224 .setStartDate(NOW) 225 .setEndDate(NOW_PLUS_10_YEARS) 226 .build()); 227 228 final KeyPair pair = mGenerator.generateKeyPair(); 229 assertNotNull("The KeyPair returned should not be null", pair); 230 231 assertKeyPairCorrect(pair, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_1, TEST_SERIAL_1, NOW, 232 NOW_PLUS_10_YEARS); 233 } 234 235 public void testKeyPairGenerator_GenerateKeyPair_RSA_WithParams_Unencrypted_Success() 236 throws Exception { 237 AlgorithmParameterSpec spec = new RSAKeyGenParameterSpec(1024, BigInteger.valueOf(3L)); 238 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 239 .setAlias(TEST_ALIAS_1) 240 .setKeySize(1024) 241 .setAlgorithmParameterSpec(spec) 242 .setSubject(TEST_DN_1) 243 .setSerialNumber(TEST_SERIAL_1) 244 .setStartDate(NOW) 245 .setEndDate(NOW_PLUS_10_YEARS) 246 .build()); 247 248 final KeyPair pair = mGenerator.generateKeyPair(); 249 assertNotNull("The KeyPair returned should not be null", pair); 250 251 assertKeyPairCorrect(pair, TEST_ALIAS_1, "RSA", 1024, spec, TEST_DN_1, TEST_SERIAL_1, NOW, 252 NOW_PLUS_10_YEARS); 253 } 254 255 public void testKeyPairGenerator_GenerateKeyPair_Replaced_Success() throws Exception { 256 // Generate the first key 257 { 258 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 259 .setAlias(TEST_ALIAS_1) 260 .setSubject(TEST_DN_1) 261 .setSerialNumber(TEST_SERIAL_1) 262 .setStartDate(NOW) 263 .setEndDate(NOW_PLUS_10_YEARS) 264 .build()); 265 final KeyPair pair1 = mGenerator.generateKeyPair(); 266 assertNotNull("The KeyPair returned should not be null", pair1); 267 assertKeyPairCorrect(pair1, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_1, TEST_SERIAL_1, 268 NOW, NOW_PLUS_10_YEARS); 269 } 270 271 // Replace the original key 272 { 273 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 274 .setAlias(TEST_ALIAS_2) 275 .setSubject(TEST_DN_2) 276 .setSerialNumber(TEST_SERIAL_2) 277 .setStartDate(NOW) 278 .setEndDate(NOW_PLUS_10_YEARS) 279 .build()); 280 final KeyPair pair2 = mGenerator.generateKeyPair(); 281 assertNotNull("The KeyPair returned should not be null", pair2); 282 assertKeyPairCorrect(pair2, TEST_ALIAS_2, "RSA", 2048, null, TEST_DN_2, TEST_SERIAL_2, 283 NOW, NOW_PLUS_10_YEARS); 284 } 285 } 286 287 public void testKeyPairGenerator_GenerateKeyPair_Replaced_UnencryptedToEncrypted_Success() 288 throws Exception { 289 // Generate the first key 290 { 291 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 292 .setAlias(TEST_ALIAS_1) 293 .setSubject(TEST_DN_1) 294 .setSerialNumber(TEST_SERIAL_1) 295 .setStartDate(NOW) 296 .setEndDate(NOW_PLUS_10_YEARS) 297 .build()); 298 final KeyPair pair1 = mGenerator.generateKeyPair(); 299 assertNotNull("The KeyPair returned should not be null", pair1); 300 assertKeyPairCorrect(pair1, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_1, TEST_SERIAL_1, 301 NOW, NOW_PLUS_10_YEARS); 302 } 303 304 // Attempt to replace previous key 305 { 306 mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) 307 .setAlias(TEST_ALIAS_1) 308 .setSubject(TEST_DN_2) 309 .setSerialNumber(TEST_SERIAL_2) 310 .setStartDate(NOW) 311 .setEndDate(NOW_PLUS_10_YEARS) 312 .setEncryptionRequired() 313 .build()); 314 try { 315 mGenerator.generateKeyPair(); 316 fail("Should not be able to generate encrypted key while not initialized"); 317 } catch (IllegalStateException expected) { 318 } 319 320 assertTrue(mAndroidKeyStore.onUserPasswordChanged("1111")); 321 assertTrue(mAndroidKeyStore.isUnlocked()); 322 323 final KeyPair pair2 = mGenerator.generateKeyPair(); 324 assertNotNull("The KeyPair returned should not be null", pair2); 325 assertKeyPairCorrect(pair2, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_2, TEST_SERIAL_2, 326 NOW, NOW_PLUS_10_YEARS); 327 } 328 } 329 330 private void assertKeyPairCorrect(KeyPair pair, String alias, String keyType, int keySize, 331 AlgorithmParameterSpec spec, X500Principal dn, BigInteger serial, Date start, Date end) 332 throws Exception { 333 final PublicKey pubKey = pair.getPublic(); 334 assertNotNull("The PublicKey for the KeyPair should be not null", pubKey); 335 assertEquals(keyType, pubKey.getAlgorithm()); 336 337 if ("EC".equalsIgnoreCase(keyType)) { 338 assertEquals("Curve should be what was specified during initialization", keySize, 339 ((ECPublicKey) pubKey).getParams().getCurve().getField().getFieldSize()); 340 } else if ("RSA".equalsIgnoreCase(keyType)) { 341 RSAPublicKey rsaPubKey = (RSAPublicKey) pubKey; 342 assertEquals("Modulus size should be what is specified during initialization", 343 (keySize + 7) & ~7, (rsaPubKey.getModulus().bitLength() + 7) & ~7); 344 if (spec != null) { 345 RSAKeyGenParameterSpec params = (RSAKeyGenParameterSpec) spec; 346 assertEquals((keySize + 7) & ~7, (params.getKeysize() + 7) & ~7); 347 assertEquals(params.getPublicExponent(), rsaPubKey.getPublicExponent()); 348 } 349 } 350 351 final PrivateKey privKey = pair.getPrivate(); 352 assertNotNull("The PrivateKey for the KeyPair should be not null", privKey); 353 assertEquals(keyType, privKey.getAlgorithm()); 354 355 if ("EC".equalsIgnoreCase(keyType)) { 356 assertTrue("EC private key must be instanceof ECKey: " + privKey.getClass().getName(), 357 privKey instanceof ECKey); 358 assertEquals("Private and public key must have the same EC parameters", 359 ((ECKey) pubKey).getParams(), ((ECKey) privKey).getParams()); 360 } else if ("RSA".equalsIgnoreCase(keyType)) { 361 assertTrue("RSA private key must be instance of RSAKey: " 362 + privKey.getClass().getName(), 363 privKey instanceof RSAKey); 364 assertEquals("Private and public key must have the same RSA modulus", 365 ((RSAKey) pubKey).getModulus(), ((RSAKey) privKey).getModulus()); 366 } 367 368 final byte[] userCertBytes = mAndroidKeyStore.get(Credentials.USER_CERTIFICATE + alias); 369 assertNotNull("The user certificate should exist for the generated entry", userCertBytes); 370 371 final CertificateFactory cf = CertificateFactory.getInstance("X.509"); 372 final Certificate userCert = 373 cf.generateCertificate(new ByteArrayInputStream(userCertBytes)); 374 375 assertTrue("Certificate should be in X.509 format", userCert instanceof X509Certificate); 376 377 final X509Certificate x509userCert = (X509Certificate) userCert; 378 379 assertEquals( 380 "Public key used to sign certificate should have the same algorithm as in KeyPair", 381 pubKey.getAlgorithm(), x509userCert.getPublicKey().getAlgorithm()); 382 383 assertEquals("PublicKey used to sign certificate should match one returned in KeyPair", 384 pubKey, 385 AndroidKeyStoreProvider.getAndroidKeyStorePublicKey( 386 Credentials.USER_PRIVATE_KEY + alias, 387 KeyStore.UID_SELF, 388 x509userCert.getPublicKey().getAlgorithm(), 389 x509userCert.getPublicKey().getEncoded())); 390 391 assertEquals("The Subject DN should be the one passed into the params", dn, 392 x509userCert.getSubjectDN()); 393 394 assertEquals("The Issuer DN should be the same as the Subject DN", dn, 395 x509userCert.getIssuerDN()); 396 397 assertEquals("The Serial should be the one passed into the params", serial, 398 x509userCert.getSerialNumber()); 399 400 assertDateEquals("The notBefore date should be the one passed into the params", start, 401 x509userCert.getNotBefore()); 402 403 assertDateEquals("The notAfter date should be the one passed into the params", end, 404 x509userCert.getNotAfter()); 405 406 // Assert that the cert's signature verifies using the public key from generated KeyPair 407 x509userCert.verify(pubKey); 408 // Assert that the cert's signature verifies using the public key from the cert itself. 409 x509userCert.verify(x509userCert.getPublicKey()); 410 411 final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias); 412 assertNull("A list of CA certificates should not exist for the generated entry", caCerts); 413 414 ExportResult exportResult = mAndroidKeyStore.exportKey( 415 Credentials.USER_PRIVATE_KEY + alias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null); 416 assertEquals(KeyStore.NO_ERROR, exportResult.resultCode); 417 final byte[] pubKeyBytes = exportResult.exportData; 418 assertNotNull("The keystore should return the public key for the generated key", 419 pubKeyBytes); 420 assertTrue("Public key X.509 format should be as expected", 421 Arrays.equals(pubKey.getEncoded(), pubKeyBytes)); 422 } 423 424 private static void assertDateEquals(String message, Date date1, Date date2) throws Exception { 425 SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss"); 426 427 String result1 = formatter.format(date1); 428 String result2 = formatter.format(date2); 429 430 assertEquals(message, result1, result2); 431 } 432} 433