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 17 package libcore.java.security; 18 19 import com.android.org.bouncycastle.asn1.DEROctetString; 20 import com.android.org.bouncycastle.asn1.x509.BasicConstraints; 21 import com.android.org.bouncycastle.asn1.x509.GeneralName; 22 import com.android.org.bouncycastle.asn1.x509.GeneralNames; 23 import com.android.org.bouncycastle.asn1.x509.GeneralSubtree; 24 import com.android.org.bouncycastle.asn1.x509.KeyUsage; 25 import com.android.org.bouncycastle.asn1.x509.NameConstraints; 26 import com.android.org.bouncycastle.asn1.x509.X509Extensions; 27 import com.android.org.bouncycastle.jce.provider.BouncyCastleProvider; 28 import com.android.org.bouncycastle.x509.X509V3CertificateGenerator; 29 import java.io.ByteArrayInputStream; 30 import java.io.PrintStream; 31 import java.math.BigInteger; 32 import java.net.InetAddress; 33 import java.net.UnknownHostException; 34 import java.security.KeyFactory; 35 import java.security.KeyPair; 36 import java.security.KeyPairGenerator; 37 import java.security.KeyStore; 38 import java.security.KeyStore.PasswordProtection; 39 import java.security.KeyStore.PrivateKeyEntry; 40 import java.security.KeyStore.TrustedCertificateEntry; 41 import java.security.KeyStoreException; 42 import java.security.NoSuchAlgorithmException; 43 import java.security.Principal; 44 import java.security.PrivateKey; 45 import java.security.PublicKey; 46 import java.security.SecureRandom; 47 import java.security.Security; 48 import java.security.UnrecoverableKeyException; 49 import java.security.cert.Certificate; 50 import java.security.cert.CertificateFactory; 51 import java.security.cert.X509Certificate; 52 import java.security.interfaces.ECPrivateKey; 53 import java.security.spec.PKCS8EncodedKeySpec; 54 import java.util.ArrayList; 55 import java.util.Collections; 56 import java.util.Date; 57 import java.util.List; 58 import java.util.Vector; 59 import javax.net.ssl.KeyManager; 60 import javax.net.ssl.KeyManagerFactory; 61 import javax.net.ssl.TrustManager; 62 import javax.net.ssl.TrustManagerFactory; 63 import javax.security.auth.x500.X500Principal; 64 import junit.framework.Assert; 65 import libcore.javax.net.ssl.TestKeyManager; 66 import libcore.javax.net.ssl.TestTrustManager; 67 68 /** 69 * TestKeyStore is a convenience class for other tests that 70 * want a canned KeyStore with a variety of key pairs. 71 * 72 * Creating a key store is relatively slow, so a singleton instance is 73 * accessible via TestKeyStore.get(). 74 */ 75 public final class TestKeyStore extends Assert { 76 77 private static TestKeyStore ROOT_CA; 78 79 private static TestKeyStore SERVER; 80 private static TestKeyStore CLIENT; 81 private static TestKeyStore CLIENT_CERTIFICATE; 82 83 private static TestKeyStore CLIENT_2; 84 85 static { 86 if (StandardNames.IS_RI) { 87 // Needed to create BKS keystore but add at end so most 88 // algorithm come from the default providers 89 Security.insertProviderAt(new BouncyCastleProvider(), 90 Security.getProviders().length+1); 91 } 92 } 93 94 private static final boolean TEST_MANAGERS = true; 95 96 public final KeyStore keyStore; 97 public final char[] storePassword; 98 public final char[] keyPassword; 99 public final KeyManager[] keyManagers; 100 public final TrustManager[] trustManagers; 101 public final TestKeyManager keyManager; 102 public final TestTrustManager trustManager; 103 104 private TestKeyStore(KeyStore keyStore, char[] storePassword, char[] keyPassword) { 105 this.keyStore = keyStore; 106 this.storePassword = storePassword; 107 this.keyPassword = keyPassword; 108 this.keyManagers = createKeyManagers(keyStore, storePassword); 109 this.trustManagers = createTrustManagers(keyStore); 110 this.keyManager = (TestKeyManager)keyManagers[0]; 111 this.trustManager = (TestTrustManager)trustManagers[0]; 112 } 113 114 public static KeyManager[] createKeyManagers(KeyStore keyStore, char[] storePassword) { 115 try { 116 String kmfa = KeyManagerFactory.getDefaultAlgorithm(); 117 KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfa); 118 kmf.init(keyStore, storePassword); 119 return TestKeyManager.wrap(kmf.getKeyManagers()); 120 } catch (Exception e) { 121 throw new RuntimeException(e); 122 } 123 } 124 125 public static TrustManager[] createTrustManagers(final KeyStore keyStore) { 126 try { 127 String tmfa = TrustManagerFactory.getDefaultAlgorithm(); 128 TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfa); 129 tmf.init(keyStore); 130 return TestTrustManager.wrap(tmf.getTrustManagers()); 131 } catch (Exception e) { 132 throw new RuntimeException(e); 133 } 134 } 135 136 /** 137 * Lazily create shared test certificates. 138 */ 139 private static synchronized void initCerts() { 140 if (ROOT_CA != null) { 141 return; 142 } 143 ROOT_CA = new Builder() 144 .aliasPrefix("RootCA") 145 .subject("CN=Test Root Certificate Authority") 146 .ca(true) 147 .build(); 148 TestKeyStore intermediateCa = new Builder() 149 .aliasPrefix("IntermediateCA") 150 .subject("CN=Test Intermediate Certificate Authority") 151 .ca(true) 152 .signer(ROOT_CA.getPrivateKey("RSA", "RSA")) 153 .rootCa(ROOT_CA.getRootCertificate("RSA")) 154 .build(); 155 SERVER = new Builder() 156 .aliasPrefix("server") 157 .signer(intermediateCa.getPrivateKey("RSA", "RSA")) 158 .rootCa(intermediateCa.getRootCertificate("RSA")) 159 .build(); 160 CLIENT = new TestKeyStore(createClient(intermediateCa.keyStore), null, null); 161 CLIENT_CERTIFICATE = new Builder() 162 .aliasPrefix("client") 163 .subject("emailAddress=test@user") 164 .signer(intermediateCa.getPrivateKey("RSA", "RSA")) 165 .rootCa(intermediateCa.getRootCertificate("RSA")) 166 .build(); 167 TestKeyStore rootCa2 = new Builder() 168 .aliasPrefix("RootCA2") 169 .subject("CN=Test Root Certificate Authority 2") 170 .ca(true) 171 .build(); 172 CLIENT_2 = new TestKeyStore(createClient(rootCa2.keyStore), null, null); 173 } 174 175 /** 176 * Return a server keystore with a matched RSA certificate and 177 * private key as well as a CA certificate. 178 */ 179 public static TestKeyStore getServer() { 180 initCerts(); 181 return SERVER; 182 } 183 184 /** 185 * Return a keystore with a CA certificate 186 */ 187 public static TestKeyStore getClient() { 188 initCerts(); 189 return CLIENT; 190 } 191 192 /** 193 * Return a client keystore with a matched RSA certificate and 194 * private key as well as a CA certificate. 195 */ 196 public static TestKeyStore getClientCertificate() { 197 initCerts(); 198 return CLIENT_CERTIFICATE; 199 } 200 201 /** 202 * Return a keystore with a second CA certificate that does not 203 * trust the server certificate returned by getServer for negative 204 * testing. 205 */ 206 public static TestKeyStore getClientCA2() { 207 initCerts(); 208 return CLIENT_2; 209 } 210 211 /** 212 * Creates KeyStores containing the requested key types. Since key 213 * generation can be expensive, most tests should reuse the RSA-only 214 * singleton instance returned by TestKeyStore.get. 215 */ 216 public static class Builder { 217 private String[] keyAlgorithms = { "RSA" }; 218 private char[] storePassword; 219 private char[] keyPassword; 220 private String aliasPrefix; 221 private X500Principal subject; 222 private int keyUsage; 223 private boolean ca; 224 private PrivateKeyEntry signer; 225 private Certificate rootCa; 226 private final List<GeneralName> subjectAltNames = new ArrayList<GeneralName>(); 227 private final Vector<GeneralSubtree> permittedNameConstraints 228 = new Vector<GeneralSubtree>(); 229 private final Vector<GeneralSubtree> excludedNameConstraints = new Vector<GeneralSubtree>(); 230 231 public Builder() { 232 subject = localhost(); 233 } 234 235 /** 236 * Sets the requested key types to generate and include. The default is 237 * RSA only. 238 */ 239 public Builder keyAlgorithms(String... keyAlgorithms) { 240 this.keyAlgorithms = keyAlgorithms; 241 return this; 242 } 243 244 /** A unique prefix to identify the key aliases */ 245 public Builder aliasPrefix(String aliasPrefix) { 246 this.aliasPrefix = aliasPrefix; 247 return this; 248 } 249 250 /** 251 * Sets the subject common name. The default is the local host's 252 * canonical name. 253 */ 254 public Builder subject(X500Principal subject) { 255 this.subject = subject; 256 return this; 257 } 258 259 public Builder subject(String commonName) { 260 return subject(new X500Principal(commonName)); 261 } 262 263 /** {@link KeyUsage} bit mask for 2.5.29.15 extension */ 264 public Builder keyUsage(int keyUsage) { 265 this.keyUsage = keyUsage; 266 return this; 267 } 268 269 /** true If the keys being created are for a CA */ 270 public Builder ca(boolean ca) { 271 this.ca = ca; 272 return this; 273 } 274 275 /** a private key entry to be used for signing, otherwise self-sign */ 276 public Builder signer(PrivateKeyEntry signer) { 277 this.signer = signer; 278 return this; 279 } 280 281 /** a root CA to include in the final store */ 282 public Builder rootCa(Certificate rootCa) { 283 this.rootCa = rootCa; 284 return this; 285 } 286 287 private Builder addSubjectAltName(GeneralName generalName) { 288 subjectAltNames.add(generalName); 289 return this; 290 } 291 292 public Builder addSubjectAltNameIpAddress(byte[] ipAddress) { 293 return addSubjectAltName( 294 new GeneralName(GeneralName.iPAddress, new DEROctetString(ipAddress))); 295 } 296 297 private Builder addNameConstraint(boolean permitted, GeneralName generalName) { 298 if (permitted) { 299 permittedNameConstraints.add(new GeneralSubtree(generalName)); 300 } else { 301 excludedNameConstraints.add(new GeneralSubtree(generalName)); 302 } 303 return this; 304 } 305 306 public Builder addNameConstraint(boolean permitted, byte[] ipAddress) { 307 return addNameConstraint(permitted, 308 new GeneralName(GeneralName.iPAddress, new DEROctetString(ipAddress))); 309 } 310 311 public TestKeyStore build() { 312 try { 313 if (StandardNames.IS_RI) { 314 // JKS does not allow null password 315 if (storePassword == null) { 316 storePassword = "password".toCharArray(); 317 } 318 if (keyPassword == null) { 319 keyPassword = "password".toCharArray(); 320 } 321 } 322 323 KeyStore keyStore = createKeyStore(); 324 for (String keyAlgorithm : keyAlgorithms) { 325 String publicAlias = aliasPrefix + "-public-" + keyAlgorithm; 326 String privateAlias = aliasPrefix + "-private-" + keyAlgorithm; 327 if (keyAlgorithm.equals("EC_RSA") && signer == null && rootCa == null) { 328 createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, 329 privateKey(keyStore, keyPassword, "RSA", "RSA")); 330 continue; 331 } 332 createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, signer); 333 } 334 if (rootCa != null) { 335 keyStore.setCertificateEntry(aliasPrefix 336 + "-root-ca-" 337 + rootCa.getPublicKey().getAlgorithm(), 338 rootCa); 339 } 340 return new TestKeyStore(keyStore, storePassword, keyPassword); 341 } catch (Exception e) { 342 throw new RuntimeException(e); 343 } 344 } 345 346 /** 347 * Add newly generated keys of a given key type to an existing 348 * KeyStore. The PrivateKey will be stored under the specified 349 * private alias name. The X509Certificate will be stored on the 350 * public alias name and have the given subject distinguished 351 * name. 352 * 353 * If a CA is provided, it will be used to sign the generated 354 * certificate. Otherwise, the certificate will be self 355 * signed. The certificate will be valid for one day before and 356 * one day after the time of creation. 357 * 358 * Based on: 359 * org.bouncycastle.jce.provider.test.SigTest 360 * org.bouncycastle.jce.provider.test.CertTest 361 */ 362 private KeyStore createKeys(KeyStore keyStore, 363 String keyAlgorithm, 364 String publicAlias, 365 String privateAlias, 366 PrivateKeyEntry signer) throws Exception { 367 PrivateKey caKey; 368 X509Certificate caCert; 369 X509Certificate[] caCertChain; 370 if (signer == null) { 371 caKey = null; 372 caCert = null; 373 caCertChain = null; 374 } else { 375 caKey = signer.getPrivateKey(); 376 caCert = (X509Certificate)signer.getCertificate(); 377 caCertChain = (X509Certificate[])signer.getCertificateChain(); 378 } 379 380 PrivateKey privateKey; 381 X509Certificate x509c; 382 if (publicAlias == null && privateAlias == null) { 383 // don't want anything apparently 384 privateKey = null; 385 x509c = null; 386 } else { 387 // 1.) we make the keys 388 int keySize; 389 if (keyAlgorithm.equals("RSA")) { 390 // 512 breaks SSL_RSA_EXPORT_* on RI and TLS_ECDHE_RSA_WITH_RC4_128_SHA for us 391 keySize = 1024; 392 } else if (keyAlgorithm.equals("DSA")) { 393 keySize = 512; 394 } else if (keyAlgorithm.equals("EC")) { 395 keySize = 256; 396 } else if (keyAlgorithm.equals("EC_RSA")) { 397 keySize = 256; 398 keyAlgorithm = "EC"; 399 } else { 400 throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm); 401 } 402 403 KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgorithm); 404 kpg.initialize(keySize, new SecureRandom()); 405 406 KeyPair kp = kpg.generateKeyPair(); 407 privateKey = kp.getPrivate(); 408 PublicKey publicKey = kp.getPublic(); 409 410 // 2.) use keys to make certificate 411 X500Principal issuer = ((caCert != null) 412 ? caCert.getSubjectX500Principal() 413 : subject); 414 PrivateKey signingKey = (caKey == null) ? privateKey : caKey; 415 x509c = createCertificate(publicKey, signingKey, subject, issuer, keyUsage, ca, 416 subjectAltNames, 417 permittedNameConstraints, excludedNameConstraints); 418 } 419 420 X509Certificate[] x509cc; 421 if (privateAlias == null) { 422 // don't need certificate chain 423 x509cc = null; 424 } else if (caCertChain == null) { 425 x509cc = new X509Certificate[] { x509c }; 426 } else { 427 x509cc = new X509Certificate[caCertChain.length+1]; 428 x509cc[0] = x509c; 429 System.arraycopy(caCertChain, 0, x509cc, 1, caCertChain.length); 430 } 431 432 // 3.) put certificate and private key into the key store 433 if (privateAlias != null) { 434 keyStore.setKeyEntry(privateAlias, privateKey, keyPassword, x509cc); 435 } 436 if (publicAlias != null) { 437 keyStore.setCertificateEntry(publicAlias, x509c); 438 } 439 return keyStore; 440 } 441 442 private X500Principal localhost() { 443 try { 444 return new X500Principal("CN=" + InetAddress.getLocalHost().getHostName()); 445 } catch (UnknownHostException e) { 446 throw new RuntimeException(e); 447 } 448 } 449 } 450 451 public static X509Certificate createCa(PublicKey publicKey, 452 PrivateKey privateKey, 453 String subject) { 454 try { 455 X500Principal principal = new X500Principal(subject); 456 return createCertificate(publicKey, privateKey, 457 principal, principal, 458 0, true, 459 new Vector<GeneralName>(), 460 new Vector<GeneralSubtree>(), 461 new Vector<GeneralSubtree>()); 462 } catch (Exception e) { 463 throw new RuntimeException(e); 464 } 465 } 466 467 private static X509Certificate createCertificate( 468 PublicKey publicKey, 469 PrivateKey privateKey, 470 X500Principal subject, 471 X500Principal issuer, 472 int keyUsage, 473 boolean ca, 474 List<GeneralName> subjectAltNames, 475 Vector<GeneralSubtree> permittedNameConstraints, 476 Vector<GeneralSubtree> excludedNameConstraints) throws Exception { 477 // Note that there is no way to programmatically make a 478 // Certificate using java.* or javax.* APIs. The 479 // CertificateFactory interface assumes you want to read 480 // in a stream of bytes, typically the X.509 factory would 481 // allow ASN.1 DER encoded bytes and optionally some PEM 482 // formats. Here we use Bouncy Castle's 483 // X509V3CertificateGenerator and related classes. 484 485 long millisPerDay = 24 * 60 * 60 * 1000; 486 long now = System.currentTimeMillis(); 487 Date start = new Date(now - millisPerDay); 488 Date end = new Date(now + millisPerDay); 489 BigInteger serial = BigInteger.valueOf(1); 490 491 String keyAlgorithm = privateKey.getAlgorithm(); 492 String signatureAlgorithm; 493 if (keyAlgorithm.equals("RSA")) { 494 signatureAlgorithm = "sha1WithRSA"; 495 } else if (keyAlgorithm.equals("DSA")) { 496 signatureAlgorithm = "sha1WithDSA"; 497 } else if (keyAlgorithm.equals("EC")) { 498 signatureAlgorithm = "sha1WithECDSA"; 499 } else if (keyAlgorithm.equals("EC_RSA")) { 500 signatureAlgorithm = "sha1WithRSA"; 501 } else { 502 throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm); 503 } 504 505 X509V3CertificateGenerator x509cg = new X509V3CertificateGenerator(); 506 x509cg.setSubjectDN(subject); 507 x509cg.setIssuerDN(issuer); 508 x509cg.setNotBefore(start); 509 x509cg.setNotAfter(end); 510 x509cg.setPublicKey(publicKey); 511 x509cg.setSignatureAlgorithm(signatureAlgorithm); 512 x509cg.setSerialNumber(serial); 513 if (keyUsage != 0) { 514 x509cg.addExtension(X509Extensions.KeyUsage, 515 true, 516 new KeyUsage(keyUsage)); 517 } 518 if (ca) { 519 x509cg.addExtension(X509Extensions.BasicConstraints, 520 true, 521 new BasicConstraints(true)); 522 } 523 for (GeneralName subjectAltName : subjectAltNames) { 524 x509cg.addExtension(X509Extensions.SubjectAlternativeName, 525 false, 526 new GeneralNames(subjectAltName).getEncoded()); 527 } 528 if (!permittedNameConstraints.isEmpty() || !excludedNameConstraints.isEmpty()) { 529 x509cg.addExtension(X509Extensions.NameConstraints, 530 true, 531 new NameConstraints(permittedNameConstraints, 532 excludedNameConstraints)); 533 } 534 535 if (privateKey instanceof ECPrivateKey) { 536 /* 537 * bouncycastle needs its own ECPrivateKey implementation 538 */ 539 KeyFactory kf = KeyFactory.getInstance(keyAlgorithm, "BC"); 540 PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(privateKey.getEncoded()); 541 privateKey = kf.generatePrivate(ks); 542 } 543 X509Certificate x509c = x509cg.generateX509Certificate(privateKey); 544 if (StandardNames.IS_RI) { 545 /* 546 * The RI can't handle the BC EC signature algorithm 547 * string of "ECDSA", since it expects "...WITHEC...", 548 * so convert from BC to RI X509Certificate 549 * implementation via bytes. 550 */ 551 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 552 ByteArrayInputStream bais = new ByteArrayInputStream(x509c.getEncoded()); 553 Certificate c = cf.generateCertificate(bais); 554 x509c = (X509Certificate) c; 555 } 556 return x509c; 557 } 558 559 /** 560 * Return the key algorithm for a possible compound algorithm 561 * identifier containing an underscore. If not underscore is 562 * present, the argument is returned unmodified. However for an 563 * algorithm such as EC_RSA, return EC. 564 */ 565 public static String keyAlgorithm(String algorithm) { 566 int index = algorithm.indexOf('_'); 567 if (index == -1) { 568 return algorithm; 569 } 570 return algorithm.substring(0, index); 571 } 572 573 574 /** 575 * Return the signature algorithm for a possible compound 576 * algorithm identifier containing an underscore. If not 577 * underscore is present, the argument is returned 578 * unmodified. However for an algorithm such as EC_RSA, return 579 * RSA. 580 */ 581 public static String signatureAlgorithm(String algorithm) { 582 int index = algorithm.indexOf('_'); 583 if (index == -1) { 584 return algorithm; 585 } 586 return algorithm.substring(index+1, algorithm.length()); 587 } 588 589 /** 590 * Create an empty KeyStore 591 * 592 * The KeyStore is optionally password protected by the 593 * keyStorePassword argument, which can be null if a password is 594 * not desired. 595 */ 596 public static KeyStore createKeyStore() { 597 try { 598 KeyStore keyStore = KeyStore.getInstance(StandardNames.KEY_STORE_ALGORITHM); 599 keyStore.load(null, null); 600 return keyStore; 601 } catch (Exception e) { 602 throw new RuntimeException(e); 603 } 604 } 605 606 /** 607 * Return the only private key in a TestKeyStore for the given 608 * algorithms. Throws IllegalStateException if there are are more 609 * or less than one. 610 */ 611 public PrivateKeyEntry getPrivateKey(String keyAlgorithm, String signatureAlgorithm) { 612 return privateKey(keyStore, keyPassword, keyAlgorithm, signatureAlgorithm); 613 } 614 615 /** 616 * Return the only private key in a keystore for the given 617 * algorithms. Throws IllegalStateException if there are are more 618 * or less than one. 619 */ 620 public static PrivateKeyEntry privateKey(KeyStore keyStore, char[] keyPassword, 621 String keyAlgorithm, String signatureAlgorithm) { 622 try { 623 PrivateKeyEntry found = null; 624 PasswordProtection password = new PasswordProtection(keyPassword); 625 for (String alias : Collections.list(keyStore.aliases())) { 626 if (!keyStore.entryInstanceOf(alias, PrivateKeyEntry.class)) { 627 continue; 628 } 629 PrivateKeyEntry privateKey = (PrivateKeyEntry) keyStore.getEntry(alias, password); 630 if (!privateKey.getPrivateKey().getAlgorithm().equals(keyAlgorithm)) { 631 continue; 632 } 633 X509Certificate certificate = (X509Certificate) privateKey.getCertificate(); 634 if (!certificate.getSigAlgName().contains(signatureAlgorithm)) { 635 continue; 636 } 637 if (found != null) { 638 throw new IllegalStateException("KeyStore has more than one private key for " 639 + " keyAlgorithm: " + keyAlgorithm 640 + " signatureAlgorithm: " + signatureAlgorithm 641 + "\nfirst: " + found.getPrivateKey() 642 + "\nsecond: " + privateKey.getPrivateKey() ); 643 } 644 found = privateKey; 645 } 646 if (found == null) { 647 throw new IllegalStateException("KeyStore contained no private key for " 648 + " keyAlgorithm: " + keyAlgorithm 649 + " signatureAlgorithm: " + signatureAlgorithm); 650 } 651 return found; 652 } catch (Exception e) { 653 throw new RuntimeException(e); 654 } 655 } 656 657 /** 658 * Return the issuing CA certificate of the given 659 * certificate. Throws IllegalStateException if there are are more 660 * or less than one. 661 */ 662 public Certificate getIssuer(Certificate cert) throws Exception { 663 return issuer(keyStore, cert); 664 } 665 666 /** 667 * Return the issuing CA certificate of the given 668 * certificate. Throws IllegalStateException if there are are more 669 * or less than one. 670 */ 671 public static Certificate issuer(KeyStore keyStore, Certificate c) 672 throws Exception { 673 if (!(c instanceof X509Certificate)) { 674 throw new IllegalStateException("issuer requires an X509Certificate, found " + c); 675 } 676 X509Certificate cert = (X509Certificate) c; 677 678 Certificate found = null; 679 for (String alias : Collections.list(keyStore.aliases())) { 680 if (!keyStore.entryInstanceOf(alias, TrustedCertificateEntry.class)) { 681 continue; 682 } 683 TrustedCertificateEntry certificateEntry = 684 (TrustedCertificateEntry) keyStore.getEntry(alias, null); 685 Certificate certificate = certificateEntry.getTrustedCertificate(); 686 if (!(certificate instanceof X509Certificate)) { 687 continue; 688 } 689 X509Certificate x = (X509Certificate) certificate; 690 if (!cert.getIssuerDN().equals(x.getSubjectDN())) { 691 continue; 692 } 693 if (found != null) { 694 throw new IllegalStateException("KeyStore has more than one issuing CA for " 695 + cert 696 + "\nfirst: " + found 697 + "\nsecond: " + certificate ); 698 } 699 found = certificate; 700 } 701 if (found == null) { 702 throw new IllegalStateException("KeyStore contained no issuing CA for " + cert); 703 } 704 return found; 705 } 706 707 /** 708 * Return the only self-signed root certificate in a TestKeyStore 709 * for the given algorithm. Throws IllegalStateException if there 710 * are are more or less than one. 711 */ 712 public X509Certificate getRootCertificate(String algorithm) { 713 return rootCertificate(keyStore, algorithm); 714 } 715 716 /** 717 * Return the only self-signed root certificate in a keystore for 718 * the given algorithm. Throws IllegalStateException if there are 719 * are more or less than one. 720 */ 721 public static X509Certificate rootCertificate(KeyStore keyStore, String algorithm) { 722 try { 723 X509Certificate found = null; 724 for (String alias : Collections.list(keyStore.aliases())) { 725 if (!keyStore.entryInstanceOf(alias, TrustedCertificateEntry.class)) { 726 continue; 727 } 728 TrustedCertificateEntry certificateEntry = 729 (TrustedCertificateEntry) keyStore.getEntry(alias, null); 730 Certificate certificate = certificateEntry.getTrustedCertificate(); 731 if (!certificate.getPublicKey().getAlgorithm().equals(algorithm)) { 732 continue; 733 } 734 if (!(certificate instanceof X509Certificate)) { 735 continue; 736 } 737 X509Certificate x = (X509Certificate) certificate; 738 if (!x.getIssuerDN().equals(x.getSubjectDN())) { 739 continue; 740 } 741 if (found != null) { 742 throw new IllegalStateException("KeyStore has more than one root CA for " 743 + algorithm 744 + "\nfirst: " + found 745 + "\nsecond: " + certificate ); 746 } 747 found = x; 748 } 749 if (found == null) { 750 throw new IllegalStateException("KeyStore contained no root CA for " + algorithm); 751 } 752 return found; 753 } catch (Exception e) { 754 throw new RuntimeException(e); 755 } 756 } 757 758 /** 759 * Create a client key store that only contains self-signed certificates but no private keys 760 */ 761 public static KeyStore createClient(KeyStore caKeyStore) { 762 KeyStore clientKeyStore = createKeyStore(); 763 copySelfSignedCertificates(clientKeyStore, caKeyStore); 764 return clientKeyStore; 765 } 766 767 /** 768 * Copy self-signed certificates from one key store to another. 769 * Returns true if successful, false if no match found. 770 */ 771 public static boolean copySelfSignedCertificates(KeyStore dst, KeyStore src) { 772 try { 773 boolean copied = false; 774 for (String alias : Collections.list(src.aliases())) { 775 if (!src.isCertificateEntry(alias)) { 776 continue; 777 } 778 X509Certificate cert = (X509Certificate)src.getCertificate(alias); 779 if (!cert.getSubjectDN().equals(cert.getIssuerDN())) { 780 continue; 781 } 782 dst.setCertificateEntry(alias, cert); 783 copied = true; 784 } 785 return copied; 786 } catch (Exception e) { 787 throw new RuntimeException(e); 788 } 789 } 790 791 /** 792 * Copy named certificates from one key store to another. 793 * Returns true if successful, false if no match found. 794 */ 795 public static boolean copyCertificate(Principal subject, KeyStore dst, KeyStore src) 796 throws Exception { 797 for (String alias : Collections.list(src.aliases())) { 798 if (!src.isCertificateEntry(alias)) { 799 continue; 800 } 801 X509Certificate cert = (X509Certificate)src.getCertificate(alias); 802 if (!cert.getSubjectDN().equals(subject)) { 803 continue; 804 } 805 dst.setCertificateEntry(alias, cert); 806 return true; 807 } 808 return false; 809 } 810 811 /** 812 * Dump a key store for debugging. 813 */ 814 public static void dump(String context, KeyStore keyStore, char[] keyPassword) 815 throws KeyStoreException, NoSuchAlgorithmException { 816 PrintStream out = System.out; 817 out.println("context=" + context); 818 out.println("\tkeyStore=" + keyStore); 819 out.println("\tkeyStore.type=" + keyStore.getType()); 820 out.println("\tkeyStore.provider=" + keyStore.getProvider()); 821 out.println("\tkeyPassword=" 822 + ((keyPassword == null) ? null : new String(keyPassword))); 823 out.println("\tsize=" + keyStore.size()); 824 for (String alias : Collections.list(keyStore.aliases())) { 825 out.println("alias=" + alias); 826 out.println("\tcreationDate=" + keyStore.getCreationDate(alias)); 827 if (keyStore.isCertificateEntry(alias)) { 828 out.println("\tcertificate:"); 829 out.println("=========================================="); 830 out.println(keyStore.getCertificate(alias)); 831 out.println("=========================================="); 832 continue; 833 } 834 if (keyStore.isKeyEntry(alias)) { 835 out.println("\tkey:"); 836 out.println("=========================================="); 837 String key; 838 try { 839 key = ("Key retrieved using password\n" 840 + keyStore.getKey(alias, keyPassword)); 841 } catch (UnrecoverableKeyException e1) { 842 try { 843 key = ("Key retrieved without password\n" 844 + keyStore.getKey(alias, null)); 845 } catch (UnrecoverableKeyException e2) { 846 key = "Key could not be retrieved"; 847 } 848 } 849 out.println(key); 850 out.println("=========================================="); 851 Certificate[] chain = keyStore.getCertificateChain(alias); 852 if (chain == null) { 853 out.println("No certificate chain associated with key"); 854 out.println("=========================================="); 855 } else { 856 for (int i = 0; i < chain.length; i++) { 857 out.println("Certificate chain element #" + i); 858 out.println(chain[i]); 859 out.println("=========================================="); 860 } 861 } 862 continue; 863 } 864 out.println("\tunknown entry type"); 865 } 866 } 867 868 public static void assertChainLength(Object[] chain) { 869 /* 870 * Note chain is Object[] to support both 871 * java.security.cert.X509Certificate and 872 * javax.security.cert.X509Certificate 873 */ 874 assertEquals(3, chain.length); 875 } 876 } 877