MD2InTrustAnchor.java revision 9372:171791e63397
1/*
2 * Copyright (c) 2011, 2014, 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26//
27// SunJSSE does not support dynamic system properties, no way to re-use
28// system properties in samevm/agentvm mode.
29//
30
31/*
32 * @test
33 * @bug 7113275
34 * @summary compatibility issue with MD2 trust anchor and old X509TrustManager
35 * @run main/othervm MD2InTrustAnchor PKIX TLSv1.1
36 * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.1
37 * @run main/othervm MD2InTrustAnchor PKIX TLSv1.2
38 * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.2
39 */
40
41import java.net.*;
42import java.util.*;
43import java.io.*;
44import javax.net.ssl.*;
45import java.security.Security;
46import java.security.KeyStore;
47import java.security.KeyFactory;
48import java.security.cert.Certificate;
49import java.security.cert.CertificateFactory;
50import java.security.spec.*;
51import java.security.interfaces.*;
52import java.util.Base64;
53
54public class MD2InTrustAnchor {
55
56    /*
57     * =============================================================
58     * Set the various variables needed for the tests, then
59     * specify what tests to run on each side.
60     */
61
62    /*
63     * Should we run the client or server in a separate thread?
64     * Both sides can throw exceptions, but do you have a preference
65     * as to which side should be the main thread.
66     */
67    static boolean separateServerThread = false;
68
69    /*
70     * Certificates and key used in the test.
71     */
72
73    // It's a trust anchor signed with MD2 hash function.
74    static String trustedCertStr =
75        "-----BEGIN CERTIFICATE-----\n" +
76        "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" +
77        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
78        "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
79        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
80        "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" +
81        "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" +
82        "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" +
83        "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" +
84        "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" +
85        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
86        "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" +
87        "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" +
88        "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" +
89        "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" +
90        "-----END CERTIFICATE-----";
91
92    // The certificate issued by above trust anchor, signed with MD5
93    static String targetCertStr =
94        "-----BEGIN CERTIFICATE-----\n" +
95        "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
96        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
97        "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" +
98        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" +
99        "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" +
100        "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" +
101        "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" +
102        "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" +
103        "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" +
104        "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" +
105        "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" +
106        "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" +
107        "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" +
108        "yvudOlX4BkVR0l1K\n" +
109        "-----END CERTIFICATE-----";
110
111    // Private key in the format of PKCS#8.
112    static String targetPrivateKey =
113        "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4\n" +
114        "F5NVEtFXCbEFcVLRjMp3AL3jLswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa\n" +
115        "9+uHt0Z9Wmh4wjHAZhX5Tm5xp4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPM\n" +
116        "KBpyzK6rusorkwpWywTyvH1s016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+K\n" +
117        "SH9tFt+WQbiojjz9ac49trkvUfu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck\n" +
118        "5mOIYV4uZK8jfNMSQ8v0tFEeIPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+H\n" +
119        "aY3d76hR5qly+Ys+Ww0CQQDjeOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ\n" +
120        "6t0v/xryVIdvOYcRBvKnqEogOH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7e\n" +
121        "z3TDpU9w1B0JXklcV5HddYsRqp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3M\n" +
122        "L11xwwJBAKsZ+Hur3x0tUY29No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDEl\n" +
123        "hIM6Rqv12kwCMuQE9i7vo1o3WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXse\n" +
124        "kdXAA4d2d5zGI7q/aGD9SYU6phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRT\n" +
125        "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" +
126        "njWHoKY3axDQ8OU=\n";
127
128
129    static char passphrase[] = "passphrase".toCharArray();
130
131    /*
132     * Is the server ready to serve?
133     */
134    volatile static boolean serverReady = false;
135
136    /*
137     * Turn on SSL debugging?
138     */
139    static boolean debug = false;
140
141    /*
142     * Define the server side of the test.
143     *
144     * If the server prematurely exits, serverReady will be set to true
145     * to avoid infinite hangs.
146     */
147    void doServerSide() throws Exception {
148        SSLContext context = generateSSLContext(trustedCertStr, targetCertStr,
149                                            targetPrivateKey);
150        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
151        SSLServerSocket sslServerSocket =
152            (SSLServerSocket)sslssf.createServerSocket(serverPort);
153        sslServerSocket.setNeedClientAuth(true);
154        serverPort = sslServerSocket.getLocalPort();
155
156        /*
157         * Signal Client, we're ready for his connect.
158         */
159        serverReady = true;
160
161        SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
162        InputStream sslIS = sslSocket.getInputStream();
163        OutputStream sslOS = sslSocket.getOutputStream();
164
165        sslIS.read();
166        sslOS.write('A');
167        sslOS.flush();
168
169        sslSocket.close();
170    }
171
172    /*
173     * Define the client side of the test.
174     *
175     * If the server prematurely exits, serverReady will be set to true
176     * to avoid infinite hangs.
177     */
178    void doClientSide() throws Exception {
179
180        /*
181         * Wait for server to get started.
182         */
183        while (!serverReady) {
184            Thread.sleep(50);
185        }
186
187        SSLContext context = generateSSLContext(trustedCertStr, targetCertStr,
188                                            targetPrivateKey);
189        SSLSocketFactory sslsf = context.getSocketFactory();
190
191        SSLSocket sslSocket =
192            (SSLSocket)sslsf.createSocket("localhost", serverPort);
193
194        // enable the specified TLS protocol
195        sslSocket.setEnabledProtocols(new String[] {tlsProtocol});
196
197        InputStream sslIS = sslSocket.getInputStream();
198        OutputStream sslOS = sslSocket.getOutputStream();
199
200        sslOS.write('B');
201        sslOS.flush();
202        sslIS.read();
203
204        sslSocket.close();
205    }
206
207    /*
208     * =============================================================
209     * The remainder is just support stuff
210     */
211    private static String tmAlgorithm;        // trust manager
212    private static String tlsProtocol;        // trust manager
213
214    private static void parseArguments(String[] args) {
215        tmAlgorithm = args[0];
216        tlsProtocol = args[1];
217    }
218
219    private static SSLContext generateSSLContext(String trustedCertStr,
220            String keyCertStr, String keySpecStr) throws Exception {
221
222        // generate certificate from cert string
223        CertificateFactory cf = CertificateFactory.getInstance("X.509");
224
225        // create a key store
226        KeyStore ks = KeyStore.getInstance("JKS");
227        ks.load(null, null);
228
229        // import the trused cert
230        Certificate trusedCert = null;
231        ByteArrayInputStream is = null;
232        if (trustedCertStr != null) {
233            is = new ByteArrayInputStream(trustedCertStr.getBytes());
234            trusedCert = cf.generateCertificate(is);
235            is.close();
236
237            ks.setCertificateEntry("RSA Export Signer", trusedCert);
238        }
239
240        if (keyCertStr != null) {
241            // generate the private key.
242            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
243                                Base64.getMimeDecoder().decode(keySpecStr));
244            KeyFactory kf = KeyFactory.getInstance("RSA");
245            RSAPrivateKey priKey =
246                    (RSAPrivateKey)kf.generatePrivate(priKeySpec);
247
248            // generate certificate chain
249            is = new ByteArrayInputStream(keyCertStr.getBytes());
250            Certificate keyCert = cf.generateCertificate(is);
251            is.close();
252
253            // It's not allowed to send MD2 signed certificate to peer,
254            // even it may be a trusted certificate. Then we will not
255            // place the trusted certficate in the chain.
256            Certificate[] chain = new Certificate[1];
257            chain[0] = keyCert;
258
259            // import the key entry.
260            ks.setKeyEntry("Whatever", priKey, passphrase, chain);
261        }
262
263        // create SSL context
264        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
265        tmf.init(ks);
266
267        SSLContext ctx = SSLContext.getInstance(tlsProtocol);
268        if (keyCertStr != null && !keyCertStr.isEmpty()) {
269            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
270            kmf.init(ks, passphrase);
271
272            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
273            ks = null;
274        } else {
275            ctx.init(null, tmf.getTrustManagers(), null);
276        }
277
278        return ctx;
279    }
280
281
282    // use any free port by default
283    volatile int serverPort = 0;
284
285    volatile Exception serverException = null;
286    volatile Exception clientException = null;
287
288    public static void main(String[] args) throws Exception {
289        // MD5 is used in this test case, don't disable MD5 algorithm.
290        Security.setProperty(
291                "jdk.certpath.disabledAlgorithms", "MD2, RSA keySize < 1024");
292
293        if (debug)
294            System.setProperty("javax.net.debug", "all");
295
296        /*
297         * Get the customized arguments.
298         */
299        parseArguments(args);
300
301        /*
302         * Start the tests.
303         */
304        new MD2InTrustAnchor();
305    }
306
307    Thread clientThread = null;
308    Thread serverThread = null;
309
310    /*
311     * Primary constructor, used to drive remainder of the test.
312     *
313     * Fork off the other side, then do your work.
314     */
315    MD2InTrustAnchor() throws Exception {
316        try {
317            if (separateServerThread) {
318                startServer(true);
319                startClient(false);
320            } else {
321                startClient(true);
322                startServer(false);
323            }
324        } catch (Exception e) {
325            // swallow for now.  Show later
326        }
327
328        /*
329         * Wait for other side to close down.
330         */
331        if (separateServerThread) {
332            serverThread.join();
333        } else {
334            clientThread.join();
335        }
336
337        /*
338         * When we get here, the test is pretty much over.
339         * Which side threw the error?
340         */
341        Exception local;
342        Exception remote;
343        String whichRemote;
344
345        if (separateServerThread) {
346            remote = serverException;
347            local = clientException;
348            whichRemote = "server";
349        } else {
350            remote = clientException;
351            local = serverException;
352            whichRemote = "client";
353        }
354
355        /*
356         * If both failed, return the curthread's exception, but also
357         * print the remote side Exception
358         */
359        if ((local != null) && (remote != null)) {
360            System.out.println(whichRemote + " also threw:");
361            remote.printStackTrace();
362            System.out.println();
363            throw local;
364        }
365
366        if (remote != null) {
367            throw remote;
368        }
369
370        if (local != null) {
371            throw local;
372        }
373    }
374
375    void startServer(boolean newThread) throws Exception {
376        if (newThread) {
377            serverThread = new Thread() {
378                public void run() {
379                    try {
380                        doServerSide();
381                    } catch (Exception e) {
382                        /*
383                         * Our server thread just died.
384                         *
385                         * Release the client, if not active already...
386                         */
387                        System.err.println("Server died...");
388                        serverReady = true;
389                        serverException = e;
390                    }
391                }
392            };
393            serverThread.start();
394        } else {
395            try {
396                doServerSide();
397            } catch (Exception e) {
398                serverException = e;
399            } finally {
400                serverReady = true;
401            }
402        }
403    }
404
405    void startClient(boolean newThread) throws Exception {
406        if (newThread) {
407            clientThread = new Thread() {
408                public void run() {
409                    try {
410                        doClientSide();
411                    } catch (Exception e) {
412                        /*
413                         * Our client thread just died.
414                         */
415                        System.err.println("Client died...");
416                        clientException = e;
417                    }
418                }
419            };
420            clientThread.start();
421        } else {
422            try {
423                doClientSide();
424            } catch (Exception e) {
425                clientException = e;
426            }
427        }
428    }
429}
430