java trustmanager_java – 如何使用多个信任源初始化TrustManagerFactory?

本文探讨了在Java应用程序中如何同时使用自定义密钥库和默认JRE根CA证书来建立安全连接。问题在于,自定义TrustManager覆盖了默认的信任源,导致连接到如google.com等公共站点时出现证书验证失败。为解决这个问题,提出了实现自定义X509TrustManager,该管理器能够检查服务器证书,包括默认信任管理器和自定义密钥库中的证书。通过这种方式,可以在保持对本地自签名证书信任的同时,也能正确验证公共站点的证书。

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

这里的问题是,当我连接到https://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),它可以正常工作.有没有办法支持两者?

我有自己的TrustManger用于此目的,

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 */

}

}

}

然后我初始化SSLContext,

TrustManager[] trustManagers =

new TrustManager[] { new CustomX509TrustManager(keystore) };

SSLContext customSSLContext =

SSLContext.getInstance("TLS");

customSSLContext.init(null, trustManagers, null);

并设置套接字工厂,

HttpsURLConnection.setDefaultSSLSocketFactory(customSSLContext.getSocketFactory());

主程序,

URL targetServer = new URL(url);

HttpsURLConnection conn = (HttpsURLConnection) targetServer.openConnection();

如果我没有设置自己的信任管理器,它就连接到https://google.com就好了.如何获得指向默认密钥库的“默认信任管理器”?

package com.example.kucun2.function; import android.content.Context; import android.util.Log; import java.io.InputStream; import java.security.KeyStore; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import okhttp3.OkHttpClient; public class TLSUtils { private static final String TAG = "TLSUtils"; private static final String CERT_TYPE = "X.509"; private static final String SSL_PROTOCOL = "TLSv1.2"; /** * 创建安全客户端(支持动态证书名) * @param context 应用上下文 * @param certAssetName assets目录中的证书文件名 * @return 配置好的OkHttpClient */ public static OkHttpClient createSecureClient(Context context, String certAssetName) { try { // 创建自定义信任管理器 X509TrustManager trustManager = createTrustManager(context, certAssetName); // 初始化SSL上下文 SSLContext sslContext = SSLContext.getInstance(SSL_PROTOCOL); sslContext.init(null, new TrustManager[]{trustManager}, null); return new OkHttpClient.Builder() .sslSocketFactory(sslContext.getSocketFactory(), trustManager) .hostnameVerifier((hostname, session) -> { // 安全的主机名验证(仅允许特定IP) return "192.168.1.123".equals(hostname); }) .build(); } catch (Exception e) { Log.e(TAG, "创建安全客户端失败", e); throw new RuntimeException("TLS初始化异常", e); } } /** * 创建信任管理器 * @param context 应用上下文 * @param certAssetName 证书文件名 * @return 自定义信任管理器 */ private static X509TrustManager createTrustManager(Context context, String certAssetName) throws Exception { // 使用try-with-resources确保流关闭 try (InputStream certStream = context.getAssets().open(certAssetName)) { CertificateFactory cf = CertificateFactory.getInstance(CERT_TYPE); Certificate cert = cf.generateCertificate(certStream); // 创建包含证书的KeyStore KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null); keyStore.setCertificateEntry("changeit", cert); // 初始化TrustManagerFactory TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() ); tmf.init(keyStore); // 获取并返回X509TrustManager for (TrustManager tm : tmf.getTrustManagers()) { if (tm instanceof X509TrustManager) { return (X509TrustManager) tm; } } throw new IllegalStateException("未找到X509TrustManager"); } } } 详细注解
06-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值