LoginSignup
1
1

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-11-07

背景

Let's Encryptの証明書は90日で期限が切れちゃうので、定期的に期限を確認して、切れそうだったら教えてくれるプログラムを作りたいと思った。

しかし、いまいちC#でサーバ証明書を取得する正しい方法がわからない…
思いついた方法で無理やり作ったので、知っている人いたら教えてください。

プログラム

HttpClientは、内部でSSLサーバ証明書を取得していて、有効かどうかを判定している。
HttpClientHandlerServerCertificateCustomValidationCallbackを指定すると、証明書が有効かどうかの判定を上書きできる。
その時に証明書にアクセスできるので、それを取り出せば、めでたくサーバ証明書を取得できる。

public static async Task<X509Certificate2> GetCertificateAsync(string uri)
{
    var tcs = new TaskCompletionSource<X509Certificate2>();
    _ = Task.Run(async () =>
    {
        var handler = new HttpClientHandler
        {
            ServerCertificateCustomValidationCallback = (_1, c, _2, _3) =>
            {
                tcs.TrySetResult(new X509Certificate2(c.RawData));
                return false;
            },
        };

        try
        {
            using (var hc = new HttpClient(handler))
            {
                await hc.GetAsync(uri);
            }
        }
        catch (Exception exp)
        {
            tcs.TrySetException(exp);
        }
    });

    return await tcs.Task;
}

ServerCertificateCustomValidationCallbackで証明書にアクセスできるが、その証明書はすぐに破棄されてしまうようなので、RawDataを使って証明書を複製している。WEBページの内容を取得したいわけじゃないので、false(証明書が無効であること)を返して、内容を取得しないことを期待している。

使い方

using (var certificate = await GetCertificateAsync("https://qiita.com/"))
{
    Console.WriteLine($"[{certificate.NotBefore:yyyy/MM/dd HH:mm:ss}]から[{certificate.NotAfter:yyyy/MM/dd HH:mm:ss}]まで有効");
}
1
1
0

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
1
1