1.双向认证
双向认证则是需要服务端与客户端提供身份认证,只能是服务端允许的客户能去访问,安全性相对于要高一些。服务器校验每个client,client也需要校验服务器。server需要server.key、server.crt、ca.crt;client需要client.key、client.crt、ca.crt。
1.1服务端
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
1.2客户端
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
1.3https server
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) } }
1.4https client
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来生成私人的证书。以下可运行成功。
2.HTTPS证书
2.1生成证书私钥(生成CA私钥)(无加密)
openssl genrsa -out server.key 2048 //用于生成服务端私钥文件server.key,2048单位是bit,是私钥的长度。
2.2根据私钥生成公钥
openssl rsa -in server.key -out server.key.public //openssl生成的私钥中包含了公钥的信息,根据私钥生成公钥
2.3根据私钥生成证书 (生成CA证书)
openssl req -new -x509 -key server.key -out server.crt -days 365 //根据私钥生成自签发的数字证书
3.对服务端证书校验
建立自己的CA,需要生成一个CA私钥和一个CA的数字证书: 生成server端的私钥,生成数字证书请求,并用我们的ca私钥签发server的数字证书。
3.1生成客户端私钥(生成CA私钥)
openssl genrsa -out ca.key 2048
3.2生成CA证书
openssl req -x509 -new -nodes -key ca.key -subj "/CN=ca.com" -days 5000 -out ca.crt
3.3生成server端的私钥,生成数字证书请求,并用我们的ca私钥签发server的数字证书
3.4生成服务端私钥
openssl genrsa -out server.key 2048
3.5生成证书请求文件
openssl req -new -key server.key -subj "/CN=localhost" -out server.csr
3.6根据CA的私钥和上面的证书请求文件生成服务端证书
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 5000
3.7https server
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) }
3.8https client
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)) }