src/java.base/share/classes/sun/security/ssl/SignatureScheme.java
branchdatagramsocketimpl-branch
changeset 58678 9cf78a70fa4f
parent 54483 ac20c3bdc55d
child 58679 9c3209ff7550
--- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java	Thu Oct 17 20:27:44 2019 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java	Thu Oct 17 20:53:35 2019 +0100
@@ -26,7 +26,6 @@
 package sun.security.ssl;
 
 import java.security.*;
-import java.security.interfaces.ECPrivateKey;
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECParameterSpec;
 import java.security.spec.MGF1ParameterSpec;
@@ -39,8 +38,8 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.ssl.NamedGroup.NamedGroupSpec;
+import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
 import sun.security.ssl.X509Authentication.X509Possession;
 import sun.security.util.KeyUtil;
 import sun.security.util.SignatureUtil;
@@ -150,7 +149,7 @@
     final String name;                  // literal name
     private final String algorithm;     // signature algorithm
     final String keyAlgorithm;          // signature key algorithm
-    private final AlgorithmParameterSpec signAlgParameter;
+    private final SigAlgParamSpec signAlgParams;    // signature parameters
     private final NamedGroup namedGroup;    // associated named group
 
     // The minimal required key size in bits.
@@ -185,21 +184,25 @@
         RSA_PSS_SHA384 ("SHA-384", 48),
         RSA_PSS_SHA512 ("SHA-512", 64);
 
-        final private AlgorithmParameterSpec parameterSpec;
-        final boolean isAvailable;
+        private final AlgorithmParameterSpec parameterSpec;
+        private final AlgorithmParameters parameters;
+        private final boolean isAvailable;
 
         SigAlgParamSpec(String hash, int saltLength) {
             // See RFC 8017
             PSSParameterSpec pssParamSpec =
                     new PSSParameterSpec(hash, "MGF1",
                             new MGF1ParameterSpec(hash), saltLength, 1);
+            AlgorithmParameters pssParams = null;
 
             boolean mediator = true;
             try {
                 Signature signer = Signature.getInstance("RSASSA-PSS");
                 signer.setParameter(pssParamSpec);
+                pssParams = signer.getParameters();
             } catch (InvalidAlgorithmParameterException |
-                    NoSuchAlgorithmException exp) {
+                    NoSuchAlgorithmException | RuntimeException exp) {
+                // Signature.getParameters() may throw RuntimeException.
                 mediator = false;
                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                     SSLLogger.warning(
@@ -210,10 +213,7 @@
 
             this.isAvailable = mediator;
             this.parameterSpec = mediator ? pssParamSpec : null;
-        }
-
-        AlgorithmParameterSpec getParameterSpec() {
-            return parameterSpec;
+            this.parameters = mediator ? pssParams : null;
         }
     }
 
@@ -256,7 +256,7 @@
 
     private SignatureScheme(int id, String name,
             String algorithm, String keyAlgorithm,
-            SigAlgParamSpec signAlgParamSpec,
+            SigAlgParamSpec signAlgParams,
             NamedGroup namedGroup, int minimalKeySize,
             ProtocolVersion[] supportedProtocols,
             ProtocolVersion[] handshakeSupportedProtocols) {
@@ -264,8 +264,7 @@
         this.name = name;
         this.algorithm = algorithm;
         this.keyAlgorithm = keyAlgorithm;
-        this.signAlgParameter =
-            signAlgParamSpec != null ? signAlgParamSpec.parameterSpec : null;
+        this.signAlgParams = signAlgParams;
         this.namedGroup = namedGroup;
         this.minimalKeySize = minimalKeySize;
         this.supportedProtocols = Arrays.asList(supportedProtocols);
@@ -273,8 +272,8 @@
                 Arrays.asList(handshakeSupportedProtocols);
 
         boolean mediator = true;
-        if (signAlgParamSpec != null) {
-            mediator = signAlgParamSpec.isAvailable;
+        if (signAlgParams != null) {
+            mediator = signAlgParams.isAvailable;
         } else {
             try {
                 Signature.getInstance(algorithm);
@@ -332,6 +331,18 @@
         return 2;
     }
 
+    private boolean isPermitted(AlgorithmConstraints constraints) {
+        return constraints.permits(SIGNATURE_PRIMITIVE_SET,
+                        this.name, null) &&
+               constraints.permits(SIGNATURE_PRIMITIVE_SET,
+                        this.keyAlgorithm, null) &&
+               constraints.permits(SIGNATURE_PRIMITIVE_SET,
+                        this.algorithm, (signAlgParams != null ?
+                                signAlgParams.parameters : null)) &&
+               (namedGroup != null ?
+                        namedGroup.isPermitted(constraints) : true);
+    }
+
     // Get local supported algorithm collection complying to algorithm
     // constraints.
     static List<SignatureScheme> getSupportedAlgorithms(
@@ -352,8 +363,7 @@
             }
 
             if (isMatch) {
-                if (constraints.permits(
-                        SIGNATURE_PRIMITIVE_SET, ss.algorithm, null)) {
+                if (ss.isPermitted(constraints)) {
                     supported.add(ss);
                 } else if (SSLLogger.isOn &&
                         SSLLogger.isOn("ssl,handshake,verbose")) {
@@ -384,8 +394,7 @@
                 }
             } else if (ss.isAvailable &&
                     ss.supportedProtocols.contains(protocolVersion) &&
-                    constraints.permits(SIGNATURE_PRIMITIVE_SET,
-                           ss.algorithm, null)) {
+                    ss.isPermitted(constraints)) {
                 supported.add(ss);
             } else {
                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
@@ -399,6 +408,7 @@
     }
 
     static SignatureScheme getPreferableAlgorithm(
+            AlgorithmConstraints constraints,
             List<SignatureScheme> schemes,
             SignatureScheme certScheme,
             ProtocolVersion version) {
@@ -406,8 +416,8 @@
         for (SignatureScheme ss : schemes) {
             if (ss.isAvailable &&
                     ss.handshakeSupportedProtocols.contains(version) &&
-                    certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
-
+                    certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) &&
+                    ss.isPermitted(constraints)) {
                 return ss;
             }
         }
@@ -416,6 +426,7 @@
     }
 
     static SignatureScheme getPreferableAlgorithm(
+            AlgorithmConstraints constraints,
             List<SignatureScheme> schemes,
             X509Possession x509Possession,
             ProtocolVersion version) {
@@ -432,16 +443,50 @@
         }
         for (SignatureScheme ss : schemes) {
             if (ss.isAvailable && (keySize >= ss.minimalKeySize) &&
-                ss.handshakeSupportedProtocols.contains(version) &&
-                keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
-                if (ss.namedGroup != null &&
-                    ss.namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
+                    ss.handshakeSupportedProtocols.contains(version) &&
+                    keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) &&
+                    ss.isPermitted(constraints)) {
+                if ((ss.namedGroup != null) && (ss.namedGroup.spec ==
+                        NamedGroupSpec.NAMED_GROUP_ECDHE)) {
                     ECParameterSpec params =
                             x509Possession.getECParameterSpec();
                     if (params != null &&
                             ss.namedGroup == NamedGroup.valueOf(params)) {
                         return ss;
                     }
+
+                    if (SSLLogger.isOn &&
+                            SSLLogger.isOn("ssl,handshake,verbose")) {
+                        SSLLogger.finest(
+                            "Ignore the signature algorithm (" + ss +
+                            "), unsupported EC parameter spec: " + params);
+                    }
+                } else if ("EC".equals(ss.keyAlgorithm)) {
+                    // Must be a legacy signature algorithm, which does not
+                    // specify the associated named groups.  The connection
+                    // cannot be established if the peer cannot recognize
+                    // the named group used for the signature.  RFC 8446
+                    // does not define countermeasures for the corner cases.
+                    // In order to mitigate the impact, we choose to check
+                    // against the local supported named groups.  The risk
+                    // should be minimal as applications should not use
+                    // unsupported named groups for its certificates.
+                    ECParameterSpec params =
+                            x509Possession.getECParameterSpec();
+                    if (params != null) {
+                        NamedGroup keyGroup = NamedGroup.valueOf(params);
+                        if (keyGroup != null &&
+                                SupportedGroups.isSupported(keyGroup)) {
+                            return ss;
+                        }
+                    }
+
+                    if (SSLLogger.isOn &&
+                            SSLLogger.isOn("ssl,handshake,verbose")) {
+                        SSLLogger.finest(
+                            "Ignore the legacy signature algorithm (" + ss +
+                            "), unsupported EC parameter spec: " + params);
+                    }
                 } else {
                     return ss;
                 }
@@ -473,10 +518,13 @@
         Signature signer = Signature.getInstance(algorithm);
         if (key instanceof PublicKey) {
             SignatureUtil.initVerifyWithParam(signer, (PublicKey)key,
-                    signAlgParameter);
+                    (signAlgParams != null ?
+                            signAlgParams.parameterSpec : null));
         } else {
             SignatureUtil.initSignWithParam(signer, (PrivateKey)key,
-                    signAlgParameter, null);
+                    (signAlgParams != null ?
+                            signAlgParams.parameterSpec : null),
+                    null);
         }
 
         return signer;