Node v12でTLS v1.3を試す

先日リリースされたNode v12はTLS v1.3に対応しているらしい。というわけで早速試してみた。

サーバ証明書の作成

まずテスト用に自己署名サーバ証明書を作成する。ここでは楕円曲線secp521r1*1のecdsaの秘密鍵を作成した。鍵を作成できるサブコマンドは何種類かあるようだが、今は genpkey サブコマンドが推奨されているらしい。

openssl genpkey -algorithm EC -out server.key -pkeyopt ec_paramgen_curve:secp521r1

次に作成した秘密鍵からCSRを作成する。各種パラメータの入力を求められるが、Common Name を localhost として、それ以外は適当に入力しておく。

openssl req -new -key server.key -out server.csr

CSRに自己署名する。自己署名の場合 -signkey で秘密鍵を指定するらしい。

openssl x509 -req -signkey server.key -days 30 -sha256 -in server.csr -out server.pem 

server.pemが証明書、server.keyが秘密鍵

テストサーバ実装

Node.jsでTLS v1.3対応のhttpsサーバを書く。ドキュメントのサンプルコード通りで問題ないが多少手を加えている。

const https = require("https");
const fs = require('fs');

const options = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.pem'),
  maxVersion: 'TLSv1.3',
  minVersion: 'TLSv1.3',
  ciphers: 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'
};

https.createServer(options, (req, res) => {
  res.writeHead(200, {"Content-Type": "text/html"});
  res.end('<html>Hello TLS 1.3</html>\n');
}).listen(8443, (err) => {
  if (err) {
    console.log(err);
    process.exit(1);
  }
  console.log("listen 8443")
});

optionsのkeyに先ほど作成した秘密鍵、certにサーバ証明書を指定する。TLSv1.3のみで接続するため、maxVersionとminVersionにTLSv1.3を指定する。minVersionのデフォルトはTLSv1.2、maxVersionはTLSv1.3らしい。ciphersには以下の3つの暗号スイートを指定した。TLS v1.3で使用できるのはこの3つしかない。

  • TLS_AES_256_GCM_SHA384
  • TLS_CHACHA20_POLY1305_SHA256
  • TLS_AES_128_GCM_SHA256

CHACHA20_POLY1305という暗号はあまり聞きなれないが、暗号界隈のスーパーヒーロー、ダニエル・バーンスタインが開発し、Googleが一押ししているストリーム暗号である。

接続

最新のFirefoxChromeSafariで使えない楕円曲線で証明書を作ってしまったのでFirefoxのみ・・・)であればTLS v1.3で接続できるが、ブラウザで見ても違いがわからないのでopensslコマンドで接続

openssl s_client -connect localhost:8443 -tls1_3

以下のような出力があり、TLSv1.3で接続できているらしいことが確認できる

Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384

上記コマンドはTLSハンドシェイクしか行わず、HTTPリクエストは送られていない。入力待ちになっているのでGET / とタイプし、改行を2回打ってHTTPリクエストを送ろう。

GET /

HTTP/1.1 200 OK
Content-Type: text/html
Date: Sun, 28 Apr 2019 16:55:36 GMT
Connection: close

<html>Hello TLS 1.3</html>
closed

HTTPレスポンスが得られました。

*1:ChromeSafariはsecp521r1をサポートしていないためエラーになります。prime256v1, secp384r1で作成すると接続できます