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