1/* 2 * Copyright (C) 2010 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 libcore.java.security; 18 19import static org.junit.Assert.assertEquals; 20 21import com.android.org.bouncycastle.asn1.DEROctetString; 22import com.android.org.bouncycastle.asn1.x500.X500Name; 23import com.android.org.bouncycastle.asn1.x509.BasicConstraints; 24import com.android.org.bouncycastle.asn1.x509.CRLReason; 25import com.android.org.bouncycastle.asn1.x509.ExtendedKeyUsage; 26import com.android.org.bouncycastle.asn1.x509.Extension; 27import com.android.org.bouncycastle.asn1.x509.GeneralName; 28import com.android.org.bouncycastle.asn1.x509.GeneralNames; 29import com.android.org.bouncycastle.asn1.x509.GeneralSubtree; 30import com.android.org.bouncycastle.asn1.x509.KeyPurposeId; 31import com.android.org.bouncycastle.asn1.x509.KeyUsage; 32import com.android.org.bouncycastle.asn1.x509.NameConstraints; 33import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 34import com.android.org.bouncycastle.cert.X509CertificateHolder; 35import com.android.org.bouncycastle.cert.X509v3CertificateBuilder; 36import com.android.org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; 37import com.android.org.bouncycastle.cert.ocsp.BasicOCSPResp; 38import com.android.org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder; 39import com.android.org.bouncycastle.cert.ocsp.CertificateID; 40import com.android.org.bouncycastle.cert.ocsp.CertificateStatus; 41import com.android.org.bouncycastle.cert.ocsp.OCSPResp; 42import com.android.org.bouncycastle.cert.ocsp.OCSPRespBuilder; 43import com.android.org.bouncycastle.cert.ocsp.RevokedStatus; 44import com.android.org.bouncycastle.jce.provider.BouncyCastleProvider; 45import com.android.org.bouncycastle.operator.DigestCalculatorProvider; 46import com.android.org.bouncycastle.operator.bc.BcDigestCalculatorProvider; 47import com.android.org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; 48import java.io.ByteArrayInputStream; 49import java.io.IOException; 50import java.io.PrintStream; 51import java.math.BigInteger; 52import java.security.KeyPair; 53import java.security.KeyPairGenerator; 54import java.security.KeyStore; 55import java.security.KeyStore.PasswordProtection; 56import java.security.KeyStore.PrivateKeyEntry; 57import java.security.KeyStore.TrustedCertificateEntry; 58import java.security.KeyStoreException; 59import java.security.NoSuchAlgorithmException; 60import java.security.Principal; 61import java.security.PrivateKey; 62import java.security.PublicKey; 63import java.security.SecureRandom; 64import java.security.Security; 65import java.security.UnrecoverableEntryException; 66import java.security.UnrecoverableKeyException; 67import java.security.cert.Certificate; 68import java.security.cert.CertificateException; 69import java.security.cert.CertificateFactory; 70import java.security.cert.X509Certificate; 71import java.security.spec.AlgorithmParameterSpec; 72import java.util.ArrayList; 73import java.util.Collections; 74import java.util.Date; 75import java.util.List; 76import javax.crypto.spec.DHParameterSpec; 77import javax.net.ssl.KeyManager; 78import javax.net.ssl.KeyManagerFactory; 79import javax.net.ssl.TrustManager; 80import javax.net.ssl.TrustManagerFactory; 81import javax.security.auth.x500.X500Principal; 82import libcore.javax.net.ssl.TestKeyManager; 83import libcore.javax.net.ssl.TestTrustManager; 84 85/** 86 * TestKeyStore is a convenience class for other tests that 87 * want a canned KeyStore with a variety of key pairs. 88 * 89 * Creating a key store is relatively slow, so a singleton instance is 90 * accessible via TestKeyStore.get(). 91 */ 92public final class TestKeyStore { 93 /** Size of DSA keys to generate for testing. */ 94 private static final int DSA_KEY_SIZE_BITS = 1024; 95 96 /** Size of EC keys to generate for testing. */ 97 private static final int EC_KEY_SIZE_BITS = 256; 98 99 /** Size of RSA keys to generate for testing. */ 100 private static final int RSA_KEY_SIZE_BITS = 1024; 101 102 // Generated with: openssl dhparam -C 1024 103 private static final BigInteger DH_PARAMS_P = new BigInteger(1, new byte[] { 104 (byte) 0xA2, (byte) 0x31, (byte) 0xB4, (byte) 0xB3, (byte) 0x6D, (byte) 0x9B, 105 (byte) 0x7E, (byte) 0xF4, (byte) 0xE7, (byte) 0x21, (byte) 0x51, (byte) 0x40, 106 (byte) 0xEB, (byte) 0xC6, (byte) 0xB6, (byte) 0xD6, (byte) 0x54, (byte) 0x56, 107 (byte) 0x72, (byte) 0xBE, (byte) 0x43, (byte) 0x18, (byte) 0x30, (byte) 0x5C, 108 (byte) 0x15, (byte) 0x5A, (byte) 0xF9, (byte) 0x19, (byte) 0x62, (byte) 0xAD, 109 (byte) 0xF4, (byte) 0x29, (byte) 0xCB, (byte) 0xC6, (byte) 0xF6, (byte) 0x64, 110 (byte) 0x0B, (byte) 0x9D, (byte) 0x23, (byte) 0x80, (byte) 0xF9, (byte) 0x5B, 111 (byte) 0x1C, (byte) 0x1C, (byte) 0x6A, (byte) 0xB4, (byte) 0xEA, (byte) 0xB9, 112 (byte) 0x80, (byte) 0x98, (byte) 0x8B, (byte) 0xAF, (byte) 0x15, (byte) 0xA8, 113 (byte) 0x5C, (byte) 0xC4, (byte) 0xB0, (byte) 0x41, (byte) 0x29, (byte) 0x66, 114 (byte) 0x9F, (byte) 0x9F, (byte) 0x1F, (byte) 0x88, (byte) 0x50, (byte) 0x97, 115 (byte) 0x38, (byte) 0x0B, (byte) 0x01, (byte) 0x16, (byte) 0xD6, (byte) 0x84, 116 (byte) 0x1D, (byte) 0x48, (byte) 0x6F, (byte) 0x7C, (byte) 0x06, (byte) 0x8C, 117 (byte) 0x6E, (byte) 0x68, (byte) 0xCD, (byte) 0x38, (byte) 0xE6, (byte) 0x22, 118 (byte) 0x30, (byte) 0x61, (byte) 0x37, (byte) 0x02, (byte) 0x3D, (byte) 0x47, 119 (byte) 0x62, (byte) 0xCE, (byte) 0xB9, (byte) 0x1A, (byte) 0x69, (byte) 0x9D, 120 (byte) 0xA1, (byte) 0x9F, (byte) 0x10, (byte) 0xA1, (byte) 0xAA, (byte) 0x70, 121 (byte) 0xF7, (byte) 0x27, (byte) 0x9C, (byte) 0xD4, (byte) 0xA5, (byte) 0x15, 122 (byte) 0xE2, (byte) 0x15, (byte) 0x0C, (byte) 0x20, (byte) 0x90, (byte) 0x08, 123 (byte) 0xB6, (byte) 0xF5, (byte) 0xDF, (byte) 0x1C, (byte) 0xCB, (byte) 0x82, 124 (byte) 0x6D, (byte) 0xC0, (byte) 0xE1, (byte) 0xBD, (byte) 0xCC, (byte) 0x4A, 125 (byte) 0x76, (byte) 0xE3, 126 }); 127 128 // generator of 2 129 private static final BigInteger DH_PARAMS_G = BigInteger.valueOf(2); 130 131 private static TestKeyStore ROOT_CA; 132 private static TestKeyStore INTERMEDIATE_CA; 133 private static TestKeyStore INTERMEDIATE_CA_2; 134 private static TestKeyStore INTERMEDIATE_CA_EC; 135 136 private static TestKeyStore SERVER; 137 private static TestKeyStore CLIENT; 138 private static TestKeyStore CLIENT_CERTIFICATE; 139 private static TestKeyStore CLIENT_EC_RSA_CERTIFICATE; 140 private static TestKeyStore CLIENT_EC_EC_CERTIFICATE; 141 142 private static TestKeyStore CLIENT_2; 143 144 static { 145 if (StandardNames.IS_RI) { 146 // Needed to create BKS keystore but add at end so most 147 // algorithm come from the default providers 148 Security.insertProviderAt(new BouncyCastleProvider(), 149 Security.getProviders().length+1); 150 } else if (!BouncyCastleProvider.class.getName().startsWith("com.android")) { 151 // If we run outside of the Android system, we need to make sure 152 // that the BouncyCastleProvider's static field keyInfoConverters 153 // is initialized. This happens in the default constructor only. 154 new BouncyCastleProvider(); 155 } 156 } 157 158 private static final byte[] LOCAL_HOST_ADDRESS = { 127, 0, 0, 1 }; 159 private static final String LOCAL_HOST_NAME = "localhost"; 160 161 public final KeyStore keyStore; 162 public final char[] storePassword; 163 public final char[] keyPassword; 164 public final KeyManager[] keyManagers; 165 public final TrustManager[] trustManagers; 166 public final TestTrustManager trustManager; 167 168 private TestKeyStore(KeyStore keyStore, char[] storePassword, char[] keyPassword) { 169 this.keyStore = keyStore; 170 this.storePassword = storePassword; 171 this.keyPassword = keyPassword; 172 this.keyManagers = createKeyManagers(keyStore, storePassword); 173 this.trustManagers = createTrustManagers(keyStore); 174 this.trustManager = (TestTrustManager)trustManagers[0]; 175 } 176 177 public static KeyManager[] createKeyManagers(KeyStore keyStore, char[] storePassword) { 178 try { 179 String kmfa = KeyManagerFactory.getDefaultAlgorithm(); 180 KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfa); 181 kmf.init(keyStore, storePassword); 182 return TestKeyManager.wrap(kmf.getKeyManagers()); 183 } catch (Exception e) { 184 throw new RuntimeException(e); 185 } 186 } 187 188 public static TrustManager[] createTrustManagers(final KeyStore keyStore) { 189 try { 190 String tmfa = TrustManagerFactory.getDefaultAlgorithm(); 191 TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfa); 192 tmf.init(keyStore); 193 return TestTrustManager.wrap(tmf.getTrustManagers()); 194 } catch (Exception e) { 195 throw new RuntimeException(e); 196 } 197 } 198 199 /** 200 * Lazily create shared test certificates. 201 */ 202 private static synchronized void initCerts() { 203 if (ROOT_CA != null) { 204 return; 205 } 206 ROOT_CA = new Builder() 207 .aliasPrefix("RootCA") 208 .subject("CN=Test Root Certificate Authority") 209 .ca(true) 210 .certificateSerialNumber(BigInteger.valueOf(1)) 211 .build(); 212 INTERMEDIATE_CA_EC = new Builder() 213 .aliasPrefix("IntermediateCA-EC") 214 .keyAlgorithms("EC") 215 .subject("CN=Test Intermediate Certificate Authority ECDSA") 216 .ca(true) 217 .signer(ROOT_CA.getPrivateKey("RSA", "RSA")) 218 .rootCa(ROOT_CA.getRootCertificate("RSA")) 219 .certificateSerialNumber(BigInteger.valueOf(2)) 220 .build(); 221 INTERMEDIATE_CA = new Builder() 222 .aliasPrefix("IntermediateCA") 223 .subject("CN=Test Intermediate Certificate Authority") 224 .ca(true) 225 .signer(ROOT_CA.getPrivateKey("RSA", "RSA")) 226 .rootCa(ROOT_CA.getRootCertificate("RSA")) 227 .certificateSerialNumber(BigInteger.valueOf(2)) 228 .build(); 229 SERVER = new Builder() 230 .aliasPrefix("server") 231 .signer(INTERMEDIATE_CA.getPrivateKey("RSA", "RSA")) 232 .rootCa(INTERMEDIATE_CA.getRootCertificate("RSA")) 233 .addSubjectAltName(new GeneralName(GeneralName.dNSName, LOCAL_HOST_NAME)) 234 .certificateSerialNumber(BigInteger.valueOf(3)) 235 .build(); 236 CLIENT = new TestKeyStore(createClient(INTERMEDIATE_CA.keyStore), null, null); 237 CLIENT_EC_RSA_CERTIFICATE = new Builder() 238 .aliasPrefix("client-ec") 239 .keyAlgorithms("EC") 240 .subject("emailAddress=test-ec@user") 241 .signer(INTERMEDIATE_CA.getPrivateKey("RSA", "RSA")) 242 .rootCa(INTERMEDIATE_CA.getRootCertificate("RSA")) 243 .build(); 244 CLIENT_EC_EC_CERTIFICATE = new Builder() 245 .aliasPrefix("client-ec") 246 .keyAlgorithms("EC") 247 .subject("emailAddress=test-ec@user") 248 .signer(INTERMEDIATE_CA_EC.getPrivateKey("EC", "RSA")) 249 .rootCa(INTERMEDIATE_CA_EC.getRootCertificate("RSA")) 250 .build(); 251 CLIENT_CERTIFICATE = new Builder() 252 .aliasPrefix("client") 253 .subject("emailAddress=test@user") 254 .signer(INTERMEDIATE_CA.getPrivateKey("RSA", "RSA")) 255 .rootCa(INTERMEDIATE_CA.getRootCertificate("RSA")) 256 .build(); 257 TestKeyStore rootCa2 = new Builder() 258 .aliasPrefix("RootCA2") 259 .subject("CN=Test Root Certificate Authority 2") 260 .ca(true) 261 .build(); 262 INTERMEDIATE_CA_2 = new Builder() 263 .aliasPrefix("IntermediateCA") 264 .subject("CN=Test Intermediate Certificate Authority") 265 .ca(true) 266 .signer(rootCa2.getPrivateKey("RSA", "RSA")) 267 .rootCa(rootCa2.getRootCertificate("RSA")) 268 .build(); 269 CLIENT_2 = new TestKeyStore(createClient(rootCa2.keyStore), null, null); 270 } 271 272 /** 273 * Return an root CA that can be used to issue new certificates. 274 */ 275 public static TestKeyStore getRootCa() { 276 initCerts(); 277 return ROOT_CA; 278 } 279 280 /** 281 * Return an intermediate CA that can be used to issue new certificates. 282 */ 283 public static TestKeyStore getIntermediateCa() { 284 initCerts(); 285 return INTERMEDIATE_CA; 286 } 287 288 /** 289 * Return an intermediate CA that can be used to issue new certificates. 290 */ 291 public static TestKeyStore getIntermediateCa2() { 292 initCerts(); 293 return INTERMEDIATE_CA_2; 294 } 295 296 /** 297 * Return a server keystore with a matched RSA certificate and 298 * private key as well as a CA certificate. 299 */ 300 public static TestKeyStore getServer() { 301 initCerts(); 302 return SERVER; 303 } 304 305 /** 306 * Return a keystore with a CA certificate 307 */ 308 public static TestKeyStore getClient() { 309 initCerts(); 310 return CLIENT; 311 } 312 313 /** 314 * Return a client keystore with a matched RSA certificate and 315 * private key as well as a CA certificate. 316 */ 317 public static TestKeyStore getClientCertificate() { 318 initCerts(); 319 return CLIENT_CERTIFICATE; 320 } 321 322 /** 323 * Return a client keystore with a matched RSA certificate and 324 * private key as well as a CA certificate. 325 */ 326 public static TestKeyStore getClientEcRsaCertificate() { 327 initCerts(); 328 return CLIENT_EC_RSA_CERTIFICATE; 329 } 330 331 /** 332 * Return a client keystore with a matched RSA certificate and 333 * private key as well as a CA certificate. 334 */ 335 public static TestKeyStore getClientEcEcCertificate() { 336 initCerts(); 337 return CLIENT_EC_EC_CERTIFICATE; 338 } 339 340 /** 341 * Return a keystore with a second CA certificate that does not 342 * trust the server certificate returned by getServer for negative 343 * testing. 344 */ 345 public static TestKeyStore getClientCA2() { 346 initCerts(); 347 return CLIENT_2; 348 } 349 350 /** 351 * Creates KeyStores containing the requested key types. Since key 352 * generation can be expensive, most tests should reuse the RSA-only 353 * singleton instance returned by TestKeyStore.get. 354 */ 355 public static class Builder { 356 private String[] keyAlgorithms = { "RSA" }; 357 private char[] storePassword; 358 private char[] keyPassword; 359 private String aliasPrefix; 360 private X500Principal subject; 361 private int keyUsage; 362 private boolean ca; 363 private PrivateKeyEntry privateEntry; 364 private PrivateKeyEntry signer; 365 private Certificate rootCa; 366 private final List<KeyPurposeId> extendedKeyUsages = new ArrayList<KeyPurposeId>(); 367 private final List<Boolean> criticalExtendedKeyUsages = new ArrayList<Boolean>(); 368 private final List<GeneralName> subjectAltNames = new ArrayList<GeneralName>(); 369 private final List<GeneralSubtree> permittedNameConstraints 370 = new ArrayList<GeneralSubtree>(); 371 private final List<GeneralSubtree> excludedNameConstraints 372 = new ArrayList<GeneralSubtree>(); 373 // Generated randomly if not set 374 private BigInteger certificateSerialNumber = null; 375 376 public Builder() { 377 subject = localhost(); 378 } 379 380 /** 381 * Sets the requested key types to generate and include. The default is 382 * RSA only. 383 */ 384 public Builder keyAlgorithms(String... keyAlgorithms) { 385 this.keyAlgorithms = keyAlgorithms; 386 return this; 387 } 388 389 /** A unique prefix to identify the key aliases */ 390 public Builder aliasPrefix(String aliasPrefix) { 391 this.aliasPrefix = aliasPrefix; 392 return this; 393 } 394 395 /** 396 * Sets the subject common name. The default is the local host's 397 * canonical name. 398 */ 399 public Builder subject(X500Principal subject) { 400 this.subject = subject; 401 return this; 402 } 403 404 public Builder subject(String commonName) { 405 return subject(new X500Principal(commonName)); 406 } 407 408 /** {@link KeyUsage} bit mask for 2.5.29.15 extension */ 409 public Builder keyUsage(int keyUsage) { 410 this.keyUsage = keyUsage; 411 return this; 412 } 413 414 /** true If the keys being created are for a CA */ 415 public Builder ca(boolean ca) { 416 this.ca = ca; 417 return this; 418 } 419 420 /** a private key entry to use for the generation of the certificate */ 421 public Builder privateEntry(PrivateKeyEntry privateEntry) { 422 this.privateEntry = privateEntry; 423 return this; 424 } 425 426 /** a private key entry to be used for signing, otherwise self-sign */ 427 public Builder signer(PrivateKeyEntry signer) { 428 this.signer = signer; 429 return this; 430 } 431 432 /** a root CA to include in the final store */ 433 public Builder rootCa(Certificate rootCa) { 434 this.rootCa = rootCa; 435 return this; 436 } 437 438 public Builder addExtendedKeyUsage(KeyPurposeId keyPurposeId, boolean critical) { 439 extendedKeyUsages.add(keyPurposeId); 440 criticalExtendedKeyUsages.add(critical); 441 return this; 442 } 443 444 public Builder addSubjectAltName(GeneralName generalName) { 445 subjectAltNames.add(generalName); 446 return this; 447 } 448 449 public Builder addSubjectAltNameIpAddress(byte[] ipAddress) { 450 return addSubjectAltName( 451 new GeneralName(GeneralName.iPAddress, new DEROctetString(ipAddress))); 452 } 453 454 private Builder addNameConstraint(boolean permitted, GeneralName generalName) { 455 if (permitted) { 456 permittedNameConstraints.add(new GeneralSubtree(generalName)); 457 } else { 458 excludedNameConstraints.add(new GeneralSubtree(generalName)); 459 } 460 return this; 461 } 462 463 public Builder addNameConstraint(boolean permitted, byte[] ipAddress) { 464 return addNameConstraint(permitted, 465 new GeneralName(GeneralName.iPAddress, new DEROctetString(ipAddress))); 466 } 467 468 public Builder certificateSerialNumber(BigInteger certificateSerialNumber) { 469 this.certificateSerialNumber = certificateSerialNumber; 470 return this; 471 } 472 473 public TestKeyStore build() { 474 try { 475 if (StandardNames.IS_RI) { 476 // JKS does not allow null password 477 if (storePassword == null) { 478 storePassword = "password".toCharArray(); 479 } 480 if (keyPassword == null) { 481 keyPassword = "password".toCharArray(); 482 } 483 } 484 485 /* 486 * This is not implemented for other key types because the logic 487 * would be long to write and it's not needed currently. 488 */ 489 if (privateEntry != null 490 && (keyAlgorithms.length != 1 || !"RSA".equals(keyAlgorithms[0]))) { 491 throw new IllegalStateException( 492 "Only reusing an existing key is implemented for RSA"); 493 } 494 495 KeyStore keyStore = createKeyStore(); 496 for (String keyAlgorithm : keyAlgorithms) { 497 String publicAlias = aliasPrefix + "-public-" + keyAlgorithm; 498 String privateAlias = aliasPrefix + "-private-" + keyAlgorithm; 499 if ((keyAlgorithm.equals("EC_RSA") || keyAlgorithm.equals("DH_RSA")) 500 && signer == null && rootCa == null) { 501 createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, null, 502 privateKey(keyStore, keyPassword, "RSA", "RSA")); 503 continue; 504 } else if (keyAlgorithm.equals("DH_DSA") && signer == null && rootCa == null) { 505 createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, null, 506 privateKey(keyStore, keyPassword, "DSA", "DSA")); 507 continue; 508 } 509 createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, privateEntry, 510 signer); 511 } 512 if (rootCa != null) { 513 keyStore.setCertificateEntry(aliasPrefix 514 + "-root-ca-" 515 + rootCa.getPublicKey().getAlgorithm(), 516 rootCa); 517 } 518 return new TestKeyStore(keyStore, storePassword, keyPassword); 519 } catch (Exception e) { 520 throw new RuntimeException(e); 521 } 522 } 523 524 /** 525 * Add newly generated keys of a given key type to an existing 526 * KeyStore. The PrivateKey will be stored under the specified 527 * private alias name. The X509Certificate will be stored on the 528 * public alias name and have the given subject distinguished 529 * name. 530 * 531 * If a CA is provided, it will be used to sign the generated 532 * certificate and OCSP responses. Otherwise, the certificate 533 * will be self signed. The certificate will be valid for one 534 * day before and one day after the time of creation. 535 * 536 * Based on: 537 * org.bouncycastle.jce.provider.test.SigTest 538 * org.bouncycastle.jce.provider.test.CertTest 539 */ 540 private KeyStore createKeys(KeyStore keyStore, 541 String keyAlgorithm, 542 String publicAlias, 543 String privateAlias, 544 PrivateKeyEntry privateEntry, 545 PrivateKeyEntry signer) throws Exception { 546 PrivateKey caKey; 547 X509Certificate caCert; 548 X509Certificate[] caCertChain; 549 if (signer == null) { 550 caKey = null; 551 caCert = null; 552 caCertChain = null; 553 } else { 554 caKey = signer.getPrivateKey(); 555 caCert = (X509Certificate)signer.getCertificate(); 556 caCertChain = (X509Certificate[])signer.getCertificateChain(); 557 } 558 559 final PrivateKey privateKey; 560 final PublicKey publicKey; 561 X509Certificate x509c; 562 if (publicAlias == null && privateAlias == null) { 563 // don't want anything apparently 564 privateKey = null; 565 publicKey = null; 566 x509c = null; 567 } else { 568 if (privateEntry == null) { 569 // 1a.) we make the keys 570 int keySize = -1; 571 AlgorithmParameterSpec spec = null; 572 if (keyAlgorithm.equals("RSA")) { 573 keySize = RSA_KEY_SIZE_BITS; 574 } else if (keyAlgorithm.equals("DH_RSA")) { 575 spec = new DHParameterSpec(DH_PARAMS_P, DH_PARAMS_G); 576 keyAlgorithm = "DH"; 577 } else if (keyAlgorithm.equals("DSA")) { 578 keySize = DSA_KEY_SIZE_BITS; 579 } else if (keyAlgorithm.equals("DH_DSA")) { 580 spec = new DHParameterSpec(DH_PARAMS_P, DH_PARAMS_G); 581 keyAlgorithm = "DH"; 582 } else if (keyAlgorithm.equals("EC")) { 583 keySize = EC_KEY_SIZE_BITS; 584 } else if (keyAlgorithm.equals("EC_RSA")) { 585 keySize = EC_KEY_SIZE_BITS; 586 keyAlgorithm = "EC"; 587 } else { 588 throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm); 589 } 590 591 KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgorithm); 592 if (spec != null) { 593 kpg.initialize(spec); 594 } else if (keySize != -1) { 595 kpg.initialize(keySize); 596 } else { 597 throw new AssertionError("Must either have set algorithm parameters or key size!"); 598 } 599 600 KeyPair kp = kpg.generateKeyPair(); 601 privateKey = kp.getPrivate(); 602 publicKey = kp.getPublic(); 603 } else { 604 // 1b.) we use the previous keys 605 privateKey = privateEntry.getPrivateKey(); 606 publicKey = privateEntry.getCertificate().getPublicKey(); 607 } 608 609 // 2.) use keys to make certificate 610 X500Principal issuer = ((caCert != null) 611 ? caCert.getSubjectX500Principal() 612 : subject); 613 PrivateKey signingKey = (caKey == null) ? privateKey : caKey; 614 x509c = createCertificate(publicKey, signingKey, subject, issuer, keyUsage, ca, 615 extendedKeyUsages, criticalExtendedKeyUsages, 616 subjectAltNames, 617 permittedNameConstraints, excludedNameConstraints, 618 certificateSerialNumber); 619 } 620 621 X509Certificate[] x509cc; 622 if (privateAlias == null) { 623 // don't need certificate chain 624 x509cc = null; 625 } else if (caCertChain == null) { 626 x509cc = new X509Certificate[] { x509c }; 627 } else { 628 x509cc = new X509Certificate[caCertChain.length+1]; 629 x509cc[0] = x509c; 630 System.arraycopy(caCertChain, 0, x509cc, 1, caCertChain.length); 631 } 632 633 // 3.) put certificate and private key into the key store 634 if (privateAlias != null) { 635 keyStore.setKeyEntry(privateAlias, privateKey, keyPassword, x509cc); 636 } 637 if (publicAlias != null) { 638 keyStore.setCertificateEntry(publicAlias, x509c); 639 } 640 return keyStore; 641 } 642 643 private X500Principal localhost() { 644 return new X500Principal("CN=Local Host"); 645 } 646 } 647 648 public static X509Certificate createCa(PublicKey publicKey, 649 PrivateKey privateKey, 650 String subject) { 651 try { 652 X500Principal principal = new X500Principal(subject); 653 return createCertificate(publicKey, privateKey, 654 principal, principal, 655 0, true, 656 new ArrayList<KeyPurposeId>(), 657 new ArrayList<Boolean>(), 658 new ArrayList<GeneralName>(), 659 new ArrayList<GeneralSubtree>(), 660 new ArrayList<GeneralSubtree>(), 661 null /* serialNumber, generated randomly */); 662 } catch (Exception e) { 663 throw new RuntimeException(e); 664 } 665 } 666 667 private static X509Certificate createCertificate( 668 PublicKey publicKey, 669 PrivateKey privateKey, 670 X500Principal subject, 671 X500Principal issuer, 672 int keyUsage, 673 boolean ca, 674 List<KeyPurposeId> extendedKeyUsages, 675 List<Boolean> criticalExtendedKeyUsages, 676 List<GeneralName> subjectAltNames, 677 List<GeneralSubtree> permittedNameConstraints, 678 List<GeneralSubtree> excludedNameConstraints, 679 BigInteger serialNumber) throws Exception { 680 // Note that there is no way to programmatically make a 681 // Certificate using java.* or javax.* APIs. The 682 // CertificateFactory interface assumes you want to read 683 // in a stream of bytes, typically the X.509 factory would 684 // allow ASN.1 DER encoded bytes and optionally some PEM 685 // formats. Here we use Bouncy Castle's 686 // X509V3CertificateGenerator and related classes. 687 688 long millisPerDay = 24 * 60 * 60 * 1000; 689 long now = System.currentTimeMillis(); 690 Date start = new Date(now - millisPerDay); 691 Date end = new Date(now + millisPerDay); 692 693 String keyAlgorithm = privateKey.getAlgorithm(); 694 String signatureAlgorithm; 695 if (keyAlgorithm.equals("RSA")) { 696 signatureAlgorithm = "sha1WithRSA"; 697 } else if (keyAlgorithm.equals("DSA")) { 698 signatureAlgorithm = "sha1WithDSA"; 699 } else if (keyAlgorithm.equals("EC")) { 700 signatureAlgorithm = "sha1WithECDSA"; 701 } else if (keyAlgorithm.equals("EC_RSA")) { 702 signatureAlgorithm = "sha1WithRSA"; 703 } else { 704 throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm); 705 } 706 707 if (serialNumber == null) { 708 byte[] serialBytes = new byte[16]; 709 new SecureRandom().nextBytes(serialBytes); 710 serialNumber = new BigInteger(1, serialBytes); 711 } 712 713 X509v3CertificateBuilder x509cg = new X509v3CertificateBuilder( 714 X500Name.getInstance(issuer.getEncoded()), serialNumber, start, end, 715 X500Name.getInstance(subject.getEncoded()), 716 SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); 717 if (keyUsage != 0) { 718 x509cg.addExtension(Extension.keyUsage, 719 true, 720 new KeyUsage(keyUsage)); 721 } 722 if (ca) { 723 x509cg.addExtension(Extension.basicConstraints, 724 true, 725 new BasicConstraints(true)); 726 } 727 for (int i = 0; i < extendedKeyUsages.size(); i++) { 728 KeyPurposeId keyPurposeId = extendedKeyUsages.get(i); 729 boolean critical = criticalExtendedKeyUsages.get(i); 730 x509cg.addExtension(Extension.extendedKeyUsage, 731 critical, 732 new ExtendedKeyUsage(keyPurposeId)); 733 } 734 for (GeneralName subjectAltName : subjectAltNames) { 735 x509cg.addExtension(Extension.subjectAlternativeName, 736 false, 737 new GeneralNames(subjectAltName).getEncoded()); 738 } 739 if (!permittedNameConstraints.isEmpty() || !excludedNameConstraints.isEmpty()) { 740 x509cg.addExtension(Extension.nameConstraints, 741 true, 742 new NameConstraints(permittedNameConstraints.toArray( 743 new GeneralSubtree[ 744 permittedNameConstraints.size()]), 745 excludedNameConstraints.toArray( 746 new GeneralSubtree[ 747 excludedNameConstraints.size()]))); 748 } 749 750 X509CertificateHolder x509holder = x509cg.build( 751 new JcaContentSignerBuilder(signatureAlgorithm).build(privateKey)); 752 CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 753 X509Certificate x509c = (X509Certificate) certFactory.generateCertificate( 754 new ByteArrayInputStream(x509holder.getEncoded())); 755 756 if (StandardNames.IS_RI) { 757 /* 758 * The RI can't handle the BC EC signature algorithm 759 * string of "ECDSA", since it expects "...WITHEC...", 760 * so convert from BC to RI X509Certificate 761 * implementation via bytes. 762 */ 763 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 764 ByteArrayInputStream bais = new ByteArrayInputStream(x509c.getEncoded()); 765 Certificate c = cf.generateCertificate(bais); 766 x509c = (X509Certificate) c; 767 } 768 return x509c; 769 } 770 771 /** 772 * Return the key algorithm for a possible compound algorithm 773 * identifier containing an underscore. If not underscore is 774 * present, the argument is returned unmodified. However for an 775 * algorithm such as EC_RSA, return EC. 776 */ 777 public static String keyAlgorithm(String algorithm) { 778 int index = algorithm.indexOf('_'); 779 if (index == -1) { 780 return algorithm; 781 } 782 return algorithm.substring(0, index); 783 } 784 785 786 /** 787 * Return the signature algorithm for a possible compound 788 * algorithm identifier containing an underscore. If not 789 * underscore is present, the argument is returned 790 * unmodified. However for an algorithm such as EC_RSA, return 791 * RSA. 792 */ 793 public static String signatureAlgorithm(String algorithm) { 794 int index = algorithm.indexOf('_'); 795 if (index == -1) { 796 return algorithm; 797 } 798 return algorithm.substring(index+1, algorithm.length()); 799 } 800 801 /** 802 * Create an empty KeyStore 803 */ 804 public static KeyStore createKeyStore() { 805 try { 806 KeyStore keyStore = KeyStore.getInstance(StandardNames.KEY_STORE_ALGORITHM); 807 keyStore.load(null, null); 808 return keyStore; 809 } catch (Exception e) { 810 throw new RuntimeException(e); 811 } 812 } 813 814 /** 815 * Return the only private key in a TestKeyStore for the given 816 * algorithms. Throws IllegalStateException if there are are more 817 * or less than one. 818 */ 819 public PrivateKeyEntry getPrivateKey(String keyAlgorithm, String signatureAlgorithm) { 820 return privateKey(keyStore, keyPassword, keyAlgorithm, signatureAlgorithm); 821 } 822 823 /** 824 * Return the only private key in a keystore for the given 825 * algorithms. Throws IllegalStateException if there are are more 826 * or less than one. 827 */ 828 public static PrivateKeyEntry privateKey(KeyStore keyStore, char[] keyPassword, 829 String keyAlgorithm, String signatureAlgorithm) { 830 try { 831 PrivateKeyEntry found = null; 832 PasswordProtection password = new PasswordProtection(keyPassword); 833 for (String alias : Collections.list(keyStore.aliases())) { 834 if (!keyStore.entryInstanceOf(alias, PrivateKeyEntry.class)) { 835 continue; 836 } 837 PrivateKeyEntry privateKey = (PrivateKeyEntry) keyStore.getEntry(alias, password); 838 if (!privateKey.getPrivateKey().getAlgorithm().equals(keyAlgorithm)) { 839 continue; 840 } 841 X509Certificate certificate = (X509Certificate) privateKey.getCertificate(); 842 if (!certificate.getSigAlgName().contains(signatureAlgorithm)) { 843 continue; 844 } 845 if (found != null) { 846 throw new IllegalStateException("KeyStore has more than one private key for" 847 + " keyAlgorithm: " + keyAlgorithm 848 + " signatureAlgorithm: " + signatureAlgorithm 849 + "\nfirst: " + found.getPrivateKey() 850 + "\nsecond: " + privateKey.getPrivateKey() ); 851 } 852 found = privateKey; 853 } 854 if (found == null) { 855 throw new IllegalStateException("KeyStore contained no private key for" 856 + " keyAlgorithm: " + keyAlgorithm 857 + " signatureAlgorithm: " + signatureAlgorithm); 858 } 859 return found; 860 } catch (Exception e) { 861 throw new RuntimeException("Problem getting key for " + keyAlgorithm 862 + " and signature " + signatureAlgorithm, e); 863 } 864 } 865 866 /** 867 * Return the issuing CA certificate of the given 868 * certificate. Throws IllegalStateException if there are are more 869 * or less than one. 870 */ 871 public Certificate getIssuer(Certificate cert) throws Exception { 872 return issuer(keyStore, cert); 873 } 874 875 /** 876 * Return the issuing CA certificate of the given 877 * certificate. Throws IllegalStateException if there are are more 878 * or less than one. 879 */ 880 public static Certificate issuer(KeyStore keyStore, Certificate c) 881 throws Exception { 882 if (!(c instanceof X509Certificate)) { 883 throw new IllegalStateException("issuer requires an X509Certificate, found " + c); 884 } 885 X509Certificate cert = (X509Certificate) c; 886 887 Certificate found = null; 888 for (String alias : Collections.list(keyStore.aliases())) { 889 if (!keyStore.entryInstanceOf(alias, TrustedCertificateEntry.class)) { 890 continue; 891 } 892 TrustedCertificateEntry certificateEntry = 893 (TrustedCertificateEntry) keyStore.getEntry(alias, null); 894 Certificate certificate = certificateEntry.getTrustedCertificate(); 895 if (!(certificate instanceof X509Certificate)) { 896 continue; 897 } 898 X509Certificate x = (X509Certificate) certificate; 899 if (!cert.getIssuerDN().equals(x.getSubjectDN())) { 900 continue; 901 } 902 if (found != null) { 903 throw new IllegalStateException("KeyStore has more than one issuing CA for " 904 + cert 905 + "\nfirst: " + found 906 + "\nsecond: " + certificate ); 907 } 908 found = certificate; 909 } 910 if (found == null) { 911 throw new IllegalStateException("KeyStore contained no issuing CA for " + cert); 912 } 913 return found; 914 } 915 916 /** 917 * Return the only self-signed root certificate in a TestKeyStore 918 * for the given algorithm. Throws IllegalStateException if there 919 * are are more or less than one. 920 */ 921 public X509Certificate getRootCertificate(String algorithm) { 922 return rootCertificate(keyStore, algorithm); 923 } 924 925 private static OCSPResp generateOCSPResponse(PrivateKeyEntry server, PrivateKeyEntry issuer, 926 CertificateStatus status) throws CertificateException { 927 try { 928 X509Certificate serverCertJca = (X509Certificate) server.getCertificate(); 929 X509Certificate caCertJca = (X509Certificate) issuer.getCertificate(); 930 931 X509CertificateHolder caCert = new JcaX509CertificateHolder(caCertJca); 932 933 DigestCalculatorProvider digCalcProv = new BcDigestCalculatorProvider(); 934 BasicOCSPRespBuilder basicBuilder = new BasicOCSPRespBuilder( 935 SubjectPublicKeyInfo.getInstance(caCertJca.getPublicKey().getEncoded()), 936 digCalcProv.get(CertificateID.HASH_SHA1)); 937 938 CertificateID certId = new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), 939 caCert, serverCertJca.getSerialNumber()); 940 941 basicBuilder.addResponse(certId, status); 942 943 BasicOCSPResp resp = basicBuilder.build( 944 new JcaContentSignerBuilder("SHA256withRSA").build(issuer.getPrivateKey()), 945 null, new Date()); 946 947 OCSPRespBuilder builder = new OCSPRespBuilder(); 948 return builder.build(OCSPRespBuilder.SUCCESSFUL, resp); 949 } catch (Exception e) { 950 throw new CertificateException("cannot generate OCSP response", e); 951 } 952 } 953 954 public static byte[] getOCSPResponseForGood(PrivateKeyEntry server, PrivateKeyEntry issuer) throws CertificateException { 955 try { 956 return generateOCSPResponse(server, issuer, CertificateStatus.GOOD).getEncoded(); 957 } catch (IOException e) { 958 throw new CertificateException(e); 959 } 960 } 961 962 public static byte[] getOCSPResponseForRevoked(PrivateKeyEntry server, PrivateKeyEntry issuer) 963 throws CertificateException { 964 try { 965 return generateOCSPResponse(server, issuer, 966 new RevokedStatus(new Date(), CRLReason.keyCompromise)).getEncoded(); 967 } catch (IOException e) { 968 throw new CertificateException(e); 969 } 970 } 971 972 /** 973 * Return the only self-signed root certificate in a keystore for 974 * the given algorithm. Throws IllegalStateException if there are 975 * are more or less than one. 976 */ 977 public static X509Certificate rootCertificate(KeyStore keyStore, String algorithm) { 978 try { 979 X509Certificate found = null; 980 for (String alias : Collections.list(keyStore.aliases())) { 981 if (!keyStore.entryInstanceOf(alias, TrustedCertificateEntry.class)) { 982 continue; 983 } 984 TrustedCertificateEntry certificateEntry = 985 (TrustedCertificateEntry) keyStore.getEntry(alias, null); 986 Certificate certificate = certificateEntry.getTrustedCertificate(); 987 if (!certificate.getPublicKey().getAlgorithm().equals(algorithm)) { 988 continue; 989 } 990 if (!(certificate instanceof X509Certificate)) { 991 continue; 992 } 993 X509Certificate x = (X509Certificate) certificate; 994 if (!x.getIssuerDN().equals(x.getSubjectDN())) { 995 continue; 996 } 997 if (found != null) { 998 throw new IllegalStateException("KeyStore has more than one root CA for " 999 + algorithm 1000 + "\nfirst: " + found 1001 + "\nsecond: " + certificate ); 1002 } 1003 found = x; 1004 } 1005 if (found == null) { 1006 throw new IllegalStateException("KeyStore contained no root CA for " + algorithm); 1007 } 1008 return found; 1009 } catch (Exception e) { 1010 throw new RuntimeException(e); 1011 } 1012 } 1013 1014 /** 1015 * Return an {@code X509Certificate that matches the given {@code alias}. 1016 */ 1017 public KeyStore.Entry getEntryByAlias(String alias) { 1018 return entryByAlias(keyStore, alias); 1019 } 1020 1021 /** 1022 * Finds an entry in the keystore by the given alias. 1023 */ 1024 public static KeyStore.Entry entryByAlias(KeyStore keyStore, String alias) { 1025 try { 1026 return keyStore.getEntry(alias, null); 1027 } catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException e) { 1028 throw new RuntimeException(e); 1029 } 1030 } 1031 1032 /** 1033 * Create a client key store that only contains self-signed certificates but no private keys 1034 */ 1035 public static KeyStore createClient(KeyStore caKeyStore) { 1036 KeyStore clientKeyStore = createKeyStore(); 1037 copySelfSignedCertificates(clientKeyStore, caKeyStore); 1038 return clientKeyStore; 1039 } 1040 1041 /** 1042 * Copy self-signed certificates from one key store to another. 1043 * Returns true if successful, false if no match found. 1044 */ 1045 public static boolean copySelfSignedCertificates(KeyStore dst, KeyStore src) { 1046 try { 1047 boolean copied = false; 1048 for (String alias : Collections.list(src.aliases())) { 1049 if (!src.isCertificateEntry(alias)) { 1050 continue; 1051 } 1052 X509Certificate cert = (X509Certificate)src.getCertificate(alias); 1053 if (!cert.getSubjectDN().equals(cert.getIssuerDN())) { 1054 continue; 1055 } 1056 dst.setCertificateEntry(alias, cert); 1057 copied = true; 1058 } 1059 return copied; 1060 } catch (Exception e) { 1061 throw new RuntimeException(e); 1062 } 1063 } 1064 1065 /** 1066 * Copy named certificates from one key store to another. 1067 * Returns true if successful, false if no match found. 1068 */ 1069 public static boolean copyCertificate(Principal subject, KeyStore dst, KeyStore src) 1070 throws Exception { 1071 for (String alias : Collections.list(src.aliases())) { 1072 if (!src.isCertificateEntry(alias)) { 1073 continue; 1074 } 1075 X509Certificate cert = (X509Certificate)src.getCertificate(alias); 1076 if (!cert.getSubjectDN().equals(subject)) { 1077 continue; 1078 } 1079 dst.setCertificateEntry(alias, cert); 1080 return true; 1081 } 1082 return false; 1083 } 1084 1085 /** 1086 * Dump a key store for debugging. 1087 */ 1088 public void dump(String context) throws KeyStoreException, NoSuchAlgorithmException { 1089 dump(context, keyStore, keyPassword); 1090 } 1091 1092 /** 1093 * Dump a key store for debugging. 1094 */ 1095 public static void dump(String context, KeyStore keyStore, char[] keyPassword) 1096 throws KeyStoreException, NoSuchAlgorithmException { 1097 PrintStream out = System.out; 1098 out.println("context=" + context); 1099 out.println("\tkeyStore=" + keyStore); 1100 out.println("\tkeyStore.type=" + keyStore.getType()); 1101 out.println("\tkeyStore.provider=" + keyStore.getProvider()); 1102 out.println("\tkeyPassword=" 1103 + ((keyPassword == null) ? null : new String(keyPassword))); 1104 out.println("\tsize=" + keyStore.size()); 1105 for (String alias : Collections.list(keyStore.aliases())) { 1106 out.println("alias=" + alias); 1107 out.println("\tcreationDate=" + keyStore.getCreationDate(alias)); 1108 if (keyStore.isCertificateEntry(alias)) { 1109 out.println("\tcertificate:"); 1110 out.println("=========================================="); 1111 out.println(keyStore.getCertificate(alias)); 1112 out.println("=========================================="); 1113 continue; 1114 } 1115 if (keyStore.isKeyEntry(alias)) { 1116 out.println("\tkey:"); 1117 out.println("=========================================="); 1118 String key; 1119 try { 1120 key = ("Key retrieved using password\n" 1121 + keyStore.getKey(alias, keyPassword)); 1122 } catch (UnrecoverableKeyException e1) { 1123 try { 1124 key = ("Key retrieved without password\n" 1125 + keyStore.getKey(alias, null)); 1126 } catch (UnrecoverableKeyException e2) { 1127 key = "Key could not be retrieved"; 1128 } 1129 } 1130 out.println(key); 1131 out.println("=========================================="); 1132 Certificate[] chain = keyStore.getCertificateChain(alias); 1133 if (chain == null) { 1134 out.println("No certificate chain associated with key"); 1135 out.println("=========================================="); 1136 } else { 1137 for (int i = 0; i < chain.length; i++) { 1138 out.println("Certificate chain element #" + i); 1139 out.println(chain[i]); 1140 out.println("=========================================="); 1141 } 1142 } 1143 continue; 1144 } 1145 out.println("\tunknown entry type"); 1146 } 1147 } 1148 1149 public static void assertChainLength(Object[] chain) { 1150 /* 1151 * Note chain is Object[] to support both 1152 * java.security.cert.X509Certificate and 1153 * javax.security.cert.X509Certificate 1154 */ 1155 assertEquals(3, chain.length); 1156 } 1157} 1158