Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

支持TLS传输国密 #290

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open

Conversation

springrain
Copy link
Contributor

Description

What is the purpose of the change?

基于 github.com/tjfoc/gmsm 实现TLS传输加密,使用双证书模式,实际是一个证书对象,slice里放了两次,简化操作

Fixes # (issue)

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

Brief of your solution

基于 github.com/tjfoc/gmsm 实现TLS传输加密,使用双证书模式,实际是一个证书对象,slice里放了两次,简化操作

@@ -20,32 +26,79 @@ import (
"github.com/xuperchain/xupercore/kernel/network/config"
)

// serverName 为key,缓存 creds
var serverNameMap = make(map[string]credentials.TransportCredentials)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

全局变量的读写最好加锁进行保护

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好的

}

//如果缓存中有值
if creds, ok := serverNameMap[serviceName]; ok {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

serverNameMap 对应性能等没有实质性的作用,反而增加了代码的复杂度。
TransportCredentials 的使用包括两种场景

  1. 服务端: Accept 完成 TCP 三次握手之后,调用 Server 对象上的 opts.creds 完成SSL 握手中的服务端部分,不会重复加载TransportCredentials
  2. 客户端: 底层采用 HTTP2 长链接,同一个服务端只有一个连接,不需要重复加载TransportCredentials,serverNameMap 缓存 基本处于缓存不命中的情况,对性能等没有实质性的帮助

func NewTLS(path, serviceName string) (credentials.TransportCredentials, error) {

if len(serviceName) < 1 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

去掉 ServerName 为空的判断,标准库TLS 是允许ServerName 为空的
ServerName 为空时,标准库中 SSL 握手的证书为

  • 客户端: 根据连接时根据 dial 的 addr 判断自动推断 ServerName
  • 服务端: 不需要 ServerName 字段
    gmtls 的逻辑应该也类似,可以进一步确认

if !ok {
return nil, err
}
certificate, err := tls.LoadX509KeyPair(filepath.Join(path, "cert.pem"), filepath.Join(path, "private.key"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gmtls 中的 x509 证书兼容标准的 RSA x509 解析,同一个证书只需要加载和解析一次,可以参考官方示例
https://github.com/tjfoc/gmsm/blob/fdaa5ff368db5ce62bb672fc424b23f8923858dc/gmtls/websvr/websvr.go#L52

ClientAuth: tls.RequireAndVerifyClientCert,
})
return creds, nil
if strings.Contains(strings.ToLower(x509cert.SignatureAlgorithm.String()), "sm") { //国密
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

修改判断是否使用国密的逻辑,区分客户端和服务端
客户端通过配置项选择是否使用国密,或者通过本地证书判断支持的密码学套件
服务端支持支持加载多个证书,根据 SSL 握手时协商的结果选择对应的密码学套件
理由如下

SSL/TLS 握手区分服务端和客户端,具体流程如图所示
image

其中,ClientHello 结构中包含了客户端支持的加密套件,服务端根据自身的支持的加密套件和客户端支持的加密套件返回对应的加密套件协商结果。

ClientHello 字段参考下图
image

客户端是否使用国密可以通过以下方案判断

  1. 通过配置项来判断是否使用国密
  2. 通过判断证书类型确定是否使用国密。
    值得注意的是,在商用密码系列算法中,SM2为公钥加密, SM3 为哈希算法,SM4 为分组加密。gmtls 支持SM2,SM3,SM4 其中只有SM2 可能出现在证书的 PublicKeyAlgorithm 字段,而不必要使字符串比较。

服务端通过如下方案
服务端在收到 Client 服务端在 ClientHello 信息之后,会通过 ClientHelloHello 信息之后,会通过 ClientHello 中的 SupportedVersions 字段决定是否使用国密。

certPool := x509.NewCertPool()
ok := certPool.AppendCertsFromPEM(bs)
if !ok {
cacert, err := ioutil.ReadFile(filepath.Join(path, "cacert.pem"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bs 和 cacert 是同样的内容,不需要重复读取

@codecov-commenter
Copy link

Codecov Report

Merging #290 (7e4c02c) into master (dcc1e24) will decrease coverage by 0.15%.
The diff coverage is 0.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #290      +/-   ##
==========================================
- Coverage   45.81%   45.65%   -0.16%     
==========================================
  Files         138      138              
  Lines       12284    12307      +23     
==========================================
- Hits         5628     5619       -9     
- Misses       5504     5534      +30     
- Partials     1152     1154       +2     
Impacted Files Coverage Δ
kernel/network/p2p/util.go 0.00% <0.00%> (ø)
bcs/network/p2pv1/conn.go 55.10% <0.00%> (-6.13%) ⬇️
bcs/contract/xvm/code_manager.go 63.63% <0.00%> (-2.73%) ⬇️
bcs/consensus/tdpos/schedule.go 42.98% <0.00%> (-0.91%) ⬇️
bcs/network/p2pv2/server.go 52.40% <0.00%> (+1.06%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update dcc1e24...7e4c02c. Read the comment docs.

return nil, err
}

certificate, err := defaulttls.LoadX509KeyPair(filepath.Join(path, "cert.pem"), filepath.Join(path, "private.key"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

通 70 行 comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants