背景
Let's Encryptの証明書は90日で期限が切れちゃうので、定期的に期限を確認して、切れそうだったら教えてくれるプログラムを作りたいと思った。
しかし、いまいちC#でサーバ証明書を取得する正しい方法がわからない…
思いついた方法で無理やり作ったので、知っている人いたら教えてください。
プログラム
HttpClient
は、内部でSSLサーバ証明書を取得していて、有効かどうかを判定している。HttpClientHandler
のServerCertificateCustomValidationCallback
を指定すると、証明書が有効かどうかの判定を上書きできる。
その時に証明書にアクセスできるので、それを取り出せば、めでたくサーバ証明書を取得できる。
publicstaticasyncTask<X509Certificate2>GetCertificateAsync(stringuri){vartcs=newTaskCompletionSource<X509Certificate2>();_=Task.Run(async()=>{varhandler=newHttpClientHandler{ServerCertificateCustomValidationCallback=(_1,c,_2,_3)=>{tcs.TrySetResult(newX509Certificate2(c.RawData));returnfalse;},};try{using(varhc=newHttpClient(handler)){awaithc.GetAsync(uri);}}catch(Exceptionexp){tcs.TrySetException(exp);}});returnawaittcs.Task;}
ServerCertificateCustomValidationCallback
で証明書にアクセスできるが、その証明書はすぐに破棄されてしまうようなので、RawData
を使って証明書を複製している。WEBページの内容を取得したいわけじゃないので、false
(証明書が無効であること)を返して、内容を取得しないことを期待している。
使い方
using(varcertificate=awaitGetCertificateAsync("https://qiita.com/")){Console.WriteLine($"[{certificate.NotBefore:yyyy/MM/ddHH:mm:ss}]から[{certificate.NotAfter:yyyy/MM/ddHH:mm:ss}]まで有効");}