1 /* 2 * Copyright (c) 1997, 2017, 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.tools.jarsigner; 27 28 import java.io.*; 29 import java.security.cert.CertPathValidatorException; 30 import java.security.cert.PKIXBuilderParameters; 31 import java.util.*; 32 import java.util.zip.*; 33 import java.util.jar.*; 34 import java.net.URI; 35 import java.text.Collator; 36 import java.text.MessageFormat; 37 import java.security.cert.Certificate; 38 import java.security.cert.X509Certificate; 39 import java.security.cert.CertificateException; 40 import java.security.*; 41 42 import java.net.SocketTimeoutException; 43 import java.net.URL; 44 import java.security.cert.CertPath; 45 import java.security.cert.CertificateExpiredException; 46 import java.security.cert.CertificateFactory; 47 import java.security.cert.CertificateNotYetValidException; 48 import java.security.cert.TrustAnchor; 49 import java.util.Map.Entry; 50 51 import jdk.security.jarsigner.JarSigner; 52 import jdk.security.jarsigner.JarSignerException; 53 import sun.security.pkcs.PKCS7; 54 import sun.security.pkcs.SignerInfo; 55 import sun.security.timestamp.TimestampToken; 56 import sun.security.tools.KeyStoreUtil; 57 import sun.security.validator.Validator; 58 import sun.security.validator.ValidatorException; 59 import sun.security.x509.*; 60 import sun.security.util.*; 61 62 63 /** 64 * <p>The jarsigner utility. 65 * 66 * The exit codes for the main method are: 67 * 68 * 0: success 69 * 1: any error that the jar cannot be signed or verified, including: 70 * keystore loading error 71 * TSP communication error 72 * jarsigner command line error... 73 * otherwise: error codes from -strict 74 * 75 * @author Roland Schemers 76 * @author Jan Luehe 77 */ 78 public class Main { 79 80 // for i18n 81 private static final java.util.ResourceBundle rb = 82 java.util.ResourceBundle.getBundle 83 ("sun.security.tools.jarsigner.Resources"); 84 private static final Collator collator = Collator.getInstance(); 85 static { 86 // this is for case insensitive string comparisions 87 collator.setStrength(Collator.PRIMARY); 88 } 89 90 private static final String NONE = "NONE"; 91 private static final String P11KEYSTORE = "PKCS11"; 92 93 private static final long SIX_MONTHS = 180*24*60*60*1000L; //milliseconds 94 95 private static final DisabledAlgorithmConstraints DISABLED_CHECK = 96 new DisabledAlgorithmConstraints( 97 DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS); 98 99 private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET = Collections 100 .unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST)); 101 private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections 102 .unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); 103 104 // Attention: 105 // This is the entry that get launched by the security tool jarsigner. 106 public static void main(String args[]) throws Exception { 107 Main js = new Main(); 108 js.run(args); 109 } 110 111 static final String VERSION = "1.0"; 112 113 static final int IN_KEYSTORE = 0x01; // signer is in keystore 114 static final int NOT_ALIAS = 0x04; // alias list is NOT empty and 115 // signer is not in alias list 116 static final int SIGNED_BY_ALIAS = 0x08; // signer is in alias list 117 118 X509Certificate[] certChain; // signer's cert chain (when composing) 119 PrivateKey privateKey; // private key 120 KeyStore store; // the keystore specified by -keystore 121 // or the default keystore, never null 122 123 String keystore; // key store file 124 boolean nullStream = false; // null keystore input stream (NONE) 125 boolean token = false; // token-based keystore 126 String jarfile; // jar files to sign or verify 127 String alias; // alias to sign jar with 128 List<String> ckaliases = new ArrayList<>(); // aliases in -verify 129 char[] storepass; // keystore password 130 boolean protectedPath; // protected authentication path 131 String storetype; // keystore type 132 String providerName; // provider name 133 List<String> providers = null; // list of provider names 134 List<String> providerClasses = null; // list of provider classes 135 // arguments for provider constructors 136 HashMap<String,String> providerArgs = new HashMap<>(); 137 char[] keypass; // private key password 138 String sigfile; // name of .SF file 139 String sigalg; // name of signature algorithm 140 String digestalg; // name of digest algorithm 141 String signedjar; // output filename 142 String tsaUrl; // location of the Timestamping Authority 143 String tsaAlias; // alias for the Timestamping Authority's certificate 144 String altCertChain; // file to read alternative cert chain from 145 String tSAPolicyID; 146 String tSADigestAlg; 147 boolean verify = false; // verify the jar 148 String verbose = null; // verbose output when signing/verifying 149 boolean showcerts = false; // show certs when verifying 150 boolean debug = false; // debug 151 boolean signManifest = true; // "sign" the whole manifest 152 boolean externalSF = true; // leave the .SF out of the PKCS7 block 153 boolean strict = false; // treat warnings as error 154 155 // read zip entry raw bytes 156 private String altSignerClass = null; 157 private String altSignerClasspath = null; 158 private ZipFile zipFile = null; 159 160 // Informational warnings 161 private boolean hasExpiringCert = false; 162 private boolean noTimestamp = false; 163 private Date expireDate = new Date(0L); // used in noTimestamp warning 164 165 // Severe warnings. 166 167 // jarsigner used to check signer cert chain validity and key usages 168 // itself and set various warnings. Later CertPath validation is 169 // added but chainNotValidated is only flagged when no other existing 170 // warnings are set. TSA cert chain check is added separately and 171 // only tsaChainNotValidated is set, i.e. has no affect on hasExpiredCert, 172 // notYetValidCert, or any badXyzUsage. 173 174 private int weakAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg 175 private boolean hasExpiredCert = false; 176 private boolean notYetValidCert = false; 177 private boolean chainNotValidated = false; 178 private boolean tsaChainNotValidated = false; 179 private boolean notSignedByAlias = false; 180 private boolean aliasNotInStore = false; 181 private boolean hasUnsignedEntry = false; 182 private boolean badKeyUsage = false; 183 private boolean badExtendedKeyUsage = false; 184 private boolean badNetscapeCertType = false; 185 private boolean signerSelfSigned = false; 186 187 private Throwable chainNotValidatedReason = null; 188 private Throwable tsaChainNotValidatedReason = null; 189 190 private boolean seeWeak = false; 191 192 PKIXBuilderParameters pkixParameters; 193 194 public void run(String args[]) { 195 try { 196 args = parseArgs(args); 197 198 // Try to load and install the specified providers 199 if (providers != null) { 200 for (String provName: providers) { 201 try { 202 KeyStoreUtil.loadProviderByName(provName, 203 providerArgs.get(provName)); 204 if (debug) { 205 System.out.println("loadProviderByName: " + provName); 206 } 207 } catch (IllegalArgumentException e) { 208 throw new Exception(String.format(rb.getString( 209 "provider.name.not.found"), provName)); 210 } 211 } 212 } 213 214 if (providerClasses != null) { 215 ClassLoader cl = ClassLoader.getSystemClassLoader(); 216 for (String provClass: providerClasses) { 217 try { 218 KeyStoreUtil.loadProviderByClass(provClass, 219 providerArgs.get(provClass), cl); 220 if (debug) { 221 System.out.println("loadProviderByClass: " + provClass); 222 } 223 } catch (ClassCastException cce) { 224 throw new Exception(String.format(rb.getString( 225 "provclass.not.a.provider"), provClass)); 226 } catch (IllegalArgumentException e) { 227 throw new Exception(String.format(rb.getString( 228 "provider.class.not.found"), provClass), e.getCause()); 229 } 230 } 231 } 232 233 if (verify) { 234 try { 235 loadKeyStore(keystore, false); 236 } catch (Exception e) { 237 if ((keystore != null) || (storepass != null)) { 238 System.out.println(rb.getString("jarsigner.error.") + 239 e.getMessage()); 240 if (debug) { 241 e.printStackTrace(); 242 } 243 System.exit(1); 244 } 245 } 246 /* if (debug) { 247 SignatureFileVerifier.setDebug(true); 248 ManifestEntryVerifier.setDebug(true); 249 } 250 */ 251 verifyJar(jarfile); 252 } else { 253 loadKeyStore(keystore, true); 254 getAliasInfo(alias); 255 256 signJar(jarfile, alias); 257 } 258 } catch (Exception e) { 259 System.out.println(rb.getString("jarsigner.error.") + e); 260 if (debug) { 261 e.printStackTrace(); 262 } 263 System.exit(1); 264 } finally { 265 // zero-out private key password 266 if (keypass != null) { 267 Arrays.fill(keypass, ' '); 268 keypass = null; 269 } 270 // zero-out keystore password 271 if (storepass != null) { 272 Arrays.fill(storepass, ' '); 273 storepass = null; 274 } 275 } 276 277 if (strict) { 278 int exitCode = 0; 279 if (weakAlg != 0 || chainNotValidated 280 || hasExpiredCert || notYetValidCert || signerSelfSigned) { 281 exitCode |= 4; 282 } 283 if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) { 284 exitCode |= 8; 285 } 286 if (hasUnsignedEntry) { 287 exitCode |= 16; 288 } 289 if (notSignedByAlias || aliasNotInStore) { 290 exitCode |= 32; 291 } 292 if (tsaChainNotValidated) { 293 exitCode |= 64; 294 } 295 if (exitCode != 0) { 296 System.exit(exitCode); 297 } 298 } 299 } 300 301 /* 302 * Parse command line arguments. 303 */ 304 String[] parseArgs(String args[]) throws Exception { 305 /* parse flags */ 306 int n = 0; 307 308 if (args.length == 0) fullusage(); 309 310 String confFile = null; 311 String command = "-sign"; 312 for (n=0; n < args.length; n++) { 313 if (collator.compare(args[n], "-verify") == 0) { 314 command = "-verify"; 315 } else if (collator.compare(args[n], "-conf") == 0) { 316 if (n == args.length - 1) { 317 usageNoArg(); 318 } 319 confFile = args[++n]; 320 } 321 } 322 323 if (confFile != null) { 324 args = KeyStoreUtil.expandArgs( 325 "jarsigner", confFile, command, null, args); 326 } 327 328 debug = Arrays.stream(args).anyMatch( 329 x -> collator.compare(x, "-debug") == 0); 330 331 if (debug) { 332 // No need to localize debug output 333 System.out.println("Command line args: " + 334 Arrays.toString(args)); 335 } 336 337 for (n=0; n < args.length; n++) { 338 339 String flags = args[n]; 340 String modifier = null; 341 342 if (flags.startsWith("-")) { 343 int pos = flags.indexOf(':'); 344 if (pos > 0) { 345 modifier = flags.substring(pos+1); 346 flags = flags.substring(0, pos); 347 } 348 } 349 350 if (!flags.startsWith("-")) { 351 if (jarfile == null) { 352 jarfile = flags; 353 } else { 354 alias = flags; 355 ckaliases.add(alias); 356 } 357 } else if (collator.compare(flags, "-conf") == 0) { 358 if (++n == args.length) usageNoArg(); 359 } else if (collator.compare(flags, "-keystore") == 0) { 360 if (++n == args.length) usageNoArg(); 361 keystore = args[n]; 362 } else if (collator.compare(flags, "-storepass") ==0) { 363 if (++n == args.length) usageNoArg(); 364 storepass = getPass(modifier, args[n]); 365 } else if (collator.compare(flags, "-storetype") ==0) { 366 if (++n == args.length) usageNoArg(); 367 storetype = args[n]; 368 } else if (collator.compare(flags, "-providerName") ==0) { 369 if (++n == args.length) usageNoArg(); 370 providerName = args[n]; 371 } else if (collator.compare(flags, "-provider") == 0 || 372 collator.compare(flags, "-providerClass") == 0) { 373 if (++n == args.length) usageNoArg(); 374 if (providerClasses == null) { 375 providerClasses = new ArrayList<>(3); 376 } 377 providerClasses.add(args[n]); 378 379 if (args.length > (n+1)) { 380 flags = args[n+1]; 381 if (collator.compare(flags, "-providerArg") == 0) { 382 if (args.length == (n+2)) usageNoArg(); 383 providerArgs.put(args[n], args[n+2]); 384 n += 2; 385 } 386 } 387 } else if (collator.compare(flags, "-addprovider") == 0) { 388 if (++n == args.length) usageNoArg(); 389 if (providers == null) { 390 providers = new ArrayList<>(3); 391 } 392 providers.add(args[n]); 393 394 if (args.length > (n+1)) { 395 flags = args[n+1]; 396 if (collator.compare(flags, "-providerArg") == 0) { 397 if (args.length == (n+2)) usageNoArg(); 398 providerArgs.put(args[n], args[n+2]); 399 n += 2; 400 } 401 } 402 } else if (collator.compare(flags, "-protected") ==0) { 403 protectedPath = true; 404 } else if (collator.compare(flags, "-certchain") ==0) { 405 if (++n == args.length) usageNoArg(); 406 altCertChain = args[n]; 407 } else if (collator.compare(flags, "-tsapolicyid") ==0) { 408 if (++n == args.length) usageNoArg(); 409 tSAPolicyID = args[n]; 410 } else if (collator.compare(flags, "-tsadigestalg") ==0) { 411 if (++n == args.length) usageNoArg(); 412 tSADigestAlg = args[n]; 413 } else if (collator.compare(flags, "-debug") ==0) { 414 // Already processed 415 } else if (collator.compare(flags, "-keypass") ==0) { 416 if (++n == args.length) usageNoArg(); 417 keypass = getPass(modifier, args[n]); 418 } else if (collator.compare(flags, "-sigfile") ==0) { 419 if (++n == args.length) usageNoArg(); 420 sigfile = args[n]; 421 } else if (collator.compare(flags, "-signedjar") ==0) { 422 if (++n == args.length) usageNoArg(); 423 signedjar = args[n]; 424 } else if (collator.compare(flags, "-tsa") ==0) { 425 if (++n == args.length) usageNoArg(); 426 tsaUrl = args[n]; 427 } else if (collator.compare(flags, "-tsacert") ==0) { 428 if (++n == args.length) usageNoArg(); 429 tsaAlias = args[n]; 430 } else if (collator.compare(flags, "-altsigner") ==0) { 431 if (++n == args.length) usageNoArg(); 432 altSignerClass = args[n]; 433 System.err.println( 434 rb.getString("This.option.is.deprecated") + 435 "-altsigner"); 436 } else if (collator.compare(flags, "-altsignerpath") ==0) { 437 if (++n == args.length) usageNoArg(); 438 altSignerClasspath = args[n]; 439 System.err.println( 440 rb.getString("This.option.is.deprecated") + 441 "-altsignerpath"); 442 } else if (collator.compare(flags, "-sectionsonly") ==0) { 443 signManifest = false; 444 } else if (collator.compare(flags, "-internalsf") ==0) { 445 externalSF = false; 446 } else if (collator.compare(flags, "-verify") ==0) { 447 verify = true; 448 } else if (collator.compare(flags, "-verbose") ==0) { 449 verbose = (modifier != null) ? modifier : "all"; 450 } else if (collator.compare(flags, "-sigalg") ==0) { 451 if (++n == args.length) usageNoArg(); 452 sigalg = args[n]; 453 } else if (collator.compare(flags, "-digestalg") ==0) { 454 if (++n == args.length) usageNoArg(); 455 digestalg = args[n]; 456 } else if (collator.compare(flags, "-certs") ==0) { 457 showcerts = true; 458 } else if (collator.compare(flags, "-strict") ==0) { 459 strict = true; 460 } else if (collator.compare(flags, "-?") == 0 || 461 collator.compare(flags, "-h") == 0 || 462 collator.compare(flags, "--help") == 0 || 463 // -help: legacy. Undocumented. 464 collator.compare(flags, "-help") == 0) { 465 fullusage(); 466 } else { 467 System.err.println( 468 rb.getString("Illegal.option.") + flags); 469 usage(); 470 } 471 } 472 473 // -certs must always be specified with -verbose 474 if (verbose == null) showcerts = false; 475 476 if (jarfile == null) { 477 System.err.println(rb.getString("Please.specify.jarfile.name")); 478 usage(); 479 } 480 if (!verify && alias == null) { 481 System.err.println(rb.getString("Please.specify.alias.name")); 482 usage(); 483 } 484 if (!verify && ckaliases.size() > 1) { 485 System.err.println(rb.getString("Only.one.alias.can.be.specified")); 486 usage(); 487 } 488 489 if (storetype == null) { 490 storetype = KeyStore.getDefaultType(); 491 } 492 storetype = KeyStoreUtil.niceStoreTypeName(storetype); 493 494 try { 495 if (signedjar != null && new File(signedjar).getCanonicalPath().equals( 496 new File(jarfile).getCanonicalPath())) { 497 signedjar = null; 498 } 499 } catch (IOException ioe) { 500 // File system error? 501 // Just ignore it. 502 } 503 504 if (P11KEYSTORE.equalsIgnoreCase(storetype) || 505 KeyStoreUtil.isWindowsKeyStore(storetype)) { 506 token = true; 507 if (keystore == null) { 508 keystore = NONE; 509 } 510 } 511 512 if (NONE.equals(keystore)) { 513 nullStream = true; 514 } 515 516 if (token && !nullStream) { 517 System.err.println(MessageFormat.format(rb.getString 518 (".keystore.must.be.NONE.if.storetype.is.{0}"), storetype)); 519 usage(); 520 } 521 522 if (token && keypass != null) { 523 System.err.println(MessageFormat.format(rb.getString 524 (".keypass.can.not.be.specified.if.storetype.is.{0}"), storetype)); 525 usage(); 526 } 527 528 if (protectedPath) { 529 if (storepass != null || keypass != null) { 530 System.err.println(rb.getString 531 ("If.protected.is.specified.then.storepass.and.keypass.must.not.be.specified")); 532 usage(); 533 } 534 } 535 if (KeyStoreUtil.isWindowsKeyStore(storetype)) { 536 if (storepass != null || keypass != null) { 537 System.err.println(rb.getString 538 ("If.keystore.is.not.password.protected.then.storepass.and.keypass.must.not.be.specified")); 539 usage(); 540 } 541 } 542 return args; 543 } 544 545 static char[] getPass(String modifier, String arg) { 546 char[] output = KeyStoreUtil.getPassWithModifier(modifier, arg, rb); 547 if (output != null) return output; 548 usage(); 549 return null; // Useless, usage() already exit 550 } 551 552 static void usageNoArg() { 553 System.out.println(rb.getString("Option.lacks.argument")); 554 usage(); 555 } 556 557 static void usage() { 558 System.out.println(); 559 System.out.println(rb.getString("Please.type.jarsigner.help.for.usage")); 560 System.exit(1); 561 } 562 563 static void fullusage() { 564 System.out.println(rb.getString 565 ("Usage.jarsigner.options.jar.file.alias")); 566 System.out.println(rb.getString 567 (".jarsigner.verify.options.jar.file.alias.")); 568 System.out.println(); 569 System.out.println(rb.getString 570 (".keystore.url.keystore.location")); 571 System.out.println(); 572 System.out.println(rb.getString 573 (".storepass.password.password.for.keystore.integrity")); 574 System.out.println(); 575 System.out.println(rb.getString 576 (".storetype.type.keystore.type")); 577 System.out.println(); 578 System.out.println(rb.getString 579 (".keypass.password.password.for.private.key.if.different.")); 580 System.out.println(); 581 System.out.println(rb.getString 582 (".certchain.file.name.of.alternative.certchain.file")); 583 System.out.println(); 584 System.out.println(rb.getString 585 (".sigfile.file.name.of.SF.DSA.file")); 586 System.out.println(); 587 System.out.println(rb.getString 588 (".signedjar.file.name.of.signed.JAR.file")); 589 System.out.println(); 590 System.out.println(rb.getString 591 (".digestalg.algorithm.name.of.digest.algorithm")); 592 System.out.println(); 593 System.out.println(rb.getString 594 (".sigalg.algorithm.name.of.signature.algorithm")); 595 System.out.println(); 596 System.out.println(rb.getString 597 (".verify.verify.a.signed.JAR.file")); 598 System.out.println(); 599 System.out.println(rb.getString 600 (".verbose.suboptions.verbose.output.when.signing.verifying.")); 601 System.out.println(rb.getString 602 (".suboptions.can.be.all.grouped.or.summary")); 603 System.out.println(); 604 System.out.println(rb.getString 605 (".certs.display.certificates.when.verbose.and.verifying")); 606 System.out.println(); 607 System.out.println(rb.getString 608 (".tsa.url.location.of.the.Timestamping.Authority")); 609 System.out.println(); 610 System.out.println(rb.getString 611 (".tsacert.alias.public.key.certificate.for.Timestamping.Authority")); 612 System.out.println(); 613 System.out.println(rb.getString 614 (".tsapolicyid.tsapolicyid.for.Timestamping.Authority")); 615 System.out.println(); 616 System.out.println(rb.getString 617 (".tsadigestalg.algorithm.of.digest.data.in.timestamping.request")); 618 System.out.println(); 619 System.out.println(rb.getString 620 (".altsigner.class.class.name.of.an.alternative.signing.mechanism")); 621 System.out.println(); 622 System.out.println(rb.getString 623 (".altsignerpath.pathlist.location.of.an.alternative.signing.mechanism")); 624 System.out.println(); 625 System.out.println(rb.getString 626 (".internalsf.include.the.SF.file.inside.the.signature.block")); 627 System.out.println(); 628 System.out.println(rb.getString 629 (".sectionsonly.don.t.compute.hash.of.entire.manifest")); 630 System.out.println(); 631 System.out.println(rb.getString 632 (".protected.keystore.has.protected.authentication.path")); 633 System.out.println(); 634 System.out.println(rb.getString 635 (".providerName.name.provider.name")); 636 System.out.println(); 637 System.out.println(rb.getString 638 (".add.provider.option")); 639 System.out.println(rb.getString 640 (".providerArg.option.1")); 641 System.out.println(); 642 System.out.println(rb.getString 643 (".providerClass.option")); 644 System.out.println(rb.getString 645 (".providerArg.option.2")); 646 System.out.println(); 647 System.out.println(rb.getString 648 (".strict.treat.warnings.as.errors")); 649 System.out.println(); 650 System.out.println(rb.getString 651 (".conf.url.specify.a.pre.configured.options.file")); 652 System.out.println(); 653 System.out.println(rb.getString 654 (".print.this.help.message")); 655 System.out.println(); 656 657 System.exit(0); 658 } 659 660 void verifyJar(String jarName) 661 throws Exception 662 { 663 boolean anySigned = false; // if there exists entry inside jar signed 664 JarFile jf = null; 665 Map<String,String> digestMap = new HashMap<>(); 666 Map<String,PKCS7> sigMap = new HashMap<>(); 667 Map<String,String> sigNameMap = new HashMap<>(); 668 Map<String,String> unparsableSignatures = new HashMap<>(); 669 670 try { 671 jf = new JarFile(jarName, true); 672 Vector<JarEntry> entriesVec = new Vector<>(); 673 byte[] buffer = new byte[8192]; 674 675 Enumeration<JarEntry> entries = jf.entries(); 676 while (entries.hasMoreElements()) { 677 JarEntry je = entries.nextElement(); 678 entriesVec.addElement(je); 679 try (InputStream is = jf.getInputStream(je)) { 680 String name = je.getName(); 681 if (signatureRelated(name) 682 && SignatureFileVerifier.isBlockOrSF(name)) { 683 String alias = name.substring(name.lastIndexOf('/') + 1, 684 name.lastIndexOf('.')); 685 try { 686 if (name.endsWith(".SF")) { 687 Manifest sf = new Manifest(is); 688 boolean found = false; 689 for (Object obj : sf.getMainAttributes().keySet()) { 690 String key = obj.toString(); 691 if (key.endsWith("-Digest-Manifest")) { 692 digestMap.put(alias, 693 key.substring(0, key.length() - 16)); 694 found = true; 695 break; 696 } 697 } 698 if (!found) { 699 unparsableSignatures.putIfAbsent(alias, 700 String.format( 701 rb.getString("history.unparsable"), 702 name)); 703 } 704 } else { 705 sigNameMap.put(alias, name); 706 sigMap.put(alias, new PKCS7(is)); 707 } 708 } catch (IOException ioe) { 709 unparsableSignatures.putIfAbsent(alias, String.format( 710 rb.getString("history.unparsable"), name)); 711 } 712 } else { 713 while (is.read(buffer, 0, buffer.length) != -1) { 714 // we just read. this will throw a SecurityException 715 // if a signature/digest check fails. 716 } 717 } 718 } 719 } 720 721 Manifest man = jf.getManifest(); 722 boolean hasSignature = false; 723 724 // The map to record display info, only used when -verbose provided 725 // key: signer info string 726 // value: the list of files with common key 727 Map<String,List<String>> output = new LinkedHashMap<>(); 728 729 if (man != null) { 730 if (verbose != null) System.out.println(); 731 Enumeration<JarEntry> e = entriesVec.elements(); 732 733 String tab = rb.getString("6SPACE"); 734 735 while (e.hasMoreElements()) { 736 JarEntry je = e.nextElement(); 737 String name = je.getName(); 738 739 hasSignature = hasSignature 740 || SignatureFileVerifier.isBlockOrSF(name); 741 742 CodeSigner[] signers = je.getCodeSigners(); 743 boolean isSigned = (signers != null); 744 anySigned |= isSigned; 745 hasUnsignedEntry |= !je.isDirectory() && !isSigned 746 && !signatureRelated(name); 747 748 int inStoreWithAlias = inKeyStore(signers); 749 750 boolean inStore = (inStoreWithAlias & IN_KEYSTORE) != 0; 751 752 notSignedByAlias |= (inStoreWithAlias & NOT_ALIAS) != 0; 753 if (keystore != null) { 754 aliasNotInStore |= isSigned && !inStore; 755 } 756 757 // Only used when -verbose provided 758 StringBuffer sb = null; 759 if (verbose != null) { 760 sb = new StringBuffer(); 761 boolean inManifest = 762 ((man.getAttributes(name) != null) || 763 (man.getAttributes("./"+name) != null) || 764 (man.getAttributes("/"+name) != null)); 765 sb.append(isSigned ? rb.getString("s") : rb.getString("SPACE")) 766 .append(inManifest ? rb.getString("m") : rb.getString("SPACE")) 767 .append(inStore ? rb.getString("k") : rb.getString("SPACE")) 768 .append((inStoreWithAlias & NOT_ALIAS) != 0 ? 'X' : ' ') 769 .append(rb.getString("SPACE")); 770 sb.append('|'); 771 } 772 773 // When -certs provided, display info has extra empty 774 // lines at the beginning and end. 775 if (isSigned) { 776 if (showcerts) sb.append('\n'); 777 for (CodeSigner signer: signers) { 778 // signerInfo() must be called even if -verbose 779 // not provided. The method updates various 780 // warning flags. 781 String si = signerInfo(signer, tab); 782 if (showcerts) { 783 sb.append(si); 784 sb.append('\n'); 785 } 786 } 787 } else if (showcerts && !verbose.equals("all")) { 788 // Print no info for unsigned entries when -verbose:all, 789 // to be consistent with old behavior. 790 if (signatureRelated(name)) { 791 sb.append('\n') 792 .append(tab) 793 .append(rb 794 .getString(".Signature.related.entries.")) 795 .append("\n\n"); 796 } else { 797 sb.append('\n').append(tab) 798 .append(rb.getString(".Unsigned.entries.")) 799 .append("\n\n"); 800 } 801 } 802 803 if (verbose != null) { 804 String label = sb.toString(); 805 if (signatureRelated(name)) { 806 // Entries inside META-INF and other unsigned 807 // entries are grouped separately. 808 label = "-" + label; 809 } 810 811 // The label finally contains 2 parts separated by '|': 812 // The legend displayed before the entry names, and 813 // the cert info (if -certs specified). 814 815 if (!output.containsKey(label)) { 816 output.put(label, new ArrayList<String>()); 817 } 818 819 StringBuilder fb = new StringBuilder(); 820 String s = Long.toString(je.getSize()); 821 for (int i = 6 - s.length(); i > 0; --i) { 822 fb.append(' '); 823 } 824 fb.append(s).append(' '). 825 append(new Date(je.getTime()).toString()); 826 fb.append(' ').append(name); 827 828 output.get(label).add(fb.toString()); 829 } 830 } 831 } 832 if (verbose != null) { 833 for (Entry<String,List<String>> s: output.entrySet()) { 834 List<String> files = s.getValue(); 835 String key = s.getKey(); 836 if (key.charAt(0) == '-') { // the signature-related group 837 key = key.substring(1); 838 } 839 int pipe = key.indexOf('|'); 840 if (verbose.equals("all")) { 841 for (String f: files) { 842 System.out.println(key.substring(0, pipe) + f); 843 System.out.printf(key.substring(pipe+1)); 844 } 845 } else { 846 if (verbose.equals("grouped")) { 847 for (String f: files) { 848 System.out.println(key.substring(0, pipe) + f); 849 } 850 } else if (verbose.equals("summary")) { 851 System.out.print(key.substring(0, pipe)); 852 if (files.size() > 1) { 853 System.out.println(files.get(0) + " " + 854 String.format(rb.getString( 855 ".and.d.more."), files.size()-1)); 856 } else { 857 System.out.println(files.get(0)); 858 } 859 } 860 System.out.printf(key.substring(pipe+1)); 861 } 862 } 863 System.out.println(); 864 System.out.println(rb.getString( 865 ".s.signature.was.verified.")); 866 System.out.println(rb.getString( 867 ".m.entry.is.listed.in.manifest")); 868 System.out.println(rb.getString( 869 ".k.at.least.one.certificate.was.found.in.keystore")); 870 if (ckaliases.size() > 0) { 871 System.out.println(rb.getString( 872 ".X.not.signed.by.specified.alias.es.")); 873 } 874 } 875 if (man == null) { 876 System.out.println(); 877 System.out.println(rb.getString("no.manifest.")); 878 } 879 880 // If signer is a trusted cert or private entry in user's own 881 // keystore, it can be self-signed. 882 if (!aliasNotInStore) { 883 signerSelfSigned = false; 884 } 885 886 // If there is a time stamp block inside the PKCS7 block file 887 boolean hasTimestampBlock = false; 888 889 // Even if the verbose option is not specified, all out strings 890 // must be generated so seeWeak can be updated. 891 if (!digestMap.isEmpty() 892 || !sigMap.isEmpty() 893 || !unparsableSignatures.isEmpty()) { 894 if (verbose != null) { 895 System.out.println(); 896 } 897 for (String s : sigMap.keySet()) { 898 if (!digestMap.containsKey(s)) { 899 unparsableSignatures.putIfAbsent(s, String.format( 900 rb.getString("history.nosf"), s)); 901 } 902 } 903 for (String s : digestMap.keySet()) { 904 PKCS7 p7 = sigMap.get(s); 905 if (p7 != null) { 906 String history; 907 try { 908 SignerInfo si = p7.getSignerInfos()[0]; 909 X509Certificate signer = si.getCertificate(p7); 910 String digestAlg = digestMap.get(s); 911 String sigAlg = AlgorithmId.makeSigAlg( 912 si.getDigestAlgorithmId().getName(), 913 si.getDigestEncryptionAlgorithmId().getName()); 914 PublicKey key = signer.getPublicKey(); 915 PKCS7 tsToken = si.getTsToken(); 916 if (tsToken != null) { 917 hasTimestampBlock = true; 918 SignerInfo tsSi = tsToken.getSignerInfos()[0]; 919 X509Certificate tsSigner = tsSi.getCertificate(tsToken); 920 byte[] encTsTokenInfo = tsToken.getContentInfo().getData(); 921 TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo); 922 PublicKey tsKey = tsSigner.getPublicKey(); 923 String tsDigestAlg = tsTokenInfo.getHashAlgorithm().getName(); 924 String tsSigAlg = AlgorithmId.makeSigAlg( 925 tsSi.getDigestAlgorithmId().getName(), 926 tsSi.getDigestEncryptionAlgorithmId().getName()); 927 Calendar c = Calendar.getInstance( 928 TimeZone.getTimeZone("UTC"), 929 Locale.getDefault(Locale.Category.FORMAT)); 930 c.setTime(tsTokenInfo.getDate()); 931 history = String.format( 932 rb.getString("history.with.ts"), 933 signer.getSubjectX500Principal(), 934 withWeak(digestAlg, DIGEST_PRIMITIVE_SET), 935 withWeak(sigAlg, SIG_PRIMITIVE_SET), 936 withWeak(key), 937 c, 938 tsSigner.getSubjectX500Principal(), 939 withWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET), 940 withWeak(tsSigAlg, SIG_PRIMITIVE_SET), 941 withWeak(tsKey)); 942 } else { 943 history = String.format( 944 rb.getString("history.without.ts"), 945 signer.getSubjectX500Principal(), 946 withWeak(digestAlg, DIGEST_PRIMITIVE_SET), 947 withWeak(sigAlg, SIG_PRIMITIVE_SET), 948 withWeak(key)); 949 } 950 } catch (Exception e) { 951 // The only usage of sigNameMap, remember the name 952 // of the block file if it's invalid. 953 history = String.format( 954 rb.getString("history.unparsable"), 955 sigNameMap.get(s)); 956 } 957 if (verbose != null) { 958 System.out.println(history); 959 } 960 } else { 961 unparsableSignatures.putIfAbsent(s, String.format( 962 rb.getString("history.nobk"), s)); 963 } 964 } 965 if (verbose != null) { 966 for (String s : unparsableSignatures.keySet()) { 967 System.out.println(unparsableSignatures.get(s)); 968 } 969 } 970 } 971 System.out.println(); 972 if (!anySigned) { 973 if (seeWeak) { 974 if (verbose != null) { 975 System.out.println(rb.getString("jar.treated.unsigned.see.weak.verbose")); 976 System.out.println("\n " + 977 DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS + 978 "=" + Security.getProperty(DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS)); 979 } else { 980 System.out.println(rb.getString("jar.treated.unsigned.see.weak")); 981 } 982 } else if (hasSignature) { 983 System.out.println(rb.getString("jar.treated.unsigned")); 984 } else { 985 System.out.println(rb.getString("jar.is.unsigned")); 986 } 987 } else { 988 boolean warningAppeared = false; 989 boolean errorAppeared = false; 990 if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType || 991 notYetValidCert || chainNotValidated || hasExpiredCert || 992 hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) || 993 aliasNotInStore || notSignedByAlias || tsaChainNotValidated) { 994 995 if (strict) { 996 System.out.println(rb.getString("jar.verified.with.signer.errors.")); 997 System.out.println(); 998 System.out.println(rb.getString("Error.")); 999 errorAppeared = true; 1000 } else { 1001 System.out.println(rb.getString("jar.verified.")); 1002 System.out.println(); 1003 System.out.println(rb.getString("Warning.")); 1004 warningAppeared = true; 1005 } 1006 1007 if (weakAlg != 0) { 1008 // In fact, jarsigner verification did not catch this 1009 // since it has not read the JarFile content itself. 1010 // Everything is done with JarFile API. The signing 1011 // history (digestMap etc) will show these info and 1012 // print out proper warnings. 1013 } 1014 1015 if (badKeyUsage) { 1016 System.out.println( 1017 rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing.")); 1018 } 1019 1020 if (badExtendedKeyUsage) { 1021 System.out.println( 1022 rb.getString("This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing.")); 1023 } 1024 1025 if (badNetscapeCertType) { 1026 System.out.println( 1027 rb.getString("This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing.")); 1028 } 1029 1030 if (hasUnsignedEntry) { 1031 System.out.println(rb.getString( 1032 "This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked.")); 1033 } 1034 if (hasExpiredCert) { 1035 System.out.println(rb.getString( 1036 "This.jar.contains.entries.whose.signer.certificate.has.expired.")); 1037 } 1038 if (notYetValidCert) { 1039 System.out.println(rb.getString( 1040 "This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid.")); 1041 } 1042 1043 if (chainNotValidated) { 1044 System.out.println(String.format( 1045 rb.getString("This.jar.contains.entries.whose.certificate.chain.is.invalid.reason.1"), 1046 chainNotValidatedReason.getLocalizedMessage())); 1047 } 1048 1049 if (tsaChainNotValidated) { 1050 System.out.println(String.format( 1051 rb.getString("This.jar.contains.entries.whose.tsa.certificate.chain.is.invalid.reason.1"), 1052 tsaChainNotValidatedReason.getLocalizedMessage())); 1053 } 1054 1055 if (notSignedByAlias) { 1056 System.out.println( 1057 rb.getString("This.jar.contains.signed.entries.which.is.not.signed.by.the.specified.alias.es.")); 1058 } 1059 1060 if (aliasNotInStore) { 1061 System.out.println(rb.getString("This.jar.contains.signed.entries.that.s.not.signed.by.alias.in.this.keystore.")); 1062 } 1063 1064 if (signerSelfSigned) { 1065 System.out.println(rb.getString( 1066 "This.jar.contains.entries.whose.signer.certificate.is.self.signed.")); 1067 } 1068 } else { 1069 System.out.println(rb.getString("jar.verified.")); 1070 } 1071 if (hasExpiringCert || noTimestamp) { 1072 if (!warningAppeared) { 1073 System.out.println(); 1074 System.out.println(rb.getString("Warning.")); 1075 warningAppeared = true; 1076 } 1077 if (hasExpiringCert) { 1078 System.out.println(rb.getString( 1079 "This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months.")); 1080 } 1081 if (noTimestamp) { 1082 if (hasTimestampBlock) { 1083 // JarSigner API has not seen the timestamp, 1084 // might have ignored it due to weak alg, etc. 1085 System.out.println( 1086 String.format(rb.getString("bad.timestamp.verifying"), expireDate)); 1087 } else { 1088 System.out.println( 1089 String.format(rb.getString("no.timestamp.verifying"), expireDate)); 1090 } 1091 } 1092 } 1093 if (warningAppeared || errorAppeared) { 1094 if (! (verbose != null && showcerts)) { 1095 System.out.println(); 1096 System.out.println(rb.getString( 1097 "Re.run.with.the.verbose.and.certs.options.for.more.details.")); 1098 } 1099 } 1100 } 1101 return; 1102 } catch (Exception e) { 1103 System.out.println(rb.getString("jarsigner.") + e); 1104 if (debug) { 1105 e.printStackTrace(); 1106 } 1107 } finally { // close the resource 1108 if (jf != null) { 1109 jf.close(); 1110 } 1111 } 1112 1113 System.exit(1); 1114 } 1115 1116 private String withWeak(String alg, Set<CryptoPrimitive> primitiveSet) { 1117 if (DISABLED_CHECK.permits(primitiveSet, alg, null)) { 1118 return alg; 1119 } else { 1120 seeWeak = true; 1121 return String.format(rb.getString("with.weak"), alg); 1122 } 1123 } 1124 1125 private String withWeak(PublicKey key) { 1126 if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) { 1127 int kLen = KeyUtil.getKeySize(key); 1128 if (kLen >= 0) { 1129 return String.format(rb.getString("key.bit"), kLen); 1130 } else { 1131 return rb.getString("unknown.size"); 1132 } 1133 } else { 1134 seeWeak = true; 1135 return String.format( 1136 rb.getString("key.bit.weak"), KeyUtil.getKeySize(key)); 1137 } 1138 } 1139 1140 private static MessageFormat validityTimeForm = null; 1141 private static MessageFormat notYetTimeForm = null; 1142 private static MessageFormat expiredTimeForm = null; 1143 private static MessageFormat expiringTimeForm = null; 1144 1145 /** 1146 * Returns a string about a certificate: 1147 * 1148 * [<tab>] <cert-type> [", " <subject-DN>] [" (" <keystore-entry-alias> ")"] 1149 * [<validity-period> | <expiry-warning>] 1150 * [<key-usage-warning>] 1151 * 1152 * Note: no newline character at the end. 1153 * 1154 * When isTsCert is true, this method sets global flags like hasExpiredCert, 1155 * notYetValidCert, badKeyUsage, badExtendedKeyUsage, badNetscapeCertType. 1156 * 1157 * @param isTsCert true if c is in the TSA cert chain, false otherwise. 1158 * @param checkUsage true to check code signer keyUsage 1159 */ 1160 String printCert(boolean isTsCert, String tab, Certificate c, 1161 Date timestamp, boolean checkUsage) throws Exception { 1162 1163 StringBuilder certStr = new StringBuilder(); 1164 String space = rb.getString("SPACE"); 1165 X509Certificate x509Cert = null; 1166 1167 if (c instanceof X509Certificate) { 1168 x509Cert = (X509Certificate) c; 1169 certStr.append(tab).append(x509Cert.getType()) 1170 .append(rb.getString("COMMA")) 1171 .append(x509Cert.getSubjectDN().getName()); 1172 } else { 1173 certStr.append(tab).append(c.getType()); 1174 } 1175 1176 String alias = storeHash.get(c); 1177 if (alias != null) { 1178 certStr.append(space).append(alias); 1179 } 1180 1181 if (x509Cert != null) { 1182 1183 certStr.append("\n").append(tab).append("["); 1184 Date notAfter = x509Cert.getNotAfter(); 1185 try { 1186 boolean printValidity = true; 1187 if (timestamp == null) { 1188 if (expireDate.getTime() == 0 || expireDate.after(notAfter)) { 1189 expireDate = notAfter; 1190 } 1191 x509Cert.checkValidity(); 1192 // test if cert will expire within six months 1193 if (notAfter.getTime() < System.currentTimeMillis() + SIX_MONTHS) { 1194 if (!isTsCert) hasExpiringCert = true; 1195 if (expiringTimeForm == null) { 1196 expiringTimeForm = new MessageFormat( 1197 rb.getString("certificate.will.expire.on")); 1198 } 1199 Object[] source = { notAfter }; 1200 certStr.append(expiringTimeForm.format(source)); 1201 printValidity = false; 1202 } 1203 } else { 1204 x509Cert.checkValidity(timestamp); 1205 } 1206 if (printValidity) { 1207 if (validityTimeForm == null) { 1208 validityTimeForm = new MessageFormat( 1209 rb.getString("certificate.is.valid.from")); 1210 } 1211 Object[] source = { x509Cert.getNotBefore(), notAfter }; 1212 certStr.append(validityTimeForm.format(source)); 1213 } 1214 } catch (CertificateExpiredException cee) { 1215 if (!isTsCert) hasExpiredCert = true; 1216 1217 if (expiredTimeForm == null) { 1218 expiredTimeForm = new MessageFormat( 1219 rb.getString("certificate.expired.on")); 1220 } 1221 Object[] source = { notAfter }; 1222 certStr.append(expiredTimeForm.format(source)); 1223 1224 } catch (CertificateNotYetValidException cnyve) { 1225 if (!isTsCert) notYetValidCert = true; 1226 1227 if (notYetTimeForm == null) { 1228 notYetTimeForm = new MessageFormat( 1229 rb.getString("certificate.is.not.valid.until")); 1230 } 1231 Object[] source = { x509Cert.getNotBefore() }; 1232 certStr.append(notYetTimeForm.format(source)); 1233 } 1234 certStr.append("]"); 1235 1236 if (checkUsage) { 1237 boolean[] bad = new boolean[3]; 1238 checkCertUsage(x509Cert, bad); 1239 if (bad[0] || bad[1] || bad[2]) { 1240 String x = ""; 1241 if (bad[0]) { 1242 x ="KeyUsage"; 1243 } 1244 if (bad[1]) { 1245 if (x.length() > 0) x = x + ", "; 1246 x = x + "ExtendedKeyUsage"; 1247 } 1248 if (bad[2]) { 1249 if (x.length() > 0) x = x + ", "; 1250 x = x + "NetscapeCertType"; 1251 } 1252 certStr.append("\n").append(tab) 1253 .append(MessageFormat.format(rb.getString( 1254 ".{0}.extension.does.not.support.code.signing."), x)); 1255 } 1256 } 1257 } 1258 return certStr.toString(); 1259 } 1260 1261 private static MessageFormat signTimeForm = null; 1262 1263 private String printTimestamp(String tab, Timestamp timestamp) { 1264 1265 if (signTimeForm == null) { 1266 signTimeForm = 1267 new MessageFormat(rb.getString("entry.was.signed.on")); 1268 } 1269 Object[] source = { timestamp.getTimestamp() }; 1270 1271 return new StringBuilder().append(tab).append("[") 1272 .append(signTimeForm.format(source)).append("]").toString(); 1273 } 1274 1275 private Map<CodeSigner,Integer> cacheForInKS = new IdentityHashMap<>(); 1276 1277 private int inKeyStoreForOneSigner(CodeSigner signer) { 1278 if (cacheForInKS.containsKey(signer)) { 1279 return cacheForInKS.get(signer); 1280 } 1281 1282 int result = 0; 1283 List<? extends Certificate> certs = signer.getSignerCertPath().getCertificates(); 1284 for (Certificate c : certs) { 1285 String alias = storeHash.get(c); 1286 if (alias != null) { 1287 if (alias.startsWith("(")) { 1288 result |= IN_KEYSTORE; 1289 } 1290 if (ckaliases.contains(alias.substring(1, alias.length() - 1))) { 1291 result |= SIGNED_BY_ALIAS; 1292 } 1293 } else { 1294 if (store != null) { 1295 try { 1296 alias = store.getCertificateAlias(c); 1297 } catch (KeyStoreException kse) { 1298 // never happens, because keystore has been loaded 1299 } 1300 if (alias != null) { 1301 storeHash.put(c, "(" + alias + ")"); 1302 result |= IN_KEYSTORE; 1303 } 1304 } 1305 if (ckaliases.contains(alias)) { 1306 result |= SIGNED_BY_ALIAS; 1307 } 1308 } 1309 } 1310 cacheForInKS.put(signer, result); 1311 return result; 1312 } 1313 1314 Hashtable<Certificate, String> storeHash = new Hashtable<>(); 1315 1316 int inKeyStore(CodeSigner[] signers) { 1317 1318 if (signers == null) 1319 return 0; 1320 1321 int output = 0; 1322 1323 for (CodeSigner signer: signers) { 1324 int result = inKeyStoreForOneSigner(signer); 1325 output |= result; 1326 } 1327 if (ckaliases.size() > 0 && (output & SIGNED_BY_ALIAS) == 0) { 1328 output |= NOT_ALIAS; 1329 } 1330 return output; 1331 } 1332 1333 void signJar(String jarName, String alias) 1334 throws Exception { 1335 1336 if (digestalg != null && !DISABLED_CHECK.permits( 1337 DIGEST_PRIMITIVE_SET, digestalg, null)) { 1338 weakAlg |= 1; 1339 } 1340 if (tSADigestAlg != null && !DISABLED_CHECK.permits( 1341 DIGEST_PRIMITIVE_SET, tSADigestAlg, null)) { 1342 weakAlg |= 4; 1343 } 1344 if (sigalg != null && !DISABLED_CHECK.permits( 1345 SIG_PRIMITIVE_SET , sigalg, null)) { 1346 weakAlg |= 2; 1347 } 1348 if (!DISABLED_CHECK.permits( 1349 SIG_PRIMITIVE_SET, privateKey)) { 1350 weakAlg |= 8; 1351 } 1352 1353 boolean aliasUsed = false; 1354 X509Certificate tsaCert = null; 1355 1356 if (sigfile == null) { 1357 sigfile = alias; 1358 aliasUsed = true; 1359 } 1360 1361 if (sigfile.length() > 8) { 1362 sigfile = sigfile.substring(0, 8).toUpperCase(Locale.ENGLISH); 1363 } else { 1364 sigfile = sigfile.toUpperCase(Locale.ENGLISH); 1365 } 1366 1367 StringBuilder tmpSigFile = new StringBuilder(sigfile.length()); 1368 for (int j = 0; j < sigfile.length(); j++) { 1369 char c = sigfile.charAt(j); 1370 if (! 1371 ((c>= 'A' && c<= 'Z') || 1372 (c>= '0' && c<= '9') || 1373 (c == '-') || 1374 (c == '_'))) { 1375 if (aliasUsed) { 1376 // convert illegal characters from the alias to be _'s 1377 c = '_'; 1378 } else { 1379 throw new 1380 RuntimeException(rb.getString 1381 ("signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or.")); 1382 } 1383 } 1384 tmpSigFile.append(c); 1385 } 1386 1387 sigfile = tmpSigFile.toString(); 1388 1389 String tmpJarName; 1390 if (signedjar == null) tmpJarName = jarName+".sig"; 1391 else tmpJarName = signedjar; 1392 1393 File jarFile = new File(jarName); 1394 File signedJarFile = new File(tmpJarName); 1395 1396 // Open the jar (zip) file 1397 try { 1398 zipFile = new ZipFile(jarName); 1399 } catch (IOException ioe) { 1400 error(rb.getString("unable.to.open.jar.file.")+jarName, ioe); 1401 } 1402 1403 FileOutputStream fos = null; 1404 try { 1405 fos = new FileOutputStream(signedJarFile); 1406 } catch (IOException ioe) { 1407 error(rb.getString("unable.to.create.")+tmpJarName, ioe); 1408 } 1409 1410 CertPath cp = CertificateFactory.getInstance("X.509") 1411 .generateCertPath(Arrays.asList(certChain)); 1412 JarSigner.Builder builder = new JarSigner.Builder(privateKey, cp); 1413 1414 if (verbose != null) { 1415 builder.eventHandler((action, file) -> { 1416 System.out.println(rb.getString("." + action + ".") + file); 1417 }); 1418 } 1419 1420 if (digestalg != null) { 1421 builder.digestAlgorithm(digestalg); 1422 } 1423 if (sigalg != null) { 1424 builder.signatureAlgorithm(sigalg); 1425 } 1426 1427 URI tsaURI = null; 1428 1429 if (tsaUrl != null) { 1430 tsaURI = new URI(tsaUrl); 1431 } else if (tsaAlias != null) { 1432 tsaCert = getTsaCert(tsaAlias); 1433 tsaURI = TimestampedSigner.getTimestampingURI(tsaCert); 1434 } 1435 1436 if (tsaURI != null) { 1437 if (verbose != null) { 1438 System.out.println( 1439 rb.getString("requesting.a.signature.timestamp")); 1440 if (tsaUrl != null) { 1441 System.out.println(rb.getString("TSA.location.") + tsaUrl); 1442 } else if (tsaCert != null) { 1443 System.out.println(rb.getString("TSA.certificate.") + 1444 printCert(true, "", tsaCert, null, false)); 1445 } 1446 } 1447 builder.tsa(tsaURI); 1448 if (tSADigestAlg != null) { 1449 builder.setProperty("tsaDigestAlg", tSADigestAlg); 1450 } 1451 1452 if (tSAPolicyID != null) { 1453 builder.setProperty("tsaPolicyId", tSAPolicyID); 1454 } 1455 } else { 1456 noTimestamp = true; 1457 } 1458 1459 if (altSignerClass != null) { 1460 builder.setProperty("altSigner", altSignerClass); 1461 if (verbose != null) { 1462 System.out.println( 1463 rb.getString("using.an.alternative.signing.mechanism")); 1464 } 1465 } 1466 1467 if (altSignerClasspath != null) { 1468 builder.setProperty("altSignerPath", altSignerClasspath); 1469 } 1470 1471 builder.signerName(sigfile); 1472 1473 builder.setProperty("sectionsOnly", Boolean.toString(!signManifest)); 1474 builder.setProperty("internalSF", Boolean.toString(!externalSF)); 1475 1476 try { 1477 builder.build().sign(zipFile, fos); 1478 } catch (JarSignerException e) { 1479 Throwable cause = e.getCause(); 1480 if (cause != null && cause instanceof SocketTimeoutException) { 1481 // Provide a helpful message when TSA is beyond a firewall 1482 error(rb.getString("unable.to.sign.jar.") + 1483 rb.getString("no.response.from.the.Timestamping.Authority.") + 1484 "\n -J-Dhttp.proxyHost=<hostname>" + 1485 "\n -J-Dhttp.proxyPort=<portnumber>\n" + 1486 rb.getString("or") + 1487 "\n -J-Dhttps.proxyHost=<hostname> " + 1488 "\n -J-Dhttps.proxyPort=<portnumber> ", e); 1489 } else { 1490 error(rb.getString("unable.to.sign.jar.")+e.getCause(), e.getCause()); 1491 } 1492 } finally { 1493 // close the resouces 1494 if (zipFile != null) { 1495 zipFile.close(); 1496 zipFile = null; 1497 } 1498 1499 if (fos != null) { 1500 fos.close(); 1501 } 1502 } 1503 1504 // The JarSigner API always accepts the timestamp received. 1505 // We need to extract the certs from the signed jar to 1506 // validate it. 1507 if (!noTimestamp) { 1508 try (JarFile check = new JarFile(signedJarFile)) { 1509 PKCS7 p7 = new PKCS7(check.getInputStream(check.getEntry( 1510 "META-INF/" + sigfile + "." + privateKey.getAlgorithm()))); 1511 SignerInfo si = p7.getSignerInfos()[0]; 1512 PKCS7 tsToken = si.getTsToken(); 1513 SignerInfo tsSi = tsToken.getSignerInfos()[0]; 1514 try { 1515 validateCertChain(Validator.VAR_TSA_SERVER, 1516 tsSi.getCertificateChain(tsToken), null); 1517 } catch (Exception e) { 1518 tsaChainNotValidated = true; 1519 tsaChainNotValidatedReason = e; 1520 } 1521 } catch (Exception e) { 1522 if (debug) { 1523 e.printStackTrace(); 1524 } 1525 } 1526 } 1527 1528 // no IOException thrown in the follow try clause, so disable 1529 // the try clause. 1530 // try { 1531 if (signedjar == null) { 1532 // attempt an atomic rename. If that fails, 1533 // rename the original jar file, then the signed 1534 // one, then delete the original. 1535 if (!signedJarFile.renameTo(jarFile)) { 1536 File origJar = new File(jarName+".orig"); 1537 1538 if (jarFile.renameTo(origJar)) { 1539 if (signedJarFile.renameTo(jarFile)) { 1540 origJar.delete(); 1541 } else { 1542 MessageFormat form = new MessageFormat(rb.getString 1543 ("attempt.to.rename.signedJarFile.to.jarFile.failed")); 1544 Object[] source = {signedJarFile, jarFile}; 1545 error(form.format(source)); 1546 } 1547 } else { 1548 MessageFormat form = new MessageFormat(rb.getString 1549 ("attempt.to.rename.jarFile.to.origJar.failed")); 1550 Object[] source = {jarFile, origJar}; 1551 error(form.format(source)); 1552 } 1553 } 1554 } 1555 1556 boolean warningAppeared = false; 1557 if (weakAlg != 0 || badKeyUsage || badExtendedKeyUsage 1558 || badNetscapeCertType || notYetValidCert 1559 || chainNotValidated || tsaChainNotValidated 1560 || hasExpiredCert || signerSelfSigned) { 1561 if (strict) { 1562 System.out.println(rb.getString("jar.signed.with.signer.errors.")); 1563 System.out.println(); 1564 System.out.println(rb.getString("Error.")); 1565 } else { 1566 System.out.println(rb.getString("jar.signed.")); 1567 System.out.println(); 1568 System.out.println(rb.getString("Warning.")); 1569 warningAppeared = true; 1570 } 1571 1572 if (badKeyUsage) { 1573 System.out.println( 1574 rb.getString("The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing.")); 1575 } 1576 1577 if (badExtendedKeyUsage) { 1578 System.out.println( 1579 rb.getString("The.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing.")); 1580 } 1581 1582 if (badNetscapeCertType) { 1583 System.out.println( 1584 rb.getString("The.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing.")); 1585 } 1586 1587 if (hasExpiredCert) { 1588 System.out.println( 1589 rb.getString("The.signer.certificate.has.expired.")); 1590 } else if (notYetValidCert) { 1591 System.out.println( 1592 rb.getString("The.signer.certificate.is.not.yet.valid.")); 1593 } 1594 1595 if (chainNotValidated) { 1596 System.out.println(String.format( 1597 rb.getString("The.signer.s.certificate.chain.is.invalid.reason.1"), 1598 chainNotValidatedReason.getLocalizedMessage())); 1599 } 1600 1601 if (tsaChainNotValidated) { 1602 System.out.println(String.format( 1603 rb.getString("The.tsa.certificate.chain.is.invalid.reason.1"), 1604 tsaChainNotValidatedReason.getLocalizedMessage())); 1605 } 1606 1607 if (signerSelfSigned) { 1608 System.out.println( 1609 rb.getString("The.signer.s.certificate.is.self.signed.")); 1610 } 1611 1612 if ((weakAlg & 1) == 1) { 1613 System.out.println(String.format( 1614 rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."), 1615 digestalg, "-digestalg")); 1616 } 1617 1618 if ((weakAlg & 2) == 2) { 1619 System.out.println(String.format( 1620 rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."), 1621 sigalg, "-sigalg")); 1622 } 1623 if ((weakAlg & 4) == 4) { 1624 System.out.println(String.format( 1625 rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."), 1626 tSADigestAlg, "-tsadigestalg")); 1627 } 1628 if ((weakAlg & 8) == 8) { 1629 System.out.println(String.format( 1630 rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk."), 1631 privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey))); 1632 } 1633 } else { 1634 System.out.println(rb.getString("jar.signed.")); 1635 } 1636 if (hasExpiringCert || noTimestamp) { 1637 if (!warningAppeared) { 1638 System.out.println(); 1639 System.out.println(rb.getString("Warning.")); 1640 } 1641 1642 if (hasExpiringCert) { 1643 System.out.println( 1644 rb.getString("The.signer.certificate.will.expire.within.six.months.")); 1645 } 1646 1647 if (noTimestamp) { 1648 System.out.println( 1649 String.format(rb.getString("no.timestamp.signing"), expireDate)); 1650 } 1651 } 1652 1653 // no IOException thrown in the above try clause, so disable 1654 // the catch clause. 1655 // } catch(IOException ioe) { 1656 // error(rb.getString("unable.to.sign.jar.")+ioe, ioe); 1657 // } 1658 } 1659 1660 /** 1661 * signature-related files include: 1662 * . META-INF/MANIFEST.MF 1663 * . META-INF/SIG-* 1664 * . META-INF/*.SF 1665 * . META-INF/*.DSA 1666 * . META-INF/*.RSA 1667 * . META-INF/*.EC 1668 */ 1669 private boolean signatureRelated(String name) { 1670 return SignatureFileVerifier.isSigningRelated(name); 1671 } 1672 1673 Map<CodeSigner,String> cacheForSignerInfo = new IdentityHashMap<>(); 1674 1675 /** 1676 * Returns a string of singer info, with a newline at the end 1677 */ 1678 private String signerInfo(CodeSigner signer, String tab) throws Exception { 1679 if (cacheForSignerInfo.containsKey(signer)) { 1680 return cacheForSignerInfo.get(signer); 1681 } 1682 StringBuilder sb = new StringBuilder(); 1683 List<? extends Certificate> certs = signer.getSignerCertPath().getCertificates(); 1684 // display the signature timestamp, if present 1685 Date timestamp; 1686 Timestamp ts = signer.getTimestamp(); 1687 if (ts != null) { 1688 sb.append(printTimestamp(tab, ts)); 1689 sb.append('\n'); 1690 timestamp = ts.getTimestamp(); 1691 } else { 1692 timestamp = null; 1693 noTimestamp = true; 1694 } 1695 // display the certificate(sb). The first one is end-entity cert and 1696 // its KeyUsage should be checked. 1697 boolean first = true; 1698 sb.append(tab).append(rb.getString("...Signer")).append('\n'); 1699 for (Certificate c : certs) { 1700 sb.append(printCert(false, tab, c, timestamp, first)); 1701 sb.append('\n'); 1702 first = false; 1703 } 1704 try { 1705 validateCertChain(Validator.VAR_CODE_SIGNING, certs, ts); 1706 } catch (Exception e) { 1707 chainNotValidated = true; 1708 chainNotValidatedReason = e; 1709 sb.append(tab).append(rb.getString(".Invalid.certificate.chain.")) 1710 .append(e.getLocalizedMessage()).append("]\n"); 1711 } 1712 if (ts != null) { 1713 sb.append(tab).append(rb.getString("...TSA")).append('\n'); 1714 for (Certificate c : ts.getSignerCertPath().getCertificates()) { 1715 sb.append(printCert(true, tab, c, timestamp, false)); 1716 sb.append('\n'); 1717 } 1718 try { 1719 validateCertChain(Validator.VAR_TSA_SERVER, 1720 ts.getSignerCertPath().getCertificates(), null); 1721 } catch (Exception e) { 1722 tsaChainNotValidated = true; 1723 tsaChainNotValidatedReason = e; 1724 sb.append(tab).append(rb.getString(".Invalid.TSA.certificate.chain.")) 1725 .append(e.getLocalizedMessage()).append("]\n"); 1726 } 1727 } 1728 if (certs.size() == 1 1729 && KeyStoreUtil.isSelfSigned((X509Certificate)certs.get(0))) { 1730 signerSelfSigned = true; 1731 } 1732 String result = sb.toString(); 1733 cacheForSignerInfo.put(signer, result); 1734 return result; 1735 } 1736 1737 void loadKeyStore(String keyStoreName, boolean prompt) { 1738 1739 if (!nullStream && keyStoreName == null) { 1740 keyStoreName = System.getProperty("user.home") + File.separator 1741 + ".keystore"; 1742 } 1743 1744 try { 1745 Set<TrustAnchor> tas = new HashSet<>(); 1746 try { 1747 KeyStore caks = KeyStoreUtil.getCacertsKeyStore(); 1748 if (caks != null) { 1749 Enumeration<String> aliases = caks.aliases(); 1750 while (aliases.hasMoreElements()) { 1751 String a = aliases.nextElement(); 1752 try { 1753 tas.add(new TrustAnchor((X509Certificate)caks.getCertificate(a), null)); 1754 } catch (Exception e2) { 1755 // ignore, when a SecretkeyEntry does not include a cert 1756 } 1757 } 1758 } 1759 } catch (Exception e) { 1760 // Ignore, if cacerts cannot be loaded 1761 } 1762 1763 if (providerName == null) { 1764 store = KeyStore.getInstance(storetype); 1765 } else { 1766 store = KeyStore.getInstance(storetype, providerName); 1767 } 1768 1769 // Get pass phrase 1770 // XXX need to disable echo; on UNIX, call getpass(char *prompt)Z 1771 // and on NT call ?? 1772 if (token && storepass == null && !protectedPath 1773 && !KeyStoreUtil.isWindowsKeyStore(storetype)) { 1774 storepass = getPass 1775 (rb.getString("Enter.Passphrase.for.keystore.")); 1776 } else if (!token && storepass == null && prompt) { 1777 storepass = getPass 1778 (rb.getString("Enter.Passphrase.for.keystore.")); 1779 } 1780 1781 try { 1782 if (nullStream) { 1783 store.load(null, storepass); 1784 } else { 1785 keyStoreName = keyStoreName.replace(File.separatorChar, '/'); 1786 URL url = null; 1787 try { 1788 url = new URL(keyStoreName); 1789 } catch (java.net.MalformedURLException e) { 1790 // try as file 1791 url = new File(keyStoreName).toURI().toURL(); 1792 } 1793 InputStream is = null; 1794 try { 1795 is = url.openStream(); 1796 store.load(is, storepass); 1797 } finally { 1798 if (is != null) { 1799 is.close(); 1800 } 1801 } 1802 } 1803 Enumeration<String> aliases = store.aliases(); 1804 while (aliases.hasMoreElements()) { 1805 String a = aliases.nextElement(); 1806 try { 1807 X509Certificate c = (X509Certificate)store.getCertificate(a); 1808 // Only add TrustedCertificateEntry and self-signed 1809 // PrivateKeyEntry 1810 if (store.isCertificateEntry(a) || 1811 c.getSubjectDN().equals(c.getIssuerDN())) { 1812 tas.add(new TrustAnchor(c, null)); 1813 } 1814 } catch (Exception e2) { 1815 // ignore, when a SecretkeyEntry does not include a cert 1816 } 1817 } 1818 } finally { 1819 try { 1820 pkixParameters = new PKIXBuilderParameters(tas, null); 1821 pkixParameters.setRevocationEnabled(false); 1822 } catch (InvalidAlgorithmParameterException ex) { 1823 // Only if tas is empty 1824 } 1825 } 1826 } catch (IOException ioe) { 1827 throw new RuntimeException(rb.getString("keystore.load.") + 1828 ioe.getMessage()); 1829 } catch (java.security.cert.CertificateException ce) { 1830 throw new RuntimeException(rb.getString("certificate.exception.") + 1831 ce.getMessage()); 1832 } catch (NoSuchProviderException pe) { 1833 throw new RuntimeException(rb.getString("keystore.load.") + 1834 pe.getMessage()); 1835 } catch (NoSuchAlgorithmException nsae) { 1836 throw new RuntimeException(rb.getString("keystore.load.") + 1837 nsae.getMessage()); 1838 } catch (KeyStoreException kse) { 1839 throw new RuntimeException 1840 (rb.getString("unable.to.instantiate.keystore.class.") + 1841 kse.getMessage()); 1842 } 1843 } 1844 1845 X509Certificate getTsaCert(String alias) { 1846 1847 java.security.cert.Certificate cs = null; 1848 1849 try { 1850 cs = store.getCertificate(alias); 1851 } catch (KeyStoreException kse) { 1852 // this never happens, because keystore has been loaded 1853 } 1854 if (cs == null || (!(cs instanceof X509Certificate))) { 1855 MessageFormat form = new MessageFormat(rb.getString 1856 ("Certificate.not.found.for.alias.alias.must.reference.a.valid.KeyStore.entry.containing.an.X.509.public.key.certificate.for.the")); 1857 Object[] source = {alias, alias}; 1858 error(form.format(source)); 1859 } 1860 return (X509Certificate) cs; 1861 } 1862 1863 /** 1864 * Check if userCert is designed to be a code signer 1865 * @param userCert the certificate to be examined 1866 * @param bad 3 booleans to show if the KeyUsage, ExtendedKeyUsage, 1867 * NetscapeCertType has codeSigning flag turned on. 1868 * If null, the class field badKeyUsage, badExtendedKeyUsage, 1869 * badNetscapeCertType will be set. 1870 */ 1871 void checkCertUsage(X509Certificate userCert, boolean[] bad) { 1872 1873 // Can act as a signer? 1874 // 1. if KeyUsage, then [0:digitalSignature] or 1875 // [1:nonRepudiation] should be true 1876 // 2. if ExtendedKeyUsage, then should contains ANY or CODE_SIGNING 1877 // 3. if NetscapeCertType, then should contains OBJECT_SIGNING 1878 // 1,2,3 must be true 1879 1880 if (bad != null) { 1881 bad[0] = bad[1] = bad[2] = false; 1882 } 1883 1884 boolean[] keyUsage = userCert.getKeyUsage(); 1885 if (keyUsage != null) { 1886 keyUsage = Arrays.copyOf(keyUsage, 9); 1887 if (!keyUsage[0] && !keyUsage[1]) { 1888 if (bad != null) { 1889 bad[0] = true; 1890 badKeyUsage = true; 1891 } 1892 } 1893 } 1894 1895 try { 1896 List<String> xKeyUsage = userCert.getExtendedKeyUsage(); 1897 if (xKeyUsage != null) { 1898 if (!xKeyUsage.contains("2.5.29.37.0") // anyExtendedKeyUsage 1899 && !xKeyUsage.contains("1.3.6.1.5.5.7.3.3")) { // codeSigning 1900 if (bad != null) { 1901 bad[1] = true; 1902 badExtendedKeyUsage = true; 1903 } 1904 } 1905 } 1906 } catch (java.security.cert.CertificateParsingException e) { 1907 // shouldn't happen 1908 } 1909 1910 try { 1911 // OID_NETSCAPE_CERT_TYPE 1912 byte[] netscapeEx = userCert.getExtensionValue 1913 ("2.16.840.1.113730.1.1"); 1914 if (netscapeEx != null) { 1915 DerInputStream in = new DerInputStream(netscapeEx); 1916 byte[] encoded = in.getOctetString(); 1917 encoded = new DerValue(encoded).getUnalignedBitString() 1918 .toByteArray(); 1919 1920 NetscapeCertTypeExtension extn = 1921 new NetscapeCertTypeExtension(encoded); 1922 1923 Boolean val = extn.get(NetscapeCertTypeExtension.OBJECT_SIGNING); 1924 if (!val) { 1925 if (bad != null) { 1926 bad[2] = true; 1927 badNetscapeCertType = true; 1928 } 1929 } 1930 } 1931 } catch (IOException e) { 1932 // 1933 } 1934 } 1935 1936 void getAliasInfo(String alias) throws Exception { 1937 1938 Key key = null; 1939 1940 try { 1941 java.security.cert.Certificate[] cs = null; 1942 if (altCertChain != null) { 1943 try (FileInputStream fis = new FileInputStream(altCertChain)) { 1944 cs = CertificateFactory.getInstance("X.509"). 1945 generateCertificates(fis). 1946 toArray(new Certificate[0]); 1947 } catch (FileNotFoundException ex) { 1948 error(rb.getString("File.specified.by.certchain.does.not.exist")); 1949 } catch (CertificateException | IOException ex) { 1950 error(rb.getString("Cannot.restore.certchain.from.file.specified")); 1951 } 1952 } else { 1953 try { 1954 cs = store.getCertificateChain(alias); 1955 } catch (KeyStoreException kse) { 1956 // this never happens, because keystore has been loaded 1957 } 1958 } 1959 if (cs == null || cs.length == 0) { 1960 if (altCertChain != null) { 1961 error(rb.getString 1962 ("Certificate.chain.not.found.in.the.file.specified.")); 1963 } else { 1964 MessageFormat form = new MessageFormat(rb.getString 1965 ("Certificate.chain.not.found.for.alias.alias.must.reference.a.valid.KeyStore.key.entry.containing.a.private.key.and")); 1966 Object[] source = {alias, alias}; 1967 error(form.format(source)); 1968 } 1969 } 1970 1971 certChain = new X509Certificate[cs.length]; 1972 for (int i=0; i<cs.length; i++) { 1973 if (!(cs[i] instanceof X509Certificate)) { 1974 error(rb.getString 1975 ("found.non.X.509.certificate.in.signer.s.chain")); 1976 } 1977 certChain[i] = (X509Certificate)cs[i]; 1978 } 1979 1980 // We don't meant to print anything, the next call 1981 // checks validity and keyUsage etc 1982 printCert(false, "", certChain[0], null, true); 1983 1984 try { 1985 validateCertChain(Validator.VAR_CODE_SIGNING, 1986 Arrays.asList(certChain), null); 1987 } catch (Exception e) { 1988 chainNotValidated = true; 1989 chainNotValidatedReason = e; 1990 } 1991 1992 if (KeyStoreUtil.isSelfSigned(certChain[0])) { 1993 signerSelfSigned = true; 1994 } 1995 1996 try { 1997 if (!token && keypass == null) 1998 key = store.getKey(alias, storepass); 1999 else 2000 key = store.getKey(alias, keypass); 2001 } catch (UnrecoverableKeyException e) { 2002 if (token) { 2003 throw e; 2004 } else if (keypass == null) { 2005 // Did not work out, so prompt user for key password 2006 MessageFormat form = new MessageFormat(rb.getString 2007 ("Enter.key.password.for.alias.")); 2008 Object[] source = {alias}; 2009 keypass = getPass(form.format(source)); 2010 key = store.getKey(alias, keypass); 2011 } 2012 } 2013 } catch (NoSuchAlgorithmException e) { 2014 error(e.getMessage()); 2015 } catch (UnrecoverableKeyException e) { 2016 error(rb.getString("unable.to.recover.key.from.keystore")); 2017 } catch (KeyStoreException kse) { 2018 // this never happens, because keystore has been loaded 2019 } 2020 2021 if (!(key instanceof PrivateKey)) { 2022 MessageFormat form = new MessageFormat(rb.getString 2023 ("key.associated.with.alias.not.a.private.key")); 2024 Object[] source = {alias}; 2025 error(form.format(source)); 2026 } else { 2027 privateKey = (PrivateKey)key; 2028 } 2029 } 2030 2031 void error(String message) { 2032 System.out.println(rb.getString("jarsigner.")+message); 2033 System.exit(1); 2034 } 2035 2036 2037 void error(String message, Throwable e) { 2038 System.out.println(rb.getString("jarsigner.")+message); 2039 if (debug) { 2040 e.printStackTrace(); 2041 } 2042 System.exit(1); 2043 } 2044 2045 /** 2046 * Validates a cert chain. 2047 * 2048 * @param parameter this might be a timestamp 2049 */ 2050 void validateCertChain(String variant, List<? extends Certificate> certs, 2051 Object parameter) 2052 throws Exception { 2053 try { 2054 Validator.getInstance(Validator.TYPE_PKIX, 2055 variant, 2056 pkixParameters) 2057 .validate(certs.toArray(new X509Certificate[certs.size()]), 2058 null, parameter); 2059 } catch (Exception e) { 2060 if (debug) { 2061 e.printStackTrace(); 2062 } 2063 2064 // Exception might be dismissed if another warning flag 2065 // is already set by printCert. This is only done for 2066 // code signing certs. 2067 2068 if (variant.equals(Validator.VAR_CODE_SIGNING) && 2069 e instanceof ValidatorException) { 2070 // Throw cause if it's CertPathValidatorException, 2071 if (e.getCause() != null && 2072 e.getCause() instanceof CertPathValidatorException) { 2073 e = (Exception) e.getCause(); 2074 Throwable t = e.getCause(); 2075 if ((t instanceof CertificateExpiredException && 2076 hasExpiredCert) || 2077 (t instanceof CertificateNotYetValidException && 2078 notYetValidCert)) { 2079 // we already have hasExpiredCert and notYetValidCert 2080 return; 2081 } 2082 } 2083 if (e instanceof ValidatorException) { 2084 ValidatorException ve = (ValidatorException)e; 2085 if (ve.getErrorType() == ValidatorException.T_EE_EXTENSIONS && 2086 (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType)) { 2087 // We already have badKeyUsage, badExtendedKeyUsage 2088 // and badNetscapeCertType 2089 return; 2090 } 2091 } 2092 } 2093 throw e; 2094 } 2095 } 2096 2097 char[] getPass(String prompt) { 2098 System.err.print(prompt); 2099 System.err.flush(); 2100 try { 2101 char[] pass = Password.readPassword(System.in); 2102 2103 if (pass == null) { 2104 error(rb.getString("you.must.enter.key.password")); 2105 } else { 2106 return pass; 2107 } 2108 } catch (IOException ioe) { 2109 error(rb.getString("unable.to.read.password.")+ioe.getMessage()); 2110 } 2111 // this shouldn't happen 2112 return null; 2113 } 2114 }