Path: blob/master/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java
41161 views
/*1* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.tools.jarsigner;2627import java.io.*;28import java.net.UnknownHostException;29import java.security.cert.CertPathValidatorException;30import java.security.cert.PKIXBuilderParameters;31import java.util.*;32import java.util.stream.Collectors;33import java.util.zip.*;34import java.util.jar.*;35import java.net.URI;36import java.text.Collator;37import java.text.MessageFormat;38import java.security.cert.Certificate;39import java.security.cert.X509Certificate;40import java.security.cert.CertificateException;41import java.security.*;4243import java.net.SocketTimeoutException;44import java.net.URL;45import java.security.cert.CertPath;46import java.security.cert.CertificateExpiredException;47import java.security.cert.CertificateFactory;48import java.security.cert.CertificateNotYetValidException;49import java.security.cert.TrustAnchor;50import java.util.Map.Entry;5152import jdk.internal.access.JavaUtilZipFileAccess;53import jdk.internal.access.SharedSecrets;54import jdk.security.jarsigner.JarSigner;55import jdk.security.jarsigner.JarSignerException;56import sun.security.pkcs.PKCS7;57import sun.security.pkcs.SignerInfo;58import sun.security.timestamp.TimestampToken;59import sun.security.tools.KeyStoreUtil;60import sun.security.validator.Validator;61import sun.security.validator.ValidatorException;62import sun.security.x509.*;63import sun.security.util.*;646566/**67* <p>The jarsigner utility.68*69* The exit codes for the main method are:70*71* 0: success72* 1: any error that the jar cannot be signed or verified, including:73* keystore loading error74* TSP communication error75* jarsigner command line error...76* otherwise: error codes from -strict77*78* @author Roland Schemers79* @author Jan Luehe80*/81public class Main {8283// for i18n84private static final java.util.ResourceBundle rb =85java.util.ResourceBundle.getBundle86("sun.security.tools.jarsigner.Resources");87private static final Collator collator = Collator.getInstance();88static {89// this is for case insensitive string comparisions90collator.setStrength(Collator.PRIMARY);91}9293private static final String NONE = "NONE";94private static final String P11KEYSTORE = "PKCS11";9596private static final long SIX_MONTHS = 180*24*60*60*1000L; //milliseconds97private static final long ONE_YEAR = 366*24*60*60*1000L;9899private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK =100new DisabledAlgorithmConstraints(101DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);102103private static final DisabledAlgorithmConstraints CERTPATH_DISABLED_CHECK =104new DisabledAlgorithmConstraints(105DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);106107private static final DisabledAlgorithmConstraints LEGACY_CHECK =108new DisabledAlgorithmConstraints(109DisabledAlgorithmConstraints.PROPERTY_SECURITY_LEGACY_ALGS);110111private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET = Collections112.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));113private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections114.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));115116private static boolean extraAttrsDetected;117118static final String VERSION = "1.0";119120static final int IN_KEYSTORE = 0x01; // signer is in keystore121static final int NOT_ALIAS = 0x04; // alias list is NOT empty and122// signer is not in alias list123static final int SIGNED_BY_ALIAS = 0x08; // signer is in alias list124125static final JavaUtilZipFileAccess JUZFA = SharedSecrets.getJavaUtilZipFileAccess();126127// Attention:128// This is the entry that get launched by the security tool jarsigner.129public static void main(String args[]) throws Exception {130Main js = new Main();131js.run(args);132}133134X509Certificate[] certChain; // signer's cert chain (when composing)135PrivateKey privateKey; // private key136KeyStore store; // the keystore specified by -keystore137// or the default keystore, never null138139String keystore; // key store file140boolean nullStream = false; // null keystore input stream (NONE)141boolean token = false; // token-based keystore142String jarfile; // jar files to sign or verify143String alias; // alias to sign jar with144List<String> ckaliases = new ArrayList<>(); // aliases in -verify145char[] storepass; // keystore password146boolean protectedPath; // protected authentication path147String storetype; // keystore type148String providerName; // provider name149List<String> providers = null; // list of provider names150List<String> providerClasses = null; // list of provider classes151// arguments for provider constructors152HashMap<String,String> providerArgs = new HashMap<>();153char[] keypass; // private key password154String sigfile; // name of .SF file155String sigalg; // name of signature algorithm156String digestalg; // name of digest algorithm157String signedjar; // output filename158String tsaUrl; // location of the Timestamping Authority159String tsaAlias; // alias for the Timestamping Authority's certificate160String altCertChain; // file to read alternative cert chain from161String tSAPolicyID;162String tSADigestAlg;163boolean verify = false; // verify the jar164String verbose = null; // verbose output when signing/verifying165boolean showcerts = false; // show certs when verifying166boolean debug = false; // debug167boolean signManifest = true; // "sign" the whole manifest168boolean externalSF = true; // leave the .SF out of the PKCS7 block169boolean strict = false; // treat warnings as error170boolean revocationCheck = false; // Revocation check flag171172// read zip entry raw bytes173private String altSignerClass = null;174private String altSignerClasspath = null;175private ZipFile zipFile = null;176177// Informational warnings178private boolean hasExpiringCert = false;179private boolean hasExpiringTsaCert = false;180private boolean noTimestamp = true;181182// Expiration date. The value could be null if signed by a trusted cert.183private Date expireDate = null;184private Date tsaExpireDate = null;185186// If there is a time stamp block inside the PKCS7 block file187boolean hasTimestampBlock = false;188189private PublicKey weakPublicKey = null;190private boolean disabledAlgFound = false;191private String legacyDigestAlg = null;192private String legacyTsaDigestAlg = null;193private String legacySigAlg = null;194195// Severe warnings.196197// jarsigner used to check signer cert chain validity and key usages198// itself and set various warnings. Later CertPath validation is199// added but chainNotValidated is only flagged when no other existing200// warnings are set. TSA cert chain check is added separately and201// only tsaChainNotValidated is set, i.e. has no affect on hasExpiredCert,202// notYetValidCert, or any badXyzUsage.203204private int legacyAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg, 8. key205private int disabledAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg, 8. key206private boolean hasExpiredCert = false;207private boolean hasExpiredTsaCert = false;208private boolean notYetValidCert = false;209private boolean chainNotValidated = false;210private boolean tsaChainNotValidated = false;211private boolean notSignedByAlias = false;212private boolean aliasNotInStore = false;213private boolean hasUnsignedEntry = false;214private boolean badKeyUsage = false;215private boolean badExtendedKeyUsage = false;216private boolean badNetscapeCertType = false;217private boolean signerSelfSigned = false;218219private Throwable chainNotValidatedReason = null;220private Throwable tsaChainNotValidatedReason = null;221222PKIXBuilderParameters pkixParameters;223Set<X509Certificate> trustedCerts = new HashSet<>();224225public void run(String args[]) {226try {227args = parseArgs(args);228229// Try to load and install the specified providers230if (providers != null) {231for (String provName: providers) {232try {233KeyStoreUtil.loadProviderByName(provName,234providerArgs.get(provName));235if (debug) {236System.out.println("loadProviderByName: " + provName);237}238} catch (IllegalArgumentException e) {239throw new Exception(String.format(rb.getString(240"provider.name.not.found"), provName));241}242}243}244245if (providerClasses != null) {246ClassLoader cl = ClassLoader.getSystemClassLoader();247for (String provClass: providerClasses) {248try {249KeyStoreUtil.loadProviderByClass(provClass,250providerArgs.get(provClass), cl);251if (debug) {252System.out.println("loadProviderByClass: " + provClass);253}254} catch (ClassCastException cce) {255throw new Exception(String.format(rb.getString(256"provclass.not.a.provider"), provClass));257} catch (IllegalArgumentException e) {258throw new Exception(String.format(rb.getString(259"provider.class.not.found"), provClass), e.getCause());260}261}262}263264if (verify) {265try {266loadKeyStore(keystore, false);267} catch (Exception e) {268if ((keystore != null) || (storepass != null)) {269System.out.println(rb.getString("jarsigner.error.") +270e.getMessage());271if (debug) {272e.printStackTrace();273}274System.exit(1);275}276}277/* if (debug) {278SignatureFileVerifier.setDebug(true);279ManifestEntryVerifier.setDebug(true);280}281*/282verifyJar(jarfile);283} else {284loadKeyStore(keystore, true);285getAliasInfo(alias);286287signJar(jarfile, alias);288}289} catch (Exception e) {290System.out.println(rb.getString("jarsigner.error.") + e);291if (debug) {292e.printStackTrace();293}294System.exit(1);295} finally {296// zero-out private key password297if (keypass != null) {298Arrays.fill(keypass, ' ');299keypass = null;300}301// zero-out keystore password302if (storepass != null) {303Arrays.fill(storepass, ' ');304storepass = null;305}306Event.clearReportListener(Event.ReporterCategory.CRLCHECK);307}308309if (strict) {310int exitCode = 0;311if (disabledAlg != 0 || chainNotValidated || hasExpiredCert312|| hasExpiredTsaCert || notYetValidCert || signerSelfSigned) {313exitCode |= 4;314}315if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) {316exitCode |= 8;317}318if (hasUnsignedEntry) {319exitCode |= 16;320}321if (notSignedByAlias || aliasNotInStore) {322exitCode |= 32;323}324if (tsaChainNotValidated) {325exitCode |= 64;326}327if (exitCode != 0) {328System.exit(exitCode);329}330}331}332333/*334* Parse command line arguments.335*/336String[] parseArgs(String args[]) throws Exception {337/* parse flags */338int n = 0;339340if (args.length == 0) fullusage();341342String confFile = null;343String command = "-sign";344for (n=0; n < args.length; n++) {345if (collator.compare(args[n], "-verify") == 0) {346command = "-verify";347} else if (collator.compare(args[n], "-conf") == 0) {348if (n == args.length - 1) {349usageNoArg();350}351confFile = args[++n];352}353}354355if (confFile != null) {356args = KeyStoreUtil.expandArgs(357"jarsigner", confFile, command, null, args);358}359360debug = Arrays.stream(args).anyMatch(361x -> collator.compare(x, "-debug") == 0);362363if (debug) {364// No need to localize debug output365System.out.println("Command line args: " +366Arrays.toString(args));367}368369for (n=0; n < args.length; n++) {370371String flags = args[n];372String modifier = null;373374if (flags.startsWith("-")) {375int pos = flags.indexOf(':');376if (pos > 0) {377modifier = flags.substring(pos+1);378flags = flags.substring(0, pos);379}380}381382if (!flags.startsWith("-")) {383if (jarfile == null) {384jarfile = flags;385} else {386alias = flags;387ckaliases.add(alias);388}389} else if (collator.compare(flags, "-conf") == 0) {390if (++n == args.length) usageNoArg();391} else if (collator.compare(flags, "-keystore") == 0) {392if (++n == args.length) usageNoArg();393keystore = args[n];394} else if (collator.compare(flags, "-storepass") ==0) {395if (++n == args.length) usageNoArg();396storepass = getPass(modifier, args[n]);397} else if (collator.compare(flags, "-storetype") ==0) {398if (++n == args.length) usageNoArg();399storetype = args[n];400} else if (collator.compare(flags, "-providerName") ==0) {401if (++n == args.length) usageNoArg();402providerName = args[n];403} else if (collator.compare(flags, "-provider") == 0 ||404collator.compare(flags, "-providerClass") == 0) {405if (++n == args.length) usageNoArg();406if (providerClasses == null) {407providerClasses = new ArrayList<>(3);408}409providerClasses.add(args[n]);410411if (args.length > (n+1)) {412flags = args[n+1];413if (collator.compare(flags, "-providerArg") == 0) {414if (args.length == (n+2)) usageNoArg();415providerArgs.put(args[n], args[n+2]);416n += 2;417}418}419} else if (collator.compare(flags, "-addprovider") == 0) {420if (++n == args.length) usageNoArg();421if (providers == null) {422providers = new ArrayList<>(3);423}424providers.add(args[n]);425426if (args.length > (n+1)) {427flags = args[n+1];428if (collator.compare(flags, "-providerArg") == 0) {429if (args.length == (n+2)) usageNoArg();430providerArgs.put(args[n], args[n+2]);431n += 2;432}433}434} else if (collator.compare(flags, "-protected") ==0) {435protectedPath = true;436} else if (collator.compare(flags, "-certchain") ==0) {437if (++n == args.length) usageNoArg();438altCertChain = args[n];439} else if (collator.compare(flags, "-tsapolicyid") ==0) {440if (++n == args.length) usageNoArg();441tSAPolicyID = args[n];442} else if (collator.compare(flags, "-tsadigestalg") ==0) {443if (++n == args.length) usageNoArg();444tSADigestAlg = args[n];445} else if (collator.compare(flags, "-debug") ==0) {446// Already processed447} else if (collator.compare(flags, "-keypass") ==0) {448if (++n == args.length) usageNoArg();449keypass = getPass(modifier, args[n]);450} else if (collator.compare(flags, "-sigfile") ==0) {451if (++n == args.length) usageNoArg();452sigfile = args[n];453} else if (collator.compare(flags, "-signedjar") ==0) {454if (++n == args.length) usageNoArg();455signedjar = args[n];456} else if (collator.compare(flags, "-tsa") ==0) {457if (++n == args.length) usageNoArg();458tsaUrl = args[n];459} else if (collator.compare(flags, "-tsacert") ==0) {460if (++n == args.length) usageNoArg();461tsaAlias = args[n];462} else if (collator.compare(flags, "-altsigner") ==0) {463if (++n == args.length) usageNoArg();464altSignerClass = args[n];465System.err.println(466rb.getString("This.option.is.forremoval") +467"-altsigner");468} else if (collator.compare(flags, "-altsignerpath") ==0) {469if (++n == args.length) usageNoArg();470altSignerClasspath = args[n];471System.err.println(472rb.getString("This.option.is.forremoval") +473"-altsignerpath");474} else if (collator.compare(flags, "-sectionsonly") ==0) {475signManifest = false;476} else if (collator.compare(flags, "-internalsf") ==0) {477externalSF = false;478} else if (collator.compare(flags, "-verify") ==0) {479verify = true;480} else if (collator.compare(flags, "-verbose") ==0) {481verbose = (modifier != null) ? modifier : "all";482} else if (collator.compare(flags, "-sigalg") ==0) {483if (++n == args.length) usageNoArg();484sigalg = args[n];485} else if (collator.compare(flags, "-digestalg") ==0) {486if (++n == args.length) usageNoArg();487digestalg = args[n];488} else if (collator.compare(flags, "-certs") ==0) {489showcerts = true;490} else if (collator.compare(flags, "-strict") ==0) {491strict = true;492} else if (collator.compare(flags, "-?") == 0 ||493collator.compare(flags, "-h") == 0 ||494collator.compare(flags, "--help") == 0 ||495// -help: legacy.496collator.compare(flags, "-help") == 0) {497fullusage();498} else if (collator.compare(flags, "-revCheck") == 0) {499revocationCheck = true;500} else {501System.err.println(502rb.getString("Illegal.option.") + flags);503usage();504}505}506507// -certs must always be specified with -verbose508if (verbose == null) showcerts = false;509510if (jarfile == null) {511System.err.println(rb.getString("Please.specify.jarfile.name"));512usage();513}514if (!verify && alias == null) {515System.err.println(rb.getString("Please.specify.alias.name"));516usage();517}518if (!verify && ckaliases.size() > 1) {519System.err.println(rb.getString("Only.one.alias.can.be.specified"));520usage();521}522523if (storetype == null) {524storetype = KeyStore.getDefaultType();525}526storetype = KeyStoreUtil.niceStoreTypeName(storetype);527528try {529if (signedjar != null && new File(signedjar).getCanonicalPath().equals(530new File(jarfile).getCanonicalPath())) {531signedjar = null;532}533} catch (IOException ioe) {534// File system error?535// Just ignore it.536}537538if (P11KEYSTORE.equalsIgnoreCase(storetype) ||539KeyStoreUtil.isWindowsKeyStore(storetype)) {540token = true;541if (keystore == null) {542keystore = NONE;543}544}545546if (NONE.equals(keystore)) {547nullStream = true;548}549550if (token && !nullStream) {551System.err.println(MessageFormat.format(rb.getString552(".keystore.must.be.NONE.if.storetype.is.{0}"), storetype));553usage();554}555556if (token && keypass != null) {557System.err.println(MessageFormat.format(rb.getString558(".keypass.can.not.be.specified.if.storetype.is.{0}"), storetype));559usage();560}561562if (protectedPath) {563if (storepass != null || keypass != null) {564System.err.println(rb.getString565("If.protected.is.specified.then.storepass.and.keypass.must.not.be.specified"));566usage();567}568}569if (KeyStoreUtil.isWindowsKeyStore(storetype)) {570if (storepass != null || keypass != null) {571System.err.println(rb.getString572("If.keystore.is.not.password.protected.then.storepass.and.keypass.must.not.be.specified"));573usage();574}575}576return args;577}578579static char[] getPass(String modifier, String arg) {580char[] output =581KeyStoreUtil.getPassWithModifier(modifier, arg, rb, collator);582if (output != null) return output;583usage();584return null; // Useless, usage() already exit585}586587static void usageNoArg() {588System.out.println(rb.getString("Option.lacks.argument"));589usage();590}591592static void usage() {593System.out.println();594System.out.println(rb.getString("Please.type.jarsigner.help.for.usage"));595System.exit(1);596}597598static void fullusage() {599System.out.println(rb.getString600("Usage.jarsigner.options.jar.file.alias"));601System.out.println(rb.getString602(".jarsigner.verify.options.jar.file.alias."));603System.out.println();604System.out.println(rb.getString605(".keystore.url.keystore.location"));606System.out.println();607System.out.println(rb.getString608(".storepass.password.password.for.keystore.integrity"));609System.out.println();610System.out.println(rb.getString611(".storetype.type.keystore.type"));612System.out.println();613System.out.println(rb.getString614(".keypass.password.password.for.private.key.if.different."));615System.out.println();616System.out.println(rb.getString617(".certchain.file.name.of.alternative.certchain.file"));618System.out.println();619System.out.println(rb.getString620(".sigfile.file.name.of.SF.DSA.file"));621System.out.println();622System.out.println(rb.getString623(".signedjar.file.name.of.signed.JAR.file"));624System.out.println();625System.out.println(rb.getString626(".digestalg.algorithm.name.of.digest.algorithm"));627System.out.println();628System.out.println(rb.getString629(".sigalg.algorithm.name.of.signature.algorithm"));630System.out.println();631System.out.println(rb.getString632(".verify.verify.a.signed.JAR.file"));633System.out.println();634System.out.println(rb.getString635(".verbose.suboptions.verbose.output.when.signing.verifying."));636System.out.println(rb.getString637(".suboptions.can.be.all.grouped.or.summary"));638System.out.println();639System.out.println(rb.getString640(".certs.display.certificates.when.verbose.and.verifying"));641System.out.println();642System.out.println(rb.getString643(".certs.revocation.check"));644System.out.println();645System.out.println(rb.getString646(".tsa.url.location.of.the.Timestamping.Authority"));647System.out.println();648System.out.println(rb.getString649(".tsacert.alias.public.key.certificate.for.Timestamping.Authority"));650System.out.println();651System.out.println(rb.getString652(".tsapolicyid.tsapolicyid.for.Timestamping.Authority"));653System.out.println();654System.out.println(rb.getString655(".tsadigestalg.algorithm.of.digest.data.in.timestamping.request"));656System.out.println();657System.out.println(rb.getString658(".altsigner.class.class.name.of.an.alternative.signing.mechanism"));659System.out.println();660System.out.println(rb.getString661(".altsignerpath.pathlist.location.of.an.alternative.signing.mechanism"));662System.out.println();663System.out.println(rb.getString664(".internalsf.include.the.SF.file.inside.the.signature.block"));665System.out.println();666System.out.println(rb.getString667(".sectionsonly.don.t.compute.hash.of.entire.manifest"));668System.out.println();669System.out.println(rb.getString670(".protected.keystore.has.protected.authentication.path"));671System.out.println();672System.out.println(rb.getString673(".providerName.name.provider.name"));674System.out.println();675System.out.println(rb.getString676(".add.provider.option"));677System.out.println(rb.getString678(".providerArg.option.1"));679System.out.println();680System.out.println(rb.getString681(".providerClass.option"));682System.out.println(rb.getString683(".providerArg.option.2"));684System.out.println();685System.out.println(rb.getString686(".strict.treat.warnings.as.errors"));687System.out.println();688System.out.println(rb.getString689(".conf.url.specify.a.pre.configured.options.file"));690System.out.println();691System.out.println(rb.getString692(".print.this.help.message"));693System.out.println();694695System.exit(0);696}697698void verifyJar(String jarName)699throws Exception700{701boolean anySigned = false; // if there exists entry inside jar signed702JarFile jf = null;703Map<String,String> digestMap = new HashMap<>();704Map<String,PKCS7> sigMap = new HashMap<>();705Map<String,String> sigNameMap = new HashMap<>();706Map<String,String> unparsableSignatures = new HashMap<>();707708try {709jf = new JarFile(jarName, true);710Vector<JarEntry> entriesVec = new Vector<>();711byte[] buffer = new byte[8192];712713String suffix1 = "-Digest-Manifest";714String suffix2 = "-Digest-" + ManifestDigester.MF_MAIN_ATTRS;715716int suffixLength1 = suffix1.length();717int suffixLength2 = suffix2.length();718719Enumeration<JarEntry> entries = jf.entries();720while (entries.hasMoreElements()) {721JarEntry je = entries.nextElement();722entriesVec.addElement(je);723try (InputStream is = jf.getInputStream(je)) {724String name = je.getName();725if (signatureRelated(name)726&& SignatureFileVerifier.isBlockOrSF(name)) {727String alias = name.substring(name.lastIndexOf('/') + 1,728name.lastIndexOf('.'));729try {730if (name.endsWith(".SF")) {731Manifest sf = new Manifest(is);732boolean found = false;733for (Object obj : sf.getMainAttributes().keySet()) {734String key = obj.toString();735if (key.endsWith(suffix1)) {736digestMap.put(alias, key.substring(7370, key.length() - suffixLength1));738found = true;739break;740} else if (key.endsWith(suffix2)) {741digestMap.put(alias, key.substring(7420, key.length() - suffixLength2));743found = true;744break;745}746}747if (!found) {748unparsableSignatures.putIfAbsent(alias,749String.format(750rb.getString("history.unparsable"),751name));752}753} else {754sigNameMap.put(alias, name);755sigMap.put(alias, new PKCS7(is));756}757} catch (IOException ioe) {758unparsableSignatures.putIfAbsent(alias, String.format(759rb.getString("history.unparsable"), name));760}761} else {762while (is.read(buffer, 0, buffer.length) != -1) {763// we just read. this will throw a SecurityException764// if a signature/digest check fails.765}766}767}768}769770Manifest man = jf.getManifest();771boolean hasSignature = false;772773// The map to record display info, only used when -verbose provided774// key: signer info string775// value: the list of files with common key776Map<String,List<String>> output = new LinkedHashMap<>();777778if (man != null) {779if (verbose != null) System.out.println();780Enumeration<JarEntry> e = entriesVec.elements();781782String tab = rb.getString("6SPACE");783784while (e.hasMoreElements()) {785JarEntry je = e.nextElement();786String name = je.getName();787788if (!extraAttrsDetected && JUZFA.getExtraAttributes(je) != -1) {789extraAttrsDetected = true;790}791hasSignature = hasSignature792|| SignatureFileVerifier.isBlockOrSF(name);793794CodeSigner[] signers = je.getCodeSigners();795boolean isSigned = (signers != null);796anySigned |= isSigned;797hasUnsignedEntry |= !je.isDirectory() && !isSigned798&& !signatureRelated(name);799800int inStoreWithAlias = inKeyStore(signers);801802boolean inStore = (inStoreWithAlias & IN_KEYSTORE) != 0;803804notSignedByAlias |= (inStoreWithAlias & NOT_ALIAS) != 0;805if (keystore != null) {806aliasNotInStore |= isSigned && !inStore;807}808809// Only used when -verbose provided810StringBuffer sb = null;811if (verbose != null) {812sb = new StringBuffer();813boolean inManifest =814((man.getAttributes(name) != null) ||815(man.getAttributes("./"+name) != null) ||816(man.getAttributes("/"+name) != null));817sb.append(isSigned ? rb.getString("s") : rb.getString("SPACE"))818.append(inManifest ? rb.getString("m") : rb.getString("SPACE"))819.append(inStore ? rb.getString("k") : rb.getString("SPACE"))820.append((inStoreWithAlias & NOT_ALIAS) != 0 ? 'X' : ' ')821.append(rb.getString("SPACE"));822sb.append('|');823}824825// When -certs provided, display info has extra empty826// lines at the beginning and end.827if (isSigned) {828if (showcerts) sb.append('\n');829for (CodeSigner signer: signers) {830// signerInfo() must be called even if -verbose831// not provided. The method updates various832// warning flags.833String si = signerInfo(signer, tab);834if (showcerts) {835sb.append(si);836sb.append('\n');837}838}839} else if (showcerts && !verbose.equals("all")) {840// Print no info for unsigned entries when -verbose:all,841// to be consistent with old behavior.842if (signatureRelated(name)) {843sb.append('\n')844.append(tab)845.append(rb846.getString(".Signature.related.entries."))847.append("\n\n");848} else {849sb.append('\n').append(tab)850.append(rb.getString(".Unsigned.entries."))851.append("\n\n");852}853}854855if (verbose != null) {856String label = sb.toString();857if (signatureRelated(name)) {858// Entries inside META-INF and other unsigned859// entries are grouped separately.860label = "-" + label;861}862863// The label finally contains 2 parts separated by '|':864// The legend displayed before the entry names, and865// the cert info (if -certs specified).866867if (!output.containsKey(label)) {868output.put(label, new ArrayList<String>());869}870871StringBuilder fb = new StringBuilder();872String s = Long.toString(je.getSize());873for (int i = 6 - s.length(); i > 0; --i) {874fb.append(' ');875}876fb.append(s).append(' ').877append(new Date(je.getTime()).toString());878fb.append(' ').append(name);879880output.get(label).add(fb.toString());881}882}883}884if (verbose != null) {885for (Entry<String,List<String>> s: output.entrySet()) {886List<String> files = s.getValue();887String key = s.getKey();888if (key.charAt(0) == '-') { // the signature-related group889key = key.substring(1);890}891int pipe = key.indexOf('|');892if (verbose.equals("all")) {893for (String f: files) {894System.out.println(key.substring(0, pipe) + f);895System.out.printf(key.substring(pipe+1));896}897} else {898if (verbose.equals("grouped")) {899for (String f: files) {900System.out.println(key.substring(0, pipe) + f);901}902} else if (verbose.equals("summary")) {903System.out.print(key.substring(0, pipe));904if (files.size() > 1) {905System.out.println(files.get(0) + " " +906String.format(rb.getString(907".and.d.more."), files.size()-1));908} else {909System.out.println(files.get(0));910}911}912System.out.printf(key.substring(pipe+1));913}914}915System.out.println();916System.out.println(rb.getString(917".s.signature.was.verified."));918System.out.println(rb.getString(919".m.entry.is.listed.in.manifest"));920System.out.println(rb.getString(921".k.at.least.one.certificate.was.found.in.keystore"));922if (ckaliases.size() > 0) {923System.out.println(rb.getString(924".X.not.signed.by.specified.alias.es."));925}926}927if (man == null) {928System.out.println();929System.out.println(rb.getString("no.manifest."));930}931932// If signer is a trusted cert or private entry in user's own933// keystore, it can be self-signed. Please note aliasNotInStore934// is always false when ~/.keystore is used.935if (!aliasNotInStore && keystore != null) {936signerSelfSigned = false;937}938939// Even if the verbose option is not specified, all out strings940// must be generated so disabledAlgFound can be updated.941if (!digestMap.isEmpty()942|| !sigMap.isEmpty()943|| !unparsableSignatures.isEmpty()) {944if (verbose != null) {945System.out.println();946}947for (String s : sigMap.keySet()) {948if (!digestMap.containsKey(s)) {949unparsableSignatures.putIfAbsent(s, String.format(950rb.getString("history.nosf"), s));951}952}953for (String s : digestMap.keySet()) {954PKCS7 p7 = sigMap.get(s);955if (p7 != null) {956String history;957try {958SignerInfo si = p7.getSignerInfos()[0];959X509Certificate signer = si.getCertificate(p7);960String digestAlg = digestMap.get(s);961String sigAlg = SignerInfo.makeSigAlg(962si.getDigestAlgorithmId(),963si.getDigestEncryptionAlgorithmId(),964si.getAuthenticatedAttributes() == null);965PublicKey key = signer.getPublicKey();966PKCS7 tsToken = si.getTsToken();967if (tsToken != null) {968hasTimestampBlock = true;969SignerInfo tsSi = tsToken.getSignerInfos()[0];970X509Certificate tsSigner = tsSi.getCertificate(tsToken);971byte[] encTsTokenInfo = tsToken.getContentInfo().getData();972TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo);973PublicKey tsKey = tsSigner.getPublicKey();974String tsDigestAlg = tsTokenInfo.getHashAlgorithm().getName();975String tsSigAlg = SignerInfo.makeSigAlg(976tsSi.getDigestAlgorithmId(),977tsSi.getDigestEncryptionAlgorithmId(),978tsSi.getAuthenticatedAttributes() == null);979Calendar c = Calendar.getInstance(980TimeZone.getTimeZone("UTC"),981Locale.getDefault(Locale.Category.FORMAT));982c.setTime(tsTokenInfo.getDate());983history = String.format(984rb.getString("history.with.ts"),985signer.getSubjectX500Principal(),986verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false),987verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false),988verifyWithWeak(key),989c,990tsSigner.getSubjectX500Principal(),991verifyWithWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET, true),992verifyWithWeak(tsSigAlg, SIG_PRIMITIVE_SET, true),993verifyWithWeak(tsKey));994} else {995history = String.format(996rb.getString("history.without.ts"),997signer.getSubjectX500Principal(),998verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false),999verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false),1000verifyWithWeak(key));1001}1002} catch (Exception e) {1003// The only usage of sigNameMap, remember the name1004// of the block file if it's invalid.1005history = String.format(1006rb.getString("history.unparsable"),1007sigNameMap.get(s));1008}1009if (verbose != null) {1010System.out.println(history);1011}1012} else {1013unparsableSignatures.putIfAbsent(s, String.format(1014rb.getString("history.nobk"), s));1015}1016}1017if (verbose != null) {1018for (String s : unparsableSignatures.keySet()) {1019System.out.println(unparsableSignatures.get(s));1020}1021}1022}1023System.out.println();10241025if (!anySigned) {1026if (disabledAlgFound) {1027if (verbose != null) {1028System.out.println(rb.getString("jar.treated.unsigned.see.weak.verbose"));1029System.out.println("\n " +1030DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS +1031"=" + Security.getProperty(DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS));1032} else {1033System.out.println(rb.getString("jar.treated.unsigned.see.weak"));1034}1035} else if (hasSignature) {1036System.out.println(rb.getString("jar.treated.unsigned"));1037} else {1038System.out.println(rb.getString("jar.is.unsigned"));1039}1040} else {1041displayMessagesAndResult(false);1042}1043return;1044} catch (Exception e) {1045System.out.println(rb.getString("jarsigner.") + e);1046if (debug) {1047e.printStackTrace();1048}1049} finally { // close the resource1050if (jf != null) {1051jf.close();1052}1053}10541055System.exit(1);1056}10571058private void displayMessagesAndResult(boolean isSigning) {1059String result;1060List<String> errors = new ArrayList<>();1061List<String> warnings = new ArrayList<>();1062List<String> info = new ArrayList<>();10631064boolean signerNotExpired = expireDate == null1065|| expireDate.after(new Date());10661067if (badKeyUsage) {1068errors.add(isSigning1069? rb.getString("The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing.")1070: rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));1071}10721073if (badExtendedKeyUsage) {1074errors.add(isSigning1075? rb.getString("The.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing.")1076: rb.getString("This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));1077}10781079if (badNetscapeCertType) {1080errors.add(isSigning1081? rb.getString("The.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing.")1082: rb.getString("This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));1083}10841085// only in verifying1086if (hasUnsignedEntry) {1087errors.add(rb.getString(1088"This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));1089}10901091if (hasExpiredCert) {1092errors.add(isSigning1093? rb.getString("The.signer.certificate.has.expired.")1094: rb.getString("This.jar.contains.entries.whose.signer.certificate.has.expired."));1095}10961097if (notYetValidCert) {1098errors.add(isSigning1099? rb.getString("The.signer.certificate.is.not.yet.valid.")1100: rb.getString("This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid."));1101}11021103if (chainNotValidated) {1104errors.add(String.format(isSigning1105? rb.getString("The.signer.s.certificate.chain.is.invalid.reason.1")1106: rb.getString("This.jar.contains.entries.whose.certificate.chain.is.invalid.reason.1"),1107chainNotValidatedReason.getLocalizedMessage()));1108}11091110if (tsaChainNotValidated) {1111errors.add(String.format(isSigning1112? rb.getString("The.tsa.certificate.chain.is.invalid.reason.1")1113: rb.getString("This.jar.contains.entries.whose.tsa.certificate.chain.is.invalid.reason.1"),1114tsaChainNotValidatedReason.getLocalizedMessage()));1115}11161117// only in verifying1118if (notSignedByAlias) {1119errors.add(1120rb.getString("This.jar.contains.signed.entries.which.is.not.signed.by.the.specified.alias.es."));1121}11221123// only in verifying1124if (aliasNotInStore) {1125errors.add(rb.getString("This.jar.contains.signed.entries.that.s.not.signed.by.alias.in.this.keystore."));1126}11271128if (signerSelfSigned) {1129errors.add(isSigning1130? rb.getString("The.signer.s.certificate.is.self.signed.")1131: rb.getString("This.jar.contains.entries.whose.signer.certificate.is.self.signed."));1132}11331134if (isSigning) {1135if ((legacyAlg & 1) == 1) {1136warnings.add(String.format(1137rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."),1138digestalg, "-digestalg"));1139}11401141if ((disabledAlg & 1) == 1) {1142errors.add(String.format(1143rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk.and.is.disabled."),1144digestalg, "-digestalg"));1145}11461147if ((legacyAlg & 2) == 2) {1148warnings.add(String.format(1149rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."),1150sigalg, "-sigalg"));1151}11521153if ((disabledAlg & 2) == 2) {1154errors.add(String.format(1155rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk.and.is.disabled."),1156sigalg, "-sigalg"));1157}11581159if ((legacyAlg & 4) == 4) {1160warnings.add(String.format(1161rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."),1162tSADigestAlg, "-tsadigestalg"));1163}11641165if ((disabledAlg & 4) == 4) {1166errors.add(String.format(1167rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk.and.is.disabled."),1168tSADigestAlg, "-tsadigestalg"));1169}11701171if ((legacyAlg & 8) == 8) {1172warnings.add(String.format(1173rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk..This.key.size.will.be.disabled.in.a.future.update."),1174privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));1175}11761177if ((disabledAlg & 8) == 8) {1178errors.add(String.format(1179rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk.and.is.disabled."),1180privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));1181}1182} else {1183if ((legacyAlg & 1) != 0) {1184warnings.add(String.format(1185rb.getString("The.digest.algorithm.1.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."),1186legacyDigestAlg));1187}11881189if ((legacyAlg & 2) == 2) {1190warnings.add(String.format(1191rb.getString("The.signature.algorithm.1.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."),1192legacySigAlg));1193}11941195if ((legacyAlg & 4) != 0) {1196warnings.add(String.format(1197rb.getString("The.timestamp.digest.algorithm.1.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."),1198legacyTsaDigestAlg));1199}12001201if ((legacyAlg & 8) == 8) {1202warnings.add(String.format(1203rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk..This.key.size.will.be.disabled.in.a.future.update."),1204weakPublicKey.getAlgorithm(), KeyUtil.getKeySize(weakPublicKey)));1205}1206}12071208// This check must be placed after all other "errors.add()" calls were done.1209if (hasExpiredTsaCert) {1210// No need to warn about expiring if already expired1211hasExpiringTsaCert = false;1212// If there are already another errors, we just say it expired.1213if (!signerNotExpired || !errors.isEmpty()) {1214errors.add(rb.getString("The.timestamp.has.expired."));1215} else if (signerNotExpired) {1216if (expireDate != null) {1217warnings.add(String.format(1218rb.getString("The.timestamp.expired.1.but.usable.2"),1219tsaExpireDate,1220expireDate));1221}1222// Reset the flag so exit code is 01223hasExpiredTsaCert = false;1224}1225}12261227if (hasExpiringCert) {1228warnings.add(isSigning1229? rb.getString("The.signer.certificate.will.expire.within.six.months.")1230: rb.getString("This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months."));1231}12321233if (hasExpiringTsaCert && expireDate != null) {1234if (expireDate.after(tsaExpireDate)) {1235warnings.add(String.format(rb.getString(1236"The.timestamp.will.expire.within.one.year.on.1.but.2"), tsaExpireDate, expireDate));1237} else {1238warnings.add(String.format(rb.getString(1239"The.timestamp.will.expire.within.one.year.on.1"), tsaExpireDate));1240}1241}12421243if (noTimestamp && expireDate != null) {1244if (hasTimestampBlock) {1245warnings.add(String.format(isSigning1246? rb.getString("invalid.timestamp.signing")1247: rb.getString("bad.timestamp.verifying"), expireDate));1248} else {1249warnings.add(String.format(isSigning1250? rb.getString("no.timestamp.signing")1251: rb.getString("no.timestamp.verifying"), expireDate));1252}1253}12541255if (extraAttrsDetected) {1256warnings.add(rb.getString("extra.attributes.detected"));1257}12581259if ((strict) && (!errors.isEmpty())) {1260result = isSigning1261? rb.getString("jar.signed.with.signer.errors.")1262: rb.getString("jar.verified.with.signer.errors.");1263} else {1264result = isSigning1265? rb.getString("jar.signed.")1266: rb.getString("jar.verified.");1267}1268System.out.println(result);12691270if (strict) {1271if (!errors.isEmpty()) {1272System.out.println();1273System.out.println(rb.getString("Error."));1274errors.forEach(System.out::println);1275}1276if (!warnings.isEmpty()) {1277System.out.println();1278System.out.println(rb.getString("Warning."));1279warnings.forEach(System.out::println);1280}1281} else {1282if (!errors.isEmpty() || !warnings.isEmpty()) {1283System.out.println();1284System.out.println(rb.getString("Warning."));1285errors.forEach(System.out::println);1286warnings.forEach(System.out::println);1287}1288}12891290if (!isSigning && (!errors.isEmpty() || !warnings.isEmpty())) {1291if (! (verbose != null && showcerts)) {1292System.out.println();1293System.out.println(rb.getString(1294"Re.run.with.the.verbose.and.certs.options.for.more.details."));1295}1296}12971298if (isSigning || verbose != null) {1299// Always print out expireDate, unless expired or expiring.1300if (!hasExpiringCert && !hasExpiredCert1301&& expireDate != null && signerNotExpired) {1302info.add(String.format(rb.getString(1303"The.signer.certificate.will.expire.on.1."), expireDate));1304}1305if (!noTimestamp) {1306if (!hasExpiringTsaCert && !hasExpiredTsaCert && tsaExpireDate != null) {1307if (signerNotExpired) {1308info.add(String.format(rb.getString(1309"The.timestamp.will.expire.on.1."), tsaExpireDate));1310} else {1311info.add(String.format(rb.getString(1312"signer.cert.expired.1.but.timestamp.good.2."),1313expireDate,1314tsaExpireDate));1315}1316}1317}1318}13191320if (!info.isEmpty()) {1321System.out.println();1322info.forEach(System.out::println);1323}1324}13251326private String verifyWithWeak(String alg, Set<CryptoPrimitive> primitiveSet, boolean tsa) {1327if (JAR_DISABLED_CHECK.permits(primitiveSet, alg, null)) {1328if (LEGACY_CHECK.permits(primitiveSet, alg, null)) {1329return alg;1330} else {1331if (primitiveSet == SIG_PRIMITIVE_SET) {1332legacyAlg |= 2;1333legacySigAlg = alg;1334} else {1335if (tsa) {1336legacyAlg |= 4;1337legacyTsaDigestAlg = alg;1338} else {1339legacyAlg |= 1;1340legacyDigestAlg = alg;1341}1342}1343return String.format(rb.getString("with.weak"), alg);1344}1345} else {1346disabledAlgFound = true;1347return String.format(rb.getString("with.disabled"), alg);1348}1349}13501351private String verifyWithWeak(PublicKey key) {1352int kLen = KeyUtil.getKeySize(key);1353if (JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {1354if (LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) {1355if (kLen >= 0) {1356return String.format(rb.getString("key.bit"), kLen);1357} else {1358return rb.getString("unknown.size");1359}1360} else {1361weakPublicKey = key;1362legacyAlg |= 8;1363return String.format(rb.getString("key.bit.weak"), kLen);1364}1365} else {1366disabledAlgFound = true;1367return String.format(rb.getString("key.bit.disabled"), kLen);1368}1369}13701371private void checkWeakSign(String alg, Set<CryptoPrimitive> primitiveSet, boolean tsa) {1372if (JAR_DISABLED_CHECK.permits(primitiveSet, alg, null)) {1373if (!LEGACY_CHECK.permits(primitiveSet, alg, null)) {1374if (primitiveSet == SIG_PRIMITIVE_SET) {1375legacyAlg |= 2;1376} else {1377if (tsa) {1378legacyAlg |= 4;1379} else {1380legacyAlg |= 1;1381}1382}1383}1384} else {1385if (primitiveSet == SIG_PRIMITIVE_SET) {1386disabledAlg |= 2;1387} else {1388if (tsa) {1389disabledAlg |= 4;1390} else {1391disabledAlg |= 1;1392}1393}1394}1395}13961397private void checkWeakSign(PrivateKey key) {1398if (JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {1399if (!LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) {1400legacyAlg |= 8;1401}1402} else {1403disabledAlg |= 8;1404}1405}14061407private static String checkWeakKey(PublicKey key) {1408int kLen = KeyUtil.getKeySize(key);1409if (CERTPATH_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {1410if (LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) {1411if (kLen >= 0) {1412return String.format(rb.getString("key.bit"), kLen);1413} else {1414return rb.getString("unknown.size");1415}1416} else {1417return String.format(rb.getString("key.bit.weak"), kLen);1418}1419} else {1420return String.format(rb.getString("key.bit.disabled"), kLen);1421}1422}14231424private static String checkWeakAlg(String alg) {1425if (CERTPATH_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, alg, null)) {1426if (LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, alg, null)) {1427return alg;1428} else {1429return String.format(rb.getString("with.weak"), alg);1430}1431} else {1432return String.format(rb.getString("with.disabled"), alg);1433}1434}14351436private static MessageFormat validityTimeForm = null;1437private static MessageFormat notYetTimeForm = null;1438private static MessageFormat expiredTimeForm = null;1439private static MessageFormat expiringTimeForm = null;14401441/**1442* Returns a string about a certificate:1443*1444* [<tab>] <cert-type> [", " <subject-DN>] [" (" <keystore-entry-alias> ")"]1445* [<validity-period> | <expiry-warning>]1446* [<key-usage-warning>]1447*1448* Note: no newline character at the end.1449*1450* This method sets global flags like hasExpiringCert, hasExpiredCert,1451* notYetValidCert, badKeyUsage, badExtendedKeyUsage, badNetscapeCertType,1452* hasExpiringTsaCert, hasExpiredTsaCert.1453*1454* @param isTsCert true if c is in the TSA cert chain, false otherwise.1455* @param checkUsage true to check code signer keyUsage1456*/1457String printCert(boolean isTsCert, String tab, Certificate c,1458Date timestamp, boolean checkUsage) throws Exception {14591460StringBuilder certStr = new StringBuilder();1461String space = rb.getString("SPACE");1462X509Certificate x509Cert = null;14631464if (c instanceof X509Certificate) {1465x509Cert = (X509Certificate) c;1466certStr.append(tab).append(x509Cert.getType())1467.append(rb.getString("COMMA"))1468.append(x509Cert.getSubjectX500Principal().toString());1469} else {1470certStr.append(tab).append(c.getType());1471}14721473String alias = storeHash.get(c);1474if (alias != null) {1475certStr.append(space).append("(").append(alias).append(")");1476}14771478if (x509Cert != null) {1479PublicKey key = x509Cert.getPublicKey();1480String sigalg = x509Cert.getSigAlgName();14811482// Process the certificate in the signer's cert chain to see if1483// weak algorithms are used, and provide warnings as needed.1484if (trustedCerts.contains(x509Cert)) {1485// If the cert is trusted, only check its key size, but not its1486// signature algorithm.1487certStr.append("\n").append(tab)1488.append("Signature algorithm: ")1489.append(sigalg)1490.append(rb.getString("COMMA"))1491.append(checkWeakKey(key));14921493certStr.append("\n").append(tab).append("[");1494certStr.append(rb.getString("trusted.certificate"));1495} else {1496certStr.append("\n").append(tab)1497.append("Signature algorithm: ")1498.append(checkWeakAlg(sigalg))1499.append(rb.getString("COMMA"))1500.append(checkWeakKey(key));15011502certStr.append("\n").append(tab).append("[");15031504Date notAfter = x509Cert.getNotAfter();1505try {1506boolean printValidity = true;1507if (isTsCert) {1508if (tsaExpireDate == null || tsaExpireDate.after(notAfter)) {1509tsaExpireDate = notAfter;1510}1511} else {1512if (expireDate == null || expireDate.after(notAfter)) {1513expireDate = notAfter;1514}1515}1516if (timestamp == null) {1517x509Cert.checkValidity();1518// test if cert will expire within six months (or one year for tsa)1519long age = isTsCert ? ONE_YEAR : SIX_MONTHS;1520if (notAfter.getTime() < System.currentTimeMillis() + age) {1521if (isTsCert) {1522hasExpiringTsaCert = true;1523} else {1524hasExpiringCert = true;1525}1526if (expiringTimeForm == null) {1527expiringTimeForm = new MessageFormat(1528rb.getString("certificate.will.expire.on"));1529}1530Object[] source = {notAfter};1531certStr.append(expiringTimeForm.format(source));1532printValidity = false;1533}1534} else {1535x509Cert.checkValidity(timestamp);1536}1537if (printValidity) {1538if (validityTimeForm == null) {1539validityTimeForm = new MessageFormat(1540rb.getString("certificate.is.valid.from"));1541}1542Object[] source = {x509Cert.getNotBefore(), notAfter};1543certStr.append(validityTimeForm.format(source));1544}1545} catch (CertificateExpiredException cee) {1546if (isTsCert) {1547hasExpiredTsaCert = true;1548} else {1549hasExpiredCert = true;1550}15511552if (expiredTimeForm == null) {1553expiredTimeForm = new MessageFormat(1554rb.getString("certificate.expired.on"));1555}1556Object[] source = {notAfter};1557certStr.append(expiredTimeForm.format(source));15581559} catch (CertificateNotYetValidException cnyve) {1560if (!isTsCert) notYetValidCert = true;15611562if (notYetTimeForm == null) {1563notYetTimeForm = new MessageFormat(1564rb.getString("certificate.is.not.valid.until"));1565}1566Object[] source = {x509Cert.getNotBefore()};1567certStr.append(notYetTimeForm.format(source));1568}1569}1570certStr.append("]");15711572if (checkUsage) {1573boolean[] bad = new boolean[3];1574checkCertUsage(x509Cert, bad);1575if (bad[0] || bad[1] || bad[2]) {1576String x = "";1577if (bad[0]) {1578x ="KeyUsage";1579}1580if (bad[1]) {1581if (x.length() > 0) x = x + ", ";1582x = x + "ExtendedKeyUsage";1583}1584if (bad[2]) {1585if (x.length() > 0) x = x + ", ";1586x = x + "NetscapeCertType";1587}1588certStr.append("\n").append(tab)1589.append(MessageFormat.format(rb.getString(1590".{0}.extension.does.not.support.code.signing."), x));1591}1592}1593}1594return certStr.toString();1595}15961597private static MessageFormat signTimeForm = null;15981599private String printTimestamp(String tab, Timestamp timestamp) {16001601if (signTimeForm == null) {1602signTimeForm =1603new MessageFormat(rb.getString("entry.was.signed.on"));1604}1605Object[] source = { timestamp.getTimestamp() };16061607return new StringBuilder().append(tab).append("[")1608.append(signTimeForm.format(source)).append("]").toString();1609}16101611private Map<CodeSigner,Integer> cacheForInKS = new IdentityHashMap<>();16121613private int inKeyStoreForOneSigner(CodeSigner signer) {1614if (cacheForInKS.containsKey(signer)) {1615return cacheForInKS.get(signer);1616}16171618int result = 0;1619if (store != null) {1620try {1621List<? extends Certificate> certs =1622signer.getSignerCertPath().getCertificates();1623for (Certificate c : certs) {1624String alias = storeHash.get(c);1625if (alias == null) {1626alias = store.getCertificateAlias(c);1627if (alias != null) {1628storeHash.put(c, alias);1629}1630}1631if (alias != null) {1632result |= IN_KEYSTORE;1633}1634for (String ckalias : ckaliases) {1635if (c.equals(store.getCertificate(ckalias))) {1636result |= SIGNED_BY_ALIAS;1637// must continue with next certificate c and cannot1638// return or break outer loop because has to fill1639// storeHash for printCert1640break;1641}1642}1643}1644} catch (KeyStoreException kse) {1645// never happens, because keystore has been loaded1646}1647}1648cacheForInKS.put(signer, result);1649return result;1650}16511652/**1653* Maps certificates (as keys) to alias names associated in the keystore1654* {@link #keystore} (as values).1655*/1656Hashtable<Certificate, String> storeHash = new Hashtable<>();16571658int inKeyStore(CodeSigner[] signers) {16591660if (signers == null)1661return 0;16621663int output = 0;16641665for (CodeSigner signer: signers) {1666int result = inKeyStoreForOneSigner(signer);1667output |= result;1668}1669if (ckaliases.size() > 0 && (output & SIGNED_BY_ALIAS) == 0) {1670output |= NOT_ALIAS;1671}1672return output;1673}16741675void signJar(String jarName, String alias)1676throws Exception {16771678if (digestalg == null) {1679digestalg = JarSigner.Builder.getDefaultDigestAlgorithm();1680}1681checkWeakSign(digestalg, DIGEST_PRIMITIVE_SET, false);16821683if (tSADigestAlg == null) {1684tSADigestAlg = JarSigner.Builder.getDefaultDigestAlgorithm();1685}1686checkWeakSign(tSADigestAlg, DIGEST_PRIMITIVE_SET, true);16871688if (sigalg == null) {1689sigalg = JarSigner.Builder.getDefaultSignatureAlgorithm(privateKey);1690}1691checkWeakSign(sigalg, SIG_PRIMITIVE_SET, false);16921693checkWeakSign(privateKey);16941695boolean aliasUsed = false;1696X509Certificate tsaCert = null;16971698if (sigfile == null) {1699sigfile = alias;1700aliasUsed = true;1701}17021703if (sigfile.length() > 8) {1704sigfile = sigfile.substring(0, 8).toUpperCase(Locale.ENGLISH);1705} else {1706sigfile = sigfile.toUpperCase(Locale.ENGLISH);1707}17081709StringBuilder tmpSigFile = new StringBuilder(sigfile.length());1710for (int j = 0; j < sigfile.length(); j++) {1711char c = sigfile.charAt(j);1712if (!1713((c>= 'A' && c<= 'Z') ||1714(c>= '0' && c<= '9') ||1715(c == '-') ||1716(c == '_'))) {1717if (aliasUsed) {1718// convert illegal characters from the alias to be _'s1719c = '_';1720} else {1721throw new1722RuntimeException(rb.getString1723("signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or."));1724}1725}1726tmpSigFile.append(c);1727}17281729sigfile = tmpSigFile.toString();17301731String tmpJarName;1732if (signedjar == null) tmpJarName = jarName+".sig";1733else tmpJarName = signedjar;17341735File jarFile = new File(jarName);1736File signedJarFile = new File(tmpJarName);17371738// Open the jar (zip) file1739try {1740zipFile = new ZipFile(jarName);1741} catch (IOException ioe) {1742error(rb.getString("unable.to.open.jar.file.")+jarName, ioe);1743}17441745CertPath cp = CertificateFactory.getInstance("X.509")1746.generateCertPath(Arrays.asList(certChain));1747JarSigner.Builder builder = new JarSigner.Builder(privateKey, cp);17481749if (verbose != null) {1750builder.eventHandler((action, file) -> {1751switch (action) {1752case "signing":1753System.out.println(rb.getString(".signing.") + file);1754break;1755case "adding":1756System.out.println(rb.getString(".adding.") + file);1757break;1758case "updating":1759System.out.println(rb.getString(".updating.") + file);1760break;1761default:1762throw new IllegalArgumentException("unknown action: "1763+ action);1764}1765});1766}17671768if (digestalg != null) {1769builder.digestAlgorithm(digestalg);1770}1771if (sigalg != null) {1772builder.signatureAlgorithm(sigalg);1773}17741775URI tsaURI = null;17761777if (tsaUrl != null) {1778tsaURI = new URI(tsaUrl);1779} else if (tsaAlias != null) {1780tsaCert = getTsaCert(tsaAlias);1781tsaURI = PKCS7.getTimestampingURI(tsaCert);1782}17831784if (tsaURI != null) {1785if (verbose != null) {1786System.out.println(1787rb.getString("requesting.a.signature.timestamp"));1788if (tsaUrl != null) {1789System.out.println(rb.getString("TSA.location.") + tsaUrl);1790} else if (tsaCert != null) {1791System.out.println(rb.getString("TSA.certificate.") +1792printCert(true, "", tsaCert, null, false));1793}1794}1795builder.tsa(tsaURI);1796if (tSADigestAlg != null) {1797builder.setProperty("tsaDigestAlg", tSADigestAlg);1798}17991800if (tSAPolicyID != null) {1801builder.setProperty("tsaPolicyId", tSAPolicyID);1802}1803}18041805if (altSignerClass != null) {1806builder.setProperty("altSigner", altSignerClass);1807if (verbose != null) {1808System.out.println(1809rb.getString("using.an.alternative.signing.mechanism"));1810}1811}18121813if (altSignerClasspath != null) {1814builder.setProperty("altSignerPath", altSignerClasspath);1815}18161817builder.signerName(sigfile);18181819builder.setProperty("sectionsOnly", Boolean.toString(!signManifest));1820builder.setProperty("internalSF", Boolean.toString(!externalSF));18211822FileOutputStream fos = null;1823try {1824fos = new FileOutputStream(signedJarFile);1825} catch (IOException ioe) {1826error(rb.getString("unable.to.create.")+tmpJarName, ioe);1827}18281829Throwable failedCause = null;1830String failedMessage = null;18311832try {1833Event.setReportListener(Event.ReporterCategory.ZIPFILEATTRS,1834(t, o) -> extraAttrsDetected = true);1835builder.build().sign(zipFile, fos);1836} catch (JarSignerException e) {1837failedCause = e.getCause();1838if (failedCause instanceof SocketTimeoutException1839|| failedCause instanceof UnknownHostException) {1840// Provide a helpful message when TSA is beyond a firewall1841failedMessage = rb.getString("unable.to.sign.jar.") +1842rb.getString("no.response.from.the.Timestamping.Authority.") +1843"\n -J-Dhttp.proxyHost=<hostname>" +1844"\n -J-Dhttp.proxyPort=<portnumber>\n" +1845rb.getString("or") +1846"\n -J-Dhttps.proxyHost=<hostname> " +1847"\n -J-Dhttps.proxyPort=<portnumber> ";1848} else {1849// JarSignerException might have a null cause1850if (failedCause == null) {1851failedCause = e;1852}1853failedMessage = rb.getString("unable.to.sign.jar.") + failedCause;1854}1855} catch (Exception e) {1856failedCause = e;1857failedMessage = rb.getString("unable.to.sign.jar.") + failedCause;1858} finally {1859// close the resources1860if (zipFile != null) {1861zipFile.close();1862zipFile = null;1863}18641865if (fos != null) {1866fos.close();1867}18681869Event.clearReportListener(Event.ReporterCategory.ZIPFILEATTRS);1870}18711872if (failedCause != null) {1873signedJarFile.delete();1874error(failedMessage, failedCause);1875}18761877if (verbose != null) {1878System.out.println();1879}18801881// The JarSigner API always accepts the timestamp received.1882// We need to extract the certs from the signed jar to1883// validate it.1884try (JarFile check = new JarFile(signedJarFile)) {1885PKCS7 p7 = new PKCS7(check.getInputStream(check.getEntry(1886"META-INF/" + sigfile + "."1887+ SignatureFileVerifier.getBlockExtension(privateKey))));1888Timestamp ts = null;1889try {1890SignerInfo si = p7.getSignerInfos()[0];1891if (si.getTsToken() != null) {1892hasTimestampBlock = true;1893}1894ts = si.getTimestamp();1895} catch (Exception e) {1896tsaChainNotValidated = true;1897tsaChainNotValidatedReason = e;1898}1899// Spaces before the ">>> Signer" and other lines are different1900String result = certsAndTSInfo("", " ", Arrays.asList(certChain), ts);1901if (verbose != null) {1902System.out.println(result);1903}1904} catch (Exception e) {1905if (debug) {1906e.printStackTrace();1907}1908}19091910if (signedjar == null) {1911// attempt an atomic rename. If that fails,1912// rename the original jar file, then the signed1913// one, then delete the original.1914if (!signedJarFile.renameTo(jarFile)) {1915File origJar = new File(jarName+".orig");19161917if (jarFile.renameTo(origJar)) {1918if (signedJarFile.renameTo(jarFile)) {1919origJar.delete();1920} else {1921MessageFormat form = new MessageFormat(rb.getString1922("attempt.to.rename.signedJarFile.to.jarFile.failed"));1923Object[] source = {signedJarFile, jarFile};1924error(form.format(source));1925}1926} else {1927MessageFormat form = new MessageFormat(rb.getString1928("attempt.to.rename.jarFile.to.origJar.failed"));1929Object[] source = {jarFile, origJar};1930error(form.format(source));1931}1932}1933}1934displayMessagesAndResult(true);1935}19361937/**1938* signature-related files include:1939* . META-INF/MANIFEST.MF1940* . META-INF/SIG-*1941* . META-INF/*.SF1942* . META-INF/*.DSA1943* . META-INF/*.RSA1944* . META-INF/*.EC1945*/1946private boolean signatureRelated(String name) {1947return SignatureFileVerifier.isSigningRelated(name);1948}19491950Map<CodeSigner,String> cacheForSignerInfo = new IdentityHashMap<>();19511952/**1953* Returns a string of signer info, with a newline at the end.1954* Called by verifyJar().1955*/1956private String signerInfo(CodeSigner signer, String tab) throws Exception {1957if (cacheForSignerInfo.containsKey(signer)) {1958return cacheForSignerInfo.get(signer);1959}1960List<? extends Certificate> certs = signer.getSignerCertPath().getCertificates();1961// signing time is only displayed on verification1962Timestamp ts = signer.getTimestamp();1963String tsLine = "";1964if (ts != null) {1965tsLine = printTimestamp(tab, ts) + "\n";1966}1967// Spaces before the ">>> Signer" and other lines are the same.19681969String result = certsAndTSInfo(tab, tab, certs, ts);1970cacheForSignerInfo.put(signer, tsLine + result);1971return result;1972}19731974/**1975* Fills info on certs and timestamp into a StringBuilder, sets1976* warning flags (through printCert) and validates cert chains.1977*1978* @param tab1 spaces before the ">>> Signer" line1979* @param tab2 spaces before the other lines1980* @param certs the signer cert1981* @param ts the timestamp, can be null1982* @return the info as a string1983*/1984private String certsAndTSInfo(1985String tab1,1986String tab2,1987List<? extends Certificate> certs, Timestamp ts)1988throws Exception {19891990Date timestamp;1991if (ts != null) {1992timestamp = ts.getTimestamp();1993noTimestamp = false;1994} else {1995timestamp = null;1996}1997// display the certificate(sb). The first one is end-entity cert and1998// its KeyUsage should be checked.1999boolean first = true;2000StringBuilder sb = new StringBuilder();2001sb.append(tab1).append(rb.getString("...Signer")).append('\n');2002for (Certificate c : certs) {2003sb.append(printCert(false, tab2, c, timestamp, first));2004sb.append('\n');2005first = false;2006}2007try {2008validateCertChain(Validator.VAR_CODE_SIGNING, certs, ts);2009} catch (Exception e) {2010chainNotValidated = true;2011chainNotValidatedReason = e;2012sb.append(tab2).append(rb.getString(".Invalid.certificate.chain."))2013.append(e.getLocalizedMessage()).append("]\n");2014}2015if (ts != null) {2016sb.append(tab1).append(rb.getString("...TSA")).append('\n');2017for (Certificate c : ts.getSignerCertPath().getCertificates()) {2018sb.append(printCert(true, tab2, c, null, false));2019sb.append('\n');2020}2021try {2022validateCertChain(Validator.VAR_TSA_SERVER,2023ts.getSignerCertPath().getCertificates(), null);2024} catch (Exception e) {2025tsaChainNotValidated = true;2026tsaChainNotValidatedReason = e;2027sb.append(tab2).append(rb.getString(".Invalid.TSA.certificate.chain."))2028.append(e.getLocalizedMessage()).append("]\n");2029}2030}2031if (certs.size() == 12032&& KeyStoreUtil.isSelfSigned((X509Certificate)certs.get(0))) {2033signerSelfSigned = true;2034}20352036return sb.toString();2037}20382039void loadKeyStore(String keyStoreName, boolean prompt) {20402041if (!nullStream && keyStoreName == null) {2042keyStoreName = System.getProperty("user.home") + File.separator2043+ ".keystore";2044}20452046try {2047try {2048KeyStore caks = KeyStoreUtil.getCacertsKeyStore();2049if (caks != null) {2050Enumeration<String> aliases = caks.aliases();2051while (aliases.hasMoreElements()) {2052String a = aliases.nextElement();2053try {2054trustedCerts.add((X509Certificate)caks.getCertificate(a));2055} catch (Exception e2) {2056// ignore, when a SecretkeyEntry does not include a cert2057}2058}2059}2060} catch (Exception e) {2061// Ignore, if cacerts cannot be loaded2062}20632064if (providerName == null) {2065store = KeyStore.getInstance(storetype);2066} else {2067store = KeyStore.getInstance(storetype, providerName);2068}20692070// Get pass phrase2071// XXX need to disable echo; on UNIX, call getpass(char *prompt)Z2072// and on NT call ??2073if (token && storepass == null && !protectedPath2074&& !KeyStoreUtil.isWindowsKeyStore(storetype)) {2075storepass = getPass2076(rb.getString("Enter.Passphrase.for.keystore."));2077} else if (!token && storepass == null && prompt) {2078storepass = getPass2079(rb.getString("Enter.Passphrase.for.keystore."));2080}20812082try {2083if (nullStream) {2084store.load(null, storepass);2085} else {2086keyStoreName = keyStoreName.replace(File.separatorChar, '/');2087URL url = null;2088try {2089url = new URL(keyStoreName);2090} catch (java.net.MalformedURLException e) {2091// try as file2092url = new File(keyStoreName).toURI().toURL();2093}2094InputStream is = null;2095try {2096is = url.openStream();2097store.load(is, storepass);2098} finally {2099if (is != null) {2100is.close();2101}2102}2103}2104Enumeration<String> aliases = store.aliases();2105while (aliases.hasMoreElements()) {2106String a = aliases.nextElement();2107try {2108X509Certificate c = (X509Certificate)store.getCertificate(a);2109// Only add TrustedCertificateEntry and self-signed2110// PrivateKeyEntry2111if (store.isCertificateEntry(a) ||2112c.getSubjectX500Principal().equals(c.getIssuerX500Principal())) {2113trustedCerts.add(c);2114}2115} catch (Exception e2) {2116// ignore, when a SecretkeyEntry does not include a cert2117}2118}2119} finally {2120try {2121pkixParameters = new PKIXBuilderParameters(2122trustedCerts.stream()2123.map(c -> new TrustAnchor(c, null))2124.collect(Collectors.toSet()),2125null);21262127if (revocationCheck) {2128Security.setProperty("ocsp.enable", "true");2129System.setProperty("com.sun.security.enableCRLDP", "true");2130Event.setReportListener(Event.ReporterCategory.CRLCHECK,2131(t, o) -> System.out.println(String.format(rb.getString(t), o)));2132}2133pkixParameters.setRevocationEnabled(revocationCheck);2134} catch (InvalidAlgorithmParameterException ex) {2135// Only if tas is empty2136}2137}2138} catch (IOException ioe) {2139throw new RuntimeException(rb.getString("keystore.load.") +2140ioe.getMessage());2141} catch (java.security.cert.CertificateException ce) {2142throw new RuntimeException(rb.getString("certificate.exception.") +2143ce.getMessage());2144} catch (NoSuchProviderException pe) {2145throw new RuntimeException(rb.getString("keystore.load.") +2146pe.getMessage());2147} catch (NoSuchAlgorithmException nsae) {2148throw new RuntimeException(rb.getString("keystore.load.") +2149nsae.getMessage());2150} catch (KeyStoreException kse) {2151throw new RuntimeException2152(rb.getString("unable.to.instantiate.keystore.class.") +2153kse.getMessage());2154}2155}21562157X509Certificate getTsaCert(String alias) {21582159java.security.cert.Certificate cs = null;21602161try {2162cs = store.getCertificate(alias);2163} catch (KeyStoreException kse) {2164// this never happens, because keystore has been loaded2165}2166if (cs == null || (!(cs instanceof X509Certificate))) {2167MessageFormat form = new MessageFormat(rb.getString2168("Certificate.not.found.for.alias.alias.must.reference.a.valid.KeyStore.entry.containing.an.X.509.public.key.certificate.for.the"));2169Object[] source = {alias, alias};2170error(form.format(source));2171}2172return (X509Certificate) cs;2173}21742175/**2176* Check if userCert is designed to be a code signer2177* @param userCert the certificate to be examined2178* @param bad 3 booleans to show if the KeyUsage, ExtendedKeyUsage,2179* NetscapeCertType has codeSigning flag turned on.2180* If null, the class field badKeyUsage, badExtendedKeyUsage,2181* badNetscapeCertType will be set.2182*/2183void checkCertUsage(X509Certificate userCert, boolean[] bad) {21842185// Can act as a signer?2186// 1. if KeyUsage, then [0:digitalSignature] or2187// [1:nonRepudiation] should be true2188// 2. if ExtendedKeyUsage, then should contains ANY or CODE_SIGNING2189// 3. if NetscapeCertType, then should contains OBJECT_SIGNING2190// 1,2,3 must be true21912192if (bad != null) {2193bad[0] = bad[1] = bad[2] = false;2194}21952196boolean[] keyUsage = userCert.getKeyUsage();2197if (keyUsage != null) {2198keyUsage = Arrays.copyOf(keyUsage, 9);2199if (!keyUsage[0] && !keyUsage[1]) {2200if (bad != null) {2201bad[0] = true;2202badKeyUsage = true;2203}2204}2205}22062207try {2208List<String> xKeyUsage = userCert.getExtendedKeyUsage();2209if (xKeyUsage != null) {2210if (!xKeyUsage.contains("2.5.29.37.0") // anyExtendedKeyUsage2211&& !xKeyUsage.contains("1.3.6.1.5.5.7.3.3")) { // codeSigning2212if (bad != null) {2213bad[1] = true;2214badExtendedKeyUsage = true;2215}2216}2217}2218} catch (java.security.cert.CertificateParsingException e) {2219// shouldn't happen2220}22212222try {2223// OID_NETSCAPE_CERT_TYPE2224byte[] netscapeEx = userCert.getExtensionValue2225("2.16.840.1.113730.1.1");2226if (netscapeEx != null) {2227DerInputStream in = new DerInputStream(netscapeEx);2228byte[] encoded = in.getOctetString();2229encoded = new DerValue(encoded).getUnalignedBitString()2230.toByteArray();22312232NetscapeCertTypeExtension extn =2233new NetscapeCertTypeExtension(encoded);22342235Boolean val = extn.get(NetscapeCertTypeExtension.OBJECT_SIGNING);2236if (!val) {2237if (bad != null) {2238bad[2] = true;2239badNetscapeCertType = true;2240}2241}2242}2243} catch (IOException e) {2244//2245}2246}22472248// Called by signJar().2249void getAliasInfo(String alias) throws Exception {22502251Key key = null;22522253try {2254java.security.cert.Certificate[] cs = null;2255if (altCertChain != null) {2256try (FileInputStream fis = new FileInputStream(altCertChain)) {2257cs = CertificateFactory.getInstance("X.509").2258generateCertificates(fis).2259toArray(new Certificate[0]);2260} catch (FileNotFoundException ex) {2261error(rb.getString("File.specified.by.certchain.does.not.exist"));2262} catch (CertificateException | IOException ex) {2263error(rb.getString("Cannot.restore.certchain.from.file.specified"));2264}2265} else {2266try {2267cs = store.getCertificateChain(alias);2268} catch (KeyStoreException kse) {2269// this never happens, because keystore has been loaded2270}2271}2272if (cs == null || cs.length == 0) {2273if (altCertChain != null) {2274error(rb.getString2275("Certificate.chain.not.found.in.the.file.specified."));2276} else {2277MessageFormat form = new MessageFormat(rb.getString2278("Certificate.chain.not.found.for.alias.alias.must.reference.a.valid.KeyStore.key.entry.containing.a.private.key.and"));2279Object[] source = {alias, alias};2280error(form.format(source));2281}2282}22832284certChain = new X509Certificate[cs.length];2285for (int i=0; i<cs.length; i++) {2286if (!(cs[i] instanceof X509Certificate)) {2287error(rb.getString2288("found.non.X.509.certificate.in.signer.s.chain"));2289}2290certChain[i] = (X509Certificate)cs[i];2291}22922293try {2294if (!token && keypass == null)2295key = store.getKey(alias, storepass);2296else2297key = store.getKey(alias, keypass);2298} catch (UnrecoverableKeyException e) {2299if (token) {2300throw e;2301} else if (keypass == null) {2302// Did not work out, so prompt user for key password2303MessageFormat form = new MessageFormat(rb.getString2304("Enter.key.password.for.alias."));2305Object[] source = {alias};2306keypass = getPass(form.format(source));2307key = store.getKey(alias, keypass);2308}2309}2310} catch (NoSuchAlgorithmException e) {2311error(e.getMessage());2312} catch (UnrecoverableKeyException e) {2313error(rb.getString("unable.to.recover.key.from.keystore"));2314} catch (KeyStoreException kse) {2315// this never happens, because keystore has been loaded2316}23172318if (!(key instanceof PrivateKey)) {2319MessageFormat form = new MessageFormat(rb.getString2320("key.associated.with.alias.not.a.private.key"));2321Object[] source = {alias};2322error(form.format(source));2323} else {2324privateKey = (PrivateKey)key;2325}2326}23272328void error(String message) {2329System.out.println(rb.getString("jarsigner.")+message);2330System.exit(1);2331}233223332334void error(String message, Throwable e) {2335System.out.println(rb.getString("jarsigner.")+message);2336if (debug) {2337e.printStackTrace();2338}2339System.exit(1);2340}23412342/**2343* Validates a cert chain.2344*2345* @param parameter this might be a timestamp2346*/2347void validateCertChain(String variant, List<? extends Certificate> certs,2348Timestamp parameter)2349throws Exception {2350try {2351Validator.getInstance(Validator.TYPE_PKIX,2352variant,2353pkixParameters)2354.validate(certs.toArray(new X509Certificate[certs.size()]),2355null, parameter);2356} catch (Exception e) {2357if (debug) {2358e.printStackTrace();2359}23602361// Exception might be dismissed if another warning flag2362// is already set by printCert.23632364if (variant.equals(Validator.VAR_TSA_SERVER) &&2365e instanceof ValidatorException) {2366// Throw cause if it's CertPathValidatorException,2367if (e.getCause() != null &&2368e.getCause() instanceof CertPathValidatorException) {2369e = (Exception) e.getCause();2370Throwable t = e.getCause();2371if ((t instanceof CertificateExpiredException &&2372hasExpiredTsaCert)) {2373// we already have hasExpiredTsaCert2374return;2375}2376}2377}23782379if (variant.equals(Validator.VAR_CODE_SIGNING) &&2380e instanceof ValidatorException) {2381// Throw cause if it's CertPathValidatorException,2382if (e.getCause() != null &&2383e.getCause() instanceof CertPathValidatorException) {2384e = (Exception) e.getCause();2385Throwable t = e.getCause();2386if ((t instanceof CertificateExpiredException &&2387hasExpiredCert) ||2388(t instanceof CertificateNotYetValidException &&2389notYetValidCert)) {2390// we already have hasExpiredCert and notYetValidCert2391return;2392}2393}2394if (e instanceof ValidatorException) {2395ValidatorException ve = (ValidatorException)e;2396if (ve.getErrorType() == ValidatorException.T_EE_EXTENSIONS &&2397(badKeyUsage || badExtendedKeyUsage || badNetscapeCertType)) {2398// We already have badKeyUsage, badExtendedKeyUsage2399// and badNetscapeCertType2400return;2401}2402}2403}2404throw e;2405}2406}24072408char[] getPass(String prompt) {2409System.err.print(prompt);2410System.err.flush();2411try {2412char[] pass = Password.readPassword(System.in);24132414if (pass == null) {2415error(rb.getString("you.must.enter.key.password"));2416} else {2417return pass;2418}2419} catch (IOException ioe) {2420error(rb.getString("unable.to.read.password.")+ioe.getMessage());2421}2422// this shouldn't happen2423return null;2424}2425}242624272428