当前位置:  开发笔记 > 编程语言 > 正文

Java支持Let的加密证书吗?

如何解决《Java支持Let的加密证书吗?》经验,为你挑选了4个好方法。

我正在开发一个Java应用程序,它通过HTTP查询远程服务器上的REST API.出于安全原因,应将此通信切换为HTTPS.

现在Let's Encrypt开始了他们的公开测试版,我想知道Java目前是否可以使用他们的证书(或者确认将来会工作).

让加密得到IdenTrust的中间交叉签名,这应该是个好消息.但是,我在这个命令的输出中找不到这两个中的任何一个:

keytool -keystore "..\lib\security\cacerts" -storepass changeit -list

我知道可以在每台机器上手动添加可信任的CA,但由于我的应用程序可以免费下载和执行而无需进一步配置,我正在寻找"开箱即用"的解决方案.你有好消息吗?



1> zapl..:

[ 更新2016-06-08:根据https://bugs.openjdk.java.net/browse/JDK-8154757,IdenTrust CA将包含在Oracle Java 8u101中.]

[ 更新2016-08-05:Java 8u101已发布,确实包含了IdenTrust CA:发行说明 ]


Java支持Let的加密证书吗?

是.Let's Encrypt证书只是一个普通的公钥证书.Java支持它(根据Let的加密证书兼容性,对于Java 7> = 7u111和Java 8> = 8u101).

Java是否相信Let's加密证书是开箱即用的?

不/它取决于JVM.Oracle JDK/JRE的信任库最高为8u66,既不包含Let的加密CA,也不包含交叉签名的IdenTrust CA. new URL("https://letsencrypt.org/").openConnection().connect();例如结果javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException.

但是,您可以提供自己的验证器/定义包含所需根CA的自定义密钥库,或将证书导入JVM信任库.

https://community.letsencrypt.org/t/will-the-cross-root-cover-trust-by-the-default-list-in-the-jdk-jre/134/10也讨论了该主题.


下面是一些示例代码,演示如何在运行时将证书添加到默认信任库.你只需要添加证书(从firefox导出为.der并放入classpath)

基于如何获取Java中受信任的根证书列表?和http://developer.android.com/training/articles/security-ssl.html#UnknownCa

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.PKIXParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManagerFactory;

public class SSLExample {
    // BEGIN ------- ADDME
    static {
        try {
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            Path ksPath = Paths.get(System.getProperty("java.home"),
                    "lib", "security", "cacerts");
            keyStore.load(Files.newInputStream(ksPath),
                    "changeit".toCharArray());

            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            try (InputStream caInput = new BufferedInputStream(
                    // this files is shipped with the application
                    SSLExample.class.getResourceAsStream("DSTRootCAX3.der"))) {
                Certificate crt = cf.generateCertificate(caInput);
                System.out.println("Added Cert for " + ((X509Certificate) crt)
                        .getSubjectDN());

                keyStore.setCertificateEntry("DSTRootCAX3", crt);
            }

            if (false) { // enable to see
                System.out.println("Truststore now trusting: ");
                PKIXParameters params = new PKIXParameters(keyStore);
                params.getTrustAnchors().stream()
                        .map(TrustAnchor::getTrustedCert)
                        .map(X509Certificate::getSubjectDN)
                        .forEach(System.out::println);
                System.out.println();
            }

            TrustManagerFactory tmf = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(keyStore);
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), null);
            SSLContext.setDefault(sslContext);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    // END ---------- ADDME

    public static void main(String[] args) throws IOException {
        // signed by default trusted CAs.
        testUrl(new URL("https://google.com"));
        testUrl(new URL("https://www.thawte.com"));

        // signed by letsencrypt
        testUrl(new URL("https://helloworld.letsencrypt.org"));
        // signed by LE's cross-sign CA
        testUrl(new URL("https://letsencrypt.org"));
        // expired
        testUrl(new URL("https://tv.eurosport.com/"));
        // self-signed
        testUrl(new URL("https://www.pcwebshop.co.uk/"));

    }

    static void testUrl(URL url) throws IOException {
        URLConnection connection = url.openConnection();
        try {
            connection.connect();
            System.out.println("Headers of " + url + " => "
                    + connection.getHeaderFields());
        } catch (SSLHandshakeException e) {
            System.out.println("Untrusted: " + url);
        }
    }

}


@ adapt-dev不,软件为什么要相信未知系统提供良好的证书?软件需要能够信任它实际信任的证书.如果这意味着我的java程序可以为别人程序安装证书,那将是一个安全漏洞.但这不会发生在这里,代码只在它自己的运行时添加了证书
用于显示不仅仅通过设置`javax.net.ssl.trustStore`系统属性而作弊的代码的+1,但是为-1然后设置JVM的默认`SSLContext`.最好创建一个新的`SSLSocketFactory`,然后将其用于各种连接(例如`HttpUrlConnection`),而不是替换VM范围的SSL配置.(我意识到这种变化只对正在运行的JVM有效,并且不会持续存在或影响其他程序.我认为这是一种更好的编程习惯,可以明确说明配置的适用位置.)

2> Jan Berkel..:

我知道OP要求提供没有本地配置更改的解决方案,但是如果您想永久地将信任链添加到密钥库:

$ keytool -trustcacerts \
    -keystore $JAVA_HOME/jre/lib/security/cacerts \
    -storepass changeit \
    -noprompt \
    -importcert \
    -file /etc/letsencrypt/live/hostname.com/chain.pem

来源:https://community.letsencrypt.org/t/will-the-cross-root-cover-trust-by-the-default-list-in-the-jdk-jre/134/13


是的,OP没有要求它,但这对我来说是迄今为止最简单的解决方案!

3> 小智..:

我们这些愿意进行本地配置更改的详细解答,包括备份配置文件:

1.在更改之前测试它是否正常工作

如果您还没有测试程序,可以使用我的java SSLPing ping程序来测试TLS握手(可以使用任何SSL/TLS端口,而不仅仅是HTTPS).我将使用预先构建的SSLPing.jar,但是阅读代码并自己构建它是一项快速而简单的任务:

$ git clone https://github.com/dimalinux/SSLPing.git
Cloning into 'SSLPing'...
[... output snipped ...]

由于我的Java版本早于1.8.0_101(在撰写本文时尚未发布),因此默认情况下不会验证Let的加密证书.在应用修复之前,让我们看看失败的样子:

$ java -jar SSLPing/dist/SSLPing.jar helloworld.letsencrypt.org 443
About to connect to 'helloworld.letsencrypt.org' on port 443
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
[... output snipped ...]

2.导入证书

我在Mac OS X上使用JAVA_HOME环境变量集.以后的命令将假定为要修改的java安装设置了此变量:

$ echo $JAVA_HOME 
/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/

备份我们将要修改的cacerts文件,这样您就可以在不重新安装JDK的情况下退出任何更改:

$ sudo cp -a $JAVA_HOME/jre/lib/security/cacerts $JAVA_HOME/jre/lib/security/cacerts.orig

下载我们需要导入的签名证书:

$ wget https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.der

执行导入:

$ sudo keytool -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -noprompt -importcert -alias lets-encrypt-x3-cross-signed -file lets-encrypt-x3-cross-signed.der 
Certificate was added to keystore

3.验证更改后它是否正常工作

验证Java现在是否满意连接到SSL端口:

$ java -jar SSLPing/dist/SSLPing.jar helloworld.letsencrypt.org 443
About to connect to 'helloworld.letsencrypt.org' on port 443
Successfully connected



4> Anthony O...:

对于尚不支持Let的加密证书的JDK,您可以在cacerts此过程之后将这些证书添加到JDK (由此).

下载https://letsencrypt.org/certificates/上的所有证书(选择der格式)并使用这种命令逐个添加它们(示例为letsencryptauthorityx1.der):

keytool -import -keystore PATH_TO_JDK\jre\lib\security\cacerts -storepass changeit -noprompt -trustcacerts -alias letsencryptauthorityx1 -file PATH_TO_DOWNLOADS\letsencryptauthorityx1.der

推荐阅读
保佑欣疼你的芯疼
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有