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