1 /* 2 * Copyright (c) 2018, 2019, 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.BufferOverflowException; 30 import java.nio.BufferUnderflowException; 31 import java.nio.ByteBuffer; 32 import java.security.AlgorithmConstraints; 33 import java.security.CryptoPrimitive; 34 import java.util.AbstractMap.SimpleImmutableEntry; 35 import java.util.ArrayList; 36 import java.util.Collections; 37 import java.util.EnumMap; 38 import java.util.EnumSet; 39 import java.util.HashMap; 40 import java.util.LinkedHashMap; 41 import java.util.LinkedList; 42 import java.util.List; 43 import java.util.Map; 44 import java.util.Queue; 45 import javax.crypto.SecretKey; 46 import javax.net.ssl.SNIServerName; 47 import javax.net.ssl.SSLHandshakeException; 48 import javax.security.auth.x500.X500Principal; 49 import sun.security.ssl.NamedGroup.NamedGroupSpec; 50 import static sun.security.ssl.NamedGroup.NamedGroupSpec.*; 51 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups; 52 53 abstract class HandshakeContext implements ConnectionContext { 54 // System properties 55 56 // By default, disable the unsafe legacy session renegotiation. 57 static final boolean allowUnsafeRenegotiation = 58 Utilities.getBooleanProperty( 59 "sun.security.ssl.allowUnsafeRenegotiation", false); 60 61 // For maximum interoperability and backward compatibility, RFC 5746 62 // allows server (or client) to accept ClientHello (or ServerHello) 63 // message without the secure renegotiation_info extension or SCSV. 64 // 65 // For maximum security, RFC 5746 also allows server (or client) to 66 // reject such message with a fatal "handshake_failure" alert. 67 // 68 // By default, allow such legacy hello messages. 69 static final boolean allowLegacyHelloMessages = 70 Utilities.getBooleanProperty( 71 "sun.security.ssl.allowLegacyHelloMessages", true); 72 73 // registered handshake message actors 74 LinkedHashMap<Byte, SSLConsumer> handshakeConsumers; 75 final HashMap<Byte, HandshakeProducer> handshakeProducers; 76 77 // context 78 final SSLContextImpl sslContext; 79 final TransportContext conContext; 80 final SSLConfiguration sslConfig; 81 82 // consolidated parameters 83 final List<ProtocolVersion> activeProtocols; 84 final List<CipherSuite> activeCipherSuites; 85 final AlgorithmConstraints algorithmConstraints; 86 final ProtocolVersion maximumActiveProtocol; 87 88 // output stream 89 final HandshakeOutStream handshakeOutput; 90 91 // handshake transcript hash 92 final HandshakeHash handshakeHash; 93 94 // negotiated security parameters 95 SSLSessionImpl handshakeSession; 96 boolean handshakeFinished; 97 // boolean isInvalidated; 98 99 boolean kickstartMessageDelivered; 100 101 // Resumption 102 boolean isResumption; 103 SSLSessionImpl resumingSession; 104 // Session is using stateless resumption 105 boolean statelessResumption = false; 106 107 final Queue<Map.Entry<Byte, ByteBuffer>> delegatedActions; 108 volatile boolean taskDelegated = false; 109 volatile Exception delegatedThrown = null; 110 111 ProtocolVersion negotiatedProtocol; 112 CipherSuite negotiatedCipherSuite; 113 final List<SSLPossession> handshakePossessions; 114 final List<SSLCredentials> handshakeCredentials; 115 SSLKeyDerivation handshakeKeyDerivation; 116 SSLKeyExchange handshakeKeyExchange; 117 SecretKey baseReadSecret; 118 SecretKey baseWriteSecret; 119 120 // protocol version being established 121 int clientHelloVersion; 122 String applicationProtocol; 123 124 RandomCookie clientHelloRandom; 125 RandomCookie serverHelloRandom; 126 byte[] certRequestContext; 127 128 //////////////////// 129 // Extensions 130 131 // the extensions used in the handshake 132 final Map<SSLExtension, SSLExtension.SSLExtensionSpec> 133 handshakeExtensions; 134 135 // MaxFragmentLength 136 int maxFragmentLength; 137 138 // SignatureScheme 139 List<SignatureScheme> localSupportedSignAlgs; 140 List<SignatureScheme> peerRequestedSignatureSchemes; 141 List<SignatureScheme> peerRequestedCertSignSchemes; 142 143 // Known authorities 144 X500Principal[] peerSupportedAuthorities = null; 145 146 // SupportedGroups 147 List<NamedGroup> clientRequestedNamedGroups; 148 149 // HelloRetryRequest 150 NamedGroup serverSelectedNamedGroup; 151 152 // if server name indicator is negotiated 153 // 154 // May need a public API for the indication in the future. 155 List<SNIServerName> requestedServerNames; 156 SNIServerName negotiatedServerName; 157 158 // OCSP Stapling info 159 boolean staplingActive = false; 160 HandshakeContext(SSLContextImpl sslContext, TransportContext conContext)161 protected HandshakeContext(SSLContextImpl sslContext, 162 TransportContext conContext) throws IOException { 163 this.sslContext = sslContext; 164 this.conContext = conContext; 165 this.sslConfig = (SSLConfiguration)conContext.sslConfig.clone(); 166 167 this.algorithmConstraints = new SSLAlgorithmConstraints( 168 sslConfig.userSpecifiedAlgorithmConstraints); 169 this.activeProtocols = getActiveProtocols(sslConfig.enabledProtocols, 170 sslConfig.enabledCipherSuites, algorithmConstraints); 171 if (activeProtocols.isEmpty()) { 172 throw new SSLHandshakeException( 173 "No appropriate protocol (protocol is disabled or " + 174 "cipher suites are inappropriate)"); 175 } 176 177 ProtocolVersion maximumVersion = ProtocolVersion.NONE; 178 for (ProtocolVersion pv : this.activeProtocols) { 179 if (maximumVersion == ProtocolVersion.NONE || 180 pv.compare(maximumVersion) > 0) { 181 maximumVersion = pv; 182 } 183 } 184 this.maximumActiveProtocol = maximumVersion; 185 this.activeCipherSuites = getActiveCipherSuites(this.activeProtocols, 186 sslConfig.enabledCipherSuites, algorithmConstraints); 187 if (activeCipherSuites.isEmpty()) { 188 throw new SSLHandshakeException("No appropriate cipher suite"); 189 } 190 191 this.handshakeConsumers = new LinkedHashMap<>(); 192 this.handshakeProducers = new HashMap<>(); 193 this.handshakeHash = conContext.inputRecord.handshakeHash; 194 this.handshakeOutput = new HandshakeOutStream(conContext.outputRecord); 195 196 this.handshakeFinished = false; 197 this.kickstartMessageDelivered = false; 198 199 this.delegatedActions = new LinkedList<>(); 200 this.handshakeExtensions = new HashMap<>(); 201 this.handshakePossessions = new LinkedList<>(); 202 this.handshakeCredentials = new LinkedList<>(); 203 this.requestedServerNames = null; 204 this.negotiatedServerName = null; 205 this.negotiatedCipherSuite = conContext.cipherSuite; 206 initialize(); 207 } 208 209 /** 210 * Constructor for PostHandshakeContext 211 */ HandshakeContext(TransportContext conContext)212 protected HandshakeContext(TransportContext conContext) { 213 this.sslContext = conContext.sslContext; 214 this.conContext = conContext; 215 this.sslConfig = conContext.sslConfig; 216 217 this.negotiatedProtocol = conContext.protocolVersion; 218 this.negotiatedCipherSuite = conContext.cipherSuite; 219 this.handshakeOutput = new HandshakeOutStream(conContext.outputRecord); 220 this.delegatedActions = new LinkedList<>(); 221 222 this.handshakeConsumers = new LinkedHashMap<>(); 223 this.handshakeProducers = null; 224 this.handshakeHash = null; 225 this.activeProtocols = null; 226 this.activeCipherSuites = null; 227 this.algorithmConstraints = null; 228 this.maximumActiveProtocol = null; 229 this.handshakeExtensions = Collections.emptyMap(); // Not in TLS13 230 this.handshakePossessions = null; 231 this.handshakeCredentials = null; 232 } 233 234 // Initialize the non-final class variables. initialize()235 private void initialize() { 236 ProtocolVersion inputHelloVersion; 237 ProtocolVersion outputHelloVersion; 238 if (conContext.isNegotiated) { 239 inputHelloVersion = conContext.protocolVersion; 240 outputHelloVersion = conContext.protocolVersion; 241 } else { 242 if (activeProtocols.contains(ProtocolVersion.SSL20Hello)) { 243 inputHelloVersion = ProtocolVersion.SSL20Hello; 244 245 // Per TLS 1.3 protocol, implementation MUST NOT send an SSL 246 // version 2.0 compatible CLIENT-HELLO. 247 if (maximumActiveProtocol.useTLS13PlusSpec()) { 248 outputHelloVersion = maximumActiveProtocol; 249 } else { 250 outputHelloVersion = ProtocolVersion.SSL20Hello; 251 } 252 } else { 253 inputHelloVersion = maximumActiveProtocol; 254 outputHelloVersion = maximumActiveProtocol; 255 } 256 } 257 258 conContext.inputRecord.setHelloVersion(inputHelloVersion); 259 conContext.outputRecord.setHelloVersion(outputHelloVersion); 260 261 if (!conContext.isNegotiated) { 262 conContext.protocolVersion = maximumActiveProtocol; 263 } 264 conContext.outputRecord.setVersion(conContext.protocolVersion); 265 } 266 getActiveProtocols( List<ProtocolVersion> enabledProtocols, List<CipherSuite> enabledCipherSuites, AlgorithmConstraints algorithmConstraints)267 private static List<ProtocolVersion> getActiveProtocols( 268 List<ProtocolVersion> enabledProtocols, 269 List<CipherSuite> enabledCipherSuites, 270 AlgorithmConstraints algorithmConstraints) { 271 boolean enabledSSL20Hello = false; 272 ArrayList<ProtocolVersion> protocols = new ArrayList<>(4); 273 for (ProtocolVersion protocol : enabledProtocols) { 274 if (!enabledSSL20Hello && protocol == ProtocolVersion.SSL20Hello) { 275 enabledSSL20Hello = true; 276 continue; 277 } 278 279 if (!algorithmConstraints.permits( 280 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), 281 protocol.name, null)) { 282 // Ignore disabled protocol. 283 continue; 284 } 285 286 boolean found = false; 287 Map<NamedGroupSpec, Boolean> cachedStatus = 288 new EnumMap<>(NamedGroupSpec.class); 289 for (CipherSuite suite : enabledCipherSuites) { 290 if (suite.isAvailable() && suite.supports(protocol)) { 291 if (isActivatable(suite, 292 algorithmConstraints, cachedStatus)) { 293 protocols.add(protocol); 294 found = true; 295 break; 296 } 297 } else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { 298 SSLLogger.fine( 299 "Ignore unsupported cipher suite: " + suite + 300 " for " + protocol); 301 } 302 } 303 304 if (!found && (SSLLogger.isOn) && SSLLogger.isOn("handshake")) { 305 SSLLogger.fine( 306 "No available cipher suite for " + protocol); 307 } 308 } 309 310 if (!protocols.isEmpty()) { 311 if (enabledSSL20Hello) { 312 protocols.add(ProtocolVersion.SSL20Hello); 313 } 314 Collections.sort(protocols); 315 } 316 317 return Collections.unmodifiableList(protocols); 318 } 319 getActiveCipherSuites( List<ProtocolVersion> enabledProtocols, List<CipherSuite> enabledCipherSuites, AlgorithmConstraints algorithmConstraints)320 private static List<CipherSuite> getActiveCipherSuites( 321 List<ProtocolVersion> enabledProtocols, 322 List<CipherSuite> enabledCipherSuites, 323 AlgorithmConstraints algorithmConstraints) { 324 325 List<CipherSuite> suites = new LinkedList<>(); 326 if (enabledProtocols != null && !enabledProtocols.isEmpty()) { 327 Map<NamedGroupSpec, Boolean> cachedStatus = 328 new EnumMap<>(NamedGroupSpec.class); 329 for (CipherSuite suite : enabledCipherSuites) { 330 if (!suite.isAvailable()) { 331 continue; 332 } 333 334 boolean isSupported = false; 335 for (ProtocolVersion protocol : enabledProtocols) { 336 if (!suite.supports(protocol)) { 337 continue; 338 } 339 if (isActivatable(suite, 340 algorithmConstraints, cachedStatus)) { 341 suites.add(suite); 342 isSupported = true; 343 break; 344 } 345 } 346 347 if (!isSupported && 348 SSLLogger.isOn && SSLLogger.isOn("verbose")) { 349 SSLLogger.finest( 350 "Ignore unsupported cipher suite: " + suite); 351 } 352 } 353 } 354 355 return Collections.unmodifiableList(suites); 356 } 357 358 /** 359 * Parse the handshake record and return the contentType 360 */ getHandshakeType(TransportContext conContext, Plaintext plaintext)361 static byte getHandshakeType(TransportContext conContext, 362 Plaintext plaintext) throws IOException { 363 // struct { 364 // HandshakeType msg_type; /* handshake type */ 365 // uint24 length; /* bytes in message */ 366 // select (HandshakeType) { 367 // ... 368 // } body; 369 // } Handshake; 370 371 if (plaintext.contentType != ContentType.HANDSHAKE.id) { 372 throw conContext.fatal(Alert.INTERNAL_ERROR, 373 "Unexpected operation for record: " + plaintext.contentType); 374 } 375 376 if (plaintext.fragment == null || plaintext.fragment.remaining() < 4) { 377 throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, 378 "Invalid handshake message: insufficient data"); 379 } 380 381 byte handshakeType = (byte)Record.getInt8(plaintext.fragment); 382 int handshakeLen = Record.getInt24(plaintext.fragment); 383 if (handshakeLen != plaintext.fragment.remaining()) { 384 throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, 385 "Invalid handshake message: insufficient handshake body"); 386 } 387 388 return handshakeType; 389 } 390 dispatch(byte handshakeType, Plaintext plaintext)391 void dispatch(byte handshakeType, Plaintext plaintext) throws IOException { 392 if (conContext.transport.useDelegatedTask()) { 393 boolean hasDelegated = !delegatedActions.isEmpty(); 394 if (hasDelegated || 395 (handshakeType != SSLHandshake.FINISHED.id && 396 handshakeType != SSLHandshake.KEY_UPDATE.id && 397 handshakeType != SSLHandshake.NEW_SESSION_TICKET.id)) { 398 if (!hasDelegated) { 399 taskDelegated = false; 400 delegatedThrown = null; 401 } 402 403 // Clone the fragment for delegated actions. 404 // 405 // The plaintext may share the application buffers. It is 406 // fine to use shared buffers if no delegated actions. 407 // However, for delegated actions, the shared buffers may be 408 // polluted in application layer before the delegated actions 409 // executed. 410 ByteBuffer fragment = ByteBuffer.wrap( 411 new byte[plaintext.fragment.remaining()]); 412 fragment.put(plaintext.fragment); 413 fragment = fragment.rewind(); 414 415 delegatedActions.add(new SimpleImmutableEntry<>( 416 handshakeType, 417 fragment 418 )); 419 } else { 420 dispatch(handshakeType, plaintext.fragment); 421 } 422 } else { 423 dispatch(handshakeType, plaintext.fragment); 424 } 425 } 426 dispatch(byte handshakeType, ByteBuffer fragment)427 void dispatch(byte handshakeType, 428 ByteBuffer fragment) throws IOException { 429 SSLConsumer consumer; 430 if (handshakeType == SSLHandshake.HELLO_REQUEST.id) { 431 // For TLS 1.2 and prior versions, the HelloRequest message MAY 432 // be sent by the server at any time. 433 consumer = SSLHandshake.HELLO_REQUEST; 434 } else { 435 consumer = handshakeConsumers.get(handshakeType); 436 } 437 438 if (consumer == null) { 439 throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, 440 "Unexpected handshake message: " + 441 SSLHandshake.nameOf(handshakeType)); 442 } 443 444 try { 445 consumer.consume(this, fragment); 446 } catch (UnsupportedOperationException unsoe) { 447 throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, 448 "Unsupported handshake message: " + 449 SSLHandshake.nameOf(handshakeType), unsoe); 450 } catch (BufferUnderflowException | BufferOverflowException be) { 451 throw conContext.fatal(Alert.DECODE_ERROR, 452 "Illegal handshake message: " + 453 SSLHandshake.nameOf(handshakeType), be); 454 } 455 456 // update handshake hash after handshake message consumption. 457 handshakeHash.consume(); 458 } 459 kickstart()460 abstract void kickstart() throws IOException; 461 462 /** 463 * Check if the given cipher suite is enabled and available within 464 * the current active cipher suites. 465 * 466 * Does not check if the required server certificates are available. 467 */ isNegotiable(CipherSuite cs)468 boolean isNegotiable(CipherSuite cs) { 469 return isNegotiable(activeCipherSuites, cs); 470 } 471 472 /** 473 * Check if the given cipher suite is enabled and available within 474 * the proposed cipher suite list. 475 * 476 * Does not check if the required server certificates are available. 477 */ isNegotiable( List<CipherSuite> proposed, CipherSuite cs)478 static final boolean isNegotiable( 479 List<CipherSuite> proposed, CipherSuite cs) { 480 return proposed.contains(cs) && cs.isNegotiable(); 481 } 482 483 /** 484 * Check if the given cipher suite is enabled and available within 485 * the proposed cipher suite list and specific protocol version. 486 * 487 * Does not check if the required server certificates are available. 488 */ isNegotiable(List<CipherSuite> proposed, ProtocolVersion protocolVersion, CipherSuite cs)489 static final boolean isNegotiable(List<CipherSuite> proposed, 490 ProtocolVersion protocolVersion, CipherSuite cs) { 491 return proposed.contains(cs) && 492 cs.isNegotiable() && cs.supports(protocolVersion); 493 } 494 495 /** 496 * Check if the given protocol version is enabled and available. 497 */ isNegotiable(ProtocolVersion protocolVersion)498 boolean isNegotiable(ProtocolVersion protocolVersion) { 499 return activeProtocols.contains(protocolVersion); 500 } 501 502 /** 503 * Set the active protocol version and propagate it to the SSLSocket 504 * and our handshake streams. Called from ClientHandshaker 505 * and ServerHandshaker with the negotiated protocol version. 506 */ setVersion(ProtocolVersion protocolVersion)507 void setVersion(ProtocolVersion protocolVersion) { 508 this.conContext.protocolVersion = protocolVersion; 509 } 510 isActivatable(CipherSuite suite, AlgorithmConstraints algorithmConstraints, Map<NamedGroupSpec, Boolean> cachedStatus)511 private static boolean isActivatable(CipherSuite suite, 512 AlgorithmConstraints algorithmConstraints, 513 Map<NamedGroupSpec, Boolean> cachedStatus) { 514 515 if (algorithmConstraints.permits( 516 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), suite.name, null)) { 517 if (suite.keyExchange == null) { 518 // TLS 1.3, no definition of key exchange in cipher suite. 519 return true; 520 } 521 522 // Is at least one of the group types available? 523 boolean groupAvailable, retval = false; 524 NamedGroupSpec[] groupTypes = suite.keyExchange.groupTypes; 525 for (NamedGroupSpec groupType : groupTypes) { 526 if (groupType != NAMED_GROUP_NONE) { 527 Boolean checkedStatus = cachedStatus.get(groupType); 528 if (checkedStatus == null) { 529 groupAvailable = SupportedGroups.isActivatable( 530 algorithmConstraints, groupType); 531 cachedStatus.put(groupType, groupAvailable); 532 533 if (!groupAvailable && 534 SSLLogger.isOn && SSLLogger.isOn("verbose")) { 535 SSLLogger.fine( 536 "No activated named group in " + groupType); 537 } 538 } else { 539 groupAvailable = checkedStatus; 540 } 541 542 retval |= groupAvailable; 543 } else { 544 retval |= true; 545 } 546 } 547 548 if (!retval && SSLLogger.isOn && SSLLogger.isOn("verbose")) { 549 SSLLogger.fine("No active named group(s), ignore " + suite); 550 } 551 552 return retval; 553 554 } else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { 555 SSLLogger.fine("Ignore disabled cipher suite: " + suite); 556 } 557 558 return false; 559 } 560 getRequestedServerNames()561 List<SNIServerName> getRequestedServerNames() { 562 if (requestedServerNames == null) { 563 return Collections.emptyList(); 564 } 565 return requestedServerNames; 566 } 567 } 568 569