【问题标题】:How CSP find the private key of certificate to perform cryptographic operations?CSP 如何找到证书的私钥来执行加密操作?
【发布时间】:2017-08-10 19:12:21
【问题描述】:

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

【问题讨论】:

  • 我会说这取决于使用的 CSP。如果证书由 USB 令牌的 CSP 管理,则它希望私钥出现在 USB 令牌上。
  • CSP 发现了什么机制并访问了用于加密操作的私钥?能详细点吗?
  • 我猜这取决于 CSP 使用的密钥库的位置和类型,而不是 CSP 本身。例如,USB 令牌通常需要 PKCS#11 驱动程序。 CSP 通过驱动程序“使用”密钥,但没有“获取”它,因为无法从令牌中提取私钥。但是,软件密钥库可以提供密钥或允许在不暴露内容的情况下使用它(如 Windows 密钥库)这是您要求的吗?
  • @pedrofb 是的!选择证书以签名时,CSP如何知道要使用的私钥? span>
  • U盘确实提供了证书和私钥,两者都是相关的。当您知道应该使用什么证书时,您会自动知道要使用什么密钥。

标签: windows digital-signature private-key cryptoapi


【解决方案1】:

当您将证书导入系统存储时,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]

因此,如果您希望导入的证书具有指向私钥的链接,则需要设置 CERT_KEY_PROV_INFO_PROP_ID。您可以使用CRYPT_KEY_PROV_INFO 结构和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,而后者又会调用 CertGetCertificateContextProperty(..., CERT_KEY_PROV_INFO_PROP_ID, ...)

【讨论】:

  • 谢谢。很好的解释。
  • @Thinh - 这个答案似乎是唯一真正回答你问题的答案。你为什么接受这个答案?答案有什么问题?
猜你喜欢
  • 2021-11-08
  • 1970-01-01
  • 2017-11-25
  • 2015-02-17
  • 2010-11-15
  • 1970-01-01
  • 2011-04-25
  • 2019-04-20
  • 2013-05-09
相关资源
最近更新 更多