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