...
1# TLS/GMSSL 服务端协议自适应
2
3目录结构说明:
4
5```
6├─certs // 证书以及密钥
7├─websvr_test //HTTP服务端/客户端测试Demo
8└─websvr //协议自适应实现
9```
10
11## 服务端 GMTLS/TLS 工作逻辑
12
13
14
15
16通过配置`gmtls.Config` 对象提供自动切换相关的配置,创建`gmtls.Conn`。
17
18在对`gmtls.Conn`的`Read/Wirte`时将会触发握手行为`HandShake`。
19
20`HandShake`会根据用户配置参数,判断需要使用 GMSSL、TLS、GMSSL/TLS 三种工作模式中的哪一种,
21然后进入到相应的工作模式中运行。
22
23- **TLS工作模式**:
24 - 运行`serverHandshake` 进入TLS握手。
25 - 创建TLS握手上下文`serverHandshakeState`。
26 - 读取并处理 来自于客户端的ClientHello 消息。
27 - 进入 TLS握手流程。
28- **GMSSL工作模式**:
29 - 运行`serverHandshakeGM` 进入GMSSL握手。
30 - 创建TLS握手上下文`serverHandshakeStateGM`。
31 - 读取并处理 来自于客户端的ClientHello 消息。
32 - 进入 GMSSL握手流程。
33- **GMSSL/TLS工作模式**:
34 - 运行`serverHandshakeAutoSwitch` 进入自动切换的握手模式。
35 - 读取来自于客户端的ClientHello 消息。
36 - 分析处理ClientHello,根据客户端协议版本。
37 - 根据协议版本,选择使用具体握手方式:
38 - GMSSL: 创建上下文`serverHandshakeStateGM`,进入GMSSL握手流程。
39 - TLS: 创建上下文`serverHandshakeState`,进入TLS握手流程。
40
41
42在GMSSL/TLS模式的服务端运行过程中,如何根据客户端版本选择需要使用的证书以及密钥?
43
44自动切换模式,同时需要为服务端提供2份证书与密钥对(一份用于标准的TLS、一份用于GMSSL),
45在运行过程需要使用到`gmtls.Config#GetCertificate`方法来根据客户端的版本选择出合适的
46证书密钥对,即在客户端版本是GMSSL的时候返回SM2签名证书密钥对;在客户端版本是标准的TLS时
47返还RSA/ECC的证书密钥对,以次来动态适应不同客户端的连接需求。
48针对于GMSSL特殊的双证书需求,特别为`gmtls.Config`增加了一个方法`gmtls.Config#GetKECertificate`
49通过该方法来提供GMSSL密钥交换过程中使用密钥对。
50
51更多细节实现见: [auto_handshake_server](../auto_handshake_server.go)
52
53## GMSSL/TLS 自动切换模式
54
55快速开始:
56
571. 准备 RSA、SM2签名、SM2加密,证书以及密钥对。
582. 调用`gmtls.NewBasicAutoSwitchConfig`构造基础的配置对象。
593. Use it.
60
61```go
62func main() {
63 config, err := gmtls.NewBasicAutoSwitchConfig(&sigCert, &encCert, &rsaKeypair)
64 if err != nil {
65 panic(err)
66 }
67
68 ln, err := gmtls.Listen("tcp", ":443", config)
69 if err != nil {
70 panic(err)
71 }
72 defer ln.Close()
73
74 http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
75 fmt.Fprintf(writer, "hello\n")
76 })
77 err = http.Serve(ln, nil)
78 if err != nil {
79 panic(err)
80 }
81}
82```
83
84
85详细服务端的配置流程如下:
86
871. 准备:
88 - SM2签名密钥对、证书:`sigCert`
89 - SM2加密密钥对、证书:`encCert`
90 - RSA/ECC加密密钥对、证书:`rsaKeypair`
912. 创建一个实现`gmtls.Config#GetCertificate`方法签名的方法,方法需要根据支持的签名类型:
92 - 含有GMSSL版本:返回SM2签名证书密钥对(`sigCert`)。
93 - 不含有GMSSL版本:返回RSA签名证书密钥对(`rsaKeypair`)。
943. 创建一个实现`gmtls.Config#GetKECertificate`方法签名的方法,固定返回SM2加密证书密钥对(`encCert`)。
954. 创建`GMSupport`并启用,自动切换模式。
965. 创建`gmtls.Config`对象,接下就可以启动服务端实现自动切换功能。
97
98```go
99// Step 1:
100fncGetSignCertKeypair := func(info *gmtls.ClientHelloInfo) (*gmtls.Certificate, error) {
101 gmFlag := false
102 // 检查支持协议中是否包含GMSSL
103 for _, v := range info.SupportedVersions {
104 if v == gmtls.VersionGMSSL {
105 gmFlag = true
106 break
107 }
108 }
109 if gmFlag {
110 return &sigCert, nil
111 } else {
112 return &rsaKeypair, nil
113 }
114}
115
116fncGetEncCertKeypair := func(info *gmtls.ClientHelloInfo) (*gmtls.Certificate, error) {
117 return &encCert, nil
118}
119support := gmtls.NewGMSupport()
120support.EnableMixMode()
121config := &gmtls.Config{
122 GMSupport: support,
123 GetCertificate: fncGetSignCertKeypair,
124 GetKECertificate: fncGetEncCertKeypair,
125}
126```
127
128> 更多细节请参考: [HTTP over GMTLS/TLS Server Demo](./websvr.go)
129
130
131## 双向身份认证
132
133服务端开启双向身份认证,需要配置而外参数`ClientAuth`。
134
135建议使用`gmtls.RequireAndVerifyClientCert`表明服务端需要客户端证书请求且需要验证客户端证书。
136
137```go
138config, err := gmtls.NewBasicAutoSwitchConfig(&sigCert, &encCert, &rsaKeypair)
139if err != nil {
140 panic(err)
141}
142
143// 开启客户端的身份认证
144config.ClientAuth = gmtls.RequireAndVerifyClientCert
145```
146
147> 更多细节请参考:
148>
149> - [自适应Web服务端 Demo websvr.go #loadAutoSwitchConfigClientAuth](./websvr.go)
150
151
152
153客户端的启用双向身份认证也需要配置,只需要提供认证所使用的证书密钥对就可以。
154
155例如:
156
157```go
158config ,err = &gmtls.Config{
159 GMSupport: &gmtls.GMSupport{},
160 RootCAs: certPool,
161 Certificates: []gmtls.Certificate{authKeypair},
162 InsecureSkipVerify: false,
163}
164```
165
166> 更多细节请参考:
167>
168> - [国际算法标准 客户端 Demo websvr.go #bothAuthConfig](./websvr.go)
View as plain text