1 /* 2 * Copyright (c) 2016, 2018, 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 import java.io.File; 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.io.OutputStream; 28 import java.net.URI; 29 import java.net.URISyntaxException; 30 import java.security.Security; 31 import java.net.http.HttpClient; 32 import java.net.http.HttpRequest; 33 import java.net.http.HttpRequest.BodyPublishers; 34 import java.net.http.HttpResponse.BodyHandlers; 35 import javax.net.ssl.SSLContext; 36 import javax.net.ssl.SSLParameters; 37 import javax.net.ssl.SSLSession; 38 39 /* 40 * @test 41 * @bug 8150769 8157107 42 * @library server 43 * @summary Checks that SSL parameters can be set for HTTP/2 connection 44 * @modules java.base/sun.net.www.http 45 * java.net.http/jdk.internal.net.http.common 46 * java.net.http/jdk.internal.net.http.frame 47 * java.net.http/jdk.internal.net.http.hpack 48 * @run main/othervm 49 * -Djdk.internal.httpclient.debug=true 50 * -Djdk.httpclient.HttpClient.log=all 51 * TLSConnection 52 */ 53 public class TLSConnection { 54 55 private static final String KEYSTORE = System.getProperty("test.src") 56 + File.separator + "keystore.p12"; 57 private static final String PASSWORD = "password"; 58 59 private static final SSLParameters USE_DEFAULT_SSL_PARAMETERS = new SSLParameters(); 60 61 // expect highest supported version we know about expectedTLSVersion(SSLContext ctx)62 static String expectedTLSVersion(SSLContext ctx) throws Exception { 63 if (ctx == null) 64 ctx = SSLContext.getDefault(); 65 SSLParameters params = ctx.getSupportedSSLParameters(); 66 String[] protocols = params.getProtocols(); 67 for (String prot : protocols) { 68 if (prot.equals("TLSv1.3")) 69 return "TLSv1.3"; 70 } 71 return "TLSv1.2"; 72 } 73 main(String[] args)74 public static void main(String[] args) throws Exception { 75 // re-enable 3DES 76 Security.setProperty("jdk.tls.disabledAlgorithms", ""); 77 78 // enable all logging 79 System.setProperty("jdk.httpclient.HttpClient.log", "all,frames:all"); 80 81 // initialize JSSE 82 System.setProperty("javax.net.ssl.keyStore", KEYSTORE); 83 System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD); 84 System.setProperty("javax.net.ssl.trustStore", KEYSTORE); 85 System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD); 86 87 Handler handler = new Handler(); 88 89 try (Http2TestServer server = new Http2TestServer("localhost", true, 0)) { 90 server.addHandler(handler, "/"); 91 server.start(); 92 93 int port = server.getAddress().getPort(); 94 String uriString = "https://localhost:" + Integer.toString(port); 95 96 // run test cases 97 boolean success = true; 98 99 SSLParameters parameters = null; 100 success &= expectFailure( 101 "---\nTest #1: SSL parameters is null, expect NPE", 102 () -> connect(uriString, parameters), 103 NullPointerException.class); 104 105 success &= expectSuccess( 106 "---\nTest #2: default SSL parameters, " 107 + "expect successful connection", 108 () -> connect(uriString, USE_DEFAULT_SSL_PARAMETERS)); 109 success &= checkProtocol(handler.getSSLSession(), expectedTLSVersion(null)); 110 111 // set SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA cipher suite 112 // which has less priority in default cipher suite list 113 success &= expectSuccess( 114 "---\nTest #3: SSL parameters with " 115 + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA cipher suite, " 116 + "expect successful connection", 117 () -> connect(uriString, new SSLParameters( 118 new String[] { "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA" }, 119 new String[] { "TLSv1.2" }))); 120 success &= checkProtocol(handler.getSSLSession(), "TLSv1.2"); 121 success &= checkCipherSuite(handler.getSSLSession(), 122 "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"); 123 124 // set TLS_RSA_WITH_AES_128_CBC_SHA cipher suite 125 // which has less priority in default cipher suite list 126 // also set TLSv1.2 protocol 127 success &= expectSuccess( 128 "---\nTest #4: SSL parameters with " 129 + "TLS_RSA_WITH_AES_128_CBC_SHA cipher suite," 130 + " expect successful connection", 131 () -> connect(uriString, new SSLParameters( 132 new String[] { "TLS_RSA_WITH_AES_128_CBC_SHA" }, 133 new String[] { "TLSv1.2" }))); 134 success &= checkProtocol(handler.getSSLSession(), "TLSv1.2"); 135 success &= checkCipherSuite(handler.getSSLSession(), 136 "TLS_RSA_WITH_AES_128_CBC_SHA"); 137 138 if (success) { 139 System.out.println("Test passed"); 140 } else { 141 throw new RuntimeException("At least one test case failed"); 142 } 143 } 144 } 145 146 private static interface Test { 147 run()148 public void run() throws Exception; 149 } 150 151 private static class Handler implements Http2Handler { 152 153 private static final byte[] BODY = "Test response".getBytes(); 154 155 private volatile SSLSession sslSession; 156 157 @Override handle(Http2TestExchange t)158 public void handle(Http2TestExchange t) throws IOException { 159 System.out.println("Handler: received request to " 160 + t.getRequestURI()); 161 162 try (InputStream is = t.getRequestBody()) { 163 byte[] body = is.readAllBytes(); 164 System.out.println("Handler: read " + body.length 165 + " bytes of body: "); 166 System.out.println(new String(body)); 167 } 168 169 try (OutputStream os = t.getResponseBody()) { 170 t.sendResponseHeaders(200, BODY.length); 171 os.write(BODY); 172 } 173 174 sslSession = t.getSSLSession(); 175 } 176 getSSLSession()177 SSLSession getSSLSession() { 178 return sslSession; 179 } 180 } 181 connect(String uriString, SSLParameters sslParameters)182 private static void connect(String uriString, SSLParameters sslParameters) 183 throws URISyntaxException, IOException, InterruptedException 184 { 185 HttpClient.Builder builder = HttpClient.newBuilder() 186 .version(HttpClient.Version.HTTP_2); 187 if (sslParameters != USE_DEFAULT_SSL_PARAMETERS) 188 builder.sslParameters(sslParameters); 189 HttpClient client = builder.build(); 190 191 HttpRequest request = HttpRequest.newBuilder(new URI(uriString)) 192 .POST(BodyPublishers.ofString("body")) 193 .build(); 194 String body = client.send(request, BodyHandlers.ofString()).body(); 195 196 System.out.println("Response: " + body); 197 } 198 checkProtocol(SSLSession session, String protocol)199 private static boolean checkProtocol(SSLSession session, String protocol) { 200 if (session == null) { 201 System.out.println("Check protocol: no session provided"); 202 return false; 203 } 204 205 System.out.println("Check protocol: negotiated protocol: " 206 + session.getProtocol()); 207 System.out.println("Check protocol: expected protocol: " 208 + protocol); 209 if (!protocol.equals(session.getProtocol())) { 210 System.out.println("Check protocol: unexpected negotiated protocol"); 211 return false; 212 } 213 214 return true; 215 } 216 checkCipherSuite(SSLSession session, String ciphersuite)217 private static boolean checkCipherSuite(SSLSession session, String ciphersuite) { 218 if (session == null) { 219 System.out.println("Check protocol: no session provided"); 220 return false; 221 } 222 223 System.out.println("Check protocol: negotiated ciphersuite: " 224 + session.getCipherSuite()); 225 System.out.println("Check protocol: expected ciphersuite: " 226 + ciphersuite); 227 if (!ciphersuite.equals(session.getCipherSuite())) { 228 System.out.println("Check protocol: unexpected negotiated ciphersuite"); 229 return false; 230 } 231 232 return true; 233 } 234 expectSuccess(String message, Test test)235 private static boolean expectSuccess(String message, Test test) { 236 System.out.println(message); 237 try { 238 test.run(); 239 System.out.println("Passed"); 240 return true; 241 } catch (Exception e) { 242 System.out.println("Failed: unexpected exception:"); 243 e.printStackTrace(System.out); 244 return false; 245 } 246 } 247 expectFailure(String message, Test test, Class<? extends Throwable> expectedException)248 private static boolean expectFailure(String message, Test test, 249 Class<? extends Throwable> expectedException) { 250 251 System.out.println(message); 252 try { 253 test.run(); 254 System.out.println("Failed: unexpected successful connection"); 255 return false; 256 } catch (Exception e) { 257 System.out.println("Got an exception:"); 258 e.printStackTrace(System.out); 259 if (expectedException != null 260 && !expectedException.isAssignableFrom(e.getClass())) { 261 System.out.printf("Failed: expected %s, but got %s%n", 262 expectedException.getName(), 263 e.getClass().getName()); 264 return false; 265 } 266 System.out.println("Passed: expected exception"); 267 return true; 268 } 269 } 270 } 271