23.04.2004 14:47:14Проверка S/MIME сообщения. Ответов: 8
Алексей
Возникла проблема проверки сообщения в S/MIME. Необходимо проверить целостность текста

сообщения после получения. Делаю так:
1. С помощью функций CryptMsgOpenToDecode и CryptMsgUpdate создаю объект HCRYPTMSG hMsg из p7s файла.
2. Из сообщения получаю сертификат подписавшей стороны (PCCERT_CONTEXT pSignerCert).
3. Получаю хэндл CSP с помощью CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);
4. Получаю открытый ключ CryptImportPublicKeyInfoEx(hProv, MY_TYPE,

&pSignerCert->pCertInfo->SubjectPublicKeyInfo, CALG_RSA_SIGN, 0, NULL, &hPubKey));
5. Создаю хэш CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash);
6. Вычисляю хэш для открытого текста из сообщения CryptHashData(hHash, pbBuffer, cbBuffer, 0);

где pbBuffer и cbBuffer указатель на буфер с текстом полученного сообщения и его длина.
7. Получаю сигнатуру из сообщения с помощью CryptMsgGetParam(hMsg, CMSG_ENCRYPTED_DIGEST, 0,

pbDigest, &cbDigest);
8. Далее пытаюсь расшифровать сигнатуру на основе открытого ключа из сообщения

CryptDecrypt(hPubKey, 0, TRUE, 0, pbDigest, &cbDigest);
Здесь возникает ошибка: "Bad Key".
9. Если пропустить шаг 8 и пытаться проверить сигнатуру таким образом СryptVerifySignature(

hHash, pbDigest, cbDigest, hPubKey, NULL, 0), то вернется FALSE.
Текст полученного сообщения совпадает с текстом отправленного. Подскажите что я делаю

неправильно. Может я неправильно получаю сигнатуру или открытый ключ из сообщения? И вообще

как проверить полученный тест сообщения, что он не был изменен? Алгоритм хэширования SHA-1.
 
Ответы:
29.04.2004 0:37:12mAx
>Далее пытаюсь расшифровать сигнатуру
>на основе открытого ключа из сообщения
а это зачем и как понимать?
CryptVerifySignature, если не ошибаюсь, должна использоваться.
29.04.2004 1:03:28mAx
Есть еще функция CryptVerifyMessageSignature
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/cpverifysignature.asp
Думаю ее целесообразнее использовать.
29.04.2004 14:35:31Алексей
Спасибо за ответ, mAx. Сейчас постараюсь понятно объяснить что я делаю. В MSDN написано (PlatformSDK-> Cryptography-> CryptoAPI-> Using CryptoAPI-> Signing Data-> Veryfying a Signed Messsage), что надо вытащить сигнатуру из сообщения и расшифровать ее, а затем проверить с новой, созданной на основе текста полученного сообщения. Поэтому я когда с помощью функции CryptMsgGetParam(..., CMSG_ENCRYPTED_DIGEST,...) получал зашифрованную сигнатуру, то я пытался ее расшифровать. Но даже если ее не расшифровывать, а передавать зашифрованной в CryptVerifySignature, то возвращалось FALSE.
Насчет функции CryptVerifyMessageSignature. Подписанное сообщение состоит из открытого текста и приаттаченного файла smime.p7s. Я передаю в эту функцию только p7s файл, она отрабатывает и возвращает TRUE. Но проблема вот в чем, получается что p7s файл не связан с открытом текстом сообщения, т.е. злоумышленник может изменить текст сообщения, а p7s файл оставить тем же и получится, что сигнатура осталась правильной. Мне же необходимо проверить что текст сообщения не был изменен. Так что если есть какие-нибудь мысли по этому поводу, убедительная просьба поделиться.
29.04.2004 14:57:41kure
Ну в MSDN не совсем так написано.
Первая часть описыват теорию проверки ЭЦП.
Во второй части написано.
Пользуйтесь одной функцией, которая все сделает:
A single function, CryptVerifyMessageSignature, can be used to verify a signature, as shown in the following procedure.

To verify a signed message

Get a pointer to the signed message.
Get the size of the signed message.
Get a handle on a cryptographic provider.
Initialize the CRYPT_VERIFY_MESSAGE_PARA structure.
Call CryptVerifyMessageSignature to verify the signature.

Что касается возможности внесения изменения в текст, когда подпсись в отдельном файле (p7s). Конечно внести изменения можно, но на то она и подпись чтобы обнаружить изменения. Ведь когда вы проверяете эту подпись (которая в отдельном файле) вы же в функций проверки подписи передаете сначала исходный открытых текст, от которого считается хеш. А где подпись (в одном файле или отдельно) значения не имеет.
Посмотрите http://www.ietf.org/rfc/rfc2630.txt.
Описание формата, который является основой S/MIME
29.04.2004 16:06:34Алексей
Спасибо, kure. Я читал RFC2630, с теорией то понятно, не получается это реализовать на практике средствами CryptoAPI. Например для функции CryptVerifyMessageSignature есть параметры, которыми ей передается подписанное сообщение (pbSignedBlob, cbSignedBlob), но тогда возникает вопрос, что туда передавать? Все сообщение, или только открытый текст или только p7s файл, или еще что-то? У меня эта функция отрабатывала только с p7s файлом. Но как я писал выше отсутствует связь с открытым текстом. Т.е. если можно объясните как на практике (какими функциями и какими параметрами этих функций) можно проверить целостность открытого текста сообщения.
PS. Вы писали:"... в функций проверки подписи передаете сначала исходный открытых текст, от которого считается хеш." О какой функции вы говорите, это какая-то конкретная функция CryptoAPI или ее нужно написать самому? Хэш создается CryptCreateHash и CryptHashData, но полученный хэш нельзя связать с CryptVerifyMessageSignature, с CryptVerifySignature - да, и я так и делал, но у меня, к сожалению, тот порядок действий, который я описал в самом начале, приводил к ошибке "Invalid Signature" этой функции. Заранее спасибо.
29.04.2004 16:38:35kure
На странице http://www.cryptopro.ru/CryptoPro/products/csp4.asp есть примеры в исходных текстах http://www.cryptopro.ru/CryptoPro/test/sample2_0.zip

Посмотрите примеры signlo.c, signtsf.c. Там все это есть.
Кроме этого рекомендую посмотреть на RFC S/MIME, в котором написано как проверять подпись MIME. А почему бы вам не использовать например CDO?
http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q280391
29.04.2004 17:09:32Алексей
Спасибо за ссылки, kure. А вот CDO и CAPICOM не могу использовать потому что по ТЗ необходимо использовать CryptoAPI :’-(
30.04.2004 14:19:26Алексей
Проблема решена!!! Все оказалось гораздо проще чем я думал. Просто нужно было воспользоваться функцией CryptVerifyDetachedMessageSignature, одним из параметров которой передавать p7s файл, а другим открытый текст. Еще раз спасибо всем кто помогал.