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.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),
  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 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);
 239     }
 240 
 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         }
 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     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
 506                     // the named group used for the signature.  RFC 8446
 507                     // does not define countermeasures for the corner cases.
 508                     // In order to mitigate the impact, we choose to check
 509                     // against the local supported named groups.  The risk
 510                     // should be minimal as applications should not use
 511                     // unsupported named groups for its certificates.
 512                     ECParameterSpec params =
 513                             x509Possession.getECParameterSpec();
 514                     if (params != null) {
 515                         NamedGroup keyGroup = NamedGroup.valueOf(params);
 516                         if (keyGroup != null &&
 517                                 SupportedGroups.isSupported(keyGroup)) {
 518                             Signature signer = ss.getSigner(signingKey);
 519                             if (signer != null) {
 520                                 return new SimpleImmutableEntry<>(ss, signer);
 521                             }
 522                         }
 523                     }
 524 
 525                     if (SSLLogger.isOn &&
 526                             SSLLogger.isOn("ssl,handshake,verbose")) {
 527                         SSLLogger.finest(
 528                             "Ignore the legacy signature algorithm (" + ss +
 529                             "), unsupported EC parameter spec: " + params);
 530                     }
 531                 } else {
 532                     Signature signer = ss.getSigner(signingKey);
 533                     if (signer != null) {
 534                         return new SimpleImmutableEntry<>(ss, signer);
 535                     }
 536                 }
 537             }
 538         }
 539 
 540         return null;
 541     }
 542 
 543     static String[] getAlgorithmNames(Collection<SignatureScheme> schemes) {
 544         if (schemes != null) {
 545             ArrayList<String> names = new ArrayList<>(schemes.size());
 546             for (SignatureScheme scheme : schemes) {
 547                 names.add(scheme.algorithm);
 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 }