ECDSA で証明書を作成する
特に何も指定しない状態ではRSA 2048 bit 長の公開鍵ペアで証明書が作成されます。
そこを、ECDSA で作成するようにしてみます。
ECDSA で証明書を作成することで、RSA よりも短い鍵長でより高い暗号強度が得られると言われています。
構成
今回検証する環境は次のとおりです。
- 構成
OS | Fedora 23 |
---|---|
OpenSSL | 1.0.2f |
Apache | 2.4.18 |
ECDSA で公開鍵ペア(CSR) を作成する
openssl
コマンドを使用してECDSA なCSR(証明書要求) を作成します。
--csr フラグが追加され、こちら側で作成したCSR を指定できるようになりました。
そこに今回作成したECDSA なCSR を指定します。
それでは、ECDSA なCSR を作成してみましょう。
今回は/etc/letsencrypt/self
ディレクトリを独自に作成して、そこにECDSA な秘密鍵と証明書を作成していきます。
# mkdir -p /etc/letsencrypt/self/foo.example.com
# cd /etc/letsencrypt/self/foo.example.com
openssl コマンドで使える楕円曲線を確認してみます。
# openssl version
OpenSSL 1.0.2f-fips 28 Jan 2016
# openssl ecparam -list_curves
secp256k1 : SECG curve over a 256 bit prime field
secp384r1 : NIST/SECG curve over a 384 bit prime field
secp521r1 : NIST/SECG curve over a 521 bit prime field
prime256v1: X9.62/SECG curve over a 256 bit prime field
今回は比較的、証明書発行機関でも使われているprime256v1
でCSR を作成してみます。
# openssl ecparam -out private_prime256v1.key -name prime256v1 -genkey
# openssl req -new -sha256 -key private_prime256v1.key -subj "/CN=foo.example.com" -reqexts SAN -outform der -out csr_prime256v1.der -config <(
cat <<-EOF
[req]
distinguished_name = dn
[dn]
[SAN]
subjectAltName = DNS:foo.example.com
EOF
)
CSR を作成したら、CSR に対して署名を行ってもらい、証明書を作成します。
# cd /root/letsencrypt
# ./letsencrypt-auto certonly --webroot --renew-by-default --agree-tos -w /var/www/html --csr /etc/letsencrypt/self/foo.example.com/csr_prime256v1.der
Checking for new version...
Requesting root privileges to run letsencrypt...
/root/.local/share/letsencrypt/bin/letsencrypt --no-self-upgrade certonly --webroot --renew-by-default --agree-tos -w /var/www/html --csr /etc/letsencrypt/self/foo.example.com/csr_prime256v1.der
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/root/letsencrypt/0001_chain.pem. Your cert will expire on
YYYY-MM-DD. To obtain a new version of the certificate in the
future, simply run Let's Encrypt again.
- If you like Let's Encrypt, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
letsencrypt コマンドの実行が完了すると、カレントディレクトリに以下のファイルが作成されます。
0000_cert.pem # サーバ証明書
0000_chain.pem # 中間証明書
0001_chain.pem # サーバ証明書と中間証明書の連結ファイル
これらのファイルを/etc/letsencrypt/self/foo.example.com
ディレクトリに移動し、それぞれファイル名をcert.pem
, chain.pem
, fullchain.pem
というファイル名に変更します。
# mv 0000_cert.pem /etc/letsencrypt/self/foo.example.com/cert.pem
# mv 0000_chain.pem /etc/letsencrypt/self/foo.example.com/chain.pem
# mv 0001_chain.pem /etc/letsencrypt/self/foo.example.com/fullchain.pem
以上で証明書の取得は完了です。
暗号化スイートの決定
今回作成した証明書で使用できる暗号化スイートとしては、現在使用しているopenssl 1.0.2f
によると...
# openssl ciphers -v 'ECDSA'
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256
ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1
ECDHE-ECDSA-RC4-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=RC4(128) Mac=SHA1
ECDHE-ECDSA-DES-CBC3-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=3DES(168) Mac=SHA1
ECDHE-ECDSA-NULL-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=None Mac=SHA1
のようです。
ここではさらにデータの暗号化方式としてNone
, RC4
と3DES
が使われている暗号化スイートを除いていきます。
# openssl ciphers -v 'ECDSA !eNULL !3DES !RC4'
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256
ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1
上記に表示されているものを今回採用することにします。
現段階ではECDHE-ECDSA
な鍵交換 + 認証 しかないので、フィルタの書き方をECDSA
からECDHE+ECDSA
に変えておきます。
openssl ciphers -v 'ECDHE+ECDSA !eNULL !3DES !RC4'
また、保険の意味も込めて除外する暗号化スイートのフィルタをもっと追加しておきます。
結果以下のようなフィルタ定義を採用することとします。
openssl ciphers -v 'ECDHE+ECDSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4'
今回、Apache を使って設定をしていきますが、このフィルタ定義はnginx でも使えます。
ひとりごと1: RSA な証明書が対応している暗号化スイートについて
RSA な証明書が対応している暗号化スイートを確認する場合はopenssl ciphers -v 'aRSA'
を実行してみてください。
こちらのほうが、だいぶ多くの暗号化スイートの選択肢があることがわかるはずです。
そのため、古いクライアントがあなたのWeb サイトにアクセスする可能性がある場合、そのクライアントはECDSA な暗号化スイートに対応しいない可能性もある点に注意してください。
ひとりごと2:
暗号化スイートとして、より強固に、TLS1.2 系のみを使用したい場合は、メッセージ認証コード(Mac) としてSHA1 を除去するようにしてください。
フィルタの定義例としては、例えば次のようになります。
openssl ciphers -v 'ECDHE+ECDSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4 !SHA1'
ひとりごと3: Enc=None な暗号化スイート
本記事の調べごとをしていて知ったことですが、通信内容を暗号化しない通信方式も立派なSSL/TLS 通信なんですね。しかもTLS1.2 対応だしTLS1.3 の草稿にも含まれています!
「ログ見ればちゃんとTLS1.2 でやっているし安心安心〜(´ー)y-~~」とか余裕こいていると、痛い目見そうですね…。
Enc=None` な暗号化スイートは(あまり用途は思いつきませんが)、通信の暗号化は行わないが接続先の認証はしっかり行うようなケースで使用されるようです。
Web サーバへの設定
細かい手順については割愛しますが、例えばApache を使用している場合、httpd.conf の適切な場所に次のように設定してください。
<VirtualHost *:443>
ServerName foo.example.com
......
SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite "ECDHE+ECDSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"
## あなたのサイトが常時SSL (http -> https にリダイレクトする)な設定になっている場合、
## 任意でHSTS (HTTP Strict Transport Security)の設定も追加しておいてください。
# Header set Strict-Transport-Security "max-age=315360000; includeSubDomains"
SSLCertificateFile /etc/letsencrypt/self/foo.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/self/foo.example.com/private_prime256v1.key
......
</VirtualHost>
設定ファイルを書き換えたら、Apache をreload させます。
# systemctl reload httpd
確認
Web サーバに証明書を設定したら、openssl コマンドで確認してみましょう。
# openssl s_client -servername foo.example.com -connect foo.example.com:443 < <(echo QUIT)
......
New, TLSv1/SSLv3, Cipher is ECDHE-ECDSA-AES256-GCM-SHA384
Server public key is 256 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-ECDSA-AES256-GCM-SHA384
......
Verify return code: 0 (ok)
......
上記の出力結果を確認するとECDHE-ECDSA-AES256-GCM-SHA384
な暗号化スイートが使われて、署名検証にも成功していることがわかります。
上記のような結果になれば成功です。
その他
Letsencrypt 自体がまだ開発段階にあるので、おそらくここで実施した手順は今後、まだまだ変わっていくと思います。
今回、prime256v1
で公開鍵ペアを作成しましたが、secp256k1
, secp384r1
, secp521r1
なものについては未検証。
参考
-
Eliptic Curve Cryptography (ECC) Support
-
ECDSA対応CSRを生成して、Let's Encryptをつかう場合
-
ECDSA testing on staging
-
Enabling Perfect Forward Secrecy
-
Wikipedia - Transport Layer Security