C#.NETでのSSL証明書情報取得方法

2021年8月時点、C# .NETでのモダンなSSL証明書情報(URL, 署名者, 期限日等)取得方法について調査した。

結論的には.NET Core ではServicePoint.Certificateは使えなくなっているため、HttpClientHandler.ServerCertificateCustomValidationCallbackを用いて取得する。

確認環境

.NET Core 3.1 on Windows 10

正常動作するコード

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace GetExpirationDateTest
{
class Program
{
static void Main(string[] args)
{
List tasks = new List();
tasks.Add(Task.Run(() => GetExpirationDate(@”https://example.com/”)));
//tasks.Add(Task.Run(() => GetExpirationDate(@”https://example.com/”)));
Task.WhenAll(tasks);
Console.WriteLine(@”DONE”);
string sign = Console.ReadLine();
}

    static async Task GetExpirationDate(string url)
    {
        Console.WriteLine(url);

        // Create an HttpClientHandler object and set to use default credentials
        HttpClientHandler handler = new HttpClientHandler();

        // Set custom server validation callback
        handler.ServerCertificateCustomValidationCallback = ServerCertificateCustomValidation;

        // Create an HttpClient object
        HttpClient client = new HttpClient(handler);

        // Call asynchronous network methods in a try/catch block to handle exceptions
        try
        {
            HttpResponseMessage response = await client.GetAsync(url);

            response.EnsureSuccessStatusCode();

            string responseBody = await response.Content.ReadAsStringAsync();
            Console.WriteLine($"Read {responseBody.Length} characters");
        }
        catch (HttpRequestException e)
        {
            Console.WriteLine("\nException Caught!");
            Console.WriteLine($"Message: {e.Message} ");
        }

        // Need to call dispose on the HttpClient and HttpClientHandler objects
        // when done using them, so the app doesn't leak resources
        handler.Dispose();
        client.Dispose();
    }

    private static bool ServerCertificateCustomValidation(HttpRequestMessage requestMessage, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslErrors)
    {
        // It is possible inpect the certificate provided by server
        Console.WriteLine($"Requested URI: {requestMessage.RequestUri}");
        Console.WriteLine($"Effective date: {certificate.GetEffectiveDateString()}");
        Console.WriteLine($"Exp date: {certificate.GetExpirationDateString()}");
        Console.WriteLine($"Issuer: {certificate.Issuer}");
        Console.WriteLine($"Subject: {certificate.Subject}");

        // Based on the custom logic it is possible to decide whether the client considers certificate valid or not
        Console.WriteLine($"Errors: {sslErrors}");
        return sslErrors == SslPolicyErrors.None;
    }
}

}

参考URL:

ServicePoint.Certificate プロパティ – .NET Core では常にnullになり使えないと言及

https://docs.microsoft.com/ja-jp/dotnet/api/system.net.servicepoint.certificate?view=net-5.0

HttpClientHandler.ServerCertificateCustomValidationCallback プロパティ – 使用サンプルあり

https://docs.microsoft.com/ja-jp/dotnet/api/system.net.http.httpclienthandler.servercertificatecustomvalidationcallback?view=net-5.0

TERSEファイル形式(フォーマット)

TERSE(タース)はIBM社が開発した無損失の圧縮ファイル形式で拡張子は .trs

シーケンシャルデータセットやパーシャルデータセット及びその拡張を扱える。

使い勝手

IBM社がApache 2 ライセンス下でオープンソースのJava展開プログラム:TERSE, DETERSE コマンドを用意している。

メインフレーム界隈で働く人なら一括でデータを取り扱えて便利なものの、一般的に使われる方式ではない。

www.japanbattery.jpでの違和感

長く使っているノートPCのバッテリーに赤ランプがともってしまい、バッテリーの寿命を検知した。

念のためバッテリーを売っていないか、何円か、確認するため検索すると、以下サイトがヒットした。

https://www-japanbattery-jp/

購入を進めようと思ったが、違和感がある。

  • 一般的なサイトと比較して品質・日本をアピールし過ぎている印象
  • ところどころ日本語が不自然
  • 『会社概要』ページはふわっとした情報しかなく会社情報が載っていない。
  • 支払いの安全性を伝える部分でペイパル(好きだけれど、何故クレカを書かず一点プッシュ?)

japanbattery.jp の登録情報を調べてみよう。

2021年4月29日時点

日本をプッシュ、品質をプッシュ、しかし登録情報は中国の深圳(シンセン)市らしい。

日本をプッシュしてドメイン名登録情報がこうなっていると気持ち悪いので購入を見送った。

※検索を進めると過去他にも同様な日本プッシュのバッテリーサイトが存在した様子。もしかしたら定期的にドメインを変えてサービスを続けているのかもしれない。