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