8273236: keytool does not accurately warn about algorithms that are disabled but have additional constraints

Reviewed-by: mullan
This commit is contained in:
Hai-May Chao 2022-01-26 20:31:04 +00:00
parent 16e0ad0ad0
commit c2ee1b33c3
3 changed files with 433 additions and 56 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2022, 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
@ -31,10 +31,14 @@ import java.nio.file.Path;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.CertStoreException;
import java.security.cert.CRL;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateParsingException;
import java.security.cert.TrustAnchor;
import java.security.cert.URICertStoreParameters;
@ -43,6 +47,8 @@ import java.security.interfaces.EdECKey;
import java.security.spec.ECParameterSpec;
import java.text.Collator;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.BiFunction;
import java.util.jar.JarEntry;
@ -60,6 +66,7 @@ import javax.security.auth.x500.X500Principal;
import java.util.Base64;
import sun.security.pkcs12.PKCS12KeyStore;
import sun.security.provider.certpath.CertPathConstraintsParameters;
import sun.security.util.ECKeySizeParameterSpec;
import sun.security.util.KeyUtil;
import sun.security.util.NamedCurve;
@ -83,6 +90,7 @@ import sun.security.tools.KeyStoreUtil;
import sun.security.tools.PathList;
import sun.security.util.DerValue;
import sun.security.util.Pem;
import sun.security.validator.Validator;
import sun.security.x509.*;
import static java.security.KeyStore.*;
@ -178,6 +186,8 @@ public final class Main {
// Warnings on weak algorithms etc
private List<String> weakWarnings = new ArrayList<>();
private Set<X509Certificate> trustedCerts = new HashSet<>();
private static final DisabledAlgorithmConstraints DISABLED_CHECK =
new DisabledAlgorithmConstraints(
DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
@ -1118,6 +1128,7 @@ public final class Main {
}
}
KeyStore cakstore = buildTrustedCerts();
// -trustcacerts can be specified on -importcert, -printcert or -printcrl.
// Reset it so that warnings on CA cert will remain for other command.
if (command != IMPORTCERT && command != PRINTCERT
@ -1126,8 +1137,14 @@ public final class Main {
}
if (trustcacerts) {
if (cakstore != null) {
caks = cakstore;
} else {
// try to load cacerts again, and let exception propagate
// if it cannot be loaded
caks = KeyStoreUtil.getCacertsKeyStore();
}
}
// Perform the specified command
if (command == CERTREQ) {
@ -1485,7 +1502,9 @@ public final class Main {
byte[] rawReq = Pem.decode(new String(sb));
PKCS10 req = new PKCS10(rawReq);
checkWeak(rb.getString("the.certificate.request"), req);
CertPathConstraintsParameters cpcp = new CertPathConstraintsParameters(
req.getSubjectPublicKeyInfo(), null, null, null);
checkWeakConstraint(rb.getString("the.certificate.request"), req, cpcp);
info.set(X509CertInfo.KEY, new CertificateX509Key(req.getSubjectPublicKeyInfo()));
info.set(X509CertInfo.SUBJECT,
@ -1542,8 +1561,11 @@ public final class Main {
}
}
checkWeak(rb.getString("the.issuer"), keyStore.getCertificateChain(alias));
checkWeak(rb.getString("the.generated.certificate"), cert);
checkWeakConstraint(rb.getString("the.issuer"),
keyStore.getCertificateChain(alias));
cpcp = buildCertPathConstraint(cert, null);
checkWeakConstraint(rb.getString("the.generated.certificate"),
cert, cpcp);
}
private void doGenCRL(PrintStream out)
@ -1592,7 +1614,10 @@ public final class Main {
} else {
out.write(crl.getEncodedInternal());
}
checkWeak(rb.getString("the.generated.crl"), crl, privateKey);
CertPathConstraintsParameters cpcp = new CertPathConstraintsParameters(
privateKey, null, null, null);
checkWeakConstraint(rb.getString("the.generated.crl"), crl, privateKey,
cpcp);
}
/**
@ -1638,7 +1663,10 @@ public final class Main {
request.encodeAndSign(subject, privKey, sigAlgName);
request.print(out);
checkWeak(rb.getString("the.generated.certificate.request"), request);
CertPathConstraintsParameters cpcp = new CertPathConstraintsParameters(
request.getSubjectPublicKeyInfo(), null, null, null);
checkWeakConstraint(rb.getString("the.generated.certificate.request"),
request, cpcp);
}
/**
@ -1683,7 +1711,9 @@ public final class Main {
throw new Exception(form.format(source));
}
dumpCert(cert, out);
checkWeak(rb.getString("the.certificate"), cert);
CertPathConstraintsParameters cpcp =
buildCertPathConstraint(cert, null);
checkWeakConstraint(rb.getString("the.certificate"), cert, cpcp);
}
/**
@ -2021,7 +2051,8 @@ public final class Main {
} else {
finalChain = new Certificate[] { newCert };
}
checkWeak(rb.getString("the.generated.certificate"), finalChain);
checkWeakConstraint(rb.getString("the.generated.certificate"),
finalChain);
keyStore.setKeyEntry(alias, privKey, keyPass, finalChain);
}
@ -2114,6 +2145,7 @@ public final class Main {
private void doPrintEntry(String label, String alias, PrintStream out)
throws Exception
{
CertPathConstraintsParameters cpcp;
if (keyStore.containsAlias(alias) == false) {
MessageFormat form = new MessageFormat
(rb.getString("Alias.alias.does.not.exist"));
@ -2170,6 +2202,10 @@ public final class Main {
if (verbose || rfc || debug) {
out.println(rb.getString
("Certificate.chain.length.") + chain.length);
X509Certificate[] xcerts = convertCerts(chain);
List<X509Certificate> certs = Arrays.asList(xcerts);
TrustAnchor anchor = findTrustAnchor(certs);
for (int i = 0; i < chain.length; i ++) {
MessageFormat form = new MessageFormat
(rb.getString("Certificate.i.1."));
@ -2182,14 +2218,26 @@ public final class Main {
} else {
dumpCert(chain[i], out);
}
checkWeak(label, chain[i]);
if (i == 0 &&
((X509Certificate)chain[0]).
getBasicConstraints() == -1) {
// this is an EE
cpcp = buildCertPathConstraint((X509Certificate) chain[i], anchor);
} else {
cpcp = new CertPathConstraintsParameters(
(X509Certificate)chain[i], null, anchor,
null);
}
checkWeakConstraint(label, chain[i], cpcp);
}
} else {
// Print the digest of the user cert only
out.println
(rb.getString("Certificate.fingerprint.SHA.256.") +
getCertFingerPrint("SHA-256", chain[0]));
checkWeak(label, chain);
checkWeakConstraint(label, chain);
}
} else {
out.println(rb.getString
@ -2215,7 +2263,8 @@ public final class Main {
out.println(rb.getString("Certificate.fingerprint.SHA.256.")
+ getCertFingerPrint("SHA-256", cert));
}
checkWeak(label, cert);
cpcp = buildCertPathConstraint((X509Certificate)cert, null);
checkWeakConstraint(label, cert, cpcp);
} else {
out.println(rb.getString("Unknown.Entry.Type"));
}
@ -2442,7 +2491,9 @@ public final class Main {
try {
Certificate c = srckeystore.getCertificate(alias);
if (c != null) {
checkWeak("<" + newAlias + ">", c);
CertPathConstraintsParameters cpcp =
buildCertPathConstraint((X509Certificate)c, null);
checkWeakConstraint("<" + newAlias + ">", c, cpcp);
}
keyStore.setEntry(newAlias, entry, pp);
// Place the check so that only successful imports are blocked.
@ -2639,11 +2690,14 @@ public final class Main {
issuer = verifyCRL(caks, crl);
if (issuer != null) {
signer = caks.getCertificate(issuer);
CertPathConstraintsParameters cpcp =
buildCertPathConstraint((X509Certificate)signer,
null);
out.printf(rb.getString(
"verified.by.s.in.s.weak"),
issuer,
"cacerts",
withWeak(signer.getPublicKey()));
withWeakConstraint(signer.getPublicKey(), cpcp));
out.println();
}
}
@ -2651,11 +2705,14 @@ public final class Main {
issuer = verifyCRL(keyStore, crl);
if (issuer != null) {
signer = keyStore.getCertificate(issuer);
CertPathConstraintsParameters cpcp =
buildCertPathConstraint((X509Certificate)signer,
null);
out.printf(rb.getString(
"verified.by.s.in.s.weak"),
issuer,
"keystore",
withWeak(signer.getPublicKey()));
withWeakConstraint(signer.getPublicKey(), cpcp));
out.println();
}
}
@ -2672,7 +2729,15 @@ public final class Main {
out.println(rb.getString
("STARNN"));
}
checkWeak(rb.getString("the.crl"), crl, signer == null ? null : signer.getPublicKey());
if (signer != null) {
CertPathConstraintsParameters cpcp =
buildCertPathConstraint((X509Certificate)signer, null);
checkWeakConstraint(rb.getString("the.crl"), crl,
signer.getPublicKey(), cpcp);
} else {
checkWeak(rb.getString("the.crl"), crl, null);
}
}
}
@ -2718,10 +2783,12 @@ public final class Main {
PKCS10 req = new PKCS10(Pem.decode(new String(sb)));
PublicKey pkey = req.getSubjectPublicKeyInfo();
CertPathConstraintsParameters cpcp =
new CertPathConstraintsParameters(pkey, null, null, null);
out.printf(rb.getString("PKCS.10.with.weak"),
req.getSubjectName(),
pkey.getFormat(),
withWeak(pkey),
withWeakConstraint(pkey, cpcp),
withWeak(req.getSigAlg()));
for (PKCS10Attribute attr: req.getAttributes().getAttributes()) {
ObjectIdentifier oid = attr.getAttributeId();
@ -2745,7 +2812,12 @@ public final class Main {
if (debug) {
out.println(req); // Just to see more, say, public key length...
}
checkWeak(rb.getString("the.certificate.request"), req);
CertPathConstraintsParameters cpcp1 =
new CertPathConstraintsParameters(
req.getSubjectPublicKeyInfo(), null, null, null);
checkWeakConstraint(rb.getString("the.certificate.request"), req,
cpcp1);
}
/**
@ -2765,6 +2837,9 @@ public final class Main {
throw new Exception(rb.getString("Empty.input"));
}
Certificate[] certs = c.toArray(new Certificate[c.size()]);
X509Certificate[] xcerts = convertCerts(certs);
List<X509Certificate> chain = Arrays.asList(xcerts);
TrustAnchor anchor = findTrustAnchor(chain);
for (int i=0; i<certs.length; i++) {
X509Certificate x509Cert = null;
try {
@ -2785,7 +2860,17 @@ public final class Main {
if (i < (certs.length-1)) {
out.println();
}
checkWeak(oneInMany(rb.getString("the.certificate"), i, certs.length), x509Cert);
CertPathConstraintsParameters cpcp;
if (i == 0 &&
x509Cert.getBasicConstraints() == -1) {
// this is an EE
cpcp = buildCertPathConstraint(x509Cert, anchor);
} else {
cpcp = new CertPathConstraintsParameters(x509Cert,
null, anchor, null);
}
checkWeakConstraint(oneInMany(rb.getString("the.certificate"),
i, certs.length), x509Cert, cpcp);
}
}
@ -2901,6 +2986,11 @@ public final class Main {
List<? extends Certificate> certs
= signer.getSignerCertPath().getCertificates();
@SuppressWarnings("unchecked")
List<X509Certificate> chain =
(List<X509Certificate>)certs;
TrustAnchor anchor = findTrustAnchor(chain);
CertPathConstraintsParameters cpcp;
int cc = 0;
for (Certificate cert: certs) {
out.printf(rb.getString("Certificate.d."), ++cc);
@ -2913,16 +3003,27 @@ public final class Main {
printX509Cert(x, out);
}
out.println();
checkWeak(oneInManys(rb.getString(
if (cc == 0 && x.getBasicConstraints() == -1) {
// this is an EE
cpcp = buildCertPathConstraint(x, anchor);
} else {
cpcp = new CertPathConstraintsParameters(
x, null, anchor, null);
}
checkWeakConstraint(oneInManys(rb.getString(
"the.certificate"), cc,
certs.size(), pos,
ss.size()), x);
ss.size()), x, cpcp);
}
Timestamp ts = signer.getTimestamp();
if (ts != null) {
out.println(rb.getString("Timestamp."));
out.println();
certs = ts.getSignerCertPath().getCertificates();
@SuppressWarnings("unchecked")
List<X509Certificate> tschain =
(List<X509Certificate>)certs;
anchor = findTrustAnchor(tschain);
cc = 0;
for (Certificate cert: certs) {
out.printf(rb.getString("Certificate.d."), ++cc);
@ -2935,10 +3036,18 @@ public final class Main {
printX509Cert(x, out);
}
out.println();
checkWeak(oneInManys(rb.getString(
if (cc == 0 &&
x.getBasicConstraints() == -1) {
// this is an EE
cpcp = buildCertPathConstraint(x, anchor);
} else {
cpcp = new CertPathConstraintsParameters(
x, null, anchor, null);
}
checkWeakConstraint(oneInManys(rb.getString(
"the.tsa.certificate"), cc,
certs.size(), pos,
ss.size()), x);
ss.size()), x, cpcp);
}
}
}
@ -2968,6 +3077,9 @@ public final class Main {
}
int i = 0;
@SuppressWarnings("unchecked")
List<X509Certificate> xcerts = (List<X509Certificate>)chain;
TrustAnchor anchor = findTrustAnchor(xcerts);
for (Certificate cert : chain) {
try {
if (rfc) {
@ -2978,7 +3090,17 @@ public final class Main {
printX509Cert((X509Certificate)cert, out);
out.println();
}
checkWeak(oneInMany(rb.getString("the.certificate"), i++, chain.size()), cert);
X509Certificate x = (X509Certificate)cert;
CertPathConstraintsParameters cpcp;
if (i == 0 && x.getBasicConstraints() == -1) {
// this is an EE
cpcp = buildCertPathConstraint(x, anchor);
} else {
cpcp = new CertPathConstraintsParameters(
x, null, anchor, null);
}
checkWeakConstraint(oneInMany(rb.getString(
"the.certificate"), i++, chain.size()), x, cpcp);
} catch (Exception e) {
if (debug) {
e.printStackTrace();
@ -3202,8 +3324,11 @@ public final class Main {
throw new Exception(rb.getString("Input.not.an.X.509.certificate"));
}
CertPathConstraintsParameters cpcp =
buildCertPathConstraint(cert, null);
if (noprompt) {
checkWeak(rb.getString("the.input"), cert);
checkWeakConstraint(rb.getString("the.input"), cert, cpcp);
keyStore.setCertificateEntry(alias, cert);
return true;
}
@ -3223,7 +3348,7 @@ public final class Main {
("Certificate.already.exists.in.keystore.under.alias.trustalias."));
Object[] source = {trustalias};
System.err.println(form.format(source));
checkWeak(rb.getString("the.input"), cert);
checkWeakConstraint(rb.getString("the.input"), cert, cpcp);
printWeakWarnings(true);
reply = getYesNoReply
(rb.getString("Do.you.still.want.to.add.it.no."));
@ -3234,7 +3359,7 @@ public final class Main {
("Certificate.already.exists.in.system.wide.CA.keystore.under.alias.trustalias."));
Object[] source = {trustalias};
System.err.println(form.format(source));
checkWeak(rb.getString("the.input"), cert);
checkWeakConstraint(rb.getString("the.input"), cert, cpcp);
printWeakWarnings(true);
reply = getYesNoReply
(rb.getString("Do.you.still.want.to.add.it.to.your.own.keystore.no."));
@ -3243,7 +3368,7 @@ public final class Main {
// Print the cert and ask user if they really want to add
// it to their keystore
printX509Cert(cert, System.out);
checkWeak(rb.getString("the.input"), cert);
checkWeakConstraint(rb.getString("the.input"), cert, cpcp);
printWeakWarnings(true);
reply = getYesNoReply
(rb.getString("Trust.this.certificate.no."));
@ -3270,7 +3395,7 @@ public final class Main {
// Print the cert and ask user if they really want to add it to
// their keystore
printX509Cert(cert, System.out);
checkWeak(rb.getString("the.input"), cert);
checkWeakConstraint(rb.getString("the.input"), cert, cpcp);
printWeakWarnings(true);
reply = getYesNoReply
(rb.getString("Trust.this.certificate.no."));
@ -3410,6 +3535,21 @@ public final class Main {
return keyPass;
}
private String withWeakConstraint(String alg,
CertPathConstraintsParameters cpcp) {
try {
DISABLED_CHECK.permits(alg, cpcp, false);
} catch (CertPathValidatorException e) {
return String.format(rb.getString("with.disabled"), alg);
}
try {
LEGACY_CHECK.permits(alg, cpcp, false);
return alg;
} catch (CertPathValidatorException e) {
return String.format(rb.getString("with.weak"), alg);
}
}
private String withWeak(String alg) {
if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, alg, null)) {
if (LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, alg, null)) {
@ -3436,22 +3576,25 @@ public final class Main {
return result;
}
private String withWeak(Key key) {
private String withWeakConstraint(Key key,
CertPathConstraintsParameters cpcp) {
int kLen = KeyUtil.getKeySize(key);
String displayAlg = fullDisplayAlgName(key);
if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
if (LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
try {
DISABLED_CHECK.permits(key.getAlgorithm(), cpcp, true);
} catch (CertPathValidatorException e) {
return String.format(rb.getString("key.bit.disabled"), kLen, displayAlg);
}
try {
LEGACY_CHECK.permits(key.getAlgorithm(), cpcp, true);
if (kLen >= 0) {
return String.format(rb.getString("key.bit"), kLen, displayAlg);
} else {
return String.format(rb.getString("unknown.size.1"), displayAlg);
}
} else {
} catch (CertPathValidatorException e) {
return String.format(rb.getString("key.bit.weak"), kLen, displayAlg);
}
} else {
return String.format(rb.getString("key.bit.disabled"), kLen, displayAlg);
}
}
/**
@ -3465,9 +3608,11 @@ public final class Main {
(rb.getString(".PATTERN.printX509Cert.with.weak"));
PublicKey pkey = cert.getPublicKey();
String sigName = cert.getSigAlgName();
CertPathConstraintsParameters cpcp =
buildCertPathConstraint(cert, null);
// No need to warn about sigalg of a trust anchor
if (!isTrustedCert(cert)) {
sigName = withWeak(sigName);
sigName = withWeakConstraint(sigName, cpcp);
}
Object[] source = {cert.getSubjectX500Principal().toString(),
cert.getIssuerX500Principal().toString(),
@ -3477,7 +3622,7 @@ public final class Main {
getCertFingerPrint("SHA-1", cert),
getCertFingerPrint("SHA-256", cert),
sigName,
withWeak(pkey),
withWeakConstraint(pkey, cpcp),
cert.getVersion()
};
out.println(form.format(source));
@ -3801,7 +3946,7 @@ public final class Main {
throws Exception
{
checkWeak(rb.getString("reply"), replyCerts);
checkWeakConstraint(rb.getString("reply"), replyCerts);
// order the certs in the reply (bottom-up).
// we know that all certs in the reply are of type X.509, because
@ -3883,11 +4028,14 @@ public final class Main {
replyCerts.length);
tmpCerts[tmpCerts.length-1] = root.snd;
replyCerts = tmpCerts;
checkWeak(String.format(fromKeyStore
CertPathConstraintsParameters cpcp =
buildCertPathConstraint((X509Certificate)root.snd,
null);
checkWeakConstraint(String.format(fromKeyStore
? rb.getString("alias.in.keystore")
: rb.getString("alias.in.cacerts"),
root.fst),
root.snd);
root.snd, cpcp);
}
}
return replyCerts;
@ -3952,7 +4100,9 @@ public final class Main {
(X509Certificate) certToVerify),
chain, certs)) {
for (Pair<String,X509Certificate> p : chain) {
checkWeak(p.fst, p.snd);
CertPathConstraintsParameters cpcp =
buildCertPathConstraint(p.snd, null);
checkWeakConstraint(p.fst, p.snd, cpcp);
}
Certificate[] newChain =
new Certificate[chain.size()];
@ -4748,6 +4898,78 @@ public final class Main {
}
}
private void checkWeakConstraint(String label, String sigAlg, Key key,
CertPathConstraintsParameters cpcp) throws Exception {
if (sigAlg != null) {
try {
DISABLED_CHECK.permits(sigAlg, cpcp, false);
try {
LEGACY_CHECK.permits(sigAlg, cpcp, false);
} catch (CertPathValidatorException e) {
weakWarnings.add(String.format(
rb.getString("whose.sigalg.weak"), label, sigAlg));
}
} catch (CertPathValidatorException e) {
String eMessage = e.getMessage();
if (eMessage.contains("denyAfter constraint check failed") &&
e.getReason() == BasicReason.ALGORITHM_CONSTRAINED) {
String startSeparator = "Constraint date: ";
int startSepPos = eMessage.indexOf(startSeparator);
String endSeparator = "; params date";
int endSepPos = eMessage.indexOf(endSeparator);
String denyAfterDate = null;
try {
denyAfterDate = eMessage.substring(startSepPos + startSeparator.length(),
endSepPos);
} catch (IndexOutOfBoundsException e1) {
throw new Exception(rb.getString(
"Unable.to.parse.denyAfter.string.in.exception.message"));
}
SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy");
Date dateObj = null;
try {
dateObj = formatter.parse(denyAfterDate);
} catch (ParseException e2) {
throw new Exception(rb.getString(
"Unable.to.parse.denyAfter.string.in.exception.message"));
}
formatter = new SimpleDateFormat("yyyy-MM-dd");
denyAfterDate = formatter.format(dateObj);
weakWarnings.add(String.format(
rb.getString("whose.sigalg.usagesignedjar"), label, sigAlg,
denyAfterDate));
} else {
weakWarnings.add(String.format(
rb.getString("whose.sigalg.disabled"), label, sigAlg));
}
if (debug) {
e.printStackTrace();
}
}
}
if (key != null) {
try {
DISABLED_CHECK.permits(key.getAlgorithm(), cpcp, true);
try {
LEGACY_CHECK.permits(key.getAlgorithm(), cpcp, true);
} catch (CertPathValidatorException e) {
weakWarnings.add(String.format(
rb.getString("whose.key.weak"), label,
String.format(rb.getString("key.bit"),
KeyUtil.getKeySize(key), fullDisplayAlgName(key))));
}
} catch (CertPathValidatorException e) {
weakWarnings.add(String.format(
rb.getString("whose.key.disabled"), label,
String.format(rb.getString("key.bit"),
KeyUtil.getKeySize(key), fullDisplayAlgName(key))));
}
}
}
private void checkWeak(String label, String sigAlg, Key key) {
if (sigAlg != null) {
if (!DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, sigAlg, null)) {
@ -4774,8 +4996,11 @@ public final class Main {
}
}
private void checkWeak(String label, Certificate[] certs)
throws KeyStoreException {
private void checkWeakConstraint(String label, Certificate[] certs)
throws KeyStoreException, Exception {
X509Certificate[] xcerts = convertCerts(certs);
List<X509Certificate> chain = Arrays.asList(xcerts);
TrustAnchor anchor = findTrustAnchor(chain);
for (int i = 0; i < certs.length; i++) {
Certificate cert = certs[i];
if (cert instanceof X509Certificate) {
@ -4784,23 +5009,43 @@ public final class Main {
if (certs.length > 1) {
fullLabel = oneInMany(label, i, certs.length);
}
checkWeak(fullLabel, xc);
CertPathConstraintsParameters cpcp = null;
if (i == 0 && xc.getBasicConstraints() == -1) {
// this is an EE
cpcp = buildCertPathConstraint(xc, anchor);
} else {
cpcp = new CertPathConstraintsParameters(
xc, null, anchor, null);
}
checkWeakConstraint(fullLabel, xc, cpcp);
}
}
}
private void checkWeak(String label, Certificate cert)
throws KeyStoreException {
private void checkWeakConstraint(String label, Certificate cert,
CertPathConstraintsParameters cpcp)
throws KeyStoreException, Exception {
if (cert instanceof X509Certificate) {
X509Certificate xc = (X509Certificate)cert;
// No need to check the sigalg of a trust anchor
String sigAlg = isTrustedCert(cert) ? null : xc.getSigAlgName();
checkWeak(label, sigAlg, xc.getPublicKey());
checkWeakConstraint(label, sigAlg, xc.getPublicKey(), cpcp);
}
}
private void checkWeak(String label, PKCS10 p10) {
checkWeak(label, p10.getSigAlg(), p10.getSubjectPublicKeyInfo());
private void checkWeakConstraint(String label, PKCS10 p10,
CertPathConstraintsParameters cpcp) throws Exception {
checkWeakConstraint(label, p10.getSigAlg(),
p10.getSubjectPublicKeyInfo(), cpcp);
}
private void checkWeakConstraint(String label, CRL crl, Key key,
CertPathConstraintsParameters cpcp) throws Exception {
if (crl instanceof X509CRLImpl) {
X509CRLImpl impl = (X509CRLImpl)crl;
checkWeakConstraint(label, impl.getSigAlgName(), key, cpcp);
}
}
private void checkWeak(String label, CRL crl, Key key) {
@ -4810,6 +5055,76 @@ public final class Main {
}
}
private KeyStore buildTrustedCerts() {
KeyStore caks = null;
try {
caks = KeyStoreUtil.getCacertsKeyStore();
if (caks != null) {
Enumeration<String> aliases = caks.aliases();
while (aliases.hasMoreElements()) {
String a = aliases.nextElement();
try {
trustedCerts.add((X509Certificate)caks.getCertificate(a));
} catch (Exception e2) {
// ignore, if the keystore has not been loaded/initialized properly
}
}
}
} catch (Exception e) {
// Ignore, if cacerts cannot be loaded
}
return caks;
}
private TrustAnchor findTrustAnchor(List<X509Certificate> chain) {
if (chain.isEmpty()) {
return null;
}
X509Certificate last = chain.get(chain.size() - 1);
Optional<X509Certificate> trusted =
trustedCerts.stream()
.filter(c -> c.getSubjectX500Principal().equals(last.getIssuerX500Principal()))
.findFirst();
return trusted.isPresent() ? new TrustAnchor(trusted.get(), null) : null;
}
private X509Certificate[] convertCerts(Certificate[] certs) {
X509Certificate[] xcerts = new X509Certificate[certs.length];
for (int i = 0; i < certs.length; i++) {
if (certs[i] instanceof X509Certificate) {
xcerts[i] = (X509Certificate) certs[i];
}
}
return xcerts;
}
private CertPathConstraintsParameters buildCertPathConstraint(
X509Certificate xcert, TrustAnchor anchor) throws Exception{
List<String> eku = xcert.getExtendedKeyUsage();
if (eku == null) {
return new CertPathConstraintsParameters(xcert, null,
anchor, null);
}
if (eku.contains(KnownOIDs.codeSigning.value())) {
return new CertPathConstraintsParameters(xcert,
Validator.VAR_CODE_SIGNING, anchor, null);
} else if (eku.contains(KnownOIDs.clientAuth.value())) {
return new CertPathConstraintsParameters(xcert,
Validator.VAR_TLS_CLIENT, anchor, null);
} else if (eku.contains(KnownOIDs.serverAuth.value())) {
return new CertPathConstraintsParameters(xcert,
Validator.VAR_TLS_SERVER, anchor, null);
} else if (eku.contains(KnownOIDs.KP_TimeStamping.value())) {
return new CertPathConstraintsParameters(xcert,
Validator.VAR_TSA_SERVER, anchor, null);
}
return new CertPathConstraintsParameters(xcert, Validator.VAR_GENERIC,
anchor, null);
}
private void printWeakWarnings(boolean newLine) {
if (!weakWarnings.isEmpty() && !nowarn) {
System.err.println("\nWarning:");

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, 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
@ -483,6 +483,8 @@ public class Resources extends java.util.ListResourceBundle {
"Subject: %1$s\nFormat: %2$s\nPublic Key: %3$s\nSignature algorithm: %4$s\n"},
{"verified.by.s.in.s.weak", "Verified by %1$s in %2$s with a %3$s"},
{"whose.sigalg.disabled", "%1$s uses the %2$s signature algorithm which is considered a security risk and is disabled."},
{"whose.sigalg.usagesignedjar", "%1$s uses the %2$s signature algorithm which is considered a security risk and cannot be used to sign JARs after %3$s."},
{"Unable.to.parse.denyAfter.string.in.exception.message", "Unable to parse denyAfter date string in exception message"},
{"whose.sigalg.weak", "%1$s uses the %2$s signature algorithm which is considered a security risk. This algorithm will be disabled in a future update."},
{"whose.key.disabled", "%1$s uses a %2$s which is considered a security risk and is disabled."},
{"whose.key.weak", "%1$s uses a %2$s which is considered a security risk. This key size will be disabled in a future update."},

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2022, 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 8273236
* @summary Test SHA1 usage SignedJAR
* @library /test/lib
*/
import jdk.test.lib.SecurityTools;
import jdk.test.lib.process.OutputAnalyzer;
public class TestSha1Usage {
static OutputAnalyzer kt(String cmd, String ks) throws Exception {
return SecurityTools.keytool("-storepass changeit " + cmd +
" -keystore " + ks);
}
public static void main(String[] args) throws Exception {
SecurityTools.keytool("-keystore ks -storepass changeit " +
"-genkeypair -keyalg rsa -alias ca -dname CN=CA " +
"-ext eku=codeSigning -sigalg SHA1withRSA")
.shouldContain("Warning:")
.shouldMatch("The generated certificate.*SHA1withRSA.*considered a security risk")
.shouldMatch("cannot be used to sign JARs")
.shouldHaveExitValue(0);
kt("-genkeypair -keyalg rsa -alias e1 -dname CN=E1", "ks");
kt("-certreq -alias e1 -file tmp.req", "ks");
SecurityTools.keytool("-keystore ks -storepass changeit " +
"-gencert -alias ca -infile tmp.req -outfile tmp.cert")
.shouldContain("Warning:")
.shouldMatch("The issuer.*SHA1withRSA.*considered a security risk")
.shouldMatch("cannot be used to sign JARs")
.shouldHaveExitValue(0);
}
}