首页 > 解决方案 > 如何获取先前导入到 Windows Cert: 存储(在 Delphi 中)的公共证书的 CNG 密钥句柄?

问题描述

我需要使用CNG验证消息签名 (RSA )。唯一的问题是如果我将公共证书存储在 Windows 证书(Cert:\CurrentUser\My)中,如何获取 CNG 密钥句柄NCRYPT_KEY_HANDLE 或 BCRYPT_KEY_HANDLE )。我正在使用一个

NCryptOpenStorageProvider({out}hProv, MS_KEY_STORAGE_PROVIDER, 0)

我试图让公钥句柄使用

NCryptOpenKey(hProv, {out}hKey, PWideChar('my.test.com'), AT_KEYEXCHANGE, 0) 

但似乎NCryptOpenKey () 只能打开也有私钥的证书。

我也在查看BCryptImportKeyPair () 但这需要在我不知道如何实现的BCRYPT_RSAKEY_BLOB结构中拥有公钥。

我看到的最后一个函数是NCryptImportKey () 但这又只适用于private keys

任何人都知道如何使用 CNG 获取公钥句柄?我在一个文件(cer/pem)中有公钥,我将它导入到 WindowsCert:商店,但如果你知道如何将它直接从文件加载到 CNG 密钥句柄,我也会很高兴。

标签: signaturecng

解决方案


NCrypt* 函数适用于存储在密钥存储提供程序中的持久密钥对。如果您在证书存储中导入证书并且此证书不包含私钥,则公钥将不会保存在 KSP 中。
您可以使用函数CryptImportPublicKeyInfoEx2来获取 BCRYPT_KEY_HANDLE。
C中的示例代码:

HCERTSTORE hStore = nullptr;
    PCCERT_CONTEXT pCert = nullptr;
    BCRYPT_KEY_HANDLE hKey = nullptr;

    /* Open MY certificate store */
    hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY");
    if (!hStore) {
        goto Exit;
    }

    /* Find your certificate in store. For example search by subject name */
    pCert = CertFindCertificateInStore(hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, L"subject name", nullptr);
    if (!pCert) {
        goto Exit;
    }

    /* Or if you want to load certificate from file (assuming you read file to cert_data): 

        pCert = CertCreateCertificateContext(X509_ASN_ENCODING, cert_data, cert_size);

    */

    /* Now you can create BCRYPTKEY_HANDLE from your public key */
    if (!CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, &pCert->pCertInfo->SubjectPublicKeyInfo, 0, nullptr, &hKey)) {
        goto Exit;
    }

    /* Now you can verify signature with BCryptVerifySignature(hKey...) */


Exit:
    /* Don't forget to free handle after use */
    if (hKey) {
        BCryptDestroyKey(hKey);
    }
    if (pCert) {
        CertFreeCertificateContext(pCert);
    }
    if (hStore) {
        CertCloseStore(hStore, 0);
    }
    return 0;

推荐阅读