Microsoft CNG - создание самозаверяющего сертификата в памяти с использованием функций BCrypt - PullRequest
3 голосов
/ 08 января 2020

Я использую API шифрования Microsoft CNG и пытаюсь создать самозаверяющий сертификат.

У нас есть код, использующий метод CertCreateSelfSignCertificate в сочетании с NCryptOpenStorageProvider и NCryptCreatePersistedKey для создания пары ключей.

Проблема, с которой я сталкиваюсь сейчас, заключается в том, что приведенная выше комбинация создает ключ, который заканчивается в крипто магазине windows. Я явно не хочу хранить ключи там, я хочу, чтобы сертификат и закрытый ключ были в памяти, поскольку я планирую затем записать их в зашифрованное / защищенное хранилище по нашему выбору.

Из того, что я Я был в состоянии сказать, что семейство функций BCrypt предназначено для использования в памяти, и действительно я могу использовать BCryptGenerateKeyPair, чтобы сделать это, но тогда CertCreateSelfSignCertificate не работает как это ожидает ключевой поставщик хранилища.

Есть ли способ решить эту проблему? Я думал либо попытаться как-то сделать временного провайдера хранилища ключей в памяти, либо сделать это сложным путем и создать весь бланк сертификата X509 самостоятельно, используя сложную цепочку вызовов CryptEncodeObjectEx. Документация / справочная информация и примеры кода для такого рода вещей ужасны, и я изо всех сил пытался найти что-нибудь, несмотря на интенсивное поиск в Google: - (

Любая помощь для различных идей или примеров кода, которые могли бы работать, очень ценилась бы

1 Ответ

3 голосов
/ 08 января 2020

Следующий код является точным кодом из одного из моих приложений, которые я делаю (за исключением нескольких изменений имени приложения в коде.)

Он создает самозаверяющий сертификат в памяти и добавляет его в локальный системный магазин. Несколько настроек, и вы можете получить сам контекст сертификата. Он использует API CNG Next Generation, чтобы оставаться современным.

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;
}

Пожалуйста, дайте мне знать, если это поможет вам. Спасибо.

...