証明書要求を作成する - プログラムによる証明書要求ファイルの作成 - C#

.NET Framework 4.7.2 で導入された、プログラムからの証明書要求を作成するコードを紹介します。

プログラム例

Windows Form アプリケーションを作成します。

UI

下図のUIを作成します。フォームにボタンを一つ配置します。

アセンブリの追加

ソリューションエクスローラの[参照]ノードから、System.Security アセンブリを追加します。


コード

下記のコードを記述します。button1のクリックイベントの実装になります。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.IO;

namespace CreateCertificationRequest
{
  public partial class FormMain : Form
  {
    public FormMain()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      RSACryptoServiceProvider rsaPrivateKey = new RSACryptoServiceProvider();

      CertificateRequest request = new CertificateRequest(
        "CN=test.ipentec.net, O=iPentec, C=JP",
        rsaPrivateKey,
        HashAlgorithmName.SHA256,
        RSASignaturePadding.Pkcs1);

      // 証明書の制約を追加 (CAの証明書ではなくパスに関する制限もなしの設定)
      request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));

      //サーバー認証のOID(1.3.6.1.5.5.7.3.1) を追加
      request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, false));

      //フラグの設定 (暗号化に利用する証明書、デジタル署名に利用する証明書 を指定)
      request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, true));

      /*
      //DNS名を指定する
      SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();
      sanBuilder.AddDnsName("test.ipentec.net");
      sanBuilder.AddDnsName("blog.test.ipentec.net");
      request.CertificateExtensions.Add(sanBuilder.Build());
      */

      // DER-エンコードされた証明書リクエスト取得文字列
      byte[] csrBytes = request.CreateSigningRequest();
      string base64str = Convert.ToBase64String(csrBytes);

      FileStream fs = new FileStream("req.txt", FileMode.CreateNew, FileAccess.Write, FileShare.None, 4096, FileOptions.None);
      StreamWriter sw = new StreamWriter(fs);
      try {
        sw.Write(base64str);
      }
      finally {
        sw.Close();
        fs.Close();
      }

      MessageBox.Show("証明書要求を作成しました。");
      
    }
  }
}

解説

RSAのキーペアを作成し、証明書要求オブジェクトを作成します。証明書要求オブジェクトには、サブジェクトの値、RSAキーぺーあ、ハッシュアルゴリズム、パティングの処理を方法を指定します。
  RSACryptoServiceProvider rsaPrivateKey = new RSACryptoServiceProvider();

  CertificateRequest request = new CertificateRequest(
    "CN=test.ipentec.net, O=iPentec, C=JP",
    rsaPrivateKey,
    HashAlgorithmName.SHA256,
    RSASignaturePadding.Pkcs1);

CertificateRequest クラスのコンストラクタの第一引数にはサブジェクトの文字列を指定します。サブジェクトの文字列書式は下記となります。
名称識別子意味入力例
コモンネームCommon NameCNサーバー証明書の場合は接続先のサーバー名が入りますwww.ipentec.com
組織名Organization NameO組織名ですiPentec
組織単位名Organization UnitOU部署名です
市町村名Locality NameL組織の市町村名住所ですMinato-Ku
都道府県名State or Province NameS または ST組織の住所の都道府県名ですTokyo
国名CountryC組織の住所の国名ですJapan
サブジェクトの例
"CN=www.ipentec.net, O=iPentec, OU=Web Division, L=Shinagawa, ST=Tokyo, C=JP",


証明書の追加情報を設定します。
  // 証明書の制約を追加 (CAの証明書ではなくパスに関する制限もなしの設定)
  request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));

  //サーバー認証のOID(1.3.6.1.5.5.7.3.1) を追加
  request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, false));

  //フラグの設定 (暗号化に利用する証明書、デジタル署名に利用する証明書 を指定)
  request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, true));

OIDの値は用途来よってきめられており、以下の値になっています。
用途OIDの値
クライアント認証1.3.6.1.5.5.7.3.2
サーバー認証1.3.6.1.5.5.7.3.1
ドキュメントの署名1.3.6.1.4.1.311.10.3.12

証明書にDNS名を設定する場合は、下記のコードを有効にします。
  //DNS名を指定する
  SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();
  sanBuilder.AddDnsName("test.ipentec.net");
  sanBuilder.AddDnsName("blog.test.ipentec.net");
  request.CertificateExtensions.Add(sanBuilder.Build());

下記のコードにより、証明書要求情報を取得します。証明書の要求情報はbyte型の配列のバイナリ値のため、Base64エンコードして値をファイルを保存しています。
  // DER-エンコードされた証明書リクエスト取得文字列
  byte[] csrBytes = request.CreateSigningRequest();
  string base64str = Convert.ToBase64String(csrBytes);

  FileStream fs = new FileStream("req.txt", FileMode.CreateNew, FileAccess.Write, FileShare.None, 4096, FileOptions.None);
  StreamWriter sw = new StreamWriter(fs);
  try {
    sw.Write(base64str);
  }
  finally {
    sw.Close();
    fs.Close();
  }

  MessageBox.Show("証明書要求を作成しました。");

実行結果

上記のプロジェクトを実行します。下図のウィンドウが表示されます。


[button1]をクリックします。証明書要求情報が生成され、証明書要求ファイルが保存されます。証明書要求が取得できた旨のメッセージが画面に表示されます。


実行したプログラムと同じディレクトリに 証明書要求ファイル "req.txt" が作成されています。


"req.txt"ファイルを開きます。Base 64でエンコードされた文字列が並んでいます。


証明機関に証明書要求ファイル "req.txt" を渡します。


証明機関のタスクから[新しい要求の送信]メニューを選択し証明書要求ファイルを登録します。


保留中の要求に登録されることが確認できます。


タスクから[発行]メニューをクリックし証明書を発行します。


証明書が発行できました。プログラムコードで指定した"test.ipentec.net" が共通名に設定されていることも確認できます。


C#のプログラムで生成した証明書要求情報から証明書が発行できました。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2024-01-07
作成日: 2018-09-26
iPentec all rights reserverd.