1204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom/* 2204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * Copyright (C) 2010 The Android Open Source Project 3204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * 4204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License"); 5204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * you may not use this file except in compliance with the License. 6204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * You may obtain a copy of the License at 7204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * 8204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * http://www.apache.org/licenses/LICENSE-2.0 9204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * 10204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * Unless required by applicable law or agreed to in writing, software 11204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS, 12204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * See the License for the specific language governing permissions and 14204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * limitations under the License. 15204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom */ 16204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom 174557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonpackage libcore.java.security; 18204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom 192bdd86ec6cbafe421e5f4c24b6ec0f0fffe27f90Kenny Rootimport static org.junit.Assert.assertEquals; 202bdd86ec6cbafe421e5f4c24b6ec0f0fffe27f90Kenny Root 216ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilsonimport com.android.org.bouncycastle.asn1.DEROctetString; 2204ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Rootimport com.android.org.bouncycastle.asn1.x500.X500Name; 230ac85ead96f1ba7d35f3acadd154de4ef0a8fd87Brian Carlstromimport com.android.org.bouncycastle.asn1.x509.BasicConstraints; 240435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.asn1.x509.CRLReason; 250da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmerimport com.android.org.bouncycastle.asn1.x509.ExtendedKeyUsage; 2604ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Rootimport com.android.org.bouncycastle.asn1.x509.Extension; 276ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilsonimport com.android.org.bouncycastle.asn1.x509.GeneralName; 286ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilsonimport com.android.org.bouncycastle.asn1.x509.GeneralNames; 296ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilsonimport com.android.org.bouncycastle.asn1.x509.GeneralSubtree; 300da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmerimport com.android.org.bouncycastle.asn1.x509.KeyPurposeId; 310ac85ead96f1ba7d35f3acadd154de4ef0a8fd87Brian Carlstromimport com.android.org.bouncycastle.asn1.x509.KeyUsage; 326ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilsonimport com.android.org.bouncycastle.asn1.x509.NameConstraints; 330435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 340435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.cert.X509CertificateHolder; 3504ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Rootimport com.android.org.bouncycastle.cert.X509v3CertificateBuilder; 360435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; 370435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.BasicOCSPResp; 380435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder; 390435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.CertificateID; 400435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.CertificateStatus; 410435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.OCSPResp; 420435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.OCSPRespBuilder; 430435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.cert.ocsp.RevokedStatus; 440ac85ead96f1ba7d35f3acadd154de4ef0a8fd87Brian Carlstromimport com.android.org.bouncycastle.jce.provider.BouncyCastleProvider; 450435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.operator.DigestCalculatorProvider; 460435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.operator.bc.BcDigestCalculatorProvider; 470435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport com.android.org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; 486c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstromimport java.io.ByteArrayInputStream; 490435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport java.io.IOException; 50059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstromimport java.io.PrintStream; 51204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstromimport java.math.BigInteger; 524557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.security.KeyPair; 534557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.security.KeyPairGenerator; 54547450702efd233213f953ba2213bb38803c34c3Jesse Wilsonimport java.security.KeyStore; 55059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstromimport java.security.KeyStore.PasswordProtection; 56059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstromimport java.security.KeyStore.PrivateKeyEntry; 576c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstromimport java.security.KeyStore.TrustedCertificateEntry; 58101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilsonimport java.security.KeyStoreException; 59101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilsonimport java.security.NoSuchAlgorithmException; 60a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstromimport java.security.Principal; 614557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.security.PrivateKey; 624557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.security.PublicKey; 636882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstromimport java.security.SecureRandom; 644557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.security.Security; 65258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Rootimport java.security.UnrecoverableEntryException; 664557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport java.security.UnrecoverableKeyException; 678a720cceee7ce319d647738dfeda3f302879f370Brian Carlstromimport java.security.cert.Certificate; 680435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Rootimport java.security.cert.CertificateException; 696c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstromimport java.security.cert.CertificateFactory; 70204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstromimport java.security.cert.X509Certificate; 71b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Rootimport java.security.spec.AlgorithmParameterSpec; 726ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilsonimport java.util.ArrayList; 73059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstromimport java.util.Collections; 74204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstromimport java.util.Date; 756ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilsonimport java.util.List; 76b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Rootimport javax.crypto.spec.DHParameterSpec; 776882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstromimport javax.net.ssl.KeyManager; 786882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstromimport javax.net.ssl.KeyManagerFactory; 796882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstromimport javax.net.ssl.TrustManager; 806882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstromimport javax.net.ssl.TrustManagerFactory; 811b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstromimport javax.security.auth.x500.X500Principal; 826c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstromimport libcore.javax.net.ssl.TestKeyManager; 836c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstromimport libcore.javax.net.ssl.TestTrustManager; 84204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom 85204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom/** 86b7eec62f6db198a76b67d7915b03e59189c6df4fBrian Carlstrom * TestKeyStore is a convenience class for other tests that 87204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * want a canned KeyStore with a variety of key pairs. 88204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * 89204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * Creating a key store is relatively slow, so a singleton instance is 90204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom * accessible via TestKeyStore.get(). 91204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom */ 922bdd86ec6cbafe421e5f4c24b6ec0f0fffe27f90Kenny Rootpublic final class TestKeyStore { 935fe0dc42747e190d165e5b52b32318826a56fe0cKenny Root /** Size of DSA keys to generate for testing. */ 945fe0dc42747e190d165e5b52b32318826a56fe0cKenny Root private static final int DSA_KEY_SIZE_BITS = 1024; 955fe0dc42747e190d165e5b52b32318826a56fe0cKenny Root 965fe0dc42747e190d165e5b52b32318826a56fe0cKenny Root /** Size of EC keys to generate for testing. */ 975fe0dc42747e190d165e5b52b32318826a56fe0cKenny Root private static final int EC_KEY_SIZE_BITS = 256; 985fe0dc42747e190d165e5b52b32318826a56fe0cKenny Root 995fe0dc42747e190d165e5b52b32318826a56fe0cKenny Root /** Size of RSA keys to generate for testing. */ 1005fe0dc42747e190d165e5b52b32318826a56fe0cKenny Root private static final int RSA_KEY_SIZE_BITS = 1024; 101204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom 102b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root // Generated with: openssl dhparam -C 1024 103b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root private static final BigInteger DH_PARAMS_P = new BigInteger(1, new byte[] { 104b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0xA2, (byte) 0x31, (byte) 0xB4, (byte) 0xB3, (byte) 0x6D, (byte) 0x9B, 105b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x7E, (byte) 0xF4, (byte) 0xE7, (byte) 0x21, (byte) 0x51, (byte) 0x40, 106b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0xEB, (byte) 0xC6, (byte) 0xB6, (byte) 0xD6, (byte) 0x54, (byte) 0x56, 107b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x72, (byte) 0xBE, (byte) 0x43, (byte) 0x18, (byte) 0x30, (byte) 0x5C, 108b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x15, (byte) 0x5A, (byte) 0xF9, (byte) 0x19, (byte) 0x62, (byte) 0xAD, 109b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0xF4, (byte) 0x29, (byte) 0xCB, (byte) 0xC6, (byte) 0xF6, (byte) 0x64, 110b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x0B, (byte) 0x9D, (byte) 0x23, (byte) 0x80, (byte) 0xF9, (byte) 0x5B, 111b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x1C, (byte) 0x1C, (byte) 0x6A, (byte) 0xB4, (byte) 0xEA, (byte) 0xB9, 112b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x80, (byte) 0x98, (byte) 0x8B, (byte) 0xAF, (byte) 0x15, (byte) 0xA8, 113b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x5C, (byte) 0xC4, (byte) 0xB0, (byte) 0x41, (byte) 0x29, (byte) 0x66, 114b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x9F, (byte) 0x9F, (byte) 0x1F, (byte) 0x88, (byte) 0x50, (byte) 0x97, 115b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x38, (byte) 0x0B, (byte) 0x01, (byte) 0x16, (byte) 0xD6, (byte) 0x84, 116b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x1D, (byte) 0x48, (byte) 0x6F, (byte) 0x7C, (byte) 0x06, (byte) 0x8C, 117b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x6E, (byte) 0x68, (byte) 0xCD, (byte) 0x38, (byte) 0xE6, (byte) 0x22, 118b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x30, (byte) 0x61, (byte) 0x37, (byte) 0x02, (byte) 0x3D, (byte) 0x47, 119b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x62, (byte) 0xCE, (byte) 0xB9, (byte) 0x1A, (byte) 0x69, (byte) 0x9D, 120b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0xA1, (byte) 0x9F, (byte) 0x10, (byte) 0xA1, (byte) 0xAA, (byte) 0x70, 121b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0xF7, (byte) 0x27, (byte) 0x9C, (byte) 0xD4, (byte) 0xA5, (byte) 0x15, 122b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0xE2, (byte) 0x15, (byte) 0x0C, (byte) 0x20, (byte) 0x90, (byte) 0x08, 123b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0xB6, (byte) 0xF5, (byte) 0xDF, (byte) 0x1C, (byte) 0xCB, (byte) 0x82, 124b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x6D, (byte) 0xC0, (byte) 0xE1, (byte) 0xBD, (byte) 0xCC, (byte) 0x4A, 125b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root (byte) 0x76, (byte) 0xE3, 126b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root }); 127b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root 128b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root // generator of 2 129b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root private static final BigInteger DH_PARAMS_G = BigInteger.valueOf(2); 130b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root 1316ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson private static TestKeyStore ROOT_CA; 1320da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer private static TestKeyStore INTERMEDIATE_CA; 133181e96d17e879a1f063530cf1c540c2c5097cb02William Luh private static TestKeyStore INTERMEDIATE_CA_2; 134a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root private static TestKeyStore INTERMEDIATE_CA_EC; 1356ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson 1366ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson private static TestKeyStore SERVER; 1376ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson private static TestKeyStore CLIENT; 1386ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson private static TestKeyStore CLIENT_CERTIFICATE; 139a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root private static TestKeyStore CLIENT_EC_RSA_CERTIFICATE; 140a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root private static TestKeyStore CLIENT_EC_EC_CERTIFICATE; 1416ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson 1426ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson private static TestKeyStore CLIENT_2; 143101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 144059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom static { 145059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom if (StandardNames.IS_RI) { 1466c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom // Needed to create BKS keystore but add at end so most 1476c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom // algorithm come from the default providers 1486c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom Security.insertProviderAt(new BouncyCastleProvider(), 1496c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom Security.getProviders().length+1); 150a1d3063e3f0d9b8eb9b049bcaa0808f4ea6fba64Kenny Root } else if (!BouncyCastleProvider.class.getName().startsWith("com.android")) { 151a1d3063e3f0d9b8eb9b049bcaa0808f4ea6fba64Kenny Root // If we run outside of the Android system, we need to make sure 152a1d3063e3f0d9b8eb9b049bcaa0808f4ea6fba64Kenny Root // that the BouncyCastleProvider's static field keyInfoConverters 153a1d3063e3f0d9b8eb9b049bcaa0808f4ea6fba64Kenny Root // is initialized. This happens in the default constructor only. 154a1d3063e3f0d9b8eb9b049bcaa0808f4ea6fba64Kenny Root new BouncyCastleProvider(); 155059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 156059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 157101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 158a5caedeac65e6f1193fb51824af957c9f69c5191Sergio Giro private static final byte[] LOCAL_HOST_ADDRESS = { 127, 0, 0, 1 }; 159a5caedeac65e6f1193fb51824af957c9f69c5191Sergio Giro private static final String LOCAL_HOST_NAME = "localhost"; 160a5caedeac65e6f1193fb51824af957c9f69c5191Sergio Giro 161204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom public final KeyStore keyStore; 162e3a187163504f00c98bd75cbd8bcbdde123ae2cdBrian Carlstrom public final char[] storePassword; 163e3a187163504f00c98bd75cbd8bcbdde123ae2cdBrian Carlstrom public final char[] keyPassword; 1646882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstrom public final KeyManager[] keyManagers; 1656882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstrom public final TrustManager[] trustManagers; 1666c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom public final TestTrustManager trustManager; 167204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom 1681b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom private TestKeyStore(KeyStore keyStore, char[] storePassword, char[] keyPassword) { 169204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom this.keyStore = keyStore; 170e3a187163504f00c98bd75cbd8bcbdde123ae2cdBrian Carlstrom this.storePassword = storePassword; 171e3a187163504f00c98bd75cbd8bcbdde123ae2cdBrian Carlstrom this.keyPassword = keyPassword; 1726882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstrom this.keyManagers = createKeyManagers(keyStore, storePassword); 1736882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstrom this.trustManagers = createTrustManagers(keyStore); 1746c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom this.trustManager = (TestTrustManager)trustManagers[0]; 1756882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstrom } 1766882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstrom 1771b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom public static KeyManager[] createKeyManagers(KeyStore keyStore, char[] storePassword) { 1781b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom try { 1791b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom String kmfa = KeyManagerFactory.getDefaultAlgorithm(); 1801b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfa); 1811b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom kmf.init(keyStore, storePassword); 1821b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom return TestKeyManager.wrap(kmf.getKeyManagers()); 1831b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } catch (Exception e) { 1841b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom throw new RuntimeException(e); 1851b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 1866882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstrom } 1876882e31b7ce2d04ebbc91c7a55d7840e8fdce8a5Brian Carlstrom 1881b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom public static TrustManager[] createTrustManagers(final KeyStore keyStore) { 1891b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom try { 1901b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom String tmfa = TrustManagerFactory.getDefaultAlgorithm(); 1911b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfa); 1921b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom tmf.init(keyStore); 1931b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom return TestTrustManager.wrap(tmf.getTrustManagers()); 1941b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } catch (Exception e) { 1951b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom throw new RuntimeException(e); 1961b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 197204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom } 198204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom 199059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom /** 2006ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson * Lazily create shared test certificates. 2016ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson */ 2026ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson private static synchronized void initCerts() { 2036ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson if (ROOT_CA != null) { 2046ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson return; 2056ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson } 2061b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom ROOT_CA = new Builder() 2071b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .aliasPrefix("RootCA") 2081b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .subject("CN=Test Root Certificate Authority") 2091b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .ca(true) 2107abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro .certificateSerialNumber(BigInteger.valueOf(1)) 2111b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .build(); 212a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root INTERMEDIATE_CA_EC = new Builder() 213a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .aliasPrefix("IntermediateCA-EC") 214a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .keyAlgorithms("EC") 215a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .subject("CN=Test Intermediate Certificate Authority ECDSA") 216a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .ca(true) 217a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .signer(ROOT_CA.getPrivateKey("RSA", "RSA")) 218a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .rootCa(ROOT_CA.getRootCertificate("RSA")) 219a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .certificateSerialNumber(BigInteger.valueOf(2)) 220a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .build(); 2210da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer INTERMEDIATE_CA = new Builder() 2221b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .aliasPrefix("IntermediateCA") 2231b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .subject("CN=Test Intermediate Certificate Authority") 2241b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .ca(true) 2251b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .signer(ROOT_CA.getPrivateKey("RSA", "RSA")) 2261b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .rootCa(ROOT_CA.getRootCertificate("RSA")) 2277abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro .certificateSerialNumber(BigInteger.valueOf(2)) 2281b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .build(); 229a5caedeac65e6f1193fb51824af957c9f69c5191Sergio Giro SERVER = new Builder() 230a5caedeac65e6f1193fb51824af957c9f69c5191Sergio Giro .aliasPrefix("server") 231a5caedeac65e6f1193fb51824af957c9f69c5191Sergio Giro .signer(INTERMEDIATE_CA.getPrivateKey("RSA", "RSA")) 232a5caedeac65e6f1193fb51824af957c9f69c5191Sergio Giro .rootCa(INTERMEDIATE_CA.getRootCertificate("RSA")) 23370bd0982aa6ed2603615df8a963f285b91872c87Tobias Thierer .addSubjectAltName(new GeneralName(GeneralName.dNSName, LOCAL_HOST_NAME)) 2347abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro .certificateSerialNumber(BigInteger.valueOf(3)) 235a5caedeac65e6f1193fb51824af957c9f69c5191Sergio Giro .build(); 2360da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer CLIENT = new TestKeyStore(createClient(INTERMEDIATE_CA.keyStore), null, null); 237a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root CLIENT_EC_RSA_CERTIFICATE = new Builder() 238a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .aliasPrefix("client-ec") 239a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .keyAlgorithms("EC") 240a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .subject("emailAddress=test-ec@user") 241a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .signer(INTERMEDIATE_CA.getPrivateKey("RSA", "RSA")) 242a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .rootCa(INTERMEDIATE_CA.getRootCertificate("RSA")) 243a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .build(); 244a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root CLIENT_EC_EC_CERTIFICATE = new Builder() 245a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .aliasPrefix("client-ec") 246a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .keyAlgorithms("EC") 247a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .subject("emailAddress=test-ec@user") 248a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .signer(INTERMEDIATE_CA_EC.getPrivateKey("EC", "RSA")) 249a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .rootCa(INTERMEDIATE_CA_EC.getRootCertificate("RSA")) 250a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root .build(); 2511b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom CLIENT_CERTIFICATE = new Builder() 2521b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .aliasPrefix("client") 2531b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .subject("emailAddress=test@user") 2540da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer .signer(INTERMEDIATE_CA.getPrivateKey("RSA", "RSA")) 2550da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer .rootCa(INTERMEDIATE_CA.getRootCertificate("RSA")) 2561b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .build(); 2571b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom TestKeyStore rootCa2 = new Builder() 2581b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .aliasPrefix("RootCA2") 2591b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .subject("CN=Test Root Certificate Authority 2") 2601b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .ca(true) 2611b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom .build(); 262181e96d17e879a1f063530cf1c540c2c5097cb02William Luh INTERMEDIATE_CA_2 = new Builder() 263181e96d17e879a1f063530cf1c540c2c5097cb02William Luh .aliasPrefix("IntermediateCA") 264181e96d17e879a1f063530cf1c540c2c5097cb02William Luh .subject("CN=Test Intermediate Certificate Authority") 265181e96d17e879a1f063530cf1c540c2c5097cb02William Luh .ca(true) 266181e96d17e879a1f063530cf1c540c2c5097cb02William Luh .signer(rootCa2.getPrivateKey("RSA", "RSA")) 267181e96d17e879a1f063530cf1c540c2c5097cb02William Luh .rootCa(rootCa2.getRootCertificate("RSA")) 268181e96d17e879a1f063530cf1c540c2c5097cb02William Luh .build(); 2691b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom CLIENT_2 = new TestKeyStore(createClient(rootCa2.keyStore), null, null); 2706ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson } 2716ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson 2726ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson /** 2730da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer * Return an root CA that can be used to issue new certificates. 2740da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer */ 2750da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer public static TestKeyStore getRootCa() { 2760da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer initCerts(); 2770da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer return ROOT_CA; 2780da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer } 2790da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer 2800da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer /** 2810da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer * Return an intermediate CA that can be used to issue new certificates. 2820da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer */ 2830da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer public static TestKeyStore getIntermediateCa() { 2840da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer initCerts(); 2850da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer return INTERMEDIATE_CA; 2860da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer } 2870da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer 2880da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer /** 289181e96d17e879a1f063530cf1c540c2c5097cb02William Luh * Return an intermediate CA that can be used to issue new certificates. 290181e96d17e879a1f063530cf1c540c2c5097cb02William Luh */ 291181e96d17e879a1f063530cf1c540c2c5097cb02William Luh public static TestKeyStore getIntermediateCa2() { 292181e96d17e879a1f063530cf1c540c2c5097cb02William Luh initCerts(); 293181e96d17e879a1f063530cf1c540c2c5097cb02William Luh return INTERMEDIATE_CA_2; 294181e96d17e879a1f063530cf1c540c2c5097cb02William Luh } 295181e96d17e879a1f063530cf1c540c2c5097cb02William Luh 296181e96d17e879a1f063530cf1c540c2c5097cb02William Luh /** 297059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom * Return a server keystore with a matched RSA certificate and 298059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom * private key as well as a CA certificate. 299059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom */ 300059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom public static TestKeyStore getServer() { 3016ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson initCerts(); 302059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom return SERVER; 303059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 304059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom 305059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom /** 306059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom * Return a keystore with a CA certificate 307059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom */ 308059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom public static TestKeyStore getClient() { 3096ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson initCerts(); 310059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom return CLIENT; 311059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 312204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom 313b7eec62f6db198a76b67d7915b03e59189c6df4fBrian Carlstrom /** 314059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom * Return a client keystore with a matched RSA certificate and 315059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom * private key as well as a CA certificate. 316b7eec62f6db198a76b67d7915b03e59189c6df4fBrian Carlstrom */ 317059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom public static TestKeyStore getClientCertificate() { 3186ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson initCerts(); 319059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom return CLIENT_CERTIFICATE; 320204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom } 321204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom 322b7eec62f6db198a76b67d7915b03e59189c6df4fBrian Carlstrom /** 323a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root * Return a client keystore with a matched RSA certificate and 324a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root * private key as well as a CA certificate. 325a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root */ 326a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root public static TestKeyStore getClientEcRsaCertificate() { 327a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root initCerts(); 328a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root return CLIENT_EC_RSA_CERTIFICATE; 329a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root } 330a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root 331a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root /** 332a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root * Return a client keystore with a matched RSA certificate and 333a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root * private key as well as a CA certificate. 334a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root */ 335a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root public static TestKeyStore getClientEcEcCertificate() { 336a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root initCerts(); 337a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root return CLIENT_EC_EC_CERTIFICATE; 338a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root } 339a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root 340a86c73bb4b81906c965a55de48e38dd4e44f49e6Kenny Root /** 3412915378e253f08e47fe5a9bfd026cd1ca7c6c351Brian Carlstrom * Return a keystore with a second CA certificate that does not 3422915378e253f08e47fe5a9bfd026cd1ca7c6c351Brian Carlstrom * trust the server certificate returned by getServer for negative 3432915378e253f08e47fe5a9bfd026cd1ca7c6c351Brian Carlstrom * testing. 3442915378e253f08e47fe5a9bfd026cd1ca7c6c351Brian Carlstrom */ 3452915378e253f08e47fe5a9bfd026cd1ca7c6c351Brian Carlstrom public static TestKeyStore getClientCA2() { 3466ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson initCerts(); 3472915378e253f08e47fe5a9bfd026cd1ca7c6c351Brian Carlstrom return CLIENT_2; 3482915378e253f08e47fe5a9bfd026cd1ca7c6c351Brian Carlstrom } 3492915378e253f08e47fe5a9bfd026cd1ca7c6c351Brian Carlstrom 3502915378e253f08e47fe5a9bfd026cd1ca7c6c351Brian Carlstrom /** 351101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * Creates KeyStores containing the requested key types. Since key 352101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * generation can be expensive, most tests should reuse the RSA-only 353101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * singleton instance returned by TestKeyStore.get. 354b7eec62f6db198a76b67d7915b03e59189c6df4fBrian Carlstrom */ 355101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson public static class Builder { 356101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson private String[] keyAlgorithms = { "RSA" }; 357101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson private char[] storePassword; 358101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson private char[] keyPassword; 359101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson private String aliasPrefix; 3601b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom private X500Principal subject; 361101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson private int keyUsage; 362101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson private boolean ca; 363258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root private PrivateKeyEntry privateEntry; 364101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson private PrivateKeyEntry signer; 365101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson private Certificate rootCa; 3660da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer private final List<KeyPurposeId> extendedKeyUsages = new ArrayList<KeyPurposeId>(); 3670da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer private final List<Boolean> criticalExtendedKeyUsages = new ArrayList<Boolean>(); 3686ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson private final List<GeneralName> subjectAltNames = new ArrayList<GeneralName>(); 3690da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer private final List<GeneralSubtree> permittedNameConstraints 3700da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer = new ArrayList<GeneralSubtree>(); 3710da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer private final List<GeneralSubtree> excludedNameConstraints 3720da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer = new ArrayList<GeneralSubtree>(); 3737abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro // Generated randomly if not set 3747abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro private BigInteger certificateSerialNumber = null; 375101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 3761b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom public Builder() { 377101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson subject = localhost(); 378101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 379101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 380101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson /** 381101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * Sets the requested key types to generate and include. The default is 382101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * RSA only. 383101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson */ 384101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson public Builder keyAlgorithms(String... keyAlgorithms) { 385101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson this.keyAlgorithms = keyAlgorithms; 386101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson return this; 387101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 388101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 389101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson /** A unique prefix to identify the key aliases */ 390101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson public Builder aliasPrefix(String aliasPrefix) { 391101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson this.aliasPrefix = aliasPrefix; 392101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson return this; 393101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 394101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 395101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson /** 396101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * Sets the subject common name. The default is the local host's 397101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * canonical name. 398101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson */ 3991b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom public Builder subject(X500Principal subject) { 400101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson this.subject = subject; 401101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson return this; 402101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 403101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 404101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson public Builder subject(String commonName) { 4051b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom return subject(new X500Principal(commonName)); 406101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 407101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 408101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson /** {@link KeyUsage} bit mask for 2.5.29.15 extension */ 409101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson public Builder keyUsage(int keyUsage) { 410101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson this.keyUsage = keyUsage; 411101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson return this; 412101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 413101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 414101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson /** true If the keys being created are for a CA */ 415101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson public Builder ca(boolean ca) { 416101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson this.ca = ca; 417101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson return this; 418101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 419101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 420258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root /** a private key entry to use for the generation of the certificate */ 421258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root public Builder privateEntry(PrivateKeyEntry privateEntry) { 422258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root this.privateEntry = privateEntry; 423258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root return this; 424258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } 425258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root 426101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson /** a private key entry to be used for signing, otherwise self-sign */ 427101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson public Builder signer(PrivateKeyEntry signer) { 428101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson this.signer = signer; 429101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson return this; 430101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 431101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 432101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson /** a root CA to include in the final store */ 433101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson public Builder rootCa(Certificate rootCa) { 434101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson this.rootCa = rootCa; 435101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson return this; 436101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 437101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 4380da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer public Builder addExtendedKeyUsage(KeyPurposeId keyPurposeId, boolean critical) { 4390da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer extendedKeyUsages.add(keyPurposeId); 4400da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer criticalExtendedKeyUsages.add(critical); 4410da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer return this; 4420da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer } 4430da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer 4440da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer public Builder addSubjectAltName(GeneralName generalName) { 4456ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson subjectAltNames.add(generalName); 4466ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson return this; 4476ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson } 4486ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson 4496ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson public Builder addSubjectAltNameIpAddress(byte[] ipAddress) { 4506ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson return addSubjectAltName( 4516ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson new GeneralName(GeneralName.iPAddress, new DEROctetString(ipAddress))); 4526ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson } 4536ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson 4546ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson private Builder addNameConstraint(boolean permitted, GeneralName generalName) { 4556ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson if (permitted) { 4566ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson permittedNameConstraints.add(new GeneralSubtree(generalName)); 4576ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson } else { 4586ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson excludedNameConstraints.add(new GeneralSubtree(generalName)); 4596ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson } 4606ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson return this; 4616ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson } 4626ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson 4636ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson public Builder addNameConstraint(boolean permitted, byte[] ipAddress) { 4646ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson return addNameConstraint(permitted, 4656ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson new GeneralName(GeneralName.iPAddress, new DEROctetString(ipAddress))); 4666ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson } 4676ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson 4687abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro public Builder certificateSerialNumber(BigInteger certificateSerialNumber) { 4697abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro this.certificateSerialNumber = certificateSerialNumber; 4707abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro return this; 4717abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro } 4727abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro 4731b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom public TestKeyStore build() { 4741b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom try { 4751b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (StandardNames.IS_RI) { 4761b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom // JKS does not allow null password 4771b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (storePassword == null) { 4781b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom storePassword = "password".toCharArray(); 4791b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 4801b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (keyPassword == null) { 4811b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom keyPassword = "password".toCharArray(); 4821b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 4836c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom } 484101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 485258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root /* 486258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root * This is not implemented for other key types because the logic 487258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root * would be long to write and it's not needed currently. 488258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root */ 489258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root if (privateEntry != null 490258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root && (keyAlgorithms.length != 1 || !"RSA".equals(keyAlgorithms[0]))) { 491258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root throw new IllegalStateException( 492258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root "Only reusing an existing key is implemented for RSA"); 493258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } 494258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root 4951b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom KeyStore keyStore = createKeyStore(); 4961b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom for (String keyAlgorithm : keyAlgorithms) { 4971b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom String publicAlias = aliasPrefix + "-public-" + keyAlgorithm; 4981b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom String privateAlias = aliasPrefix + "-private-" + keyAlgorithm; 499888373c54fd5f8fa0b1965238309db8187e3b381Kenny Root if ((keyAlgorithm.equals("EC_RSA") || keyAlgorithm.equals("DH_RSA")) 500888373c54fd5f8fa0b1965238309db8187e3b381Kenny Root && signer == null && rootCa == null) { 501258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, null, 502258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root privateKey(keyStore, keyPassword, "RSA", "RSA")); 5031b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom continue; 504888373c54fd5f8fa0b1965238309db8187e3b381Kenny Root } else if (keyAlgorithm.equals("DH_DSA") && signer == null && rootCa == null) { 505258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, null, 506888373c54fd5f8fa0b1965238309db8187e3b381Kenny Root privateKey(keyStore, keyPassword, "DSA", "DSA")); 507888373c54fd5f8fa0b1965238309db8187e3b381Kenny Root continue; 5081b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 509258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, privateEntry, 510258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root signer); 5116c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom } 5121b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (rootCa != null) { 5131b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom keyStore.setCertificateEntry(aliasPrefix 5141b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom + "-root-ca-" 5151b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom + rootCa.getPublicKey().getAlgorithm(), 5161b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom rootCa); 5171b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 5181b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom return new TestKeyStore(keyStore, storePassword, keyPassword); 5191b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } catch (Exception e) { 5201b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom throw new RuntimeException(e); 521204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom } 522101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 523101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 524101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson /** 525101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * Add newly generated keys of a given key type to an existing 526101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * KeyStore. The PrivateKey will be stored under the specified 527101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * private alias name. The X509Certificate will be stored on the 528101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * public alias name and have the given subject distinguished 529101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * name. 530101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * 531101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * If a CA is provided, it will be used to sign the generated 5320435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root * certificate and OCSP responses. Otherwise, the certificate 5330435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root * will be self signed. The certificate will be valid for one 5340435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root * day before and one day after the time of creation. 535101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * 536101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * Based on: 537101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * org.bouncycastle.jce.provider.test.SigTest 538101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * org.bouncycastle.jce.provider.test.CertTest 539101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson */ 540101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson private KeyStore createKeys(KeyStore keyStore, 541101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson String keyAlgorithm, 542101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson String publicAlias, 543101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson String privateAlias, 544258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root PrivateKeyEntry privateEntry, 545101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson PrivateKeyEntry signer) throws Exception { 546101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson PrivateKey caKey; 547101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson X509Certificate caCert; 548101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson X509Certificate[] caCertChain; 549101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson if (signer == null) { 550101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson caKey = null; 551101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson caCert = null; 552101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson caCertChain = null; 553101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } else { 554101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson caKey = signer.getPrivateKey(); 555101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson caCert = (X509Certificate)signer.getCertificate(); 556101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson caCertChain = (X509Certificate[])signer.getCertificateChain(); 557101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 558101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 559258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root final PrivateKey privateKey; 560258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root final PublicKey publicKey; 561101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson X509Certificate x509c; 562101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson if (publicAlias == null && privateAlias == null) { 563101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson // don't want anything apparently 564101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson privateKey = null; 565258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root publicKey = null; 566101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson x509c = null; 567101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } else { 568258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root if (privateEntry == null) { 569258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root // 1a.) we make the keys 570b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root int keySize = -1; 571b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root AlgorithmParameterSpec spec = null; 572258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root if (keyAlgorithm.equals("RSA")) { 5735fe0dc42747e190d165e5b52b32318826a56fe0cKenny Root keySize = RSA_KEY_SIZE_BITS; 574258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } else if (keyAlgorithm.equals("DH_RSA")) { 575b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root spec = new DHParameterSpec(DH_PARAMS_P, DH_PARAMS_G); 576258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root keyAlgorithm = "DH"; 577258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } else if (keyAlgorithm.equals("DSA")) { 5785fe0dc42747e190d165e5b52b32318826a56fe0cKenny Root keySize = DSA_KEY_SIZE_BITS; 579258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } else if (keyAlgorithm.equals("DH_DSA")) { 580b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root spec = new DHParameterSpec(DH_PARAMS_P, DH_PARAMS_G); 581258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root keyAlgorithm = "DH"; 582258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } else if (keyAlgorithm.equals("EC")) { 5835fe0dc42747e190d165e5b52b32318826a56fe0cKenny Root keySize = EC_KEY_SIZE_BITS; 584258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } else if (keyAlgorithm.equals("EC_RSA")) { 5855fe0dc42747e190d165e5b52b32318826a56fe0cKenny Root keySize = EC_KEY_SIZE_BITS; 586258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root keyAlgorithm = "EC"; 587258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } else { 588258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm); 589258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } 590101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 591258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgorithm); 592b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root if (spec != null) { 593b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root kpg.initialize(spec); 594b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root } else if (keySize != -1) { 595b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root kpg.initialize(keySize); 596b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root } else { 597b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root throw new AssertionError("Must either have set algorithm parameters or key size!"); 598b38c1d0379aae312f2a3edd5a0581850988afba1Kenny Root } 599101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 600258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root KeyPair kp = kpg.generateKeyPair(); 601258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root privateKey = kp.getPrivate(); 602258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root publicKey = kp.getPublic(); 603258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } else { 604258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root // 1b.) we use the previous keys 605258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root privateKey = privateEntry.getPrivateKey(); 606258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root publicKey = privateEntry.getCertificate().getPublicKey(); 607258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } 6086ed93fa8be996378e766d3fd2586b51c6fe656b1Jesse Wilson 6091b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom // 2.) use keys to make certificate 6101b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom X500Principal issuer = ((caCert != null) 6111b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom ? caCert.getSubjectX500Principal() 6121b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom : subject); 613101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson PrivateKey signingKey = (caKey == null) ? privateKey : caKey; 6141b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom x509c = createCertificate(publicKey, signingKey, subject, issuer, keyUsage, ca, 6150da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer extendedKeyUsages, criticalExtendedKeyUsages, 6161b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom subjectAltNames, 6177abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro permittedNameConstraints, excludedNameConstraints, 6187abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro certificateSerialNumber); 619101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 620101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 621101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson X509Certificate[] x509cc; 622101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson if (privateAlias == null) { 623101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson // don't need certificate chain 624101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson x509cc = null; 625101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } else if (caCertChain == null) { 626101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson x509cc = new X509Certificate[] { x509c }; 627101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } else { 628101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson x509cc = new X509Certificate[caCertChain.length+1]; 629101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson x509cc[0] = x509c; 630101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson System.arraycopy(caCertChain, 0, x509cc, 1, caCertChain.length); 631101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 632101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 633101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson // 3.) put certificate and private key into the key store 634101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson if (privateAlias != null) { 635101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson keyStore.setKeyEntry(privateAlias, privateKey, keyPassword, x509cc); 636101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 637101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson if (publicAlias != null) { 638101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson keyStore.setCertificateEntry(publicAlias, x509c); 639101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 640101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson return keyStore; 641101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 642101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 6431b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom private X500Principal localhost() { 64470bd0982aa6ed2603615df8a963f285b91872c87Tobias Thierer return new X500Principal("CN=Local Host"); 645101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 6461b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 647101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson 648003f7a4d100cd1527d94bac81a4a3c5a8216c6eeBrian Carlstrom public static X509Certificate createCa(PublicKey publicKey, 6491b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom PrivateKey privateKey, 6501b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom String subject) { 6511b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom try { 6521b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom X500Principal principal = new X500Principal(subject); 6531b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom return createCertificate(publicKey, privateKey, 6541b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom principal, principal, 6551b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom 0, true, 6560da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer new ArrayList<KeyPurposeId>(), 6570da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer new ArrayList<Boolean>(), 6580da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer new ArrayList<GeneralName>(), 6590da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer new ArrayList<GeneralSubtree>(), 6607abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro new ArrayList<GeneralSubtree>(), 6617abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro null /* serialNumber, generated randomly */); 6621b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } catch (Exception e) { 6631b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom throw new RuntimeException(e); 6641b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 6651b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 6661b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom 6671b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom private static X509Certificate createCertificate( 6681b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom PublicKey publicKey, 6691b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom PrivateKey privateKey, 6701b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom X500Principal subject, 6711b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom X500Principal issuer, 6721b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom int keyUsage, 6731b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom boolean ca, 6740da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer List<KeyPurposeId> extendedKeyUsages, 6750da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer List<Boolean> criticalExtendedKeyUsages, 6761b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom List<GeneralName> subjectAltNames, 6770da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer List<GeneralSubtree> permittedNameConstraints, 6787abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro List<GeneralSubtree> excludedNameConstraints, 6797abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro BigInteger serialNumber) throws Exception { 6801b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom // Note that there is no way to programmatically make a 6811b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom // Certificate using java.* or javax.* APIs. The 6821b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom // CertificateFactory interface assumes you want to read 6831b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom // in a stream of bytes, typically the X.509 factory would 6841b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom // allow ASN.1 DER encoded bytes and optionally some PEM 6851b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom // formats. Here we use Bouncy Castle's 6861b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom // X509V3CertificateGenerator and related classes. 6871b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom 6881b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom long millisPerDay = 24 * 60 * 60 * 1000; 6891b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom long now = System.currentTimeMillis(); 6901b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom Date start = new Date(now - millisPerDay); 6911b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom Date end = new Date(now + millisPerDay); 6920435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root 6931b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom String keyAlgorithm = privateKey.getAlgorithm(); 6941b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom String signatureAlgorithm; 6951b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (keyAlgorithm.equals("RSA")) { 6961b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom signatureAlgorithm = "sha1WithRSA"; 6971b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } else if (keyAlgorithm.equals("DSA")) { 6981b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom signatureAlgorithm = "sha1WithDSA"; 6991b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } else if (keyAlgorithm.equals("EC")) { 7001b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom signatureAlgorithm = "sha1WithECDSA"; 7011b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } else if (keyAlgorithm.equals("EC_RSA")) { 7021b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom signatureAlgorithm = "sha1WithRSA"; 7031b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } else { 7041b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm); 7051b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 7061b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom 7077abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro if (serialNumber == null) { 7087abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro byte[] serialBytes = new byte[16]; 7097abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro new SecureRandom().nextBytes(serialBytes); 7107abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro serialNumber = new BigInteger(1, serialBytes); 7117abb54e68e213538f8df3357a8abce4a6e49b086Sergio Giro } 71204ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root 71304ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root X509v3CertificateBuilder x509cg = new X509v3CertificateBuilder( 71404ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root X500Name.getInstance(issuer.getEncoded()), serialNumber, start, end, 71504ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root X500Name.getInstance(subject.getEncoded()), 71604ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); 7171b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (keyUsage != 0) { 71804ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root x509cg.addExtension(Extension.keyUsage, 7191b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom true, 7201b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom new KeyUsage(keyUsage)); 7211b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 7221b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (ca) { 72304ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root x509cg.addExtension(Extension.basicConstraints, 7241b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom true, 7251b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom new BasicConstraints(true)); 7261b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 7270da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer for (int i = 0; i < extendedKeyUsages.size(); i++) { 7280da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer KeyPurposeId keyPurposeId = extendedKeyUsages.get(i); 7290da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer boolean critical = criticalExtendedKeyUsages.get(i); 73004ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root x509cg.addExtension(Extension.extendedKeyUsage, 7310da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer critical, 7320da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer new ExtendedKeyUsage(keyPurposeId)); 7330da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer } 7341b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom for (GeneralName subjectAltName : subjectAltNames) { 73504ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root x509cg.addExtension(Extension.subjectAlternativeName, 7361b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom false, 7371b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom new GeneralNames(subjectAltName).getEncoded()); 738204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom } 7391b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (!permittedNameConstraints.isEmpty() || !excludedNameConstraints.isEmpty()) { 74004ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root x509cg.addExtension(Extension.nameConstraints, 7411b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom true, 742ac4b39b3f93a28ba0375ac108155b752a79e4f5fBrian Carlstrom new NameConstraints(permittedNameConstraints.toArray( 743ac4b39b3f93a28ba0375ac108155b752a79e4f5fBrian Carlstrom new GeneralSubtree[ 744ac4b39b3f93a28ba0375ac108155b752a79e4f5fBrian Carlstrom permittedNameConstraints.size()]), 745ac4b39b3f93a28ba0375ac108155b752a79e4f5fBrian Carlstrom excludedNameConstraints.toArray( 746ac4b39b3f93a28ba0375ac108155b752a79e4f5fBrian Carlstrom new GeneralSubtree[ 747ac4b39b3f93a28ba0375ac108155b752a79e4f5fBrian Carlstrom excludedNameConstraints.size()]))); 7481b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 7491b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom 75004ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root X509CertificateHolder x509holder = x509cg.build( 75104ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root new JcaContentSignerBuilder(signatureAlgorithm).build(privateKey)); 75204ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 75304ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root X509Certificate x509c = (X509Certificate) certFactory.generateCertificate( 75404ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root new ByteArrayInputStream(x509holder.getEncoded())); 75504ba2ae5ace8d45cbce4139bec5889cf7191d15aKenny Root 7561b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (StandardNames.IS_RI) { 7571b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom /* 7581b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom * The RI can't handle the BC EC signature algorithm 7591b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom * string of "ECDSA", since it expects "...WITHEC...", 7601b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom * so convert from BC to RI X509Certificate 7611b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom * implementation via bytes. 7621b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom */ 7631b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom CertificateFactory cf = CertificateFactory.getInstance("X.509"); 7641b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom ByteArrayInputStream bais = new ByteArrayInputStream(x509c.getEncoded()); 7651b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom Certificate c = cf.generateCertificate(bais); 7661b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom x509c = (X509Certificate) c; 7671b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 7681b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom return x509c; 769204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom } 770204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom 771204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom /** 7726c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * Return the key algorithm for a possible compound algorithm 7736c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * identifier containing an underscore. If not underscore is 7746c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * present, the argument is returned unmodified. However for an 7756c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * algorithm such as EC_RSA, return EC. 7766c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom */ 7776c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom public static String keyAlgorithm(String algorithm) { 7786c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom int index = algorithm.indexOf('_'); 7796c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom if (index == -1) { 7806c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom return algorithm; 7816c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom } 7826c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom return algorithm.substring(0, index); 7836c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom } 7846c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom 7856c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom 7866c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom /** 7876c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * Return the signature algorithm for a possible compound 7886c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * algorithm identifier containing an underscore. If not 7896c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * underscore is present, the argument is returned 7906c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * unmodified. However for an algorithm such as EC_RSA, return 7916c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * RSA. 7926c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom */ 7936c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom public static String signatureAlgorithm(String algorithm) { 7946c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom int index = algorithm.indexOf('_'); 7956c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom if (index == -1) { 7966c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom return algorithm; 7976c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom } 7986c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom return algorithm.substring(index+1, algorithm.length()); 7996c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom } 8006c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom 8016c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom /** 8026c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * Create an empty KeyStore 803204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom */ 8041b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom public static KeyStore createKeyStore() { 8051b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom try { 8061b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom KeyStore keyStore = KeyStore.getInstance(StandardNames.KEY_STORE_ALGORITHM); 8071b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom keyStore.load(null, null); 8081b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom return keyStore; 8091b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } catch (Exception e) { 8101b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom throw new RuntimeException(e); 8111b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 812204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom } 813204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom 814204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom /** 815a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom * Return the only private key in a TestKeyStore for the given 8166c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * algorithms. Throws IllegalStateException if there are are more 817a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom * or less than one. 818a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom */ 8191b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom public PrivateKeyEntry getPrivateKey(String keyAlgorithm, String signatureAlgorithm) { 8206c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom return privateKey(keyStore, keyPassword, keyAlgorithm, signatureAlgorithm); 821a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } 822a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom 823a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom /** 824059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom * Return the only private key in a keystore for the given 8256c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * algorithms. Throws IllegalStateException if there are are more 826059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom * or less than one. 827059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom */ 828101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson public static PrivateKeyEntry privateKey(KeyStore keyStore, char[] keyPassword, 8291b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom String keyAlgorithm, String signatureAlgorithm) { 8301b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom try { 8311b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom PrivateKeyEntry found = null; 8321b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom PasswordProtection password = new PasswordProtection(keyPassword); 8331b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom for (String alias : Collections.list(keyStore.aliases())) { 8341b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (!keyStore.entryInstanceOf(alias, PrivateKeyEntry.class)) { 8351b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom continue; 8361b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 8371b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom PrivateKeyEntry privateKey = (PrivateKeyEntry) keyStore.getEntry(alias, password); 8381b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (!privateKey.getPrivateKey().getAlgorithm().equals(keyAlgorithm)) { 8391b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom continue; 8401b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 8411b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom X509Certificate certificate = (X509Certificate) privateKey.getCertificate(); 8421b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (!certificate.getSigAlgName().contains(signatureAlgorithm)) { 8431b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom continue; 8441b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 8451b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (found != null) { 846888373c54fd5f8fa0b1965238309db8187e3b381Kenny Root throw new IllegalStateException("KeyStore has more than one private key for" 8471b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom + " keyAlgorithm: " + keyAlgorithm 8481b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom + " signatureAlgorithm: " + signatureAlgorithm 8491b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom + "\nfirst: " + found.getPrivateKey() 8501b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom + "\nsecond: " + privateKey.getPrivateKey() ); 8511b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 8521b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom found = privateKey; 853059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 8541b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (found == null) { 855888373c54fd5f8fa0b1965238309db8187e3b381Kenny Root throw new IllegalStateException("KeyStore contained no private key for" 8566c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom + " keyAlgorithm: " + keyAlgorithm 8571b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom + " signatureAlgorithm: " + signatureAlgorithm); 8586c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom } 8591b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom return found; 8601b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } catch (Exception e) { 861888373c54fd5f8fa0b1965238309db8187e3b381Kenny Root throw new RuntimeException("Problem getting key for " + keyAlgorithm 862888373c54fd5f8fa0b1965238309db8187e3b381Kenny Root + " and signature " + signatureAlgorithm, e); 8636c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom } 8646c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom } 8656c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom 8666c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom /** 8673258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom * Return the issuing CA certificate of the given 8683258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom * certificate. Throws IllegalStateException if there are are more 8693258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom * or less than one. 8703258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom */ 8713258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom public Certificate getIssuer(Certificate cert) throws Exception { 8723258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom return issuer(keyStore, cert); 8733258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom } 8743258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom 8753258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom /** 8763258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom * Return the issuing CA certificate of the given 8773258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom * certificate. Throws IllegalStateException if there are are more 8783258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom * or less than one. 8793258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom */ 8803258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom public static Certificate issuer(KeyStore keyStore, Certificate c) 8813258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom throws Exception { 8823258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom if (!(c instanceof X509Certificate)) { 8833258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom throw new IllegalStateException("issuer requires an X509Certificate, found " + c); 8843258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom } 8853258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom X509Certificate cert = (X509Certificate) c; 8863258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom 8873258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom Certificate found = null; 8883258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom for (String alias : Collections.list(keyStore.aliases())) { 8893258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom if (!keyStore.entryInstanceOf(alias, TrustedCertificateEntry.class)) { 8903258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom continue; 8913258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom } 8923258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom TrustedCertificateEntry certificateEntry = 8933258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom (TrustedCertificateEntry) keyStore.getEntry(alias, null); 8943258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom Certificate certificate = certificateEntry.getTrustedCertificate(); 8953258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom if (!(certificate instanceof X509Certificate)) { 8963258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom continue; 8973258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom } 8983258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom X509Certificate x = (X509Certificate) certificate; 8993258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom if (!cert.getIssuerDN().equals(x.getSubjectDN())) { 9003258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom continue; 9013258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom } 9023258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom if (found != null) { 9033258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom throw new IllegalStateException("KeyStore has more than one issuing CA for " 9043258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom + cert 9053258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom + "\nfirst: " + found 9063258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom + "\nsecond: " + certificate ); 9073258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom } 9083258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom found = certificate; 9093258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom } 9103258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom if (found == null) { 9113258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom throw new IllegalStateException("KeyStore contained no issuing CA for " + cert); 9123258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom } 9133258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom return found; 9143258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom } 9153258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom 9163258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom /** 9176c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * Return the only self-signed root certificate in a TestKeyStore 9186c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * for the given algorithm. Throws IllegalStateException if there 9196c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * are are more or less than one. 9206c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom */ 9211b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom public X509Certificate getRootCertificate(String algorithm) { 9226c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom return rootCertificate(keyStore, algorithm); 9236c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom } 9246c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom 9250435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root private static OCSPResp generateOCSPResponse(PrivateKeyEntry server, PrivateKeyEntry issuer, 9260435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root CertificateStatus status) throws CertificateException { 9270435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root try { 9280435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root X509Certificate serverCertJca = (X509Certificate) server.getCertificate(); 9290435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root X509Certificate caCertJca = (X509Certificate) issuer.getCertificate(); 9300435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root 9310435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root X509CertificateHolder caCert = new JcaX509CertificateHolder(caCertJca); 9320435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root 9330435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root DigestCalculatorProvider digCalcProv = new BcDigestCalculatorProvider(); 9340435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root BasicOCSPRespBuilder basicBuilder = new BasicOCSPRespBuilder( 9350435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root SubjectPublicKeyInfo.getInstance(caCertJca.getPublicKey().getEncoded()), 9360435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root digCalcProv.get(CertificateID.HASH_SHA1)); 9370435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root 9380435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root CertificateID certId = new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), 9390435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root caCert, serverCertJca.getSerialNumber()); 9400435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root 9410435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root basicBuilder.addResponse(certId, status); 9420435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root 9430435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root BasicOCSPResp resp = basicBuilder.build( 9440435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root new JcaContentSignerBuilder("SHA256withRSA").build(issuer.getPrivateKey()), 9450435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root null, new Date()); 9460435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root 9470435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root OCSPRespBuilder builder = new OCSPRespBuilder(); 9480435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root return builder.build(OCSPRespBuilder.SUCCESSFUL, resp); 9490435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root } catch (Exception e) { 9500435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root throw new CertificateException("cannot generate OCSP response", e); 9510435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root } 9520435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root } 9530435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root 9540435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root public static byte[] getOCSPResponseForGood(PrivateKeyEntry server, PrivateKeyEntry issuer) throws CertificateException { 9550435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root try { 9560435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root return generateOCSPResponse(server, issuer, CertificateStatus.GOOD).getEncoded(); 9570435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root } catch (IOException e) { 9580435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root throw new CertificateException(e); 9590435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root } 9600435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root } 9610435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root 9620435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root public static byte[] getOCSPResponseForRevoked(PrivateKeyEntry server, PrivateKeyEntry issuer) 9630435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root throws CertificateException { 9640435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root try { 9650435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root return generateOCSPResponse(server, issuer, 9660435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root new RevokedStatus(new Date(), CRLReason.keyCompromise)).getEncoded(); 9670435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root } catch (IOException e) { 9680435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root throw new CertificateException(e); 9690435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root } 9700435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root } 9710435fdbd46bdbbec9c97932ebb86bffe8cb981b6Kenny Root 9726c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom /** 9736c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * Return the only self-signed root certificate in a keystore for 9746c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * the given algorithm. Throws IllegalStateException if there are 9756c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom * are more or less than one. 9766c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom */ 9771b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom public static X509Certificate rootCertificate(KeyStore keyStore, String algorithm) { 9781b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom try { 9791b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom X509Certificate found = null; 9801b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom for (String alias : Collections.list(keyStore.aliases())) { 9811b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (!keyStore.entryInstanceOf(alias, TrustedCertificateEntry.class)) { 9821b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom continue; 9831b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 9841b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom TrustedCertificateEntry certificateEntry = 9851b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom (TrustedCertificateEntry) keyStore.getEntry(alias, null); 9861b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom Certificate certificate = certificateEntry.getTrustedCertificate(); 9871b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (!certificate.getPublicKey().getAlgorithm().equals(algorithm)) { 9881b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom continue; 9891b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 9901b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (!(certificate instanceof X509Certificate)) { 9911b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom continue; 9921b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 9931b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom X509Certificate x = (X509Certificate) certificate; 9941b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (!x.getIssuerDN().equals(x.getSubjectDN())) { 9951b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom continue; 9961b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 9971b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (found != null) { 9981b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom throw new IllegalStateException("KeyStore has more than one root CA for " 9991b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom + algorithm 10001b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom + "\nfirst: " + found 10011b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom + "\nsecond: " + certificate ); 10021b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 10031b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom found = x; 1004101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 10051b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (found == null) { 10061b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom throw new IllegalStateException("KeyStore contained no root CA for " + algorithm); 1007101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 10081b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom return found; 10091b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } catch (Exception e) { 10101b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom throw new RuntimeException(e); 1011258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } 1012258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } 1013258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root 1014258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root /** 1015258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root * Return an {@code X509Certificate that matches the given {@code alias}. 1016258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root */ 1017258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root public KeyStore.Entry getEntryByAlias(String alias) { 1018258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root return entryByAlias(keyStore, alias); 1019258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } 1020258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root 1021258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root /** 1022258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root * Finds an entry in the keystore by the given alias. 1023258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root */ 1024258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root public static KeyStore.Entry entryByAlias(KeyStore keyStore, String alias) { 1025258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root try { 1026258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root return keyStore.getEntry(alias, null); 1027258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root } catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException e) { 1028258e3d158c9a876307d5111972f7e9f1ad87b076Kenny Root throw new RuntimeException(e); 1029059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 1030059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 1031059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom 1032059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom /** 1033059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom * Create a client key store that only contains self-signed certificates but no private keys 1034059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom */ 10351b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom public static KeyStore createClient(KeyStore caKeyStore) { 1036101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson KeyStore clientKeyStore = createKeyStore(); 1037101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson copySelfSignedCertificates(clientKeyStore, caKeyStore); 1038101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson return clientKeyStore; 1039059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 1040059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom 1041059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom /** 1042101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * Copy self-signed certificates from one key store to another. 1043a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom * Returns true if successful, false if no match found. 1044059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom */ 10451b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom public static boolean copySelfSignedCertificates(KeyStore dst, KeyStore src) { 10461b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom try { 10471b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom boolean copied = false; 10481b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom for (String alias : Collections.list(src.aliases())) { 10491b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (!src.isCertificateEntry(alias)) { 10501b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom continue; 10511b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 10521b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom X509Certificate cert = (X509Certificate)src.getCertificate(alias); 10531b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom if (!cert.getSubjectDN().equals(cert.getIssuerDN())) { 10541b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom continue; 10551b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } 10561b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom dst.setCertificateEntry(alias, cert); 10571b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom copied = true; 1058059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 10591b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom return copied; 10601b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom } catch (Exception e) { 10611b3c5388d0fffde4392007eb1b0be011a5dfae82Brian Carlstrom throw new RuntimeException(e); 1062a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } 1063a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } 1064a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom 1065a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom /** 1066101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson * Copy named certificates from one key store to another. 1067a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom * Returns true if successful, false if no match found. 1068a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom */ 1069a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom public static boolean copyCertificate(Principal subject, KeyStore dst, KeyStore src) 1070a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom throws Exception { 10713258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom for (String alias : Collections.list(src.aliases())) { 1072a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom if (!src.isCertificateEntry(alias)) { 1073a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom continue; 1074a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } 1075a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom X509Certificate cert = (X509Certificate)src.getCertificate(alias); 1076a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom if (!cert.getSubjectDN().equals(subject)) { 1077a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom continue; 1078a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom } 1079a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom dst.setCertificateEntry(alias, cert); 1080a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom return true; 1081059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 1082a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom return false; 1083059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 1084059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom 1085059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom /** 1086059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom * Dump a key store for debugging. 1087059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom */ 10880da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer public void dump(String context) throws KeyStoreException, NoSuchAlgorithmException { 10890da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer dump(context, keyStore, keyPassword); 10900da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer } 10910da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer 10920da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer /** 10930da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer * Dump a key store for debugging. 10940da1515c5fe4e97fc2d4d24a41ebd4c078fec4dbChris Palmer */ 1095101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson public static void dump(String context, KeyStore keyStore, char[] keyPassword) 1096101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson throws KeyStoreException, NoSuchAlgorithmException { 1097101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson PrintStream out = System.out; 1098101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("context=" + context); 1099101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("\tkeyStore=" + keyStore); 1100101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("\tkeyStore.type=" + keyStore.getType()); 1101101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("\tkeyStore.provider=" + keyStore.getProvider()); 1102101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("\tkeyPassword=" 1103101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson + ((keyPassword == null) ? null : new String(keyPassword))); 1104101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("\tsize=" + keyStore.size()); 11053258b52429c7768ea91bda93c5a15257cdd390e5Brian Carlstrom for (String alias : Collections.list(keyStore.aliases())) { 1106101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("alias=" + alias); 1107101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("\tcreationDate=" + keyStore.getCreationDate(alias)); 1108101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson if (keyStore.isCertificateEntry(alias)) { 1109101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("\tcertificate:"); 1110101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("=========================================="); 1111101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println(keyStore.getCertificate(alias)); 1112101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("=========================================="); 1113101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson continue; 1114101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 1115101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson if (keyStore.isKeyEntry(alias)) { 1116101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("\tkey:"); 1117101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("=========================================="); 1118101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson String key; 1119101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson try { 1120101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson key = ("Key retrieved using password\n" 1121101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson + keyStore.getKey(alias, keyPassword)); 1122101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } catch (UnrecoverableKeyException e1) { 1123e3a187163504f00c98bd75cbd8bcbdde123ae2cdBrian Carlstrom try { 1124101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson key = ("Key retrieved without password\n" 1125101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson + keyStore.getKey(alias, null)); 1126101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } catch (UnrecoverableKeyException e2) { 1127101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson key = "Key could not be retrieved"; 1128e3a187163504f00c98bd75cbd8bcbdde123ae2cdBrian Carlstrom } 1129101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } 1130101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println(key); 1131101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("=========================================="); 1132101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson Certificate[] chain = keyStore.getCertificateChain(alias); 1133101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson if (chain == null) { 1134101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("No certificate chain associated with key"); 1135059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom out.println("=========================================="); 1136101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson } else { 1137101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson for (int i = 0; i < chain.length; i++) { 1138101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("Certificate chain element #" + i); 1139101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println(chain[i]); 11408a720cceee7ce319d647738dfeda3f302879f370Brian Carlstrom out.println("=========================================="); 11418a720cceee7ce319d647738dfeda3f302879f370Brian Carlstrom } 1142059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 1143101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson continue; 1144059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 1145101547d4a82ba21031dc7cb62018720dbd493758Jesse Wilson out.println("\tunknown entry type"); 1146059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 1147059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 1148059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom 1149059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom public static void assertChainLength(Object[] chain) { 1150059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom /* 1151059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom * Note chain is Object[] to support both 1152059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom * java.security.cert.X509Certificate and 1153059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom * javax.security.cert.X509Certificate 1154059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom */ 1155059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom assertEquals(3, chain.length); 1156059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom } 1157204cab3c22b4d75c866c95e2d2eec42e14cbd924Brian Carlstrom} 1158