1 /*
   2  * Copyright (c) 2015, 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.*;
  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),
  64     ECDSA_SECP384R1_SHA384  (0x0503, "ecdsa_secp384r1_sha384",
  65                                     "SHA384withECDSA",
  66                                     "EC",
  67                                     NamedGroup.SECP384_R1,
  68                                     ProtocolVersion.PROTOCOLS_TO_13),
  69     ECDSA_SECP521R1_SHA512  (0x0603, "ecdsa_secp521r1_sha512",
  70                                     "SHA512withECDSA",
  71                                     "EC",
  72                                     NamedGroup.SECP521_R1,
  73                                     ProtocolVersion.PROTOCOLS_TO_13),
  74 
  75     // RSASSA-PSS algorithms with public key OID rsaEncryption
  76     //
  77     // The minimalKeySize is calculated as (See RFC 8017 for details):
  78     //     hash length + salt length + 16
  79     RSA_PSS_RSAE_SHA256     (0x0804, "rsa_pss_rsae_sha256",
  80                                     "RSASSA-PSS", "RSA",
  81                                     SigAlgParamSpec.RSA_PSS_SHA256, 528,
  82                                     ProtocolVersion.PROTOCOLS_12_13),
  83     RSA_PSS_RSAE_SHA384     (0x0805, "rsa_pss_rsae_sha384",
  84                                     "RSASSA-PSS", "RSA",
  85                                     SigAlgParamSpec.RSA_PSS_SHA384, 784,
  86                                     ProtocolVersion.PROTOCOLS_12_13),
  87     RSA_PSS_RSAE_SHA512     (0x0806, "rsa_pss_rsae_sha512",
  88                                     "RSASSA-PSS", "RSA",
  89                                     SigAlgParamSpec.RSA_PSS_SHA512, 1040,
  90                                     ProtocolVersion.PROTOCOLS_12_13),
  91 
  92     // RSASSA-PSS algorithms with public key OID RSASSA-PSS
  93     //
  94     // The minimalKeySize is calculated as (See RFC 8017 for details):
  95     //     hash length + salt length + 16
  96     RSA_PSS_PSS_SHA256      (0x0809, "rsa_pss_pss_sha256",
  97                                     "RSASSA-PSS", "RSASSA-PSS",
  98                                     SigAlgParamSpec.RSA_PSS_SHA256, 528,
  99                                     ProtocolVersion.PROTOCOLS_12_13),
 100     RSA_PSS_PSS_SHA384      (0x080A, "rsa_pss_pss_sha384",
 101                                     "RSASSA-PSS", "RSASSA-PSS",
 102                                     SigAlgParamSpec.RSA_PSS_SHA384, 784,
 103                                     ProtocolVersion.PROTOCOLS_12_13),
 104     RSA_PSS_PSS_SHA512      (0x080B, "rsa_pss_pss_sha512",
 105                                     "RSASSA-PSS", "RSASSA-PSS",
 106                                     SigAlgParamSpec.RSA_PSS_SHA512, 1040,
 107                                     ProtocolVersion.PROTOCOLS_12_13),
 108 
 109     // RSASSA-PKCS1-v1_5 algorithms
 110     RSA_PKCS1_SHA256        (0x0401, "rsa_pkcs1_sha256", "SHA256withRSA",
 111                                     "RSA", null, null, 511,
 112                                     ProtocolVersion.PROTOCOLS_TO_13,
 113                                     ProtocolVersion.PROTOCOLS_TO_12),
 114     RSA_PKCS1_SHA384        (0x0501, "rsa_pkcs1_sha384", "SHA384withRSA",
 115                                     "RSA", null, null, 768,
 116                                     ProtocolVersion.PROTOCOLS_TO_13,
 117                                     ProtocolVersion.PROTOCOLS_TO_12),
 118     RSA_PKCS1_SHA512        (0x0601, "rsa_pkcs1_sha512", "SHA512withRSA",
 119                                     "RSA", null, null, 768,
 120                                     ProtocolVersion.PROTOCOLS_TO_13,
 121                                     ProtocolVersion.PROTOCOLS_TO_12),
 122 
 123     // Legacy algorithms
 124     DSA_SHA256              (0x0402, "dsa_sha256", "SHA256withDSA",
 125                                     "DSA",
 126                                     ProtocolVersion.PROTOCOLS_TO_12),
 127     ECDSA_SHA224            (0x0303, "ecdsa_sha224", "SHA224withECDSA",
 128                                     "EC",
 129                                     ProtocolVersion.PROTOCOLS_TO_12),
 130     RSA_SHA224              (0x0301, "rsa_sha224", "SHA224withRSA",
 131                                     "RSA", 511,
 132                                     ProtocolVersion.PROTOCOLS_TO_12),
 133     DSA_SHA224              (0x0302, "dsa_sha224", "SHA224withDSA",
 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);
 238     }
 239 
 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         }
 309 
 310         this.isAvailable = mediator;
 311     }
 312 
 313     static SignatureScheme valueOf(int id) {
 314         for (SignatureScheme ss: SignatureScheme.values()) {
 315             if (ss.id == id) {
 316                 return ss;
 317             }
 318         }
 319 
 320         return null;
 321     }
 322 
 323     static String nameOf(int id) {
 324         for (SignatureScheme ss: SignatureScheme.values()) {
 325             if (ss.id == id) {
 326                 return ss.name;
 327             }
 328         }
 329 
 330         // Use TLS 1.2 style name for unknown signature scheme.
 331         int hashId = ((id >> 8) & 0xFF);
 332         int signId = (id & 0xFF);
 333         String hashName = (hashId >= hashAlgorithms.length) ?
 334             "UNDEFINED-HASH(" + hashId + ")" : hashAlgorithms[hashId];
 335         String signName = (signId >= signatureAlgorithms.length) ?
 336             "UNDEFINED-SIGNATURE(" + signId + ")" :
 337             signatureAlgorithms[signId];
 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
 493                     // the named group used for the signature.  RFC 8446
 494                     // does not define countermeasures for the corner cases.
 495                     // In order to mitigate the impact, we choose to check
 496                     // against the local supported named groups.  The risk
 497                     // should be minimal as applications should not use
 498                     // unsupported named groups for its certificates.
 499                     ECParameterSpec params =
 500                             x509Possession.getECParameterSpec();
 501                     if (params != null) {
 502                         NamedGroup keyGroup = NamedGroup.valueOf(params);
 503                         if (keyGroup != null &&
 504                                 SupportedGroups.isSupported(keyGroup)) {
 505                             Signature signer = ss.getSigner(signingKey);
 506                             if (signer != null) {
 507                                 return new SimpleImmutableEntry<>(ss, signer);
 508                             }
 509                         }
 510                     }
 511 
 512                     if (SSLLogger.isOn &&
 513                             SSLLogger.isOn("ssl,handshake,verbose")) {
 514                         SSLLogger.finest(
 515                             "Ignore the legacy signature algorithm (" + ss +
 516                             "), unsupported EC parameter spec: " + params);
 517                     }
 518                 } else {
 519                     Signature signer = ss.getSigner(signingKey);
 520                     if (signer != null) {
 521                         return new SimpleImmutableEntry<>(ss, signer);
 522                     }
 523                 }
 524             }
 525         }
 526 
 527         return null;
 528     }
 529 
 530     static String[] getAlgorithmNames(Collection<SignatureScheme> schemes) {
 531         if (schemes != null) {
 532             ArrayList<String> names = new ArrayList<>(schemes.size());
 533             for (SignatureScheme scheme : schemes) {
 534                 names.add(scheme.algorithm);
 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 }