mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-24 13:51:12 +00:00
8130132: jarsigner should emit warning if weak algorithms or keysizes are used
Reviewed-by: mullan
This commit is contained in:
parent
7779102abc
commit
8fc9b58a4e
@ -38,6 +38,7 @@ import java.net.URL;
|
||||
|
||||
import java.security.KeyStore;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.text.Collator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -67,6 +68,25 @@ public class KeyStoreUtil {
|
||||
collator.setStrength(Collator.PRIMARY);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the certificate is self-signed, false otherwise.
|
||||
*/
|
||||
public static boolean isSelfSigned(X509Certificate cert) {
|
||||
return signedBy(cert, cert);
|
||||
}
|
||||
|
||||
public static boolean signedBy(X509Certificate end, X509Certificate ca) {
|
||||
if (!ca.getSubjectX500Principal().equals(end.getIssuerX500Principal())) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
end.verify(ca.getPublicKey());
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if KeyStore has a password. This is true except for
|
||||
* MSCAPI KeyStores
|
||||
|
||||
@ -1297,7 +1297,7 @@ public final class Main {
|
||||
for (Certificate ca: keyStore.getCertificateChain(alias)) {
|
||||
if (ca instanceof X509Certificate) {
|
||||
X509Certificate xca = (X509Certificate)ca;
|
||||
if (!isSelfSigned(xca)) {
|
||||
if (!KeyStoreUtil.isSelfSigned(xca)) {
|
||||
dumpCert(xca, out);
|
||||
}
|
||||
}
|
||||
@ -2705,7 +2705,7 @@ public final class Main {
|
||||
|
||||
// if certificate is self-signed, make sure it verifies
|
||||
boolean selfSigned = false;
|
||||
if (isSelfSigned(cert)) {
|
||||
if (KeyStoreUtil.isSelfSigned(cert)) {
|
||||
cert.verify(cert.getPublicKey());
|
||||
selfSigned = true;
|
||||
}
|
||||
@ -2964,25 +2964,6 @@ public final class Main {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the certificate is self-signed, false otherwise.
|
||||
*/
|
||||
private boolean isSelfSigned(X509Certificate cert) {
|
||||
return signedBy(cert, cert);
|
||||
}
|
||||
|
||||
private boolean signedBy(X509Certificate end, X509Certificate ca) {
|
||||
if (!ca.getSubjectDN().equals(end.getIssuerDN())) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
end.verify(ca.getPublicKey());
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates a signer for a given certificate from a given keystore and
|
||||
* returns the signer's certificate.
|
||||
@ -3320,7 +3301,7 @@ public final class Main {
|
||||
// find a cert in the reply who signs thisCert
|
||||
int j;
|
||||
for (j=i; j<replyCerts.length; j++) {
|
||||
if (signedBy(thisCert, (X509Certificate)replyCerts[j])) {
|
||||
if (KeyStoreUtil.signedBy(thisCert, (X509Certificate)replyCerts[j])) {
|
||||
tmpCert = replyCerts[i];
|
||||
replyCerts[i] = replyCerts[j];
|
||||
replyCerts[j] = tmpCert;
|
||||
@ -3451,7 +3432,7 @@ public final class Main {
|
||||
Vector<Certificate> chain,
|
||||
Hashtable<Principal, Vector<Certificate>> certs) {
|
||||
Principal issuer = certToVerify.getIssuerDN();
|
||||
if (isSelfSigned(certToVerify)) {
|
||||
if (KeyStoreUtil.isSelfSigned(certToVerify)) {
|
||||
// reached self-signed root cert;
|
||||
// no verification needed because it's trusted.
|
||||
chain.addElement(certToVerify);
|
||||
|
||||
@ -150,6 +150,7 @@ public class Main {
|
||||
private Date expireDate = new Date(0L); // used in noTimestamp warning
|
||||
|
||||
// Severe warnings
|
||||
private int weakAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg
|
||||
private boolean hasExpiredCert = false;
|
||||
private boolean notYetValidCert = false;
|
||||
private boolean chainNotValidated = false;
|
||||
@ -159,6 +160,9 @@ public class Main {
|
||||
private boolean badKeyUsage = false;
|
||||
private boolean badExtendedKeyUsage = false;
|
||||
private boolean badNetscapeCertType = false;
|
||||
private boolean signerSelfSigned = false;
|
||||
|
||||
private Throwable chainNotValidatedReason = null;
|
||||
|
||||
CertificateFactory certificateFactory;
|
||||
CertPathValidator validator;
|
||||
@ -243,7 +247,7 @@ public class Main {
|
||||
|
||||
if (strict) {
|
||||
int exitCode = 0;
|
||||
if (chainNotValidated || hasExpiredCert || notYetValidCert) {
|
||||
if (weakAlg != 0 || chainNotValidated || hasExpiredCert || notYetValidCert || signerSelfSigned) {
|
||||
exitCode |= 4;
|
||||
}
|
||||
if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) {
|
||||
@ -780,6 +784,12 @@ public class Main {
|
||||
if (man == null)
|
||||
System.out.println(rb.getString("no.manifest."));
|
||||
|
||||
// If signer is a trusted cert or private entry in user's own
|
||||
// keystore, it can be self-signed.
|
||||
if (!aliasNotInStore) {
|
||||
signerSelfSigned = false;
|
||||
}
|
||||
|
||||
if (!anySigned) {
|
||||
System.out.println(rb.getString(
|
||||
"jar.is.unsigned.signatures.missing.or.not.parsable."));
|
||||
@ -788,7 +798,7 @@ public class Main {
|
||||
boolean errorAppeared = false;
|
||||
if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
|
||||
notYetValidCert || chainNotValidated || hasExpiredCert ||
|
||||
hasUnsignedEntry ||
|
||||
hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) ||
|
||||
aliasNotInStore || notSignedByAlias) {
|
||||
|
||||
if (strict) {
|
||||
@ -803,6 +813,12 @@ public class Main {
|
||||
warningAppeared = true;
|
||||
}
|
||||
|
||||
if (weakAlg != 0) {
|
||||
// In fact, jarsigner verification did not catch this
|
||||
// since it has not read the JarFile content itself.
|
||||
// Everything is done with JarFile API.
|
||||
}
|
||||
|
||||
if (badKeyUsage) {
|
||||
System.out.println(
|
||||
rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
|
||||
@ -832,8 +848,9 @@ public class Main {
|
||||
}
|
||||
|
||||
if (chainNotValidated) {
|
||||
System.out.println(
|
||||
rb.getString("This.jar.contains.entries.whose.certificate.chain.is.not.validated."));
|
||||
System.out.println(String.format(
|
||||
rb.getString("This.jar.contains.entries.whose.certificate.chain.is.not.validated.reason.1"),
|
||||
chainNotValidatedReason.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
if (notSignedByAlias) {
|
||||
@ -844,6 +861,11 @@ public class Main {
|
||||
if (aliasNotInStore) {
|
||||
System.out.println(rb.getString("This.jar.contains.signed.entries.that.s.not.signed.by.alias.in.this.keystore."));
|
||||
}
|
||||
|
||||
if (signerSelfSigned) {
|
||||
System.out.println(rb.getString(
|
||||
"This.jar.contains.entries.whose.signer.certificate.is.self.signed."));
|
||||
}
|
||||
} else {
|
||||
System.out.println(rb.getString("jar.verified."));
|
||||
}
|
||||
@ -1074,7 +1096,25 @@ public class Main {
|
||||
}
|
||||
|
||||
void signJar(String jarName, String alias)
|
||||
throws Exception {
|
||||
throws Exception {
|
||||
|
||||
DisabledAlgorithmConstraints dac =
|
||||
new DisabledAlgorithmConstraints(
|
||||
DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
|
||||
|
||||
if (digestalg != null && !dac.permits(
|
||||
Collections.singleton(CryptoPrimitive.MESSAGE_DIGEST), digestalg, null)) {
|
||||
weakAlg |= 1;
|
||||
}
|
||||
if (tSADigestAlg != null && !dac.permits(
|
||||
Collections.singleton(CryptoPrimitive.MESSAGE_DIGEST), tSADigestAlg, null)) {
|
||||
weakAlg |= 4;
|
||||
}
|
||||
if (sigalg != null && !dac.permits(
|
||||
Collections.singleton(CryptoPrimitive.SIGNATURE), sigalg, null)) {
|
||||
weakAlg |= 2;
|
||||
}
|
||||
|
||||
boolean aliasUsed = false;
|
||||
X509Certificate tsaCert = null;
|
||||
|
||||
@ -1255,8 +1295,8 @@ public class Main {
|
||||
}
|
||||
|
||||
boolean warningAppeared = false;
|
||||
if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
|
||||
notYetValidCert || chainNotValidated || hasExpiredCert) {
|
||||
if (weakAlg != 0 || badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
|
||||
notYetValidCert || chainNotValidated || hasExpiredCert || signerSelfSigned) {
|
||||
if (strict) {
|
||||
System.out.println(rb.getString("jar.signed.with.signer.errors."));
|
||||
System.out.println();
|
||||
@ -1292,8 +1332,31 @@ public class Main {
|
||||
}
|
||||
|
||||
if (chainNotValidated) {
|
||||
System.out.println(String.format(
|
||||
rb.getString("The.signer.s.certificate.chain.is.not.validated.reason.1"),
|
||||
chainNotValidatedReason.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
if (signerSelfSigned) {
|
||||
System.out.println(
|
||||
rb.getString("The.signer.s.certificate.chain.is.not.validated."));
|
||||
rb.getString("The.signer.s.certificate.is.self.signed."));
|
||||
}
|
||||
|
||||
if ((weakAlg & 1) == 1) {
|
||||
System.out.println(String.format(
|
||||
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
|
||||
digestalg, "-digestalg"));
|
||||
}
|
||||
|
||||
if ((weakAlg & 2) == 2) {
|
||||
System.out.println(String.format(
|
||||
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
|
||||
sigalg, "-sigalg"));
|
||||
}
|
||||
if ((weakAlg & 4) == 4) {
|
||||
System.out.println(String.format(
|
||||
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
|
||||
tSADigestAlg, "-tsadigestalg"));
|
||||
}
|
||||
} else {
|
||||
System.out.println(rb.getString("jar.signed."));
|
||||
@ -1377,10 +1440,15 @@ public class Main {
|
||||
// No more warning, we alreay have hasExpiredCert or notYetValidCert
|
||||
} else {
|
||||
chainNotValidated = true;
|
||||
chainNotValidatedReason = e;
|
||||
sb.append(tab).append(rb.getString(".CertPath.not.validated."))
|
||||
.append(e.getLocalizedMessage()).append("]\n"); // TODO
|
||||
}
|
||||
}
|
||||
if (certs.size() == 1
|
||||
&& KeyStoreUtil.isSelfSigned((X509Certificate)certs.get(0))) {
|
||||
signerSelfSigned = true;
|
||||
}
|
||||
String result = sb.toString();
|
||||
cacheForSignerInfo.put(signer, result);
|
||||
return result;
|
||||
@ -1645,12 +1713,17 @@ public class Main {
|
||||
if (e.getCause() != null &&
|
||||
(e.getCause() instanceof CertificateExpiredException ||
|
||||
e.getCause() instanceof CertificateNotYetValidException)) {
|
||||
// No more warning, we alreay have hasExpiredCert or notYetValidCert
|
||||
// No more warning, we already have hasExpiredCert or notYetValidCert
|
||||
} else {
|
||||
chainNotValidated = true;
|
||||
chainNotValidatedReason = e;
|
||||
}
|
||||
}
|
||||
|
||||
if (KeyStoreUtil.isSelfSigned(certChain[0])) {
|
||||
signerSelfSigned = true;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!token && keypass == null)
|
||||
key = store.getKey(alias, storepass);
|
||||
|
||||
@ -212,6 +212,8 @@ public class Resources extends java.util.ListResourceBundle {
|
||||
"This jar contains entries whose signer certificate will expire within six months. "},
|
||||
{"This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid.",
|
||||
"This jar contains entries whose signer certificate is not yet valid. "},
|
||||
{"This.jar.contains.entries.whose.signer.certificate.is.self.signed.",
|
||||
"This jar contains entries whose signer certificate is self-signed."},
|
||||
{"Re.run.with.the.verbose.option.for.more.details.",
|
||||
"Re-run with the -verbose option for more details."},
|
||||
{"Re.run.with.the.verbose.and.certs.options.for.more.details.",
|
||||
@ -236,10 +238,14 @@ public class Resources extends java.util.ListResourceBundle {
|
||||
"This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing."},
|
||||
{".{0}.extension.does.not.support.code.signing.",
|
||||
"[{0} extension does not support code signing]"},
|
||||
{"The.signer.s.certificate.chain.is.not.validated.",
|
||||
"The signer's certificate chain is not validated."},
|
||||
{"This.jar.contains.entries.whose.certificate.chain.is.not.validated.",
|
||||
"This jar contains entries whose certificate chain is not validated."},
|
||||
{"The.signer.s.certificate.chain.is.not.validated.reason.1",
|
||||
"The signer's certificate chain is not validated. Reason: %s"},
|
||||
{"The.signer.s.certificate.is.self.signed.",
|
||||
"The signer's certificate is self-signed."},
|
||||
{"The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk.",
|
||||
"The %1$s algorithm specified for the %2$s option is considered a security risk."},
|
||||
{"This.jar.contains.entries.whose.certificate.chain.is.not.validated.reason.1",
|
||||
"This jar contains entries whose certificate chain is not validated. Reason: %s"},
|
||||
{"no.timestamp.signing",
|
||||
"No -tsa or -tsacert is provided and this jar is not timestamped. Without a timestamp, users may not be able to validate this jar after the signer certificate's expiration date (%1$tY-%1$tm-%1$td) or after any future revocation date."},
|
||||
{"no.timestamp.verifying",
|
||||
|
||||
@ -52,6 +52,7 @@ public class TsacertOptionTest {
|
||||
+ ".txt";
|
||||
private static final String PASSWORD = "changeit";
|
||||
private static final String KEYSTORE = "ks.jks";
|
||||
private static final String CA_KEY_ALIAS = "ca";
|
||||
private static final String SIGNING_KEY_ALIAS = "sign_alias";
|
||||
private static final String TSA_KEY_ALIAS = "ts";
|
||||
private static final String KEY_ALG = "RSA";
|
||||
@ -79,10 +80,20 @@ public class TsacertOptionTest {
|
||||
|
||||
// look for free network port for TSA service
|
||||
int port = jdk.testlibrary.Utils.getFreePort();
|
||||
String host = jdk.testlibrary.Utils.getHostname();
|
||||
String host = "127.0.0.1";
|
||||
String tsaUrl = "http://" + host + ":" + port;
|
||||
|
||||
// create key pair for jar signing
|
||||
ProcessTools.executeCommand(KEYTOOL,
|
||||
"-genkey",
|
||||
"-alias", CA_KEY_ALIAS,
|
||||
"-keyalg", KEY_ALG,
|
||||
"-keysize", Integer.toString(KEY_SIZE),
|
||||
"-keystore", KEYSTORE,
|
||||
"-storepass", PASSWORD,
|
||||
"-keypass", PASSWORD,
|
||||
"-dname", "CN=CA",
|
||||
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
|
||||
ProcessTools.executeCommand(KEYTOOL,
|
||||
"-genkey",
|
||||
"-alias", SIGNING_KEY_ALIAS,
|
||||
@ -91,8 +102,30 @@ public class TsacertOptionTest {
|
||||
"-keystore", KEYSTORE,
|
||||
"-storepass", PASSWORD,
|
||||
"-keypass", PASSWORD,
|
||||
"-dname", "CN=Test",
|
||||
"-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
|
||||
"-dname", "CN=Test").shouldHaveExitValue(0);
|
||||
ProcessTools.executeCommand(KEYTOOL,
|
||||
"-certreq",
|
||||
"-alias", SIGNING_KEY_ALIAS,
|
||||
"-keystore", KEYSTORE,
|
||||
"-storepass", PASSWORD,
|
||||
"-keypass", PASSWORD,
|
||||
"-file", "certreq").shouldHaveExitValue(0);
|
||||
ProcessTools.executeCommand(KEYTOOL,
|
||||
"-gencert",
|
||||
"-alias", CA_KEY_ALIAS,
|
||||
"-keystore", KEYSTORE,
|
||||
"-storepass", PASSWORD,
|
||||
"-keypass", PASSWORD,
|
||||
"-validity", Integer.toString(VALIDITY),
|
||||
"-infile", "certreq",
|
||||
"-outfile", "cert").shouldHaveExitValue(0);
|
||||
ProcessTools.executeCommand(KEYTOOL,
|
||||
"-importcert",
|
||||
"-alias", SIGNING_KEY_ALIAS,
|
||||
"-keystore", KEYSTORE,
|
||||
"-storepass", PASSWORD,
|
||||
"-keypass", PASSWORD,
|
||||
"-file", "cert").shouldHaveExitValue(0);
|
||||
|
||||
// create key pair for TSA service
|
||||
// SubjectInfoAccess extension contains URL to TSA service
|
||||
|
||||
248
jdk/test/sun/security/tools/jarsigner/Warning.java
Normal file
248
jdk/test/sun/security/tools/jarsigner/Warning.java
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
import jdk.testlibrary.JDKToolLauncher;
|
||||
import jdk.testlibrary.JarUtils;
|
||||
import jdk.testlibrary.OutputAnalyzer;
|
||||
import jdk.testlibrary.ProcessTools;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8024302 8026037 8130132
|
||||
* @summary warnings, errors and -strict
|
||||
* @library /lib/testlibrary
|
||||
*/
|
||||
public class Warning {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
|
||||
Files.deleteIfExists(Paths.get("ks"));
|
||||
|
||||
newCert("ca", "-validity 365000");
|
||||
|
||||
recreateJar();
|
||||
|
||||
newCert("a");
|
||||
run("jarsigner", "a.jar a")
|
||||
.shouldContain("is self-signed");
|
||||
run("jarsigner", "a.jar a -strict")
|
||||
.shouldContain("is self-signed")
|
||||
.shouldHaveExitValue(4);
|
||||
// Trusted entry can be self-signed without a warning
|
||||
run("jarsigner", "-verify a.jar")
|
||||
.shouldNotContain("is self-signed")
|
||||
.shouldNotContain("not signed by alias in this keystore");
|
||||
run("keytool", "-delete -alias a");
|
||||
// otherwise a warning will be shown
|
||||
run("jarsigner", "-verify a.jar")
|
||||
.shouldContain("is self-signed")
|
||||
.shouldContain("not signed by alias in this keystore");
|
||||
|
||||
recreateJar();
|
||||
|
||||
newCert("b");
|
||||
issueCert("b");
|
||||
run("jarsigner", "a.jar b")
|
||||
.shouldNotContain("is self-signed");
|
||||
run("jarsigner", "-verify a.jar")
|
||||
.shouldNotContain("is self-signed");
|
||||
|
||||
run("jarsigner", "a.jar b -digestalg MD5")
|
||||
.shouldContain("-digestalg option is considered a security risk.");
|
||||
run("jarsigner", "a.jar b -digestalg MD5 -strict")
|
||||
.shouldHaveExitValue(4)
|
||||
.shouldContain("-digestalg option is considered a security risk.");
|
||||
run("jarsigner", "a.jar b -sigalg MD5withRSA")
|
||||
.shouldContain("-sigalg option is considered a security risk");
|
||||
|
||||
issueCert("b", "-sigalg MD5withRSA");
|
||||
run("jarsigner", "a.jar b")
|
||||
.shouldMatch("chain is not validated. Reason:.*MD5withRSA");
|
||||
|
||||
recreateJar();
|
||||
|
||||
newCert("c", "-keysize 512");
|
||||
issueCert("c");
|
||||
run("jarsigner", "a.jar c")
|
||||
.shouldContain("chain is not validated. " +
|
||||
"Reason: algorithm constraints check failed");
|
||||
|
||||
recreateJar();
|
||||
|
||||
newCert("s1"); issueCert("s1", "-startdate 2000/01/01 -validity 36525");
|
||||
run("jarsigner", "a.jar s1")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain("Warning:")
|
||||
.shouldNotContain("Error:")
|
||||
.shouldContain("timestamp").shouldContain("2100-01-01")
|
||||
.shouldNotContain("with signer errors");
|
||||
run("jarsigner", "a.jar s1 -strict")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain("Warning:")
|
||||
.shouldNotContain("Error:")
|
||||
.shouldContain("timestamp").shouldContain("2100-01-01")
|
||||
.shouldNotContain("with signer errors");
|
||||
run("jarsigner", "a.jar s1 -verify")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain("Warning:")
|
||||
.shouldNotContain("Error:")
|
||||
.shouldContain("timestamp").shouldContain("2100-01-01")
|
||||
.shouldNotContain("with signer errors");
|
||||
run("jarsigner", "a.jar s1 -verify -strict")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain("Warning:")
|
||||
.shouldNotContain("Error:")
|
||||
.shouldContain("timestamp").shouldContain("2100-01-01")
|
||||
.shouldNotContain("with signer errors");
|
||||
|
||||
recreateJar();
|
||||
|
||||
newCert("s2"); issueCert("s2", "-validity 100");
|
||||
run("jarsigner", "a.jar s2")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain("Warning:")
|
||||
.shouldNotContain("Error:")
|
||||
.shouldContain("timestamp")
|
||||
.shouldContain("will expire")
|
||||
.shouldNotContain("with signer errors");
|
||||
run("jarsigner", "a.jar s2 -strict")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain("Warning:")
|
||||
.shouldNotContain("Error:")
|
||||
.shouldContain("timestamp")
|
||||
.shouldContain("will expire")
|
||||
.shouldNotContain("with signer errors");
|
||||
run("jarsigner", "a.jar s2 -verify")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain("Warning:")
|
||||
.shouldNotContain("Error:")
|
||||
.shouldContain("timestamp")
|
||||
.shouldContain("will expire")
|
||||
.shouldNotContain("with signer errors");
|
||||
run("jarsigner", "a.jar s2 -verify -strict")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain("Warning:")
|
||||
.shouldNotContain("Error:")
|
||||
.shouldContain("timestamp")
|
||||
.shouldContain("will expire")
|
||||
.shouldNotContain("with signer errors");
|
||||
|
||||
recreateJar();
|
||||
|
||||
newCert("s3"); issueCert("s3", "-startdate -200d -validity 100");
|
||||
run("jarsigner", "a.jar s3")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain("Warning:")
|
||||
.shouldContain("has expired")
|
||||
.shouldNotContain("with signer errors")
|
||||
.shouldNotContain("Error:");
|
||||
run("jarsigner", "a.jar s3 -strict")
|
||||
.shouldHaveExitValue(4)
|
||||
.shouldContain("with signer errors")
|
||||
.shouldMatch("(?s).*Error:.*has expired.*Warning:.*");
|
||||
run("jarsigner", "a.jar s3 -verify")
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain("Warning:")
|
||||
.shouldNotContain("with signer errors")
|
||||
.shouldNotContain("Error:");
|
||||
run("jarsigner", "a.jar s3 -verify -strict")
|
||||
.shouldHaveExitValue(4)
|
||||
.shouldContain("with signer errors")
|
||||
.shouldMatch("(?s).*Error:.*has expired.*Warning:.*");
|
||||
}
|
||||
|
||||
// Creates a new jar without signature
|
||||
static void recreateJar() throws Exception {
|
||||
JarUtils.createJar("a.jar", "ks");
|
||||
}
|
||||
|
||||
// Creates a self-signed cert for alias with zero or more -genkey options
|
||||
static void newCert(String alias, String... more) throws Exception {
|
||||
String args = "-genkeypair -alias " + alias + " -dname CN=" + alias;
|
||||
for (String s: more) {
|
||||
args += " " + s;
|
||||
}
|
||||
run("keytool", args).shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
// Asks ca to issue a cert to alias with zero or more -gencert options
|
||||
static void issueCert(String alias, String...more) throws Exception {
|
||||
String req = run("keytool", "-certreq -alias " + alias)
|
||||
.shouldHaveExitValue(0).getStdout();
|
||||
String args = "-gencert -alias ca -rfc";
|
||||
for (String s: more) {
|
||||
args += " " + s;
|
||||
}
|
||||
String cert = run("keytool", args, req)
|
||||
.shouldHaveExitValue(0).getStdout();
|
||||
run("keytool", "-import -alias " + alias, cert).shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
// Runs a java tool with command line arguments
|
||||
static OutputAnalyzer run(String command, String args)
|
||||
throws Exception {
|
||||
return run(command, args, null);
|
||||
}
|
||||
|
||||
// Runs a java tool with command line arguments and an optional input block
|
||||
static OutputAnalyzer run(String command, String args, String input)
|
||||
throws Exception {
|
||||
JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK(command);
|
||||
launcher.addVMArg("-Duser.language=en").addVMArg("-Duser.country=US");
|
||||
switch (command) {
|
||||
case "keytool":
|
||||
for (String s: new String[] {
|
||||
"-keystore", "ks", "-storepass", "changeit",
|
||||
"-storetype", "jks",
|
||||
"-keypass", "changeit", "-keyalg", "rsa", "-debug"}) {
|
||||
launcher.addToolArg(s);
|
||||
}
|
||||
break;
|
||||
case "jarsigner":
|
||||
for (String s: new String[] {
|
||||
"-keystore", "ks", "-storepass", "changeit",
|
||||
"-storetype", "jks"}) {
|
||||
launcher.addToolArg(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (String arg: args.split(" ")) {
|
||||
launcher.addToolArg(arg);
|
||||
}
|
||||
String[] cmd = launcher.getCommand();
|
||||
ProcessBuilder pb = new ProcessBuilder(cmd);
|
||||
OutputAnalyzer out = ProcessTools.executeProcess(pb, input);
|
||||
System.out.println("======================");
|
||||
System.out.println(Arrays.toString(cmd));
|
||||
String msg = " stdout: [" + out.getStdout() + "];\n"
|
||||
+ " stderr: [" + out.getStderr() + "]\n"
|
||||
+ " exitValue = " + out.getExitValue() + "\n";
|
||||
System.out.println(msg);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,19 +140,19 @@ LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep "more)" | wc -l`
|
||||
# 16 and 32 already covered in the first part
|
||||
# ==========================================================
|
||||
|
||||
$KT -genkeypair -alias expired -dname CN=expired -startdate -10m
|
||||
$KT -genkeypair -alias notyetvalid -dname CN=notyetvalid -startdate +1m
|
||||
$KT -genkeypair -alias badku -dname CN=badku -ext KU=cRLSign -validity 365
|
||||
$KT -genkeypair -alias badeku -dname CN=badeku -ext EKU=sa -validity 365
|
||||
$KT -genkeypair -alias goodku -dname CN=goodku -ext KU=dig -validity 365
|
||||
$KT -genkeypair -alias goodeku -dname CN=goodeku -ext EKU=codesign -validity 365
|
||||
|
||||
# badchain signed by ca, but ca is removed later
|
||||
$KT -genkeypair -alias badchain -dname CN=badchain -validity 365
|
||||
$KT -genkeypair -alias ca -dname CN=ca -ext bc -validity 365
|
||||
$KT -certreq -alias badchain | $KT -gencert -alias ca -validity 365 | \
|
||||
$KT -importcert -alias badchain
|
||||
$KT -delete -alias ca
|
||||
$KT -genkeypair -alias expired -dname CN=expired
|
||||
$KT -certreq -alias expired | $KT -gencert -alias ca -startdate -10m | $KT -import -alias expired
|
||||
$KT -genkeypair -alias notyetvalid -dname CN=notyetvalid
|
||||
$KT -certreq -alias notyetvalid | $KT -gencert -alias ca -startdate +1m | $KT -import -alias notyetvalid
|
||||
$KT -genkeypair -alias badku -dname CN=badku
|
||||
$KT -certreq -alias badku | $KT -gencert -alias ca -ext KU=cRLSign -validity 365 | $KT -import -alias badku
|
||||
$KT -genkeypair -alias badeku -dname CN=badeku
|
||||
$KT -certreq -alias badeku | $KT -gencert -alias ca -ext EKU=sa -validity 365 | $KT -import -alias badeku
|
||||
$KT -genkeypair -alias goodku -dname CN=goodku
|
||||
$KT -certreq -alias goodku | $KT -gencert -alias ca -ext KU=dig -validity 365 | $KT -import -alias goodku
|
||||
$KT -genkeypair -alias goodeku -dname CN=goodeku
|
||||
$KT -certreq -alias goodeku | $KT -gencert -alias ca -ext EKU=codesign -validity 365 | $KT -import -alias goodeku
|
||||
|
||||
$JARSIGNER -strict -keystore $KS -storepass changeit a.jar expired
|
||||
[ $? = 4 ] || exit $LINENO
|
||||
@ -172,6 +172,12 @@ $JARSIGNER -strict -keystore $KS -storepass changeit a.jar goodku
|
||||
$JARSIGNER -strict -keystore $KS -storepass changeit a.jar goodeku
|
||||
[ $? = 0 ] || exit $LINENO
|
||||
|
||||
# badchain signed by ca, but ca is removed later
|
||||
$KT -genkeypair -alias badchain -dname CN=badchain -validity 365
|
||||
$KT -certreq -alias badchain | $KT -gencert -alias ca -validity 365 | \
|
||||
$KT -importcert -alias badchain
|
||||
$KT -delete -alias ca
|
||||
|
||||
$JARSIGNER -strict -keystore $KS -storepass changeit a.jar badchain
|
||||
[ $? = 4 ] || exit $LINENO
|
||||
|
||||
@ -182,18 +188,22 @@ $JARSIGNER -verify a.jar
|
||||
# Third part: -certchain test
|
||||
# ==========================================================
|
||||
|
||||
# altchain signed by ca2, but ca2 is removed later
|
||||
# altchain signed by ca2
|
||||
$KT -genkeypair -alias altchain -dname CN=altchain -validity 365
|
||||
$KT -genkeypair -alias ca2 -dname CN=ca2 -ext bc -validity 365
|
||||
$KT -certreq -alias altchain | $KT -gencert -alias ca2 -validity 365 -rfc > certchain
|
||||
$KT -exportcert -alias ca2 -rfc >> certchain
|
||||
$KT -delete -alias ca2
|
||||
|
||||
# Now altchain is still self-signed
|
||||
# Self-signed cert does not work
|
||||
$JARSIGNER -strict -keystore $KS -storepass changeit a.jar altchain
|
||||
[ $? = 4 ] || exit $LINENO
|
||||
|
||||
# -certchain works
|
||||
$JARSIGNER -strict -keystore $KS -storepass changeit -certchain certchain a.jar altchain
|
||||
[ $? = 0 ] || exit $LINENO
|
||||
|
||||
# If -certchain is used, then it's bad
|
||||
# but if ca2 is removed, -certchain does not work
|
||||
$KT -delete -alias ca2
|
||||
$JARSIGNER -strict -keystore $KS -storepass changeit -certchain certchain a.jar altchain
|
||||
[ $? = 4 ] || exit $LINENO
|
||||
|
||||
|
||||
@ -31,19 +31,21 @@ if [ "${TESTJAVA}" = "" ] ; then
|
||||
TESTJAVA=`dirname $JAVAC_CMD`/..
|
||||
fi
|
||||
|
||||
PASS=changeit
|
||||
export PASS
|
||||
|
||||
KS=ks
|
||||
KEYTOOL="$TESTJAVA/bin/keytool ${TESTTOOLVMOPTS}"
|
||||
KEYTOOL="$TESTJAVA/bin/keytool ${TESTTOOLVMOPTS} -storepass:env PASS -keypass:env PASS -keystore $KS"
|
||||
JAR="$TESTJAVA/bin/jar ${TESTTOOLVMOPTS}"
|
||||
JARSIGNER="$TESTJAVA/bin/jarsigner ${TESTTOOLVMOPTS}"
|
||||
|
||||
rm $KS 2> /dev/null
|
||||
|
||||
PASS=changeit
|
||||
export PASS
|
||||
|
||||
$KEYTOOL -genkeypair -dname CN=A -alias a \
|
||||
-storepass:env PASS -keypass:env PASS -keystore $KS \
|
||||
-keyalg rsa || exit 1
|
||||
$KEYTOOL -genkeypair -dname CN=A -alias a -keyalg rsa || exit 1
|
||||
$KEYTOOL -genkeypair -dname CN=CA -alias ca -keyalg rsa || exit 2
|
||||
$KEYTOOL -alias a -certreq |
|
||||
$KEYTOOL -alias ca -gencert |
|
||||
$KEYTOOL -alias a -import || exit 3
|
||||
|
||||
cat <<EOF > js.conf
|
||||
jarsigner.all = -keystore \${user.dir}/$KS -storepass:env PASS -debug -strict
|
||||
|
||||
@ -53,11 +53,20 @@ rm $KS $JFILE
|
||||
echo A > A
|
||||
$JAR cvf $JFILE A
|
||||
|
||||
$KT -alias a -dname CN=a -keyalg ec -genkey -validity 300 || exit 11
|
||||
$KT -alias b -dname CN=b -keyalg ec -genkey -validity 300 || exit 12
|
||||
$KT -alias ca -dname CN=ca -keyalg ec -genkey -validity 300 || exit 11
|
||||
|
||||
$KT -alias a -dname CN=a -keyalg ec -genkey || exit 11
|
||||
$KT -alias a -certreq | $KT -gencert -alias ca -validity 300 | $KT -import -alias a || exit 111
|
||||
|
||||
$KT -alias b -dname CN=b -keyalg ec -genkey || exit 12
|
||||
$KT -alias b -certreq | $KT -gencert -alias ca -validity 300 | $KT -import -alias b || exit 121
|
||||
|
||||
# Ensure that key length is sufficient for the intended hash (SHA512withECDSA)
|
||||
$KT -alias c -dname CN=c -keyalg ec -genkey -validity 300 -keysize 521 || exit 13
|
||||
$KT -alias c -dname CN=c -keyalg ec -genkey -keysize 521 || exit 13
|
||||
$KT -alias c -certreq | $KT -gencert -alias ca -validity 300 | $KT -import -alias c || exit 131
|
||||
|
||||
$KT -alias x -dname CN=x -keyalg ec -genkey -validity 300 || exit 14
|
||||
$KT -alias x -certreq | $KT -gencert -alias ca -validity 300 | $KT -import -alias x || exit 141
|
||||
|
||||
$JARSIGNER -keystore $KS -storepass changeit $JFILE a -debug -strict || exit 21
|
||||
$JARSIGNER -keystore $KS -storepass changeit $JFILE b -debug -strict -sigalg SHA1withECDSA || exit 22
|
||||
|
||||
@ -57,12 +57,14 @@ rm $KS $JFILE 2> /dev/null
|
||||
echo "Key: Value" > manifest
|
||||
$JAR cvfm $JFILE manifest
|
||||
|
||||
$KT -alias a -dname CN=a -genkey -validity 300 || exit 1
|
||||
$JARSIGNER -keystore $KS -storepass changeit $JFILE a -debug -strict || exit 2
|
||||
$KT -alias ca -dname CN=ca -genkey -validity 300 || exit 1
|
||||
$KT -alias a -dname CN=a -genkey -validity 300 || exit 2
|
||||
$KT -alias a -certreq | $KT -gencert -alias ca -validity 300 | $KT -import -alias a || exit 3
|
||||
$JARSIGNER -keystore $KS -storepass changeit $JFILE a -debug -strict || exit 4
|
||||
$JARSIGNER -keystore $KS -storepass changeit -verify $JFILE a -debug -strict \
|
||||
> onlymanifest.out || exit 3
|
||||
> onlymanifest.out || exit 5
|
||||
|
||||
grep unsigned onlymanifest.out && exit 4
|
||||
grep unsigned onlymanifest.out && exit 6
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
@ -73,6 +73,10 @@ $KT -alias ts -genkeypair -dname CN=ts
|
||||
$KT -alias tsbad1 -genkeypair -dname CN=tsbad1
|
||||
$KT -alias tsbad2 -genkeypair -dname CN=tsbad2
|
||||
$KT -alias tsbad3 -genkeypair -dname CN=tsbad3
|
||||
|
||||
$KT -alias old -certreq | \
|
||||
$KT -alias ca -gencert | \
|
||||
$KT -alias old -importcert
|
||||
$KT -alias ts -certreq | \
|
||||
$KT -alias ca -gencert -ext eku:critical=ts | \
|
||||
$KT -alias ts -importcert
|
||||
|
||||
@ -1,117 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# @test
|
||||
# @bug 8024302
|
||||
# @bug 8026037
|
||||
# @summary Clarify jar verifications
|
||||
#
|
||||
|
||||
if [ "${TESTJAVA}" = "" ] ; then
|
||||
JAVAC_CMD=`which javac`
|
||||
TESTJAVA=`dirname $JAVAC_CMD`/..
|
||||
fi
|
||||
|
||||
# set platform-dependent variables
|
||||
OS=`uname -s`
|
||||
case "$OS" in
|
||||
Windows_* )
|
||||
FS="\\"
|
||||
;;
|
||||
* )
|
||||
FS="/"
|
||||
;;
|
||||
esac
|
||||
|
||||
KS=warnings.jks
|
||||
JFILE=warnings.jar
|
||||
|
||||
KT="$TESTJAVA${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -storepass changeit -keypass changeit \
|
||||
-keystore $KS"
|
||||
JAR="$TESTJAVA${FS}bin${FS}jar ${TESTTOOLVMOPTS}"
|
||||
JARSIGNER="$TESTJAVA${FS}bin${FS}jarsigner ${TESTTOOLVMOPTS} -keystore $KS -storepass changeit"
|
||||
|
||||
rm $KS 2> /dev/null
|
||||
|
||||
LANG=C
|
||||
export LANG
|
||||
|
||||
echo 12345 > file
|
||||
|
||||
ERR=""
|
||||
|
||||
# Normal signer expiring on 2100-01-01
|
||||
$KT -alias s1 -dname CN=s1 -genkey -startdate 2000/01/01 -validity 36525 || ERR="$ERR keytool s1,"
|
||||
# Cert expiring soon, informational warning
|
||||
$KT -alias s2 -dname CN=s2 -genkey -validity 100 || ERR="$ERR keytool s2,"
|
||||
# Cert expired, severe warning
|
||||
$KT -alias s3 -dname CN=s3 -genkey -startdate -200d -validity 100 || ERR="$ERR keytool s3,"
|
||||
|
||||
# noTimestamp is informatiional warning and includes a date
|
||||
$JAR cvf $JFILE file
|
||||
$JARSIGNER $JFILE s1 > output1 || ERR="$ERR jarsigner s1,"
|
||||
$JARSIGNER -strict $JFILE s1 >> output1 || ERR="$ERR jarsigner s1 strict,"
|
||||
$JARSIGNER -verify $JFILE s1 >> output1 || ERR="$ERR jarsigner s1,"
|
||||
$JARSIGNER -verify -strict $JFILE s1 >> output1 || ERR="$ERR jarsigner s1 strict,"
|
||||
|
||||
cat output1 | grep Warning || ERR="$ERR s1 warning,"
|
||||
cat output1 | grep Error && ERR="$ERR s1 error,"
|
||||
cat output1 | grep timestamp | grep 2100-01-01 || ERR="$ERR s1 timestamp,"
|
||||
cat output1 | grep "with signer errors" && ERR="$ERR s1 err,"
|
||||
|
||||
# hasExpiringCert is informatiional warning
|
||||
$JAR cvf $JFILE file
|
||||
$JARSIGNER $JFILE s2 > output2 || ERR="$ERR jarsigner s2,"
|
||||
$JARSIGNER -strict $JFILE s2 >> output2 || ERR="$ERR jarsigner s2 strict,"
|
||||
$JARSIGNER -verify $JFILE s2 >> output2 || ERR="$ERR jarsigner s2,"
|
||||
$JARSIGNER -verify -strict $JFILE s2 >> output2 || ERR="$ERR jarsigner s2 strict,"
|
||||
|
||||
cat output2 | grep Warning || ERR="$ERR s2 warning,"
|
||||
cat output2 | grep Error && ERR="$ERR s2 error,"
|
||||
cat output2 | grep timestamp || ERR="$ERR s2 timestamp,"
|
||||
cat output2 | grep "will expire" || ERR="$ERR s2 expiring,"
|
||||
cat output2 | grep "with signer errors" && ERR="$ERR s2 err,"
|
||||
|
||||
# hasExpiredCert is severe warning
|
||||
$JAR cvf $JFILE file
|
||||
$JARSIGNER $JFILE s3 > output3 || ERR="$ERR jarsigner s3,"
|
||||
$JARSIGNER -strict $JFILE s3 > output3s && ERR="$ERR jarsigner s3 strict,"
|
||||
$JARSIGNER -verify $JFILE s3 >> output3 || ERR="$ERR jarsigner s3,"
|
||||
$JARSIGNER -verify -strict $JFILE s3 >> output3s && ERR="$ERR jarsigner s3 strict,"
|
||||
|
||||
# warning without -strict
|
||||
cat output3 | grep Warning || ERR="$ERR s3 warning,"
|
||||
cat output3 | grep Error && ERR="$ERR s3 error,"
|
||||
cat output3 | grep "with signer errors" && ERR="$ERR s3 err,"
|
||||
|
||||
# error with -strict
|
||||
cat output3s | grep Warning || ERR="$ERR s3s warning,"
|
||||
cat output3s | grep Error || ERR="$ERR s3s error,"
|
||||
cat output3s | grep "with signer errors" || ERR="$ERR s3 err,"
|
||||
|
||||
if [ "$ERR" = "" ]; then
|
||||
exit 0
|
||||
else
|
||||
echo "ERR is $ERR"
|
||||
exit 1
|
||||
fi
|
||||
@ -52,9 +52,9 @@ $KT -certreq -alias signer | \
|
||||
$JAR cvf a.jar ks
|
||||
|
||||
# We always trust a TrustedCertificateEntry
|
||||
$JS a.jar ca || exit 1
|
||||
$JS a.jar ca | grep "chain is not validated" && exit 1
|
||||
|
||||
# An end-entity cert must follow algorithm constraints
|
||||
$JS a.jar signer && exit 2
|
||||
$JS a.jar signer | grep "chain is not validated" || exit 2
|
||||
|
||||
exit 0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user