13.10.2004 15:27:46Вопрос про АРМ разбора конфликтов Ответов: 20
Михаил
подписываю своей прогой простой тхт файлик. ГОСТ. ЭЦП в отдельном файле. проверяю - все ок.
Запускаю АРМ выбираю подписанный тхт файл и файл ЭЦП. выводится ошибка -Ошибка при декодировании сообщения!- В чем причина? спасибо
 
Ответы:
13.10.2004 17:21:20uri
Файл с подписью должен соответствовать RFC 3369, "Cryptographic Message Syntax", August 2002 (http://www.ietf.org/rfc/rfc3369.txt) с учетом использования криптографических алгоритмов ГОСТ 28147-89, ГОСТ Р 34.10-94, ГОСТ Р 34.10-2001, ГОСТ Р 34.11-94 в соответствии с проектом рекомендаций "Using the GOST 28147-89, GOST R 34.11-94, GOST R 34.10-94 and GOST R 34.10-2001 algorithms with the Cryptographic Message Syntax (CMS)" (http://www.ietf.org/internet-drafts/draft-ietf-smime-gost-02.txt).
14.10.2004 11:45:35Михаил
Подпись получаю ф-ей CryptSignHash(hash, AT_KEYEXCHANGE, nil, 0, Pointer(signature), @size). Подскажите, мне нужно полученную ЭЦП еще перекодировать?
14.10.2004 12:44:18uri
ф-ей CryptSignHash вы получаете подписанный хэш. Это еще не подпись, того формата, который понимает АРМ разбора КС. Смотрите мой предыдущий ответ.
15.10.2004 23:58:16Serge3leo
Здравствуйте,

Вероятно CryptSignMessage должно помочь. Смотрите наши примеры, <http://msdn.microsoft.com/library/en-us/security/security/cryptsignmessage.asp> или <http://msdn.microsoft.com/library/en-us/security/security/procedure_for_signing_data.asp>.

Успехов.
19.10.2004 17:17:58Михаил
Дело в том что эта ф-я требует наличия сертификата.. а мне бы не хотелось с ним связываться. В криптоконтейнере его может и не быть, да и уже времени нет :) ). Можно ли привести к этому формату искусственно? т.е. создать заголовок самому и перекодировать в pkcs7? спасибо.
19.10.2004 17:25:15uri
Возвращаемся к началу разговора:
1. в сабже был АРМ разбора конфликтов. А он подпись без сертификатов ключей подписи не проверяет.
2. Подпись на подписанном сообщении предусматривает наличие информации о сертификате ключе подписи и его издателе.

Итог: без сертификатов нет подписи!
20.10.2004 1:42:22Serge3leo
Здравствуйте,

Вам надо что-бы ЭЦП было проверено на АРМ разбора. Для это нужно выполнение следующих условий:

1. ЭЦП должно быть в формате собщения CMS (PKCS#7);

2. Формат сообщения CMS (PKCS#7) требует, либо наличия сертификата открытого ключа, которым выполнено ЭЦП, в самом сообщении, либо собщение должно содержать серийный номер этого сертификата, либо содержать идентифкатор открытого ключа этого сертификата (cMsgCert != 0, cMsgCert == 0 && !(dwFlags&CRYPT_MESSAGE_KEYID_SIGNER_FLAG ), cMsgCert == 0 && (dwFlags&CRYPT_MESSAGE_KEYID_SIGNER_FLAG ));

3. Для этого сертификата АРМ может построить цепочку до сертификата находящегося в хранилище "Доверенные корневые центры сертификации";

4. У АРМ есть СОС (список отозванных сертификатов, CRL) от УЦ выпустившего этот сертификат и он не отозван;

> В криптоконтейнере его может и не быть, да и уже времени нет :)

Если сертифакт у АРМ есть, то Ваш клиент на Windows 2k и выше может попробовать вызвать CryptSignMessage c (cMsgCert == 0 && (dwFlags&CRYPT_MESSAGE_KEYID_SIGNER_FLAG )) и pSigningCert созданном в ОЗУ с заполненым CERT_KEY_CONTEXT_PROP_ID.

Либо Вы можете, прочитать цитированные RFC и draft, промоделировать на CryptSignMessage, и на коленке преобразовать результат CryptSignHash в CMS (PKCS#7). Если удавить все атрибуты и сертификаты, то там не очень сложно.

Успехов.
20.10.2004 1:52:27Serge3leo
P.S.

Если времени нет, то считайте, что в контейнере есть сертификат (большинство приложений КриптоПро CSP использует XEnroll или capilite, а они его туда всегда пытаются запихнуть).

Соотвественно, делайте CryptGetKeyParam(..KP_CERTIFICATE..), формируйте CERT_CONTEXT c CERT_KEY_CONTEXT_PROP_ID и зовите CryptSignMessage. Для первой версии будет нормально.

Успехов.
20.10.2004 13:26:39Михаил
В соответствии с последним советом и посмотрев Ваши примеры делаю так:
...
CryptAcquireContext();
CryptGetUserKey(hProv, AT_KEYEXCHANGE, @hUserKey);
CryptGetKeyParam(hUserKey, KP_CERTIFICATE, nil, @dwUserCertLength, 0);
SetLength(pbUserCert,dwUserCertLength);
CryptGetKeyParam (hUserKey, KP_CERTIFICATE, Pointer(pbUserCert), @dwUserCertLength, 0);
PCRTC:=CertCreateCertificateContext(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, Pointer(pbUserCert), dwUserCertLength);

SigParams.cbSize := sizeof(CRYPT_SIGN_MESSAGE_PARA);
SigParams.dwMsgEncodingType := X509_ASN_ENCODING or PKCS_7_ASN_ENCODING;
SigParams.pSigningCert := PCRTC;
SigParams.HashAlgorithm.pszObjId := szOID_CP_GOST_R3411;
SigParams.HashAlgorithm.Parameters.cbData := 0;
SigParams.HashAlgorithm.Parameters.pbData := nil;
SigParams.cMsgCert := 0;
SigParams.rgpMsgCert := 0;
SigParams.cAuthAttr := 0;
SigParams.dwInnerContentType := 0;
SigParams.cMsgCrl := 0;
SigParams.cUnauthAttr := 0;
SigParams.dwFlags := 0;
SigParams.pvHashAuxInfo := nil;
SigParams.rgAuthAttr := nil;

CryptSignMessage(@SigParams,TRUE,1,ar1,ar2,nil,@size)
...
Валится при первом вызове CryptSignMessage c ошибкой все время по одному и тому же адресу памяти в crypt32.dll

Вопрос: нужно ли делать CryptAcquireContext и не вызывает ли
CryptSignMessage его еще раз из себя
или может причина в чем-то другом?
20.10.2004 15:34:17Serge3leo
Здравствуйте,

> Вопрос: нужно ли делать CryptAcquireContext и не вызывает ли
CryptSignMessage его еще раз из себя
или может причина в чем-то другом?

Хороший вопрос. Я же Вам указывал на необходимость установки CERT_KEY_CONTEXT_PROP_ID, а Вы это проигнорировали. Смотрите описание CertSetCertificateContextProperty.

> Валится при первом вызове CryptSignMessage c ошибкой все время по одному и тому же адресу памяти в crypt32.dll

Ну я же Вам не отладчик.

Успехов.
21.10.2004 11:20:00Михаил
Господа! Взгляните краем глаза. видимо упускаю чтото. но все примеры,форум уже просмотрел и идей просто больше нет.. вываливается на CryptSignMessage в Access Volation.

var
SigParams : CRYPT_SIGN_MESSAGE_PARA;
i : Integer;
size : DWORD;
arrBuff : array of PBYTE;
arrECP : array of PBYTE;
lenBuff,lenECP : array of DWORD;
hUserKey : HCRYPTKEY;
dwUserCertLength: DWORD;
pbUserCert : String;
PCRTC : PCCERT_CONTEXT;
s : String;
EncryptPara : CRYPT_ENCRYPT_MESSAGE_PARA ;
rgpRecipientCert :array of PCCERT_CONTEXT;
begin
s:=&rsquo;&rsquo;;
size:=0;
SetLastError(0);

CryptAcquireContext(@hProv, PChar(name), nil, PROV_GOST_2001_DH, 0);

if not CryptGetUserKey (hProv, AT_KEYEXCHANGE, @hUserKey) then begin
end;
if not CryptGetKeyParam (hUserKey, KP_CERTIFICATE, nil, @dwUserCertLength, 0) then begin
end;

SetLength (pbUserCert,dwUserCertLength);

if not CryptGetKeyParam (hUserKey, KP_CERTIFICATE, Pointer(pbUserCert), @dwUserCertLength, 0) then begin
end;

PCRTC:=CertCreateCertificateContext(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, Pointer(pbUserCert), dwUserCertLength);
if (PCRTC=nil) then begin
end;

if not CertSetCertificateContextProperty(PCRTC,CERT_KEY_CONTEXT_PROP_ID,CERT_STORE_NO_CRYPT_RELEASE_FLAG,nil) then begin
end;

ZeroMemory(@SigParams,sizeof(CRYPT_SIGN_MESSAGE_PARA));

SigParams.cbSize := sizeof(CRYPT_SIGN_MESSAGE_PARA);
SigParams.dwMsgEncodingType := X509_ASN_ENCODING or PKCS_7_ASN_ENCODING;
SigParams.pSigningCert := PCRTC;
SigParams.HashAlgorithm.pszObjId := szOID_CP_GOST_R3411;
SigParams.HashAlgorithm.Parameters.cbData := 0;
SigParams.cMsgCert := 0;
SigParams.rgpMsgCert := nil;
SigParams.cAuthAttr := 0;
SigParams.dwInnerContentType := 0;
SigParams.cMsgCrl := 0;
SigParams.cUnauthAttr := 0;
SigParams.dwFlags := 0;
SigParams.pvHashAuxInfo := nil;
SigParams.rgAuthAttr := nil;
SigParams.dwInnerContentType:=0;

SetLength(arrBuff,1);
SetLength(lenBuff,1);
SetLength(ECP,9024);
arrBuff[0]:= Pointer(Buff[1]);
lenBuff[0]:=Length(Buff);

if(CryptSignMessage(
@SigParams,
TRUE,
1,
arrBuff,
lenBuff,
Pointer(ECP),
@size ) )
then begin
end;
21.10.2004 13:43:49Kirill Sobolev
а чему у Вас равен последний параметр в CryptSignMessage?
21.10.2004 14:14:45Михаил
последний параметр=0. насколько я понял ф-я должна вернуть в него размер подписи.. я пробовал использовать в 2 прохода, на результат это не повлияло. Access Volation
22.10.2004 11:32:35Serge3leo
Здравствуйте,

Причины "Access Volation" не ясны. Но, очевидно, что Вы не устанавливаете для PCRTC.

Нужно установить hProv и AT_KEYEXCHANGE в свойства PCRTC.

Успехов.
22.10.2004 11:40:37Serge3leo
Если на входе в функцию, Pointer(ECP) != 0 (pbSignedBlob != 0), то в она должна вернуть ERROR_MORE_DATA для size == 0 (*pcbSignedBlob == 0)
22.10.2004 13:48:14Михаил
Добрый день! не совсем понял что значит установить. я ведь при получении контекста использую
CryptAcquireContext(@hProv, PChar(name), nil, PROV_GOST_2001_DH, 0);
CryptGetUserKey (hProv, AT_KEYEXCHANGE, @hUserKey);
т.е. они установлены...
или сделать
CertSetCertificateContextProperty(PCRTC,CERT_KEY_PROV_HANDLE_PROP_ID,CERT_STORE_NO_CRYPT_RELEASE_FLAG ,nil);
CertSetCertificateContextProperty(PCRTC,CERT_KEY_SPEC_PROP_ID,CERT_STORE_NO_CRYPT_RELEASE_FLAG ,nil);
так это не помагает..
22.10.2004 14:37:07Serge3leo
Вы же устанавливаете CERT_KEY_PROV_HANDLE_PROP_ID в nil, и не задаёте, что следует использовать AT_EXCHANGE с помощью CERT_KEY_PROV_INFO_PROP_ID.

Вы же должны объяснить CryptoAPI, что этот ключ для этого сертификата, а не для другого.

Читайте MSDN. На мой взгляд лучше использовать CERT_KEY_CONTEXT_PROP_ID
22.10.2004 14:41:29Serge3leo
Пардон.
Вы же устанавливаете CERT_KEY_PROV_HANDLE_PROP_ID в nil, и не задаёте, что следует использовать AT_EXCHANGE с помощью CERT_KEY_SPEC_PROP_ID.
22.10.2004 16:38:30Михаил
Подскажите, а это на CAPICOM или Xenroll можно сделать?
25.10.2004 16:00:18Михаил
Добрый день!
С подписанием разобрался.
АРМ РКС все воспринимает.
А какую функцию мне нужно использовать теперь для проверки, CryptVerifyDetachedMessageSignature или CryptVerifyMessageSignature, если при подписании detached=True, наверно CryptVerifyDetachedMessageSignature ?