1 /* 2 * Copyright (c) 2015, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.ssl; 27 28 import java.io.IOException; 29 import java.nio.ByteBuffer; 30 import java.security.AlgorithmConstraints; 31 import java.security.GeneralSecurityException; 32 import java.text.MessageFormat; 33 import java.util.Arrays; 34 import java.util.LinkedList; 35 import java.util.List; 36 import java.util.Locale; 37 import java.util.Map; 38 import java.util.Optional; 39 import javax.crypto.SecretKey; 40 import javax.crypto.spec.IvParameterSpec; 41 import javax.net.ssl.SSLException; 42 import javax.net.ssl.SSLHandshakeException; 43 import sun.security.ssl.CipherSuite.KeyExchange; 44 import sun.security.ssl.ClientHello.ClientHelloMessage; 45 import sun.security.ssl.SSLCipher.SSLReadCipher; 46 import sun.security.ssl.SSLCipher.SSLWriteCipher; 47 import sun.security.ssl.SSLHandshake.HandshakeMessage; 48 import sun.security.ssl.SupportedVersionsExtension.SHSupportedVersionsSpec; 49 50 /** 51 * Pack of the ServertHello/HelloRetryRequest handshake message. 52 */ 53 final class ServerHello { 54 static final SSLConsumer handshakeConsumer = 55 new ServerHelloConsumer(); 56 static final HandshakeProducer t12HandshakeProducer = 57 new T12ServerHelloProducer(); 58 static final HandshakeProducer t13HandshakeProducer = 59 new T13ServerHelloProducer(); 60 static final HandshakeProducer hrrHandshakeProducer = 61 new T13HelloRetryRequestProducer(); 62 63 static final HandshakeProducer hrrReproducer = 64 new T13HelloRetryRequestReproducer(); 65 66 private static final HandshakeConsumer t12HandshakeConsumer = 67 new T12ServerHelloConsumer(); 68 private static final HandshakeConsumer t13HandshakeConsumer = 69 new T13ServerHelloConsumer(); 70 71 private static final HandshakeConsumer d12HandshakeConsumer = 72 new T12ServerHelloConsumer(); 73 private static final HandshakeConsumer d13HandshakeConsumer = 74 new T13ServerHelloConsumer(); 75 76 private static final HandshakeConsumer t13HrrHandshakeConsumer = 77 new T13HelloRetryRequestConsumer(); 78 private static final HandshakeConsumer d13HrrHandshakeConsumer = 79 new T13HelloRetryRequestConsumer(); 80 81 /** 82 * The ServertHello handshake message. 83 */ 84 static final class ServerHelloMessage extends HandshakeMessage { 85 final ProtocolVersion serverVersion; // TLS 1.3 legacy 86 final RandomCookie serverRandom; 87 final SessionId sessionId; // TLS 1.3 legacy 88 final CipherSuite cipherSuite; 89 final byte compressionMethod; // TLS 1.3 legacy 90 final SSLExtensions extensions; 91 92 // The HelloRetryRequest producer needs to use the ClientHello message 93 // for cookie generation. Please don't use this field for other 94 // purpose unless it is really necessary. 95 final ClientHelloMessage clientHello; 96 97 // Reserved for HelloRetryRequest consumer. Please don't use this 98 // field for other purpose unless it is really necessary. 99 final ByteBuffer handshakeRecord; 100 101 ServerHelloMessage(HandshakeContext context, 102 ProtocolVersion serverVersion, SessionId sessionId, 103 CipherSuite cipherSuite, RandomCookie serverRandom, 104 ClientHelloMessage clientHello) { 105 super(context); 106 107 this.serverVersion = serverVersion; 108 this.serverRandom = serverRandom; 109 this.sessionId = sessionId; 110 this.cipherSuite = cipherSuite; 111 this.compressionMethod = 0x00; // Don't support compression. 112 this.extensions = new SSLExtensions(this); 113 114 // Reserve the ClientHello message for cookie generation. 115 this.clientHello = clientHello; 116 117 // The handshakeRecord field is used for HelloRetryRequest consumer 118 // only. It's fine to set it to null for gnerating side of the 119 // ServerHello/HelloRetryRequest message. 120 this.handshakeRecord = null; 121 } 122 123 ServerHelloMessage(HandshakeContext context, 124 ByteBuffer m) throws IOException { 125 super(context); 126 127 // Reserve for HelloRetryRequest consumer if needed. 128 this.handshakeRecord = m.duplicate(); 129 130 byte major = m.get(); 131 byte minor = m.get(); 132 this.serverVersion = ProtocolVersion.valueOf(major, minor); 133 if (this.serverVersion == null) { 134 // The client should only request for known protovol versions. 135 context.conContext.fatal(Alert.PROTOCOL_VERSION, 136 "Unsupported protocol version: " + 137 ProtocolVersion.nameOf(major, minor)); 138 } 139 140 this.serverRandom = new RandomCookie(m); 141 this.sessionId = new SessionId(Record.getBytes8(m)); 142 sessionId.checkLength(serverVersion.id); 143 144 145 int cipherSuiteId = Record.getInt16(m); 146 this.cipherSuite = CipherSuite.valueOf(cipherSuiteId); 147 if (cipherSuite == null || !context.isNegotiable(cipherSuite)) { 148 context.conContext.fatal(Alert.ILLEGAL_PARAMETER, 149 "Server selected improper ciphersuite " + 150 CipherSuite.nameOf(cipherSuiteId)); 151 } 152 153 this.compressionMethod = m.get(); 154 if (compressionMethod != 0) { 155 context.conContext.fatal(Alert.ILLEGAL_PARAMETER, 156 "compression type not supported, " + compressionMethod); 157 } 158 159 SSLExtension[] supportedExtensions; 160 if (serverRandom.isHelloRetryRequest()) { 161 supportedExtensions = context.sslConfig.getEnabledExtensions( 162 SSLHandshake.HELLO_RETRY_REQUEST); 163 } else { 164 supportedExtensions = context.sslConfig.getEnabledExtensions( 165 SSLHandshake.SERVER_HELLO); 166 } 167 168 if (m.hasRemaining()) { 169 this.extensions = 170 new SSLExtensions(this, m, supportedExtensions); 171 } else { 172 this.extensions = new SSLExtensions(this); 173 } 174 175 // The clientHello field is used for HelloRetryRequest producer 176 // only. It's fine to set it to null for receiving side of 177 // ServerHello/HelloRetryRequest message. 178 this.clientHello = null; // not used, let it be null; 179 } 180 181 @Override 182 public SSLHandshake handshakeType() { 183 return serverRandom.isHelloRetryRequest() ? 184 SSLHandshake.HELLO_RETRY_REQUEST : SSLHandshake.SERVER_HELLO; 185 } 186 187 @Override 188 public int messageLength() { 189 // almost fixed header size, except session ID and extensions: 190 // major + minor = 2 191 // random = 32 192 // session ID len field = 1 193 // cipher suite = 2 194 // compression = 1 195 // extensions: if present, 2 + length of extensions 196 // In TLS 1.3, use of certain extensions is mandatory. 197 return 38 + sessionId.length() + extensions.length(); 198 } 199 200 @Override 201 public void send(HandshakeOutStream hos) throws IOException { 202 hos.putInt8(serverVersion.major); 203 hos.putInt8(serverVersion.minor); 204 hos.write(serverRandom.randomBytes); 205 hos.putBytes8(sessionId.getId()); 206 hos.putInt8((cipherSuite.id >> 8) & 0xFF); 207 hos.putInt8(cipherSuite.id & 0xff); 208 hos.putInt8(compressionMethod); 209 210 extensions.send(hos); // In TLS 1.3, use of certain 211 // extensions is mandatory. 212 } 213 214 @Override 215 public String toString() { 216 MessageFormat messageFormat = new MessageFormat( 217 "\"{0}\": '{'\n" + 218 " \"server version\" : \"{1}\",\n" + 219 " \"random\" : \"{2}\",\n" + 220 " \"session id\" : \"{3}\",\n" + 221 " \"cipher suite\" : \"{4}\",\n" + 222 " \"compression methods\" : \"{5}\",\n" + 223 " \"extensions\" : [\n" + 224 "{6}\n" + 225 " ]\n" + 226 "'}'", 227 Locale.ENGLISH); 228 Object[] messageFields = { 229 serverRandom.isHelloRetryRequest() ? 230 "HelloRetryRequest" : "ServerHello", 231 serverVersion.name, 232 Utilities.toHexString(serverRandom.randomBytes), 233 sessionId.toString(), 234 cipherSuite.name + "(" + 235 Utilities.byte16HexString(cipherSuite.id) + ")", 236 Utilities.toHexString(compressionMethod), 237 Utilities.indent(extensions.toString(), " ") 238 }; 239 240 return messageFormat.format(messageFields); 241 } 242 } 243 244 /** 245 * The "ServerHello" handshake message producer. 246 */ 247 private static final class T12ServerHelloProducer 248 implements HandshakeProducer { 249 250 // Prevent instantiation of this class. 251 private T12ServerHelloProducer() { 252 // blank 253 } 254 255 @Override 256 public byte[] produce(ConnectionContext context, 257 HandshakeMessage message) throws IOException { 258 // The producing happens in server side only. 259 ServerHandshakeContext shc = (ServerHandshakeContext)context; 260 ClientHelloMessage clientHello = (ClientHelloMessage)message; 261 262 // If client hasn't specified a session we can resume, start a 263 // new one and choose its cipher suite and compression options, 264 // unless new session creation is disabled for this connection! 265 if (!shc.isResumption || shc.resumingSession == null) { 266 if (!shc.sslConfig.enableSessionCreation) { 267 throw new SSLException( 268 "Not resumption, and no new session is allowed"); 269 } 270 271 if (shc.localSupportedSignAlgs == null) { 272 shc.localSupportedSignAlgs = 273 SignatureScheme.getSupportedAlgorithms( 274 shc.algorithmConstraints, shc.activeProtocols); 275 } 276 277 SSLSessionImpl session = 278 new SSLSessionImpl(shc, CipherSuite.C_NULL); 279 session.setMaximumPacketSize(shc.sslConfig.maximumPacketSize); 280 shc.handshakeSession = session; 281 282 // consider the handshake extension impact 283 SSLExtension[] enabledExtensions = 284 shc.sslConfig.getEnabledExtensions( 285 SSLHandshake.CLIENT_HELLO, shc.negotiatedProtocol); 286 clientHello.extensions.consumeOnTrade(shc, enabledExtensions); 287 288 // negotiate the cipher suite. 289 KeyExchangeProperties credentials = 290 chooseCipherSuite(shc, clientHello); 291 if (credentials == null) { 292 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 293 "no cipher suites in common"); 294 295 return null; // make the compiler happy 296 } 297 shc.negotiatedCipherSuite = credentials.cipherSuite; 298 shc.handshakeKeyExchange = credentials.keyExchange; 299 shc.handshakeSession.setSuite(credentials.cipherSuite); 300 shc.handshakePossessions.addAll( 301 Arrays.asList(credentials.possessions)); 302 shc.handshakeHash.determine( 303 shc.negotiatedProtocol, shc.negotiatedCipherSuite); 304 305 // Check the incoming OCSP stapling extensions and attempt 306 // to get responses. If the resulting stapleParams is non 307 // null, it implies that stapling is enabled on the server side. 308 shc.stapleParams = StatusResponseManager.processStapling(shc); 309 shc.staplingActive = (shc.stapleParams != null); 310 311 // update the responders 312 SSLKeyExchange ke = credentials.keyExchange; 313 if (ke != null) { 314 for (Map.Entry<Byte, HandshakeProducer> me : 315 ke.getHandshakeProducers(shc)) { 316 shc.handshakeProducers.put( 317 me.getKey(), me.getValue()); 318 } 319 } 320 321 if ((ke != null) && 322 (shc.sslConfig.clientAuthType != 323 ClientAuthType.CLIENT_AUTH_NONE) && 324 !shc.negotiatedCipherSuite.isAnonymous()) { 325 for (SSLHandshake hs : 326 ke.getRelatedHandshakers(shc)) { 327 if (hs == SSLHandshake.CERTIFICATE) { 328 shc.handshakeProducers.put( 329 SSLHandshake.CERTIFICATE_REQUEST.id, 330 SSLHandshake.CERTIFICATE_REQUEST); 331 break; 332 } 333 } 334 } 335 shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO_DONE.id, 336 SSLHandshake.SERVER_HELLO_DONE); 337 } else { 338 shc.handshakeSession = shc.resumingSession; 339 shc.negotiatedProtocol = 340 shc.resumingSession.getProtocolVersion(); 341 shc.negotiatedCipherSuite = shc.resumingSession.getSuite(); 342 shc.handshakeHash.determine( 343 shc.negotiatedProtocol, shc.negotiatedCipherSuite); 344 } 345 346 // Generate the ServerHello handshake message. 347 // TODO: not yet consider downgrade protection. 348 ServerHelloMessage shm = new ServerHelloMessage(shc, 349 shc.negotiatedProtocol, 350 shc.handshakeSession.getSessionId(), 351 shc.negotiatedCipherSuite, 352 new RandomCookie(shc.sslContext.getSecureRandom()), 353 clientHello); 354 shc.serverHelloRandom = shm.serverRandom; 355 356 // Produce extensions for ServerHello handshake message. 357 SSLExtension[] serverHelloExtensions = 358 shc.sslConfig.getEnabledExtensions( 359 SSLHandshake.SERVER_HELLO, shc.negotiatedProtocol); 360 shm.extensions.produce(shc, serverHelloExtensions); 361 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 362 SSLLogger.fine("Produced ServerHello handshake message", shm); 363 } 364 365 // Output the handshake message. 366 shm.write(shc.handshakeOutput); 367 shc.handshakeOutput.flush(); 368 369 if (shc.isResumption && shc.resumingSession != null) { 370 SSLTrafficKeyDerivation kdg = 371 SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol); 372 if (kdg == null) { 373 // unlikely 374 shc.conContext.fatal(Alert.INTERNAL_ERROR, 375 "Not supported key derivation: " + 376 shc.negotiatedProtocol); 377 } else { 378 shc.handshakeKeyDerivation = kdg.createKeyDerivation( 379 shc, shc.resumingSession.getMasterSecret()); 380 } 381 382 // update the responders 383 shc.handshakeProducers.put(SSLHandshake.FINISHED.id, 384 SSLHandshake.FINISHED); 385 } 386 387 // The handshake message has been delivered. 388 return null; 389 } 390 391 private static KeyExchangeProperties chooseCipherSuite( 392 ServerHandshakeContext shc, 393 ClientHelloMessage clientHello) throws IOException { 394 List<CipherSuite> prefered; 395 List<CipherSuite> proposed; 396 if (shc.sslConfig.preferLocalCipherSuites) { 397 prefered = shc.activeCipherSuites; 398 proposed = clientHello.cipherSuites; 399 } else { 400 prefered = clientHello.cipherSuites; 401 proposed = shc.activeCipherSuites; 402 } 403 404 List<CipherSuite> legacySuites = new LinkedList<>(); 405 for (CipherSuite cs : prefered) { 406 if (!HandshakeContext.isNegotiable( 407 proposed, shc.negotiatedProtocol, cs)) { 408 continue; 409 } 410 411 if (shc.sslConfig.clientAuthType == 412 ClientAuthType.CLIENT_AUTH_REQUIRED) { 413 if ((cs.keyExchange == KeyExchange.K_DH_ANON) || 414 (cs.keyExchange == KeyExchange.K_ECDH_ANON)) { 415 continue; 416 } 417 } 418 419 SSLKeyExchange ke = SSLKeyExchange.valueOf(cs.keyExchange); 420 if (ke == null) { 421 continue; 422 } 423 if (!ServerHandshakeContext.legacyAlgorithmConstraints.permits( 424 null, cs.name, null)) { 425 legacySuites.add(cs); 426 continue; 427 } 428 429 SSLPossession[] hcds = ke.createPossessions(shc); 430 if ((hcds == null) || (hcds.length == 0)) { 431 continue; 432 } 433 434 // The cipher suite has been negotiated. 435 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 436 SSLLogger.fine("use cipher suite " + cs.name); 437 } 438 439 return new KeyExchangeProperties(cs, ke, hcds); 440 } 441 442 for (CipherSuite cs : legacySuites) { 443 SSLKeyExchange ke = SSLKeyExchange.valueOf(cs.keyExchange); 444 if (ke != null) { 445 SSLPossession[] hcds = ke.createPossessions(shc); 446 if ((hcds != null) && (hcds.length != 0)) { 447 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 448 SSLLogger.warning( 449 "use legacy cipher suite " + cs.name); 450 } 451 return new KeyExchangeProperties(cs, ke, hcds); 452 } 453 } 454 } 455 456 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 457 "no cipher suites in common"); 458 459 return null; // make the compiler happy. 460 } 461 462 private static final class KeyExchangeProperties { 463 final CipherSuite cipherSuite; 464 final SSLKeyExchange keyExchange; 465 final SSLPossession[] possessions; 466 467 private KeyExchangeProperties(CipherSuite cipherSuite, 468 SSLKeyExchange keyExchange, SSLPossession[] possessions) { 469 this.cipherSuite = cipherSuite; 470 this.keyExchange = keyExchange; 471 this.possessions = possessions; 472 } 473 } 474 } 475 476 /** 477 * The "ServerHello" handshake message producer. 478 */ 479 private static final 480 class T13ServerHelloProducer implements HandshakeProducer { 481 // Prevent instantiation of this class. 482 private T13ServerHelloProducer() { 483 // blank 484 } 485 486 @Override 487 public byte[] produce(ConnectionContext context, 488 HandshakeMessage message) throws IOException { 489 // The producing happens in server side only. 490 ServerHandshakeContext shc = (ServerHandshakeContext)context; 491 ClientHelloMessage clientHello = (ClientHelloMessage)message; 492 493 // If client hasn't specified a session we can resume, start a 494 // new one and choose its cipher suite and compression options, 495 // unless new session creation is disabled for this connection! 496 if (!shc.isResumption || shc.resumingSession == null) { 497 if (!shc.sslConfig.enableSessionCreation) { 498 throw new SSLException( 499 "Not resumption, and no new session is allowed"); 500 } 501 502 if (shc.localSupportedSignAlgs == null) { 503 shc.localSupportedSignAlgs = 504 SignatureScheme.getSupportedAlgorithms( 505 shc.algorithmConstraints, shc.activeProtocols); 506 } 507 508 SSLSessionImpl session = 509 new SSLSessionImpl(shc, CipherSuite.C_NULL); 510 session.setMaximumPacketSize(shc.sslConfig.maximumPacketSize); 511 shc.handshakeSession = session; 512 513 // consider the handshake extension impact 514 SSLExtension[] enabledExtensions = 515 shc.sslConfig.getEnabledExtensions( 516 SSLHandshake.CLIENT_HELLO, shc.negotiatedProtocol); 517 clientHello.extensions.consumeOnTrade(shc, enabledExtensions); 518 519 // negotiate the cipher suite. 520 CipherSuite cipherSuite = chooseCipherSuite(shc, clientHello); 521 if (cipherSuite == null) { 522 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 523 "no cipher suites in common"); 524 return null; // make the compiler happy 525 } 526 shc.negotiatedCipherSuite = cipherSuite; 527 shc.handshakeSession.setSuite(cipherSuite); 528 shc.handshakeHash.determine( 529 shc.negotiatedProtocol, shc.negotiatedCipherSuite); 530 } else { 531 shc.handshakeSession = shc.resumingSession; 532 533 // consider the handshake extension impact 534 SSLExtension[] enabledExtensions = 535 shc.sslConfig.getEnabledExtensions( 536 SSLHandshake.CLIENT_HELLO, shc.negotiatedProtocol); 537 clientHello.extensions.consumeOnTrade(shc, enabledExtensions); 538 539 shc.negotiatedProtocol = 540 shc.resumingSession.getProtocolVersion(); 541 shc.negotiatedCipherSuite = shc.resumingSession.getSuite(); 542 shc.handshakeHash.determine( 543 shc.negotiatedProtocol, shc.negotiatedCipherSuite); 544 545 setUpPskKD(shc, shc.resumingSession.consumePreSharedKey().get()); 546 547 // The session can't be resumed again---remove it from cache 548 SSLSessionContextImpl sessionCache = (SSLSessionContextImpl) 549 shc.sslContext.engineGetServerSessionContext(); 550 sessionCache.remove(shc.resumingSession.getSessionId()); 551 } 552 553 // update the responders 554 shc.handshakeProducers.put(SSLHandshake.ENCRYPTED_EXTENSIONS.id, 555 SSLHandshake.ENCRYPTED_EXTENSIONS); 556 shc.handshakeProducers.put(SSLHandshake.FINISHED.id, 557 SSLHandshake.FINISHED); 558 559 // TODO: not yet consider downgrade protection. 560 ServerHelloMessage shm = new ServerHelloMessage(shc, 561 ProtocolVersion.TLS12, // use legacy version 562 clientHello.sessionId, // echo back 563 shc.negotiatedCipherSuite, 564 new RandomCookie(shc.sslContext.getSecureRandom()), 565 clientHello); 566 shc.serverHelloRandom = shm.serverRandom; 567 568 // Produce extensions for ServerHello handshake message. 569 SSLExtension[] serverHelloExtensions = 570 shc.sslConfig.getEnabledExtensions( 571 SSLHandshake.SERVER_HELLO, shc.negotiatedProtocol); 572 shm.extensions.produce(shc, serverHelloExtensions); 573 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 574 SSLLogger.fine("Produced ServerHello handshake message", shm); 575 } 576 577 // Output the handshake message. 578 shm.write(shc.handshakeOutput); 579 shc.handshakeOutput.flush(); 580 581 // Change client/server handshake traffic secrets. 582 // Refresh handshake hash 583 shc.handshakeHash.update(); 584 585 // Change client/server handshake traffic secrets. 586 SSLKeyExchange ke = shc.handshakeKeyExchange; 587 if (ke == null) { 588 // unlikely 589 shc.conContext.fatal(Alert.INTERNAL_ERROR, 590 "Not negotiated key shares"); 591 return null; // make the compiler happy 592 } 593 594 SSLKeyDerivation handshakeKD = ke.createKeyDerivation(shc); 595 SecretKey handshakeSecret = handshakeKD.deriveKey( 596 "TlsHandshakeSecret", null); 597 598 SSLTrafficKeyDerivation kdg = 599 SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol); 600 if (kdg == null) { 601 // unlikely 602 shc.conContext.fatal(Alert.INTERNAL_ERROR, 603 "Not supported key derivation: " + 604 shc.negotiatedProtocol); 605 return null; // make the compiler happy 606 } 607 608 SSLKeyDerivation kd = 609 new SSLSecretDerivation(shc, handshakeSecret); 610 611 // update the handshake traffic read keys. 612 SecretKey readSecret = kd.deriveKey( 613 "TlsClientHandshakeTrafficSecret", null); 614 SSLKeyDerivation readKD = 615 kdg.createKeyDerivation(shc, readSecret); 616 SecretKey readKey = readKD.deriveKey( 617 "TlsKey", null); 618 SecretKey readIvSecret = readKD.deriveKey( 619 "TlsIv", null); 620 IvParameterSpec readIv = 621 new IvParameterSpec(readIvSecret.getEncoded()); 622 SSLReadCipher readCipher; 623 try { 624 readCipher = 625 shc.negotiatedCipherSuite.bulkCipher.createReadCipher( 626 Authenticator.valueOf(shc.negotiatedProtocol), 627 shc.negotiatedProtocol, readKey, readIv, 628 shc.sslContext.getSecureRandom()); 629 } catch (GeneralSecurityException gse) { 630 // unlikely 631 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 632 "Missing cipher algorithm", gse); 633 return null; // make the compiler happy 634 } 635 636 shc.baseReadSecret = readSecret; 637 shc.conContext.inputRecord.changeReadCiphers(readCipher); 638 639 // update the handshake traffic write secret. 640 SecretKey writeSecret = kd.deriveKey( 641 "TlsServerHandshakeTrafficSecret", null); 642 SSLKeyDerivation writeKD = 643 kdg.createKeyDerivation(shc, writeSecret); 644 SecretKey writeKey = writeKD.deriveKey( 645 "TlsKey", null); 646 SecretKey writeIvSecret = writeKD.deriveKey( 647 "TlsIv", null); 648 IvParameterSpec writeIv = 649 new IvParameterSpec(writeIvSecret.getEncoded()); 650 SSLWriteCipher writeCipher; 651 try { 652 writeCipher = 653 shc.negotiatedCipherSuite.bulkCipher.createWriteCipher( 654 Authenticator.valueOf(shc.negotiatedProtocol), 655 shc.negotiatedProtocol, writeKey, writeIv, 656 shc.sslContext.getSecureRandom()); 657 } catch (GeneralSecurityException gse) { 658 // unlikely 659 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 660 "Missing cipher algorithm", gse); 661 return null; // make the compiler happy 662 } 663 664 shc.baseWriteSecret = writeSecret; 665 shc.conContext.outputRecord.changeWriteCiphers( 666 writeCipher, (clientHello.sessionId.length() != 0)); 667 668 // Update the context for master key derivation. 669 shc.handshakeKeyDerivation = kd; 670 671 // The handshake message has been delivered. 672 return null; 673 } 674 675 private static CipherSuite chooseCipherSuite( 676 ServerHandshakeContext shc, 677 ClientHelloMessage clientHello) throws IOException { 678 List<CipherSuite> prefered; 679 List<CipherSuite> proposed; 680 if (shc.sslConfig.preferLocalCipherSuites) { 681 prefered = shc.activeCipherSuites; 682 proposed = clientHello.cipherSuites; 683 } else { 684 prefered = clientHello.cipherSuites; 685 proposed = shc.activeCipherSuites; 686 } 687 688 CipherSuite legacySuite = null; 689 AlgorithmConstraints legacyConstraints = 690 ServerHandshakeContext.legacyAlgorithmConstraints; 691 for (CipherSuite cs : prefered) { 692 if (!HandshakeContext.isNegotiable( 693 proposed, shc.negotiatedProtocol, cs)) { 694 continue; 695 } 696 697 if ((legacySuite == null) && 698 !legacyConstraints.permits(null, cs.name, null)) { 699 legacySuite = cs; 700 continue; 701 } 702 703 // The cipher suite has been negotiated. 704 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 705 SSLLogger.fine("use cipher suite " + cs.name); 706 } 707 return cs; 708 } 709 710 if (legacySuite != null) { 711 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 712 SSLLogger.warning( 713 "use legacy cipher suite " + legacySuite.name); 714 } 715 return legacySuite; 716 } 717 718 // no cipher suites in common 719 return null; 720 } 721 } 722 723 /** 724 * The "HelloRetryRequest" handshake message producer. 725 */ 726 private static final 727 class T13HelloRetryRequestProducer implements HandshakeProducer { 728 // Prevent instantiation of this class. 729 private T13HelloRetryRequestProducer() { 730 // blank 731 } 732 733 @Override 734 public byte[] produce(ConnectionContext context, 735 HandshakeMessage message) throws IOException { 736 ServerHandshakeContext shc = (ServerHandshakeContext) context; 737 ClientHelloMessage clientHello = (ClientHelloMessage) message; 738 739 // negotiate the cipher suite. 740 CipherSuite cipherSuite = 741 T13ServerHelloProducer.chooseCipherSuite(shc, clientHello); 742 if (cipherSuite == null) { 743 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 744 "no cipher suites in common for hello retry request"); 745 return null; // make the compiler happy 746 } 747 748 ServerHelloMessage hhrm = new ServerHelloMessage(shc, 749 ProtocolVersion.TLS12, // use legacy version 750 clientHello.sessionId, // echo back 751 cipherSuite, 752 RandomCookie.hrrRandom, 753 clientHello 754 ); 755 756 shc.negotiatedCipherSuite = cipherSuite; 757 shc.handshakeHash.determine( 758 shc.negotiatedProtocol, shc.negotiatedCipherSuite); 759 760 // Produce extensions for HelloRetryRequest handshake message. 761 SSLExtension[] serverHelloExtensions = 762 shc.sslConfig.getEnabledExtensions( 763 SSLHandshake.HELLO_RETRY_REQUEST, shc.negotiatedProtocol); 764 hhrm.extensions.produce(shc, serverHelloExtensions); 765 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 766 SSLLogger.fine( 767 "Produced HelloRetryRequest handshake message", hhrm); 768 } 769 770 // Output the handshake message. 771 hhrm.write(shc.handshakeOutput); 772 shc.handshakeOutput.flush(); 773 774 // TODO: stateless, clean up the handshake context? 775 shc.handshakeHash.finish(); // forgot about the handshake hash 776 shc.handshakeExtensions.clear(); 777 778 // What's the expected response? 779 shc.handshakeConsumers.put( 780 SSLHandshake.CLIENT_HELLO.id, SSLHandshake.CLIENT_HELLO); 781 782 // The handshake message has been delivered. 783 return null; 784 } 785 } 786 787 /** 788 * The "HelloRetryRequest" handshake message reproducer. 789 */ 790 private static final 791 class T13HelloRetryRequestReproducer implements HandshakeProducer { 792 // Prevent instantiation of this class. 793 private T13HelloRetryRequestReproducer() { 794 // blank 795 } 796 797 @Override 798 public byte[] produce(ConnectionContext context, 799 HandshakeMessage message) throws IOException { 800 ServerHandshakeContext shc = (ServerHandshakeContext) context; 801 ClientHelloMessage clientHello = (ClientHelloMessage) message; 802 803 // negotiate the cipher suite. 804 CipherSuite cipherSuite = shc.negotiatedCipherSuite; 805 ServerHelloMessage hhrm = new ServerHelloMessage(shc, 806 ProtocolVersion.TLS12, // use legacy version 807 clientHello.sessionId, // echo back 808 cipherSuite, 809 RandomCookie.hrrRandom, 810 clientHello 811 ); 812 813 // Produce extensions for HelloRetryRequest handshake message. 814 SSLExtension[] serverHelloExtensions = 815 shc.sslConfig.getEnabledExtensions( 816 SSLHandshake.MESSAGE_HASH, shc.negotiatedProtocol); 817 hhrm.extensions.produce(shc, serverHelloExtensions); 818 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 819 SSLLogger.fine( 820 "Reproduced HelloRetryRequest handshake message", hhrm); 821 } 822 823 HandshakeOutStream hos = new HandshakeOutStream(null); 824 hhrm.write(hos); 825 826 return hos.toByteArray(); 827 } 828 } 829 830 /** 831 * The "ServerHello" handshake message consumer. 832 */ 833 private static final 834 class ServerHelloConsumer implements SSLConsumer { 835 // Prevent instantiation of this class. 836 private ServerHelloConsumer() { 837 // blank 838 } 839 840 @Override 841 public void consume(ConnectionContext context, 842 ByteBuffer message) throws IOException { 843 // The consuming happens in client side only. 844 ClientHandshakeContext chc = (ClientHandshakeContext)context; 845 846 // clean up this consumer 847 chc.handshakeConsumers.remove(SSLHandshake.SERVER_HELLO.id); 848 if (!chc.handshakeConsumers.isEmpty()) { 849 // DTLS 1.0/1.2 850 chc.handshakeConsumers.remove( 851 SSLHandshake.HELLO_VERIFY_REQUEST.id); 852 } 853 if (!chc.handshakeConsumers.isEmpty()) { 854 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, 855 "No more message expected before ServerHello is processed"); 856 } 857 858 int startPos = message.position(); 859 ServerHelloMessage shm = new ServerHelloMessage(chc, message); 860 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 861 SSLLogger.fine("Consuming ServerHello handshake message", shm); 862 } 863 864 if (shm.serverRandom.isHelloRetryRequest()) { 865 onHelloRetryRequest(chc, shm); 866 } else { 867 onServerHello(chc, shm); 868 } 869 } 870 871 private void onHelloRetryRequest(ClientHandshakeContext chc, 872 ServerHelloMessage helloRetryRequest) throws IOException { 873 // Negotiate protocol version. 874 // 875 // Check and lanuch SupportedVersions. 876 SSLExtension[] extTypes = new SSLExtension[] { 877 SSLExtension.HRR_SUPPORTED_VERSIONS 878 }; 879 helloRetryRequest.extensions.consumeOnLoad(chc, extTypes); 880 881 ProtocolVersion serverVersion; 882 SHSupportedVersionsSpec svs = 883 (SHSupportedVersionsSpec)chc.handshakeExtensions.get( 884 SSLExtension.HRR_SUPPORTED_VERSIONS); 885 if (svs != null) { 886 serverVersion = // could be null 887 ProtocolVersion.valueOf(svs.selectedVersion); 888 } else { 889 serverVersion = helloRetryRequest.serverVersion; 890 } 891 892 if (!chc.activeProtocols.contains(serverVersion)) { 893 chc.conContext.fatal(Alert.PROTOCOL_VERSION, 894 "The server selected protocol version " + serverVersion + 895 " is not accepted by client preferences " + 896 chc.activeProtocols); 897 } 898 899 if (!serverVersion.useTLS13PlusSpec()) { 900 chc.conContext.fatal(Alert.PROTOCOL_VERSION, 901 "Unexpected HelloRetryRequest for " + serverVersion.name); 902 } 903 904 chc.negotiatedProtocol = serverVersion; 905 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 906 SSLLogger.fine( 907 "Negotiated protocol version: " + serverVersion.name); 908 } 909 910 // TLS 1.3 key share extension may have produced client 911 // possessions for TLS 1.3 key exchanges. 912 // 913 // Clean up before producing new client key share possessions. 914 chc.handshakePossessions.clear(); 915 916 if (serverVersion.isDTLS) { 917 d13HrrHandshakeConsumer.consume(chc, helloRetryRequest); 918 } else { 919 t13HrrHandshakeConsumer.consume(chc, helloRetryRequest); 920 } 921 } 922 923 private void onServerHello(ClientHandshakeContext chc, 924 ServerHelloMessage serverHello) throws IOException { 925 // Negotiate protocol version. 926 // 927 // Check and lanuch SupportedVersions. 928 SSLExtension[] extTypes = new SSLExtension[] { 929 SSLExtension.SH_SUPPORTED_VERSIONS 930 }; 931 serverHello.extensions.consumeOnLoad(chc, extTypes); 932 933 ProtocolVersion serverVersion; 934 SHSupportedVersionsSpec svs = 935 (SHSupportedVersionsSpec)chc.handshakeExtensions.get( 936 SSLExtension.SH_SUPPORTED_VERSIONS); 937 if (svs != null) { 938 serverVersion = // could be null 939 ProtocolVersion.valueOf(svs.selectedVersion); 940 } else { 941 serverVersion = serverHello.serverVersion; 942 } 943 944 if (!chc.activeProtocols.contains(serverVersion)) { 945 chc.conContext.fatal(Alert.PROTOCOL_VERSION, 946 "The server selected protocol version " + serverVersion + 947 " is not accepted by client preferences " + 948 chc.activeProtocols); 949 } 950 951 chc.negotiatedProtocol = serverVersion; 952 if (!chc.conContext.isNegotiated) { 953 chc.conContext.protocolVersion = chc.negotiatedProtocol; 954 chc.conContext.outputRecord.setVersion(chc.negotiatedProtocol); 955 } 956 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 957 SSLLogger.fine( 958 "Negotiated protocol version: " + serverVersion.name); 959 } 960 961 // Consume the handshake message for the specific protocol version. 962 if (serverVersion.isDTLS) { 963 if (serverVersion.useTLS13PlusSpec()) { 964 d13HandshakeConsumer.consume(chc, serverHello); 965 } else { 966 // TLS 1.3 key share extension may have produced client 967 // possessions for TLS 1.3 key exchanges. 968 chc.handshakePossessions.clear(); 969 970 d12HandshakeConsumer.consume(chc, serverHello); 971 } 972 } else { 973 if (serverVersion.useTLS13PlusSpec()) { 974 t13HandshakeConsumer.consume(chc, serverHello); 975 } else { 976 // TLS 1.3 key share extension may have produced client 977 // possessions for TLS 1.3 key exchanges. 978 chc.handshakePossessions.clear(); 979 980 t12HandshakeConsumer.consume(chc, serverHello); 981 } 982 } 983 } 984 } 985 986 private static final 987 class T12ServerHelloConsumer implements HandshakeConsumer { 988 // Prevent instantiation of this class. 989 private T12ServerHelloConsumer() { 990 // blank 991 } 992 993 @Override 994 public void consume(ConnectionContext context, 995 HandshakeMessage message) throws IOException { 996 // The consuming happens in client side only. 997 ClientHandshakeContext chc = (ClientHandshakeContext)context; 998 ServerHelloMessage serverHello = (ServerHelloMessage)message; 999 if (!chc.isNegotiable(serverHello.serverVersion)) { 1000 chc.conContext.fatal(Alert.PROTOCOL_VERSION, 1001 "Server chose " + serverHello.serverVersion + 1002 ", but that protocol version is not enabled or " + 1003 "not supported by the client."); 1004 } 1005 1006 // chc.negotiatedProtocol = serverHello.serverVersion; 1007 chc.negotiatedCipherSuite = serverHello.cipherSuite; 1008 chc.handshakeHash.determine( 1009 chc.negotiatedProtocol, chc.negotiatedCipherSuite); 1010 chc.serverHelloRandom = serverHello.serverRandom; 1011 if (chc.negotiatedCipherSuite.keyExchange == null) { 1012 chc.conContext.fatal(Alert.PROTOCOL_VERSION, 1013 "TLS 1.2 or prior version does not support the " + 1014 "server cipher suite: " + chc.negotiatedCipherSuite.name); 1015 } 1016 1017 // 1018 // validate 1019 // 1020 1021 // Check and lanuch the "renegotiation_info" extension. 1022 SSLExtension[] extTypes = new SSLExtension[] { 1023 SSLExtension.SH_RENEGOTIATION_INFO 1024 }; 1025 serverHello.extensions.consumeOnLoad(chc, extTypes); 1026 1027 // Is it session resuming? 1028 if (chc.resumingSession != null) { 1029 // we tried to resume, let's see what the server decided 1030 if (serverHello.sessionId.equals( 1031 chc.resumingSession.getSessionId())) { 1032 // server resumed the session, let's make sure everything 1033 // checks out 1034 1035 // Verify that the session ciphers are unchanged. 1036 CipherSuite sessionSuite = chc.resumingSession.getSuite(); 1037 if (chc.negotiatedCipherSuite != sessionSuite) { 1038 chc.conContext.fatal(Alert.PROTOCOL_VERSION, 1039 "Server returned wrong cipher suite for session"); 1040 } 1041 1042 // verify protocol version match 1043 ProtocolVersion sessionVersion = 1044 chc.resumingSession.getProtocolVersion(); 1045 if (chc.negotiatedProtocol != sessionVersion) { 1046 chc.conContext.fatal(Alert.PROTOCOL_VERSION, 1047 "Server resumed with wrong protocol version"); 1048 } 1049 1050 // looks fine; resume it. 1051 chc.isResumption = true; 1052 chc.resumingSession.setAsSessionResumption(true); 1053 chc.handshakeSession = chc.resumingSession; 1054 } else { 1055 // we wanted to resume, but the server refused 1056 // 1057 // Invalidate the session for initial handshake in case 1058 // of reusing next time. 1059 if (chc.resumingSession != null) { 1060 chc.resumingSession.invalidate(); 1061 chc.resumingSession = null; 1062 } 1063 chc.isResumption = false; 1064 if (!chc.sslConfig.enableSessionCreation) { 1065 chc.conContext.fatal(Alert.PROTOCOL_VERSION, 1066 "New session creation is disabled"); 1067 } 1068 } 1069 } 1070 1071 // Check and launch ClientHello extensions. 1072 extTypes = chc.sslConfig.getEnabledExtensions( 1073 SSLHandshake.SERVER_HELLO); 1074 serverHello.extensions.consumeOnLoad(chc, extTypes); 1075 1076 if (!chc.isResumption) { 1077 if (chc.resumingSession != null) { 1078 // in case the resumption happens next time. 1079 chc.resumingSession.invalidate(); 1080 chc.resumingSession = null; 1081 } 1082 1083 if (!chc.sslConfig.enableSessionCreation) { 1084 chc.conContext.fatal(Alert.PROTOCOL_VERSION, 1085 "New session creation is disabled"); 1086 } 1087 chc.handshakeSession = new SSLSessionImpl(chc, 1088 chc.negotiatedCipherSuite, 1089 serverHello.sessionId); 1090 chc.handshakeSession.setMaximumPacketSize( 1091 chc.sslConfig.maximumPacketSize); 1092 } 1093 1094 // 1095 // update 1096 // 1097 serverHello.extensions.consumeOnTrade(chc, extTypes); 1098 1099 // update the consumers and producers 1100 if (chc.isResumption) { 1101 SSLTrafficKeyDerivation kdg = 1102 SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol); 1103 if (kdg == null) { 1104 // unlikely 1105 chc.conContext.fatal(Alert.INTERNAL_ERROR, 1106 "Not supported key derivation: " + 1107 chc.negotiatedProtocol); 1108 } else { 1109 chc.handshakeKeyDerivation = kdg.createKeyDerivation( 1110 chc, chc.resumingSession.getMasterSecret()); 1111 } 1112 1113 chc.conContext.consumers.putIfAbsent( 1114 ContentType.CHANGE_CIPHER_SPEC.id, 1115 ChangeCipherSpec.t10Consumer); 1116 chc.handshakeConsumers.put( 1117 SSLHandshake.FINISHED.id, 1118 SSLHandshake.FINISHED); 1119 } else { 1120 SSLKeyExchange ke = SSLKeyExchange.valueOf( 1121 chc.negotiatedCipherSuite.keyExchange); 1122 chc.handshakeKeyExchange = ke; 1123 if (ke != null) { 1124 for (SSLHandshake handshake : 1125 ke.getRelatedHandshakers(chc)) { 1126 chc.handshakeConsumers.put(handshake.id, handshake); 1127 } 1128 } 1129 1130 chc.handshakeConsumers.put(SSLHandshake.SERVER_HELLO_DONE.id, 1131 SSLHandshake.SERVER_HELLO_DONE); 1132 } 1133 1134 // 1135 // produce 1136 // 1137 // Need no new handshake message producers here. 1138 } 1139 } 1140 1141 private static void setUpPskKD(HandshakeContext hc, 1142 SecretKey psk) throws SSLHandshakeException { 1143 1144 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 1145 SSLLogger.fine("Using PSK to derive early secret"); 1146 } 1147 1148 try { 1149 CipherSuite.HashAlg hashAlg = hc.negotiatedCipherSuite.hashAlg; 1150 HKDF hkdf = new HKDF(hashAlg.name); 1151 byte[] zeros = new byte[hashAlg.hashLength]; 1152 SecretKey earlySecret = hkdf.extract(zeros, psk, "TlsEarlySecret"); 1153 hc.handshakeKeyDerivation = new SSLSecretDerivation(hc, earlySecret); 1154 } catch (GeneralSecurityException gse) { 1155 throw (SSLHandshakeException) new SSLHandshakeException( 1156 "Could not generate secret").initCause(gse); 1157 } 1158 } 1159 1160 private static final 1161 class T13ServerHelloConsumer implements HandshakeConsumer { 1162 // Prevent instantiation of this class. 1163 private T13ServerHelloConsumer() { 1164 // blank 1165 } 1166 1167 @Override 1168 public void consume(ConnectionContext context, 1169 HandshakeMessage message) throws IOException { 1170 // The consuming happens in client side only. 1171 ClientHandshakeContext chc = (ClientHandshakeContext)context; 1172 ServerHelloMessage serverHello = (ServerHelloMessage)message; 1173 if (serverHello.serverVersion != ProtocolVersion.TLS12) { 1174 chc.conContext.fatal(Alert.PROTOCOL_VERSION, 1175 "The ServerHello.legacy_version field is not TLS 1.2"); 1176 } 1177 1178 chc.negotiatedCipherSuite = serverHello.cipherSuite; 1179 chc.handshakeHash.determine( 1180 chc.negotiatedProtocol, chc.negotiatedCipherSuite); 1181 chc.serverHelloRandom = serverHello.serverRandom; 1182 1183 // 1184 // validate 1185 // 1186 1187 // Check and launch ServerHello extensions. 1188 SSLExtension[] extTypes = chc.sslConfig.getEnabledExtensions( 1189 SSLHandshake.SERVER_HELLO); 1190 serverHello.extensions.consumeOnLoad(chc, extTypes); 1191 if (!chc.isResumption) { 1192 if (chc.resumingSession != null) { 1193 // in case the resumption happens next time. 1194 chc.resumingSession.invalidate(); 1195 chc.resumingSession = null; 1196 } 1197 1198 if (!chc.sslConfig.enableSessionCreation) { 1199 chc.conContext.fatal(Alert.PROTOCOL_VERSION, 1200 "New session creation is disabled"); 1201 } 1202 chc.handshakeSession = new SSLSessionImpl(chc, 1203 chc.negotiatedCipherSuite, 1204 serverHello.sessionId); 1205 chc.handshakeSession.setMaximumPacketSize( 1206 chc.sslConfig.maximumPacketSize); 1207 } else { 1208 // The PSK is consumed to allow it to be deleted 1209 Optional<SecretKey> psk = chc.resumingSession.consumePreSharedKey(); 1210 if(!psk.isPresent()) { 1211 chc.conContext.fatal(Alert.INTERNAL_ERROR, 1212 "No PSK available. Unable to resume."); 1213 } 1214 1215 chc.handshakeSession = chc.resumingSession; 1216 1217 setUpPskKD(chc, psk.get()); 1218 } 1219 1220 // 1221 // update 1222 // 1223 serverHello.extensions.consumeOnTrade(chc, extTypes); 1224 1225 // Change client/server handshake traffic secrets. 1226 // Refresh handshake hash 1227 chc.handshakeHash.update(); 1228 1229 SSLKeyExchange ke = chc.handshakeKeyExchange; 1230 if (ke == null) { 1231 // unlikely 1232 chc.conContext.fatal(Alert.INTERNAL_ERROR, 1233 "Not negotiated key shares"); 1234 return; // make the compiler happy 1235 } 1236 1237 SSLKeyDerivation handshakeKD = ke.createKeyDerivation(chc); 1238 SecretKey handshakeSecret = handshakeKD.deriveKey( 1239 "TlsHandshakeSecret", null); 1240 SSLTrafficKeyDerivation kdg = 1241 SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol); 1242 if (kdg == null) { 1243 // unlikely 1244 chc.conContext.fatal(Alert.INTERNAL_ERROR, 1245 "Not supported key derivation: " + 1246 chc.negotiatedProtocol); 1247 return; // make the compiler happy 1248 } 1249 1250 SSLKeyDerivation secretKD = 1251 new SSLSecretDerivation(chc, handshakeSecret); 1252 1253 // update the handshake traffic read keys. 1254 SecretKey readSecret = secretKD.deriveKey( 1255 "TlsServerHandshakeTrafficSecret", null); 1256 1257 SSLKeyDerivation readKD = 1258 kdg.createKeyDerivation(chc, readSecret); 1259 SecretKey readKey = readKD.deriveKey( 1260 "TlsKey", null); 1261 SecretKey readIvSecret = readKD.deriveKey( 1262 "TlsIv", null); 1263 IvParameterSpec readIv = 1264 new IvParameterSpec(readIvSecret.getEncoded()); 1265 SSLReadCipher readCipher; 1266 try { 1267 readCipher = 1268 chc.negotiatedCipherSuite.bulkCipher.createReadCipher( 1269 Authenticator.valueOf(chc.negotiatedProtocol), 1270 chc.negotiatedProtocol, readKey, readIv, 1271 chc.sslContext.getSecureRandom()); 1272 } catch (GeneralSecurityException gse) { 1273 // unlikely 1274 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 1275 "Missing cipher algorithm", gse); 1276 return; // make the compiler happy 1277 } 1278 1279 chc.baseReadSecret = readSecret; 1280 chc.conContext.inputRecord.changeReadCiphers(readCipher); 1281 1282 // update the handshake traffic write keys. 1283 SecretKey writeSecret = secretKD.deriveKey( 1284 "TlsClientHandshakeTrafficSecret", null); 1285 SSLKeyDerivation writeKD = 1286 kdg.createKeyDerivation(chc, writeSecret); 1287 SecretKey writeKey = writeKD.deriveKey( 1288 "TlsKey", null); 1289 SecretKey writeIvSecret = writeKD.deriveKey( 1290 "TlsIv", null); 1291 IvParameterSpec writeIv = 1292 new IvParameterSpec(writeIvSecret.getEncoded()); 1293 SSLWriteCipher writeCipher; 1294 try { 1295 writeCipher = 1296 chc.negotiatedCipherSuite.bulkCipher.createWriteCipher( 1297 Authenticator.valueOf(chc.negotiatedProtocol), 1298 chc.negotiatedProtocol, writeKey, writeIv, 1299 chc.sslContext.getSecureRandom()); 1300 } catch (GeneralSecurityException gse) { 1301 // unlikely 1302 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 1303 "Missing cipher algorithm", gse); 1304 return; // make the compiler happy 1305 } 1306 1307 chc.baseWriteSecret = writeSecret; 1308 chc.conContext.outputRecord.changeWriteCiphers( 1309 writeCipher, (serverHello.sessionId.length() != 0)); 1310 1311 // Should use resumption_master_secret for TLS 1.3. 1312 // chc.handshakeSession.setMasterSecret(masterSecret); 1313 1314 // Update the context for master key derivation. 1315 chc.handshakeKeyDerivation = secretKD; 1316 1317 // update the consumers and producers 1318 // 1319 // The server sends a dummy change_cipher_spec record immediately 1320 // after its first handshake message. This may either be after a 1321 // ServerHello or a HelloRetryRequest. 1322 chc.conContext.consumers.putIfAbsent( 1323 ContentType.CHANGE_CIPHER_SPEC.id, 1324 ChangeCipherSpec.t13Consumer); 1325 1326 chc.handshakeConsumers.put( 1327 SSLHandshake.ENCRYPTED_EXTENSIONS.id, 1328 SSLHandshake.ENCRYPTED_EXTENSIONS); 1329 1330 // TODO: Optional cert authentication, when not PSK 1331 chc.handshakeConsumers.put( 1332 SSLHandshake.CERTIFICATE_REQUEST.id, 1333 SSLHandshake.CERTIFICATE_REQUEST); 1334 chc.handshakeConsumers.put( 1335 SSLHandshake.CERTIFICATE.id, 1336 SSLHandshake.CERTIFICATE); 1337 chc.handshakeConsumers.put( 1338 SSLHandshake.CERTIFICATE_VERIFY.id, 1339 SSLHandshake.CERTIFICATE_VERIFY); 1340 1341 chc.handshakeConsumers.put( 1342 SSLHandshake.FINISHED.id, 1343 SSLHandshake.FINISHED); 1344 1345 // 1346 // produce 1347 // 1348 // Need no new handshake message producers here. 1349 } 1350 } 1351 1352 private static final 1353 class T13HelloRetryRequestConsumer implements HandshakeConsumer { 1354 // Prevent instantiation of this class. 1355 private T13HelloRetryRequestConsumer() { 1356 // blank 1357 } 1358 1359 @Override 1360 public void consume(ConnectionContext context, 1361 HandshakeMessage message) throws IOException { 1362 // The consuming happens in client side only. 1363 ClientHandshakeContext chc = (ClientHandshakeContext)context; 1364 ServerHelloMessage helloRetryRequest = (ServerHelloMessage)message; 1365 if (helloRetryRequest.serverVersion != ProtocolVersion.TLS12) { 1366 chc.conContext.fatal(Alert.PROTOCOL_VERSION, 1367 "The HelloRetryRequest.legacy_version is not TLS 1.2"); 1368 } 1369 1370 chc.negotiatedCipherSuite = helloRetryRequest.cipherSuite; 1371 1372 // 1373 // validate 1374 // 1375 1376 // Check and launch ClientHello extensions. 1377 SSLExtension[] extTypes = chc.sslConfig.getEnabledExtensions( 1378 SSLHandshake.HELLO_RETRY_REQUEST); 1379 helloRetryRequest.extensions.consumeOnLoad(chc, extTypes); 1380 1381 // 1382 // update 1383 // 1384 helloRetryRequest.extensions.consumeOnTrade(chc, extTypes); 1385 1386 // Change client/server handshake traffic secrets. 1387 // Refresh handshake hash 1388 chc.handshakeHash.finish(); // reset the handshake hash 1389 1390 // calculate the transcript hash of the 1st ClientHello message 1391 HandshakeOutStream hos = new HandshakeOutStream(null); 1392 try { 1393 chc.initialClientHelloMsg.write(hos); 1394 } catch (IOException ioe) { 1395 // unlikely 1396 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 1397 "Failed to construct message hash", ioe); 1398 } 1399 chc.handshakeHash.deliver(hos.toByteArray()); 1400 chc.handshakeHash.determine( 1401 chc.negotiatedProtocol, chc.negotiatedCipherSuite); 1402 byte[] clientHelloHash = chc.handshakeHash.digest(); 1403 1404 // calculate the message_hash 1405 // 1406 // Transcript-Hash(ClientHello1, HelloRetryRequest, ... Mn) = 1407 // Hash(message_hash || /* Handshake type */ 1408 // 00 00 Hash.length || /* Handshake message length (bytes) */ 1409 // Hash(ClientHello1) || /* Hash of ClientHello1 */ 1410 // HelloRetryRequest || ... || Mn) 1411 int hashLen = chc.negotiatedCipherSuite.hashAlg.hashLength; 1412 byte[] hashedClientHello = new byte[4 + hashLen]; 1413 hashedClientHello[0] = SSLHandshake.MESSAGE_HASH.id; 1414 hashedClientHello[1] = (byte)0x00; 1415 hashedClientHello[2] = (byte)0x00; 1416 hashedClientHello[3] = (byte)(hashLen & 0xFF); 1417 System.arraycopy(clientHelloHash, 0, 1418 hashedClientHello, 4, hashLen); 1419 1420 chc.handshakeHash.finish(); // reset the handshake hash 1421 chc.handshakeHash.deliver(hashedClientHello); 1422 1423 int hrrBodyLen = helloRetryRequest.handshakeRecord.remaining(); 1424 byte[] hrrMessage = new byte[4 + hrrBodyLen]; 1425 hrrMessage[0] = SSLHandshake.HELLO_RETRY_REQUEST.id; 1426 hrrMessage[1] = (byte)((hrrBodyLen >> 16) & 0xFF); 1427 hrrMessage[2] = (byte)((hrrBodyLen >> 8) & 0xFF); 1428 hrrMessage[3] = (byte)(hrrBodyLen & 0xFF); 1429 1430 ByteBuffer hrrBody = helloRetryRequest.handshakeRecord.duplicate(); 1431 hrrBody.get(hrrMessage, 4, hrrBodyLen); 1432 1433 chc.handshakeHash.receive(hrrMessage); 1434 1435 // Update the initial ClientHello handshake message. 1436 chc.initialClientHelloMsg.extensions.reproduce(chc, 1437 new SSLExtension[] { 1438 SSLExtension.CH_COOKIE, 1439 SSLExtension.CH_KEY_SHARE, 1440 SSLExtension.CH_PRE_SHARED_KEY 1441 }); 1442 1443 // 1444 // produce response handshake message 1445 // 1446 SSLHandshake.CLIENT_HELLO.produce(context, helloRetryRequest); 1447 } 1448 } 1449 }