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 }