Webサーバでクライアント認証

サーバの証明ができたので,こんどはクライアント認証をしてみる.
クライアント認証って何だ?
クライアント証明書の発行
サーバでクライアント認証の設定を行う

クライアント認証って何だ?

サーバ証明はサーバがサーバ証明書をクライアントに渡して,サーバが信頼できることを確認する. この際にその証明書はクライアントが信頼するCAから発行されているかどうかで信頼度をはかる. クライアント認証はこの逆の流れである. クライアントはサーバに証明書(クライアント証明書)を送る. サーバはクライアントから送信されるクライアント証明書が信頼するCAから発行されちているかどうかで信頼度をはかる. 以上から,クライアント認証をするには,以下の作業が必要となる.
クライアント証明書の発行
Webブラウザにクライアント証明書をインポート
サーバでクライアント認証に関する設定をする
サーバで信頼するCAの証明書を登録

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

まず,OpenSSLがクライアント証明書を発行するようにOpenSSLの設定ファイルを編集する.
$ cd ~/openssl/client
$ cp /etc/ssl/openssl.cnf .
$ vi openssl.cnf
設定ファイルに
nsCertType = client, email
と記述する. すでにnsCertTypeという項目があれば,そちらはコメントアウトする. 次にCSRを作成する.

$ openssl req -new -keyout client-privatekey.pem -out client-csr.pem
Generating a 1024 bit RSA private key
......++++++
..........................................................................++++++
writing new private key to 'client-privatekey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
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) [AU]:JP
State or Province Name (full name) [Some-State]:SOMEWHERE-KEN
Locality Name (eg, city) []:SOMEWHERE-SI
Organization Name (eg, company) [Internet Widgits Pty Ltd]:FIREPROJECT
Organizational Unit Name (eg, section) []:CLIENT
Common Name (eg, YOUR name) []:client.fireproject.jp
Email Address []:matsu-client@fireproject.jp

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:challenge
An optional company name []:

/usr/lib/ssl/misc/CA.sh は設定ファイルを読み込んでくれないので,直接opensslを呼び出した. これにより以下の二つのファイルが出力される.
client-privatekey.pem
-keyoutオプションで指定したファイル. この証明書の秘密鍵が記述されている.
client-csr.pem
-outオプションで指定したファイル. この証明書のCSRが記述されている.
この証明書をCAに送り,署名する.

$ cp client-csr.pem ../ca/newreq.pem 
$ cd ../ca
$ /usr/lib/ssl/misc/CA.sh -sign
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:
DEBUG[load_index]: unique_subject = "yes"
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 2 (0x2)
        Validity
            Not Before: Jul  3 04:50:05 2005 GMT
            Not After : Jul  3 04:50:05 2006 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = SOMEWHERE-KEN
            localityName              = SOMEWHERE-SI
            organizationName          = FIREPROJECT
            organizationalUnitName    = CLIENT
            commonName                = client.fireproject.jp
            emailAddress              = matsu-client@fireproject.jp
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Comment: 
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier: 
                BF:EB:C3:FA:E1:75:E5:80:7C:4F:F8:B2:71:02:93:CE:91:A2:A3:84
            X509v3 Authority Key Identifier: 
                keyid:AF:E5:54:93:60:19:B0:7C:BA:1E:EA:5A:A8:96:8C:71:50:63:93:BD
                DirName:/C=JP/ST=SOMEWHERE-KEN/L=SOMEWHERE-SI/O=FIREPROJECT/OU=CA/CN=ca.fireproject.jp/emailAddress=matsu-ca@fireproject.jp
                serial:B2:36:4F:63:84:74:77:80

Certificate is to be certified until Jul  3 04:50:05 2006 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
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 2 (0x2)
        Signature Algorithm: md5WithRSAEncryption
        Issuer: C=JP, ST=SOMEWHERE-KEN, L=SOMEWHERE-SI, O=FIREPROJECT, OU=CA, CN=ca.fireproject.jp/emailAddress=matsu-ca@fireproject.jp
        Validity
            Not Before: Jul  3 04:50:05 2005 GMT
            Not After : Jul  3 04:50:05 2006 GMT
        Subject: C=JP, ST=SOMEWHERE-KEN, L=SOMEWHERE-SI, O=FIREPROJECT, OU=CLIENT, CN=client.fireproject.jp/emailAddress=matsu-client@fireproject.jp
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:ed:45:20:05:3d:d9:86:73:1e:d0:37:75:f0:06:
                    fb:23:e3:bd:a0:ec:e0:aa:62:a2:13:5a:75:34:0d:
                    8e:fd:e2:25:d7:fb:69:cb:c7:69:e1:73:ee:7e:85:
                    b3:8d:68:35:69:a4:81:cd:f4:2a:3a:33:fb:54:78:
                    2f:1f:25:3b:c0:de:bb:13:8c:1c:d3:92:8d:3c:e1:
                    8c:ba:c4:91:8b:12:d3:1c:72:24:20:06:3c:a5:2c:
                    72:09:28:f6:5f:3f:d9:ac:58:70:69:cf:01:2d:28:
                    e2:67:35:af:c6:09:eb:45:da:a0:8f:ea:03:9e:3d:
                    aa:61:7a:f9:a0:54:4d:22:5f
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Comment: 
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier: 
                BF:EB:C3:FA:E1:75:E5:80:7C:4F:F8:B2:71:02:93:CE:91:A2:A3:84
            X509v3 Authority Key Identifier: 
                keyid:AF:E5:54:93:60:19:B0:7C:BA:1E:EA:5A:A8:96:8C:71:50:63:93:BD
                DirName:/C=JP/ST=SOMEWHERE-KEN/L=SOMEWHERE-SI/O=FIREPROJECT/OU=CA/CN=ca.fireproject.jp/emailAddress=matsu-ca@fireproject.jp
                serial:B2:36:4F:63:84:74:77:80

    Signature Algorithm: md5WithRSAEncryption
        df:8d:94:a4:7f:e0:53:f7:e4:fb:3c:d8:73:2c:76:30:89:f8:
        47:77:15:2a:96:1a:a1:8c:42:85:32:7b:ad:91:32:cd:07:99:
        86:b8:89:64:36:9e:2b:88:39:1a:ad:15:d8:62:9a:b0:ff:f3:
        54:c3:1f:87:a3:ba:34:b9:5e:8d:d4:15:18:e0:0b:a9:3f:25:
        c9:ad:c2:dc:e9:3f:e4:5f:fb:0f:5e:1f:e8:9c:21:9b:df:14:
        50:ed:0e:0a:15:dd:97:16:9a:5b:c6:72:7d:e1:28:9c:42:f9:
        02:cb:f7:40:ae:fe:05:90:a0:0f:bd:dd:ff:b1:49:9a:53:94:
        12:ae
-----BEGIN CERTIFICATE-----
MIIEBzCCA3CgAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBpTELMAkGA1UEBhMCSlAx
FjAUBgNVBAgTDVNPTUVXSEVSRS1LRU4xFTATBgNVBAcTDFNPTUVXSEVSRS1TSTEU
MBIGA1UEChMLRklSRVBST0pFQ1QxCzAJBgNVBAsTAkNBMRwwGgYDVQQDExN0aG9y
LmZpcmVwcm9qZWN0LmpwMSYwJAYJKoZIhvcNAQkBFhdtYXRzdS1jYUBmaXJlcHJv
amVjdC5qcDAeFw0wNTA3MDMwNDUwMDVaFw0wNjA3MDMwNDUwMDVaMIGvMQswCQYD
VQQGEwJKUDEWMBQGA1UECBMNU09NRVdIRVJFLUtFTjEVMBMGA1UEBxMMU09NRVdI
RVJFLVNJMRQwEgYDVQQKEwtGSVJFUFJPSkVDVDEPMA0GA1UECxMGQ0xJRU5UMR4w
HAYDVQQDExVjbGllbnQuZmlyZXByb2plY3QuanAxKjAoBgkqhkiG9w0BCQEWG21h
dHN1LWNsaWVudEBmaXJlcHJvamVjdC5qcDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEA7UUgBT3ZhnMe0Dd18Ab7I+O9oOzgqmKiE1p1NA2O/eIl1/tpy8dp4XPu
foWzjWg1aaSBzfQqOjP7VHgvHyU7wN67E4wc05KNPOGMusSRixLTHHIkIAY8pSxy
CSj2Xz/ZrFhwac8BLSjiZzWvxgnrRdqgj+oDnj2qYXr5oFRNIl8CAwEAAaOCATkw
ggE1MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVk
IENlcnRpZmljYXRlMB0GA1UdDgQWBBS/68P64XXlgHxP+LJxApPOkaKjhDCB2gYD
VR0jBIHSMIHPgBSv5VSTYBmwfLoe6lqoloxxUGOTvaGBq6SBqDCBpTELMAkGA1UE
BhMCSlAxFjAUBgNVBAgTDVNPTUVXSEVSRS1LRU4xFTATBgNVBAcTDFNPTUVXSEVS
RS1TSTEUMBIGA1UEChMLRklSRVBST0pFQ1QxCzAJBgNVBAsTAkNBMRwwGgYDVQQD
ExN0aG9yLmZpcmVwcm9qZWN0LmpwMSYwJAYJKoZIhvcNAQkBFhdtYXRzdS1jYUBm
aXJlcHJvamVjdC5qcIIJALI2T2OEdHeAMA0GCSqGSIb3DQEBBAUAA4GBAN+NlKR/
4FP35Ps82HMsdjCJ+Ed3FSqWGqGMQoUye62RMs0HmYa4iWQ2niuIORqtFdhimrD/
81TDH4ejujS5Xo3UFRjgC6k/JcmtwtzpP+Rf+w9eH+icIZvfFFDtDgoV3ZcWmlvG
cn3hKJxC+QLL90Cu/gWQoA+93f+xSZpTlBKu
-----END CERTIFICATE-----
Signed certificate is in newcert.pem

証明書をCAからクライアントに返し,PKCS12に変換する.

作成されたclient_cert.p12ファイルをWebブラウザにてインポートする. Firefoxだと以下のようにする.

設定->詳細->証明書マネージャ->あなたの証明書(TAB)->インポート
このときパスワードを尋ねられるが,これはpkcs12へ変換した際に入力したパスワードを入力する.

サーバでクライアント認証の設定を行う

まず,httpd.confにてクライアント認証を行うように設定をする. 前頁によってすでにHTTPSのためのバーチャルホストを設定しているので,そこにクライアント認証の設定を追加する.
<VirtualHost sslthor.fireproject.jp:443>
SSLEngine on
SSLCertificateFile      /etc/apache/ssl.crt/server.crt
SSLCertificateKeyFile   /etc/apache/ssl.key/server.key
SSLVerifyClient require
#SSLCACertificatePath    /etc/apache/ssl.cacrt/
SSLCACertificateFile    /etc/apache/ssl.cacrt/cacert.pem
SSLLog /var/log/apache/ssl_engine.log
SSLLogLevel info

ServerAdmin matsu@fireproject.jp
DocumentRoot /home/matsu/protected_html/
</VirtualHost>
追加した設定は以下である.
SSLVerifyClient
クライアント認証をするかどうか. 値には以下がある.
none
クライアント認証しない
optional
クライアント認証できる. クライアント認証しなくてもよいが,クライアント認証するときは妥当なクライアント証明書が必要.
require
クライアント認証が必須.
optional_no_ca
クライアント認証できる. クライアント認証しなくてもよいし,クライアント認証するときにクライアント証明書の妥当性が確認できなくてもよい.
SSLCACertificateFile
信頼するCAの証明書ファイル. クライアント証明書はこの証明書ファイルのCAに署名されている必要がある. 信頼するCAが複数ある場合はSSLCACertificatePathでCAの証明書ファイルのあるディレクトリを指定する雰囲気だが,なぜかうまくいかなかった.
SSLLog
SSLに関するログ出力ファイル. トラブルシューティングのために設定してみた.
SSLLogLevel
上記ログを出力する際のログレベル.
上記設定にて信頼するCAの証明書ファイルを/etc/apache/ssl.cacrt/cacert.pemと指定したので,そのように配置する.
cp ~matsu/openssl/ca/demoCA/cacert.pem /etc/apache/ssl.cacrt/cacert.pem 
あとはサーバを再起動してWebブラウザにてアクセスする. 今回はSSLVerifyClientの値がrequireなので,Webブラウザにてクライアント証明書を削除するとアクセスできないことも確認した. また,今回はログファイルを見て,トラブルシューティングした. 以下に私が出会ったトラブルとその際のログ出力されたエラーコードを記述しておく.
error:140890B2:SSL
信頼するCA証明書がない
error:140890C7:SSL
信頼するCAとクライアント証明書に署名したCAが不一致か,クライアント証明書がWebブラウザから送信されない.

This article was written by Fujiko