FreeNAS 9.3 jail + h2o でオレオレ認証局

[FreeNAS9.3 + h2o の環境]( http://qiita.com/katz_engineer/items/bc61ac926107d2118de2)でいわゆるオレオレ認証局を作りました。今更なネタですが、これを FreeBSD + h2o でやってる所に目新しさがあるかな。多分あると思う。あるんじゃないかな。ま、ちょっと覚悟はしておこう…

…h2oはあんまり関係無いけど☆

ところでオレオレ認証局の正式名称は何と言うんでしょうか？プロトコル上はルート認証局で、内輪向けを意識すると自己認証局？プライベート認証局？

# 参考文献
手順は下記Webページを参考にさせていただきました。いずれもぐぐれば上の方にヒットします。

[自己署名証明書](http://www.wirednoize.net/freebsd/index.php?%E8%87%AA%E5%B7%B1%E7%BD%B2%E5%90%8D%E8%A8%BC%E6%98%8E%E6%9B%B8)
[OpenSSLでの自己認証局(CA)と自己証明書の作成](http://www015.upp.so-net.ne.jp/unixlife/practical/openssl.html)

# インストール
FreeBSD には最初から openSSL が組み込まれていますので、黙ってこれを使います。

なお私の環境では、自分サイトのファイル類は ```/media/www``` 以下に置く事にしていますので、認証局の各種ファイルはその下の ```/media/www/ssl``` に置く事にします。

# 認証局の作成
中二病全開で「俺の考えた最強の認証局」を作ります。←この言い方気に入りました:grin:

そしてデフォルトの置き場所 ```./demoCA``` は気に入らないので ```/media/www/ssl/ca``` に変更します。これがどうも、オプションスイッチで変更できないようなので…:persevere: 

```
# cd /usr/local/openssl/misc
# mv CA.sh CA.sh.org
# cp -p CA.sh.org CA.sh
# vi CA.sh
《編集内容は下記diffを参照》
# diff -U0 CA.sh.org CA.sh
--- CA.sh.org   2015-12-17 21:45:46.000000000 +0900
+++ CA.sh       2015-12-29 20:18:04.056739932 +0900
@@ -63,2 +63,2 @@
-if [ -z "$DAYS" ] ; then DAYS="-days 365" ; fi # 1 year
-CADAYS="-days 1095"    # 3 years
+if [ -z "$DAYS" ] ; then DAYS="-days 36500" ; fi       # 100 year
+CADAYS="-days 36500"   # 100 years
@@ -71 +71 @@
-if [ -z "$CATOP" ] ; then CATOP=./demoCA ; fi
+if [ -z "$CATOP" ] ; then CATOP=/media/www/ssl/ca ; fi
# cd /etc/ssl
# mv openssl.cnf openssl.cnf.org
# cp -p openssl.cnf.org openssl.cnf
# vi openssl.cnf
《編集内容は下記diffを参照》
# diff -U0 openssl.cnf.org openssl.cnf
--- openssl.cnf.org     2014-07-11 08:50:16.000000000 +0900
+++ openssl.cnf 2015-12-29 22:52:31.767742583 +0900
@@ -38 +38 @@
-dir            = ./demoCA              # Where everything is kept
+dir            = /media/www/ssl/ca     # Where everything is kept
@@ -69 +69 @@
-default_days   = 365                   # how long to certify for
+default_days   = 36500                 # how long to certify for
@@ -71 +71 @@
-default_md     = sha1                  # which md to use.
+default_md     = sha256                # which md to use.
@@ -102 +102 @@
-default_bits           = 1024
+default_bits           = 2048
# /usr/local/openssl/misc/CA.sh -newca
CA certificate filename (or enter to create) 《黙ってenterだけ押します》

Making CA certificate ...
Generating a 2048 bit RSA private key
..................+++
...........................+++
writing new private key to '/media/www/ssl/ca/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) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Certificate Authority
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:Certificate Authority
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/ssl/openssl.cnf
Enter pass phrase for /media/www/ssl/ca/private/./cakey.pem: 《パスフレーズ入力》
```

上記の各入力欄にはそれぞれ環境に合わせた文字列を入力してください。最後のパスフレーズを入力したら、画面一杯に証明書の内容が表示されて溢れます…

一応は内容を確認しましょう。

```
# openssl x509 -in /media/www/ssl/ca/cacert.pem -text | less
```

問題無ければ、ブラウザへの配布用にバイナリ化します。

```
# openssl x509 -in /media/www/ssl/ca/cacert.pem -outform DER -out /media/www/ssl/ca/cacert.der
```

# 署名要求書の作成と署名
まずは公開サーバとして署名要求書を作ります。作業場所としては ```/media/www/ssl``` 内にFQDNと同じ名前のディレクトリを作成する事にします。

```
# mkdir /media/www/ssl/test.example.com
# cd /media/www/ssl/test.example.com
```

以下ここで作業。

```
# /usr/local/openssl/misc/CA.sh -newreq
Generating a 2048 bit RSA private key
.............................+++
...........+++
writing new private key to 'newkey.pem'
Enter PEM pass phrase: 《パスフレーズ入力、省略不可、後で削除するので最短の4文字を適当に》
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) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:.
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:test.example.com
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
```

オレオレ認証局として要求書に署名します。

```
# /usr/local/openssl/misc/CA.sh -sign
Using configuration from /etc/ssl/openssl.cnf
Enter pass phrase for /media/www/ssl/ca/private/cakey.pem: 《認証局のパスフレーズ》
《証明書内容の表示》

Certificate is to be certified until Dec  5 12:03:24 2115 GMT (36500 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
《内容表示》
Signed certificate is in newcert.pem
```

最後に秘密鍵 newkey.pem のパスフレーズを削除します。奪われても実害の無い鍵ですからいいでしょう。それよりも、Webサービスの再起動の度にパスフレーズを要求されたらたまりません。その辺は労力と効果を天秤に掛けましょう。

```
# /usr/local/bin/openssl rsa -in newkey.pem -out newkey-withoutpass.pem
WARNING: can't open config file: /usr/local/openssl/openssl.cnf
Enter pass phrase for newkey.pem: 《署名要求書を作成した時のパスフレーズ》
writing RSA key
```

# サーバへの設定と確認

うちのhttpサーバは h2o です。

```/usr/local/etc/h2o/h2o.conf
user: www
pid-file: /var/run/h2o.pid
access-log: /var/log/h2o/h2o-access.log
error-log: /var/log/h2o/h2o-error.log

file.custom-handler:
  extension: .php
  fastcgi.spawn: "PHP_FCGI_CHILDREN=3 exec /usr/local/bin/php-cgi"

hosts:
  test.example.com:
    listen:
      port: 443
      ssl:
        certificate-file: /media/www/ssl/test.example.com/newcert.pem
        key-file: /media/www/ssl/test.example.com/newkey-withoutpass.pem
    paths:
      "/":
        file.dir: "/media/www/test"
```

設定ファイルを修正したらサーバ再起動を忘れずに。証明書などを修正した場合も再起動が必要です。

```
# /usr/local/etc/rc.d/h2o restart
```

# ブラウザ

この段階で https://test.example.com/index.php にアクセスすると「証明書は信頼できない」的なメッセージが表示されてブロックされます。強引に閲覧を指示すると、渋々ながらも表示してくれます:stuck_out_tongue_winking_eye:

ここで、オレオレ認証局の証明書をバイナリ化した cacert.der をブラウザに取り込みます。まずは jail 内で作ったファイルをクライアントマシンにコピーする方法ですが、 FreeNAS のストレージ内にあるファイルなのでどうにでも出来ますよね。FreeNAS のシェルを起動し、該当パスをたどり、共有用ディレクトリを適当に見繕ってコピーします。そうしたらクライアントマシンからは普通のファイル共有でコピーできるはず。

cacert.der をクライアントマシンに持ってきたら、次にブラウザへの導入です。その手順はブラウザの手順を調べてください。ひとまず IE なら、手順に従って「信頼されたルート証明機関」にインポートします。世界的に信頼されているルート証明機関と肩を並べます。なんかカッコいいぞ。っていうか IE は使うのやめましょう、とにかく色々と世界標準から外れているので:sweat:

そして再度 https://test.example.com/index.php にアクセスすると、今度は文句を言わずに素直に表示してくれます。やった！:+1: