java - 使用 HttpClient 4.2 从失败的连接尝试中获取服务器证书

标签 java ssl certificate httpclient apache-httpclient-4.x

我目前正在使用 Apache HttpClient(特别是版本 4.2.3)向我的应用程序添加 https 下载功能。

如果证书验证失败,我想获取服务器证书链。抛出的异常 SSLPeerUnverifiedException 没有提供任何信息的字段。

try {
    HttpResponse response = client.execute(get);
} catch (SSLPeerUnverifiedException e) {
    // retrieve server certificate here
}

有一种方法是将 TrustManager(用于捕获证书)注入(inject) SSLContext 并重新创建 SSLContextSSLSocketFactory HttpClient 用于每个请求。但是,我希望能够为多个可能的并行请求重用这些实例。

最佳答案

我在这个例子中使用了 HC 4.3,但在 HC 4.2 中应该以完全相同的方式工作,尽管我建议升级

public static void main(final String[] args) throws Exception {

    TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmfactory.init((KeyStore) null);
    TrustManager[] tms = tmfactory.getTrustManagers();
    if (tms != null) {
        for (int i = 0; i < tms.length; i++) {
            final TrustManager tm = tms[i];
            if (tm instanceof X509TrustManager) {
                tms[i] = new TrustManagerDelegate((X509TrustManager) tm);
            }
        }
    }
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, tms, null);

    CloseableHttpClient httpClient = HttpClients.custom()
            .setSslcontext(sslContext)
            .build();
    try {
        CloseableHttpResponse response = httpClient.execute(new HttpGet("https://google.com/"));
        try {
            // do something usefull
        } finally {
            response.close();
        }
    } catch (SSLException ex) {
        Throwable cause = ex.getCause();
        if (cause instanceof MyCertificateException) {
            X509Certificate[] chain = ((MyCertificateException) cause).getChain();
            for (X509Certificate cert: chain) {
                System.out.println(cert);
            }
        }
    }
}

static class TrustManagerDelegate implements X509TrustManager {

    private final X509TrustManager trustManager;

    TrustManagerDelegate(final X509TrustManager trustManager) {
        super();
        this.trustManager = trustManager;
    }

    @Override
    public void checkClientTrusted(
            final X509Certificate[] chain, final String authType) throws CertificateException {
        this.trustManager.checkClientTrusted(chain, authType);
    }

    @Override
    public void checkServerTrusted(
            final X509Certificate[] chain, final String authType) throws CertificateException {
        try {
            this.trustManager.checkServerTrusted(chain, authType);
        } catch (CertificateException ex) {
            throw new MyCertificateException(chain, ex);
        }
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return this.trustManager.getAcceptedIssuers();
    }

}

static class MyCertificateException extends CertificateException {

    private final X509Certificate[] chain;

    MyCertificateException(final X509Certificate[] chain, final CertificateException ex) {
        super(ex);
        this.chain = chain;
    }

    public X509Certificate[] getChain() {
        return chain;
    }

}

关于java - 使用 HttpClient 4.2 从失败的连接尝试中获取服务器证书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28052322/

相关文章:

swift - 如何从 SecCertificate 中提取或比较 kSecPropertyKeyValue

ruby-on-rails - 证书验证失败 Heroku Ruby on Rails 3.2.1 Ruby 1.9.2p290

java - 如何将项目从 Github 同步到 Eclipse

java - 从 jTextPane 中删除最后一行

java - 在 jax-rs Web 服务中使用 java 接口(interface)的好处?

apache - Wamp SSL 配置抛出 404

Wordpress get_template_directory_uri() 返回 http 而不是 https

haskell - 接受带有 http-client-tls 或 tls 的特定证书?

java.security.cert.CertificateException : Unable to initialize

java - 通过 Jenkins 作业进行 maven 部署的策略