TLS/GMSSL 服务端协议自适应
目录结构说明:
├─certs // 证书以及密钥
├─websvr_test //HTTP服务端/客户端测试Demo
└─websvr //协议自适应实现
服务端 GMTLS/TLS 工作逻辑
通过配置gmtls.Config
对象提供自动切换相关的配置,创建gmtls.Conn
。
在对gmtls.Conn
的Read/Wirte
时将会触发握手行为HandShake
。
HandShake
会根据用户配置参数,判断需要使用 GMSSL、TLS、GMSSL/TLS 三种工作模式中的哪一种,
然后进入到相应的工作模式中运行。
- TLS工作模式:
- 运行
serverHandshake
进入TLS握手。
- 创建TLS握手上下文
serverHandshakeState
。
- 读取并处理 来自于客户端的ClientHello 消息。
- 进入 TLS握手流程。
- GMSSL工作模式:
- 运行
serverHandshakeGM
进入GMSSL握手。
- 创建TLS握手上下文
serverHandshakeStateGM
。
- 读取并处理 来自于客户端的ClientHello 消息。
- 进入 GMSSL握手流程。
- GMSSL/TLS工作模式:
- 运行
serverHandshakeAutoSwitch
进入自动切换的握手模式。
- 读取来自于客户端的ClientHello 消息。
- 分析处理ClientHello,根据客户端协议版本。
- 根据协议版本,选择使用具体握手方式:
- GMSSL: 创建上下文
serverHandshakeStateGM
,进入GMSSL握手流程。
- TLS: 创建上下文
serverHandshakeState
,进入TLS握手流程。
在GMSSL/TLS模式的服务端运行过程中,如何根据客户端版本选择需要使用的证书以及密钥?
自动切换模式,同时需要为服务端提供2份证书与密钥对(一份用于标准的TLS、一份用于GMSSL),
在运行过程需要使用到gmtls.Config#GetCertificate
方法来根据客户端的版本选择出合适的
证书密钥对,即在客户端版本是GMSSL的时候返回SM2签名证书密钥对;在客户端版本是标准的TLS时
返还RSA/ECC的证书密钥对,以次来动态适应不同客户端的连接需求。
针对于GMSSL特殊的双证书需求,特别为gmtls.Config
增加了一个方法gmtls.Config#GetKECertificate
通过该方法来提供GMSSL密钥交换过程中使用密钥对。
更多细节实现见: auto_handshake_server
GMSSL/TLS 自动切换模式
快速开始:
- 准备 RSA、SM2签名、SM2加密,证书以及密钥对。
- 调用
gmtls.NewBasicAutoSwitchConfig
构造基础的配置对象。
- Use it.
func main() {
config, err := gmtls.NewBasicAutoSwitchConfig(&sigCert, &encCert, &rsaKeypair)
if err != nil {
panic(err)
}
ln, err := gmtls.Listen("tcp", ":443", config)
if err != nil {
panic(err)
}
defer ln.Close()
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "hello\n")
})
err = http.Serve(ln, nil)
if err != nil {
panic(err)
}
}
详细服务端的配置流程如下:
- 准备:
- SM2签名密钥对、证书:
sigCert
- SM2加密密钥对、证书:
encCert
- RSA/ECC加密密钥对、证书:
rsaKeypair
- 创建一个实现
gmtls.Config#GetCertificate
方法签名的方法,方法需要根据支持的签名类型:
- 含有GMSSL版本:返回SM2签名证书密钥对(
sigCert
)。
- 不含有GMSSL版本:返回RSA签名证书密钥对(
rsaKeypair
)。
- 创建一个实现
gmtls.Config#GetKECertificate
方法签名的方法,固定返回SM2加密证书密钥对(encCert
)。
- 创建
GMSupport
并启用,自动切换模式。
- 创建
gmtls.Config
对象,接下就可以启动服务端实现自动切换功能。
// Step 1:
fncGetSignCertKeypair := func(info *gmtls.ClientHelloInfo) (*gmtls.Certificate, error) {
gmFlag := false
// 检查支持协议中是否包含GMSSL
for _, v := range info.SupportedVersions {
if v == gmtls.VersionGMSSL {
gmFlag = true
break
}
}
if gmFlag {
return &sigCert, nil
} else {
return &rsaKeypair, nil
}
}
fncGetEncCertKeypair := func(info *gmtls.ClientHelloInfo) (*gmtls.Certificate, error) {
return &encCert, nil
}
support := gmtls.NewGMSupport()
support.EnableMixMode()
config := &gmtls.Config{
GMSupport: support,
GetCertificate: fncGetSignCertKeypair,
GetKECertificate: fncGetEncCertKeypair,
}
更多细节请参考: HTTP over GMTLS/TLS Server Demo
双向身份认证
服务端开启双向身份认证,需要配置而外参数ClientAuth
。
建议使用gmtls.RequireAndVerifyClientCert
表明服务端需要客户端证书请求且需要验证客户端证书。
config, err := gmtls.NewBasicAutoSwitchConfig(&sigCert, &encCert, &rsaKeypair)
if err != nil {
panic(err)
}
// 开启客户端的身份认证
config.ClientAuth = gmtls.RequireAndVerifyClientCert
更多细节请参考:
客户端的启用双向身份认证也需要配置,只需要提供认证所使用的证书密钥对就可以。
例如:
config ,err = &gmtls.Config{
GMSupport: &gmtls.GMSupport{},
RootCAs: certPool,
Certificates: []gmtls.Certificate{authKeypair},
InsecureSkipVerify: false,
}
更多细节请参考: