Крипто-Про CSP |
Этот пример демонстрирует использование следующих функций
//-------------------------------------------------------------------- // Пример создания подписи документа MSXML 5.0 на ключе, получаемом по // имени ключевого контейнера. Имя контейнера, в свою очередь, получается // из расширенных свойств заданного сертификата. // Данная программа имеет два аргумента командной строки: // 1) Имя исходного XML-документа (документ должен соответствовать // шаблону, приведенному в примере). // 2) Имя сертификата. // Подписанным (выходным) XML-документом является файл "out_signature.xml". //-------------------------------------------------------------------- #include <tchar.h> #include <stdio.h> #import <msxml5.dll> using namespace MSXML2; #define DSIGNS "xmlns:ds='http://www.w3.org/2000/09/xmldsig#'" void HandleError(char *s); //------------------------------------------------------------- // Объявление и инициализация переменных. IXMLDOMDocument3Ptr xmldoc = NULL; IXMLDigitalSignaturePtr xmldsig = NULL; VARIANT_BOOL objectsAreInitialized = VARIANT_FALSE; PCCERT_CONTEXT pContext = NULL ; // Контекст сертификата HCERTSTORE hStore = NULL; // Дескритор хранилища сертификатов HCRYPTPROV hProv = 0 ; // Дескриптор криптопровайдера DWORD dwPropId = CERT_KEY_PROV_INFO_PROP_ID; // Параметр для получения информации // из свойств сертификата BYTE *pbData; // Указатель на буфер данных, получаемых из свойств сертификата. DWORD cbData; // Длина буфера данных TCHAR* fileName = NULL; //Имя подписываемого XML-документа TCHAR* userName = NULL; //Имя сертификата, используемого для подписи HRESULT hr; //Переменные, которые используются BSTR bstr = NULL; //для получения XML документа #undef CERT_FIND_SUBJECT_STR #ifdef UNICODE #define CERT_FIND_SUBJECT_STR CERT_FIND_SUBJECT_STR_W #else #define CERT_FIND_SUBJECT_STR CERT_FIND_SUBJECT_STR_A #endif // !UNICODE //--------------------------------------------------------------------------- // Описание функции загрузки XML-документа. //--------------------------------------------------------------------------- VARIANT_BOOL LoadXML(_bstr_t sigFile) { if (!objectsAreInitialized) { printf("Must initialize objects before loading signature.\n"); return VARIANT_FALSE; } if (xmldoc->load(sigFile) == VARIANT_FALSE) { printf("Can't load %s\n", (LPCSTR)sigFile); return VARIANT_FALSE; } xmldoc->setProperty("SelectionNamespaces", DSIGNS); //------------------------------------------------------------------------------ // Определение свойств подписи в соответствии с DOM узлом <ds:Signature> // XML-документа. xmldsig->signature = xmldoc->selectSingleNode(".//ds:Signature"); if (xmldsig->signature == NULL) { printf("Failed to set the signature property.\n"); return VARIANT_FALSE; } return VARIANT_TRUE; }// Конец описания функции LoadXML //--------------------------------------------------------------------------- // Описание функции подписи 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>, а затем добавляет сертификаты. //--------------------------------------------------------------------------- VARIANT_BOOL SignXML(XMLDSIG_WRITEKEYINFO fwWriteKeyInfo) { if (xmldsig->signature == NULL) { printf("Invalid signature template\n"); return false; } //------------------------------------------------------------------------------ // Открытие хранилища сертификатов "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"); } //----------------------------------------------------------------- // Получение сертификата с заданным именем из хранилища сертификатов. pContext = CertFindCertificateInStore( hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, userName, NULL); if(pContext == NULL) { HandleError("There is no such a certificate in the store\n"); } //-------------------------------------------------------------------------- // Указатель на структуру CRYPT_KEY_PROV_INFO, содержащую подробную информацию // о ключевом контейнере. CRYPT_KEY_PROV_INFO *pbData; //-------------------------------------------------------------------------- // Получение информации из расширенных свойств контекста сертификата. Определение размера // возвращаемых данных. 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 "); } //------------------------------------------------------------------------- // Выделение памяти. 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 "); } //-------------------------------------------------------------------------- // Освобождение контекста сертификата. 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); } //---------------------------------------------------- // Создание ключа подписи по полученному имени ключевого контейнера. IXMLDSigKeyPtr pKey = xmldsig->createKeyFromCSP(pbData->dwProvType, pbData->pwszProvName, pbData->pwszContainerName, 0); if (pKey==NULL) { printf("Invalid key\n"); return false; } //---------------------------------------------------- // Подпись XML-документа на полученном ключе. IXMLDSigKeyPtr pKeyOut = xmldsig->sign(pKey, fwWriteKeyInfo); if (NULL == pKeyOut) { printf("sign failed.\n"); return false; } printf("The specified data was signed successfully.\n"); printf("Resultant signature:\n"); printf((LPCSTR)xmldoc->xml); //---------------------------------------------------- // Запись подписи в файл "out_signature.xml". hr = xmldoc->get_xml(&bstr); printf("\n"); printf("out_signature.xml:\n%S\n", bstr); { FILE * f; if( (f = fopen("out_signature.xml","w")) == NULL) HandleError( "The file 'out_signature.xml' was not opened\n" ); else printf( "The file 'out_signature.xml' was opened\n" ); fprintf(f,"%S",bstr); if( fclose( f ) ) HandleError( "The file 'out_signature.xml' was not closed\n" ); } return true; }// Конец описания SignXML //------------------------------------------------------------------------------- // Описание функции инициализации объектов. //------------------------------------------------------------------------------- VARIANT_BOOL initObjects() { if (FAILED(xmldsig.CreateInstance(__uuidof(MXDigitalSignature50)) )) { printf("Installation of msxml5 is required to run this app.\n"); return VARIANT_FALSE; } if (FAILED(xmldoc.CreateInstance(__uuidof(DOMDocument50)) )) { printf("Installation of msxml5 is required to run this app.\n"); return VARIANT_FALSE; } xmldoc->async = VARIANT_FALSE; xmldoc->validateOnParse = VARIANT_FALSE; xmldoc->preserveWhiteSpace = VARIANT_TRUE; xmldoc->resolveExternals = VARIANT_FALSE; objectsAreInitialized = VARIANT_TRUE; return VARIANT_TRUE; }// Конец описания initObjects //------------------------------------------------------------------------------ // Описание функции очистки объектов. //------------------------------------------------------------------------------- void cleanObjects() { if (xmldoc) xmldoc.Release(); if (xmldsig) xmldsig.Release(); }// Конец описания cleanObjects //------------------------------------------------------------------------------ // Подпись XML-документа на основе сертификата. //------------------------------------------------------------------------------ void _tmain(int argc, TCHAR **argv) { //------------------------------------------------------------------------------ // Инициализация COM библиотеки. if ( CoInitialize(NULL) == E_FAIL) { printf("can't initialize COM Lib\n"); exit(-1); } //------------------------------------------------------------------------------ // Инициализация объектов. if (!initObjects()) { cleanObjects(); exit(-1); } //------------------------------------------------------------------------------ // Разбор командной строки. if (argc < 2) { printf("Please, enter tne name of xml-file and certificate name!\n"); exit(-1); } fileName = argv[1]; userName = argv[2]; printf("Verifying %S\n\n", fileName); if (VARIANT_TRUE == LoadXML((_bstr_t)fileName)) { //------------------------------------------------------------------------------ // Подпись XML-документа. printf("Sign with fwWriteKeyInfo = CERTIFICATES:\n"); SignXML(CERTIFICATES); } //------------------------------------------------------------------------------ // Очистка. cleanObjects(); CoUninitialize(); }// Конец main
Windows 2000/XP/2003: Необходимо Windows 2000 SP4 или
старше с Internet Explorer 6.0 или старше и MSXML 5.0.
Что Вы
думаете по поводу данной статьи? |
Закажите CD c Крипто-Про CSP |