如果我的客户端程序是Java,而不是在C#中,为什么我必须添加服务器SSL证书?

时间:2011-02-17 14:07:05

标签: c# java .net ssl https

如果我在Java程序中使用HttpsURLConnection并尝试打开以https://开头的URL,我将收到错误消息:

  

无法找到所请求目标的有效证书路径

我找到的解决方案是to add the server certificate to the client certificate storage。但是如果我编写一个使用HttpWebRequest的C#程序,那么我就不必在任何地方添加任何内容。

所以对我而言,它看起来像一个C#客户端“只是工作”而Java客户端只有在用锤子调整后才能工作。

为什么Java客户端需要额外的步骤?我可以以某种方式跳过将证书保存到JVM的客户端存储中吗?

4 个答案:

答案 0 :(得分:2)

HttpWebRequest将使用Window自己的证书存储来验证证书,即与IE相同。如果您的IE可以通过将证书或CA路径返回到受信任的根目录来正确验证证书,那么HttpWebRequest应该接受证书确定。

在Java案例中我怀疑添加服务器证书本身是错误的,除非它是自签名的,在这种情况下你将别无选择。您应该将CA路径添加回受信任的根目录 - 您可以将这些证书从Windows的CA存储中提取出来,或者如果需要,可以从根CA的网站下载它们。

答案 1 :(得分:2)

我认为这是因为C#使用与MSIE相同的HTTP客户端,因此它有许多预先安装的SSL证书,包括您使用的SSL证书。 JVM预安装的证书较少。

答案 2 :(得分:1)

默认情况下,Java使用自己的一组信任锚(在默认信任库中,请参阅JSSE Reference Guide)。

如果要使用Windows证书存储区,可以使用Windows-ROOT keystore作为信任存储区。

答案 3 :(得分:1)

有关此主题的一个很好的信息来源是Oracle网站上的Leveraging Security in the Native Platform Using Java SE 6 TechnologyJava Secure Socket Extension (JSSE) Reference Guide

如果您希望Java使用Windows证书存储来验证证书,那么您可以在启动时指定以下系统属性:

-Djavax.net.ssl.keyStoreType=Windows-MY -Djavax.net.ssl.trustStoreType=Windows-ROOT

如果您只想使用一个连接来使用Windows证书存储来验证证书,则可以修改以下代码以满足您的需求:

    KeyStore ks = KeyStore.getInstance("Windows-MY");
    ks.load(null, null);

    KeyStore ts = KeyStore.getInstance("Windows-ROOT");
    ts.load(null, null);

    TrustManagerFactory tmf = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(ts);

    KeyManagerFactory kmf = KeyManagerFactory
                .getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(ks, new char[0]);

    SSLContext ctx = SSLContext.getInstance("TLS");
    ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);    

    URL url = new URL("https://some.web.site.org");
    javax.net.ssl.HttpsURLConnection urlConnection = 
            (javax.net.ssl.HttpsURLConnection) url.openConnection();
    urlConnection.setSSLSocketFactory(ctx.getSocketFactory());
    urlConnection.connect();
    try (InputStream in = urlConnection.getInputStream();) {
        byte[] chunk = new byte[1024];
        for (int len; (len = in.read(chunk)) > -1;) {
            System.out.write(chunk, 0, len);
        }
    } finally {
        urlConnection.disconnect();
    }