29 import java.nio.BufferOverflowException;
30 import java.nio.BufferUnderflowException;
31 import java.nio.ByteBuffer;
32 import java.security.AlgorithmConstraints;
33 import java.security.CryptoPrimitive;
34 import java.util.AbstractMap.SimpleImmutableEntry;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.EnumMap;
38 import java.util.EnumSet;
39 import java.util.HashMap;
40 import java.util.LinkedHashMap;
41 import java.util.LinkedList;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Queue;
45 import javax.crypto.SecretKey;
46 import javax.net.ssl.SNIServerName;
47 import javax.net.ssl.SSLHandshakeException;
48 import javax.security.auth.x500.X500Principal;
49 import sun.security.ssl.NamedGroup.NamedGroupType;
50 import static sun.security.ssl.NamedGroup.NamedGroupType.*;
51 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
52
53 abstract class HandshakeContext implements ConnectionContext {
54 // System properties
55
56 // By default, disable the unsafe legacy session renegotiation.
57 static final boolean allowUnsafeRenegotiation =
58 Utilities.getBooleanProperty(
59 "sun.security.ssl.allowUnsafeRenegotiation", false);
60
61 // For maximum interoperability and backward compatibility, RFC 5746
62 // allows server (or client) to accept ClientHello (or ServerHello)
63 // message without the secure renegotiation_info extension or SCSV.
64 //
65 // For maximum security, RFC 5746 also allows server (or client) to
66 // reject such message with a fatal "handshake_failure" alert.
67 //
68 // By default, allow such legacy hello messages.
69 static final boolean allowLegacyHelloMessages =
70 Utilities.getBooleanProperty(
265 private static List<ProtocolVersion> getActiveProtocols(
266 List<ProtocolVersion> enabledProtocols,
267 List<CipherSuite> enabledCipherSuites,
268 AlgorithmConstraints algorithmConstraints) {
269 boolean enabledSSL20Hello = false;
270 ArrayList<ProtocolVersion> protocols = new ArrayList<>(4);
271 for (ProtocolVersion protocol : enabledProtocols) {
272 if (!enabledSSL20Hello && protocol == ProtocolVersion.SSL20Hello) {
273 enabledSSL20Hello = true;
274 continue;
275 }
276
277 if (!algorithmConstraints.permits(
278 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
279 protocol.name, null)) {
280 // Ignore disabled protocol.
281 continue;
282 }
283
284 boolean found = false;
285 Map<NamedGroupType, Boolean> cachedStatus =
286 new EnumMap<>(NamedGroupType.class);
287 for (CipherSuite suite : enabledCipherSuites) {
288 if (suite.isAvailable() && suite.supports(protocol)) {
289 if (isActivatable(suite,
290 algorithmConstraints, cachedStatus)) {
291 protocols.add(protocol);
292 found = true;
293 break;
294 }
295 } else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
296 SSLLogger.fine(
297 "Ignore unsupported cipher suite: " + suite +
298 " for " + protocol);
299 }
300 }
301
302 if (!found && (SSLLogger.isOn) && SSLLogger.isOn("handshake")) {
303 SSLLogger.fine(
304 "No available cipher suite for " + protocol);
305 }
306 }
307
308 if (!protocols.isEmpty()) {
309 if (enabledSSL20Hello) {
310 protocols.add(ProtocolVersion.SSL20Hello);
311 }
312 Collections.sort(protocols);
313 }
314
315 return Collections.unmodifiableList(protocols);
316 }
317
318 private static List<CipherSuite> getActiveCipherSuites(
319 List<ProtocolVersion> enabledProtocols,
320 List<CipherSuite> enabledCipherSuites,
321 AlgorithmConstraints algorithmConstraints) {
322
323 List<CipherSuite> suites = new LinkedList<>();
324 if (enabledProtocols != null && !enabledProtocols.isEmpty()) {
325 Map<NamedGroupType, Boolean> cachedStatus =
326 new EnumMap<>(NamedGroupType.class);
327 for (CipherSuite suite : enabledCipherSuites) {
328 if (!suite.isAvailable()) {
329 continue;
330 }
331
332 boolean isSupported = false;
333 for (ProtocolVersion protocol : enabledProtocols) {
334 if (!suite.supports(protocol)) {
335 continue;
336 }
337 if (isActivatable(suite,
338 algorithmConstraints, cachedStatus)) {
339 suites.add(suite);
340 isSupported = true;
341 break;
342 }
343 }
344
345 if (!isSupported &&
346 SSLLogger.isOn && SSLLogger.isOn("verbose")) {
491 }
492
493 /**
494 * Check if the given protocol version is enabled and available.
495 */
496 boolean isNegotiable(ProtocolVersion protocolVersion) {
497 return activeProtocols.contains(protocolVersion);
498 }
499
500 /**
501 * Set the active protocol version and propagate it to the SSLSocket
502 * and our handshake streams. Called from ClientHandshaker
503 * and ServerHandshaker with the negotiated protocol version.
504 */
505 void setVersion(ProtocolVersion protocolVersion) {
506 this.conContext.protocolVersion = protocolVersion;
507 }
508
509 private static boolean isActivatable(CipherSuite suite,
510 AlgorithmConstraints algorithmConstraints,
511 Map<NamedGroupType, Boolean> cachedStatus) {
512
513 if (algorithmConstraints.permits(
514 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), suite.name, null)) {
515 if (suite.keyExchange == null) {
516 // TLS 1.3, no definition of key exchange in cipher suite.
517 return true;
518 }
519
520 // Is at least one of the group types available?
521 boolean groupAvailable, retval = false;
522 NamedGroupType[] groupTypes = suite.keyExchange.groupTypes;
523 for (NamedGroupType groupType : groupTypes) {
524 if (groupType != NAMED_GROUP_NONE) {
525 Boolean checkedStatus = cachedStatus.get(groupType);
526 if (checkedStatus == null) {
527 groupAvailable = SupportedGroups.isActivatable(
528 algorithmConstraints, groupType);
529 cachedStatus.put(groupType, groupAvailable);
530
531 if (!groupAvailable &&
532 SSLLogger.isOn && SSLLogger.isOn("verbose")) {
533 SSLLogger.fine(
534 "No activated named group in " + groupType);
535 }
536 } else {
537 groupAvailable = checkedStatus;
538 }
539
540 retval |= groupAvailable;
541 } else {
542 retval |= true;
543 }
|
29 import java.nio.BufferOverflowException;
30 import java.nio.BufferUnderflowException;
31 import java.nio.ByteBuffer;
32 import java.security.AlgorithmConstraints;
33 import java.security.CryptoPrimitive;
34 import java.util.AbstractMap.SimpleImmutableEntry;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.EnumMap;
38 import java.util.EnumSet;
39 import java.util.HashMap;
40 import java.util.LinkedHashMap;
41 import java.util.LinkedList;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Queue;
45 import javax.crypto.SecretKey;
46 import javax.net.ssl.SNIServerName;
47 import javax.net.ssl.SSLHandshakeException;
48 import javax.security.auth.x500.X500Principal;
49 import sun.security.ssl.NamedGroup.NamedGroupSpec;
50 import static sun.security.ssl.NamedGroup.NamedGroupSpec.*;
51 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
52
53 abstract class HandshakeContext implements ConnectionContext {
54 // System properties
55
56 // By default, disable the unsafe legacy session renegotiation.
57 static final boolean allowUnsafeRenegotiation =
58 Utilities.getBooleanProperty(
59 "sun.security.ssl.allowUnsafeRenegotiation", false);
60
61 // For maximum interoperability and backward compatibility, RFC 5746
62 // allows server (or client) to accept ClientHello (or ServerHello)
63 // message without the secure renegotiation_info extension or SCSV.
64 //
65 // For maximum security, RFC 5746 also allows server (or client) to
66 // reject such message with a fatal "handshake_failure" alert.
67 //
68 // By default, allow such legacy hello messages.
69 static final boolean allowLegacyHelloMessages =
70 Utilities.getBooleanProperty(
265 private static List<ProtocolVersion> getActiveProtocols(
266 List<ProtocolVersion> enabledProtocols,
267 List<CipherSuite> enabledCipherSuites,
268 AlgorithmConstraints algorithmConstraints) {
269 boolean enabledSSL20Hello = false;
270 ArrayList<ProtocolVersion> protocols = new ArrayList<>(4);
271 for (ProtocolVersion protocol : enabledProtocols) {
272 if (!enabledSSL20Hello && protocol == ProtocolVersion.SSL20Hello) {
273 enabledSSL20Hello = true;
274 continue;
275 }
276
277 if (!algorithmConstraints.permits(
278 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
279 protocol.name, null)) {
280 // Ignore disabled protocol.
281 continue;
282 }
283
284 boolean found = false;
285 Map<NamedGroupSpec, Boolean> cachedStatus =
286 new EnumMap<>(NamedGroupSpec.class);
287 for (CipherSuite suite : enabledCipherSuites) {
288 if (suite.isAvailable() && suite.supports(protocol)) {
289 if (isActivatable(suite,
290 algorithmConstraints, cachedStatus)) {
291 protocols.add(protocol);
292 found = true;
293 break;
294 }
295 } else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
296 SSLLogger.fine(
297 "Ignore unsupported cipher suite: " + suite +
298 " for " + protocol);
299 }
300 }
301
302 if (!found && (SSLLogger.isOn) && SSLLogger.isOn("handshake")) {
303 SSLLogger.fine(
304 "No available cipher suite for " + protocol);
305 }
306 }
307
308 if (!protocols.isEmpty()) {
309 if (enabledSSL20Hello) {
310 protocols.add(ProtocolVersion.SSL20Hello);
311 }
312 Collections.sort(protocols);
313 }
314
315 return Collections.unmodifiableList(protocols);
316 }
317
318 private static List<CipherSuite> getActiveCipherSuites(
319 List<ProtocolVersion> enabledProtocols,
320 List<CipherSuite> enabledCipherSuites,
321 AlgorithmConstraints algorithmConstraints) {
322
323 List<CipherSuite> suites = new LinkedList<>();
324 if (enabledProtocols != null && !enabledProtocols.isEmpty()) {
325 Map<NamedGroupSpec, Boolean> cachedStatus =
326 new EnumMap<>(NamedGroupSpec.class);
327 for (CipherSuite suite : enabledCipherSuites) {
328 if (!suite.isAvailable()) {
329 continue;
330 }
331
332 boolean isSupported = false;
333 for (ProtocolVersion protocol : enabledProtocols) {
334 if (!suite.supports(protocol)) {
335 continue;
336 }
337 if (isActivatable(suite,
338 algorithmConstraints, cachedStatus)) {
339 suites.add(suite);
340 isSupported = true;
341 break;
342 }
343 }
344
345 if (!isSupported &&
346 SSLLogger.isOn && SSLLogger.isOn("verbose")) {
491 }
492
493 /**
494 * Check if the given protocol version is enabled and available.
495 */
496 boolean isNegotiable(ProtocolVersion protocolVersion) {
497 return activeProtocols.contains(protocolVersion);
498 }
499
500 /**
501 * Set the active protocol version and propagate it to the SSLSocket
502 * and our handshake streams. Called from ClientHandshaker
503 * and ServerHandshaker with the negotiated protocol version.
504 */
505 void setVersion(ProtocolVersion protocolVersion) {
506 this.conContext.protocolVersion = protocolVersion;
507 }
508
509 private static boolean isActivatable(CipherSuite suite,
510 AlgorithmConstraints algorithmConstraints,
511 Map<NamedGroupSpec, Boolean> cachedStatus) {
512
513 if (algorithmConstraints.permits(
514 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), suite.name, null)) {
515 if (suite.keyExchange == null) {
516 // TLS 1.3, no definition of key exchange in cipher suite.
517 return true;
518 }
519
520 // Is at least one of the group types available?
521 boolean groupAvailable, retval = false;
522 NamedGroupSpec[] groupTypes = suite.keyExchange.groupTypes;
523 for (NamedGroupSpec groupType : groupTypes) {
524 if (groupType != NAMED_GROUP_NONE) {
525 Boolean checkedStatus = cachedStatus.get(groupType);
526 if (checkedStatus == null) {
527 groupAvailable = SupportedGroups.isActivatable(
528 algorithmConstraints, groupType);
529 cachedStatus.put(groupType, groupAvailable);
530
531 if (!groupAvailable &&
532 SSLLogger.isOn && SSLLogger.isOn("verbose")) {
533 SSLLogger.fine(
534 "No activated named group in " + groupType);
535 }
536 } else {
537 groupAvailable = checkedStatus;
538 }
539
540 retval |= groupAvailable;
541 } else {
542 retval |= true;
543 }
|