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.SupportedGroupsExtension.NamedGroup; 50 import sun.security.ssl.SupportedGroupsExtension.NamedGroupType; 51 import static sun.security.ssl.SupportedGroupsExtension.NamedGroupType.*; 52 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups; 53 54 abstract class HandshakeContext implements ConnectionContext { 55 // System properties 56 57 // By default, disable the unsafe legacy session renegotiation. 58 static final boolean allowUnsafeRenegotiation = 59 Utilities.getBooleanProperty( 60 "sun.security.ssl.allowUnsafeRenegotiation", false); 61 62 // For maximum interoperability and backward compatibility, RFC 5746 63 // allows server (or client) to accept ClientHello (or ServerHello) 64 // message without the secure renegotiation_info extension or SCSV. 65 // 66 // For maximum security, RFC 5746 also allows server (or client) to 67 // reject such message with a fatal "handshake_failure" alert. 68 // 69 // By default, allow such legacy hello messages. 70 static final boolean allowLegacyHelloMessages = 71 Utilities.getBooleanProperty( 72 "sun.security.ssl.allowLegacyHelloMessages", true); 73 74 // registered handshake message actors 75 LinkedHashMap<Byte, SSLConsumer> handshakeConsumers; 76 final HashMap<Byte, HandshakeProducer> handshakeProducers; 77 78 // context 79 final SSLContextImpl sslContext; 80 final TransportContext conContext; 81 final SSLConfiguration sslConfig; 82 83 // consolidated parameters 84 final List<ProtocolVersion> activeProtocols; 85 final List<CipherSuite> activeCipherSuites; 86 final AlgorithmConstraints algorithmConstraints; 87 final ProtocolVersion maximumActiveProtocol; 88 89 // output stream 90 final HandshakeOutStream handshakeOutput; 91 92 // handshake transcript hash 93 final HandshakeHash handshakeHash; 94 95 // negotiated security parameters 96 SSLSessionImpl handshakeSession; 97 boolean handshakeFinished; 98 // boolean isInvalidated; 99 100 boolean kickstartMessageDelivered; 101 102 // Resumption 103 boolean isResumption; 104 SSLSessionImpl resumingSession; 105 106 final Queue<Map.Entry<Byte, ByteBuffer>> delegatedActions; 107 volatile boolean taskDelegated = false; 108 volatile Exception delegatedThrown = null; 109 110 ProtocolVersion negotiatedProtocol; 111 CipherSuite negotiatedCipherSuite; 112 final List<SSLPossession> handshakePossessions; 113 final List<SSLCredentials> handshakeCredentials; 114 SSLKeyDerivation handshakeKeyDerivation; 115 SSLKeyExchange handshakeKeyExchange; 116 SecretKey baseReadSecret; 117 SecretKey baseWriteSecret; 118 119 // protocol version being established 120 int clientHelloVersion; 121 String applicationProtocol; 122 123 RandomCookie clientHelloRandom; 124 RandomCookie serverHelloRandom; 125 byte[] certRequestContext; 126 127 //////////////////// 128 // Extensions 129 130 // the extensions used in the handshake 131 final Map<SSLExtension, SSLExtension.SSLExtensionSpec> 132 handshakeExtensions; 133 134 // MaxFragmentLength 135 int maxFragmentLength; 136 137 // SignatureScheme 138 List<SignatureScheme> localSupportedSignAlgs; 139 List<SignatureScheme> peerRequestedSignatureSchemes; 140 List<SignatureScheme> peerRequestedCertSignSchemes; 141 142 // Known authorities 143 X500Principal[] peerSupportedAuthorities = null; 144 145 // SupportedGroups 146 List<NamedGroup> clientRequestedNamedGroups; 147 148 // HelloRetryRequest 149 NamedGroup serverSelectedNamedGroup; 150 151 // if server name indicator is negotiated 152 // 153 // May need a public API for the indication in the future. 154 List<SNIServerName> requestedServerNames; 155 SNIServerName negotiatedServerName; 156 157 // OCSP Stapling info 158 boolean staplingActive = false; 159 160 protected HandshakeContext(SSLContextImpl sslContext, 161 TransportContext conContext) throws IOException { 162 this.sslContext = sslContext; 163 this.conContext = conContext; 164 this.sslConfig = (SSLConfiguration)conContext.sslConfig.clone(); 165 166 this.activeProtocols = getActiveProtocols(sslConfig.enabledProtocols, 167 sslConfig.enabledCipherSuites, sslConfig.algorithmConstraints); 168 if (activeProtocols.isEmpty()) { 169 throw new SSLHandshakeException( 170 "No appropriate protocol (protocol is disabled or " + 171 "cipher suites are inappropriate)"); 172 } 173 174 ProtocolVersion maximumVersion = ProtocolVersion.NONE; 175 for (ProtocolVersion pv : this.activeProtocols) { 176 if (maximumVersion == ProtocolVersion.NONE || 177 pv.compare(maximumVersion) > 0) { 178 maximumVersion = pv; 179 } 180 } 181 this.maximumActiveProtocol = maximumVersion; 182 this.activeCipherSuites = getActiveCipherSuites(this.activeProtocols, 183 sslConfig.enabledCipherSuites, sslConfig.algorithmConstraints); 184 if (activeCipherSuites.isEmpty()) { 185 throw new SSLHandshakeException("No appropriate cipher suite"); 186 } 187 this.algorithmConstraints = 188 new SSLAlgorithmConstraints(sslConfig.algorithmConstraints); 189 190 this.handshakeConsumers = new LinkedHashMap<>(); 191 this.handshakeProducers = new HashMap<>(); 192 this.handshakeHash = conContext.inputRecord.handshakeHash; 193 this.handshakeOutput = new HandshakeOutStream(conContext.outputRecord); 194 195 this.handshakeFinished = false; 196 this.kickstartMessageDelivered = false; 197 198 this.delegatedActions = new LinkedList<>(); 199 this.handshakeExtensions = new HashMap<>(); 200 this.handshakePossessions = new LinkedList<>(); 201 this.handshakeCredentials = new LinkedList<>(); 202 this.requestedServerNames = null; 203 this.negotiatedServerName = null; 204 this.negotiatedCipherSuite = conContext.cipherSuite; 205 initialize(); 206 } 207 208 /** 209 * Constructor for PostHandshakeContext 210 */ 211 HandshakeContext(TransportContext conContext) { 212 this.sslContext = conContext.sslContext; 213 this.conContext = conContext; 214 this.sslConfig = conContext.sslConfig; 215 216 this.negotiatedProtocol = conContext.protocolVersion; 217 this.negotiatedCipherSuite = conContext.cipherSuite; 218 this.handshakeOutput = new HandshakeOutStream(conContext.outputRecord); 219 this.delegatedActions = new LinkedList<>(); 220 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. 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 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<NamedGroupType, Boolean> cachedStatus = 286 new EnumMap<>(NamedGroupType.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 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<NamedGroupType, Boolean> cachedStatus = 326 new EnumMap<>(NamedGroupType.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 */ 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 505 void setVersion(ProtocolVersion protocolVersion) { 506 this.conContext.protocolVersion = protocolVersion; 507 } 508 509 private static boolean isActivatable(CipherSuite suite, 510 AlgorithmConstraints algorithmConstraints, 511 Map<NamedGroupType, 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 boolean available; 521 NamedGroupType groupType = suite.keyExchange.groupType; 522 if (groupType != NAMED_GROUP_NONE) { 523 Boolean checkedStatus = cachedStatus.get(groupType); 524 if (checkedStatus == null) { 525 available = SupportedGroups.isActivatable( 526 algorithmConstraints, groupType); 527 cachedStatus.put(groupType, available); 528 529 if (!available && 530 SSLLogger.isOn && SSLLogger.isOn("verbose")) { 531 SSLLogger.fine("No activated named group"); 532 } 533 } else { 534 available = checkedStatus; 535 } 536 537 if (!available && SSLLogger.isOn && SSLLogger.isOn("verbose")) { 538 SSLLogger.fine( 539 "No active named group, ignore " + suite); 540 } 541 return available; 542 } else { 543 return true; 544 } 545 } else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { 546 SSLLogger.fine("Ignore disabled cipher suite: " + suite); 547 } 548 549 return false; 550 } 551 552 List<SNIServerName> getRequestedServerNames() { 553 if (requestedServerNames == null) { 554 return Collections.<SNIServerName>emptyList(); 555 } 556 return requestedServerNames; 557 } 558 } 559