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)。