C++ Microsoft CNG-使用BCrypt函数在内存中创建自签名证书

C++ Microsoft CNG-使用BCrypt函数在内存中创建自签名证书,c++,visual-c++,cryptography,x509,cng,C++,Visual C++,Cryptography,X509,Cng,我正在使用Microsoft CNG加密API,并尝试创建一个自签名证书 我们有使用该方法的现有代码,结合和创建密钥对 我现在面临的问题是,上面的组合创建了一个密钥,该密钥最终位于windows crypto store中。我明确不想在那里存储密钥,我希望证书和私钥都在内存中,因为我计划将它们写入我们自己选择的加密/保护存储 据我所知,BCrypt系列函数是为内存使用而设计的,事实上我可以使用它来实现这一点,但是,CertCreateSelfSignCertificate不能像密钥存储提供程序所

我正在使用Microsoft CNG加密API,并尝试创建一个自签名证书

我们有使用该方法的现有代码,结合和创建密钥对

我现在面临的问题是,上面的组合创建了一个密钥,该密钥最终位于windows crypto store中。我明确不想在那里存储密钥,我希望证书和私钥都在内存中,因为我计划将它们写入我们自己选择的加密/保护存储

据我所知,BCrypt系列函数是为内存使用而设计的,事实上我可以使用它来实现这一点,但是,
CertCreateSelfSignCertificate
不能像密钥存储提供程序所期望的那样工作

有什么办法解决这个问题吗?我在想,要么尝试以某种方式创建一个临时内存密钥存储提供程序,要么以艰难的方式创建一个完整的X509证书blob,然后自己使用一个复杂的调用链来构建整个X509证书blob。关于这类东西的文档/参考和示例代码非常糟糕,尽管谷歌搜索了很多次,我还是很难找到任何东西:-(


非常感谢您对可能有效的不同想法或示例代码的任何帮助

以下代码正是我的一个应用程序中的代码(除了代码中对应用程序名称的一些更改)

它在内存中创建一个自签名证书,并将其添加到本地系统存储区。稍作调整,您就可以获得证书上下文本身。它使用CNG下一代API保持现代感

bool GenerateSelfSignedCertificate()
{
    auto result{ false };
    CERT_NAME_BLOB nameBlob{ 0 };
    CERT_EXTENSIONS certExtensions{ 0 };
    NCRYPT_PROV_HANDLE providerHandle{ 0 };
    NCRYPT_KEY_HANDLE keyHandle{ 0 };
    PCCERT_CONTEXT certContext{ nullptr };
    HCERTSTORE certStore{ nullptr };
    CRYPT_KEY_PROV_INFO keyProvInfo{
        const_cast<LPWSTR>(L"MyService_Key"), const_cast<LPWSTR>(MS_KEY_STORAGE_PROVIDER),
        0, NCRYPT_SILENT_FLAG, 0, nullptr, AT_KEYEXCHANGE
    };

    if (!CertStrToNameW(X509_ASN_ENCODING, L"CN=MyService", 0, nullptr, nameBlob.pbData,
        &nameBlob.cbData, nullptr))
        goto fail;
    nameBlob.pbData = new UCHAR[nameBlob.cbData];
    if (!CertStrToNameW(X509_ASN_ENCODING, L"CN=MyService", 0, nullptr, nameBlob.pbData,
        &nameBlob.cbData, nullptr))
        goto fail;
    if (NCryptOpenStorageProvider(&providerHandle, MS_KEY_STORAGE_PROVIDER, 0) != ERROR_SUCCESS)
        goto fail;
    if (NCryptCreatePersistedKey(providerHandle, &keyHandle, BCRYPT_RSA_ALGORITHM, L"MyService_Key",
        AT_KEYEXCHANGE, 0) != ERROR_SUCCESS)
        goto fail;
    if (NCryptFinalizeKey(keyHandle, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
        goto fail;
    certContext = CertCreateSelfSignCertificate(keyHandle, &nameBlob, 0, &keyProvInfo, nullptr,
        nullptr, nullptr, &certExtensions);
    if (!certContext)
        goto fail;
    certStore = CertOpenSystemStoreW(NULL, L"MY");
    if (!certStore)
        goto fail;
    if (!CertAddCertificateContextToStore(certStore, certContext, CERT_STORE_ADD_REPLACE_EXISTING, nullptr))
        goto fail;
    result = true;

fail:
    delete[] nameBlob.pbData;
    if (keyHandle)
        OutputDebugStringW(L"NCryptFinalizeKey successfully finalized the key for use in the certificate.\r\n");
    if (providerHandle)
        NCryptFreeObject(providerHandle);
    if (certStore)
        CertCloseStore(certStore, 0);
    if (certContext)
        CertFreeCertificateContext(certContext);
    return result;
}
bool GenerateSelfSignedCertificate()
{
自动结果{false};
证书名称BLOB nameBlob{0};
证书扩展证书扩展{0};
NCRYPT_PROV_HANDLE providerHandle{0};
NCRYPT_KEY_HANDLE keyHandle{0};
PCCERT_CONTEXT certContext{nullptr};
HCERTSTORE certStore{nullptr};
加密密钥提供信息密钥提供信息{
const_cast(L“MyService_Key”)、const_cast(MS_Key_STORAGE_PROVIDER),
0,NCRYPT_SILENT_标志,0,nullptr,AT_密钥交换
};
如果(!CertStrToNameW(X509\u ASN\u编码,L“CN=MyService”,0,nullptr,nameBlob.pbData,
&nameBlob.cbData,nullptr)
走向失败;
nameBlob.pbData=new-UCHAR[nameBlob.cbData];
如果(!CertStrToNameW(X509\u ASN\u编码,L“CN=MyService”,0,nullptr,nameBlob.pbData,
&nameBlob.cbData,nullptr)
走向失败;
if(NCryptOpenStorageProvider(&providerHandle,MS_KEY_STORAGE_PROVIDER,0)!=ERROR_SUCCESS)
走向失败;
if(NCryptCreatePersistedKey(providerHandle,&keyHandle,BCRYPT_RSA_算法,L“MyService_密钥”),
在密钥交换时,0)!=错误(成功)
走向失败;
if(NCryptFinalizeKey(钥匙手柄,NCRYPT_SILENT_标志)!=ERROR_SUCCESS)
走向失败;
certContext=CertCreateSelfSignCertificate(keyHandle,&nameBlob,0,&keyProvInfo,nullptr,
nullptr、nullptr和证书扩展);
如果(!certContext)
走向失败;
certStore=CertOpenSystemStoreW(空,L“我的”);
如果(!certStore)
走向失败;
如果(!CertAddCertificateContextToStore(certStore、certContext、CERT\u STORE\u ADD\u REPLACE\u EXISTING、nullptr))
走向失败;
结果=真;
失败:
删除[]nameBlob.pbData;
if(钥匙手柄)
OutputDebugStringW(L“NCryptFinalizeKey成功地确定了证书中使用的密钥。\r\n”);
if(提供程序句柄)
NCryptFreeObject(providerHandle);
if(证书库)
CertCloseStore(certStore,0);
如果(证书上下文)
CertFreeCertificateContext(certContext);
返回结果;
}

请让我知道这是否对您有帮助。谢谢。

谢谢!我修改了上面的代码,将keyName设置为nullptr,它似乎可以工作。如果我使用非null keyName运行两次,则第二次调用失败,NTE_存在,但使用null keyName,每次都会成功,这表明存在临时密钥。这正是我想要的@OrionEdwards没问题,很高兴听到它完全按照您的要求工作!您是对的,我应该说我设计了上面的代码,用于一次性创建一个名为object的证书,我很高兴您找到了它