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 // 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 8145854 8153829 30 * @summary SSLContextImpl.statusResponseManager should be generated if required 31 * @library ../../../../java/security/testlibrary 32 * @build CertificateBuilder SimpleOCSPServer 33 * @run main/othervm StapleEnableProps 34 */ 35 36 import javax.net.ssl.*; 37 import javax.net.ssl.SSLEngineResult.*; 38 import java.io.*; 39 import java.math.BigInteger; 40 import java.security.*; 41 import java.nio.*; 42 import java.security.cert.X509Certificate; 43 import java.util.ArrayList; 44 import java.util.Collections; 45 import java.util.Date; 46 import java.util.HashMap; 47 import java.util.List; 48 import java.util.Map; 49 import java.util.Objects; 50 import java.util.concurrent.TimeUnit; 51 52 import sun.security.testlibrary.SimpleOCSPServer; 53 import sun.security.testlibrary.CertificateBuilder; 54 55 public class StapleEnableProps { 56 57 /* 58 * Enables logging of the SSLEngine operations. 59 */ 60 private static final boolean logging = true; 61 62 /* 63 * Enables the JSSE system debugging system property: 64 * 65 * -Djavax.net.debug=all 66 * 67 * This gives a lot of low-level information about operations underway, 68 * including specific handshake messages, and might be best examined 69 * after gaining some familiarity with this application. 70 */ 71 private static final boolean debug = false; 72 73 // These four ByteBuffer references will be used to hang onto ClientHello 74 // messages with and without the status_request[_v2] extensions. These 75 // will be used in the server-side stapling tests. There are two sets, 76 // one for 1.2 and earlier versions of the protocol and one for 1.3 77 // and later versions, since the handshake and extension sets differ 78 // between the two sets. 79 private static ByteBuffer cHello12Staple; 80 private static ByteBuffer cHello12NoStaple; 81 private static ByteBuffer cHello13Staple; 82 private static ByteBuffer cHello13NoStaple; 83 84 // The following items are used to set up the keystores. 85 private static final String passwd = "passphrase"; 86 private static final String ROOT_ALIAS = "root"; 87 private static final String INT_ALIAS = "intermediate"; 88 private static final String SSL_ALIAS = "ssl"; 89 90 // PKI components we will need for this test 91 private static KeyManagerFactory kmf; 92 private static TrustManagerFactory tmf; 93 private static KeyStore rootKeystore; // Root CA Keystore 94 private static KeyStore intKeystore; // Intermediate CA Keystore 95 private static KeyStore serverKeystore; // SSL Server Keystore 96 private static KeyStore trustStore; // SSL Client trust store 97 private static SimpleOCSPServer rootOcsp; // Root CA OCSP Responder 98 private static int rootOcspPort; // Port for root OCSP 99 private static SimpleOCSPServer intOcsp; // Intermediate CA OCSP server 100 private static int intOcspPort; // Port for intermediate OCSP 101 102 // Extra configuration parameters and constants 103 static final String[] TLS13ONLY = new String[] { "TLSv1.3" }; 104 static final String[] TLS12MAX = 105 new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }; 106 107 // A few helpful TLS definitions to make it easier 108 private static final int HELLO_EXT_STATUS_REQ = 5; 109 private static final int HELLO_EXT_STATUS_REQ_V2 = 17; 110 111 /* 112 * Main entry point for this test. 113 */ main(String args[])114 public static void main(String args[]) throws Exception { 115 if (debug) { 116 System.setProperty("javax.net.debug", "ssl:handshake,verbose"); 117 } 118 119 // Create the PKI we will use for the test and start the OCSP servers 120 createPKI(); 121 122 // Set up the KeyManagerFactory and TrustManagerFactory 123 kmf = KeyManagerFactory.getInstance("PKIX"); 124 kmf.init(serverKeystore, passwd.toCharArray()); 125 tmf = TrustManagerFactory.getInstance("PKIX"); 126 tmf.init(trustStore); 127 128 // Run the client and server property tests 129 testClientProp(); 130 testServerProp(); 131 132 } 133 testClientProp()134 private static void testClientProp() throws Exception { 135 SSLEngineResult clientResult; 136 137 // Test with the client-side enable property set to true 138 System.out.println("========================================="); 139 System.out.println("Client Test 1: " + 140 "jdk.tls.client.enableStatusRequestExtension = true"); 141 System.out.println("Version = TLS 1.2"); 142 System.out.println("========================================="); 143 144 System.setProperty("jdk.tls.client.enableStatusRequestExtension", 145 "true"); 146 SSLContext ctxStaple = SSLContext.getInstance("TLS"); 147 ctxStaple.init(null, tmf.getTrustManagers(), null); 148 SSLEngine engine = ctxStaple.createSSLEngine(); 149 engine.setUseClientMode(true); 150 engine.setEnabledProtocols(TLS12MAX); 151 SSLSession session = engine.getSession(); 152 ByteBuffer clientOut = ByteBuffer.wrap("I'm a Client".getBytes()); 153 ByteBuffer cTOs = 154 ByteBuffer.allocateDirect(session.getPacketBufferSize()); 155 156 // Create and check the ClientHello message 157 clientResult = engine.wrap(clientOut, cTOs); 158 log("client wrap: ", clientResult); 159 if (clientResult.getStatus() != SSLEngineResult.Status.OK) { 160 throw new SSLException("Client wrap got status: " + 161 clientResult.getStatus()); 162 } 163 cTOs.flip(); 164 System.out.println(dumpHexBytes(cTOs)); 165 checkClientHello(cTOs, true, true); 166 cHello12Staple = cTOs; 167 168 // Test with the property set to false 169 System.out.println("========================================="); 170 System.out.println("Client Test 2: " + 171 "jdk.tls.client.enableStatusRequestExtension = false"); 172 System.out.println("Version = TLS 1.2"); 173 System.out.println("========================================="); 174 175 System.setProperty("jdk.tls.client.enableStatusRequestExtension", 176 "false"); 177 SSLContext ctxNoStaple = SSLContext.getInstance("TLS"); 178 ctxNoStaple.init(null, tmf.getTrustManagers(), null); 179 engine = ctxNoStaple.createSSLEngine(); 180 engine.setUseClientMode(true); 181 engine.setEnabledProtocols(TLS12MAX); 182 session = engine.getSession(); 183 cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize()); 184 185 // Create and check the ClientHello message 186 clientResult = engine.wrap(clientOut, cTOs); 187 log("client wrap: ", clientResult); 188 if (clientResult.getStatus() != SSLEngineResult.Status.OK) { 189 throw new SSLException("Client wrap got status: " + 190 clientResult.getStatus()); 191 } 192 cTOs.flip(); 193 System.out.println(dumpHexBytes(cTOs)); 194 checkClientHello(cTOs, false, false); 195 cHello12NoStaple = cTOs; 196 197 // Turn the property back on to true and test using TLS 1.3 198 System.out.println("========================================="); 199 System.out.println("Client Test 3: " + 200 "jdk.tls.client.enableStatusRequestExtension = true"); 201 System.out.println("Version = TLS 1.3"); 202 System.out.println("========================================="); 203 204 System.setProperty("jdk.tls.client.enableStatusRequestExtension", 205 "true"); 206 ctxStaple = SSLContext.getInstance("TLS"); 207 ctxStaple.init(null, tmf.getTrustManagers(), null); 208 engine = ctxStaple.createSSLEngine(); 209 engine.setUseClientMode(true); 210 engine.setEnabledProtocols(TLS13ONLY); 211 session = engine.getSession(); 212 cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize()); 213 214 // Create and check the ClientHello message 215 clientResult = engine.wrap(clientOut, cTOs); 216 log("client wrap: ", clientResult); 217 if (clientResult.getStatus() != SSLEngineResult.Status.OK) { 218 throw new SSLException("Client wrap got status: " + 219 clientResult.getStatus()); 220 } 221 cTOs.flip(); 222 System.out.println(dumpHexBytes(cTOs)); 223 checkClientHello(cTOs, true, false); 224 cHello13Staple = cTOs; 225 226 // Turn the property off again and test in a TLS 1.3 handshake 227 System.out.println("========================================="); 228 System.out.println("Client Test 4: " + 229 "jdk.tls.client.enableStatusRequestExtension = false"); 230 System.out.println("Version = TLS 1.3"); 231 System.out.println("========================================="); 232 233 System.setProperty("jdk.tls.client.enableStatusRequestExtension", 234 "false"); 235 ctxNoStaple = SSLContext.getInstance("TLS"); 236 ctxNoStaple.init(null, tmf.getTrustManagers(), null); 237 engine = ctxNoStaple.createSSLEngine(); 238 engine.setUseClientMode(true); 239 engine.setEnabledProtocols(TLS13ONLY); 240 session = engine.getSession(); 241 cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize()); 242 243 // Create and check the ClientHello message 244 clientResult = engine.wrap(clientOut, cTOs); 245 log("client wrap: ", clientResult); 246 if (clientResult.getStatus() != SSLEngineResult.Status.OK) { 247 throw new SSLException("Client wrap got status: " + 248 clientResult.getStatus()); 249 } 250 cTOs.flip(); 251 System.out.println(dumpHexBytes(cTOs)); 252 checkClientHello(cTOs, false, false); 253 cHello13NoStaple = cTOs; 254 255 // A TLS 1.3-capable hello, one that is not strictly limited to 256 // the TLS 1.3 protocol should have both status_request and 257 // status_request_v2 258 System.out.println("========================================="); 259 System.out.println("Client Test 5: " + 260 "jdk.tls.client.enableStatusRequestExtension = true"); 261 System.out.println("Version = TLS 1.3 capable [default hello]"); 262 System.out.println("========================================="); 263 264 System.setProperty("jdk.tls.client.enableStatusRequestExtension", 265 "true"); 266 ctxStaple = SSLContext.getInstance("TLS"); 267 ctxStaple.init(null, tmf.getTrustManagers(), null); 268 engine = ctxStaple.createSSLEngine(); 269 engine.setUseClientMode(true); 270 // Note: Unlike the other tests, there is no explicit protocol setting 271 session = engine.getSession(); 272 cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize()); 273 274 // Create and check the ClientHello message 275 clientResult = engine.wrap(clientOut, cTOs); 276 log("client wrap: ", clientResult); 277 if (clientResult.getStatus() != SSLEngineResult.Status.OK) { 278 throw new SSLException("Client wrap got status: " + 279 clientResult.getStatus()); 280 } 281 cTOs.flip(); 282 System.out.println(dumpHexBytes(cTOs)); 283 checkClientHello(cTOs, true, true); 284 } 285 testServerProp()286 private static void testServerProp() throws Exception { 287 SSLEngineResult serverResult; 288 HandshakeStatus hsStat; 289 290 // Test with the server-side enable property set to true 291 System.out.println("========================================="); 292 System.out.println("Server Test 1: " + 293 "jdk.tls.server.enableStatusRequestExtension = true"); 294 System.out.println("Version = TLS 1.2"); 295 System.out.println("========================================="); 296 297 System.setProperty("jdk.tls.server.enableStatusRequestExtension", 298 "true"); 299 SSLContext ctxStaple = SSLContext.getInstance("TLS"); 300 ctxStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 301 SSLEngine engine = ctxStaple.createSSLEngine(); 302 engine.setUseClientMode(false); 303 engine.setEnabledProtocols(TLS12MAX); 304 SSLSession session = engine.getSession(); 305 ByteBuffer serverOut = ByteBuffer.wrap("I'm a Server".getBytes()); 306 ByteBuffer serverIn = 307 ByteBuffer.allocate(session.getApplicationBufferSize() + 50); 308 ByteBuffer sTOc = 309 ByteBuffer.allocateDirect(session.getPacketBufferSize()); 310 311 // Consume the client hello 312 serverResult = engine.unwrap(cHello12Staple, serverIn); 313 log("server unwrap: ", serverResult); 314 if (serverResult.getStatus() != SSLEngineResult.Status.OK) { 315 throw new SSLException("Server unwrap got status: " + 316 serverResult.getStatus()); 317 } else if (serverResult.getHandshakeStatus() != 318 SSLEngineResult.HandshakeStatus.NEED_TASK) { 319 throw new SSLException("Server unwrap expected NEED_TASK, got: " + 320 serverResult.getHandshakeStatus()); 321 } 322 runDelegatedTasks(serverResult, engine); 323 if (engine.getHandshakeStatus() != 324 SSLEngineResult.HandshakeStatus.NEED_WRAP) { 325 throw new SSLException("Expected NEED_WRAP, got: " + 326 engine.getHandshakeStatus()); 327 } 328 329 // Generate a TLS record with the ServerHello 330 serverResult = engine.wrap(serverOut, sTOc); 331 log("client wrap: ", serverResult); 332 if (serverResult.getStatus() != SSLEngineResult.Status.OK) { 333 throw new SSLException("Client wrap got status: " + 334 serverResult.getStatus()); 335 } 336 sTOc.flip(); 337 System.out.println(dumpHexBytes(sTOc)); 338 checkServerHello(sTOc, false, true); 339 340 // Flip the client hello so we can reuse it in the next test. 341 cHello12Staple.flip(); 342 343 // Test with the server-side enable property set to false 344 System.out.println("========================================="); 345 System.out.println("Server Test 2: " + 346 "jdk.tls.server.enableStatusRequestExtension = false"); 347 System.out.println("Version = TLS 1.2"); 348 System.out.println("========================================="); 349 350 System.setProperty("jdk.tls.server.enableStatusRequestExtension", 351 "false"); 352 SSLContext ctxNoStaple = SSLContext.getInstance("TLS"); 353 ctxNoStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 354 engine = ctxNoStaple.createSSLEngine(); 355 engine.setUseClientMode(false); 356 engine.setEnabledProtocols(TLS12MAX); 357 session = engine.getSession(); 358 serverIn = ByteBuffer.allocate(session.getApplicationBufferSize() + 50); 359 sTOc = ByteBuffer.allocateDirect(session.getPacketBufferSize()); 360 361 // Consume the client hello 362 serverResult = engine.unwrap(cHello12Staple, serverIn); 363 log("server unwrap: ", serverResult); 364 if (serverResult.getStatus() != SSLEngineResult.Status.OK) { 365 throw new SSLException("Server unwrap got status: " + 366 serverResult.getStatus()); 367 } else if (serverResult.getHandshakeStatus() != 368 SSLEngineResult.HandshakeStatus.NEED_TASK) { 369 throw new SSLException("Server unwrap expected NEED_TASK, got: " + 370 serverResult.getHandshakeStatus()); 371 } 372 runDelegatedTasks(serverResult, engine); 373 if (engine.getHandshakeStatus() != 374 SSLEngineResult.HandshakeStatus.NEED_WRAP) { 375 throw new SSLException("Expected NEED_WRAP, got: " + 376 engine.getHandshakeStatus()); 377 } 378 379 // Generate a TLS record with the ServerHello 380 serverResult = engine.wrap(serverOut, sTOc); 381 log("client wrap: ", serverResult); 382 if (serverResult.getStatus() != SSLEngineResult.Status.OK) { 383 throw new SSLException("Client wrap got status: " + 384 serverResult.getStatus()); 385 } 386 sTOc.flip(); 387 System.out.println(dumpHexBytes(sTOc)); 388 checkServerHello(sTOc, false, false); 389 } 390 391 /* 392 * If the result indicates that we have outstanding tasks to do, 393 * go ahead and run them in this thread. 394 */ runDelegatedTasks(SSLEngineResult result, SSLEngine engine)395 private static void runDelegatedTasks(SSLEngineResult result, 396 SSLEngine engine) throws Exception { 397 398 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { 399 Runnable runnable; 400 while ((runnable = engine.getDelegatedTask()) != null) { 401 log("\trunning delegated task..."); 402 runnable.run(); 403 } 404 HandshakeStatus hsStatus = engine.getHandshakeStatus(); 405 if (hsStatus == HandshakeStatus.NEED_TASK) { 406 throw new Exception( 407 "handshake shouldn't need additional tasks"); 408 } 409 log("\tnew HandshakeStatus: " + hsStatus); 410 } 411 } 412 log(String str, SSLEngineResult result)413 private static void log(String str, SSLEngineResult result) { 414 if (!logging) { 415 return; 416 } 417 HandshakeStatus hsStatus = result.getHandshakeStatus(); 418 log(str + 419 result.getStatus() + "/" + hsStatus + ", " + 420 result.bytesConsumed() + "/" + result.bytesProduced() + 421 " bytes"); 422 if (hsStatus == HandshakeStatus.FINISHED) { 423 log("\t...ready for application data"); 424 } 425 } 426 log(String str)427 private static void log(String str) { 428 if (logging) { 429 System.out.println(str); 430 } 431 } 432 433 /** 434 * Dump a ByteBuffer as a hexdump to stdout. The dumping routine will 435 * start at the current position of the buffer and run to its limit. 436 * After completing the dump, the position will be returned to its 437 * starting point. 438 * 439 * @param data the ByteBuffer to dump to stdout. 440 * 441 * @return the hexdump of the byte array. 442 */ dumpHexBytes(ByteBuffer data)443 private static String dumpHexBytes(ByteBuffer data) { 444 StringBuilder sb = new StringBuilder(); 445 if (data != null) { 446 int i = 0; 447 data.mark(); 448 while (data.hasRemaining()) { 449 if (i % 16 == 0 && i != 0) { 450 sb.append("\n"); 451 } 452 sb.append(String.format("%02X ", data.get())); 453 i++; 454 } 455 data.reset(); 456 } 457 458 return sb.toString(); 459 } 460 461 /** 462 * Tests the ClientHello for the presence (or not) of the status_request 463 * and status_request_v2 hello extensions. It is assumed that the provided 464 * ByteBuffer has its position set at the first byte of the TLS record 465 * containing the ClientHello and contains the entire hello message. Upon 466 * successful completion of this method the ByteBuffer will have its 467 * position reset to the initial offset in the buffer. If an exception is 468 * thrown the position at the time of the exception will be preserved. 469 * 470 * @param data the ByteBuffer containing the ClientHello bytes 471 * @param statReqPresent true if the status_request hello extension should 472 * be present. 473 * @param statReqV2Present true if the status_request_v2 hello extension 474 * should be present. 475 * 476 * @throws SSLException if the presence or lack of either the 477 * status_request or status_request_v2 extensions is inconsistent with 478 * the expected settings in the statReqPresent or statReqV2Present 479 * parameters. 480 */ checkClientHello(ByteBuffer data, boolean statReqPresent, boolean statReqV2Present)481 private static void checkClientHello(ByteBuffer data, 482 boolean statReqPresent, boolean statReqV2Present) 483 throws SSLException { 484 boolean hasV1 = false; 485 boolean hasV2 = false; 486 Objects.requireNonNull(data); 487 data.mark(); 488 489 // Process the TLS record header 490 int type = Byte.toUnsignedInt(data.get()); 491 int ver_major = Byte.toUnsignedInt(data.get()); 492 int ver_minor = Byte.toUnsignedInt(data.get()); 493 int recLen = Short.toUnsignedInt(data.getShort()); 494 495 // Simple sanity checks 496 if (type != 22) { 497 throw new SSLException("Not a handshake: Type = " + type); 498 } else if (recLen > data.remaining()) { 499 throw new SSLException("Incomplete record in buffer: " + 500 "Record length = " + recLen + ", Remaining = " + 501 data.remaining()); 502 } 503 504 // Grab the handshake message header. 505 int msgHdr = data.getInt(); 506 int msgType = (msgHdr >> 24) & 0x000000FF; 507 int msgLen = msgHdr & 0x00FFFFFF; 508 509 // More simple sanity checks 510 if (msgType != 1) { 511 throw new SSLException("Not a ClientHello: Type = " + msgType); 512 } 513 514 // Skip over the protocol version and client random 515 data.position(data.position() + 34); 516 517 // Jump past the session ID (if there is one) 518 int sessLen = Byte.toUnsignedInt(data.get()); 519 if (sessLen != 0) { 520 data.position(data.position() + sessLen); 521 } 522 523 // Jump past the cipher suites 524 int csLen = Short.toUnsignedInt(data.getShort()); 525 if (csLen != 0) { 526 data.position(data.position() + csLen); 527 } 528 529 // ...and the compression 530 int compLen = Byte.toUnsignedInt(data.get()); 531 if (compLen != 0) { 532 data.position(data.position() + compLen); 533 } 534 535 // Now for the fun part. Go through the extensions and look 536 // for the two status request exts. 537 int extsLen = Short.toUnsignedInt(data.getShort()); 538 while (data.hasRemaining()) { 539 int extType = Short.toUnsignedInt(data.getShort()); 540 int extLen = Short.toUnsignedInt(data.getShort()); 541 hasV1 |= (extType == HELLO_EXT_STATUS_REQ); 542 hasV2 |= (extType == HELLO_EXT_STATUS_REQ_V2); 543 data.position(data.position() + extLen); 544 } 545 546 if (hasV1 != statReqPresent) { 547 throw new SSLException("The status_request extension is " + 548 "inconsistent with the expected result: expected = " + 549 statReqPresent + ", actual = " + hasV1); 550 } else if (hasV2 != statReqV2Present) { 551 throw new SSLException("The status_request_v2 extension is " + 552 "inconsistent with the expected result: expected = " + 553 statReqV2Present + ", actual = " + hasV2); 554 } 555 556 // We should be at the end of the ClientHello 557 data.reset(); 558 } 559 560 /** 561 * Tests the ServerHello for the presence (or not) of the status_request 562 * or status_request_v2 hello extension. It is assumed that the provided 563 * ByteBuffer has its position set at the first byte of the TLS record 564 * containing the ServerHello and contains the entire hello message. Upon 565 * successful completion of this method the ByteBuffer will have its 566 * position reset to the initial offset in the buffer. If an exception is 567 * thrown the position at the time of the exception will be preserved. 568 * 569 * @param statReqPresent true if the status_request hello extension should 570 * be present. 571 * @param statReqV2Present true if the status_request_v2 hello extension 572 * should be present. 573 * 574 * @throws SSLException if the presence or lack of either the 575 * status_request or status_request_v2 extensions is inconsistent with 576 * the expected settings in the statReqPresent or statReqV2Present 577 * parameters. 578 */ checkServerHello(ByteBuffer data, boolean statReqPresent, boolean statReqV2Present)579 private static void checkServerHello(ByteBuffer data, 580 boolean statReqPresent, boolean statReqV2Present) 581 throws SSLException { 582 boolean hasV1 = false; 583 boolean hasV2 = false; 584 Objects.requireNonNull(data); 585 int startPos = data.position(); 586 data.mark(); 587 588 // Process the TLS record header 589 int type = Byte.toUnsignedInt(data.get()); 590 int ver_major = Byte.toUnsignedInt(data.get()); 591 int ver_minor = Byte.toUnsignedInt(data.get()); 592 int recLen = Short.toUnsignedInt(data.getShort()); 593 594 // Simple sanity checks 595 if (type != 22) { 596 throw new SSLException("Not a handshake: Type = " + type); 597 } else if (recLen > data.remaining()) { 598 throw new SSLException("Incomplete record in buffer: " + 599 "Record length = " + recLen + ", Remaining = " + 600 data.remaining()); 601 } 602 603 // Grab the handshake message header. 604 int msgHdr = data.getInt(); 605 int msgType = (msgHdr >> 24) & 0x000000FF; 606 int msgLen = msgHdr & 0x00FFFFFF; 607 608 // More simple sanity checks 609 if (msgType != 2) { 610 throw new SSLException("Not a ServerHello: Type = " + msgType); 611 } 612 613 // Skip over the protocol version and server random 614 data.position(data.position() + 34); 615 616 // Jump past the session ID 617 int sessLen = Byte.toUnsignedInt(data.get()); 618 if (sessLen != 0) { 619 data.position(data.position() + sessLen); 620 } 621 622 // Skip the cipher suite and compression method 623 data.position(data.position() + 3); 624 625 // Go through the extensions and look for the request extension 626 // expected by the caller. 627 int extsLen = Short.toUnsignedInt(data.getShort()); 628 while (data.position() < recLen + startPos + 5) { 629 int extType = Short.toUnsignedInt(data.getShort()); 630 int extLen = Short.toUnsignedInt(data.getShort()); 631 hasV1 |= (extType == HELLO_EXT_STATUS_REQ); 632 hasV2 |= (extType == HELLO_EXT_STATUS_REQ_V2); 633 data.position(data.position() + extLen); 634 } 635 636 if (hasV1 != statReqPresent) { 637 throw new SSLException("The status_request extension is " + 638 "inconsistent with the expected result: expected = " + 639 statReqPresent + ", actual = " + hasV1); 640 } else if (hasV2 != statReqV2Present) { 641 throw new SSLException("The status_request_v2 extension is " + 642 "inconsistent with the expected result: expected = " + 643 statReqV2Present + ", actual = " + hasV2); 644 } 645 646 // Reset the position to the initial spot at the start of this method. 647 data.reset(); 648 } 649 650 /** 651 * Creates the PKI components necessary for this test, including 652 * Root CA, Intermediate CA and SSL server certificates, the keystores 653 * for each entity, a client trust store, and starts the OCSP responders. 654 */ createPKI()655 private static void createPKI() throws Exception { 656 CertificateBuilder cbld = new CertificateBuilder(); 657 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 658 keyGen.initialize(2048); 659 KeyStore.Builder keyStoreBuilder = 660 KeyStore.Builder.newInstance("PKCS12", null, 661 new KeyStore.PasswordProtection(passwd.toCharArray())); 662 663 // Generate Root, IntCA, EE keys 664 KeyPair rootCaKP = keyGen.genKeyPair(); 665 log("Generated Root CA KeyPair"); 666 KeyPair intCaKP = keyGen.genKeyPair(); 667 log("Generated Intermediate CA KeyPair"); 668 KeyPair sslKP = keyGen.genKeyPair(); 669 log("Generated SSL Cert KeyPair"); 670 671 // Set up the Root CA Cert 672 cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany"); 673 cbld.setPublicKey(rootCaKP.getPublic()); 674 cbld.setSerialNumber(new BigInteger("1")); 675 // Make a 3 year validity starting from 60 days ago 676 long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); 677 long end = start + TimeUnit.DAYS.toMillis(1085); 678 cbld.setValidity(new Date(start), new Date(end)); 679 addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic()); 680 addCommonCAExts(cbld); 681 // Make our Root CA Cert! 682 X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(), 683 "SHA256withRSA"); 684 log("Root CA Created:\n" + certInfo(rootCert)); 685 686 // Now build a keystore and add the keys and cert 687 rootKeystore = keyStoreBuilder.getKeyStore(); 688 java.security.cert.Certificate[] rootChain = {rootCert}; 689 rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(), 690 passwd.toCharArray(), rootChain); 691 692 // Now fire up the OCSP responder 693 rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null); 694 rootOcsp.enableLog(logging); 695 rootOcsp.setNextUpdateInterval(3600); 696 rootOcsp.start(); 697 698 // Wait 5 seconds for server ready 699 for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) { 700 Thread.sleep(50); 701 } 702 if (!rootOcsp.isServerReady()) { 703 throw new RuntimeException("Server not ready yet"); 704 } 705 706 rootOcspPort = rootOcsp.getPort(); 707 String rootRespURI = "http://localhost:" + rootOcspPort; 708 log("Root OCSP Responder URI is " + rootRespURI); 709 710 // Now that we have the root keystore and OCSP responder we can 711 // create our intermediate CA. 712 cbld.reset(); 713 cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany"); 714 cbld.setPublicKey(intCaKP.getPublic()); 715 cbld.setSerialNumber(new BigInteger("100")); 716 // Make a 2 year validity starting from 30 days ago 717 start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30); 718 end = start + TimeUnit.DAYS.toMillis(730); 719 cbld.setValidity(new Date(start), new Date(end)); 720 addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic()); 721 addCommonCAExts(cbld); 722 cbld.addAIAExt(Collections.singletonList(rootRespURI)); 723 // Make our Intermediate CA Cert! 724 X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(), 725 "SHA256withRSA"); 726 log("Intermediate CA Created:\n" + certInfo(intCaCert)); 727 728 // Provide intermediate CA cert revocation info to the Root CA 729 // OCSP responder. 730 Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo = 731 new HashMap<>(); 732 revInfo.put(intCaCert.getSerialNumber(), 733 new SimpleOCSPServer.CertStatusInfo( 734 SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); 735 rootOcsp.updateStatusDb(revInfo); 736 737 // Now build a keystore and add the keys, chain and root cert as a TA 738 intKeystore = keyStoreBuilder.getKeyStore(); 739 java.security.cert.Certificate[] intChain = {intCaCert, rootCert}; 740 intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(), 741 passwd.toCharArray(), intChain); 742 intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert); 743 744 // Now fire up the Intermediate CA OCSP responder 745 intOcsp = new SimpleOCSPServer(intKeystore, passwd, 746 INT_ALIAS, null); 747 intOcsp.enableLog(logging); 748 intOcsp.setNextUpdateInterval(3600); 749 intOcsp.start(); 750 751 // Wait 5 seconds for server ready 752 for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) { 753 Thread.sleep(50); 754 } 755 if (!intOcsp.isServerReady()) { 756 throw new RuntimeException("Server not ready yet"); 757 } 758 759 intOcspPort = intOcsp.getPort(); 760 String intCaRespURI = "http://localhost:" + intOcspPort; 761 log("Intermediate CA OCSP Responder URI is " + intCaRespURI); 762 763 // Last but not least, let's make our SSLCert and add it to its own 764 // Keystore 765 cbld.reset(); 766 cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany"); 767 cbld.setPublicKey(sslKP.getPublic()); 768 cbld.setSerialNumber(new BigInteger("4096")); 769 // Make a 1 year validity starting from 7 days ago 770 start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7); 771 end = start + TimeUnit.DAYS.toMillis(365); 772 cbld.setValidity(new Date(start), new Date(end)); 773 774 // Add extensions 775 addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic()); 776 boolean[] kuBits = {true, false, true, false, false, false, 777 false, false, false}; 778 cbld.addKeyUsageExt(kuBits); 779 List<String> ekuOids = new ArrayList<>(); 780 ekuOids.add("1.3.6.1.5.5.7.3.1"); 781 ekuOids.add("1.3.6.1.5.5.7.3.2"); 782 cbld.addExtendedKeyUsageExt(ekuOids); 783 cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost")); 784 cbld.addAIAExt(Collections.singletonList(intCaRespURI)); 785 // Make our SSL Server Cert! 786 X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(), 787 "SHA256withRSA"); 788 log("SSL Certificate Created:\n" + certInfo(sslCert)); 789 790 // Provide SSL server cert revocation info to the Intermeidate CA 791 // OCSP responder. 792 revInfo = new HashMap<>(); 793 revInfo.put(sslCert.getSerialNumber(), 794 new SimpleOCSPServer.CertStatusInfo( 795 SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD)); 796 intOcsp.updateStatusDb(revInfo); 797 798 // Now build a keystore and add the keys, chain and root cert as a TA 799 serverKeystore = keyStoreBuilder.getKeyStore(); 800 java.security.cert.Certificate[] sslChain = {sslCert, intCaCert, rootCert}; 801 serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(), 802 passwd.toCharArray(), sslChain); 803 serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert); 804 805 // And finally a Trust Store for the client 806 trustStore = keyStoreBuilder.getKeyStore(); 807 trustStore.setCertificateEntry(ROOT_ALIAS, rootCert); 808 } 809 addCommonExts(CertificateBuilder cbld, PublicKey subjKey, PublicKey authKey)810 private static void addCommonExts(CertificateBuilder cbld, 811 PublicKey subjKey, PublicKey authKey) throws IOException { 812 cbld.addSubjectKeyIdExt(subjKey); 813 cbld.addAuthorityKeyIdExt(authKey); 814 } 815 addCommonCAExts(CertificateBuilder cbld)816 private static void addCommonCAExts(CertificateBuilder cbld) 817 throws IOException { 818 cbld.addBasicConstraintsExt(true, true, -1); 819 // Set key usage bits for digitalSignature, keyCertSign and cRLSign 820 boolean[] kuBitSettings = {true, false, false, false, false, true, 821 true, false, false}; 822 cbld.addKeyUsageExt(kuBitSettings); 823 } 824 825 /** 826 * Helper routine that dumps only a few cert fields rather than 827 * the whole toString() output. 828 * 829 * @param cert an X509Certificate to be displayed 830 * 831 * @return the String output of the issuer, subject and 832 * serial number 833 */ certInfo(X509Certificate cert)834 private static String certInfo(X509Certificate cert) { 835 StringBuilder sb = new StringBuilder(); 836 sb.append("Issuer: ").append(cert.getIssuerX500Principal()). 837 append("\n"); 838 sb.append("Subject: ").append(cert.getSubjectX500Principal()). 839 append("\n"); 840 sb.append("Serial: ").append(cert.getSerialNumber()).append("\n"); 841 return sb.toString(); 842 } 843 } 844