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