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