单向认证
单向认证,只对服务端证书进行校验
自签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("https://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("https://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("https://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("https://172.168.1.2:8081")