生成证书
:::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 main
import (
"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 main
import (
"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.go
panic: Get "https://127.0.0.1:443/ping": remote error: tls: bad certificate
成功
package main
import (
"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.go
pong