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)SHA3_224_oid) || 200 algid.equals((Object)SHA3_256_oid) || 201 algid.equals((Object)SHA3_384_oid) || 202 algid.equals((Object)SHA3_512_oid) || 203 algid.equals((Object)DSA_oid) || 204 algid.equals((Object)sha1WithDSA_oid)) { 205 ; // no parameter part encoded 206 } else { 207 bytes.putNull(); 208 }*/ 209 if (algid.equals(RSASSA_PSS_oid) || algid.equals(ed448_oid) 210 || algid.equals(ed25519_oid)) { 211 // RFC 4055 3.3: when an RSASSA-PSS key does not require 212 // parameter validation, field is absent. 213 } else { 214 bytes.putNull(); 215 } 216 } else { 217 bytes.putDerValue(params); 218 } 219 tmp.write(DerValue.tag_Sequence, bytes); 220 out.write(tmp.toByteArray()); 221 } 222 223 224 /** 225 * Returns the DER-encoded X.509 AlgorithmId as a byte array. 226 */ 227 public final byte[] encode() throws IOException { 228 DerOutputStream out = new DerOutputStream(); 229 derEncode(out); 230 return out.toByteArray(); 231 } 232 233 /** 234 * Returns the ISO OID for this algorithm. This is usually converted 235 * to a string and used as part of an algorithm name, for example 236 * "OID.1.3.14.3.2.13" style notation. Use the <code>getName</code> 237 * call when you do not need to ensure cross-system portability 238 * of algorithm names, or need a user friendly name. 239 */ 240 public final ObjectIdentifier getOID () { 241 return algid; 242 } 243 244 /** 245 * Returns a name for the algorithm which may be more intelligible 246 * to humans than the algorithm's OID, but which won't necessarily 247 * be comprehensible on other systems. For example, this might 248 * return a name such as "MD5withRSA" for a signature algorithm on 249 * some systems. It also returns names like "OID.1.2.3.4", when 250 * no particular name for the algorithm is known. 251 * 252 * Note: for ecdsa-with-SHA2 plus hash algorithm (Ex: SHA-256), this method 253 * returns the "full" signature algorithm (Ex: SHA256withECDSA) directly. 254 */ 255 public String getName() { 256 String oidStr = algid.toString(); 257 // first check the list of support oids 258 KnownOIDs o = KnownOIDs.findMatch(oidStr); 259 if (o == KnownOIDs.SpecifiedSHA2withECDSA) { 260 if (params != null) { 261 try { 262 AlgorithmId paramsId = 263 AlgorithmId.parse(new DerValue(params.toByteArray())); 264 String paramsName = paramsId.getName(); 265 return makeSigAlg(paramsName, "EC"); 266 } catch (IOException e) { 267 // ignore 268 } 269 } 270 } 271 if (o != null) { 272 return o.stdName(); 273 } else { 274 String n = aliasOidsTable().get(oidStr); 275 if (n != null) { 276 return n; 277 } else { 278 return algid.toString(); 279 } 280 } 281 } 282 283 public AlgorithmParameters getParameters() { 284 return algParams; 285 } 286 287 /** 288 * Returns the DER encoded parameter, which can then be 289 * used to initialize java.security.AlgorithmParameters. 290 * 291 * Note: for ecdsa-with-SHA2 plus hash algorithm (Ex: SHA-256), this method 292 * returns null because {@link #getName()} has already returned the "full" 293 * signature algorithm (Ex: SHA256withECDSA). 294 * 295 * @return DER encoded parameters, or null not present. 296 */ 297 public byte[] getEncodedParams() throws IOException { 298 return (params == null || 299 algid.toString().equals(KnownOIDs.SpecifiedSHA2withECDSA.value())) 300 ? null 301 : params.toByteArray(); 302 } 303 304 /** 305 * Returns true iff the argument indicates the same algorithm 306 * with the same parameters. 307 */ 308 public boolean equals(AlgorithmId other) { 309 boolean paramsEqual = Objects.equals(other.params, params); 310 return (algid.equals((Object)other.algid) && paramsEqual); 311 } 312 313 /** 314 * Compares this AlgorithmID to another. If algorithm parameters are 315 * available, they are compared. Otherwise, just the object IDs 316 * for the algorithm are compared. 317 * 318 * @param other preferably an AlgorithmId, else an ObjectIdentifier 319 */ 320 public boolean equals(Object other) { 321 if (this == other) { 322 return true; 323 } 324 if (other instanceof AlgorithmId) { 325 return equals((AlgorithmId) other); 326 } else if (other instanceof ObjectIdentifier) { 327 return equals((ObjectIdentifier) other); 328 } else { 329 return false; 330 } 331 } 332 333 /** 334 * Compares two algorithm IDs for equality. Returns true iff 335 * they are the same algorithm, ignoring algorithm parameters. 336 */ 337 public final boolean equals(ObjectIdentifier id) { 338 return algid.equals((Object)id); 339 } 340 341 /** 342 * Returns a hashcode for this AlgorithmId. 343 * 344 * @return a hashcode for this AlgorithmId. 345 */ 346 public int hashCode() { 347 StringBuilder sbuf = new StringBuilder(); 348 sbuf.append(algid.toString()); 349 sbuf.append(paramsToString()); 350 return sbuf.toString().hashCode(); 351 } 352 353 /** 354 * Provides a human-readable description of the algorithm parameters. 355 * This may be redefined by subclasses which parse those parameters. 356 */ 357 protected String paramsToString() { 358 if (params == null) { 359 return ""; 360 } else if (algParams != null) { 361 return algParams.toString(); 362 } else { 363 return ", params unparsed"; 364 } 365 } 366 367 /** 368 * Returns a string describing the algorithm and its parameters. 369 */ 370 public String toString() { 371 return getName() + paramsToString(); 372 } 373 374 /** 375 * Parse (unmarshal) an ID from a DER sequence input value. This form 376 * parsing might be used when expanding a value which has already been 377 * partially unmarshaled as a set or sequence member. 378 * 379 * @exception IOException on error. 380 * @param val the input value, which contains the algid and, if 381 * there are any parameters, those parameters. 382 * @return an ID for the algorithm. If the system is configured 383 * appropriately, this may be an instance of a class 384 * with some kind of special support for this algorithm. 385 * In that case, you may "narrow" the type of the ID. 386 */ 387 public static AlgorithmId parse(DerValue val) throws IOException { 388 if (val.tag != DerValue.tag_Sequence) { 389 throw new IOException("algid parse error, not a sequence"); 390 } 391 392 /* 393 * Get the algorithm ID and any parameters. 394 */ 395 ObjectIdentifier algid; 396 DerValue params; 397 DerInputStream in = val.toDerInputStream(); 398 399 algid = in.getOID(); 400 if (in.available() == 0) { 401 params = null; 402 } else { 403 params = in.getDerValue(); 404 if (params.tag == DerValue.tag_Null) { 405 if (params.length() != 0) { 406 throw new IOException("invalid NULL"); 407 } 408 params = null; 409 } 410 if (in.available() != 0) { 411 throw new IOException("Invalid AlgorithmIdentifier: extra data"); 412 } 413 } 414 415 return new AlgorithmId(algid, params); 416 } 417 418 /** 419 * Returns one of the algorithm IDs most commonly associated 420 * with this algorithm name. 421 * 422 * @param algname the name being used 423 * @deprecated use the short get form of this method. 424 * @exception NoSuchAlgorithmException on error. 425 */ 426 @Deprecated 427 public static AlgorithmId getAlgorithmId(String algname) 428 throws NoSuchAlgorithmException { 429 return get(algname); 430 } 431 432 /** 433 * Returns one of the algorithm IDs most commonly associated 434 * with this algorithm name. 435 * 436 * @param algname the name being used 437 * @exception NoSuchAlgorithmException on error. 438 */ 439 public static AlgorithmId get(String algname) 440 throws NoSuchAlgorithmException { 441 ObjectIdentifier oid; 442 try { 443 oid = algOID(algname); 444 } catch (IOException ioe) { 445 throw new NoSuchAlgorithmException 446 ("Invalid ObjectIdentifier " + algname); 447 } 448 449 if (oid == null) { 450 throw new NoSuchAlgorithmException 451 ("unrecognized algorithm name: " + algname); 452 } 453 return new AlgorithmId(oid); 454 } 455 456 /** 457 * Returns one of the algorithm IDs most commonly associated 458 * with this algorithm parameters. 459 * 460 * @param algparams the associated algorithm parameters. 461 * @exception NoSuchAlgorithmException on error. 462 */ 463 public static AlgorithmId get(AlgorithmParameters algparams) 464 throws NoSuchAlgorithmException { 465 ObjectIdentifier oid; 466 String algname = algparams.getAlgorithm(); 467 try { 468 oid = algOID(algname); 469 } catch (IOException ioe) { 470 throw new NoSuchAlgorithmException 471 ("Invalid ObjectIdentifier " + algname); 472 } 473 if (oid == null) { 474 throw new NoSuchAlgorithmException 475 ("unrecognized algorithm name: " + algname); 476 } 477 return new AlgorithmId(oid, algparams); 478 } 479 480 /* 481 * Translates from some common algorithm names to the 482 * OID with which they're usually associated ... this mapping 483 * is the reverse of the one below, except in those cases 484 * where synonyms are supported or where a given algorithm 485 * is commonly associated with multiple OIDs. 486 * 487 * XXX This method needs to be enhanced so that we can also pass the 488 * scope of the algorithm name to it, e.g., the algorithm name "DSA" 489 * may have a different OID when used as a "Signature" algorithm than when 490 * used as a "KeyPairGenerator" algorithm. 491 */ 492 private static ObjectIdentifier algOID(String name) throws IOException { 493 if (name.startsWith("OID.")) { 494 name = name.substring("OID.".length()); 495 } 496 497 KnownOIDs k = KnownOIDs.findMatch(name); 498 if (k != null) { 499 return ObjectIdentifier.of(k); 500 } 501 502 // unknown algorithm oids 503 if (name.indexOf(".") == -1) { 504 // see if there is a matching oid string alias mapping from 505 // 3rd party providers 506 name = name.toUpperCase(Locale.ENGLISH); 507 String oidStr = aliasOidsTable().get(name); 508 if (oidStr != null) { 509 return ObjectIdentifier.of(oidStr); 510 } return null; 511 } else { 512 return ObjectIdentifier.of(name); 513 } 514 } 515 516 // oid string cache index'ed by algorithm name and oid strings 517 private static volatile Map<String,String> aliasOidsTable; 518 519 // returns the aliasOidsTable, lazily initializing it on first access. 520 private static Map<String,String> aliasOidsTable() { 521 // Double checked locking; safe because aliasOidsTable is volatile 522 Map<String,String> tab = aliasOidsTable; 523 if (tab == null) { 524 synchronized (AlgorithmId.class) { 525 if ((tab = aliasOidsTable) == null) { 526 aliasOidsTable = tab = collectOIDAliases(); 527 } 528 } 529 } 530 return tab; 531 } 532 533 private static boolean isKnownProvider(Provider p) { 534 String pn = p.getName(); 535 String mn = p.getClass().getModule().getName(); 536 if (pn != null && mn != null) { 537 return ((mn.equals("java.base") && 538 (pn.equals("SUN") || pn.equals("SunRsaSign") || 539 pn.equals("SunJCE") || pn.equals("SunJSSE"))) || 540 (mn.equals("jdk.crypto.ec") && pn.equals("SunEC")) || 541 (mn.equals("jdk.crypto.mscapi") && pn.equals("SunMSCAPI")) || 542 (mn.equals("jdk.crypto.cryptoki") && 543 pn.startsWith("SunPKCS11"))); 544 } else { 545 return false; 546 } 547 } 548 549 private static ConcurrentHashMap<String, String> collectOIDAliases() { 550 ConcurrentHashMap<String, String> t = new ConcurrentHashMap<>(); 551 for (Provider provider : Security.getProviders()) { 552 // skip providers which are already using SecurityProviderConstants 553 // and KnownOIDs 554 if (isKnownProvider(provider)) { 555 continue; 556 } 557 for (Object key : provider.keySet()) { 558 String alias = (String)key; 559 String upperCaseAlias = alias.toUpperCase(Locale.ENGLISH); 560 int index; 561 if (upperCaseAlias.startsWith("ALG.ALIAS") && 562 (index = upperCaseAlias.indexOf("OID.", 0)) != -1) { 563 index += "OID.".length(); 564 if (index == alias.length()) { 565 // invalid alias entry 566 break; 567 } 568 String ostr = alias.substring(index); 569 String stdAlgName = provider.getProperty(alias); 570 if (stdAlgName != null) { 571 stdAlgName = stdAlgName.toUpperCase(Locale.ENGLISH); 572 } 573 // add the name->oid and oid->name mappings if none exists 574 if (KnownOIDs.findMatch(stdAlgName) == null) { 575 // not override earlier entries if it exists 576 t.putIfAbsent(stdAlgName, ostr); 577 } 578 if (KnownOIDs.findMatch(ostr) == null) { 579 // not override earlier entries if it exists 580 t.putIfAbsent(ostr, stdAlgName); 581 } 582 } 583 } 584 } 585 return t; 586 } 587 588 public static final ObjectIdentifier MD2_oid = 589 ObjectIdentifier.of(KnownOIDs.MD2); 590 591 public static final ObjectIdentifier MD5_oid = 592 ObjectIdentifier.of(KnownOIDs.MD5); 593 594 public static final ObjectIdentifier SHA_oid = 595 ObjectIdentifier.of(KnownOIDs.SHA_1); 596 597 public static final ObjectIdentifier SHA224_oid = 598 ObjectIdentifier.of(KnownOIDs.SHA_224); 599 600 public static final ObjectIdentifier SHA256_oid = 601 ObjectIdentifier.of(KnownOIDs.SHA_256); 602 603 public static final ObjectIdentifier SHA384_oid = 604 ObjectIdentifier.of(KnownOIDs.SHA_384); 605 606 public static final ObjectIdentifier SHA512_oid = 607 ObjectIdentifier.of(KnownOIDs.SHA_512); 608 609 public static final ObjectIdentifier SHA512_224_oid = 610 ObjectIdentifier.of(KnownOIDs.SHA_512$224); 611 612 public static final ObjectIdentifier SHA512_256_oid = 613 ObjectIdentifier.of(KnownOIDs.SHA_512$256); 614 615 public static final ObjectIdentifier SHA3_224_oid = 616 ObjectIdentifier.of(KnownOIDs.SHA3_224); 617 618 public static final ObjectIdentifier SHA3_256_oid = 619 ObjectIdentifier.of(KnownOIDs.SHA3_256); 620 621 public static final ObjectIdentifier SHA3_384_oid = 622 ObjectIdentifier.of(KnownOIDs.SHA3_384); 623 624 public static final ObjectIdentifier SHA3_512_oid = 625 ObjectIdentifier.of(KnownOIDs.SHA3_512); 626 627 public static final ObjectIdentifier DSA_oid = 628 ObjectIdentifier.of(KnownOIDs.DSA); 629 630 public static final ObjectIdentifier EC_oid = 631 ObjectIdentifier.of(KnownOIDs.EC); 632 633 public static final ObjectIdentifier RSAEncryption_oid = 634 ObjectIdentifier.of(KnownOIDs.RSA); 635 636 public static final ObjectIdentifier RSASSA_PSS_oid = 637 ObjectIdentifier.of(KnownOIDs.RSASSA_PSS); 638 639 public static final ObjectIdentifier MGF1_oid = 640 ObjectIdentifier.of(KnownOIDs.MGF1); 641 642 public static final ObjectIdentifier ed25519_oid = 643 ObjectIdentifier.of(KnownOIDs.Ed25519); 644 public static final ObjectIdentifier ed448_oid = 645 ObjectIdentifier.of(KnownOIDs.Ed448); 646 647 /** 648 * Creates a signature algorithm name from a digest algorithm 649 * name and a encryption algorithm name. 650 */ 651 public static String makeSigAlg(String digAlg, String encAlg) { 652 digAlg = digAlg.replace("-", ""); 653 if (encAlg.equalsIgnoreCase("EC")) encAlg = "ECDSA"; 654 655 return digAlg + "with" + encAlg; 656 } 657 658 /** 659 * Extracts the encryption algorithm name from a signature 660 * algorithm name. 661 */ 662 public static String getEncAlgFromSigAlg(String signatureAlgorithm) { 663 signatureAlgorithm = signatureAlgorithm.toUpperCase(Locale.ENGLISH); 664 int with = signatureAlgorithm.indexOf("WITH"); 665 String keyAlgorithm = null; 666 if (with > 0) { 667 int and = signatureAlgorithm.indexOf("AND", with + 4); 668 if (and > 0) { 669 keyAlgorithm = signatureAlgorithm.substring(with + 4, and); 670 } else { 671 keyAlgorithm = signatureAlgorithm.substring(with + 4); 672 } 673 if (keyAlgorithm.equalsIgnoreCase("ECDSA")) { 674 keyAlgorithm = "EC"; 675 } 676 } 677 return keyAlgorithm; 678 } 679 680 /** 681 * Extracts the digest algorithm name from a signature 682 * algorithm name. 683 */ 684 public static String getDigAlgFromSigAlg(String signatureAlgorithm) { 685 signatureAlgorithm = signatureAlgorithm.toUpperCase(Locale.ENGLISH); 686 int with = signatureAlgorithm.indexOf("WITH"); 687 if (with > 0) { 688 return signatureAlgorithm.substring(0, with); 689 } 690 return null; 691 } 692 693 /** 694 * Checks if a signature algorithm matches a key algorithm, i.e. a 695 * signature can be initialized with a key. 696 * 697 * @param kAlg must not be null 698 * @param sAlg must not be null 699 * @throws IllegalArgumentException if they do not match 700 */ 701 public static void checkKeyAndSigAlgMatch(String kAlg, String sAlg) { 702 String sAlgUp = sAlg.toUpperCase(Locale.US); 703 if ((sAlgUp.endsWith("WITHRSA") && !kAlg.equalsIgnoreCase("RSA")) || 704 (sAlgUp.endsWith("WITHECDSA") && !kAlg.equalsIgnoreCase("EC")) || 705 (sAlgUp.endsWith("WITHDSA") && !kAlg.equalsIgnoreCase("DSA"))) { 706 throw new IllegalArgumentException( 707 "key algorithm not compatible with signature algorithm"); 708 } 709 } 710 711 /** 712 * Returns the default signature algorithm for a private key. The digest 713 * part might evolve with time. Remember to update the spec of 714 * {@link jdk.security.jarsigner.JarSigner.Builder#getDefaultSignatureAlgorithm(PrivateKey)} 715 * if updated. 716 * 717 * @param k cannot be null 718 * @return the default alg, might be null if unsupported 719 */ 720 public static String getDefaultSigAlgForKey(PrivateKey k) { 721 switch (k.getAlgorithm().toUpperCase(Locale.ENGLISH)) { 722 case "EC": 723 return ecStrength(KeyUtil.getKeySize(k)) 724 + "withECDSA"; 725 case "DSA": 726 return ifcFfcStrength(KeyUtil.getKeySize(k)) 727 + "withDSA"; 728 case "RSA": 729 return ifcFfcStrength(KeyUtil.getKeySize(k)) 730 + "withRSA"; 731 case "RSASSA-PSS": 732 return "RSASSA-PSS"; 733 case "EDDSA": 734 return edAlgFromKey(k); 735 default: 736 return null; 737 } 738 } 739 740 // Most commonly used PSSParameterSpec and AlgorithmId 741 private static class PSSParamsHolder { 742 743 final static PSSParameterSpec PSS_256_SPEC = new PSSParameterSpec( 744 "SHA-256", "MGF1", 745 new MGF1ParameterSpec("SHA-256"), 746 32, PSSParameterSpec.TRAILER_FIELD_BC); 747 final static PSSParameterSpec PSS_384_SPEC = new PSSParameterSpec( 748 "SHA-384", "MGF1", 749 new MGF1ParameterSpec("SHA-384"), 750 48, PSSParameterSpec.TRAILER_FIELD_BC); 751 final static PSSParameterSpec PSS_512_SPEC = new PSSParameterSpec( 752 "SHA-512", "MGF1", 753 new MGF1ParameterSpec("SHA-512"), 754 64, PSSParameterSpec.TRAILER_FIELD_BC); 755 756 final static AlgorithmId PSS_256_ID; 757 final static AlgorithmId PSS_384_ID; 758 final static AlgorithmId PSS_512_ID; 759 760 static { 761 try { 762 PSS_256_ID = new AlgorithmId(RSASSA_PSS_oid, 763 new DerValue(PSSParameters.getEncoded(PSS_256_SPEC))); 764 PSS_384_ID = new AlgorithmId(RSASSA_PSS_oid, 765 new DerValue(PSSParameters.getEncoded(PSS_384_SPEC))); 766 PSS_512_ID = new AlgorithmId(RSASSA_PSS_oid, 767 new DerValue(PSSParameters.getEncoded(PSS_512_SPEC))); 768 } catch (IOException e) { 769 throw new AssertionError("Should not happen", e); 770 } 771 } 772 } 773 774 public static AlgorithmId getWithParameterSpec(String algName, 775 AlgorithmParameterSpec spec) throws NoSuchAlgorithmException { 776 777 if (spec == null) { 778 return AlgorithmId.get(algName); 779 } else if (spec == PSSParamsHolder.PSS_256_SPEC) { 780 return PSSParamsHolder.PSS_256_ID; 781 } else if (spec == PSSParamsHolder.PSS_384_SPEC) { 782 return PSSParamsHolder.PSS_384_ID; 783 } else if (spec == PSSParamsHolder.PSS_512_SPEC) { 784 return PSSParamsHolder.PSS_512_ID; 785 } else if (spec instanceof EdDSAParameterSpec) { 786 return AlgorithmId.get(algName); 787 } else { 788 try { 789 AlgorithmParameters result = 790 AlgorithmParameters.getInstance(algName); 791 result.init(spec); 792 return get(result); 793 } catch (InvalidParameterSpecException | NoSuchAlgorithmException e) { 794 throw new ProviderException(e); 795 } 796 } 797 } 798 799 public static AlgorithmParameterSpec getDefaultAlgorithmParameterSpec( 800 String sigAlg, PrivateKey k) { 801 if (sigAlg.equalsIgnoreCase("RSASSA-PSS")) { 802 if (k instanceof RSAKey) { 803 AlgorithmParameterSpec spec = ((RSAKey) k).getParams(); 804 if (spec instanceof PSSParameterSpec) { 805 return spec; 806 } 807 } 808 switch (ifcFfcStrength(KeyUtil.getKeySize(k))) { 809 case "SHA256": 810 return PSSParamsHolder.PSS_256_SPEC; 811 case "SHA384": 812 return PSSParamsHolder.PSS_384_SPEC; 813 case "SHA512": 814 return PSSParamsHolder.PSS_512_SPEC; 815 default: 816 throw new AssertionError("Should not happen"); 817 } 818 } else { 819 return null; 820 } 821 } 822 823 private static String edAlgFromKey(PrivateKey k) { 824 if (k instanceof EdECPrivateKey) { 825 EdECPrivateKey edKey = (EdECPrivateKey) k; 826 return edKey.getParams().getName(); 827 } 828 return "EdDSA"; 829 } 830 831 // Values from SP800-57 part 1 rev 4 tables 2 and 3 832 private static String ecStrength (int bitLength) { 833 if (bitLength >= 512) { // 256 bits of strength 834 return "SHA512"; 835 } else if (bitLength >= 384) { // 192 bits of strength 836 return "SHA384"; 837 } else { // 128 bits of strength and less 838 return "SHA256"; 839 } 840 } 841 842 // Same values for RSA and DSA 843 private static String ifcFfcStrength (int bitLength) { 844 if (bitLength > 7680) { // 256 bits 845 return "SHA512"; 846 } else if (bitLength > 3072) { // 192 bits 847 return "SHA384"; 848 } else { // 128 bits and less 849 return "SHA256"; 850 } 851 } 852 }