本文介绍了MS CryptoAPI-错误为0x80090016的计算机密钥库(NTE_BAD_KEYSET),带有certreq创建的密钥的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I create a PKCS#10 CSR with certreq and have set the option Exportable=TRUE. This successfully creates a key under the location REQUEST. I also have a valid certificate with key in MY. If I try to access any one of them the CryptoAPI reports error code 0x80090016.

在不同的访问权限下运行至今无法解决此问题.

Running under different access rights could not solve this problem so far.

我的目标是同时获取MYREQUEST中的键.如果我在其中任何一个上调用CryptAcquireContextA(),它都会失败.

My goal is to get both the keys in MY and REQUEST. If I call CryptAcquireContextA() on any of those, it fails.

Windows 7 x64

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引擎复制的.由于引擎发生故障,我创建了最小的代码来搜索错误.

This code is mostly copied from the OpenSSL capi engine. Since the engine failed, I created the smallest possible code to search the error.

如果运行此命令,它将失败,并显示输出Error: 0x80090016.这表示根据 Microsoft 的三件事之一:

If I run this, it fails with the output Error: 0x80090016. This means one of three things according to Microsoft:

  • 密钥容器不存在.
  • 您无权访问密钥容器.
  • 受保护的存储服务未运行.
  • 已启动的服务受保护的存储"
  • 已验证的容器与MMC& Local Computer
  • 的证书管理单元
  • 在用户上下文中在用户存储区上运行相同的代码-确实有效
  • Started service "Protected Storage"
  • Verified container exists with MMC & Certificate Snap-In for Local Computer
  • Ran the same code on the User store in user context - it worked

在进行一些谷歌搜索之后,我尝试更改文件系统上的权限.我通过查看代码的contname变量并搜索文件来找到文件.我更改了对它们的权限(更准确地说,我更改了对父文件夹的权限).虽然这解决了MY的问题,但看来我无法更改REQUEST的问题.

After some googling, I tried to change permissions on the file system. I found the files by looking at the contname variable of my code and searching for the file. I changed permissions on them (more accurate, I changed permissions on the parent folder). While this fixed the issue for MY, it seems I cannot change it for REQUEST.

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

One note here is that my container for MY seems to be here:

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

对于REQUEST,我在另一个地址下找到它:

For REQUEST I found it under a different address:

%ALLUSERSPROFILE%\Microsoft\Crypto\RSA\MachineKeys

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

I am not sure on the workings here so I cannot explain why it would put them in different locations (one being user centric, the other one a system folder). The MY store was created with a regular administrator prompt and the command certreq -new inf_file.inf cert-csr.csr and after I received my certificate, I issued certreq -accept cert.pem. Then I created a new csr with the same command.

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

I tried to execute my program with the following privileges:

  • 我的本地用户帐户
  • 管理员提示(cmd->以管理员身份启动)
  • nt权限\系统(whoami输出)
  • my local user account
  • admin prompt (cmd->start as administrator)
  • nt authority\system (whoami output)

要接收服务提示,我根据 MaaSters中心

To recieve a service prompt, I executed psexec.exe –ids cmd.exe according to a tip from MaaSters Center

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

Any help or guidance on how to further narrow this problem down will be greatly appreciated.

推荐答案

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

I was finally able to solve this problem and it is a lot simpler than I thought. I was sure that I would receive an unambiguous container name and don't need to be more specific but CryptAcquireContext actually requires me to pass a flag CRYPT_MACHINE_KEYSET.

所以我的函数调用必须看起来像这样:

So my function call has to look like this:

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

不幸的是,OpenSSL引擎不支持此功能,因此您必须在引擎中自行对其进行更改.

Unfortunately this is not supported by the OpenSSL engine, so you would have to alter it yourself in the engine.

这篇关于MS CryptoAPI-错误为0x80090016的计算机密钥库(NTE_BAD_KEYSET),带有certreq创建的密钥的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-13 13:30