我正在尝试编写一个自定义的
X509TrustManager
,通过在getAcceptedIssuers
方法中返回接受的CA根来限制接受的CA根的列表,但这似乎不起作用。这是一个简单的实现,它委托给系统的默认信任管理器,但覆盖 getAcceptedIssuers
以返回空数组:
import java.security.KeyStore;
import java.security.cert.*;
import javax.net.ssl.*;
public class DefaultTrustManagerWrapper implements X509TrustManager {
private final X509TrustManager defaultTrustManager;
public DefaultTrustManagerWrapper() throws Exception {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null); // Init with default keystore
// Find the X509TrustManager instance from the array of trust managers
X509TrustManager foundTrustManager = null;
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
defaultTrustManager = (X509TrustManager) tm;
}
}
if (defaultTrustManager == null) {
throw new IllegalStateException("No X509TrustManager found");
}
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
defaultTrustManager.checkClientTrusted(chain, authType);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
defaultTrustManager.checkServerTrusted(chain, authType);
}
@Override
public X509Certificate[] getAcceptedIssuers() {
// Return no accepted issuers
return new X509Certificate[0];
}
}
但是使用此方法时,服务器证书仍然有效。
为什么会发生这种情况?验证服务器证书时不是默认调用
getAcceptedIssuers
吗?
不幸的是,返回一个空数组作为acceptedIsseurs将不起作用。因为客户端总是会调用 checkServerTrusted ,而它只会再次验证每个证书。因此,拥有一个包装器自定义信任管理器并不能解决问题。我认为最简单的方法是拥有一个不包含 CA 证书的单独的 KeyStore。不过,我有一种感觉,您的 JDK 默认信任库又名 cacerts 密钥库文件包含 CA 和自签名证书的混合,因此您正在使用该证书,因为它是正在维护的证书。如果我错了请纠正我。如果是这种情况,您仍然可以以编程方式过滤掉 CA 证书,并从剩余的证书中创建 TrustManager。您可以尝试一下下面的代码片段。它基本上检查每个证书是否不是 CA,然后将其添加到临时密钥库中,稍后将使用该临时密钥库来创建新的信任管理器。
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.cert.X509CertificateHolder;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class App {
public static void main(String[] args) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
X509TrustManager trustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
KeyStore trustStoreWithoutCa = KeyStore.getInstance(KeyStore.getDefaultType());
trustStoreWithoutCa.load(null, null);
X509Certificate[] acceptedIssuers = trustManager.getAcceptedIssuers();
System.out.println("Trusted certificates size: " + acceptedIssuers.length);
for (int i = 0; i < acceptedIssuers.length; i++) {
X509Certificate certificate = acceptedIssuers[i];
X509CertificateHolder c = new X509CertificateHolder(certificate.getEncoded());
BasicConstraints basicConstraints = BasicConstraints.fromExtensions(c.getExtensions());
if (basicConstraints != null && !basicConstraints.isCA()) {
trustStoreWithoutCa.setCertificateEntry(Integer.toString(i), certificate);
}
}
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStoreWithoutCa);
trustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
X509Certificate[] filteredIssuers = trustManager.getAcceptedIssuers();
System.out.println("Trusted certificates size with excluded CA: " + filteredIssuers.length);
}
}
顺便说一句,我正在使用 Bouncy Castle 的一些类,因此您需要具有以下依赖项才能使其正常工作:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>1.77</version>
</dependency>