亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Go:使用存儲在 SmartCard 上的客戶端證書的 HTTPS 請求 (Windows)

Go:使用存儲在 SmartCard 上的客戶端證書的 HTTPS 請求 (Windows)

Go
aluckdog 2022-05-23 16:46:44
為了執行客戶端證書身份驗證(相互身份驗證),我發現的所有示例都假設可以訪問私鑰(例如從文件中訪問)。生成包含私鑰和公鑰的證書,如下所示:cert, err := tls.LoadX509KeyPair("certs/client.pem", "certs/client.key")現在,我必須從智能卡中獲取證書(和私鑰,據我所知無法提取 - 簽名應該通過 PKCS#11 完成)。到目前為止,我能夠枚舉 Windows 證書存儲中的證書:store, err := syscall.UTF16PtrFromString("MY")storeHandle, err := syscall.CertOpenSystemStore(0, store)if err != nil {    fmt.Println(syscall.GetLastError())}var certs []*x509.Certificatevar cert *syscall.CertContextfor {    cert, err = syscall.CertEnumCertificatesInStore(storeHandle, cert)    if err != nil {        if errno, ok := err.(syscall.Errno); ok {            if errno == CRYPT_E_NOT_FOUND {                break            }        }        fmt.Println(syscall.GetLastError())    }    if cert == nil {        break    }    // Copy the buf, since ParseCertificate does not create its own copy.    buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]    buf2 := make([]byte, cert.Length)    copy(buf2, buf)    if c, err := x509.ParseCertificate(buf2); err == nil {        for _, value := range c.ExtKeyUsage {            if value == x509.ExtKeyUsageClientAuth {                fmt.Println(c.Subject.CommonName)                fmt.Println(c.Issuer.CommonName)                certs = append(certs, c)            }        }    }}這種方式檢索到的證書確實來自智能卡。稍后使用時,身份驗證失敗:cer:= tls.Certificate{Certificate: [][]byte{certs[0].Raw}, Leaf: certs[0],}tlsConfig := &tls.Config{    Certificates:       []tls.Certificate{cer},    RootCAs:            caCertPool,    InsecureSkipVerify: true,}transport := &http.Transport{TLSClientConfig: tlsConfig}client := http.Client{    Timeout:   time.Minute * 2,    Transport: transport,}我想失敗是意料之中的,因為我沒有提供私鑰。Java (SunMSCAPI) 和 .NET 似乎在幕后使用智能卡上的私鑰,例如,我做的與上面幾乎相同,并且身份驗證“正常工作”。有沒有辦法用 Go 實現這一點?
查看完整描述

2 回答

?
鳳凰求蠱

TA貢獻1825條經驗 獲得超4個贊

您為您指定的私鑰tls.Certificate可以是任何實現的對象crypto.Signer,根據文檔:

是可用于簽名操作的不透明私鑰的接口。例如,保存在硬件模塊中的 RSA 密鑰。

并且專門用于這種用途。

一旦您可以訪問底層密鑰,實現接口就相當簡單了。例如, thalesignite/crypto11為 PKCS#11 密鑰提供了這樣的實現。


查看完整回答
反對 回復 2022-05-23
?
千萬里不及你

TA貢獻1784條經驗 獲得超9個贊

您可以使用供應商的 PKCS11 文件 + crypto11庫。


package main


import (

    "crypto/tls"

    "fmt"

    "io/ioutil"

    "log"

    "net/http"

    "github.com/ThalesIgnite/crypto11"

)


func main() {

    config := crypto11.Config{

        Path: "C:\\Windows\\System32\\vendor-pkcs11.dll",

        TokenSerial: "123456789456123",

        Pin: "123456",

    }


    context, err := crypto11.Configure(&config)

    if err != nil{

        log.Fatalln(err)

    }


    certificates, err := context.FindAllPairedCertificates()

    if err != nil{

        log.Fatalln(err)

    }


    fmt.Println("total certificates: ", len(certificates))


    cert := certificates[0]

    client := &http.Client{

        Transport: &http.Transport{

            TLSClientConfig: &tls.Config{

                Certificates: []tls.Certificate{cert},

                Renegotiation:      tls.RenegotiateOnceAsClient,

            },

        },

    }


    req, err := http.NewRequest("GET", "https://server.cryptomix.com:443/secure/", nil)

    if err != nil {

        log.Fatalln(err)

    }


    req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36")


    resp, err := client.Do(req)

    if err != nil {

        log.Fatalln(err)

    }


    fmt.Println("status code: ", resp.StatusCode)


    if resp.StatusCode == http.StatusOK {

        bodyBytes, err := ioutil.ReadAll(resp.Body)

        if err != nil {

            log.Fatal(err)

        }

        bodyString := string(bodyBytes)

        fmt.Println(bodyString)

    }

}


查看完整回答
反對 回復 2022-05-23
  • 2 回答
  • 0 關注
  • 186 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號