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 }