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