Java 兼容 Let’s Encrypt 证书

最近公司打算将网站 HTTPS 证书更换为 Let’s Encrypt 的证书。虽然现在主流浏览器已经信任 Let’s Encrypt 证书了,但是对于一些 Java 老版本,还是会出现不兼容的情况。

hello_world_lets_encrypt.png

为解决此问题,本文应运而生。

什么是 Let's Encrypt

Let's Encrypt 是一个免费,自动化和开放的证书颁发机构(CA),为公益而运行,由 Internet Security Research Group(ISRG) 提供服务。

Let's Encrypt 由 Mozilla、Cisco、Akamai、IdenTrust、EFF 等组织人员发起,主要的目的是为了推进网站从 HTTP 向 HTTPS 过度的进程,目前已经有越来越多的商家加入和赞助支持,其证书现在已经可以被所有主流的浏览器所信任。

证书兼容性

因 Let's Encrypt 证书较新,下列 JDK/JRE 旧版本会不信任 Let's Encrypt 证书
(查看 Java 版本:命令行输入 java -version ):

  • Java 7 < 7u111
  • Java 8 < 8u101

而抛出以下异常:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException
[... 以下输出省略 ...]

详细兼容性问题参考:https://letsencrypt.org/docs/certificate-compatibility/

检查 Java 环境是否兼容 Let's Encrypt 证书

自行编写程序测试

自行编写测试程序查看 Java 环境是否支持 Let's Encrypt 证书:

new URL("https://helloworld.letsencrypt.org").openConnection().connect();

然后查看是否抛出以下异常即可:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException
[... 以下输出省略 ...]

使用 SSLPing 进行测试

如还没有测试程序,可以使用 ping 测试程序:SSLPing(可测试任何 SSL/TLS 端口,不仅是 HTTPS)。下面将使用预先编译的 SSLPing.jar 进行测试(阅读源码后自行编译也非常容易):

在命令行输入以下内容以克隆 SSLPing 这个项目(请确保已安装 git)或点击链接下载 SSLPing.jar

git clone https://github.com/dimalinux/SSLPing.git

成功后进行测试:

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
[... 以下输出省略 ...]

问题解决

出现这种证书不兼容的情况,只是因为 Let’s Encrypt 证书太新,Java 老版本未将其加入根证书导致。
具体解决办法有两种共三个:

  • 1.更新 Java update 版本
    比如 JDK8_8u100,升级到 JDK8_8u101 及以上就可以了。但是搞 Java 的都是老学究,怕出现兼容问题,坚决不肯升级,所以不推荐。
  • 2.自行将 Let's Encrypt 证书加入信任
    Chrome 浏览器打开一个使用 Let's Encrypt 证书的网站:https://chengww.com,可以看到一共有三个证书:
    letsencrypt_certificate.png

现在关键是将哪个证书加入信任的问题。

isrg-keys.png

参考 Let's Encrypt 官网 Chain of Trust 里面的这段说明:

Our roots are kept safely offline. We issue end-entity certificates to subscribers from the intermediates in the next section.

根证书 ISRG Root X1 (self-signed) 是离线安全保存的,在下一节中向中间人发放终端实体证书。

IdenTrust has cross-signed our intermediates. This allows our end certificates to be accepted by all major browsers while we propagate our own root.

Under normal circumstances, certificates issued by Let’s Encrypt will come from “Let’s Encrypt Authority X3”. The other intermediate, “Let’s Encrypt Authority X4”, is reserved for disaster recovery and will only be used should we lose the ability to issue with “Let’s Encrypt Authority X3”. The X1 and X2 intermediates were our first generation of intermediates. We’ve replaced them with new intermediates that are more compatible with Windows XP.

IdenTrust 和 Let's Encrypt 中间证书已经交叉签名,故所有主流浏览器都接受 Let’s Encrypt 的结束证书。

正常情况下,Let's Encrypt 颁发的证书将来自“Let's Encrypt Authority X3”。另一个中间件“Let's Encrypt Authority X4”保留用于灾难恢复,只有在Let's Encrypt 失去发出“Let's Encrypt Authority X3”的能力时才会使用。X1和X2中间体是Let's Encrypt 的第一代中间体。Let's Encrypt 用与Windows XP更兼容的新中间体替换它们。

也就是现在只有 Let's Encrypt Authority X3 是正在签名用的。将其加入信任即可。

参考解决方法(任选其一):

往 JRE 中导入 Let's Encrypt 证书(无需修改代码,推荐)

可以将 Let's Encrypt 证书加入 JRE 的信任证书,这种方式无需修改代码,简单快捷,推荐使用。

操作系统为 Mac OS X 或 Linux

  • 检查 JAVA_HOME 已经正确配置

在终端上输入以下内容:

echo $JAVA_HOME 

出现以下类似回应即为正确配置:

/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/

如未配置请自行搜索配置 Java 环境变量即可。

  • 下载 Let's Encrypt 中间证书
wget https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem

或直接复制上述链接下载即可

  • 导入证书
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.pem"

出现

Certificate was added to keystore 

即可

(注:当出现 java.io.FileNotFoundException... 时可能要检查相关文件路径是否正确)

操作系统为 Windows

  • 检查 JAVA_HOME 已经正确配置

在命令行上输入以下内容:

echo %JAVA_HOME%

出现以下类似回应即为正确配置:

C:\Program Files (x86)\Java\jdk1.8.0_92

如未配置请自行搜索配置 Java 环境变量即可。

  • 下载 Let's Encrypt 中间证书
wget https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem

或直接复制上述链接下载即可

  • 导入证书
cd %JAVA_HOME%\bin
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.pem"

出现

Certificate was added to keystore 

即可

(注:当出现 java.io.FileNotFoundException... 时可能要检查相关文件路径是否正确)

该方法至此已经完成,请检测是否成功。


程序运行时添加 Let's Encrypt 证书为信任证书

也可以在程序初始化或网络初始化时将 Let's Encrypt 证书添加进信任证书。

使用火狐浏览器访问 https://helloworld.letsencrypt.org ,然后将 Let's Encrypt Authority X3 导出为 .cer 文件,或点击下载 Let's Encrypt Authority X3.cer

将文件地址替换下述文件地址中: "Let's Encrypt Authority X3.cer"

具体请参考以下示例添加:

/**
 * Created by chengww on 2018/9/18.
 */

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;

import javax.net.ssl.SSLHandshakeException;

public class SSLExample {

    private static void initTrustManager() {
        // Enter the path of the file named 'Let's Encrypt Authority X3.cer'
        System.setProperty("javax.net.ssl.trustStore", "Let's Encrypt Authority X3.cer");
    }

    public static void main(String[] args) throws IOException {
        initTrustManager();
        
        // signed by default trusted CAs.
        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"));
        // qingstorage
        testUrl(new URL("https://stor.qingstorage.com"));
        // qingcloud
        testUrl(new URL("https://www.qingcloud.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);
        }
    }

}

该方法至此已经完成,请检测是否成功。


升级 JDK/JRE 版本

可以直接升级的 JDK/JRE update 版本,7u111 及 8u101 之后已将 Let's Encrypt 证书加入信任。

前往 https://www.oracle.com/technetwork/java/javase/downloads/index.html 下拉到最后一项 Java Archive,点击 DOWNLOAD

Java_Archive.png

选择 Accept License Agreement,下载对应的 JDK/JRE 版本后安装即可

Accept_License_Agreement.png

该方法至此已经完成,请检测是否成功。


检查是否成功

重复操作上述 检查 Java 环境是否兼容 Let's Encrypt 证书 的内容即可。


文章作者: chengww
文章链接: https://chengww.com/archives/Java_compatible_certificate_of_Lets_Encrypt.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 chengww's blog

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容