Featured image of post Gmtls

Gmtls

一个使用国密双向认证的demo 示例

双向认证


最近的一个项目合规要求使用国密算法实现双向认证,这里就将国密和常见的X509 RSA 的双向认证的实现都分享一下

RSA 双向认证

 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
import (
    "crypto/tls"
    "crypto/x509"
    "io/ioutil"
    "net"
)
func UseX509TLS(carootpath,certpath,keypath string)(*tls.Config,error){
    certPool := x509.NewCertPool()
    cacert, err := ioutil.ReadFile(carootpath)
    if err != nil {
        return nil, err
    }
    certPool.AppendCertsFromPEM(cacert)
    authKeypair, err := tls.LoadX509KeyPair(certpath, keypath)
    if err != nil {
        return nil, err
    }
    return &tls.Config{
        MaxVersion:         tls.VersionTLS12,
        RootCAs:            certPool,
        Certificates:       []tls.Certificate{authKeypair},
        InsecureSkipVerify: false,
    }, nil
}

func ClientConn(addr string)(*net.Conn,error){
    // 三个分别是 ca证书路径,客户端证书路径,客户端私钥路径
    cfg,err := UseX509TLS("ca.crt","client.crt","client.key")
    //
    conn,err := tls.Dial("tcp", addr, cfg)
    if err!= nil{
        return nil, err
    }
    return &conn, nil
}

这里的客户端证书和密钥是给服务端用于认证客户端的身份,同时使用指定的ca 根证书 这里用在mqtt 上就很简单了,甚至不用写连接创建的函数opts.SetTLSConfig(tlsConfig) 里面将tls 配置进去,mqtt 库会自动完成

国密双向认证

这里就比较复杂一些了,因为目前go 的标准库的暂不支持国密认证,需要使用github.com/tjfoc/gmsm 这个仓库,来建立国密认证连接,仅配置tls 是不行的,需要

 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

func GMTLSDialer(broker string, ca, key, cert string) (net.Conn, error) {
	cfg, err := BothAuthConfig(ca, key, cert)
	if err != nil {
		return nil, err
	}
	addr := broker
	if strings.HasPrefix(broker, "mqtt://") {
		addr = broker[7:]
	}
	fmt.Printf("addr: %s\n", addr)
	conn, err := gmtls.Dial("tcp", addr, cfg)
	if err != nil {
		return nil, err
	}
	return conn, nil
}

func BothAuthConfig(ca, key, cert string) (*gmtls.Config, error) {
	// 信任的根证书
	certPool := x509.NewCertPool()
	cacert, err := os.ReadFile(ca)
	if err != nil {
		return nil, err
	}
	certPool.AppendCertsFromPEM(cacert)
	authKeypair, err := gmtls.LoadX509KeyPair(cert, key)
	if err != nil {
		return nil, err
	}
	return &gmtls.Config{
		GMSupport:          &gmtls.GMSupport{},
		RootCAs:            certPool,
		Certificates:       []gmtls.Certificate{authKeypair},
		InsecureSkipVerify: false,
	}, nil

}

func MqttOpenConnectionFn(uri *url.URL, options mqtt.ClientOptions) (net.Conn, error) {
	return cert.GMTLSDialer(cfg.Mqtt.Addr, 
                            "ca.crt",
                            "client.crt",
                            "client.key"
                            )
}

最后如何在mqtt 中使用呢opts.SetCustomOpenConnectionFn(MqttOpenConnectionFn) 这样就行

Licensed under CC BY-NC-SA 4.0
往日已经不在,未来尚未开始
使用 Hugo 构建
主题 StackJimmy 设计