はじめに
HttpClientでクライアント証明書を使うとか、証明書を.NETのプログラムで読み込む話。
証明書ストアからの読み込み
System.Security.Cryptography.X509CertificatesのX509Storeを使うと、証明書ストアから読み込みできる。
例えば、個人証明書を読み込む場合は以下のようになる。
using System;
using System.Security.Cryptography.X509Certificates;
namespace clientcert
{
internal class Program
{
static void Main(string[] args)
{
// 証明書ストアの現在のユーザ(Windowsアカウント)の「個人」を開く
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
// 証明書を選ぶ(絞り込む)、まずは有効期間内のもの
// 最後のtrueは証明のパスが正式なもののみ取り出す指定なので、オレオレの場合はfalseにする
X509Certificate2Collection col_all = store.Certificates;
X509Certificate2Collection col_date = col_all.Find(X509FindType.FindByTimeValid, DateTime.Now, true);
// 次に署名者の名前(CA証明書のCNなど)で絞り込む
X509Certificate2Collection col_issuer = col_date.Find(X509FindType.FindByIssuerName, "TestRoot", true);
// 見つかった証明書を出力
// X509Certificate2のオブジェクトなので、HttpClientとかでクライアント証明書として使える
foreach (X509Certificate2 cert in col_issuer)
{
Console.WriteLine(cert.ToString());
}
}
}
}
cert.Issuer は普通に文字列なので、Findで絞らず、自分で文字列を比較するなどでも問題ない。
オレオレ証明書で、ルート証明書をインポートしていない場合、Findの最後の引数をfalseにしないと出てこなくなるので注意。
ファイルからの読み込み
証明書ストアに入れないで読み込む場合、また、Windowsサービスから使うなど、ユーザが異なる場合はファイルから読み込むこともできる。
一般的にはpkcs12ファイル(.p12, .pfx)だと思うので、その想定。
using System;
using System.Security.Cryptography.X509Certificates;
using System.IO;
namespace clientcert
{
internal class Program
{
static void Main(string[] args)
{
// ファイルをバイト列として読み込む
// ファイル全体を読んで、全部読めなかったら(ファイルサイズと読み込んだサイズが違ったら)エラーにしている
byte[] file_data = null;
try
{
// 証明書のファイル名はここで指定
using (FileStream fs = new FileStream("client01.pfx", FileMode.Open, FileAccess.Read))
{
file_data = new byte[fs.Length];
int read_size = fs.Read(file_data, 0, file_data.Length);
if (read_size != fs.Length)
{
Console.WriteLine("Read error: size=" + read_size);
return;
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return;
}
// クライアント証明書のパスワード
string cert_pass = "password";
// ここまで来たらX509Certificate2のインスタンスが作れる
X509Certificate2 cert2 = new X509Certificate2(file_data, cert_pass, X509KeyStorageFlags.EphemeralKeySet);
Console.WriteLine(cert2.ToString());
}
}
}
使い方によっては X509KeyStorageFlags.EphemeralKeySetのところを変える必要があるかもしれない。