Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何初始化具有多个信任源的TrustManagerFactory?_Java_Ssl_X509_Jsse - Fatal编程技术网

Java 如何初始化具有多个信任源的TrustManagerFactory?

Java 如何初始化具有多个信任源的TrustManagerFactory?,java,ssl,x509,jsse,Java,Ssl,X509,Jsse,我的应用程序有一个个人密钥库,其中包含可在本地网络中使用的可信自签名证书-比如说mykeystore.jks。我希望能够连接到公共网站(比如google.com)以及使用本地提供的自签名证书的本地网络中的网站 这里的问题是,当我连接到时,路径构建失败,因为设置我自己的密钥库会覆盖包含与JRE绑定的根CA的默认密钥库,并报告异常 sun.security.validator.ValidatorException: PKIX path building failed: sun.security.pr

我的应用程序有一个个人密钥库,其中包含可在本地网络中使用的可信自签名证书-比如说
mykeystore.jks
。我希望能够连接到公共网站(比如google.com)以及使用本地提供的自签名证书的本地网络中的网站

这里的问题是,当我连接到时,路径构建失败,因为设置我自己的密钥库会覆盖包含与JRE绑定的根CA的默认密钥库,并报告异常

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
但是,如果我将CA证书导入我自己的密钥库(
mykeystore.jks
),它就可以正常工作。有什么方法可以同时支持这两个方面吗

为此,我有自己的信托经理

public class CustomX509TrustManager implements X509TrustManager {

        X509TrustManager defaultTrustManager;

        public MyX509TrustManager(KeyStore keystore) {
                TrustManagerFactory trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                trustMgrFactory.init(keystore);
                TrustManager trustManagers[] = trustMgrFactory.getTrustManagers();
                for (int i = 0; i < trustManagers.length; i++) {
                    if (trustManagers[i] instanceof X509TrustManager) {
                        defaultTrustManager = (X509TrustManager) trustManagers[i];
                        return;
                    }
                }

        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            try {
                defaultTrustManager.checkServerTrusted(chain, authType);
            } catch (CertificateException ce) {
            /* Handle untrusted certificates */
            }
        }
    }
设置插座工厂

HttpsURLConnection.setDefaultSSLSocketFactory(customSSLContext.getSocketFactory());
主节目,

URL targetServer = new URL(url);
HttpsURLConnection conn = (HttpsURLConnection) targetServer.openConnection();

如果我不设置自己的信任管理器,它就可以正常连接。如何获取指向默认密钥存储的“默认信任管理器”?
trustMgrFactory.init(keystore)中的您正在使用自己的个人密钥库而不是系统默认密钥库配置defaultTrustManager


基于读取sun.security.ssl.TrustManagerFactoryImpl的源代码,它看起来像
trustMgrFactory.init((KeyStore)null)
将完全满足您的需要(加载系统默认密钥库),基于快速测试,它似乎适合我。

我在Commons HttpClient中遇到了同样的问题。我的案例的工作解决方案是通过以下方式为PKIX TrustManager创建委派链:

公共类TrustManagerDelegate实现X509TrustManager{
私人最终X509TrustManager mainTrustManager;
私人最终X509TrustManager trustManager;
私人最终信任策略;
公共信任管理者委派(X509TrustManager主信任管理者、X509TrustManager信任管理者、信任策略信任策略){
this.mainTrustManager=mainTrustManager;
this.trustManager=trustManager;
this.trustStrategy=trustStrategy;
}
@凌驾
公共无效checkClientTrusted(
最终X509Certificate[]链,最终字符串authType)引发CertificateException{
this.trustManager.checkClientTrusted(chain,authType);
}
@凌驾
公共无效检查服务器受信任(
最终X509Certificate[]链,最终字符串authType)引发CertificateException{
如果(!this.trustStrategy.isTrusted(chain,authType)){
试一试{
mainTrustManager.checkServerTrusted(链,authType);
}捕获(证书例外){
this.trustManager.checkServerTrusted(链,authType);
}
}
}
@凌驾
公共X509证书[]getAcceptedIssuers(){
返回此.trustManager.getAcceptedIssuers();
}
}
并以以下方式初始化HttpClient(是的,它很难看):

最终SSLContext SSLContext;
试一试{
sslContext=sslContext.getInstance(“TLS”);
最终的TrustManagerFactory javaDefaultTrustManager=TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
javaDefaultTrustManager.init((KeyStore)null);
最终TrustManagerFactory customCaTrustManager=TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
init(getKeyStore());
sslContext.init(
无效的
新信托管理人[]{
新TrustManagerDelegate(
(X509TrustManager)customCaTrustManager.GetTrustManager()[0],
(X509TrustManager)javaDefaultTrustManager.GetTrustManager()[0],
新的TrustSelfSignedStrategy()
)
},
安全随机
);
}捕获(最终NoSuchAlgorithmException ex){
抛出新的SSLinitalizationException(例如getMessage(),例如);
}捕获(最终KeyManagementException ex){
抛出新的SSLinitalizationException(例如getMessage(),例如);
}
SSLConnectionSocketFactory sslSocketFactory=新的SSLConnectionSocketFactory(sslContext);
PoolightPClientConnectionManager cm=新的PoolightPClientConnectionManager(
RegistryBuilder.create()文件
.register(“http”,PlainConnectionSocketFactory.getSocketFactory())
.register(“https”,sslSocketFactory)
.build()
);
//最大并行请求数为500
cm.setMaxTotal(500);
cm.setDefaultMaxPerRoute(500);
CredentialsProvider cp=新的基本概念Provider();
cp.setCredentials(
新的AuthScope(apiSettings.getIdcApiUrl(),443),
新用户名密码凭据(apiSettings.getAgencyId(),apiSettings.getAgencyPassword())
);
client=HttpClients.custom()
.setConnectionManager(cm)
.build();
在使用简单HttpsURLConnection的情况下,您可以使用简化版本的委托类:

公共类TrustManagerDelegate实现X509TrustManager{
私人最终X509TrustManager mainTrustManager;
私人最终X509TrustManager trustManager;
公共信任管理者委派(X509TrustManager主信任管理者,X509TrustManager信任管理者){
this.mainTrustManager=mainTrustManager;
this.trustManager=trustManager;
}
@凌驾
公共无效checkClientTrusted(
最终X509Certificate[]链,最终字符串authType)引发CertificateException{
this.trustManager.checkClientTrusted(chain,authType);
}
@凌驾
公共无效检查服务器受信任(
最终X509Certificate[]链,最终字符串authType)引发CertificateException{
试一试{
mainTrustManager.checkServerTrusted(链,authType);
}捕获(证书例外){
this.trustManager.checkServerTrusted(链,authType);
}
}
@凌驾
公共X509证书[]getAcceptedIssuers(){
返回此.trustManager.getAcceptedIssuers();
}
}
答案是我是如何做到的
URL targetServer = new URL(url);
HttpsURLConnection conn = (HttpsURLConnection) targetServer.openConnection();
KeyStore keystore; // Get your own keystore here
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManager[] tm = CompositeX509TrustManager.getTrustManagers(keystore);
sslContext.init(null, tm, null);
<manifest ... >
    <application android:networkSecurityConfig="@xml/network_security_config"
                    ... >
        ...
    </application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="@raw/extracas"/>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;

import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

/**
 * Represents an ordered list of {@link X509TrustManager}s with additive trust. If any one of the composed managers
 * trusts a certificate chain, then it is trusted by the composite manager.
 *
 * This is necessary because of the fine-print on {@link SSLContext#init}: Only the first instance of a particular key
 * and/or trust manager implementation type in the array is used. (For example, only the first
 * javax.net.ssl.X509KeyManager in the array will be used.)
 *
 * @author codyaray
 * @since 4/22/2013
 * @see <a href="http://stackoverflow.com/questions/1793979/registering-multiple-keystores-in-jvm">
 *     http://stackoverflow.com/questions/1793979/registering-multiple-keystores-in-jvm
 *     </a>
 */
@SuppressWarnings("unused")
public class CompositeX509TrustManager implements X509TrustManager {

    private final List<X509TrustManager> trustManagers;

    public CompositeX509TrustManager(List<X509TrustManager> trustManagers) {
        this.trustManagers = ImmutableList.copyOf(trustManagers);
    }

    public CompositeX509TrustManager(KeyStore keystore) {

        this.trustManagers = ImmutableList.of(getDefaultTrustManager(), getTrustManager(keystore));

    }

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        for (X509TrustManager trustManager : trustManagers) {
            try {
                trustManager.checkClientTrusted(chain, authType);
                return; // someone trusts them. success!
            } catch (CertificateException e) {
                // maybe someone else will trust them
            }
        }
        throw new CertificateException("None of the TrustManagers trust this certificate chain");
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        for (X509TrustManager trustManager : trustManagers) {
            try {
                trustManager.checkServerTrusted(chain, authType);
                return; // someone trusts them. success!
            } catch (CertificateException e) {
                // maybe someone else will trust them
            }
        }
        throw new CertificateException("None of the TrustManagers trust this certificate chain");
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        ImmutableList.Builder<X509Certificate> certificates = ImmutableList.builder();
        for (X509TrustManager trustManager : trustManagers) {
            for (X509Certificate cert : trustManager.getAcceptedIssuers()) {
                certificates.add(cert);
            }
        }
        return Iterables.toArray(certificates.build(), X509Certificate.class);
    }

    public static TrustManager[] getTrustManagers(KeyStore keyStore) {

        return new TrustManager[] { new CompositeX509TrustManager(keyStore) };

    }

    public static X509TrustManager getDefaultTrustManager() {

        return getTrustManager(null);

    }

    public static X509TrustManager getTrustManager(KeyStore keystore) {

        return getTrustManager(TrustManagerFactory.getDefaultAlgorithm(), keystore);

    }

    public static X509TrustManager getTrustManager(String algorithm, KeyStore keystore) {

        TrustManagerFactory factory;

        try {
            factory = TrustManagerFactory.getInstance(algorithm);
            factory.init(keystore);
            return Iterables.getFirst(Iterables.filter(
                    Arrays.asList(factory.getTrustManagers()), X509TrustManager.class), null);
        } catch (NoSuchAlgorithmException | KeyStoreException e) {
            e.printStackTrace();
        }

        return null;

    }

}
SSLFactory sslFactory = SSLFactory.builder()
    .withDefaultTrustMaterial() // --> uses the JDK trusted certificates
    .withTrustMaterial("/path/to/mykeystore.jks", "password".toCharArray())
    .build();

HttpsURLConnection.setDefaultSSLSocketFactory(sslFactory.getSslSocketFactory());