@ironzhang
2018-02-08T07:07:34.000000Z
字数 3387
阅读 927
技术文章/golang
以单向的客户端认证服务端身份为例
首先我们需要生成一个用于签发数字证书的CA私钥
和CA数字证书
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -days 5000 -out ca.crt -subj "/CN=ablecloud.cn"
然后需要生成服务端私钥和数字证书,并用CA私钥
给服务端数字证书做签名。
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 ../root/ca.crt -CAkey ../root/ca.key -CAcreateserial -out server.crt -days 5000
单向认证流程如下:
以上流程中忽略了双方协商加密算法之类的步骤。如果是双向认证,则还有服务端要求客户端发送证书的过程[1]。
要实现双向认证,还需要生成客户端的私钥和数字证书,并用CA私钥
给服务端数字证书做签名。
openssl genrsa -out client.key 2048
openssl req -new -key client.key -subj "/CN=localhost" -out client.csr
openssl x509 -req -in client.csr -CA ../root/ca.crt -CAkey ../root/ca.key -CAcreateserial -out client.crt -days 5000
加载TLS配置代码
func LoadCertPool(caFile string) (*x509.CertPool, error) {
pem, err := ioutil.ReadFile(caFile)
if err != nil {
return nil, err
}
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM(pem) {
return nil, errors.New("pool append certs from pem failed")
}
return pool, nil
}
func LoadTLSConfig(caFile, certFile, keyFile string) (*tls.Config, error) {
pool, err := LoadCertPool(caFile)
if err != nil {
return nil, fmt.Errorf("load cert pool from (%s): %v", caFile, err)
}
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return nil, fmt.Errorf("load x509 key pair from (%s, %s): %v", certFile, keyFile, err)
}
cfg := &tls.Config{
RootCAs: pool,
ClientCAs: pool,
ClientAuth: tls.RequireAndVerifyClientCert,
MinVersion: tls.VersionTLS12,
Certificates: []tls.Certificate{cert},
}
return cfg, nil
}
server代码
func main() {
config, err := tlscfg.LoadTLSConfig("../openssl/root/ca.crt", "../openssl/server/server.crt", "../openssl/server/server.key")
if err != nil {
log.Fatal(err)
}
ln, err := tls.Listen("tcp", "localhost:8000", config)
if err != nil {
log.Fatal(err)
}
for {
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
go handle(conn)
}
}
func handle(conn net.Conn) {
input := bufio.NewScanner(conn)
for input.Scan() {
fmt.Println(input.Text())
fmt.Fprintf(conn, input.Text())
}
}
client代码
func main() {
config, err := tlscfg.LoadTLSConfig("../openssl/root/ca.crt", "../openssl/client/client.crt", "../openssl/client/client.key")
if err != nil {
log.Fatal(err)
}
conn, err := tls.Dial("tcp", "localhost:8000", config)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
go mustCopy(os.Stdout, conn)
mustCopy(conn, os.Stdin)
}
func mustCopy(dst io.Writer, src io.Reader) {
if _, err := io.Copy(dst, src); err != nil {
log.Fatal(err)
}
}
要以TLS方式接入我们系统,设备端需要三个文件,CA数字证书
,设备私钥
,设备数字证书
。
CA数字证书
必须由我们颁发,没有保密要求。
设备私钥
由厂商自己生成,设备私钥
不能泄露。
设备数字证书
须由我们颁发,需要厂商根据设备私钥
先生成一个数字证书,再将该证书传给我们,由我们的CA私钥
和CA证书
对其签发生成真正的设备数字证书
,在保证设备私钥
不泄露的情况下,设备数字证书
没有保密要求。
后端需要四个文件,CA私钥
,CA数字证书
,服务端私钥
,服务端数字证书
CA私钥
用来和CA数字证书
一起签发服务端数字证书
和设备端数字证书
,必须保密。
CA数字证书
还被服务端用来验证设备数字证书
的真假,没有保密要求。
服务端私钥
必须保密
服务端数字证书
没有保密要求。