CryptAcquireCertificatePrivateKey() 失败并出现错误 CRYPT_E_NO_KEY_PROPERTY

问题描述 投票:0回答:1

这是设置

AD CS(Windows Server 2019 Hyper-V 虚拟机)

  • 通过复制智能卡登录模板创建了一个新模板。
    将提供商更改为 Microsoft Software Key Storage Provider。 算法为 RSA,最小密钥大小为 2048。目的设置为 签名和加密。启用“允许导出私钥”。

客户端(Windows 10 Hyper-V 虚拟机)

  • 本机已加入与 AD CS 相同的域。 已安装 AD CS 根证书到受信任的根证书颁发机构。
    从新模板请求新证书。 得到了 证书并使用私钥将其导出到 pfx 文件并 密码。导出时选择这些选项“如果可能,包括证书路径中的所有证书”、“启用证书隐私”。

当我尝试使用以下代码导入私钥时,CertFindCertificateInStore() 返回错误 CRYPT_E_NO_KEY_PROPERTY。

 HANDLE hFile = CreateFileA(pfxPath.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
 if (hFile == INVALID_HANDLE_VALUE) {
     HandleError("Unable to open PFX file");
 }

 DWORD fileSize = GetFileSize(hFile, nullptr);
 std::vector<BYTE> fileData(fileSize);
 DWORD bytesRead;
 if (!ReadFile(hFile, fileData.data(), fileSize, &bytesRead, nullptr) || bytesRead != fileSize) {
     HandleError("Unable to read PFX file");
 }

 CloseHandle(hFile);

 CRYPT_DATA_BLOB pfxBlob = { static_cast<DWORD>(fileData.size()), fileData.data() };
 if (!PFXIsPFXBlob(&pfxBlob)) {
     HandleError("Invalid PFX file");
 }

 hStore = PFXImportCertStore(&pfxBlob, password.c_str(), CRYPT_EXPORTABLE);

 if (!hStore) {
     HandleError("Failed to import PFX certificate store");
 }

 certContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, nullptr);
 if (!certContext) {
     HandleError("Failed to find certificate in PFX store");
 }

 
 if (!CryptAcquireCertificatePrivateKey(certContext, CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG, nullptr, &hCryptProvOrNCryptKey, &dwKeySpec, &fCallerFreeProvOrNCryptKey)) {
     auto dw = GetLastError();
     HandleError("Failed to acquire private key");
 }

具有自签名证书,能够成功导入私钥并导出私钥。

我尝试传递 0 而不是 CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG,但仍然出现相同的错误。

感谢您的帮助。

winapi active-directory cryptography certificate private-key
1个回答
0
投票

CryptAcquireCertificatePrivateKey
返回错误
CRYPT_E_NO_KEY_PROPERTY

CryptAcquireCertificatePrivateKey
查找
CERT_KEY_PROV_INFO_PROP_ID
,如果不存在,则返回此类错误。

在证书

PFXImportCertStore
上设置
CERT_KEY_PROV_INFO_PROP_ID
,以防
PKCS12_NO_PERSIST_KEY
未使用,或
CERT_KEY_CONTEXT_PROP_ID
,如果我们使用此标志。但这并不适用于 pfx 中的所有证书,而仅适用于与 pfx 中的私钥相对应的公钥的证书。但你:

导出时选择这些选项“将所有证书包含在 证书路径(如果可能)”

pfx 中有多个证书,并且只有一个包含

CERT_KEY_PROV_INFO_PROP_ID
CERT_KEY_CONTEXT_PROP_ID
属性。

所以

CertFindCertificateInStore
我们需要
CertEnumCertificatesInStore
并检查存储中的每张证书,直到找到一个“好”。

在大多数情况下最好使用

PKCS12_NO_PERSIST_KEY
,否则私钥将存储在具有自动生成的随机名称的新密钥容器中。

代码可以是这样的:

CRYPT_DATA_BLOB PFX;
if (NOERROR ReadFromFile(pfxPath, &PFX.pbData, &PFX.cbData))
{
    if (HCERTSTORE hStore = PFXImportCertStore(&PFX, password, 
        CRYPT_EXPORTABLE|PKCS12_ALWAYS_CNG_KSP|PKCS12_NO_PERSIST_KEY))
    {
        PCCERT_CONTEXT pCertContext = 0;
        while(pCertContext = CertEnumCertificatesInStore(hStore, pCertContext))
        {
            CERT_KEY_CONTEXT ckc;
            ULONG cb = sizeof(ckc);
            if (CertGetCertificateContextProperty(pCertContext, CERT_KEY_CONTEXT_PROP_ID, &ckc, &cb))
            {
                // use ckc.hNCryptKey
                // not need call NCryptFreeObject(ckc.hNCryptKey);
                CertFreeCertificateContext(pCertContext);
                break;
            }
        }
        CertCloseStore(hStore, 0);
    }
    LocalFree(PFX.pbData);
}
© www.soinside.com 2019 - 2024. All rights reserved.