Крипто-Про CSP |
В данном примере осуществляется создание и проверка двух независимых подписей XML-документа, а также осуществляется проверка цепочки сертификатов, начиная с сертификата, на котором осуществлялась подпись. Этот пример демонстрирует использование следующих функций
//-------------------------------------------------------------------- // Пример создания и проверки двух независимых подписей документа MSXML 5.0. // Ключ подписи получается по имени ключевого контейнера. Имя контейнера, в свою очередь, // получается из расширенных свойств заданного сертификата. // Ключ проверки подписи получается из DOM узла <ds:KeyInfo> подписанного XML-документа. // Имя подписанного XML-документа задается по умолчанию ("out_signature.xml"). // Данная программа имеет три аргумента командной строки: // 1) Имя исходного XML-документа (документ должен соответствовать // шаблону, приведенному в примере). // 2) Имя сертификата для первой подписи. // 3) Имя сертификата для второй подписи. //-------------------------------------------------------------------- #include <windows.h> #include <wincrypt.h> #include <tchar.h> #include "wincryptex.h" #include <stdio.h> #import <msxml5.dll> using namespace MSXML2; #import <capicom.dll> using namespace CAPICOM; #define DSIGNS "xmlns:ds='http://www.w3.org/2000/09/xmldsig#'" #define OUTFILE "out_signatures.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 //------------------------------------------------------------- // Объявление и инициализация переменных. _bstr_t outfile; IXMLDOMDocument3Ptr xmldoc = NULL; IXMLDigitalSignaturePtr xmldsig = NULL; VARIANT_BOOL objectsAreInitialized = VARIANT_FALSE; void HandleError(char *s); 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; //имя сертификата, который используется для подписи TCHAR* userName1 = NULL; //имя сертификата для первой подписи TCHAR* userName2 = NULL; //имя сертификата для второй подписи int COUNT; //счётчик HRESULT hr; //переменная, которая используются для получения XML документа //--------------------------------------------------------------------------- // Описание функции загрузки XML-документа. //--------------------------------------------------------------------------- VARIANT_BOOL LoadXML(_bstr_t sigFile) { if (!objectsAreInitialized) { printf("Must initialize objects before loading signature.\n"); return VARIANT_FALSE; } xmldoc->setProperty("SelectionNamespaces", DSIGNS); if( COUNT == 1 ) { if (xmldoc->load(sigFile) == VARIANT_FALSE) { printf("Can't load %s\n", (LPCSTR)sigFile); return VARIANT_FALSE; } //------------------------------------------------------------------------------ // Определение свойств первой подписи в соответствии с DOM узлом <ds:Signature> // XML-документа. xmldsig->signature = xmldoc->selectSingleNode(".//ds:Signature[@Id='FirstSignature']"); } else if( COUNT == 2 ) { //------------------------------------------------------------------------------ // Определение свойств второй подписи в соответствии с DOM узлом <ds:Signature> // XML-документа. xmldsig->signature = xmldoc->selectSingleNode(".//ds:Signature[@Id='SecondSignature']"); } else printf("COUNT !=1 and COUNT!=2, COUNT is %d\n", COUNT); if (xmldsig->signature == NULL) { printf("Failed to set the signature property.\n"); return VARIANT_FALSE; } return VARIANT_TRUE; }// Конец описания функции LoadXML //--------------------------------------------------------------------------- // Описание функции подписи XML-документа. //--------------------------------------------------------------------------- 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, _TEXT("MY")); if (!hStore) { HandleError("The store could not be opened!\n"); } else { printf("The store is open!\n"); } //----------------------------------------------------------------- // Определение сертификата, используемого для подписи в данный момент if( COUNT == 1) { userName = userName1; } else if( COUNT == 2 ) { userName = userName2; } else printf("COUNT !=1 and COUNT!=2, COUNT is %d\n", COUNT); //----------------------------------------------------------------- // Получение сертификата с заданным именем из хранилища сертификатов. 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 "); } //------------------------------------------------------------------------- // Выделение памяти. pbData = (CRYPT_KEY_PROV_INFO*)malloc(cbData); if(pbData) { 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\n", pbData->pwszContainerName); } 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); printf("\n"); //---------------------------------------------------- // Запись подписи в файл outfile. hr = xmldoc->save(outfile); if (FAILED(hr)) { printf("can't save the signed signature file.\n"); return false; } //----------------------------------------------------------------------- return true; }// Конец описания SignXML //--------------------------------------------------------------------------- // Описание функции проверки цепочки сертификатов, начиная с сертификата, на // котором осуществлялась подпись XML-документа. //--------------------------------------------------------------------------- VARIANT_BOOL IsCertificateValid(IXMLDSigKeyPtr pKey) { if (pKey == NULL) { printf("invalid key object.\n"); return VARIANT_FALSE; } //--------------------------------------------------------------------------- // Получение сертификата, на котором осуществлялась подпись, из ключа проверки. ICertificatePtr pCert=NULL; pCert = pKey->getVerifyingCertificate(); if (pCert == NULL) { printf ("Can't get verifying certificate\n"); return VARIANT_FALSE; } //--------------------------------------------------------------------------- // Построение и прохождение по доверенной цепочке сертификатов. IChain2Ptr pChain = NULL; HRESULT hr = pChain.CreateInstance(__uuidof(Chain)); if (FAILED(hr)) { printf("Can't instantiate a trust chain.\n"); return VARIANT_FALSE; } if (VARIANT_FALSE == pChain->Build(pCert)) { printf("broken trust chain.\n"); return VARIANT_FALSE; } printf("Examining certificate chain:\n"); long count = pChain->Certificates->Count; for (long i=1; i<=count; i++) { printf(" Certificate No. %d:\n", i); if (pCert) { pCert.Release(); pCert=NULL; } pCert = pChain->Certificates->Item[i]; if (pCert == NULL) { printf("Can't get the %d-th certificate.\n",i); return VARIANT_FALSE; } printf(" subject: %s\n",(LPSTR)pCert->SubjectName); printf(" issuer: %s\n\n",(LPSTR)pCert->IssuerName); } //--------------------------------------------------------------------------- // Проверка корневого сертификата в цепочке. if (pCert) { pCert.Release(); pCert=NULL; } pCert = pChain->Certificates->Item[count]; if (pCert == NULL) { printf("Can't get root certificate.\n"); return VARIANT_FALSE; } printf("Display the Root certificate:\n"); printf(" subject: %s\n",(LPSTR)pCert->SubjectName); printf(" issuer: %s\n\n",(LPSTR)pCert->IssuerName); if (pCert) pCert.Release(); if (pChain) pChain.Release(); return VARIANT_TRUE; }// Конец описания IsCertificateValid //--------------------------------------------------------------------------- // Описание функции проверки подписи XML-документа. //--------------------------------------------------------------------------- VARIANT_BOOL VerifyXML(XMLDSIG_WRITEKEYINFO fWriteKeyInfo) { MSXML2::IXMLDOMNodePtr pKeyInfo, pNode; IXMLDSigKeyPtr pKey, pKeyOut; if (xmldsig->signature == NULL) { printf("Invalid signature.\n"); return VARIANT_FALSE; } //--------------------------------------------------------------------------- // Проверка DOM узла <ds:KeyInfo> XML-документа. if(COUNT==1) // для первой подписи { pKeyInfo = xmldoc->selectSingleNode( ".//ds:Signature[@Id='FirstSignature']/ds:KeyInfo/ds:X509Data"); } else if( COUNT == 2 ) // для второй подписи { pKeyInfo = xmldoc->selectSingleNode( ".//ds:Signature[@Id='SecondSignature']/ds:KeyInfo/ds:X509Data"); } else printf("COUNT !=1 and COUNT!=2, COUNT is %d\n", COUNT); if (pKeyInfo == NULL) { printf("Invalid <ds:KeyInfo>\n"); return VARIANT_FALSE; } //--------------------------------------------------------------------------- // Получение ключа проверки подписи из DOM узла <ds:KeyInfo> XML-документа. pKey = xmldsig->createKeyFromNode(pKeyInfo); if (pKey== NULL) { printf("Invalid key from <ds:KeyInfo>\n"); return VARIANT_FALSE; } //--------------------------------------------------------------------------- // Получение ключа проверки цепочки сертификатов и проверка подписи. pKeyOut = xmldsig->verify(pKey); if (pKeyOut== NULL) { printf("Invalid signature.\n"); return VARIANT_FALSE; } printf("\n"); printf("Signature verified on the data.\n\n"); //--------------------------------------------------------------------------- // Проверка цепочки сертификатов, начиная с сертификата, на котором осуществлялась подпись. if (fWriteKeyInfo == CERTIFICATES) { if (IsCertificateValid(pKeyOut)) { printf("Certificate used is valid.\n"); } } return VARIANT_TRUE; }// Конец описания VerifyXML //------------------------------------------------------------------------------- // Описание функции инициализации объектов. //------------------------------------------------------------------------------- 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 < 4) { printf("Please, enter tne name of xml-file and two certificate's names!\n"); exit(-1); } fileName = argv[1]; userName1 = argv[2]; userName2 = argv[3]; printf("Verifying %S\n\n", fileName); outfile = OUTFILE; COUNT=1; //------------------------------------------------------------------------------ // Создание двух независимых подписей XML-документа. for(int i=0;i<2;i++) { if (VARIANT_TRUE == LoadXML((_bstr_t)fileName)) { printf("\n"); printf("Sign with fwWriteKeyInfo = CERTIFICATES:\n"); SignXML(CERTIFICATES); COUNT++; } } COUNT=1; //------------------------------------------------------------------------------ // Проверка двух независимых подписей XML-документа. for(i=0;i<2;i++) { if (VARIANT_TRUE == LoadXML(outfile)) { printf("\n"); printf("Verify with fwWriteKeyInfo = CERTIFICATES:\n"); VerifyXML(CERTIFICATES); COUNT++; } } //------------------------------------------------------------------------------ // Очистка. cleanObjects(); CoUninitialize(); }// Конец main
Windows 2000/XP/2003: Необходимо Windows 2000 SP4 или
старше с Internet Explorer 6.0 или старше и MSXML 5.0.
Что Вы
думаете по поводу данной статьи? |
Закажите CD c Крипто-Про CSP |