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