1/*
2 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24//
25// SunJSSE does not support dynamic system properties, no way to re-use
26// system properties in samevm/agentvm mode.
27//
28
29/*
30 * @test
31 * @bug 6822460
32 * @summary support self-issued certificate
33 * @run main/othervm SelfIssuedCert PKIX
34 * @run main/othervm SelfIssuedCert SunX509
35 * @author Xuelei Fan
36 */
37
38import java.net.*;
39import java.util.*;
40import java.io.*;
41import javax.net.ssl.*;
42import java.security.Security;
43import java.security.KeyStore;
44import java.security.KeyFactory;
45import java.security.cert.Certificate;
46import java.security.cert.CertificateFactory;
47import java.security.spec.*;
48import java.security.interfaces.*;
49import java.math.BigInteger;
50
51import java.util.Base64;
52
53public class SelfIssuedCert {
54
55    /*
56     * =============================================================
57     * Set the various variables needed for the tests, then
58     * specify what tests to run on each side.
59     */
60
61    /*
62     * Should we run the client or server in a separate thread?
63     * Both sides can throw exceptions, but do you have a preference
64     * as to which side should be the main thread.
65     */
66    static boolean separateServerThread = true;
67
68    /*
69     * Where do we find the keystores?
70     */
71    // Certificate information:
72    // Issuer: C=US, O=Example, CN=localhost
73    // Validity
74    //     Not Before: May 25 00:35:58 2009 GMT
75    //     Not After : May  5 00:35:58 2030 GMT
76    // Subject: C=US, O=Example, CN=localhost
77    // X509v3 Subject Key Identifier:
78    //     56:AB:FE:15:4C:9C:4A:70:90:DC:0B:9B:EB:BE:DC:03:CC:7F:CE:CF
79    // X509v3 Authority Key Identifier:
80    //     keyid:56:AB:FE:15:4C:9C:4A:70:90:DC:0B:9B:EB:BE:DC:03:CC:7F:CE:CF
81    //     DirName:/C=US/O=Example/CN=localhost
82    //     serial:00
83    static String trusedCertStr =
84        "-----BEGIN CERTIFICATE-----\n" +
85        "MIICejCCAeOgAwIBAgIBADANBgkqhkiG9w0BAQQFADAzMQswCQYDVQQGEwJVUzEQ\n" +
86        "MA4GA1UEChMHRXhhbXBsZTESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTA5MDUyNTAw\n" +
87        "MDQ0M1oXDTMwMDUwNTAwMDQ0M1owMzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4\n" +
88        "YW1wbGUxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" +
89        "gYkCgYEA0Wvh3FHYGQ3vvw59yTjUxT6QuY0fzwCGQTM9evXr/V9+pjWmaTkNDW+7\n" +
90        "S/LErlWz64gOWTgcMZN162sVgx4ct/q27brY+SlUO5eSud1fSac6SfefhOPBa965\n" +
91        "Xc4mnpDt5sgQPMDCuFK7Le6A+/S9J42BO2WYmNcmvcwWWrv+ehcCAwEAAaOBnTCB\n" +
92        "mjAdBgNVHQ4EFgQUq3q5fYEibdvLpab+JY4pmifj2vYwWwYDVR0jBFQwUoAUq3q5\n" +
93        "fYEibdvLpab+JY4pmifj2vahN6Q1MDMxCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdF\n" +
94        "eGFtcGxlMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAwDwYDVR0TAQH/BAUwAwEB/zAL\n" +
95        "BgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEEBQADgYEAHL8BSwtX6s8WPPG2FbQBX+K8\n" +
96        "GquAyQNtgfJNm60B4i+fVBkJiQJtLmE0emvHx/3sIaHmB0Gd0HKnk/cIQXY304vr\n" +
97        "QpqwudKcIZuzmj+pa7807joV+WzRDVIlt4HpYg7tiUvEoyw+X8jwY2lgiGR7mWu6\n" +
98        "jQU8PN/06+qgtvSGFpo=\n" +
99        "-----END CERTIFICATE-----";
100
101    // Certificate information:
102    // Issuer: C=US, O=Example, CN=localhost
103    // Validity
104    //     Not Before: May 25 00:35:58 2009 GMT
105    //     Not After : May  5 00:35:58 2030 GMT
106    // Subject: C=US, O=Example, CN=localhost
107    // X509v3 Subject Key Identifier:
108    //     0D:30:76:22:D6:9D:75:EF:FD:83:50:31:18:08:83:CD:01:4E:6A:C4
109    // X509v3 Authority Key Identifier:
110    //     keyid:56:AB:FE:15:4C:9C:4A:70:90:DC:0B:9B:EB:BE:DC:03:CC:7F:CE:CF
111    //     DirName:/C=US/O=Example/CN=localhost
112    //     serial:00
113    static String targetCertStr =
114        "-----BEGIN CERTIFICATE-----\n" +
115        "MIICaTCCAdKgAwIBAgIBAjANBgkqhkiG9w0BAQQFADAzMQswCQYDVQQGEwJVUzEQ\n" +
116        "MA4GA1UEChMHRXhhbXBsZTESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTA5MDUyNTAw\n" +
117        "MDQ0M1oXDTI5MDIwOTAwMDQ0M1owMzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4\n" +
118        "YW1wbGUxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" +
119        "gYkCgYEAzmPahrH9LTQv3HEWsua+hIpzyU1ACooSd5BtDjc7XnVzSdGW8QD9R8EA\n" +
120        "xko7TvfJo6IH6wwgHBspySwsl+6xvHhbwQjgtWlT71ksrUbqcUzmvSvcycQYA8RC\n" +
121        "yk9HK5pEJQgSxldpR3Kmy0V6CHC4dCm15trnJYWisTuezY3fjXECAwEAAaOBjDCB\n" +
122        "iTAdBgNVHQ4EFgQUQkiWFRkjKsfwFo7UMQfGEzNNW60wWwYDVR0jBFQwUoAUq3q5\n" +
123        "fYEibdvLpab+JY4pmifj2vahN6Q1MDMxCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdF\n" +
124        "eGFtcGxlMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAwCwYDVR0PBAQDAgPoMA0GCSqG\n" +
125        "SIb3DQEBBAUAA4GBAIMz7c1R+6KEO7FmH4rnv9XE62xkg03ff0vKXLZMjjs0CX2z\n" +
126        "ybRttuTFafHA6/JS+Wz0G83FCRVeiw2WPU6BweMwwejzzIrQ/K6mbp6w6sRFcbNa\n" +
127        "eLBtzkjEtI/htOSSq3/0mbKmWn5uVJckO4QiB8kUR4F7ngM9l1uuI46ZfUsk\n" +
128        "-----END CERTIFICATE-----";
129
130    // Private key in the format of PKCS#8
131    static String targetPrivateKey =
132        "MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAM5j2oax/S00L9xx\n" +
133        "FrLmvoSKc8lNQAqKEneQbQ43O151c0nRlvEA/UfBAMZKO073yaOiB+sMIBwbKcks\n" +
134        "LJfusbx4W8EI4LVpU+9ZLK1G6nFM5r0r3MnEGAPEQspPRyuaRCUIEsZXaUdypstF\n" +
135        "eghwuHQpteba5yWForE7ns2N341xAgMBAAECgYEAgZ8k98OBhopoJMLBxso0jXmH\n" +
136        "Dr59oiDlSEJku7DkkIajSZFggyxj5lTI78BfT1FASozQ/EY5RG2q6LXdq+41oU/U\n" +
137        "JVEQWhdIE1mQDwE0vgaYdjzMaVIsC3cZYOCOmCYvNxCiTt7e/z8yBMmAE5udqJMB\n" +
138        "pim4WXDfpy0ssK81oCECQQDwMC4xu+kn0yD/Qyi9Zn26gIRDv4bjzDQoJfSvMhrY\n" +
139        "a4duxLzh9u4gCDd0+wHxpPQvNxGCk0c1JUxBJ2rb4G3HAkEA2/oVRV6+xiRXUnoo\n" +
140        "bdPEO27zEJmdpE42yU/JLIy6DPu2IUhEqY45fU2ZERmwMdhpiK/vsf/CZKJ2j/ZU\n" +
141        "PdMLBwJBAJIYTFDWAqjFpCGAASzLRZiGiW0H941h7Suqgp159ZhEN5mps1Yis47q\n" +
142        "UIkoEHOiKSD69vychsiNykcrKbVaWosCQQC1UrYX4Vo1r5z/EkyjAwzcxL68rzM/\n" +
143        "TW1hkU/NVg7CRvXBB3X5oY+H1t/WNauD2tRa5FMbESwmkbhTQIP+FikfAkEA4goD\n" +
144        "HCxUn0Z1OQq9QL6y1Yoof6sHxicUwABosuCLJnDJmA5vhpemvdXQTzFII8g1hyQf\n" +
145        "z1yyDoxhddcleKlJvQ==";
146
147    static char passphrase[] = "passphrase".toCharArray();
148
149    /*
150     * Is the server ready to serve?
151     */
152    volatile static boolean serverReady = false;
153
154    /*
155     * Turn on SSL debugging?
156     */
157    static boolean debug = false;
158
159    /*
160     * Define the server side of the test.
161     *
162     * If the server prematurely exits, serverReady will be set to true
163     * to avoid infinite hangs.
164     */
165    void doServerSide() throws Exception {
166        SSLContext context = getSSLContext(null, targetCertStr,
167                                            targetPrivateKey);
168        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
169
170        SSLServerSocket sslServerSocket =
171            (SSLServerSocket)sslssf.createServerSocket(serverPort);
172        serverPort = sslServerSocket.getLocalPort();
173
174        /*
175         * Signal Client, we're ready for his connect.
176         */
177        serverReady = true;
178
179        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
180        sslSocket.setNeedClientAuth(false);
181
182        InputStream sslIS = sslSocket.getInputStream();
183        OutputStream sslOS = sslSocket.getOutputStream();
184
185        sslIS.read();
186        sslOS.write(85);
187        sslOS.flush();
188
189        sslSocket.close();
190
191    }
192
193    /*
194     * Define the client side of the test.
195     *
196     * If the server prematurely exits, serverReady will be set to true
197     * to avoid infinite hangs.
198     */
199    void doClientSide() throws Exception {
200        /*
201         * Wait for server to get started.
202         */
203        while (!serverReady) {
204            Thread.sleep(50);
205        }
206
207        SSLContext context = getSSLContext(trusedCertStr, null, null);
208        SSLSocketFactory sslsf = context.getSocketFactory();
209
210        SSLSocket sslSocket =
211            (SSLSocket)sslsf.createSocket("localhost", serverPort);
212
213        InputStream sslIS = sslSocket.getInputStream();
214        OutputStream sslOS = sslSocket.getOutputStream();
215
216        sslOS.write(280);
217        sslOS.flush();
218        sslIS.read();
219
220        sslSocket.close();
221    }
222
223    // get the ssl context
224    private static SSLContext getSSLContext(String trusedCertStr,
225            String keyCertStr, String keySpecStr) throws Exception {
226
227        // generate certificate from cert string
228        CertificateFactory cf = CertificateFactory.getInstance("X.509");
229
230        // create a key store
231        KeyStore ks = KeyStore.getInstance("JKS");
232        ks.load(null, null);
233
234        // import the trused cert
235        Certificate trusedCert = null;
236        ByteArrayInputStream is = null;
237        if (trusedCertStr != null) {
238            is = new ByteArrayInputStream(trusedCertStr.getBytes());
239            trusedCert = cf.generateCertificate(is);
240            is.close();
241
242            ks.setCertificateEntry("RSA Export Signer", trusedCert);
243        }
244
245        if (keyCertStr != null) {
246            // generate the private key.
247            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
248                                Base64.getMimeDecoder().decode(keySpecStr));
249            KeyFactory kf = KeyFactory.getInstance("RSA");
250            RSAPrivateKey priKey =
251                    (RSAPrivateKey)kf.generatePrivate(priKeySpec);
252
253            // generate certificate chain
254            is = new ByteArrayInputStream(keyCertStr.getBytes());
255            Certificate keyCert = cf.generateCertificate(is);
256            is.close();
257
258            Certificate[] chain = null;
259            if (trusedCert != null) {
260                chain = new Certificate[2];
261                chain[0] = keyCert;
262                chain[1] = trusedCert;
263            } else {
264                chain = new Certificate[1];
265                chain[0] = keyCert;
266            }
267
268            // import the key entry.
269            ks.setKeyEntry("Whatever", priKey, passphrase, chain);
270        }
271
272        // create SSL context
273        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
274        tmf.init(ks);
275
276        SSLContext ctx = SSLContext.getInstance("TLS");
277        if (keyCertStr != null && !keyCertStr.isEmpty()) {
278            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
279            kmf.init(ks, passphrase);
280
281            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
282            ks = null;
283        } else {
284            ctx.init(null, tmf.getTrustManagers(), null);
285        }
286
287        return ctx;
288    }
289
290    private static String tmAlgorithm;        // trust manager
291
292    private static void parseArguments(String[] args) {
293        tmAlgorithm = args[0];
294    }
295
296    /*
297     * =============================================================
298     * The remainder is just support stuff
299     */
300
301    // use any free port by default
302    volatile int serverPort = 0;
303
304    volatile Exception serverException = null;
305    volatile Exception clientException = null;
306
307    public static void main(String args[]) throws Exception {
308        // MD5 is used in this test case, don't disable MD5 algorithm.
309        Security.setProperty("jdk.certpath.disabledAlgorithms",
310                "MD2, RSA keySize < 1024");
311        Security.setProperty("jdk.tls.disabledAlgorithms",
312                "SSLv3, RC4, DH keySize < 768");
313
314        if (debug)
315            System.setProperty("javax.net.debug", "all");
316
317
318        /*
319         * Get the customized arguments.
320         */
321        parseArguments(args);
322
323        /*
324         * Start the tests.
325         */
326        new SelfIssuedCert();
327    }
328
329    Thread clientThread = null;
330    Thread serverThread = null;
331    /*
332     * Primary constructor, used to drive remainder of the test.
333     *
334     * Fork off the other side, then do your work.
335     */
336    SelfIssuedCert() throws Exception {
337        if (separateServerThread) {
338            startServer(true);
339            startClient(false);
340        } else {
341            startClient(true);
342            startServer(false);
343        }
344
345        /*
346         * Wait for other side to close down.
347         */
348        if (separateServerThread) {
349            serverThread.join();
350        } else {
351            clientThread.join();
352        }
353
354        /*
355         * When we get here, the test is pretty much over.
356         *
357         * If the main thread excepted, that propagates back
358         * immediately.  If the other thread threw an exception, we
359         * should report back.
360         */
361        if (serverException != null)
362            throw serverException;
363        if (clientException != null)
364            throw clientException;
365    }
366
367    void startServer(boolean newThread) throws Exception {
368        if (newThread) {
369            serverThread = new Thread() {
370                public void run() {
371                    try {
372                        doServerSide();
373                    } catch (Exception e) {
374                        /*
375                         * Our server thread just died.
376                         *
377                         * Release the client, if not active already...
378                         */
379                        System.err.println("Server died...");
380                        serverReady = true;
381                        serverException = e;
382                    }
383                }
384            };
385            serverThread.start();
386        } else {
387            doServerSide();
388        }
389    }
390
391    void startClient(boolean newThread) throws Exception {
392        if (newThread) {
393            clientThread = new Thread() {
394                public void run() {
395                    try {
396                        doClientSide();
397                    } catch (Exception e) {
398                        /*
399                         * Our client thread just died.
400                         */
401                        System.err.println("Client died...");
402                        clientException = e;
403                    }
404                }
405            };
406            clientThread.start();
407        } else {
408            doClientSide();
409        }
410    }
411
412}
413