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