“sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException” に対する対処

HTTPS でホストされている、あるウェブサイトをクロールする Java プログラムを動かしていたところ、次のような例外が表示された。

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

sun.security.validator.ValidatorException は、Java の持つルート証明書ではウェブサイトの SSL 証明書の正当性を検証できないときに投げられる例外である。

この問題を解決するためにできることはふたつある。

  • ウェブサイトの SSL 証明書に対応するルート証明書を Java にインストールする
  • Java のバージョンを更新して、Java が標準で使うルート証明書を更新する

後者の方が手軽なので、今回は単に Java をアップデートすることにした。なお、前者に興味がある場合は “java keytool” などで検索するとよい。

ただし、今回の僕のケースでは Java を最新版に更新しても問題は解決しなかった。調べてみると、ウェブサイトの側の SSL 中間証明書の設定に問題があるようであった。中間証明書の設定に問題があるかどうかは、たとえば Symantec が提供するサービスなどで確認できる。

ssl-intermediate-cert-verification

“Intermediate certificate missing.” とのことだ。ここで、対応する “GeoTrust SSL CA – G3” をダウンロードして Java の適切なパスに置いてやることで、当面の問題は解決する。

ただし、ウェブサイト側は中間証明書を置かなければ、古いブラウザのユーザーを切り捨てることになるし、BEAST攻撃に対して脆弱なまま放置することにもなる。

Gradle で “Failed to load native library ‘libnative-platform.so’ for Linux amd64.” と言われるときの対処

gradle build をして、次のようなエラーに遭遇した:

FAILURE: Build failed with an exception.

* What went wrong:
Failed to load native library 'libnative-platform.so' for Linux amd64.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

いかにも何か依存パッケージが足りていないようなエラーメッセージだ。検索してみると「libstdc++ をインストールすると解決するよ」という記事も実際に存在する。

僕も libstdc++ をインストールしてみたが、問題は解決しなかった。実際には ~/.gradleroot 権限でディレクトリが作られてしまっていたことが問題であった。単に ~/.gradle/* を削除して gradle build を実行しなおすことでビルドを実行できた。

わかってしまえば簡単な問題だけど、エラーメッセージが不親切だと時間を無駄にしてしまう事例だ。

JVM オプションでの SOCKS プロキシの指定

Java (or JVM 言語) で SOCKS プロキシを経由して外部リソースにアクセスしたい場合を考えてみよう。

まずは次のようなコマンドを実行して、localhost の 1080 番ポートに SOCKS サーバを立ち上げる。

$ ssh -f -N -D 1080 bastion.example.com
$ sudo lsof -i :1080
COMMAND  PID            USER   FD   TYPE            DEVICE SIZE/OFF NODE NAME
ssh     4006 yasunori.mahata    8u  IPv6 0x103xxxxxxxxxxxx      0t0  TCP localhost:socks (LISTEN)
ssh     4006 yasunori.mahata    9u  IPv4 0x103xxxxxxxxxxxx      0t0  TCP localhost:socks (LISTEN)

Java アプリケーションにこの SOCKS プロキシを使わせたいとしよう。例えば、bastion.example.com からしかアクセスできないリソースにさわりたい場合だ。

そういう場合は、JVM に次のオプションを渡せばよい。

-DsocksProxyHost=localhost -DsocksProxyPort=1080

参考記事