MS CryptoAPI – 机器密钥库,错误0x80090016(NTE_BAD_KEYSET),带有certreq创建的密钥

摘要

我使用certreq创建了一个PKCS#10 CSR,并设置了Exportable=TRUE选项。 这在REQUEST位置下成功创建了一个密钥。 我还有一个有效的证书,钥匙在MY 。 如果我尝试访问其中任何一个,CryptoAPI报告错误代码0x80090016

到目前为止,在不同的访问权限下运行无法解决此问题。

目标

我的目标是获得MYREQUEST两个键。 如果我在其中任何一个上调用CryptAcquireContextA() ,它就会失败。

系统

Windows 7 x64

示例源代码

我的完整代码如下所示:

 hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, "REQUEST"); pCert = CertFindCertificateInStore(hStore, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR_A, "CERTIFICATE_SUBJECT", NULL); CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &len); pinfo = (CRYPT_KEY_PROV_INFO *) malloc(len); CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, pinfo, &len); provname = wide_to_asc(pinfo->pwszProvName); contname = wide_to_asc(pinfo->pwszContainerName); if(!CryptAcquireContextA(&hCryptProv, contname, provname, pinfo->dwProvType, 0)) { err = GetLastError(); fprintf(stderr, "Error: 0x%x\n", err); } CryptGetUserKey(hCryptProv, pinfo->dwKeySpec, &hUserkey); 

此代码主要是从OpenSSL capi引擎复制的。 由于引擎发生故障,我创建了尽可能小的代码来搜索错误。

错误

如果我运行它,它失败,输出Error: 0x80090016 。 根据微软的说法,这意味着三件事之一:

  • 密钥容器不存在。
  • 您无权访问密钥容器。
  • Protected Storage Service未运行。

到目前为止我做了什么?

  • 开始服务“保护存储”
  • 已validation的容器存在MMC和Local Computer证书管理单元
  • 在用户上下文中在用户存储上运行相同的代码 – 它工作正常

文件系统权限

经过一些谷歌搜索,我试图更改文件系统的权限。 我通过查看代码的contname变量并搜索文件找到了这些文件。 我更改了对它们的权限(更准确,我更改了父文件夹的权限)。 虽然这解决了MY的问题,但似乎我无法为REQUEST更改它。

这里需要注意的是我的MY容器似乎在这里:

 %APPDATA%\Microsoft\Crypto\RSA\S-1-5-21-1650336054-1974872081-316617838-545102 

对于REQUEST我发现它在不同的地址:

 %ALLUSERSPROFILE%\Microsoft\Crypto\RSA\MachineKeys 

我不确定这里的工作方式,所以我无法解释为什么它会将它们放在不同的位置(一个是以用户为中心,另一个是系统文件夹)。 MY商店是使用常规管理员提示和命令certreq -new inf_file.inf cert-csr.csr ,在我收到证书后,我发出了certreq -accept cert.pem 。 然后我使用相同的命令创建了一个新的csr。

不同的权限级别

我尝试使用以下权限执行我的程序:

  • 我的本地用户帐户
  • 管理员提示(cmd->以管理员身份启动)
  • 权限\系统( whoami输出)

为了接收服务提示,我根据MaaSters Center的提示执行了psexec.exe –ids cmd.exe

最后的话

任何有关如何进一步缩小此问题的帮助或指导将不胜感激。

我终于能够解决这个问题了,它比我想象的要简单得多。 我确信我会收到一个明确的容器名称,并且不需要更具体,但CryptAcquireContext实际上要求我传递一个标志CRYPT_MACHINE_KEYSET

所以我的函数调用必须如下所示:

 CryptAcquireContextA(&hCryptProv, contname, provname, pinfo->dwProvType, CRYPT_MACHINE_KEYSET) 

不幸的是,OpenSSL引擎不支持此function,因此您必须在引擎中自行更改它。

请参阅MSDN:“只有创建密钥容器和本地系统帐户的用户才能访问非管理员用户在没有此标志的情况下创建的密钥容器。”

完整的详细信息: https : //msdn.microsoft.com/en-us/library/windows/desktop/aa379886(v = vs。85).aspx