Help us understand the problem. What is going on with this article?

Let's Encrypt の証明書をECDSA(ECC: 楕円曲線暗号)で作成する

More than 3 years have passed since last update.

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 を作成してみます。

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 に対して署名を行ってもらい、証明書を作成します。

letsencryptコマンドで証明書を作成する
# 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 によると...

opensslciphers
# 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, RC43DES が使われている暗号化スイートを除いていきます。

# 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 に変えておきます。

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 の適切な場所に次のように設定してください。

SSL/TLS周りの設定例
<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 させます。

Apachereload
# systemctl reload httpd

確認

Web サーバに証明書を設定したら、openssl コマンドで確認してみましょう。

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 なものについては未検証。

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした