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