mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8172404: Tools should warn if weak algorithms are used before restricting them
Reviewed-by: mullan, weijun
This commit is contained in:
parent
9735678c26
commit
f04a7e5cb4
14 changed files with 713 additions and 228 deletions
|
@ -99,6 +99,10 @@ public class Main {
|
|||
new DisabledAlgorithmConstraints(
|
||||
DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
|
||||
|
||||
private static final DisabledAlgorithmConstraints LEGACY_CHECK =
|
||||
new DisabledAlgorithmConstraints(
|
||||
DisabledAlgorithmConstraints.PROPERTY_SECURITY_LEGACY_ALGS);
|
||||
|
||||
private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET = Collections
|
||||
.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
|
||||
private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections
|
||||
|
@ -172,6 +176,11 @@ public class Main {
|
|||
// If there is a time stamp block inside the PKCS7 block file
|
||||
boolean hasTimestampBlock = false;
|
||||
|
||||
private PublicKey weakPublicKey = null;
|
||||
private boolean disabledAlgFound = false;
|
||||
private String legacyDigestAlg = null;
|
||||
private String legacyTsaDigestAlg = null;
|
||||
private String legacySigAlg = null;
|
||||
|
||||
// Severe warnings.
|
||||
|
||||
|
@ -182,7 +191,8 @@ public class Main {
|
|||
// only tsaChainNotValidated is set, i.e. has no affect on hasExpiredCert,
|
||||
// notYetValidCert, or any badXyzUsage.
|
||||
|
||||
private int weakAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg
|
||||
private int legacyAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg, 8. key
|
||||
private int disabledAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg, 8. key
|
||||
private boolean hasExpiredCert = false;
|
||||
private boolean hasExpiredTsaCert = false;
|
||||
private boolean notYetValidCert = false;
|
||||
|
@ -199,8 +209,6 @@ public class Main {
|
|||
private Throwable chainNotValidatedReason = null;
|
||||
private Throwable tsaChainNotValidatedReason = null;
|
||||
|
||||
private boolean seeWeak = false;
|
||||
|
||||
PKIXBuilderParameters pkixParameters;
|
||||
Set<X509Certificate> trustedCerts = new HashSet<>();
|
||||
|
||||
|
@ -289,7 +297,7 @@ public class Main {
|
|||
|
||||
if (strict) {
|
||||
int exitCode = 0;
|
||||
if (weakAlg != 0 || chainNotValidated || hasExpiredCert
|
||||
if (disabledAlg != 0 || chainNotValidated || hasExpiredCert
|
||||
|| hasExpiredTsaCert || notYetValidCert || signerSelfSigned) {
|
||||
exitCode |= 4;
|
||||
}
|
||||
|
@ -910,7 +918,7 @@ public class Main {
|
|||
}
|
||||
|
||||
// Even if the verbose option is not specified, all out strings
|
||||
// must be generated so seeWeak can be updated.
|
||||
// must be generated so disabledAlgFound can be updated.
|
||||
if (!digestMap.isEmpty()
|
||||
|| !sigMap.isEmpty()
|
||||
|| !unparsableSignatures.isEmpty()) {
|
||||
|
@ -954,21 +962,21 @@ public class Main {
|
|||
history = String.format(
|
||||
rb.getString("history.with.ts"),
|
||||
signer.getSubjectX500Principal(),
|
||||
withWeak(digestAlg, DIGEST_PRIMITIVE_SET),
|
||||
withWeak(sigAlg, SIG_PRIMITIVE_SET),
|
||||
withWeak(key),
|
||||
verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false),
|
||||
verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false),
|
||||
verifyWithWeak(key),
|
||||
c,
|
||||
tsSigner.getSubjectX500Principal(),
|
||||
withWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET),
|
||||
withWeak(tsSigAlg, SIG_PRIMITIVE_SET),
|
||||
withWeak(tsKey));
|
||||
verifyWithWeak(tsDigestAlg, DIGEST_PRIMITIVE_SET, true),
|
||||
verifyWithWeak(tsSigAlg, SIG_PRIMITIVE_SET, true),
|
||||
verifyWithWeak(tsKey));
|
||||
} else {
|
||||
history = String.format(
|
||||
rb.getString("history.without.ts"),
|
||||
signer.getSubjectX500Principal(),
|
||||
withWeak(digestAlg, DIGEST_PRIMITIVE_SET),
|
||||
withWeak(sigAlg, SIG_PRIMITIVE_SET),
|
||||
withWeak(key));
|
||||
verifyWithWeak(digestAlg, DIGEST_PRIMITIVE_SET, false),
|
||||
verifyWithWeak(sigAlg, SIG_PRIMITIVE_SET, false),
|
||||
verifyWithWeak(key));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// The only usage of sigNameMap, remember the name
|
||||
|
@ -992,8 +1000,9 @@ public class Main {
|
|||
}
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
if (!anySigned) {
|
||||
if (seeWeak) {
|
||||
if (disabledAlgFound) {
|
||||
if (verbose != null) {
|
||||
System.out.println(rb.getString("jar.treated.unsigned.see.weak.verbose"));
|
||||
System.out.println("\n " +
|
||||
|
@ -1036,8 +1045,8 @@ public class Main {
|
|||
|
||||
if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
|
||||
notYetValidCert || chainNotValidated || hasExpiredCert ||
|
||||
hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) ||
|
||||
aliasNotInStore || notSignedByAlias ||
|
||||
hasUnsignedEntry || signerSelfSigned || (legacyAlg != 0) ||
|
||||
(disabledAlg != 0) || aliasNotInStore || notSignedByAlias ||
|
||||
tsaChainNotValidated ||
|
||||
(hasExpiredTsaCert && !signerNotExpired)) {
|
||||
|
||||
|
@ -1119,28 +1128,75 @@ public class Main {
|
|||
: rb.getString("This.jar.contains.entries.whose.signer.certificate.is.self.signed."));
|
||||
}
|
||||
|
||||
// weakAlg only detected in signing. The jar file is
|
||||
// now simply treated unsigned in verifying.
|
||||
if ((weakAlg & 1) == 1) {
|
||||
errors.add(String.format(
|
||||
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
|
||||
digestalg, "-digestalg"));
|
||||
}
|
||||
if (isSigning) {
|
||||
if ((legacyAlg & 1) == 1) {
|
||||
warnings.add(String.format(
|
||||
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."),
|
||||
digestalg, "-digestalg"));
|
||||
}
|
||||
|
||||
if ((weakAlg & 2) == 2) {
|
||||
errors.add(String.format(
|
||||
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
|
||||
sigalg, "-sigalg"));
|
||||
}
|
||||
if ((weakAlg & 4) == 4) {
|
||||
errors.add(String.format(
|
||||
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
|
||||
tSADigestAlg, "-tsadigestalg"));
|
||||
}
|
||||
if ((weakAlg & 8) == 8) {
|
||||
errors.add(String.format(
|
||||
rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk."),
|
||||
privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));
|
||||
if ((disabledAlg & 1) == 1) {
|
||||
errors.add(String.format(
|
||||
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk.and.is.disabled."),
|
||||
digestalg, "-digestalg"));
|
||||
}
|
||||
|
||||
if ((legacyAlg & 2) == 2) {
|
||||
warnings.add(String.format(
|
||||
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."),
|
||||
sigalg, "-sigalg"));
|
||||
}
|
||||
if ((disabledAlg & 2) == 2) {
|
||||
errors.add(String.format(
|
||||
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk.and.is.disabled."),
|
||||
sigalg, "-sigalg"));
|
||||
}
|
||||
|
||||
if ((legacyAlg & 4) == 4) {
|
||||
warnings.add(String.format(
|
||||
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."),
|
||||
tSADigestAlg, "-tsadigestalg"));
|
||||
}
|
||||
if ((disabledAlg & 4) == 4) {
|
||||
errors.add(String.format(
|
||||
rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk.and.is.disabled."),
|
||||
tSADigestAlg, "-tsadigestalg"));
|
||||
}
|
||||
|
||||
if ((legacyAlg & 8) == 8) {
|
||||
warnings.add(String.format(
|
||||
rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk..This.key.size.will.be.disabled.in.a.future.update."),
|
||||
privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));
|
||||
}
|
||||
if ((disabledAlg & 8) == 8) {
|
||||
errors.add(String.format(
|
||||
rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk.and.is.disabled."),
|
||||
privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));
|
||||
}
|
||||
} else {
|
||||
if ((legacyAlg & 1) != 0) {
|
||||
warnings.add(String.format(
|
||||
rb.getString("The.digest.algorithm.1.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."),
|
||||
legacyDigestAlg));
|
||||
}
|
||||
|
||||
if ((legacyAlg & 2) == 2) {
|
||||
warnings.add(String.format(
|
||||
rb.getString("The.signature.algorithm.1.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."),
|
||||
legacySigAlg));
|
||||
}
|
||||
|
||||
if ((legacyAlg & 4) != 0) {
|
||||
warnings.add(String.format(
|
||||
rb.getString("The.digest.algorithm.1.is.considered.a.security.risk..This.algorithm.will.be.disabled.in.a.future.update."),
|
||||
legacyTsaDigestAlg));
|
||||
}
|
||||
|
||||
if ((legacyAlg & 8) == 8) {
|
||||
warnings.add(String.format(
|
||||
rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk..This.key.size.will.be.disabled.in.a.future.update."),
|
||||
weakPublicKey.getAlgorithm(), KeyUtil.getKeySize(weakPublicKey)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = isSigning ? rb.getString("jar.signed.") : rb.getString("jar.verified.");
|
||||
|
@ -1249,27 +1305,84 @@ public class Main {
|
|||
}
|
||||
}
|
||||
|
||||
private String withWeak(String alg, Set<CryptoPrimitive> primitiveSet) {
|
||||
private String verifyWithWeak(String alg, Set<CryptoPrimitive> primitiveSet, boolean tsa) {
|
||||
if (DISABLED_CHECK.permits(primitiveSet, alg, null)) {
|
||||
return alg;
|
||||
if (LEGACY_CHECK.permits(primitiveSet, alg, null)) {
|
||||
return alg;
|
||||
} else {
|
||||
if (primitiveSet == SIG_PRIMITIVE_SET) {
|
||||
legacyAlg |= 2;
|
||||
legacySigAlg = alg;
|
||||
} else {
|
||||
if (tsa) {
|
||||
legacyAlg |= 4;
|
||||
legacyTsaDigestAlg = alg;
|
||||
} else {
|
||||
legacyAlg |= 1;
|
||||
legacyDigestAlg = alg;
|
||||
}
|
||||
}
|
||||
return String.format(rb.getString("with.weak"), alg);
|
||||
}
|
||||
} else {
|
||||
seeWeak = true;
|
||||
return String.format(rb.getString("with.weak"), alg);
|
||||
disabledAlgFound = true;
|
||||
return String.format(rb.getString("with.disabled"), alg);
|
||||
}
|
||||
}
|
||||
|
||||
private String withWeak(PublicKey key) {
|
||||
private String verifyWithWeak(PublicKey key) {
|
||||
int kLen = KeyUtil.getKeySize(key);
|
||||
if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
|
||||
int kLen = KeyUtil.getKeySize(key);
|
||||
if (kLen >= 0) {
|
||||
return String.format(rb.getString("key.bit"), kLen);
|
||||
if (LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
|
||||
if (kLen >= 0) {
|
||||
return String.format(rb.getString("key.bit"), kLen);
|
||||
} else {
|
||||
return rb.getString("unknown.size");
|
||||
}
|
||||
} else {
|
||||
return rb.getString("unknown.size");
|
||||
weakPublicKey = key;
|
||||
legacyAlg |= 8;
|
||||
return String.format(rb.getString("key.bit.weak"), kLen);
|
||||
}
|
||||
} else {
|
||||
seeWeak = true;
|
||||
return String.format(
|
||||
rb.getString("key.bit.weak"), KeyUtil.getKeySize(key));
|
||||
disabledAlgFound = true;
|
||||
return String.format(rb.getString("key.bit.disabled"), kLen);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkWeakSign(String alg, Set<CryptoPrimitive> primitiveSet, boolean tsa) {
|
||||
if (DISABLED_CHECK.permits(primitiveSet, alg, null)) {
|
||||
if (!LEGACY_CHECK.permits(primitiveSet, alg, null)) {
|
||||
if (primitiveSet == SIG_PRIMITIVE_SET) {
|
||||
legacyAlg |= 2;
|
||||
} else {
|
||||
if (tsa) {
|
||||
legacyAlg |= 4;
|
||||
} else {
|
||||
legacyAlg |= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (primitiveSet == SIG_PRIMITIVE_SET) {
|
||||
disabledAlg |= 2;
|
||||
} else {
|
||||
if (tsa) {
|
||||
disabledAlg |= 4;
|
||||
} else {
|
||||
disabledAlg |= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkWeakSign(PrivateKey key) {
|
||||
if (DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
|
||||
if (!LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
|
||||
legacyAlg |= 8;
|
||||
}
|
||||
} else {
|
||||
disabledAlg |= 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1496,22 +1609,22 @@ public class Main {
|
|||
void signJar(String jarName, String alias)
|
||||
throws Exception {
|
||||
|
||||
if (digestalg != null && !DISABLED_CHECK.permits(
|
||||
DIGEST_PRIMITIVE_SET, digestalg, null)) {
|
||||
weakAlg |= 1;
|
||||
if (digestalg == null) {
|
||||
digestalg = JarSigner.Builder.getDefaultDigestAlgorithm();
|
||||
}
|
||||
if (tSADigestAlg != null && !DISABLED_CHECK.permits(
|
||||
DIGEST_PRIMITIVE_SET, tSADigestAlg, null)) {
|
||||
weakAlg |= 4;
|
||||
checkWeakSign(digestalg, DIGEST_PRIMITIVE_SET, false);
|
||||
|
||||
if (tSADigestAlg == null) {
|
||||
tSADigestAlg = JarSigner.Builder.getDefaultDigestAlgorithm();
|
||||
}
|
||||
if (sigalg != null && !DISABLED_CHECK.permits(
|
||||
SIG_PRIMITIVE_SET , sigalg, null)) {
|
||||
weakAlg |= 2;
|
||||
}
|
||||
if (!DISABLED_CHECK.permits(
|
||||
SIG_PRIMITIVE_SET, privateKey)) {
|
||||
weakAlg |= 8;
|
||||
checkWeakSign(tSADigestAlg, DIGEST_PRIMITIVE_SET, true);
|
||||
|
||||
if (sigalg == null) {
|
||||
sigalg = JarSigner.Builder.getDefaultSignatureAlgorithm(privateKey);
|
||||
}
|
||||
checkWeakSign(sigalg, SIG_PRIMITIVE_SET, false);
|
||||
|
||||
checkWeakSign(privateKey);
|
||||
|
||||
boolean aliasUsed = false;
|
||||
X509Certificate tsaCert = null;
|
||||
|
@ -1748,7 +1861,6 @@ public class Main {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
displayMessagesAndResult(true);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue