2019/05/02(Thu)
○[Windows] オレオレ証明書によるコード署名の手順 (その2 - certreq編)
先日の記事の続き、今回はcertreqを使用するのだけどそもそもcert「req」というくらいで認証局(CA)に対して署名要求(CSR)を行うためのコマンドなので、コード署名用証明書の作成目的で使うのは本来の用途ではないことに注意。
前回のmakecertを使った方法では
- まず最初にオレオレ認証局を建立(大仏みたいに)
- ↑を主体として開発者に対してコード署名用証明書を発行
という形をとったのだけど、この方法のメリットは
- 今後もオレオレ認証局からコード署名用だけでなくSSLサーバー・クライアント証明書なんかも発行することができる
- その際にまた新たに公開鍵をルート証明書として登録する必要が無い
というとこですかね、自宅内でそんなものが必要になるかはどうかは知らんけど(いわゆる誤家庭ってやつ)。
しかし今回は
- certreqコマンドで署名要求を作成し
- その時に証明書ストア内に副次的に作られる自己署名証明書をそのまま流用
することになるのでこのコマンド単体では他の鍵に署名を行うことができないのだ(縛りプレイ)。 よって今回は認証局を置かずにいきなりコード署名用証明書を発行し、その公開鍵をルート証明書として登録してもらうという形になるよ。
そんでコマンドに渡すパラメーターは引数オプションではなくinfファイル形式による応答ファイルが必要になる。
certreq -new apps.inf apps.req
と叩いて署名要求を作成する。
まず正しい使い方、認証局に送りつけるCSRを作成するだけなら
[Version]
Signature="$Windows NT$"
[NewRequest]
Subject="CN=Example Apps,O=Example Corp.,OU=Example Div.,C=JP,DC=com,DC=example"
KeySpec=AT_SIGNATURE
KeyUsage="CERT_DIGITAL_SIGNATURE_KEY_USAGE|CERT_KEY_ENCIPHERMENT_KEY_USAGE"
RequestType=CMC
[EnhancedKeyUsageExtension]
OID=1.3.6.1.5.5.7.3.1
くらいで問題ないはず、これで作成された署名要求(apps.req)を認証局に送りつければコード署名用証明書を発行してくれる。認証局の手順書にしたがって作成してくれ。
今回はこれを書換えて自己署名証明書を作るようにする。
[Version]
Signature="$Windows NT$"
[NewRequest]
Subject="CN=Example Apps,O=Example Corp.,OU=Example Div.,C=JP,DC=com,DC=example"
RequestType=Cert
Exportable=true
ExportableEncrypted=true
HashAlgorithm=SHA256
KeyAlgorithm=ECDSA_P256
KeySpec=AT_SIGNATURE
KeyUsage="CERT_DIGITAL_SIGNATURE_KEY_USAGE|CERT_KEY_ENCIPHERMENT_KEY_USAGE"
SMIME=false
NotBefore="5/01/2019 12:00 AM"
NotAfter="12/31/2039 11:59 PM"
FriendlyName="Example Apps"
[EnhancedKeyUsageExtension]
OID=1.3.6.1.5.5.7.3.3
ポイントは以下の通り
- 発行元(Subject)とフレンドリ名(FriendlyName)は好きにしろ
- 要求タイプ(RequestType)をCMCでなくCertに変更、これで証明書ストア内に署名発行要求だけでなく自己署名証明書も作成される
- ↑で作られた鍵ペアを.pfxにエクスポート可能なようにExportableとExportableEncrypted両方にtrueをセット
- ハッシュアルゴリズムのデフォルトがいまどきは非推奨のSHA1なので、明示的に-aオプション指定してSHA256にしておけ
- 暗号方式のデフォルトはRSA、KeyAlgorithmで楕円曲線暗号なんかに変更可能(Windowsのバージョンによる)
- 鍵用途(KeySpec)で署名(AT_SIGNATURE)に限定
- 鍵使用法(KeyUsage)は
- デジタル署名(CERT_DIGITAL_SIGNATURE_KEY_USAGE)
- 鍵暗号(CERT_KEY_ENCIPHERMENT_KEY_USAGE)
- S/MIME(SMIME)がデフォルトで出力されるので不要だからfalse
- 有効期限をNotBefore/NotAfterで指定(時刻はGMTではなくローカル)
- 使用目的はコード署名のみに限定しEnhancedKeyUsageExtensionセクションにOID=1.3.6.1.5.5.7.3.3を指定しておけ
あたりですかね、作成された署名要求は要らないので捨ててヨシ。
makecertに対するメリットは
- WinDDK入れるまでも無く標準コマンドとして利用可能
- キー使用法(key usage)の指定が可能
- フレンドリ名が指定できる
あたり、ただし問題も多くて
- 前述の通り自己署名証明書発行目的のコマンドではない
- KeyAlgorithmキーワードがWindows 7以前だと認識しないようで、ProviderName/ProviderTypeキーワードで四苦八苦する必要がある
ProviderName="Microsoft RSA SChannel Cryptographic Provider" ProviderType=12 KeyLength=4096
- NotBefore/NotAfterキーワードも同様にWindows 7では認識しないので、ValidityPeriod/ValidityPeriodUnitsキーワードで以下同文
開始が指定できないない上に、終了も何{年,月,日,時,分,秒}というざっくり指定しかできないので使い物にならんですわValidityPeriod=Days ValidityPeriodUnits=114514
基本制限にEnd Entityを付与したいけどオプションが無い- 鍵使用法に重要(Critical)を指定できない
- 失効証明書(CRL)の情報を指定できない(もしかするとExtensionセクションで頑張ればできるかも?)
というかんじ、またしても帯に短し襷にも短しじゃねーか。
[追記] certreqの場合でもCAかEnd Entityかの基本制限をinfのExtensionセクションに記述することで追加できますな。
- CAの場合
[Extension] 2.5.29.19="{text}ca=1&pathlength=0" Critical=2.5.29.19
- End Entityの場合
[Extension] 2.5.29.19="{text}ca=0" Critical=2.5.29.19
ただしやっぱりWindows 8以降のcertreqでないとパースエラーで死ぬので意味ナッシングですが。
ちなみに証明書の管理(Certmgr)のGUIからもcertreq同様に署名要求が可能なんだけど、こいつの「カスタム要求の作成」ウィザードを使えば
- 基本制限としてCA(とPath Lenth)あるいはEnd Entityかの指定ができる
- 鍵使用法などにCriticalも指定できる
のだけどね…
@次回予告
次はMicrosoftが推奨するPowerShellを使った方法、PowerShell歴もだいぶ長いはずなんだがまるで覚えられなくて何年た経っても初心者気分やぞ(老い)。
そして可能なら実際に作成したコード署名用証明書でスクリプトやドライバなどにコード署名してみる(さすがに次々回になるかな…)