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

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline mtv06  
#1 Оставлено : 27 декабря 2017 г. 19:19:58(UTC)
mtv06

Статус: Активный участник

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

Добрый вечер! Пробую подписать xml согласно примеру XMLSignForVerify, но когда доходит до подписания документа, вываливается с ошибкой - "Вызвано исключение по адресу 0x60BF1152 (cpxml5.dll) в FSS2.exe: 0xC0000005: нарушение прав доступа при чтении по адресу 0x00000000." Я так понимаю это из-за того, что указатель &signKeyRef на объект к которому я обращаюсь равен NULL. В чем может быть дело? Подскажите пожалуйста!!! Задача горит!!!
Цитата:
// Подпись XML-документа на полученном ключе.
CComPtr<IXMLDSigKey> signKeyRef;
if (FAILED(xmldsig->sign(keyRef, fwWriteKeyInfo, &signKeyRef))
|| !signKeyRef)
{
printf("sign failed.\n");
system("pause");
return false;
}
Offline Максим Коллегин  
#2 Оставлено : 27 декабря 2017 г. 19:23:27(UTC)
Максим Коллегин

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

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

Сказал «Спасибо»: 37 раз
Поблагодарили: 722 раз в 626 постах
Не работает наш пример или модифицированный?
Знания в базе знаний, поддержка в центре поддержки
Offline mtv06  
#3 Оставлено : 27 декабря 2017 г. 19:35:43(UTC)
mtv06

Статус: Активный участник

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

Нет, немного модифицировал. Запускаю не из командной строки. Задал xml и имя сертификата, который требуется использовать.
Цитата:
// Начало примера (не следует удалять данный комментарий, он используется
// для автоматической сборки документации)
//--------------------------------------------------------------------
// Пример создания подписи документа MSXML 5.0 на ключе, получаемом по
// имени ключевого контейнера. Имя контейнера, в свою очередь, получается
// из расширенных свойств заданного сертификата.
// Данная программа имеет два аргумента командной строки:
// 1) Имя исходного XML-документа (документ должен соответствовать
// шаблону, приведенному в примере).
// 2) Имя сертификата.
// Подписанным (выходным) XML-документом является файл "out_signature.xml".
// Замечание: под win32 рекомендуется использовать _s аналоги CRT функций.
//--------------------------------------------------------------------
//#import <C:\\Program Files (x86)\\Common Files\\microsoft shared\\OFFICE11\\msxml5.dll>
//using namespace MSXML2;
#pragma comment(lib, "crypt32.lib")
#pragma comment (lib, "cryptui.lib")

#include <atlbase.h>
#include <wincrypt.h>
#include <cryptuiapi.h>
#include <iostream>
#include <windows.h>
#include "C:\Users\aivanov\Documents\Visual Studio 2017\Projects\FSS2\Debug\include\msxml5.h"


#define DSIGNS L"xmlns:ds='http://www.w3.org/2000/09/xmldsig#'"
#define OUTFILE L"out_signature.xml"
#define CERT_STORE_NAME L"MY"
#define SIGNER_NAME L"Иванов Иван Сергеевич"

//-------------------------------------------------------------
// Объявление и инициализация переменных.

CComPtr<IXMLDOMDocument2> xmldoc;
CComPtr<IXMLDigitalSignatureEx> xmldsig;

bool initObjects(void);
bool LoadXML(CComBSTR sigFile);
bool SetSignature(BSTR queryString);
bool SignXML(XMLDSIG_WRITEKEYINFO fwWriteKeyInfo, VARIANT outfile);
void HandleError(char *s);
HCERTSTORE hCertStore;
PCCERT_CONTEXT pCertContext;

using namespace std;
//------------------------------------------------------------------------------
// Подпись XML-документа на основе сертификата.
//------------------------------------------------------------------------------
int main()
{
// Инициализация COM библиотеки.
if (FAILED(CoInitialize(NULL)))
HandleError("can't initialize COM Lib");

// Разбор командной строки.
//if (argc < 2)
// HandleError("usage: XMLSignForVerify test.xml certname\n");

// Инициализация объектов.
if (!initObjects())
exit(-1);

//CComVariant sigFile(argv[1]);
CComBSTR sigFile;
sigFile = "<?xml version=\"1.0\" encoding=\"UTF - 8\"?> \
<ds:signatures xmlns : ds = \"http://www.w3.org/2000/09/xmldsig#\"> \
<ds:Signature Id = \"FirstSignature\" > \
<ds:SignedInfo> \
<ds:CanonicalizationMethod \
Algorithm = \"http://www.w3.org/TR/2001/REC-xml-c14n-20010315\" / > \
<ds:SignatureMethod \
Algorithm = \"http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411\" / > \
<ds:Reference URI = \"#obj\" \
Type = \"http://www.w3.org/2000/09/xmldsig#;Object\"> \
<ds:DigestMethod \
Algorithm = \"http://www.w3.org/2001/04/xmldsig-more#gostr3411\" / > \
<ds:DigestValue / > \
< / ds:Reference> \
< / ds:SignedInfo> \
<ds:SignatureValue / > \
<ds:Object Id = \"obj\" MimeType = \"text/xml\">Hello, World!< / ds:Object> \
<ds:KeyInfo>< / ds:KeyInfo> \
< / ds:Signature>";
printf("Signing %S\n\n", sigFile);
if (!LoadXML(sigFile))
exit(-1);

if (!SetSignature(CComBSTR(L".//ds:Signature")))
exit(-1);

// Подпись XML-документа.
CComVariant outfile(OUTFILE);
if (!SignXML(CERTIFICATES, outfile))
exit(-1);

return 0;
}

//---------------------------------------------------------------------------
// Описание функции загрузки XML-документа.
//---------------------------------------------------------------------------

bool LoadXML(CComBSTR sigFile)
{
VARIANT_BOOL isSuccessful = VARIANT_FALSE;
//if (FAILED(xmldoc->loadXML(sigFile, &isSuccessful)) || isSuccessful == VARIANT_FALSE)
if (FAILED(xmldoc->loadXML(sigFile, &isSuccessful)))
{
printf("Can't load %S\n", sigFile);
return false;
}
if (FAILED(xmldoc->setProperty(L"SelectionNamespaces", CComVariant(DSIGNS))))
{
printf("setProperty failed\n");
return false;
}
return true;
}
// Конец описания функции LoadXML

//------------------------------------------------------------------------------
// Определение свойств подписи в соответствии с DOM узлом <ds:Signature>
// XML-документа.

bool SetSignature(BSTR queryString)
{
CComPtr<IXMLDOMNode> signatureNode;
if (FAILED(xmldoc->selectSingleNode(queryString, &signatureNode)))
{
printf("Failed to get Signature node.\n");
return false;
}
if (FAILED(xmldsig->putref_signature(signatureNode)))
{
printf("Failed to set the signature property.\n");
return false;
}
signatureNode.Release();
// Попробуем тут же получить обратно и проверить
if (FAILED(xmldsig->get_signature(&signatureNode)) || !signatureNode)
{
printf("Invalid signature template\n");
system("pause");
//return false;
}
return true;
}


//---------------------------------------------------------------------------
// Описание функции подписи XML-документа.
//
// Данная функция имеет параметр fwWriteKeyInfo, отвечающий
// за заполнение шаблона подписанного (выходного) XML-документа.
// Шаблон подписанного (выходного) XML-документа изначально включает в себя
// три пустых элемента: <ds:DigestValue>, <ds:SignatureValue> и <ds:KeyInfo>.
// Первые два заполняются после выполнения функции SignXML(fwWriteKeyInfo).
// Последний будет заполнен только в том случае, если функции
// в качестве параметра fwWriteKeyInfo передаётся KEYVALUE.
// Параметр не меняется, если fwWriteKeyInfo = NOKEYINFO и всё
// содержимое элементов очищается в случае fwWriteKeyInfo = PURGE.
// Когда fwWriteKeyInfo = CERTIFICATES, заполняется элемент <X509Data>
// при условии, что сертификат ключа, который используется, доступен.
//
// Также параметр fwWriteKeyInfo может представлять собой комбинацию
// перечисленных выше значений, объединённых знаком "|" :
// KEYVALUE | CERTIFICATES - Добавляет значение ключа и сертификаты в <ds:KeyInfo>,
// не изменяя другие элементы.
// KEYVALUE | CERTIFICATES | PURGE - Сначала удаляет всё из <ds:KeyInfo>, а затем
// добавляет значение ключа и сертификаты.
// KEYVALUE | PURGE - Сначала удаляет всё из <ds:KeyInfo>,
// а затем добавляет значение ключа.
// CERTIFICATES | PURGE - Сначала удаляет всё из <ds:KeyInfo>,
// а затем добавляет сертификаты.
//---------------------------------------------------------------------------

bool SignXML(XMLDSIG_WRITEKEYINFO fwWriteKeyInfo, VARIANT outfile)
{
if (fwWriteKeyInfo & CERTIFICATES)
printf("Sign with fwWriteKeyInfo = CERTIFICATES:\n");

HCERTSTORE hStore = NULL; // Дескритор хранилища сертификатов
//------------------------------------------------------------------------------
// Открытие хранилища сертификатов "MY" текущего пользователя.
hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG |
CERT_SYSTEM_STORE_CURRENT_USER, L"MY");
if (!hStore)
{
HandleError("The store could not be opened!\n");
}
else
{
printf("The store is open!\n");
}

//-----------------------------------------------------------------
// Получение сертификата с заданным именем из хранилища сертификатов.
PCCERT_CONTEXT pContext = NULL; // Контекст сертификата
pContext = CertFindCertificateInStore(hStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR_W,
SIGNER_NAME, NULL);
if (pContext == NULL)
{
HandleError("There is no such a certificate in the store\n");
}

// Параметр для получения информации из свойств сертификата
DWORD dwPropId = CERT_KEY_PROV_INFO_PROP_ID;
DWORD cbData; // Длина буфера данных

//--------------------------------------------------------------------------
// Получение информации из расширенных свойств контекста сертификата.
// Определение размера возвращаемых данных.
if (CertGetCertificateContextProperty(pContext, dwPropId, NULL, &cbData))
{
printf("CertGetCertificateContextProperty was started for the 1-st time\n");
}
else
{
printf("CertGetCertificateContextProperty was started for the 1-st time\n");
HandleError("It's impossible to get the certificate property!\n ");
}

//--------------------------------------------------------------------------
// Указатель на структуру CRYPT_KEY_PROV_INFO, содержащую подробную информацию
// о ключевом контейнере.
CRYPT_KEY_PROV_INFO *pbData;

//-------------------------------------------------------------------------
// Выделение памяти.
if (pbData = (CRYPT_KEY_PROV_INFO*)malloc(cbData))
printf("Memory has been allocated.\n");
else
HandleError("Malloc operation failed. ");

//------------------------------------------------------------------------
// Получение подробной информации о ключевом контейнере из расширенных свойств
// контекста сертификата.
if (CertGetCertificateContextProperty(pContext, dwPropId, pbData, &cbData))
{
printf("CertGetCertificateContextProperty was started for the 2-nd time\n");
printf("ContainerName is %S ProvType = %d\n", pbData->pwszContainerName,
pbData->dwProvType);
}
else
{
printf("CertGetCertificateContextProperty was started for the 2-nd time\n");
HandleError("It's impossible to get the certificate property!\n ");
}


CComPtr<IXMLDSigKey> keyCSPRef;
if (FAILED(xmldsig->createKeyFromCSP(pbData->dwProvType,
pbData->pwszProvName, pbData->pwszContainerName, 0, &keyCSPRef))
|| !keyCSPRef)
{
printf("createKeyFromCSP failed.\n");
return false;
}

//----------------------------------------------------
// Создание ключа подписи по контексту сертификата.
CComPtr<IXMLDSigKeyEx> keyRef;
if (FAILED(xmldsig->createKeyFromCertContext((void*)pContext, &keyRef))
|| !keyRef)
{
printf("createKeyFromCertContext failed.\n");
return false;
}

//----------------------------------------------------
// Подпись XML-документа на полученном ключе.
CComPtr<IXMLDSigKey> signKeyRef;
if (FAILED(xmldsig->sign(keyRef, fwWriteKeyInfo, &signKeyRef))
|| !signKeyRef)
{
printf("sign failed.\n");
system("pause");
return false;
}

printf("The specified data was signed successfully.\n");
printf("Resultant signature:\n");
system("pause");

//--------------------------------------------------------------------------
// Освобождение контекста сертификата.
if (pContext)
CertFreeCertificateContext(pContext);

//--------------------------------------------------------------------------
// Закрытие хранилища сертификатов.

if (CertCloseStore(hStore, 0))
{
printf("Store was closed successfully!\n");
printf("\n");
}
else
{
printf("Attempt to close the store is failed\n");
exit(1);
}

CComBSTR bstrXml;
if (SUCCEEDED(xmldoc->get_xml(&bstrXml)))
{
printf("%S\n", bstrXml.m_str);
// Запись подписи в файл outfile.
if (FAILED(xmldoc->save(outfile))) {
printf("can't save the signed signature to file: %S.\n", outfile.bstrVal);
return false;
}
printf("signature saved to file: %S\n", outfile.bstrVal);
}
return true;
}// Конец описания SignXML

//-------------------------------------------------------------------------------
// Описание функции инициализации объектов.
//-------------------------------------------------------------------------------
bool initObjects(void)
{
if (FAILED(xmldsig.CoCreateInstance(__uuidof(MXDigitalSignature50))))
{
printf("Installation of msxml5 is required to run this app.\n");
return false;
}
if (FAILED(xmldoc.CoCreateInstance(__uuidof(DOMDocument50)))) {
printf("Installation of msxml5 is required to run this app.\n");
return false;
}
xmldoc->put_async(VARIANT_FALSE);
xmldoc->put_validateOnParse(VARIANT_FALSE);
xmldoc->put_preserveWhiteSpace(VARIANT_TRUE);
xmldoc->put_resolveExternals(VARIANT_FALSE);
return true;
}
// Конец описания initObjects

// Конец примера
// (не следует удалять данный комментарий, он используется
// для автоматической сборки документации)

//------------------------------------------------------------------------------
// В этом примере используется функция HandleError, функция обработки
// простых ошибок, для печати сообщения об ошибке в стандартный файл
// ошибок (stderr) и выхода из программы.
// В большинстве приложений эта функция заменяется другой функцией,
// которая выводит более полное сообщение об ошибке.
//------------------------------------------------------------------------------
void HandleError(char *s)
{
DWORD err = GetLastError();
printf("Error number : 0x%x\n", err);
printf("Error description: %s\n", s);
if (!err) err = 1;
system("pause");
exit(err);
}
Offline Максим Коллегин  
#4 Оставлено : 27 декабря 2017 г. 19:50:17(UTC)
Максим Коллегин

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

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

Сказал «Спасибо»: 37 раз
Поблагодарили: 722 раз в 626 постах
Скорее всего это не отработало:

// Создание ключа подписи по контексту сертификата.
CComPtr<IXMLDSigKeyEx> keyRef;
if (FAILED(xmldsig->createKeyFromCertContext((void*)pContext, &keyRef))
|| !keyRef)
{
printf("createKeyFromCertContext failed.\n");
return false;
}
Знания в базе знаний, поддержка в центре поддержки
Offline mtv06  
#5 Оставлено : 28 декабря 2017 г. 8:52:55(UTC)
mtv06

Статус: Активный участник

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

Ну keyRef не пуст - значит отработало. В чем может быть ещё дело?

Отредактировано пользователем 28 декабря 2017 г. 9:39:31(UTC)  | Причина: Не указана

RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.