1 /*
   2  * Copyright (c) 2018, 2020, 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.security.AccessControlContext;
  29 import java.security.AccessController;
  30 import java.security.AlgorithmConstraints;
  31 import java.security.NoSuchAlgorithmException;
  32 import java.util.ArrayList;
  33 import java.util.Arrays;
  34 import java.util.Collection;
  35 import java.util.Collections;
  36 import java.util.HashMap;
  37 import java.util.List;
  38 import java.util.function.BiFunction;
  39 import javax.net.ssl.HandshakeCompletedListener;
  40 import javax.net.ssl.SNIMatcher;
  41 import javax.net.ssl.SNIServerName;
  42 import javax.net.ssl.SSLEngine;
  43 import javax.net.ssl.SSLParameters;
  44 import javax.net.ssl.SSLSocket;
  45 import sun.security.action.GetIntegerAction;
  46 import sun.security.ssl.SSLExtension.ClientExtensions;
  47 import sun.security.ssl.SSLExtension.ServerExtensions;
  48 
  49 /**
  50  * SSL/TLS configuration.
  51  */
  52 final class SSLConfiguration implements Cloneable {
  53     // configurations with SSLParameters
  54     AlgorithmConstraints        userSpecifiedAlgorithmConstraints;
  55     List<ProtocolVersion>       enabledProtocols;
  56     List<CipherSuite>           enabledCipherSuites;
  57     ClientAuthType              clientAuthType;
  58     String                      identificationProtocol;
  59     List<SNIServerName>         serverNames;
  60     Collection<SNIMatcher>      sniMatchers;
  61     String[]                    applicationProtocols;
  62     boolean                     preferLocalCipherSuites;
  63     int                         maximumPacketSize = 0;
  64 
  65     // the maximum protocol version of enabled protocols
  66     ProtocolVersion             maximumProtocolVersion;
  67 
  68     // Configurations per SSLSocket or SSLEngine instance.
  69     boolean                     isClientMode;
  70     boolean                     enableSessionCreation;
  71 
  72     // the application layer protocol negotiation configuration
  73     BiFunction<SSLSocket, List<String>, String> socketAPSelector;
  74     BiFunction<SSLEngine, List<String>, String> engineAPSelector;
  75 
  76     HashMap<HandshakeCompletedListener, AccessControlContext>
  77                                 handshakeListeners;
  78 
  79     boolean                     noSniExtension;
  80     boolean                     noSniMatcher;
  81 
  82     // To switch off the extended_master_secret extension.
  83     static final boolean useExtendedMasterSecret;
  84 
  85     // Allow session resumption without Extended Master Secret extension.
  86     static final boolean allowLegacyResumption =
  87         Utilities.getBooleanProperty("jdk.tls.allowLegacyResumption", true);
  88 
  89     // Allow full handshake without Extended Master Secret extension.
  90     static final boolean allowLegacyMasterSecret =
  91         Utilities.getBooleanProperty("jdk.tls.allowLegacyMasterSecret", true);
  92 
  93     // Allow full handshake without Extended Master Secret extension.
  94     static final boolean useCompatibilityMode = Utilities.getBooleanProperty(
  95             "jdk.tls.client.useCompatibilityMode", true);
  96 
  97     // Respond a close_notify alert if receiving close_notify alert.
  98     static final boolean acknowledgeCloseNotify  = Utilities.getBooleanProperty(
  99             "jdk.tls.acknowledgeCloseNotify", false);
 100 
 101     // Set the max size limit for Handshake Message to 2^15
 102     static final int maxHandshakeMessageSize = AccessController.doPrivileged(
 103             new GetIntegerAction("jdk.tls.maxHandshakeMessageSize", 32768)).intValue();
 104 
 105     // Set the max certificate chain length to 10
 106     static final int maxCertificateChainLength = AccessController.doPrivileged(
 107             new GetIntegerAction("jdk.tls.maxCertificateChainLength", 10)).intValue();
 108 
 109     // Is the extended_master_secret extension supported?
 110     static {
 111         boolean supportExtendedMasterSecret = Utilities.getBooleanProperty(
 112                     "jdk.tls.useExtendedMasterSecret", true);
 113         if (supportExtendedMasterSecret) {
 114             try {
 115                 JsseJce.getKeyGenerator("SunTlsExtendedMasterSecret");
 116             } catch (NoSuchAlgorithmException nae) {
 117                 supportExtendedMasterSecret = false;
 118             }
 119         }
 120         useExtendedMasterSecret = supportExtendedMasterSecret;
 121     }
 122 
 123     SSLConfiguration(SSLContextImpl sslContext, boolean isClientMode) {
 124 
 125         // Configurations with SSLParameters, default values.
 126         this.userSpecifiedAlgorithmConstraints =
 127                 SSLAlgorithmConstraints.DEFAULT;
 128         this.enabledProtocols =
 129                 sslContext.getDefaultProtocolVersions(!isClientMode);
 130         this.enabledCipherSuites =
 131                 sslContext.getDefaultCipherSuites(!isClientMode);
 132         this.clientAuthType = ClientAuthType.CLIENT_AUTH_NONE;
 133 
 134         this.identificationProtocol = null;
 135         this.serverNames = Collections.<SNIServerName>emptyList();
 136         this.sniMatchers = Collections.<SNIMatcher>emptyList();
 137         this.preferLocalCipherSuites = false;
 138 
 139         this.applicationProtocols = new String[0];
 140 
 141         this.maximumProtocolVersion = ProtocolVersion.NONE;
 142         for (ProtocolVersion pv : enabledProtocols) {
 143             if (pv.compareTo(maximumProtocolVersion) > 0) {
 144                 this.maximumProtocolVersion = pv;
 145             }
 146         }
 147 
 148         // Configurations per SSLSocket or SSLEngine instance.
 149         this.isClientMode = isClientMode;
 150         this.enableSessionCreation = true;
 151         this.socketAPSelector = null;
 152         this.engineAPSelector = null;
 153 
 154         this.handshakeListeners = null;
 155         this.noSniExtension = false;
 156         this.noSniMatcher = false;
 157     }
 158 
 159     SSLParameters getSSLParameters() {
 160         SSLParameters params = new SSLParameters();
 161 
 162         params.setAlgorithmConstraints(this.userSpecifiedAlgorithmConstraints);
 163         params.setProtocols(ProtocolVersion.toStringArray(enabledProtocols));
 164         params.setCipherSuites(CipherSuite.namesOf(enabledCipherSuites));
 165         switch (this.clientAuthType) {
 166             case CLIENT_AUTH_REQUIRED:
 167                 params.setNeedClientAuth(true);
 168                 break;
 169             case CLIENT_AUTH_REQUESTED:
 170                 params.setWantClientAuth(true);
 171                 break;
 172             default:
 173                 params.setWantClientAuth(false);
 174         }
 175         params.setEndpointIdentificationAlgorithm(this.identificationProtocol);
 176 
 177         if (serverNames.isEmpty() && !noSniExtension) {
 178             // 'null' indicates none has been set
 179             params.setServerNames(null);
 180         } else {
 181             params.setServerNames(this.serverNames);
 182         }
 183 
 184         if (sniMatchers.isEmpty() && !noSniMatcher) {
 185             // 'null' indicates none has been set
 186             params.setSNIMatchers(null);
 187         } else {
 188             params.setSNIMatchers(this.sniMatchers);
 189         }
 190 
 191         params.setApplicationProtocols(this.applicationProtocols);
 192         params.setUseCipherSuitesOrder(this.preferLocalCipherSuites);
 193 
 194         return params;
 195     }
 196 
 197     void setSSLParameters(SSLParameters params) {
 198         AlgorithmConstraints ac = params.getAlgorithmConstraints();
 199         if (ac != null) {
 200             this.userSpecifiedAlgorithmConstraints = ac;
 201         }   // otherwise, use the default value
 202 
 203         String[] sa = params.getCipherSuites();
 204         if (sa != null) {
 205             this.enabledCipherSuites = CipherSuite.validValuesOf(sa);
 206         }   // otherwise, use the default values
 207 
 208         sa = params.getProtocols();
 209         if (sa != null) {
 210             this.enabledProtocols = ProtocolVersion.namesOf(sa);
 211 
 212             this.maximumProtocolVersion = ProtocolVersion.NONE;
 213             for (ProtocolVersion pv : enabledProtocols) {
 214                 if (pv.compareTo(maximumProtocolVersion) > 0) {
 215                     this.maximumProtocolVersion = pv;
 216                 }
 217             }
 218         }   // otherwise, use the default values
 219 
 220         if (params.getNeedClientAuth()) {
 221             this.clientAuthType = ClientAuthType.CLIENT_AUTH_REQUIRED;
 222         } else if (params.getWantClientAuth()) {
 223             this.clientAuthType = ClientAuthType.CLIENT_AUTH_REQUESTED;
 224         } else {
 225             this.clientAuthType = ClientAuthType.CLIENT_AUTH_NONE;
 226         }
 227 
 228         String s = params.getEndpointIdentificationAlgorithm();
 229         if (s != null) {
 230             this.identificationProtocol = s;
 231         }   // otherwise, use the default value
 232 
 233         List<SNIServerName> sniNames = params.getServerNames();
 234         if (sniNames != null) {
 235             this.noSniExtension = sniNames.isEmpty();
 236             this.serverNames = sniNames;
 237         }   // null if none has been set
 238 
 239         Collection<SNIMatcher> matchers = params.getSNIMatchers();
 240         if (matchers != null) {
 241             this.noSniMatcher = matchers.isEmpty();
 242             this.sniMatchers = matchers;
 243         }   // null if none has been set
 244 
 245         sa = params.getApplicationProtocols();
 246         if (sa != null) {
 247             this.applicationProtocols = sa;
 248         }   // otherwise, use the default values
 249 
 250         this.preferLocalCipherSuites = params.getUseCipherSuitesOrder();
 251     }
 252 
 253     // SSLSocket only
 254     void addHandshakeCompletedListener(
 255             HandshakeCompletedListener listener) {
 256 
 257         if (handshakeListeners == null) {
 258             handshakeListeners = new HashMap<>(4);
 259         }
 260 
 261         handshakeListeners.put(listener, AccessController.getContext());
 262     }
 263 
 264     // SSLSocket only
 265     void removeHandshakeCompletedListener(
 266             HandshakeCompletedListener listener) {
 267 
 268         if (handshakeListeners == null) {
 269             throw new IllegalArgumentException("no listeners");
 270         }
 271 
 272         if (handshakeListeners.remove(listener) == null) {
 273             throw new IllegalArgumentException("listener not registered");
 274         }
 275 
 276         if (handshakeListeners.isEmpty()) {
 277             handshakeListeners = null;
 278         }
 279     }
 280 
 281     /**
 282      * Return true if the extension is available.
 283      */
 284     boolean isAvailable(SSLExtension extension) {
 285         for (ProtocolVersion protocolVersion : enabledProtocols) {
 286             if (extension.isAvailable(protocolVersion)) {
 287                 if (isClientMode ?
 288                         ClientExtensions.defaults.contains(extension) :
 289                         ServerExtensions.defaults.contains(extension)) {
 290                     return true;
 291                 }
 292             }
 293         }
 294 
 295         return false;
 296     }
 297 
 298     /**
 299      * Return true if the extension is available for the specific protocol.
 300      */
 301     boolean isAvailable(SSLExtension extension,
 302             ProtocolVersion protocolVersion) {
 303         return extension.isAvailable(protocolVersion) &&
 304                 (isClientMode ? ClientExtensions.defaults.contains(extension) :
 305                                 ServerExtensions.defaults.contains(extension));
 306     }
 307 
 308     /**
 309      * Get the enabled extensions for the specific handshake message.
 310      *
 311      * Used to consume handshake extensions.
 312      */
 313     SSLExtension[] getEnabledExtensions(SSLHandshake handshakeType) {
 314         List<SSLExtension> extensions = new ArrayList<>();
 315         for (SSLExtension extension : SSLExtension.values()) {
 316             if (extension.handshakeType == handshakeType) {
 317                 if (isAvailable(extension)) {
 318                     extensions.add(extension);
 319                 }
 320             }
 321         }
 322 
 323         return extensions.toArray(new SSLExtension[0]);
 324     }
 325 
 326     /**
 327      * Get the enabled extensions for the specific handshake message, excluding
 328      * the specified extensions.
 329      *
 330      * Used to consume handshake extensions.
 331      */
 332     SSLExtension[] getExclusiveExtensions(SSLHandshake handshakeType,
 333             List<SSLExtension> excluded) {
 334         List<SSLExtension> extensions = new ArrayList<>();
 335         for (SSLExtension extension : SSLExtension.values()) {
 336             if (extension.handshakeType == handshakeType) {
 337                 if (isAvailable(extension) && !excluded.contains(extension)) {
 338                     extensions.add(extension);
 339                 }
 340             }
 341         }
 342 
 343         return extensions.toArray(new SSLExtension[0]);
 344     }
 345 
 346     /**
 347      * Get the enabled extensions for the specific handshake message
 348      * and the specific protocol version.
 349      *
 350      * Used to produce handshake extensions after handshake protocol
 351      * version negotiation.
 352      */
 353     SSLExtension[] getEnabledExtensions(
 354             SSLHandshake handshakeType, ProtocolVersion protocolVersion) {
 355         return getEnabledExtensions(
 356             handshakeType, Arrays.asList(protocolVersion));
 357     }
 358 
 359     /**
 360      * Get the enabled extensions for the specific handshake message
 361      * and the specific protocol versions.
 362      *
 363      * Used to produce ClientHello extensions before handshake protocol
 364      * version negotiation.
 365      */
 366     SSLExtension[] getEnabledExtensions(
 367             SSLHandshake handshakeType, List<ProtocolVersion> activeProtocols) {
 368         List<SSLExtension> extensions = new ArrayList<>();
 369         for (SSLExtension extension : SSLExtension.values()) {
 370             if (extension.handshakeType == handshakeType) {
 371                 if (!isAvailable(extension)) {
 372                     continue;
 373                 }
 374 
 375                 for (ProtocolVersion protocolVersion : activeProtocols) {
 376                     if (extension.isAvailable(protocolVersion)) {
 377                         extensions.add(extension);
 378                         break;
 379                     }
 380                 }
 381             }
 382         }
 383 
 384         return extensions.toArray(new SSLExtension[0]);
 385     }
 386 
 387     @Override
 388     @SuppressWarnings({"unchecked", "CloneDeclaresCloneNotSupported"})
 389     public Object clone() {
 390         // Note that only references to the configurations are copied.
 391         try {
 392             SSLConfiguration config = (SSLConfiguration)super.clone();
 393             if (handshakeListeners != null) {
 394                 config.handshakeListeners =
 395                     (HashMap<HandshakeCompletedListener, AccessControlContext>)
 396                             handshakeListeners.clone();
 397             }
 398 
 399             return config;
 400         } catch (CloneNotSupportedException cnse) {
 401             // unlikely
 402         }
 403 
 404         return null;    // unlikely
 405     }
 406 }