英文:
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>
。
考虑到它应该被填充为一个指针,我尝试将其声明为*uintptr
和uint32
(只是为了看看是否有任何内容被填充进去),但是没有任何效果。该值始终保持不变(如果我手动在其中放入垃圾数据,那么在执行系统调用后,垃圾数据仍然存在)。
我是否错误地定义了这个结构体?在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, &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.
答案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("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
}
(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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论