调用Go中的PFXExportCertStoreEx函数不返回数据。

huangapple go评论86阅读模式
英文:

Calling PFXExportCertStoreEx in Go does not return data

问题

我正在使用Go 1.6在Windows上工作,并尝试将证书容器导出为PFX(这里的最终目标是从证书存储中访问可导出的私钥)。

我已经打开了一个内存存储并将证书插入存储中:

var storedCertCtx *syscall.CertContext
storeHandle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0)
err = syscall.CertAddCertificateContextToStore(storeHandle, certenum, syscall.CERT_STORE_ADD_ALWAYS, &storedCertCtx)

现在我想生成该存储的PFX。我已经定义了一个用于包含data blob的结构体,并希望使用PFXExportCertStoreEx来获取存储的PFX:

var (
    crypt32                  = syscall.NewLazyDLL("crypt32.dll")
    procPFXExportCertStoreEx = crypt32.NewProc("PFXExportCertStoreEx")
)

type CRYPTOAPI_BLOB struct {
    DataSize uint32
    Data     *byte
}

var pfxBlob CRYPTOAPI_BLOB
err = PfxExportCertStore(storeHandle, &pfxBlob, syscall.StringToUTF16Ptr("MyPassword"), 0, 0)

syscall.Syscall6(procPFXExportCertStoreEx.Addr(), 5,
    uintptr(storeHandle),                //hStore
    uintptr(unsafe.Pointer(&pfxBlob)),   //*pPFX
    uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("password"))), //szPassword
    0,   //*pvPara
    0,   //dwFlags
    0)

这个代码部分“半”起作用。

DataSize的值被填充为一个看起来合适的值(即如果我向存储中添加更多证书,它会变得更大),但是Data始终为<nil>

考虑到它应该被填充为一个指针,我尝试将其声明为*uintptruint32(只是为了看看是否有任何内容被填充进去),但是没有任何效果。该值始终保持不变(如果我手动在其中放入垃圾数据,那么在执行系统调用后,垃圾数据仍然存在)。

我是否错误地定义了这个结构体?在Go中很少有可以参考的示例,但是从我从众多的C示例中看到的内容来看,这应该是可以工作的。

英文:

I'm working in Go 1.6 on Windows and trying to export a certificate container to a PFX (the ultimate goal here is to access an exportable private key from the certificate store).

I have opened a memory store and inserted a certificate into the store:

var storedCertCtx *syscall.CertContext
storeHandle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0)
err = syscall.CertAddCertificateContextToStore(storeHandle, certenum, syscall.CERT_STORE_ADD_ALWAYS, &amp;storedCertCtx)

Now I want to generate a PFX of that store. I have defined a struct for containing the data blob and want to use PFXExportCertStoreEx to get a PFX of the store:

var (
	crypt32                  = syscall.NewLazyDLL(&quot;crypt32.dll&quot;)
	procPFXExportCertStoreEx = crypt32.NewProc(&quot;PFXExportCertStoreEx&quot;)
)

type CRYPTOAPI_BLOB struct {
	DataSize uint32
	Data     *byte
}

var pfxBlob CRYPTOAPI_BLOB
err = PfxExportCertStore(storeHandle, &amp;pfxBlob, syscall.StringToUTF16Ptr(&quot;MyPassword&quot;), 0, 0)

syscall.Syscall6(procPFXExportCertStoreEx.Addr(), 5,
		uintptr(storeHandle),                //hStore
		uintptr(unsafe.Pointer(&amp;pfxBlob)),   //*pPFX
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(&quot;password&quot;))), //szPassword
		0,   //*pvPara
		0,   //dwFlags
		0)

And this half works.

DataSize is populated with what looks like an appropriate value (i.e. if I add more certificates to the store, it grows bigger), however Data is always &lt;nil&gt;.

Seeing as it's meant to be populated with a pointer, I have tried declaring it as *uintptr and uint32 (just to see if anything gets populated), but nothing. The value is always untouched (if I manually put junk data in there, the junk data stays after the syscall is executed).

Have I defined the struct incorrectly? There is precious few examples to go for getting this done in Go, but from what I can see from the numerous C examples, this should be working.

答案1

得分: 4

这是预期的行为。

根据这个链接:https://msdn.microsoft.com/en-us/library/windows/desktop/aa387313(v=vs.85).aspx,pPFX 结构体需要一个预先分配的缓冲区,大小在 cbData 字段中指定,该字段将被更新为复制的数据的大小。

如果调用时 pbData 等于 NULL,则只会更新 cbData 字段,以反映输出缓冲区所需的大小。

英文:

This is the expected behavior.

According to this: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387313(v=vs.85).aspx, the pPFX struct requires a pre-allocated buffer, with the size in the cbData field, which will be updated with the size of the data copied in.

If the call is made with pbData equal to NULL, only the cbData field is updated to reflect the size needed for the output buffer.

答案2

得分: 0

JimB的答案肯定是正确的,但是我想补充一下,以便其他人在进行这个过程时能够跟进。我需要使用以下实际代码将PFX文件转换为CRYPTOAPI_BLOB

var (
    crypt32                  = syscall.NewLazyDLL("crypt32.dll")
    procPFXExportCertStoreEx = crypt32.NewProc("PFXExportCertStoreEx")
    procCryptMemAlloc        = crypt32.NewProc("CryptMemAlloc")
    procCryptMemFree         = crypt32.NewProc("CryptMemFree")
)

type CRYPTOAPI_BLOB struct {
    cbData uint32
    pbData *byte
}

func (b *CRYPTOAPI_BLOB) ToByteArray() []byte {
    d := make([]byte, b.cbData)
    copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
    return d
}

func PfxExportCertStore(storeHandle syscall.Handle, password string, flags uint32) (returnData []byte, err error) {

    var pfxBlob CRYPTOAPI_BLOB

    r1, _, _ := syscall.Syscall6(procPFXExportCertStoreEx.Addr(), 5,
        uintptr(storeHandle),                                        //hStore
        uintptr(unsafe.Pointer(&pfxBlob)),                           //*pPFX
        uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(password))), //szPassword
        0,              //*pvPara
        uintptr(flags), //dwFlags
        0)

    r2, _, _ := syscall.Syscall(procCryptMemAlloc.Addr(), 1, uintptr(unsafe.Pointer(&pfxBlob.cbData)), 0, 0)

    p := unsafe.Pointer(&r2)
    q := (*byte)(p)
    pfxBlob.pbData = q
    defer syscall.Syscall(procCryptMemFree.Addr(), 1, uintptr(unsafe.Pointer(pfxBlob.pbData)), 0, 0)

    r3, _, _ := syscall.Syscall6(procPFXExportCertStoreEx.Addr(), 5,
        uintptr(storeHandle),                                        //hStore
        uintptr(unsafe.Pointer(&pfxBlob)),                           //*pPFX
        uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(password))), //szPassword
        0,              //*pvPara
        uintptr(flags), //dwFlags
        0)


    returnData = pfxBlob.ToByteArray()
    return
}

(我已经删除了错误处理以便阅读)。第一次调用PFXExportCertStoreEx只返回大小,一旦我们有了大小,我们可以调用PFXExportCertStoreEx来分配一个缓冲区,然后将相同的指针传递给PFXExportCertStoreEx,但这次它有了分配的缓冲区,我们会得到完整的PFX文件返回。

英文:

JimB's answer is most certainly correct, but I want to add this for followup in case anyone else is going down this path. The actual code that I had to use to get the PFX file into CRYPTOAPI_BLOB was:

var (
crypt32                  = syscall.NewLazyDLL(&quot;crypt32.dll&quot;)
procPFXExportCertStoreEx = crypt32.NewProc(&quot;PFXExportCertStoreEx&quot;)
procCryptMemAlloc        = crypt32.NewProc(&quot;CryptMemAlloc&quot;)
procCryptMemFree         = crypt32.NewProc(&quot;CryptMemFree&quot;)
)
type CRYPTOAPI_BLOB struct {
cbData uint32
pbData *byte
}
func (b *CRYPTOAPI_BLOB) ToByteArray() []byte {
d := make([]byte, b.cbData)
copy(d, (*[1 &lt;&lt; 30]byte)(unsafe.Pointer(b.pbData))[:])
return d
}
func PfxExportCertStore(storeHandle syscall.Handle, password string, flags uint32) (returnData []byte, err error) {
var pfxBlob CRYPTOAPI_BLOB
r1, _, _ := syscall.Syscall6(procPFXExportCertStoreEx.Addr(), 5,
uintptr(storeHandle),                                        //hStore
uintptr(unsafe.Pointer(&amp;pfxBlob)),                           //*pPFX
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(password))), //szPassword
0,              //*pvPara
uintptr(flags), //dwFlags
0)
r2, _, _ := syscall.Syscall(procCryptMemAlloc.Addr(), 1, uintptr(unsafe.Pointer(&amp;pfxBlob.cbData)), 0, 0)
p := unsafe.Pointer(&amp;r2)
q := (*byte)(p)
pfxBlob.pbData = q
defer syscall.Syscall(procCryptMemFree.Addr(), 1, uintptr(unsafe.Pointer(pfxBlob.pbData)), 0, 0)
r3, _, _ := syscall.Syscall6(procPFXExportCertStoreEx.Addr(), 5,
uintptr(storeHandle),                                        //hStore
uintptr(unsafe.Pointer(&amp;pfxBlob)),                           //*pPFX
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(password))), //szPassword
0,              //*pvPara
uintptr(flags), //dwFlags
0)
returnData = pfxBlob.ToByteArray()
return
}

(I have stripped the error handling to make it easier to read). The first call to PFXExportCertStoreEx just returns the size, and once we have the size we can do a call to PFXExportCertStoreEx to allocate a buffer, and then we pass the same pointer to PFXExportCertStoreEx, but this time it has the allocated buffer, and we get the full PFX file returned.

huangapple
  • 本文由 发表于 2016年2月26日 01:22:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/35634088.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定