5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

任意のサイトのSSLサーバ証明書を取得する(新)

Last updated at Posted at 2022-02-02

背景

定期的にSSL証明書の期限を確認して、切れそうだったら教えてくれるプログラムを作りたいと思って作った(3年前)

↑これより、もっといい方法があるんじゃないか?と思ってILSpyを見てた。
だいぶいろいろわかってきたので、最新版を書こうと思った。

コード

以前書いたコードでは、HttpClientの処理の途中で証明書だけ奪ってた。
HttpClientはかなり複雑なことをやっているんだけど、最終的にはSslStreamを使っているようなので、それを直接使う。

public static async Task<X509Certificate2?> GetCertificateAsync(string host, int port = 443)
{
    using var client = new TcpClient(host, port); //※1.1
    using var stream = client.GetStream();
    using var sslStream = new SslStream(stream, false, (_, _, _, _) => true); //※2
    await sslStream.AuthenticateAsClientAsync(host); //※1.2
    return sslStream.RemoteCertificate as X509Certificate2; //※3
}

※1: 接続先と認証で、ホスト名を2回使う。※1.2でホスト名が必要なのはなんでだろう?取得した証明書の確認の為か?(SSL SNIの解決のため、ということでした。サーバは複数の証明書を持つことが可能で、どのホスト名の証明書が必要か送らないとダメです。@jzkeyさんありがとうございます。)
※2: 証明書を検査する(ふりをする)コールバック(_, _, _, _) => trueを設定しないといけない。これをやらないと、証明書にエラーがあったときに例外が発生する。今回はたとえエラーがあっても証明書自体を取得したいので、エラーは無視。
※3: 取得できる証明書の型はX509Certificateなんだけど、実体はX509Certificate2っぽいので変換。変換しなくてもいいかもしれないけどよくわかっていない。

取得した証明書は、使い終わったらDisposeする必要がある。
sslStream.RemoteCertificateで証明書を取得すると、SslStreamの破棄時に証明書が一緒に破棄されなくなるっぽい。

CancellationTokenでキャンセルできるようにしたバージョン

5
5
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?