< prev index next >

src/java.base/share/classes/sun/security/ssl/HandshakeContext.java

Print this page
rev 54061 : 8226374: Restrict TLS signature schemes and named groups
Reviewed-by: mullan


  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                 }


< prev index next >