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