Java:Let’s EncryptのSSL証明書が認識されない
単純にJavaプログラムからLet’s EncryptのSSLサイト(https)に接続しようとする際にエラーが発生してしまうことがある。
原因はまだ明確ではないのだが、どうもLet’s Encryptのルート証明書が古いJavaには含まれていないせいらしい。
問題の現象
Jetty-Clientライブラリを使用した場合には以下のエラーになる。
javax.net.ssl.SSLHandshakeException: General SSLEngine problem
ごく普通にjava.net.URLを使用したプログラムの場合は以下だ。
public static void main(String[]args) throws Exception {
URL url = new URL("https://some.site");
url.openStream();
}
JRE1.6.0_45で実行した場合の例外は以下になる。
Exception in thread "main" 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
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1747)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
原因と思われるもの
Trusting Let’s Encrypt SSL certificate in a Java Spring applicationに説明がある。
これによれば、Let’s Encryptの使用しているDST Root CA X3という証明書が追加されたのは、JDK 7u111+とJDK 8u101+だという(この記事は2017/2/22のものであることに注意)。
したがって、それ以前のバージョンのJavaには必要な証明書が格納されていない。
ちなみに、2016/4の日本語記事として以下のようなものがある。
解決策
- Javaのバージョンを上げる
- 独自に証明書をインポートする
ということになる。後者について記事中ではやり方が記載されているが、いかにも面倒だ。
今後の懸念点
参照した記事では、DST Root CA X3に言及しているのだが、2019年にLet’s EncryptはISRG Rootというものに移行するそうだ。というよりも、本サイトの証明書を見てみると、既にISRG Root X1というものになっている。
これについて以下の記事がある(2019/4/16)。