自己証明書でSSL通信を実装する手順

手順なので、認証局や自己証明書についての説明はあまりしていない。 
ただの自己証明書でSSL通信を実装する手順。

## SSL 通信実装
### 環境
- OS : CentOS 6

環境はgcpのVMインスタンスを使用しており、インスタンスイメージは「CentOS 6」を使用している。
### 準備するもの
- ドメイン 

本記事では、`fmbrain.work`という個人取得のドメインを使用する。 

### 概要
CentOSに入っているApacheでたてられたWebサイトを自己証明書を使ってSSL化する。 

### 秘密鍵の作成
```
$ openssl genrsa 2048 > /etc/httpd/conf/server.key
```
RSA秘密鍵を2048bitの鍵長で作成する。
RSA秘密鍵の拡張子は`.key` や`.pem`がよく使用されている。

```
$ cat server.key | openssl rsa -text
```
一応、作成した秘密鍵を確認しておく。

```
$ sudo chmod 600 server.key
```
今、作成した秘密鍵はrootのみで参照できるように権限を変更する。  


### CSRの作成

CSRは、サーバーの情報とさっき作成した秘密鍵とペアの公開鍵が入る。    

```
$ openssl req -new -key /etc/httpd/conf/server.key > /etc/httpd/conf/server.csr
> Country Name (2 letter code) [XX]:JP
> State or Province Name (full name) []:Kanagawa
> Locality Name (eg, city) [Default City]:Yokohama
> Organization Name (eg, company) [Default Company Ltd]:(Enter)
> Organizational Unit Name (eg, section) []:(Enter)
> Common Name (eg, your name or your server's hostname) []:fmbrain.work
> Email Address []:dozo13189@gmail.com
> Please enter the following 'extra' attributes
> to be sent with your certificate request
> A challenge password []:(Enter)
> An optional company name []:(Enter)
```

`openssl req`で、CSRの作成要求をして、`-key`でインプットとなる秘密鍵を指定する。
`-new`は、新しい鍵の生成を意味する。
入力を求められているCSRに書くサーバー情報は、ドメインのwhois情報と一致される必要があるが(一致しないと認証局は署名してくれないはず)、今回は自己証明書なのでCommon Nameだけ取得したドメインを書いておけば、後はどうでもいい。  

```
openssl req -new -days 365 -sha256 -key /etc/httpd/conf/server.key > /etc/ httpd/conf/server.csr
```
さっきのCSRの発行コマンドだと、有効期限が短く、ハッシュ関数も脆弱なため、実用に耐えれないので、ちゃんと指定する。 
CSRの有効期限を365日にするために`-days 365`を指定し、ハッシュ関数は`-sha256`で指定している。有効期限は、引数の指定なしだと30日になり、ハッシュ関数は引数の指定なしだとsha1になる。  

```
cat /etc/httpd/conf/server.csr | openssl req -text
```
生成したCSRの確認をする。  

```
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=JP, ST=Kanagawa, L=Yokohama, CN=fmbrain.work/emailAddress=xxxxxx@gmail.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ...省略
                Exponent: 65537 (0x10001)
        Attributes:
            challengePassword        :unable to print attribute
    Signature Algorithm: sha256WithRSAEncryption
        ...省略
-----BEGIN CERTIFICATE REQUEST-----
...省略
-----END CERTIFICATE REQUEST-----
```
`Subject`に入力したサーバーの情報が書かれている。Common Name(=CN)だけちゃんと見ておく。 
`Subject Public Key Info`にCSR生成に使用した秘密鍵とペアの公開鍵が書かれている。`Subject Public Key Info`に書かれている公開鍵に対して認証局は署名を行う。署名がされれば、`Subject Public Key Info`の公開鍵が`Subject`に入力したサーバーのものであるという証明になる。 
`Signature Algorithm`には、公開鍵暗号とハッシュ関数のアルゴリズムが書かれている。 
例では、`sha256WithRSAEncryption`と記載されているため、`sha256`のハッシュ関数、`RSA`の公開鍵暗号方式であることがわかる。 
`-----BEGIN CERTIFICATE REQUEST-----`から`-----END CERTIFICATE REQUEST-----`は、PEM形式で記述された実際のCSRになる。

### 自己証明書
本来は作成したCSRを元に認証局に証明書を作成してもらうことになる。 
今回は自己証明書のため、作成したCSRを元に自分で証明書を作成する。

```
$ openssl x509 -req -signkey /etc/httpd/conf/server.key < /etc/httpd/conf/server.csr > /etc/httpd/conf/server.crt
```
`x509`は、標準証明書フォーマットを意味している。(RFCのドキュメント参照) 
[https://www.ipa.go.jp/security/rfc/RFC5280-03JA.html#031](https://www.ipa.go.jp/security/rfc/RFC5280-03JA.html#031)
`openssl x509 -req`は、フォーマット`x509`の証明書を作成する、という意味になる。  
パブリック証明書を作成する場合は、`server.csr`を認証局に送り、認証局の秘密鍵で署名をしてもらうはず。 今回は、`-signkey server.key`で、自分の秘密鍵を使用して署名しているため、`server.crt`は自己証明書となる。 
自己証明書なので`server.csr`に書かれている公開鍵は、`fmbrain.work`の公開鍵であると、`fmbrain.work`が言っている、ことになる。  

```
$ cat /etc/httpd/conf/server.crt | openssl x509 -text
```
生成された証明書を確認する。 
これで自己証明書の作成が完了したため、これをApacheに設定して、通信をSSL化していく。

## Apacheの設定

ApacheはCentOSにデフォルトでインストールされているものを使用する。  

### index.html
```
$ vim /var/www/html/index.html
> <p>hello world</p>
```

### httpd.conf
```
sudo vim /etc/httpd/conf/httpd.conf
> ServerAdmin dozo13189@gmail.com
> ServerName fmbrain.work:443
# Listen 443は削除する。ポートは`ssl.conf`で設定する。
> Listen 443
```
DocumentRootはデフォルトで"/var/www/html"のはずなので、変更はない。
DirectoryIndexもデフォルトで、index.htmlが設定されているはずなので、/var/www/html/index.htmlが読み込まれる。 
ServerAdminは適当に何か書いて(サーバー管理者のメールアドレスが推奨)、ServerNameにドメインを書き、接続ポートも合わせて書く。  

### ssl.conf
```
$ vim /etc/httpd/conf.d/ssl.conf
# Listen 443があることを確認する。
> Listen 443
> SSLCertificateFile /etc/httpd/conf/server.crt
> SSLCertificateKeyFile /etc/httpd/conf/server.key
```
SSLCertificateFileに証明書のパスを設定して、SSLCertificateKeyFileには秘密鍵のパスを設定する。
これでSSL通信をする最低限の設定は完了したので、Apacheを再起動する。

### Apacheの起動
```
$ service httpd status
> httpd is stopped

$ service httpd status
httpd (pid  13529) is running...
```

ドメインにアクセスする。(プロトコルはhttpではなく、httpsでアクセスする)  

<img width="755" alt="fmbrain.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606419/7837a8e5-0b21-84c9-5ec1-9dfedd2ac6f7.png">


アクセス後は、このサイトが使用している証明書は正しい認証局が署名したものではないため、警告が出る。(正しい認証局は、ブラウザに信頼された認証局として登録されており、登録されていない認証局が署名していない証明書が使用されている場合は、このように警告が出る。つまり、これが正しい挙動)  

### トラブルシューティング
エラーが発生した場合のトラブルシューティング。

```
ErrorLog logs/error_log
```
`httpd.conf`にエラーログの場所が書いてある。

```
$ tail -n 100 /var/log/httpd/error_log
```
エラーログを見よう。

```
$ apachectl configtest
> Syntax OK
```
Apacheのconfigファイルのシンタックスが正しいかどうかは、上記のコマンドで確認できるらしい。

## この接続ではプライバシーが保護されません問題

自己証明書でSSL化されたサイトへのアクセスは、信頼された認証局が署名した証明書ではないため、当然、ブラウザはそれを警告する。 
これを解決方法を書いておく。

### 解決方法1(作成した自己証明書をChromeに設定する)

ブラウザに「この証明書は信頼できる」ということを設定する方法。
[https://blog.fileshelfplus.com/vps/312](https://blog.fileshelfplus.com/vps/312)

### 解決方法2(SANを設定する)

解決方法1では、chromiumベースのブラウザは問題が解決できない。(chromeなど) 
理由は、IEやEdgeの場合は、証明書のCN(Common Name)とアクセスするドメインが同一であれば問題ないが、chromeの場合は、CNではなくSANのDNS Nameの値と同一にする必要がある、ということらしい。 
SANは、Subject Alternative Nameの略。 
SANのDNS Nameは、CRT(証明書)に追加情報として書くことができる。 
面倒だが、もう一度、CRT(証明書)を作り直し、作り直すときに追加オプションコマンドを指定する。  

```
$ vim san.txt
> subjectAltName = DNS:fmbrain.work
```
ファイル名は何でもいいので、SANを書く。

```
$ openssl x509 -req -signkey server.key -extfile san.txt < server.csr > server.crt
```
`-extfile`でSANを書いたファイルを指定して、CRT(証明書)を作成する。


```
$ cat server.crt | openssl x509 -text
> X509v3 extensions:
>     X509v3 Subject Alternative Name: 
>         DNS:fmbrain.work
```
作成したCRT(証明書)を確認すると、`X509v3 extensions`にSANが書かれている。
このCRT(証明書)をApacheに設定しなおして、再起動して、ブラウザにも設定し直してやると、「この接続ではプライバシーが保護されません問題」は解決する。

## 参考
食べる！SSL！　―HTTPS環境構築から始めるSSL入門(小島 拓也; 中嶋 亜美; 吉原 恵美; 中塚 淳. )

[https://www.ipentec.com/document/windows-chrime-error-net-err-cert-common-name-invalid-using-ssl-certificate-signed-with-local-ca](https://www.ipentec.com/document/windows-chrime-error-net-err-cert-common-name-invalid-using-ssl-certificate-signed-with-local-ca)

[https://qiita.com/nis_nagaid_1984/items/b8f87d41ea108d47af61](https://qiita.com/nis_nagaid_1984/items/b8f87d41ea108d47af61)