CSP如何找到证书的私钥进行加密操作?

How CSP find the private key of certificate to perform cryptographic operations?

我的问题是:应用调用CSP进行签名等加密操作时,CSP如何分别找到证书的私钥?
如果导入到cert存储的证书私钥不在本地计算机(USB令牌,外部存储,例如移动设备),它可以找到吗?

当您将证书导入系统存储时,Windows 会创建一个包含编码证书本身及其属性的 BLOB 结构。 BLOB 具有以下结构:

property1_id (4 bytes)
reserved = 0x00000001
property1_length (4 bytes)
property1_data[property1_length]
...
cert_property_id = 0x00000020
reserved = 0x00000001
cert_data_length (4 bytes)
cert_data[cert_data_length]

因此,如果您希望导入的证书有link私钥,您需要设置CERT_KEY_PROV_INFO_PROP_ID。您可以使用 CRYPT_KEY_PROV_INFO structure and CertSetCertificateContextProperty 函数实现。

例如:

#include <Windows.h>
#include <wincrypt.h>

void SetKeyLink()
{
    HCERTSTORE hStore = NULL;
    CRYPT_KEY_PROV_INFO key_prov_info = { 0 };
    PCCERT_CONTEXT pCertContext = nullptr;
    std::vector<BYTE> der_encoded_cert;

    hStore = CertOpenSystemStore(NULL, L"MY");
    if (!hStore)
    {
        goto Exit;
    }

    der_encoded_cert = LoadFromFile();

    pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, der_encoded_cert.data(), der_encoded_cert.size());
    if (!pCertContext)
    {
        goto Exit;
    }

    /* For legacy CSP */
    key_prov_info.dwProvType = PROV_RSA_AES; // Or YOUR_PROVIDER_TYPE
    key_prov_info.dwKeySpec = AT_SIGNATURE; // Or AT_KEYEXCHANGE
    key_prov_info.pwszContainerName = L"Your_key_name";
    key_prov_info.dwFlags = CERT_SET_KEY_PROV_HANDLE_PROP_ID;
    key_prov_info.cProvParam = 0;
    key_prov_info.pwszProvName = nullptr;
    key_prov_info.rgProvParam = 0;

    /*
    Or if you use CNG Key storage provider:

    // Or L"Your_CNG_key_storage_provider_name"
    key_prov_info.pwszProvName = L"Microsoft Software Key Storage Provider"; 
    key_prov_info.pwszContainerName = L"Your_key_name";
    key_prov_info.dwFlags = CERT_SET_KEY_PROV_HANDLE_PROP_ID;
    key_prov_info.dwProvType = 0;
    key_prov_info.dwKeySpec = 0;
    key_prov_info.cProvParam = 0;
    key_prov_info.rgProvParam = 0;
    */

    if (!CertSetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &key_prov_info))
    {
        goto Exit;
    }

    if (!CertAddCertificateContextToStore(hStore, pCertContext, CERT_STORE_ADD_ALWAYS, NULL))
    {
        goto Exit;
    }

    std::cout << "success";

Exit:

    if (pCertContext)
    {
        CertFreeCertificateContext(pCertContext);
    }

    if (hStore)
    {
        CertCloseStore(hStore, 0);
    }
    return;
}

现在你的证书看起来像这样(抱歉不是英语):

当Windows要获取私钥时,调用CryptAcquireCertificatePrivateKey which in turn calls CertGetCertificateContextProperty(..., CERT_KEY_PROV_INFO_PROP_ID, ...)