Golang ssl 證書 雙向認(rèn)證 keytool

openssl 與 keytool 都是證書的相關(guān)工具。但是兩者使用方法各有不同。

openssl 使用方法

第一步、生成根證書:

openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -days 3650 -out ca.crt

或者直接使用下面命令生成兩個(gè) crt 和 key

openssl req  -x509 -new -nodes -keyout ca.key -out  ca.crt -days 3650

參數(shù)

 -nodes: 不使用密碼

第二步、生成服務(wù)端證書:

# server.key 為私鑰
openssl genrsa -out server.key 2048
#這里的/cn是必須添加的 是服務(wù)端的域名或者是etc/hosts中的ip別名 也可以是使用*
openssl req -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

第三步、生成客戶端證書:

這一步與第二部相同,只是一個(gè)是用于服務(wù)端,一個(gè)是用于客戶端使用

opensslgenrsa -out client.key 2048
# /cn是服務(wù)端的域名 或者是etc/hosts中的ip別名 也可以是使用*
openssl req -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 是個(gè)密鑰和證書管理工具。它使用戶能夠管理自己的公鑰/私鑰對(duì)及相關(guān)證書,用于(通過數(shù)字簽名)自我認(rèn)證(用戶向別的用戶/服務(wù)認(rèn)證自己)或數(shù)據(jù)完整性以及認(rèn)證服務(wù)。
keystore:keytool將密鑰和證書存在一個(gè)稱為keystore的文件中。
在keystore包含兩種數(shù)據(jù):

  • 密鑰實(shí)體——密鑰(secret key)又或者是私鑰和配對(duì)密鑰(非對(duì)稱加密)
  • 可信任的證書實(shí)體——只包含公鑰

Alias(別名):每個(gè)keystore都關(guān)聯(lián)這一個(gè)獨(dú)一無二的alias,通常不區(qū)分大小寫。
keystore存儲(chǔ)位置:在沒有制定生成位置的情況下,keystore會(huì)存到用戶的系統(tǒng)默認(rèn)目錄。

keytool 生成證書的命令

1、生成證書,存儲(chǔ)到 jks 文件中

keytool -genkey -alias [這里是證書別名] -keyalg RSA -keystore [這里寫證書的存儲(chǔ)文件和位置格式為jks] -validity [這里填有效天數(shù)] -keysize 2048

2、查看存儲(chǔ)文件中是否有證書

keytool -list  -v -keystore [這里寫證書的存儲(chǔ)文件和位置格式為jks] 

3、從 store 文件中導(dǎo)出證書,這里導(dǎo)出的是二進(jìn)制證書

keytool -export -alias  [這里是證書別名] -keystore selfsigned.jks -file [證書文件名] 

4、如果要導(dǎo)出 pem 格式的十六進(jìn)制證書需要加參數(shù) -rfc

keytool -export -alias  [這里是證書別名]  -keystore selfsigned.jks  -rfc -file  [證書文件名] 

5、導(dǎo)出 pkcs12 客戶端使用證書,導(dǎo)出的證書文件格式一般是 .p12 或者 .pfx 。

keytool -alias [這里是證書別名] -v -importkeystore -srckeystore [這里是jks 證書存儲(chǔ)文件] -srcstoretype jks -destkeystore [pfx 文件名] -deststoretype pkcs12

6、導(dǎo)出私鑰
jks文件中的私鑰不能直接得到,需要通過openssl將jks文件轉(zhuǎn)換成pkcs12格式后再進(jìn)行提取。

openssl pkcs12 -in [pfx 類型的文件,或者p12類型文件] -nocerts -nodes -out [私鑰文件]

keytool 示例

在生成證書過程中會(huì)需要設(shè)置密碼,地區(qū),公司組織等相關(guān)信息,自己使用是可以隨便輸入。

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 證書認(rèn)證

在 openssl 和 key 中我們生成了 ca , server, client , ville 等相關(guān)的證書。

使用場(chǎng)景

我們這里假設(shè) server 的證書是與 client 證書不是同一個(gè)地方生成的,他們是兩個(gè)不同的公司提供的,ca 、client 和 ville 是屬于客戶端公司的證書,server 是屬于服務(wù)端公司的證書??蛻舳斯拘枰?qǐng)求服務(wù)端公司的接口。1、首先客戶端公司要啊把他們的證書(公鑰 .crt)提供給服務(wù)端公司,服務(wù)端公司要把客戶端提供的證書加載到服務(wù)中,這樣服務(wù)請(qǐng)求的時(shí)候就好校驗(yàn)客戶端的請(qǐng)求。
2、服務(wù)端公司也要把他們的服務(wù)證書(公鑰 .crt)提供給客戶公司,客戶端公司要加載到客戶端程序,用以校驗(yàn)請(qǐng)求到的數(shù)據(jù)是服務(wù)公司的。
下面我們就以 Golang 的雙向認(rèn)證來做示例

SSL 雙向認(rèn)證

1、 服務(wù)端程序

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,
        },
    }
        // 這里是加載 服務(wù)端自己的證書和私鑰
    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()
        // 這里加載服務(wù)端提供的證書,用于校驗(yàn)服務(wù)端返回的數(shù)據(jù)
    addTrust(pool,"../sslfile/server.crt")
        // 這里加載客戶端自己的證書,要與提供給服務(wù)端的證書一致,不然服務(wù)端校驗(yàn)會(huì)不通過
    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()
}

Github 源代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容