8024302: Clarify jar verifications
8023338: Update jarsigner to encourage timestamping Reviewed-by: mullan, ahgross
This commit is contained in:
parent
132ff0eea1
commit
cccb39a270
@ -158,8 +158,13 @@ public class Main {
|
||||
private String altSignerClasspath = null;
|
||||
private ZipFile zipFile = null;
|
||||
|
||||
private boolean hasExpiredCert = false;
|
||||
// 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 notYetValidCert = false;
|
||||
private boolean chainNotValidated = false;
|
||||
private boolean notSignedByAlias = false;
|
||||
@ -258,9 +263,6 @@ public class Main {
|
||||
|
||||
if (strict) {
|
||||
int exitCode = 0;
|
||||
if (hasExpiringCert) {
|
||||
exitCode |= 2;
|
||||
}
|
||||
if (chainNotValidated || hasExpiredCert || notYetValidCert) {
|
||||
exitCode |= 4;
|
||||
}
|
||||
@ -754,14 +756,25 @@ public class Main {
|
||||
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) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
System.out.println(rb.getString("Warning."));
|
||||
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 @@ public class Main {
|
||||
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 @@ public class Main {
|
||||
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 @@ public class Main {
|
||||
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 @@ public class Main {
|
||||
tsaCert = getTsaCert(tsaAlias);
|
||||
}
|
||||
|
||||
if (tsaUrl == null && tsaCert == null) {
|
||||
noTimestamp = true;
|
||||
}
|
||||
|
||||
SignatureFile.Block block = null;
|
||||
|
||||
try {
|
||||
@ -1380,12 +1415,20 @@ public class Main {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class Main {
|
||||
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 @@ public class Main {
|
||||
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 @@ public class Main {
|
||||
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.
|
||||
|
@ -135,7 +135,10 @@ public class Resources extends java.util.ListResourceBundle {
|
||||
{".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 @@ public class Resources extends java.util.ListResourceBundle {
|
||||
"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 @@ public class Resources extends java.util.ListResourceBundle {
|
||||
"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: "},
|
||||
|
@ -239,13 +239,13 @@ public class TimestampCheck {
|
||||
" -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 @@ public class TimestampCheck {
|
||||
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 @@ public class TimestampCheck {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,6 @@ LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep "more)" | wc -l`
|
||||
# 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 -certreq -alias badchain | $KT -gencert -alias ca -validity 365 | \
|
||||
$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
|
||||
|
||||
|
@ -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 @@ fi
|
||||
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
|
||||
|
117
jdk/test/sun/security/tools/jarsigner/warnings.sh
Normal file
117
jdk/test/sun/security/tools/jarsigner/warnings.sh
Normal file
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user