Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 2 [3] 4 5 6   вперед  Ctrl      все
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Miktor
Member

Откуда: г. Хабаровск
Сообщений: 398
Намек понял ) Готов возместить пивом потраченое на меня время )
На самом деле огоромное спасибо. Все подписывает.
Если я еще не довел до белого коленя...
Как теперь вывести на экран информацию о том кто подписал?
Да, и вторая процедура тоже компилируется, но при втором вызове CryptVerifyMessageSignature говорит что "Не удалось проверить подпись". :(
И еще... сверял с MSDN протопит фукнции CryptVerifyMessageSignature... там почемуто pbSignedBlob и pbDecoded объявлены как BYTE. (вот).
3 апр 08, 02:28    [5495692]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Альт
Member

Откуда: Сибирь
Сообщений: 4581
Ну раз на проверке сертификата не скандалит на структуру "подписи", значит и правда подписали удачно... чтобы опять не переделывать код... поменяйте тип так:

function CryptVerifyMessageSignature(pVerifyPara :PCRYPT_VERIFY_MESSAGE_PARA;
                                     dwSignerIndex :DWORD;
                               const pbSignedBlob :PBYTE;
                                     cbSignedBlob :DWORD;
                                     pbDecoded :PBYTE;
                                     pcbDecoded :DWORD;
                                     ppSignerCert :PCCERT_CONTEXT
                                     ):BOOL ; stdcall;


function CryptVerifyMessageSignature( pVerifyPara : PCRYPT_VERIFY_MESSAGE_PARA;
                                      dwSignerIndex : DWORD;
                                const pbSignedBlob : PBYTE;
                                      cbSignedBlob : DWORD;
                                      pbDecoded : PBYTE;
                                 var  pcbDecoded : DWORD;
                                      ppSignerCert : PCCERT_CONTEXT
                                     ) : BOOL; stdcall;                                     

BOOL WINAPI CryptVerifyMessageSignature(
  __in       PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara,
  __in       DWORD dwSignerIndex,
  __in       const BYTE* pbSignedBlob,
  __in       DWORD cbSignedBlob,
  __out      BYTE* pbDecoded,
  __inout    DWORD* pcbDecoded,
  __out_opt  PCCERT_CONTEXT* ppSignerCert
);

вроде все.


Скажи, что с нами будет, если нам дадут все ни за что,
Мы умрем в изумрудах, не сказав ничего (с) Магнитная Аномалия - В Изумрудах
3 апр 08, 12:30    [5497402]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Miktor
Member

Откуда: г. Хабаровск
Сообщений: 398
Да у меня так и сделано. Вот только при проверке - "Не удалось проверить подпись. 0x80090006 Неправильная подпись." :(
4 апр 08, 01:45    [5502039]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Альт
Member

Откуда: Сибирь
Сообщений: 4581
>на проверке сертификата
это не я писал... это демоны...

Выложите уже эту "подпись"... я не телепат... я программист


Скажи, что с нами будет, если нам дадут все ни за что,
Мы умрем в изумрудах, не сказав ничего (с) Магнитная Аномалия - В Изумрудах
4 апр 08, 22:03    [5506900]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
vovanka
Member

Откуда:
Сообщений: 11
мне нужно включить в прграмму возможность выбора криптопровайдера из всех возможных. подскажите пожалуйста функцию в дельфи позволяющую вывести список всех доступных криптоправайдеров
16 апр 08, 09:00    [5552012]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Мимопроходящий
Member

Откуда: бурятский тундрюк, эсквайр
Сообщений: 29238

Привет, vovanka!
Ты пишешь:

vovanka
v> мне нужно включить в прграмму возможность выбора криптопровайдера из всех возможных.

смотри описание Predefined Provider Types

--
With best regards, Мимопроходящий.

Posted via ActualForum NNTP Server 1.4

16 апр 08, 12:22    [5553679]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Альт
Member

Откуда: Сибирь
Сообщений: 4581
vovanka
мне нужно включить в прграмму возможность выбора криптопровайдера из всех возможных. подскажите пожалуйста функцию в дельфи позволяющую вывести список всех доступных криптоправайдеров


перебираете функциями CryptEnumProviderTypes/CryptEnumProviders начиная с Index = 0 до тех пор пока не вернет ошибку ERROR_NO_MORE_ITEMS
16 апр 08, 12:32    [5553790]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Альт
Member

Откуда: Сибирь
Сообщений: 4581
Хотя стоп... vovanka, вы вообще читали ссылки, которые тут приводились по нескольку раз... вот первое же с CryptEnumProviders...
http://www.podgoretsky.com/ftp/Docs/Delphi/CryptoAPI/list2.htm
лень - это ваша беда


Скажи, что с нами будет, если нам дадут все ни за что,
Мы умрем в изумрудах, не сказав ничего (с) Магнитная Аномалия - В Изумрудах
16 апр 08, 13:02    [5554130]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Miktor
Member

Откуда: г. Хабаровск
Сообщений: 398
2Альт

Вот файлик с подписью...

К сообщению приложен файл (test.sig - 1Kb) cкачать
18 апр 08, 04:50    [5564249]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Альт
Member

Откуда: Сибирь
Сообщений: 4581
Сейчас мозг себе сломаю... подпись правильна


Скажи, что с нами будет, если нам дадут все ни за что,
Мы умрем в изумрудах, не сказав ничего (с) Магнитная Аномалия - В Изумрудах
18 апр 08, 14:38    [5566909]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Альт
Member

Откуда: Сибирь
Сообщений: 4581
Структурно правильная. Подпись заявлена именно от того сертификата, который в нее и вложен, дата использования у сертификата не просрочена, в szOID_KEY_USAGE (Digital Signature заявлено)... но на проверке получаю стабильное "0x80090006 Invalid Signature."... одолевает, кучу времени убил на перепроверках. Смущает внушительный список Extension, может использование сертификата ограничивает одна из них. Сейчас у меня уже каша в голове и не получается сообразить (может что-то в szOID_ENHANCED_KEY_USAGE).

Вадим, давайте проведем эксперимент, я выкладываю самоподписной сертификат с приватным ключем вообще без ограничений на использование и подпись с моей машины. Проверяем в два этапа:
1. На первом просто валидируете мою подпись. Если все ок. Двигаемся дальше.
2. На втором вы импортируете сертификат с паролем 123, включив приватный ключ. Устанавливаете его в пользовательское хранилище и до кучи в хранилище доверенных корневых центров.
Пользователь для поиска DPN, подписываете и проверяете подпись. Если опять все ок, то разбираемся с областью использования вашего сертификата.


Скажи, что с нами будет, если нам дадут все ни за что,
Мы умрем в изумрудах, не сказав ничего (с) Магнитная Аномалия - В Изумрудах


К сообщению приложен файл (SERTS.zip - 2Kb) cкачать
18 апр 08, 15:30    [5567371]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Miktor
Member

Откуда: г. Хабаровск
Сообщений: 398
Понял. Попробую. (я уже чуствую что пивом не обойдусь )
19 апр 08, 04:54    [5569514]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Miktor
Member

Откуда: г. Хабаровск
Сообщений: 398
Все проходит на ура. И проверка вашего файла и подпись и проверка на месте.

Miktor
19 апр 08, 05:02    [5569515]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Альт
Member

Откуда: Сибирь
Сообщений: 4581
В общем моя теория, что виноваты KU/EKU не подтвердилась, в приложении к посту проверочный сертификат с приватным ключем (пароль тот же, пользователь при поиске Test). Есть последняя мысль, что надо обязательно кормить систему корневым сертификатом и списком отзыва (у меня на проверке он конечно нагибает сеть, но по заявленным в сертификате путям и для CS-ROOTDC.crl и для CS-ROOTDC.crt ничего нет). Выложите их

К сообщению приложен файл (test.p12 - 1Kb) cкачать
19 апр 08, 21:35    [5570445]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Miktor
Member

Откуда: г. Хабаровск
Сообщений: 398
Проверочный сертификат тоже все подписал и проверил успешно. У меня есть 3 корневых сертификата с именем CS-ROOTDC. Выложил в архиве...

К сообщению приложен файл (Sert.rar - 3Kb) cкачать
21 апр 08, 02:28    [5572060]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Альт
Member

Откуда: Сибирь
Сообщений: 4581
Зачем вам столько перевыпусков (да еще и не цепочкой)? Подошел второй. Перепроверил до кучи самую тоску Application Certificate Policy (szOID_APPLICATION_CERT_POLICIES = '1.3.6.1.4.1.311.21.10')
Подписывает!, что с политикой:
XCN_OID_KP_DOCUMENT_SIGNING = 1.3.6.1.4.1.311.10.3.12
The certificate can be used for signing documents.
Вот по этому списку, что без него (как у вас).
Все. Больше в сертификате нет узких мест. Вы морочите мне голову. Ваш сертификат выпущен от другой ключевой пары. Либо пара была пересоздана позднее. Очень жаль потраченное время.
Ключевые пары обычно вообще не пересоздаются или в редких чп случаях... вроде ситуации компрометации. И корневые сертификаты так тоже не пересоздаются. Отформатируйте ключевой носитель. Создайте чистую пару. Создайте запрос своему ца именно от этой пары и выпустите на нем (текущем!) нормальный сертификат


Скажи, что с нами будет, если нам дадут все ни за что,
Мы умрем в изумрудах, не сказав ничего (с) Магнитная Аномалия - В Изумрудах
21 апр 08, 10:38    [5572607]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Альт
Member

Откуда: Сибирь
Сообщений: 4581
Все стихло... я забыл последние тестовые сертификаты прикрепить. Корневой с приватным ключем для хранилища доверенных корневых. И тестовый, копия по всем ключевым атрибутам обсуждаемого. Пароли 123. И, в принципе, мне больше нечего добавить к теме симпл-функций. Все работает, если делать правильно

К сообщению приложен файл (demo_cert_123.zip - 5Kb) cкачать
21 апр 08, 14:19    [5574266]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Miktor
Member

Откуда: г. Хабаровск
Сообщений: 398
Большущее спасибо. Удалил лишние корневые пары и все заработало. Надеюсь все-таки что время потрачено не зря и топик будет полезен еще кому-нибудь.
22 апр 08, 01:49    [5577368]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Miktor
Member

Откуда: г. Хабаровск
Сообщений: 398
Снова я...
Хочу вывести информацию о подписи (сертификате)
  pSignerCert: PCCERT_CONTEXT;
  CertInfo: CERT_INFO;
  VerifyParams : CRYPT_VERIFY_MESSAGE_PARA;
  pStreamIn, pStreamOut : TMemoryStream;
  cbDecodedMessageBlob : DWORD;
  MemAddr: Cardinal;
  hCertStoreHandle : HCERTSTORE;
begin
  Memo1.Clear;
  pStreamIn := TMemoryStream.Create;
  pStreamOut := TMemoryStream.Create;
  //if ( not assigned( hCertStoreHandle )) then
  //  Err( Format( 'Îøèáêà ïðè îòêðûòèè õðàíèëèùà: %s', [ CERT_STORE_NAME ] ));
  try
    //pSignerCert := CertFindCertificateInStore( hCertStoreHandle, MY_ENCODING_TYPE, 0, CERT_FIND_SUBJECT_STR, PWideChar( SignerName ), nil );
    pStreamIn.LoadFromFile( 'c:\test.sig' );
    FillChar( VerifyParams, SizeOf( CRYPT_VERIFY_MESSAGE_PARA ), #0 );
    VerifyParams.cbSize := SizeOf( CRYPT_VERIFY_MESSAGE_PARA );
    VerifyParams.dwMsgAndCertEncodingType := MY_ENCODING_TYPE;
    if not ( CryptVerifyMessageSignature( @VerifyParams, 0, pStreamIn.Memory, pStreamIn.Size,
                                          nil, cbDecodedMessageBlob, nil )) then
      Err( 'Íå óäàëîñü óçíàòü ðàçìåð áóôåðà' );
    pStreamOut.Size := cbDecodedMessageBlob;
    if not ( CryptVerifyMessageSignature( @VerifyParams, 0, pStreamIn.Memory, pStreamIn.Size,
                                          pStreamOut.Memory, cbDecodedMessageBlob, nil )) then
      Err( 'Íå óäàëîñü ïðîâåðèòü ïîäïèñü' );
    pStreamOut.Size := cbDecodedMessageBlob;
    pStreamOut.SaveToFile( 'c:\test.res' );
    Memo1.Lines.Add( 'Ïîäïèñü âåðíà' );
    FillChar(CertInfo, SizeOf(CERT_INFO), #0);
    hCertStoreHandle := CertOpenSystemStore( 0, PChar( CERT_STORE_NAME ));
    pSignerCert := VerifyParams.pfnGetSignerCertificate(VerifyParams.pvGetArg,
                                                        X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,
                                                        @CertInfo,
                                                        hCertStoreHandle);
    Memo1.Lines.Add('Äî: '+DateTimeToStr(CertInfo.NotAfter.dwHighDateTime+CertInfo.NotAfter.dwLowDateTime));
  finally
    FreeAndNil( pStreamIn );
    FreeAndNil( pStreamOut );
  end;

Но ругается в функции pfnGetSignerCertificate на AccessViol...
Может кто знает в чем тут дело? Сама проверка проходит нормально. Структура CertInfo благополучно заполняется 0-ми... Чего ему еще надо?
6 май 08, 05:26    [5628719]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Альт
Member

Откуда: Сибирь
Сообщений: 4581
Привет, а это снова я... душевно сидим ) похоже, что тема больше никому не интересна...
Между вашей постановкой задачи и реализацией мало связей... или я опять не понял ваш код. Вам нужно поймать контексты сертификатов... и сделать это можно кучей способов... хотите про pfnGetSignerCertificate, давайте... она является калбек функцией и вызывается крипто ядром для поиска сертификата еще на этапе валидации... сама attached подпись является, если утрировать, хранилищем сертификатов... вы делаете странные вещи… занулили структуру VerifyParams, а потом пытаетесь вызвать pfnGetSignerCertificate с нулевого адреса… какой в этом смысл? только не говорите, что в мсдн именно так выглядит пример...

Я не знаю, что придумать, чтобы нам не лезть в дебри… давайте просто отработаем калбек и переберем сертификаты в подписи…
function CompareCertificateInfo( const Base, Comp: PCERT_INFO ) : Boolean;
var iSize : DWORD;
begin
  iSize := Base.SerialNumber.cbData;
  if iSize > Comp.SerialNumber.cbData then
    iSize := Comp.SerialNumber.cbData;
  Result := CompareMem( Base.SerialNumber.pbData, Comp.SerialNumber.pbData, iSize );
end;

function GetSignerCertificate( pvGetArg: PVOID; dwCertEncodingType: DWORD; pSignerId: PCERT_INFO;
          hMsgCertStore: HCERTSTORE  ) : PCCERT_CONTEXT; stdcall;
begin
  Result := nil;
  repeat
    Result := CertEnumCertificatesInStore( hMsgCertStore, Result );
    if Assigned( Result ) then
      if CompareCertificateInfo( pSignerId, Result.pCertInfo ) then
        Break;
  until not assigned( Result );
end;

...
var
  Certificate : PCCERT_CONTEXT;
  VerifyParams : CRYPT_VERIFY_MESSAGE_PARA;
  pStreamIn, pStreamOut : TMemoryStream;
  cbDecodedMessageBlob : DWORD;
begin
  Memo.Clear;
  pStreamIn := TMemoryStream.Create;
  pStreamOut := TMemoryStream.Create;
  try
    pStreamIn.LoadFromFile( 'c:\test.sig' );
    FillChar( VerifyParams, SizeOf( CRYPT_VERIFY_MESSAGE_PARA ), #0 );
    VerifyParams.cbSize := SizeOf( CRYPT_VERIFY_MESSAGE_PARA );
    VerifyParams.dwMsgAndCertEncodingType := MY_ENCODING_TYPE;
    VerifyParams.pfnGetSignerCertificate := @GetSignerCertificate;
    if not ( CryptVerifyMessageSignature( VerifyParams, 0, pStreamIn.Memory, pStreamIn.Size,
                                          nil, cbDecodedMessageBlob, nil )) then
      Err( 'Не удалось узнать размер буфера' );
    pStreamOut.Size := cbDecodedMessageBlob;
    Memo.Lines.Add( IntToStr( cbDecodedMessageBlob ));
    if not ( CryptVerifyMessageSignature( VerifyParams, 0, pStreamIn.Memory, pStreamIn.Size,
                                          pStreamOut.Memory, cbDecodedMessageBlob, @Certificate )) then
      Err( 'Не удалось проверить подпись' );
    pStreamOut.Size := cbDecodedMessageBlob;
    pStreamOut.SaveToFile( 'c:\test.res' );
    Memo.Lines.Add( 'Подпись верна' );
    { тут можно делать с контекстом серитфиката все, что вашей душе угодно }
    if not ( CertFreeCertificateContext( Certificate )) then
      Err( 'Не удалось удалить контекс сертификата' );
  finally
    FreeAndNil( pStreamIn );
    FreeAndNil( pStreamOut );
  end;
end;

а вообще вам все это не нужно... калбек интересен, например, когда мы хотим работать с альтернативными хранилищами сертификатов... например бд... лучше посмотрите на описание последнего параметра CryptVerifyMessageSignature, до CertFreeCertificateContext вы можете все что угодно делать в полученным в Certificate контекстом сертификата подписавшего...


Скажи, что с нами будет, если нам дадут все ни за что,
Мы умрем в изумрудах, не сказав ничего (с) Магнитная Аномалия - В Изумрудах
6 май 08, 09:03    [5628867]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Альт
Member

Откуда: Сибирь
Сообщений: 4581
что-то у меня только сейчас мозг включился... исправляю дополнительную функцию сравнения...
function CompareBlob( const Base, Comp: PCRYPTOAPI_BLOB ) : Boolean;
begin
  Result := ( Base.cbData = Comp.cbData );
  if Result then
    Result := CompareMem( Base.pbData, Comp.pbData, Base.cbData );
end;

function CompareCertificateInfo( const Base, Comp: PCERT_INFO ) : Boolean;
begin
  Result := CompareBlob( @Base.Issuer, @Comp.Issuer ) and
            CompareBlob( @Base.SerialNumber, @Comp.SerialNumber );
end;
извиняюсь за неточность


Скажи, что с нами будет, если нам дадут все ни за что,
Мы умрем в изумрудах, не сказав ничего (с) Магнитная Аномалия - В Изумрудах
6 май 08, 12:43    [5630296]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
vovanka
Member

Откуда:
Сообщений: 11
интересна, я ее постоянно читаю
6 май 08, 21:00    [5633353]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Miktor
Member

Откуда: г. Хабаровск
Сообщений: 398
Да нет, это я извиняюсь за безграмотную постановку. Надо было действительно внимательней прочиться описание функции CryptVerifyMessageSignature. Кажется это все что мне надо. Т.е. хотелось бы подписать документ (проверив его валидность по срокам), потом проверить правильность подписи и в случае необходимости вывести информацию о сертификате. Больше ничего не надо. Ну может быть еще при настройке клиента, вывести список его личных сертификатов, чтобы выбрать тот, которым он будет подписывать. Но это можно сделать и в ручную.
И опять же спасибо за помощ.
8 май 08, 01:12    [5639553]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Miktor
Member

Откуда: г. Хабаровск
Сообщений: 398
Еще вопрос. (может не в тему) Не могу получить дату из CertInfo.NotAfter. Пытаюсь
Var
  FileTime: DWORD;
...
    LongRec(FileTime).Lo := CertInfo.NotAfter.dwLowDateTime;
    LongRec(FileTime).Hi := CertInfo.NotAfter.dwHighDateTime;
    Memo1.Lines.Add('Äî: '+DateTimeToStr(FileDateToDateTime(FileTime)));

Выдает 1982 год. Ну вообще не ту дату. Нашел функцию
function FileDate2DateTime(FileTime : tFileTime) : tDateTime;
var LocalTime : tFileTime;
    DOSFileTime : DWord;
begin
  FileTimeToLocalFileTime(LocalTime, LocalTime); // Compensate for time zone
  FileTimeToDosDateTime(FileTime,  LongRec(DOSFileTime).Hi,
     LongRec(DOSFileTime).Lo);
  Result := FileDateToDateTime(DOSFileTime);
end;
но результат тоже не тот. Совсем не тот. Че не так-то?
8 май 08, 02:02    [5639607]     Ответить | Цитировать Сообщить модератору
 Re: Как сделать цифровую подпись на основе сертификата  [new]
Альт
Member

Откуда: Сибирь
Сообщений: 4581
Валидация срока использования пойманного контекста выполняется, например, вызовом в лоб:
Win32Check( CertVerifyTimeValidity( nil, Certificate.pCertInfo ) = 0 );

функция разбора дат
function DecodeDate( FileTime : TFileTime ) : TDateTime;
var
  SystemTime : TSystemTime;
  ModifiedTime : TFileTime;
begin
  FileTimeToLocalFileTime( FileTime, ModifiedTime );
  FileTimeToSystemTime( ModifiedTime, SystemTime );
  Result := SystemTimeToDateTime( SystemTime );
end;

пример вызова
  ...
  DateTimeToStr( DecodeDate( Certificate.pCertInfo.NotBefore ))
  DateTimeToStr( DecodeDate( Certificate.pCertInfo.NotAfter ))
  ...

А вообще я не гордый и бедный... принимаю любые суммы на вебмани счет R153279149005
Раз уж писать код... тем более профильный, то делать это надо за вознаграждение.
С уважением, Павел Данченко
http://cryptocode.ru
8 май 08, 10:04    [5640111]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 2 [3] 4 5 6   вперед  Ctrl      все
Все форумы / Delphi Ответить