原创文章,转发请注明出处
java的keytool、单向验证、https等网上有很多教程,这里不再讲述,本篇文章着重讲述:
1、go如何使用openssl生产的证书(crt文件)建立https服务器与客户端进行双向验证
2、go如何与java的https服务进行通讯
生成证书:
第一步、生成根证书:
opensslgenrsa -out ca.key 2048
opensslreq -x509 -new -nodes -key ca.key -days 5000 -out ca.crt
第二步、生成服务端证书:
opensslgenrsa -out server.key 2048
#这里的/cn是必须添加的 是服务端的域名或者是etc/hosts中的ip别名
opensslreq -new -key server.key -subj "/CN=bgi_bc" -out server.csr
opensslx509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -outserver.crt -days 5000
第三部、生成客户端证书:
opensslgenrsa -out client.key 2048
# /cn是服务端的域名 或者是etc/hosts中的ip别名 也可以是使用*
opensslreq -new -key client.key -subj "/CN=*" -out client.csr
echoextendedKeyUsage=clientAuth > extfile.cnf
#如果需要制定ip执行以下命令
# echosubjectAltName = IP:10.225.2.162 > extfile.cnf
opensslx509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfileextfile.cnf -out client.crt -days 5000
#查询证书的情况
opensslx509 -in ./server.crt -noout -text
ps:以上命令都在centos7内执行
go代码
服务端:
packagemain
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
)
type myhandlerstruct {
}
func (h*myhandler)ServeHTTP(w http.ResponseWriter,r *http.Request) {
fmt.Fprintf(w,"Hi, This is an example of http service in golang!\n")
}
func main() {
pool := x509.NewCertPool()
addTrust(pool,"https6/ca.crt")//添加信任的证书,最好是客户端对应的根证书
addTrust(pool,"https7/ca.crt")//添加信任的证书
server := &http.Server{
Addr: ":8081",
Handler: &myhandler{},
TLSConfig: &tls.Config{
ClientCAs: pool,
ClientAuth:tls.RequireAndVerifyClientCert,
},
}
err := server.ListenAndServeTLS("https6/server.crt","https6/server.key")//添加服务端证书和密钥
if err!= nil {
fmt.Println("ListenAndServeTLS err:",err)
}
}
func addTrust(pool*x509.CertPool,path string) {
aCrt, err := ioutil.ReadFile(path)
if err!= nil {
fmt.Println("ReadFile err:",err)
return
}
pool.AppendCertsFromPEM(aCrt)
}
用户端:
package main import ( "crypto/tls" "crypto/x509" "fmt" "io/ioutil" "net/http" ) func main() { pool := x509.NewCertPool() addTrust(pool, "https6/ca.crt") //添加信任的证书,最好是服务端对应的根证书 cliCrt, err := tls.LoadX509KeyPair("https7/client.crt", "https7/client.key") if err != nil { fmt.Println("Loadx509keypair err:", err) return } tr := &http.Transport{ TLSClientConfig: &tls.Config{ RootCAs: pool, Certificates: []tls.Certificate{cliCrt}, //InsecureSkipVerify: true, //跳过验证服务端证书 }, } client := &http.Client{Transport: tr} resp, err := client.Get("https://bgi_bc:8081") //此处必须使用域名或者host内的别名 if err != nil { fmt.Println("Get error:", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) fmt.Println(string(body)) } func addTrust(pool *x509.CertPool, path string) { aCrt, err := ioutil.ReadFile(path) if err != nil { fmt.Println("ReadFile err:", err) return } pool.AppendCertsFromPEM(aCrt) }
ps:
1、 参考https技术知识后,值得注意的是,客户端和用户的使用的证书可以是不同的,但是必须是使用根证书签名授权后端客户端/服务端证书,且证书对应的key必须一致
2、 如果对方使用java生成的证书,后缀为cer时,必须转换成pem或者crt格式给go使用,命令如下
openssl x509 -in 你的证书.cer -inform DER -out 你的证书.pem -outform PEM
3、 给java使用的转换命令
openssl x509 -in ca.crt -out ca.cer-outform der
资料参考:
https基础:
http://www.techug.com/post/https-ssl-tls.html
单向验证与双向验证的区别:
https://blog.csdn.net/duanbokan/article/details/50847612
go语言https的单向验证与双向验证:
https://www.tuicool.com/articles/aymYbmM