TestSSLContext.java revision f33eae7e84eb6d3b0f4e86b59605bb3de73009f3
1bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom/*
2bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom * Copyright (C) 2010 The Android Open Source Project
3bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom *
4bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License");
5bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom * you may not use this file except in compliance with the License.
6bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom * You may obtain a copy of the License at
7bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom *
8bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom *      http://www.apache.org/licenses/LICENSE-2.0
9bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom *
10bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom * Unless required by applicable law or agreed to in writing, software
11bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS,
12bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom * See the License for the specific language governing permissions and
14bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom * limitations under the License.
15bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom */
16bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
17bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrompackage javax.net.ssl;
18bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
19bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.math.BigInteger;
20bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.net.InetAddress;
21bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.net.InetSocketAddress;
22bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.security.KeyPair;
23bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.security.KeyPairGenerator;
24bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.security.KeyStore;
25bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.security.SecureRandom;
26bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.security.Security;
27e688a4123f165ed2905878e312b074b8c825d119Brian Carlstromimport java.security.cert.Certificate;
28bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.security.cert.X509Certificate;
29bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.security.interfaces.RSAPrivateKey;
30bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.security.interfaces.RSAPublicKey;
31bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.util.Date;
32bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport java.util.Hashtable;
33bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport org.bouncycastle.jce.X509Principal;
34bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport org.bouncycastle.jce.provider.BouncyCastleProvider;
35bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstromimport org.bouncycastle.x509.X509V3CertificateGenerator;
36bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
37bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom/**
38bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom * TestSSLContext is a convenience class for other tests that
39bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom * want a canned SSLContext and related state for testing so they
40bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom * don't have to duplicate the logic.
41bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom */
42bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrompublic final class TestSSLContext {
43bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
44bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public static final boolean IS_RI = !"Dalvik Core Library".equals(System.getProperty("java.specification.name"));
45bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public static final String PROVIDER_NAME = (IS_RI) ? "SunJSSE" : "HarmonyJSSE";
46bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
47f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    /*
480af0a7959d838c48e6b4e8dc9ac188ff6bbb6a87Brian Carlstrom     * The RI and Android have very different default SSLSession cache behaviors.
490af0a7959d838c48e6b4e8dc9ac188ff6bbb6a87Brian Carlstrom     * The RI keeps an unlimited number of SSLSesions around for 1 day.
50f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * Android keeps 10 SSLSessions forever.
510af0a7959d838c48e6b4e8dc9ac188ff6bbb6a87Brian Carlstrom     */
520af0a7959d838c48e6b4e8dc9ac188ff6bbb6a87Brian Carlstrom    public static final int EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE = (IS_RI) ? 0 : 10;
530af0a7959d838c48e6b4e8dc9ac188ff6bbb6a87Brian Carlstrom    public static final int EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE = (IS_RI) ? 0 : 100;
540af0a7959d838c48e6b4e8dc9ac188ff6bbb6a87Brian Carlstrom    public static final int EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT = (IS_RI) ? 86400 : 0;
55bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    static {
56bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        if (IS_RI) {
57bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            Security.addProvider(new BouncyCastleProvider());
58bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        }
59bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
60bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
61bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    /**
62bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * The Android SSLSocket and SSLServerSocket implementations are
63bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * based on a version of OpenSSL which includes support for RFC
64bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * 4507 session tickets. When using session tickets, the server
65bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * does not need to keep a cache mapping session IDs to SSL
66bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * sessions for reuse. Instead, the client presents the server
67bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * with a session ticket it received from the server earlier,
68bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * which is an SSL session encrypted by the server's secret
69bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * key. Since in this case the server does not need to keep a
70bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * cache, some tests may find different results depending on
71bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * whether or not the session tickets are in use. These tests can
72bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * use this function to determine if loopback SSL connections are
73bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * expected to use session tickets and conditionalize their
74bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * results appropriately.
75bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     */
76bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public static boolean sslServerSocketSupportsSessionTickets () {
77bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        return !IS_RI;
78bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
79bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
80bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public final KeyStore keyStore;
81bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public final char[] keyStorePassword;
82bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public final String publicAlias;
83bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public final String privateAlias;
84bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public final SSLContext sslContext;
85bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public final SSLServerSocket serverSocket;
86bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public final InetAddress host;
87bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public final int port;
88bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
89bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private TestSSLContext(KeyStore keyStore,
90bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                           char[] keyStorePassword,
91bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                           String publicAlias,
92bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                           String privateAlias,
93bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                           SSLContext sslContext,
94bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                           SSLServerSocket serverSocket,
95bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                           InetAddress host,
96bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                           int port) {
97bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.keyStore = keyStore;
98bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.keyStorePassword = keyStorePassword;
99bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.publicAlias = publicAlias;
100bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.privateAlias = privateAlias;
101bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.sslContext = sslContext;
102bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.serverSocket = serverSocket;
103bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.host = host;
104bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.port = port;
105bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
106bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
107e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom    /**
108e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom     * Usual TestSSLContext creation method, creates underlying
109e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom     * SSLContext with certificate and key as well as SSLServerSocket
110e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom     * listening provided host and port.
111e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom     */
112bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public static TestSSLContext create() {
113bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        try {
114bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            char[] keyStorePassword = null;
115bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            String publicAlias = "public";
116bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            String privateAlias = "private";
117bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            return create(createKeyStore(keyStorePassword, publicAlias, privateAlias),
118e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                          keyStorePassword,
119bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                          publicAlias,
120bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                          privateAlias);
121bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        } catch (RuntimeException e) {
122bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            throw e;
123bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        } catch (Exception e) {
124bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            throw new RuntimeException(e);
125bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        }
126bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
127bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
128e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom    /**
129e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom     * TestSSLContext creation method that allows separate creation of key store
130e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom     */
131bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public static TestSSLContext create(KeyStore keyStore,
132bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                                        char[] keyStorePassword,
133bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                                        String publicAlias,
134bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                                        String privateAlias) {
135bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        try {
136bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            SSLContext sslContext = createSSLContext(keyStore, keyStorePassword);
137bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
138bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            SSLServerSocket serverSocket = (SSLServerSocket)
139bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                sslContext.getServerSocketFactory().createServerSocket(0);
140bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            InetSocketAddress sa = (InetSocketAddress) serverSocket.getLocalSocketAddress();
141bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            InetAddress host = sa.getAddress();
142bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            int port = sa.getPort();
143bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
144bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            return new TestSSLContext(keyStore, keyStorePassword, publicAlias, privateAlias,
145bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                                      sslContext, serverSocket, host, port);
146bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        } catch (RuntimeException e) {
147bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            throw e;
148bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        } catch (Exception e) {
149bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            throw new RuntimeException(e);
150bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        }
151bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
152bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
153bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    /**
154e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom     * Create a client version of the server TestSSLContext. The
155e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom     * client will trust the server's certificate, but not contain any
156e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom     * keys of its own.
157e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom     */
158e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom    public static TestSSLContext createClient(TestSSLContext server) {
159e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        try {
160e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            String publicAlias = server.publicAlias;
161e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            Certificate cert = server.keyStore.getCertificate(publicAlias);
162e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom
163e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            KeyStore keyStore = KeyStore.getInstance("BKS");
164e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            keyStore.load(null, null);
165e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            keyStore.setCertificateEntry(publicAlias, cert);
166e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom
167e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            char[] keyStorePassword = server.keyStorePassword;
168e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            String privateAlias = null;
169e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom
170e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            String tmfa = TrustManagerFactory.getDefaultAlgorithm();
171e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfa);
172e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            tmf.init(keyStore);
173e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom
174e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            SSLContext sslContext = SSLContext.getInstance("TLS");
175e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
176e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom
177e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            return new TestSSLContext(keyStore, keyStorePassword, publicAlias, publicAlias,
178e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                                      sslContext, null, null, -1);
179e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        } catch (RuntimeException e) {
180e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            throw e;
181e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        } catch (Exception e) {
182e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            throw new RuntimeException(e);
183e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        }
184e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom    }
185e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom
186e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom    /**
187bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * Create a BKS KeyStore containing an RSAPrivateKey with alias
188bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * "private" and a X509Certificate based on the matching
189bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * RSAPublicKey stored under the alias name publicAlias.
190bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     *
191bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * The private key will have a certificate chain including the
192bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * certificate stored under the alias name privateAlias. The
193bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * certificate will be signed by the private key. The certificate
194bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * Subject and Issuer Common-Name will be the local host's
195bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * canonical hostname. The certificate will be valid for one day
196bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * before and one day after the time of creation.
197bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     *
198bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * The KeyStore is optionally password protected by the
199bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * keyStorePassword argument, which can be null if a password is
200bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * not desired.
201bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     *
202bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * Based on:
203bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * org.bouncycastle.jce.provider.test.SigTest
204bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * org.bouncycastle.jce.provider.test.CertTest
205bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     */
206bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public static KeyStore createKeyStore(char[] keyStorePassword,
207bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                                          String publicAlias,
208bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                                          String privateAlias)
209bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        throws Exception {
210bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
211e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        RSAPrivateKey privateKey;
212e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        X509Certificate x509c;
213e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        if (publicAlias == null && privateAlias == null) {
214e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            // don't want anything apparently
215e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            privateKey = null;
216e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            x509c = null;
217e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        } else {
218e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            // 1.) we make the keys
219e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            int keysize = 1024;
220e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
221e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            kpg.initialize(keysize, new SecureRandom());
222e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            KeyPair kp = kpg.generateKeyPair();
223e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            privateKey = (RSAPrivateKey)kp.getPrivate();
224e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            RSAPublicKey publicKey  = (RSAPublicKey)kp.getPublic();
225e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom
226e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            // 2.) use keys to make certficate
227e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom
228e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            // note that there doesn't seem to be a standard way to make a
229e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            // certificate using java.* or javax.*. The CertificateFactory
230e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            // interface assumes you want to read in a stream of bytes a
231e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            // factory specific format. So here we use Bouncy Castle's
232e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            // X509V3CertificateGenerator and related classes.
233bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
234e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            Hashtable attributes = new Hashtable();
235e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            attributes.put(X509Principal.CN, InetAddress.getLocalHost().getCanonicalHostName());
236e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            X509Principal dn = new X509Principal(attributes);
237e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom
238e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            long millisPerDay = 24 * 60 * 60 * 1000;
239e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            long now = System.currentTimeMillis();
240e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            Date start = new Date(now - millisPerDay);
241e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            Date end = new Date(now + millisPerDay);
242e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            BigInteger serial = BigInteger.valueOf(1);
243e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom
244e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            X509V3CertificateGenerator x509cg = new X509V3CertificateGenerator();
245e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            x509cg.setSubjectDN(dn);
246e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            x509cg.setIssuerDN(dn);
247e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            x509cg.setNotBefore(start);
248e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            x509cg.setNotAfter(end);
249e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            x509cg.setPublicKey(publicKey);
250e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            x509cg.setSignatureAlgorithm("sha1WithRSAEncryption");
251e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            x509cg.setSerialNumber(serial);
252e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            x509c = x509cg.generateX509Certificate(privateKey);
253e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        }
254e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom
255e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        X509Certificate[] x509cc;
256e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        if (privateAlias == null) {
257e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            // don't need certificate chain
258e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            x509cc = null;
259e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        } else {
260e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            x509cc = new X509Certificate[] { x509c };
261e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        }
262bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
263bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // 3.) put certificate and private key to make a key store
264bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        KeyStore ks = KeyStore.getInstance("BKS");
265bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        ks.load(null, null);
266e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        if (privateAlias != null) {
267e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            ks.setKeyEntry(privateAlias, privateKey, keyStorePassword, x509cc);
268e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        }
269e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        if (publicAlias != null) {
270e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            ks.setCertificateEntry(publicAlias, x509c);
271e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom        }
272bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        return ks;
273bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
274bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
275bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    /**
276bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * Create a SSLContext with a KeyManager using the private key and
277bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * certificate chain from the given KeyStore and a TrustManager
278bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * using the certificates authorities from the same KeyStore.
279bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     */
280bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public static final SSLContext createSSLContext(final KeyStore keyStore, final char[] keyStorePassword)
281bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        throws Exception {
282bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        String kmfa = KeyManagerFactory.getDefaultAlgorithm();
283bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfa);
284bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        kmf.init(keyStore, keyStorePassword);
285bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
286bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        String tmfa = TrustManagerFactory.getDefaultAlgorithm();
287bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfa);
288bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        tmf.init(keyStore);
289bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
290bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        SSLContext context = SSLContext.getInstance("TLS");
291bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
292bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        return context;
293bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
294bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom}
295