< prev index next >

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

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


  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.security.*;
  29 import java.security.spec.AlgorithmParameterSpec;
  30 import java.security.spec.ECParameterSpec;
  31 import java.security.spec.MGF1ParameterSpec;
  32 import java.security.spec.PSSParameterSpec;
  33 import java.util.AbstractMap.SimpleImmutableEntry;
  34 import java.util.ArrayList;
  35 import java.util.Arrays;
  36 import java.util.Collection;
  37 import java.util.Collections;
  38 import java.util.EnumSet;
  39 import java.util.LinkedList;
  40 import java.util.List;
  41 import java.util.Map;
  42 import java.util.Set;
  43 import sun.security.ssl.NamedGroup.NamedGroupType;
  44 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
  45 import sun.security.ssl.X509Authentication.X509Possession;
  46 import sun.security.util.KeyUtil;
  47 import sun.security.util.SignatureUtil;
  48 
  49 enum SignatureScheme {
  50     // EdDSA algorithms
  51     ED25519                 (0x0807, "ed25519", "ed25519",
  52                                     "ed25519",
  53                                     ProtocolVersion.PROTOCOLS_OF_13),
  54     ED448                   (0x0808, "ed448", "ed448",
  55                                     "ed448",
  56                                     ProtocolVersion.PROTOCOLS_OF_13),
  57 
  58     // ECDSA algorithms
  59     ECDSA_SECP256R1_SHA256  (0x0403, "ecdsa_secp256r1_sha256",
  60                                     "SHA256withECDSA",
  61                                     "EC",
  62                                     NamedGroup.SECP256_R1,
  63                                     ProtocolVersion.PROTOCOLS_TO_13),


 134                                     "DSA",
 135                                     ProtocolVersion.PROTOCOLS_TO_12),
 136     ECDSA_SHA1              (0x0203, "ecdsa_sha1", "SHA1withECDSA",
 137                                     "EC",
 138                                     ProtocolVersion.PROTOCOLS_TO_13),
 139     RSA_PKCS1_SHA1          (0x0201, "rsa_pkcs1_sha1", "SHA1withRSA",
 140                                     "RSA", null, null, 511,
 141                                     ProtocolVersion.PROTOCOLS_TO_13,
 142                                     ProtocolVersion.PROTOCOLS_TO_12),
 143     DSA_SHA1                (0x0202, "dsa_sha1", "SHA1withDSA",
 144                                     "DSA",
 145                                     ProtocolVersion.PROTOCOLS_TO_12),
 146     RSA_MD5                 (0x0101, "rsa_md5", "MD5withRSA",
 147                                     "RSA", 511,
 148                                     ProtocolVersion.PROTOCOLS_TO_12);
 149 
 150     final int id;                       // hash + signature
 151     final String name;                  // literal name
 152     private final String algorithm;     // signature algorithm
 153     final String keyAlgorithm;          // signature key algorithm
 154     private final AlgorithmParameterSpec signAlgParameter;
 155     private final NamedGroup namedGroup;    // associated named group
 156 
 157     // The minimal required key size in bits.
 158     //
 159     // Only need to check RSA algorithm at present. RSA keys of 512 bits
 160     // have been shown to be practically breakable, it does not make much
 161     // sense to use the strong hash algorithm for keys whose key size less
 162     // than 512 bits.  So it is not necessary to calculate the minimal
 163     // required key size exactly for a hash algorithm.
 164     //
 165     // Note that some provider may use 511 bits for 512-bit strength RSA keys.
 166     final int minimalKeySize;
 167     final List<ProtocolVersion> supportedProtocols;
 168 
 169     // Some signature schemes are supported in different versions for handshake
 170     // messages and certificates. This field holds the supported protocols
 171     // for handshake messages.
 172     final List<ProtocolVersion> handshakeSupportedProtocols;
 173     final boolean isAvailable;
 174 
 175     private static final String[] hashAlgorithms = new String[] {
 176             "none",         "md5",      "sha1",     "sha224",
 177             "sha256",       "sha384",   "sha512"
 178         };
 179 
 180     private static final String[] signatureAlgorithms = new String[] {
 181             "anonymous",    "rsa",      "dsa",      "ecdsa",
 182         };
 183 
 184     static enum SigAlgParamSpec {   // support RSASSA-PSS only now
 185         RSA_PSS_SHA256 ("SHA-256", 32),
 186         RSA_PSS_SHA384 ("SHA-384", 48),
 187         RSA_PSS_SHA512 ("SHA-512", 64);
 188 
 189         final private AlgorithmParameterSpec parameterSpec;
 190         final boolean isAvailable;

 191 
 192         SigAlgParamSpec(String hash, int saltLength) {
 193             // See RFC 8017
 194             PSSParameterSpec pssParamSpec =
 195                     new PSSParameterSpec(hash, "MGF1",
 196                             new MGF1ParameterSpec(hash), saltLength, 1);

 197 
 198             boolean mediator = true;
 199             try {
 200                 Signature signer = JsseJce.getSignature("RSASSA-PSS");
 201                 signer.setParameter(pssParamSpec);

 202             } catch (InvalidAlgorithmParameterException |
 203                     NoSuchAlgorithmException exp) {

 204                 mediator = false;
 205                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 206                     SSLLogger.warning(
 207                         "RSASSA-PSS signature with " + hash +
 208                         " is not supported by the underlying providers", exp);
 209                 }
 210             }
 211 
 212             this.isAvailable = mediator;
 213             this.parameterSpec = mediator ? pssParamSpec : null;
 214         }
 215 
 216         AlgorithmParameterSpec getParameterSpec() {
 217             return parameterSpec;
 218         }
 219     }
 220 
 221     // performance optimization
 222     private static final Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
 223         Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
 224 
 225 
 226     private SignatureScheme(int id, String name,
 227             String algorithm, String keyAlgorithm,
 228             ProtocolVersion[] supportedProtocols) {
 229         this(id, name, algorithm, keyAlgorithm, -1, supportedProtocols);
 230     }
 231 
 232     private SignatureScheme(int id, String name,
 233             String algorithm, String keyAlgorithm,
 234             int minimalKeySize,
 235             ProtocolVersion[] supportedProtocols) {
 236         this(id, name, algorithm, keyAlgorithm,
 237                 null, minimalKeySize, supportedProtocols);


 240     private SignatureScheme(int id, String name,
 241             String algorithm, String keyAlgorithm,
 242             SigAlgParamSpec signAlgParamSpec, int minimalKeySize,
 243             ProtocolVersion[] supportedProtocols) {
 244         this(id, name, algorithm, keyAlgorithm,
 245                 signAlgParamSpec, null, minimalKeySize,
 246                 supportedProtocols, supportedProtocols);
 247     }
 248 
 249     private SignatureScheme(int id, String name,
 250             String algorithm, String keyAlgorithm,
 251             NamedGroup namedGroup,
 252             ProtocolVersion[] supportedProtocols) {
 253         this(id, name, algorithm, keyAlgorithm,
 254                 null, namedGroup, -1,
 255                 supportedProtocols, supportedProtocols);
 256     }
 257 
 258     private SignatureScheme(int id, String name,
 259             String algorithm, String keyAlgorithm,
 260             SigAlgParamSpec signAlgParamSpec,
 261             NamedGroup namedGroup, int minimalKeySize,
 262             ProtocolVersion[] supportedProtocols,
 263             ProtocolVersion[] handshakeSupportedProtocols) {
 264         this.id = id;
 265         this.name = name;
 266         this.algorithm = algorithm;
 267         this.keyAlgorithm = keyAlgorithm;
 268         this.signAlgParameter =
 269             signAlgParamSpec != null ? signAlgParamSpec.parameterSpec : null;
 270         this.namedGroup = namedGroup;
 271         this.minimalKeySize = minimalKeySize;
 272         this.supportedProtocols = Arrays.asList(supportedProtocols);
 273         this.handshakeSupportedProtocols =
 274                 Arrays.asList(handshakeSupportedProtocols);
 275 
 276         boolean mediator = true;
 277         // An EC provider, for example the SunEC provider, may support
 278         // AlgorithmParameters but not KeyPairGenerator or Signature.
 279         //
 280         // Note: Please be careful if removing this block!
 281         if ("EC".equals(keyAlgorithm)) {
 282             mediator = JsseJce.isEcAvailable();
 283         }
 284 
 285         // Check the specific algorithm and parameters.
 286         if (mediator) {
 287             if (signAlgParamSpec != null) {
 288                 mediator = signAlgParamSpec.isAvailable;
 289             } else {
 290                 try {
 291                     JsseJce.getSignature(algorithm);
 292                 } catch (Exception e) {
 293                     mediator = false;
 294                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 295                         SSLLogger.warning(
 296                             "Signature algorithm, " + algorithm +
 297                             ", is not supported by the underlying providers");
 298                     }
 299                 }
 300             }
 301         }
 302 
 303         if (mediator && ((id >> 8) & 0xFF) == 0x03) {   // SHA224
 304             // There are some problems to use SHA224 on Windows.
 305             if (Security.getProvider("SunMSCAPI") != null) {
 306                 mediator = false;
 307             }
 308         }


 338 
 339         return signName + "_" + hashName;
 340     }
 341 
 342     // Note: the signatureSchemeName is not case-sensitive.
 343     static SignatureScheme nameOf(String signatureSchemeName) {
 344         for (SignatureScheme ss: SignatureScheme.values()) {
 345             if (ss.name.equalsIgnoreCase(signatureSchemeName)) {
 346                 return ss;
 347             }
 348         }
 349 
 350         return null;
 351     }
 352 
 353     // Return the size of a SignatureScheme structure in TLS record
 354     static int sizeInRecord() {
 355         return 2;
 356     }
 357 












 358     // Get local supported algorithm collection complying to algorithm
 359     // constraints.
 360     static List<SignatureScheme> getSupportedAlgorithms(
 361             SSLConfiguration config,
 362             AlgorithmConstraints constraints,
 363             List<ProtocolVersion> activeProtocols) {
 364         List<SignatureScheme> supported = new LinkedList<>();
 365         for (SignatureScheme ss: SignatureScheme.values()) {
 366             if (!ss.isAvailable ||
 367                     (!config.signatureSchemes.isEmpty() &&
 368                         !config.signatureSchemes.contains(ss))) {
 369                 if (SSLLogger.isOn &&
 370                         SSLLogger.isOn("ssl,handshake,verbose")) {
 371                     SSLLogger.finest(
 372                         "Ignore unsupported signature scheme: " + ss.name);
 373                 }
 374                 continue;
 375             }
 376 
 377             boolean isMatch = false;
 378             for (ProtocolVersion pv : activeProtocols) {
 379                 if (ss.supportedProtocols.contains(pv)) {
 380                     isMatch = true;
 381                     break;
 382                 }
 383             }
 384 
 385             if (isMatch) {
 386                 if (constraints.permits(
 387                         SIGNATURE_PRIMITIVE_SET, ss.algorithm, null)) {
 388                     supported.add(ss);
 389                 } else if (SSLLogger.isOn &&
 390                         SSLLogger.isOn("ssl,handshake,verbose")) {
 391                     SSLLogger.finest(
 392                         "Ignore disabled signature scheme: " + ss.name);
 393                 }
 394             } else if (SSLLogger.isOn &&
 395                     SSLLogger.isOn("ssl,handshake,verbose")) {
 396                 SSLLogger.finest(
 397                     "Ignore inactive signature scheme: " + ss.name);
 398             }
 399         }
 400 
 401         return supported;
 402     }
 403 
 404     static List<SignatureScheme> getSupportedAlgorithms(
 405             SSLConfiguration config,
 406             AlgorithmConstraints constraints,
 407             ProtocolVersion protocolVersion, int[] algorithmIds) {
 408         List<SignatureScheme> supported = new LinkedList<>();
 409         for (int ssid : algorithmIds) {
 410             SignatureScheme ss = SignatureScheme.valueOf(ssid);
 411             if (ss == null) {
 412                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 413                     SSLLogger.warning(
 414                             "Unsupported signature scheme: " +
 415                             SignatureScheme.nameOf(ssid));
 416                 }
 417             } else if (ss.isAvailable &&
 418                     ss.supportedProtocols.contains(protocolVersion) &&
 419                     (config.signatureSchemes.isEmpty() ||
 420                         config.signatureSchemes.contains(ss)) &&
 421                     constraints.permits(SIGNATURE_PRIMITIVE_SET,
 422                            ss.algorithm, null)) {
 423                 supported.add(ss);
 424             } else {
 425                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 426                     SSLLogger.warning(
 427                             "Unsupported signature scheme: " + ss.name);
 428                 }
 429             }
 430         }
 431 
 432         return supported;
 433     }
 434 
 435     static SignatureScheme getPreferableAlgorithm(

 436             List<SignatureScheme> schemes,
 437             SignatureScheme certScheme,
 438             ProtocolVersion version) {
 439 
 440         for (SignatureScheme ss : schemes) {
 441             if (ss.isAvailable &&
 442                     ss.handshakeSupportedProtocols.contains(version) &&
 443                     certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
 444 
 445                 return ss;
 446             }
 447         }
 448 
 449         return null;
 450     }
 451 
 452     static Map.Entry<SignatureScheme, Signature> getSignerOfPreferableAlgorithm(

 453             List<SignatureScheme> schemes,
 454             X509Possession x509Possession,
 455             ProtocolVersion version) {
 456 
 457         PrivateKey signingKey = x509Possession.popPrivateKey;
 458         String keyAlgorithm = signingKey.getAlgorithm();
 459         int keySize;
 460         // Only need to check RSA algorithm at present.
 461         if (keyAlgorithm.equalsIgnoreCase("RSA") ||
 462                 keyAlgorithm.equalsIgnoreCase("RSASSA-PSS")) {
 463             keySize = KeyUtil.getKeySize(signingKey);
 464         } else {
 465             keySize = Integer.MAX_VALUE;
 466         }
 467         for (SignatureScheme ss : schemes) {
 468             if (ss.isAvailable && (keySize >= ss.minimalKeySize) &&
 469                     ss.handshakeSupportedProtocols.contains(version) &&
 470                     keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
 471                 if ((ss.namedGroup != null) && (ss.namedGroup.type ==
 472                         NamedGroupType.NAMED_GROUP_ECDHE)) {

 473                     ECParameterSpec params =
 474                             x509Possession.getECParameterSpec();
 475                     if (params != null &&
 476                             ss.namedGroup == NamedGroup.valueOf(params)) {
 477                         Signature signer = ss.getSigner(signingKey);
 478                         if (signer != null) {
 479                             return new SimpleImmutableEntry<>(ss, signer);
 480                         }
 481                     }
 482 
 483                     if (SSLLogger.isOn &&
 484                             SSLLogger.isOn("ssl,handshake,verbose")) {
 485                         SSLLogger.finest(
 486                             "Ignore the signature algorithm (" + ss +
 487                             "), unsupported EC parameter spec: " + params);
 488                     }
 489                 } else if ("EC".equals(ss.keyAlgorithm)) {
 490                     // Must be a legacy signature algorithm, which does not
 491                     // specify the associated named groups.  The connection
 492                     // cannot be established if the peer cannot recognize


 535             }
 536 
 537             return names.toArray(new String[0]);
 538         }
 539 
 540         return new String[0];
 541     }
 542 
 543     // This method is used to get the signature instance of this signature
 544     // scheme for the specific public key.  Unlike getSigner(), the exception
 545     // is bubbled up.  If the public key does not support this signature
 546     // scheme, it normally means the TLS handshaking cannot continue and
 547     // the connection should be terminated.
 548     Signature getVerifier(PublicKey publicKey) throws NoSuchAlgorithmException,
 549             InvalidAlgorithmParameterException, InvalidKeyException {
 550         if (!isAvailable) {
 551             return null;
 552         }
 553 
 554         Signature verifier = Signature.getInstance(algorithm);
 555         SignatureUtil.initVerifyWithParam(verifier, publicKey, signAlgParameter);


 556 
 557         return verifier;
 558     }
 559 
 560     // This method is also used to choose preferable signature scheme for the
 561     // specific private key.  If the private key does not support the signature
 562     // scheme, {@code null} is returned, and the caller may fail back to next
 563     // available signature scheme.
 564     private Signature getSigner(PrivateKey privateKey) {
 565         if (!isAvailable) {
 566             return null;
 567         }
 568 
 569         try {
 570             Signature signer = Signature.getInstance(algorithm);
 571             SignatureUtil.initSignWithParam(signer, privateKey,
 572                 signAlgParameter,

 573                 null);
 574             return signer;
 575         } catch (NoSuchAlgorithmException | InvalidKeyException |
 576                 InvalidAlgorithmParameterException nsae) {
 577             if (SSLLogger.isOn &&
 578                     SSLLogger.isOn("ssl,handshake,verbose")) {
 579                 SSLLogger.finest(
 580                     "Ignore unsupported signature algorithm (" +
 581                     this.name + ")", nsae);
 582             }
 583         }
 584 
 585         return null;
 586     }
 587 }


  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.security.*;
  29 import java.security.spec.AlgorithmParameterSpec;
  30 import java.security.spec.ECParameterSpec;
  31 import java.security.spec.MGF1ParameterSpec;
  32 import java.security.spec.PSSParameterSpec;
  33 import java.util.AbstractMap.SimpleImmutableEntry;
  34 import java.util.ArrayList;
  35 import java.util.Arrays;
  36 import java.util.Collection;
  37 import java.util.Collections;
  38 import java.util.EnumSet;
  39 import java.util.LinkedList;
  40 import java.util.List;
  41 import java.util.Map;
  42 import java.util.Set;
  43 import sun.security.ssl.NamedGroup.NamedGroupSpec;
  44 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
  45 import sun.security.ssl.X509Authentication.X509Possession;
  46 import sun.security.util.KeyUtil;
  47 import sun.security.util.SignatureUtil;
  48 
  49 enum SignatureScheme {
  50     // EdDSA algorithms
  51     ED25519                 (0x0807, "ed25519", "ed25519",
  52                                     "ed25519",
  53                                     ProtocolVersion.PROTOCOLS_OF_13),
  54     ED448                   (0x0808, "ed448", "ed448",
  55                                     "ed448",
  56                                     ProtocolVersion.PROTOCOLS_OF_13),
  57 
  58     // ECDSA algorithms
  59     ECDSA_SECP256R1_SHA256  (0x0403, "ecdsa_secp256r1_sha256",
  60                                     "SHA256withECDSA",
  61                                     "EC",
  62                                     NamedGroup.SECP256_R1,
  63                                     ProtocolVersion.PROTOCOLS_TO_13),


 134                                     "DSA",
 135                                     ProtocolVersion.PROTOCOLS_TO_12),
 136     ECDSA_SHA1              (0x0203, "ecdsa_sha1", "SHA1withECDSA",
 137                                     "EC",
 138                                     ProtocolVersion.PROTOCOLS_TO_13),
 139     RSA_PKCS1_SHA1          (0x0201, "rsa_pkcs1_sha1", "SHA1withRSA",
 140                                     "RSA", null, null, 511,
 141                                     ProtocolVersion.PROTOCOLS_TO_13,
 142                                     ProtocolVersion.PROTOCOLS_TO_12),
 143     DSA_SHA1                (0x0202, "dsa_sha1", "SHA1withDSA",
 144                                     "DSA",
 145                                     ProtocolVersion.PROTOCOLS_TO_12),
 146     RSA_MD5                 (0x0101, "rsa_md5", "MD5withRSA",
 147                                     "RSA", 511,
 148                                     ProtocolVersion.PROTOCOLS_TO_12);
 149 
 150     final int id;                       // hash + signature
 151     final String name;                  // literal name
 152     private final String algorithm;     // signature algorithm
 153     final String keyAlgorithm;          // signature key algorithm
 154     private final SigAlgParamSpec signAlgParams;    // signature parameters
 155     private final NamedGroup namedGroup;    // associated named group
 156 
 157     // The minimal required key size in bits.
 158     //
 159     // Only need to check RSA algorithm at present. RSA keys of 512 bits
 160     // have been shown to be practically breakable, it does not make much
 161     // sense to use the strong hash algorithm for keys whose key size less
 162     // than 512 bits.  So it is not necessary to calculate the minimal
 163     // required key size exactly for a hash algorithm.
 164     //
 165     // Note that some provider may use 511 bits for 512-bit strength RSA keys.
 166     final int minimalKeySize;
 167     final List<ProtocolVersion> supportedProtocols;
 168 
 169     // Some signature schemes are supported in different versions for handshake
 170     // messages and certificates. This field holds the supported protocols
 171     // for handshake messages.
 172     final List<ProtocolVersion> handshakeSupportedProtocols;
 173     final boolean isAvailable;
 174 
 175     private static final String[] hashAlgorithms = new String[] {
 176             "none",         "md5",      "sha1",     "sha224",
 177             "sha256",       "sha384",   "sha512"
 178         };
 179 
 180     private static final String[] signatureAlgorithms = new String[] {
 181             "anonymous",    "rsa",      "dsa",      "ecdsa",
 182         };
 183 
 184     static enum SigAlgParamSpec {   // support RSASSA-PSS only now
 185         RSA_PSS_SHA256 ("SHA-256", 32),
 186         RSA_PSS_SHA384 ("SHA-384", 48),
 187         RSA_PSS_SHA512 ("SHA-512", 64);
 188 
 189         private final AlgorithmParameterSpec parameterSpec;
 190         private final AlgorithmParameters parameters;
 191         private final boolean isAvailable;
 192 
 193         SigAlgParamSpec(String hash, int saltLength) {
 194             // See RFC 8017
 195             PSSParameterSpec pssParamSpec =
 196                     new PSSParameterSpec(hash, "MGF1",
 197                             new MGF1ParameterSpec(hash), saltLength, 1);
 198             AlgorithmParameters pssParams = null;
 199 
 200             boolean mediator = true;
 201             try {
 202                 Signature signer = JsseJce.getSignature("RSASSA-PSS");
 203                 signer.setParameter(pssParamSpec);
 204                 pssParams = signer.getParameters();
 205             } catch (InvalidAlgorithmParameterException |
 206                     NoSuchAlgorithmException | RuntimeException exp) {
 207                 // Signature.getParameters() may throw RuntimeException.
 208                 mediator = false;
 209                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 210                     SSLLogger.warning(
 211                         "RSASSA-PSS signature with " + hash +
 212                         " is not supported by the underlying providers", exp);
 213                 }
 214             }
 215 
 216             this.isAvailable = mediator;
 217             this.parameterSpec = mediator ? pssParamSpec : null;
 218             this.parameters = mediator ? pssParams : null;



 219         }
 220     }
 221 
 222     // performance optimization
 223     private static final Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
 224         Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
 225 
 226 
 227     private SignatureScheme(int id, String name,
 228             String algorithm, String keyAlgorithm,
 229             ProtocolVersion[] supportedProtocols) {
 230         this(id, name, algorithm, keyAlgorithm, -1, supportedProtocols);
 231     }
 232 
 233     private SignatureScheme(int id, String name,
 234             String algorithm, String keyAlgorithm,
 235             int minimalKeySize,
 236             ProtocolVersion[] supportedProtocols) {
 237         this(id, name, algorithm, keyAlgorithm,
 238                 null, minimalKeySize, supportedProtocols);


 241     private SignatureScheme(int id, String name,
 242             String algorithm, String keyAlgorithm,
 243             SigAlgParamSpec signAlgParamSpec, int minimalKeySize,
 244             ProtocolVersion[] supportedProtocols) {
 245         this(id, name, algorithm, keyAlgorithm,
 246                 signAlgParamSpec, null, minimalKeySize,
 247                 supportedProtocols, supportedProtocols);
 248     }
 249 
 250     private SignatureScheme(int id, String name,
 251             String algorithm, String keyAlgorithm,
 252             NamedGroup namedGroup,
 253             ProtocolVersion[] supportedProtocols) {
 254         this(id, name, algorithm, keyAlgorithm,
 255                 null, namedGroup, -1,
 256                 supportedProtocols, supportedProtocols);
 257     }
 258 
 259     private SignatureScheme(int id, String name,
 260             String algorithm, String keyAlgorithm,
 261             SigAlgParamSpec signAlgParams,
 262             NamedGroup namedGroup, int minimalKeySize,
 263             ProtocolVersion[] supportedProtocols,
 264             ProtocolVersion[] handshakeSupportedProtocols) {
 265         this.id = id;
 266         this.name = name;
 267         this.algorithm = algorithm;
 268         this.keyAlgorithm = keyAlgorithm;
 269         this.signAlgParams = signAlgParams;

 270         this.namedGroup = namedGroup;
 271         this.minimalKeySize = minimalKeySize;
 272         this.supportedProtocols = Arrays.asList(supportedProtocols);
 273         this.handshakeSupportedProtocols =
 274                 Arrays.asList(handshakeSupportedProtocols);
 275 
 276         boolean mediator = true;
 277         // An EC provider, for example the SunEC provider, may support
 278         // AlgorithmParameters but not KeyPairGenerator or Signature.
 279         //
 280         // Note: Please be careful if removing this block!
 281         if ("EC".equals(keyAlgorithm)) {
 282             mediator = JsseJce.isEcAvailable();
 283         }
 284 
 285         // Check the specific algorithm and parameters.
 286         if (mediator) {
 287             if (signAlgParams != null) {
 288                 mediator = signAlgParams.isAvailable;
 289             } else {
 290                 try {
 291                     JsseJce.getSignature(algorithm);
 292                 } catch (Exception e) {
 293                     mediator = false;
 294                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 295                         SSLLogger.warning(
 296                             "Signature algorithm, " + algorithm +
 297                             ", is not supported by the underlying providers");
 298                     }
 299                 }
 300             }
 301         }
 302 
 303         if (mediator && ((id >> 8) & 0xFF) == 0x03) {   // SHA224
 304             // There are some problems to use SHA224 on Windows.
 305             if (Security.getProvider("SunMSCAPI") != null) {
 306                 mediator = false;
 307             }
 308         }


 338 
 339         return signName + "_" + hashName;
 340     }
 341 
 342     // Note: the signatureSchemeName is not case-sensitive.
 343     static SignatureScheme nameOf(String signatureSchemeName) {
 344         for (SignatureScheme ss: SignatureScheme.values()) {
 345             if (ss.name.equalsIgnoreCase(signatureSchemeName)) {
 346                 return ss;
 347             }
 348         }
 349 
 350         return null;
 351     }
 352 
 353     // Return the size of a SignatureScheme structure in TLS record
 354     static int sizeInRecord() {
 355         return 2;
 356     }
 357 
 358     private boolean isPermitted(AlgorithmConstraints constraints) {
 359         return constraints.permits(SIGNATURE_PRIMITIVE_SET,
 360                         this.name, null) &&
 361                constraints.permits(SIGNATURE_PRIMITIVE_SET,
 362                         this.keyAlgorithm, null) &&
 363                constraints.permits(SIGNATURE_PRIMITIVE_SET,
 364                         this.algorithm, (signAlgParams != null ?
 365                                 signAlgParams.parameters : null)) &&
 366                (namedGroup != null ?
 367                         namedGroup.isPermitted(constraints) : true);
 368     }
 369 
 370     // Get local supported algorithm collection complying to algorithm
 371     // constraints.
 372     static List<SignatureScheme> getSupportedAlgorithms(
 373             SSLConfiguration config,
 374             AlgorithmConstraints constraints,
 375             List<ProtocolVersion> activeProtocols) {
 376         List<SignatureScheme> supported = new LinkedList<>();
 377         for (SignatureScheme ss: SignatureScheme.values()) {
 378             if (!ss.isAvailable ||
 379                     (!config.signatureSchemes.isEmpty() &&
 380                         !config.signatureSchemes.contains(ss))) {
 381                 if (SSLLogger.isOn &&
 382                         SSLLogger.isOn("ssl,handshake,verbose")) {
 383                     SSLLogger.finest(
 384                         "Ignore unsupported signature scheme: " + ss.name);
 385                 }
 386                 continue;
 387             }
 388 
 389             boolean isMatch = false;
 390             for (ProtocolVersion pv : activeProtocols) {
 391                 if (ss.supportedProtocols.contains(pv)) {
 392                     isMatch = true;
 393                     break;
 394                 }
 395             }
 396 
 397             if (isMatch) {
 398                 if (ss.isPermitted(constraints)) {

 399                     supported.add(ss);
 400                 } else if (SSLLogger.isOn &&
 401                         SSLLogger.isOn("ssl,handshake,verbose")) {
 402                     SSLLogger.finest(
 403                         "Ignore disabled signature scheme: " + ss.name);
 404                 }
 405             } else if (SSLLogger.isOn &&
 406                     SSLLogger.isOn("ssl,handshake,verbose")) {
 407                 SSLLogger.finest(
 408                     "Ignore inactive signature scheme: " + ss.name);
 409             }
 410         }
 411 
 412         return supported;
 413     }
 414 
 415     static List<SignatureScheme> getSupportedAlgorithms(
 416             SSLConfiguration config,
 417             AlgorithmConstraints constraints,
 418             ProtocolVersion protocolVersion, int[] algorithmIds) {
 419         List<SignatureScheme> supported = new LinkedList<>();
 420         for (int ssid : algorithmIds) {
 421             SignatureScheme ss = SignatureScheme.valueOf(ssid);
 422             if (ss == null) {
 423                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 424                     SSLLogger.warning(
 425                             "Unsupported signature scheme: " +
 426                             SignatureScheme.nameOf(ssid));
 427                 }
 428             } else if (ss.isAvailable &&
 429                     ss.supportedProtocols.contains(protocolVersion) &&
 430                     (config.signatureSchemes.isEmpty() ||
 431                         config.signatureSchemes.contains(ss)) &&
 432                     ss.isPermitted(constraints)) {

 433                 supported.add(ss);
 434             } else {
 435                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 436                     SSLLogger.warning(
 437                             "Unsupported signature scheme: " + ss.name);
 438                 }
 439             }
 440         }
 441 
 442         return supported;
 443     }
 444 
 445     static SignatureScheme getPreferableAlgorithm(
 446             AlgorithmConstraints constraints,
 447             List<SignatureScheme> schemes,
 448             SignatureScheme certScheme,
 449             ProtocolVersion version) {
 450 
 451         for (SignatureScheme ss : schemes) {
 452             if (ss.isAvailable &&
 453                     ss.handshakeSupportedProtocols.contains(version) &&
 454                     certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) &&
 455                     ss.isPermitted(constraints)) {
 456                 return ss;
 457             }
 458         }
 459 
 460         return null;
 461     }
 462 
 463     static Map.Entry<SignatureScheme, Signature> getSignerOfPreferableAlgorithm(
 464             AlgorithmConstraints constraints,
 465             List<SignatureScheme> schemes,
 466             X509Possession x509Possession,
 467             ProtocolVersion version) {
 468 
 469         PrivateKey signingKey = x509Possession.popPrivateKey;
 470         String keyAlgorithm = signingKey.getAlgorithm();
 471         int keySize;
 472         // Only need to check RSA algorithm at present.
 473         if (keyAlgorithm.equalsIgnoreCase("RSA") ||
 474                 keyAlgorithm.equalsIgnoreCase("RSASSA-PSS")) {
 475             keySize = KeyUtil.getKeySize(signingKey);
 476         } else {
 477             keySize = Integer.MAX_VALUE;
 478         }
 479         for (SignatureScheme ss : schemes) {
 480             if (ss.isAvailable && (keySize >= ss.minimalKeySize) &&
 481                     ss.handshakeSupportedProtocols.contains(version) &&
 482                     keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) &&
 483                     ss.isPermitted(constraints)) {
 484                 if ((ss.namedGroup != null) && (ss.namedGroup.spec ==
 485                         NamedGroupSpec.NAMED_GROUP_ECDHE)) {
 486                     ECParameterSpec params =
 487                             x509Possession.getECParameterSpec();
 488                     if (params != null &&
 489                             ss.namedGroup == NamedGroup.valueOf(params)) {
 490                         Signature signer = ss.getSigner(signingKey);
 491                         if (signer != null) {
 492                             return new SimpleImmutableEntry<>(ss, signer);
 493                         }
 494                     }
 495 
 496                     if (SSLLogger.isOn &&
 497                             SSLLogger.isOn("ssl,handshake,verbose")) {
 498                         SSLLogger.finest(
 499                             "Ignore the signature algorithm (" + ss +
 500                             "), unsupported EC parameter spec: " + params);
 501                     }
 502                 } else if ("EC".equals(ss.keyAlgorithm)) {
 503                     // Must be a legacy signature algorithm, which does not
 504                     // specify the associated named groups.  The connection
 505                     // cannot be established if the peer cannot recognize


 548             }
 549 
 550             return names.toArray(new String[0]);
 551         }
 552 
 553         return new String[0];
 554     }
 555 
 556     // This method is used to get the signature instance of this signature
 557     // scheme for the specific public key.  Unlike getSigner(), the exception
 558     // is bubbled up.  If the public key does not support this signature
 559     // scheme, it normally means the TLS handshaking cannot continue and
 560     // the connection should be terminated.
 561     Signature getVerifier(PublicKey publicKey) throws NoSuchAlgorithmException,
 562             InvalidAlgorithmParameterException, InvalidKeyException {
 563         if (!isAvailable) {
 564             return null;
 565         }
 566 
 567         Signature verifier = Signature.getInstance(algorithm);
 568         SignatureUtil.initVerifyWithParam(verifier, publicKey,
 569                 (signAlgParams != null ?
 570                         signAlgParams.parameterSpec : null));
 571 
 572         return verifier;
 573     }
 574 
 575     // This method is also used to choose preferable signature scheme for the
 576     // specific private key.  If the private key does not support the signature
 577     // scheme, {@code null} is returned, and the caller may fail back to next
 578     // available signature scheme.
 579     private Signature getSigner(PrivateKey privateKey) {
 580         if (!isAvailable) {
 581             return null;
 582         }
 583 
 584         try {
 585             Signature signer = Signature.getInstance(algorithm);
 586             SignatureUtil.initSignWithParam(signer, privateKey,
 587                     (signAlgParams != null ?
 588                             signAlgParams.parameterSpec : null),
 589                     null);
 590             return signer;
 591         } catch (NoSuchAlgorithmException | InvalidKeyException |
 592                 InvalidAlgorithmParameterException nsae) {
 593             if (SSLLogger.isOn &&
 594                     SSLLogger.isOn("ssl,handshake,verbose")) {
 595                 SSLLogger.finest(
 596                     "Ignore unsupported signature algorithm (" +
 597                     this.name + ")", nsae);
 598             }
 599         }
 600 
 601         return null;
 602     }
 603 }
< prev index next >