openssl オレオレ認証局で証明書発行

# openssl でオレオレ認証局で証明書を発行する

#### ubuntuバージョン  

```
$ cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Ubuntu 18.04.4 LTS"
```
#### openssl バージョン

```
$ openssl version  
OpenSSL 1.1.1  11 Sep 2018
```
## 概要  
<strong>2020/05/31 
ちょー簡単に証明書を発行してくれる mkcert という開発環境用の証明書発行ツールが存在しています。</strong>
https://github.com/FiloSottile/mkcert

何らかの理由でLetsEncryptなど無料の証明書が使えない場合とにかく開発環境でSSLを使いたい。
ルート認証局を作成し、ルートCA証明書（ルート認証局の証明書）とサーバ証明書を発行する。
ルートCA証明書は、クライアントのブラウザにインポートする。
サーバ証明書は、Webサーバにインポートする。
ルート認証局から発行したルートCA証明書とサーバ証明書を使用することでクライアント（ブラウザ）とサーバ（WEBサーバ）でSSL通信ができる。

シェルを作った。けど mkcert の方を使った方がいいと思う。
https://github.com/yutakachi/createCertificates

## ルート認証局（オレオレ認証局）を作成する  
### ルート証明局用のディレクトリを作成する
```
$ cd ~
$ mkdir -p ./rootCA/private
$ mkdir -p ./rootCA/newcerts
$ mkdir -p ./rootCA/testDomain.jp
$ mkdir -p ./rootCA/testDomain.jp/certs
$ mkdir -p ./rootCA/testDomain.jp/private
```

### 秘密鍵を作る
```
$ openssl genrsa -aes256 -out ./rootCA/private/cakey.pem 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
...................+++++
..........................................................+++++
e is 65537 (0x010001)
Enter pass phrase for ./rootCA/private/cakey.pem:任意のパスフレーズ
Verifying - Enter pass phrase for ./rootCA/private/cakey.pem:確認用のパスフレーズ
```

### CSRを作る
秘密鍵に対する公開鍵を作るための情報を作成する
(Can't load /home/a_user/.rnd into RNG のエラーがでたら。。後述)

```
$ openssl req -new -key ./rootCA/private/cakey.pem -subj "/C=JP/ST=Tokyo/L=edogawa/O=testCompany/OU=software/CN=my_rootCA/" -out ./rootCA/cacert.csr
Enter pass phrase for ./rootCA/private/cakey.pem:秘密鍵のパスフレーズ
```
-subj オプションの補足 
-subj無しの場合、対話形式で入力を求められる
/C  Country Name(2 letter code) 
/ST State or Province Name (full name) 
/L  Locality Name(eg, company) 
/O  Organization Name (eg, company) 
/OU Organization Unit Name (eg, section) 
/CN Common Name (eg, your name or your server's hostname) 
※ /CN はサーバ証明書の作成時にはドメイン名を指定する必要がある。
https://ドメイン名/xxx　一致しないとSSLのエラーとなる。

以下、注意すべきオプション。
/O Organization (認証局の組織名)　会社名とか。。　例） testCompany
ルートCA証明書をブラウザにインポートした後、確認するのでわかりやすい名前がいい。

/CN Common Name (コモンネーム)　ルート認証局の名前　例) my_rootCA
ルートCA証明書用なのでmy_rootCA としているが、サーバ証明書を作成(後述)する際は、ドメイン名にする。

##### Can't load /home/a_user/.rnd into RNG のエラーがでたら。。

```
Can't load /home/a_user/.rnd into RNG
140491206660544:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/home/a_user/.rnd
```
以下の対応をする。

```
$ sudo vim /etc/ssl/openssl.cnf

コメントアウトする
RANDFILE              = $ENV::HOME/.rnd
↓
# RANDFILE              = $ENV::HOME/.rnd
```


### ルートCA証明書(自己証明書）認証局自信が自分を証明する  
自己署名(openssl x509)することで証明する。  

```
$ openssl x509 -days 825 -in ./rootCA/cacert.csr -req -signkey ./rootCA/private/cakey.pem -out ./rootCA/cacert.pem
Signature ok
subject=C = JP, ST = Tokyo, L = edogawa, O = testCompany, OU = software, CN = my_rootCA
Getting Private key
Enter pass phrase for ./rootCA/private/cakey.pem:秘密鍵のパスフレーズ
```
補足　-days 有効期限の最長（上限）で 825日。

### 認証局に必要なファイル  
証明書発行を記録していくファイルを作成する

```
$ touch ./rootCA/index.txt
$ touch ./rootCA/index.txt.attr
$ echo 00 > ./rootCA/serial
```
ここまででルート証明局は完了。

## ブラウザにルートCA証明書をインポート
ルートCA証明書（./rootCA/cacert.pem）をインポートすることで、my_rootCAで発行されたサーバ証明書は有効なものになる。  
Chrome
ブラウザ右上点３つ > 設定 > 左メニューのプライバシーとセキュリティ > もっと見る > 証明書の管理 > インポート
windows 信用さえた認証期間タブ
Linux 認証局タブ
org-testCompany　で一覧に登録されていることを確認する。
org-は接頭語 testCompanyは、opensslの/Oオプションで設定した Organization name

Firefox
ブラウザの右上三本線 > 設定 > プライバシーとセキュリティ > 証明書（一番下）> 証明書を表示 > 認証局証明書 > インポート
testCompany で一覧に登録されていることを確認する

## Webサーバ用証明書作成
ルート認証局からWebサーバで使用する鍵や証明書を発行する

### openssl.cnf を修正する

```
$ sudo cp /etc/ssl/openssl.cnf /etc/ssl/openssl.cnf.org
$ sudo vim /etc/ssl/openssl.cnf 

[CA_default]
dir = ./rootCA

[usr_cert]
subjectAltName = @alt_names

```
### SANs拡張を使用する (subjectAltName = Subject Alternative Names)  

subjectAltNameを設定しないとブラウザで不正な証明書と認識されてしまう。
サーバ証明書に登録するドメインをtestDomain.jpとする。
今回はサブドメインにも対応できるように設定する。
san.ext を作成する。san.extは証明書を発行する際のオプション-extfileで読み込む

```
vim ./rootCA/san.ext
subjectAltName=DNS:*.testDomain.jp, DNS:testDomain.jp
```

### 秘密鍵を作成  

```
openssl genrsa -aes256 -out ./rootCA/testDomain.jp/private/privkey.pem 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
...............................+++++
.+++++
e is 65537 (0x010001)
Enter pass phrase for ./rootCA/testDomain.jp/private/privkey.pem:任意のパスフレーズ
Verifying - Enter pass phrase for ./rootCA/testDomain.jp/private/privkey.pem:確認用パスフレーズ
```

### CSR作成  
```
$ openssl req -new -key ./rootCA/testDomain.jp/private/privkey.pem -subj "/C=JP/ST=Tokyo/L=edogawa/O=testCompany/OU=software/CN=testDomain.jp/" -out ./rootCA/testDomain.jp/certs/testDomain.csr
Enter pass phrase for ./rootCA/testDomain.jp/private/privkey.pem:秘密鍵のパスフレーズを入力
```

### 証明書発行
ルート（オレオレ）認証局（openssl ca）で署名する。

```
$ openssl ca -keyfile ./rootCA/private/cakey.pem -cert ./rootCA/cacert.pem -in ./rootCA/testDomain.jp/certs/testDomain.csr -out ./rootCA/testDomain.jp/certs/testDomain.crt.pem -days 825 -outdir ./rootCA/newcerts -extfile ./rootCA/san.ext

Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./rootCA/private/cakey.pem: cakey.pemの秘密鍵のパスフレーズを入力
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 0 (0x0)
        Validity
            Not Before: Apr 15 07:51:59 2020 GMT
            Not After : Jul 19 07:51:59 2022 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = Tokyo
            organizationName          = testCompany
            organizationalUnitName    = software
            commonName                = testDomain.jp
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DNS:*.testDomain.jp, DNS:testDomain.jp
Certificate is to be certified until Jul 19 07:51:59 2022 GMT (825 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

```

ここまででサーバ証明書の作成、発行は完了  

## Webサーバへの適用  
### Apacheの場合

Apache2.4

apache ssl 設定ファイルを編集

```
vim /etc/apache2/sites-available/default-ssl.conf
<IfModule mod_ssl.c>
	<VirtualHost _default_:443>
		# ServerAdmin webmaster@localhost

		DocumentRoot /home/a_user/testDomain.jp
		ServerName gitproject
		ErrorLog ${APACHE_LOG_DIR}/error-ssl.log
		CustomLog ${APACHE_LOG_DIR}/access-ssl.log combined

		SSLEngine on

		SSLCertificateFile "/home/a_user/rootCA/testDomain.jp/certs/testDomain.crt.pem"
		SSLCertificateKeyFile "/home/a_user/rootCA/testDomain.jp/private/privkey.pem"

		<FilesMatch "\.(cgi|shtml|phtml|php)$">
		        SSLOptions +StdEnvVars
		</FilesMatch>
		<Directory /usr/lib/cgi-bin>
		        SSLOptions +StdEnvVars
		</Directory>

	</VirtualHost>
</IfModule>
```

ssl の有効化

```
$ sudo a2enmod ssl
Considering dependency setenvif for ssl:
Module setenvif already enabled
Considering dependency mime for ssl:
Module mime already enabled
Considering dependency socache_shmcb for ssl:
Enabling module socache_shmcb.
Enabling module ssl.
See /usr/share/doc/apache2/README.Debian.gz on how to configure SSL and create self-signed certificates.
To activate the new configuration, you need to run:
  systemctl restart apache2

$ sudo systemctl restart apache2
Enter passphrase for SSL/TLS keys for testDomain.jp:443 (RSA): *********
サーバ証明書を作成した際の秘密鍵のパスフレーズを入力する 　↑
```

サーバ秘密鍵のパスフレーズを確認したい場合

```
$ openssl rsa -in ./rootCA/testDomain.jp/private/privkey.pem 
Enter pass phrase for ./rootCA/testDomain.jp/private/privkey.pem:確認するパスフレーズをいれる
パスフレーズが正しければ以下のように表示される。間違っている場合、エラーとなる。
※パスフレーズが設定されていない場合は、Enter pass phrase は表示されない。
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1lD1H2Z8HIZihM/VGqCkAXNLuTCxJvGX7jduajypN+t6gAYB
RX+pWNPjkVE1G69k0RlplxF+951x1+54QZ9CuYQNbKuamfEQg5VKnn8jyhZgWfPn
QoPnQiMdUwurlBsjUE24XusdU24aXXXXXXXXXXXXXXXXXXXXX
省略。。。
-----END RSA PRIVATE KEY-----
```


### nginxの場合  
/etc/nginx/nginx.conf は直接いじらない。
sslの鍵のパスフレーズを記載したファイルを用意しておく必要がある。
Apacheの場合は、起動時に入力を求められるが、nginxの場合はエラーになる。  

```
Job for nginx.service failed because the control process exited with error code.
See "systemctl status nginx.service" and "journalctl -xe" for details.
```
パスフレーズを記載した任意のファイルを用意する。ここでは pwf　とした。  

```
vim /home/a_user/rootCA/testDomain.jp/pwf
記述内容は、SSLのパスフレーズを記述する
password01
```
default.conf の ssl_password_file に設定する

```
sudo vim /etc/nginx/conf.d/default.conf

server {
  listen 80;
  listen 443 ssl;
  ssl on;
  ssl_certificate /home/a_user/rootCA/testDomain.jp/certs/testDomain.crt.pem;
  ssl_password_file /home/a_user/rootCA/testDomain.jp/pwf;
  ssl_certificate_key /home/a_user/rootCA/testDomain.jp/private/privkey.pem;
  server_name testDomain.jp;
  access_log /home/a_user/testDomain/log/testDomain.access.log;
  location / {
    root /home/a_user/testDomain;
    index index.html;
  }
}

```

https 接続確認

ブラウザで確認

```
https://testDomain.jp/index.html
```

curlで確認

```
$ curl --cacert /home/a_user/rootCA/cacert.pem https://testDomain.jp/index.html
```

以上。