8309966: Enhanced TLS connections

Reviewed-by: mschoene, hchao, rhalade, jnimeh
This commit is contained in:
Sean Mullan 2023-08-08 19:06:37 +00:00 committed by Henry Jen
parent adca97b659
commit 7c80cb26df
6 changed files with 96 additions and 169 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2023, 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
@ -26,14 +26,10 @@
package sun.security.provider.certpath;
import java.util.Date;
import java.util.Set;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CertSelector;
import java.security.cert.X509CRLSelector;
import sun.security.x509.GeneralNameInterface;
/**
* Helper class that allows access to JDK specific known-public methods in the
* java.security.cert package. It relies on a subclass in the
@ -55,18 +51,10 @@ public abstract class CertPathHelper {
// empty
}
protected abstract void implSetPathToNames(X509CertSelector sel,
Set<GeneralNameInterface> names);
protected abstract void implSetDateAndTime(X509CRLSelector sel, Date date, long skew);
protected abstract boolean implIsJdkCA(TrustAnchor anchor);
static void setPathToNames(X509CertSelector sel,
Set<GeneralNameInterface> names) {
instance.implSetPathToNames(sel, names);
}
public static void setDateAndTime(X509CRLSelector sel, Date date, long skew) {
instance.implSetDateAndTime(sel, date, skew);
}

View file

@ -47,7 +47,6 @@ import sun.security.x509.AccessDescription;
import sun.security.x509.AuthorityInfoAccessExtension;
import sun.security.x509.AuthorityKeyIdentifierExtension;
import static sun.security.x509.PKIXExtensions.*;
import sun.security.x509.SubjectAlternativeNameExtension;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
@ -257,14 +256,6 @@ final class ForwardBuilder extends Builder {
*/
caSelector.setSubject(currentState.issuerDN);
/*
* Match on subjectNamesTraversed (both DNs and AltNames)
* (checks that current cert's name constraints permit it
* to certify all the DNs and AltNames that have been traversed)
*/
CertPathHelper.setPathToNames
(caSelector, currentState.subjectNamesTraversed);
/*
* check the validity period
*/
@ -697,19 +688,6 @@ final class ForwardBuilder extends Builder {
// Don't bother to verify untrusted certificate more.
currState.untrustedChecker.check(cert, Collections.emptySet());
/*
* Abort if we encounter the same certificate or a certificate with
* the same public key, subject DN, and subjectAltNames as a cert
* that is already in path.
*/
for (X509Certificate cpListCert : certPathList) {
if (repeated(cpListCert, cert)) {
throw new CertPathValidatorException(
"cert with repeated subject, public key, and " +
"subjectAltNames detected");
}
}
/* check if trusted cert */
boolean isTrustedCert = trustedCerts.contains(cert);
@ -787,49 +765,6 @@ final class ForwardBuilder extends Builder {
}
}
/**
* Return true if two certificates are equal or have the same subject,
* public key, and subject alternative names.
*/
private static boolean repeated(
X509Certificate currCert, X509Certificate nextCert) {
if (currCert.equals(nextCert)) {
return true;
}
return (currCert.getSubjectX500Principal().equals(
nextCert.getSubjectX500Principal()) &&
currCert.getPublicKey().equals(nextCert.getPublicKey()) &&
altNamesEqual(currCert, nextCert));
}
/**
* Return true if two certificates have the same subject alternative names.
*/
private static boolean altNamesEqual(
X509Certificate currCert, X509Certificate nextCert) {
X509CertImpl curr, next;
try {
curr = X509CertImpl.toImpl(currCert);
next = X509CertImpl.toImpl(nextCert);
} catch (CertificateException ce) {
return false;
}
SubjectAlternativeNameExtension currAltNameExt =
curr.getSubjectAlternativeNameExtension();
SubjectAlternativeNameExtension nextAltNameExt =
next.getSubjectAlternativeNameExtension();
if (currAltNameExt != null) {
if (nextAltNameExt == null) {
return false;
}
return Arrays.equals(currAltNameExt.getExtensionValue(),
nextAltNameExt.getExtensionValue());
} else {
return (nextAltNameExt == null);
}
}
/**
* Verifies whether the input certificate completes the path.
* First checks the cert against each trust anchor that was specified,

View file

@ -31,17 +31,11 @@ import java.security.cert.CertPathValidatorException;
import java.security.cert.PKIXCertPathChecker;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import javax.security.auth.x500.X500Principal;
import sun.security.util.Debug;
import sun.security.x509.SubjectAlternativeNameExtension;
import sun.security.x509.GeneralNames;
import sun.security.x509.GeneralName;
import sun.security.x509.GeneralNameInterface;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
/**
@ -61,9 +55,6 @@ class ForwardState implements State {
/* The last cert in the path */
X509CertImpl cert;
/* The set of subjectDNs and subjectAltNames of all certs in the path */
HashSet<GeneralNameInterface> subjectNamesTraversed;
/*
* The number of intermediate CA certs which have been traversed so
* far in the path
@ -73,7 +64,6 @@ class ForwardState implements State {
/* Flag indicating if state is initial (path is just starting) */
private boolean init = true;
/* the untrusted certificates checker */
UntrustedChecker untrustedChecker;
@ -103,8 +93,6 @@ class ForwardState implements State {
"\n issuerDN of last cert: " + issuerDN +
"\n traversedCACerts: " + traversedCACerts +
"\n init: " + init +
"\n subjectNamesTraversed: \n" +
subjectNamesTraversed +
"\n selfIssued: " + selfIssued + "\n" +
"]\n";
}
@ -117,7 +105,6 @@ class ForwardState implements State {
public void initState(List<PKIXCertPathChecker> certPathCheckers)
throws CertPathValidatorException
{
subjectNamesTraversed = new HashSet<>();
traversedCACerts = 0;
/*
@ -167,22 +154,6 @@ class ForwardState implements State {
}
}
/* update subjectNamesTraversed only if this is the EE cert or if
this cert is not self-issued */
if (init || !selfIssued) {
X500Principal subjName = cert.getSubjectX500Principal();
subjectNamesTraversed.add(X500Name.asX500Name(subjName));
SubjectAlternativeNameExtension subjAltNameExt
= icert.getSubjectAlternativeNameExtension();
if (subjAltNameExt != null) {
GeneralNames gNames = subjAltNameExt.getNames();
for (GeneralName gName : gNames.names()) {
subjectNamesTraversed.add(gName.getName());
}
}
}
init = false;
}
@ -190,10 +161,6 @@ class ForwardState implements State {
* Clone current state. The state is cloned as each cert is
* added to the path. This is necessary if backtracking occurs,
* and a prior state needs to be restored.
*
* Note that this is a SMART clone. Not all fields are fully copied,
* because some of them will
* not have their contents modified by subsequent calls to updateState.
*/
@Override
@SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
@ -213,13 +180,6 @@ class ForwardState implements State {
}
}
/*
* Shallow copy traversed names. There is no need to
* deep copy contents, since the elements of the Set
* are never modified by subsequent calls to updateState().
*/
clonedState.subjectNamesTraversed
= (HashSet<GeneralNameInterface>)subjectNamesTraversed.clone();
return clonedState;
} catch (CloneNotSupportedException e) {
throw new InternalError(e.toString(), e);

View file

@ -33,6 +33,7 @@ import java.security.cert.*;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.PKIXReason;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -42,6 +43,7 @@ import javax.security.auth.x500.X500Principal;
import sun.security.provider.certpath.PKIX.BuilderParams;
import static sun.security.x509.PKIXExtensions.*;
import sun.security.x509.SubjectAlternativeNameExtension;
import sun.security.x509.X509CertImpl;
import sun.security.util.Debug;
@ -265,7 +267,7 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
*/
Collection<X509Certificate> certs =
builder.getMatchingCerts(currentState, buildParams.certStores());
List<Vertex> vertices = addVertices(certs, adjList);
List<Vertex> vertices = addVertices(certs, adjList, cpList);
if (debug != null) {
debug.println("SunCertPathBuilder.depthFirstSearchForward(): "
+ "certs.size=" + vertices.size());
@ -325,33 +327,9 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
* cert (which is signed by the trusted public key), but
* don't add it yet to the cpList
*/
if (builder.trustAnchor.getTrustedCert() == null) {
appendedCerts.add(0, cert);
}
Set<String> initExpPolSet =
Collections.singleton(PolicyChecker.ANY_POLICY);
PolicyNodeImpl rootNode = new PolicyNodeImpl(null,
PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false);
List<PKIXCertPathChecker> checkers = new ArrayList<>();
PolicyChecker policyChecker
= new PolicyChecker(buildParams.initialPolicies(),
appendedCerts.size(),
buildParams.explicitPolicyRequired(),
buildParams.policyMappingInhibited(),
buildParams.anyPolicyInhibited(),
buildParams.policyQualifiersRejected(),
rootNode);
checkers.add(policyChecker);
// add the algorithm checker
checkers.add(new AlgorithmChecker(builder.trustAnchor,
buildParams.timestamp(), buildParams.variant()));
PublicKey rootKey = cert.getPublicKey();
if (builder.trustAnchor.getTrustedCert() == null) {
appendedCerts.add(0, cert);
rootKey = builder.trustAnchor.getCAPublicKey();
if (debug != null)
debug.println(
@ -363,11 +341,35 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
(cert.getSubjectX500Principal(), rootKey, null);
// add the basic checker
List<PKIXCertPathChecker> checkers = new ArrayList<>();
BasicChecker basicChecker = new BasicChecker(anchor,
buildParams.date(),
buildParams.sigProvider(),
true);
checkers.add(basicChecker);
Set<String> initExpPolSet =
Collections.singleton(PolicyChecker.ANY_POLICY);
PolicyNodeImpl rootNode = new PolicyNodeImpl(null,
PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false);
PolicyChecker policyChecker
= new PolicyChecker(buildParams.initialPolicies(),
appendedCerts.size(),
buildParams.explicitPolicyRequired(),
buildParams.policyMappingInhibited(),
buildParams.anyPolicyInhibited(),
buildParams.policyQualifiersRejected(),
rootNode);
checkers.add(policyChecker);
// add the constraints checker
checkers.add(new ConstraintsChecker(appendedCerts.size()));
// add the algorithm checker
checkers.add(new AlgorithmChecker(builder.trustAnchor,
buildParams.timestamp(), buildParams.variant()));
buildParams.setCertPath(cf.generateCertPath(appendedCerts));
@ -563,18 +565,79 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
* adjacency list.
*/
private static List<Vertex> addVertices(Collection<X509Certificate> certs,
List<List<Vertex>> adjList)
List<List<Vertex>> adjList,
List<X509Certificate> cpList)
{
List<Vertex> l = adjList.get(adjList.size() - 1);
for (X509Certificate cert : certs) {
Vertex v = new Vertex(cert);
l.add(v);
boolean repeated = false;
for (X509Certificate cpListCert : cpList) {
/*
* Ignore if we encounter the same certificate or a
* certificate with the same public key, subject DN, and
* subjectAltNames as a cert that is already in path.
*/
if (repeated(cpListCert, cert)) {
if (debug != null) {
debug.println("cert with repeated subject, " +
"public key, and subjectAltNames detected");
}
repeated = true;
break;
}
}
if (!repeated) {
l.add(new Vertex(cert));
}
}
return l;
}
/**
* Return true if two certificates are equal or have the same subject,
* public key, and subject alternative names.
*/
private static boolean repeated(
X509Certificate currCert, X509Certificate nextCert) {
if (currCert.equals(nextCert)) {
return true;
}
return (currCert.getSubjectX500Principal().equals(
nextCert.getSubjectX500Principal()) &&
currCert.getPublicKey().equals(nextCert.getPublicKey()) &&
altNamesEqual(currCert, nextCert));
}
/**
* Return true if two certificates have the same subject alternative names.
*/
private static boolean altNamesEqual(
X509Certificate currCert, X509Certificate nextCert) {
X509CertImpl curr, next;
try {
curr = X509CertImpl.toImpl(currCert);
next = X509CertImpl.toImpl(nextCert);
} catch (CertificateException ce) {
return false;
}
SubjectAlternativeNameExtension currAltNameExt =
curr.getSubjectAlternativeNameExtension();
SubjectAlternativeNameExtension nextAltNameExt =
next.getSubjectAlternativeNameExtension();
if (currAltNameExt != null) {
if (nextAltNameExt == null) {
return false;
}
return Arrays.equals(currAltNameExt.getExtensionValue(),
nextAltNameExt.getExtensionValue());
} else {
return (nextAltNameExt == null);
}
}
/**
* Returns true if trust anchor certificate matches specified
* certificate constraints.