8130132: jarsigner should emit warning if weak algorithms or keysizes are used
Reviewed-by: mullan
--- a/jdk/src/java.base/share/classes/sun/security/tools/KeyStoreUtil.java Wed Dec 02 16:44:54 2015 +0800
+++ b/jdk/src/java.base/share/classes/sun/security/tools/KeyStoreUtil.java Wed Dec 02 16:44:57 2015 +0800
@@ -38,6 +38,7 @@
import java.security.KeyStore;
+import java.security.cert.X509Certificate;
import java.text.Collator;
import java.util.ArrayList;
@@ -68,6 +69,25 @@
};
/**
+ * 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
*/
--- a/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java Wed Dec 02 16:44:54 2015 +0800
+++ b/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java Wed Dec 02 16:44:57 2015 +0800
@@ -1297,7 +1297,7 @@
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 @@
// 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;
}
@@ -2965,25 +2965,6 @@
}
/**
- * 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.
* @param cert the certificate whose signer is searched, not null
@@ -3320,7 +3301,7 @@
// 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 @@
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);
--- a/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java Wed Dec 02 16:44:54 2015 +0800
+++ b/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java Wed Dec 02 16:44:57 2015 +0800
@@ -150,6 +150,7 @@
private Date expireDate = new Date(0L); // used in noTimestamp warning
// Severe warnings
+ private int weakAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg
private boolean hasExpiredCert = false;
private boolean notYetValidCert = false;
private boolean chainNotValidated = false;
@@ -159,6 +160,9 @@
private boolean badKeyUsage = false;
private boolean badExtendedKeyUsage = false;
private boolean badNetscapeCertType = false;
+ private boolean signerSelfSigned = false;
+
+ private Throwable chainNotValidatedReason = null;
CertificateFactory certificateFactory;
CertPathValidator validator;
@@ -243,7 +247,7 @@
if (strict) {
int exitCode = 0;
- if (chainNotValidated || hasExpiredCert || notYetValidCert) {
+ if (weakAlg != 0 || chainNotValidated || hasExpiredCert || notYetValidCert || signerSelfSigned) {
exitCode |= 4;
}
if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) {
@@ -780,6 +784,12 @@
if (man == null)
System.out.println(rb.getString("no.manifest."));
+ // If signer is a trusted cert or private entry in user's own
+ // keystore, it can be self-signed.
+ if (!aliasNotInStore) {
+ signerSelfSigned = false;
+ }
+
if (!anySigned) {
System.out.println(rb.getString(
"jar.is.unsigned.signatures.missing.or.not.parsable."));
@@ -788,7 +798,7 @@
boolean errorAppeared = false;
if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
notYetValidCert || chainNotValidated || hasExpiredCert ||
- hasUnsignedEntry ||
+ hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) ||
aliasNotInStore || notSignedByAlias) {
if (strict) {
@@ -803,6 +813,12 @@
warningAppeared = true;
}
+ if (weakAlg != 0) {
+ // In fact, jarsigner verification did not catch this
+ // since it has not read the JarFile content itself.
+ // Everything is done with JarFile API.
+ }
+
if (badKeyUsage) {
System.out.println(
rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
@@ -832,8 +848,9 @@
}
if (chainNotValidated) {
- System.out.println(
- rb.getString("This.jar.contains.entries.whose.certificate.chain.is.not.validated."));
+ System.out.println(String.format(
+ rb.getString("This.jar.contains.entries.whose.certificate.chain.is.not.validated.reason.1"),
+ chainNotValidatedReason.getLocalizedMessage()));
}
if (notSignedByAlias) {
@@ -844,6 +861,11 @@
if (aliasNotInStore) {
System.out.println(rb.getString("This.jar.contains.signed.entries.that.s.not.signed.by.alias.in.this.keystore."));
}
+
+ if (signerSelfSigned) {
+ System.out.println(rb.getString(
+ "This.jar.contains.entries.whose.signer.certificate.is.self.signed."));
+ }
} else {
System.out.println(rb.getString("jar.verified."));
}
@@ -1074,7 +1096,25 @@
}
void signJar(String jarName, String alias)
- throws Exception {
+ throws Exception {
+
+ DisabledAlgorithmConstraints dac =
+ new DisabledAlgorithmConstraints(
+ DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
+
+ if (digestalg != null && !dac.permits(
+ Collections.singleton(CryptoPrimitive.MESSAGE_DIGEST), digestalg, null)) {
+ weakAlg |= 1;
+ }
+ if (tSADigestAlg != null && !dac.permits(
+ Collections.singleton(CryptoPrimitive.MESSAGE_DIGEST), tSADigestAlg, null)) {
+ weakAlg |= 4;
+ }
+ if (sigalg != null && !dac.permits(
+ Collections.singleton(CryptoPrimitive.SIGNATURE), sigalg, null)) {
+ weakAlg |= 2;
+ }
+
boolean aliasUsed = false;
X509Certificate tsaCert = null;
@@ -1255,8 +1295,8 @@
}
boolean warningAppeared = false;
- if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
- notYetValidCert || chainNotValidated || hasExpiredCert) {
+ if (weakAlg != 0 || badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
+ notYetValidCert || chainNotValidated || hasExpiredCert || signerSelfSigned) {
if (strict) {
System.out.println(rb.getString("jar.signed.with.signer.errors."));
System.out.println();
@@ -1292,8 +1332,31 @@
}
if (chainNotValidated) {
+ System.out.println(String.format(
+ rb.getString("The.signer.s.certificate.chain.is.not.validated.reason.1"),
+ chainNotValidatedReason.getLocalizedMessage()));
+ }
+
+ if (signerSelfSigned) {
System.out.println(
- rb.getString("The.signer.s.certificate.chain.is.not.validated."));
+ rb.getString("The.signer.s.certificate.is.self.signed."));
+ }
+
+ if ((weakAlg & 1) == 1) {
+ System.out.println(String.format(
+ rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
+ digestalg, "-digestalg"));
+ }
+
+ if ((weakAlg & 2) == 2) {
+ System.out.println(String.format(
+ rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
+ sigalg, "-sigalg"));
+ }
+ if ((weakAlg & 4) == 4) {
+ System.out.println(String.format(
+ rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
+ tSADigestAlg, "-tsadigestalg"));
}
} else {
System.out.println(rb.getString("jar.signed."));
@@ -1377,10 +1440,15 @@
// No more warning, we alreay have hasExpiredCert or notYetValidCert
} else {
chainNotValidated = true;
+ chainNotValidatedReason = e;
sb.append(tab).append(rb.getString(".CertPath.not.validated."))
.append(e.getLocalizedMessage()).append("]\n"); // TODO
}
}
+ if (certs.size() == 1
+ && KeyStoreUtil.isSelfSigned((X509Certificate)certs.get(0))) {
+ signerSelfSigned = true;
+ }
String result = sb.toString();
cacheForSignerInfo.put(signer, result);
return result;
@@ -1645,12 +1713,17 @@
if (e.getCause() != null &&
(e.getCause() instanceof CertificateExpiredException ||
e.getCause() instanceof CertificateNotYetValidException)) {
- // No more warning, we alreay have hasExpiredCert or notYetValidCert
+ // No more warning, we already have hasExpiredCert or notYetValidCert
} else {
chainNotValidated = true;
+ chainNotValidatedReason = e;
}
}
+ if (KeyStoreUtil.isSelfSigned(certChain[0])) {
+ signerSelfSigned = true;
+ }
+
try {
if (!token && keypass == null)
key = store.getKey(alias, storepass);
--- a/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java Wed Dec 02 16:44:54 2015 +0800
+++ b/jdk/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java Wed Dec 02 16:44:57 2015 +0800
@@ -212,6 +212,8 @@
"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 @@
"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",
--- a/jdk/test/sun/security/tools/jarsigner/TsacertOptionTest.java Wed Dec 02 16:44:54 2015 +0800
+++ b/jdk/test/sun/security/tools/jarsigner/TsacertOptionTest.java Wed Dec 02 16:44:57 2015 +0800
@@ -52,6 +52,7 @@
+ ".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,20 +80,52 @@
// 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,
"-keyalg", KEY_ALG,
"-keysize", Integer.toString(KEY_SIZE),
"-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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/tools/jarsigner/Warning.java Wed Dec 02 16:44:57 2015 +0800
@@ -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;
+ }
+}
+
--- a/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh Wed Dec 02 16:44:54 2015 +0800
+++ b/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh Wed Dec 02 16:44:57 2015 +0800
@@ -140,19 +140,19 @@
# 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 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 @@
# 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
--- a/jdk/test/sun/security/tools/jarsigner/default_options.sh Wed Dec 02 16:44:54 2015 +0800
+++ b/jdk/test/sun/security/tools/jarsigner/default_options.sh Wed Dec 02 16:44:57 2015 +0800
@@ -31,19 +31,21 @@
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
--- a/jdk/test/sun/security/tools/jarsigner/ec.sh Wed Dec 02 16:44:54 2015 +0800
+++ b/jdk/test/sun/security/tools/jarsigner/ec.sh Wed Dec 02 16:44:57 2015 +0800
@@ -53,11 +53,20 @@
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
--- a/jdk/test/sun/security/tools/jarsigner/onlymanifest.sh Wed Dec 02 16:44:54 2015 +0800
+++ b/jdk/test/sun/security/tools/jarsigner/onlymanifest.sh Wed Dec 02 16:44:57 2015 +0800
@@ -57,12 +57,14 @@
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
--- a/jdk/test/sun/security/tools/jarsigner/ts.sh Wed Dec 02 16:44:54 2015 +0800
+++ b/jdk/test/sun/security/tools/jarsigner/ts.sh Wed Dec 02 16:44:57 2015 +0800
@@ -73,6 +73,10 @@
$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
--- a/jdk/test/sun/security/tools/jarsigner/warning.sh Wed Dec 02 16:44:54 2015 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
--- a/jdk/test/sun/security/tools/jarsigner/weaksize.sh Wed Dec 02 16:44:54 2015 +0800
+++ b/jdk/test/sun/security/tools/jarsigner/weaksize.sh Wed Dec 02 16:44:57 2015 +0800
@@ -52,9 +52,9 @@
$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