Not only is the Internet dead, it's starting to smell really bad.:2019年04月27日分

2019/04/27(Sat)

[Windows] オレオレ証明書によるコード署名の手順 (その1 - makecert編)

先日の記事の続き、Windowsではオレオレ認証局(CA)を建ててオレオレ証明書を発行するには3つの方法がある *1

基本的に3以外はobsolete扱いの上、1と2は不足する機能が多いのであまりお勧めできないが、何が問題か説明してる文書をみかけない気がするので、何回かに分けて書いていこう。

@makecertを使った作成法

まずはオレオレ認証局(CA)の鍵ペアを作る、すでに別件で作成済ならそれ使ってもいいし新規に作っても誰も気にしない、なんせオレオレだからな!

makecert ^
	-r ^
	-n "CN=Example CA,O=Example Corp.,OU=Example Div.,C=JP,DC=com,DC=example" ^
	-a sha256 ^
	-len 4096 ^
	-sky signature ^
	-cy authority ^
	-b 05/01/2019 ^
	-e 12/31/2039 ^
	-sv root.pvk root.cer

ポイントは

  • 自己署名証明書となるので-rオプション指定しろ
  • 証明書の名前は-nで指定する、どーせオレオレなのでCNとか好きにしろ
  • ハッシュアルゴリズムのデフォルトがいまどきは非推奨のSHA1なので、明示的に-aオプション指定してSHA256にしておけ
  • 暗号方式は-syオプションで変えられるけど、デフォルトのRSAから変えられるのはDSAのみっぽいのでそのままで
  • 鍵長がもはや時代遅れの1024bitなので、-lenオプションでせめて2048bit以上に変更しておけ
  • 鍵用途に-sky signatureをして署名(AT_SIGNATURE)に限定
  • 基本制限に-cy authorityを指定しCAとしての利用に限定しておけ
  • 証明書の期限は-b(開始)と-e(終了)をmm/dd/yyyyとかいうメリケンの田舎者形式で指定する(指定しない場合現在からGMTで2039年12月31日23時59分59秒まで)
  • -svで秘密鍵と公開鍵の名前を指定する
  • 秘密鍵に設定するパスフレーズの入力と確認を求められる、コマンドラインツールなのに入力はダイアログなので他の窓の裏に隠れてないか注意
  • 公開鍵の出力に秘密鍵のパスワードを聞かれる、やはりダイアログ以下略

くらいかな。

次にコード署名用の鍵ペアを作成する

makecert ^
	-iv root.pvk -ic root.cer ^
	-n "CN=Example Apps,O=Example Corp.,OU=Example Div.,C=JP,DC=com,DC=example" ^
	-a sha256 ^
	-len 4096 ^
	-sky signature ^
	-cy end ^
	-b 05/01/2019 ^
	-e 12/31/2039 ^
	-eku 1.3.6.1.5.5.7.3.3 ^
	-sv apps.pvk apps.cer
  • 自己署名ではないので-rオプションでなく-ivと-icで発行者となるCAの鍵ペア(さっき作ったやつ)を指定する
  • -nで指定する名前は同じにすると運用上紛らわしくて事故の元だからさっきのとは別にしておけ
  • 基本制限に新たな証明書を発行できないよう-cy endで末代(エンドエンティティ)指定して中間証明書として使えないようにしろ
  • 使用目的はコード署名のみに限定し-ekuオプションでOIDに「1.3.6.1.5.5.7.3.3」を指定しておけ
  • パスフレーズ設定はさっきと同じ手順、漏洩リスクを考えて認証局に設定したものとは別のものにしとけ
  • 公開鍵への署名にさっき作成した認証局の秘密鍵のパスフレーズを求められるので入力する

ちゅーとこ。

ファイルに出力せず証明書ストアを利用することも可能で

  • 出力先は「-sv 鍵ペア」でなく「-ss ストア名」
  • 署名用の鍵ペア指定は「-iv 秘密鍵 -ic 公開鍵」ではなく「-ir ストアの場所 -is ストア名 -in 名前」
  • ストアの場所およびストア名は証明書マネージャーに表示される日本語は認識しないので(l10n/i18nの敗北)、英語名はググるかレジストリ値探せ

と適宜読み替えてどうぞ、ただし試行錯誤した結果が全て証明書ストアに蓄積され後で削除めんどくさくなるしでお勧めしない。

そんでmakecertを使う上での問題点は

  • キー使用法(key usage)の指定ができない(なぜか拡張キー使用法はできる)ので厳密な運用を求める人には向いてない
  • いまどき楕円曲線暗号が指定できないので、署名だけならいいけど鍵交換用だとRSA/DSAで安全と思われる鍵長を指定するとオーバーヘッドが生じる
  • 有効期間に時刻の指定ができない(GMTで00:00:00固定)
  • フレンドリ名が指定できない
  • 失効証明書(CRL)の情報を指定できない

あたりか、オレオレ用途ならまぁ及第点ってとこだな…

問題なく作成できたと確信できたらようやっと証明書ストアにインポートする。ただし暗号鍵はMicrosoft独自形式の上で自分らも直接の証明書ストア取込に対応していないのが謎過ぎる。 なので公開鍵と一緒にPFX(Personal inFormation eXchange)形式に変換をする、これはpvk2pfxコマンドで行う。

まず認証局の鍵ペアの変換。

pvk2pfx -pvk root.pvk -spc root.cer -pfx root.pfx -pi 最初につけたパスワード -po 新たにつけなおすパスワード

ポイントは-poを指定し忘れるとパスワード無しの.pfxが出来あがるので危険というとこやね。

そしてコード署名の鍵ペアだけど、認証局の公開鍵とコード署名の公開鍵を証明書チェーンとするためにcert2spcというコマンドを使ってソフトウェア発行元証明書(.spc)というものを作る必要がある。

cert2spc root.cer apps.cer apps.spc

そんでpvk2pfxの-spcオプションの引数にapps.cerではなく証明書チェーンのapps.spcを指定してやる。

pvk2pfx -pvk apps.pvk -spc apps.spc -pfx apps.pfx -pi 最初につけたパスワード -po 新たにつけなおすパスワード

あーもうめんどくせぇ…すぞ(血管ブチ切れ)。

ちなみに本来はここでMicrosoftのクロスルート証明書チェーンにしてやる必要があるんだろう、 先日書いたオレオレ署名がデバイスマネージャで「デジタル認証されていません」の表示のままである原因はこれかな多分。

そして後はpfxをダブルクリックすれば証明書ストアへのインストールウィザードがはじまる、今後認証局として他の証明書の発行を行う端末にはroot.pfxを、ドライバなどのコード署名を行う端末にはapps.pfxをインポートしてやればいい。味噌とよく似た何かを一緒にしてはならない権限分離は大事だよ(戒め)、 なおコード署名するだけならpfxをインポートする必要も無いので後回しでいいです。

実際のコード署名の手順はまた最終回にでも。

@次回

certreqを使った作成法を説明する予定、いつになるかは知らない。

*1:openssl(1)とか知らない子ですね(すっとぼけ)