在Go中调用PFXExportCertStoreEx不会返回数据

时间:2016-02-25 17:22:59

标签: go system-calls x509 certificate-store

我在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示例中我可以看到,这个应该正在工作。

2 个答案:

答案 0 :(得分:3)

这是预期的行为。

根据这个:https://msdn.microsoft.com/en-us/library/windows/desktop/aa387313(v=vs.85).aspxpPFX结构需要一个预先分配的缓冲区,其大小在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文件。