1 /*
2  * Copyright (c) 2012, 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.
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 7068321
32  * @summary Support TLS Server Name Indication (SNI) Extension in JSSE Server
33  * @library ../SSLEngine ../templates
34  * @build SSLEngineService SSLCapabilities SSLExplorer
35  * @run main/othervm SSLEngineExplorer SSLv2Hello,SSLv3
36  * @run main/othervm SSLEngineExplorer SSLv3
37  * @run main/othervm SSLEngineExplorer TLSv1
38  * @run main/othervm SSLEngineExplorer TLSv1.1
39  * @run main/othervm SSLEngineExplorer TLSv1.2
40  */
41 
42 import javax.net.ssl.*;
43 import java.nio.*;
44 import java.net.*;
45 import java.util.*;
46 import java.nio.channels.*;
47 import java.security.Security;
48 
49 public class SSLEngineExplorer extends SSLEngineService {
50 
51     /*
52      * =============================================================
53      * Set the various variables needed for the tests, then
54      * specify what tests to run on each side.
55      */
56 
57     /*
58      * Should we run the client or server in a separate thread?
59      * Both sides can throw exceptions, but do you have a preference
60      * as to which side should be the main thread.
61      */
62     static boolean separateServerThread = true;
63 
64     // Is the server ready to serve?
65     volatile static boolean serverReady = false;
66 
67     /*
68      * Turn on SSL debugging?
69      */
70     static boolean debug = false;
71 
72     /*
73      * Define the server side of the test.
74      *
75      * If the server prematurely exits, serverReady will be set to true
76      * to avoid infinite hangs.
77      */
doServerSide()78     void doServerSide() throws Exception {
79 
80         // create SSLEngine.
81         SSLEngine ssle = createSSLEngine(false);
82 
83         // Create a server socket channel.
84         InetSocketAddress isa =
85                 new InetSocketAddress(InetAddress.getLocalHost(), serverPort);
86         ServerSocketChannel ssc = ServerSocketChannel.open();
87         ssc.socket().bind(isa);
88         serverPort = ssc.socket().getLocalPort();
89 
90         // Signal Client, we're ready for his connect.
91         serverReady = true;
92 
93         // Accept a socket channel.
94         SocketChannel sc = ssc.accept();
95         sc.configureBlocking(false);
96 
97         // Complete connection.
98         while (!sc.finishConnect()) {
99             Thread.sleep(50);
100             // waiting for the connection completed.
101         }
102 
103         ByteBuffer buffer = ByteBuffer.allocate(0xFF);
104         int position = 0;
105         SSLCapabilities capabilities = null;
106 
107         // Read the header of TLS record
108         buffer.limit(SSLExplorer.RECORD_HEADER_SIZE);
109         while (position < SSLExplorer.RECORD_HEADER_SIZE) {
110             int n = sc.read(buffer);
111             if (n < 0) {
112                 throw new Exception("unexpected end of stream!");
113             }
114             position += n;
115         }
116         buffer.flip();
117 
118         int recordLength = SSLExplorer.getRequiredSize(buffer);
119         if (buffer.capacity() < recordLength) {
120             ByteBuffer oldBuffer = buffer;
121             buffer = ByteBuffer.allocate(recordLength);
122             buffer.put(oldBuffer);
123         }
124 
125         buffer.position(SSLExplorer.RECORD_HEADER_SIZE);
126         buffer.limit(buffer.capacity());
127         while (position < recordLength) {
128             int n = sc.read(buffer);
129             if (n < 0) {
130                 throw new Exception("unexpected end of stream!");
131             }
132             position += n;
133         }
134         buffer.flip();
135 
136         capabilities = SSLExplorer.explore(buffer);
137         if (capabilities != null) {
138             System.out.println("Record version: " +
139                     capabilities.getRecordVersion());
140             System.out.println("Hello version: " +
141                     capabilities.getHelloVersion());
142         }
143 
144         // handshaking
145         handshaking(ssle, sc, buffer);
146 
147         // receive application data
148         receive(ssle, sc);
149 
150         // send out application data
151         deliver(ssle, sc);
152 
153         ExtendedSSLSession session = (ExtendedSSLSession)ssle.getSession();
154         checkCapabilities(capabilities, session);
155 
156         // close the socket channel.
157         sc.close();
158         ssc.close();
159     }
160 
161     /*
162      * Define the client side of the test.
163      *
164      * If the server prematurely exits, serverReady will be set to true
165      * to avoid infinite hangs.
166      */
doClientSide()167     void doClientSide() throws Exception {
168         // create SSLEngine.
169         SSLEngine ssle = createSSLEngine(true);
170 
171         /*
172          * Wait for server to get started.
173          */
174         while (!serverReady) {
175             Thread.sleep(50);
176         }
177 
178         // Create a non-blocking socket channel.
179         SocketChannel sc = SocketChannel.open();
180         sc.configureBlocking(false);
181         InetSocketAddress isa =
182                 new InetSocketAddress(InetAddress.getLocalHost(), serverPort);
183         sc.connect(isa);
184 
185         // Complete connection.
186         while (!sc.finishConnect() ) {
187             Thread.sleep(50);
188             // waiting for the connection completed.
189         }
190 
191         // enable the specified TLS protocol
192         ssle.setEnabledProtocols(supportedProtocols);
193 
194         // handshaking
195         handshaking(ssle, sc, null);
196 
197         // send out application data
198         deliver(ssle, sc);
199 
200         // receive application data
201         receive(ssle, sc);
202 
203         // close the socket channel.
204         sc.close();
205     }
206 
checkCapabilities(SSLCapabilities capabilities, ExtendedSSLSession session)207     void checkCapabilities(SSLCapabilities capabilities,
208             ExtendedSSLSession session) throws Exception {
209 
210         List<SNIServerName> sessionSNI = session.getRequestedServerNames();
211         if (!sessionSNI.equals(capabilities.getServerNames())) {
212             throw new Exception(
213                     "server name indication does not match capabilities");
214         }
215     }
216 
217     private static String[] supportedProtocols;    // supported protocols
218 
parseArguments(String[] args)219     private static void parseArguments(String[] args) {
220         supportedProtocols = args[0].split(",");
221     }
222 
223 
224     /*
225      * =============================================================
226      * The remainder is just support stuff
227      */
228     volatile Exception serverException = null;
229     volatile Exception clientException = null;
230 
231     // use any free port by default
232     volatile int serverPort = 0;
233 
main(String args[])234     public static void main(String args[]) throws Exception {
235         // reset the security property to make sure that the algorithms
236         // and keys used in this test are not disabled.
237         Security.setProperty("jdk.tls.disabledAlgorithms", "");
238 
239         if (debug)
240             System.setProperty("javax.net.debug", "all");
241 
242         /*
243          * Get the customized arguments.
244          */
245         parseArguments(args);
246 
247         new SSLEngineExplorer();
248     }
249 
250     Thread clientThread = null;
251     Thread serverThread = null;
252 
253     /*
254      * Primary constructor, used to drive remainder of the test.
255      *
256      * Fork off the other side, then do your work.
257      */
SSLEngineExplorer()258     SSLEngineExplorer() throws Exception {
259         super("../etc");
260 
261         if (separateServerThread) {
262             startServer(true);
263             startClient(false);
264         } else {
265             startClient(true);
266             startServer(false);
267         }
268 
269         /*
270          * Wait for other side to close down.
271          */
272         if (separateServerThread) {
273             serverThread.join();
274         } else {
275             clientThread.join();
276         }
277 
278         /*
279          * When we get here, the test is pretty much over.
280          *
281          * If the main thread excepted, that propagates back
282          * immediately.  If the other thread threw an exception, we
283          * should report back.
284          */
285         if (serverException != null) {
286             System.out.print("Server Exception:");
287             throw serverException;
288         }
289         if (clientException != null) {
290             System.out.print("Client Exception:");
291             throw clientException;
292         }
293     }
294 
startServer(boolean newThread)295     void startServer(boolean newThread) throws Exception {
296         if (newThread) {
297             serverThread = new Thread() {
298                 public void run() {
299                     try {
300                         doServerSide();
301                     } catch (Exception e) {
302                         /*
303                          * Our server thread just died.
304                          *
305                          * Release the client, if not active already...
306                          */
307                         System.err.println("Server died...");
308                         System.err.println(e);
309                         serverReady = true;
310                         serverException = e;
311                     }
312                 }
313             };
314             serverThread.start();
315         } else {
316             doServerSide();
317         }
318     }
319 
startClient(boolean newThread)320     void startClient(boolean newThread) throws Exception {
321         if (newThread) {
322             clientThread = new Thread() {
323                 public void run() {
324                     try {
325                         doClientSide();
326                     } catch (Exception e) {
327                         /*
328                          * Our client thread just died.
329                          */
330                         System.err.println("Client died...");
331                         clientException = e;
332                     }
333                 }
334             };
335             clientThread.start();
336         } else {
337             doClientSide();
338         }
339     }
340 }
341