8270946: X509CertImpl.getFingerprint should not return the empty String

Reviewed-by: weijun
This commit is contained in:
Sean Mullan 2021-07-27 13:49:03 +00:00
parent 45d277feb0
commit fc80a6b493
6 changed files with 216 additions and 36 deletions

View file

@ -70,8 +70,14 @@ public class AnchorCertificates {
if (alias.contains(" [jdk")) {
X509Certificate cert = (X509Certificate) cacerts
.getCertificate(alias);
certs.add(X509CertImpl.getFingerprint(HASH, cert));
certIssuers.add(cert.getSubjectX500Principal());
String fp =
X509CertImpl.getFingerprint(HASH, cert, debug);
// only add trust anchor if fingerprint can
// be calculated
if (fp != null) {
certs.add(fp);
certIssuers.add(cert.getSubjectX500Principal());
}
}
}
}
@ -93,8 +99,8 @@ public class AnchorCertificates {
* @return true if the certificate is a JDK trust anchor
*/
public static boolean contains(X509Certificate cert) {
String key = X509CertImpl.getFingerprint(HASH, cert);
boolean result = certs.contains(key);
String key = X509CertImpl.getFingerprint(HASH, cert, debug);
boolean result = (key == null ? false : certs.contains(key));
if (result && debug != null) {
debug.println("AnchorCertificate.contains: matched " +
cert.getSubjectX500Principal());

View file

@ -28,7 +28,6 @@ import java.io.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.util.Properties;
import jdk.internal.util.StaticProperty;
@ -80,17 +79,9 @@ public final class UntrustedCertificates {
if (algorithm == null) {
return false;
}
String key;
if (cert instanceof X509CertImpl) {
key = ((X509CertImpl)cert).getFingerprint(algorithm);
} else {
try {
key = new X509CertImpl(cert.getEncoded()).getFingerprint(algorithm);
} catch (CertificateException cee) {
return false;
}
}
return props.containsKey(key);
// if fingerprint cannot be calculated, also treat it as untrusted
String key = X509CertImpl.getFingerprint(algorithm, cert, debug);
return (key == null || props.containsKey(key));
}
private UntrustedCertificates() {}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
@ -32,6 +32,7 @@ import java.util.Date;
import java.util.Map;
import java.util.Set;
import sun.security.util.Debug;
import sun.security.x509.X509CertImpl;
/**
@ -40,6 +41,8 @@ import sun.security.x509.X509CertImpl;
*/
final class SymantecTLSPolicy {
private static final Debug debug = Debug.getInstance("certpath");
// SHA-256 certificate fingerprints of distrusted roots
private static final Set<String> FINGERPRINTS = Set.of(
// cacerts alias: geotrustglobalca
@ -154,14 +157,24 @@ final class SymantecTLSPolicy {
static void checkDistrust(X509Certificate[] chain)
throws ValidatorException {
X509Certificate anchor = chain[chain.length-1];
if (FINGERPRINTS.contains(fingerprint(anchor))) {
String fp = fingerprint(anchor);
if (fp == null) {
throw new ValidatorException("Cannot generate fingerprint for "
+ "trust anchor of TLS server certificate");
}
if (FINGERPRINTS.contains(fp)) {
Date notBefore = chain[0].getNotBefore();
LocalDate ldNotBefore = LocalDate.ofInstant(notBefore.toInstant(),
ZoneOffset.UTC);
// check if chain goes through one of the subCAs
if (chain.length > 2) {
X509Certificate subCA = chain[chain.length-2];
LocalDate distrustDate = EXEMPT_SUBCAS.get(fingerprint(subCA));
fp = fingerprint(subCA);
if (fp == null) {
throw new ValidatorException("Cannot generate fingerprint "
+ "for intermediate CA of TLS server certificate");
}
LocalDate distrustDate = EXEMPT_SUBCAS.get(fp);
if (distrustDate != null) {
// reject if certificate is issued after specified date
checkNotBefore(ldNotBefore, distrustDate, anchor);
@ -174,9 +187,7 @@ final class SymantecTLSPolicy {
}
private static String fingerprint(X509Certificate cert) {
return (cert instanceof X509CertImpl)
? ((X509CertImpl)cert).getFingerprint("SHA-256")
: X509CertImpl.getFingerprint("SHA-256", cert);
return X509CertImpl.getFingerprint("SHA-256", cert, debug);
}
private static void checkNotBefore(LocalDate notBeforeDate,

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2021, 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
@ -1917,25 +1917,57 @@ public class X509CertImpl extends X509Certificate implements DerEncoder {
private ConcurrentHashMap<String,String> fingerprints =
new ConcurrentHashMap<>(2);
public String getFingerprint(String algorithm) {
private String getFingerprint(String algorithm, Debug debug) {
return fingerprints.computeIfAbsent(algorithm,
x -> getFingerprint(x, this));
x -> {
try {
return getFingerprintInternal(x, getEncodedInternal(), debug);
} catch (CertificateEncodingException e) {
if (debug != null) {
debug.println("Cannot encode certificate: " + e);
}
return null;
}
});
}
private static String getFingerprintInternal(String algorithm,
byte[] encodedCert, Debug debug) {
try {
MessageDigest md = MessageDigest.getInstance(algorithm);
byte[] digest = md.digest(encodedCert);
return HexFormat.of().withUpperCase().formatHex(digest);
} catch (NoSuchAlgorithmException e) {
if (debug != null) {
debug.println("Cannot create " + algorithm
+ " MessageDigest: " + e);
}
return null;
}
}
/**
* Gets the requested finger print of the certificate. The result
* Gets the requested fingerprint of the certificate. The result
* only contains 0-9 and A-F. No small case, no colon.
*
* @param algorithm the MessageDigest algorithm
* @param cert the X509Certificate
* @return the fingerprint, or null if it cannot be calculated because
* of an exception
*/
public static String getFingerprint(String algorithm,
X509Certificate cert) {
try {
byte[] encCertInfo = cert.getEncoded();
MessageDigest md = MessageDigest.getInstance(algorithm);
byte[] digest = md.digest(encCertInfo);
return HexFormat.of().withUpperCase().formatHex(digest);
} catch (NoSuchAlgorithmException | CertificateEncodingException e) {
// ignored
X509Certificate cert, Debug debug) {
if (cert instanceof X509CertImpl) {
return ((X509CertImpl)cert).getFingerprint(algorithm, debug);
} else {
try {
return getFingerprintInternal(algorithm, cert.getEncoded(), debug);
} catch (CertificateEncodingException e) {
if (debug != null) {
debug.println("Cannot encode certificate: " + e);
}
return null;
}
}
return "";
}
}