ルート証明書を使ったサーバ証明書・クライアント証明書の作成方法

概要

  • 検証・開発環境での使用を前提とした、ルート証明書の作成、その証明書で署名したサーバ証明書とクライアント証明書を作成する手順を説明します。
  • 可能な限りシンプルで簡単な条件・手順になっています。結果として、証明書の作成条件やコマンド操作ではセキュリティを考慮していないことに注意してください。(証明書の有効期限やその他条件、パスワードの取り扱い等)
  • 単純に自己署名のサーバ証明書やクライアント証明書を作成したい場合、ルート証明書を作成せずにサーバ証明書、クライアント証明書を作成するだけで済みます。自己署名クライアント証明書のみを作成したい場合、こちらの手順をご覧ください。
  • 次の環境で動作確認しています。
    • Windows 10(64ビット)環境のPowerShell(PSVersion: 5.1, PSEdition: Desktop, CLRVersion: 4.0)で検証しています。
    • 作成したルート証明書、サーバ証明書、クライアント証明書はリバースプロキシサーバとして構成したApache HTTPサーバで確認しています。具体的な構築手順はこちらをご覧ください。
    • PowerShellで行えない一部操作は、Windows向けのopenssl(slproweb.com)のWin64 OpenSSL v1.1.1h Lightを使用しています。その他のバイナリはopensselのwikiを参照のこと。
  • 証明書関連の用語(和名)は、可能な限り、証明書管理ツール(certmgr.msc)等のWindowsのGUIの表示名に合わせています。

証明書の作成方法

手順の前提条件や参考

  • ここで説明する手順の前提条件です。
    • 一般的な証明書の運用では、ルート証明書の他に中間証明書を用意し、中間証明書を使ってサーバ証明書やクライアント証明書を署名することになりますが、ここで便宜上、ルート証明書を使ってサーバ証明書・クライアント証明書を署名する手順になっています。
    • 証明書の作成場所(証明書ストア)として、「現在のユーザー」の「個人」(“cert:\CurrentUser\My”)を使用します。証明書ストアの基礎知識と証明書ストアの論理名・物理名の対応はこちらをご覧ください。
    • 検証用なので証明書の有効期限は10年にしています。
  • 証明書の作成で使用するNew-SelfSignedCertificateコマンドレットの参考です。
    • X.509のバージョン3から、後述の「拡張キー使用方法」「サブジェクト代替名」等のような拡張属性が追加されました。-DnsName等の特定用途のオプションはこのような拡張属性に対する値を設定します。より一般的な拡張属性に対する値の設定は、-TextExtensionオプションで行います。
      拡張属性の定義はRFC2549を参考にしてください。
    • 証明書に設定する項目や値はOIDと呼ばれる番号体系が使用されます。証明書関連のOIDの定義はRFC5280で定義されています。RFC5280でのOIDの読み方はこちらをご覧ください。
    • 証明書の作成時に、その証明書の使用方法「キー使用方法」と、その詳細「拡張キー使用方法」を指定できます。「拡張キー使用方法」(OID: 2.5.29.37)の英語名は、インターネット標準だと”Extended Key Usage: EKU”が正しいのですが、ここではマイクロソフトのリファレンスに合わせて”Enhanced Key Usage”と記載しています。(この辺の表記の違いはマイクロソフトの都合のようです。)
    • ファイルの拡張子の違いについては、こちらをご参考にしてください。
    • PowerShellの証明書関連のコマンド体系はこちらをご覧ください。

ルート証明書の作成

  1. サーバ証明書、クライアント証明書に署名するためのルート証明書を作成します。
    • New-SelfSignedCertificateを使用してルート証明書を作成します。
    • 認証局のルート証明書としての他の証明書を署名できるようキーの使用目的と基本制限を指定します。
      • キーの使用目的(-KeyUsage)として、署名系の値(CertSign, CRLSign)を指定します。
      • 基本制限(-TextExtensionの”2.5.29.19″)として、「認証局である(CA=true)」「下位の認証局(中間証明書)の数」(pathlength)も指定します。
      • pathlengthの値が既定の無制限の場合、サーバ証明書・クライアント証明書等(エンドエンティティ)に対する署名は下位の認証局(中間証明書)で行う前提となり、このルート証明書では署名できません。そのため、ここではpathlengthとして0(下位の認証局は存在しない)を指定して、このルート証明書で署名できるようにしています。
      • なお、証明書の作成先として「信頼されたルート証明機関」を指定するエラーになってしまいます。
  2. 作成したルート証明書を「信頼するルート証明書」として登録します。
    • 証明書ストア作成したルート証明書をExport-Certificateを使ってファイルにエクスポートします。なお、作成したルート証明書にキーも含まれますが、Export-Certificateはキーをエクスポートしません。
    • そのファイルをImport-Certificateを使って「信頼されたルート証明機関」にインポートします。
    • 証明書管理ツール(certmgr.msc)のGUIで証明書をエクスポート・インポートする方法や、作成したcerファイルをダブルクリックしてインストールする方法でも可能です。

サーバ証明書の作成

前述の手順で作成したルート証明書を使用して、サーバ証明書を作成します。
ローカルでの動作確認を想定しているため、サーバ名は”localhost”にしています。

  • 前述の手順で作成済みのルート証明書を$rootcaに取得します。
  • New-SelfSignedCertificateを使用してサーバ証明書を作成します。
  • サーバ名を指定するために-DnsNameオプションを指定します。
    • 以前は、サブジェクト(CN値)に指定されたサーバ名を使ってサーバ証明書の検証が行われていました。この方法は曖昧さがあるため、近年のブラウザではサブジェクト代替名(Subject Alternative Name: SAN)に指定されたサーバ名で検証するように変わっています。
    • 仕様の根拠はRFC2818の”3.1. Server Identity“にあります。この対応はChrome58から始まっています。
    • -DnsNameの最初のホスト名がサブジェクト(CN値)に設定されます。
  • -TextExtensionで次を設定しています。
    • 基本制限(2.5.29.19)として「エンドエンティティ(認証局ではない)」を指定しています。通常、ルート証明書で署名された中間証明書でサーバ証明書やクライアント証明書が署名されます。このような署名の連なり(証明書チェーン)の最後の証明書であることを示します。
    • キーの使用方法である「拡張キー使用法」(Enhanced Key Usage: 2.5.29.37)として「サーバー認証 (1.3.6.1.5.5.7.3.1)」を指定しています。
    • 拡張キー使用法で指定できるOIDは、New-SelfSignedCertificateリファレンスの-TextExtensionオプションの説明をご覧ください。

クライアント証明書の作成

前述の手順で作成したルート証明書を使用して、クライアント証明書を作成します。

  • 前述の手順で作成済みのルート証明書を$rootcaに取得します。
  • New-SelfSignedCertificateを使用してクライアント証明書を作成します。
  • -Subjectの値は例であり、ユーザを識別する情報として名前ではなくメールアドレスのみであれば、”-Subject test@example.com”のような指定も可能です。
  • -TextExtensionで次を設定しています。
    • 「拡張キー使用法」(Enhanced Key Usage: 2.5.29.37)として「クライアント認証 (1.3.6.1.5.5.7.3.2)」を指定しています。
    • サブジェクト代替名(2.5.29.17)としてUPNを指定しています。
  • 拡張キー使用法やサブジェクト代替名で指定できるOIDは、New-SelfSignedCertificatリファレンスの-TextExtensionオプションの説明をご覧ください。
  • 作成したクライアント証明書をユーザに配布できるよう、Export-PfxCertificateを使用して、証明書と鍵をPFX(PKCS#12)形式でファイルにエクスポートします。

PEM形式でエクスポート

作成した証明書をApache httpdで使用する場合、PEM形式に変換する必要があります。
Windows(PowerShell)の標準コマンドでは実現できないため、ここではopensslを使用します。
次の例では、ルート証明書、サーバ証明書と鍵、の3つをPEM形式のファイルにエクスポートします。

  • 前述の手順で作成したルート証明書を$rootca、サーバ証明書を$serverに取得します。
  • opensslでファイルを使って証明書の操作が行えるよう、Export-PfxCertificateを使って証明書とキーをPKCS#12形式のファイル(PFXファイル)にエクスポートします。
  • opensslを使ってPFXファイルからルート証明書(server-ca.crt)、サーバ証明書(server.crt)と鍵(server.key)をPEM形式でエクスポートします。(Windowsでは証明書ファイルの拡張子としてcerを使うことが多いのですが、apache(httpd)ではcrt, keyを使っているので、ここではそれに合わせています。)
  • ルート証明書、サーバ証明書のエクスポートでは、証明書を出力するために”-clcerts”、キー出力を抑制するために”-nokeys”オプションを指定しています。
    (“-clcerts”の説明を読むと”output client certificate”とありますが、この文脈ではCAに署名された証明書のことを言っているようです。このオプションを付けないと、ルート証明書まで出力される場合があります。)
  • サーバ証明書のキーのエクスポートでは、証明書の出力を抑制する”-nocerts”、出力先ファイルの暗号化を抑制するために”-nodes”を指定しています。(出力先ファイルが暗号化されていると、HTTPサーバの起動が難しくなるため。実運用では、パーミッション設定等のセキュリティ上の考慮が必要です。)
  • ここでは、Windows向けのopenssl(slproweb.com)のWin64 OpenSSL v1.1.1h Lightを使用しています。