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.util.*;
  30 import java.util.zip.*;
  31 import java.util.jar.*;
  32 import java.net.URI;
  33 import java.text.Collator;
  34 import java.text.MessageFormat;
  35 import java.security.cert.Certificate;
  36 import java.security.cert.X509Certificate;
  37 import java.security.cert.CertificateException;
  38 import java.security.*;
  39 
  40 import java.net.SocketTimeoutException;
  41 import java.net.URL;
  42 import java.security.cert.CertPath;
  43 import java.security.cert.CertPathValidator;
  44 import java.security.cert.CertificateExpiredException;
  45 import java.security.cert.CertificateFactory;
  46 import java.security.cert.CertificateNotYetValidException;
  47 import java.security.cert.PKIXParameters;
  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.x509.*;
  58 import sun.security.util.*;
  59 
  60 
  61 /**
  62  * <p>The jarsigner utility.
  63  *
  64  * The exit codes for the main method are:
  65  *
  66  * 0: success
  67  * 1: any error that the jar cannot be signed or verified, including:
  68  *      keystore loading error
  69  *      TSP communication error
  70  *      jarsigner command line error...
  71  * otherwise: error codes from -strict
  72  *
  73  * @author Roland Schemers
  74  * @author Jan Luehe
  75  */
  76 public class Main {
  77 
  78     // for i18n
  79     private static final java.util.ResourceBundle rb =
  80         java.util.ResourceBundle.getBundle
  81         ("sun.security.tools.jarsigner.Resources");
  82     private static final Collator collator = Collator.getInstance();
  83     static {
  84         // this is for case insensitive string comparisions
  85         collator.setStrength(Collator.PRIMARY);
  86     }
  87 
  88     private static final String NONE = "NONE";
  89     private static final String P11KEYSTORE = "PKCS11";
  90 
  91     private static final long SIX_MONTHS = 180*24*60*60*1000L; //milliseconds
  92 
  93     // PROPERTY_CERTPATH_DISABLED_ALGS is currently more restrictive than
  94     // PROPERTY_JAR_DISABLED_ALGS and we used it at signing time.
  95     private static final DisabledAlgorithmConstraints VERIFY_CHECK =
  96             new DisabledAlgorithmConstraints(
  97                     DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
  98     private static final DisabledAlgorithmConstraints SIGN_CHECK =
  99             new DisabledAlgorithmConstraints(
 100                     DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
 101 
 102     private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET = Collections
 103             .unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
 104     private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections
 105             .unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
 106 
 107     // Attention:
 108     // This is the entry that get launched by the security tool jarsigner.
 109     public static void main(String args[]) throws Exception {
 110         Main js = new Main();
 111         js.run(args);
 112     }
 113 
 114     static final String VERSION = "1.0";
 115 
 116     static final int IN_KEYSTORE = 0x01;        // signer is in keystore
 117     static final int NOT_ALIAS = 0x04;          // alias list is NOT empty and
 118                                                 // signer is not in alias list
 119     static final int SIGNED_BY_ALIAS = 0x08;    // signer is in alias list
 120 
 121     X509Certificate[] certChain;    // signer's cert chain (when composing)
 122     PrivateKey privateKey;          // private key
 123     KeyStore store;                 // the keystore specified by -keystore
 124                                     // or the default keystore, never null
 125 
 126     String keystore; // key store file
 127     boolean nullStream = false; // null keystore input stream (NONE)
 128     boolean token = false; // token-based keystore
 129     String jarfile;  // jar files to sign or verify
 130     String alias;    // alias to sign jar with
 131     List<String> ckaliases = new ArrayList<>(); // aliases in -verify
 132     char[] storepass; // keystore password
 133     boolean protectedPath; // protected authentication path
 134     String storetype; // keystore type
 135     String providerName; // provider name
 136     List<String> providers = null; // list of provider names
 137     List<String> providerClasses = null; // list of provider classes
 138     // arguments for provider constructors
 139     HashMap<String,String> providerArgs = new HashMap<>();
 140     char[] keypass; // private key password
 141     String sigfile; // name of .SF file
 142     String sigalg; // name of signature algorithm
 143     String digestalg; // name of digest algorithm
 144     String signedjar; // output filename
 145     String tsaUrl; // location of the Timestamping Authority
 146     String tsaAlias; // alias for the Timestamping Authority's certificate
 147     String altCertChain; // file to read alternative cert chain from
 148     String tSAPolicyID;
 149     String tSADigestAlg;
 150     boolean verify = false; // verify the jar
 151     String verbose = null; // verbose output when signing/verifying
 152     boolean showcerts = false; // show certs when verifying
 153     boolean debug = false; // debug
 154     boolean signManifest = true; // "sign" the whole manifest
 155     boolean externalSF = true; // leave the .SF out of the PKCS7 block
 156     boolean strict = false;  // treat warnings as error
 157 
 158     // read zip entry raw bytes
 159     private String altSignerClass = null;
 160     private String altSignerClasspath = null;
 161     private ZipFile zipFile = null;
 162 
 163     // Informational warnings
 164     private boolean hasExpiringCert = false;
 165     private boolean noTimestamp = false;
 166     private Date expireDate = new Date(0L);     // used in noTimestamp warning
 167 
 168     // Severe warnings
 169     private int weakAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg
 170     private boolean hasExpiredCert = false;
 171     private boolean notYetValidCert = false;
 172     private boolean chainNotValidated = false;
 173     private boolean notSignedByAlias = false;
 174     private boolean aliasNotInStore = false;
 175     private boolean hasUnsignedEntry = false;
 176     private boolean badKeyUsage = false;
 177     private boolean badExtendedKeyUsage = false;
 178     private boolean badNetscapeCertType = false;
 179     private boolean signerSelfSigned = false;
 180 
 181     private Throwable chainNotValidatedReason = null;
 182 
 183     private boolean seeWeak = false;
 184 
 185     CertificateFactory certificateFactory;
 186     CertPathValidator validator;
 187     PKIXParameters pkixParameters;
 188 
 189     public void run(String args[]) {
 190         try {
 191             args = parseArgs(args);
 192 
 193             // Try to load and install the specified providers
 194             if (providers != null) {
 195                 for (String provName: providers) {
 196                     try {
 197                         KeyStoreUtil.loadProviderByName(provName,
 198                                 providerArgs.get(provName));
 199                         if (debug) {
 200                             System.out.println("loadProviderByName: " + provName);
 201                         }
 202                     } catch (IllegalArgumentException e) {
 203                         throw new Exception(String.format(rb.getString(
 204                                 "provider.name.not.found"), provName));
 205                     }
 206                 }
 207             }
 208 
 209             if (providerClasses != null) {
 210                 ClassLoader cl = ClassLoader.getSystemClassLoader();
 211                 for (String provClass: providerClasses) {
 212                     try {
 213                         KeyStoreUtil.loadProviderByClass(provClass,
 214                                 providerArgs.get(provClass), cl);
 215                         if (debug) {
 216                             System.out.println("loadProviderByClass: " + provClass);
 217                         }
 218                     } catch (ClassCastException cce) {
 219                         throw new Exception(String.format(rb.getString(
 220                                 "provclass.not.a.provider"), provClass));
 221                     } catch (IllegalArgumentException e) {
 222                         throw new Exception(String.format(rb.getString(
 223                                 "provider.class.not.found"), provClass), e.getCause());
 224                     }
 225                 }
 226             }
 227 
 228             if (verify) {
 229                 try {
 230                     loadKeyStore(keystore, false);
 231                 } catch (Exception e) {
 232                     if ((keystore != null) || (storepass != null)) {
 233                         System.out.println(rb.getString("jarsigner.error.") +
 234                                         e.getMessage());
 235                         if (debug) {
 236                             e.printStackTrace();
 237                         }
 238                         System.exit(1);
 239                     }
 240                 }
 241                 /*              if (debug) {
 242                     SignatureFileVerifier.setDebug(true);
 243                     ManifestEntryVerifier.setDebug(true);
 244                 }
 245                 */
 246                 verifyJar(jarfile);
 247             } else {
 248                 loadKeyStore(keystore, true);
 249                 getAliasInfo(alias);
 250 
 251                 signJar(jarfile, alias);
 252             }
 253         } catch (Exception e) {
 254             System.out.println(rb.getString("jarsigner.error.") + e);
 255             if (debug) {
 256                 e.printStackTrace();
 257             }
 258             System.exit(1);
 259         } finally {
 260             // zero-out private key password
 261             if (keypass != null) {
 262                 Arrays.fill(keypass, ' ');
 263                 keypass = null;
 264             }
 265             // zero-out keystore password
 266             if (storepass != null) {
 267                 Arrays.fill(storepass, ' ');
 268                 storepass = null;
 269             }
 270         }
 271 
 272         if (strict) {
 273             int exitCode = 0;
 274             if (weakAlg != 0 || chainNotValidated || hasExpiredCert || notYetValidCert || signerSelfSigned) {
 275                 exitCode |= 4;
 276             }
 277             if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) {
 278                 exitCode |= 8;
 279             }
 280             if (hasUnsignedEntry) {
 281                 exitCode |= 16;
 282             }
 283             if (notSignedByAlias || aliasNotInStore) {
 284                 exitCode |= 32;
 285             }
 286             if (exitCode != 0) {
 287                 System.exit(exitCode);
 288             }
 289         }
 290     }
 291 
 292     /*
 293      * Parse command line arguments.
 294      */
 295     String[] parseArgs(String args[]) throws Exception {
 296         /* parse flags */
 297         int n = 0;
 298 
 299         if (args.length == 0) fullusage();
 300 
 301         String confFile = null;
 302         String command = "-sign";
 303         for (n=0; n < args.length; n++) {
 304             if (collator.compare(args[n], "-verify") == 0) {
 305                 command = "-verify";
 306             } else if (collator.compare(args[n], "-conf") == 0) {
 307                 if (n == args.length - 1) {
 308                     usageNoArg();
 309                 }
 310                 confFile = args[++n];
 311             }
 312         }
 313 
 314         if (confFile != null) {
 315             args = KeyStoreUtil.expandArgs(
 316                     "jarsigner", confFile, command, null, args);
 317         }
 318 
 319         debug = Arrays.stream(args).anyMatch(
 320                 x -> collator.compare(x, "-debug") == 0);
 321 
 322         if (debug) {
 323             // No need to localize debug output
 324             System.out.println("Command line args: " +
 325                     Arrays.toString(args));
 326         }
 327 
 328         for (n=0; n < args.length; n++) {
 329 
 330             String flags = args[n];
 331             String modifier = null;
 332 
 333             if (flags.startsWith("-")) {
 334                 int pos = flags.indexOf(':');
 335                 if (pos > 0) {
 336                     modifier = flags.substring(pos+1);
 337                     flags = flags.substring(0, pos);
 338                 }
 339             }
 340 
 341             if (!flags.startsWith("-")) {
 342                 if (jarfile == null) {
 343                     jarfile = flags;
 344                 } else {
 345                     alias = flags;
 346                     ckaliases.add(alias);
 347                 }
 348             } else if (collator.compare(flags, "-conf") == 0) {
 349                 if (++n == args.length) usageNoArg();
 350             } else if (collator.compare(flags, "-keystore") == 0) {
 351                 if (++n == args.length) usageNoArg();
 352                 keystore = args[n];
 353             } else if (collator.compare(flags, "-storepass") ==0) {
 354                 if (++n == args.length) usageNoArg();
 355                 storepass = getPass(modifier, args[n]);
 356             } else if (collator.compare(flags, "-storetype") ==0) {
 357                 if (++n == args.length) usageNoArg();
 358                 storetype = args[n];
 359             } else if (collator.compare(flags, "-providerName") ==0) {
 360                 if (++n == args.length) usageNoArg();
 361                 providerName = args[n];
 362             } else if (collator.compare(flags, "-provider") == 0 ||
 363                         collator.compare(flags, "-providerClass") == 0) {
 364                 if (++n == args.length) usageNoArg();
 365                 if (providerClasses == null) {
 366                     providerClasses = new ArrayList<>(3);
 367                 }
 368                 providerClasses.add(args[n]);
 369 
 370                 if (args.length > (n+1)) {
 371                     flags = args[n+1];
 372                     if (collator.compare(flags, "-providerArg") == 0) {
 373                         if (args.length == (n+2)) usageNoArg();
 374                         providerArgs.put(args[n], args[n+2]);
 375                         n += 2;
 376                     }
 377                 }
 378             } else if (collator.compare(flags, "-addprovider") == 0) {
 379                 if (++n == args.length) usageNoArg();
 380                 if (providers == null) {
 381                     providers = new ArrayList<>(3);
 382                 }
 383                 providers.add(args[n]);
 384 
 385                 if (args.length > (n+1)) {
 386                     flags = args[n+1];
 387                     if (collator.compare(flags, "-providerArg") == 0) {
 388                         if (args.length == (n+2)) usageNoArg();
 389                         providerArgs.put(args[n], args[n+2]);
 390                         n += 2;
 391                     }
 392                 }
 393             } else if (collator.compare(flags, "-protected") ==0) {
 394                 protectedPath = true;
 395             } else if (collator.compare(flags, "-certchain") ==0) {
 396                 if (++n == args.length) usageNoArg();
 397                 altCertChain = args[n];
 398             } else if (collator.compare(flags, "-tsapolicyid") ==0) {
 399                 if (++n == args.length) usageNoArg();
 400                 tSAPolicyID = args[n];
 401             } else if (collator.compare(flags, "-tsadigestalg") ==0) {
 402                 if (++n == args.length) usageNoArg();
 403                 tSADigestAlg = args[n];
 404             } else if (collator.compare(flags, "-debug") ==0) {
 405                 // Already processed
 406             } else if (collator.compare(flags, "-keypass") ==0) {
 407                 if (++n == args.length) usageNoArg();
 408                 keypass = getPass(modifier, args[n]);
 409             } else if (collator.compare(flags, "-sigfile") ==0) {
 410                 if (++n == args.length) usageNoArg();
 411                 sigfile = args[n];
 412             } else if (collator.compare(flags, "-signedjar") ==0) {
 413                 if (++n == args.length) usageNoArg();
 414                 signedjar = args[n];
 415             } else if (collator.compare(flags, "-tsa") ==0) {
 416                 if (++n == args.length) usageNoArg();
 417                 tsaUrl = args[n];
 418             } else if (collator.compare(flags, "-tsacert") ==0) {
 419                 if (++n == args.length) usageNoArg();
 420                 tsaAlias = args[n];
 421             } else if (collator.compare(flags, "-altsigner") ==0) {
 422                 if (++n == args.length) usageNoArg();
 423                 altSignerClass = args[n];
 424                 System.err.println(
 425                         rb.getString("This.option.is.deprecated") +
 426                                 "-altsigner");
 427             } else if (collator.compare(flags, "-altsignerpath") ==0) {
 428                 if (++n == args.length) usageNoArg();
 429                 altSignerClasspath = args[n];
 430                 System.err.println(
 431                         rb.getString("This.option.is.deprecated") +
 432                                 "-altsignerpath");
 433             } else if (collator.compare(flags, "-sectionsonly") ==0) {
 434                 signManifest = false;
 435             } else if (collator.compare(flags, "-internalsf") ==0) {
 436                 externalSF = false;
 437             } else if (collator.compare(flags, "-verify") ==0) {
 438                 verify = true;
 439             } else if (collator.compare(flags, "-verbose") ==0) {
 440                 verbose = (modifier != null) ? modifier : "all";
 441             } else if (collator.compare(flags, "-sigalg") ==0) {
 442                 if (++n == args.length) usageNoArg();
 443                 sigalg = args[n];
 444             } else if (collator.compare(flags, "-digestalg") ==0) {
 445                 if (++n == args.length) usageNoArg();
 446                 digestalg = args[n];
 447             } else if (collator.compare(flags, "-certs") ==0) {
 448                 showcerts = true;
 449             } else if (collator.compare(flags, "-strict") ==0) {
 450                 strict = true;
 451             } else if (collator.compare(flags, "-h") == 0 ||
 452                         collator.compare(flags, "-help") == 0) {
 453                 fullusage();
 454             } else {
 455                 System.err.println(
 456                         rb.getString("Illegal.option.") + flags);
 457                 usage();
 458             }
 459         }
 460 
 461         // -certs must always be specified with -verbose
 462         if (verbose == null) showcerts = false;
 463 
 464         if (jarfile == null) {
 465             System.err.println(rb.getString("Please.specify.jarfile.name"));
 466             usage();
 467         }
 468         if (!verify && alias == null) {
 469             System.err.println(rb.getString("Please.specify.alias.name"));
 470             usage();
 471         }
 472         if (!verify && ckaliases.size() > 1) {
 473             System.err.println(rb.getString("Only.one.alias.can.be.specified"));
 474             usage();
 475         }
 476 
 477         if (storetype == null) {
 478             storetype = KeyStore.getDefaultType();
 479         }
 480         storetype = KeyStoreUtil.niceStoreTypeName(storetype);
 481 
 482         try {
 483             if (signedjar != null && new File(signedjar).getCanonicalPath().equals(
 484                     new File(jarfile).getCanonicalPath())) {
 485                 signedjar = null;
 486             }
 487         } catch (IOException ioe) {
 488             // File system error?
 489             // Just ignore it.
 490         }
 491 
 492         if (P11KEYSTORE.equalsIgnoreCase(storetype) ||
 493                 KeyStoreUtil.isWindowsKeyStore(storetype)) {
 494             token = true;
 495             if (keystore == null) {
 496                 keystore = NONE;
 497             }
 498         }
 499 
 500         if (NONE.equals(keystore)) {
 501             nullStream = true;
 502         }
 503 
 504         if (token && !nullStream) {
 505             System.err.println(MessageFormat.format(rb.getString
 506                 (".keystore.must.be.NONE.if.storetype.is.{0}"), storetype));
 507             usage();
 508         }
 509 
 510         if (token && keypass != null) {
 511             System.err.println(MessageFormat.format(rb.getString
 512                 (".keypass.can.not.be.specified.if.storetype.is.{0}"), storetype));
 513             usage();
 514         }
 515 
 516         if (protectedPath) {
 517             if (storepass != null || keypass != null) {
 518                 System.err.println(rb.getString
 519                         ("If.protected.is.specified.then.storepass.and.keypass.must.not.be.specified"));
 520                 usage();
 521             }
 522         }
 523         if (KeyStoreUtil.isWindowsKeyStore(storetype)) {
 524             if (storepass != null || keypass != null) {
 525                 System.err.println(rb.getString
 526                         ("If.keystore.is.not.password.protected.then.storepass.and.keypass.must.not.be.specified"));
 527                 usage();
 528             }
 529         }
 530         return args;
 531     }
 532 
 533     static char[] getPass(String modifier, String arg) {
 534         char[] output = KeyStoreUtil.getPassWithModifier(modifier, arg, rb);
 535         if (output != null) return output;
 536         usage();
 537         return null;    // Useless, usage() already exit
 538     }
 539 
 540     static void usageNoArg() {
 541         System.out.println(rb.getString("Option.lacks.argument"));
 542         usage();
 543     }
 544 
 545     static void usage() {
 546         System.out.println();
 547         System.out.println(rb.getString("Please.type.jarsigner.help.for.usage"));
 548         System.exit(1);
 549     }
 550 
 551     static void fullusage() {
 552         System.out.println(rb.getString
 553                 ("Usage.jarsigner.options.jar.file.alias"));
 554         System.out.println(rb.getString
 555                 (".jarsigner.verify.options.jar.file.alias."));
 556         System.out.println();
 557         System.out.println(rb.getString
 558                 (".keystore.url.keystore.location"));
 559         System.out.println();
 560         System.out.println(rb.getString
 561                 (".storepass.password.password.for.keystore.integrity"));
 562         System.out.println();
 563         System.out.println(rb.getString
 564                 (".storetype.type.keystore.type"));
 565         System.out.println();
 566         System.out.println(rb.getString
 567                 (".keypass.password.password.for.private.key.if.different."));
 568         System.out.println();
 569         System.out.println(rb.getString
 570                 (".certchain.file.name.of.alternative.certchain.file"));
 571         System.out.println();
 572         System.out.println(rb.getString
 573                 (".sigfile.file.name.of.SF.DSA.file"));
 574         System.out.println();
 575         System.out.println(rb.getString
 576                 (".signedjar.file.name.of.signed.JAR.file"));
 577         System.out.println();
 578         System.out.println(rb.getString
 579                 (".digestalg.algorithm.name.of.digest.algorithm"));
 580         System.out.println();
 581         System.out.println(rb.getString
 582                 (".sigalg.algorithm.name.of.signature.algorithm"));
 583         System.out.println();
 584         System.out.println(rb.getString
 585                 (".verify.verify.a.signed.JAR.file"));
 586         System.out.println();
 587         System.out.println(rb.getString
 588                 (".verbose.suboptions.verbose.output.when.signing.verifying."));
 589         System.out.println(rb.getString
 590                 (".suboptions.can.be.all.grouped.or.summary"));
 591         System.out.println();
 592         System.out.println(rb.getString
 593                 (".certs.display.certificates.when.verbose.and.verifying"));
 594         System.out.println();
 595         System.out.println(rb.getString
 596                 (".tsa.url.location.of.the.Timestamping.Authority"));
 597         System.out.println();
 598         System.out.println(rb.getString
 599                 (".tsacert.alias.public.key.certificate.for.Timestamping.Authority"));
 600         System.out.println();
 601         System.out.println(rb.getString
 602                 (".tsapolicyid.tsapolicyid.for.Timestamping.Authority"));
 603         System.out.println();
 604         System.out.println(rb.getString
 605                 (".tsadigestalg.algorithm.of.digest.data.in.timestamping.request"));
 606         System.out.println();
 607         System.out.println(rb.getString
 608                 (".altsigner.class.class.name.of.an.alternative.signing.mechanism"));
 609         System.out.println();
 610         System.out.println(rb.getString
 611                 (".altsignerpath.pathlist.location.of.an.alternative.signing.mechanism"));
 612         System.out.println();
 613         System.out.println(rb.getString
 614                 (".internalsf.include.the.SF.file.inside.the.signature.block"));
 615         System.out.println();
 616         System.out.println(rb.getString
 617                 (".sectionsonly.don.t.compute.hash.of.entire.manifest"));
 618         System.out.println();
 619         System.out.println(rb.getString
 620                 (".protected.keystore.has.protected.authentication.path"));
 621         System.out.println();
 622         System.out.println(rb.getString
 623                 (".providerName.name.provider.name"));
 624         System.out.println();
 625         System.out.println(rb.getString
 626                 (".add.provider.option"));
 627         System.out.println(rb.getString
 628                 (".providerArg.option.1"));
 629         System.out.println();
 630         System.out.println(rb.getString
 631                 (".providerClass.option"));
 632         System.out.println(rb.getString
 633                 (".providerArg.option.2"));
 634         System.out.println();
 635         System.out.println(rb.getString
 636                 (".strict.treat.warnings.as.errors"));
 637         System.out.println();
 638         System.out.println(rb.getString
 639                 (".conf.url.specify.a.pre.configured.options.file"));
 640         System.out.println();
 641 
 642         System.exit(0);
 643     }
 644 
 645     void verifyJar(String jarName)
 646         throws Exception
 647     {
 648         boolean anySigned = false;  // if there exists entry inside jar signed
 649         JarFile jf = null;
 650         Map<String,String> digestMap = new HashMap<>();
 651         Map<String,PKCS7> sigMap = new HashMap<>();
 652         Map<String,String> sigNameMap = new HashMap<>();
 653         Map<String,String> unparsableSignatures = new HashMap<>();
 654 
 655         try {
 656             jf = new JarFile(jarName, true);
 657             Vector<JarEntry> entriesVec = new Vector<>();
 658             byte[] buffer = new byte[8192];
 659 
 660             Enumeration<JarEntry> entries = jf.entries();
 661             while (entries.hasMoreElements()) {
 662                 JarEntry je = entries.nextElement();
 663                 entriesVec.addElement(je);
 664                 try (InputStream is = jf.getInputStream(je)) {
 665                     String name = je.getName();
 666                     if (signatureRelated(name)
 667                             && SignatureFileVerifier.isBlockOrSF(name)) {
 668                         String alias = name.substring(name.lastIndexOf('/') + 1,
 669                                 name.lastIndexOf('.'));
 670                         try {
 671                             if (name.endsWith(".SF")) {
 672                                 Manifest sf = new Manifest(is);
 673                                 boolean found = false;
 674                                 for (Object obj : sf.getMainAttributes().keySet()) {
 675                                     String key = obj.toString();
 676                                     if (key.endsWith("-Digest-Manifest")) {
 677                                         digestMap.put(alias,
 678                                                 key.substring(0, key.length() - 16));
 679                                         found = true;
 680                                         break;
 681                                     }
 682                                 }
 683                                 if (!found) {
 684                                     unparsableSignatures.putIfAbsent(alias,
 685                                         String.format(
 686                                             rb.getString("history.unparsable"),
 687                                             name));
 688                                 }
 689                             } else {
 690                                 sigNameMap.put(alias, name);
 691                                 sigMap.put(alias, new PKCS7(is));
 692                             }
 693                         } catch (IOException ioe) {
 694                             unparsableSignatures.putIfAbsent(alias, String.format(
 695                                     rb.getString("history.unparsable"), name));
 696                         }
 697                     } else {
 698                         while (is.read(buffer, 0, buffer.length) != -1) {
 699                             // we just read. this will throw a SecurityException
 700                             // if  a signature/digest check fails.
 701                         }
 702                     }
 703                 }
 704             }
 705 
 706             Manifest man = jf.getManifest();
 707             boolean hasSignature = false;
 708 
 709             // The map to record display info, only used when -verbose provided
 710             //      key: signer info string
 711             //      value: the list of files with common key
 712             Map<String,List<String>> output = new LinkedHashMap<>();
 713 
 714             if (man != null) {
 715                 if (verbose != null) System.out.println();
 716                 Enumeration<JarEntry> e = entriesVec.elements();
 717 
 718                 String tab = rb.getString("6SPACE");
 719 
 720                 while (e.hasMoreElements()) {
 721                     JarEntry je = e.nextElement();
 722                     String name = je.getName();
 723 
 724                     hasSignature = hasSignature
 725                             || SignatureFileVerifier.isBlockOrSF(name);
 726 
 727                     CodeSigner[] signers = je.getCodeSigners();
 728                     boolean isSigned = (signers != null);
 729                     anySigned |= isSigned;
 730                     hasUnsignedEntry |= !je.isDirectory() && !isSigned
 731                                         && !signatureRelated(name);
 732 
 733                     int inStoreWithAlias = inKeyStore(signers);
 734 
 735                     boolean inStore = (inStoreWithAlias & IN_KEYSTORE) != 0;
 736 
 737                     notSignedByAlias |= (inStoreWithAlias & NOT_ALIAS) != 0;
 738                     if (keystore != null) {
 739                         aliasNotInStore |= isSigned && !inStore;
 740                     }
 741 
 742                     // Only used when -verbose provided
 743                     StringBuffer sb = null;
 744                     if (verbose != null) {
 745                         sb = new StringBuffer();
 746                         boolean inManifest =
 747                             ((man.getAttributes(name) != null) ||
 748                              (man.getAttributes("./"+name) != null) ||
 749                              (man.getAttributes("/"+name) != null));
 750                         sb.append(isSigned ? rb.getString("s") : rb.getString("SPACE"))
 751                                 .append(inManifest ? rb.getString("m") : rb.getString("SPACE"))
 752                                 .append(inStore ? rb.getString("k") : rb.getString("SPACE"))
 753                                 .append((inStoreWithAlias & NOT_ALIAS) != 0 ? 'X' : ' ')
 754                                 .append(rb.getString("SPACE"));
 755                         sb.append('|');
 756                     }
 757 
 758                     // When -certs provided, display info has extra empty
 759                     // lines at the beginning and end.
 760                     if (isSigned) {
 761                         if (showcerts) sb.append('\n');
 762                         for (CodeSigner signer: signers) {
 763                             // signerInfo() must be called even if -verbose
 764                             // not provided. The method updates various
 765                             // warning flags.
 766                             String si = signerInfo(signer, tab);
 767                             if (showcerts) {
 768                                 sb.append(si);
 769                                 sb.append('\n');
 770                             }
 771                         }
 772                     } else if (showcerts && !verbose.equals("all")) {
 773                         // Print no info for unsigned entries when -verbose:all,
 774                         // to be consistent with old behavior.
 775                         if (signatureRelated(name)) {
 776                             sb.append('\n')
 777                                     .append(tab)
 778                                     .append(rb
 779                                             .getString(".Signature.related.entries."))
 780                                     .append("\n\n");
 781                         } else {
 782                             sb.append('\n').append(tab)
 783                                     .append(rb.getString(".Unsigned.entries."))
 784                                     .append("\n\n");
 785                         }
 786                     }
 787 
 788                     if (verbose != null) {
 789                         String label = sb.toString();
 790                         if (signatureRelated(name)) {
 791                             // Entries inside META-INF and other unsigned
 792                             // entries are grouped separately.
 793                             label = "-" + label;
 794                         }
 795 
 796                         // The label finally contains 2 parts separated by '|':
 797                         // The legend displayed before the entry names, and
 798                         // the cert info (if -certs specified).
 799 
 800                         if (!output.containsKey(label)) {
 801                             output.put(label, new ArrayList<String>());
 802                         }
 803 
 804                         StringBuilder fb = new StringBuilder();
 805                         String s = Long.toString(je.getSize());
 806                         for (int i = 6 - s.length(); i > 0; --i) {
 807                             fb.append(' ');
 808                         }
 809                         fb.append(s).append(' ').
 810                                 append(new Date(je.getTime()).toString());
 811                         fb.append(' ').append(name);
 812 
 813                         output.get(label).add(fb.toString());
 814                     }
 815                 }
 816             }
 817             if (verbose != null) {
 818                 for (Entry<String,List<String>> s: output.entrySet()) {
 819                     List<String> files = s.getValue();
 820                     String key = s.getKey();
 821                     if (key.charAt(0) == '-') { // the signature-related group
 822                         key = key.substring(1);
 823                     }
 824                     int pipe = key.indexOf('|');
 825                     if (verbose.equals("all")) {
 826                         for (String f: files) {
 827                             System.out.println(key.substring(0, pipe) + f);
 828                             System.out.printf(key.substring(pipe+1));
 829                         }
 830                     } else {
 831                         if (verbose.equals("grouped")) {
 832                             for (String f: files) {
 833                                 System.out.println(key.substring(0, pipe) + f);
 834                             }
 835                         } else if (verbose.equals("summary")) {
 836                             System.out.print(key.substring(0, pipe));
 837                             if (files.size() > 1) {
 838                                 System.out.println(files.get(0) + " " +
 839                                         String.format(rb.getString(
 840                                         ".and.d.more."), files.size()-1));
 841                             } else {
 842                                 System.out.println(files.get(0));
 843                             }
 844                         }
 845                         System.out.printf(key.substring(pipe+1));
 846                     }
 847                 }
 848                 System.out.println();
 849                 System.out.println(rb.getString(
 850                     ".s.signature.was.verified."));
 851                 System.out.println(rb.getString(
 852                     ".m.entry.is.listed.in.manifest"));
 853                 System.out.println(rb.getString(
 854                     ".k.at.least.one.certificate.was.found.in.keystore"));
 855                 if (ckaliases.size() > 0) {
 856                     System.out.println(rb.getString(
 857                         ".X.not.signed.by.specified.alias.es."));
 858                 }
 859             }
 860             if (man == null) {
 861                 System.out.println();
 862                 System.out.println(rb.getString("no.manifest."));
 863             }
 864 
 865             // If signer is a trusted cert or private entry in user's own
 866             // keystore, it can be self-signed.
 867             if (!aliasNotInStore) {
 868                 signerSelfSigned = false;
 869             }
 870 
 871             // Even if the verbose option is not specified, all out strings
 872             // must be generated so seeWeak can be updated.
 873             if (!digestMap.isEmpty()
 874                     || !sigMap.isEmpty()
 875                     || !unparsableSignatures.isEmpty()) {
 876                 if (verbose != null) {
 877                     System.out.println();
 878                 }
 879                 for (String s : sigMap.keySet()) {
 880                     if (!digestMap.containsKey(s)) {
 881                         unparsableSignatures.putIfAbsent(s, String.format(
 882                                 rb.getString("history.nosf"), s));
 883                     }
 884                 }
 885                 for (String s : digestMap.keySet()) {
 886                     PKCS7 p7 = sigMap.get(s);
 887                     if (p7 != null) {
 888                         String history;
 889                         try {
 890                             SignerInfo si = p7.getSignerInfos()[0];
 891                             X509Certificate signer = si.getCertificate(p7);
 892                             String digestAlg = digestMap.get(s);
 893                             String sigAlg = AlgorithmId.makeSigAlg(
 894                                     si.getDigestAlgorithmId().getName(),
 895                                     si.getDigestEncryptionAlgorithmId().getName());
 896                             PublicKey key = signer.getPublicKey();
 897                             PKCS7 tsToken = si.getTsToken();
 898                             if (tsToken != null) {
 899                                 SignerInfo tsSi = tsToken.getSignerInfos()[0];
 900                                 X509Certificate tsSigner = tsSi.getCertificate(tsToken);
 901                                 byte[] encTsTokenInfo = tsToken.getContentInfo().getData();
 902                                 TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo);
 903                                 PublicKey tsKey = tsSigner.getPublicKey();
 904                                 String tsDigestAlg = tsTokenInfo.getHashAlgorithm().getName();
 905                                 String tsSigAlg = AlgorithmId.makeSigAlg(
 906                                         tsSi.getDigestAlgorithmId().getName(),
 907                                         tsSi.getDigestEncryptionAlgorithmId().getName());
 908                                 Calendar c = Calendar.getInstance(
 909                                         TimeZone.getTimeZone("UTC"),
 910                                         Locale.getDefault(Locale.Category.FORMAT));
 911                                 c.setTime(tsTokenInfo.getDate());
 912                                 history = String.format(
 913                                         rb.getString("history.with.ts"),
 914                                         signer.getSubjectX500Principal(),
 915                                         withWeak(digestAlg, DIGEST_PRIMITIVE_SET),
 916                                         withWeak(sigAlg, SIG_PRIMITIVE_SET),
 917                                         withWeak(key),
 918                                         c,
 919                                         tsSigner.getSubjectX500Principal(),
 920                                         withWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET),
 921                                         withWeak(tsSigAlg, SIG_PRIMITIVE_SET),
 922                                         withWeak(tsKey));
 923                             } else {
 924                                 history = String.format(
 925                                         rb.getString("history.without.ts"),
 926                                         signer.getSubjectX500Principal(),
 927                                         withWeak(digestAlg, DIGEST_PRIMITIVE_SET),
 928                                         withWeak(sigAlg, SIG_PRIMITIVE_SET),
 929                                         withWeak(key));
 930                             }
 931                         } catch (Exception e) {
 932                             // The only usage of sigNameMap, remember the name
 933                             // of the block file if it's invalid.
 934                             history = String.format(
 935                                     rb.getString("history.unparsable"),
 936                                     sigNameMap.get(s));
 937                         }
 938                         if (verbose != null) {
 939                             System.out.println(history);
 940                         }
 941                     } else {
 942                         unparsableSignatures.putIfAbsent(s, String.format(
 943                                 rb.getString("history.nobk"), s));
 944                     }
 945                 }
 946                 if (verbose != null) {
 947                     for (String s : unparsableSignatures.keySet()) {
 948                         System.out.println(unparsableSignatures.get(s));
 949                     }
 950                 }
 951             }
 952             System.out.println();
 953             if (!anySigned) {
 954                 if (seeWeak) {
 955                     if (verbose != null) {
 956                         System.out.println(rb.getString("jar.treated.unsigned.see.weak.verbose"));
 957                         System.out.println("\n  " +
 958                                 DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS +
 959                                 "=" + Security.getProperty(DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS));
 960                     } else {
 961                         System.out.println(rb.getString("jar.treated.unsigned.see.weak"));
 962                     }
 963                 } else if (hasSignature) {
 964                     System.out.println(rb.getString("jar.treated.unsigned"));
 965                 } else {
 966                     System.out.println(rb.getString("jar.is.unsigned"));
 967                 }
 968             } else {
 969                 boolean warningAppeared = false;
 970                 boolean errorAppeared = false;
 971                 if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
 972                         notYetValidCert || chainNotValidated || hasExpiredCert ||
 973                         hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) ||
 974                         aliasNotInStore || notSignedByAlias) {
 975 
 976                     if (strict) {
 977                         System.out.println(rb.getString("jar.verified.with.signer.errors."));
 978                         System.out.println();
 979                         System.out.println(rb.getString("Error."));
 980                         errorAppeared = true;
 981                     } else {
 982                         System.out.println(rb.getString("jar.verified."));
 983                         System.out.println();
 984                         System.out.println(rb.getString("Warning."));
 985                         warningAppeared = true;
 986                     }
 987 
 988                     if (weakAlg != 0) {
 989                         // In fact, jarsigner verification did not catch this
 990                         // since it has not read the JarFile content itself.
 991                         // Everything is done with JarFile API. The signing
 992                         // history (digestMap etc) will show these info and
 993                         // print out proper warnings.
 994                     }
 995 
 996                     if (badKeyUsage) {
 997                         System.out.println(
 998                             rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
 999                     }
1000 
1001                     if (badExtendedKeyUsage) {
1002                         System.out.println(
1003                             rb.getString("This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
1004                     }
1005 
1006                     if (badNetscapeCertType) {
1007                         System.out.println(
1008                             rb.getString("This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
1009                     }
1010 
1011                     if (hasUnsignedEntry) {
1012                         System.out.println(rb.getString(
1013                             "This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));
1014                     }
1015                     if (hasExpiredCert) {
1016                         System.out.println(rb.getString(
1017                             "This.jar.contains.entries.whose.signer.certificate.has.expired."));
1018                     }
1019                     if (notYetValidCert) {
1020                         System.out.println(rb.getString(
1021                             "This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid."));
1022                     }
1023 
1024                     if (chainNotValidated) {
1025                         System.out.println(String.format(
1026                                 rb.getString("This.jar.contains.entries.whose.certificate.chain.is.not.validated.reason.1"),
1027                                 chainNotValidatedReason.getLocalizedMessage()));
1028                     }
1029 
1030                     if (notSignedByAlias) {
1031                         System.out.println(
1032                                 rb.getString("This.jar.contains.signed.entries.which.is.not.signed.by.the.specified.alias.es."));
1033                     }
1034 
1035                     if (aliasNotInStore) {
1036                         System.out.println(rb.getString("This.jar.contains.signed.entries.that.s.not.signed.by.alias.in.this.keystore."));
1037                     }
1038 
1039                     if (signerSelfSigned) {
1040                         System.out.println(rb.getString(
1041                                 "This.jar.contains.entries.whose.signer.certificate.is.self.signed."));
1042                     }
1043                 } else {
1044                     System.out.println(rb.getString("jar.verified."));
1045                 }
1046                 if (hasExpiringCert || noTimestamp) {
1047                     if (!warningAppeared) {
1048                         System.out.println();
1049                         System.out.println(rb.getString("Warning."));
1050                         warningAppeared = true;
1051                     }
1052                     if (hasExpiringCert) {
1053                         System.out.println(rb.getString(
1054                                 "This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months."));
1055                     }
1056                     if (noTimestamp) {
1057                         System.out.println(
1058                                 String.format(rb.getString("no.timestamp.verifying"), expireDate));
1059                     }
1060                 }
1061                 if (warningAppeared || errorAppeared) {
1062                     if (! (verbose != null && showcerts)) {
1063                         System.out.println();
1064                         System.out.println(rb.getString(
1065                                 "Re.run.with.the.verbose.and.certs.options.for.more.details."));
1066                     }
1067                 }
1068             }
1069             return;
1070         } catch (Exception e) {
1071             System.out.println(rb.getString("jarsigner.") + e);
1072             if (debug) {
1073                 e.printStackTrace();
1074             }
1075         } finally { // close the resource
1076             if (jf != null) {
1077                 jf.close();
1078             }
1079         }
1080 
1081         System.exit(1);
1082     }
1083 
1084     private String withWeak(String alg, Set<CryptoPrimitive> primitiveSet) {
1085         if (VERIFY_CHECK.permits(primitiveSet, alg, null)) {
1086             return alg;
1087         } else {
1088             seeWeak = true;
1089             return String.format(rb.getString("with.weak"), alg);
1090         }
1091     }
1092 
1093     private String withWeak(PublicKey key) {
1094         if (VERIFY_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
1095             return String.format(
1096                     rb.getString("key.bit"), KeyUtil.getKeySize(key));
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 && !SIGN_CHECK.permits(
1294                 DIGEST_PRIMITIVE_SET, digestalg, null)) {
1295             weakAlg |= 1;
1296         }
1297         if (tSADigestAlg != null && !SIGN_CHECK.permits(
1298                 DIGEST_PRIMITIVE_SET, tSADigestAlg, null)) {
1299             weakAlg |= 4;
1300         }
1301         if (sigalg != null && !SIGN_CHECK.permits(
1302                 SIG_PRIMITIVE_SET , sigalg, null)) {
1303             weakAlg |= 2;
1304         }
1305         if (!SIGN_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             if (debug) {
1632                 e.printStackTrace();
1633             }
1634             if (e.getCause() != null &&
1635                     (e.getCause() instanceof CertificateExpiredException ||
1636                      e.getCause() instanceof CertificateNotYetValidException)) {
1637                 // No more warning, we alreay have hasExpiredCert or notYetValidCert
1638             } else {
1639                 chainNotValidated = true;
1640                 chainNotValidatedReason = e;
1641                 sb.append(tab).append(rb.getString(".CertPath.not.validated."))
1642                         .append(e.getLocalizedMessage()).append("]\n"); // TODO
1643             }
1644         }
1645         if (certs.size() == 1
1646                 && KeyStoreUtil.isSelfSigned((X509Certificate)certs.get(0))) {
1647             signerSelfSigned = true;
1648         }
1649         String result = sb.toString();
1650         cacheForSignerInfo.put(signer, result);
1651         return result;
1652     }
1653 
1654     void loadKeyStore(String keyStoreName, boolean prompt) {
1655 
1656         if (!nullStream && keyStoreName == null) {
1657             keyStoreName = System.getProperty("user.home") + File.separator
1658                 + ".keystore";
1659         }
1660 
1661         try {
1662 
1663             certificateFactory = CertificateFactory.getInstance("X.509");
1664             validator = CertPathValidator.getInstance("PKIX");
1665             Set<TrustAnchor> tas = new HashSet<>();
1666             try {
1667                 KeyStore caks = KeyStoreUtil.getCacertsKeyStore();
1668                 if (caks != null) {
1669                     Enumeration<String> aliases = caks.aliases();
1670                     while (aliases.hasMoreElements()) {
1671                         String a = aliases.nextElement();
1672                         try {
1673                             tas.add(new TrustAnchor((X509Certificate)caks.getCertificate(a), null));
1674                         } catch (Exception e2) {
1675                             // ignore, when a SecretkeyEntry does not include a cert
1676                         }
1677                     }
1678                 }
1679             } catch (Exception e) {
1680                 // Ignore, if cacerts cannot be loaded
1681             }
1682 
1683             if (providerName == null) {
1684                 store = KeyStore.getInstance(storetype);
1685             } else {
1686                 store = KeyStore.getInstance(storetype, providerName);
1687             }
1688 
1689             // Get pass phrase
1690             // XXX need to disable echo; on UNIX, call getpass(char *prompt)Z
1691             // and on NT call ??
1692             if (token && storepass == null && !protectedPath
1693                     && !KeyStoreUtil.isWindowsKeyStore(storetype)) {
1694                 storepass = getPass
1695                         (rb.getString("Enter.Passphrase.for.keystore."));
1696             } else if (!token && storepass == null && prompt) {
1697                 storepass = getPass
1698                         (rb.getString("Enter.Passphrase.for.keystore."));
1699             }
1700 
1701             try {
1702                 if (nullStream) {
1703                     store.load(null, storepass);
1704                 } else {
1705                     keyStoreName = keyStoreName.replace(File.separatorChar, '/');
1706                     URL url = null;
1707                     try {
1708                         url = new URL(keyStoreName);
1709                     } catch (java.net.MalformedURLException e) {
1710                         // try as file
1711                         url = new File(keyStoreName).toURI().toURL();
1712                     }
1713                     InputStream is = null;
1714                     try {
1715                         is = url.openStream();
1716                         store.load(is, storepass);
1717                     } finally {
1718                         if (is != null) {
1719                             is.close();
1720                         }
1721                     }
1722                 }
1723                 Enumeration<String> aliases = store.aliases();
1724                 while (aliases.hasMoreElements()) {
1725                     String a = aliases.nextElement();
1726                     try {
1727                         X509Certificate c = (X509Certificate)store.getCertificate(a);
1728                         // Only add TrustedCertificateEntry and self-signed
1729                         // PrivateKeyEntry
1730                         if (store.isCertificateEntry(a) ||
1731                                 c.getSubjectDN().equals(c.getIssuerDN())) {
1732                             tas.add(new TrustAnchor(c, null));
1733                         }
1734                     } catch (Exception e2) {
1735                         // ignore, when a SecretkeyEntry does not include a cert
1736                     }
1737                 }
1738             } finally {
1739                 try {
1740                     pkixParameters = new PKIXParameters(tas);
1741                     pkixParameters.setRevocationEnabled(false);
1742                 } catch (InvalidAlgorithmParameterException ex) {
1743                     // Only if tas is empty
1744                 }
1745             }
1746         } catch (IOException ioe) {
1747             throw new RuntimeException(rb.getString("keystore.load.") +
1748                                         ioe.getMessage());
1749         } catch (java.security.cert.CertificateException ce) {
1750             throw new RuntimeException(rb.getString("certificate.exception.") +
1751                                         ce.getMessage());
1752         } catch (NoSuchProviderException pe) {
1753             throw new RuntimeException(rb.getString("keystore.load.") +
1754                                         pe.getMessage());
1755         } catch (NoSuchAlgorithmException nsae) {
1756             throw new RuntimeException(rb.getString("keystore.load.") +
1757                                         nsae.getMessage());
1758         } catch (KeyStoreException kse) {
1759             throw new RuntimeException
1760                 (rb.getString("unable.to.instantiate.keystore.class.") +
1761                 kse.getMessage());
1762         }
1763     }
1764 
1765     X509Certificate getTsaCert(String alias) {
1766 
1767         java.security.cert.Certificate cs = null;
1768 
1769         try {
1770             cs = store.getCertificate(alias);
1771         } catch (KeyStoreException kse) {
1772             // this never happens, because keystore has been loaded
1773         }
1774         if (cs == null || (!(cs instanceof X509Certificate))) {
1775             MessageFormat form = new MessageFormat(rb.getString
1776                 ("Certificate.not.found.for.alias.alias.must.reference.a.valid.KeyStore.entry.containing.an.X.509.public.key.certificate.for.the"));
1777             Object[] source = {alias, alias};
1778             error(form.format(source));
1779         }
1780         return (X509Certificate) cs;
1781     }
1782 
1783     /**
1784      * Check if userCert is designed to be a code signer
1785      * @param userCert the certificate to be examined
1786      * @param bad 3 booleans to show if the KeyUsage, ExtendedKeyUsage,
1787      *            NetscapeCertType has codeSigning flag turned on.
1788      *            If null, the class field badKeyUsage, badExtendedKeyUsage,
1789      *            badNetscapeCertType will be set.
1790      */
1791     void checkCertUsage(X509Certificate userCert, boolean[] bad) {
1792 
1793         // Can act as a signer?
1794         // 1. if KeyUsage, then [0:digitalSignature] or
1795         //    [1:nonRepudiation] should be true
1796         // 2. if ExtendedKeyUsage, then should contains ANY or CODE_SIGNING
1797         // 3. if NetscapeCertType, then should contains OBJECT_SIGNING
1798         // 1,2,3 must be true
1799 
1800         if (bad != null) {
1801             bad[0] = bad[1] = bad[2] = false;
1802         }
1803 
1804         boolean[] keyUsage = userCert.getKeyUsage();
1805         if (keyUsage != null) {
1806             keyUsage = Arrays.copyOf(keyUsage, 9);
1807             if (!keyUsage[0] && !keyUsage[1]) {
1808                 if (bad != null) {
1809                     bad[0] = true;
1810                     badKeyUsage = true;
1811                 }
1812             }
1813         }
1814 
1815         try {
1816             List<String> xKeyUsage = userCert.getExtendedKeyUsage();
1817             if (xKeyUsage != null) {
1818                 if (!xKeyUsage.contains("2.5.29.37.0") // anyExtendedKeyUsage
1819                         && !xKeyUsage.contains("1.3.6.1.5.5.7.3.3")) {  // codeSigning
1820                     if (bad != null) {
1821                         bad[1] = true;
1822                         badExtendedKeyUsage = true;
1823                     }
1824                 }
1825             }
1826         } catch (java.security.cert.CertificateParsingException e) {
1827             // shouldn't happen
1828         }
1829 
1830         try {
1831             // OID_NETSCAPE_CERT_TYPE
1832             byte[] netscapeEx = userCert.getExtensionValue
1833                     ("2.16.840.1.113730.1.1");
1834             if (netscapeEx != null) {
1835                 DerInputStream in = new DerInputStream(netscapeEx);
1836                 byte[] encoded = in.getOctetString();
1837                 encoded = new DerValue(encoded).getUnalignedBitString()
1838                         .toByteArray();
1839 
1840                 NetscapeCertTypeExtension extn =
1841                         new NetscapeCertTypeExtension(encoded);
1842 
1843                 Boolean val = extn.get(NetscapeCertTypeExtension.OBJECT_SIGNING);
1844                 if (!val) {
1845                     if (bad != null) {
1846                         bad[2] = true;
1847                         badNetscapeCertType = true;
1848                     }
1849                 }
1850             }
1851         } catch (IOException e) {
1852             //
1853         }
1854     }
1855 
1856     void getAliasInfo(String alias) {
1857 
1858         Key key = null;
1859 
1860         try {
1861             java.security.cert.Certificate[] cs = null;
1862             if (altCertChain != null) {
1863                 try (FileInputStream fis = new FileInputStream(altCertChain)) {
1864                     cs = CertificateFactory.getInstance("X.509").
1865                             generateCertificates(fis).
1866                             toArray(new Certificate[0]);
1867                 } catch (FileNotFoundException ex) {
1868                     error(rb.getString("File.specified.by.certchain.does.not.exist"));
1869                 } catch (CertificateException | IOException ex) {
1870                     error(rb.getString("Cannot.restore.certchain.from.file.specified"));
1871                 }
1872             } else {
1873                 try {
1874                     cs = store.getCertificateChain(alias);
1875                 } catch (KeyStoreException kse) {
1876                     // this never happens, because keystore has been loaded
1877                 }
1878             }
1879             if (cs == null || cs.length == 0) {
1880                 if (altCertChain != null) {
1881                     error(rb.getString
1882                             ("Certificate.chain.not.found.in.the.file.specified."));
1883                 } else {
1884                     MessageFormat form = new MessageFormat(rb.getString
1885                         ("Certificate.chain.not.found.for.alias.alias.must.reference.a.valid.KeyStore.key.entry.containing.a.private.key.and"));
1886                     Object[] source = {alias, alias};
1887                     error(form.format(source));
1888                 }
1889             }
1890 
1891             certChain = new X509Certificate[cs.length];
1892             for (int i=0; i<cs.length; i++) {
1893                 if (!(cs[i] instanceof X509Certificate)) {
1894                     error(rb.getString
1895                         ("found.non.X.509.certificate.in.signer.s.chain"));
1896                 }
1897                 certChain[i] = (X509Certificate)cs[i];
1898             }
1899 
1900             // We don't meant to print anything, the next call
1901             // checks validity and keyUsage etc
1902             printCert("", certChain[0], true, null, true);
1903 
1904             try {
1905                 validateCertChain(Arrays.asList(certChain));
1906             } catch (Exception e) {
1907                 if (debug) {
1908                     e.printStackTrace();
1909                 }
1910                 if (e.getCause() != null &&
1911                         (e.getCause() instanceof CertificateExpiredException ||
1912                         e.getCause() instanceof CertificateNotYetValidException)) {
1913                     // No more warning, we already have hasExpiredCert or notYetValidCert
1914                 } else {
1915                     chainNotValidated = true;
1916                     chainNotValidatedReason = e;
1917                 }
1918             }
1919 
1920             if (KeyStoreUtil.isSelfSigned(certChain[0])) {
1921                 signerSelfSigned = true;
1922             }
1923 
1924             try {
1925                 if (!token && keypass == null)
1926                     key = store.getKey(alias, storepass);
1927                 else
1928                     key = store.getKey(alias, keypass);
1929             } catch (UnrecoverableKeyException e) {
1930                 if (token) {
1931                     throw e;
1932                 } else if (keypass == null) {
1933                     // Did not work out, so prompt user for key password
1934                     MessageFormat form = new MessageFormat(rb.getString
1935                         ("Enter.key.password.for.alias."));
1936                     Object[] source = {alias};
1937                     keypass = getPass(form.format(source));
1938                     key = store.getKey(alias, keypass);
1939                 }
1940             }
1941         } catch (NoSuchAlgorithmException e) {
1942             error(e.getMessage());
1943         } catch (UnrecoverableKeyException e) {
1944             error(rb.getString("unable.to.recover.key.from.keystore"));
1945         } catch (KeyStoreException kse) {
1946             // this never happens, because keystore has been loaded
1947         }
1948 
1949         if (!(key instanceof PrivateKey)) {
1950             MessageFormat form = new MessageFormat(rb.getString
1951                 ("key.associated.with.alias.not.a.private.key"));
1952             Object[] source = {alias};
1953             error(form.format(source));
1954         } else {
1955             privateKey = (PrivateKey)key;
1956         }
1957     }
1958 
1959     void error(String message) {
1960         System.out.println(rb.getString("jarsigner.")+message);
1961         System.exit(1);
1962     }
1963 
1964 
1965     void error(String message, Throwable e) {
1966         System.out.println(rb.getString("jarsigner.")+message);
1967         if (debug) {
1968             e.printStackTrace();
1969         }
1970         System.exit(1);
1971     }
1972 
1973     void validateCertChain(List<? extends Certificate> certs) throws Exception {
1974         int cpLen = 0;
1975         out: for (; cpLen<certs.size(); cpLen++) {
1976             for (TrustAnchor ta: pkixParameters.getTrustAnchors()) {
1977                 if (ta.getTrustedCert().equals(certs.get(cpLen))) {
1978                     break out;
1979                 }
1980             }
1981         }
1982         if (cpLen > 0) {
1983             CertPath cp = certificateFactory.generateCertPath(
1984                     (cpLen == certs.size())? certs: certs.subList(0, cpLen));
1985             validator.validate(cp, pkixParameters);
1986         }
1987     }
1988 
1989     char[] getPass(String prompt) {
1990         System.err.print(prompt);
1991         System.err.flush();
1992         try {
1993             char[] pass = Password.readPassword(System.in);
1994 
1995             if (pass == null) {
1996                 error(rb.getString("you.must.enter.key.password"));
1997             } else {
1998                 return pass;
1999             }
2000         } catch (IOException ioe) {
2001             error(rb.getString("unable.to.read.password.")+ioe.getMessage());
2002         }
2003         // this shouldn't happen
2004         return null;
2005     }
2006 }