Search code examples
gosystem-callsx509certificate-store

Calling PFXExportCertStoreEx in Go does not return data


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, &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("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)

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 <nil>.

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.


Solution

  • 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.