Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline s_aa10  
#1 Оставлено : 14 апреля 2021 г. 16:24:33(UTC)
s_aa10

Статус: Новичок

Группы: Участники
Зарегистрирован: 13.04.2021(UTC)
Сообщений: 2
Российская Федерация

Здравствуйте!

Написал консольную программу на C++ для формирования подписи сообщения в Честный знак. На компьютере установлен CSP 5.0.11455 KC1.
Программа несколько месяцев работала, все устраивало. Потом случайно обнаружил, что время от времени, закономерности
не установлено, вызов CryptSignMessage бывает неудачен, GetLastError() возвращает 0xC0000225. Где-то из 10 запусков один раз не
срабатывает. Вот сделал пример.
Как такое может быть? Подтолкните не верный путь.

Код:

#define CRYPT_SIGN_MESSAGE_PARA_HAS_CMS_FIELDS
#include <iostream>
#include <Windows.h>
#include <io.h>
#include <fcntl.h>
#include "PureExampleC0000225.h"

#define ERROR_BUFFER_SIZE 2048
#define MAX_SIZE_CERT_NAME 1024
#define MY_MSG "CryptoAPI is a good way to handle security"

static BYTE* msg = nullptr;
static LPWSTR errmsg = nullptr;
static LPCWSTR HandleError(DWORD err, LPCWSTR custMsg);
static PCCERT_CONTEXT
FindCertificate(
    const HCERTSTORE hStore,
    const WCHAR* CertSearchString);
static DWORD Sign(BYTE* message, DWORD cbmess_len,
    BYTE** signMessage, LPCWSTR cert, LPCWSTR* errMessage, BOOL Detached);

int main()
{
    auto a = _setmode(_fileno(stdout), _O_U16TEXT);
    a = _setmode(_fileno(stderr), _O_U16TEXT);
    a = _setmode(_fileno(stdin), _O_U16TEXT);

    BYTE* pbMessage = (BYTE*)MY_MSG;
    DWORD cbMessage = (strlen((CHAR*)pbMessage) + 1);
    BYTE* signMessage = nullptr;
    LPCWSTR errMessage = nullptr;
    DWORD result = Sign(pbMessage, cbMessage, &signMessage, L"Common name (CN) сертификата",
        &errMessage, TRUE);
    if (result != -1)
    {
        std::wcout << L"Все хорошо!\n";
        ClearSignMemory();
    }
    else
    {
        std::wcout << errMessage << "\n";
        ClearErrorMemory();
    }
}

static DWORD Sign(BYTE* message, DWORD cbmess_len,
    BYTE** signMessage, LPCWSTR cert, LPCWSTR* errMessage, BOOL Detached)
{
    DWORD cbsignMessage = 0;
    HCERTSTORE certStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
        NULL, CERT_STORE_OPEN_EXISTING_FLAG |
        CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG, L"MY");
    if (certStore != nullptr)
    {
        PCCERT_CONTEXT certContext = FindCertificate(certStore, cert);
        if (certContext != nullptr)
        {
            CRYPT_OBJID_BLOB hashParam;
            hashParam.cbData = 0;
            hashParam.pbData = nullptr;
            CRYPT_ALGORITHM_IDENTIFIER hashAlg;
            hashAlg.pszObjId = (LPSTR)"1.2.643.7.1.1.2.2";
            hashAlg.Parameters = hashParam;
            CRYPT_ALGORITHM_IDENTIFIER hashEncryptionAlg;
            hashEncryptionAlg.pszObjId = (LPSTR)"1.2.643.7.1.1.1.1";
            hashEncryptionAlg.Parameters = hashParam;
            CRYPT_SIGN_MESSAGE_PARA signPara;
            signPara.cbSize = sizeof(signPara);
            signPara.dwMsgEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
            signPara.pSigningCert = certContext;
            signPara.HashAlgorithm = hashAlg;
            signPara.pvHashAuxInfo = nullptr;
            signPara.cMsgCert = 1;
            signPara.rgpMsgCert = &certContext;
            signPara.cMsgCrl = 0;
            signPara.cAuthAttr = 0;
            signPara.rgAuthAttr = NULL;
            signPara.cUnauthAttr = 0;
            signPara.dwFlags = 0;
            signPara.dwInnerContentType = 0;
            signPara.HashEncryptionAlgorithm = hashEncryptionAlg;
            signPara.pvHashEncryptionAuxInfo = 0;

            const BYTE* MessageArray[] = { message };
            DWORD_PTR MessageSizeArray[1];
            MessageSizeArray[0] = cbmess_len;

            // !!!!!!!!!! вот здесь бывает ошибка, 1 раз в 10 запусков примерно, случайным образом.
            if (!CryptSignMessage(
                &signPara,
                Detached,
                1,
                MessageArray,
                MessageSizeArray,
                NULL,
                &cbsignMessage))
            {
                *errMessage = HandleError(GetLastError(), L"Calculation size of buffer is failed!!!.");
                CertFreeCertificateContext(certContext);
                CertCloseStore(certStore, 0);
                return -1;
            }

            msg = new BYTE[cbsignMessage];

            if (!CryptSignMessage(
                &signPara,
                Detached,
                1,
                MessageArray,
                MessageSizeArray,
                msg,
                &cbsignMessage))
            {
                *errMessage = HandleError(GetLastError(), L"Sign message is failed.");
                delete[] msg;
                CertFreeCertificateContext(certContext);
                CertCloseStore(certStore, 0);
                return -1;
            }

            *signMessage = msg;
            CertFreeCertificateContext(certContext);
            CertCloseStore(certStore, 0);
            return cbsignMessage;
        }
        else
        {
            *errMessage = HandleError(GetLastError(), L"Find certificate is failed.");
            CertCloseStore(certStore, 0);
            return -1;
        }
    }
    else
    {
        *errMessage = HandleError(GetLastError(), L"Find certificate store is failed.");
        return -1;
    }
}

static PCCERT_CONTEXT
FindCertificate(
    const HCERTSTORE hStore,
    const WCHAR* CertSearchString)
{
    PCCERT_CONTEXT capiCertificate = NULL;
    WCHAR certname[MAX_SIZE_CERT_NAME] = { 0 };

    for (;;)
    {
        capiCertificate = CertEnumCertificatesInStore(hStore, capiCertificate);
        if (NULL == capiCertificate)
        {
            break;
        }

        if (FALSE ==
            CertGetNameStringW(capiCertificate, CERT_NAME_ATTR_TYPE,
                0, (LPSTR)szOID_COMMON_NAME, certname, MAX_SIZE_CERT_NAME))
        {
            CertFreeCertificateContext(capiCertificate);
            capiCertificate = NULL;
            break;
        }

        if ((0 == wcsncmp(certname, CertSearchString, MAX_SIZE_CERT_NAME)))
        {
            break;
        }
    }
    return capiCertificate;
}

static LPCWSTR HandleError(DWORD err, LPCWSTR custMsg)
{
    errmsg = new WCHAR[ERROR_BUFFER_SIZE];
    DWORD nSize = ERROR_BUFFER_SIZE;
    wcscpy_s(errmsg, ERROR_BUFFER_SIZE, custMsg);
    wcscat_s(errmsg, ERROR_BUFFER_SIZE, L"\n");
    wcscat_s(errmsg, ERROR_BUFFER_SIZE, L"GetLastError: ");
    _ultow_s(err, errmsg + wcslen(errmsg), nSize - wcslen(errmsg), 10);
    wcscat_s(errmsg, ERROR_BUFFER_SIZE, L"\n");
    FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        nullptr, err, 0, errmsg + wcslen(errmsg), nSize - wcslen(errmsg), nullptr);
    return errmsg;
}

void ClearSignMemory()
{
    if (msg != nullptr)
    {
        delete msg;
        msg = nullptr;
    }
}

void ClearErrorMemory()
{
    if (errmsg != nullptr)
    {
        delete errmsg;
        errmsg = nullptr;
    }
}


Offline Максим Коллегин  
#2 Оставлено : 15 апреля 2021 г. 10:41:14(UTC)
Максим Коллегин

Статус: Сотрудник

Группы: Администраторы
Зарегистрирован: 12.12.2007(UTC)
Сообщений: 6,377
Мужчина
Откуда: КРИПТО-ПРО

Сказал «Спасибо»: 32 раз
Поблагодарили: 706 раз в 614 постах
Попробуйте обновить CSP до 5r2
Знания в базе знаний, поддержка в техподдержке
Offline s_aa10  
#3 Оставлено : 21 апреля 2021 г. 11:28:52(UTC)
s_aa10

Статус: Новичок

Группы: Участники
Зарегистрирован: 13.04.2021(UTC)
Сообщений: 2
Российская Федерация

Для последней версии CSP нужна другая лицензия? Сейчас CSP 5.0.11455 KC1. Если я установлю последнюю версию в пробном варианте, какой срок она у меня будет действовать? В сентябре 2020 г. я устанавливал на этом компьютере последнюю на тот момент пробную версию. Потом она закончилась и мне установили 5.0.11455 на которую есть лицензия. Смогу я еще поработать пробный период? Рисковать не могу, постоянно приходится подписывать важные данные.
Offline Максим Коллегин  
#4 Оставлено : 21 апреля 2021 г. 11:49:34(UTC)
Максим Коллегин

Статус: Сотрудник

Группы: Администраторы
Зарегистрирован: 12.12.2007(UTC)
Сообщений: 6,377
Мужчина
Откуда: КРИПТО-ПРО

Сказал «Спасибо»: 32 раз
Поблагодарили: 706 раз в 614 постах
Для 5R2 нужна лицензия 5.0.
Знания в базе знаний, поддержка в техподдержке
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.