PKI の基本と SSL証明書と OpenSSL コマンド
目的
- 自分の備忘録
- しらべごとのまとめ
対象
- SSL証明書、なんとなく使ってるけど実はよく分かってない
- ググった先のコマンドコピペで自己証明書作ったりはできる、けど
- 手順が書いてあればファイルを配置してコンフィグ編集してSSL化はできる、けど
内容
-
- PKI とはなにか?
-
- SSL証明書を準備しよう
- 自己証明書
- Route53 + Let's Encrypt
-
- テストしてみよう
- openssl コマンドを使ってみよう(s_server, s_client)
- SSL ハンドシェイク
- TLS バージョンと Cipher(サイファー)強度 と 脆弱性
References
- IPA: https://www.ipa.go.jp/security/pki/index.html
- SSLハンドシェイク: http://itpro.nikkeibp.co.jp/article/COLUMN/20071012/284445/
1. PKI とはなにか?
PKI とは 公開鍵認証基盤 (Public Key Infrastructure) のこと
まず、以下のドキュメントを読もう。(ありがとう新野さん)
話のキーになるのは4ページ目
つまり、
- 情報の送信元(サーバー)は 証明書(Cert File) と 公開鍵(Public Key) を相手(クライアント)に渡す
- クライアントは、受け取った 証明書(Cert File) を見て信頼できると確認できたら、もらった 公開鍵(Public Key) で暗号化して送信元へ情報を渡す
- 送信元は受け取ったデータと、もともと持っていた 秘密鍵(Private Key) を使って暗号化を解いて情報を参照する
(共通鍵とSSLハンドシェイクについては後述する)
自己証明書を作ったことがある人はわかると思うが、いろいろと中間ファイル含めて作成するが大事なのは、
サーバの持ち物: 秘密鍵 (Private Key)
クライアントの持ち物: 証明書 (Cert File), 公開鍵 (Public Key)
だ。そこで、
「"公開"とは書いてあるが"鍵"をそんな簡単にクライアントに渡していいの?」
「秘密鍵はサーバー側で完全に管理しなければならないのに、公開鍵はいいの?」
という疑問を抱くかもしれないが、なんの問題もない。
公開鍵を使って暗号化した情報は、秘密鍵 のみで復号化できるからだ。
2. SSL証明書を準備しよう
- 自己証明書
- 正規のSSL証明書(無料)
2-1. 自己証明書の作成
ref. http://qiita.com/akito1986/items/8eb41f5a43bb9421ae79
自己証明書の利用には注意
可能なら無料もあるので正規の証明書を使いたいところ
- -subj オプションを使うことで非対話にすることが可能です。
openssl genrsa -out ca-privatekey.pem 2048
openssl req -new -key ca-privatekey.pem -out ca-csr.pem \
-subj "/C=JP/ST=Tokyo/O=Test Company/OU=IT Department/CN=ssl.example.com"
openssl req -x509 -key ca-privatekey.pem -in ca-csr.pem -out ca-crt.pem -days 3560
openssl genrsa -out server-privatekey.pem
openssl req -new -key server-privatekey.pem -out server-csr.pem \
-subj "/C=JP/ST=Tokyo/O=Test Company/OU=IT Department/CN=ssl.example.com"
openssl x509 -req -CA ca-crt.pem -CAkey ca-privatekey.pem -CAcreateserial -in server-csr.pem -out server-crt.pem -days 3650
- Serverに置くファイル
- server-crt.pem
- server-privatekey.pem
- クライアントに置くファイル
- ca-crt.pem
2-2. 正規のSSL証明書(無料)
2017 現在、無料でSSL証明書を取得できます。有名なのな以下の2つでしょうか。
-
AWS の ACM(AWS Certificate Manager)
-
Let's Encrypt
今回は AWS 以外での利用も可能なように Let's Encrypt を利用します
1) まずは ドメイン名 を取得します。.net などであれば年額1000円程度(US$11.0)で取得可能です。
-
今回は AWS の Route53 で取得し管理します。
-
今回は test-domain.net を取得したとします。
2) 恒久的なグローバルIPをもったサーバーもしくは仮想マシンを準備します。
-
今回は GCP 上に CentOS7 VM を用意しました。
- Static な External IP アドレスを取得しVMにアサインします。
-
ホスト名は FQDN で www.test-domain.net とします。
3) Let's Encrypt で証明書を作成します。
- https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-centos-
- https://www.linode.com/docs/security/ssl/install-lets-encrypt-to-create-ssl-certificates
sudo yum update -y
sudo yum install epel-release
sudo yum install certbot git
sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
cd /opt/letsencrypt
sudo -H ./letsencrypt-auto certonly --standalone -d www.test-domain.net
sudo ls -al /etc/letsencrypt/live/www.test-domain.net/fullchain.pem
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/www.test-domain.net/fullchain.pem. Your cert
will expire on 2017-04-07. To obtain a new or tweaked version of
this certificate in the future, simply run letsencrypt-auto again.
To non-interactively renew *all* of your certificates, run
"letsencrypt-auto renew"
- If you lose your account credentials, you can recover through
e-mails sent to *****@gmail.com.
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
sudo ls /etc/letsencrypt/live
www.test-domain.net
sudo ls /etc/letsencrypt/live/www.test-domain.net
cert.pem chain.pem fullchain.pem privkey.pem
3. 証明書をテストする
3-1. openssl コマンドを使ってみよう(s_server, s_client)
- ref.
- man s_client
- man s_server
sudo openssl s_server -key \
> /etc/letsencrypt/live/www.test-domain.net/privkey.pem \
> -cert /etc/letsencrypt/live/www.test-domain.net/cert.pem \
> -accept 443 -www -state -debug
echo "Q" | openssl s_client -connect localhost:443 -state -debug
-
ブラウザからアクセスしてみましょう。
-
以下のように緑の鍵アイコンが表示されていれば有効な証明書でHTTPS通信できています。
-
テストが終わったら openssl コマンドで実行している s_server セッションを Ctrl + c で終了させておきます。
3-2. SSL ハンドシェイク
- IPA: https://www.ipa.go.jp/security/pki/index.html
- SSLハンドシェイク: http://itpro.nikkeibp.co.jp/article/COLUMN/20071012/284445/
- https://tools.ietf.org/html/rfc5246#page-33
クライアント側の動きは上で実行した openssl s_client コマンドから確認できます。
$ sudo echo "Q" | openssl s_client -connect localhost:443 -state 2>&1 | grep SSL_
SSL_connect:before/connect initialization
SSL_connect:SSLv2/v3 write client hello A
SSL_connect:SSLv3 read server hello A
SSL_connect:SSLv3 read server certificate A
SSL_connect:SSLv3 read server key exchange A
SSL_connect:SSLv3 read server done A
SSL_connect:SSLv3 write client key exchange A
SSL_connect:SSLv3 write change cipher spec A
SSL_connect:SSLv3 write finished A
SSL_connect:SSLv3 flush data
SSL_connect:SSLv3 read server session ticket A
SSL_connect:SSLv3 read finished A
- サーバ側も同様
$ sudo openssl s_server -key \
> /etc/letsencrypt/live/www.test-domain.net/privkey.pem \
> -cert /etc/letsencrypt/live/www.test-domain.net/cert.pem \
> -accept 443 -www -state 2>&1 | grep SSL_
SSL_accept:before/accept initialization
SSL_accept:SSLv3 read client hello A
SSL_accept:SSLv3 write server hello A
SSL_accept:SSLv3 write certificate A
SSL_accept:SSLv3 write key exchange A
SSL_accept:SSLv3 write server done A
SSL_accept:SSLv3 flush data
SSL_accept:SSLv3 read client key exchange A
SSL_accept:SSLv3 read finished A
SSL_accept:SSLv3 write session ticket A
SSL_accept:SSLv3 write change cipher spec A
SSL_accept:SSLv3 write finished A
SSL_accept:SSLv3 flush data
3-3. TLS バージョンと Cipher(サイファー)強度 と 脆弱性
-
TL;DR 端的に言うと、そのときに利用可能な最新の openssl バージョンを利用することで強度の高い Cipher Suite(暗号アルゴリズムの組み合わせ)を利用することができ、 すくなくとも利用開始時点でより安全な SSL/TLS 環境を構築することができる、ということ。
-
openssl のバージョン確認
-
リリース
-
サーバ上
$ openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013
$ rpm -q openssl
openssl-1.0.1e-60.el7.x86_64
- 利用可能な Cipher Suite
ref. man ciphers
$ openssl ciphers -v ECDH+aRSA+HIGH
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256
ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1
ECDHE-RSA-DES-CBC3-SHA SSLv3 Kx=ECDH Au=RSA Enc=3DES(168) Mac=SHA1
- どの Cipher Suite を使うべきかは IPA のガイドラインを参照して参考にしても良いと思います。
- 例えばクライアント側の環境が古いなどでサーバ側の暗号化強度を高い方で制限しにくい場合などもあり、弱めから強いのまで幅広く対応せざるを得ないこともあります。
おまけ
-
RFC 5077
- Transport Layer Security (TLS) Session Resumption without Server-Side State
- https://tools.ietf.org/html/rfc5077
-
https://techblog.yahoo.co.jp/infrastructure/ssl-session-resumption/
所感: 端的に言うとサーバーサイドのキャッシュ保持が不要になるため、分散環境などで有効かもしれません。あと、キャッシュサイズの増加の心配もなくなりそうなので適切な利用が進むと良いのではないかと思います。