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