生成证书
:::info
// 生成根证书
openssl genrsa -out ca.key 2048
openssl req -sha256 -new -out ca.csr -key ca.key
openssl x509 -req -sha256 -in ca.csr -out ca.crt -signkey ca.key -CAcreateserial -days 3650
// 生成服务端证书
openssl genrsa -out server.key 2048
openssl req -sha256 -new -out server.csr -key server.key
openssl x509 -req -sha256 -in server.csr -out server.crt -signkey server.key -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650
// 生成客户端证书
openssl genrsa -out client.key 2048
openssl req -sha256 -new -out client.csr -key client.key
openssl x509 -req -sha256 -in client.csr -out client.crt -signkey client.key -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650
openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12
服务端
package mainimport ("crypto/tls""crypto/x509""github.com/gin-gonic/gin""io/ioutil""net/http""time")func main() {router := gin.Default()caCertData, err := ioutil.ReadFile("./ca.crt")if err != nil {panic(err)}rootCAs := x509.NewCertPool()rootCAs.AppendCertsFromPEM(caCertData)s := &http.Server{Addr: ":443",Handler: router,ReadTimeout: 10 * time.Second,WriteTimeout: 10 * time.Second,MaxHeaderBytes: 1 << 20,TLSConfig: &tls.Config{// 客户端需要提供证书ClientAuth: tls.RequireAndVerifyClientCert,// 用于验证客户端证书ClientCAs: rootCAs,},}router.GET("ping", func(context *gin.Context) {context.String(200, "%s", "pong")})//s.ListenAndServe()s.ListenAndServeTLS("./server.crt", "./server.key")}
客户端(失败)
package mainimport ("crypto/tls""fmt""io""net/http""strconv")func main() {client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true,},}}rsp, err := client.Get("https://127.0.0.1:443/ping")if err != nil {panic(err)}defer rsp.Body.Close()length, err := strconv.Atoi(rsp.Header.Get("Content-Length"))if err != nil {panic(err)}var data = make([]byte, length)n, err := rsp.Body.Read(data)if err != nil && err != io.EOF {panic(err)}fmt.Println(string(data[:n]))}➜ mutual-auth go run client-2.gopanic: Get "https://127.0.0.1:443/ping": remote error: tls: bad certificate
成功
package mainimport ("crypto/tls""fmt""io""net/http")func main() {cert, err := tls.LoadX509KeyPair("client.crt", "client.key")if err != nil {panic(err)}tr := &http.Transport{TLSClientConfig: &tls.Config{// 因为用的是自签名证书,所以要跳过验证InsecureSkipVerify: true,Certificates: []tls.Certificate{cert},},}client := &http.Client{Transport: tr}rsp, err := client.Get("https://127.0.0.1:443/ping")if err != nil {panic(err)}defer rsp.Body.Close()var data = make([]byte, 1024)n, err := rsp.Body.Read(data)if err != nil && err != io.EOF {panic(err)}fmt.Println(string(data[:n]))}➜ mutual-auth go run client-1.gopong
