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