オレオレクロスルート証明書

オレオレクロスルート証明書を生成する機会があったので、そのやり方を記録に残しておきます。

そもそも、オレオレクロスルート証明書の作り方なんかは、ググってもあまり出てこないようです。私が見つけた情報だと [情報 1](http://soudan1.biglobe.ne.jp/qa8201691.html "BIGLOBE なんでも相談室"), [情報 2 (情報 1 と同じ内容)](http://okwave.jp/qa/q8201691.html "OKWave"), [情報 3](http://brenhilt.com/tech/2013/0211 "brenhilt.com"), [情報 4](http://ascii.jp/elem/000/000/550/550214/img.html "ascii.jp") があるのですが、いまいち情報不足です。ググり方がまずいのか、英語のページでもあまり情報がないようです。

これ以降、上記の情報が正しいと信じて進みます。ちなみに使用する openssl のバージョンは 1.0.2 で、ソースからコンパイルしたものを /opt/openssl-1.0.2 にインストールして使っています。Web サーバには Apache を使用しています。バージョンは 2.4.10 です。

コマンドラインはコピペしやすさを重視して書いています。また、オプション引数のデフォルト値を明示的に引数で指定したりしています。いちいち man で調べなくても済むからです。なので、冗長なコマンドラインになります。

openssl.cnf は認証局ごとにカスタマイズして利用するものと勝手に理解していますが、ここでは何個も認証局を作るので openssl.cnf はデフォルトのものをそのまま使います。認証局ごとに書き換えたりしません (もちろん書き換えても構いません)。認証局ごとの差違はコマンドラインで指定します。これまた長いコマンドラインになります。

認証局の構成は下図のようにします。
![aa.png](https://qiita-image-store.s3.amazonaws.com/0/65370/59c0fe84-2547-61c7-73e0-ff7d97187a55.png)
CN はコモンネーム (Common Name) の略です。


### 前準備

作業するディレクトリの構成は以下のようにします。主要なファイルを書き出しています。
![tree.png](https://qiita-image-store.s3.amazonaws.com/0/65370/c941b137-47a2-111c-43a0-cd27c43af675.png)
初期状態として必要なディレクトリやファイルを以下のコマンドで作成します。~ や dir は適当なディレクトリ名に置き換えてください。もちろんそのままコピペしても構いません。

```shell-session
umask 077
cd ~
rm -rf dir
mkdir dir
cd dir
mkdir server
mkdir -p root1024/demoCA/newcerts root1024/demoCA/private
mkdir -p root2048/demoCA/newcerts root2048/demoCA/private
mkdir -p interCA/demoCA/newcerts  interCA/demoCA/private
mkdir -p crossCA/demoCA/newcerts  crossCA/demoCA/private
(cd root1024; touch demoCA/index.txt; echo 01 > demoCA/serial)
(cd root2048; touch demoCA/index.txt; echo 01 > demoCA/serial)
(cd interCA; touch demoCA/index.txt; echo 01 > demoCA/serial)
(cd crossCA; touch demoCA/index.txt; echo 01 > demoCA/serial)
```

openssl.cnf をコピーして使いまわします。私は openssl を /opt/openssl-1.0.2 にインストールして使っていますので、/opt/openssl-1.0.2/ssl/openssl.cnf からコピーしています。~/dir/openssl.cnf は、この時点で都合のいいように書き換えても構いません。

```shell-session
cp /opt/openssl-1.0.2/ssl/openssl.cnf ~/dir/openssl.cnf
```


### ルート認証局 AAA (2048 bit)

ルート証明書 (2048 bit) を生成します。秘密鍵と CSR（Certificate Signing Request; 証明書署名要求) を生成し、自己署名します。~/dir/root2048/demoCA/cacert.pem がルート証明書になります。


#### 秘密鍵と CSR の生成

```shell-session
cd ~/dir/root2048
openssl req -new -newkey rsa:2048 -sha256 \
        -keyout demoCA/private/cakey.pem \
        -out    demoCA/careq.pem
(中略)
Enter PEM pass phrase:********
Verifying - Enter PEM pass phrase:********
(中略)
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Chiba
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:AAA Corporation
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:AAA ROOT CA 2048
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
```


#### 自己署名

```shell-session
cd ~/dir/root2048
openssl ca -config ~/dir/openssl.cnf \
        -md sha256 \
        -in      demoCA/careq.pem \
        -keyfile demoCA/private/cakey.pem \
        -out     demoCA/cacert.pem \
        -selfsign -days 3650 -extensions v3_ca -batch
Using configuration from /home/g0117736/dir/openssl.cnf
Enter pass phrase for demoCA/private/cakey.pem:********
Check that the request matches the signature
Signature ok
(中略)
Write out database with 1 new entries
Data Base Updated
```


### ルート認証局 BBB (1024 bit)

ルート証明書 (1024 bit) を生成します。秘密鍵と CSR を生成し、自己署名します。~/dir/root1024/demoCA/cacert.pem がルート証明書になります。


#### 秘密鍵と CSR の生成

```shell-session
cd ~/dir/root1024
openssl req -new -newkey rsa:1024 -sha256 \
        -keyout demoCA/private/cakey.pem \
        -out    demoCA/careq.pem
(中略)
Enter PEM pass phrase:********
Verifying - Enter PEM pass phrase:********
(中略)
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Chiba
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:BBB Corporation
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:BBB ROOT CA 1024
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
```


#### 自己署名

```shell-session
cd ~/dir/root1024
openssl ca -config ~/dir/openssl.cnf \
        -md sha256 \
        -in      demoCA/careq.pem \
        -keyfile demoCA/private/cakey.pem \
        -out     demoCA/cacert.pem \
        -selfsign -days 3650 -extensions v3_ca -batch
Using configuration from /home/g0117736/dir/openssl.cnf
Enter pass phrase for demoCA/private/cakey.pem:********
Check that the request matches the signature
Signature ok
(中略)
Write out database with 1 new entries
Data Base Updated
```


### 中間認証局 CCC

中間 CA 証明書を生成します。秘密鍵と CSR を生成し、ルート認証局 AAA (root2048) で署名します。~/dir/interCA/demoCA/cacert.pem が中間 CA 証明書になります。


#### 秘密鍵と CSR の生成

```shell-session
cd ~/dir/interCA
openssl req -new -newkey rsa:2048 -sha256 \
        -keyout demoCA/private/cakey.pem \
        -out    demoCA/careq.pem
(中略)
Enter PEM pass phrase:********
Verifying - Enter PEM pass phrase:********
(中略)
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Chiba
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:CCC Corporation
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:CCC Inter CA
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
```


#### ルート認証局 AAA (root2048) で署名

```shell-session
cd ~/dir/root2048
openssl ca -config ~/dir/openssl.cnf \
        -md sha256 \
        -in      ../interCA/demoCA/careq.pem \
        -keyfile demoCA/private/cakey.pem \
        -out     ../interCA/demoCA/cacert.pem \
        -days 3650 -extensions v3_ca -batch -policy policy_anything
Using configuration from /home/g0117736/dir/openssl.cnf
Enter pass phrase for demoCA/private/cakey.pem:********
Check that the request matches the signature
Signature ok
(中略)
Write out database with 1 new entries
Data Base Updated
```


### サーバー証明書

サーバー証明書を生成します。秘密鍵と CSR を生成し、中間認証局 CCC (interCA) で署名します。~/dir/server/server.crt がサーバー証明書になります。


#### 秘密鍵と CSR の生成

```shell-session
cd ~/dir/server
openssl genrsa 2048 > server.key
openssl req -new -sha256 -key server.key > server.csr
(中略)
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Chiba
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:EEE CO., LTD.
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:www.example.jp
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
```

#### 中間認証局 CCC (interCA) で署名

```shell-session
cd ~/dir/interCA
openssl ca -config ~/dir/openssl.cnf \
        -md sha256 \
        -in      ../server/server.csr \
        -out     ../server/server.crt \
        -keyfile demoCA/private/cakey.pem \
        -cert    demoCA/cacert.pem \
        -batch -policy policy_anything
Using configuration from /home/g0117736/dir/openssl.cnf
Enter pass phrase for demoCA/private/cakey.pem:********
Check that the request matches the signature
Signature ok
(中略)
Write out database with 1 new entries
Data Base Updated
```


### サーバー証明書の確認 (クロスルートなし)

この時点で、クロスルートなしのサーバー証明書が利用可能です。~/dir/server/server.key と ~/dir/server/server.crt をそれぞれ Apache の SSLCertificateKeyFile と SSLCertificateFile に指定します。
中間認証局 CCC (interCA) の中間 CA 証明書 ~/dir/interCA/demoCA/cacert.pem は SSLCertificateChainFile に指定します。

ルート認証局 AAA (root2048) のルート証明書 ~/dir/root2048/demoCA/cacert.pem は SSL クライアント (例えば Firefox) にインストールします。

Firefox でサーバー証明書を確認すると、以下の図のように 3 階層で構成されていることがわかります。

![tier3.png](https://qiita-image-store.s3.amazonaws.com/0/65370/5f572424-c88f-2e09-f104-c2738ff7d832.png)


openssl の s_client ならば、以下のように確認することができます。

```shell-session
openssl s_client \
        -CAfile ~/dir/root2048/demoCA/cacert.pem -trusted_first \
        -connect www.example.jp:443  < /dev/null
CONNECTED(00000003)
depth=2 C = JP, ST = Chiba, O = AAA Corporation, CN = AAA ROOT CA 2048
verify return:1
depth=1 C = JP, ST = Chiba, O = CCC Corporation, CN = CCC Inter CA
verify return:1
depth=0 C = JP, ST = Chiba, O = "EEE CO., LTD.", CN = www.example.jp
verify return:1
---
Certificate chain
 0 s:/C=JP/ST=Chiba/O=EEE CO., LTD./CN=www.example.jp
   i:/C=JP/ST=Chiba/O=CCC Corporation/CN=CCC Inter CA
 1 s:/C=JP/ST=Chiba/O=CCC Corporation/CN=CCC Inter CA
   i:/C=JP/ST=Chiba/O=AAA Corporation/CN=AAA ROOT CA 2048
---
(中略)
    Verify return code: 0 (ok)
---
DONE
```


### クロスルート証明書

#### 秘密鍵

クロスルート認証局 DDD (crossCA) の秘密鍵と ルート認証局 AAA (root2048) の秘密鍵は同じものになります。以下のコマンドでシンボリックリンクを張ります。コピーしても構いません。

```shell-session
cd ~/dir
ln -s ../../../root2048/demoCA/private/cakey.pem crossCA/demoCA/private/cakey.pem
```


#### CSR の生成

クロスルート認証局 DDD (crossCA) の Organization Name や CN は、ルート認証局 AAA (root2048) の CN と同じものにします。

```shell-session
cd ~/dir/crossCA
openssl req -new -sha256 \
        -key demoCA/private/cakey.pem \
        -out demoCA/careq.pem
Enter pass phrase for demoCA/private/cakey.pem:********
(中略)
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Chiba
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:AAA Corporation
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:AAA ROOT CA 2048
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
```


#### ルート認証局 BBB (root1024) で署名

```shell-session
cd ~/dir/root1024
openssl ca -config ~/dir/openssl.cnf \
        -md sha256 \
        -in      ../crossCA/demoCA/careq.pem \
        -keyfile demoCA/private/cakey.pem \
        -out     ../crossCA/demoCA/cacert.pem \
        -days 3650 -extensions v3_ca -batch -policy policy_anything
Using configuration from /home/g0117736/dir/openssl.cnf
Enter pass phrase for demoCA/private/cakey.pem:********
Check that the request matches the signature
Signature ok
(中略)
Write out database with 1 new entries
Data Base Updated
```

### サーバー証明書の確認 (クロスルート)

今、中間 CA 証明書が Apache の SSLCertificateChainFile に指定されていますが、このファイルにクロスルート証明書 ~/dir/crossCA/demoCA/cacert.pem の内容を追加書き込みします。

ルート認証局 BBB のルート証明書 ~/dir/root1024/demoCA/cacert.pem は SSL クライアントにインストールします。先にインストールしたルート認証局 AAA のルート証明書は SSL クライアントから削除しておきます。

Firefox でサーバー証明書を確認すると、以下の図のように 4 階層で構成されていることがわかります。

![tier4.png](https://qiita-image-store.s3.amazonaws.com/0/65370/330cf788-91cb-020a-520c-a4b409054d0b.png)

openssl の s_client ならば、以下のように確認することができます。

```shell-session
openssl s_client \
        -CAfile ~/dir/root1024/demoCA/cacert.pem -trusted_first \
        -connect www.example.jp:443  < /dev/null
CONNECTED(00000003)
depth=3 C = JP, ST = Chiba, O = BBB Corporation, CN = BBB ROOT CA 1024
verify return:1
depth=2 C = JP, ST = Chiba, O = AAA Corporation, CN = AAA ROOT CA 2048
verify return:1
depth=1 C = JP, ST = Chiba, O = CCC Corporation, CN = CCC Inter CA
verify return:1
depth=0 C = JP, ST = Chiba, O = "EEE CO., LTD.", CN = www.example.jp
verify return:1
---
Certificate chain
 0 s:/C=JP/ST=Chiba/O=EEE CO., LTD./CN=www.example.jp
   i:/C=JP/ST=Chiba/O=CCC Corporation/CN=CCC Inter CA
 1 s:/C=JP/ST=Chiba/O=CCC Corporation/CN=CCC Inter CA
   i:/C=JP/ST=Chiba/O=AAA Corporation/CN=AAA ROOT CA 2048
 2 s:/C=JP/ST=Chiba/O=AAA Corporation/CN=AAA ROOT CA 2048
   i:/C=JP/ST=Chiba/O=BBB Corporation/CN=BBB ROOT CA 1024
---
(中略)
    Verify return code: 0 (ok)
---
DONE
```
---