< prev index next >

src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java

Print this page
rev 15874 : 8163304: jarsigner -verbose -verify should print the algorithms used to sign the jar

*** 48,57 **** --- 48,60 ---- import java.security.cert.TrustAnchor; import java.util.Map.Entry; import jdk.security.jarsigner.JarSigner; import jdk.security.jarsigner.JarSignerException; + import sun.security.pkcs.PKCS7; + import sun.security.pkcs.SignerInfo; + import sun.security.timestamp.TimestampToken; import sun.security.tools.KeyStoreUtil; import sun.security.x509.*; import sun.security.util.*;
*** 85,94 **** --- 88,106 ---- private static final String NONE = "NONE"; private static final String P11KEYSTORE = "PKCS11"; private static final long SIX_MONTHS = 180*24*60*60*1000L; //milliseconds + private static final DisabledAlgorithmConstraints DISABLED_CHECK = + new DisabledAlgorithmConstraints( + DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS); + + private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET = Collections + .unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST)); + private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections + .unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); + // Attention: // This is the entry that get launched by the security tool jarsigner. public static void main(String args[]) throws Exception { Main js = new Main(); js.run(args);
*** 161,170 **** --- 173,184 ---- private boolean badNetscapeCertType = false; private boolean signerSelfSigned = false; private Throwable chainNotValidatedReason = null; + private boolean seeWeak = false; + CertificateFactory certificateFactory; CertPathValidator validator; PKIXParameters pkixParameters; public void run(String args[]) {
*** 626,655 **** void verifyJar(String jarName) throws Exception { boolean anySigned = false; // if there exists entry inside jar signed JarFile jf = null; try { jf = new JarFile(jarName, true); Vector<JarEntry> entriesVec = new Vector<>(); byte[] buffer = new byte[8192]; Enumeration<JarEntry> entries = jf.entries(); while (entries.hasMoreElements()) { JarEntry je = entries.nextElement(); entriesVec.addElement(je); ! InputStream is = null; ! try { ! is = jf.getInputStream(je); while (is.read(buffer, 0, buffer.length) != -1) { // we just read. this will throw a SecurityException // if a signature/digest check fails. } - } finally { - if (is != null) { - is.close(); } } } Manifest man = jf.getManifest(); --- 640,701 ---- void verifyJar(String jarName) throws Exception { boolean anySigned = false; // if there exists entry inside jar signed JarFile jf = null; + Map<String,String> digestMap = new HashMap<>(); + Map<String,PKCS7> sigMap = new HashMap<>(); + Map<String,String> sigNameMap = new HashMap<>(); + Map<String,String> unparsableSignatures = new HashMap<>(); try { jf = new JarFile(jarName, true); Vector<JarEntry> entriesVec = new Vector<>(); byte[] buffer = new byte[8192]; Enumeration<JarEntry> entries = jf.entries(); while (entries.hasMoreElements()) { JarEntry je = entries.nextElement(); entriesVec.addElement(je); ! try (InputStream is = jf.getInputStream(je)) { ! String name = je.getName(); ! if (signatureRelated(name) ! && SignatureFileVerifier.isBlockOrSF(name)) { ! String alias = name.substring(name.lastIndexOf('/') + 1, ! name.lastIndexOf('.')); ! try { ! if (name.endsWith(".SF")) { ! Manifest sf = new Manifest(is); ! boolean found = false; ! for (Object obj : sf.getMainAttributes().keySet()) { ! String key = obj.toString(); ! if (key.endsWith("-Digest-Manifest")) { ! digestMap.put(alias, ! key.substring(0, key.length() - 16)); ! found = true; ! break; ! } ! } ! if (!found) { ! unparsableSignatures.putIfAbsent(alias, ! String.format( ! rb.getString("history.unparsable"), ! name)); ! } ! } else { ! sigNameMap.put(alias, name); ! sigMap.put(alias, new PKCS7(is)); ! } ! } catch (IOException ioe) { ! unparsableSignatures.putIfAbsent(alias, String.format( ! rb.getString("history.unparsable"), name)); ! } ! } else { while (is.read(buffer, 0, buffer.length) != -1) { // we just read. this will throw a SecurityException // if a signature/digest check fails. } } } } Manifest man = jf.getManifest();
*** 803,825 **** ".k.at.least.one.certificate.was.found.in.keystore")); if (ckaliases.size() > 0) { System.out.println(rb.getString( ".X.not.signed.by.specified.alias.es.")); } - System.out.println(); } ! if (man == null) System.out.println(rb.getString("no.manifest.")); // If signer is a trusted cert or private entry in user's own // keystore, it can be self-signed. if (!aliasNotInStore) { signerSelfSigned = false; } if (!anySigned) { ! if (hasSignature) { System.out.println(rb.getString("jar.treated.unsigned")); } else { System.out.println(rb.getString("jar.is.unsigned")); } } else { --- 849,963 ---- ".k.at.least.one.certificate.was.found.in.keystore")); if (ckaliases.size() > 0) { System.out.println(rb.getString( ".X.not.signed.by.specified.alias.es.")); } } ! if (man == null) { ! System.out.println(); System.out.println(rb.getString("no.manifest.")); + } // If signer is a trusted cert or private entry in user's own // keystore, it can be self-signed. if (!aliasNotInStore) { signerSelfSigned = false; } + // Even if the verbose option is not specified, all out strings + // must be generated so seeWeak can be updated. + if (!digestMap.isEmpty() + || !sigMap.isEmpty() + || !unparsableSignatures.isEmpty()) { + if (verbose != null) { + System.out.println(); + } + for (String s : sigMap.keySet()) { + if (!digestMap.containsKey(s)) { + unparsableSignatures.putIfAbsent(s, String.format( + rb.getString("history.nosf"), s)); + } + } + for (String s : digestMap.keySet()) { + PKCS7 p7 = sigMap.get(s); + if (p7 != null) { + String history; + try { + SignerInfo si = p7.getSignerInfos()[0]; + X509Certificate signer = si.getCertificate(p7); + String digestAlg = digestMap.get(s); + String sigAlg = AlgorithmId.makeSigAlg( + si.getDigestAlgorithmId().getName(), + si.getDigestEncryptionAlgorithmId().getName()); + PublicKey key = signer.getPublicKey(); + PKCS7 tsToken = si.getTsToken(); + if (tsToken != null) { + SignerInfo tsSi = tsToken.getSignerInfos()[0]; + X509Certificate tsSigner = tsSi.getCertificate(tsToken); + byte[] encTsTokenInfo = tsToken.getContentInfo().getData(); + TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo); + PublicKey tsKey = tsSigner.getPublicKey(); + String tsDigestAlg = tsTokenInfo.getHashAlgorithm().getName(); + String tsSigAlg = AlgorithmId.makeSigAlg( + tsSi.getDigestAlgorithmId().getName(), + tsSi.getDigestEncryptionAlgorithmId().getName()); + Calendar c = Calendar.getInstance( + TimeZone.getTimeZone("UTC"), + Locale.getDefault(Locale.Category.FORMAT)); + c.setTime(tsTokenInfo.getDate()); + history = String.format( + rb.getString("history.with.ts"), + signer.getSubjectX500Principal(), + withWeak(digestAlg, DIGEST_PRIMITIVE_SET), + withWeak(sigAlg, SIG_PRIMITIVE_SET), + withWeak(key), + c, + tsSigner.getSubjectX500Principal(), + withWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET), + withWeak(tsSigAlg, SIG_PRIMITIVE_SET), + withWeak(tsKey)); + } else { + history = String.format( + rb.getString("history.without.ts"), + signer.getSubjectX500Principal(), + withWeak(digestAlg, DIGEST_PRIMITIVE_SET), + withWeak(sigAlg, SIG_PRIMITIVE_SET), + withWeak(key)); + } + } catch (Exception e) { + // The only usage of sigNameMap, remember the name + // of the block file if it's invalid. + history = String.format( + rb.getString("history.unparsable"), + sigNameMap.get(s)); + } + if (verbose != null) { + System.out.println(history); + } + } else { + unparsableSignatures.putIfAbsent(s, String.format( + rb.getString("history.nobk"), s)); + } + } + if (verbose != null) { + for (String s : unparsableSignatures.keySet()) { + System.out.println(unparsableSignatures.get(s)); + } + } + } + System.out.println(); if (!anySigned) { ! if (seeWeak) { ! if (verbose != null) { ! System.out.println(rb.getString("jar.treated.unsigned.see.weak.verbose")); ! System.out.println("\n " + ! DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS + ! "=" + Security.getProperty(DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS)); ! } else { ! System.out.println(rb.getString("jar.treated.unsigned.see.weak")); ! } ! } else if (hasSignature) { System.out.println(rb.getString("jar.treated.unsigned")); } else { System.out.println(rb.getString("jar.is.unsigned")); } } else {
*** 843,853 **** } if (weakAlg != 0) { // In fact, jarsigner verification did not catch this // since it has not read the JarFile content itself. ! // Everything is done with JarFile API. } if (badKeyUsage) { System.out.println( rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing.")); --- 981,993 ---- } if (weakAlg != 0) { // In fact, jarsigner verification did not catch this // since it has not read the JarFile content itself. ! // Everything is done with JarFile API. The signing ! // history (digestMap etc) will show these info and ! // print out proper warnings. } if (badKeyUsage) { System.out.println( rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
*** 934,943 **** --- 1074,1103 ---- } System.exit(1); } + private String withWeak(String alg, Set<CryptoPrimitive> primitiveSet) { + if (DISABLED_CHECK.permits(primitiveSet, alg, null)) { + return alg; + } else { + seeWeak = true; + return String.format(rb.getString("with.weak"), alg); + } + } + + private String withWeak(PublicKey key) { + if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) { + return String.format( + rb.getString("key.bit"), KeyUtil.getKeySize(key)); + } else { + seeWeak = true; + return String.format( + rb.getString("key.bit.weak"), KeyUtil.getKeySize(key)); + } + } + private static MessageFormat validityTimeForm = null; private static MessageFormat notYetTimeForm = null; private static MessageFormat expiredTimeForm = null; private static MessageFormat expiringTimeForm = null;
*** 1123,1148 **** } void signJar(String jarName, String alias) throws Exception { ! DisabledAlgorithmConstraints dac = ! new DisabledAlgorithmConstraints( ! DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS); ! ! if (digestalg != null && !dac.permits( ! Collections.singleton(CryptoPrimitive.MESSAGE_DIGEST), digestalg, null)) { weakAlg |= 1; } ! if (tSADigestAlg != null && !dac.permits( ! Collections.singleton(CryptoPrimitive.MESSAGE_DIGEST), tSADigestAlg, null)) { weakAlg |= 4; } ! if (sigalg != null && !dac.permits( ! Collections.singleton(CryptoPrimitive.SIGNATURE), sigalg, null)) { weakAlg |= 2; } boolean aliasUsed = false; X509Certificate tsaCert = null; if (sigfile == null) { --- 1283,1308 ---- } void signJar(String jarName, String alias) throws Exception { ! if (digestalg != null && !DISABLED_CHECK.permits( ! DIGEST_PRIMITIVE_SET, digestalg, null)) { weakAlg |= 1; } ! if (tSADigestAlg != null && !DISABLED_CHECK.permits( ! DIGEST_PRIMITIVE_SET, tSADigestAlg, null)) { weakAlg |= 4; } ! if (sigalg != null && !DISABLED_CHECK.permits( ! SIG_PRIMITIVE_SET , sigalg, null)) { weakAlg |= 2; } + if (!DISABLED_CHECK.permits( + SIG_PRIMITIVE_SET, privateKey)) { + weakAlg |= 8; + } boolean aliasUsed = false; X509Certificate tsaCert = null; if (sigfile == null) {
*** 1383,1392 **** --- 1543,1557 ---- if ((weakAlg & 4) == 4) { System.out.println(String.format( rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."), tSADigestAlg, "-tsadigestalg")); } + if ((weakAlg & 8) == 8) { + System.out.println(String.format( + rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk."), + privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey))); + } } else { System.out.println(rb.getString("jar.signed.")); } if (hasExpiringCert || noTimestamp) { if (!warningAppeared) {
< prev index next >