gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/gmtls/tls_test/tls_test.go (about)

     1  // Copyright (c) 2022 zhaochun
     2  // core-gm 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  	"log"
    16  	"net"
    17  	"net/http"
    18  	"testing"
    19  	"time"
    20  
    21  	"gitee.com/ks-custle/core-gm/gmtls"
    22  	"gitee.com/ks-custle/core-gm/x509"
    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  	// 导入tls配置
   105  	config, err := loadServerConfig(needClientAuth)
   106  	if err != nil {
   107  		panic(err)
   108  	}
   109  	// 定义tls监听器
   110  	ln, err := gmtls.Listen("tcp", ":50052", config)
   111  	if err != nil {
   112  		log.Println(err)
   113  		return
   114  	}
   115  	defer func(ln net.Listener) {
   116  		err := ln.Close()
   117  		if err != nil {
   118  			panic(err)
   119  		}
   120  	}(ln)
   121  
   122  	// 定义http请求处理
   123  	http.HandleFunc("/test", func(writer http.ResponseWriter, request *http.Request) {
   124  		clientName := request.URL.Query().Get("clientName")
   125  		fmt.Printf("接受到来自 %s 的http请求...\n", clientName)
   126  		// 在http响应中写入内容
   127  		_, err := fmt.Fprintf(writer, "你好, %s ! \n", clientName)
   128  		if err != nil {
   129  			panic(err)
   130  		}
   131  	})
   132  
   133  	// 在tls监听器上开启https服务
   134  	err = http.Serve(ln, nil)
   135  	if err != nil {
   136  		panic(err)
   137  	}
   138  }
   139  
   140  func ClientRunGMSSL(certType string) {
   141  	// 创建客户端本地的证书池
   142  	certPool := x509.NewCertPool()
   143  	var cacert []byte
   144  	var cert gmtls.Certificate
   145  	// 客户端优先曲线列表
   146  	var curvePreference []gmtls.CurveID
   147  	// 客户端优先密码套件列表
   148  	var cipherSuitesPrefer []uint16
   149  	// 客户端优先签名算法
   150  	var sigAlgPrefer []gmtls.SignatureScheme
   151  	var err error
   152  	switch certType {
   153  	case "sm2":
   154  		// 读取sm2 ca证书
   155  		cacert, err = ioutil.ReadFile(SM2CaCertPath)
   156  		// 读取User证书与私钥,作为客户端的证书与私钥,一般用作密钥交换证书。
   157  		// 但如果服务端要求查看客户端证书(双向tls通信)则也作为客户端身份验证用证书,
   158  		// 此时该证书应该由第三方ca机构颁发签名。
   159  		cert, _ = gmtls.LoadX509KeyPair(sm2UserCertPath, sm2UserKeyPath)
   160  		curvePreference = append(curvePreference, gmtls.Curve256Sm2)
   161  		cipherSuitesPrefer = append(cipherSuitesPrefer, gmtls.TLS_SM4_GCM_SM3)
   162  	case "ecdsa":
   163  		// 读取ecdsa ca证书
   164  		cacert, err = ioutil.ReadFile(ecdsaCaCertPath)
   165  		// 读取User证书与私钥,作为客户端的证书与私钥,一般用作密钥交换证书。
   166  		// 但如果服务端要求查看客户端证书(双向tls通信)则也作为客户端身份验证用证书,
   167  		// 此时该证书应该由第三方ca机构颁发签名。
   168  		cert, _ = gmtls.LoadX509KeyPair(ecdsaUserCertPath, ecdsaUserKeyPath)
   169  		curvePreference = append(curvePreference, gmtls.CurveP256)
   170  		cipherSuitesPrefer = append(cipherSuitesPrefer, gmtls.TLS_AES_128_GCM_SHA256)
   171  		sigAlgPrefer = append(sigAlgPrefer, gmtls.ECDSAWithP256AndSHA256)
   172  	case "ecdsaext":
   173  		// 读取ecdsaext ca证书
   174  		cacert, err = ioutil.ReadFile(ecdsaextCaCertPath)
   175  		// 读取User证书与私钥,作为客户端的证书与私钥,一般用作密钥交换证书。
   176  		// 但如果服务端要求查看客户端证书(双向tls通信)则也作为客户端身份验证用证书,
   177  		// 此时该证书应该由第三方ca机构颁发签名。
   178  		cert, _ = gmtls.LoadX509KeyPair(ecdsaextUserCertPath, ecdsaextUserKeyPath)
   179  		curvePreference = append(curvePreference, gmtls.CurveP256)
   180  		cipherSuitesPrefer = append(cipherSuitesPrefer, gmtls.TLS_AES_128_GCM_SHA256)
   181  		sigAlgPrefer = append(sigAlgPrefer, gmtls.ECDSAEXTWithP256AndSHA256)
   182  	default:
   183  		err = errors.New("目前只支持sm2/ecdsa/ecdsaext")
   184  	}
   185  	if err != nil {
   186  		log.Fatal(err)
   187  	}
   188  	// 将ca证书作为根证书加入证书池
   189  	// 即,客户端相信持有该ca颁发的证书的服务端
   190  	certPool.AppendCertsFromPEM(cacert)
   191  
   192  	// 定义gmtls配置
   193  	// 选择最高tls协议版本为VersionGMSSL, 服务端选择的默认密码套件将是 TLS_SM4_GCM_SM3
   194  	config := &gmtls.Config{
   195  		RootCAs:      certPool,
   196  		Certificates: []gmtls.Certificate{cert},
   197  		// 因为sm2相关证书是由`x509/x509_test.go`的`TestCreateCertFromCA`生成的,
   198  		// 指定了SAN包含"server.test.com"
   199  		ServerName:         "server.test.com",
   200  		MaxVersion:         gmtls.VersionGMSSL,
   201  		CurvePreferences:   curvePreference,
   202  		PreferCipherSuites: cipherSuitesPrefer,
   203  		SignAlgPrefer:      sigAlgPrefer,
   204  	}
   205  
   206  	// 向服务端拨号,建立tls连接
   207  	conn, err := gmtls.Dial("tcp", "localhost:50052", config)
   208  	if err != nil {
   209  		panic(err)
   210  	}
   211  	defer func(conn *gmtls.Conn) {
   212  		err := conn.Close()
   213  		if err != nil {
   214  			panic(err)
   215  		}
   216  	}(conn)
   217  
   218  	// 定义http请求
   219  	req := []byte("GET /test?clientName=gmtlsClient(gmssl) HTTP/1.1\r\n" +
   220  		"Host: localhost\r\n" +
   221  		"Connection: close\r\n\r\n")
   222  	// 向tls连接写入请求
   223  	_, _ = conn.Write(req)
   224  
   225  	// 从tls连接中读取http请求响应
   226  	buff := make([]byte, 1024)
   227  	for {
   228  		n, _ := conn.Read(buff)
   229  		if n <= 0 {
   230  			break
   231  		} else {
   232  			fmt.Printf("%s", buff[0:n])
   233  		}
   234  	}
   235  	end <- true
   236  }
   237  
   238  func ClientRunTls13(certType string) {
   239  	// 创建客户端本地的CA证书池
   240  	caPool := x509.NewCertPool()
   241  	// ca证书
   242  	var cacert []byte
   243  	// 客户端证书
   244  	var cert gmtls.Certificate
   245  	// 客户端优先曲线列表
   246  	var curvePreference []gmtls.CurveID
   247  	// 客户端优先密码套件列表
   248  	var cipherSuitesPrefer []uint16
   249  	// 客户端优先签名算法
   250  	var sigAlgPrefer []gmtls.SignatureScheme
   251  	var err error
   252  	switch certType {
   253  	case "sm2":
   254  		// 读取sm2 ca证书
   255  		cacert, err = ioutil.ReadFile(SM2CaCertPath)
   256  		// 读取User证书与私钥,作为客户端的证书与私钥,一般用作密钥交换证书。
   257  		// 但如果服务端要求查看客户端证书(双向tls通信)则也作为客户端身份验证用证书,
   258  		// 此时该证书应该由第三方ca机构颁发签名。
   259  		cert, err = gmtls.LoadX509KeyPair(sm2UserCertPath, sm2UserKeyPath)
   260  		curvePreference = append(curvePreference, gmtls.Curve256Sm2)
   261  		cipherSuitesPrefer = append(cipherSuitesPrefer, gmtls.TLS_SM4_GCM_SM3)
   262  	case "ecdsa":
   263  		// 读取ecdsa ca证书
   264  		cacert, err = ioutil.ReadFile(ecdsaCaCertPath)
   265  		// 读取User证书与私钥,作为客户端的证书与私钥,一般用作密钥交换证书。
   266  		// 但如果服务端要求查看客户端证书(双向tls通信)则也作为客户端身份验证用证书,
   267  		// 此时该证书应该由第三方ca机构颁发签名。
   268  		cert, err = gmtls.LoadX509KeyPair(ecdsaUserCertPath, ecdsaUserKeyPath)
   269  		curvePreference = append(curvePreference, gmtls.CurveP256)
   270  		cipherSuitesPrefer = append(cipherSuitesPrefer, gmtls.TLS_AES_128_GCM_SHA256)
   271  		sigAlgPrefer = append(sigAlgPrefer, gmtls.ECDSAWithP256AndSHA256)
   272  	case "ecdsaext":
   273  		// 读取ecdsaext ca证书
   274  		cacert, err = ioutil.ReadFile(ecdsaextCaCertPath)
   275  		// 读取User证书与私钥,作为客户端的证书与私钥,一般用作密钥交换证书。
   276  		// 但如果服务端要求查看客户端证书(双向tls通信)则也作为客户端身份验证用证书,
   277  		// 此时该证书应该由第三方ca机构颁发签名。
   278  		cert, err = gmtls.LoadX509KeyPair(ecdsaextUserCertPath, ecdsaextUserKeyPath)
   279  		curvePreference = append(curvePreference, gmtls.CurveP256)
   280  		cipherSuitesPrefer = append(cipherSuitesPrefer, gmtls.TLS_AES_128_GCM_SHA256)
   281  		sigAlgPrefer = append(sigAlgPrefer, gmtls.ECDSAEXTWithP256AndSHA256)
   282  	default:
   283  		err = errors.New("目前只支持sm2/ecdsa/ecdsaext")
   284  	}
   285  	if err != nil {
   286  		log.Fatal(err)
   287  	}
   288  	// 将ca证书作为根证书加入证书池
   289  	// 即,客户端相信持有该ca颁发的证书的服务端
   290  	caPool.AppendCertsFromPEM(cacert)
   291  
   292  	// 定义gmtls配置
   293  	config := &gmtls.Config{
   294  		RootCAs:      caPool,
   295  		Certificates: []gmtls.Certificate{cert},
   296  		// 因为相关证书是由`x509/x509_test.go`的`TestCreateCertFromCA`生成的,
   297  		// 指定了SAN包含"server.test.com"
   298  		ServerName:         "server.test.com",
   299  		CurvePreferences:   curvePreference,
   300  		PreferCipherSuites: cipherSuitesPrefer,
   301  		SignAlgPrefer:      sigAlgPrefer,
   302  	}
   303  	// 要启用psk,除了默认SessionTicketsDisabled为false,还需要配置客户端会话缓存为非nil。
   304  	// 这样服务端才会在握手完成后发出 newSessionTicketMsgTLS13 将加密并认证的会话票据发送给客户端。
   305  	config.ClientSessionCache = gmtls.NewLRUClientSessionCache(1)
   306  
   307  	// 向服务端拨号,建立tls连接
   308  	conn, err := gmtls.Dial("tcp", "localhost:50052", config)
   309  	if err != nil {
   310  		panic(err)
   311  	}
   312  	defer func(conn *gmtls.Conn) {
   313  		err := conn.Close()
   314  		if err != nil {
   315  			panic(err)
   316  		}
   317  	}(conn)
   318  
   319  	// 定义http请求
   320  	req := []byte("GET /test?clientName=gmtlsClient(tls1.3) HTTP/1.1\r\n" +
   321  		"Host: localhost\r\n" +
   322  		"Connection: close\r\n\r\n")
   323  	// 向tls连接写入请求
   324  	_, _ = conn.Write(req)
   325  
   326  	// 从tls连接中读取http请求响应
   327  	buff := make([]byte, 1024)
   328  	for {
   329  		n, _ := conn.Read(buff)
   330  		if n <= 0 {
   331  			break
   332  		} else {
   333  			fmt.Printf("%s", buff[0:n])
   334  		}
   335  	}
   336  	end <- true
   337  }
   338  
   339  func loadServerConfig(needClientAuth bool) (*gmtls.Config, error) {
   340  	// 准备服务端证书,分别是sm2,ecdsa,ecdsaext
   341  	var certs []gmtls.Certificate
   342  	// 读取sm2Sign证书与私钥,作为国密tls场景的服务器证书用
   343  	sm2Cert, err := gmtls.LoadX509KeyPair(sm2SignCertPath, sm2SignKeyPath)
   344  	if err != nil {
   345  		return nil, err
   346  	}
   347  	certs = append(certs, sm2Cert)
   348  	// 读取ecdsaSign证书与私钥,作为国密tls场景的服务器证书用
   349  	ecdsaCert, err := gmtls.LoadX509KeyPair(ecdsaSignCertPath, ecdsaSignKeyPath)
   350  	if err != nil {
   351  		return nil, err
   352  	}
   353  	certs = append(certs, ecdsaCert)
   354  	// 读取ecdsaextSign证书与私钥,作为国密tls场景的服务器证书用
   355  	ecdsaextCert, err := gmtls.LoadX509KeyPair(ecdsaextSignCertPath, ecdsaextSignKeyPath)
   356  	if err != nil {
   357  		return nil, err
   358  	}
   359  	certs = append(certs, ecdsaextCert)
   360  
   361  	// 创建gmtls配置
   362  	config := &gmtls.Config{
   363  		Certificates:   certs,
   364  		GetCertificate: nil,
   365  	}
   366  
   367  	// 如果开启对客户端的身份验证,则需要导入颁发客户端证书的CA证书
   368  	if needClientAuth {
   369  		// 如果服务端想要验证客户端身份,在这里添加对应配置信任的根证书
   370  		certPool := x509.NewCertPool()
   371  		sm2CaCert, err := ioutil.ReadFile(SM2CaCertPath)
   372  		if err != nil {
   373  			return nil, err
   374  		}
   375  		certPool.AppendCertsFromPEM(sm2CaCert)
   376  		ecdsaCaCert, err := ioutil.ReadFile(ecdsaCaCertPath)
   377  		if err != nil {
   378  			return nil, err
   379  		}
   380  		certPool.AppendCertsFromPEM(ecdsaCaCert)
   381  		ecdsaextCaCert, err := ioutil.ReadFile(ecdsaextCaCertPath)
   382  		if err != nil {
   383  			return nil, err
   384  		}
   385  		certPool.AppendCertsFromPEM(ecdsaextCaCert)
   386  		config.ClientAuth = gmtls.RequireAndVerifyClientCert
   387  		config.ClientCAs = certPool
   388  		// config.SessionTicketsDisabled = false
   389  		fmt.Println("------ debug用 : 服务端配置了ClientAuth")
   390  	}
   391  
   392  	return config, nil
   393  }