1/*
2 * Copyright (c) 2012, 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.  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 7068321
34 * @summary Support TLS Server Name Indication (SNI) Extension in JSSE Server
35 * @run main/othervm SSLSocketSNISensitive PKIX www.example.com
36 * @run main/othervm SSLSocketSNISensitive SunX509 www.example.com
37 * @run main/othervm SSLSocketSNISensitive PKIX www.example.net
38 * @run main/othervm SSLSocketSNISensitive SunX509 www.example.net
39 * @run main/othervm SSLSocketSNISensitive PKIX www.invalid.com
40 * @run main/othervm SSLSocketSNISensitive SunX509 www.invalid.com
41 */
42
43import java.net.*;
44import java.util.*;
45import java.io.*;
46import javax.net.ssl.*;
47import java.security.Security;
48import java.security.KeyStore;
49import java.security.KeyFactory;
50import java.security.cert.Certificate;
51import java.security.cert.X509Certificate;
52import java.security.cert.CertificateFactory;
53import java.security.spec.*;
54import java.security.interfaces.*;
55import java.util.Base64;
56
57
58public class SSLSocketSNISensitive {
59
60    /*
61     * =============================================================
62     * Set the various variables needed for the tests, then
63     * specify what tests to run on each side.
64     */
65
66    /*
67     * Should we run the client or server in a separate thread?
68     * Both sides can throw exceptions, but do you have a preference
69     * as to which side should be the main thread.
70     */
71    static boolean separateServerThread = false;
72
73    /*
74     * Where do we find the keystores?
75     */
76    // Certificates and key used in the test.
77    static String trustedCertStr =
78        "-----BEGIN CERTIFICATE-----\n" +
79        "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
80        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
81        "MTIwNDE3MTIwNjA3WhcNMzMwMzI4MTIwNjA3WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
82        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
83        "KoZIhvcNAQEBBQADgY0AMIGJAoGBANY+7Enp+1S566kLcKk+qe4Ki6BxaHGZ+v7r\n" +
84        "vLksx9IQZCbAEf4YLbrZhKzKD3SPIJXyxPFwknAknIh3Knk8mViOZks7T8L3GnJr\n" +
85        "TBaVvDyTzDJum/QYiahfO2qpfN/Oya2UILmqsBAeLyWpzbQsAyWBXfoUtkOUgnzK\n" +
86        "fk6QAKYrAgMBAAGjgaUwgaIwHQYDVR0OBBYEFEtmQi7jT1ijXOafPsfkrLwSVu9e\n" +
87        "MGMGA1UdIwRcMFqAFEtmQi7jT1ijXOafPsfkrLwSVu9eoT+kPTA7MQswCQYDVQQG\n" +
88        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
89        "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" +
90        "BQADgYEAkKWxMc4+ODk5WwLXXweB8/IKfVfrizNn0KLEgsZ6xNXFIXDpiPGAFcgl\n" +
91        "MzFO424JgyvUulsUc/X16Cnuwwntkk6KUG7vEV7h4o9sAV7Cax3gfQE/EZFb4ybn\n" +
92        "aBm1UsujMKd/ovqbbbxJbmOWzCeo0QfIGleDEyh3NBBZ0i11Kiw=\n" +
93        "-----END CERTIFICATE-----";
94
95    // web server certificate, www.example.com
96    static String targetCertStr_A =
97        "-----BEGIN CERTIFICATE-----\n" +
98        "MIICVTCCAb6gAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
99        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
100        "MTIwNDE3MTIwNjA4WhcNMzIwMTAzMTIwNjA4WjBVMQswCQYDVQQGEwJVUzENMAsG\n" +
101        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxGDAWBgNV\n" +
102        "BAMTD3d3dy5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" +
103        "4zFp3PZNzsd3ZwG6FNNWO9eSN+UBymlf8oCwpKJM2tIinmMWvWIXnlx/2UXIfSAq\n" +
104        "QEG3aXkAFyEiGGpQlBbqcfrESsHsiz2pnnm5dG2v/eS0Bwz1jmcuNmwnh3UQw2Vl\n" +
105        "+BLk8ukdrLjiCT8jARiHExYf1Xg+wUqQ9y8NV26hdaUCAwEAAaNPME0wCwYDVR0P\n" +
106        "BAQDAgPoMB0GA1UdDgQWBBQwtx+gqzn2w4y82brXlp7tqBYEZDAfBgNVHSMEGDAW\n" +
107        "gBRLZkIu409Yo1zmnz7H5Ky8ElbvXjANBgkqhkiG9w0BAQQFAAOBgQAJWo8B6Ud+\n" +
108        "/OU+UcZLihlfMX02OSlK2ZB7mfqpj2G3JT9yb0A+VbY3uuajmaYYIIxl3kXGz/n8\n" +
109        "M2Q/Ux/MDxG+IFKHC26Kuj4dAQgzjq2pILVPTE2QnaQTNCsgVZtTaC47SG9FRSoC\n" +
110        "qvnIvn/oTpKSqus76I1cR4joDtiV2OEuVw==\n" +
111        "-----END CERTIFICATE-----";
112
113    // Private key in the format of PKCS#8
114    static String targetPrivateKey_A =
115        "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOMxadz2Tc7Hd2cB\n" +
116        "uhTTVjvXkjflAcppX/KAsKSiTNrSIp5jFr1iF55cf9lFyH0gKkBBt2l5ABchIhhq\n" +
117        "UJQW6nH6xErB7Is9qZ55uXRtr/3ktAcM9Y5nLjZsJ4d1EMNlZfgS5PLpHay44gk/\n" +
118        "IwEYhxMWH9V4PsFKkPcvDVduoXWlAgMBAAECgYAqX2nuIyXp3fvgA0twXOYlbRRB\n" +
119        "Rn3qAXM6qFPJsNeCrFR2k+aG1cev6nKR1FkLNTeMGnWZv06MAcr5IML8i7WXyG4C\n" +
120        "LY/C0gedn94FDKFlln+bTENwQTGjn4lKysDA+IuNpasTeMCajbic+dPByhIdTOjZ\n" +
121        "iMCyxbLfpk40zQopVQJBAPyfGmkeHB3GjdbdgujWCGKb2UxBa4O8dy3O4l2yizTn\n" +
122        "uUqMGcwGY4ciNSVvZQ7jKo4vDmkSuYib4/woPChaNfMCQQDmO0BQuSWYGNtSwV35\n" +
123        "lafZfX1dNCLKm1iNA6A12evXgvQiE9WT4mqionig0VZW16HtiY4/BkHOcos/K9Um\n" +
124        "ARQHAkA8mkaRtSF1my5nv1gqVz5Hua+VdZQ/VDUbDiiL5cszc+ulkJqXsWirAG/T\n" +
125        "fTe3LJQG7A7+8fkEZrF4yoY0AAA1AkEAotokezULj5N9iAL5SzL9wIzQYV4ggfny\n" +
126        "YATBjXXxKccakwQ+ndWZIiMUeoS4ssLialhTgucVI0fIkU2a/r/ifwJAc6e+5Pvh\n" +
127        "MghQj/U788Od/v6rgqz/NGsduZ7uilCMcWiwA73OR2MHMH/OIuoofuEPrfuV9isV\n" +
128        "xVXhgpKfP/pdOA==";
129
130    // web server certificate, www.example.net
131    static String targetCertStr_B =
132        "-----BEGIN CERTIFICATE-----\n" +
133        "MIICVTCCAb6gAwIBAgIBBDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
134        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
135        "MTIwNDE3MTIwNjA5WhcNMzIwMTAzMTIwNjA5WjBVMQswCQYDVQQGEwJVUzENMAsG\n" +
136        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxGDAWBgNV\n" +
137        "BAMTD3d3dy5leGFtcGxlLm5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" +
138        "2VlzF1fvWYczDChrUeJiLJ1M/dIShCaOTfYGiXfQGEZCAWTacUclwr+rVMnZ75/c\n" +
139        "wwg5pNdXRijxMil8DBTS1gFcIFQhosLHvzIAe6ULlg/xB+/L6KBz+NTWfo/2KF6t\n" +
140        "xatmcToNrCcwi7eUOfbzQje65Tizs56jJYem2m7Rk0ECAwEAAaNPME0wCwYDVR0P\n" +
141        "BAQDAgPoMB0GA1UdDgQWBBQT/FR0cAWcZQ7h0X79KGki34OSQjAfBgNVHSMEGDAW\n" +
142        "gBRLZkIu409Yo1zmnz7H5Ky8ElbvXjANBgkqhkiG9w0BAQQFAAOBgQB67cPIT6fz\n" +
143        "6Ws8fBpYgW2ad4ci66i1WduBD9CpGFE+jRK2feRj6hvYBXocKj0AMWUFIEB2E3hA\n" +
144        "oIjxcf1GxIpHVl9DjlhxqXbA0Ktl7/NGNRlDSLTizOTl3FB1mMTlOGvXDVmpcFhl\n" +
145        "HuoP1hYvhTsBwPx5igGNchuPtDIUzL2mXw==\n" +
146        "-----END CERTIFICATE-----";
147
148    static String targetPrivateKey_B =
149        "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANlZcxdX71mHMwwo\n" +
150        "a1HiYiydTP3SEoQmjk32Bol30BhGQgFk2nFHJcK/q1TJ2e+f3MMIOaTXV0Yo8TIp\n" +
151        "fAwU0tYBXCBUIaLCx78yAHulC5YP8Qfvy+igc/jU1n6P9ihercWrZnE6DawnMIu3\n" +
152        "lDn280I3uuU4s7OeoyWHptpu0ZNBAgMBAAECgYEAl19H26sfhD+32rDPxZCgBShs\n" +
153        "dZ33zVe45i0Bcn4iTLWpxKTDyf7eGps4rO2DvfKdYqt40ggzvSZIjUH9JcDe8GmG\n" +
154        "d3m0ILB7pg4jsFlpyeHpTO8grPLxA1G9s3o0DoFpz/rooqgFfe/DrRDmRoOSkgfV\n" +
155        "/gseIbgJHRO/Ctyvdh0CQQD6uFd0HxhH1jl/JzvPzIH4LSnPcdEh9zsMEb6uzh75\n" +
156        "9qL+IHD5N2I/pYZTKqDFIwhJf701+LKag55AX/zrDt7rAkEA3e00AbnwanDMa6Wj\n" +
157        "+gFekUQveSVra38LiihzCkyVvQpFjbiF1rUhSNQ0dpU5/hmrYF0C6H9VXAesfkUY\n" +
158        "WhpDgwJAYjgZOop77piDycZK7isFt32p5XSHIzFBVocVFlH1XKM8UyXOXDNQL/Le\n" +
159        "XnJSrSf+NRzvuNcG0PVC56Ey6brXpQJAY4M4vcltt5zq3R5CQBmbGRJ1IyKXX3Vx\n" +
160        "bDslEqoyvri7ZYgnY5aG3UxiVgYmIf3KrgQnCLAIS6MZQumiuMxsFwJAK5pEG063\n" +
161        "9ngUof4fDMvZphqZjZR1zMKz/V/9ge0DWBINaqFgsgebNu+MyImsC8C6WKjGmV/2\n" +
162        "f1MY0D7sC2vU/Q==";
163
164    // web server certificate, www.invalid.com
165    static String targetCertStr_C =
166        "-----BEGIN CERTIFICATE-----\n" +
167        "MIICVTCCAb6gAwIBAgIBAzANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
168        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
169        "MTIwNDE3MTIwNjA5WhcNMzIwMTAzMTIwNjA5WjBVMQswCQYDVQQGEwJVUzENMAsG\n" +
170        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxGDAWBgNV\n" +
171        "BAMTD3d3dy5pbnZhbGlkLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" +
172        "q6MyQwzCr2nJ41l0frmHL0qULSyW51MhevBC+1W28i0LE/efrmpwV3LdnlQEGFak\n" +
173        "DLDwtnff3iru8dSMcA7KdWVkivsE7ZTP+qFDaWBAy7XXiSsv6yZ2Nh4jJb0YcD28\n" +
174        "45zk2nAl5Az1/PuoTi1vpQxzFZKuBm1HGgz3MEZvBvMCAwEAAaNPME0wCwYDVR0P\n" +
175        "BAQDAgPoMB0GA1UdDgQWBBRRMifrND015Nm8N6gV5X7cg1YjjjAfBgNVHSMEGDAW\n" +
176        "gBRLZkIu409Yo1zmnz7H5Ky8ElbvXjANBgkqhkiG9w0BAQQFAAOBgQBjkUO6Ri/B\n" +
177        "uDC2gDMIyL5+NTe/1dPPQYM4HhCNa/KQYvU5lzCKO9Vpa+i+nyrUNNXUu8Tkyq4Y\n" +
178        "A+aGSm6+FT/i9rFwkYUdorBtD3KfQiwTIWrVERXBkWI5iZNaVZhx0TFy4vUpf65d\n" +
179        "QtwkbHpC66fdKc2EdLXkuY9KkmtZZJJ7YA==\n" +
180        "-----END CERTIFICATE-----";
181
182    static String targetPrivateKey_C =
183        "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKujMkMMwq9pyeNZ\n" +
184        "dH65hy9KlC0sludTIXrwQvtVtvItCxP3n65qcFdy3Z5UBBhWpAyw8LZ3394q7vHU\n" +
185        "jHAOynVlZIr7BO2Uz/qhQ2lgQMu114krL+smdjYeIyW9GHA9vOOc5NpwJeQM9fz7\n" +
186        "qE4tb6UMcxWSrgZtRxoM9zBGbwbzAgMBAAECgYASJDK40Y12Wvki1Z6xkkyOnBRj\n" +
187        "XfYpRykfxGtgA2RN3qLwHlk7Zzaul46DIKA6LlYynTUkJDF+Ww1cdDnP0lBlwcmM\n" +
188        "iD0ck3zYyYBLhQHuVbkK3SYE+ANRhM0icvvqANP2at/U4awQcPNEae/KCiecLNu3\n" +
189        "CJGqyhPDdrEAqPuJGQJBAN46pQC6l3yrcSYE2s53jSmsm2HVVOFlFXjU6k/RMTxG\n" +
190        "FfDJtGUAOQ37rPQ06ugr/gjLAmmPp+FXozaBdA32D80CQQDFuGRgv3WYqbglIcRL\n" +
191        "JRs6xlj9w1F97s/aiUenuwhIPNiUoRbV7mnNuZ/sGF0svOVE7SazRjuFX6UqL9Y9\n" +
192        "HzG/AkEA170pCI8cl4w8eUNHRB9trGKEKjMXhwVCFh7lJf2ZBcGodSzr8w2HVhrZ\n" +
193        "Ke7hiemDYffrbJ1oxmv05+o+x3r0lQJBAL6adVm2+FyFMFnLZXmzeb59O4jWY5bt\n" +
194        "Qz6/HG6bpO5OidMuP99YCHMkQQDOs/PO3Y5GuAoW6IY4n/Y9S2B80+0CQBl1/H9/\n" +
195        "0n/vrb6vW6Azds49tuS82RFAnOhtwTyBEajs08WF8rZQ3WD2RHJnH0+jjfL0anIp\n" +
196        "dQBSeNN7s7b6rRk=";
197
198    // This is a certificate for client
199    static String targetCertStr_D=
200        "-----BEGIN CERTIFICATE-----\n" +
201        "MIICVDCCAb2gAwIBAgIBBTANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
202        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
203        "MTIwNDE3MTIwNjEwWhcNMzIwMTAzMTIwNjEwWjBUMQswCQYDVQQGEwJVUzENMAsG\n" +
204        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxFzAVBgNV\n" +
205        "BAMTDkludGVyT3AgVGVzdGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDo\n" +
206        "Q/KoAIAC2ljFfW2KwjnxTzi4NQJeUuk2seqKpsAY8x4O5dvixzUl6142zmljapqi\n" +
207        "bJloQVpfB+CEc5/l4h5gzGRVzkuqP1oPzDrpZ5GsvmvuHenV/TzCIgX1cLETzQVt\n" +
208        "6Rk06okoBPnw3hDJEJiEc1Rv7HCE8p/p+SaiHrskwwIDAQABo08wTTALBgNVHQ8E\n" +
209        "BAMCA+gwHQYDVR0OBBYEFPr91O33RIGfFSqza2AwQIgE4QswMB8GA1UdIwQYMBaA\n" +
210        "FEtmQi7jT1ijXOafPsfkrLwSVu9eMA0GCSqGSIb3DQEBBAUAA4GBANIDFYgAhoj3\n" +
211        "B8u1YpqeoEp2Lt9TwrYBshaIrbmBPCwCGio0JIsoov3n8BCSg5F+8MnOtPl+TjeO\n" +
212        "0Ug+7guPdCk/wg8YNxLHgSsQlpcNJDjWiErqmUPVrg5BPPQb65qMund6KTmMN0y6\n" +
213        "4EbSmxRpZO/N0/5oK4umTk0EeXKNekBj\n" +
214        "-----END CERTIFICATE-----";
215
216    static String targetPrivateKey_D =
217        "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOhD8qgAgALaWMV9\n" +
218        "bYrCOfFPOLg1Al5S6Tax6oqmwBjzHg7l2+LHNSXrXjbOaWNqmqJsmWhBWl8H4IRz\n" +
219        "n+XiHmDMZFXOS6o/Wg/MOulnkay+a+4d6dX9PMIiBfVwsRPNBW3pGTTqiSgE+fDe\n" +
220        "EMkQmIRzVG/scITyn+n5JqIeuyTDAgMBAAECgYBw37yIKp4LRONJLnhSq6sO+0n8\n" +
221        "Mz6waiiN/Q6XTQwj09pysQAYCGlqwSRrDAqpVsBJWO+Ae+oYLrLMi4hUZnwN75v3\n" +
222        "pe1nXlrD11RmPLXwBxqFxNSvAs2FgLHZEtwHI7Bn8KybT/8bGkQ8csLceInYtMDD\n" +
223        "MuTyy2KRk/pj60zIKQJBAPgebQiAH6viFQ88AwHaNvQhlUfwmSC1i6f8LVoeqaHC\n" +
224        "lnP0LJBwlyDeeEInhHrCR2ibnCB6I/Pig+49XQgabK8CQQDvpJwuGEbsOO+3rkJJ\n" +
225        "OpOw4toG0QJZdRnT6l8I6BlboQRZSfFh+lGGahvFXkxc4KdUpJ7QPtXU7HHk6Huk\n" +
226        "8RYtAkA9CW8VGj+wTuuTVdX/jKjcIa7RhbSFwWNbrcOSWdys+Gt+luCnn6rt4QyA\n" +
227        "aaxDbquWZkFgE+voQR7nap0KM0XtAkAznd0WAJymHM1lXt9gLoHJQ9N6TGKZKiPa\n" +
228        "BU1a+cMcfV4WbVrUo7oTnZ9Fr73681iXXq3mZOJh7lvJ1llreZIxAkBEnbiTgEf4\n" +
229        "tvku68jHcRbRPmdS7CBSWNEBaHLOm4pUSTcxVTKKMHw7vmM5/UYUxJ8QNKCYxn6O\n" +
230        "+vtiBwBawwzN";
231
232    static String[] serverCerts = {targetCertStr_A,
233                                targetCertStr_B, targetCertStr_C};
234    static String[] serverKeys  = {targetPrivateKey_A,
235                                targetPrivateKey_B, targetPrivateKey_C};
236    static String[] clientCerts = {targetCertStr_D};
237    static String[] clientKeys  = {targetPrivateKey_D};
238
239    static char passphrase[] = "passphrase".toCharArray();
240
241    /*
242     * Is the server ready to serve?
243     */
244    volatile static boolean serverReady = false;
245
246    /*
247     * Turn on SSL debugging?
248     */
249    static boolean debug = false;
250
251    /*
252     * Define the server side of the test.
253     *
254     * If the server prematurely exits, serverReady will be set to true
255     * to avoid infinite hangs.
256     */
257    void doServerSide() throws Exception {
258        SSLContext context = generateSSLContext(false);
259        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
260        SSLServerSocket sslServerSocket =
261            (SSLServerSocket)sslssf.createServerSocket(serverPort);
262        serverPort = sslServerSocket.getLocalPort();
263
264        /*
265         * Signal Client, we're ready for his connect.
266         */
267        serverReady = true;
268
269        SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
270        try {
271            sslSocket.setSoTimeout(5000);
272            sslSocket.setSoLinger(true, 5);
273
274            InputStream sslIS = sslSocket.getInputStream();
275            OutputStream sslOS = sslSocket.getOutputStream();
276
277            sslIS.read();
278            sslOS.write('A');
279            sslOS.flush();
280
281            SSLSession session = sslSocket.getSession();
282            checkCertificate(session.getLocalCertificates(),
283                                                clientRequestedHostname);
284        } finally {
285            sslSocket.close();
286            sslServerSocket.close();
287        }
288    }
289
290    /*
291     * Define the client side of the test.
292     *
293     * If the server prematurely exits, serverReady will be set to true
294     * to avoid infinite hangs.
295     */
296    void doClientSide() throws Exception {
297
298        /*
299         * Wait for server to get started.
300         */
301        while (!serverReady) {
302            Thread.sleep(50);
303        }
304
305        SSLContext context = generateSSLContext(true);
306        SSLSocketFactory sslsf = context.getSocketFactory();
307
308        SSLSocket sslSocket =
309            (SSLSocket)sslsf.createSocket("localhost", serverPort);
310
311        SNIHostName serverName = new SNIHostName(clientRequestedHostname);
312        List<SNIServerName> serverNames = new ArrayList<>(1);
313        serverNames.add(serverName);
314        SSLParameters params = sslSocket.getSSLParameters();
315        params.setServerNames(serverNames);
316        sslSocket.setSSLParameters(params);
317
318        try {
319            sslSocket.setSoTimeout(5000);
320            sslSocket.setSoLinger(true, 5);
321
322            InputStream sslIS = sslSocket.getInputStream();
323            OutputStream sslOS = sslSocket.getOutputStream();
324
325            sslOS.write('B');
326            sslOS.flush();
327            sslIS.read();
328
329            SSLSession session = sslSocket.getSession();
330            checkCertificate(session.getPeerCertificates(),
331                                                clientRequestedHostname);
332        } finally {
333            sslSocket.close();
334        }
335    }
336
337    private static void checkCertificate(Certificate[] certs,
338            String hostname) throws Exception {
339        if (certs != null && certs.length != 0) {
340            X509Certificate x509Cert = (X509Certificate)certs[0];
341
342            String subject = x509Cert.getSubjectX500Principal().getName();
343
344            if (!subject.contains(hostname)) {
345                throw new Exception(
346                        "Not the expected certificate: " + subject);
347            }
348        }
349    }
350
351    /*
352     * =============================================================
353     * The remainder is just support stuff
354     */
355    private static String tmAlgorithm;             // trust manager
356    private static String clientRequestedHostname; // server name indication
357
358    private static void parseArguments(String[] args) {
359        tmAlgorithm = args[0];
360        clientRequestedHostname = args[1];
361    }
362
363    private static SSLContext generateSSLContext(boolean isClient)
364            throws Exception {
365
366        // generate certificate from cert string
367        CertificateFactory cf = CertificateFactory.getInstance("X.509");
368
369        // create a key store
370        KeyStore ks = KeyStore.getInstance("JKS");
371        ks.load(null, null);
372
373        // import the trused cert
374        ByteArrayInputStream is =
375                    new ByteArrayInputStream(trustedCertStr.getBytes());
376        Certificate trusedCert = cf.generateCertificate(is);
377        is.close();
378
379        ks.setCertificateEntry("RSA Export Signer", trusedCert);
380
381        String[] certStrs = null;
382        String[] keyStrs = null;
383        if (isClient) {
384            certStrs = clientCerts;
385            keyStrs = clientKeys;
386        } else {
387            certStrs = serverCerts;
388            keyStrs = serverKeys;
389        }
390
391        for (int i = 0; i < certStrs.length; i++) {
392            // generate the private key.
393            String keySpecStr = keyStrs[i];
394            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
395                                Base64.getMimeDecoder().decode(keySpecStr));
396            KeyFactory kf = KeyFactory.getInstance("RSA");
397            RSAPrivateKey priKey =
398                    (RSAPrivateKey)kf.generatePrivate(priKeySpec);
399
400            // generate certificate chain
401            String keyCertStr = certStrs[i];
402            is = new ByteArrayInputStream(keyCertStr.getBytes());
403            Certificate keyCert = cf.generateCertificate(is);
404            is.close();
405
406            Certificate[] chain = new Certificate[2];
407            chain[0] = keyCert;
408            chain[1] = trusedCert;
409
410            // import the key entry.
411            ks.setKeyEntry("key-entry-" + i, priKey, passphrase, chain);
412        }
413
414        // create SSL context
415        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
416        tmf.init(ks);
417
418        SSLContext ctx = SSLContext.getInstance("TLS");
419        KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
420        kmf.init(ks, passphrase);
421
422        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
423        ks = null;
424
425        return ctx;
426    }
427
428    // use any free port by default
429    volatile int serverPort = 0;
430
431    volatile Exception serverException = null;
432    volatile Exception clientException = null;
433
434    public static void main(String[] args) throws Exception {
435        // MD5 is used in this test case, don't disable MD5 algorithm.
436        Security.setProperty("jdk.certpath.disabledAlgorithms",
437                "MD2, RSA keySize < 1024");
438        Security.setProperty("jdk.tls.disabledAlgorithms",
439                "SSLv3, RC4, DH keySize < 768");
440
441        if (debug)
442            System.setProperty("javax.net.debug", "all");
443
444        /*
445         * Get the customized arguments.
446         */
447        parseArguments(args);
448
449        /*
450         * Start the tests.
451         */
452        new SSLSocketSNISensitive();
453    }
454
455    Thread clientThread = null;
456    Thread serverThread = null;
457
458    /*
459     * Primary constructor, used to drive remainder of the test.
460     *
461     * Fork off the other side, then do your work.
462     */
463    SSLSocketSNISensitive() throws Exception {
464        try {
465            if (separateServerThread) {
466                startServer(true);
467                startClient(false);
468            } else {
469                startClient(true);
470                startServer(false);
471            }
472        } catch (Exception e) {
473            // swallow for now.  Show later
474        }
475
476        /*
477         * Wait for other side to close down.
478         */
479        if (separateServerThread) {
480            serverThread.join();
481        } else {
482            clientThread.join();
483        }
484
485        /*
486         * When we get here, the test is pretty much over.
487         * Which side threw the error?
488         */
489        Exception local;
490        Exception remote;
491        String whichRemote;
492
493        if (separateServerThread) {
494            remote = serverException;
495            local = clientException;
496            whichRemote = "server";
497        } else {
498            remote = clientException;
499            local = serverException;
500            whichRemote = "client";
501        }
502
503        /*
504         * If both failed, return the curthread's exception, but also
505         * print the remote side Exception
506         */
507        if ((local != null) && (remote != null)) {
508            System.out.println(whichRemote + " also threw:");
509            remote.printStackTrace();
510            System.out.println();
511            throw local;
512        }
513
514        if (remote != null) {
515            throw remote;
516        }
517
518        if (local != null) {
519            throw local;
520        }
521    }
522
523    void startServer(boolean newThread) throws Exception {
524        if (newThread) {
525            serverThread = new Thread() {
526                public void run() {
527                    try {
528                        doServerSide();
529                    } catch (Exception e) {
530                        /*
531                         * Our server thread just died.
532                         *
533                         * Release the client, if not active already...
534                         */
535                        System.err.println("Server died, because of " + e);
536                        serverReady = true;
537                        serverException = e;
538                    }
539                }
540            };
541            serverThread.start();
542        } else {
543            try {
544                doServerSide();
545            } catch (Exception e) {
546                serverException = e;
547            } finally {
548                serverReady = true;
549            }
550        }
551    }
552
553    void startClient(boolean newThread) throws Exception {
554        if (newThread) {
555            clientThread = new Thread() {
556                public void run() {
557                    try {
558                        doClientSide();
559                    } catch (Exception e) {
560                        /*
561                         * Our client thread just died.
562                         */
563                        System.err.println("Client died, because of " + e);
564                        clientException = e;
565                    }
566                }
567            };
568            clientThread.start();
569        } else {
570            try {
571                doClientSide();
572            } catch (Exception e) {
573                clientException = e;
574            }
575        }
576    }
577}
578