saba1024のブログ

どうでも良い思いついた事とかプログラミング関係のメモとか書いていきます。

Apache GroovyでSSL証明書の有効期限を確認する

本記事はG* Advent Calendar 2017の19日目の記事です。

さて、2016年から正式に公開されたLet's Encryptを利用することで、誰でも無料でSSLを導入してセキュアな通信をお手軽に導入できるようになりました。
しかしLet's Encryptの証明書の有効期限は3ヶ月となっており、油断していると有効期限が切れていてエラーが表示されるようになりかねません。
opensslコマンド等を利用すればSSLの有効期限等が取得できるので、Zabbixなどで定期的に実行、確認してあげるようにする必要が有ります。

しかしWindowsだとopensslコマンドが。。。などなど問題が有りますので、今回Apache GroovyでSSLの有効期限を取得するスクリプトを書いてみました。
これであればLinuxでもWindowsApache Groovyが動くようにしておけば問題なく実行することが出来ます。

import java.security.cert.X509Certificate;
import javax.net.ssl.HttpsURLConnection;
import java.security.cert.Certificate;
import java.security.Principal

// SSL情報を確認したいサーバに接続
URL url = new URL("https://www.example.com")
HttpsURLConnection con = url.openConnection()
con.connect()

// サーバの主体(?)を取得する。
// 下記のgetServerCertificates()では複数の証明書が返ってくるので、このPeerPrincipalのhashCodeと比較して実際のSSL証明書情報を取得するために利用する。
Principal peerPrincipal = con.getPeerPrincipal()

// サーバーの証明書チェーンを取得する
List<Certificate> certs = con.getServerCertificates()
Certificate certificate = certs.findAll {
    it instanceof X509Certificate
}.find {
    it.getSubjectDN().hashCode() == peerPrincipal.hashCode()
}

// あとはCertificateクラスのメソッドなどを利用してSSL情報を取得できる。以下が有効期限の取得方法。
Date expirationDate = certificate.getNotAfter()
println expirationDate

con.disconnect()

すこし手こずった部分が、サーバから返ってくる証明書が複数あるので、どの証明書の有効期限を確認すれば良いか、という部分です。
コメントに書いてありますが、実際に利用されるSSL証明書の情報はgetPeerPrincipal()で取得できるので、サーバから返される証明書の一覧から、これと一致するものを取得するようにする必要が有ります。
なお、Principal#getName()で比較することも出来ますが、これだと同じ内容でもgetPeerPrincipal()で取得するPrincipalと証明書一覧からそれぞれ取得するPrincipalで文字列内のスペースがtrimされていたりして上手く比較できるパターンと出来ないパターンが混在しています。
そのため、比較はhashCode()で行うようにしています。