# HG changeset patch # User chegar # Date 1380894677 -3600 # Node ID 5df7062f4a68b20da09000c8e2f8b14131d77048 # Parent b420ef26d23818e55d2c57c2fe29c71d7ffbc589# Parent 5668a8abf2121e2072eb2b325f28fa893daf3e8c Merge diff -r b420ef26d238 -r 5df7062f4a68 jdk/src/share/classes/java/util/jar/JarFile.java --- a/jdk/src/share/classes/java/util/jar/JarFile.java Thu Oct 03 19:07:42 2013 +0100 +++ b/jdk/src/share/classes/java/util/jar/JarFile.java Fri Oct 04 14:51:17 2013 +0100 @@ -53,6 +53,13 @@ * or method in this class will cause a {@link NullPointerException} to be * thrown. * + * If the verify flag is on when opening a signed jar file, the content of the + * file is verified against its signature embedded inside the file. Please note + * that the verification process does not include validating the signer's + * certificate. A caller should inspect the return value of + * {@link JarEntry#getCodeSigners()} to further determine if the signature + * can be trusted. + * * @author David Connelly * @see Manifest * @see java.util.zip.ZipFile diff -r b420ef26d238 -r 5df7062f4a68 jdk/src/share/classes/sun/security/tools/jarsigner/Main.java --- a/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java Thu Oct 03 19:07:42 2013 +0100 +++ b/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java Fri Oct 04 14:51:17 2013 +0100 @@ -158,8 +158,13 @@ private String altSignerClasspath = null; private ZipFile zipFile = null; + // Informational warnings + private boolean hasExpiringCert = false; + private boolean noTimestamp = false; + private Date expireDate = new Date(0L); // used in noTimestamp warning + + // Severe warnings private boolean hasExpiredCert = false; - private boolean hasExpiringCert = false; private boolean notYetValidCert = false; private boolean chainNotValidated = false; private boolean notSignedByAlias = false; @@ -258,9 +263,6 @@ if (strict) { int exitCode = 0; - if (hasExpiringCert) { - exitCode |= 2; - } if (chainNotValidated || hasExpiredCert || notYetValidCert) { exitCode |= 4; } @@ -754,14 +756,25 @@ System.out.println(rb.getString( "jar.is.unsigned.signatures.missing.or.not.parsable.")); } else { - System.out.println(rb.getString("jar.verified.")); - if (hasUnsignedEntry || hasExpiredCert || hasExpiringCert || - badKeyUsage || badExtendedKeyUsage || badNetscapeCertType || - notYetValidCert || chainNotValidated || - aliasNotInStore || notSignedByAlias) { + boolean warningAppeared = false; + boolean errorAppeared = false; + if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType || + notYetValidCert || chainNotValidated || hasExpiredCert || + hasUnsignedEntry || + aliasNotInStore || notSignedByAlias) { - System.out.println(); - System.out.println(rb.getString("Warning.")); + if (strict) { + System.out.println(rb.getString("jar.verified.with.signer.errors.")); + System.out.println(); + System.out.println(rb.getString("Error.")); + errorAppeared = true; + } else { + System.out.println(rb.getString("jar.verified.")); + System.out.println(); + System.out.println(rb.getString("Warning.")); + warningAppeared = true; + } + if (badKeyUsage) { System.out.println( rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing.")); @@ -785,10 +798,6 @@ System.out.println(rb.getString( "This.jar.contains.entries.whose.signer.certificate.has.expired.")); } - if (hasExpiringCert) { - System.out.println(rb.getString( - "This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months.")); - } if (notYetValidCert) { System.out.println(rb.getString( "This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid.")); @@ -807,10 +816,29 @@ if (aliasNotInStore) { System.out.println(rb.getString("This.jar.contains.signed.entries.that.s.not.signed.by.alias.in.this.keystore.")); } + } else { + System.out.println(rb.getString("jar.verified.")); + } + if (hasExpiringCert || noTimestamp) { + if (!warningAppeared) { + System.out.println(); + System.out.println(rb.getString("Warning.")); + warningAppeared = true; + } + if (hasExpiringCert) { + System.out.println(rb.getString( + "This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months.")); + } + if (noTimestamp) { + System.out.println( + String.format(rb.getString("no.timestamp.verifying"), expireDate)); + } + } + if (warningAppeared || errorAppeared) { if (! (verbose != null && showcerts)) { System.out.println(); System.out.println(rb.getString( - "Re.run.with.the.verbose.and.certs.options.for.more.details.")); + "Re.run.with.the.verbose.and.certs.options.for.more.details.")); } } } @@ -870,6 +898,9 @@ try { boolean printValidity = true; if (timestamp == null) { + if (expireDate.getTime() == 0 || expireDate.after(notAfter)) { + expireDate = notAfter; + } x509Cert.checkValidity(); // test if cert will expire within six months if (notAfter.getTime() < System.currentTimeMillis() + SIX_MONTHS) { @@ -1233,6 +1264,10 @@ tsaCert = getTsaCert(tsaAlias); } + if (tsaUrl == null && tsaCert == null) { + noTimestamp = true; + } + SignatureFile.Block block = null; try { @@ -1380,12 +1415,20 @@ } } - if (hasExpiredCert || hasExpiringCert || notYetValidCert - || badKeyUsage || badExtendedKeyUsage - || badNetscapeCertType || chainNotValidated) { - System.out.println(); + boolean warningAppeared = false; + if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType || + notYetValidCert || chainNotValidated || hasExpiredCert) { + if (strict) { + System.out.println(rb.getString("jar.signed.with.signer.errors.")); + System.out.println(); + System.out.println(rb.getString("Error.")); + } else { + System.out.println(rb.getString("jar.signed.")); + System.out.println(); + System.out.println(rb.getString("Warning.")); + warningAppeared = true; + } - System.out.println(rb.getString("Warning.")); if (badKeyUsage) { System.out.println( rb.getString("The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing.")); @@ -1404,9 +1447,6 @@ if (hasExpiredCert) { System.out.println( rb.getString("The.signer.certificate.has.expired.")); - } else if (hasExpiringCert) { - System.out.println( - rb.getString("The.signer.certificate.will.expire.within.six.months.")); } else if (notYetValidCert) { System.out.println( rb.getString("The.signer.certificate.is.not.yet.valid.")); @@ -1416,6 +1456,24 @@ System.out.println( rb.getString("The.signer.s.certificate.chain.is.not.validated.")); } + } else { + System.out.println(rb.getString("jar.signed.")); + } + if (hasExpiringCert || noTimestamp) { + if (!warningAppeared) { + System.out.println(); + System.out.println(rb.getString("Warning.")); + } + + if (hasExpiringCert) { + System.out.println( + rb.getString("The.signer.certificate.will.expire.within.six.months.")); + } + + if (noTimestamp) { + System.out.println( + String.format(rb.getString("no.timestamp.signing"), expireDate)); + } } // no IOException thrown in the above try clause, so disable @@ -1502,6 +1560,7 @@ timestamp = ts.getTimestamp(); } else { timestamp = null; + noTimestamp = true; } // display the certificate(s). The first one is end-entity cert and // its KeyUsage should be checked. diff -r b420ef26d238 -r 5df7062f4a68 jdk/src/share/classes/sun/security/tools/jarsigner/Resources.java --- a/jdk/src/share/classes/sun/security/tools/jarsigner/Resources.java Thu Oct 03 19:07:42 2013 +0100 +++ b/jdk/src/share/classes/sun/security/tools/jarsigner/Resources.java Fri Oct 04 14:51:17 2013 +0100 @@ -135,7 +135,10 @@ {".Unsigned.entries.", "(Unsigned entries)"}, {"jar.is.unsigned.signatures.missing.or.not.parsable.", "jar is unsigned. (signatures missing or not parsable)"}, + {"jar.signed.", "jar signed."}, + {"jar.signed.with.signer.errors.", "jar signed, with signer errors."}, {"jar.verified.", "jar verified."}, + {"jar.verified.with.signer.errors.", "jar verified, with signer errors."}, {"jarsigner.", "jarsigner: "}, {"signature.filename.must.consist.of.the.following.characters.A.Z.0.9.or.", "signature filename must consist of the following characters: A-Z, 0-9, _ or -"}, @@ -193,6 +196,7 @@ "using an alternative signing mechanism"}, {"entry.was.signed.on", "entry was signed on {0}"}, {"Warning.", "Warning: "}, + {"Error.", "Error: "}, {"This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked.", "This jar contains unsigned entries which have not been integrity-checked. "}, {"This.jar.contains.entries.whose.signer.certificate.has.expired.", @@ -229,6 +233,10 @@ "The signer's certificate chain is not validated."}, {"This.jar.contains.entries.whose.certificate.chain.is.not.validated.", "This jar contains entries whose certificate chain is not validated."}, + {"no.timestamp.signing", + "No -tsa or -tsacert is provided and this jar is not timestamped. Without a timestamp, users may not be able to validate this jar after the signer certificate's expiration date (%1$tY-%1$tm-%1$td) or after any future revocation date."}, + {"no.timestamp.verifying", + "This jar contains signatures that does not include a timestamp. Without a timestamp, users may not be able to validate this jar after the signer certificate's expiration date (%1$tY-%1$tm-%1$td) or after any future revocation date."}, {"Unknown.password.type.", "Unknown password type: "}, {"Cannot.find.environment.variable.", "Cannot find environment variable: "}, diff -r b420ef26d238 -r 5df7062f4a68 jdk/test/sun/security/tools/jarsigner/TimestampCheck.java --- a/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java Thu Oct 03 19:07:42 2013 +0100 +++ b/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java Fri Oct 04 14:51:17 2013 +0100 @@ -239,13 +239,13 @@ " -J-Djava.security.egd=file:/dev/./urandom" + " -debug -keystore " + TSKS + " -storepass changeit" + " -tsa http://localhost:" + port + "/%d" + - " -signedjar new.jar " + JAR + " old"; + " -signedjar new_%d.jar " + JAR + " old"; } else { cmd = System.getProperty("java.home") + "/bin/jarsigner" + " -J-Djava.security.egd=file:/dev/./urandom" + " -debug -keystore " + TSKS + " -storepass changeit" + " -tsa http://localhost:" + port + "/%d" + - " -signedjar new.jar " + JAR + " old"; + " -signedjar new_%d.jar " + JAR + " old"; } try { @@ -280,7 +280,7 @@ static void jarsigner(String cmd, int path, boolean expected) throws Exception { System.err.println("Test " + path); - Process p = Runtime.getRuntime().exec(String.format(cmd, path)); + Process p = Runtime.getRuntime().exec(String.format(cmd, path, path)); BufferedReader reader = new BufferedReader( new InputStreamReader(p.getErrorStream())); while (true) { @@ -288,9 +288,25 @@ if (s == null) break; System.err.println(s); } + + // Will not see noTimestamp warning + boolean seeWarning = false; + reader = new BufferedReader( + new InputStreamReader(p.getInputStream())); + while (true) { + String s = reader.readLine(); + if (s == null) break; + System.err.println(s); + if (s.indexOf("Warning:") >= 0) { + seeWarning = true; + } + } int result = p.waitFor(); if (expected && result != 0 || !expected && result == 0) { throw new Exception("Failed"); } + if (seeWarning) { + throw new Exception("See warning"); + } } } diff -r b420ef26d238 -r 5df7062f4a68 jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh --- a/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh Thu Oct 03 19:07:42 2013 +0100 +++ b/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh Fri Oct 04 14:51:17 2013 +0100 @@ -139,7 +139,6 @@ # 16 and 32 already covered in the first part # ========================================================== -$KT -genkeypair -alias expiring -dname CN=expiring -startdate -1m $KT -genkeypair -alias expired -dname CN=expired -startdate -10m $KT -genkeypair -alias notyetvalid -dname CN=notyetvalid -startdate +1m $KT -genkeypair -alias badku -dname CN=badku -ext KU=cRLSign -validity 365 @@ -154,9 +153,6 @@ $KT -importcert -alias badchain $KT -delete -alias ca -$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar expiring -[ $? = 2 ] || exit $LINENO - $JARSIGNER -strict -keystore js.jks -storepass changeit a.jar expired [ $? = 4 ] || exit $LINENO diff -r b420ef26d238 -r 5df7062f4a68 jdk/test/sun/security/tools/jarsigner/ts.sh --- a/jdk/test/sun/security/tools/jarsigner/ts.sh Thu Oct 03 19:07:42 2013 +0100 +++ b/jdk/test/sun/security/tools/jarsigner/ts.sh Fri Oct 04 14:51:17 2013 +0100 @@ -22,7 +22,7 @@ # # @test -# @bug 6543842 6543440 6939248 8009636 +# @bug 6543842 6543440 6939248 8009636 8024302 # @summary checking response of timestamp # # @run shell/timeout=600 ts.sh @@ -53,7 +53,7 @@ JAR="${TESTJAVA}${FS}bin${FS}jar" JAVA="${TESTJAVA}${FS}bin${FS}java" JAVAC="${TESTJAVA}${FS}bin${FS}javac" -KT="${TESTJAVA}${FS}bin${FS}keytool -keystore tsks -storepass changeit -keypass changeit" +KT="${TESTJAVA}${FS}bin${FS}keytool -keystore tsks -storepass changeit -keypass changeit -validity 200" rm tsks echo Nothing > A diff -r b420ef26d238 -r 5df7062f4a68 jdk/test/sun/security/tools/jarsigner/warnings.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/tools/jarsigner/warnings.sh Fri Oct 04 14:51:17 2013 +0100 @@ -0,0 +1,117 @@ +# +# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 8024302 +# @summary Clarify jar verifications +# + +if [ "${TESTJAVA}" = "" ] ; then + JAVAC_CMD=`which javac` + TESTJAVA=`dirname $JAVAC_CMD`/.. +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + ;; + * ) + FS="/" + ;; +esac + +KS=warnings.jks +JFILE=warnings.jar + +KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit \ + -keystore $KS" +JAR=$TESTJAVA${FS}bin${FS}jar +JARSIGNER="$TESTJAVA${FS}bin${FS}jarsigner -keystore $KS -storepass changeit" + +rm $KS 2> /dev/null + +export LANG=C + +echo 12345 > file + +ERR="" + +# Normal signer expiring on 2100-01-01 +$KT -alias s1 -dname CN=s1 -genkey -startdate 2000/01/01 -validity 36525 || ERR="$ERR keytool s1," +# Cert expiring soon, informational warning +$KT -alias s2 -dname CN=s2 -genkey -validity 100 || ERR="$ERR keytool s2," +# Cert expired, severe warning +$KT -alias s3 -dname CN=s3 -genkey -startdate -200d -validity 100 || ERR="$ERR keytool s3," + +# noTimestamp is informatiional warning and includes a date +$JAR cvf $JFILE file +$JARSIGNER $JFILE s1 > output1 || ERR="$ERR jarsigner s1," +$JARSIGNER -strict $JFILE s1 >> output1 || ERR="$ERR jarsigner s1 strict," +$JARSIGNER -verify $JFILE s1 >> output1 || ERR="$ERR jarsigner s1," +$JARSIGNER -verify -strict $JFILE s1 >> output1 || ERR="$ERR jarsigner s1 strict," + +cat output1 | grep Warning || ERR="$ERR s1 warning," +cat output1 | grep Error && ERR="$ERR s1 error," +cat output1 | grep timestamp | grep 2100-01-01 || ERR="$ERR s1 timestamp," +cat output1 | grep "with signer errors" && ERR="$ERR s1 err," + +# hasExpiringCert is informatiional warning +$JAR cvf $JFILE file +$JARSIGNER $JFILE s2 > output2 || ERR="$ERR jarsigner s2," +$JARSIGNER -strict $JFILE s2 >> output2 || ERR="$ERR jarsigner s2 strict," +$JARSIGNER -verify $JFILE s2 >> output2 || ERR="$ERR jarsigner s2," +$JARSIGNER -verify -strict $JFILE s2 >> output2 || ERR="$ERR jarsigner s2 strict," + +cat output2 | grep Warning || ERR="$ERR s2 warning," +cat output2 | grep Error && ERR="$ERR s2 error," +cat output2 | grep timestamp || ERR="$ERR s2 timestamp," +cat output2 | grep "will expire" || ERR="$ERR s2 expiring," +cat output2 | grep "with signer errors" && ERR="$ERR s2 err," + +# hasExpiredCert is severe warning +$JAR cvf $JFILE file +$JARSIGNER $JFILE s3 > output3 || ERR="$ERR jarsigner s3," +$JARSIGNER -strict $JFILE s3 > output3s && ERR="$ERR jarsigner s3 strict," +$JARSIGNER -verify $JFILE s3 >> output3 || ERR="$ERR jarsigner s3," +$JARSIGNER -verify -strict $JFILE s3 >> output3s && ERR="$ERR jarsigner s3 strict," + +# warning without -strict +cat output3 | grep Warning || ERR="$ERR s3 warning," +cat output3 | grep Error && ERR="$ERR s3 error," +cat output3 | grep "with signer errors" && ERR="$ERR s3 err," + +# error with -strict +cat output3s | grep Warning || ERR="$ERR s3s warning," +cat output3s | grep Error || ERR="$ERR s3s error," +cat output3s | grep "with signer errors" || ERR="$ERR s3 err," + +if [ "$ERR" = "" ]; then + exit 0 +else + echo "ERR is $ERR" + exit 1 +fi + +