| ||||
| ||||
Добрый день. С подписыванием файлов я более-менее разобрался. Теперь приступил к проверке подписи. Подпись файла идет отдельно от файла. В подпись включен сертификат пользователя. Не совсем понятна такая ситуация. Иду так сказать с конца...Для того, чтобы проверить подпись, мне необходим сертификат пользователя(в сертификате кроме всего прочего указан тип провайдера, с которым он работает, я так понимаю). Чтобы извлечь сертификат из ЭЦП, мне необходимо использовать ф-ию CryptMsgGetParam(hMsg,...). Чтобы использовать эту ф-ию я делжен открыть сообщение для декодирования и проапдейтить его содержимым файла подписи(p7s) и содержимым файла, который был подписан. !! Но для того, чтобы использовать ф-ию CryptMsgOpenToDecode(..., hProv,...) я должен указать также дескриптор криптопровайдера! !! А как же я его узнаю, если еще не получил информацию о сертификате пользователя. Т.е. получается какой-то замкнутый круг. Как в таком случае быть? Можно ли работать с ф-ями CryptMsgOpenToDecode, CryptMsgUpdate, CryptMsgGetParam и т.д. без получения дескриптора криптопровайдера. И вот еще один вопрос. Если я в ЦС получил сертификат с использованием какого-то определенного криптопровайдера(напр, Schlumberger Cryptographic Service Provider), значит ли это, что при написании крипто-прог. я должен в программе получать контекст именно этого криптопровайдера? Спасибо. | ||||
Ответы: | ||||
| ||||
Диагноз: хронический НЕДОЧИТ документации :) Рецепт: еще почитать про функцию CryptMsgOpenToDecode. | ||||
| ||||
Добрый день. Извините за мою назойливость, но очень хочется "добить" эту тему, а знаний и сообразительности маловато. Почитал про CryptMsgOpenToDecode, решил отказаться от стриминга. Делаю все так, как в Вашем примере lowsign.c. --------------------------------------- Var cbSignerCertInfo : DWORD; pSignerCertInfo : PCERT_INFO; pSignerCertContext : PCCERT_CONTEXT; pSignerCertificateInfo : PCERT_INFO; hStoreHandle : HCERTSTORE; flags : DWORD; Begin flags := CMSG_DETACHED_FLAG; // -------------------------------------------------------------------- // Откроем сообщение для декодирования hMsg := CryptMsgOpenToDecode( TYPE_DER, // Encoding type flags, // Flags (CMSG_DETACHED_FLAG) 0, // Use the default message type 0, // Cryptographic provider NIL, // Recipient information NIL // Stream information (not used) ); // -------------------------------------------------------------------- // Поместим в сообщение данные ЭЦП CryptMsgUpdate(hMsg, pbyte(buffer), iFileLength, True); // -------------------------------------------------------------------- // Поместим в сообщение файл, который подписывали CryptMsgUpdate(hMsg, pbyte(SourceBuffer), iSourceFileLength, True); CryptMsgGetParam( hMsg, // Handle to the message CMSG_SIGNER_CERT_INFO_PARAM, // Parameter type 0, // Index NIL, // Pointer to the blob @cbSignerCertInfo); // Size of the blob CryptMsgGetParam( hMsg, // Handle to the message CMSG_SIGNER_CERT_INFO_PARAM,// Parameter type 0, // Index pSignerCertInfo, // Pointer to the blob @cbSignerCertInfo); // Size of the blob End; --------------------------------------- В результате все отработало успешно: cbSignerCertInfo=272, а вот в pSignerCertInfo как был NIL, так и остался... Не подскажите, что может быть? Спасибо. | ||||
| ||||
Ну а кто под pSignerCertInfo память выделять будет? :) Это же просто POINTER, на что ему указывать? | ||||
| ||||
:) Ламер я, ламер...:) Но проблема не исчезла. Выделил память: new(pSignerCertInfo); Обнулил все, что можно в структуре: NULL_DATA.cbData := 0; NULL_DATA.pbData := NIL; with pSignerCertInfo^ Do Begin dwVersion := 0; SerialNumber := NULL_DATA; SignatureAlgorithm.pszObjId := NIL; SignatureAlgorithm.Parameters := NULL_DATA; Issuer := NULL_DATA; NotBefore.dwLowDateTime := 0; NotBefore.dwHighDateTime := 0; NotAfter.dwLowDateTime := 0; NotAfter.dwHighDateTime := 0; SubjectPublicKeyInfo.Algorithm.pszObjId := NIL; SubjectPublicKeyInfo.Algorithm.Parameters := NULL_DATA; SubjectPublicKeyInfo.PublicKey.cbData := 0; SubjectPublicKeyInfo.PublicKey.pbData := NIL; SubjectPublicKeyInfo.PublicKey.cUnusedBits := 0; IssuerUniqueId.cbData := 0; IssuerUniqueId.pbData := NIL; IssuerUniqueId.cUnusedBits := 0; SubjectUniqueId.cbData := 0; SubjectUniqueId.pbData := NIL; SubjectUniqueId.cUnusedBits := 0; cExtension := 0; rgExtension := NIL; End; Но вызов: CryptMsgGetParam( hMsg, // Handle to the message CMSG_SIGNER_CERT_INFO_PARAM,// Parameter type 0, // Index pSignerCertInfo, // Pointer to the blob @cbSignerCertInfo); // Size of the blob Вернул в pSignerCertInfo^ как бы НЕ ВСЮ информацию о сертификате. Нет ни subject, ни NotBefore, ни NotAfter, и т.д(т.е. соответствующие поля содержат только нули и NIL-ы). Есть только Issuer. И то, в нем "нормальная" информация(соответсвующая реальному значению этого поля в сертификате) перемешана с каким-то мусором(например,’0‡1*0( *†H†÷ alex_drobazko@ukrpatent.org10 UUA1 0UKyiv10U UKRPATENT10USARIT10UeFilingKeyCentre’) | ||||
| ||||
P.S. Забыл заметить, что если перед получением информации о сертификате подписчика, попробывать получить размер подписанных данных и сами данные: CryptMsgGetParam( hMsg, // Handle to the message CMSG_CONTENT_PARAM, // Parameter type 0, // Index NIL, // Pointer to the blob @cbDecoded); // Size of the blob new(pbDecoded); CryptMsgGetParam( hMsg, // Handle to the message CMSG_CONTENT_PARAM, // Parameter type 0, // Index pbDecoded, // Pointer to the blob @cbDecoded); // Size of the blob ...то результат подобный: cbDecoded=0, pbDecoded=какая-то чушь... | ||||
| ||||
На С++: if(!CryptMsgGetParam(...,NULL,&dwSize)) { // something wrong, write ERROR! } BYTE* pbSignerInfo=(BYTE*)malloc(dwSize); ZeroMemory(pbSignerInfo,dwSize); if(!CryptMsgGetParam(...,pbSignerInfo,&dwSize)) { // something wrong, write ERROR! } То есть ошибки еще нужно проверять и оператор типа "new(pSignerInfo)" - это что? pSignerInfo это класс что-ли какой-то? ПАМЯТЬ (блок памяти) нужно выделить. | ||||
| ||||
Добрый день. Ну вроде получилось с проверкой подписи...вроде проверяет :). Теперь возник вопрос, как вытащить из контекста сертификата серийный номер, срок его действия, используемый алгоритм хеширования(т.е., например, у меня есть его ID=’1.2.840.113549.1.1.5’, а я хотел бы получить SHA1), подписи(1.2.840.113549.1.1.1 -> RSA). Спасибо. | ||||
| ||||
...Все, хватит потворствовать "недочиту документации"... Знаю как, но лучше почитать самому. | ||||
| ||||
Большое спасибо за науку! Разобрался. Даже прицепил к подписи время ее создания. :)) Еще раз прошу прощения за назойливость. | ||||