1 /* 2 * Copyright (c) 2010, 2012, 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.AlgorithmConstraints; 29 import java.security.CryptoPrimitive; 30 import java.security.PrivateKey; 31 32 import java.util.Set; 33 import java.util.HashSet; 34 import java.util.Map; 35 import java.util.EnumSet; 36 import java.util.TreeMap; 37 import java.util.Collection; 38 import java.util.Collections; 39 import java.util.ArrayList; 40 41 import sun.security.util.KeyUtil; 42 43 /** 44 * Signature and hash algorithm. 45 * 46 * [RFC5246] The client uses the "signature_algorithms" extension to 47 * indicate to the server which signature/hash algorithm pairs may be 48 * used in digital signatures. The "extension_data" field of this 49 * extension contains a "supported_signature_algorithms" value. 50 * 51 * enum { 52 * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), 53 * sha512(6), (255) 54 * } HashAlgorithm; 55 * 56 * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } 57 * SignatureAlgorithm; 58 * 59 * struct { 60 * HashAlgorithm hash; 61 * SignatureAlgorithm signature; 62 * } SignatureAndHashAlgorithm; 63 */ 64 final class SignatureAndHashAlgorithm { 65 66 // minimum priority for default enabled algorithms 67 final static int SUPPORTED_ALG_PRIORITY_MAX_NUM = 0x00F0; 68 69 // performance optimization 70 private final static Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET = 71 EnumSet.of(CryptoPrimitive.SIGNATURE); 72 73 // supported pairs of signature and hash algorithm 74 private final static Map<Integer, SignatureAndHashAlgorithm> supportedMap; 75 private final static Map<Integer, SignatureAndHashAlgorithm> priorityMap; 76 77 // the hash algorithm 78 private HashAlgorithm hash; 79 80 // the signature algorithm 81 private SignatureAlgorithm signature; 82 83 // id in 16 bit MSB format, i.e. 0x0603 for SHA512withECDSA 84 private int id; 85 86 // the standard algorithm name, for example "SHA512withECDSA" 87 private String algorithm; 88 89 // Priority for the preference order. The lower the better. 90 // 91 // If the algorithm is unsupported, its priority should be bigger 92 // than SUPPORTED_ALG_PRIORITY_MAX_NUM. 93 private int priority; 94 95 // constructor for supported algorithm SignatureAndHashAlgorithm(HashAlgorithm hash, SignatureAlgorithm signature, String algorithm, int priority)96 private SignatureAndHashAlgorithm(HashAlgorithm hash, 97 SignatureAlgorithm signature, String algorithm, int priority) { 98 this.hash = hash; 99 this.signature = signature; 100 this.algorithm = algorithm; 101 this.id = ((hash.value & 0xFF) << 8) | (signature.value & 0xFF); 102 this.priority = priority; 103 } 104 105 // constructor for unsupported algorithm SignatureAndHashAlgorithm(String algorithm, int id, int sequence)106 private SignatureAndHashAlgorithm(String algorithm, int id, int sequence) { 107 this.hash = HashAlgorithm.valueOf((id >> 8) & 0xFF); 108 this.signature = SignatureAlgorithm.valueOf(id & 0xFF); 109 this.algorithm = algorithm; 110 this.id = id; 111 112 // add one more to the sequece number, in case that the number is zero 113 this.priority = SUPPORTED_ALG_PRIORITY_MAX_NUM + sequence + 1; 114 } 115 116 // Note that we do not use the sequence argument for supported algorithms, 117 // so please don't sort by comparing the objects read from handshake 118 // messages. valueOf(int hash, int signature, int sequence)119 static SignatureAndHashAlgorithm valueOf(int hash, 120 int signature, int sequence) { 121 hash &= 0xFF; 122 signature &= 0xFF; 123 124 int id = (hash << 8) | signature; 125 SignatureAndHashAlgorithm signAlg = supportedMap.get(id); 126 if (signAlg == null) { 127 // unsupported algorithm 128 signAlg = new SignatureAndHashAlgorithm( 129 "Unknown (hash:0x" + Integer.toString(hash, 16) + 130 ", signature:0x" + Integer.toString(signature, 16) + ")", 131 id, sequence); 132 } 133 134 return signAlg; 135 } 136 getHashValue()137 int getHashValue() { 138 return (id >> 8) & 0xFF; 139 } 140 getSignatureValue()141 int getSignatureValue() { 142 return id & 0xFF; 143 } 144 getAlgorithmName()145 String getAlgorithmName() { 146 return algorithm; 147 } 148 149 // return the size of a SignatureAndHashAlgorithm structure in TLS record sizeInRecord()150 static int sizeInRecord() { 151 return 2; 152 } 153 154 // Get local supported algorithm collection complying to 155 // algorithm constraints 156 static Collection<SignatureAndHashAlgorithm> getSupportedAlgorithms(AlgorithmConstraints constraints)157 getSupportedAlgorithms(AlgorithmConstraints constraints) { 158 159 Collection<SignatureAndHashAlgorithm> supported = new ArrayList<>(); 160 synchronized (priorityMap) { 161 for (SignatureAndHashAlgorithm sigAlg : priorityMap.values()) { 162 if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM && 163 constraints.permits(SIGNATURE_PRIMITIVE_SET, 164 sigAlg.algorithm, null)) { 165 supported.add(sigAlg); 166 } 167 } 168 } 169 170 return supported; 171 } 172 173 // Get supported algorithm collection from an untrusted collection getSupportedAlgorithms( Collection<SignatureAndHashAlgorithm> algorithms )174 static Collection<SignatureAndHashAlgorithm> getSupportedAlgorithms( 175 Collection<SignatureAndHashAlgorithm> algorithms ) { 176 Collection<SignatureAndHashAlgorithm> supported = new ArrayList<>(); 177 for (SignatureAndHashAlgorithm sigAlg : algorithms) { 178 if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM) { 179 supported.add(sigAlg); 180 } 181 } 182 183 return supported; 184 } 185 getAlgorithmNames( Collection<SignatureAndHashAlgorithm> algorithms)186 static String[] getAlgorithmNames( 187 Collection<SignatureAndHashAlgorithm> algorithms) { 188 ArrayList<String> algorithmNames = new ArrayList<>(); 189 if (algorithms != null) { 190 for (SignatureAndHashAlgorithm sigAlg : algorithms) { 191 algorithmNames.add(sigAlg.algorithm); 192 } 193 } 194 195 String[] array = new String[algorithmNames.size()]; 196 return algorithmNames.toArray(array); 197 } 198 getHashAlgorithmNames( Collection<SignatureAndHashAlgorithm> algorithms)199 static Set<String> getHashAlgorithmNames( 200 Collection<SignatureAndHashAlgorithm> algorithms) { 201 Set<String> algorithmNames = new HashSet<>(); 202 if (algorithms != null) { 203 for (SignatureAndHashAlgorithm sigAlg : algorithms) { 204 if (sigAlg.hash.value > 0) { 205 algorithmNames.add(sigAlg.hash.standardName); 206 } 207 } 208 } 209 210 return algorithmNames; 211 } 212 getHashAlgorithmName(SignatureAndHashAlgorithm algorithm)213 static String getHashAlgorithmName(SignatureAndHashAlgorithm algorithm) { 214 return algorithm.hash.standardName; 215 } 216 supports(HashAlgorithm hash, SignatureAlgorithm signature, String algorithm, int priority)217 private static void supports(HashAlgorithm hash, 218 SignatureAlgorithm signature, String algorithm, int priority) { 219 220 SignatureAndHashAlgorithm pair = 221 new SignatureAndHashAlgorithm(hash, signature, algorithm, priority); 222 if (supportedMap.put(pair.id, pair) != null) { 223 throw new RuntimeException( 224 "Duplicate SignatureAndHashAlgorithm definition, id: " + 225 pair.id); 226 } 227 if (priorityMap.put(pair.priority, pair) != null) { 228 throw new RuntimeException( 229 "Duplicate SignatureAndHashAlgorithm definition, priority: " + 230 pair.priority); 231 } 232 } 233 getPreferableAlgorithm( Collection<SignatureAndHashAlgorithm> algorithms, String expected)234 static SignatureAndHashAlgorithm getPreferableAlgorithm( 235 Collection<SignatureAndHashAlgorithm> algorithms, String expected) { 236 237 return SignatureAndHashAlgorithm.getPreferableAlgorithm( 238 algorithms, expected, null); 239 } 240 getPreferableAlgorithm( Collection<SignatureAndHashAlgorithm> algorithms, String expected, PrivateKey signingKey)241 static SignatureAndHashAlgorithm getPreferableAlgorithm( 242 Collection<SignatureAndHashAlgorithm> algorithms, 243 String expected, PrivateKey signingKey) { 244 245 if (expected == null && !algorithms.isEmpty()) { 246 for (SignatureAndHashAlgorithm sigAlg : algorithms) { 247 if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM) { 248 return sigAlg; 249 } 250 } 251 252 return null; // no supported algorithm 253 } 254 255 if (expected == null ) { 256 return null; // no expected algorithm, no supported algorithm 257 } 258 259 /* 260 * Need to check RSA key length to match the length of hash value 261 */ 262 int maxDigestLength = Integer.MAX_VALUE; 263 if (signingKey != null && 264 "rsa".equalsIgnoreCase(signingKey.getAlgorithm()) && 265 expected.equalsIgnoreCase("rsa")) { 266 /* 267 * RSA keys of 512 bits have been shown to be practically 268 * breakable, it does not make much sense to use the strong 269 * hash algorithm for keys whose key size less than 512 bits. 270 * So it is not necessary to caculate the required max digest 271 * length exactly. 272 * 273 * If key size is greater than or equals to 768, there is no max 274 * digest length limitation in currect implementation. 275 * 276 * If key size is greater than or equals to 512, but less than 277 * 768, the digest length should be less than or equal to 32 bytes. 278 * 279 * If key size is less than 512, the digest length should be 280 * less than or equal to 20 bytes. 281 */ 282 int keySize = KeyUtil.getKeySize(signingKey); 283 if (keySize >= 768) { 284 maxDigestLength = HashAlgorithm.SHA512.length; 285 } else if ((keySize >= 512) && (keySize < 768)) { 286 maxDigestLength = HashAlgorithm.SHA256.length; 287 } else if ((keySize > 0) && (keySize < 512)) { 288 maxDigestLength = HashAlgorithm.SHA1.length; 289 } // Otherwise, cannot determine the key size, prefer the most 290 // perferable hash algorithm. 291 } 292 293 for (SignatureAndHashAlgorithm algorithm : algorithms) { 294 int signValue = algorithm.id & 0xFF; 295 if (expected.equalsIgnoreCase("rsa") && 296 signValue == SignatureAlgorithm.RSA.value) { 297 if (algorithm.hash.length <= maxDigestLength) { 298 return algorithm; 299 } 300 } else if ( 301 (expected.equalsIgnoreCase("dsa") && 302 signValue == SignatureAlgorithm.DSA.value) || 303 (expected.equalsIgnoreCase("ecdsa") && 304 signValue == SignatureAlgorithm.ECDSA.value) || 305 (expected.equalsIgnoreCase("ec") && 306 signValue == SignatureAlgorithm.ECDSA.value)) { 307 return algorithm; 308 } 309 } 310 311 return null; 312 } 313 314 static enum HashAlgorithm { 315 UNDEFINED("undefined", "", -1, -1), 316 NONE( "none", "NONE", 0, -1), 317 MD5( "md5", "MD5", 1, 16), 318 SHA1( "sha1", "SHA-1", 2, 20), 319 SHA224( "sha224", "SHA-224", 3, 28), 320 SHA256( "sha256", "SHA-256", 4, 32), 321 SHA384( "sha384", "SHA-384", 5, 48), 322 SHA512( "sha512", "SHA-512", 6, 64); 323 324 final String name; // not the standard signature algorithm name 325 // except the UNDEFINED, other names are defined 326 // by TLS 1.2 protocol 327 final String standardName; // the standard MessageDigest algorithm name 328 final int value; 329 final int length; // digest length in bytes, -1 means not applicable 330 HashAlgorithm(String name, String standardName, int value, int length)331 private HashAlgorithm(String name, String standardName, 332 int value, int length) { 333 this.name = name; 334 this.standardName = standardName; 335 this.value = value; 336 this.length = length; 337 } 338 valueOf(int value)339 static HashAlgorithm valueOf(int value) { 340 HashAlgorithm algorithm = UNDEFINED; 341 switch (value) { 342 case 0: 343 algorithm = NONE; 344 break; 345 case 1: 346 algorithm = MD5; 347 break; 348 case 2: 349 algorithm = SHA1; 350 break; 351 case 3: 352 algorithm = SHA224; 353 break; 354 case 4: 355 algorithm = SHA256; 356 break; 357 case 5: 358 algorithm = SHA384; 359 break; 360 case 6: 361 algorithm = SHA512; 362 break; 363 } 364 365 return algorithm; 366 } 367 } 368 369 static enum SignatureAlgorithm { 370 UNDEFINED("undefined", -1), 371 ANONYMOUS("anonymous", 0), 372 RSA( "rsa", 1), 373 DSA( "dsa", 2), 374 ECDSA( "ecdsa", 3); 375 376 final String name; // not the standard signature algorithm name 377 // except the UNDEFINED, other names are defined 378 // by TLS 1.2 protocol 379 final int value; 380 SignatureAlgorithm(String name, int value)381 private SignatureAlgorithm(String name, int value) { 382 this.name = name; 383 this.value = value; 384 } 385 valueOf(int value)386 static SignatureAlgorithm valueOf(int value) { 387 SignatureAlgorithm algorithm = UNDEFINED; 388 switch (value) { 389 case 0: 390 algorithm = ANONYMOUS; 391 break; 392 case 1: 393 algorithm = RSA; 394 break; 395 case 2: 396 algorithm = DSA; 397 break; 398 case 3: 399 algorithm = ECDSA; 400 break; 401 } 402 403 return algorithm; 404 } 405 } 406 407 static { 408 supportedMap = Collections.synchronizedSortedMap( 409 new TreeMap<Integer, SignatureAndHashAlgorithm>()); 410 priorityMap = Collections.synchronizedSortedMap( 411 new TreeMap<Integer, SignatureAndHashAlgorithm>()); 412 413 synchronized (supportedMap) { 414 int p = SUPPORTED_ALG_PRIORITY_MAX_NUM; supports(HashAlgorithm.MD5, SignatureAlgorithm.RSA, "MD5withRSA", --p)415 supports(HashAlgorithm.MD5, SignatureAlgorithm.RSA, 416 "MD5withRSA", --p); supports(HashAlgorithm.SHA1, SignatureAlgorithm.DSA, "SHA1withDSA", --p)417 supports(HashAlgorithm.SHA1, SignatureAlgorithm.DSA, 418 "SHA1withDSA", --p); supports(HashAlgorithm.SHA1, SignatureAlgorithm.RSA, "SHA1withRSA", --p)419 supports(HashAlgorithm.SHA1, SignatureAlgorithm.RSA, 420 "SHA1withRSA", --p); supports(HashAlgorithm.SHA1, SignatureAlgorithm.ECDSA, "SHA1withECDSA", --p)421 supports(HashAlgorithm.SHA1, SignatureAlgorithm.ECDSA, 422 "SHA1withECDSA", --p); supports(HashAlgorithm.SHA224, SignatureAlgorithm.RSA, "SHA224withRSA", --p)423 supports(HashAlgorithm.SHA224, SignatureAlgorithm.RSA, 424 "SHA224withRSA", --p); supports(HashAlgorithm.SHA224, SignatureAlgorithm.ECDSA, "SHA224withECDSA", --p)425 supports(HashAlgorithm.SHA224, SignatureAlgorithm.ECDSA, 426 "SHA224withECDSA", --p); supports(HashAlgorithm.SHA256, SignatureAlgorithm.RSA, "SHA256withRSA", --p)427 supports(HashAlgorithm.SHA256, SignatureAlgorithm.RSA, 428 "SHA256withRSA", --p); supports(HashAlgorithm.SHA256, SignatureAlgorithm.ECDSA, "SHA256withECDSA", --p)429 supports(HashAlgorithm.SHA256, SignatureAlgorithm.ECDSA, 430 "SHA256withECDSA", --p); supports(HashAlgorithm.SHA384, SignatureAlgorithm.RSA, "SHA384withRSA", --p)431 supports(HashAlgorithm.SHA384, SignatureAlgorithm.RSA, 432 "SHA384withRSA", --p); supports(HashAlgorithm.SHA384, SignatureAlgorithm.ECDSA, "SHA384withECDSA", --p)433 supports(HashAlgorithm.SHA384, SignatureAlgorithm.ECDSA, 434 "SHA384withECDSA", --p); supports(HashAlgorithm.SHA512, SignatureAlgorithm.RSA, "SHA512withRSA", --p)435 supports(HashAlgorithm.SHA512, SignatureAlgorithm.RSA, 436 "SHA512withRSA", --p); supports(HashAlgorithm.SHA512, SignatureAlgorithm.ECDSA, "SHA512withECDSA", --p)437 supports(HashAlgorithm.SHA512, SignatureAlgorithm.ECDSA, 438 "SHA512withECDSA", --p); 439 } 440 } 441 } 442 443