Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
 Как получить сведения подписантов из sig-файла? (CryptVerifyDetachedMessageSignature)  [new]
Devillio
Member

Откуда: Волгоград
Сообщений: 231
Доброго времени суток!

Требуется подписывать файлы, проверять валидность подписей, выдавать информацию о подписантах.
Получилось подписывать и проверять, на просторах есть готовые тексты, завис с выводом информации.

Вот текст тестовой процедуры, в комментариях
+ Сори за форматирование, просто изучаю :)
procedure TMainForm.Button3Click(Sender: TObject);
var veriPara: CRYPT_VERIFY_MESSAGE_PARA;
     mStreamIn, mStreamSignIn: TMemoryStream;
     arrDataPointer: array of Pointer;
     arrDataSize: array of DWORD;

     c, i: Integer;
     sFileToVerifyPath, sSignaturePath: String;
     S: String;
     ACert: PCCERT_CONTEXT;
     PPCert: PPCCERT_CONTEXT;

function ByteArrayToStr(pbData: PByte; cbData: DWORD): String;
var
I, J: Integer;
S: String;
begin
Result := '';
if not Assigned(pbData) or (cbData <= 0) then
Exit;
for I := 0 to cbData - 1 do
begin
J := PByteArray(pbData)^[i];
S := IntToHex(J, 2);
if (I > 0) and (I and 1 = 0) then
S := S + ' ';
Result := S + Result;
end;
end;

function GetSerialNumber(CertInfo: PCCERT_CONTEXT): String;
begin
Result := ByteArrayToStr(CertInfo.pCertInfo.SerialNumber.pbData,
CertInfo.pCertInfo.SerialNumber.cbData);
end;

function MySignerCertificateCallback( pvGetArg : pvoid; dwCertEncodingType : DWORD;pSignerId : PCERT_INFO;hMsgCertStore : HCERTSTORE): PCCERT_CONTEXT ;
begin
Result := PCCERT_CONTEXT(pvGetArg); //вот здесь Access Violation
end;

begin
  if not OpenDialog1.Execute then Exit;
  sFileToVerifyPath := OpenDialog1.FileName;
  sSignaturePath := OpenDialog1.FileName+'.sig';
  try
    mStreamIn:= TMemoryStream.Create;
    mStreamIn.LoadFromFile(sFileToVerifyPath);
    SetLength(arrDataPointer, 1);
    SetLength(arrDataSize, 1);
    arrDataPointer[0]:= mStreamIn.memory;
    arrDataSize[0]:= mStreamIn.Size;
    mStreamSignIn:= TMemoryStream.Create;
    mStreamSignIn.LoadFromFile(sSignaturePath);
    FillChar(veriPara, SizeOf(CRYPT_VERIFY_MESSAGE_PARA), #0);
    veriPara.cbSize:= SizeOf(CRYPT_VERIFY_MESSAGE_PARA);
    veriPara.dwMsgAndCertEncodingType:= PKCS_7_ASN_ENCODING or X509_ASN_ENCODING;
//    veriPara.pfnGetSignerCertificate := @MySignerCertificateCallback;
    C := CryptGetMessageSignerCount(PKCS_7_ASN_ENCODING or X509_ASN_ENCODING, mStreamSignIn.Memory, mStreamSignIn.Size);
    for i := 0 to C-1 do
      if CryptVerifyDetachedMessageSignature(@veriPara, i, mStreamSignIn.Memory, mStreamSignIn.Size, 1, Pointer(arrDataPointer), Pointer(arrDataSize), PPCert) then
      begin
        //при ремарке строки "veriPara.pfnGetSignerCertificate := @..." здесь Access Violation
        //PPCert всегда nil приходит, но подпись есть и верна (проверял сайтом криптопро)
        with PPCert^.pCertInfo.Issuer do 
        S :=S+#13#10+'SN: '+ByteArrayToStr(pbData, cbData) ;
//        S :=S+#13#10+'SN: '+GetSerialNumber(aCERT^);
        S:=S+#13#10;
//       CertFreeCertificateContext(ACert^);
      end;


  except
    on e:exception do
    MessageDlg(e.Message, mtInformation, [mbok], 0);
  end;

  MessageDlg('Подписантов: '+IntToStr(C)+S, mtInformation, [mbok], 0);
end;


Помогите, будьте добры? Очень не очень я с указателями :(
Спасибо!
12 май 18, 09:04    [21404608]     Ответить | Цитировать Сообщить модератору
 Re: Как получить сведения подписантов из sig-файла? (CryptVerifyDetachedMessageSignature)  [new]
Devillio
Member

Откуда: Волгоград
Сообщений: 231
Может это важно?

Картинка с другого сайта.
Картинка с другого сайта.
12 май 18, 09:49    [21404631]     Ответить | Цитировать Сообщить модератору
 Re: Как получить сведения подписантов из sig-файла? (CryptVerifyDetachedMessageSignature)  [new]
alekcvp
Member

Откуда:
Сообщений: 761
Devillio,

Навскидку - вот так, не?
function MySignerCertificateCallback( pvGetArg : pvoid; dwCertEncodingType : DWORD;pSignerId : PCERT_INFO;hMsgCertStore : HCERTSTORE): PCCERT_CONTEXT ; stdcall;
12 май 18, 11:14    [21404719]     Ответить | Цитировать Сообщить модератору
 Re: Как получить сведения подписантов из sig-файла? (CryptVerifyDetachedMessageSignature)  [new]
Devillio
Member

Откуда: Волгоград
Сообщений: 231
alekcvp, благодарю за ответ.
Да, натыкался на такой совет, не помогло, т.к. навертел там еще несколько ошибок :)
Мож вдруг кто-то на те же грабли наступит:
1)
veriPara.pfnGetSignerCertificate := nil; // @MySignerCertificateCallback;
veriPara.pvGetArg := nil; // ACert;
(не надо куралесить своё, встроенное работает)
2) CryptVerifyDetachedMessageSignature(@veriPara, i, mStreamSignIn.Memory, mStreamSignIn.Size, 1, Pointer(arrDataPointer), Pointer(arrDataSize), @ACert)
(ACert: PCCERT_CONTEXT)

3) еще вот такую функцию нашел читать encoded data:
+
function GetCertString(dwType,dwFlags:DWORD;pvTypePara:Pointer=nil):string;
var dwSize: DWORD;
  begin
    dwSize:=CertGetNameString(ACert,dwType,dwFlags,pvTypePara,nil,0);
    Win32Check(dwSize<>0);
    SetLength(Result,dwSize);
    Win32Check(CertGetNameString(ACert,dwType,dwFlags,pvTypePara,
      Pointer(Result),dwSize)<>0);
    Result := StringReplace(Result, #0, '', []);
  end;

...
        S :=S+#13#10+'Issuer Name: '+GetCertString(CERT_NAME_SIMPLE_DISPLAY_TYPE,CERT_NAME_ISSUER_FLAG);
        S :=S+#13#10+'Subject: '+ GetCertString(CERT_NAME_SIMPLE_DISPLAY_TYPE,0) ;
//GetCertString возвращает распакованные строчки кто выпустил серт, на кого, и т.д.

Результирующую процедуру пока не могу проверить на две и более подписи, но для одной работает
12 май 18, 13:42    [21404889]     Ответить | Цитировать Сообщить модератору
 Re: Как получить сведения подписантов из sig-файла? (CryptVerifyDetachedMessageSignature)  [new]
alekcvp
Member

Откуда:
Сообщений: 761
Devillio
Да, натыкался на такой совет

Это не совет, это правило. Любые коллбэки, которые вызывает винда, должны быть объявлены как stdcall, если в описании не сказано иного. Иначе параметры передаются неправильно и вы получаете мусор внутри.
12 май 18, 16:38    [21405094]     Ответить | Цитировать Сообщить модератору
Все форумы / Delphi Ответить