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))
}