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