Go 1.12 TLS 1.3 簡單測試
在《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 .
測試程式碼
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).
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
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 的管轄範圍,因此,在允許的情況下,儘量複用連線。
–EOF–