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