openssl 与 keytool 都是证书的相关工具。但是两者使用方法各有不同。
openssl 使用方法
第一步、生成根证书:
openssl genrsa -out ca.key 2048 openssl req -x509 -new -nodes -key ca.key -days 3650 -out ca.crt
或者直接使用下面命令生成两个 crt 和 key
openssl req -x509 -new -nodes -keyout ca.key -out ca.crt -days 3650
参数
-nodes: 不使用密码
第二步、生成服务端证书:
# server.key 为私钥 opensslgenrsa -out server.key 2048 #这里的/cn是必须添加的 是服务端的域名或者是etc/hosts中的ip别名 也可以是使用* openss lreq -new -key server.key -subj "/CN=bgi_bc" -out server.csr openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650
第三步、生成客户端证书:
这一步与第二部相同,只是一个是用于服务端,一个是用于客户端使用
opensslgenrsa -out client.key 2048 # /cn是服务端的域名 或者是etc/hosts中的ip别名 也可以是使用* opensslreq -new -key client.key -subj "/CN=*" -out client.csr openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 3650
keytool 使用方法
keytool 是个密钥和证书管理工具。它使用户能够管理自己的公钥/私钥对及相关证书,用于(通过数字签名)自我认证(用户向别的用户/服务认证自己)或数据完整性以及认证服务。
keystore:keytool将密钥和证书存在一个称为keystore的文件中。
在keystore包含两种数据:
- 密钥实体——密钥(secret key)又或者是私钥和配对密钥(非对称加密)
- 可信任的证书实体——只包含公钥
Alias(别名):每个keystore都关联这一个独一无二的alias,通常不区分大小写。
keystore存储位置:在没有制定生成位置的情况下,keystore会存到用户的系统默认目录。
keytool 生成证书的命令
1、生成证书,存储到 jks 文件中
keytool -genkey -alias [这里是证书别名] -keyalg RSA -keystore [这里写证书的存储文件和位置格式为jks] -validity [这里填有效天数] -keysize 2048
2、查看存储文件中是否有证书
keytool -list -v -keystore [这里写证书的存储文件和位置格式为jks]
3、从 store 文件中导出证书,这里导出的是二进制证书
keytool -export -alias [这里是证书别名] -keystore selfsigned.jks -file [证书文件名]
4、如果要导出 pem 格式的十六进制证书需要加参数 -rfc
keytool -export -alias [这里是证书别名] -keystore selfsigned.jks -rfc -file [证书文件名]
5、导出 pkcs12 客户端使用证书,导出的证书文件格式一般是 .p12 或者 .pfx 。
keytool -alias [这里是证书别名] -v -importkeystore -srckeystore [这里是jks 证书存储文件] -srcstoretype jks -destkeystore [pfx 文件名] -deststoretype pkcs12
6、导出私钥
jks文件中的私钥不能直接得到,需要通过openssl将jks文件转换成pkcs12格式后再进行提取。
openssl pkcs12 -in [pfx 类型的文件,或者p12类型文件] -nocerts -nodes -out [私钥文件]
keytool 示例
在生成证书过程中会需要设置密码,地区,公司组织等相关信息,自己使用是可以随便输入。
keytool -genkey -alias ville -keyalg RSA -keystore ville.jks -validity 3650 -keysize 2048 keytool -list -v -keystore ville.jks keytool -export -alias ville -keystore ville.jks -rfc -file ville.crt keytool -alias ville -v -importkeystore -srckeystore ville.jks -srcstoretype jks -destkeystore ville.pfx -deststoretype pkcs12 openssl pkcs12 -in ville.pfx -nocerts -nodes -out ville.key
生成如下文件:
ville.jks ville.key ville.crt ville.pfx
其中 ville.key 是私钥,ville.crt 是提公钥, ville.pfx 是浏览器之类使用私钥的文件。
Golang 证书认证
先提供代码后面有时间在说明
SSL 双向认证
1、 服务端
package main import ( "crypto/tls" "crypto/x509" "fmt" "io" "io/ioutil" "log" "net/http" ) type httpsHandler struct { } func addTrust(pool*x509.CertPool, path string) { aCrt, err := ioutil.ReadFile(path) if err!= nil { fmt.Println("ReadFile err:",err) return } pool.AppendCertsFromPEM(aCrt) } func (*httpsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "golang https server!!!") } func main() { pool := x509.NewCertPool() // 这里是加载客户端提供的证书,最好是加载客户端提供的根证书 addTrust(pool,"../sslfile/ca.crt") addTrust(pool,"../sslfile/ville.crt") s := &http.Server{ Addr: ":8080", Handler: &httpsHandler{}, TLSConfig: &tls.Config{ ClientCAs: pool, ClientAuth: tls.RequireAndVerifyClientCert, }, } if err := s.ListenAndServeTLS("../sslfile/server.crt", "../sslfile/server.key"); err != nil { log.Fatal("ListenAndServeTLS err:", err) } }
2、客户端
package main import ( "crypto/tls" "crypto/x509" "fmt" "io/ioutil" "net/http" ) func addTrust(pool*x509.CertPool, path string) { aCrt, err := ioutil.ReadFile(path) if err!= nil { fmt.Println("ReadFile err:",err) return } pool.AppendCertsFromPEM(aCrt) } func TwoWaySSlCheck(){ pool := x509.NewCertPool() addTrust(pool,"../sslfile/server.crt") cliCrt, err := tls.LoadX509KeyPair("../sslfile/ville.crt", "../sslfile/ville.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://localhost:8080") if err != nil { fmt.Println("Get error:", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) fmt.Println(string(body)) } func main(){ TwoWaySSlCheck() }