我在Windows上使用Go 1.6并尝试将证书容器导出到PFX(此处的最终目标是从证书存储区访问可导出的私钥)。
我打开了一个内存存储并将证书插入到商店中:
import argparse
from apiclient.discovery import build
import httplib2
from oauth2client import client
SERVICE_ACCOUNT_EMAIL = (
'myaccountemail.com')
# Declare command-line flags.
argparser = argparse.ArgumentParser(add_help=False)
argparser.add_argument('package_name',
help='The package name. Example: com.android.sample')
def main():
# Load the key in PKCS 12 format that you downloaded from the Google APIs
# Console when you created your Service account.
f = file('mykeyname.p12', 'rb')
key = f.read()
f.close()
# HERE IS THE EXCEPTION
credentials = client.SignedJwtAssertionCredentials(
SERVICE_ACCOUNT_EMAIL,
key,
scope='https://www.googleapis.com/auth/androidpublisher')
http = httplib2.Http()
http = credentials.authorize(http)
...
现在我要生成该商店的PFX。我已经定义了一个包含data blob的结构,并希望使用PFXExportCertStoreEx来获取商店的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)
此一半有效。
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
总是 {{ 1}}。
看到它意味着要用一个指针填充,我已经尝试将其声明为Data
和<nil>
(只是为了查看是否任何被填充),但没有。该值始终未触及(如果我手动将垃圾数据放入其中,则在执行系统调用后垃圾数据仍然存在)。
我是否错误地定义了结构?在Go中完成这项工作的例子很少,但从众多C示例中我可以看到,这个应该正在工作。
答案 0 :(得分:3)
这是预期的行为。
根据这个:https://msdn.microsoft.com/en-us/library/windows/desktop/aa387313(v=vs.85).aspx,pPFX
结构需要一个预先分配的缓冲区,其大小在cbData
字段中,将根据复制的数据大小进行更新英寸
如果调用pbData
等于NULL
,则只更新cbData
字段以反映输出缓冲区所需的大小。
答案 1 :(得分: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文件。