單向認證
單向認證,只對服務端證書進行校驗
自簽CA證書
自簽發證書,生成根證書。根證書是CA認證中心給自己頒發的證書,是信任鏈的起始點.
這里我們自己做CA使用openssl命令來生成根證書. 首先建立我們自己的CA,需要生成一個CA私鑰和一個CA的數字證書。
生成CA私鑰和CA證書
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=ca-01" -days 5000 -out ca.crt
服務端證書
然后生成server端的私鑰,生成數字證書請求,并用我們的ca私鑰簽發server的數字證書
開始生成X509格式的自簽名證書,會要求輸入各項信息(國家,省份,城市,組織,姓名,email等 )
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=server-01" -out server.csr
openssl x509 -req -in server.csr -extfile san.cnf -extensions v3_req -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 5000
openssl req -in server.csr -text -noout
openssl x509 -in server.crt -text -noout
其中
# cat san.cnf
[ req ]
distinguished_name = req_distinguished_name
# 生成v3版本帶擴展屬性的證書
req_extensions = v3_req
# 設置默認域名
[ req_distinguished_name ]
# 拓展信息配置
[ v3_req ]
subjectAltName = @alt_names
# 要配置的域名
[alt_names]
DNS.1 = server-01
DNS.2 = localhost
IP.1 = 127.0.0.1
IP.2 = 172.168.1.2
# openssl x509 -in server.crt -text -noout
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:server-01, DNS:localhost, IP Address:127.0.0.1, IP Address:172.168.1.2
包含DANS 和 IP 相關的SAN配置信息。 在生成證書這一步,才帶上SAN配置信息。
現在我們的工作目錄下,有以下私鑰和證書文件:
CA:
私鑰文件 ca.key
數字證書ca.crt
Server:
私鑰文件 server.key
數字證書 server.crt
# ls
ca.crt ca.key server.crt server.csr server.key
服務端
// server-v1.go
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w,"這是HTTPS服務器頁面,單向認證完成,我們可以通信了!")
}
func main() {
http.HandleFunc("/", handler)
// https,必須提供包含服務器的證書和私鑰的文件
http.ListenAndServeTLS(":8081", "server.crt", "server.key", nil)
}
客戶端
// client-v1.go
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)
tr := &http.Transport{
TLSClientConfig: &tls.Config{RootCAs: pool},
}
client := &http.Client{Transport: tr}
resp, err := client.Get("//server-01:8081")
if err != nil {
fmt.Println("Get error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
go build server-v1.go
go build client-v1.go
驗證過程
驗證1: 通過域名
修改 client-v1.go 中代碼
resp, err := client.Get("//server-01:8081")
/etc/hosts 是一個將主機名或域名轉換為 IP 地址的操作系統文件。
echo "127.0.0.1 server-01" >> /etc/hosts
ping server-01 -c 1
PING server-01 (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.031 ms
--- server-01 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.031/0.031/0.031/0.000 ms
驗證2: 通過IP
修改 client-v1.go 中代碼
resp, err := client.Get("//127.0.0.1:8081")
驗證3: 通過IP
ip link add my-dummy0 type dummy
ip addr add 172.168.1.2 dev my-dummy0
ip addr show my-dummy0
resp, err := client.Get("//172.168.1.2:8081")