3002N/A/*
4589N/A * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
3002N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3002N/A *
3002N/A * This code is free software; you can redistribute it and/or modify it
3002N/A * under the terms of the GNU General Public License version 2 only, as
3002N/A * published by the Free Software Foundation. Oracle designates this
3002N/A * particular file as subject to the "Classpath" exception as provided
3002N/A * by Oracle in the LICENSE file that accompanied this code.
3002N/A *
3002N/A * This code is distributed in the hope that it will be useful, but WITHOUT
3002N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3002N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
3002N/A * version 2 for more details (a copy is included in the LICENSE file that
3002N/A * accompanied this code).
3002N/A *
3002N/A * You should have received a copy of the GNU General Public License version
3002N/A * 2 along with this work; if not, write to the Free Software Foundation,
3002N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
3002N/A *
3002N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
3002N/A * or visit www.oracle.com if you need additional information or have any
3002N/A * questions.
3002N/A */
3002N/A
3002N/Apackage sun.security.ssl;
3002N/A
3002N/Aimport java.security.AlgorithmConstraints;
3002N/Aimport java.security.CryptoPrimitive;
4589N/Aimport java.security.PrivateKey;
3002N/A
3002N/Aimport java.util.Set;
3002N/Aimport java.util.HashSet;
3002N/Aimport java.util.Map;
3002N/Aimport java.util.EnumSet;
3002N/Aimport java.util.TreeMap;
3002N/Aimport java.util.Collection;
3002N/Aimport java.util.Collections;
3002N/Aimport java.util.ArrayList;
3002N/A
5690N/Aimport sun.security.util.KeyUtil;
4589N/A
3002N/A/**
3002N/A * Signature and hash algorithm.
3002N/A *
3002N/A * [RFC5246] The client uses the "signature_algorithms" extension to
3002N/A * indicate to the server which signature/hash algorithm pairs may be
3002N/A * used in digital signatures. The "extension_data" field of this
3002N/A * extension contains a "supported_signature_algorithms" value.
3002N/A *
3002N/A * enum {
3002N/A * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
3002N/A * sha512(6), (255)
3002N/A * } HashAlgorithm;
3002N/A *
3002N/A * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
3002N/A * SignatureAlgorithm;
3002N/A *
3002N/A * struct {
3002N/A * HashAlgorithm hash;
3002N/A * SignatureAlgorithm signature;
3002N/A * } SignatureAndHashAlgorithm;
3002N/A */
3002N/Afinal class SignatureAndHashAlgorithm {
3002N/A
3002N/A // minimum priority for default enabled algorithms
3002N/A final static int SUPPORTED_ALG_PRIORITY_MAX_NUM = 0x00F0;
3002N/A
3002N/A // performance optimization
3002N/A private final static Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
3002N/A EnumSet.of(CryptoPrimitive.SIGNATURE);
3002N/A
3002N/A // supported pairs of signature and hash algorithm
3002N/A private final static Map<Integer, SignatureAndHashAlgorithm> supportedMap;
3002N/A private final static Map<Integer, SignatureAndHashAlgorithm> priorityMap;
3002N/A
3002N/A // the hash algorithm
3002N/A private HashAlgorithm hash;
3002N/A
3002N/A // the signature algorithm
3002N/A private SignatureAlgorithm signature;
3002N/A
3002N/A // id in 16 bit MSB format, i.e. 0x0603 for SHA512withECDSA
3002N/A private int id;
3002N/A
3002N/A // the standard algorithm name, for example "SHA512withECDSA"
3002N/A private String algorithm;
3002N/A
3002N/A // Priority for the preference order. The lower the better.
3002N/A //
3002N/A // If the algorithm is unsupported, its priority should be bigger
3002N/A // than SUPPORTED_ALG_PRIORITY_MAX_NUM.
3002N/A private int priority;
3002N/A
3002N/A // constructor for supported algorithm
3002N/A private SignatureAndHashAlgorithm(HashAlgorithm hash,
3002N/A SignatureAlgorithm signature, String algorithm, int priority) {
3002N/A this.hash = hash;
3002N/A this.signature = signature;
3002N/A this.algorithm = algorithm;
3002N/A this.id = ((hash.value & 0xFF) << 8) | (signature.value & 0xFF);
3002N/A this.priority = priority;
3002N/A }
3002N/A
3002N/A // constructor for unsupported algorithm
3002N/A private SignatureAndHashAlgorithm(String algorithm, int id, int sequence) {
3002N/A this.hash = HashAlgorithm.valueOf((id >> 8) & 0xFF);
3002N/A this.signature = SignatureAlgorithm.valueOf(id & 0xFF);
3002N/A this.algorithm = algorithm;
3002N/A this.id = id;
3002N/A
3002N/A // add one more to the sequece number, in case that the number is zero
3002N/A this.priority = SUPPORTED_ALG_PRIORITY_MAX_NUM + sequence + 1;
3002N/A }
3002N/A
3002N/A // Note that we do not use the sequence argument for supported algorithms,
3002N/A // so please don't sort by comparing the objects read from handshake
3002N/A // messages.
3002N/A static SignatureAndHashAlgorithm valueOf(int hash,
3002N/A int signature, int sequence) {
3002N/A hash &= 0xFF;
3002N/A signature &= 0xFF;
3002N/A
3002N/A int id = (hash << 8) | signature;
3002N/A SignatureAndHashAlgorithm signAlg = supportedMap.get(id);
3002N/A if (signAlg == null) {
3002N/A // unsupported algorithm
3002N/A signAlg = new SignatureAndHashAlgorithm(
3002N/A "Unknown (hash:0x" + Integer.toString(hash, 16) +
3002N/A ", signature:0x" + Integer.toString(signature, 16) + ")",
3002N/A id, sequence);
3002N/A }
3002N/A
3002N/A return signAlg;
3002N/A }
3002N/A
3002N/A int getHashValue() {
3002N/A return (id >> 8) & 0xFF;
3002N/A }
3002N/A
3002N/A int getSignatureValue() {
3002N/A return id & 0xFF;
3002N/A }
3002N/A
3002N/A String getAlgorithmName() {
3002N/A return algorithm;
3002N/A }
3002N/A
3002N/A // return the size of a SignatureAndHashAlgorithm structure in TLS record
3002N/A static int sizeInRecord() {
3002N/A return 2;
3002N/A }
3002N/A
3002N/A // Get local supported algorithm collection complying to
3002N/A // algorithm constraints
3002N/A static Collection<SignatureAndHashAlgorithm>
3002N/A getSupportedAlgorithms(AlgorithmConstraints constraints) {
3002N/A
3401N/A Collection<SignatureAndHashAlgorithm> supported = new ArrayList<>();
3002N/A synchronized (priorityMap) {
3002N/A for (SignatureAndHashAlgorithm sigAlg : priorityMap.values()) {
3002N/A if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM &&
3002N/A constraints.permits(SIGNATURE_PRIMITIVE_SET,
3002N/A sigAlg.algorithm, null)) {
3002N/A supported.add(sigAlg);
3002N/A }
3002N/A }
3002N/A }
3002N/A
3002N/A return supported;
3002N/A }
3002N/A
3002N/A // Get supported algorithm collection from an untrusted collection
3002N/A static Collection<SignatureAndHashAlgorithm> getSupportedAlgorithms(
3002N/A Collection<SignatureAndHashAlgorithm> algorithms ) {
3401N/A Collection<SignatureAndHashAlgorithm> supported = new ArrayList<>();
3002N/A for (SignatureAndHashAlgorithm sigAlg : algorithms) {
3002N/A if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM) {
3002N/A supported.add(sigAlg);
3002N/A }
3002N/A }
3002N/A
3002N/A return supported;
3002N/A }
3002N/A
3002N/A static String[] getAlgorithmNames(
3002N/A Collection<SignatureAndHashAlgorithm> algorithms) {
3401N/A ArrayList<String> algorithmNames = new ArrayList<>();
3002N/A if (algorithms != null) {
3002N/A for (SignatureAndHashAlgorithm sigAlg : algorithms) {
3002N/A algorithmNames.add(sigAlg.algorithm);
3002N/A }
3002N/A }
3002N/A
3002N/A String[] array = new String[algorithmNames.size()];
3002N/A return algorithmNames.toArray(array);
3002N/A }
3002N/A
3002N/A static Set<String> getHashAlgorithmNames(
3002N/A Collection<SignatureAndHashAlgorithm> algorithms) {
3401N/A Set<String> algorithmNames = new HashSet<>();
3002N/A if (algorithms != null) {
3002N/A for (SignatureAndHashAlgorithm sigAlg : algorithms) {
3002N/A if (sigAlg.hash.value > 0) {
3002N/A algorithmNames.add(sigAlg.hash.standardName);
3002N/A }
3002N/A }
3002N/A }
3002N/A
3002N/A return algorithmNames;
3002N/A }
3002N/A
3002N/A static String getHashAlgorithmName(SignatureAndHashAlgorithm algorithm) {
3002N/A return algorithm.hash.standardName;
3002N/A }
3002N/A
3002N/A private static void supports(HashAlgorithm hash,
3002N/A SignatureAlgorithm signature, String algorithm, int priority) {
3002N/A
3002N/A SignatureAndHashAlgorithm pair =
3002N/A new SignatureAndHashAlgorithm(hash, signature, algorithm, priority);
3002N/A if (supportedMap.put(pair.id, pair) != null) {
3002N/A throw new RuntimeException(
3002N/A "Duplicate SignatureAndHashAlgorithm definition, id: " +
3002N/A pair.id);
3002N/A }
3002N/A if (priorityMap.put(pair.priority, pair) != null) {
3002N/A throw new RuntimeException(
3002N/A "Duplicate SignatureAndHashAlgorithm definition, priority: " +
3002N/A pair.priority);
3002N/A }
3002N/A }
3002N/A
3002N/A static SignatureAndHashAlgorithm getPreferableAlgorithm(
3002N/A Collection<SignatureAndHashAlgorithm> algorithms, String expected) {
3002N/A
4589N/A return SignatureAndHashAlgorithm.getPreferableAlgorithm(
4589N/A algorithms, expected, null);
4589N/A }
4589N/A
4589N/A static SignatureAndHashAlgorithm getPreferableAlgorithm(
4589N/A Collection<SignatureAndHashAlgorithm> algorithms,
4589N/A String expected, PrivateKey signingKey) {
4589N/A
3002N/A if (expected == null && !algorithms.isEmpty()) {
3002N/A for (SignatureAndHashAlgorithm sigAlg : algorithms) {
3002N/A if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM) {
3002N/A return sigAlg;
3002N/A }
3002N/A }
3002N/A
3002N/A return null; // no supported algorithm
3002N/A }
3002N/A
4589N/A if (expected == null ) {
4589N/A return null; // no expected algorithm, no supported algorithm
4589N/A }
4589N/A
4589N/A /*
4589N/A * Need to check RSA key length to match the length of hash value
4589N/A */
4589N/A int maxDigestLength = Integer.MAX_VALUE;
4589N/A if (signingKey != null &&
4589N/A "rsa".equalsIgnoreCase(signingKey.getAlgorithm()) &&
4589N/A expected.equalsIgnoreCase("rsa")) {
4589N/A /*
4589N/A * RSA keys of 512 bits have been shown to be practically
4589N/A * breakable, it does not make much sense to use the strong
4589N/A * hash algorithm for keys whose key size less than 512 bits.
4589N/A * So it is not necessary to caculate the required max digest
4589N/A * length exactly.
4589N/A *
4589N/A * If key size is greater than or equals to 768, there is no max
4589N/A * digest length limitation in currect implementation.
4589N/A *
4589N/A * If key size is greater than or equals to 512, but less than
4589N/A * 768, the digest length should be less than or equal to 32 bytes.
4589N/A *
4589N/A * If key size is less than 512, the digest length should be
4589N/A * less than or equal to 20 bytes.
4589N/A */
5690N/A int keySize = KeyUtil.getKeySize(signingKey);
4589N/A if (keySize >= 768) {
4589N/A maxDigestLength = HashAlgorithm.SHA512.length;
4589N/A } else if ((keySize >= 512) && (keySize < 768)) {
4589N/A maxDigestLength = HashAlgorithm.SHA256.length;
4589N/A } else if ((keySize > 0) && (keySize < 512)) {
4589N/A maxDigestLength = HashAlgorithm.SHA1.length;
4589N/A } // Otherwise, cannot determine the key size, prefer the most
4589N/A // perferable hash algorithm.
4589N/A }
3002N/A
3002N/A for (SignatureAndHashAlgorithm algorithm : algorithms) {
3002N/A int signValue = algorithm.id & 0xFF;
4589N/A if (expected.equalsIgnoreCase("rsa") &&
4589N/A signValue == SignatureAlgorithm.RSA.value) {
4589N/A if (algorithm.hash.length <= maxDigestLength) {
4589N/A return algorithm;
4589N/A }
4589N/A } else if (
4589N/A (expected.equalsIgnoreCase("dsa") &&
4589N/A signValue == SignatureAlgorithm.DSA.value) ||
4589N/A (expected.equalsIgnoreCase("ecdsa") &&
4589N/A signValue == SignatureAlgorithm.ECDSA.value) ||
4589N/A (expected.equalsIgnoreCase("ec") &&
4589N/A signValue == SignatureAlgorithm.ECDSA.value)) {
3002N/A return algorithm;
3002N/A }
3002N/A }
3002N/A
3002N/A return null;
3002N/A }
3002N/A
3002N/A static enum HashAlgorithm {
4589N/A UNDEFINED("undefined", "", -1, -1),
4589N/A NONE( "none", "NONE", 0, -1),
4589N/A MD5( "md5", "MD5", 1, 16),
4589N/A SHA1( "sha1", "SHA-1", 2, 20),
4589N/A SHA224( "sha224", "SHA-224", 3, 28),
4589N/A SHA256( "sha256", "SHA-256", 4, 32),
4589N/A SHA384( "sha384", "SHA-384", 5, 48),
4589N/A SHA512( "sha512", "SHA-512", 6, 64);
3002N/A
3002N/A final String name; // not the standard signature algorithm name
3002N/A // except the UNDEFINED, other names are defined
3002N/A // by TLS 1.2 protocol
3002N/A final String standardName; // the standard MessageDigest algorithm name
3002N/A final int value;
4589N/A final int length; // digest length in bytes, -1 means not applicable
3002N/A
4589N/A private HashAlgorithm(String name, String standardName,
4589N/A int value, int length) {
3002N/A this.name = name;
3002N/A this.standardName = standardName;
3002N/A this.value = value;
4589N/A this.length = length;
3002N/A }
3002N/A
3002N/A static HashAlgorithm valueOf(int value) {
3002N/A HashAlgorithm algorithm = UNDEFINED;
3002N/A switch (value) {
3002N/A case 0:
3002N/A algorithm = NONE;
3002N/A break;
3002N/A case 1:
3002N/A algorithm = MD5;
3002N/A break;
3002N/A case 2:
3002N/A algorithm = SHA1;
3002N/A break;
3002N/A case 3:
3002N/A algorithm = SHA224;
3002N/A break;
3002N/A case 4:
3002N/A algorithm = SHA256;
3002N/A break;
3002N/A case 5:
3002N/A algorithm = SHA384;
3002N/A break;
3002N/A case 6:
3002N/A algorithm = SHA512;
3002N/A break;
3002N/A }
3002N/A
3002N/A return algorithm;
3002N/A }
3002N/A }
3002N/A
3002N/A static enum SignatureAlgorithm {
3002N/A UNDEFINED("undefined", -1),
3002N/A ANONYMOUS("anonymous", 0),
3002N/A RSA( "rsa", 1),
3002N/A DSA( "dsa", 2),
3002N/A ECDSA( "ecdsa", 3);
3002N/A
3002N/A final String name; // not the standard signature algorithm name
3002N/A // except the UNDEFINED, other names are defined
3002N/A // by TLS 1.2 protocol
3002N/A final int value;
3002N/A
3002N/A private SignatureAlgorithm(String name, int value) {
3002N/A this.name = name;
3002N/A this.value = value;
3002N/A }
3002N/A
3002N/A static SignatureAlgorithm valueOf(int value) {
3002N/A SignatureAlgorithm algorithm = UNDEFINED;
3002N/A switch (value) {
3002N/A case 0:
3002N/A algorithm = ANONYMOUS;
3002N/A break;
3002N/A case 1:
3002N/A algorithm = RSA;
3002N/A break;
3002N/A case 2:
3002N/A algorithm = DSA;
3002N/A break;
3002N/A case 3:
3002N/A algorithm = ECDSA;
3002N/A break;
3002N/A }
3002N/A
3002N/A return algorithm;
3002N/A }
3002N/A }
3002N/A
3002N/A static {
3002N/A supportedMap = Collections.synchronizedSortedMap(
3002N/A new TreeMap<Integer, SignatureAndHashAlgorithm>());
3002N/A priorityMap = Collections.synchronizedSortedMap(
3002N/A new TreeMap<Integer, SignatureAndHashAlgorithm>());
3002N/A
3002N/A synchronized (supportedMap) {
3002N/A int p = SUPPORTED_ALG_PRIORITY_MAX_NUM;
3002N/A supports(HashAlgorithm.MD5, SignatureAlgorithm.RSA,
3002N/A "MD5withRSA", --p);
3002N/A supports(HashAlgorithm.SHA1, SignatureAlgorithm.DSA,
3002N/A "SHA1withDSA", --p);
3002N/A supports(HashAlgorithm.SHA1, SignatureAlgorithm.RSA,
3002N/A "SHA1withRSA", --p);
3002N/A supports(HashAlgorithm.SHA1, SignatureAlgorithm.ECDSA,
3002N/A "SHA1withECDSA", --p);
3002N/A supports(HashAlgorithm.SHA224, SignatureAlgorithm.RSA,
3002N/A "SHA224withRSA", --p);
3002N/A supports(HashAlgorithm.SHA224, SignatureAlgorithm.ECDSA,
3002N/A "SHA224withECDSA", --p);
3002N/A supports(HashAlgorithm.SHA256, SignatureAlgorithm.RSA,
3002N/A "SHA256withRSA", --p);
3002N/A supports(HashAlgorithm.SHA256, SignatureAlgorithm.ECDSA,
3002N/A "SHA256withECDSA", --p);
3002N/A supports(HashAlgorithm.SHA384, SignatureAlgorithm.RSA,
3002N/A "SHA384withRSA", --p);
3002N/A supports(HashAlgorithm.SHA384, SignatureAlgorithm.ECDSA,
3002N/A "SHA384withECDSA", --p);
3002N/A supports(HashAlgorithm.SHA512, SignatureAlgorithm.RSA,
3002N/A "SHA512withRSA", --p);
3002N/A supports(HashAlgorithm.SHA512, SignatureAlgorithm.ECDSA,
3002N/A "SHA512withECDSA", --p);
3002N/A }
3002N/A }
3002N/A}
3002N/A