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 }