在《TLS 1.3 当前(2018.10)支持与部署之现状》中,我们提到 Go 将在 1.12 中支持 TLS 1.3. 作为一个 Gopher, 终于在前几天盼来了 golang 1.12 的发布。
但是从 release 日志看,本次对选择性的部分支持 TLS 1.3, 且默认处于关闭状态:
Go 1.12 adds opt-in support for TLS 1.3 in the crypto/tls package as specified by RFC 8446. It can be enabled by adding the value tls13=1 to the GODEBUG environment variable. It will be enabled by default in Go 1.13.
如果要开启 TLS 1.3, 需要设置环境变量:GODEBUG=tls13=1
.
本次发布的 TLS 1.3 的 cipher suite 无法配置,也不支持 0-RTT 模式:
TLS 1.3 cipher suites are not configurable. All supported cipher suites are safe, and if PreferServerCipherSuites is set in Config the preference order is based on the available hardware.
Early data (also called “0-RTT mode”) is not currently supported as a client or server.
要知道,没有 0-RTT 的 TLS 1.3 是没有灵魂的,对本次版本的失望那是肯定的。但是依然在第一时间升级了 Go 版本,简单测试了一下国内网络环境下 TLS 1.3 与 1.2 的握手延迟。如果对 TLS 1.3 握手延迟还不太熟悉,可以参见拙文《TLS1.3/QUIC 是怎样做到 0-RTT 的》 以及 TLS 1.3 Handshake Protocol.
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
package main import ( "crypto/tls" "flag" "log" "time" ) const ( MaxInt = int(^uint(0) >> 1) MinInt = -MaxInt - 1 ) func main() { var testCnt int flag.IntVar(&testCnt, "c", 10, "test count") flag.Parse() testAddr := "blog.cloudflare.com:443" // tls 1.2 config := &tls.Config{ SessionTicketsDisabled: true, MaxVersion: tls.VersionTLS12, } min12, max12, avg12 := testTLS(testCnt, testAddr, config) log.Printf("tls 1.2 dial, min:%dms, max:%dms, avg:%dms", min12/1e6, max12/1e6, avg12/1e6) // tls 1.3 config.MaxVersion = tls.VersionTLS13 min13, max13, avg13 := testTLS(testCnt, testAddr, config) log.Printf("tls 1.3 dial, min:%dms, max:%dms, avg:%dms", min13/1e6, max13/1e6, avg13/1e6) log.Printf("tls 1.3 vs 1.2: min:%.02f, max:%.02f, avg:%.02f", float32(min13)/float32(min12), float32(max13)/float32(max12), float32(avg13)/float32(avg12)) } func testTLS(testCnt int, addr string, config *tls.Config) (min, max, avg int) { min = MaxInt max = MinInt total := 0 for i := 0; i < testCnt; i++ { hsStartTime := time.Now() conn, err := tls.Dial("tcp", addr, config) if err != nil { log.Fatalf("make tls connection failed:%v", err) } dialCost := int(time.Since(hsStartTime).Nanoseconds()) if dialCost > max { max = dialCost } if dialCost < min { min = dialCost } total += dialCost state := conn.ConnectionState() log.Printf("tls version:%#v", state.Version) conn.Close() } avg = total / testCnt return } |
需要说明的是,这个测试是不严谨,里面没有考虑 cipher suite 以及 early data 的差异。测试结果定性意义大于定量意义。
测试结果
测试使用的目标服务器地址是 blog.cloudflare.com:443
, 我的网络环境下,ping 延迟为 226 ms (1-RTT).
1 2 3 4 5 6 7 8 9 |
root@host:~/tmp# GODEBUG=tls13=1 go run tlst.go -c 20 2019/03/03 00:06:44 tls version:0x303 ... 2019/03/03 00:07:02 tls 1.2 dial, min:497ms, max:2977ms, avg:952ms 2019/03/03 00:07:02 tls version:0x304 ... 2019/03/03 00:07:17 tls 1.3 dial, min:320ms, max:2176ms, avg:755ms 2019/03/03 00:07:17 tls 1.3 vs 1.2: min:0.64, max:0.73, avg:0.79 |
1 2 3 4 5 6 7 8 |
const ( VersionSSL30 = 0x0300 VersionTLS10 = 0x0301 VersionTLS11 = 0x0302 VersionTLS12 = 0x0303 VersionTLS13 = 0x0304 ) |
从结果看,有如下结论:
- TLS 1.3 平均比 TLS 1.2 建立连接的延迟低约 1-RTT, 跟理论分析是吻合的。但是,
- 从 max 项可以看出,部分时候国内到目标服务器网络不稳定带来的波动比 TLS 本身协议优化的 RTT 大的多。因此,稳定高延迟的网络链路有时候比低延迟高抖动的网络更有实际意义。
- TLS 建立在 TCP 基础上,TCP 的握手延迟在 TLS 层面是优化不掉的,或者说不是 TLS 的管辖范围,因此,在允许的情况下,尽量复用连接。