ECDSAなSSL証明書を作ってみる

よく使われているRSA暗号方式からECC(楕円曲線暗号)に変えると、同程度の強度のRSAと較べて鍵長が短くなってサーバ側の鍵認証のsign処理が速くなる。クライアント側の鍵認証のverify処理は少し遅くなるようだがトータルでは速くなると考えて良さそう。なによりサーバ側が軽くなるのが良い。
ちなみにRSAで鍵長が1024bitから2048bitになって数倍の処理、何年か後に4096bitになったらまたその数倍の処理が必要になるのだが、ECCだと256bitでRSAの3072bit相当と言われている。10年とかそれ以上の有効期間の長いEE証明書を使うならともかく5年以下のEE証明書でアホみたいにRSAで鍵長を4096bitにする人は殆どいないと思うけど、2048bitでもちょっと重いかなと思うことがあるので軽めのP-256でRSAの2048bitよりずっと暗号強度が高いというのは良いわぁ。

そこで楕円曲線DSA(ECDSA)でSSL証明書を作ってみる。

CSR発行まで

現在インストールされているopensslで使える楕円曲線暗号の種類を確認

% openssl ecparam -list_curves

おそらくprime256v1, secp384r1, secp521r1はある筈。(それがこの記事の前提)
ほかにもドバッと出ている筈だけどウェブサーバとブラウザで使い物になる組み合わせが割りと限られてるので上の3つ(実際はsecp521r1を除く2つ)を確認。

サーバ鍵の生成
X9.62/SECG curve over a 256 bit prime field (P-256)
% openssl ecparam -name prime256v1 -genkey -out server.key

NIST/SECG curve over a 384 bit prime field (P-384)
% openssl ecparam -name secp384r1 -genkey -out server.key

NIST/SECG curve over a 521 bit prime field (P-521)
% openssl ecparam -name secp521r1 -genkey -out server.key

普通はSuite BのP-256かP-384で。P-521はChromeで使えなくなっているので選ばないこと。
そして実行するとほぼ一瞬で作成される。また、RSAのサーバ鍵の作成時とは違いパスワードの入力を求められない。

server.keyの確認
% openssl ec -in server.key -text
CSR発行
% openssl req -new -sha256 -key server.key -out server.csr

作成したCSRをCA(認証局)に送ってEE証明書を発行して貰う。
ECDSAなCSRは受け付けられないということはない筈。

Apache

Apache2.4ではRSAとECDSAのハイブリッド証明書が使えるので既存のRSA証明書の記述そのままでECDSAの証明書を追記する。(4行)
もちろん、RSA証明書が無いならECDSAの証明書だけで構わない(2行)。ただしブラウザの互換性の問題はあるのでハイブリッドがお勧め。

1
2
3
4
SSLCertificateFile	/PATH/RSAの証明書.crt
SSLCertificateKeyFile	/PATH/RSAのサーバ鍵.key
SSLCertificateFile	/PATH/ECDSAの証明書.crt
SSLCertificateKeyFile	/PATH/ECDSAのサーバ鍵.key
暗号化スイートを指定する。
1
2
3
4
5
簡略化して書くとおそらくRSA優先になるかと。(未確認)
SSLCipherSuite 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'

もしくはECDSA優先なハイブリッドで下のようなの。
SSLCipherSuite 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128:AES256:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK'

せっかくなので?ECDSAだけにしたいというなら下。(参考)

1
2
3
4
5
SSLCipherSuite 'AESGCM+ECDSA' #AEADだけ
#実質ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256と同じ
または
SSLCipherSuite 'AES+ECDSA:-SSLv3';   #上よりちょっと広め
#実質ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256と同じ
楕円曲線暗号の種類を指定。(Apache2.4)
1
2
3
4
5
SSLOpenSSLConfCmd ECDHParameters prime256v1
SSLOpenSSLConfCmd Curves prime256v1
または
SSLOpenSSLConfCmd ECDHParameters secp384r1
SSLOpenSSLConfCmd Curves secp384r1

Nginx

Nginx 1.9.15以上ではRSAとECDSAのハイブリッド証明書が使えるので既存のRSA証明書の記述そのままでECDSAの証明書を追記する。(4行)
もちろん、RSA証明書が無いならECDSAの証明書だけで構わない(2行)。ただしブラウザの互換性の問題はあるのでハイブリッドがお勧め。

1
2
3
4
ssl_certificate		/PATH/RSAの証明書.crt;
ssl_certificate_key	/PATH/RSAのサーバ鍵.key;
ssl_certificate		/PATH/ECDSAの証明書.crt;
ssl_certificate_key	/PATH/ECDSAのサーバ鍵.key;
暗号化スイートの指定。
1
2
3
4
5
#簡略化して書くとおそらくRSA優先になるかと。
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

#もしくはECDSA優先なハイブリッドで下のようなの。
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128:AES256:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK';

せっかくなので?ECDSAだけにしたいというなら下。(参考)

1
2
3
4
5
ssl_ciphers   'AESGCM+ECDSA'; #AEADだけ
#実質ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256と同じ
または
ssl_ciphers   'AES+ECDSA:-SSLv3';   #上よりちょっと広め
#実質ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256と同じ
楕円曲線暗号の種類を指定も忘れずに。(nginx 1.9.15以上)
1
2
3
ssl_ecdh_curve  prime256v1;
#または
ssl_ecdh_curve	secp384r1;

動作確認

ECDSAなSSL証明書 1
例によってQualys SSL LABSのSSL Server Testで確認。
サマリのすぐ下、Authenticationの最初の項目でKey(暗号鍵)がEC ***bitsになっていること。上の画像はprime256v1の暗号鍵で作成した証明書なのでEC 256bitsとなっている。
secp384r1の暗号鍵で作成した証明書ならEC 384bitsとなる。
署名アルゴリズムの欄(この記事とおりに作成していればsha256RSAの筈)と見間違えないこと。

ECDSAなSSL証明書 2
もう少し下のConfigurationの欄の下段。ECDSA証明書だけでウェブサーバを公開すると使える暗号スイートが限られる。上の画像の例では4つだけというお寒いものに。ブラウザとの互換性で厳しい。そこでRSAの証明書とECDSAの証明書のハイブリッドにするとブラウザとの互換性が改善する。

ECDSAなSSL証明書 3
ブラウザのChromeで証明書を確認する。
注目するのは上の画像のリストの「公開キー」と「公開キーのパラメーター」
上の画像の証明書はprime256v1の暗号鍵で作成されているのでECC(256 Bits), ECDSA_P256になっている。
secp384r1の暗号鍵で作成した証明書ならECC(384 Bits), ECDSA_P384になる。

関連記事: