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 プロパティ – 使用サンプルあり