go - Go:使用存储在 SmartCard 上的客户端证书的 HTTPS 请求 (Windows)
问题描述
为了执行客户端证书身份验证(相互身份验证),我发现的所有示例都假设可以访问私钥(例如从文件中访问)。生成包含私钥和公钥的证书,如下所示:
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.Certificate
var cert *syscall.CertContext
for {
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 实现这一点?
解决方案
您为您指定的私钥tls.Certificate
可以是任何实现的对象crypto.Signer
,根据文档:
是可用于签名操作的不透明私钥的接口。例如,保存在硬件模块中的 RSA 密钥。
并且专门用于这种用途。
一旦您可以访问底层密钥,实现接口就相当简单。例如, thalesignite/crypto11为 PKCS#11 密钥提供了这样的实现。
推荐阅读
- directory - 通用目录(例如不是用户特定的)
- java - 如何使用两个不同的包进行排序?
- c++ - 对 std::variant 中保存的类型调用 << 运算符?
- javascript - 如何检测页面滚动到长 div 的底部?
- javascript - 导航栏中的链接将我重定向到错误的路径
- reactjs - 为什么传递状态值会传递字典?
- java - 如何从两个 DayOfWeeks 之间获取 DayOfWeek 列表
- r - DEoptim 包 - 缺少参数,没有默认值
- python - Python代码循环遍历每个循环有2个变量的列表
- javascript - 函数表达式有什么意义,它们似乎没用