使用Golang通过KSP或CSP将P12/PFX证书导入Windows证书存储
使用Golang通过KSP或CSP将P12/PFX证书导入Windows证书存储 我需要一个功能,能够将捆绑在p12/pfx文件中的证书及相关私钥导入到Windows证书存储中,最好使用任何KSP或CSP。我在网上搜索过,但没有找到任何相关信息。我也查看了Google的certtostore库,但它无法帮助我将证书和私钥导入到Windows证书存储中,或将证书及相关私钥导出到p12或pfx文件。
1 回复
更多关于使用Golang通过KSP或CSP将P12/PFX证书导入Windows证书存储的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Golang中,通过KSP或CSP将P12/PFX证书导入Windows证书存储,可以使用crypto/x509和syscall包配合Windows API实现。以下是一个示例代码,演示如何加载PFX文件并将其导入到Windows的个人证书存储中:
package main
import (
"crypto/x509"
"encoding/pem"
"fmt"
"syscall"
"unsafe"
)
const (
MY_STORE_TYPE = "MY"
CERT_STORE_PROV_SYSTEM = 10
CERT_SYSTEM_STORE_CURRENT_USER = 1 << 16
PKCS12_NO_PERSIST_KEY = 0x00008000
X509_ASN_ENCODING = 0x00000001
PKCS12_IMPORT_RESERVED_MASK = 0xffff0000
)
var (
crypt32 = syscall.NewLazyDLL("crypt32.dll")
pfxImportCertStore = crypt32.NewProc("PFXImportCertStore")
certOpenStore = crypt32.NewProc("CertOpenStore")
certAddCertificateContextToStore = crypt32.NewProc("CertAddCertificateContextToStore")
certCloseStore = crypt32.NewProc("CertCloseStore")
)
func importPFXToWindowsStore(pfxData []byte, password string) error {
// 准备PFX导入参数
pfxBlob := &syscall.CryptDataBlob{
CbData: uint32(len(pfxData)),
PbData: &pfxData[0],
}
// 转换密码为UTF-16
utf16Password, err := syscall.UTF16PtrFromString(password)
if err != nil {
return fmt.Errorf("密码转换失败: %v", err)
}
// 导入PFX到临时存储
var flags uint32 = CERT_SYSTEM_STORE_CURRENT_USER
store, _, err := pfxImportCertStore.Call(
uintptr(unsafe.Pointer(pfxBlob)),
uintptr(unsafe.Pointer(utf16Password)),
uintptr(flags|PKCS12_NO_PERSIST_KEY),
)
if store == 0 {
return fmt.Errorf("PFX导入失败: %v", err)
}
defer certCloseStore.Call(store)
// 打开目标证书存储
storeType, _ := syscall.UTF16PtrFromString(MY_STORE_TYPE)
hStore, _, err := certOpenStore.Call(
uintptr(unsafe.Pointer(storeType)),
0,
0,
uintptr(CERT_SYSTEM_STORE_CURRENT_USER),
uintptr(unsafe.Pointer(storeType)),
)
if hStore == 0 {
return fmt.Errorf("打开证书存储失败: %v", err)
}
defer certCloseStore.Call(hStore)
// 枚举并复制证书
var certContext uintptr
for {
certContext, _, _ = syscall.Syscall(
uintptr(crypt32.NewProc("CertEnumCertificatesInStore").Addr()),
store,
certContext,
0,
)
if certContext == 0 {
break
}
// 添加证书到目标存储
result, _, err := certAddCertificateContextToStore.Call(
hStore,
certContext,
1, // CERT_STORE_ADD_ALWAYS
0,
)
if result == 0 {
return fmt.Errorf("添加证书失败: %v", err)
}
}
return nil
}
func main() {
// 读取PFX文件
pfxBytes := []byte{/* 你的PFX文件内容 */} // 这里需要替换为实际的PFX数据
password := "your_password"
err := importPFXToWindowsStore(pfxBytes, password)
if err != nil {
fmt.Printf("导入失败: %v\n", err)
} else {
fmt.Println("证书导入成功")
}
}
对于需要处理PEM编码的PFX文件的情况,可以添加以下解码函数:
func decodePFX(pemData []byte, password string) ([]byte, error) {
block, _ := pem.Decode(pemData)
if block == nil {
return nil, fmt.Errorf("PEM解码失败")
}
if block.Type != "PKCS12" && block.Type != "PFX" {
return nil, fmt.Errorf("不是有效的PFX/PKCS12格式")
}
// 这里可以添加额外的PFX解码逻辑
// 注意:标准库的x509.DecodePKCS12需要Go 1.15+
_, err := x509.DecodePKCS12(block.Bytes, password)
if err != nil {
return nil, fmt.Errorf("PFX解码失败: %v", err)
}
return block.Bytes, nil
}
这个实现使用了Windows的Crypt32 API来直接处理PFX导入操作。代码中的MY_STORE_TYPE指定了个人证书存储,你可以根据需要修改为其他存储位置(如"ROOT"用于根证书存储)。注意,运行此代码需要适当的Windows权限,并且密码参数需要与PFX文件的加密密码匹配。

