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



●/etc/pki/tls/misc/CA をインストールする方法

 参考URL:CentOS8 に /etc/pki/tls/misc/CA をインストールする方法

 Rocky Linux 8でクライアント証明書を設定しようとしたところ、/etc/pki/tls/misc/CAがインストールされていませんでした。
 /etc/pki/tls/misc/CAをインストールには、
  • CentOS 7の/etc/pki/tls/misc/CAをコピーする
  • CentOS 7のopensslのRPMパッケージを利用する
かのどちらかになります。
 CentOS 7の環境が無い場合は、下記の手順で/etc/pki/tls/misc/CAをインストールすることができます。 
 適当な作業用ディレクトリを作成して、そこに移動します。
$ mkdir work
$ cd work/
 CentOS 7のopensslのRPMパッケージをダウンロードします。
$ wget http://ftp.riken.jp/Linux/centos/7/os/x86_64/Packages/openssl-1.0.2k-19.el7.x86_64.rpm
 /etc/pki/tls/misc/CA を取り出します。
$ rpm2cpio openssl-1.0.2k-19.el7.x86_64.rpm | cpio -id ./etc/pki/tls/misc/CA
 /etc/pki/tls/misc/CA を従来の場所に移動します。
$ sudo mv -i etc/pki/tls/misc/CA /etc/pki/tls/misc/
 /etc/pki/tls/misc/CAが動作することを確認します。
$ /etc/pki/tls/misc/CA -h
---(下記のように表示されればOKです)---
usage: ./CA -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify


●クライアント証明書認証の設定

 参考URL:クライアント証明書認証の設定メモ(Apache2.4 + CentOS)
 参考URL:Let’s Encryptと自己認証局でクライアント証明書接続

 今回、HTTPSで接続する場合の証明書はLet’s Encryptで、クライアント認証は自己認証局(オレオレ証明書を利用)がサインしたクライアント証明書を使って設定します。
 クライアント証明書認証とは、サービスを利用するユーザに証明書(これを「クライアント証明書」と呼びます)を発行し、その証明書によって利用するユーザを認証する仕組みのことです。一般的なユーザIDとパスワード認証に加えて、このクライアント証明書認証を導入することによって、ログイン時のセキュリティを強化することができます。

 サーバ証明書の認証局証明書はSSLCertificateChainFileディレクティブを利用して設定し、クライアント証明書の認証局証明書はSSLCACertificateFileディレクティブを利用して設定します。
 クライアント認証は、クライアントPCへの認証局証明書のインストールは不要ですが、SSLCACertificateFileディレクティブで指定する証明書(サーバ側)には認証局の発行した証明書が必要になります。
 そのため、自己認証局の認証局証明書をサーバに設置し、その認証局によってオレオレ認証したクライアント証明書をユーザに配布するようにします。

 プライベート認証局を未構築の場合、プライベート認証局の構築を参照して構築します。

 クライアント証明書の設置方法(サーバ全体)

 下記のような設定の場合、すべてのHTTPS接続についてクライアント認証を要求することになります。
※常時SSL対応済みの場合、/etc/httpd/conf.d/ssl.confを編集すること
# vi /etc/httpd/conf/httpd.conf
 :
(途中省略)
 :
Alias /.well-known/acme-challenge /var/www/html/.well-known/acme-challenge
<Directory /var/www/html/.well-known/acme-challenge>
  Order allow,deny
  Allow from all
</Directory>
 :
(途中省略)
 :
# vi /etc/httpd/conf.d/ssl.conf
 :
(途中省略)
 :
<VirtualHost _default_:443>
 :
(途中省略)
 :
# Let's Encryptの設定
SSLCertificateFile /etc/letsencrypt/live/www.bigbang.mydns.jp/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.bigbang.mydns.jp/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/www.bigbang.mydns.jp/chain.pem

#オレオレ認証局
SSLCACertificateFile /etc/pki/myCA/cacert.pem ← 仮想IPを使用してWebサーバを公開している場合、当ファイルを別サーバにコピー
SSLCARevocationFile /etc/pki/myCA/crl.pem ← 仮想IPを使用してWebサーバを公開している場合、当ファイルを別サーバにコピー
 
#クライアント認証によるアクセス制限
SSLVerifyClient require
SSLVerifyDepth 1
 :
(途中省略)
 :
</VirtualHost>

※SSLVerifyDepth
クライアント証明書に署名した認証局の階層の最大数を指定
0:自己署名のSSLクライアント証明書のみで許可
1:CAに直接署名された証明書、またはSSLCACertificateFileで指定した証明書のCAによって署名されたクライアント証明書を許可
 特定のディレクトリやロケーションに対してのみ設定する場合、SSLVerifyClient requireをDirectoryやLocationディレクティブ内に記載してください。
 SSLVerifyDepthは、個人が署名したクライアント証明書(0)にオレオレ認証局が署名(1)した2段なので、1を設定すれば問題ありません。

 クライアント証明書の設置方法(特定ディレクトリ以下)

 下記のような設定の場合、特定ディレクトリについて、指定したプライベートネットワークアドレス以外からのアクセス時にクライアント認証を要求することになります。
※常時SSL対応済みの場合、/etc/httpd/conf.d/ssl.confを編集すること
# vi /etc/httpd/conf/httpd.conf
 :
(途中省略)
 :
Alias /.well-known/acme-challenge /var/www/html/.well-known/acme-challenge
<Directory /var/www/html/.well-known/acme-challenge>
  Order allow,deny
  Allow from all
</Directory>
 :
(途中省略)
 :
# vi /etc/httpd/conf.d/ssl.conf
 :
(途中省略)
 :
<VirtualHost _default_:443>
 :
(途中省略)
 :
# Let's Encryptの設定
SSLCertificateFile /etc/letsencrypt/live/www.bigbang.mydns.jp/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.bigbang.mydns.jp/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/www.bigbang.mydns.jp/chain.pem

#オレオレ認証局
SSLCACertificateFile /etc/pki/myCA/cacert.pem ← 仮想IPを使用してWebサーバを公開している場合、当ファイルを別サーバにコピー
SSLCARevocationFile /etc/pki/myCA/crl.pem ← 仮想IPを使用してWebサーバを公開している場合、当ファイルを別サーバにコピー
 
#クライアント認証によるアクセス制限
SSLVerifyClient require
SSLVerifyDepth 1
 :
(途中省略)
 :
</VirtualHost>

# クライアント証明書動作確認のための設定
<Directory "/var/www/html/strictsecret">
  <IfModule dir_module>
    DirectoryIndex index.htm
  </IfModule>
  # アクセス元がプライベートアドレス以外の場合はクライアント証明書を要求する
  <If "! -R '10.0.0.0/8' && ! -R '172.16.0.0/12' && ! -R '192.168.0.0/16'">
    SSLVerifyClient require
    SSLVerifyDepth 1
    SSLOptions +FakeBasicAuth
    AuthUserFile /etc/httpd/conf/.htpasswd ← これがポイント
    AuthName "secret page"
    AuthType Basic
    require valid-user
  </If>
</Directory>

※SSLVerifyDepth
クライアント証明書に署名した認証局の階層の最大数を指定
0:自己署名のSSLクライアント証明書のみで許可
1:CAに直接署名された証明書、またはSSLCACertificateFileで指定した証明書のCAによって署名されたクライアント証明書を許可
 つまり、一つのクライアント証明書があれば、<Directory "・・・"> 〜 </Directory>を複数指定することにより、複数のディレクトリ以下はクライアント証明書が必要な領域となります。

 プライベート認証局の構築

 参考URL:クライアント証明書認証の設定メモ(Apache2.4 + CentOS)
 参考URL:クライアント証明書認証(Apache+OpenSSL)

 クライアント証明書を発行するためのプライベート認証局を構築します。
# CAスクリプト編集
# vi /etc/pki/tls/misc/CA
# CA証明書有効期限を100年(事実上無期限)にする
CADAYS="-days 36500"

openssl.cnf編集
# vi /etc/pki/tls/openssl.cnf

default_days    = 36500 ← クライアント証明書有効期限を100年(事実上無期限)にする
default_crl_days= 30                    # how long before next CRL
default_md      = sha256                # use SHA-256 by default
preserve        = no                    # keep passed DN ordering

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = JP ← 国コードを指定
countryName_min                 = 2
countryName_max                 = 2

stateOrProvinceName             = State or Province Name (full name)
#stateOrProvinceName_default    = Default Province
stateOrProvinceName_default     = Tokyo ← 都道府県を指定

localityName                    = Locality Name (eg, city)
localityName_default            = tokyo ← 市区町村を指定

0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = www.bigbang.mydns.jp ← サーバ名を指定

# we can do this but it is not needed normally :-)
#1.organizationName             = Second Organization Name (eg, company)
#1.organizationName_default     = World Wide Web Pty Ltd

organizationalUnitName          = Organizational Unit Name (eg, section)
#organizationalUnitName_default =

commonName                      = Common Name (eg, your name or your server\'s hostname)
commonName_max                  = 64

emailAddress                    = Email Address
emailAddress_max                = 64
emailAddress_default            = webmaster@mail.bigbang.mydns.jp ← サーバ管理者メールアドレスを指定

# cp /etc/pki/tls/openssl.cnf /etc/pki/tls/openssl-ca.cnf ← openssl.cnfをコピーしてCA用openssl.cnfを作成

# vi /etc/pki/tls/openssl-ca.cnf ← CA用openssl.cnf編集
[ usr_cert ]

# These extensions are added when 'ca' signs a request.

# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.

basicConstraints=CA:TRUE ← CA用にする

[ v3_ca ]


# Extensions for a typical CA


# PKIX recommendation.

subjectKeyIdentifier=hash

authorityKeyIdentifier=keyid:always,issuer

# This is what PKIX recommends but some broken software chokes on critical
# extensions.
#basicConstraints = critical,CA:true
# So we do this instead.
basicConstraints = CA:true

# Key usage: this is typical for a CA certificate. However since it will
# prevent it being used as an test self-signed certificate it is best
# left out by default.
# keyUsage = cRLSign, keyCertSign

# Some might want this also
nsCertType = sslCA, emailCA ← CA用にする

# cp /etc/pki/tls/openssl.cnf /etc/pki/tls/openssl-client.cnf ← openssl.cnfをコピーしてクライアント用openssl.cnfを作成

# vi /etc/pki/tls/openssl-client.cnf ← クライアント用openssl.cnf編集
[ usr_cert ]

# These extensions are added when 'ca' signs a request.

# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.

basicConstraints=CA:FALSE

# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.

# This is OK for an SSL server.
# nsCertType                    = server

# For an object signing certificate this would be used.
# nsCertType = objsign

# For normal client use this is typical
# nsCertType = client, email

# and for everything including object signing:
nsCertType = client, email, objsign ← クライアント用にする


 CA証明書作成

 CA証明書を作成します。
# SSLEAY_CONFIG="-config /etc/pki/tls/openssl-ca.cnf" /etc/pki/tls/misc/CA -newca ← CA証明書作成
CA certificate filename (or enter to create)
 ← 空ENTER
Making CA certificate ...
Generating a 2048 bit RSA private key
..........................+++
.........................+++
writing new private key to '/etc/pki/CA/private/./cakey.pem'
Enter PEM pass phrase: ← 任意のCA秘密鍵パスフレーズを入力
Verifying - Enter PEM pass phrase: ← 任意のCA秘密鍵パスフレーズを入力(確認)
-----
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]: ← 空ENTER
State or Province Name (full name) [Tokyo]: ← 空ENTER
Locality Name (eg, city) [tokyo]: ← 空ENTER
Organization Name (eg, company) [www.bigbang.mydns.jp]: ← 空ENTER
Organizational Unit Name (eg, section) []: ← 空ENTER
Common Name (eg, your name or your server's hostname) []:www.bigbang.mydns.jp ← サーバ名をを入力
Email Address [webmaster@www.bigbang.mydns.jp]: ← 空ENTER

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: ← 空ENTER
An optional company name []: ← 空ENTER
Using configuration from /etc/pki/tls/openssl-ca.cnf
Enter pass phrase for /etc/pki/CA/private/./cakey.pem: ← CA秘密鍵パスフレーズを入力
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            0c:6a:ae:c9::ed:56:cc:2b:9c:15:6f:d1:5fc2:a1:4d:a8:6e:6d:67
        Validity
            Not Before: Dec  2 07:06:49 2011 GMT
            Not After : Nov  8 07:06:49 2111 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = Tokyo
            organizationName          = www.bigbang.mydns.jp
            commonName                = www.bigbang.mydns.jp
            emailAddress              = webmaster@mail.bigbang.mydns.jp
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                52:5D:E2:BE:C1:FD:0C:73:A5:55:D0:89:A7:63:F1:A6:14:50:C5:7A
            X509v3 Authority Key Identifier: 
                keyid:52:5D:E2:BE:C1:C5:7A:0C:73:A5:55:D0:89:A7:FD:63:F1:A6:14:50

            X509v3 Basic Constraints: critical
                CA:TRUE
            Netscape Cert Type: 
                SSL CA, S/MIME CA
Certificate is to be certified until Nov  8 07:06:49 2111 GMT (36500 days)

Write out database with 1 new entries
Data Base Updated

# echo 00 > /etc/pki/CA/crlnumber ← 証明書失効に必要なcrlnumber初期作成※証明書失効については後述

# openssl ca -gencrl -out /etc/pki/CA/crl.pem ← 証明書失効リスト作成※証明書失効については後述
Using configuration from /etc/pki/tls/openssl.cnf
Enter pass phrase for /etc/pki/CA/private/cakey.pem: ← CA秘密鍵パスフレーズを入力


 クライアント証明書作成

 仮想IPを使用してWebサーバを公開している場合、下記で作成するクライアント証明書を別サーバにコピー

 クライアント証明書を作成します。
 クライアント証明書の作成には、対話型・非対話型の2通りがあります。
 クライアント証明書の作成数が少ない場合、対話型で作成し、作成数が多い場合、非対話型で作成します。

 対話型でクライアント署名書を作成

 対話型でクライアント署名書を作成してみます。
# SSLEAY_CONFIG="-config /etc/pki/tls/openssl-client.cnf" /etc/pki/tls/misc/CA -newreq ← クライアント秘密鍵・署名要求作成
Generating a 2048 bit RSA private key
......+++
.........+++
writing new private key to 'newkey.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) [JP]: ← 空ENTER
State or Province Name (full name) [Tokyo]: ← 空ENTER
Locality Name (eg, city) [tokyo]: ← 空ENTER
Organization Name (eg, company) [www.bigbang.mydns.jp]: ← 空ENTER
Organizational Unit Name (eg, section) []: ← 空ENTER
Common Name (eg, your name or your server's hostname) []:user1 ← 任意のユーザ名、または、適当な証明書の名前を入力
Email Address [webmaster@www.bigbang.mydns.jp]:user1@mail.bigbang.mydns.jp ← ユーザのメールアドレスをを入力。空でも問題なし

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: ← 空ENTER
An optional company name []: ← 空ENTER
Request is in newreq.pem, private key is in newkey.pem
※newkey.pem、newreq.pemはカレントディレクトリに作成されます。

# SSLEAY_CONFIG="-config /etc/pki/tls/openssl-client.cnf" /etc/pki/tls/misc/CA -sign ← クライアント署名要求に署名してクライアント証明書作成
Using configuration from /etc/pki/tls/openssl.cnf
Enter pass phrase for /etc/pki/CA/private/cakey.pem: ← CA秘密鍵パスフレーズを入力
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            b4:2b:0c:e4:e7:18:6e:ea
        Validity
            Not Before: Oct 16 05:11:27 2017 GMT
            Not After : Sep 22 05:11:27 2117 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = Tokyo
            localityName              = tokyo
            organizationName          = www.bigbang.mydns.jp
            commonName                = user1
            emailAddress              = user1@www.bigbang.mydns.jp
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                BD:E1:55:B3:90:08:50:B0:36:48:08:E0:FA:A7:70:E3:80:E9:C3:61
            X509v3 Authority Key Identifier:
                keyid:21:05:77:E9:A5:E6:DE:8D:46:F6:1B:43:5A:E2:2C:C0:60:13:BE:37

Certificate is to be certified until Sep 22 05:11:27 2117 GMT (36500 days)
Sign the certificate? [y/n]:y ← yを入力


1 out of 1 certificate requests certified, commit? [y/n]y ← yを入力
Write out database with 1 new entries
Data Base Updated
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            b4:2b:0c:e4:e7:18:6e:ea
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=JP, ST=Tokyo, O=www.bigbang.mydns.jp, CN=www.bigbang.mydns.jp/emailAddress=webmaster@www.bigbang.mydns.jp
        Validity
            Not Before: Oct 16 05:11:27 2017 GMT
            Not After : Sep 22 05:11:27 2117 GMT
        Subject: C=JP, ST=Tokyo, L=tokyo, O=www.bigbang.mydns.jp, CN=user1/emailAddress=user1@www.bigbang.mydns.jp
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:be:93:a3:b7:58:31:09:36:8b:ec:f8:eb:0d:41:
                    f6:cf:8a:8a:06:a6:02:6c:fe:f0:ac:24:b6:29:71:
                    1e:4f:d0:c6:bb:b1:a9:01:36:7f:fc:c9:19:70:e0:
                    09:75:e6:96:4e:b7:d0:e0:69:94:01:58:28:f8:a2:
                    7e:53:13:b5:55:62:5d:ee:50:a9:f2:3a:fd:1c:86:
                    27:c3:c1:b6:bc:f4:b3:89:6e:eb:a8:7f:e3:01:17:
                    19:90:4a:44:a0:38:2c:2b:3c:b9:ee:7b:98:53:58:
                    f1:17:ac:fa:8d:a1:7e:2c:ef:ab:54:1a:d2:07:90:
                    22:0d:a9:19:69:7b:da:a6:78:e3:4e:7f:98:43:81:
                    76:7f:b7:ae:02:61:39:39:9f:7e:7b:4e:50:12:c9:
                    2d:b6:39:a1:01:96:fa:9f:e7:6d:03:1a:f1:3b:98:
                    e3:aa:de:34:b5:cd:c0:73:47:74:f2:5c:2a:89:3c:
                    44:5f:a3:5d:35:72:82:82:bf:f6:64:6a:db:17:97:
                    c4:0f:ec:37:46:63:7f:ac:de:25:2d:58:2a:e2:2a:
                    af:53:02:11:bd:39:16:ae:f3:b6:70:bd:6c:25:87:
                    ce:7e:33:2f:d5:0a:13:86:bd:26:f8:9f:45:e3:77:
                    9c:29:97:1f:cf:c8:9f:3c:42:f4:65:87:c1:73:81:
                    7c:75
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                BD:E1:55:B3:90:08:50:B0:36:48:08:E0:FA:A7:70:E3:80:E9:C3:61
            X509v3 Authority Key Identifier:
                keyid:21:05:77:E9:A5:E6:DE:8D:46:F6:1B:43:5A:E2:2C:C0:60:13:BE:37

    Signature Algorithm: sha256WithRSAEncryption
         84:f3:b9:52:d9:8e:d6:75:cf:2b:0b:c1:a0:ba:6f:71:4e:d2:
         39:18:03:2a:3d:1d:d3:86:8c:5d:27:4e:4b:c4:5e:ae:fe:4a:
         e8:ee:8c:22:4f:70:29:11:d4:8c:b3:e8:92:9a:09:03:45:7d:
         19:8a:f8:7c:10:53:2f:f9:d2:28:8a:78:84:d0:bb:7d:67:80:
         45:02:94:01:36:02:9e:fa:a9:93:f2:83:62:d7:62:a4:78:49:
         c5:e1:36:88:bf:f0:8d:b0:77:39:e0:38:ea:d6:29:1b:56:98:
         ff:56:95:fa:83:c4:43:b6:62:c5:fb:96:71:69:d1:c2:4a:b8:
         c7:08:0f:ab:2b:0d:4c:78:94:e8:a1:8e:bd:fc:ee:68:35:9f:
         42:5e:65:78:4e:d0:7c:b5:63:bc:b5:9c:6e:c1:30:ad:0e:46:
         a1:c7:25:79:f8:b1:f8:34:5f:00:d0:67:6f:94:36:b6:35:46:
         6a:84:07:b8:a2:f7:f8:c6:c6:14:f5:14:74:3d:b3:19:3d:cf:
         e2:b7:38:5d:38:20:93:64:f9:1c:08:3e:87:9b:63:34:94:36:
         8a:51:b7:96:f2:d5:a0:89:6e:83:38:75:1a:c7:f5:87:e6:c5:
         0d:a6:29:6e:60:77:42:56:01:24:36:6b:8b:65:c3:50:c5:e7:
         a5:5b:91:38

-----BEGIN CERTIFICATE-----
MIIEOzCCAyOgAwIBAgIUDGquycKhTahubWftVswrnBVv0WAwDQYJKoZIhvcNAQEL
BQAwgYsxCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVUb2t5bzEdMBsGA1UECgwUd3d3
LmJpZ2JhbmcubXlkbnMuanAxHTAbBgNVBAMMFHd3dy5iaWdiYW5nLm15ZG5zLmpw
MS4wLAYJKoZIhvcNAQkBFh93ZWJtYXN0ZXJAbWFpbC5iaWdiYW5nLm15ZG5zLmpw
MCAXDTIxMTIwMjA4MDExOFoYDzIxMjExMTA4MDgwMTE4WjCBjjELMAkGA1UEBhMC
a3UxFjAUBgNVBAoMDWNlbnRvc3Nydi5jb20xGjAYBgNVBAMMEXRha2FzaGkuaGFz
aGltb3RvMS0wKwYJKoZIhvcNAQkBFh50YWthc2hpLmhhc2hpbW90b0Brc2RuZXQu
Y28uanAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaI4NiM1Ohyoga
L+Dq//nOL9ykrRx4bxbySKZUKBvbpwGi8z0yxrjykYaiYnPw4PWJyySb6OD4GjJi
qV64dKDnWdD7TT3mcD5+SifDwba89LOJbuuof+MBFxmQSkSgOCwrPLnue5hTWPEX
rPqNoX4s76tUGtIHkCINqRlpe9qmeONOf5hDgXZ/t64CYTk5n357TlASyS22OaEB
lvqf520DGvE7mOOq3jS1zcBzR3TyXCqJPERfo101coKCv/ZkatsXl8QP7DdGY3+s
3iUtWCriKq9TAhG9ORau87ZwvWwlh85+My/VChOGvSb4n0Xjd5wplx/PyJ88QvRl
h8FzgXx1AgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5T
U0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBS94VWzkAhQsDZICOD6
p3DjgOnDYTAfBgNVHSMEGDAWgBQhBXfppebejUb2G0Na4izAYBO+NzANBgkqhkiG
9w0BAQsFAAOCAQEAhPO5UtmO1nXPKwvBoLpvcU7SORgDKj0d04aMXSdOS8Rerv5K
GJftkCpnNudUnXj6hf0yXLDVCqqrvJPaWp+kP8LdYYaTJqXt1tscMjJreTLNUUh4
80EQKGmEz+JTjoR3/9LrDocYLIcT+8MpwH2JgqhyyzfPBMHIwoyEdzuoGsZfdGpx
YbDuP8vYvZ32A/IIRcIXXgUpSDaXeX6sTpafNwvj6JjjLcCgJk3evK+x7qXx+/uX
DX2L5MgPFAoNXZFq0tN80SQHaveV4rc4XTggk2T5HAg+h5tjNJQ2ilG3lvLVoIlu
gzh1Gsf1h+bFDaYpbmB3QlYBJDZri2XDUMXnpVuROA==
-----END CERTIFICATE-----
Signed certificate is in newcert.pem
※newcert.pemはカレントディレクトリに作成されます。

# openssl pkcs12 -export -in newcert.pem -inkey newkey.pem -certfile /etc/pki/CA/cacert.pem -out <任意のユーザ名>または<適当な証明書の名前>.p12 ← クライアント向けクライアント証明書登録ファイル作成
Enter pass phrase for newkey.pem: ← クライアント証明書パスフレーズを入力
Enter Export Password: ← 任意のクライアント証明書登録用パスフレーズを入力※クライアント証明書をクライアントの端末にインストールするときに必要
Verifying - Enter Export Password: ← 任意のクライアント証明書登録用パスフレーズを入力(確認)

※クライアント証明書はカレントディレクトリに作成されます。

ここで作成された「ユーザ名.p12」または「適当な証明書の名前.p12」ファイルをクライアントへ送付する


 非対話型でクライアント署名書を作成

 非対話型でクライアント署名書を作成してみます。
# openssl req -config /etc/pki/tls/openssl-client.cnf -new -keyout newkey.pem -out newreq.pem -days 36500 \
    -passout pass:任意のクライアント証明書パスフレーズ -subj "/CN=${CN:-任意のユーザ名}" ← クライアント秘密鍵・署名要求作成

or

# openssl req -config /etc/pki/tls/openssl-client.cnf -new -keyout newkey.pem -out newreq.pem -days 36500 \
    -passout pass:任意のクライアント証明書パスフレーズ -subj "/CN=${CN:-適当な証明書の名前}" ← クライアント秘密鍵・署名要求作成

Generating a 2048 bit RSA private key
........................................+++
..+++
writing new private key to 'newkey.pem'
-----

# openssl ca -batch -key CA秘密鍵パスフレーズ -config /etc/pki/tls/openssl-client.cnf -policy policy_anything \
    -out newcert.pem -infiles newreq.pem ← クライアント署名要求に署名してクライアント証明書作成
Using configuration from /etc/pki/tls/openssl-client.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            a9:30:4e:7e:67:c0:62:1e
        Validity
            Not Before: Oct 17 04:45:54 2017 GMT
            Not After : Sep 23 04:45:54 2117 GMT
        Subject:
            commonName                = user1
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Cert Type:
                SSL Client, S/MIME, Object Signing
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                80:2E:01:40:D9:BB:B3:7E:20:09:1A:41:D1:30:6B:0B:4E:0D:68:51
            X509v3 Authority Key Identifier:
                keyid:5D:D8:35:14:AE:15:42:2A:BA:AA:2E:C0:58:27:01:33:D3:9E:CF:FC

Certificate is to be certified until Sep 23 04:45:54 2117 GMT (36500 days)

Write out database with 1 new entries
Data Base Updated

# openssl pkcs12 -passin pass:クライアント証明書パスフレーズ -passout pass:任意のクライアント証明書登録用パスフレーズ \
    -in newcert.pem -inkey newkey.pem -certfile /etc/pki/CA/cacert.pem -out 任意のユーザ名.p12 -export ← クライアント向けクライアント証明書登録ファイル作成

or

# openssl pkcs12 -passin pass:クライアント証明書パスフレーズ -passout pass:任意のクライアント証明書登録用パスフレーズ \
    -in newcert.pem -inkey newkey.pem -certfile /etc/pki/CA/cacert.pem -out 適当な証明書の名前.p12 -export ← クライアント向けクライアント証明書登録ファイル作成

※クライアント証明書はカレントディレクトリに作成されます。

ここで作成された「ユーザ名.p12」または「適当な証明書の名前.p12」ファイルをクライアントへ送付する


 残作業

 クライアント証明書の退避及び不要ファイルを削除します。
クライアント証明書の退避
# cp -p newcert.pem /etc/pki/CA/certs/<任意のユーザ名>または<適当な証明書の名前>.crt ← クライアント証明書を失効用に退避※証明書失効については後述

不要ファイルの削除
# rm -f newcert.pem newkey.pem newreq.pem ← 後始末


 クライアント証明書をBASIC認証用ユーザデータベースに登録

 この作業は、特定ディレクトリ以下においてクライアント証明書を設定するための作業になります。
 したがって、Webサーバ全体用の作業ではありません。

 仮想IPを使用してWebサーバを公開している場合、コピーしたクライアント証明書を利用してBASIC認証用ユーザデータベースに登録

 BASIC認証用ユーザデータベース(例:/etc/httpd/conf/.htpasswd)がない場合=1件目の場合
# htpasswd -bcm /etc/httpd/conf/.htpasswd `openssl x509 -noout -subject -in /etc/pki/CA/certs/<任意のユーザ名>または<適当な証明書の名前>.crt | sed 's/subject//' | sed 's/=/\//' | sed 's/ //g' | sed 's/,/\//g'` password
 ↑ クライアント証明書をBASIC認証用ユーザデータベース(例:/etc/httpd/conf/.htpasswd)へ登録
 -cオプション利用時は、作成されるファイルのアクセス権、所有者に注意
 BASIC認証用ユーザデータベース(例:/etc/httpd/conf/.htpasswd)がある場合=2件目以降の場合
# htpasswd -bm /etc/httpd/conf/.htpasswd `openssl x509 -noout -subject -in /etc/pki/CA/certs/<任意のユーザ名>または<適当な証明書の名前>.crt | sed 's/subject//' | sed 's/=/\//' | sed 's/ //g' | sed 's/,/\//g'` password
 ↑ クライアント証明書をBASIC認証用ユーザデータベース(例:/etc/httpd/conf/.htpasswd)へ登録
※下線部のpasswordはそのまま記載する
-cオプション使用時、作成されるファイルのアクセス権、所有者を変更
# chmod 640 /etc/httpd/conf/.htpasswd
# chgrp apache /etc/httpd/conf/.htpasswd


●Apache側の設定

 Apacheを設定します。
# vi /etc/httpd/conf/httpd.conf

or

※常時SSLの場合
# vi /etc/httpd/conf.d/ssl.conf

or

※バーチャルホスト設定している場合
# vi /etc/httpd/conf.d/virtualhost-www.bigbang.mydns.jp.conf

#   Certificate Authority (CA):
#   Set the CA certificate verification path where to find CA
#   certificates for client authentication or alternatively one
#   huge file containing all of them (file must be PEM encoded)
#SSLCACertificateFile /etc/pki/tls/certs/ca-bundle.crt
#SSLCACertificateFile /etc/pki/tls/certs/ca.pem
SSLCACertificateFile /etc/pki/CA/cacert.pem ← CA証明書
SSLCARevocationFile /etc/pki/CA/crl.pem ← 証明書失効リスト
SSLCARevocationCheck chain ← 証明書失効リストチェック有効化

# systemctl reload httpd ← Apache設定反映


●クライアント証明書認証確認

 クライアント証明書認証の確認を行います。

 クライアント証明書によるアクセス制限を行うWebページを作成

 クライアント証明書によるアクセス制限を行うWebページを作成します。
# mkdir /var/www/html/strictsecret ← クライアント証明書アクセス制限ディレクトリ作成

# vi /var/www/html/strictsecret/.htaccess ← クライアント証明書アクセス制限ディレクトリに.htaccess作成
<If "! -R '10.0.0.0/8' && ! -R '172.16.0.0/12' && ! -R '192.168.0.0/16'">
    SSLVerifyClient require
    SSLVerifyDepth 1
    SSLOptions +FakeBasicAuth
    AuthUserFile /etc/httpd/conf/.htpasswd
    AuthName "secret page"
    AuthType Basic
    require valid-user
</If>

# vi /etc/httpd/conf.d/ssl.conf
# アクセス元がプライベートアドレス以外の場合はクライアント証明書を要求する
<Directory "/var/www/html/strictsecret">
    <IfModule dir_module>
      DirectoryIndex index.htm
    </IfModule>
  <If "! -R '10.0.0.0/8' && ! -R '172.16.0.0/12' && ! -R '192.168.0.0/16'">
      SSLVerifyClient require
      SSLVerifyDepth 1
      SSLOptions +FakeBasicAuth
      AuthUserFile /etc/httpd/conf/.htpasswd
      AuthName "secret page"
      AuthType Basic
      require valid-user
  </If>
</Directory>

# systemctl reload httpd

# echo test > /var/www/html/strictsecret/index.html ← クライアント証明書アクセス制限ディレクトリにテスト用ページ作成


 ブラウザへのクライアント証明書登録

 【PCの場合】

 サーバから送付された「任意のユーザ名.p12」または「適当な証明書の名前.p12」ファイルをクライアント側で開いてインストールします。
 ※パスワードはクライアント証明書登録用パスフレーズを指定
 ※CA証明書インストールに伴うセキュリティ警告メッセージには「はい」を選択
 ※Chrome、IE、Edgeは上記でOKだが、Firefoxは個別にインストールが必要
 (Firefoxのオプション → プライバシーとセキュリティ → 証明書 → 証明書を表示 → あなたの証明書 → インポート)

 ※Microsoft Edgeでのクライアント証明書登録方法
 設定 → セキュリティ → 証明書の管理 → インポート → クライアント証明書を選択 → パスワードを入力 → 終了
 初めてクライアント証明書が必要なURLを開くと、証明書の選択画面が表示されますので該当クライアント証明書を選択します。これで該当URLを開くことが出来ます。

 ※Firefoxでのクライアント証明書登録方法
 設定 → プライバシーとセキュリティ → 証明書 → 証明書の表示 → 証明書マネージャ → あなたの証明書
 → インポート → クライアント証明書を選択 → パスワードを入力 → OK → 終了
 初めてクライアント証明書が必要なURLを開くと、証明書の選択画面が表示されますので該当クライアント証明書を選択します。これで該当URLを開くことが出来ます。
 ログイン時の電子証明書選択画面(個人証明書の要求)が期待通り表示されず、前回選択した電子証明書の情報でログイン(接続)しようとする場合があります。
 この場合、「設定」-「プライバシーとセキュリティ」タブの順に押します。
 履歴で"履歴を一切記憶させない"をプルダウンから選択し、ブラウザを再起動してください。

 【スマホの場合】

 サーバからメール添付で送付された「任意のユーザ名.p12」または「適当な証明書の名前.p12」ファイルをスマホ側のメールアプリで開いてインストールする
 ※パスワードはクライアント証明書登録用パスフレーズを指定する
  • プライベートアドレスからhttps://www.bigbang.mydns.jp/strictsecret/へアクセスして、証明書なしでアクセスできること
  • 外部からhttps://www.bigbang.mydns.jp/strictsecret/へアクセスして、証明書なしでアクセスできないこと
  • 外部からhttps://www.bigbang.mydns.jp/strictsecret/へアクセスして、証明書ありでアクセスできること


●クライアント証明書失効

 クライアント証明書が不要になった場合に、該当のクライアント証明書を失効させて使用できないようにする。
# openssl ca -gencrl -revoke /etc/pki/CA/certs/<任意のユーザ名>または<適当な証明書の名前>.crt ← クライアント証明書失効
Using configuration from /etc/pki/tls/openssl.cnf
Enter pass phrase for /etc/pki/CA/private/cakey.pem: ← CA秘密鍵パスフレーズを入力
-----BEGIN X509 CRL-----
MIICsjCCAZoCAQEwDQYJKoZIhvcNAQELBQAwdTELMAkGA1UEBhMCSlAxDjAMBgNV
BAgMBVRva3lvMRYwFAYDVQQKDA1jZW50b3NzcnYuY29tMRYwFAYDVQQDDA1jZW50
b3NzcnYuY29tMSYwJAYJKoZIhvcNAQkBFhd3ZWJtYXN0ZXJAY2VudG9zc3J2LmNv
bRcNMTcxMDE3MDg0MjA3WhcNMTcxMTE2MDg0MjA3WjCB4DAaAgkAqTBOfmfAYhwX
DTE3MTAxNzA0MzMxOVowGgIJAKkwTn5nwGIeFw0xNzEwMTcwNDQ5MjJaMBoCCQCp
ME5+Z8BiHxcNMTcxMDE3MDUwNjU1WjAaAgkAqTBOfmfAYiAXDTE3MTAxNzA1MzQx
NlowGgIJAKkwTn5nwGIhFw0xNzEwMTcwNzUyMzBaMBoCCQCpME5+Z8BiIhcNMTcx
MDE3MDc1NTQ4WjAaAgkAqTBOfmfAYiMXDTE3MTAxNzA4MTg0OVowGgIJAKkwTn5n
wGIkFw0xNzEwMTcwODM3MDdaoA4wDDAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsF
AAOCAQEA7Xx4PxTejaONp+J8pd8zx1yy3SSeYgIBAmWWvsJBjmbWNATkYWTWMyc2
cvBK8dURRC6tQ7nqLEOhOAv1/jn27qylL/1pBAujbV7xDO++YsqRAn1qkr2kQmy3
vAnqA7SaCQij31410ZNxfQViD5CxDK4e36SlouqtqNONQx3Ji6VuhaiHRr9TJUxc
EKijbTOWiqYm+b1NxxmJm4y9LEL3CGVguBYHS8o6TZDWOml2O4Sz5N4Y2Gor0wnU
wUoS14e+DONCaEvJxhEblcx7Dd8zLDUkPixVqyuQIOBG7k7cWg6Jt9MtjCpHcvMl
zy+fierK3X3yjtM+QMiCh1TzwG/kRw==
-----END X509 CRL-----
Revoking Certificate 0C6AAEC9C2A14DA9304E7E67C0621C.
Data Base Updated

# openssl ca -gencrl -out /etc/pki/CA/crl.pem ← 証明書失効リスト更新
Using configuration from /etc/pki/tls/openssl.cnf
Enter pass phrase for /etc/pki/CA/private/cakey.pem: ← CA秘密鍵パスフレーズを入力

# systemctl reload httpd ← 証明書失効リスト反映
 外部からhttps://www.bigbang.mydns.jp/strictsecret/へアクセスして、失効させたクライアント証明書でアクセスできないこと
# vi /etc/cron.weekly/crlupdate ← 証明書失効リスト自動更新スクリプト作成
#!/bin/bash
openssl ca -batch -key CA証明書パスフレーズ -gencrl -out /etc/pki/CA/crl.pem > /dev/null 2>&1
systemctl reload httpd > /dev/null 2>&1

# chmod 700 /etc/cron.weekly/crlupdate ← 証明書失効リスト自動更新スクリプトに実行権限付加
 ※証明書失効リストの有効期限は初期設定で30日となっており、有効期限が過ぎるとクライアント証明書認証が行えなくなってしまうため、証明書失効が30日以内に行われなくても大丈夫なように定期的に空更新します。

●cannot perform post-handshake authentication

 参考URL:CentOS8 に /etc/pki/tls/misc/CA をインストールする方法

 TLS1.3を有効にしている場合、下記のようなエラーが発生して、クライアント証明書認証ができない場合があります。

[Thu Dec 02 23:27:32.235316 2021] [ssl:error] [pid 1003879:tid 140609486571264] [client 192.168.21.2:50091] AH: verify client post handshake
[Thu Dec 02 23:27:32.235351 2021] [ssl:error] [pid 1003879:tid 140609486571264] [client 192.168.21.2:50091] AH10158: cannot perform post-handshake authentication
[Thu Dec 02 23:27:32.235368 2021] [ssl:error] [pid 1003879:tid 140609486571264] SSL Library Error: error:14268117:SSL routines:SSL_verify_client_post_handshake:extension not received

 この場合、下記のように対処することで改善される場合があります。
# vi /etc/httpd/conf.d/ssl.conf
SSLProtocol -All +TLSv1.2 +TLSv1.3
 ↓
SSLProtocol -All +TLSv1.2

# systemctl reload httpd