概要
TLS 1.3 は、2018 年 8 月 に RFC 8446 として、正式リリースとなりました。
OpenSSL 1.1.1 で、TLS 1.3 は正式サポートとなり、各種ソフトウェアでも実装が進むものと思われます。
Golang でも、最近 TLS 1.3 サポートが、master ブランチへマージされたようです。
Golang の次のリリースは、v1.12 が 2019 年 2 月 の見込みです。Golang では、ナイトリービルドを提供していないみたいですが、処理系のビルドはそれほど難しくないので、最新の master ブランチをビルドして、TLS 1.3 を試用してみましょう。
ビルドには、docker を使用し、試用するサーバーソフトウェアとしては、Golang で実装された HTTP サーバーである Caddy を用います。
Golang 最新版ビルド
通常であれば、Dockerfile を作成して、イメージを作成するところですが、お試しということで、volume を活用して、ビルド成果物を作成します。
docker を使用できる環境で、以下のようにコマンドを打ち込みます。
$ docker volume create --name v-go
$ docker run -it --rm -v v-go:/root/go -w /root/go -e GOROOT_BOOTSTRAP=/usr/local/go golang:1.11
# git clone https://go.googlesource.com/go .
# cd src
# ./all.bash
# exit
v-go という名前の volume に最新版の Golang がビルドされます。
Caddy ビルド
先ほどビルドした、ツールチェインを用いて、Caddy をビルドします。
$ docker volume create --name v-caddy
$ docker run -it --rm -v v-go:/usr/local/go -v v-caddy:/go golang:1.11
# go get github.com/caddyserver/builds
# cd src/github.com
# mkdir mholt
# cd mholt
# git clone https://github.com/mholt/caddy.git
# cd caddy
# git checkout -b v0.11.1 v0.11.1
# cd caddy
# go run build.go
# exit
v-caddy 内部に、Caddy がビルドされます。
次のようなコマンドで、ビルド済ファイルを取り出すことができます。
$ docker create --name v-caddy -v v-caddy:/go busybox
$ docker cp v-caddy:/go/src/github.com/mholt/caddy/caddy/caddy .
こちらのバイナリーは、TLS 1.2 までのサポートになるバージョンになりますので、caddy-tls1.2
等へリネームしておきます。
パッチあて
先ほどビルドした Caddy は、TLS 1.3 対応になっていませんので、対応させるパッチを実施します。
golang:1.11 のイメージに patch コマンドが入っていないので、buildpack-deps:stretch のイメージを使用します。
$ docker run -it --rm -v v-caddy:/go -w /go/src/github.com/mholt/caddy buildpack-deps:stretch
# curl -LO https://gist.github.com/noumia/ad9787f4c8094976221e0b3419ecafb2/raw/1f97a61215c0b31d829e4c102c420382b4c12149/caddy.patch
# patch -p1 < caddy.patch
# exit
再ビルド
パッチ後の再ビルドと、バイナリーファイル抽出は、以下のようになります。
$ docker run -it --rm -v v-go:/usr/local/go -v v-caddy:/go -w /go/src/github.com/mholt/caddy/caddy golang:1.11
# go run build.go
# exit
$ docker cp v-caddy:/go/src/github.com/mholt/caddy/caddy/caddy .
動作チェック
任意のディレクトリーへ、Caddyfile ファイル、秘密鍵、証明書ファイル等を配置します。
https://loop.example.com {
tls cert/server.crt cert/server.key
root html
}
cert/server.crt
へ証明書
cert/server.key
へ秘密鍵
html/index.html
へ配信ファイル
を展開します。
example.com
は例示ドメインなので、ご自身で使用するドメインに読み替えてください。
ここでは、*.example.com
に充当するワイルドカード証明書を用意しました。
ワイルドカード証明書は、有効なドメインをお持ちであれば、Let's Encrypt で無料で取得できます。
Caddyfile のあるディレクトリーをカレントディレクトリーとして、caddy
コマンドを起動します。
$ sudo ./caddy
クライアントでの接続チェック
別ターミナルを立ち上げて、通信チェックを行います。ここでは、OpenSSL 1.1.1 をリンクした TLS 1.3 対応の curl を使います。
>curl --version
curl 7.62.0 (x86_64-pc-win32) libcurl/7.62.0 OpenSSL/1.1.1a (WinSSL) zlib/1.2.11 brotli/1.0.7 WinIDN libssh2/1.8.0 nghttp2/1.35.0
Release-Date: 2018-10-31
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile SSPI Kerberos SPNEGO NTLM SSL libz brotli TLS-SRP HTTP2 HTTPS-proxy MultiSSL
接続します。
>curl -v https://loop.example.com
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to loop.example.com (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: C:\Sirius\.bin\curl-ca-bundle.crt
CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, [no content] (0):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, [no content] (0):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, [no content] (0):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, [no content] (0):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, [no content] (0):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=example.com
* start date: Nov 20 05:17:39 2018 GMT
* expire date: Feb 18 05:17:39 2019 GMT
* subjectAltName: host "loop.example.com" matched cert's "*.example.com"
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.3 (OUT), TLS app data, [no content] (0):
* TLSv1.3 (OUT), TLS app data, [no content] (0):
* TLSv1.3 (OUT), TLS app data, [no content] (0):
* Using Stream ID: 1 (easy handle 0x22452c620a0)
* TLSv1.3 (OUT), TLS app data, [no content] (0):
> GET / HTTP/2
> Host: loop.example.com
> User-Agent: curl/7.62.0
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, [no content] (0):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS app data, [no content] (0):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
* TLSv1.3 (OUT), TLS app data, [no content] (0):
* TLSv1.3 (IN), TLS app data, [no content] (0):
* TLSv1.3 (IN), TLS app data, [no content] (0):
* TLSv1.3 (IN), TLS app data, [no content] (0):
< HTTP/2 200
< accept-ranges: bytes
< content-type: text/html; charset=utf-8
< etag: "piucxp0"
< last-modified: Tue, 27 Nov 2018 07:32:13 GMT
< server: Caddy
< content-length: 0
< date: Tue, 27 Nov 2018 07:45:10 GMT
<
* Connection #0 to host loop.example.com left intact
TLSv1.3 というログが見えているので、うまくいったようです。
比較のために、TLS 1.3 対応パッチをあてる前のバイナリーを実行したときの接続ログは、次のようになります。
>curl -v https://loop.example.com
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to loop.example.com (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: C:\Sirius\.bin\curl-ca-bundle.crt
CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-ECDSA-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=example.com
* start date: Nov 20 05:17:39 2018 GMT
* expire date: Feb 18 05:17:39 2019 GMT
* subjectAltName: host "loop.example.com" matched cert's "*.example.com"
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x1c82c5d20a0)
> GET / HTTP/2
> Host: loop.example.com
> User-Agent: curl/7.62.0
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200
< accept-ranges: bytes
< content-type: text/html; charset=utf-8
< etag: "piucxp0"
< last-modified: Tue, 27 Nov 2018 07:32:13 GMT
< server: Caddy
< content-length: 0
< date: Tue, 27 Nov 2018 07:44:39 GMT
<
* Connection #0 to host loop.example.com left intact
TLS 1.2 にダウングレードして接続されています。