クライアント証明書の発行

2003/6/11作成
2004/9/19更新


続いてクライアント証明書を発行しましょう。
クライアント証明書とは、個人や機器を特定する証明書のことです。
verisignとかでは個人証明書などと呼ばれています。
途中まではサーバ証明書の発行と変わりません。
余談ですが、「クライアント証明書」でgoogleすると、多くの有名サイトを押しのけてこのページが一番に表示されてしまいました。
複雑です。



1.クライアント証明書発行の流れ

クライアント証明書を発行するまでの流れは簡単にこんな感じです。
  1. クライアント秘密鍵を作成
  2. 秘密鍵からCSRを生成
  3. CAの秘密鍵でCSRに署名して証明書を作成
最終的にクライアントにはクライアント秘密鍵とクライアント証明書のペアと、CAの証明書があればいいのですが、クライアントがWindowsの場合、秘密鍵とCSRを作成するのは困難です。
IISについているPKIツールを使えばできなくもないのですが、現在IISが入ったマシンが用意できていないので、今回はopensslが入っているCAで鍵とCSRを作成しようと思います。
なので、こんな感じになります。
  1. クライアント秘密鍵を作成
  2. 秘密鍵からCSRを生成
  3. CAの秘密鍵でCSRに署名して証明書を作成
  4. pkcs12で鍵と証明書を固めてWindowsに移動
  5. Windowsでpkcs12の鍵と証明書を展開してインストールする
ここで気をつけないといけないのが、CAで鍵ペアを作るので、CAにクライアント鍵が残ってしまいます。
これは非常に危険なので、pkcs12で証明書発行が済んだら、CAに残っているクライアント秘密鍵は削除するべきです。

2.クライアント秘密鍵の作成

CAの秘密鍵を作ったときやサーバ証明書を作ったときと同じです。

以前はここで鍵をdesで暗号化していましたが、pkcs12にまとめるときにとれてしまい、無駄なので省きました。
でも、クライアント秘密鍵がサーバに残っていてもパスフレーズを入れないと使えないという利点があるので、全く無駄ではないと思います。(2004/9/19追加)
% openssl genrsa -out client.key 1024
Generating RSA private key, 1024 bit long modulus
...........++++++
.++++++
e is 65537 (0x10001)
そうしてclient.keyというクライアントの秘密鍵ができました。

3.秘密鍵からx509証明書発行要求(CSR)を作成

CAの証明書やサーバ証明書を作ったときのようにCSRを作成します。
openssl req -new -key client.key -out client.csr
Using configuration from /etc/ssl/openssl.cnf
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [JP]:JP
State or Province Name (full name) [Tokyo]:Tokyo
Locality Name (eg, city) []:Shinjuku-ku
Organization Name (eg, company) [example corp.]:example corp.
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:hogehoge
Email Address []:hoge@example.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
CNにはクライアントの識別子になるので一意になるような値を入れてください。
こうしてできたx509証明書発行要求がclient.csrです。

4.CSRにCAが署名してクライアント証明書を発行

サーバ証明書にCAの鍵で署名したように、クライアント証明書の発行要求に署名します。
ちなみにCSRの作成までは一般ユーザでもOKですが、CA業務はスーパーユーザじゃないとだめみたいです。
もしかしたらパーミッションの設定がどこかでできるかもしれません。CA業務を行う専用ユーザとかいてもおかしくないですし。
とりあえず、今回はスーパーユーザで。
% su
Password:
# openssl ca -out client-ca.crt -infiles client.csr
Using configuration from /etc/ssl/openssl.cnf
Check that the request matches the signature
Signature ok
The Subjects Distinguished Name is as follows
countryName :PRINTABLE:'JP'
stateOrProvinceName :PRINTABLE:'Tokyo'
locality Name :PRINTABLE:'Shinjuku-ku'
organizationName :PRINTABLE:'example corp'
commonName :PRINTABLE:'hogehoge'
emailAddress :IA5STRING:'hoge@example.com'
Certificate is to be certified until Jun 9 15:18:03 2004 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
証明書の内容について表示され、これていいか確認を聞かれます。
よければ[y]で許可しましょう。
こうしてできたclient-ca.crtがプライベートCAによって署名されたクライアント証明書になります。

5.クライアント秘密鍵とクライアント証明書のペアをpkcs12でexportする

鍵と証明書を安全にexportするために、pkcs12という方法で鍵と証明書をひとつにまとめます。
鍵と証明書を結合してopensslに放り込んでやればOKです。
% cat client.key client-ca.crt | openssl pkcs12 -export -out client.p12 -name "client key"
Enter Export Password:
Verifying password - Enter Export Password:
ここで設定するパスワードはpkcs12を展開するときのパスワードです。
このパスワードはWindowsにpkcs12のファイルを持ってきたときに、展開するために必要になります。
こうしてclient.p12というpkcs12形式の鍵ペアができました。

あとはftpでもFDDでもいいので、作成したclient.p12をWindowsに持ってきてください。

なお、今回はCAの証明書については前回のサーバ証明書でインポート済みなので入れていませんが、実際にプライベートCAの運営で証明書を配布していくときはCAの証明書もつけてあげないといけません。
CAの証明書は接続先のサーバ証明書の署名検証するために必要になります。
CAの証明書もつけるときはこんな感じでOKです。
% cp /etc/CA/ca.crt ./
% cat client.key client-ca.crt ca.crt | openssl pkcs12 -export -out client.p12 -name "client key"
pkcs12はそもそも複数の鍵や証明書をひとつにしてインポートするためにあるので、この方法を使えばいくらでも証明書をくっつけることができます。
RootCAまでのchainとかをこの方法でまとめるといいと思います。

6.クライアント証明書のインポート

おまたせしました。ここからはWindowsでの作業になります。
Windowsに持ってきたpkcs12ファイルをダブルクリックすると「証明書のインポートウィザード」が立ち上がります。
進めていくと、パスワードを聞かれます。
ここで入力するのは、pkcs12を作成したときに入力したパスワードになります。つまり4で入れたパスワードです。
チェックボックスがついています。
「秘密キー・・」を有効にすると、鍵を使うたびにいちいち確認を求められるようになります。
「・・エクスポート・・」はWindowsにpkcs12を移植したあとに、pkcs12のファイルが無くなっても、Windowsで鍵ペアを生成して他のマシンにエクスポートする事ができるようになります。
セキュリティ上あまり好ましくはありません。

これを入力するとストアの確認をひとつおいて、ウィザードが完了します。
そして・・
おめでとうございます。

7.Apacheの設定

ひとときでしたがWindowsでの作業は一旦中断。
今度はApacheの設定になります。といっても、Apache2ですが。
Apache2はsslの設定はssl.confに分かれているのでこれを修正すればいいです。
サーバ証明書のときに設定したものに手を加えましょう。
青字がサーバ証明書で変更した箇所です。
赤は今回の変更箇所になります。
今回も、すべては書いていません。必要ありそうなところだけ抜き出してあります。
# ssl.conf

# 自分のサーバ証明書の場所を指定
SSLCertificateFile /usr/local/apache2/ssl/server-ca.crt

# サーバ秘密鍵の場所を指定
SSLCertificateKeyFile /usr/local/apache2/ssl/server.key

# サーバ証明書を署名したCAの証明書がさらに他のCAによって署名されて
# いる場合、rootCAまでの証明書のリストを置きます
# 今回はプライベートCAがrootCAになっているのでコメントアウト
#SSLCertificateChainFile /usr/local/apache2/ssl/ssl.crt/ca.crt

# CAの証明書の場所を指定
# PathとFileを選択可
# クライアント証明書が入るまではとりあえずコメントアウト
#SSLCACertificatePath /usr/local/apache2/conf/ssl.crt
SSLCACertificateFile /usr/local/apache2/ssl/ca.crt

# 証明書失効リスト(CRL)を指定
# PathとFileを選択可
# 今はとりあえずコメントアウト
#SSLCARevocationPath /usr/local/apache2/conf/ssl.crl
#SSLCARevocationFile /usr/local/apache2/conf/ssl.crl/ca-bundle.crl

# httpsアクセス時のクライアント証明書の扱いを指定します。
# require => クライアント証明書は必須
# optional => クライアント証明書は持っていてもいなくてもよい
# none => クライアント証明書は不要(持っていても無視)
# optional_no_ca => optionalと同じだが、CAの証明が無くても許可
SSLVerifyClient require

# RootCAまでの深さ
# デフォルトは"1"
# SSLVerifyDepth 10

8.アクセス

それではアクセスしてみましょう。
URLをhttpsに変更してアクセスすると、クライアント証明書を要求されました。
ここでさっきの証明書を選択してOKします。
するとhttpsでのログインが完了します。
ちなみに、ここでキャンセルを押すと、画面は表示されません。
でも、ApacheのコンフィグでSSLVerifyClientがoptionalになっていれば、noneと同じ状態でのアクセスができます。
requireにしておけばクライアント証明書を持っているユーザのみアクセスができるわけです。

9.応用

プライベートCAをたてて、そのクライアント証明書の発行管理をして信頼できる人にだけクライアント証明書を配れば、かなり安全な認証手段となります。
秘密鍵さえ盗まれなければ、まず安全なのでIDとパスワードによるベーシック認証よりも安全です。

また、クライアント証明書でsslをやると、環境変数が一気に増えます。
CGIプログラミングの拡張性も増すので、Webアプリケーションを作るときの楽しみが増えます。
証明書の内容をキーにシングルサインオンを実現したり、データベースやLDAPなどと連携したアプリケーションを作ったりすることもできます。

参考文献

Apache module mod_ssl http://httpd.apache.org/docs-2.0/mod/mod_ssl.html


ひとつもどる