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