検証環境とか開発環境で自己署名証明書(self signed certificate)を使っている場合、証明書の検証に失敗してSSLHandshakeException
が発生します。
SpringのRestTepmlateでSSL Certificate Validationを無効にする の様にHttpClient側でSSLの検証を行わない様に設定をすることもできますが、いちいち全てのクライアント側で設定を入れるのは面倒です。
JavaのKeyStoreに自己署名証明書を登録することでSSLの検証を成功させることができるので設定したときのメモを残しておく。
環境
- CentOS 6
- Java8
$ rpm -qa | grep java
java-1.8.0-openjdk-1.8.0.101-3.b13.el6_8.x86_64
java-1.8.0-openjdk-devel-1.8.0.101-3.b13.el6_8.x86_64
tzdata-java-2016f-1.el6.noarch
java-1.8.0-openjdk-headless-1.8.0.101-3.b13.el6_8.x86_64
OSは違えど仕組みは一緒だと思うので適宜読み替えれば動くと思います。
Javaの自己署名証明書の検証について
CommonNameが正しく設定されていない場合は証明書の名前がおかしいよとExceptionが出ます。これはどうしようもないので証明書のCommonNameを正しく設定する必要があります。Caused by: java.security.cert.CertificateException: No name matching localhost found
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found
証明書の検証に失敗したときは以下の様なCausedが表示されるはずです。当然、自己署名証明書なので検証に失敗します。Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
あらかじめ、JavaのKeyStoreに信頼する証明書として登録しておくことでExceptionを回避することができます。
JavaのKeyStoreについて
Javaが参照しているデフォルトのKeyStoreは次の場所にあります。$ ls -la /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/lib/security/cacerts
lrwxrwxrwx. 1 root root 41 8月 4 21:36 2016 /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/lib/security/cacerts -> ../../../../../../../etc/pki/java/cacerts
CentOSの場合は上記ですが、${JAVA_HOME}/lib/security/cacerts
にあるはずです。
/etc/pki/java/cacerts
にCertファイルをImportすればOKです。
Nginxに自己署名証明書を登録する
ついでに動作確認様に使うNginxに自己署名証明書を登録しておく。
$ mkdir /etc/nginx/certs && chmod 700 /etc/nginx/certs |
KeyStoreに自己証明書を登録する
Javaが使っているKeyStoreに自己署名証明書のcertificateファイルをimportするだけです。
/etc/nginx/certs/server.crt
をKeyStoreにインポートすればOKです。
/etc/pki/java/cacerts
のパスワードはchangeit
です。
$ keytool -import -alias selfsigned -file /etc/nginx/certs/server.crt -keystore /etc/pki/java/cacerts |
yes
じゃだめなんだ:)
KeyStoreに登録できたかどうか確認する
登録できたか確認する。$ keytool -v -list -keystore /etc/pki/java/cacerts -alias selfsigned
キーストアのパスワードを入力してください:
別名: selfsigned
作成日: 2016/10/29
エントリ・タイプ: trustedCertEntry
所有者: O=Default Company Ltd, L=Default City, C=XX
発行者: O=Default Company Ltd, L=Default City, C=XX
シリアル番号: 92c66ccd2c24bd98
有効期間の開始日: Tue Oct 18 23:23:15 JST 2016終了日: Fri Oct 16 23:23:15 JST 2026
証明書のフィンガプリント:
MD5: 95:A9:6B:DC:77:7A:14:4F:EF:7C:6C:D8:E3:57:C3:9E
SHA1: 20:B5:65:DC:EF:5A:35:74:BE:1C:CB:C7:81:BA:8C:04:A7:BA:7E:A1
SHA256: 31:8A:04:09:AC:C4:A6:68:13:BF:ED:C4:CB:73:62:F1:D9:3F:DC:25:47:EF:18:CA:90:B8:A8:6F:F3:6A:B2:85
署名アルゴリズム名: SHA1withRSA
バージョン: 1
手元にcertificateファイルがない場合
opensslコマンドで簡単に取得できます。取得したserver.crtをKeyStoreにインポートすればOKです。
$ echo -n | openssl s_client -connect localhost:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > server.crt |
確認
Excepotionが出ていたプログラムを実行するとExcepotionが出ないことが確認できるはずです。
おわり。