在Java客户端中签署SSL证书

它看起来像一个标准问题,但我无法在任何地方找到明确的方向。

我有Java代码试图连接到可能自签名(或过期)证书的服务器。 该代码报告以下错误:

[HttpMethodDirector] I/O exception (javax.net.ssl.SSLHandshakeException) caught 
when processing request: sun.security.validator.ValidatorException: PKIX path 
building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target

据我了解,我必须使用keytool并告诉java,允许这种连接是可以的。

解决这个问题的所有指令都假定我完全熟悉keytool,比如

为服务器生成私钥并将其导入到密钥库中

有没有人可以发布详细的说明?

我正在运行unix,所以bash脚本将是最好的。

不确定它是否重要,但代码在jboss中执行。


基本上有两种选择:将自签名证书添加到JVM信任库或将客户端配置为

选项1

从浏览器中导出证书并将其导入到JVM信任库(以建立信任链):

<JAVA_HOME>binkeytool -import -v -trustcacerts
-alias server-alias -file server.cer
-keystore cacerts.jks -keypass changeit
-storepass changeit 

选项2

禁用证书验证:

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { 
    new X509TrustManager() {     
        public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
            return new X509Certificate[0];
        } 
        public void checkClientTrusted( 
            java.security.cert.X509Certificate[] certs, String authType) {
            } 
        public void checkServerTrusted( 
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    } 
}; 

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("SSL"); 
    sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
} 
// Now you can access an https URL without having the certificate in the truststore
try { 
    URL url = new URL("https://hostname/index.html"); 
} catch (MalformedURLException e) {
} 

请注意, 我根本不推荐选项2 。 禁用信任管理器会破坏SSL的某些部分,并使您在中间人攻击时容易受到攻击。 更喜欢选项#1,或者更好的是让服务器使用由知名CA签署的“真实”证书。


我将这个问题JDK 8u74不属于默认JVM可信主机的证书提供者。 提供商是www.identrust.com,但那不是我想要连接的域名。 该域名已从该提供商获得其证书。 请参阅JDK / JRE中的默认列表是否可以使用跨目录封面信任? - 读几个条目。 另请参阅哪些浏览器和操作系统支持Let's Encrypt。

所以,为了连接到我感兴趣的域,其中有一个从identrust.com发布的证书,我做了以下步骤。 基本上,我必须让identrust.com( DST Root CA X3 )证书被JVM信任。 我能够使用Apache HttpComponents 4.5这样做:

1:在证书链下载说明中获取来自不信任的证书。 点击DST根CA X3链接。

2:将该字符串保存到名为“DST根CA X3.pem”的文件中。 请务必在开始和结束文件中添加“----- BEGIN CERTIFICATE -----”和“----- END CERTIFICATE -----”行。

3:使用以下命令创建一个java密钥库文件cacerts.jks:

keytool -import -v -trustcacerts -alias IdenTrust -keypass yourpassword -file dst_root_ca_x3.pem -keystore cacerts.jks -storepass yourpassword

4:将生成的cacerts.jks密钥库复制到java /(maven)应用程序的资源目录中。

5:使用下面的代码加载这个文件并将它附加到Apache 4.5 HttpClient。 这将解决所有从indetrust.com发布证书的域的问题indetrust.com oracle将证书包含到JRE默认密钥库中。

SSLContext sslcontext = SSLContexts.custom()
        .loadTrustMaterial(new File(CalRestClient.class.getResource("/cacerts.jks").getFile()), "yourpasword".toCharArray(),
                new TrustSelfSignedStrategy())
        .build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        new String[] { "TLSv1" },
        null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
        .setSSLSocketFactory(sslsf)
        .build();

当项目建立时,cacerts.jks将被复制到类路径中并从那里加载。 在这个时候,我没有对其他ssl站点进行测试,但是如果上述代码在这个证书中“链接”,那么他们也会工作,但是我不知道。

参考:自定义SSL上下文以及如何使用Java HttpsURLConnection接受自签名证书?


而不是设置默认的套接字工厂(IMO是一件坏事) - 它只会影响当前的连接,而不是您试图打开的每个SSL连接:

URLConnection connection = url.openConnection();
    // JMD - this is a better way to do it that doesn't override the default SSL factory.
    if (connection instanceof HttpsURLConnection)
    {
        HttpsURLConnection conHttps = (HttpsURLConnection) connection;
        // Set up a Trust all manager
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()
        {

            public java.security.cert.X509Certificate[] getAcceptedIssuers()
            {
                return null;
            }

            public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
            {
            }

            public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
            {
            }
        } };

        // Get a new SSL context
        SSLContext sc = SSLContext.getInstance("TLSv1.2");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        // Set our connection to use this SSL context, with the "Trust all" manager in place.
        conHttps.setSSLSocketFactory(sc.getSocketFactory());
        // Also force it to trust all hosts
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
        // and set the hostname verifier.
        conHttps.setHostnameVerifier(allHostsValid);
    }
InputStream stream = connection.getInputStream();
链接地址: http://www.djcxy.com/p/21829.html

上一篇: signed ssl certificate in Java client

下一篇: SSL Authentication with Certificates: Should the Certificates have a hostname?