1 /*
2  * Copyright (c) 2001, 2021, 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 // SunJSSE does not support dynamic system properties, no way to re-use
25 // system properties in samevm/agentvm mode.
26 
27 /*
28  * @test
29  * @bug 4416068 4478803 4479736
30  * @summary 4273544 JSSE request for function forceV3ClientHello()
31  *          4479736 setEnabledProtocols API does not work correctly
32  *          4478803 Need APIs to determine the protocol versions used in an SSL
33  *                  session
34  *          4701722 protocol mismatch exceptions should be consistent between
35  *                  SSLv3 and TLSv1
36  * @library /javax/net/ssl/templates
37  * @run main/othervm TestEnabledProtocols
38  * @author Ram Marti
39  */
40 
41 import java.io.InputStream;
42 import java.io.InterruptedIOException;
43 import java.io.OutputStream;
44 import java.net.InetAddress;
45 import java.net.SocketException;
46 import java.security.Security;
47 import java.util.Arrays;
48 
49 import javax.net.ssl.SSLException;
50 import javax.net.ssl.SSLHandshakeException;
51 import javax.net.ssl.SSLServerSocket;
52 import javax.net.ssl.SSLSocket;
53 
54 public class TestEnabledProtocols extends SSLSocketTemplate {
55 
56     private final String[] serverProtocols;
57     private final String[] clientProtocols;
58     private final boolean exceptionExpected;
59     private final String selectedProtocol;
60 
TestEnabledProtocols(String[] serverProtocols, String[] clientProtocols, boolean exceptionExpected, String selectedProtocol)61     public TestEnabledProtocols(String[] serverProtocols,
62             String[] clientProtocols, boolean exceptionExpected,
63             String selectedProtocol) {
64         this.serverProtocols = serverProtocols;
65         this.clientProtocols = clientProtocols;
66         this.exceptionExpected = exceptionExpected;
67         this.selectedProtocol = selectedProtocol;
68     }
69 
70     @Override
configureServerSocket(SSLServerSocket sslServerSocket)71     protected void configureServerSocket(SSLServerSocket sslServerSocket) {
72         sslServerSocket.setEnabledProtocols(serverProtocols);
73     }
74 
75     @Override
runServerApplication(SSLSocket socket)76     protected void runServerApplication(SSLSocket socket) throws Exception {
77         try {
78             socket.startHandshake();
79 
80             InputStream in = socket.getInputStream();
81             OutputStream out = socket.getOutputStream();
82             out.write(280);
83             in.read();
84         } catch (SSLHandshakeException se) {
85             // ignore it; this is part of the testing
86             // log it for debugging
87             System.out.println("Server SSLHandshakeException:");
88             se.printStackTrace(System.out);
89         } catch (InterruptedIOException ioe) {
90             // must have been interrupted, no harm
91         } catch (SSLException | SocketException se) {
92             // The client side may have closed the socket.
93             System.out.println("Server SSLException:");
94             se.printStackTrace(System.out);
95         } catch (Exception e) {
96             System.out.println("Server exception:");
97             e.printStackTrace(System.out);
98             throw new RuntimeException(e);
99         }
100     }
101 
102     @Override
runClientApplication(SSLSocket sslSocket)103     protected void runClientApplication(SSLSocket sslSocket) throws Exception {
104         try {
105             System.out.println("=== Starting new test run ===");
106             showProtocols("server", serverProtocols);
107             showProtocols("client", clientProtocols);
108 
109             sslSocket.setEnabledProtocols(clientProtocols);
110             sslSocket.startHandshake();
111 
112             String protocolName = sslSocket.getSession().getProtocol();
113             System.out.println("Protocol name after getSession is " +
114                 protocolName);
115 
116             if (protocolName.equals(selectedProtocol)) {
117                 System.out.println("** Success **");
118             } else {
119                 System.out.println("** FAILURE ** ");
120                 throw new RuntimeException
121                     ("expected protocol " + selectedProtocol +
122                      " but using " + protocolName);
123             }
124 
125             InputStream in = sslSocket.getInputStream();
126             OutputStream out = sslSocket.getOutputStream();
127             in.read();
128             out.write(280);
129         } catch (SSLHandshakeException e) {
130             if (!exceptionExpected) {
131                 failTest(e, "Client got UNEXPECTED SSLHandshakeException:");
132             } else {
133                 System.out.println(
134                         "Client got expected SSLHandshakeException:");
135                 e.printStackTrace(System.out);
136                 System.out.println("** Success **");
137             }
138         } catch (SSLException ssle) {
139             // The server side may have closed the socket.
140             if (isConnectionReset(ssle)) {
141                 System.out.println("Client SSLException:");
142                 ssle.printStackTrace(System.out);
143             } else {
144                 failTest(ssle, "Client got UNEXPECTED SSLException:");
145             }
146 
147         } catch (Exception e) {
148             failTest(e, "Client got UNEXPECTED Exception:");
149         }
150     }
151 
isConnectionReset(SSLException ssle)152     private boolean isConnectionReset(SSLException ssle) {
153         Throwable cause = ssle.getCause();
154         return cause instanceof SocketException
155                 && "Connection reset".equals(cause.getMessage());
156     }
157 
failTest(Exception e, String message)158     private void failTest(Exception e, String message) {
159         System.out.println(message);
160         e.printStackTrace(System.out);
161         System.out.println("** FAILURE **");
162         throw new RuntimeException(e);
163     }
164 
main(String[] args)165     public static void main(String[] args) throws Exception {
166         Security.setProperty("jdk.tls.disabledAlgorithms", "");
167 
168         runCase(new String[] { "TLSv1" },
169                 new String[] { "TLSv1" },
170                 false, "TLSv1");
171         runCase(new String[] { "TLSv1" },
172                 new String[] { "TLSv1", "SSLv2Hello" },
173                 true, null);
174         runCase(new String[] { "TLSv1" },
175                 new String[] { "TLSv1", "SSLv3" },
176                 false, "TLSv1");
177         runCase(new String[] { "TLSv1" },
178                 new String[] { "SSLv3", "SSLv2Hello" },
179                 true, null);
180         runCase(new String[] { "TLSv1" },
181                 new String[] { "SSLv3" },
182                 true, null);
183         runCase(new String[] { "TLSv1" },
184                 new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
185                 true, null);
186 
187         runCase(new String[] { "TLSv1", "SSLv2Hello" },
188                 new String[] { "TLSv1" },
189                 false, "TLSv1");
190         runCase(new String[] { "TLSv1", "SSLv2Hello" },
191                 new String[] { "TLSv1", "SSLv2Hello" },
192                 false, "TLSv1");
193         runCase(new String[] { "TLSv1", "SSLv2Hello" },
194                 new String[] { "TLSv1", "SSLv3" },
195                 false, "TLSv1");
196         runCase(new String[] { "TLSv1", "SSLv2Hello" },
197                 new String[] { "SSLv3", "SSLv2Hello" },
198                 true, null);
199         runCase(new String[] { "TLSv1", "SSLv2Hello" },
200                 new String[] { "SSLv3" },
201                 true, null);
202         runCase(new String[] { "TLSv1", "SSLv2Hello" },
203                 new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
204                 false, "TLSv1");
205 
206         runCase(new String[] { "TLSv1", "SSLv3" },
207                 new String[] { "TLSv1" },
208                 false, "TLSv1");
209         runCase(new String[] { "TLSv1", "SSLv3" },
210                 new String[] { "TLSv1", "SSLv2Hello" },
211                 true, null);
212         runCase(new String[] { "TLSv1", "SSLv3" },
213                 new String[] { "TLSv1", "SSLv3" },
214                 false, "TLSv1");
215         runCase(new String[] { "TLSv1", "SSLv3" },
216                 new String[] { "SSLv3", "SSLv2Hello" },
217                 true, null);
218         runCase(new String[] { "TLSv1", "SSLv3" },
219                 new String[] { "SSLv3" },
220                 false, "SSLv3");
221         runCase(new String[] { "TLSv1", "SSLv3" },
222                 new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
223                 true, null);
224 
225         runCase(new String[] { "SSLv3", "SSLv2Hello" },
226                 new String[] { "TLSv1" },
227                 true, null);
228         runCase(new String[] { "SSLv3", "SSLv2Hello" },
229                 new String[] { "TLSv1", "SSLv2Hello" },
230                 true, null);
231         runCase(new String[] { "SSLv3", "SSLv2Hello" },
232                 new String[] { "TLSv1", "SSLv3" },
233                 false, "SSLv3");
234         runCase(new String[] { "SSLv3", "SSLv2Hello" },
235                 new String[] { "SSLv3", "SSLv2Hello" },
236                 false, "SSLv3");
237         runCase(new String[] { "SSLv3", "SSLv2Hello" },
238                 new String[] { "SSLv3" },
239                 false, "SSLv3");
240         runCase(new String[] { "SSLv3", "SSLv2Hello" },
241                 new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
242                 false, "SSLv3");
243 
244         runCase(new String[] { "SSLv3" },
245                 new String[] { "TLSv1" },
246                 true, null);
247         runCase(new String[] { "SSLv3" },
248                 new String[] { "TLSv1", "SSLv2Hello" },
249                 true, null);
250         runCase(new String[] { "SSLv3" },
251                 new String[] { "TLSv1", "SSLv3" },
252                 false, "SSLv3");
253         runCase(new String[] { "SSLv3" },
254                 new String[] { "SSLv3", "SSLv2Hello" },
255                 true, null);
256         runCase(new String[] { "SSLv3" },
257                 new String[] { "SSLv3" },
258                 false, "SSLv3");
259         runCase(new String[] { "SSLv3" },
260                 new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
261                 true, null);
262 
263         runCase(new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
264                 new String[] { "TLSv1" },
265                 false, "TLSv1");
266         runCase(new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
267                 new String[] { "TLSv1", "SSLv2Hello" },
268                 false, "TLSv1");
269         runCase(new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
270                 new String[] { "TLSv1", "SSLv3" },
271                 false, "TLSv1");
272         runCase(new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
273                 new String[] { "SSLv3", "SSLv2Hello" },
274                 false, "SSLv3");
275         runCase(new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
276                 new String[] { "SSLv3" },
277                 false, "SSLv3");
278         runCase(new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
279                 new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
280                 false, "TLSv1");
281     }
282 
runCase( String[] serverProtocols, String[] clientProtocols, boolean exceptionExpected, String selectedProtocol)283     private static void runCase(
284             String[] serverProtocols,
285             String[] clientProtocols,
286             boolean exceptionExpected,
287             String selectedProtocol) throws Exception {
288         new TestEnabledProtocols(
289                 serverProtocols,
290                 clientProtocols,
291                 exceptionExpected,
292                 selectedProtocol).run();
293     }
294 
showProtocols(String name, String[] protocols)295     private static void showProtocols(String name, String[] protocols) {
296         System.out.printf("Enabled protocols on the %s are: %s%n",
297                 name,
298                 Arrays.asList(protocols));
299     }
300 }
301