提交 439cc5ac 编写于 作者: I igerasim

8191438: jarsigner should print when a timestamp will expire

8027781: New jarsigner timestamp warning is grammatically incorrect
8159805: sun/security/tools/jarsigner/warnings/NoTimestampTest.java fails after JDK-8027781
Reviewed-by: weijun, coffeys, mullan
上级 474d3d6d
...@@ -29,6 +29,7 @@ import java.io.*; ...@@ -29,6 +29,7 @@ import java.io.*;
import java.security.cert.CertPathValidatorException; import java.security.cert.CertPathValidatorException;
import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXBuilderParameters;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.*; import java.util.zip.*;
import java.util.jar.*; import java.util.jar.*;
import java.math.BigInteger; import java.math.BigInteger;
...@@ -101,6 +102,7 @@ public class Main { ...@@ -101,6 +102,7 @@ public class Main {
private static final String P11KEYSTORE = "PKCS11"; private static final String P11KEYSTORE = "PKCS11";
private static final long SIX_MONTHS = 180*24*60*60*1000L; //milliseconds private static final long SIX_MONTHS = 180*24*60*60*1000L; //milliseconds
private static final long ONE_YEAR = 366*24*60*60*1000L;
private static final DisabledAlgorithmConstraints DISABLED_CHECK = private static final DisabledAlgorithmConstraints DISABLED_CHECK =
new DisabledAlgorithmConstraints( new DisabledAlgorithmConstraints(
...@@ -111,21 +113,21 @@ public class Main { ...@@ -111,21 +113,21 @@ public class Main {
private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections
.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); .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);
}
static final String VERSION = "1.0"; static final String VERSION = "1.0";
static final int IN_KEYSTORE = 0x01; // signer is in keystore static final int IN_KEYSTORE = 0x01; // signer is in keystore
static final int IN_SCOPE = 0x02; static final int IN_SCOPE = 0x02;
static final int NOT_ALIAS = 0x04; // alias list is NOT empty and static final int NOT_ALIAS = 0x04; // alias list is NOT empty and
// signer is not in alias list // signer is not in alias list
static final int SIGNED_BY_ALIAS = 0x08; // signer is in alias list static final int SIGNED_BY_ALIAS = 0x08; // signer is in alias list
// 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);
}
X509Certificate[] certChain; // signer's cert chain (when composing) X509Certificate[] certChain; // signer's cert chain (when composing)
PrivateKey privateKey; // private key PrivateKey privateKey; // private key
KeyStore store; // the keystore specified by -keystore KeyStore store; // the keystore specified by -keystore
...@@ -172,8 +174,16 @@ public class Main { ...@@ -172,8 +174,16 @@ public class Main {
// Informational warnings // Informational warnings
private boolean hasExpiringCert = false; private boolean hasExpiringCert = false;
private boolean noTimestamp = false; private boolean hasExpiringTsaCert = false;
private Date expireDate = new Date(0L); // used in noTimestamp warning private boolean noTimestamp = true;
// Expiration date. The value could be null if signed by a trusted cert.
private Date expireDate = null;
private Date tsaExpireDate = null;
// If there is a time stamp block inside the PKCS7 block file
boolean hasTimestampBlock = false;
// Severe warnings. // Severe warnings.
...@@ -186,6 +196,7 @@ public class Main { ...@@ -186,6 +196,7 @@ public class Main {
private int weakAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg private int weakAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg
private boolean hasExpiredCert = false; private boolean hasExpiredCert = false;
private boolean hasExpiredTsaCert = false;
private boolean notYetValidCert = false; private boolean notYetValidCert = false;
private boolean chainNotValidated = false; private boolean chainNotValidated = false;
private boolean tsaChainNotValidated = false; private boolean tsaChainNotValidated = false;
...@@ -203,6 +214,7 @@ public class Main { ...@@ -203,6 +214,7 @@ public class Main {
private boolean seeWeak = false; private boolean seeWeak = false;
PKIXBuilderParameters pkixParameters; PKIXBuilderParameters pkixParameters;
Set<X509Certificate> trustedCerts = new HashSet<>();
public void run(String args[]) { public void run(String args[]) {
try { try {
...@@ -289,8 +301,8 @@ public class Main { ...@@ -289,8 +301,8 @@ public class Main {
if (strict) { if (strict) {
int exitCode = 0; int exitCode = 0;
if (weakAlg != 0 || chainNotValidated if (weakAlg != 0 || chainNotValidated || hasExpiredCert
|| hasExpiredCert || notYetValidCert || signerSelfSigned) { || hasExpiredTsaCert || notYetValidCert || signerSelfSigned) {
exitCode |= 4; exitCode |= 4;
} }
if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) { if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) {
...@@ -825,9 +837,6 @@ public class Main { ...@@ -825,9 +837,6 @@ public class Main {
System.out.println(rb.getString("no.manifest.")); System.out.println(rb.getString("no.manifest."));
} }
// If there is a time stamp block inside the PKCS7 block file
boolean hasTimestampBlock = false;
// Even if the verbose option is not specified, all out strings // Even if the verbose option is not specified, all out strings
// must be generated so seeWeak can be updated. // must be generated so seeWeak can be updated.
if (!digestMap.isEmpty() if (!digestMap.isEmpty()
...@@ -913,8 +922,9 @@ public class Main { ...@@ -913,8 +922,9 @@ public class Main {
System.out.println(); System.out.println();
// If signer is a trusted cert or private entry in user's own // If signer is a trusted cert or private entry in user's own
// keystore, it can be self-signed. // keystore, it can be self-signed. Please note aliasNotInStore
if (!aliasNotInStore) { // is always false when ~/.keystore is used.
if (!aliasNotInStore && keystore != null) {
signerSelfSigned = false; signerSelfSigned = false;
} }
...@@ -934,130 +944,245 @@ public class Main { ...@@ -934,130 +944,245 @@ public class Main {
System.out.println(rb.getString("jar.is.unsigned")); System.out.println(rb.getString("jar.is.unsigned"));
} }
} else { } else {
boolean warningAppeared = false; displayMessagesAndResult(false);
boolean errorAppeared = false; }
if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType || return;
notYetValidCert || chainNotValidated || hasExpiredCert || } catch (Exception e) {
hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) || System.out.println(rb.getString("jarsigner.") + e);
aliasNotInStore || notSignedByAlias || tsaChainNotValidated) { if (debug) {
e.printStackTrace();
if (strict) { }
System.out.println(rb.getString("jar.verified.with.signer.errors.")); } finally { // close the resource
System.out.println(); if (jf != null) {
System.out.println(rb.getString("Error.")); jf.close();
errorAppeared = true; }
} else { }
System.out.println(rb.getString("jar.verified."));
System.out.println();
System.out.println(rb.getString("Warning."));
warningAppeared = true;
}
if (weakAlg != 0) { System.exit(1);
// 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) { private void displayMessagesAndResult(boolean isSigning) {
System.out.println( String result;
rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing.")); List<String> errors = new ArrayList<>();
} List<String> warnings = new ArrayList<>();
List<String> info = new ArrayList<>();
boolean signerNotExpired = expireDate == null
|| expireDate.after(new Date());
if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
notYetValidCert || chainNotValidated || hasExpiredCert ||
hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) ||
aliasNotInStore || notSignedByAlias ||
tsaChainNotValidated ||
(hasExpiredTsaCert && !signerNotExpired)) {
if (strict) {
result = rb.getString(isSigning
? "jar.signed.with.signer.errors."
: "jar.verified.with.signer.errors.");
} else {
result = rb.getString(isSigning
? "jar.signed."
: "jar.verified.");
}
if (badExtendedKeyUsage) { if (badKeyUsage) {
System.out.println( errors.add(rb.getString(isSigning
rb.getString("This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing.")); ? "The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."
} : "This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
}
if (badNetscapeCertType) { if (badExtendedKeyUsage) {
System.out.println( errors.add(rb.getString(isSigning
rb.getString("This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing.")); ? "The.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."
} : "This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
}
if (hasUnsignedEntry) { if (badNetscapeCertType) {
System.out.println(rb.getString( errors.add(rb.getString(isSigning
"This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked.")); ? "The.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."
} : "This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
if (hasExpiredCert) { }
System.out.println(rb.getString(
"This.jar.contains.entries.whose.signer.certificate.has.expired."));
}
if (notYetValidCert) {
System.out.println(rb.getString(
"This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid."));
}
if (chainNotValidated) { // only in verifying
System.out.println(String.format( if (hasUnsignedEntry) {
rb.getString("This.jar.contains.entries.whose.certificate.chain.is.invalid.reason.1"), errors.add(rb.getString(
chainNotValidatedReason.getLocalizedMessage())); "This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));
} }
if (hasExpiredCert) {
errors.add(rb.getString(isSigning
? "The.signer.certificate.has.expired."
: "This.jar.contains.entries.whose.signer.certificate.has.expired."));
}
if (notYetValidCert) {
errors.add(rb.getString(isSigning
? "The.signer.certificate.is.not.yet.valid."
: "This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid."));
}
if (tsaChainNotValidated) { if (chainNotValidated) {
System.out.println(String.format( errors.add(String.format(rb.getString(isSigning
rb.getString("This.jar.contains.entries.whose.tsa.certificate.chain.is.invalid.reason.1"), ? "The.signer.s.certificate.chain.is.invalid.reason.1"
tsaChainNotValidatedReason.getLocalizedMessage())); : "This.jar.contains.entries.whose.certificate.chain.is.invalid.reason.1"),
} chainNotValidatedReason.getLocalizedMessage()));
}
if (notSignedByAlias) { if (hasExpiredTsaCert) {
System.out.println( errors.add(rb.getString("The.timestamp.has.expired."));
rb.getString("This.jar.contains.signed.entries.which.is.not.signed.by.the.specified.alias.es.")); }
} if (tsaChainNotValidated) {
errors.add(String.format(rb.getString(isSigning
? "The.tsa.certificate.chain.is.invalid.reason.1"
: "This.jar.contains.entries.whose.tsa.certificate.chain.is.invalid.reason.1"),
tsaChainNotValidatedReason.getLocalizedMessage()));
}
if (aliasNotInStore) { // only in verifying
System.out.println(rb.getString("This.jar.contains.signed.entries.that.s.not.signed.by.alias.in.this.keystore.")); if (notSignedByAlias) {
} errors.add(
rb.getString("This.jar.contains.signed.entries.which.is.not.signed.by.the.specified.alias.es."));
}
if (signerSelfSigned) { // only in verifying
System.out.println(rb.getString( if (aliasNotInStore) {
"This.jar.contains.entries.whose.signer.certificate.is.self.signed.")); errors.add(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 (signerSelfSigned) {
errors.add(rb.getString(isSigning
? "The.signer.s.certificate.is.self.signed."
: "This.jar.contains.entries.whose.signer.certificate.is.self.signed."));
}
// weakAlg only detected in signing. The jar file is
// now simply treated unsigned in verifying.
if ((weakAlg & 1) == 1) {
errors.add(String.format(
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
digestalg, "-digestalg"));
}
if ((weakAlg & 2) == 2) {
errors.add(String.format(
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
sigalg, "-sigalg"));
}
if ((weakAlg & 4) == 4) {
errors.add(String.format(
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
tSADigestAlg, "-tsadigestalg"));
}
if ((weakAlg & 8) == 8) {
errors.add(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 {
result = rb.getString(isSigning ? "jar.signed." : "jar.verified.");
}
if (hasExpiredTsaCert) {
// No need to warn about expiring if already expired
hasExpiringTsaCert = false;
}
if (hasExpiringCert ||
(hasExpiringTsaCert && expireDate != null) ||
(noTimestamp && expireDate != null) ||
(hasExpiredTsaCert && signerNotExpired)) {
if (hasExpiredTsaCert && signerNotExpired) {
if (expireDate != null) {
warnings.add(String.format(
rb.getString("The.timestamp.expired.1.but.usable.2"),
tsaExpireDate,
expireDate));
} }
if (hasExpiringCert || noTimestamp) { // Reset the flag so exit code is 0
if (!warningAppeared) { hasExpiredTsaCert = false;
System.out.println(); }
System.out.println(rb.getString("Warning.")); if (hasExpiringCert) {
warningAppeared = true; warnings.add(rb.getString(isSigning
} ? "The.signer.certificate.will.expire.within.six.months."
if (hasExpiringCert) { : "This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months."));
System.out.println(rb.getString( }
"This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months.")); if (hasExpiringTsaCert && expireDate != null) {
} if (expireDate.after(tsaExpireDate)) {
if (noTimestamp) { warnings.add(String.format(rb.getString(
if (hasTimestampBlock) { "The.timestamp.will.expire.within.one.year.on.1.but.2"), tsaExpireDate, expireDate));
// JarSigner API has not seen the timestamp, } else {
// might have ignored it due to weak alg, etc. warnings.add(String.format(rb.getString(
System.out.println( "The.timestamp.will.expire.within.one.year.on.1"), tsaExpireDate));
String.format(rb.getString("bad.timestamp.verifying"), expireDate));
} else {
System.out.println(
String.format(rb.getString("no.timestamp.verifying"), expireDate));
}
}
} }
if (warningAppeared || errorAppeared) { }
if (! (verbose != null && showcerts)) { if (noTimestamp && expireDate != null) {
System.out.println(); if (hasTimestampBlock) {
System.out.println(rb.getString( warnings.add(String.format(rb.getString(isSigning
"Re.run.with.the.verbose.and.certs.options.for.more.details.")); ? "invalid.timestamp.signing"
} : "bad.timestamp.verifying"), expireDate));
} else {
warnings.add(String.format(rb.getString(isSigning
? "no.timestamp.signing"
: "no.timestamp.verifying"), expireDate));
} }
} }
return; }
} catch (Exception e) {
System.out.println(rb.getString("jarsigner.") + e); System.out.println(result);
if (debug) { if (strict) {
e.printStackTrace(); if (!errors.isEmpty()) {
System.out.println();
System.out.println(rb.getString("Error."));
errors.forEach(System.out::println);
} }
} finally { // close the resource if (!warnings.isEmpty()) {
if (jf != null) { System.out.println();
jf.close(); System.out.println(rb.getString("Warning."));
warnings.forEach(System.out::println);
}
} else {
if (!errors.isEmpty() || !warnings.isEmpty()) {
System.out.println();
System.out.println(rb.getString("Warning."));
errors.forEach(System.out::println);
warnings.forEach(System.out::println);
}
}
if (!isSigning && (!errors.isEmpty() || !warnings.isEmpty())) {
if (! (verbose != null && showcerts)) {
System.out.println();
System.out.println(rb.getString(
"Re.run.with.the.verbose.and.certs.options.for.more.details."));
} }
} }
System.exit(1); if (isSigning || verbose != null) {
// Always print out expireDate, unless expired or expiring.
if (!hasExpiringCert && !hasExpiredCert
&& expireDate != null && signerNotExpired) {
info.add(String.format(rb.getString(
"The.signer.certificate.will.expire.on.1."), expireDate));
}
if (!noTimestamp) {
if (!hasExpiringTsaCert && !hasExpiredTsaCert && tsaExpireDate != null) {
if (signerNotExpired) {
info.add(String.format(rb.getString(
"The.timestamp.will.expire.on.1."), tsaExpireDate));
} else {
info.add(String.format(rb.getString(
"signer.cert.expired.1.but.timestamp.good.2."),
expireDate,
tsaExpireDate));
}
}
}
}
if (!info.isEmpty()) {
System.out.println();
info.forEach(System.out::println);
}
} }
private String withWeak(String alg, Set<CryptoPrimitive> primitiveSet) { private String withWeak(String alg, Set<CryptoPrimitive> primitiveSet) {
...@@ -1094,8 +1219,9 @@ public class Main { ...@@ -1094,8 +1219,9 @@ public class Main {
* *
* Note: no newline character at the end. * Note: no newline character at the end.
* *
* When isTsCert is true, this method sets global flags like hasExpiredCert, * This method sets global flags like hasExpiringCert, hasExpiredCert,
* notYetValidCert, badKeyUsage, badExtendedKeyUsage, badNetscapeCertType. * notYetValidCert, badKeyUsage, badExtendedKeyUsage, badNetscapeCertType,
* hasExpiringTsaCert, hasExpiredTsaCert.
* *
* @param isTsCert true if c is in the TSA cert chain, false otherwise. * @param isTsCert true if c is in the TSA cert chain, false otherwise.
* @param checkUsage true to check code signer keyUsage * @param checkUsage true to check code signer keyUsage
...@@ -1124,55 +1250,75 @@ public class Main { ...@@ -1124,55 +1250,75 @@ public class Main {
if (x509Cert != null) { if (x509Cert != null) {
certStr.append("\n").append(tab).append("["); certStr.append("\n").append(tab).append("[");
Date notAfter = x509Cert.getNotAfter();
try { if (trustedCerts.contains(x509Cert)) {
boolean printValidity = true; certStr.append(rb.getString("trusted.certificate"));
if (timestamp == null) { } else {
if (expireDate.getTime() == 0 || expireDate.after(notAfter)) { Date notAfter = x509Cert.getNotAfter();
expireDate = notAfter; try {
boolean printValidity = true;
if (isTsCert) {
if (tsaExpireDate == null || tsaExpireDate.after(notAfter)) {
tsaExpireDate = notAfter;
}
} else {
if (expireDate == null || expireDate.after(notAfter)) {
expireDate = notAfter;
}
} }
x509Cert.checkValidity(); if (timestamp == null) {
// test if cert will expire within six months x509Cert.checkValidity();
if (notAfter.getTime() < System.currentTimeMillis() + SIX_MONTHS) { // test if cert will expire within six months (or one year for tsa)
if (!isTsCert) hasExpiringCert = true; long age = isTsCert ? ONE_YEAR : SIX_MONTHS;
if (expiringTimeForm == null) { if (notAfter.getTime() < System.currentTimeMillis() + age) {
expiringTimeForm = new MessageFormat( if (isTsCert) {
rb.getString("certificate.will.expire.on")); hasExpiringTsaCert = true;
} else {
hasExpiringCert = true;
}
if (expiringTimeForm == null) {
expiringTimeForm = new MessageFormat(
rb.getString("certificate.will.expire.on"));
}
Object[] source = {notAfter};
certStr.append(expiringTimeForm.format(source));
printValidity = false;
} }
Object[] source = { notAfter }; } else {
certStr.append(expiringTimeForm.format(source)); x509Cert.checkValidity(timestamp);
printValidity = false;
} }
} else { if (printValidity) {
x509Cert.checkValidity(timestamp); if (validityTimeForm == null) {
} validityTimeForm = new MessageFormat(
if (printValidity) { rb.getString("certificate.is.valid.from"));
if (validityTimeForm == null) { }
validityTimeForm = new MessageFormat( Object[] source = {x509Cert.getNotBefore(), notAfter};
rb.getString("certificate.is.valid.from")); certStr.append(validityTimeForm.format(source));
}
} catch (CertificateExpiredException cee) {
if (isTsCert) {
hasExpiredTsaCert = true;
} else {
hasExpiredCert = true;
} }
Object[] source = { x509Cert.getNotBefore(), notAfter };
certStr.append(validityTimeForm.format(source));
}
} catch (CertificateExpiredException cee) {
if (!isTsCert) hasExpiredCert = true;
if (expiredTimeForm == null) { if (expiredTimeForm == null) {
expiredTimeForm = new MessageFormat( expiredTimeForm = new MessageFormat(
rb.getString("certificate.expired.on")); rb.getString("certificate.expired.on"));
} }
Object[] source = { notAfter }; Object[] source = {notAfter};
certStr.append(expiredTimeForm.format(source)); certStr.append(expiredTimeForm.format(source));
} catch (CertificateNotYetValidException cnyve) { } catch (CertificateNotYetValidException cnyve) {
if (!isTsCert) notYetValidCert = true; if (!isTsCert) notYetValidCert = true;
if (notYetTimeForm == null) { if (notYetTimeForm == null) {
notYetTimeForm = new MessageFormat( notYetTimeForm = new MessageFormat(
rb.getString("certificate.is.not.valid.until")); rb.getString("certificate.is.not.valid.until"));
}
Object[] source = {x509Cert.getNotBefore()};
certStr.append(notYetTimeForm.format(source));
} }
Object[] source = { x509Cert.getNotBefore() };
certStr.append(notYetTimeForm.format(source));
} }
certStr.append("]"); certStr.append("]");
...@@ -1638,152 +1784,57 @@ public class Main { ...@@ -1638,152 +1784,57 @@ public class Main {
// The JarSigner API always accepts the timestamp received. // The JarSigner API always accepts the timestamp received.
// We need to extract the certs from the signed jar to // We need to extract the certs from the signed jar to
// validate it. // validate it.
if (!noTimestamp) { try (JarFile check = new JarFile(signedJarFile)) {
try (JarFile check = new JarFile(signedJarFile)) { PKCS7 p7 = new PKCS7(check.getInputStream(check.getEntry(
PKCS7 p7 = new PKCS7(check.getInputStream(check.getEntry( "META-INF/" + sigfile + "." + privateKey.getAlgorithm())));
"META-INF/" + sigfile + "." + privateKey.getAlgorithm()))); Timestamp ts = null;
try {
SignerInfo si = p7.getSignerInfos()[0]; SignerInfo si = p7.getSignerInfos()[0];
PKCS7 tsToken = si.getTsToken(); if (si.getTsToken() != null) {
SignerInfo tsSi = tsToken.getSignerInfos()[0]; hasTimestampBlock = true;
try {
validateCertChain(Validator.VAR_TSA_SERVER,
tsSi.getCertificateChain(tsToken), null);
} catch (Exception e) {
tsaChainNotValidated = true;
tsaChainNotValidatedReason = e;
} }
ts = si.getTimestamp();
} catch (Exception e) { } catch (Exception e) {
if (debug) { tsaChainNotValidated = true;
e.printStackTrace(); tsaChainNotValidatedReason = e;
} }
// Spaces before the ">>> Signer" and other lines are different
String result = certsAndTSInfo("", " ", Arrays.asList(certChain), ts);
if (verbose != null) {
System.out.println(result);
}
} catch (Exception e) {
if (debug) {
e.printStackTrace();
} }
} }
// no IOException thrown in the follow try clause, so disable if (signedjar == null) {
// the try clause. // attempt an atomic rename. If that fails,
// try { // rename the original jar file, then the signed
if (signedjar == null) { // one, then delete the original.
// attempt an atomic rename. If that fails, if (!signedJarFile.renameTo(jarFile)) {
// rename the original jar file, then the signed File origJar = new File(jarName+".orig");
// one, then delete the original.
if (!signedJarFile.renameTo(jarFile)) {
File origJar = new File(jarName+".orig");
if (jarFile.renameTo(origJar)) { if (jarFile.renameTo(origJar)) {
if (signedJarFile.renameTo(jarFile)) { if (signedJarFile.renameTo(jarFile)) {
origJar.delete(); origJar.delete();
} else {
MessageFormat form = new MessageFormat(rb.getString
("attempt.to.rename.signedJarFile.to.jarFile.failed"));
Object[] source = {signedJarFile, jarFile};
error(form.format(source));
}
} else { } else {
MessageFormat form = new MessageFormat(rb.getString MessageFormat form = new MessageFormat(rb.getString
("attempt.to.rename.jarFile.to.origJar.failed")); ("attempt.to.rename.signedJarFile.to.jarFile.failed"));
Object[] source = {jarFile, origJar}; Object[] source = {signedJarFile, jarFile};
error(form.format(source)); error(form.format(source));
} }
}
}
boolean warningAppeared = false;
if (weakAlg != 0 || badKeyUsage || badExtendedKeyUsage
|| badNetscapeCertType || notYetValidCert
|| chainNotValidated || tsaChainNotValidated
|| hasExpiredCert || signerSelfSigned) {
if (strict) {
System.out.println(rb.getString("jar.signed.with.signer.errors."));
System.out.println();
System.out.println(rb.getString("Error."));
} else { } else {
System.out.println(rb.getString("jar.signed.")); MessageFormat form = new MessageFormat(rb.getString
System.out.println(); ("attempt.to.rename.jarFile.to.origJar.failed"));
System.out.println(rb.getString("Warning.")); Object[] source = {jarFile, origJar};
warningAppeared = true; error(form.format(source));
}
if (badKeyUsage) {
System.out.println(
rb.getString("The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
}
if (badExtendedKeyUsage) {
System.out.println(
rb.getString("The.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
}
if (badNetscapeCertType) {
System.out.println(
rb.getString("The.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
}
if (hasExpiredCert) {
System.out.println(
rb.getString("The.signer.certificate.has.expired."));
} else if (notYetValidCert) {
System.out.println(
rb.getString("The.signer.certificate.is.not.yet.valid."));
}
if (chainNotValidated) {
System.out.println(String.format(
rb.getString("The.signer.s.certificate.chain.is.invalid.reason.1"),
chainNotValidatedReason.getLocalizedMessage()));
}
if (tsaChainNotValidated) {
System.out.println(String.format(
rb.getString("The.tsa.certificate.chain.is.invalid.reason.1"),
tsaChainNotValidatedReason.getLocalizedMessage()));
}
if (signerSelfSigned) {
System.out.println(
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."));
}
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 displayMessagesAndResult(true);
// the catch clause.
// } catch(IOException ioe) {
// error(rb.getString("unable.to.sign.jar.")+ioe, ioe);
// }
} }
/** /**
...@@ -1831,31 +1882,57 @@ public class Main { ...@@ -1831,31 +1882,57 @@ public class Main {
Map<CodeSigner,String> cacheForSignerInfo = new IdentityHashMap<>(); Map<CodeSigner,String> cacheForSignerInfo = new IdentityHashMap<>();
/** /**
* Returns a string of singer info, with a newline at the end * Returns a string of signer info, with a newline at the end.
* Called by verifyJar().
*/ */
private String signerInfo(CodeSigner signer, String tab) throws Exception { private String signerInfo(CodeSigner signer, String tab) throws Exception {
if (cacheForSignerInfo.containsKey(signer)) { if (cacheForSignerInfo.containsKey(signer)) {
return cacheForSignerInfo.get(signer); return cacheForSignerInfo.get(signer);
} }
StringBuilder sb = new StringBuilder();
List<? extends Certificate> certs = signer.getSignerCertPath().getCertificates(); List<? extends Certificate> certs = signer.getSignerCertPath().getCertificates();
// display the signature timestamp, if present // signing time is only displayed on verification
Date timestamp;
Timestamp ts = signer.getTimestamp(); Timestamp ts = signer.getTimestamp();
String tsLine = "";
if (ts != null) {
tsLine = printTimestamp(tab, ts) + "\n";
}
// Spaces before the ">>> Signer" and other lines are the same.
String result = certsAndTSInfo(tab, tab, certs, ts);
cacheForSignerInfo.put(signer, tsLine + result);
return result;
}
/**
* Fills info on certs and timestamp into a StringBuilder, sets
* warning flags (through printCert) and validates cert chains.
*
* @param tab1 spaces before the ">>> Signer" line
* @param tab2 spaces before the other lines
* @param certs the signer cert
* @param ts the timestamp, can be null
* @return the info as a string
*/
private String certsAndTSInfo(
String tab1,
String tab2,
List<? extends Certificate> certs, Timestamp ts)
throws Exception {
Date timestamp;
if (ts != null) { if (ts != null) {
sb.append(printTimestamp(tab, ts));
sb.append('\n');
timestamp = ts.getTimestamp(); timestamp = ts.getTimestamp();
noTimestamp = false;
} else { } else {
timestamp = null; timestamp = null;
noTimestamp = true;
} }
// display the certificate(s). The first one is end-entity cert and // display the certificate(s). The first one is end-entity cert and
// its KeyUsage should be checked. // its KeyUsage should be checked.
boolean first = true; boolean first = true;
sb.append(tab).append(rb.getString("...Signer")).append('\n'); StringBuilder sb = new StringBuilder();
sb.append(tab1).append(rb.getString("...Signer")).append('\n');
for (Certificate c : certs) { for (Certificate c : certs) {
sb.append(printCert(false, tab, c, timestamp, first)); sb.append(printCert(false, tab2, c, timestamp, first));
sb.append('\n'); sb.append('\n');
first = false; first = false;
} }
...@@ -1864,13 +1941,13 @@ public class Main { ...@@ -1864,13 +1941,13 @@ public class Main {
} catch (Exception e) { } catch (Exception e) {
chainNotValidated = true; chainNotValidated = true;
chainNotValidatedReason = e; chainNotValidatedReason = e;
sb.append(tab).append(rb.getString(".Invalid.certificate.chain.")) sb.append(tab2).append(rb.getString(".Invalid.certificate.chain."))
.append(e.getLocalizedMessage()).append("]\n"); .append(e.getLocalizedMessage()).append("]\n");
} }
if (ts != null) { if (ts != null) {
sb.append(tab).append(rb.getString("...TSA")).append('\n'); sb.append(tab1).append(rb.getString("...TSA")).append('\n');
for (Certificate c : ts.getSignerCertPath().getCertificates()) { for (Certificate c : ts.getSignerCertPath().getCertificates()) {
sb.append(printCert(true, tab, c, timestamp, false)); sb.append(printCert(true, tab2, c, null, false));
sb.append('\n'); sb.append('\n');
} }
try { try {
...@@ -1879,7 +1956,7 @@ public class Main { ...@@ -1879,7 +1956,7 @@ public class Main {
} catch (Exception e) { } catch (Exception e) {
tsaChainNotValidated = true; tsaChainNotValidated = true;
tsaChainNotValidatedReason = e; tsaChainNotValidatedReason = e;
sb.append(tab).append(rb.getString(".Invalid.TSA.certificate.chain.")) sb.append(tab2).append(rb.getString(".Invalid.TSA.certificate.chain."))
.append(e.getLocalizedMessage()).append("]\n"); .append(e.getLocalizedMessage()).append("]\n");
} }
} }
...@@ -1887,9 +1964,8 @@ public class Main { ...@@ -1887,9 +1964,8 @@ public class Main {
&& KeyStoreUtil.isSelfSigned((X509Certificate)certs.get(0))) { && KeyStoreUtil.isSelfSigned((X509Certificate)certs.get(0))) {
signerSelfSigned = true; signerSelfSigned = true;
} }
String result = sb.toString();
cacheForSignerInfo.put(signer, result); return sb.toString();
return result;
} }
private void writeEntry(ZipFile zf, ZipOutputStream os, ZipEntry ze) private void writeEntry(ZipFile zf, ZipOutputStream os, ZipEntry ze)
...@@ -1939,7 +2015,6 @@ public class Main { ...@@ -1939,7 +2015,6 @@ public class Main {
} }
try { try {
Set<TrustAnchor> tas = new HashSet<>();
try { try {
KeyStore caks = KeyStoreUtil.getCacertsKeyStore(); KeyStore caks = KeyStoreUtil.getCacertsKeyStore();
if (caks != null) { if (caks != null) {
...@@ -1947,7 +2022,7 @@ public class Main { ...@@ -1947,7 +2022,7 @@ public class Main {
while (aliases.hasMoreElements()) { while (aliases.hasMoreElements()) {
String a = aliases.nextElement(); String a = aliases.nextElement();
try { try {
tas.add(new TrustAnchor((X509Certificate)caks.getCertificate(a), null)); trustedCerts.add((X509Certificate)caks.getCertificate(a));
} catch (Exception e2) { } catch (Exception e2) {
// ignore, when a SecretkeyEntry does not include a cert // ignore, when a SecretkeyEntry does not include a cert
} }
...@@ -2006,7 +2081,7 @@ public class Main { ...@@ -2006,7 +2081,7 @@ public class Main {
// PrivateKeyEntry // PrivateKeyEntry
if (store.isCertificateEntry(a) || if (store.isCertificateEntry(a) ||
c.getSubjectDN().equals(c.getIssuerDN())) { c.getSubjectDN().equals(c.getIssuerDN())) {
tas.add(new TrustAnchor(c, null)); trustedCerts.add(c);
} }
} catch (Exception e2) { } catch (Exception e2) {
// ignore, when a SecretkeyEntry does not include a cert // ignore, when a SecretkeyEntry does not include a cert
...@@ -2014,7 +2089,11 @@ public class Main { ...@@ -2014,7 +2089,11 @@ public class Main {
} }
} finally { } finally {
try { try {
pkixParameters = new PKIXBuilderParameters(tas, null); pkixParameters = new PKIXBuilderParameters(
trustedCerts.stream()
.map(c -> new TrustAnchor(c, null))
.collect(Collectors.toSet()),
null);
pkixParameters.setRevocationEnabled(false); pkixParameters.setRevocationEnabled(false);
} catch (InvalidAlgorithmParameterException ex) { } catch (InvalidAlgorithmParameterException ex) {
// Only if tas is empty // Only if tas is empty
...@@ -2130,6 +2209,7 @@ public class Main { ...@@ -2130,6 +2209,7 @@ public class Main {
} }
} }
// Called by signJar().
void getAliasInfo(String alias) throws Exception { void getAliasInfo(String alias) throws Exception {
Key key = null; Key key = null;
...@@ -2174,22 +2254,6 @@ public class Main { ...@@ -2174,22 +2254,6 @@ public class Main {
certChain[i] = (X509Certificate)cs[i]; certChain[i] = (X509Certificate)cs[i];
} }
// We don't meant to print anything, the next call
// checks validity and keyUsage etc
printCert(false, "", certChain[0], null, true);
try {
validateCertChain(Validator.VAR_CODE_SIGNING,
Arrays.asList(certChain), null);
} catch (Exception e) {
chainNotValidated = true;
chainNotValidatedReason = e;
}
if (KeyStoreUtil.isSelfSigned(certChain[0])) {
signerSelfSigned = true;
}
try { try {
if (!token && keypass == null) if (!token && keypass == null)
key = store.getKey(alias, storepass); key = store.getKey(alias, storepass);
...@@ -2247,7 +2311,7 @@ public class Main { ...@@ -2247,7 +2311,7 @@ public class Main {
* @param parameter this might be a timestamp * @param parameter this might be a timestamp
*/ */
void validateCertChain(String variant, List<? extends Certificate> certs, void validateCertChain(String variant, List<? extends Certificate> certs,
Object parameter) Timestamp parameter)
throws Exception { throws Exception {
try { try {
Validator.getInstance(Validator.TYPE_PKIX, Validator.getInstance(Validator.TYPE_PKIX,
...@@ -2261,8 +2325,22 @@ public class Main { ...@@ -2261,8 +2325,22 @@ public class Main {
} }
// Exception might be dismissed if another warning flag // Exception might be dismissed if another warning flag
// is already set by printCert. This is only done for // is already set by printCert.
// code signing certs.
if (variant.equals(Validator.VAR_TSA_SERVER) &&
e instanceof ValidatorException) {
// Throw cause if it's CertPathValidatorException,
if (e.getCause() != null &&
e.getCause() instanceof CertPathValidatorException) {
e = (Exception) e.getCause();
Throwable t = e.getCause();
if ((t instanceof CertificateExpiredException &&
hasExpiredTsaCert)) {
// we already have hasExpiredTsaCert
return;
}
}
}
if (variant.equals(Validator.VAR_CODE_SIGNING) && if (variant.equals(Validator.VAR_CODE_SIGNING) &&
e instanceof ValidatorException) { e instanceof ValidatorException) {
......
...@@ -219,6 +219,7 @@ public class Resources extends java.util.ListResourceBundle { ...@@ -219,6 +219,7 @@ public class Resources extends java.util.ListResourceBundle {
{"Error.", "Error: "}, {"Error.", "Error: "},
{"...Signer", ">>> Signer"}, {"...Signer", ">>> Signer"},
{"...TSA", ">>> TSA"}, {"...TSA", ">>> TSA"},
{"trusted.certificate", "trusted certificate"},
{"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 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.", {"This.jar.contains.entries.whose.signer.certificate.has.expired.",
...@@ -235,8 +236,16 @@ public class Resources extends java.util.ListResourceBundle { ...@@ -235,8 +236,16 @@ public class Resources extends java.util.ListResourceBundle {
"Re-run with the -verbose and -certs options for more details."}, "Re-run with the -verbose and -certs options for more details."},
{"The.signer.certificate.has.expired.", {"The.signer.certificate.has.expired.",
"The signer certificate has expired."}, "The signer certificate has expired."},
{"The.timestamp.expired.1.but.usable.2",
"The timestamp expired on %1$tY-%1$tm-%1$td. However, the JAR will be valid until the signer certificate expires on %2$tY-%2$tm-%2$td."},
{"The.timestamp.has.expired.",
"The timestamp has expired."},
{"The.signer.certificate.will.expire.within.six.months.", {"The.signer.certificate.will.expire.within.six.months.",
"The signer certificate will expire within six months."}, "The signer certificate will expire within six months."},
{"The.timestamp.will.expire.within.one.year.on.1",
"The timestamp will expire within one year on %1$tY-%1$tm-%1$td."},
{"The.timestamp.will.expire.within.one.year.on.1.but.2",
"The timestamp will expire within one year on %1$tY-%1$tm-%1$td. However, the JAR will be valid until the signer certificate expires on %2$tY-%2$tm-%2$td."},
{"The.signer.certificate.is.not.yet.valid.", {"The.signer.certificate.is.not.yet.valid.",
"The signer certificate is not yet valid."}, "The signer certificate is not yet valid."},
{"The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing.", {"The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing.",
...@@ -267,10 +276,18 @@ public class Resources extends java.util.ListResourceBundle { ...@@ -267,10 +276,18 @@ public class Resources extends java.util.ListResourceBundle {
"This jar contains entries whose TSA certificate chain is invalid. Reason: %s"}, "This jar contains entries whose TSA certificate chain is invalid. Reason: %s"},
{"no.timestamp.signing", {"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 -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."},
{"invalid.timestamp.signing",
"The timestamp is invalid. Without a valid timestamp, users may not be able to validate this jar after the signer certificate's expiration date (%1$tY-%1$tm-%1$td)."},
{"no.timestamp.verifying", {"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."}, "This jar contains signatures that do not include a timestamp. Without a timestamp, users may not be able to validate this jar after any of the signer certificates expire (as early as %1$tY-%1$tm-%1$td)."},
{"bad.timestamp.verifying", {"bad.timestamp.verifying",
"This jar contains signatures that include an invalid timestamp. Without a valid timestamp, users may not be able to validate this jar after any of the signer certificates expire (as early as %1$tY-%1$tm-%1$td).\nRerun jarsigner with -J-Djava.security.debug=jar for more information."}, "This jar contains signatures that include an invalid timestamp. Without a valid timestamp, users may not be able to validate this jar after any of the signer certificates expire (as early as %1$tY-%1$tm-%1$td).\nRerun jarsigner with -J-Djava.security.debug=jar for more information."},
{"The.signer.certificate.will.expire.on.1.",
"The signer certificate will expire on %1$tY-%1$tm-%1$td."},
{"The.timestamp.will.expire.on.1.",
"The timestamp will expire on %1$tY-%1$tm-%1$td."},
{"signer.cert.expired.1.but.timestamp.good.2.",
"The signer certificate expired on %1$tY-%1$tm-%1$td. However, the JAR will be valid until the timestamp expires on %2$tY-%2$tm-%2$td."},
{"Unknown.password.type.", "Unknown password type: "}, {"Unknown.password.type.", "Unknown password type: "},
{"Cannot.find.environment.variable.", {"Cannot.find.environment.variable.",
"Cannot find environment variable: "}, "Cannot find environment variable: "},
......
/* /*
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -75,6 +75,7 @@ import jdk.testlibrary.Utils; ...@@ -75,6 +75,7 @@ import jdk.testlibrary.Utils;
* java.base/sun.security.util * java.base/sun.security.util
* java.base/sun.security.tools.keytool * java.base/sun.security.tools.keytool
* @library /lib/testlibrary * @library /lib/testlibrary
* @compile -XDignore.symbol.file TimestampCheck.java
* @run main/othervm/timeout=600 TimestampCheck * @run main/othervm/timeout=600 TimestampCheck
*/ */
public class TimestampCheck { public class TimestampCheck {
...@@ -121,12 +122,12 @@ public class TimestampCheck { ...@@ -121,12 +122,12 @@ public class TimestampCheck {
*/ */
byte[] sign(byte[] input, String path) throws Exception { byte[] sign(byte[] input, String path) throws Exception {
DerValue value = new DerValue(input); DerValue value = new DerValue(input);
System.out.println("\nIncoming Request\n==================="); System.out.println("#\n# Incoming Request\n===================");
System.out.println("Version: " + value.data.getInteger()); System.out.println("# Version: " + value.data.getInteger());
DerValue messageImprint = value.data.getDerValue(); DerValue messageImprint = value.data.getDerValue();
AlgorithmId aid = AlgorithmId.parse( AlgorithmId aid = AlgorithmId.parse(
messageImprint.data.getDerValue()); messageImprint.data.getDerValue());
System.out.println("AlgorithmId: " + aid); System.out.println("# AlgorithmId: " + aid);
ObjectIdentifier policyId = new ObjectIdentifier(defaultPolicyId); ObjectIdentifier policyId = new ObjectIdentifier(defaultPolicyId);
BigInteger nonce = null; BigInteger nonce = null;
...@@ -134,16 +135,16 @@ public class TimestampCheck { ...@@ -134,16 +135,16 @@ public class TimestampCheck {
DerValue v = value.data.getDerValue(); DerValue v = value.data.getDerValue();
if (v.tag == DerValue.tag_Integer) { if (v.tag == DerValue.tag_Integer) {
nonce = v.getBigInteger(); nonce = v.getBigInteger();
System.out.println("nonce: " + nonce); System.out.println("# nonce: " + nonce);
} else if (v.tag == DerValue.tag_Boolean) { } else if (v.tag == DerValue.tag_Boolean) {
System.out.println("certReq: " + v.getBoolean()); System.out.println("# certReq: " + v.getBoolean());
} else if (v.tag == DerValue.tag_ObjectId) { } else if (v.tag == DerValue.tag_ObjectId) {
policyId = v.getOID(); policyId = v.getOID();
System.out.println("PolicyID: " + policyId); System.out.println("# PolicyID: " + policyId);
} }
} }
System.out.println("\nResponse\n==================="); System.out.println("#\n# Response\n===================");
FileInputStream is = new FileInputStream(keystore); FileInputStream is = new FileInputStream(keystore);
KeyStore ks = KeyStore.getInstance("JCEKS"); KeyStore ks = KeyStore.getInstance("JCEKS");
ks.load(is, "changeit".toCharArray()); ks.load(is, "changeit".toCharArray());
...@@ -229,10 +230,10 @@ public class TimestampCheck { ...@@ -229,10 +230,10 @@ public class TimestampCheck {
"1.2.840.113549.1.9.16.1.4"), "1.2.840.113549.1.9.16.1.4"),
new DerValue(tstInfo2.toByteArray())); new DerValue(tstInfo2.toByteArray()));
System.out.println("Signing..."); System.out.println("# Signing...");
System.out.println(new X500Name(signer System.out.println("# " + new X500Name(signer
.getIssuerX500Principal().getName())); .getIssuerX500Principal().getName()));
System.out.println(signer.getSerialNumber()); System.out.println("# " + signer.getSerialNumber());
SignerInfo signerInfo = new SignerInfo( SignerInfo signerInfo = new SignerInfo(
new X500Name(signer.getIssuerX500Principal().getName()), new X500Name(signer.getIssuerX500Principal().getName()),
...@@ -303,8 +304,6 @@ public class TimestampCheck { ...@@ -303,8 +304,6 @@ public class TimestampCheck {
public static void main(String[] args) throws Throwable { public static void main(String[] args) throws Throwable {
prepare();
try (Handler tsa = Handler.init(0, "ks");) { try (Handler tsa = Handler.init(0, "ks");) {
tsa.start(); tsa.start();
int port = tsa.getPort(); int port = tsa.getPort();
...@@ -313,62 +312,99 @@ public class TimestampCheck { ...@@ -313,62 +312,99 @@ public class TimestampCheck {
if (args.length == 0) { // Run this test if (args.length == 0) { // Run this test
prepare();
sign("normal") sign("normal")
.shouldNotContain("Warning") .shouldNotContain("Warning")
.shouldContain("The signer certificate will expire on")
.shouldContain("The timestamp will expire on")
.shouldHaveExitValue(0); .shouldHaveExitValue(0);
verify("normal.jar") verify("normal.jar")
.shouldNotContain("Warning") .shouldNotContain("Warning")
.shouldHaveExitValue(0); .shouldHaveExitValue(0);
verify("normal.jar", "-verbose")
.shouldNotContain("Warning")
.shouldContain("The signer certificate will expire on")
.shouldContain("The timestamp will expire on")
.shouldHaveExitValue(0);
// Simulate signing at a previous date: // Simulate signing at a previous date:
// 1. tsold will create a timestamp of 20 days ago. // 1. tsold will create a timestamp of 20 days ago.
// 2. oldsigner expired 10 days ago. // 2. oldsigner expired 10 days ago.
// jarsigner will show a warning at signing.
signVerbose("tsold", "unsigned.jar", "tsold.jar", "oldsigner") signVerbose("tsold", "unsigned.jar", "tsold.jar", "oldsigner")
.shouldHaveExitValue(4); .shouldNotContain("Warning")
.shouldMatch("signer certificate expired on .*. "
+ "However, the JAR will be valid")
.shouldHaveExitValue(0);
// It verifies perfectly. // It verifies perfectly.
verify("tsold.jar", "-verbose", "-certs") verify("tsold.jar", "-verbose", "-certs")
.shouldNotContain("Warning") .shouldNotContain("Warning")
.shouldMatch("signer certificate expired on .*. "
+ "However, the JAR will be valid")
.shouldHaveExitValue(0); .shouldHaveExitValue(0);
// No timestamp
signVerbose(null, "unsigned.jar", "none.jar", "signer") signVerbose(null, "unsigned.jar", "none.jar", "signer")
.shouldContain("is not timestamped") .shouldContain("is not timestamped")
.shouldContain("The signer certificate will expire on")
.shouldHaveExitValue(0);
verify("none.jar", "-verbose")
.shouldContain("do not include a timestamp")
.shouldContain("The signer certificate will expire on")
.shouldHaveExitValue(0); .shouldHaveExitValue(0);
// Error cases
signVerbose(null, "unsigned.jar", "badku.jar", "badku") signVerbose(null, "unsigned.jar", "badku.jar", "badku")
.shouldContain("KeyUsage extension doesn't allow code signing")
.shouldHaveExitValue(8); .shouldHaveExitValue(8);
checkBadKU("badku.jar"); checkBadKU("badku.jar");
// 8180289: unvalidated TSA cert chain // 8180289: unvalidated TSA cert chain
sign("tsnoca") sign("tsnoca")
.shouldContain("TSA certificate chain is invalid") .shouldContain("The TSA certificate chain is invalid. "
+ "Reason: Path does not chain with any of the trust anchors")
.shouldHaveExitValue(64); .shouldHaveExitValue(64);
verify("tsnoca.jar", "-verbose", "-certs") verify("tsnoca.jar", "-verbose", "-certs")
.shouldHaveExitValue(64) .shouldHaveExitValue(64)
.shouldContain("jar verified") .shouldContain("jar verified")
.shouldContain("Invalid TSA certificate chain") .shouldContain("Invalid TSA certificate chain: "
.shouldContain("TSA certificate chain is invalid"); + "Path does not chain with any of the trust anchors")
.shouldContain("TSA certificate chain is invalid."
+ " Reason: Path does not chain with any of the trust anchors");
sign("nononce") sign("nononce")
.shouldContain("Nonce missing in timestamp token")
.shouldHaveExitValue(1); .shouldHaveExitValue(1);
sign("diffnonce") sign("diffnonce")
.shouldContain("Nonce changed in timestamp token")
.shouldHaveExitValue(1); .shouldHaveExitValue(1);
sign("baddigest") sign("baddigest")
.shouldContain("Digest octets changed in timestamp token")
.shouldHaveExitValue(1); .shouldHaveExitValue(1);
sign("diffalg") sign("diffalg")
.shouldContain("Digest algorithm not")
.shouldHaveExitValue(1); .shouldHaveExitValue(1);
sign("fullchain") sign("fullchain")
.shouldHaveExitValue(0); // Success, 6543440 solved. .shouldHaveExitValue(0); // Success, 6543440 solved.
sign("tsbad1") sign("tsbad1")
.shouldContain("Certificate is not valid for timestamping")
.shouldHaveExitValue(1); .shouldHaveExitValue(1);
sign("tsbad2") sign("tsbad2")
.shouldContain("Certificate is not valid for timestamping")
.shouldHaveExitValue(1); .shouldHaveExitValue(1);
sign("tsbad3") sign("tsbad3")
.shouldContain("Certificate is not valid for timestamping")
.shouldHaveExitValue(1); .shouldHaveExitValue(1);
sign("nocert") sign("nocert")
.shouldContain("Certificate not included in timestamp token")
.shouldHaveExitValue(1); .shouldHaveExitValue(1);
sign("policy", "-tsapolicyid", "1.2.3") sign("policy", "-tsapolicyid", "1.2.3")
...@@ -376,6 +412,7 @@ public class TimestampCheck { ...@@ -376,6 +412,7 @@ public class TimestampCheck {
checkTimestamp("policy.jar", "1.2.3", "SHA-256"); checkTimestamp("policy.jar", "1.2.3", "SHA-256");
sign("diffpolicy", "-tsapolicyid", "1.2.3") sign("diffpolicy", "-tsapolicyid", "1.2.3")
.shouldContain("TSAPolicyID changed in timestamp token")
.shouldHaveExitValue(1); .shouldHaveExitValue(1);
sign("sha1alg", "-tsadigestalg", "SHA") sign("sha1alg", "-tsadigestalg", "SHA")
...@@ -384,11 +421,13 @@ public class TimestampCheck { ...@@ -384,11 +421,13 @@ public class TimestampCheck {
sign("tsweak", "-digestalg", "MD5", sign("tsweak", "-digestalg", "MD5",
"-sigalg", "MD5withRSA", "-tsadigestalg", "MD5") "-sigalg", "MD5withRSA", "-tsadigestalg", "MD5")
.shouldHaveExitValue(68); .shouldHaveExitValue(68)
.shouldContain("The timestamp is invalid. Without a valid timestamp");
checkWeak("tsweak.jar"); checkWeak("tsweak.jar");
signVerbose("tsweak", "unsigned.jar", "tsweak2.jar", "signer") signVerbose("tsweak", "unsigned.jar", "tsweak2.jar", "signer")
.shouldHaveExitValue(64) .shouldHaveExitValue(64)
.shouldContain("The timestamp is invalid. Without a valid timestamp")
.shouldContain("TSA certificate chain is invalid"); .shouldContain("TSA certificate chain is invalid");
// Weak timestamp is an error and jar treated unsigned // Weak timestamp is an error and jar treated unsigned
...@@ -397,19 +436,26 @@ public class TimestampCheck { ...@@ -397,19 +436,26 @@ public class TimestampCheck {
.shouldContain("treated as unsigned") .shouldContain("treated as unsigned")
.shouldMatch("Timestamp.*512.*weak"); .shouldMatch("Timestamp.*512.*weak");
// Algorithm used in signing is weak
signVerbose("normal", "unsigned.jar", "halfWeak.jar", "signer", signVerbose("normal", "unsigned.jar", "halfWeak.jar", "signer",
"-digestalg", "MD5") "-digestalg", "MD5")
.shouldContain("-digestalg option is considered a security risk")
.shouldHaveExitValue(4); .shouldHaveExitValue(4);
checkHalfWeak("halfWeak.jar"); checkHalfWeak("halfWeak.jar");
// sign with DSA key // sign with DSA key
signVerbose("normal", "unsigned.jar", "sign1.jar", "dsakey") signVerbose("normal", "unsigned.jar", "sign1.jar", "dsakey")
.shouldHaveExitValue(0); .shouldHaveExitValue(0);
// sign with RSAkeysize < 1024 // sign with RSAkeysize < 1024
signVerbose("normal", "sign1.jar", "sign2.jar", "weakkeysize") signVerbose("normal", "sign1.jar", "sign2.jar", "weakkeysize")
.shouldContain("Algorithm constraints check failed on keysize")
.shouldHaveExitValue(4); .shouldHaveExitValue(4);
checkMultiple("sign2.jar"); checkMultiple("sign2.jar");
// 8191438: jarsigner should print when a timestamp will expire
checkExpiration();
// When .SF or .RSA is missing or invalid // When .SF or .RSA is missing or invalid
checkMissingOrInvalidFiles("normal.jar"); checkMissingOrInvalidFiles("normal.jar");
...@@ -417,12 +463,118 @@ public class TimestampCheck { ...@@ -417,12 +463,118 @@ public class TimestampCheck {
checkInvalidTsaCertKeyUsage(); checkInvalidTsaCertKeyUsage();
} }
} else { // Run as a standalone server } else { // Run as a standalone server
System.out.println("Press Enter to quit server"); System.out.println("TSA started at " + host
+ ". Press Enter to quit server");
System.in.read(); System.in.read();
} }
} }
} }
private static void checkExpiration() throws Exception {
// Warning when expired or expiring
signVerbose(null, "unsigned.jar", "expired.jar", "expired")
.shouldContain("signer certificate has expired")
.shouldHaveExitValue(4);
verify("expired.jar")
.shouldContain("signer certificate has expired")
.shouldHaveExitValue(4);
signVerbose(null, "unsigned.jar", "expiring.jar", "expiring")
.shouldContain("signer certificate will expire within")
.shouldHaveExitValue(0);
verify("expiring.jar")
.shouldContain("signer certificate will expire within")
.shouldHaveExitValue(0);
// Info for long
signVerbose(null, "unsigned.jar", "long.jar", "long")
.shouldNotContain("signer certificate has expired")
.shouldNotContain("signer certificate will expire within")
.shouldContain("signer certificate will expire on")
.shouldHaveExitValue(0);
verify("long.jar")
.shouldNotContain("signer certificate has expired")
.shouldNotContain("signer certificate will expire within")
.shouldNotContain("The signer certificate will expire")
.shouldHaveExitValue(0);
verify("long.jar", "-verbose")
.shouldContain("The signer certificate will expire")
.shouldHaveExitValue(0);
// Both expired
signVerbose("tsexpired", "unsigned.jar",
"tsexpired-expired.jar", "expired")
.shouldContain("The signer certificate has expired.")
.shouldContain("The timestamp has expired.")
.shouldHaveExitValue(4);
verify("tsexpired-expired.jar")
.shouldContain("signer certificate has expired")
.shouldContain("timestamp has expired.")
.shouldHaveExitValue(4);
// TS expired but signer still good
signVerbose("tsexpired", "unsigned.jar",
"tsexpired-long.jar", "long")
.shouldContain("The timestamp expired on")
.shouldHaveExitValue(0);
verify("tsexpired-long.jar")
.shouldMatch("timestamp expired on.*However, the JAR will be valid")
.shouldNotContain("Error")
.shouldHaveExitValue(0);
signVerbose("tsexpired", "unsigned.jar",
"tsexpired-ca.jar", "ca")
.shouldContain("The timestamp has expired.")
.shouldHaveExitValue(4);
verify("tsexpired-ca.jar")
.shouldNotContain("timestamp has expired")
.shouldNotContain("Error")
.shouldHaveExitValue(0);
// Warning when expiring
sign("tsexpiring")
.shouldContain("timestamp will expire within")
.shouldHaveExitValue(0);
verify("tsexpiring.jar")
.shouldContain("timestamp will expire within")
.shouldNotContain("still valid")
.shouldHaveExitValue(0);
signVerbose("tsexpiring", "unsigned.jar",
"tsexpiring-ca.jar", "ca")
.shouldContain("self-signed")
.stderrShouldNotMatch("The.*expir")
.shouldHaveExitValue(4); // self-signed
verify("tsexpiring-ca.jar")
.stderrShouldNotMatch("The.*expir")
.shouldHaveExitValue(0);
signVerbose("tsexpiringsoon", "unsigned.jar",
"tsexpiringsoon-long.jar", "long")
.shouldContain("The timestamp will expire")
.shouldHaveExitValue(0);
verify("tsexpiringsoon-long.jar")
.shouldMatch("timestamp will expire.*However, the JAR will be valid until")
.shouldHaveExitValue(0);
// Info for long
sign("tslong")
.shouldNotContain("timestamp has expired")
.shouldNotContain("timestamp will expire within")
.shouldContain("timestamp will expire on")
.shouldContain("signer certificate will expire on")
.shouldHaveExitValue(0);
verify("tslong.jar")
.shouldNotContain("timestamp has expired")
.shouldNotContain("timestamp will expire within")
.shouldNotContain("timestamp will expire on")
.shouldNotContain("signer certificate will expire on")
.shouldHaveExitValue(0);
verify("tslong.jar", "-verbose")
.shouldContain("timestamp will expire on")
.shouldContain("signer certificate will expire on")
.shouldHaveExitValue(0);
}
private static void checkInvalidTsaCertKeyUsage() throws Exception { private static void checkInvalidTsaCertKeyUsage() throws Exception {
// Hack: Rewrite the TSA cert inside normal.jar into ts2.jar. // Hack: Rewrite the TSA cert inside normal.jar into ts2.jar.
...@@ -670,6 +822,14 @@ public class TimestampCheck { ...@@ -670,6 +822,14 @@ public class TimestampCheck {
keytool("-alias tsbad3 -genkeypair -dname CN=tsbad3"); keytool("-alias tsbad3 -genkeypair -dname CN=tsbad3");
keytool("-alias tsnoca -genkeypair -dname CN=tsnoca"); keytool("-alias tsnoca -genkeypair -dname CN=tsnoca");
keytool("-alias expired -genkeypair -dname CN=expired");
keytool("-alias expiring -genkeypair -dname CN=expiring");
keytool("-alias long -genkeypair -dname CN=long");
keytool("-alias tsexpired -genkeypair -dname CN=tsexpired");
keytool("-alias tsexpiring -genkeypair -dname CN=tsexpiring");
keytool("-alias tsexpiringsoon -genkeypair -dname CN=tsexpiringsoon");
keytool("-alias tslong -genkeypair -dname CN=tslong");
// tsnoca's issuer will be removed from keystore later // tsnoca's issuer will be removed from keystore later
keytool("-alias ca -genkeypair -ext bc -dname CN=CA"); keytool("-alias ca -genkeypair -ext bc -dname CN=CA");
gencert("tsnoca", "-ext eku:critical=ts"); gencert("tsnoca", "-ext eku:critical=ts");
...@@ -681,7 +841,15 @@ public class TimestampCheck { ...@@ -681,7 +841,15 @@ public class TimestampCheck {
gencert("dsakey"); gencert("dsakey");
gencert("weakkeysize"); gencert("weakkeysize");
gencert("badku", "-ext ku:critical=keyAgreement"); gencert("badku", "-ext ku:critical=keyAgreement");
gencert("ts", "-ext eku:critical=ts"); gencert("ts", "-ext eku:critical=ts -validity 500");
gencert("expired", "-validity 10 -startdate -12d");
gencert("expiring", "-validity 178");
gencert("long", "-validity 182");
gencert("tsexpired", "-ext eku:critical=ts -validity 10 -startdate -12d");
gencert("tsexpiring", "-ext eku:critical=ts -validity 364");
gencert("tsexpiringsoon", "-ext eku:critical=ts -validity 170"); // earlier than expiring
gencert("tslong", "-ext eku:critical=ts -validity 367");
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
...@@ -701,7 +869,7 @@ public class TimestampCheck { ...@@ -701,7 +869,7 @@ public class TimestampCheck {
} }
} }
gencert("tsold", "-ext eku:critical=ts -startdate -40d -validity 45"); gencert("tsold", "-ext eku:critical=ts -startdate -40d -validity 500");
gencert("tsweak", "-ext eku:critical=ts"); gencert("tsweak", "-ext eku:critical=ts");
gencert("tsbad1"); gencert("tsbad1");
......
...@@ -51,32 +51,12 @@ public class AliasNotInStoreTest extends Test { ...@@ -51,32 +51,12 @@ public class AliasNotInStoreTest extends Test {
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
// create first key pair for signing // create first key pair for signing
ProcessTools.executeCommand(KEYTOOL, createAlias(FIRST_KEY_ALIAS);
"-genkey", createAlias(SECOND_KEY_ALIAS);
"-alias", FIRST_KEY_ALIAS,
"-keyalg", KEY_ALG,
"-keysize", Integer.toString(KEY_SIZE),
"-keystore", BOTH_KEYS_KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=First",
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
// create second key pair for signing
ProcessTools.executeCommand(KEYTOOL,
"-genkey",
"-alias", SECOND_KEY_ALIAS,
"-keyalg", KEY_ALG,
"-keysize", Integer.toString(KEY_SIZE),
"-keystore", BOTH_KEYS_KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=Second",
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
// sign jar with first key // sign jar with first key
OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER, OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
"-keystore", BOTH_KEYS_KEYSTORE, "-keystore", KEYSTORE,
"-storepass", PASSWORD, "-storepass", PASSWORD,
"-keypass", PASSWORD, "-keypass", PASSWORD,
"-signedjar", SIGNED_JARFILE, "-signedjar", SIGNED_JARFILE,
...@@ -93,7 +73,7 @@ public class AliasNotInStoreTest extends Test { ...@@ -93,7 +73,7 @@ public class AliasNotInStoreTest extends Test {
// sign jar with second key // sign jar with second key
analyzer = ProcessTools.executeCommand(JARSIGNER, analyzer = ProcessTools.executeCommand(JARSIGNER,
"-keystore", BOTH_KEYS_KEYSTORE, "-keystore", KEYSTORE,
"-storepass", PASSWORD, "-storepass", PASSWORD,
"-keypass", PASSWORD, "-keypass", PASSWORD,
UPDATED_SIGNED_JARFILE, UPDATED_SIGNED_JARFILE,
...@@ -104,7 +84,7 @@ public class AliasNotInStoreTest extends Test { ...@@ -104,7 +84,7 @@ public class AliasNotInStoreTest extends Test {
// create keystore that contains only first key // create keystore that contains only first key
ProcessTools.executeCommand(KEYTOOL, ProcessTools.executeCommand(KEYTOOL,
"-importkeystore", "-importkeystore",
"-srckeystore", BOTH_KEYS_KEYSTORE, "-srckeystore", KEYSTORE,
"-srcalias", FIRST_KEY_ALIAS, "-srcalias", FIRST_KEY_ALIAS,
"-srcstorepass", PASSWORD, "-srcstorepass", PASSWORD,
"-srckeypass", PASSWORD, "-srckeypass", PASSWORD,
...@@ -113,7 +93,7 @@ public class AliasNotInStoreTest extends Test { ...@@ -113,7 +93,7 @@ public class AliasNotInStoreTest extends Test {
"-deststorepass", PASSWORD, "-deststorepass", PASSWORD,
"-destkeypass", PASSWORD).shouldHaveExitValue(0); "-destkeypass", PASSWORD).shouldHaveExitValue(0);
// verify jar with keystore that contains only first key in strict mode, // verify jar with keystore that contains only first key,
// so there is signed entry (FirstClass.class) that is not signed // so there is signed entry (FirstClass.class) that is not signed
// by any alias in the keystore // by any alias in the keystore
analyzer = ProcessTools.executeCommand(JARSIGNER, analyzer = ProcessTools.executeCommand(JARSIGNER,
......
/* /*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -52,17 +52,14 @@ public class BadExtendedKeyUsageTest extends Test { ...@@ -52,17 +52,14 @@ public class BadExtendedKeyUsageTest extends Test {
// create a certificate whose signer certificate's // create a certificate whose signer certificate's
// ExtendedKeyUsage extension doesn't allow code signing // ExtendedKeyUsage extension doesn't allow code signing
ProcessTools.executeCommand(KEYTOOL, // create key pair for jar signing
"-genkey", createAlias(CA_KEY_ALIAS);
"-alias", KEY_ALIAS, createAlias(KEY_ALIAS);
"-keyalg", KEY_ALG,
"-keysize", Integer.toString(KEY_SIZE), issueCert(
"-keystore", KEYSTORE, KEY_ALIAS,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=Test",
"-ext", "ExtendedkeyUsage=serverAuth", "-ext", "ExtendedkeyUsage=serverAuth",
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0); "-validity", Integer.toString(VALIDITY));
// sign jar // sign jar
OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER, OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
......
/* /*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -53,17 +53,13 @@ public class BadKeyUsageTest extends Test { ...@@ -53,17 +53,13 @@ public class BadKeyUsageTest extends Test {
// create a certificate whose signer certificate's KeyUsage extension // create a certificate whose signer certificate's KeyUsage extension
// doesn't allow code signing // doesn't allow code signing
ProcessTools.executeCommand(KEYTOOL, createAlias(CA_KEY_ALIAS);
"-genkey", createAlias(KEY_ALIAS);
"-alias", KEY_ALIAS,
"-keyalg", KEY_ALG, issueCert(
"-keysize", Integer.toString(KEY_SIZE), KEY_ALIAS,
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=Test",
"-ext", "KeyUsage=keyAgreement", "-ext", "KeyUsage=keyAgreement",
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0); "-validity", Integer.toString(VALIDITY));
// sign jar // sign jar
OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER, OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
......
/* /*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -25,10 +25,6 @@ import jdk.testlibrary.OutputAnalyzer; ...@@ -25,10 +25,6 @@ import jdk.testlibrary.OutputAnalyzer;
import jdk.testlibrary.ProcessTools; import jdk.testlibrary.ProcessTools;
import jdk.testlibrary.JarUtils; import jdk.testlibrary.JarUtils;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
/** /**
* @test * @test
* @bug 8024302 8026037 * @bug 8024302 8026037
...@@ -38,25 +34,14 @@ import java.util.Base64; ...@@ -38,25 +34,14 @@ import java.util.Base64;
*/ */
public class BadNetscapeCertTypeTest extends Test { public class BadNetscapeCertTypeTest extends Test {
private static final String NETSCAPE_KEYSTORE_BASE64 = TEST_SOURCES + FS
+ "bad_netscape_cert_type.jks.base64";
private static final String NETSCAPE_KEYSTORE
= "bad_netscape_cert_type.jks";
/** /**
* The test signs and verifies a jar that contains entries * The test signs and verifies a jar that contains entries
* whose signer certificate's NetscapeCertType extension * whose signer certificate's NetscapeCertType extension
* doesn't allow code signing (badNetscapeCertType). * doesn't allow code signing (badNetscapeCertType).
* Warning message is expected. * Warning message is expected.
* Run bad_netscape_cert_type.sh script to create bad_netscape_cert_type.jks
*/ */
public static void main(String[] args) throws Throwable { public static void main(String[] args) throws Throwable {
Files.write(Paths.get(NETSCAPE_KEYSTORE),
Base64.getMimeDecoder().decode(
Files.readAllBytes(Paths.get(NETSCAPE_KEYSTORE_BASE64))));
BadNetscapeCertTypeTest test = new BadNetscapeCertTypeTest(); BadNetscapeCertTypeTest test = new BadNetscapeCertTypeTest();
test.start(); test.start();
} }
...@@ -66,10 +51,22 @@ public class BadNetscapeCertTypeTest extends Test { ...@@ -66,10 +51,22 @@ public class BadNetscapeCertTypeTest extends Test {
Utils.createFiles(FIRST_FILE); Utils.createFiles(FIRST_FILE);
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
// create a certificate whose signer certificate's
// NetscapeCertType extension doesn't allow code signing
// create key pair for jar signing
createAlias(CA_KEY_ALIAS);
createAlias(KEY_ALIAS);
issueCert(
KEY_ALIAS,
// NetscapeCertType [ SSL client ]
"-ext", "2.16.840.1.113730.1.1=03020780",
"-validity", Integer.toString(VALIDITY));
// sign jar // sign jar
OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER, OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
"-verbose", "-verbose",
"-keystore", NETSCAPE_KEYSTORE, "-keystore", KEYSTORE,
"-storepass", PASSWORD, "-storepass", PASSWORD,
"-keypass", PASSWORD, "-keypass", PASSWORD,
"-signedjar", SIGNED_JARFILE, "-signedjar", SIGNED_JARFILE,
...@@ -82,7 +79,7 @@ public class BadNetscapeCertTypeTest extends Test { ...@@ -82,7 +79,7 @@ public class BadNetscapeCertTypeTest extends Test {
analyzer = ProcessTools.executeCommand(JARSIGNER, analyzer = ProcessTools.executeCommand(JARSIGNER,
"-verify", "-verify",
"-verbose", "-verbose",
"-keystore", NETSCAPE_KEYSTORE, "-keystore", KEYSTORE,
"-storepass", PASSWORD, "-storepass", PASSWORD,
"-keypass", PASSWORD, "-keypass", PASSWORD,
SIGNED_JARFILE); SIGNED_JARFILE);
...@@ -94,7 +91,7 @@ public class BadNetscapeCertTypeTest extends Test { ...@@ -94,7 +91,7 @@ public class BadNetscapeCertTypeTest extends Test {
"-verify", "-verify",
"-verbose", "-verbose",
"-strict", "-strict",
"-keystore", NETSCAPE_KEYSTORE, "-keystore", KEYSTORE,
"-storepass", PASSWORD, "-storepass", PASSWORD,
"-keypass", PASSWORD, "-keypass", PASSWORD,
SIGNED_JARFILE); SIGNED_JARFILE);
......
/* /*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -21,117 +21,52 @@ ...@@ -21,117 +21,52 @@
* questions. * questions.
*/ */
import java.io.File;
import jdk.testlibrary.OutputAnalyzer; import jdk.testlibrary.OutputAnalyzer;
import jdk.testlibrary.ProcessTools; import jdk.testlibrary.ProcessTools;
import jdk.testlibrary.JarUtils; import jdk.testlibrary.JarUtils;
import java.nio.file.Files;
import java.nio.file.Paths;
/** /**
* @test * @test
* @bug 8024302 8026037 * @bug 8024302 8026037
* @summary Test for chainNotValidated warning * @summary Test for chainNotValidated warning
* @library /lib/testlibrary ../ * @library /lib/testlibrary ../
* @run main ChainNotValidatedTest * @run main ChainNotValidatedTest ca2yes
* @run main ChainNotValidatedTest ca2no
*/ */
public class ChainNotValidatedTest extends Test { public class ChainNotValidatedTest extends Test {
private static final String CHAIN = "chain";
/**
* The test signs and verifies a jar that contains entries
* whose cert chain can't be correctly validated (chainNotValidated).
* Warning message is expected.
*/
public static void main(String[] args) throws Throwable { public static void main(String[] args) throws Throwable {
ChainNotValidatedTest test = new ChainNotValidatedTest(); ChainNotValidatedTest test = new ChainNotValidatedTest();
test.start(); test.start(args[0].equals("ca2yes"));
} }
private void start() throws Throwable { private void start(boolean ca2yes) throws Throwable {
// create a jar file that contains one class file // create a jar file that contains one class file
Utils.createFiles(FIRST_FILE); Utils.createFiles(FIRST_FILE);
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
// create self-signed certificate whose BasicConstraints extension // We have 2 @run. Need cleanup.
// is set to false, so the certificate may not be used Files.deleteIfExists(Paths.get(KEYSTORE));
// as a parent certificate (certpath validation should fail)
ProcessTools.executeCommand(KEYTOOL,
"-genkeypair",
"-alias", CA_KEY_ALIAS,
"-keyalg", KEY_ALG,
"-keysize", Integer.toString(KEY_SIZE),
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=CA",
"-ext", "BasicConstraints:critical=ca:false",
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
// create a certificate that is signed by self-signed certificate // Root CA is not checked at all. If the intermediate CA has
// despite of it may not be used as a parent certificate // BasicConstraints extension set to true, it will be valid.
// (certpath validation should fail) // Otherwise, chain validation will fail.
ProcessTools.executeCommand(KEYTOOL, createAlias(CA_KEY_ALIAS);
"-genkeypair", createAlias(CA2_KEY_ALIAS);
"-alias", KEY_ALIAS, issueCert(CA2_KEY_ALIAS,
"-keyalg", KEY_ALG, "-ext",
"-keysize", Integer.toString(KEY_SIZE), "bc=ca:" + ca2yes);
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=Test",
"-ext", "BasicConstraints:critical=ca:false",
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
ProcessTools.executeCommand(KEYTOOL,
"-certreq",
"-alias", KEY_ALIAS,
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-file", CERT_REQUEST_FILENAME).shouldHaveExitValue(0);
ProcessTools.executeCommand(KEYTOOL, createAlias(KEY_ALIAS);
"-gencert", issueCert(KEY_ALIAS, "-alias", CA2_KEY_ALIAS);
"-alias", CA_KEY_ALIAS,
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-infile", CERT_REQUEST_FILENAME,
"-validity", Integer.toString(VALIDITY),
"-outfile", CERT_FILENAME).shouldHaveExitValue(0);
ProcessTools.executeCommand(KEYTOOL,
"-importcert",
"-alias", KEY_ALIAS,
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-file", CERT_FILENAME).shouldHaveExitValue(0);
ProcessBuilder pb = new ProcessBuilder(KEYTOOL,
"-export",
"-rfc",
"-alias", KEY_ALIAS,
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD);
pb.redirectOutput(ProcessBuilder.Redirect.appendTo(new File(CHAIN)));
ProcessTools.executeCommand(pb).shouldHaveExitValue(0);
pb = new ProcessBuilder(KEYTOOL,
"-export",
"-rfc",
"-alias", CA_KEY_ALIAS,
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD);
pb.redirectOutput(ProcessBuilder.Redirect.appendTo(new File(CHAIN)));
ProcessTools.executeCommand(pb).shouldHaveExitValue(0);
// remove CA certificate // remove CA2 certificate so it's not trusted
ProcessTools.executeCommand(KEYTOOL, ProcessTools.executeCommand(KEYTOOL,
"-delete", "-delete",
"-alias", CA_KEY_ALIAS, "-alias", CA2_KEY_ALIAS,
"-keystore", KEYSTORE, "-keystore", KEYSTORE,
"-storepass", PASSWORD, "-storepass", PASSWORD,
"-keypass", PASSWORD).shouldHaveExitValue(0); "-keypass", PASSWORD).shouldHaveExitValue(0);
...@@ -141,12 +76,15 @@ public class ChainNotValidatedTest extends Test { ...@@ -141,12 +76,15 @@ public class ChainNotValidatedTest extends Test {
"-keystore", KEYSTORE, "-keystore", KEYSTORE,
"-storepass", PASSWORD, "-storepass", PASSWORD,
"-keypass", PASSWORD, "-keypass", PASSWORD,
"-certchain", CHAIN,
"-signedjar", SIGNED_JARFILE, "-signedjar", SIGNED_JARFILE,
UNSIGNED_JARFILE, UNSIGNED_JARFILE,
KEY_ALIAS); KEY_ALIAS);
checkSigning(analyzer, CHAIN_NOT_VALIDATED_SIGNING_WARNING); if (ca2yes) {
checkSigning(analyzer, "!" + CHAIN_NOT_VALIDATED_SIGNING_WARNING);
} else {
checkSigning(analyzer, CHAIN_NOT_VALIDATED_SIGNING_WARNING);
}
// verify signed jar // verify signed jar
analyzer = ProcessTools.executeCommand(JARSIGNER, analyzer = ProcessTools.executeCommand(JARSIGNER,
...@@ -155,10 +93,13 @@ public class ChainNotValidatedTest extends Test { ...@@ -155,10 +93,13 @@ public class ChainNotValidatedTest extends Test {
"-keystore", KEYSTORE, "-keystore", KEYSTORE,
"-storepass", PASSWORD, "-storepass", PASSWORD,
"-keypass", PASSWORD, "-keypass", PASSWORD,
"-certchain", CHAIN,
SIGNED_JARFILE); SIGNED_JARFILE);
checkVerifying(analyzer, 0, CHAIN_NOT_VALIDATED_VERIFYING_WARNING); if (ca2yes) {
checkVerifying(analyzer, 0, "!" + CHAIN_NOT_VALIDATED_VERIFYING_WARNING);
} else {
checkVerifying(analyzer, 0, CHAIN_NOT_VALIDATED_VERIFYING_WARNING);
}
// verify signed jar in strict mode // verify signed jar in strict mode
analyzer = ProcessTools.executeCommand(JARSIGNER, analyzer = ProcessTools.executeCommand(JARSIGNER,
...@@ -168,11 +109,15 @@ public class ChainNotValidatedTest extends Test { ...@@ -168,11 +109,15 @@ public class ChainNotValidatedTest extends Test {
"-keystore", KEYSTORE, "-keystore", KEYSTORE,
"-storepass", PASSWORD, "-storepass", PASSWORD,
"-keypass", PASSWORD, "-keypass", PASSWORD,
"-certchain", CHAIN,
SIGNED_JARFILE); SIGNED_JARFILE);
checkVerifying(analyzer, CHAIN_NOT_VALIDATED_EXIT_CODE, if (ca2yes) {
CHAIN_NOT_VALIDATED_VERIFYING_WARNING); checkVerifying(analyzer, 0,
"!" + CHAIN_NOT_VALIDATED_VERIFYING_WARNING);
} else {
checkVerifying(analyzer, CHAIN_NOT_VALIDATED_EXIT_CODE,
CHAIN_NOT_VALIDATED_VERIFYING_WARNING);
}
System.out.println("Test passed"); System.out.println("Test passed");
} }
......
/* /*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -52,18 +52,13 @@ public class HasExpiredCertTest extends Test { ...@@ -52,18 +52,13 @@ public class HasExpiredCertTest extends Test {
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
// create key pair for jar signing // create key pair for jar signing
ProcessTools.executeCommand(KEYTOOL, createAlias(CA_KEY_ALIAS);
"-genkey", createAlias(KEY_ALIAS);
"-alias", KEY_ALIAS,
"-keyalg", KEY_ALG, issueCert(
"-keysize", Integer.toString(KEY_SIZE), KEY_ALIAS,
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=Test",
"-startdate", "-" + SHORT_VALIDITY * 2 + "d", "-startdate", "-" + SHORT_VALIDITY * 2 + "d",
"-validity", Integer.toString(SHORT_VALIDITY)) "-validity", Integer.toString(SHORT_VALIDITY));
.shouldHaveExitValue(0);
// sign jar // sign jar
OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER, OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
......
/* /*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -52,17 +52,12 @@ public class HasExpiringCertTest extends Test { ...@@ -52,17 +52,12 @@ public class HasExpiringCertTest extends Test {
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
// create key pair for jar signing // create key pair for jar signing
ProcessTools.executeCommand(KEYTOOL, createAlias(CA_KEY_ALIAS);
"-genkey", createAlias(KEY_ALIAS);
"-alias", KEY_ALIAS,
"-keyalg", KEY_ALG, issueCert(
"-keysize", Integer.toString(KEY_SIZE), KEY_ALIAS,
"-keystore", KEYSTORE, "-validity", Integer.toString(SHORT_VALIDITY));
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=Test",
"-validity", Integer.toString(SHORT_VALIDITY))
.shouldHaveExitValue(0);
// sign jar // sign jar
OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER, OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
......
/* /*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -51,16 +51,11 @@ public class HasUnsignedEntryTest extends Test { ...@@ -51,16 +51,11 @@ public class HasUnsignedEntryTest extends Test {
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
// create key pair for signing // create key pair for signing
ProcessTools.executeCommand(KEYTOOL, createAlias(CA_KEY_ALIAS);
"-genkey", createAlias(KEY_ALIAS);
"-alias", KEY_ALIAS, issueCert(
"-keyalg", KEY_ALG, KEY_ALIAS,
"-keysize", Integer.toString(KEY_SIZE), "-validity", Integer.toString(VALIDITY));
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=Test",
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
// sign jar // sign jar
OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER, OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
......
/* /*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -54,35 +54,25 @@ public class MultipleWarningsTest extends Test { ...@@ -54,35 +54,25 @@ public class MultipleWarningsTest extends Test {
// create a jar file that contains one class file // create a jar file that contains one class file
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
createAlias(CA_KEY_ALIAS);
// create first expired certificate // create first expired certificate
// whose ExtendedKeyUsage extension does not allow code signing // whose ExtendedKeyUsage extension does not allow code signing
ProcessTools.executeCommand(KEYTOOL, createAlias(FIRST_KEY_ALIAS);
"-genkey", issueCert(
"-alias", FIRST_KEY_ALIAS, FIRST_KEY_ALIAS,
"-keyalg", KEY_ALG,
"-keysize", Integer.toString(KEY_SIZE),
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=First",
"-ext", "ExtendedkeyUsage=serverAuth", "-ext", "ExtendedkeyUsage=serverAuth",
"-startdate", "-" + VALIDITY * 2 + "d", "-startdate", "-" + VALIDITY * 2 + "d",
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0); "-validity", Integer.toString(VALIDITY));
// create second expired certificate // create second expired certificate
// whose KeyUsage extension does not allow code signing // whose KeyUsage extension does not allow code signing
ProcessTools.executeCommand(KEYTOOL, createAlias(SECOND_KEY_ALIAS);
"-genkey", issueCert(
"-alias", SECOND_KEY_ALIAS, SECOND_KEY_ALIAS,
"-keyalg", KEY_ALG,
"-keysize", Integer.toString(KEY_SIZE),
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=Second",
"-ext", "ExtendedkeyUsage=serverAuth", "-ext", "ExtendedkeyUsage=serverAuth",
"-startdate", "-" + VALIDITY * 2 + "d", "-startdate", "-" + VALIDITY * 2 + "d",
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0); "-validity", Integer.toString(VALIDITY));
// sign jar with first key // sign jar with first key
OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER, OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
......
/* /*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -57,15 +57,9 @@ public class NoTimestampTest extends Test { ...@@ -57,15 +57,9 @@ public class NoTimestampTest extends Test {
* 24 * 60 * 60 * 1000L); * 24 * 60 * 60 * 1000L);
// create key pair // create key pair
ProcessTools.executeCommand(KEYTOOL, createAlias(CA_KEY_ALIAS);
"-genkey", createAlias(KEY_ALIAS);
"-alias", KEY_ALIAS, issueCert(KEY_ALIAS,
"-keyalg", KEY_ALG,
"-keysize", Integer.toString(KEY_SIZE),
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=Test",
"-validity", Integer.toString(VALIDITY)); "-validity", Integer.toString(VALIDITY));
// sign jar file // sign jar file
......
/* /*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -49,29 +49,19 @@ public class NotSignedByAliasTest extends Test { ...@@ -49,29 +49,19 @@ public class NotSignedByAliasTest extends Test {
Utils.createFiles(FIRST_FILE); Utils.createFiles(FIRST_FILE);
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
createAlias(CA_KEY_ALIAS);
// create first key pair for signing // create first key pair for signing
ProcessTools.executeCommand(KEYTOOL, createAlias(FIRST_KEY_ALIAS);
"-genkey", issueCert(
"-alias", FIRST_KEY_ALIAS, FIRST_KEY_ALIAS,
"-keyalg", KEY_ALG, "-validity", Integer.toString(VALIDITY));
"-keysize", Integer.toString(KEY_SIZE),
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=First",
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
// create first key pair for signing // create first key pair for signing
ProcessTools.executeCommand(KEYTOOL, createAlias(SECOND_KEY_ALIAS);
"-genkey", issueCert(
"-alias", SECOND_KEY_ALIAS, SECOND_KEY_ALIAS,
"-keyalg", KEY_ALG, "-validity", Integer.toString(VALIDITY));
"-keysize", Integer.toString(KEY_SIZE),
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=Second",
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
// sign jar with first key // sign jar with first key
OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER, OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
......
/* /*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -50,15 +50,11 @@ public class NotYetValidCertTest extends Test { ...@@ -50,15 +50,11 @@ public class NotYetValidCertTest extends Test {
JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
// create certificate that will be valid only tomorrow // create certificate that will be valid only tomorrow
ProcessTools.executeCommand(KEYTOOL, createAlias(CA_KEY_ALIAS);
"-genkey", createAlias(KEY_ALIAS);
"-alias", KEY_ALIAS,
"-keyalg", KEY_ALG, issueCert(
"-keysize", Integer.toString(KEY_SIZE), KEY_ALIAS,
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=Test",
"-startdate", "+1d", "-startdate", "+1d",
"-validity", Integer.toString(VALIDITY)); "-validity", Integer.toString(VALIDITY));
......
/* /*
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -45,7 +45,6 @@ public abstract class Test { ...@@ -45,7 +45,6 @@ public abstract class Test {
static final String FIRST_FILE = "first.txt"; static final String FIRST_FILE = "first.txt";
static final String SECOND_FILE = "second.txt"; static final String SECOND_FILE = "second.txt";
static final String PASSWORD = "password"; static final String PASSWORD = "password";
static final String BOTH_KEYS_KEYSTORE = "both_keys.jks";
static final String FIRST_KEY_KEYSTORE = "first_key.jks"; static final String FIRST_KEY_KEYSTORE = "first_key.jks";
static final String KEYSTORE = "keystore.jks"; static final String KEYSTORE = "keystore.jks";
static final String FIRST_KEY_ALIAS = "first"; static final String FIRST_KEY_ALIAS = "first";
...@@ -55,11 +54,13 @@ public abstract class Test { ...@@ -55,11 +54,13 @@ public abstract class Test {
static final String CERT_REQUEST_FILENAME = "test.req"; static final String CERT_REQUEST_FILENAME = "test.req";
static final String CERT_FILENAME = "test.crt"; static final String CERT_FILENAME = "test.crt";
static final String CA_KEY_ALIAS = "ca"; static final String CA_KEY_ALIAS = "ca";
static final String CA2_KEY_ALIAS = "ca2";
static final int KEY_SIZE = 2048; static final int KEY_SIZE = 2048;
static final int TIMEOUT = 6 * 60 * 1000; // in millis static final int TIMEOUT = 6 * 60 * 1000; // in millis
static final int VALIDITY = 365; static final int VALIDITY = 365;
static final String WARNING = "Warning:"; static final String WARNING = "Warning:";
static final String WARNING_OR_ERROR = "(Warning|Error):";
static final String CHAIN_NOT_VALIDATED_VERIFYING_WARNING static final String CHAIN_NOT_VALIDATED_VERIFYING_WARNING
= "This jar contains entries " = "This jar contains entries "
...@@ -126,10 +127,10 @@ public abstract class Test { ...@@ -126,10 +127,10 @@ public abstract class Test {
+ "(%1$tY-%1$tm-%1$td) or after any future revocation date."; + "(%1$tY-%1$tm-%1$td) or after any future revocation date.";
static final String NO_TIMESTAMP_VERIFYING_WARN_TEMPLATE static final String NO_TIMESTAMP_VERIFYING_WARN_TEMPLATE
= "This jar contains signatures that does not include a timestamp. " = "This jar contains signatures that do not include a timestamp. "
+ "Without a timestamp, users may not be able to validate this jar " + "Without a timestamp, users may not be able to validate this jar "
+ "after the signer certificate's expiration date " + "after any of the signer certificates expire "
+ "(%1$tY-%1$tm-%1$td) or after any future revocation date."; + "(as early as %1$tY-%1$tm-%1$td).";
static final String NOT_YET_VALID_CERT_SIGNING_WARNING static final String NOT_YET_VALID_CERT_SIGNING_WARNING
= "The signer certificate is not yet valid."; = "The signer certificate is not yet valid.";
...@@ -154,14 +155,72 @@ public abstract class Test { ...@@ -154,14 +155,72 @@ public abstract class Test {
static final int ALIAS_NOT_IN_STORE_EXIT_CODE = 32; static final int ALIAS_NOT_IN_STORE_EXIT_CODE = 32;
static final int NOT_SIGNED_BY_ALIAS_EXIT_CODE = 32; static final int NOT_SIGNED_BY_ALIAS_EXIT_CODE = 32;
protected void createAlias(String alias, String ... options)
throws Throwable {
List<String> cmd = new ArrayList<>();
cmd.addAll(Arrays.asList(
"-genkeypair",
"-alias", alias,
"-keyalg", KEY_ALG,
"-keysize", Integer.toString(KEY_SIZE),
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-dname", "CN=" + alias));
cmd.addAll(Arrays.asList(options));
keytool(cmd.toArray(new String[cmd.size()]))
.shouldHaveExitValue(0);
}
protected void issueCert(String alias, String ... options)
throws Throwable {
keytool("-certreq",
"-alias", alias,
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-file", alias + ".req")
.shouldHaveExitValue(0);
List<String> cmd = new ArrayList<>();
cmd.addAll(Arrays.asList(
"-gencert",
"-alias", CA_KEY_ALIAS,
"-infile", alias + ".req",
"-outfile", alias + ".cert",
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-file", alias + ".req"));
cmd.addAll(Arrays.asList(options));
keytool(cmd.toArray(new String[cmd.size()]))
.shouldHaveExitValue(0);
keytool("-importcert",
"-alias", alias,
"-keystore", KEYSTORE,
"-storepass", PASSWORD,
"-keypass", PASSWORD,
"-file", alias + ".cert")
.shouldHaveExitValue(0);
}
protected void checkVerifying(OutputAnalyzer analyzer, int expectedExitCode, protected void checkVerifying(OutputAnalyzer analyzer, int expectedExitCode,
String... warnings) { String... warnings) {
analyzer.shouldHaveExitValue(expectedExitCode); analyzer.shouldHaveExitValue(expectedExitCode);
int count = 0;
for (String warning : warnings) { for (String warning : warnings) {
analyzer.shouldContain(warning); if (warning.startsWith("!")) {
analyzer.shouldNotContain(warning.substring(1));
} else {
count++;
analyzer.shouldContain(warning);
}
} }
if (warnings.length > 0) { if (count > 0) {
analyzer.shouldContain(WARNING); analyzer.shouldMatch(WARNING_OR_ERROR);
} }
if (expectedExitCode == 0) { if (expectedExitCode == 0) {
analyzer.shouldContain(JAR_VERIFIED); analyzer.shouldContain(JAR_VERIFIED);
...@@ -172,11 +231,17 @@ public abstract class Test { ...@@ -172,11 +231,17 @@ public abstract class Test {
protected void checkSigning(OutputAnalyzer analyzer, String... warnings) { protected void checkSigning(OutputAnalyzer analyzer, String... warnings) {
analyzer.shouldHaveExitValue(0); analyzer.shouldHaveExitValue(0);
int count = 0;
for (String warning : warnings) { for (String warning : warnings) {
analyzer.shouldContain(warning); if (warning.startsWith("!")) {
analyzer.shouldNotContain(warning.substring(1));
} else {
count++;
analyzer.shouldContain(warning);
}
} }
if (warnings.length > 0) { if (count > 0) {
analyzer.shouldContain(WARNING); analyzer.shouldMatch(WARNING_OR_ERROR);
} }
analyzer.shouldContain(JAR_SIGNED); analyzer.shouldContain(JAR_SIGNED);
} }
......
/u3+7QAAAAIAAAABAAAAAQAFYWxpYXMAAAFBpkwW0gAAAr0wggK5MA4GCisGAQQB
KgIRAQEFAASCAqWkGJ3PPjYmWNKrV23Y1u413RMAkrRZ+1OLWYRcQt4jtxtIyEH5
Ho5b9dy9XN9FBKlTOD4c2Pc1T43BLKXeuLu3uLLeIxgXFt0z9CLyGwdYZZ751kXr
DQ99qY6aNQUO6SeE4Wdty0KPAqid6ZJ8bF7T6wsTZSvNhaBRzyFydEfG7bbUYjOl
mWC44nlsu6VEU3o9RQpcm1gIMwradOaIVT/HoB2bKmAv8gHqI6kreiEZwTdZkSAI
IRi2vt1RPllXt5hgjDxUfZe8XOYYweR4Vt2/jVuKLJ80DNTu/9SeUD88zQAz53k4
r3nRhv6TRcPm6tV/Fh92XLHiskL+TAzTfm+bUAudPCCVxN+yRtxvAgA+UhdV/SuM
Zn5F6nrmP+YJG1hmprgCJIJJaCEXa9RXYC+vIVpO0WVNRuGlGm+/1afnOuQC8Wss
ShXwjkaqTwAhqBFq7eYmmP8BK3gflYrt2zDLXvhl4ndVvMhMthFJ3ZvLh2LWpqLI
/n8EMCf8US3lIEFk9DTHBZjffiHkqK2e7+FXEpG3xrgE6ZYLMdbd5Pb3YjZfhQx+
ZTtiEFzYSaEGhacek/m7dRq1qmwgFsytng2OdWZe2ln8LJY0odr1dGUfJHfgafvi
tlfbkg/rgjONtwliChDggbkUwnerrj/D/zrdEufUvfyltSshhHXRNDD3fH6spmEk
hHKgxEc4yvxqJxzdMGtuib355aSfNegyl+GsnsKzXQCVEK2h3BLTQObzaD+8NZ12
LQHvbrCiaS34vxJ3rEC+a+SW7itZp0aCdXMWdMJNkRKqyLBD3vG3zN05sN3XrhEM
8BRT020TWY00tbVFbbBFheYLQRgTjrQtr0Yt6UHWBZc4N20crDLcSH5gqcCOVpla
1Y2uqFEn8yqrGRwn/kgfNgAAAAEABVguNTA5AAABtTCCAbEwggEaoAMCAQICCQDH
cEuVvzCuqzANBgkqhkiG9w0BAQUFADAPMQ0wCwYDVQQDDARUZXN0MB4XDTEzMTAx
MTA2NTUwNloXDTIzMTAwOTA2NTUwNlowDzENMAsGA1UEAwwEVGVzdDCBnzANBgkq
hkiG9w0BAQEFAAOBjQAwgYkCgYEA8hOfp2Dcnvt//ZZQAja9TRiwKqXVS+TiYE3S
gngCBjIi+YYdo0DsUeO5MBfE6uvCWOr5lwAR/u1iaJOhIoGJDiGoPasZlt+yIgtR
LzA7j2q+1q6kcwiVxfikI3aUgHV/QsybTriT4Bf7TQNKtJG23MQa4sD7+PjtCWD7
p3cHTfkCAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgeAMA0GCSqGSIb3DQEBBQUA
A4GBAKoDlTJ8wLRA7G8XdGm4gv733n1cSQzlkcsjfOO6/mA5Jvu8tyFNq9HTf9AT
VXbrbGcUYJjhzSSY3w5apXK1kXyqTB1LUNEJ45WnmciqSSecVTpJz9TuegyoX0Zf
HScSgqfDmjqoiiFiNCgn3ZEJ85ykGvoFYGH+php+BVi3S0bj5E/jRpyV3vNnii/S
wJDSAXF6bYU=
#
# Copyright (c) 2013, 2015, 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.
#
#!/bin/sh
# This script creates JKS keystore with a certificate
# that contains Netscape Certificate Type extension
# that does not allow code signing
# The keystore is used by BadNetscapeCertTypeTest.java test
rm -rf keystore.jks
echo "nsCertType = client" > ext.cfg
openssl req -new -out cert.req -keyout key.pem -days 3650 \
-passin pass:password -passout pass:password -subj "/CN=Test"
openssl x509 -in cert.req -out cert.pem -req -signkey key.pem -days 3650 \
-passin pass:password -extfile ext.cfg
openssl pkcs12 -export -in cert.pem -inkey key.pem -out keystore.p12 \
-passin pass:password -passout pass:password -name alias
${JAVA_HOME}/bin/keytool -importkeystore \
-srckeystore keystore.p12 -srcstoretype pkcs12 \
-srcstorepass password -alias alias \
-destkeystore bad_netscape_cert_type.jks -deststoretype jks \
-deststorepass password -destalias alias \
openssl base64 < bad_netscape_cert_type.jks > bad_netscape_cert_type.jks.base64
rm -rf cert.req key.pem cert.pem keystore.p12 ext.cfg bad_netscape_cert_type.jks
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册