diff --git a/src/java.base/share/classes/sun/security/provider/certpath/URICertStore.java b/src/java.base/share/classes/sun/security/provider/certpath/URICertStore.java
index 28729a56dbd..3e1fc8db164 100644
--- a/src/java.base/share/classes/sun/security/provider/certpath/URICertStore.java
+++ b/src/java.base/share/classes/sun/security/provider/certpath/URICertStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2025, 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
@@ -29,6 +29,7 @@ import java.io.InputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
+import java.net.URISyntaxException;
import java.net.URLConnection;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
@@ -48,8 +49,11 @@ import java.security.cert.X509CRL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
+import java.util.Optional;
+import java.util.Set;
import sun.security.x509.AccessDescription;
import sun.security.x509.GeneralNameInterface;
@@ -58,6 +62,8 @@ import sun.security.util.Cache;
import sun.security.util.Debug;
import sun.security.util.SecurityProperties;
+import javax.security.auth.x500.X500Principal;
+
/**
* A CertStore that retrieves Certificates or
* CRLs from a URI, for example, as specified in an X.509
@@ -182,6 +188,166 @@ class URICertStore extends CertStoreSpi {
return timeoutVal;
}
+ /**
+ * Enumeration for the allowed schemes we support when following a
+ * URI from an authorityInfoAccess extension on a certificate.
+ */
+ private enum AllowedScheme {
+ HTTP(HttpFtpRuleMatcher.HTTP),
+ HTTPS(HttpFtpRuleMatcher.HTTPS),
+ LDAP(LdapRuleMatcher.LDAP),
+ LDAPS(LdapRuleMatcher.LDAPS),
+ FTP(HttpFtpRuleMatcher.FTP);
+
+ final URIRuleMatcher ruleMatcher;
+
+ AllowedScheme(URIRuleMatcher matcher) {
+ ruleMatcher = matcher;
+ }
+
+ /**
+ * Return an {@code AllowedScheme} based on a case-insensitive match
+ * @param name the scheme name to be matched
+ * @return the {@code AllowedScheme} that corresponds to the
+ * {@code name} provided, or null if there is no match.
+ */
+ static AllowedScheme nameOf(String name) {
+ if (name == null) {
+ return null;
+ }
+
+ try {
+ return AllowedScheme.valueOf(name.toUpperCase(Locale.ROOT));
+ } catch (IllegalArgumentException _) {
+ return null;
+ }
+ }
+ }
+
+ private static Set CA_ISS_URI_FILTERS = null;
+ private static final boolean CA_ISS_ALLOW_ANY;
+
+ static {
+ boolean allowAny = false;
+ try {
+ if (Builder.USE_AIA) {
+ CA_ISS_URI_FILTERS = new LinkedHashSet<>();
+ String aiaPropVal = Optional.ofNullable(
+ SecurityProperties.getOverridableProperty(
+ "com.sun.security.allowedAIALocations")).
+ map(String::trim).orElse("");
+ if (aiaPropVal.equalsIgnoreCase("any")) {
+ allowAny = true;
+ if (debug != null) {
+ debug.println("allowedAIALocations: Warning: " +
+ "Allow-All URI filtering enabled!");
+ }
+ } else {
+ // Load all the valid rules from the Security property
+ if (!aiaPropVal.isEmpty()) {
+ String[] aiaUriStrs = aiaPropVal.trim().split("\\s+");
+ addCaIssUriFilters(aiaUriStrs);
+ }
+
+ if (CA_ISS_URI_FILTERS.isEmpty()) {
+ if (debug != null) {
+ debug.println("allowedAIALocations: Warning: " +
+ "No valid filters found. Deny-all URI " +
+ "filtering is active.");
+ }
+ }
+ }
+ }
+ } finally {
+ CA_ISS_ALLOW_ANY = allowAny;
+ }
+ }
+
+ /**
+ * Populate the filter collection from the list of AIA CA issuer URIs
+ * found in the {@code com.sun.security.allowedAIALocations} security
+ * or system property.
+ *
+ * @param aiaUriStrs array containing String URI filters
+ */
+ private static void addCaIssUriFilters(String[] aiaUriStrs) {
+ for (String aiaStr : aiaUriStrs) {
+ if (aiaStr != null && !aiaStr.isEmpty()) {
+ try {
+ AllowedScheme scheme;
+ URI aiaUri = new URI(aiaStr).normalize();
+ // It must be absolute and non-opaque
+ if (!aiaUri.isAbsolute() || aiaUri.isOpaque()) {
+ if (debug != null) {
+ debug.println("allowedAIALocations: Skipping " +
+ "non-absolute or opaque URI " + aiaUri);
+ }
+ } else if (aiaUri.getHost() == null) {
+ // We do not allow rules with URIs that omit a hostname
+ // or address.
+ if (debug != null) {
+ debug.println("allowedAIALocations: Skipping " +
+ "URI rule with no hostname or address: " +
+ aiaUri);
+ }
+ } else if ((scheme = AllowedScheme.nameOf(
+ aiaUri.getScheme())) != null) {
+ // When it is an LDAP type, we can check the path
+ // portion (the DN) for proper structure and reject
+ // the rule early if it isn't correct.
+ if (scheme == AllowedScheme.LDAP ||
+ scheme == AllowedScheme.LDAPS) {
+ try {
+ new X500Principal(aiaUri.getPath().
+ replaceFirst("^/+", ""));
+ } catch (IllegalArgumentException iae) {
+ if (debug != null) {
+ debug.println("allowedAIALocations: " +
+ "Skipping LDAP rule: " + iae);
+ }
+ continue;
+ }
+ }
+
+ // When a URI has a non-null query or fragment
+ // warn the user upon adding the rule that those
+ // components will be ignored
+ if (aiaUri.getQuery() != null) {
+ if (debug != null) {
+ debug.println("allowedAIALocations: " +
+ "Rule will ignore non-null query");
+ }
+ }
+ if (aiaUri.getFragment() != null) {
+ if (debug != null) {
+ debug.println("allowedAIALocations: " +
+ "Rule will ignore non-null fragment");
+ }
+ }
+
+ CA_ISS_URI_FILTERS.add(aiaUri);
+ if (debug != null) {
+ debug.println("allowedAIALocations: Added " +
+ aiaUri + " to URI filters");
+ }
+ } else {
+ if (debug != null) {
+ debug.println("allowedAIALocations: Disallowed " +
+ "filter URI scheme: " +
+ aiaUri.getScheme());
+ }
+ }
+ } catch (URISyntaxException urise) {
+ if (debug != null) {
+ debug.println("allowedAIALocations: Skipping " +
+ "filter URI entry " + aiaStr +
+ ": parse failure at index " + urise.getIndex());
+ }
+ }
+ }
+ }
+ }
+
/**
* Creates a URICertStore.
*
@@ -244,6 +410,39 @@ class URICertStore extends CertStoreSpi {
return null;
}
URI uri = ((URIName) gn).getURI();
+
+ // Before performing any instantiation make sure that
+ // the URI passes any filtering rules. This processing should
+ // only occur if the com.sun.security.enableAIAcaIssuers is true
+ // and the "any" rule has not been specified.
+ if (Builder.USE_AIA && !CA_ISS_ALLOW_ANY) {
+ URI normAIAUri = uri.normalize();
+ AllowedScheme scheme = AllowedScheme.nameOf(normAIAUri.getScheme());
+
+ if (scheme == null) {
+ if (debug != null) {
+ debug.println("allowedAIALocations: No matching ruleset " +
+ "for scheme " + normAIAUri.getScheme());
+ }
+ return null;
+ }
+
+ // Go through each of the filter rules and see if any will
+ // make a positive match against the caIssuer URI. If nothing
+ // matches then we won't instantiate a URICertStore.
+ if (CA_ISS_URI_FILTERS.stream().noneMatch(rule ->
+ scheme.ruleMatcher.matchRule(rule, normAIAUri))) {
+ if (debug != null) {
+ debug.println("allowedAIALocations: Warning - " +
+ "The caIssuer URI " + normAIAUri +
+ " in the AuthorityInfoAccess extension is denied " +
+ "access. Use the com.sun.security.allowedAIALocations" +
+ " security/system property to allow access.");
+ }
+ return null;
+ }
+ }
+
try {
return URICertStore.getInstance(new URICertStoreParameters(uri));
} catch (Exception ex) {
@@ -270,7 +469,7 @@ class URICertStore extends CertStoreSpi {
@Override
@SuppressWarnings("unchecked")
public synchronized Collection engineGetCertificates
- (CertSelector selector) throws CertStoreException {
+ (CertSelector selector) throws CertStoreException {
if (ldap) {
// caching mechanism, see the class description for more info.
@@ -462,4 +661,159 @@ class URICertStore extends CertStoreSpi {
super(spi, p, type, params);
}
}
+
+ /**
+ * URIRuleMatcher - abstract base class for the rule sets used for
+ * various URI schemes.
+ */
+ static abstract class URIRuleMatcher {
+ protected final int wellKnownPort;
+
+ protected URIRuleMatcher(int port) {
+ wellKnownPort = port;
+ }
+
+ /**
+ * Attempt to match the scheme, host and port between a filter
+ * rule URI and a URI coming from an AIA extension.
+ *
+ * @param filterRule the filter rule to match against
+ * @param caIssuer the AIA URI being compared
+ * @return true if the scheme, host and port numbers match, false if
+ * any of the components do not match. If a port number is omitted in
+ * either the filter rule or AIA URI, the well-known port for that
+ * scheme is used in the comparison.
+ */
+ boolean schemeHostPortCheck(URI filterRule, URI caIssuer) {
+ if (!filterRule.getScheme().equalsIgnoreCase(
+ caIssuer.getScheme())) {
+ return false;
+ } else if (!filterRule.getHost().equalsIgnoreCase(
+ caIssuer.getHost())) {
+ return false;
+ } else {
+ try {
+ // Check for port matching, taking into consideration
+ // default ports
+ int fPort = (filterRule.getPort() == -1) ? wellKnownPort :
+ filterRule.getPort();
+ int caiPort = (caIssuer.getPort() == -1) ? wellKnownPort :
+ caIssuer.getPort();
+ if (fPort != caiPort) {
+ return false;
+ }
+ } catch (IllegalArgumentException iae) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Attempt to match an AIA URI against a specific filter rule. The
+ * specific rules to apply are implementation dependent.
+ *
+ * @param filterRule the filter rule to match against
+ * @param caIssuer the AIA URI being compared
+ * @return true if all matching rules pass, false if any fail.
+ */
+ abstract boolean matchRule(URI filterRule, URI caIssuer);
+ }
+
+ static class HttpFtpRuleMatcher extends URIRuleMatcher {
+ static final HttpFtpRuleMatcher HTTP = new HttpFtpRuleMatcher(80);
+ static final HttpFtpRuleMatcher HTTPS = new HttpFtpRuleMatcher(443);
+ static final HttpFtpRuleMatcher FTP = new HttpFtpRuleMatcher(21);
+
+ private HttpFtpRuleMatcher(int port) {
+ super(port);
+ }
+
+ @Override
+ boolean matchRule(URI filterRule, URI caIssuer) {
+ // Check for scheme/host/port matching
+ if (!schemeHostPortCheck(filterRule, caIssuer)) {
+ return false;
+ }
+
+ // Check the path component to make sure the filter is at
+ // least a root of the AIA caIssuer URI's path. It must be
+ // a case-sensitive match for all platforms.
+ if (!isRootOf(filterRule, caIssuer)) {
+ if (debug != null) {
+ debug.println("allowedAIALocations: Match failed: " +
+ "AIA URI is not within the rule's path hierarchy.");
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Performs a hierarchical containment check, ensuring that the
+ * base URI's path is a root component of the candidate path. The
+ * path comparison is case-sensitive. If the base path ends in a
+ * slash (/) then all candidate paths that begin with the base
+ * path are allowed. If it does not end in a slash, then it is
+ * assumed that the leaf node in the base path is a file component
+ * and both paths must match exactly.
+ *
+ * @param base the URI that contains the root path
+ * @param candidate the URI that contains the path being evaluated
+ * @return true if {@code candidate} is a child path of {@code base},
+ * false otherwise.
+ */
+ private static boolean isRootOf(URI base, URI candidate) {
+ // Note: The URIs have already been normalized at this point and
+ // HTTP URIs cannot have null paths. If it's an empty path
+ // then consider the path to be "/".
+ String basePath = Optional.of(base.getPath()).
+ filter(p -> !p.isEmpty()).orElse("/");
+ String candPath = Optional.of(candidate.getPath()).
+ filter(p -> !p.isEmpty()).orElse("/");
+ return (basePath.endsWith("/")) ? candPath.startsWith(basePath) :
+ candPath.equals(basePath);
+ }
+ }
+
+ static class LdapRuleMatcher extends URIRuleMatcher {
+ static final LdapRuleMatcher LDAP = new LdapRuleMatcher(389);
+ static final LdapRuleMatcher LDAPS = new LdapRuleMatcher(636);
+
+ private LdapRuleMatcher(int port) {
+ super(port);
+ }
+
+ @Override
+ boolean matchRule(URI filterRule, URI caIssuer) {
+ // Check for scheme/host/port matching
+ if (!schemeHostPortCheck(filterRule, caIssuer)) {
+ return false;
+ }
+
+ // Obtain the base DN component and compare
+ try {
+ X500Principal filterBaseDn = new X500Principal(
+ filterRule.getPath().replaceFirst("^/+", ""));
+ X500Principal caIssBaseDn = new X500Principal(
+ caIssuer.getPath().replaceFirst("^/+", ""));
+ if (!filterBaseDn.equals(caIssBaseDn)) {
+ if (debug != null) {
+ debug.println("allowedAIALocations: Match failed: " +
+ "Base DN mismatch (" + filterBaseDn + " vs " +
+ caIssBaseDn + ")");
+ }
+ return false;
+ }
+ } catch (IllegalArgumentException iae) {
+ if (debug != null) {
+ debug.println("allowedAIALocations: Match failed on DN: " +
+ iae);
+ }
+ return false;
+ }
+
+ return true;
+ }
+ }
}
diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security
index b5cbce413b2..9a81ba86268 100644
--- a/src/java.base/share/conf/security/java.security
+++ b/src/java.base/share/conf/security/java.security
@@ -1655,3 +1655,48 @@ jdk.tls.alpnCharset=ISO_8859_1
# withEncryption method.
#
jdk.epkcs8.defaultAlgorithm=PBEWithHmacSHA256AndAES_128
+
+#
+# X.509 AuthorityInfoAccess caIssuer URI Filtering
+#
+# This property defines a whitespace-separated list of filters that
+# are applied to URIs found in the authorityInfoAccess extension in
+# X.509 certificates. Any caIssuers URIs in X.509 certificates are only
+# followed when the com.sun.security.enableAIAcaIssuers System property is
+# enabled and the filter allows the URI. By default this property imposes a
+# deny-all ruleset. This property may be overridden by a System property
+# of the same name.
+#
+# The filters must take the form of absolute, hierarchical URIs as defined by
+# the java.net.URI class. Additionally, only the following protocols are
+# allowed as filters: http, https, ldap and ftp.
+# See RFC 5280, section 4.2.2.1 for details about the types of URIs allowed for
+# the extension and their specific requirements.
+# The filter matching rules are applied to each CA issuer URI as follows:
+# 1. The scheme must match (case-insensitive).
+# 2. A hostname or address must be specified in the filter URI. It must match
+# the host or address in the caIssuers URI (case-insensitive). No name
+# resolution is performed on hostnames to match IP addresses.
+# 3. The port number must match. For filter and caIssuer URIs, when a port
+# number is omitted, the well-known port for that scheme will be used in the
+# comparison.
+# 4. For hierarchical filesystem schemes (e.g. http[s], ftp):
+# a. The normalized path portion of the filter URI is matched in a
+# case-sensitive manner. If the final component of the path does not end
+# in a slash (/), it is considered to be a file path component and must
+# be an exact match of the caIssuer's URI file path component. If the
+# final filter component ends in a slash, then it must either match or be
+# a prefix of the caIssuer's URI path component (e.g. a filter path of
+# /ab/cd/ will match a caIssuer path of /ab/cd/, /ab/cd/ef and
+# /ab/cd/ef/ghi).
+# b. Query strings will be ignored in filter rules and caIssuer URIs.
+# c. Fragments will be ignored in filter rules and caIssuer URIs.
+# 5. For ldap URIs:
+# a. The base DN must be an exact match (case-insensitive).
+# b. Any query string in the rule, if specified, is ignored.
+# 6. A single value "any" (case-insensitive) will create an allow-all rule.
+#
+# As an example, here is a valid filter policy consisting of two rules:
+# com.sun.security.allowedAIALocations=http://some.company.com/cacert \
+# ldap://ldap.company.com/dc=company,dc=com?caCertificate;binary
+com.sun.security.allowedAIALocations=
diff --git a/test/jdk/sun/security/x509/URICertStore/AIACertTimeout.java b/test/jdk/sun/security/x509/URICertStore/AIACertTimeout.java
index cabb225bf1c..5491d7b0d7a 100644
--- a/test/jdk/sun/security/x509/URICertStore/AIACertTimeout.java
+++ b/test/jdk/sun/security/x509/URICertStore/AIACertTimeout.java
@@ -47,6 +47,7 @@ import com.sun.net.httpserver.*;
import java.io.*;
import java.math.BigInteger;
import java.net.InetSocketAddress;
+import java.security.Security;
import java.security.cert.*;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
@@ -69,6 +70,7 @@ public class AIACertTimeout {
private static X509Certificate eeCert;
public static void main(String[] args) throws Exception {
+ Security.setProperty("com.sun.security.allowedAIALocations", "any");
int servTimeoutMsec = (args != null && args.length >= 1) ?
Integer.parseInt(args[0]) : -1;
boolean expectedPass = args != null && args.length >= 2 &&
diff --git a/test/jdk/sun/security/x509/URICertStore/ExtensionsWithLDAP.java b/test/jdk/sun/security/x509/URICertStore/ExtensionsWithLDAP.java
index 3b598d78d9f..2214e9256c3 100644
--- a/test/jdk/sun/security/x509/URICertStore/ExtensionsWithLDAP.java
+++ b/test/jdk/sun/security/x509/URICertStore/ExtensionsWithLDAP.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2025, 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
@@ -38,6 +38,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
+import java.security.Security;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
@@ -47,7 +48,6 @@ import java.security.cert.PKIXParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -67,25 +67,27 @@ public class ExtensionsWithLDAP {
* Not After : Jan 17 18:03:59 2043 GMT
* Subject: CN=Root
*/
- private static final String CA_CERT = ""
- + "-----BEGIN CERTIFICATE-----\n"
- + "MIIC8TCCAdmgAwIBAgIJAJsSNtj5wdqqMA0GCSqGSIb3DQEBDQUAMA8xDTALBgNV\n"
- + "BAMMBFJvb3QwHhcNMTUwOTAxMTgwMzU5WhcNNDMwMTE3MTgwMzU5WjAPMQ0wCwYD\n"
- + "VQQDDARSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvj892vPm\n"
- + "bB++x9QqqyBveP+ZqQ2B1stV7vh5JmDnOTevkZUOcemp3SXu/esNLSbpL+fARYXH\n"
- + "V5ubnrfip6RbvcxPfVIIDJrRTLIIsU6W7M6/LJLbLkEVGy4ZV4IHkOw9W2O92rcv\n"
- + "BkoqhzZnOTGR6uT3rRcKx4RevEKBKhZO+OPPf//lnckOybmYL7t7yQrajzHro76b\n"
- + "QTXYjAUq/DKhglXfC7vF/JzlAvG2IunGmIfjGcnuDo/9X3Bxef/q5TxCS35fvb7t\n"
- + "svC+g2QhTcBkQh4uNW2jSjlTIVp1uErCfP5aCjLaez5mqmb1hxPIlcvsNR23HwU6\n"
- + "bQO7z7NBo9Do6QIDAQABo1AwTjAdBgNVHQ4EFgQUmLZNOBBkqdYoElyxklPYHmAb\n"
- + "QXIwHwYDVR0jBBgwFoAUmLZNOBBkqdYoElyxklPYHmAbQXIwDAYDVR0TBAUwAwEB\n"
- + "/zANBgkqhkiG9w0BAQ0FAAOCAQEAYV4fOhDi5q7+XNXCxO8Eil2frR9jqdP4LaQp\n"
- + "3L0evW0gvPX68s2WmkPWzIu4TJcpdGFQqxyQFSXuKBXjthyiln77QItGTHWeafES\n"
- + "q5ESrKdSaJZq1bTIrrReCIP74f+fY/F4Tnb3dCqzaljXfzpdbeRsIW6gF71xcOUQ\n"
- + "nnPEjGVPLUegN+Wn/jQpeLxxIB7FmNXncdRUfMfZ43xVSKuMCy1UUYqJqTa/pXZj\n"
- + "jCMeRPThRjRqHlJ69jStfWUQATbLyj9KN09rUaJxzmUSt61UqJi7sjcGySaCjAJc\n"
- + "IcCdVmX/DmRLsdv8W36O3MgrvpT1zR3kaAlv2d8HppnBqcL3xg==\n"
- + "-----END CERTIFICATE-----";
+ private static final String CA_CERT =
+ """
+ -----BEGIN CERTIFICATE-----
+ MIIC8TCCAdmgAwIBAgIJAJsSNtj5wdqqMA0GCSqGSIb3DQEBDQUAMA8xDTALBgNV
+ BAMMBFJvb3QwHhcNMTUwOTAxMTgwMzU5WhcNNDMwMTE3MTgwMzU5WjAPMQ0wCwYD
+ VQQDDARSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvj892vPm
+ bB++x9QqqyBveP+ZqQ2B1stV7vh5JmDnOTevkZUOcemp3SXu/esNLSbpL+fARYXH
+ V5ubnrfip6RbvcxPfVIIDJrRTLIIsU6W7M6/LJLbLkEVGy4ZV4IHkOw9W2O92rcv
+ BkoqhzZnOTGR6uT3rRcKx4RevEKBKhZO+OPPf//lnckOybmYL7t7yQrajzHro76b
+ QTXYjAUq/DKhglXfC7vF/JzlAvG2IunGmIfjGcnuDo/9X3Bxef/q5TxCS35fvb7t
+ svC+g2QhTcBkQh4uNW2jSjlTIVp1uErCfP5aCjLaez5mqmb1hxPIlcvsNR23HwU6
+ bQO7z7NBo9Do6QIDAQABo1AwTjAdBgNVHQ4EFgQUmLZNOBBkqdYoElyxklPYHmAb
+ QXIwHwYDVR0jBBgwFoAUmLZNOBBkqdYoElyxklPYHmAbQXIwDAYDVR0TBAUwAwEB
+ /zANBgkqhkiG9w0BAQ0FAAOCAQEAYV4fOhDi5q7+XNXCxO8Eil2frR9jqdP4LaQp
+ 3L0evW0gvPX68s2WmkPWzIu4TJcpdGFQqxyQFSXuKBXjthyiln77QItGTHWeafES
+ q5ESrKdSaJZq1bTIrrReCIP74f+fY/F4Tnb3dCqzaljXfzpdbeRsIW6gF71xcOUQ
+ nnPEjGVPLUegN+Wn/jQpeLxxIB7FmNXncdRUfMfZ43xVSKuMCy1UUYqJqTa/pXZj
+ jCMeRPThRjRqHlJ69jStfWUQATbLyj9KN09rUaJxzmUSt61UqJi7sjcGySaCjAJc
+ IcCdVmX/DmRLsdv8W36O3MgrvpT1zR3kaAlv2d8HppnBqcL3xg==
+ -----END CERTIFICATE-----
+ """;
/*
* Certificate:
@@ -106,39 +108,41 @@ public class ExtensionsWithLDAP {
* Authority Information Access:
* CA Issuers - URI:ldap://ldap.host.for.aia/dc=Root?cACertificate
*/
- private static final String EE_CERT = ""
- + "-----BEGIN CERTIFICATE-----\n"
- + "MIIDHTCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQ0FADAPMQ0wCwYDVQQDDARSb290\n"
- + "MB4XDTE1MDkwMTE4MDM1OVoXDTQzMDExNzE4MDM1OVowDTELMAkGA1UEAwwCRUUw\n"
- + "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpyz97liuWPDYcLH9TX8Bi\n"
- + "T78olCmAfmevvch6ncXUVuCzbdaKuKXwn4EVbDszsVJLoK5zdtP+X3iDhutj+IgK\n"
- + "mLhuczF3M9VIcWr+JJUyTH4+3h/RT8cjCDZOmk9iXkb5ifruVsLqzb9g+Vp140Oz\n"
- + "7leikne7KmclHvTfvFd0WDI7Gb9vo4f5rT717BXJ/n+M6pNk8DLpLiEu6eziYvXR\n"
- + "v5x+t5Go3x0eCXdaxEQUf2j876Wfr2qHRJK7lDfFe1DDsMg/KpKGiILYZ+g2qtVM\n"
- + "ZSxtp5BZEtfB5qV/IE5kWO+mCIAGpXSZIdbERR6pZUq8GLEe1T9e+sO6H24w2F19\n"
- + "AgMBAAGjgYUwgYIwNAYDVR0fBC0wKzApoCegJYYjbGRhcDovL2xkYXAuaG9zdC5m\n"
- + "b3IuY3JsZHAvbWFpbi5jcmwwSgYIKwYBBQUHAQEEPjA8MDoGCCsGAQUFBzAChi5s\n"
- + "ZGFwOi8vbGRhcC5ob3N0LmZvci5haWEvZGM9Um9vdD9jQUNlcnRpZmljYXRlMA0G\n"
- + "CSqGSIb3DQEBDQUAA4IBAQBWDfZHpuUx0yn5d3+BuztFqoks1MkGdk+USlH0TB1/\n"
- + "gWWBd+4S4PCKlpSur0gj2rMW4fP5HQfNlHci8JV8/bG4KuKRAXW56dg1818Hl3pc\n"
- + "iIrUSRn8uUjH3p9qb+Rb/u3mmVQRyJjN2t/zceNsO8/+Dd808OB9aEwGs8lMT0nn\n"
- + "ZYaaAqYz1GIY/Ecyx1vfEZEQ1ljo6i/r70C3igbypBUShxSiGsleiVTLOGNA+MN1\n"
- + "/a/Qh0bkaQyTGqK3bwvzzMeQVqWu2EWTBD/PmND5ExkpRICdv8LBVXfLnpoBr4lL\n"
- + "hnxn9+e0Ah+t8dS5EKfn44w5bI5PCu2bqxs6RCTxNjcY\n"
- + "-----END CERTIFICATE-----";
+ private static final String EE_CERT =
+ """
+ -----BEGIN CERTIFICATE-----
+ MIIDHTCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQ0FADAPMQ0wCwYDVQQDDARSb290
+ MB4XDTE1MDkwMTE4MDM1OVoXDTQzMDExNzE4MDM1OVowDTELMAkGA1UEAwwCRUUw
+ ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpyz97liuWPDYcLH9TX8Bi
+ T78olCmAfmevvch6ncXUVuCzbdaKuKXwn4EVbDszsVJLoK5zdtP+X3iDhutj+IgK
+ mLhuczF3M9VIcWr+JJUyTH4+3h/RT8cjCDZOmk9iXkb5ifruVsLqzb9g+Vp140Oz
+ 7leikne7KmclHvTfvFd0WDI7Gb9vo4f5rT717BXJ/n+M6pNk8DLpLiEu6eziYvXR
+ v5x+t5Go3x0eCXdaxEQUf2j876Wfr2qHRJK7lDfFe1DDsMg/KpKGiILYZ+g2qtVM
+ ZSxtp5BZEtfB5qV/IE5kWO+mCIAGpXSZIdbERR6pZUq8GLEe1T9e+sO6H24w2F19
+ AgMBAAGjgYUwgYIwNAYDVR0fBC0wKzApoCegJYYjbGRhcDovL2xkYXAuaG9zdC5m
+ b3IuY3JsZHAvbWFpbi5jcmwwSgYIKwYBBQUHAQEEPjA8MDoGCCsGAQUFBzAChi5s
+ ZGFwOi8vbGRhcC5ob3N0LmZvci5haWEvZGM9Um9vdD9jQUNlcnRpZmljYXRlMA0G
+ CSqGSIb3DQEBDQUAA4IBAQBWDfZHpuUx0yn5d3+BuztFqoks1MkGdk+USlH0TB1/
+ gWWBd+4S4PCKlpSur0gj2rMW4fP5HQfNlHci8JV8/bG4KuKRAXW56dg1818Hl3pc
+ iIrUSRn8uUjH3p9qb+Rb/u3mmVQRyJjN2t/zceNsO8/+Dd808OB9aEwGs8lMT0nn
+ ZYaaAqYz1GIY/Ecyx1vfEZEQ1ljo6i/r70C3igbypBUShxSiGsleiVTLOGNA+MN1
+ /a/Qh0bkaQyTGqK3bwvzzMeQVqWu2EWTBD/PmND5ExkpRICdv8LBVXfLnpoBr4lL
+ hnxn9+e0Ah+t8dS5EKfn44w5bI5PCu2bqxs6RCTxNjcY
+ -----END CERTIFICATE-----""";
public static void main(String[] args) throws Exception {
String extension = args[0];
String targetHost = args[1];
-
+ Security.setProperty("com.sun.security.allowedAIALocations",
+ "ldap://" + targetHost + "/dc=Root");
X509Certificate trustedCert = loadCertificate(CA_CERT);
X509Certificate eeCert = loadCertificate(EE_CERT);
Set trustedCertsSet = new HashSet<>();
trustedCertsSet.add(new TrustAnchor(trustedCert, null));
- CertPath cp = (CertPath) CertificateFactory.getInstance("X509")
- .generateCertPath(Arrays.asList(eeCert));
+ CertPath cp = CertificateFactory.getInstance("X509")
+ .generateCertPath(List.of(eeCert));
// CertPath validator should try to parse CRLDP and AIA extensions,
// and load CRLs/certs which they point to.
@@ -151,7 +155,7 @@ public class ExtensionsWithLDAP {
= (InetSocketAddress) socket.getRemoteSocketAddress();
hosts.add(remoteAddress.getHostName());
};
- try (SocksProxy proxy = SocksProxy.startProxy(socketConsumer)) {
+ try (SocksProxy _ = SocksProxy.startProxy(socketConsumer)) {
CertPathValidator.getInstance("PKIX").validate(cp,
new PKIXParameters(trustedCertsSet));
throw new RuntimeException("CertPathValidatorException not thrown");