重新定义默认 SSL 上下文时找不到 Java 密钥库

Posted

技术标签:

【中文标题】重新定义默认 SSL 上下文时找不到 Java 密钥库【英文标题】:Java key store is not found when default SSL context is redefined 【发布时间】:2014-04-21 20:18:42 【问题描述】:

假设,当遇到不受信任或过期的服务器证书时(就像大多数 Web 浏览器一样),我希望我的 Java 应用程序中通过 SSL 的所有连接都请求用户许可。

似乎最自然的方法是在应用程序启动时替换默认 SSL 上下文。

这是最小的工作示例:

public class ClientAuthentication 
    public static final String SERVER_URL = "https://my.test.server";

    public static void main(String[] args) throws Exception 
        SSLContext defaultContext = SSLContext.getInstance("TLS");
        defaultContext.init(null, new TrustManager[]new MyX509TrustManager(), null);
        // defaultContext.init(null, null, null);
        SSLContext.setDefault(defaultContext);
        HttpURLConnection connection = (HttpURLConnection) new URL(SERVER_URL).openConnection();
        System.out.println(connection.getResponseCode());
    

    private static class MyX509TrustManager implements X509TrustManager 
        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException 
            throw new UnsupportedOperationException("Won't be called by client");
        

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String s) throws CertificateException 
            if (userAcceptsCertificate(chain)) 
                System.out.format("Certificate '%s' accepted%n", chain[0].getIssuerX500Principal().getName());
            
        

        @Override
        public X509Certificate[] getAcceptedIssuers() 
            return new X509Certificate[0];
        

        private boolean userAcceptsCertificate(X509Certificate[] x509Certificates) 
            // ...
            return true;
        
    

不幸的是,当服务器需要客户端身份验证时,它不起作用。甚至,当通过-Djavax.net.ssl.keyStore VM 选项正确指定包含客户端证书的密钥库时,连接失败并显示 javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure,因为根本没有发送客户端证书(在 Wireshark 中跟踪)。

这种行为有点令人惊讶,因为 JavaDoc for SSLContext#init(KeyManager[], TrustManager[], SecureRandom) 声明,传递 null 而不是密钥管理器或信任管理器意味着将执行默认查找过程。

Сontradictorily,如果我将 null 而不是数组与我的自定义信任管理器作为第二个参数传递给 init 并指定 JKS 信任存储,包含服务器证书,使用-Djavax.net.ssl.trustStore VM 参数,服务器证书将在那里找到并成功接受

那么,您能否建议一种重新定义默认 SSL 上下文的方法,仅替换信任管理器并保留有关搜索密钥管理器的默认行为?或者可能是一些可靠的方法来查找通过 VM 选项指定的密钥管理器。

注意事项

    如果我根本不自定义默认 SSL 上下文,则连接成功,即 VM 选项中的所有路径、密码和存储类型都正确。

    我不能以任何方式调用SSLContext.getDefault()SSLContext.getInstance("Default"),因为默认上下文只能初始化一次。

【问题讨论】:

【参考方案1】:

您已使用 null 密钥管理器初始化上下文。这意味着没有密钥管理器。这并不意味着有一个默认的密钥管理器。因此,当请求密钥管理器的功能时,什么也没有发生。这些功能包括提供客户端证书。

Javadoc 错误。 IBM JSSE 的行为与那里描述的一样,但 Sun/Oracle JSSE 没有,也从来没有。

【讨论】:

以上是关于重新定义默认 SSL 上下文时找不到 Java 密钥库的主要内容,如果未能解决你的问题,请参考以下文章

使用反应创建上下文时找不到命名空间“ctx”错误 - 打字稿

Django在重定向时找不到模式名称

# 删除期间重新加载页面时找不到页面

在 Firebase 上重新加载 Angular 页面时找不到页面

Google Play Developer API - 为啥在用户执行重新订阅时找不到linkedPurchaseToken?

初始化默认 SSL 上下文失败