无法通过 X509TrustManager.getAcceptedIssuers 限制接受的 CA 根

问题描述 投票:0回答:1

我正在尝试编写一个自定义的

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
吗?

java ssl jsse
1个回答
0
投票

不幸的是,返回一个空数组作为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>
© www.soinside.com 2019 - 2024. All rights reserved.