双向认证则是需要服务端与客户端提供身份认证,只能是服务端允许的客户能去访问,安全性相对于要高一些。服务器校验每个client,client也需要校验服务器。server需要server.key、server.crt、ca.crt;client需要client.key、client.crt、ca.crt。
openssl genrsa -out ca.key 2048 openssl req -x509 -new -nodes -key ca.key -subj "/CN=ca.com" -days 5000 -out ca.crt openssl genrsa -out server.key 2048 openssl req -new -key server.key -subj "/CN=server" -out server.csr openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 5000
openssl genrsa -out client-ca.key 2048 openssl req -x509 -new -nodes -key client-ca.key -subj "/CN=ca.com" -days 5000 -out client-ca.crt openssl genrsa -out client.key 2048 openssl req -new -key client.key -subj "/CN=client" -out client.csr openssl x509 -req -in client.csr -CA client-ca.crt -CAkey client-ca.key -CAcreateserial -out client.crt -days 5000
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
)
type myhandler struct {
}
func (h *myhandler) ServeHTTP(w http.ResponseWriter,
r *http.Request) {
fmt.Fprintf(w,
"Hi, This is a https service")
}
func main() {
pool := x509.NewCertPool()
caCertPath := "client-ca.crt"
caCrt, err := ioutil.ReadFile(caCertPath)
if err != nil {
fmt.Println("ReadFile err:", err)
return
}
pool.AppendCertsFromPEM(caCrt)
s := &http.Server{
Addr: ":8081",
Handler: &myhandler{},
TLSConfig: &tls.Config{
ClientCAs: pool,
ClientAuth: tls.RequireAndVerifyClientCert,
},
}
err = s.ListenAndServeTLS("server.crt", "server.key")
if err != nil {
fmt.Println("ListenAndServeTLS err:", err)
}
}
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
pool := x509.NewCertPool()
caCertPath := "ca.crt"
caCrt, err := ioutil.ReadFile(caCertPath)
if err != nil {
fmt.Println("ReadFile err:", err)
return
}
pool.AppendCertsFromPEM(caCrt)
cliCrt, err := tls.LoadX509KeyPair("client.crt", "client.key")
if err != nil {
fmt.Println("Loadx509keypair err:", err)
return
}
tr := &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: pool,
Certificates: []tls.Certificate{cliCrt},
},
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://server:8081")
if err != nil {
fmt.Println("Get error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
证书未经授权会报错,openssl来生成私人的证书。以下可运行成功。
openssl genrsa -out server.key 2048 //用于生成服务端私钥文件server.key,2048单位是bit,是私钥的长度。
openssl rsa -in server.key -out server.key.public //openssl生成的私钥中包含了公钥的信息,根据私钥生成公钥
openssl req -new -x509 -key server.key -out server.crt -days 365 //根据私钥生成自签发的数字证书
建立自己的CA,需要生成一个CA私钥和一个CA的数字证书: 生成server端的私钥,生成数字证书请求,并用我们的ca私钥签发server的数字证书。
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=ca.com" -days 5000 -out ca.crt
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=localhost" -out server.csr
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 5000
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w,
"Hi, This is a https service")
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServeTLS(":8042", "/home/yourpath/server.crt",
"/home/yourpath/server.key", nil)
}
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
)
//客户端对服务器校验
func main() {
//CertPool代表一个证书集合/证书池。
//创建一个CertPool
pool := x509.NewCertPool()
caCertPath := "/home/yourpath/ca.crt"
//调用ca.crt文件
caCrt, err := ioutil.ReadFile(caCertPath)
if err != nil {
fmt.Println("ReadFile err:", err)
return
}
//解析证书
pool.AppendCertsFromPEM(caCrt)
tr := &http.Transport{
////把从服务器传过来的非叶子证书,添加到中间证书的池中,使用设置的根证书和中间证书对叶子证书进行验证。
TLSClientConfig: &tls.Config{RootCAs: pool},
//TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //InsecureSkipVerify用来控制客户端是否证书和服务器主机名。如果设置为true,// //则不会校验证书以及证书中的主机名和服务器主机名是否一致。
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://localhost:8042")
if err != nil {
fmt.Println("Get error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}