TLS Protocol Analysis

概述

IEFT 在 SSL v3.0 的基础上制定了 SSL 的互联网标准版本,称为传输层安全(Transport Layer Security, TLS)协议。其目标是使 SSL 更安全,并使协议的规范更精确和完善。IEFT 在后续发布的 RFC 中建议禁用 SSL。

TLS 主要经历了 4 个版本:TLS 1.0 (RFC2246, 1999年),TLS 1.1(RFC4346, 2006年),TLS 1.2 (RFC5246, 2008年),TLS 1.3(RFC8446, 2018年)。

TLS 协议

协议栈体系结构

TLS 握手

TLS v1.2 的握手流程如下图所示,假设使用基于 RSA 的密钥交换算法:

ClientHello 消息中的密码套件(cipher suite) 参数格式如下(TLS v1.2):

参考 Analyze TLS and mTLS Authentication with Wireshark

Demo 测试

本节使用 Go 建立基于 TLS 的 C/S 通信,并使用 wireshark 解析通信协议报文。

生成证书

为了使用 TLS,我们首先需要生成一系列 TLS 证书。由于我们不是部署到生产环境,我们可以使用自签名证书;反之,我们需要从一个可信的 CA 获取证书。

a. 生成私钥

1
$ openssl genrsa -out server.key 2048

b. 生成自签名证书

1
$ openssl req -new -x509 -key server.key -out server.crt -days 365 -addext "subjectAltName = DNS:localhost"

编写 server 端代码

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
package main

import (
"bufio"
"crypto/tls"
"fmt"
"log"
"net"
)

func main() {
cert, err := tls.LoadX509KeyPair("certificates/server.crt", "certificates/server.key")
if err != nil {
log.Fatal(err)
}
fmt.Println("Server start listening on port 443")
ln, err := tls.Listen("tcp", ":443", &tls.Config{Certificates: []tls.Certificate{cert}})
if err != nil {
log.Fatal(err)
return
}
defer ln.Close()
for {
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
continue
}
go handler(conn)
}
}

func handler(conn net.Conn) {
defer conn.Close()
r := bufio.NewReader(conn)
for {
msg, err := r.ReadString('\n')
if err != nil {
log.Println(err)
return
}
fmt.Println(msg)
_, err = conn.Write([]byte("world\n"))
if err != nil {
log.Println(err)
return
}
}
}

编写 client 端代码

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
package main

import (
"crypto/tls"
"fmt"
"log"
)

func main() {
conn, err := tls.Dial("tcp", "localhost:443", &tls.Config{InsecureSkipVerify: true})
if err != nil {
log.Fatal(err)
}
defer conn.Close()
_, err = conn.Write([]byte("Hello\n"))
if err != nil {
log.Fatal(err)
}
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(buf[:n]))
}

TLS扩展和高级特性

TLS 协议不仅提供基本的加密和身份认证功能,还包括多种扩展和高级特性,这些特性可以优化性能、增强安全性,或支持特定的安全场景。

SNI

SNI(Server Name Indication) 扩展允许多个域名共享同一个 IP 地址和端口,但同时使用不同的证书。在 Go 中,可以通过 tls.configNameToCertificate 字段来实现 SNI。

1
2
3
4
5
6
config := &tls.Config {
NameToCertificate: map[string]*tls.Certificate {
"example.com" : cert1,
"example.org" : cert2
}
}

ALPN

ALPN(Application-Layer Protocol Negotiation) 扩展允许客户端和服务器在 TLS 握手过程中协商应用层协议(如 HTTP)。在 Go 的 tls.config 中,可以设置 NextProtos 来实现 ALPN。

1
2
3
config := &tls.Config {
NextProtos: []string{"h2", "http/1.1"}
}