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 }