gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/gmtls/tls_test/tls_test.go (about)

     1  // Copyright (c) 2022 zhaochun
     2  // gmgo is licensed under Mulan PSL v2.
     3  // You can use this software according to the terms and conditions of the Mulan PSL v2.
     4  // You may obtain a copy of Mulan PSL v2 at:
     5  //          http://license.coscl.org.cn/MulanPSL2
     6  // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
     7  // See the Mulan PSL v2 for more details.
     8  
     9  package tls_test
    10  
    11  import (
    12  	"errors"
    13  	"fmt"
    14  	"io/ioutil"
    15  	"net"
    16  	"net/http"
    17  	"testing"
    18  	"time"
    19  
    20  	"gitee.com/zhaochuninhefei/gmgo/gmtls"
    21  	"gitee.com/zhaochuninhefei/gmgo/x509"
    22  	"gitee.com/zhaochuninhefei/zcgolog/zclog"
    23  )
    24  
    25  //goland:noinspection GoUnusedConst
    26  const (
    27  	SM2CaCertPath   = "./certs/sm2_ca_cert.cer"
    28  	SM2AuthCertPath = "./certs/sm2_auth_cert.cer"
    29  	SM2AuthKeyPath  = "./certs/sm2_auth_key.pem"
    30  	sm2SignCertPath = "./certs/sm2_sign_cert.cer"
    31  	sm2SignKeyPath  = "./certs/sm2_sign_key.pem"
    32  	sm2UserCertPath = "./certs/sm2_auth_cert.cer"
    33  	sm2UserKeyPath  = "./certs/sm2_auth_key.pem"
    34  
    35  	ecdsaCaCertPath   = "./certs/ecdsa_ca_cert.cer"
    36  	ecdsaAuthCertPath = "./certs/ecdsa_auth_cert.cer"
    37  	ecdsaAuthKeyPath  = "./certs/ecdsa_auth_key.pem"
    38  	ecdsaSignCertPath = "./certs/ecdsa_sign_cert.cer"
    39  	ecdsaSignKeyPath  = "./certs/ecdsa_sign_key.pem"
    40  	ecdsaUserCertPath = "./certs/ecdsa_auth_cert.cer"
    41  	ecdsaUserKeyPath  = "./certs/ecdsa_auth_key.pem"
    42  
    43  	ecdsaextCaCertPath   = "./certs/ecdsaext_ca_cert.cer"
    44  	ecdsaextAuthCertPath = "./certs/ecdsaext_auth_cert.cer"
    45  	ecdsaextAuthKeyPath  = "./certs/ecdsaext_auth_key.pem"
    46  	ecdsaextSignCertPath = "./certs/ecdsaext_sign_cert.cer"
    47  	ecdsaextSignKeyPath  = "./certs/ecdsaext_sign_key.pem"
    48  	ecdsaextUserCertPath = "./certs/ecdsaext_auth_cert.cer"
    49  	ecdsaextUserKeyPath  = "./certs/ecdsaext_auth_key.pem"
    50  )
    51  
    52  func TestMain(m *testing.M) {
    53  	go ServerRun(true)
    54  	time.Sleep(5 * time.Second)
    55  	m.Run()
    56  }
    57  
    58  var end chan bool
    59  
    60  func Test_tls13_sm2(t *testing.T) {
    61  	end = make(chan bool, 64)
    62  	go ClientRunTls13("sm2")
    63  	<-end
    64  	fmt.Println("Test_tls13 over.")
    65  }
    66  
    67  func Test_tls13_ecdsa(t *testing.T) {
    68  	end = make(chan bool, 64)
    69  	go ClientRunTls13("ecdsa")
    70  	<-end
    71  	fmt.Println("Test_tls13 over.")
    72  }
    73  
    74  func Test_tls13_ecdsaext(t *testing.T) {
    75  	end = make(chan bool, 64)
    76  	go ClientRunTls13("ecdsaext")
    77  	<-end
    78  	fmt.Println("Test_tls13 over.")
    79  }
    80  
    81  func Test_gmssl_sm2(t *testing.T) {
    82  	end = make(chan bool, 64)
    83  	go ClientRunGMSSL("sm2")
    84  	<-end
    85  	fmt.Println("Test_gmssl_sm2 over.")
    86  }
    87  
    88  func Test_gmssl_ecdsa(t *testing.T) {
    89  	end = make(chan bool, 64)
    90  	go ClientRunGMSSL("ecdsa")
    91  	<-end
    92  	fmt.Println("Test_gmssl_ecdsa over.")
    93  }
    94  
    95  func Test_gmssl_ecdsaext(t *testing.T) {
    96  	end = make(chan bool, 64)
    97  	go ClientRunGMSSL("ecdsaext")
    98  	<-end
    99  	fmt.Println("Test_gmssl_ecdsaext over.")
   100  }
   101  
   102  // 启动服务端
   103  func ServerRun(needClientAuth bool) {
   104  	err := zclog.ClearDir("logs")
   105  	if err != nil {
   106  		panic(err)
   107  	}
   108  	zcgologConfig := &zclog.Config{
   109  		LogFileDir:        "logs",
   110  		LogFileNamePrefix: "tlstest",
   111  		LogMod:            zclog.LOG_MODE_LOCAL,
   112  		LogLevelGlobal:    zclog.LOG_LEVEL_DEBUG,
   113  	}
   114  	zclog.InitLogger(zcgologConfig)
   115  	// 导入tls配置
   116  	config, err := loadServerConfig(needClientAuth)
   117  	if err != nil {
   118  		panic(err)
   119  	}
   120  	// 定义tls监听器
   121  	ln, err := gmtls.Listen("tcp", ":50052", config)
   122  	if err != nil {
   123  		zclog.Println(err)
   124  		return
   125  	}
   126  	defer func(ln net.Listener) {
   127  		err := ln.Close()
   128  		if err != nil {
   129  			panic(err)
   130  		}
   131  	}(ln)
   132  
   133  	// 定义http请求处理
   134  	http.HandleFunc("/test", func(writer http.ResponseWriter, request *http.Request) {
   135  		clientName := request.URL.Query().Get("clientName")
   136  		fmt.Printf("接受到来自 %s 的http请求...\n", clientName)
   137  		// 在http响应中写入内容
   138  		_, err := fmt.Fprintf(writer, "你好, %s ! \n", clientName)
   139  		if err != nil {
   140  			panic(err)
   141  		}
   142  	})
   143  
   144  	// 在tls监听器上开启https服务
   145  	err = http.Serve(ln, nil)
   146  	if err != nil {
   147  		panic(err)
   148  	}
   149  }
   150  
   151  func ClientRunGMSSL(certType string) {
   152  	// 创建客户端本地的证书池
   153  	certPool := x509.NewCertPool()
   154  	var cacert []byte
   155  	var cert gmtls.Certificate
   156  	// 客户端优先曲线列表
   157  	var curvePreference []gmtls.CurveID
   158  	// 客户端优先密码套件列表
   159  	var cipherSuitesPrefer []uint16
   160  	// 客户端优先签名算法
   161  	var sigAlgPrefer []gmtls.SignatureScheme
   162  	var err error
   163  	switch certType {
   164  	case "sm2":
   165  		// 读取sm2 ca证书
   166  		cacert, err = ioutil.ReadFile(SM2CaCertPath)
   167  		// 读取User证书与私钥,作为客户端的证书与私钥,一般用作密钥交换证书。
   168  		// 但如果服务端要求查看客户端证书(双向tls通信)则也作为客户端身份验证用证书,
   169  		// 此时该证书应该由第三方ca机构颁发签名。
   170  		cert, _ = gmtls.LoadX509KeyPair(sm2UserCertPath, sm2UserKeyPath)
   171  		curvePreference = append(curvePreference, gmtls.Curve256Sm2)
   172  		cipherSuitesPrefer = append(cipherSuitesPrefer, gmtls.TLS_SM4_GCM_SM3)
   173  	case "ecdsa":
   174  		// 读取ecdsa ca证书
   175  		cacert, err = ioutil.ReadFile(ecdsaCaCertPath)
   176  		// 读取User证书与私钥,作为客户端的证书与私钥,一般用作密钥交换证书。
   177  		// 但如果服务端要求查看客户端证书(双向tls通信)则也作为客户端身份验证用证书,
   178  		// 此时该证书应该由第三方ca机构颁发签名。
   179  		cert, _ = gmtls.LoadX509KeyPair(ecdsaUserCertPath, ecdsaUserKeyPath)
   180  		curvePreference = append(curvePreference, gmtls.CurveP256)
   181  		cipherSuitesPrefer = append(cipherSuitesPrefer, gmtls.TLS_AES_128_GCM_SHA256)
   182  		sigAlgPrefer = append(sigAlgPrefer, gmtls.ECDSAWithP256AndSHA256)
   183  	case "ecdsaext":
   184  		// 读取ecdsaext ca证书
   185  		cacert, err = ioutil.ReadFile(ecdsaextCaCertPath)
   186  		// 读取User证书与私钥,作为客户端的证书与私钥,一般用作密钥交换证书。
   187  		// 但如果服务端要求查看客户端证书(双向tls通信)则也作为客户端身份验证用证书,
   188  		// 此时该证书应该由第三方ca机构颁发签名。
   189  		cert, _ = gmtls.LoadX509KeyPair(ecdsaextUserCertPath, ecdsaextUserKeyPath)
   190  		curvePreference = append(curvePreference, gmtls.CurveP256)
   191  		cipherSuitesPrefer = append(cipherSuitesPrefer, gmtls.TLS_AES_128_GCM_SHA256)
   192  		sigAlgPrefer = append(sigAlgPrefer, gmtls.ECDSAEXTWithP256AndSHA256)
   193  	default:
   194  		err = errors.New("目前只支持sm2/ecdsa/ecdsaext")
   195  	}
   196  	if err != nil {
   197  		zclog.Fatal(err)
   198  	}
   199  	// 将ca证书作为根证书加入证书池
   200  	// 即,客户端相信持有该ca颁发的证书的服务端
   201  	certPool.AppendCertsFromPEM(cacert)
   202  
   203  	// 定义gmtls配置
   204  	// 选择最高tls协议版本为VersionGMSSL, 服务端选择的默认密码套件将是 TLS_SM4_GCM_SM3
   205  	config := &gmtls.Config{
   206  		RootCAs:      certPool,
   207  		Certificates: []gmtls.Certificate{cert},
   208  		// 因为sm2相关证书是由`x509/x509_test.go`的`TestCreateCertFromCA`生成的,
   209  		// 指定了SAN包含"server.test.com"
   210  		ServerName:         "server.test.com",
   211  		MaxVersion:         gmtls.VersionGMSSL,
   212  		CurvePreferences:   curvePreference,
   213  		PreferCipherSuites: cipherSuitesPrefer,
   214  		SignAlgPrefer:      sigAlgPrefer,
   215  	}
   216  
   217  	// 向服务端拨号,建立tls连接
   218  	conn, err := gmtls.Dial("tcp", "localhost:50052", config)
   219  	if err != nil {
   220  		panic(err)
   221  	}
   222  	defer func(conn *gmtls.Conn) {
   223  		err := conn.Close()
   224  		if err != nil {
   225  			panic(err)
   226  		}
   227  	}(conn)
   228  
   229  	// 定义http请求
   230  	req := []byte("GET /test?clientName=gmtlsClient(gmssl) HTTP/1.1\r\n" +
   231  		"Host: localhost\r\n" +
   232  		"Connection: close\r\n\r\n")
   233  	// 向tls连接写入请求
   234  	_, _ = conn.Write(req)
   235  
   236  	// 从tls连接中读取http请求响应
   237  	buff := make([]byte, 1024)
   238  	for {
   239  		n, _ := conn.Read(buff)
   240  		if n <= 0 {
   241  			break
   242  		} else {
   243  			fmt.Printf("%s", buff[0:n])
   244  		}
   245  	}
   246  	end <- true
   247  }
   248  
   249  func ClientRunTls13(certType string) {
   250  	// 创建客户端本地的CA证书池
   251  	caPool := x509.NewCertPool()
   252  	// ca证书
   253  	var cacert []byte
   254  	// 客户端证书
   255  	var cert gmtls.Certificate
   256  	// 客户端优先曲线列表
   257  	var curvePreference []gmtls.CurveID
   258  	// 客户端优先密码套件列表
   259  	var cipherSuitesPrefer []uint16
   260  	// 客户端优先签名算法
   261  	var sigAlgPrefer []gmtls.SignatureScheme
   262  	var err error
   263  	switch certType {
   264  	case "sm2":
   265  		// 读取sm2 ca证书
   266  		cacert, err = ioutil.ReadFile(SM2CaCertPath)
   267  		// 读取User证书与私钥,作为客户端的证书与私钥,一般用作密钥交换证书。
   268  		// 但如果服务端要求查看客户端证书(双向tls通信)则也作为客户端身份验证用证书,
   269  		// 此时该证书应该由第三方ca机构颁发签名。
   270  		cert, err = gmtls.LoadX509KeyPair(sm2UserCertPath, sm2UserKeyPath)
   271  		curvePreference = append(curvePreference, gmtls.Curve256Sm2)
   272  		cipherSuitesPrefer = append(cipherSuitesPrefer, gmtls.TLS_SM4_GCM_SM3)
   273  	case "ecdsa":
   274  		// 读取ecdsa ca证书
   275  		cacert, err = ioutil.ReadFile(ecdsaCaCertPath)
   276  		// 读取User证书与私钥,作为客户端的证书与私钥,一般用作密钥交换证书。
   277  		// 但如果服务端要求查看客户端证书(双向tls通信)则也作为客户端身份验证用证书,
   278  		// 此时该证书应该由第三方ca机构颁发签名。
   279  		cert, err = gmtls.LoadX509KeyPair(ecdsaUserCertPath, ecdsaUserKeyPath)
   280  		curvePreference = append(curvePreference, gmtls.CurveP256)
   281  		cipherSuitesPrefer = append(cipherSuitesPrefer, gmtls.TLS_AES_128_GCM_SHA256)
   282  		sigAlgPrefer = append(sigAlgPrefer, gmtls.ECDSAWithP256AndSHA256)
   283  	case "ecdsaext":
   284  		// 读取ecdsaext ca证书
   285  		cacert, err = ioutil.ReadFile(ecdsaextCaCertPath)
   286  		// 读取User证书与私钥,作为客户端的证书与私钥,一般用作密钥交换证书。
   287  		// 但如果服务端要求查看客户端证书(双向tls通信)则也作为客户端身份验证用证书,
   288  		// 此时该证书应该由第三方ca机构颁发签名。
   289  		cert, err = gmtls.LoadX509KeyPair(ecdsaextUserCertPath, ecdsaextUserKeyPath)
   290  		curvePreference = append(curvePreference, gmtls.CurveP256)
   291  		cipherSuitesPrefer = append(cipherSuitesPrefer, gmtls.TLS_AES_128_GCM_SHA256)
   292  		sigAlgPrefer = append(sigAlgPrefer, gmtls.ECDSAEXTWithP256AndSHA256)
   293  	default:
   294  		err = errors.New("目前只支持sm2/ecdsa/ecdsaext")
   295  	}
   296  	if err != nil {
   297  		zclog.Fatal(err)
   298  	}
   299  	// 将ca证书作为根证书加入证书池
   300  	// 即,客户端相信持有该ca颁发的证书的服务端
   301  	caPool.AppendCertsFromPEM(cacert)
   302  
   303  	// 定义gmtls配置
   304  	config := &gmtls.Config{
   305  		RootCAs:      caPool,
   306  		Certificates: []gmtls.Certificate{cert},
   307  		// 因为相关证书是由`x509/x509_test.go`的`TestCreateCertFromCA`生成的,
   308  		// 指定了SAN包含"server.test.com"
   309  		ServerName:         "server.test.com",
   310  		CurvePreferences:   curvePreference,
   311  		PreferCipherSuites: cipherSuitesPrefer,
   312  		SignAlgPrefer:      sigAlgPrefer,
   313  	}
   314  	// 要启用psk,除了默认SessionTicketsDisabled为false,还需要配置客户端会话缓存为非nil。
   315  	// 这样服务端才会在握手完成后发出 newSessionTicketMsgTLS13 将加密并认证的会话票据发送给客户端。
   316  	config.ClientSessionCache = gmtls.NewLRUClientSessionCache(1)
   317  
   318  	// 向服务端拨号,建立tls连接
   319  	conn, err := gmtls.Dial("tcp", "localhost:50052", config)
   320  	if err != nil {
   321  		panic(err)
   322  	}
   323  	defer func(conn *gmtls.Conn) {
   324  		err := conn.Close()
   325  		if err != nil {
   326  			panic(err)
   327  		}
   328  	}(conn)
   329  
   330  	// 定义http请求
   331  	req := []byte("GET /test?clientName=gmtlsClient(tls1.3) HTTP/1.1\r\n" +
   332  		"Host: localhost\r\n" +
   333  		"Connection: close\r\n\r\n")
   334  	// 向tls连接写入请求
   335  	_, _ = conn.Write(req)
   336  
   337  	// 从tls连接中读取http请求响应
   338  	buff := make([]byte, 1024)
   339  	for {
   340  		n, _ := conn.Read(buff)
   341  		if n <= 0 {
   342  			break
   343  		} else {
   344  			fmt.Printf("%s", buff[0:n])
   345  		}
   346  	}
   347  	end <- true
   348  }
   349  
   350  func loadServerConfig(needClientAuth bool) (*gmtls.Config, error) {
   351  	// 准备服务端证书,分别是sm2,ecdsa,ecdsaext
   352  	var certs []gmtls.Certificate
   353  	// 读取sm2Sign证书与私钥,作为国密tls场景的服务器证书用
   354  	sm2Cert, err := gmtls.LoadX509KeyPair(sm2SignCertPath, sm2SignKeyPath)
   355  	if err != nil {
   356  		return nil, err
   357  	}
   358  	certs = append(certs, sm2Cert)
   359  	// 读取ecdsaSign证书与私钥,作为国密tls场景的服务器证书用
   360  	ecdsaCert, err := gmtls.LoadX509KeyPair(ecdsaSignCertPath, ecdsaSignKeyPath)
   361  	if err != nil {
   362  		return nil, err
   363  	}
   364  	certs = append(certs, ecdsaCert)
   365  	// 读取ecdsaextSign证书与私钥,作为国密tls场景的服务器证书用
   366  	ecdsaextCert, err := gmtls.LoadX509KeyPair(ecdsaextSignCertPath, ecdsaextSignKeyPath)
   367  	if err != nil {
   368  		return nil, err
   369  	}
   370  	certs = append(certs, ecdsaextCert)
   371  
   372  	// 创建gmtls配置
   373  	config := &gmtls.Config{
   374  		Certificates:   certs,
   375  		GetCertificate: nil,
   376  	}
   377  
   378  	// 如果开启对客户端的身份验证,则需要导入颁发客户端证书的CA证书
   379  	if needClientAuth {
   380  		// 如果服务端想要验证客户端身份,在这里添加对应配置信任的根证书
   381  		certPool := x509.NewCertPool()
   382  		sm2CaCert, err := ioutil.ReadFile(SM2CaCertPath)
   383  		if err != nil {
   384  			return nil, err
   385  		}
   386  		certPool.AppendCertsFromPEM(sm2CaCert)
   387  		ecdsaCaCert, err := ioutil.ReadFile(ecdsaCaCertPath)
   388  		if err != nil {
   389  			return nil, err
   390  		}
   391  		certPool.AppendCertsFromPEM(ecdsaCaCert)
   392  		ecdsaextCaCert, err := ioutil.ReadFile(ecdsaextCaCertPath)
   393  		if err != nil {
   394  			return nil, err
   395  		}
   396  		certPool.AppendCertsFromPEM(ecdsaextCaCert)
   397  		config.ClientAuth = gmtls.RequireAndVerifyClientCert
   398  		config.ClientCAs = certPool
   399  		// config.SessionTicketsDisabled = false
   400  		fmt.Println("------ debug用 : 服务端配置了ClientAuth")
   401  	}
   402  
   403  	return config, nil
   404  }
   405  
   406  func Test_clearLogs(t *testing.T) {
   407  	err := zclog.ClearDir("logs")
   408  	if err != nil {
   409  		panic(err)
   410  	}
   411  }