HTTPS双向认证

双向认证

C/S两端分别生成密钥对,交换公钥,基于公钥验证另一端。

第一步,创建密钥对,把公钥存储为自签名、PEM编码的证书。用openssl即可,这里以一个HTTPS服务端为例:

openssl req -nodes -x509 -newkey rsa:4096 -keyout serverKey.pem -out serverCrt.pem -days 365

serverKey.pem包含服务器的私钥,需要保护;serverCrt.pem包含服务器的公钥,用来分发。

客户端:

openssl req -nodes -x509 -newkey rsa:4096 -keyout clientKey.pem -out clientCrt.pem -days 365

服务端

https服务端源码:


func helloHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Printf("Hello: %s\n", r.TLS.PeerCertificates[0].Subject.CommonName)
	fmt.Fprint(w, "Authentication successful")
}

func main() {
	var (
		err        error
		clientCert []byte
		pool       *x509.CertPool
		tlsConf    *tls.Config
		server     *http.Server
	)

	http.HandleFunc("/hello", helloHandler)

	if clientCert, err = ioutil.ReadFile("../client/clientCrt.pem"); err != nil {
		log.Fatalln(err)
	}
	pool = x509.NewCertPool()
	pool.AppendCertsFromPEM(clientCert)

	tlsConf = &tls.Config{
		ClientCAs:  pool,
		ClientAuth: tls.RequireAndVerifyClientCert,
		// RequireAndVerifyClientCert indicates that a client certificate should be requested
		// during the handshake, and that at least one valid certificate is required
		// to be sent by the client.
	}
	tlsConf.BuildNameToCertificate() // map domain to certificate

	server = &http.Server{
		Addr:      ":9443",
		TLSConfig: tlsConf,
	}
	log.Fatalln(server.ListenAndServeTLS("serverCrt.pem", "serverKey.pem"))
}

访问https://localhost:9443/hello,页面会显示Your connection isn’t private。服务端也显示:http: TLS handshake error from [::1]:1157: remote error: tls: unknown certificate

用curl测试:

$ sudo curl -ik -X GET --cert clientCrtBad.pem --key clientKeyBad.pem https://localhost:9443/hello
curl: (16) SSL_write() returned SYSCALL, errno = 32

服务端:

http: TLS handshake error from 127.0.0.1:33470: tls: failed to verify client certificate: x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "Internet Widgits Pty Ltd")

再测试正确的密钥,请求连接成功:

$ sudo curl -ik -X GET --cert clientCrt.pem --key clientKey.pem https://localhost:9443/hello
HTTP/2 200 
content-type: text/plain; charset=utf-8
content-length: 25
date: Mon, 28 Feb 2022 14:00:00 GMT

Authentication successful

服务端也显示了 Hello:,完成了对客户端的验证。

客户端(问题残留)


func main() {
	var (
		err              error
		cert             tls.Certificate
		serverCert, body []byte
		pool             *x509.CertPool
		tlsConf          *tls.Config
		transport        *http.Transport
		client           *http.Client
		resp             *http.Response
	)

	if cert, err = tls.LoadX509KeyPair("clientCrt.pem", "clientKey.pem"); err != nil {
		log.Fatalln(err)
	}

	if serverCert, err = ioutil.ReadFile("../server/serverCrt.pem"); err != nil {
		log.Fatalln(err)
	}

	pool = x509.NewCertPool()
	pool.AppendCertsFromPEM(serverCert)

	tlsConf = &tls.Config{
		Certificates: []tls.Certificate{cert},
		RootCAs:      pool,
	}
	tlsConf.BuildNameToCertificate()

	transport = &http.Transport{
		TLSClientConfig: tlsConf,
	}
	client = &http.Client{
		Transport: transport,
	}

	if resp, err = client.Get("https://localhost:9443/hello"); err != nil {
		log.Fatalln(err)
	}
	if body, err = ioutil.ReadAll(resp.Body); err != nil {
		log.Fatalln(err)
	}
	defer resp.Body.Close()

	fmt.Printf("Success: %s\n", body)
}

不过在测试的时候因为域名问题报错了,暂未解决:

Get "https://localhost:9443/hello": x509: certificate is not valid for any names, but wanted to match localhost
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值