1 /* 2 * Copyright (c) 1996, 2020, 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.x509; 27 28 import java.io.*; 29 import java.security.interfaces.RSAKey; 30 import java.security.spec.AlgorithmParameterSpec; 31 import java.security.spec.EdDSAParameterSpec; 32 import java.security.spec.InvalidParameterSpecException; 33 import java.security.spec.MGF1ParameterSpec; 34 import java.security.spec.PSSParameterSpec; 35 import java.util.*; 36 import java.util.concurrent.ConcurrentHashMap; 37 import java.security.*; 38 import java.security.interfaces.*; 39 40 import sun.security.rsa.PSSParameters; 41 import sun.security.util.*; 42 43 44 /** 45 * This class identifies algorithms, such as cryptographic transforms, each 46 * of which may be associated with parameters. Instances of this base class 47 * are used when this runtime environment has no special knowledge of the 48 * algorithm type, and may also be used in other cases. Equivalence is 49 * defined according to OID and (where relevant) parameters. 50 * 51 * <P>Subclasses may be used, for example when the algorithm ID has 52 * associated parameters which some code (e.g. code using public keys) needs 53 * to have parsed. Two examples of such algorithms are Diffie-Hellman key 54 * exchange, and the Digital Signature Standard Algorithm (DSS/DSA). 55 * 56 * <P>The OID constants defined in this class correspond to some widely 57 * used algorithms, for which conventional string names have been defined. 58 * This class is not a general repository for OIDs, or for such string names. 59 * Note that the mappings between algorithm IDs and algorithm names is 60 * not one-to-one. 61 * 62 * 63 * @author David Brownell 64 * @author Amit Kapoor 65 * @author Hemma Prafullchandra 66 */ 67 public class AlgorithmId implements Serializable, DerEncoder { 68 69 /** use serialVersionUID from JDK 1.1. for interoperability */ 70 @java.io.Serial 71 private static final long serialVersionUID = 7205873507486557157L; 72 73 /** 74 * The object identitifer being used for this algorithm. 75 */ 76 private ObjectIdentifier algid; 77 78 // The (parsed) parameters 79 @SuppressWarnings("serial") // Not statically typed as Serializable 80 private AlgorithmParameters algParams; 81 private boolean constructedFromDer = true; 82 83 /** 84 * Parameters for this algorithm. These are stored in unparsed 85 * DER-encoded form; subclasses can be made to automaticaly parse 86 * them so there is fast access to these parameters. 87 */ 88 @SuppressWarnings("serial") // Not statically typed as Serializable 89 protected DerValue params; 90 91 92 /** 93 * Constructs an algorithm ID which will be initialized 94 * separately, for example by deserialization. 95 * @deprecated use one of the other constructors. 96 */ 97 @Deprecated 98 public AlgorithmId() { } 99 100 /** 101 * Constructs a parameterless algorithm ID. 102 * 103 * @param oid the identifier for the algorithm 104 */ 105 public AlgorithmId(ObjectIdentifier oid) { 106 algid = oid; 107 } 108 109 /** 110 * Constructs an algorithm ID with algorithm parameters. 111 * 112 * @param oid the identifier for the algorithm. 113 * @param algparams the associated algorithm parameters. 114 */ 115 public AlgorithmId(ObjectIdentifier oid, AlgorithmParameters algparams) { 116 algid = oid; 117 algParams = algparams; 118 constructedFromDer = false; 119 } 120 121 private AlgorithmId(ObjectIdentifier oid, DerValue params) 122 throws IOException { 123 this.algid = oid; 124 this.params = params; 125 if (this.params != null) { 126 decodeParams(); 127 } 128 } 129 130 protected void decodeParams() throws IOException { 131 String algidName = getName(); 132 try { 133 algParams = AlgorithmParameters.getInstance(algidName); 134 } catch (NoSuchAlgorithmException e) { 135 /* 136 * This algorithm parameter type is not supported, so we cannot 137 * parse the parameters. 138 */ 139 algParams = null; 140 return; 141 } 142 143 // Decode (parse) the parameters 144 algParams.init(params.toByteArray()); 145 } 146 147 /** 148 * Marshal a DER-encoded "AlgorithmID" sequence on the DER stream. 149 */ 150 public final void encode(DerOutputStream out) throws IOException { 151 derEncode(out); 152 } 153 154 /** 155 * DER encode this object onto an output stream. 156 * Implements the <code>DerEncoder</code> interface. 157 * 158 * @param out 159 * the output stream on which to write the DER encoding. 160 * 161 * @exception IOException on encoding error. 162 */ 163 public void derEncode (OutputStream out) throws IOException { 164 DerOutputStream bytes = new DerOutputStream(); 165 DerOutputStream tmp = new DerOutputStream(); 166 167 bytes.putOID(algid); 168 // Setup params from algParams since no DER encoding is given 169 if (constructedFromDer == false) { 170 if (algParams != null) { 171 params = new DerValue(algParams.getEncoded()); 172 } else { 173 params = null; 174 } 175 } 176 if (params == null) { 177 // Changes backed out for compatibility with Solaris 178 179 // Several AlgorithmId should omit the whole parameter part when 180 // it's NULL. They are --- 181 // RFC 3370 2.1: Implementations SHOULD generate SHA-1 182 // AlgorithmIdentifiers with absent parameters. 183 // RFC 3447 C1: When id-sha1, id-sha224, id-sha256, id-sha384 and 184 // id-sha512 are used in an AlgorithmIdentifier the parameters 185 // (which are optional) SHOULD be omitted. 186 // RFC 3279 2.3.2: The id-dsa algorithm syntax includes optional 187 // domain parameters... When omitted, the parameters component 188 // MUST be omitted entirely 189 // RFC 3370 3.1: When the id-dsa-with-sha1 algorithm identifier 190 // is used, the AlgorithmIdentifier parameters field MUST be absent. 191 /*if ( 192 algid.equals((Object)SHA_oid) || 193 algid.equals((Object)SHA224_oid) || 194 algid.equals((Object)SHA256_oid) || 195 algid.equals((Object)SHA384_oid) || 196 algid.equals((Object)SHA512_oid) || 197 algid.equals((Object)SHA512_224_oid) || 198 algid.equals((Object)SHA512_256_oid) || 199 algid.equals((Object)DSA_oid) || 200 algid.equals((Object)sha1WithDSA_oid)) { 201 ; // no parameter part encoded 202 } else { 203 bytes.putNull(); 204 }*/ 205 if (algid.equals(RSASSA_PSS_oid) || algid.equals(ed448_oid) 206 || algid.equals(ed25519_oid)) { 207 // RFC 4055 3.3: when an RSASSA-PSS key does not require 208 // parameter validation, field is absent. 209 } else { 210 bytes.putNull(); 211 } 212 } else { 213 bytes.putDerValue(params); 214 } 215 tmp.write(DerValue.tag_Sequence, bytes); 216 out.write(tmp.toByteArray()); 217 } 218 219 220 /** 221 * Returns the DER-encoded X.509 AlgorithmId as a byte array. 222 */ 223 public final byte[] encode() throws IOException { 224 DerOutputStream out = new DerOutputStream(); 225 derEncode(out); 226 return out.toByteArray(); 227 } 228 229 /** 230 * Returns the ISO OID for this algorithm. This is usually converted 231 * to a string and used as part of an algorithm name, for example 232 * "OID.1.3.14.3.2.13" style notation. Use the <code>getName</code> 233 * call when you do not need to ensure cross-system portability 234 * of algorithm names, or need a user friendly name. 235 */ 236 public final ObjectIdentifier getOID () { 237 return algid; 238 } 239 240 /** 241 * Returns a name for the algorithm which may be more intelligible 242 * to humans than the algorithm's OID, but which won't necessarily 243 * be comprehensible on other systems. For example, this might 244 * return a name such as "MD5withRSA" for a signature algorithm on 245 * some systems. It also returns names like "OID.1.2.3.4", when 246 * no particular name for the algorithm is known. 247 * 248 * Note: for ecdsa-with-SHA2 plus hash algorithm (Ex: SHA-256), this method 249 * returns the "full" signature algorithm (Ex: SHA256withECDSA) directly. 250 */ 251 public String getName() { 252 String oidStr = algid.toString(); 253 // first check the list of support oids 254 KnownOIDs o = KnownOIDs.findMatch(oidStr); 255 if (o == KnownOIDs.SpecifiedSHA2withECDSA) { 256 if (params != null) { 257 try { 258 AlgorithmId paramsId = 259 AlgorithmId.parse(new DerValue(params.toByteArray())); 260 String paramsName = paramsId.getName(); 261 return makeSigAlg(paramsName, "EC"); 262 } catch (IOException e) { 263 // ignore 264 } 265 } 266 } 267 if (o != null) { 268 return o.stdName(); 269 } else { 270 String n = aliasOidsTable().get(oidStr); 271 if (n != null) { 272 return n; 273 } else { 274 return algid.toString(); 275 } 276 } 277 } 278 279 public AlgorithmParameters getParameters() { 280 return algParams; 281 } 282 283 /** 284 * Returns the DER encoded parameter, which can then be 285 * used to initialize java.security.AlgorithmParameters. 286 * 287 * Note: for ecdsa-with-SHA2 plus hash algorithm (Ex: SHA-256), this method 288 * returns null because {@link #getName()} has already returned the "full" 289 * signature algorithm (Ex: SHA256withECDSA). 290 * 291 * @return DER encoded parameters, or null not present. 292 */ 293 public byte[] getEncodedParams() throws IOException { 294 return (params == null || 295 algid.toString().equals(KnownOIDs.SpecifiedSHA2withECDSA.value())) 296 ? null 297 : params.toByteArray(); 298 } 299 300 /** 301 * Returns true iff the argument indicates the same algorithm 302 * with the same parameters. 303 */ 304 public boolean equals(AlgorithmId other) { 305 boolean paramsEqual = Objects.equals(other.params, params); 306 return (algid.equals((Object)other.algid) && paramsEqual); 307 } 308 309 /** 310 * Compares this AlgorithmID to another. If algorithm parameters are 311 * available, they are compared. Otherwise, just the object IDs 312 * for the algorithm are compared. 313 * 314 * @param other preferably an AlgorithmId, else an ObjectIdentifier 315 */ 316 public boolean equals(Object other) { 317 if (this == other) { 318 return true; 319 } 320 if (other instanceof AlgorithmId) { 321 return equals((AlgorithmId) other); 322 } else if (other instanceof ObjectIdentifier) { 323 return equals((ObjectIdentifier) other); 324 } else { 325 return false; 326 } 327 } 328 329 /** 330 * Compares two algorithm IDs for equality. Returns true iff 331 * they are the same algorithm, ignoring algorithm parameters. 332 */ 333 public final boolean equals(ObjectIdentifier id) { 334 return algid.equals((Object)id); 335 } 336 337 /** 338 * Returns a hashcode for this AlgorithmId. 339 * 340 * @return a hashcode for this AlgorithmId. 341 */ 342 public int hashCode() { 343 StringBuilder sbuf = new StringBuilder(); 344 sbuf.append(algid.toString()); 345 sbuf.append(paramsToString()); 346 return sbuf.toString().hashCode(); 347 } 348 349 /** 350 * Provides a human-readable description of the algorithm parameters. 351 * This may be redefined by subclasses which parse those parameters. 352 */ 353 protected String paramsToString() { 354 if (params == null) { 355 return ""; 356 } else if (algParams != null) { 357 return algParams.toString(); 358 } else { 359 return ", params unparsed"; 360 } 361 } 362 363 /** 364 * Returns a string describing the algorithm and its parameters. 365 */ 366 public String toString() { 367 return getName() + paramsToString(); 368 } 369 370 /** 371 * Parse (unmarshal) an ID from a DER sequence input value. This form 372 * parsing might be used when expanding a value which has already been 373 * partially unmarshaled as a set or sequence member. 374 * 375 * @exception IOException on error. 376 * @param val the input value, which contains the algid and, if 377 * there are any parameters, those parameters. 378 * @return an ID for the algorithm. If the system is configured 379 * appropriately, this may be an instance of a class 380 * with some kind of special support for this algorithm. 381 * In that case, you may "narrow" the type of the ID. 382 */ 383 public static AlgorithmId parse(DerValue val) throws IOException { 384 if (val.tag != DerValue.tag_Sequence) { 385 throw new IOException("algid parse error, not a sequence"); 386 } 387 388 /* 389 * Get the algorithm ID and any parameters. 390 */ 391 ObjectIdentifier algid; 392 DerValue params; 393 DerInputStream in = val.toDerInputStream(); 394 395 algid = in.getOID(); 396 if (in.available() == 0) { 397 params = null; 398 } else { 399 params = in.getDerValue(); 400 if (params.tag == DerValue.tag_Null) { 401 if (params.length() != 0) { 402 throw new IOException("invalid NULL"); 403 } 404 params = null; 405 } 406 if (in.available() != 0) { 407 throw new IOException("Invalid AlgorithmIdentifier: extra data"); 408 } 409 } 410 411 return new AlgorithmId(algid, params); 412 } 413 414 /** 415 * Returns one of the algorithm IDs most commonly associated 416 * with this algorithm name. 417 * 418 * @param algname the name being used 419 * @deprecated use the short get form of this method. 420 * @exception NoSuchAlgorithmException on error. 421 */ 422 @Deprecated 423 public static AlgorithmId getAlgorithmId(String algname) 424 throws NoSuchAlgorithmException { 425 return get(algname); 426 } 427 428 /** 429 * Returns one of the algorithm IDs most commonly associated 430 * with this algorithm name. 431 * 432 * @param algname the name being used 433 * @exception NoSuchAlgorithmException on error. 434 */ 435 public static AlgorithmId get(String algname) 436 throws NoSuchAlgorithmException { 437 ObjectIdentifier oid; 438 try { 439 oid = algOID(algname); 440 } catch (IOException ioe) { 441 throw new NoSuchAlgorithmException 442 ("Invalid ObjectIdentifier " + algname); 443 } 444 445 if (oid == null) { 446 throw new NoSuchAlgorithmException 447 ("unrecognized algorithm name: " + algname); 448 } 449 return new AlgorithmId(oid); 450 } 451 452 /** 453 * Returns one of the algorithm IDs most commonly associated 454 * with this algorithm parameters. 455 * 456 * @param algparams the associated algorithm parameters. 457 * @exception NoSuchAlgorithmException on error. 458 */ 459 public static AlgorithmId get(AlgorithmParameters algparams) 460 throws NoSuchAlgorithmException { 461 ObjectIdentifier oid; 462 String algname = algparams.getAlgorithm(); 463 try { 464 oid = algOID(algname); 465 } catch (IOException ioe) { 466 throw new NoSuchAlgorithmException 467 ("Invalid ObjectIdentifier " + algname); 468 } 469 if (oid == null) { 470 throw new NoSuchAlgorithmException 471 ("unrecognized algorithm name: " + algname); 472 } 473 return new AlgorithmId(oid, algparams); 474 } 475 476 /* 477 * Translates from some common algorithm names to the 478 * OID with which they're usually associated ... this mapping 479 * is the reverse of the one below, except in those cases 480 * where synonyms are supported or where a given algorithm 481 * is commonly associated with multiple OIDs. 482 * 483 * XXX This method needs to be enhanced so that we can also pass the 484 * scope of the algorithm name to it, e.g., the algorithm name "DSA" 485 * may have a different OID when used as a "Signature" algorithm than when 486 * used as a "KeyPairGenerator" algorithm. 487 */ 488 private static ObjectIdentifier algOID(String name) throws IOException { 489 if (name.startsWith("OID.")) { 490 name = name.substring("OID.".length()); 491 } 492 493 KnownOIDs k = KnownOIDs.findMatch(name); 494 if (k != null) { 495 return ObjectIdentifier.of(k); 496 } 497 498 // unknown algorithm oids 499 if (name.indexOf(".") == -1) { 500 // see if there is a matching oid string alias mapping from 501 // 3rd party providers 502 name = name.toUpperCase(Locale.ENGLISH); 503 String oidStr = aliasOidsTable().get(name); 504 if (oidStr != null) { 505 return ObjectIdentifier.of(oidStr); 506 } return null; 507 } else { 508 return ObjectIdentifier.of(name); 509 } 510 } 511 512 // oid string cache index'ed by algorithm name and oid strings 513 private static volatile Map<String,String> aliasOidsTable; 514 515 // returns the aliasOidsTable, lazily initializing it on first access. 516 private static Map<String,String> aliasOidsTable() { 517 // Double checked locking; safe because aliasOidsTable is volatile 518 Map<String,String> tab = aliasOidsTable; 519 if (tab == null) { 520 synchronized (AlgorithmId.class) { 521 if ((tab = aliasOidsTable) == null) { 522 aliasOidsTable = tab = collectOIDAliases(); 523 } 524 } 525 } 526 return tab; 527 } 528 529 private static boolean isKnownProvider(Provider p) { 530 String pn = p.getName(); 531 String mn = p.getClass().getModule().getName(); 532 if (pn != null && mn != null) { 533 return ((mn.equals("java.base") && 534 (pn.equals("SUN") || pn.equals("SunRsaSign") || 535 pn.equals("SunJCE") || pn.equals("SunJSSE"))) || 536 (mn.equals("jdk.crypto.ec") && pn.equals("SunEC")) || 537 (mn.equals("jdk.crypto.mscapi") && pn.equals("SunMSCAPI")) || 538 (mn.equals("jdk.crypto.cryptoki") && 539 pn.startsWith("SunPKCS11"))); 540 } else { 541 return false; 542 } 543 } 544 545 private static ConcurrentHashMap<String, String> collectOIDAliases() { 546 ConcurrentHashMap<String, String> t = new ConcurrentHashMap<>(); 547 for (Provider provider : Security.getProviders()) { 548 // skip providers which are already using SecurityProviderConstants 549 // and KnownOIDs 550 if (isKnownProvider(provider)) { 551 continue; 552 } 553 for (Object key : provider.keySet()) { 554 String alias = (String)key; 555 String upperCaseAlias = alias.toUpperCase(Locale.ENGLISH); 556 int index; 557 if (upperCaseAlias.startsWith("ALG.ALIAS") && 558 (index = upperCaseAlias.indexOf("OID.", 0)) != -1) { 559 index += "OID.".length(); 560 if (index == alias.length()) { 561 // invalid alias entry 562 break; 563 } 564 String ostr = alias.substring(index); 565 String stdAlgName = provider.getProperty(alias); 566 if (stdAlgName != null) { 567 stdAlgName = stdAlgName.toUpperCase(Locale.ENGLISH); 568 } 569 // add the name->oid and oid->name mappings if none exists 570 if (KnownOIDs.findMatch(stdAlgName) == null) { 571 // not override earlier entries if it exists 572 t.putIfAbsent(stdAlgName, ostr); 573 } 574 if (KnownOIDs.findMatch(ostr) == null) { 575 // not override earlier entries if it exists 576 t.putIfAbsent(ostr, stdAlgName); 577 } 578 } 579 } 580 } 581 return t; 582 } 583 584 public static final ObjectIdentifier MD2_oid = 585 ObjectIdentifier.of(KnownOIDs.MD2); 586 587 public static final ObjectIdentifier MD5_oid = 588 ObjectIdentifier.of(KnownOIDs.MD5); 589 590 public static final ObjectIdentifier SHA_oid = 591 ObjectIdentifier.of(KnownOIDs.SHA_1); 592 593 public static final ObjectIdentifier SHA224_oid = 594 ObjectIdentifier.of(KnownOIDs.SHA_224); 595 596 public static final ObjectIdentifier SHA256_oid = 597 ObjectIdentifier.of(KnownOIDs.SHA_256); 598 599 public static final ObjectIdentifier SHA384_oid = 600 ObjectIdentifier.of(KnownOIDs.SHA_384); 601 602 public static final ObjectIdentifier SHA512_oid = 603 ObjectIdentifier.of(KnownOIDs.SHA_512); 604 605 public static final ObjectIdentifier SHA512_224_oid = 606 ObjectIdentifier.of(KnownOIDs.SHA_512$224); 607 608 public static final ObjectIdentifier SHA512_256_oid = 609 ObjectIdentifier.of(KnownOIDs.SHA_512$256); 610 611 public static final ObjectIdentifier DSA_oid = 612 ObjectIdentifier.of(KnownOIDs.DSA); 613 614 public static final ObjectIdentifier EC_oid = 615 ObjectIdentifier.of(KnownOIDs.EC); 616 617 public static final ObjectIdentifier RSAEncryption_oid = 618 ObjectIdentifier.of(KnownOIDs.RSA); 619 620 public static final ObjectIdentifier RSASSA_PSS_oid = 621 ObjectIdentifier.of(KnownOIDs.RSASSA_PSS); 622 623 public static final ObjectIdentifier MGF1_oid = 624 ObjectIdentifier.of(KnownOIDs.MGF1); 625 626 public static final ObjectIdentifier ed25519_oid = 627 ObjectIdentifier.of(KnownOIDs.Ed25519); 628 public static final ObjectIdentifier ed448_oid = 629 ObjectIdentifier.of(KnownOIDs.Ed448); 630 631 /** 632 * Creates a signature algorithm name from a digest algorithm 633 * name and a encryption algorithm name. 634 */ 635 public static String makeSigAlg(String digAlg, String encAlg) { 636 digAlg = digAlg.replace("-", ""); 637 if (encAlg.equalsIgnoreCase("EC")) encAlg = "ECDSA"; 638 639 return digAlg + "with" + encAlg; 640 } 641 642 /** 643 * Extracts the encryption algorithm name from a signature 644 * algorithm name. 645 */ 646 public static String getEncAlgFromSigAlg(String signatureAlgorithm) { 647 signatureAlgorithm = signatureAlgorithm.toUpperCase(Locale.ENGLISH); 648 int with = signatureAlgorithm.indexOf("WITH"); 649 String keyAlgorithm = null; 650 if (with > 0) { 651 int and = signatureAlgorithm.indexOf("AND", with + 4); 652 if (and > 0) { 653 keyAlgorithm = signatureAlgorithm.substring(with + 4, and); 654 } else { 655 keyAlgorithm = signatureAlgorithm.substring(with + 4); 656 } 657 if (keyAlgorithm.equalsIgnoreCase("ECDSA")) { 658 keyAlgorithm = "EC"; 659 } 660 } 661 return keyAlgorithm; 662 } 663 664 /** 665 * Extracts the digest algorithm name from a signature 666 * algorithm name. 667 */ 668 public static String getDigAlgFromSigAlg(String signatureAlgorithm) { 669 signatureAlgorithm = signatureAlgorithm.toUpperCase(Locale.ENGLISH); 670 int with = signatureAlgorithm.indexOf("WITH"); 671 if (with > 0) { 672 return signatureAlgorithm.substring(0, with); 673 } 674 return null; 675 } 676 677 /** 678 * Checks if a signature algorithm matches a key algorithm, i.e. a 679 * signature can be initialized with a key. 680 * 681 * @param kAlg must not be null 682 * @param sAlg must not be null 683 * @throws IllegalArgumentException if they do not match 684 */ 685 public static void checkKeyAndSigAlgMatch(String kAlg, String sAlg) { 686 String sAlgUp = sAlg.toUpperCase(Locale.US); 687 if ((sAlgUp.endsWith("WITHRSA") && !kAlg.equalsIgnoreCase("RSA")) || 688 (sAlgUp.endsWith("WITHECDSA") && !kAlg.equalsIgnoreCase("EC")) || 689 (sAlgUp.endsWith("WITHDSA") && !kAlg.equalsIgnoreCase("DSA"))) { 690 throw new IllegalArgumentException( 691 "key algorithm not compatible with signature algorithm"); 692 } 693 } 694 695 /** 696 * Returns the default signature algorithm for a private key. The digest 697 * part might evolve with time. Remember to update the spec of 698 * {@link jdk.security.jarsigner.JarSigner.Builder#getDefaultSignatureAlgorithm(PrivateKey)} 699 * if updated. 700 * 701 * @param k cannot be null 702 * @return the default alg, might be null if unsupported 703 */ 704 public static String getDefaultSigAlgForKey(PrivateKey k) { 705 switch (k.getAlgorithm().toUpperCase(Locale.ENGLISH)) { 706 case "EC": 707 return ecStrength(KeyUtil.getKeySize(k)) 708 + "withECDSA"; 709 case "DSA": 710 return ifcFfcStrength(KeyUtil.getKeySize(k)) 711 + "withDSA"; 712 case "RSA": 713 return ifcFfcStrength(KeyUtil.getKeySize(k)) 714 + "withRSA"; 715 case "RSASSA-PSS": 716 return "RSASSA-PSS"; 717 case "EDDSA": 718 return edAlgFromKey(k); 719 default: 720 return null; 721 } 722 } 723 724 // Most commonly used PSSParameterSpec and AlgorithmId 725 private static class PSSParamsHolder { 726 727 final static PSSParameterSpec PSS_256_SPEC = new PSSParameterSpec( 728 "SHA-256", "MGF1", 729 new MGF1ParameterSpec("SHA-256"), 730 32, PSSParameterSpec.TRAILER_FIELD_BC); 731 final static PSSParameterSpec PSS_384_SPEC = new PSSParameterSpec( 732 "SHA-384", "MGF1", 733 new MGF1ParameterSpec("SHA-384"), 734 48, PSSParameterSpec.TRAILER_FIELD_BC); 735 final static PSSParameterSpec PSS_512_SPEC = new PSSParameterSpec( 736 "SHA-512", "MGF1", 737 new MGF1ParameterSpec("SHA-512"), 738 64, PSSParameterSpec.TRAILER_FIELD_BC); 739 740 final static AlgorithmId PSS_256_ID; 741 final static AlgorithmId PSS_384_ID; 742 final static AlgorithmId PSS_512_ID; 743 744 static { 745 try { 746 PSS_256_ID = new AlgorithmId(RSASSA_PSS_oid, 747 new DerValue(PSSParameters.getEncoded(PSS_256_SPEC))); 748 PSS_384_ID = new AlgorithmId(RSASSA_PSS_oid, 749 new DerValue(PSSParameters.getEncoded(PSS_384_SPEC))); 750 PSS_512_ID = new AlgorithmId(RSASSA_PSS_oid, 751 new DerValue(PSSParameters.getEncoded(PSS_512_SPEC))); 752 } catch (IOException e) { 753 throw new AssertionError("Should not happen", e); 754 } 755 } 756 } 757 758 public static AlgorithmId getWithParameterSpec(String algName, 759 AlgorithmParameterSpec spec) throws NoSuchAlgorithmException { 760 761 if (spec == null) { 762 return AlgorithmId.get(algName); 763 } else if (spec == PSSParamsHolder.PSS_256_SPEC) { 764 return PSSParamsHolder.PSS_256_ID; 765 } else if (spec == PSSParamsHolder.PSS_384_SPEC) { 766 return PSSParamsHolder.PSS_384_ID; 767 } else if (spec == PSSParamsHolder.PSS_512_SPEC) { 768 return PSSParamsHolder.PSS_512_ID; 769 } else if (spec instanceof EdDSAParameterSpec) { 770 return AlgorithmId.get(algName); 771 } else { 772 try { 773 AlgorithmParameters result = 774 AlgorithmParameters.getInstance(algName); 775 result.init(spec); 776 return get(result); 777 } catch (InvalidParameterSpecException | NoSuchAlgorithmException e) { 778 throw new ProviderException(e); 779 } 780 } 781 } 782 783 public static AlgorithmParameterSpec getDefaultAlgorithmParameterSpec( 784 String sigAlg, PrivateKey k) { 785 if (sigAlg.equalsIgnoreCase("RSASSA-PSS")) { 786 if (k instanceof RSAKey) { 787 AlgorithmParameterSpec spec = ((RSAKey) k).getParams(); 788 if (spec instanceof PSSParameterSpec) { 789 return spec; 790 } 791 } 792 switch (ifcFfcStrength(KeyUtil.getKeySize(k))) { 793 case "SHA256": 794 return PSSParamsHolder.PSS_256_SPEC; 795 case "SHA384": 796 return PSSParamsHolder.PSS_384_SPEC; 797 case "SHA512": 798 return PSSParamsHolder.PSS_512_SPEC; 799 default: 800 throw new AssertionError("Should not happen"); 801 } 802 } else { 803 return null; 804 } 805 } 806 807 private static String edAlgFromKey(PrivateKey k) { 808 if (k instanceof EdECPrivateKey) { 809 EdECPrivateKey edKey = (EdECPrivateKey) k; 810 return edKey.getParams().getName(); 811 } 812 return "EdDSA"; 813 } 814 815 // Values from SP800-57 part 1 rev 4 tables 2 and 3 816 private static String ecStrength (int bitLength) { 817 if (bitLength >= 512) { // 256 bits of strength 818 return "SHA512"; 819 } else if (bitLength >= 384) { // 192 bits of strength 820 return "SHA384"; 821 } else { // 128 bits of strength and less 822 return "SHA256"; 823 } 824 } 825 826 // Same values for RSA and DSA 827 private static String ifcFfcStrength (int bitLength) { 828 if (bitLength > 7680) { // 256 bits 829 return "SHA512"; 830 } else if (bitLength > 3072) { // 192 bits 831 return "SHA384"; 832 } else { // 128 bits and less 833 return "SHA256"; 834 } 835 } 836 }