使用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/x509syscall包配合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文件的加密密码匹配。

回到顶部