jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java
changeset 34382 5d11306d6969
parent 33872 94e3836950ec
child 39633 9dc7586be5f0
--- a/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java	Wed Dec 02 16:44:54 2015 +0800
+++ b/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java	Wed Dec 02 16:44:57 2015 +0800
@@ -150,6 +150,7 @@
     private Date expireDate = new Date(0L);     // used in noTimestamp warning
 
     // Severe warnings
+    private int weakAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg
     private boolean hasExpiredCert = false;
     private boolean notYetValidCert = false;
     private boolean chainNotValidated = false;
@@ -159,6 +160,9 @@
     private boolean badKeyUsage = false;
     private boolean badExtendedKeyUsage = false;
     private boolean badNetscapeCertType = false;
+    private boolean signerSelfSigned = false;
+
+    private Throwable chainNotValidatedReason = null;
 
     CertificateFactory certificateFactory;
     CertPathValidator validator;
@@ -243,7 +247,7 @@
 
         if (strict) {
             int exitCode = 0;
-            if (chainNotValidated || hasExpiredCert || notYetValidCert) {
+            if (weakAlg != 0 || chainNotValidated || hasExpiredCert || notYetValidCert || signerSelfSigned) {
                 exitCode |= 4;
             }
             if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) {
@@ -780,6 +784,12 @@
             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) {
                 System.out.println(rb.getString(
                       "jar.is.unsigned.signatures.missing.or.not.parsable."));
@@ -788,7 +798,7 @@
                 boolean errorAppeared = false;
                 if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
                         notYetValidCert || chainNotValidated || hasExpiredCert ||
-                        hasUnsignedEntry ||
+                        hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) ||
                         aliasNotInStore || notSignedByAlias) {
 
                     if (strict) {
@@ -803,6 +813,12 @@
                         warningAppeared = true;
                     }
 
+                    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."));
@@ -832,8 +848,9 @@
                     }
 
                     if (chainNotValidated) {
-                        System.out.println(
-                                rb.getString("This.jar.contains.entries.whose.certificate.chain.is.not.validated."));
+                        System.out.println(String.format(
+                                rb.getString("This.jar.contains.entries.whose.certificate.chain.is.not.validated.reason.1"),
+                                chainNotValidatedReason.getLocalizedMessage()));
                     }
 
                     if (notSignedByAlias) {
@@ -844,6 +861,11 @@
                     if (aliasNotInStore) {
                         System.out.println(rb.getString("This.jar.contains.signed.entries.that.s.not.signed.by.alias.in.this.keystore."));
                     }
+
+                    if (signerSelfSigned) {
+                        System.out.println(rb.getString(
+                                "This.jar.contains.entries.whose.signer.certificate.is.self.signed."));
+                    }
                 } else {
                     System.out.println(rb.getString("jar.verified."));
                 }
@@ -1074,7 +1096,25 @@
     }
 
     void signJar(String jarName, String alias)
-        throws Exception {
+            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;
 
@@ -1255,8 +1295,8 @@
             }
 
             boolean warningAppeared = false;
-            if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
-                    notYetValidCert || chainNotValidated || hasExpiredCert) {
+            if (weakAlg != 0 || badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
+                    notYetValidCert || chainNotValidated || hasExpiredCert || signerSelfSigned) {
                 if (strict) {
                     System.out.println(rb.getString("jar.signed.with.signer.errors."));
                     System.out.println();
@@ -1292,8 +1332,31 @@
                 }
 
                 if (chainNotValidated) {
+                    System.out.println(String.format(
+                            rb.getString("The.signer.s.certificate.chain.is.not.validated.reason.1"),
+                            chainNotValidatedReason.getLocalizedMessage()));
+                }
+
+                if (signerSelfSigned) {
                     System.out.println(
-                            rb.getString("The.signer.s.certificate.chain.is.not.validated."));
+                            rb.getString("The.signer.s.certificate.is.self.signed."));
+                }
+
+                if ((weakAlg & 1) == 1) {
+                    System.out.println(String.format(
+                            rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
+                            digestalg, "-digestalg"));
+                }
+
+                if ((weakAlg & 2) == 2) {
+                    System.out.println(String.format(
+                            rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
+                            sigalg, "-sigalg"));
+                }
+                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"));
                 }
             } else {
                 System.out.println(rb.getString("jar.signed."));
@@ -1377,10 +1440,15 @@
                 // No more warning, we alreay have hasExpiredCert or notYetValidCert
             } else {
                 chainNotValidated = true;
+                chainNotValidatedReason = e;
                 sb.append(tab).append(rb.getString(".CertPath.not.validated."))
                         .append(e.getLocalizedMessage()).append("]\n"); // TODO
             }
         }
+        if (certs.size() == 1
+                && KeyStoreUtil.isSelfSigned((X509Certificate)certs.get(0))) {
+            signerSelfSigned = true;
+        }
         String result = sb.toString();
         cacheForSignerInfo.put(signer, result);
         return result;
@@ -1645,12 +1713,17 @@
                 if (e.getCause() != null &&
                         (e.getCause() instanceof CertificateExpiredException ||
                         e.getCause() instanceof CertificateNotYetValidException)) {
-                    // No more warning, we alreay have hasExpiredCert or notYetValidCert
+                    // No more warning, we already have hasExpiredCert or notYetValidCert
                 } else {
                     chainNotValidated = true;
+                    chainNotValidatedReason = e;
                 }
             }
 
+            if (KeyStoreUtil.isSelfSigned(certChain[0])) {
+                signerSelfSigned = true;
+            }
+
             try {
                 if (!token && keypass == null)
                     key = store.getKey(alias, storepass);