src/java.base/share/classes/sun/security/ssl/SignatureScheme.java
changeset 50768 68fa3d4026ea
child 51574 ed52ea83f830
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
       
     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.interfaces.ECPrivateKey;
       
    30 import java.security.spec.AlgorithmParameterSpec;
       
    31 import java.security.spec.ECParameterSpec;
       
    32 import java.security.spec.MGF1ParameterSpec;
       
    33 import java.security.spec.PSSParameterSpec;
       
    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.Set;
       
    42 import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
       
    43 import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
       
    44 import sun.security.util.KeyUtil;
       
    45 
       
    46 enum SignatureScheme {
       
    47     // EdDSA algorithms
       
    48     ED25519                 (0x0807, "ed25519", "ed25519",
       
    49                                     "ed25519",
       
    50                                     ProtocolVersion.PROTOCOLS_OF_13),
       
    51     ED448                   (0x0808, "ed448", "ed448",
       
    52                                     "ed448",
       
    53                                     ProtocolVersion.PROTOCOLS_OF_13),
       
    54 
       
    55     // ECDSA algorithms
       
    56     ECDSA_SECP256R1_SHA256  (0x0403, "ecdsa_secp256r1_sha256",
       
    57                                     "SHA256withECDSA",
       
    58                                     "EC",
       
    59                                     NamedGroup.SECP256_R1,
       
    60                                     ProtocolVersion.PROTOCOLS_TO_13),
       
    61     ECDSA_SECP384R1_SHA384  (0x0503, "ecdsa_secp384r1_sha384",
       
    62                                     "SHA384withECDSA",
       
    63                                     "EC",
       
    64                                     NamedGroup.SECP384_R1,
       
    65                                     ProtocolVersion.PROTOCOLS_TO_13),
       
    66     ECDSA_SECP512R1_SHA512  (0x0603, "ecdsa_secp512r1_sha512",
       
    67                                     "SHA512withECDSA",
       
    68                                     "EC",
       
    69                                     NamedGroup.SECP521_R1,
       
    70                                     ProtocolVersion.PROTOCOLS_TO_13),
       
    71 
       
    72     // RSASSA-PSS algorithms with public key OID rsaEncryption
       
    73     //
       
    74     // The minimalKeySize is calculated as (See RFC 8017 for details):
       
    75     //     hash length + salt length + 16
       
    76     RSA_PSS_RSAE_SHA256     (0x0804, "rsa_pss_rsae_sha256",
       
    77                                     "RSASSA-PSS", "RSA",
       
    78                                     SigAlgParamSpec.RSA_PSS_SHA256, 528,
       
    79                                     ProtocolVersion.PROTOCOLS_12_13),
       
    80     RSA_PSS_RSAE_SHA384     (0x0805, "rsa_pss_rsae_sha384",
       
    81                                     "RSASSA-PSS", "RSA",
       
    82                                     SigAlgParamSpec.RSA_PSS_SHA384, 784,
       
    83                                     ProtocolVersion.PROTOCOLS_12_13),
       
    84     RSA_PSS_RSAE_SHA512     (0x0806, "rsa_pss_rsae_sha512",
       
    85                                     "RSASSA-PSS", "RSA",
       
    86                                     SigAlgParamSpec.RSA_PSS_SHA512, 1040,
       
    87                                     ProtocolVersion.PROTOCOLS_12_13),
       
    88 
       
    89     // RSASSA-PSS algorithms with public key OID RSASSA-PSS
       
    90     //
       
    91     // The minimalKeySize is calculated as (See RFC 8017 for details):
       
    92     //     hash length + salt length + 16
       
    93     RSA_PSS_PSS_SHA256      (0x0809, "rsa_pss_pss_sha256",
       
    94                                     "RSASSA-PSS", "RSASSA-PSS",
       
    95                                     SigAlgParamSpec.RSA_PSS_SHA256, 528,
       
    96                                     ProtocolVersion.PROTOCOLS_12_13),
       
    97     RSA_PSS_PSS_SHA384      (0x080A, "rsa_pss_pss_sha384",
       
    98                                     "RSASSA-PSS", "RSASSA-PSS",
       
    99                                     SigAlgParamSpec.RSA_PSS_SHA384, 784,
       
   100                                     ProtocolVersion.PROTOCOLS_12_13),
       
   101     RSA_PSS_PSS_SHA512      (0x080B, "rsa_pss_pss_sha512",
       
   102                                     "RSASSA-PSS", "RSASSA-PSS",
       
   103                                     SigAlgParamSpec.RSA_PSS_SHA512, 1040,
       
   104                                     ProtocolVersion.PROTOCOLS_12_13),
       
   105 
       
   106     // RSASSA-PKCS1-v1_5 algorithms
       
   107     RSA_PKCS1_SHA256        (0x0401, "rsa_pkcs1_sha256", "SHA256withRSA",
       
   108                                     "RSA", null, null, 511,
       
   109                                     ProtocolVersion.PROTOCOLS_TO_13,
       
   110                                     ProtocolVersion.PROTOCOLS_TO_12),
       
   111     RSA_PKCS1_SHA384        (0x0501, "rsa_pkcs1_sha384", "SHA384withRSA",
       
   112                                     "RSA", null, null, 768,
       
   113                                     ProtocolVersion.PROTOCOLS_TO_13,
       
   114                                     ProtocolVersion.PROTOCOLS_TO_12),
       
   115     RSA_PKCS1_SHA512        (0x0601, "rsa_pkcs1_sha512", "SHA512withRSA",
       
   116                                     "RSA", null, null, 768,
       
   117                                     ProtocolVersion.PROTOCOLS_TO_13,
       
   118                                     ProtocolVersion.PROTOCOLS_TO_12),
       
   119 
       
   120     // Legacy algorithms
       
   121     DSA_SHA256              (0x0402, "dsa_sha256", "SHA256withDSA",
       
   122                                     "DSA",
       
   123                                     ProtocolVersion.PROTOCOLS_TO_12),
       
   124     ECDSA_SHA224            (0x0303, "ecdsa_sha224", "SHA224withECDSA",
       
   125                                     "EC",
       
   126                                     ProtocolVersion.PROTOCOLS_TO_12),
       
   127     RSA_SHA224              (0x0301, "rsa_sha224", "SHA224withRSA",
       
   128                                     "RSA", 511,
       
   129                                     ProtocolVersion.PROTOCOLS_TO_12),
       
   130     DSA_SHA224              (0x0302, "dsa_sha224", "SHA224withDSA",
       
   131                                     "DSA",
       
   132                                     ProtocolVersion.PROTOCOLS_TO_12),
       
   133     ECDSA_SHA1              (0x0203, "ecdsa_sha1", "SHA1withECDSA",
       
   134                                     "EC",
       
   135                                     ProtocolVersion.PROTOCOLS_TO_13),
       
   136     RSA_PKCS1_SHA1          (0x0201, "rsa_pkcs1_sha1", "SHA1withRSA",
       
   137                                     "RSA", null, null, 511,
       
   138                                     ProtocolVersion.PROTOCOLS_TO_13,
       
   139                                     ProtocolVersion.PROTOCOLS_TO_12),
       
   140     DSA_SHA1                (0x0202, "dsa_sha1", "SHA1withDSA",
       
   141                                     "DSA",
       
   142                                     ProtocolVersion.PROTOCOLS_TO_12),
       
   143     RSA_MD5                 (0x0101, "rsa_md5", "MD5withRSA",
       
   144                                     "RSA", 511,
       
   145                                     ProtocolVersion.PROTOCOLS_TO_12);
       
   146 
       
   147     final int id;                       // hash + signature
       
   148     final String name;                  // literal name
       
   149     private final String algorithm;     // signature algorithm
       
   150     final String keyAlgorithm;          // signature key algorithm
       
   151     private final AlgorithmParameterSpec signAlgParameter;
       
   152     private final NamedGroup namedGroup;    // associated named group
       
   153 
       
   154     // The minimal required key size in bits.
       
   155     //
       
   156     // Only need to check RSA algorithm at present. RSA keys of 512 bits
       
   157     // have been shown to be practically breakable, it does not make much
       
   158     // sense to use the strong hash algorithm for keys whose key size less
       
   159     // than 512 bits.  So it is not necessary to calculate the minimal
       
   160     // required key size exactly for a hash algorithm.
       
   161     //
       
   162     // Note that some provider may use 511 bits for 512-bit strength RSA keys.
       
   163     final int minimalKeySize;
       
   164     final List<ProtocolVersion> supportedProtocols;
       
   165 
       
   166     // Some signature schemes are supported in different versions for handshake
       
   167     // messages and certificates. This field holds the supported protocols
       
   168     // for handshake messages.
       
   169     final List<ProtocolVersion> handshakeSupportedProtocols;
       
   170     final boolean isAvailable;
       
   171 
       
   172     private static final String[] hashAlgorithms = new String[] {
       
   173             "none",         "md5",      "sha1",     "sha224",
       
   174             "sha256",       "sha384",   "sha512"
       
   175         };
       
   176 
       
   177     private static final String[] signatureAlgorithms = new String[] {
       
   178             "anonymous",    "rsa",      "dsa",      "ecdsa",
       
   179         };
       
   180 
       
   181     static enum SigAlgParamSpec {   // support RSASSA-PSS only now
       
   182         RSA_PSS_SHA256 ("SHA-256", 32),
       
   183         RSA_PSS_SHA384 ("SHA-384", 48),
       
   184         RSA_PSS_SHA512 ("SHA-512", 64);
       
   185 
       
   186         final private AlgorithmParameterSpec parameterSpec;
       
   187         final boolean isAvailable;
       
   188 
       
   189         SigAlgParamSpec(String hash, int saltLength) {
       
   190             // See RFC 8017
       
   191             PSSParameterSpec pssParamSpec =
       
   192                     new PSSParameterSpec(hash, "MGF1",
       
   193                             new MGF1ParameterSpec(hash), saltLength, 1);
       
   194 
       
   195             boolean mediator = true;
       
   196             try {
       
   197                 Signature signer = JsseJce.getSignature("RSASSA-PSS");
       
   198                 signer.setParameter(pssParamSpec);
       
   199             } catch (InvalidAlgorithmParameterException |
       
   200                     NoSuchAlgorithmException exp) {
       
   201                 mediator = false;
       
   202                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   203                     SSLLogger.warning(
       
   204                         "RSASSA-PSS signature with " + hash +
       
   205                         " is not supported by the underlying providers", exp);
       
   206                 }
       
   207             }
       
   208 
       
   209             this.isAvailable = mediator;
       
   210             this.parameterSpec = mediator ? pssParamSpec : null;
       
   211         }
       
   212 
       
   213         AlgorithmParameterSpec getParameterSpec() {
       
   214             return parameterSpec;
       
   215         }
       
   216     }
       
   217 
       
   218     // performance optimization
       
   219     private static final Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
       
   220         Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
       
   221 
       
   222 
       
   223     private SignatureScheme(int id, String name,
       
   224             String algorithm, String keyAlgorithm,
       
   225             ProtocolVersion[] supportedProtocols) {
       
   226         this(id, name, algorithm, keyAlgorithm, -1, supportedProtocols);
       
   227     }
       
   228 
       
   229     private SignatureScheme(int id, String name,
       
   230             String algorithm, String keyAlgorithm,
       
   231             int minimalKeySize,
       
   232             ProtocolVersion[] supportedProtocols) {
       
   233         this(id, name, algorithm, keyAlgorithm,
       
   234                 null, minimalKeySize, supportedProtocols);
       
   235     }
       
   236 
       
   237     private SignatureScheme(int id, String name,
       
   238             String algorithm, String keyAlgorithm,
       
   239             SigAlgParamSpec signAlgParamSpec, int minimalKeySize,
       
   240             ProtocolVersion[] supportedProtocols) {
       
   241         this(id, name, algorithm, keyAlgorithm,
       
   242                 signAlgParamSpec, null, minimalKeySize,
       
   243                 supportedProtocols, supportedProtocols);
       
   244     }
       
   245 
       
   246     private SignatureScheme(int id, String name,
       
   247             String algorithm, String keyAlgorithm,
       
   248             NamedGroup namedGroup,
       
   249             ProtocolVersion[] supportedProtocols) {
       
   250         this(id, name, algorithm, keyAlgorithm,
       
   251                 null, namedGroup, -1,
       
   252                 supportedProtocols, supportedProtocols);
       
   253     }
       
   254 
       
   255     private SignatureScheme(int id, String name,
       
   256             String algorithm, String keyAlgorithm,
       
   257             SigAlgParamSpec signAlgParamSpec,
       
   258             NamedGroup namedGroup, int minimalKeySize,
       
   259             ProtocolVersion[] supportedProtocols,
       
   260             ProtocolVersion[] handshakeSupportedProtocols) {
       
   261         this.id = id;
       
   262         this.name = name;
       
   263         this.algorithm = algorithm;
       
   264         this.keyAlgorithm = keyAlgorithm;
       
   265         this.signAlgParameter =
       
   266             signAlgParamSpec != null ? signAlgParamSpec.parameterSpec : null;
       
   267         this.namedGroup = namedGroup;
       
   268         this.minimalKeySize = minimalKeySize;
       
   269         this.supportedProtocols = Arrays.asList(supportedProtocols);
       
   270         this.handshakeSupportedProtocols =
       
   271                 Arrays.asList(handshakeSupportedProtocols);
       
   272 
       
   273         boolean mediator = true;
       
   274         if (signAlgParamSpec != null) {
       
   275             mediator = signAlgParamSpec.isAvailable;
       
   276         } else {
       
   277             try {
       
   278                 JsseJce.getSignature(algorithm);
       
   279             } catch (Exception e) {
       
   280                 mediator = false;
       
   281                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   282                     SSLLogger.warning(
       
   283                         "Signature algorithm, " + algorithm +
       
   284                         ", is not supported by the underlying providers");
       
   285                 }
       
   286             }
       
   287         }
       
   288 
       
   289         if (mediator && ((id >> 8) & 0xFF) == 0x03) {   // SHA224
       
   290             // There are some problems to use SHA224 on Windows.
       
   291             if (Security.getProvider("SunMSCAPI") != null) {
       
   292                 mediator = false;
       
   293             }
       
   294         }
       
   295 
       
   296         this.isAvailable = mediator;
       
   297     }
       
   298 
       
   299     static SignatureScheme valueOf(int id) {
       
   300         for (SignatureScheme ss: SignatureScheme.values()) {
       
   301             if (ss.id == id) {
       
   302                 return ss;
       
   303             }
       
   304         }
       
   305 
       
   306         return null;
       
   307     }
       
   308 
       
   309     static String nameOf(int id) {
       
   310         for (SignatureScheme ss: SignatureScheme.values()) {
       
   311             if (ss.id == id) {
       
   312                 return ss.name;
       
   313             }
       
   314         }
       
   315 
       
   316         // Use TLS 1.2 style name for unknown signature scheme.
       
   317         int hashId = ((id >> 8) & 0xFF);
       
   318         int signId = (id & 0xFF);
       
   319         String hashName = (hashId >= hashAlgorithms.length) ?
       
   320             "UNDEFINED-HASH(" + hashId + ")" : hashAlgorithms[hashId];
       
   321         String signName = (signId >= signatureAlgorithms.length) ?
       
   322             "UNDEFINED-SIGNATURE(" + signId + ")" :
       
   323             signatureAlgorithms[signId];
       
   324 
       
   325         return signName + "_" + hashName;
       
   326     }
       
   327 
       
   328     // Return the size of a SignatureScheme structure in TLS record
       
   329     static int sizeInRecord() {
       
   330         return 2;
       
   331     }
       
   332 
       
   333     // Get local supported algorithm collection complying to algorithm
       
   334     // constraints.
       
   335     static List<SignatureScheme> getSupportedAlgorithms(
       
   336             AlgorithmConstraints constraints,
       
   337             List<ProtocolVersion> activeProtocols) {
       
   338         List<SignatureScheme> supported = new LinkedList<>();
       
   339         for (SignatureScheme ss: SignatureScheme.values()) {
       
   340             if (!ss.isAvailable) {
       
   341                 continue;
       
   342             }
       
   343 
       
   344             boolean isMatch = false;
       
   345             for (ProtocolVersion pv : activeProtocols) {
       
   346                 if (ss.supportedProtocols.contains(pv)) {
       
   347                     isMatch = true;
       
   348                     break;
       
   349                 }
       
   350             }
       
   351 
       
   352             if (isMatch) {
       
   353                 if (constraints.permits(
       
   354                         SIGNATURE_PRIMITIVE_SET, ss.algorithm, null)) {
       
   355                     supported.add(ss);
       
   356                 } else if (SSLLogger.isOn &&
       
   357                         SSLLogger.isOn("ssl,handshake,verbose")) {
       
   358                     SSLLogger.finest(
       
   359                         "Ignore disabled signature sheme: " + ss.name);
       
   360                 }
       
   361             } else if (SSLLogger.isOn &&
       
   362                     SSLLogger.isOn("ssl,handshake,verbose")) {
       
   363                 SSLLogger.finest(
       
   364                     "Ignore inactive signature sheme: " + ss.name);
       
   365             }
       
   366         }
       
   367 
       
   368         return supported;
       
   369     }
       
   370 
       
   371     static List<SignatureScheme> getSupportedAlgorithms(
       
   372             AlgorithmConstraints constraints,
       
   373             ProtocolVersion protocolVersion, int[] algorithmIds) {
       
   374         List<SignatureScheme> supported = new LinkedList<>();
       
   375         for (int ssid : algorithmIds) {
       
   376             SignatureScheme ss = SignatureScheme.valueOf(ssid);
       
   377             if (ss == null) {
       
   378                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   379                     SSLLogger.warning(
       
   380                             "Unsupported signature scheme: " +
       
   381                             SignatureScheme.nameOf(ssid));
       
   382                 }
       
   383             } else if (ss.isAvailable &&
       
   384                     ss.supportedProtocols.contains(protocolVersion) &&
       
   385                     constraints.permits(SIGNATURE_PRIMITIVE_SET,
       
   386                            ss.algorithm, null)) {
       
   387                 supported.add(ss);
       
   388             } else {
       
   389                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   390                     SSLLogger.warning(
       
   391                             "Unsupported signature scheme: " + ss.name);
       
   392                 }
       
   393             }
       
   394         }
       
   395 
       
   396         return supported;
       
   397     }
       
   398 
       
   399     static SignatureScheme getPreferableAlgorithm(
       
   400             List<SignatureScheme> schemes,
       
   401             SignatureScheme certScheme,
       
   402             ProtocolVersion version) {
       
   403 
       
   404         for (SignatureScheme ss : schemes) {
       
   405             if (ss.isAvailable &&
       
   406             ss.handshakeSupportedProtocols.contains(version) &&
       
   407             certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
       
   408 
       
   409                 return ss;
       
   410             }
       
   411         }
       
   412 
       
   413         return null;
       
   414     }
       
   415 
       
   416     static SignatureScheme getPreferableAlgorithm(
       
   417             List<SignatureScheme> schemes,
       
   418             PrivateKey signingKey,
       
   419             ProtocolVersion version) {
       
   420 
       
   421         String keyAlgorithm = signingKey.getAlgorithm();
       
   422         int keySize;
       
   423         // Only need to check RSA algorithm at present.
       
   424         if (keyAlgorithm.equalsIgnoreCase("RSA") ||
       
   425                 keyAlgorithm.equalsIgnoreCase("RSASSA-PSS")) {
       
   426             keySize = KeyUtil.getKeySize(signingKey);
       
   427         } else {
       
   428             keySize = Integer.MAX_VALUE;
       
   429         }
       
   430         for (SignatureScheme ss : schemes) {
       
   431             if (ss.isAvailable && (keySize >= ss.minimalKeySize) &&
       
   432                 ss.handshakeSupportedProtocols.contains(version) &&
       
   433                 keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
       
   434                 if (ss.namedGroup != null &&
       
   435                     ss.namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
       
   436                     ECParameterSpec params =
       
   437                                 ((ECPrivateKey)signingKey).getParams();
       
   438                     if (ss.namedGroup == NamedGroup.valueOf(params)) {
       
   439                         return ss;
       
   440                     }
       
   441                 } else {
       
   442                     return ss;
       
   443                 }
       
   444             }
       
   445         }
       
   446 
       
   447         return null;
       
   448     }
       
   449 
       
   450     static String[] getAlgorithmNames(Collection<SignatureScheme> schemes) {
       
   451         if (schemes != null) {
       
   452             ArrayList<String> names = new ArrayList<>(schemes.size());
       
   453             for (SignatureScheme scheme : schemes) {
       
   454                 names.add(scheme.algorithm);
       
   455             }
       
   456 
       
   457             return names.toArray(new String[0]);
       
   458         }
       
   459 
       
   460         return new String[0];
       
   461     }
       
   462 
       
   463     Signature getSignature(Key key) throws NoSuchAlgorithmException,
       
   464             InvalidAlgorithmParameterException, InvalidKeyException {
       
   465         if (!isAvailable) {
       
   466             return null;
       
   467         }
       
   468 
       
   469         Signature signer = JsseJce.getSignature(algorithm);
       
   470         if (key instanceof PublicKey) {
       
   471             signer.initVerify((PublicKey)(key));
       
   472         } else {
       
   473             signer.initSign((PrivateKey)key);
       
   474         }
       
   475 
       
   476         // Important note:  Please don't set the parameters before signature
       
   477         // or verification initialization, so that the crypto provider can
       
   478         // be selected properly.
       
   479         if (signAlgParameter != null) {
       
   480             signer.setParameter(signAlgParameter);
       
   481         }
       
   482 
       
   483         return signer;
       
   484     }
       
   485 }