オレオレ認証局とオレオレ証明書（旧版）

自分のための作業メモ。サーバは CentOS 7.5 で openssl はインストール済み。

# 0) 旧版につき注意!

この記事は **obsoleted** である。最近の `openssl` パッケージには、ここで使用している `CA` スクリプトが付属していない。

新版である [**"easy-ca によるオレオレ認証局とオレオレ証明書"**](https://qiita.com/softark/items/cb92f1ebed8b4b6c55b4) を参照されたい。そっちの方が簡明でもある。

# 1) 準備作業

`/etc/pki` 以下に `saCA` ディレクトリを作成して、元になるファイルをコピーしてきて、そこで作業する。`saCA` というのは、`myCA` みたいなもの。

```
[root@centos pki]# cd /etc/pki
[root@centos pki]# mkdir saCA
[root@centos pki]# cp tls/misc/CA saCA/.
[root@centos pki]# cp tls/openssl.cnf saCA/.
[root@centos pki]# echo 01 > saCA/crlnumber
[root@centos pki]# ll saCA
合計 24
-rwxr-xr-x 1 root root  5178 12月  3 14:12 CA
-rw-r--r-- 1 root root     3 12月  3 14:12 crlnumber
-rw-r--r-- 1 root root 10923 12月  3 14:12 openssl.cnf
```

`CA` は、`openssl` コマンドを使用する作業を簡易化する（ことを目的とした）スクリプト。意図どおりに目的が達成されているかどうかは微妙だが、これを使う。

## 1-1) `/etc/pki/saCA/CA` スクリプトを修正

ディレクトリを `saCA` に合せたり、証明書の有効期限を延ばしたりする。

```bash:CA
... (前略) ...

usage() {
 echo "usage: $0 -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify" >&2
}

SSLEAY_CONFIG="-config /etc/pki/saCA/openssl.cnf"  # [kihara] 追加

if [ -z "$OPENSSL" ]; then OPENSSL=openssl; fi

if [ -z "$DAYS" ] ; then DAYS="-days 3650" ; fi  # [kihara] 修正 1年 -> 10年
CADAYS="-days 10950"     # [kihara] 修正 3年 -> 30年
REQ="$OPENSSL req $SSLEAY_CONFIG"
CA="$OPENSSL ca $SSLEAY_CONFIG"
VERIFY="$OPENSSL verify"
X509="$OPENSSL x509"
PKCS12="openssl pkcs12"

if [ -z "$CATOP" ] ; then CATOP=/etc/pki/saCA ; fi  # [kihara] 修正 トップ・ディレクトリ

CAKEY=./cakey.pem
CAREQ=./careq.pem
CACERT=./cacert.pem

... (後略) ...
```

## 1-2) `/etc/pki/saCA/openssl.cnf` 設定ファイルを修正

ディレクトリを `saCA` に合せたり、証明書の有効期限を延ばしたりする。
また、国、地域、市、会社等の情報について、デフォルト値を与えておく。
さらに、SAN (`subjectAltName`) に対応したサーバ証明書を作るときのために、いくつかのエントリを追加する。


```ini:openssl.cnf
[ CA_default ]
dir             = /etc/pki/saCA         # 修正
...
default_days    = 3650                  # 修正
...
[ req ]
...
req_extensions = v3_req  # 追加
...
[ 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    = Hyogo # 修正
 
localityName                   = Locality Name (eg, city)
localityName_default           = Taka-cho # 修正
 
0.organizationName             = Organization Name (eg, company)
0.organizationName_default     = softark.net # 修正
...
[ usr_cert ]
...
subjectAltName = @alt_names    # 追加 SAN 用
...
[ v3_req ]
...
subjectAltName = @alt_names    # 追加 SAN 用

# alt_names セクションを追加 SAN 用
[ alt_names ]
DNS.1 = web.softark.net        # 追加 SAN 用
...
```
SAN (`subjectAltName`) に関連する追加修正については、下記を参照。

- [【OpenSSL】SANでDNS情報を付与した証明書を作成する](https://kaede.jp/2018/06/10191854.html)
- [SAN対応 x.509 証明書を取得するためのCSRを作成する](https://qiita.com/saitara/items/eda74ac6a950122b5f31)

# 2) 認証局証明書

自分で勝手に認証局証明書を作成して、サーバをオレオレ認証局に仕立て上げる。

## 2-1) 認証局証明書の生成

`CA -newca` で、認証局証明書を生成する。Common Name に認証局名を指定すること。

```
[root@centos saCA]# ./CA -newca
CA certificate filename (or enter to create)

Making CA certificate ...
Generating a 2048 bit RSA private key
..................................+++
...........+++
writing new private key to '/etc/pki/saCA/private/./cakey.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]:
State or Province Name (full name) [Hyogo]:
Locality Name (eg, city) [Taka-cho]:
Organization Name (eg, company) [softark.net]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:softark-CA ... !! これが認証局名 !!
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /etc/pki/saCA/openssl.cnf
Enter pass phrase for /etc/pki/saCA/private/./cakey.pem:isa563rigami
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: ...
(中略)
Certificate is to be certified until Jan 14 17:15:18 2025 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated
```
## 2-2) 生成されたファイルの整理

署名要求ファイルを `certs` に移動

```
[root@centos saCA]# mv careq.pem certs/00.pem
```

CRL (Certificate Revocation List) ファイルを作成

```
[root@centos saCA]# openssl ca -config openssl.cnf -gencrl -out crl.pem
Using configuration from openssl.cnf
Enter pass phrase for /etc/pki/saCA/private/cakey.pem:********
```

認証局証明書ファイル (`cacert.pem`) をコピー

```
[root@centos saCA]# cp cacert.pem softark-CA.crt
```

認証局証明書を標準の場所にコピー

```
[root@centos saCA]# cp softark-CA.crt /etc/pki/tls/certs/.
```

## 2-3) 認証局証明書のファイル

- 認証局証明書 : cacert.pem, newcerts/AFF18B450CEF53A1.pem, softark-CA.crt
- 認証局秘密鍵 : private/cakey.pem
- 認証局証明書署名要求 : careq.pem, certs/00.pem
- CRL ファイル : crl.pem

## 2-4) クライアントへのインストール

サーバから認証局証明書 softark-CA.crt をダウンロードする。

IE > インターネット・オプション > コンテンツ > 証明書
(または、ファイル名を指定して実行 > certmgr.msc)

「信頼されたルート証明機関」に softark-CA.crt をインポートする。

## 2-5) グループポリシーの「信頼されたルート証明機関」として登録する

社内ネットワークなど Active Directory のドメインにおいては、オレオレ認証局をグループポリシーの「信頼されたルート証明機関」として登録すると便利である。

グループポリシー・エディタで `Default Domain Policy > コンピュータの構成 > ポリシー > Windowsの設定 > セキュリティの設定 > 公開キーのポリシー > 信頼されたルート証明機関` に認証局証明書をインポートする。

[Windows Serverを認証局にしよう > グループポリシーに証明書をインポート](https://ascii.jp/elem/000/000/533/533755/index-2.html)


# 3) サーバ証明書

オレオレ認証局で、サーバ証明書を作成して発行する。

## 3-1) サーバ証明書発行要求

SAN (`subjectAltName`) 対応のサーバ証明書を作成するためには、対象となるサーバの名前が `openssl.cnf` の `[ alt_names ]` セクションに `DNS` として挙げられている必要がある。

```ini:openssl.cnf
# alt_names セクションを追加 SAN 用
[ alt_names ]
DNS.1 = web.softark.net
DNS.2 = www.softark.net
DNS.3 = mng.softark.net
...
```

必要に応じて `openssl.cnf` を書き換えてから、下記を実行する。

`CA -newreq` で、サーバ証明書発行要求を作成する。Common Name で対象となるサーバ名を入力する。例えば、`web.softark.net`。ワイルド・カードを使っても良い。例えば、`*.softark.net`。

```
[root@centos saCA]# ./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]:
State or Province Name (full name) [Hyogo]:
Locality Name (eg, city) [Taka-cho]:
Organization Name (eg, company) [softark.net]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:web.softark.net ... !! ここにサーバ名 !!
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Request is in newreq.pem, private key is in newkey.pem

```

## 3-2) サーバ証明書に署名

`CA -sign` で、サーバ証明書に認証局のサインをする。

```
[root@centos saCA]# ./CA -sign
Using configuration from /etc/pki/saCA/openssl.cnf
Enter pass phrase for /etc/pki/saCA/private/cakey.pem:********
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: ...
(中略)
Certificate is to be certified until Jan 14 17:29:05 2025 GMT (3650 days)
Sign the certificate? [y/n]:y
(中略)
1 out of 1 certificate requests certified, commit? [y/n]y
(中略)
Signed certificate is in newcert.pem
```

以上で、サーバ証明書が出来た。

## 3-3) 整理

```
[root@centos saCA]# ll newcerts
total 16
-rw-r--r-- 1 root root 4345 Jan 18 02:15 AFF18B450CEF53A1.pem
-rw-r--r-- 1 root root 4510 Jan 18 02:29 AFF18B450CEF53A2.pem
...
```

一番大きな値のファイルを探す。それが、たった今作成されたサーバ証明書。整理する。

```
[root@centos saCA]# mv newreq.pem certs/AFF18B450CEF53A2.pem
[root@centos saCA]# mv newkey.pem private/AFF18B450CEF53A2.pem
[root@centos saCA]# rm newcert.pem
rm: remove regular file ‘newcert.pem’? y
```

## 3-4) サーバに配置するためのファイルを作成

サーバ証明書を `x509` 形式に変換する。また、パス・フレーズを埋め込んだサーバの秘密鍵を作成する（そうしないと、Apache や nginx が自動起動に失敗する）。

```
[root@centos saCA]# openssl x509 -in newcerts/AFF18B450CEF53A2.pem -out web.softark.net.crt
[root@centos saCA]# openssl rsa -in private/AFF18B450CEF53A2.pem -out web.softark.net.key
Enter pass phrase for private/AFF18B450CEF53A2.pem:********
writing RSA key

```

## 3-5) サーバ証明書のファイル

- サーバ 証明書 : web.softark.net.crt
- サーバ 鍵 : web.softark.net.key


# 4) サーバ証明書の利用

## 4-1) 証明書の設置

認証局と同じサーバの場合は、証明書と鍵を、標準の場所にコピーする。

```
[root@centos saCA]# cp web.softark.net.crt /etc/pki/tls/certs/.
[root@centos saCA]# cp web.softark.net.key /etc/pki/tls/certs/.
```

認証局と別のサーバの場合は、認証局から配布された証明書と鍵を、標準の場所に置く。

```
[root@web somewhere]# mv web.softark.net.crt /etc/pki/tls/certs/.
[root@web somewhere]# mv web.softark.net.key /etc/pki/tls/certs/.
```

後述するクライアント認証もしたい場合は、認証局証明書も貰って、同じ場所に置く。

```
[root@web somewhere]# mv softark-CA.crt /etc/pki/tls/certs/.
```


## 4-2) Apache SSL モジュールの設定

SSL モジュールをインストールする。

```
[root@centos ~]# yum install mod_ssl
```

`/etc/httpd/conf.d/ssl.conf` を編集する。

```ini:ssl.conf
# 100行目：サーバ証明書指定
SSLCertificateFile /etc/pki/tls/certs/web.softark.net.crt

# 107行目：サーバ鍵ファイル指定
SSLCertificateKeyFile /etc/pki/tls/certs/web.softark.net.key

# 122行目：認証局証明書指定 ... クライアント認証に必要
SSLCACertificateFile /etc/pki/tls/certs/softark-CA.crt
```

最後は、クライアント認証をしたい場合にだけ必要となる。

以上で、ウェブ・サーバが SSL に対応した通信が出来るようになる。

# 5) クライアント証明書

オレオレ認証局で、クライアント証明書を作成して発行する。

## 5-1) 準備作業

`/etc/pki/saCA/openssl.cnf` を編集。以下を末尾に追加。この作業は最初の一回だけ。

```ini:openssl.cnf
[ client_cert ]
basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
```

## 5-2) クライアント証明書発行

`openssl req` で、クライアント証明書を作成する。Common Name には、クライアント名を入れる。

```
[root@centos saCA]# openssl req -config openssl.cnf -new -keyout kihara.key.pem -out kihara.req.pem -days 3650 -extensions client_cert
Generating a 2048 bit RSA private key
.+++
..........................................+++
writing new private key to 'kihara.key.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]:
State or Province Name (full name) [Hyogo]:
Locality Name (eg, city) [Taka-cho]:
Organization Name (eg, company) [softark]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:kihara !! クライアント名 !!
Email Address []:

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

```

署名する。

```
[root@centos saCA]# openssl ca -config openssl.cnf -policy policy_anything -out kihara.cert.pem -extensions client_cert -infiles kihara.req.pem
Using configuration from openssl.cnf
Enter pass phrase for /etc/pki/saCA/private/cakey.pem:********
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: ...
(中略)
Certificate is to be certified until Dec 24 07:08:14 2025 GMT (3650 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
```

## 5-3) 整理

```
[root@centos saCA]# ll newcerts
total 24
-rw-r--r-- 1 root root 4345 Jan 18 02:15 AFF18B450CEF53A1.pem
-rw-r--r-- 1 root root 4510 Jan 18 02:29 AFF18B450CEF53A2.pem
-rw-r--r-- 1 root root 4494 Jan 18 03:58 AFF18B450CEF53A3.pem
...
```

一番大きな値のファイルを探す。それが、たった今作成された証明書。

整理する。

```
[root@centos saCA]# rm kihara.cert.pem
rm: remove regular file ‘kihara.cert.pem’? y
[root@centos saCA]# mv kihara.req.pem certs/AFF18B450CEF53A3.pem
[root@centos saCA]# mv kihara.key.pem private/AFF18B450CEF53A3.pem
```

クライアントに配布する .p12 ファイルを作る。

```
[root@centos saCA]# openssl pkcs12 -export -in newcerts/AFF18B450CEF53A3.pem -inkey private/AFF18B450CEF53A3.pem -certfile cacert.pem -out kihara.p12
Enter pass phrase for private/AFF18B450CEF53A3.pem:********
Enter Export Password:********   ... クライアントにインポートするときのパスワード
Verifying - Enter Export Password:********
```

## 5-4) クライアントへのインストール

サーバからクライアント証明書 kihara.p12 をダウンロードする。

IE > インターネット・オプション > コンテンツ > 証明書
(または、ファイル名を指定して実行 > crtmgr.msc)

「個人」に kihara.p12 をインポートする。


# 6) クライアント証明書の利用

## 6-1) phpMyAdmin へのアクセス制限

phpMyAdmin へのアクセスに、認証されたクライアントからの SSL 接続を要求する。

/etc/httpd/conf.d/phpMyAdmin.conf

```apache:phpMyAdmin.conf
...
<Directory /usr/share/phpMyAdmin/>
   AddDefaultCharset UTF-8

   <IfModule mod_authz_core.c>
     # Apache 2.4
     # Require local
     SSLRequireSSL
     SSLVerifyClient require
     Require expr %{SSL_CLIENT_S_DN_CN} in {"kihara"}
   </IfModule>
   <IfModule !mod_authz_core.c>
     # Apache 2.2
     Order Deny,Allow
     Deny from All
     Allow from 127.0.0.1
     Allow from ::1
   </IfModule>
</Directory>
...
```

`SSLVerifyClient require` だけでも、サーバが信頼する認証局が署名したクライアント証明書が必要になる。従って、たいていの場合、`Require expr` によるユーザ名の確認は不要である。

## 6-2) web.softark.net へのアクセス制限

web.softark.net へのアクセスに、認証されたクライアントからの SSL 接続を要求する。

`/etc/httpd/conf.d/ssl.conf` の `<VirtualHost _default_:443> ... </VirtualHost>` の部分は、全面的に削除またはコメントアウトする。その部分にフォールバック設定を持っていると、何かと問題が生じやすい。ホストごとの SSL 設定を `vhosts.conf` に直接書く方がよい。

```apache:vhosts.conf
### web.softark.net
<VirtualHost *:443>
    ...
    SSLEngine on
    SSLProtocol all -SSLv2
    SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
    SSLCertificateFile /etc/pki/tls/certs/web.softark.net.crt
    SSLCertificateKeyFile /etc/pki/tls/certs/web.softark.net.key
    SSLCACertificateFile /etc/pki/tls/certs/softark-CA.crt
    SSLVerifyClient require
    <Directory "/var/www/html">
        ...
        SSLRequireSSL
        SSLRequire %{SSL_CLIENT_S_DN_CN} in {"kihara"}
    </Directory>
</VirtualHost>

```

`SSLVerifyClient require` だけでも、サーバが信頼する認証局が署名したクライアント証明書が必要になる。従って、たいていの場合、`SSLRequire` によるユーザ名の確認は不要である。

# 参考

- [オレオレ認証局の作り方～SSL証明書を無料で作る方法](http://www.webtech.co.jp/blog/developer-news/1159/)
- [オレオレ認証局でクライアント認証 ～ ウェブの Basic 認証をリプレース](http://www.webtech.co.jp/blog/developer-news/1780/)
- [CentOS 6.5 OpenSSLでオレオレ認証局](http://qiita.com/T_Tsan/items/632e83167bbc3a90ad4e)