Apache2 Webサーバでクライアント認証
利用者を制限したいWebサーバーは多いと思います。Googleアカウント認証だったり、パスワード認証だったりいろいろと方法はありますが、今回はフリーOSのDebianにインストールしてあるApache2.4でクライアント証明書での認証をしたいと考えています。
クライアント認証を導入することで、サーバーにアクセスする人を特定できますので、それに応じた表示可否も設定しやすくなります。また利用者にとってみれば一度設定してしまえばユーザーIDとパスワードの管理から解かれるので、そちらの面でも利点があります。
また証明書の発行はOpenSSLを使った自己証明型のCAを利用します。
ApacheのインストールからSSLの設定
当ブログでも頻出しているApacheですが、再度設定をしていきたいと思います。
$ su ... # apt update ... # apt install apache2 openssl
sslはモジュールとして存在しています。それを使えるようにします。
基本は、mods-avarableにあるsslというファイルのシンボリックリンクを、mods-enabledに作成するとその設定を有効化できます。
それもわかりにくいというので、apacheにはそれら用のコマンドが用意されています。それが「a2enmod」と「a2dismod」です。
もうピンときている人もいるかもしれませんがa2=apache2、en=enable(利用可能に)、dis=disable(不可能に)、mod=modsとなっています。
mods同様にa2ensite、a2enconfやそれらの逆のdisも存在します。
通常はそれらのコマンドに引数として利用したいmodsなりconfなりを指定してやればいいのですが、引数を無しに実行することで対話的に選択することも可能です。
# /usr/sbin/a2enmod ssl # /usr/sbin/a2ensite default-ssl
sslモジュールを有効にして、sslサイト設定を有効にしました。
これだけで一応SSLサイトができています。ブラウザにhttps://サーバーのIPを入力すると証明書に関する警告が出ますがページを表示させることができます。
ここから警告の出ないサイトに変更していきます。
OpenSSLでCAを作成
以前の記事ではスクリプト(CA.pl)を使ったCAの作成をしましたが、今回はopenSSLのコマンドで作成したいと思います。
まずはCAの秘密鍵を作成します。-aes256で秘密鍵の使用する際のパスワードを設定できます。セキュリティ的には問題があるかもしれませんが省略することもできます。
# openssl genrsa -aes256 -out ca.key 2048 # パスーワード設定 # パスワード確認
まずはCAの秘密鍵を使って署名要求を作成します。先でパスワードを設定した場合は秘密鍵を使用するので求められます。
# openssl req -new -key ca.key -out ca.csr # パスワードを入力
聞かれる質問には次のように答えます。
- Country Name
国名なので「JP」とします。
- State or Province Name
都道府県名をローマ字で入力します。「Tokyo」等
- Locality Name
市町村名です。空白でかまいません。
- Organization Name
組織名です。何か適当な名前を設定しましょう。「MyOrg」等
- Organization Unit Name
部署です。空白でかまいません。
- Common Name
一番重要な名前です。CAの名前を付けます。「CA for MySite」等
- Email Address
自己署名型CAでは不要です。
- A challenge password
空白。
- An optional company name
空白。
自己署名をします。ここでもパスワードを設定した場合は入力を求められます。
# openssl x509 -req -in ca.csr -signkey ca.key -days 730 -out ca.crt # パスワードを入力
OpenSSLでサーバーの証明書を作成
CAを作成しましたので、今度はWebサーバー用の証明書を作成します。
方法はCAの時と同じで、秘密鍵を作り、それを使って署名要求を作ります。署名要求の作成時に設定する情報ははサーバー用に変えます。この時、ブラウザで表示する際の都合上Common NameはドメインまたはサーバーのIPアドレスにする必要があります。
こちらもパスワードの設定(-aes256オプション)は任意です。
# openssl genrsa -aes256 -out server.key 2048 ... # openssl req -new -key server.key -out server.csr ...
先に作ったCAの秘密鍵と証明書を使って、サーバー用の署名要求に署名します。CAの秘密鍵にパスワードを設定した場合ここではCAのパスワードを入力します。混同しないように注意してください。
-CAcreateserialはシリアルナンバー管理用のファイルがない場合は作成するオプションなので、2回目以降は不要です。(2回目以降で記述してもエラーはになりません)
秘密鍵使用時のパスワードを解除したい場合は次のようにします。一度旧パスワードを入力する必要があります。
openssl rsa -in xxx.key -out xxx.key
解除の状態から再度パスワードを設定したい場合はaes256オプションを付けます。
openssl rsa -in xxx.key -aes256 -out xxx.key
クライアントでCA証明書のインストール
通常のWebブラウジングで利用される証明書は、ブラウザに登録されているルートCAからたどることにより証明書の正当性が証明されますが、自己署名CAの場合はそうはいきません。
そのためCA証明書をOSにインストールして、「CAを信用する」作業が必要になります。
CAの証明書を単体でOSにインストールすることもできますが、ここではクライアント認証をするので、クライアント証明書にCA証明書までを含ませます。
まずはWebサーバー用の秘密鍵を証明書を作成したのと同じ手順でclient.keyとclient.crtを作成します。情報の部分にはWebサーバーに接続する端末のものを入力します。完成後はCommon Nameで接続者を認識するようになると思いますので「Cleint001」「sawada-no-iphone」等、使いやすいように設定します。
;まずはクライアント1用のserverように作成したのと同様にクライアント用の鍵を作成します。 # openssl genrsa -aes256 -out client1.key 2048 ... ;クライアント1用の署名要求を作成します。 # openssl req -new -key client1.key -out client1.csr ... ;Common Nameはクライアントを識別できる名前にします。 ... ;CAでクライアント1用の署名要求に署名します。 # openssl x509 -req -in client1.csr -CA ca.crt -CAkey ca.key -days 730 -out client1.crt ...
WindowsやAndroid端末用配布用にCA証明書とクライアントの証明書、秘密鍵をpcks12形式のひとつのファイルにまとめます。
ここではClient1の秘密鍵を使用する際のパスワードを求められるほか、pcks12形式をエクスポートする(利用する)ためのパスワード設定を求められます。
# openssl pkcs12 -in client1.crt -inkey client1.key -certfile ca.crt -out client1.p12 -export -name P12ForClient1 client1の秘密鍵 pcks12展開用のパスワード パスワード確認入力
ファイルが作成できたら、USBメモリ等にコピーして使いたい端末に配布します。基本的にファイルクリックからウィザードに従えばインストールできると思います。WindowsやAndroidでのp12証明書インストール方法の詳細はこちらの記事で掲載しています。
Webサーバー側に証明書を設定
Webサーバー側にもCA証明書とWebサーバーの証明書、秘密鍵を設定します。こちらはそれぞれ分かれた状態で設定します。apacheの設定ファイルである/etc/apache2/sites-available/default-ssl.confを修正します。
それぞれのファイルパスを、次のエントリーで指定してください。
- SSLCertificateFile
Webサーバー用の証明書ファイルのパスを指定します。先ほど作成したサーバー証明書(server.crt)のパスを記述します。
- SSLCertificateKeyFile
Webサーバー用の秘密鍵ファイルのパスを指定します。先ほど作成したサーバー証明書(server.key)のパスを記述します。
- SSLCACertificateFile
CA証明書ファイルのパスを指定します。先ほど作成したCA証明書(ca.crt)のパスを記述します。
apacheを再起動させてみましょう。そうすると、起動パスワードを聞かれます。先に設定したserver.key用のパスワード入力すると起動します。
再起動のたびにパスワードを求められるのは手間ですし、自動で再起動もできなくなります。なので先ほど紹介したパスワード解除手順を使ってserver.パスワードを解除します。
Google Chromeのプライバシーエラーへの対応
通常なら以上の設定でサーバーへのhttps接続時のエラーは解消されます。しかしGoogle Chromeでアクセスした場合は今度はプライバシーエラー(ERR_CERT_COMMON_NAME_INVALID)が表示されます。
エラーになる理由は、Google ChromeではSSL証明書のチェックを行うときに照合する名前がCommon Nameではなく、証明書のVer3(オプション)となっている、SubjectAltNameを使うからだそうです。
なので証明書のバージョンを3にして、そこにsubjectAltNameを追加します。合わせてバージョン3で設定されるほかの設定も記載します。
これらの方法は「Chromeに怒られないオレオレ証明書の作り方」や、「OpenSSLでX.509 v3の証明書を作成する」、今度こそopensslコマンドを理解して使いたい (2)を参考にさせていいただきました。ありがとうございます。
次のファイルをserver.v3という名前で作成します。
basicConstraints=CA:FALSE subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer keyUsage= nonRepudiation, digitalSignature, keyEncipherment subjectAltName=IP:192.168.0.1
これらはopenSSLの設定ファイルである、openssl.confに記述されている証明書V3における追加項目を書き写した上に、subjectAltNameを足したものとなっています。これらの説明はTrust Software System:4.2 電子証明書拡張情報のデータ形式が詳しいです。参考になりました。ありがとうございます。
- basicConstraints=CA:FALSE
basicConstraintsには他にも記されることがありますが、ここではCAか否かを記してします。
- subjectKeyIdentifier=hash
subject(Countryから始まる設定情報)に複数のカギのペアが存在した場合に使う識別方法です。hashでハッシュ値を設定しています。
- authorityKeyIdentifier
CAが複数のカギのペアを持っていた場合に必要になる公開鍵の識別方法を指定しています。
- keyUsage
鍵の用途を指定します。CAの場合場合はcRLSign,KeyCertSignにするようです。
- subjectAltName
今回設定したい名前です。IPの時はIP:xxx.xxx.xxx.xxx、ドメインの時はDNS:aaa.jpといった形で指定します。ワイルドカードを使ったマルチドメインを設定も可能です。Common Nameでチェックするブラウザもありますので基本的にCommon Nameとは同値にするようにします。
署名をやり直します。extfileオプショで先ほど作成したファイルを指定します。先ほど同様初回実行時は-CAcreateserialオプションを付けてください。
# openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -days 730 -out server.crt -extfile server.v3
これでapacheの再起動すると、Google Chromeでもエラーが出なくなります。
クライアント認証
クライアント認証に入ります。/etc/apache2/sites-available/default-ssl.confの証明書を設定した後の方にコメントアウトされて記述されている次の2行のコメントアウトを外します。CAから直接署名しますので署名の階層を制限するSSLVerifyDepthはここでは1としますが、10のままでも動きます。
SSLVerifyClient require SSLVerifyDepth 1
ちなみにrequireをoptional_no_caとするとクライアント証明書を確認しますが、なくてもアクセスできるようになります。
もし設定は正しいはずなのにアクセスできないという場合は、Windows等のOSに証明書がインストールされていても、ブラウザ側にインストールされていない可能性があります。Google Chromeでは「右上の縦の…から」→「設定」→「セキュリティ」→「証明書の管理」です。ここの「個人」タブと「信頼されたルート証明機関」にインストールした証明書があるかチェックします。また存在する場合は一度削除してインストールしなおすとうまくいくこともあります。
apache2サーバーを動かしているOSではルート証明書のインストールは不要なはずですが、改善されない場合はそれも試してみてください。
apacheを再起動してクライアントから接続してみます。先の段階でクライアント証明書をインストールしていますので、httpsでアクセスした際に表示できれば問題ありません。その状態から証明書を削除してみます。
Windowsのコントロールパネル「コンピューターの証明書の管理」「個人」から該当の証明書を右クリックして削除を実行します。また、GoogleChromeにも証明書が保持されているので「プライバシーとセキュリティー」「もっとみる」「証明書の管理」より、該当の証明書を削除してみてください。この時CAの証明書は削除しないでください。
クライアント証明書がないとページにアクセスできないのを確認できたら、先の手順で再度証明書をOSにインストールします。
クライアント証明書の失効
実は今回CAで証明書に署名する際に有効期限を設定していました。-days 730という記述がそれにあたり有効期限が2年に設定されています。それを過ぎた場合は再度証明書を発行する必要があります。
また運用の中では、有効期限前に証明書を無効にしたい場合もあると思いますので、その際の説明をします。失効された証明書の一覧はCRL(Certificate Revocation List)と呼ばれます。
失効はopensslのcaコマンドを利用します。その名の通りCAを管理するopenSSLのコマンドで、実は先にx509コマンドで行っていた署名はcaコマンドからも可能です。
caコマンドから署名を行う方法はリンク先に記載しているものを参考にしてください。ここではcaコマンドで証明書を無効にする方法だけを紹介します。
openSSLのCAの設定ファイルである/etc/ssl/openssl.confを編集して新たにCAの設定をします。念のため元のファイルはバックアップを取っておきましょう。
openssl.confファイルの中に、[ CA_default ]というエントリーがあります。その手前から[ CA_web ]というエントリーを次のように作ります。内容はCA_defaultのものを改変していくと楽です。
- dir=caforweb
ここで設定した場所にCA用のディレクトリを作成します。所有権はルート権限は744にしてください。作成したディレクトリにca.crt、ca.keyファイルを置きます。
- certs=$dir/cert
CAが発行した証明書の保存ディレクトリを指定します。今回は失効だけで運用しているので使いません。
- crl_dir=$dir/crl
CRL用のディレクトリです。特に利用されるケースがないと思いますが、一応作成しておきます。
- database=$dir/index.txt
証明書を発行・失効した際の記録をするデータベースです。ないとエラーになるので空のファイルを作成しておきます。
- new_certs_dir=$dir/newcerts
証明書を発行された際の格納するディレクトリを指定します。今回は失効だけで運用しているので使いません。
- serial=$dir/serial
証明書を発行する際の連番を記憶しておくファイルを指定します。今回は失効だけで運用しているので使いません。
- crlnumbe=$dir/crlnumber
CRL発行する際の連番を記憶しておくファイルを指定します。この名前でテキストファイルを作成し、000000と記載しておきます。
- crl=$dir/crl.pem
CRLファイルの場所を示します。
- private_key=$dir/ca.key
CAの秘密鍵の場所を示します。
- x509_extenstions=usr_cert
先にも利用した証明書の拡張で利用するルールを指定しています。使いませんが、既存のusr_certを指定しておきます。
- name_opt=ca_default
使いませんがca_defaultを指定しておきます。
- name_opt=ca_default
使いませんがca_defaultを指定しておきます。
- default_days=365
署名時の有効期限のデフォルト値を設定します。使いませんが、365を設定しておきます。
- default_crl_days=30
CRLの有効期限のデフォルト値を設定します。期限の切れたCRLを指定するとapache2は起動しなくなります。
- default_md=default
- preserve=no
- policy=policy_match
署名時のポリシーを設定します。policy_matchを指定しておきます。
設定が終わったら、まずnameオプションでCAを指定して失効処理をします。-nameオプションがないとopenssl.confに記述されているデフォルトのCAが使用されてしまいうまくいきません。nameオプションの引数には先ほど[]内に設定したセクション名を指定します。
# openssl ca -revoke client1.crt -name CA_web
失効リスト(CRL)を出力させます。crlの運用を始めるとファイルが存在しないとエラーになりますので、対象が存在しなくても出力します。
# openssl ca -gencrl -out ca.crl -name CA_web
出力した失効書をapacheに設定します。再度default-ssl.confを編集します。先ほどクライアント証明設定時にコメントアウトした上の方に「SSLCARevocationFile」というエントリーがあります。これのコメントアウトを外して、先ほど出力したCRLを指定します。またSSLCARevocationCheckというエントリーを作り、chainを設定しないとCRLは有効になりません。
SSLCARevocationFile=path/to/ca.crl SSLCARevocationCheck chain
失効の取り消し(再有効化)は、index.txtファイルに記されている該当の行を削除して再度CRLを出力することで可能です。またCRLの反映にはapache2の再起動が必要です。
PHPからクライアント証明書を確認
PHPでは$_SERVER変数にクライアント証明書情報がセットされます。Common Nameは$_SERVER["SSL_CLIENT_S_DN_CN"]に格納されます。
中間CA証明書を使う
今度は中間CA証明書を使って設定してみます。中間CAを使わないでも正常に処理ができれば不要かもしれませんが、筆者の場合はとAmazon Fire7で証明書関連のエラーとなり、中間CAを作成しました。
先ほどはルートCAを簡単に作成してしまいましたが、今度はちゃんとV3の署名をしてみます。
まずはROOT CA用にV3署名用のオプションファイルを作ります。
rootca-option.v3
basicConstraints=CA:TRUE subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer keyUsage=cRLSign,keyCertSign
ルートCAを作成します。
# CA用の鍵作成 openssl genrsa -aes256 -out rootca.key 2048 # CA用の署名要求を作成 openssl req -subj "/C=JP/ST=Tokyo/O=nanbu/CN=PrivateCA" -new -key rootca.key -out rootca.csr # 自己署名 openssl x509 -req -in rootca.csr -signkey rootca.key -days 730 -out rootca.crt -extfile rootca-option.v3
次には中間CA用にV3署名用のオプションファイルを作ります。subjectAltNameに実際に稼働させるサーバーのIPアドレスを設定しています。
mca-option.v3
basicConstraints=CA:TRUE subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer keyUsage=cRLSign,keyCertSign subjectAltName=IP:サーバーのIPアドレス
中間CAを作成してルートCAで署名します。
# MCA用の鍵作成 openssl genrsa -aes256 -out mca.key 2048 # MCA用の署名要求を作成 openssl req -subj "/C=JP/ST=Tokyo/O=nanbu/CN=サーバーのIPアドレス" -new -key mca.key -out mca.csr # 署名 openssl x509 -req -in mca.csr -CA rootca.crt -CAkey rootca.key -days 730 -out mca.crt -extfile mca-option.v3 -CAcreateserial
Apache用の証明書を作成して、中間CAで署名します。こちらもV3用のオプションを作成します。
ap-option.v3
basicConstraints=CA:FALSE subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer keyUsage= nonRepudiation, digitalSignature, keyEncipherment subjectAltName=IP:サーバーのIPアドレス
# Apache用の鍵作成 openssl genrsa -aes256 -out ap.key 2048 # Apache用の署名要求 openssl req -subj "/C=JP/ST=Tokyo/O=nanbu/CN=サーバーのIPアドレス" -new -key ap.key -out ap.csr # Apache用の署名要求を署名 openssl x509 -req -in ap.csr -CA mca.crt -CAkey mca.key -days 730 -out ap.crt -extfile ap-option.v3 -CAcreateserial # Apache用の秘密鍵はパスフレーズ解除 openssl rsa -in ap.key -out ap.key
クライアント用の証明書を作成して、中間CAで署名します。これはV3用のオプションは省略します。
# クライアントの鍵作成 openssl genrsa -aes256 -out client1.key 2048 # クライアントの署名要求 openssl req -subj "/C=JP/ST=Tokyo/O=nanbu/CN=クライアントを識別するための文字列" -new -key client1.key -out client1.csr # クライアント用の署名 openssl x509 -req -in client1.csr -CA mca.crt -CAkey mca.key -days 730 -out client1.crt -CAcreateserial
apache2の/etc/apache2/sites-enabled/default-ssl.confの次の部分を修正します。
default-ssl.conf
... #従来通り SSLCertificateFile ap.crt SSLCertificateKeyFile ap.key SSLCertificateChainFile mca.crt ... #SSLCACertificateFile ca.crtはコメントアウト#SSLCACertificateFile ca.crt
err_ssl_protocol_errorがでる場合は、SSLCertificateChainFileでちゃんと中間CAの証明書を指定しているか、元のSSLCACertificateFile ca.crtは削除されているかを確認してみてください。
クライアント側は、いったんインストールしたルート証明書、個人証明書を削除します。
Windowsなら「コンピュータ証明書の管理」から「個人」と「信頼されたルート証明機関」から削除します。削除がブラウザ側と同期されないことがあるのでブラウザ側も確認してください。
Andorid系のスマホなら「設定」→「セキュリティ」→「信頼できる証明情報」から個別に削除するか、「認証ストレージの消去」で一括削除もできます。
削除が終わったら再度インストールします。今度はルートCA証明書rootca.crtと中間CA証明書とクライアントキーのセットであるclient1.p12をインストールします。
apacheを再起動させ、接続できれば完了です。SSL通信に対して何かしらの警告がでるようなら、ルートCAや中間CAの証明書が利用するPCの適切な場所にインストールされているか、再度確認してみてください。
最後に一連のファイル生成をスクリプト化してみたので掲載しておきます。ファイルの中にパスワードが直書きになっているのに加え、コマンドの履歴にも残りますので、参考にされる場合は気を付けてください。
makecerts.sh
#!/bin/bash
# 中間CAを使ったクライアント認証用ファイル作成
# 初回はCA、中間CAを作成するので makecaを引数に渡してください。
# caデータの出力場所
ROOTDIR="/home/user/privateca"
# ca 中間ca サーバー クライアント p12用の鍵
# ※ 鍵はコマンド履歴に残るので注意してください。
PASSWORD_CA="ca1234"
PASSWORD_MCA=$PASSWORD_CA
PASSWORD_SV=$PASSWORD_CA
PASSWORD_CL=$PASSWORD_CA
PASSWORD_12=$PASSWORD_CA
# サーバーのIP
IPADDRESS="172.16.1.248"
# クライアント用のCN
CL_CN="client1"
echo root dir is ${ROOTDIR}
# makecaが引数にあったらCAから作成
# 最初は必須
if [ ".$1" = ".makeca" ]; then
# CAのシリアルクリア
rm ${ROOTDIR}/ca.srl
rm ${ROOTDIR}/mca.srl
# RootCA用のオプション設定
cat << EOF > ${ROOTDIR}/root-option.v3
basicConstraints=CA:TRUE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
keyUsage= cRLSign, keyCertSign
EOF
# CA用の鍵作成
echo root dir is ${ROOTDIR}
openssl genrsa -aes256 -out ${ROOTDIR}/rootca.key -passout pass:$PASSWORD_CA 2048
# CA用の署名要求を作成
openssl req -subj "/C=JP/ST=Tokyo/O=nanbu/CN=PrivateCA" -new -key ${ROOTDIR}/rootca.key -out ${ROOTDIR}/rootca.csr -passin pass:$PASSWORD_CA
# 自己署名
openssl x509 -req -in ${ROOTDIR}/rootca.csr -signkey ${ROOTDIR}/rootca.key -days 730 -out ${ROOTDIR}/rootca.crt -passin pass:$PASSWORD_CA -extfile ${ROOTDIR}/root-option.v3
# 中間CA用のオプション設定
cat << EOF > ${ROOTDIR}/mca-option.v3
basicConstraints=CA:TRUE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
keyUsage= cRLSign, keyCertSign
subjectAltName=IP:$IPADDRESS
EOF
# MCA用の鍵作成
openssl genrsa -aes256 -out ${ROOTDIR}/mca.key -passout pass:$PASSWORD_MCA 2048
# MCA用の署名要求を作成
openssl req -subj "/C=JP/ST=Tokyo/O=nanbu/CN=$IPADDRESS" -new -key ${ROOTDIR}/mca.key -out ${ROOTDIR}/mca.csr -passin pass:$PASSWORD_MCA
# 署名
openssl x509 -req -in ${ROOTDIR}/mca.csr -CA ${ROOTDIR}/rootca.crt -CAkey ${ROOTDIR}/rootca.key -days 730 -out ${ROOTDIR}/mca.crt -passin pass:$PASSWORD_CA -extfile ${ROOTDIR}/mca-option.v3 -CAcreateserial
fi
# Apache用の署名オプション作成
cat << EOF > ${ROOTDIR}/ap-option.v3
basicConstraints=CA:FALSE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
keyUsage= nonRepudiation, digitalSignature, keyEncipherment
subjectAltName=IP:$IPADDRESS
EOF
# Apache用の鍵作成
openssl genrsa -aes256 -out ${ROOTDIR}/ap.key -passout pass:$PASSWORD_SV 2048
# Apache用の署名要求
openssl req -subj "/C=JP/ST=Tokyo/O=nanbu/CN=$IPADDRESS" -new -key ${ROOTDIR}/ap.key -out ${ROOTDIR}/ap.csr -passin pass:$PASSWORD_SV
# Apache用の署名要求を署名
openssl x509 -req -in ${ROOTDIR}/ap.csr -CA ${ROOTDIR}/mca.crt -CAkey ${ROOTDIR}/mca.key -days 730 -out ${ROOTDIR}/ap.crt -passin pass:$PASSWORD_MCA -extfile ${ROOTDIR}/ap-option.v3 -CAcreateserial
# Apache用の秘密鍵はパスフレーズ解除
openssl rsa -in ${ROOTDIR}/ap.key -out ${ROOTDIR}/ap.key -passin pass:$PASSWORD_SV
# クライアントの鍵作成
openssl genrsa -aes256 -out ${ROOTDIR}/client1.key -passout pass:$PASSWORD_CL 2048
# クライアントの署名要求
openssl req -subj "/C=JP/ST=Tokyo/O=nanbu/CN=$CL_CN" -new -key ${ROOTDIR}/client1.key -out ${ROOTDIR}/client1.csr -passin pass:$PASSWORD_CL
# クライアント用の署名
openssl x509 -req -in ${ROOTDIR}/client1.csr -CA ${ROOTDIR}/mca.crt -CAkey ${ROOTDIR}/mca.key -days 730 -out ${ROOTDIR}/client1.crt -passin pass:$PASSWORD_MCA -CAcreateserial
# p12形式に
openssl pkcs12 -in ${ROOTDIR}/client1.crt -inkey ${ROOTDIR}/client1.key -certfile ${ROOTDIR}/mca.crt -out ${ROOTDIR}/client1.p12 -export -passin pass:$PASSWORD_CL -passout pass:$PASSWORD_12
クライアント証明書まで作成されますが、クライアント認証が不要な場合(通常のSSLの場合)は不要です。利用側の端末でルート証明書と、中間証明書を手動でOSにインストールすればセキュリティの警告は出なくなります。