crm

До слета в Пятигорске осталось

  • 7
  • 8
дней

Форум

RatWar

Форум

Дата создания

Выбрать дату в календареВыбрать дату в календаре

Тема

Сообщение

Упорядочить

Выбрать дату в календареВыбрать дату в календаре

Взаимодействие с ГИС ЖКХ: XLSX vs. SOAP
 
[QUOTE]two_oceans пишет:
По идее для вычисления хеша не нужен закрытый ключ, но для вычисления SignatureValue закрытый ключ потребуется.[/QUOTE]
Да, один раз вычисляю дайджест и сохраняю его. Если сертификат не меняется, то дайджест тоже не меняется. Потому то в дальнейшем не нужен *.key.
Fdigest2: string; // Берётся сертификат в x509, декодируется из BASE64, считается от него хеш-сумма и вывод кодируется в BASE64
Взаимодействие с ГИС ЖКХ: XLSX vs. SOAP
 
[QUOTE]two_oceans пишет:
Ну отдельный класс для каждого отчета править после смен версий ГИС это немного чересчур.[/QUOTE]
В примере класса можно увидеть, что сама версия ГИС обозначается константой cVer_xxx..., константы эти собраны в отдельном файле. Ну если метод измениться, то придется корректировать класс. На каждый метод свой класс, в главном классе вызов методов класса идет по интерфейсной переменой, что упрощает управление памятью и не трогает основную логику.
Взаимодействие с ГИС ЖКХ: XLSX vs. SOAP
 
OpenSSL не сертифицирован это да, насчет устаревания, всегда можно скачать свежую версию и собрать.
КриптоПро использует ту же OpenSSL, сертифицирует и продает, у них то как раз версия будет устаревшая, т.к. на сертификацию требуется время.
Для подписи ключ не нужен, нужны лишь его параметры, которые можно один раз получить и хранить например, в ini-файле. Для IdSSLIOHandlerSocketOpenSSL нужны ключи, в формате *.key и *.pem

[SIZE=85px][COLOR=greenpt]Отправлено спустя 3 минуты 2 секунды:[/COLOR][/SIZE]
В заголовке класса подписи видно, что у меня реализовано 2 конструктора, с параметрами и с чтением ключа

[SIZE=85px][COLOR=greenpt]Отправлено спустя 1 минуту 51 секунды:[/COLOR][/SIZE]
[QUOTE]Programmer пишет:
ГОСПОДИ! Откуда Вы все это знаете?[/QUOTE]
Опыт сын ошибок трудных...
Взаимодействие с ГИС ЖКХ: XLSX vs. SOAP
 
Приветствую всех.
Шлю запросы по https с подписью.
Кратко опишу свой путь.
Использовал [B]Delphi 7[/B](лиценз.),
[B]P12FromGostCSP[/B] для получения *.key (закрытый ключ для подписи).
[B]SoapUI[/B] для получения и отладки запросов.
Статья на Хабре "[I]Взаимодействие с ГИС ЖКХ с помощью stunnel и openssl по ГОСТу[/I]".
[B]OpenSSL[/B] с гост, по ссылке той статьи.
[B]Python[/B] + [B]Eclipse[/B] для изучения алгоритма подписи.
Компоненты [B]Indy[/B] поддерживают OpenSSL, т.о. защищенный канал "из коробки".
Каждый метод ГИСа, реализовал отдельным классом, с генерацией каноникализированного xml ручками. Для удобства наследовал от интерфейса.
Для подписи, по алгоритму статьи, написал класс для подписи, процедуры шифрования вызываю из dll, скачал заголовочный файл [U]libeay32.pas[/U], каноникализации в Delphi 7 нет, но т.к. запросы сами каноникализированы, то разобрался с namespace и всё, готов класс.
Парсинг ответных сообщений с помощью [U]SimpleXML.pas[/U], для логирования - [U]LDSLogger.pas[/U].
Задача с ГИСом пока фоновая, есть поважнее проекты.
КриптоПро не использую, это тот же самый OpenSSL + сервисные функции, и за деньги.
stunnel также не нужен использую Indy

[SIZE=85px][COLOR=greenpt]Отправлено спустя 11 минуты 42 секунды:[/COLOR][/SIZE]
Шифрование по ГОСТу (алгоритм)
[code:fs2tuymr]function SignGOST(const Data, KeyFN: string): string;
var
 dlen: Integer;
 slen: Cardinal;
 md: pEVP_MD;
 Key: pEVP_PKEY;
 mdctx: pEVP_MD_CTX;
 memout, Base64: pBIO;
 b64Length: Integer;
 outBuf: array[0..4095] of Char;
 mdValue: array[0..EVP_MAX_MD_SIZE] of byte;
begin
 dlen := Length(Data);
 Key := ReadPrivateKey(KeyFN); // читаем файл закрытого ключа
 slen := EVP_PKEY_size(Key);   // определяем размер ключа
 SetLength(Result, slen);     // размер подписи будет таким же
 md := EVP_get_digestbyname('md_gost94');  // получаем доступ к хэш-функции
 New(mdctx);    // формируем контекст подписи
 EVP_SignInit(mdctx, md);     // устанавливаем хэш-функцию, которая буддет использована
 EVP_SignUpdate(mdctx, PChar(Data), dlen);   // подписываем данные
 EVP_SignFinal(mdctx, @mdValue, slen, Key);   // завершаем формирование подписи
 EVP_PKEY_free(Key);      // освобождаем ресурсы
 Dispose(mdctx);
 // вывод в Base64
 Base64 := BIO_new(BIO_f_base64); // BIO типа base64
 memout := BIO_new(BIO_s_mem);    // BIO в памяти для чтения-записи
 Base64 := BIO_push(Base64, memout);
 BIO_write(Base64, @mdValue, slen);  // Пытается записать в Base64 sLen байт из буфера Result. Возвращает количество записанных байт
 BIO_flush(Base64);
 b64Length := BIO_read(memout, @outbuf, 4096);
 outbuf[b64Length - 1] := #0;
 Result := StrPas(@outbuf);
end;[/code:fs2tuymr]

[SIZE=85px][COLOR=greenpt]Отправлено спустя 2 минуты 23 секунды:[/COLOR][/SIZE]
Заголовок класса подписи
[code:fs2tuymr]unit Xades;

interface

//{$DEFINE TEST}

uses
 Classes;

(*
 Класс TXades подписывает XML,
   пример:
 x: TXades;
 создание при указании файла ключа ->  x := TXades.Create('C:\cert.key');
 создание при передаче параметров  ->  x := TXades.Create(key, digest2, x509_issuer_name, x509_sn);
 возврат текста подписанного XML   ->  mmo1.Text := x.GetSignXML(XML, SignedId);
*)

type
 TXades = class
 private
   FItemXML: TStringList;   // элементы сообщения
   FBodyXML: TStringList;   // тело сообщения
   FSignXML: TStringList;   // подписанный XML
   FNameSpace: TStringList; // пространство имен
   FSignedInfo: TStringList;// информация о подписи
   Fsignature_id: string;   // генерируются
   Fsigned_id: string;      // ID запроса, который указываем, как хотим и на который ориентируемся, подписывая запрос
   Fdigest1: string; // Берётся содержимое тега <ns1:Body>), канонизируется алгоритмом C14N (exclusive=True), считается от неё хеш-сумма по ГОСТу и выводится в виде BASE64
   Fdigest2: string; // Берётся сертификат в x509, декодируется из BASE64, считается от него хеш-сумма и вывод кодируется в BASE64
   Fdigest3: string; // Формируется содержимое тега <xades:SignedProperties>, канонизируется алгоритмом C14N (exclusive=False) и от содержимого считается
   Fsignature_value: string;  // Формируется блок <ds:SignedInfo>, канонизируется алгоритмом C14N (exclusive=False), подписывается и кодируется в BASE64.
   Fx590_cert: string;    // x509 ключ из файла
   Fsigning_time: string; // запоминается текущее время
   Fx509_issuer_name: string; // Данные УЦ, выпустившего сертификат
   Fx509_sn: string;          // номер сертификата
   Fkey: string;              // имя и путь ключа
   procedure GetDigest1();      // Вычисление Fdigest1
   procedure GetDigest3();      // Вычисление Fdigest3
   procedure LoadNameSpace();   // Поиск и загрузка пространства имен
   procedure SetSignatureId();  // Генерация Id
   procedure SetTextSignXML();  // Все полученные значения вносятся в шаблон XML-документа формата XAdES-BES
   procedure Signature();       // Вычисление Fsignature_value
 public
   constructor Create(const key, digest2, x509_issuer_name, x509_sn: string); overload;
   constructor Create(const Key: string); overload;
   destructor Destroy; override;
   function GetSignXML(const XML, SignedId: string): string;
{$IFDEF TEST}
   function GetDigests(const XML, SignedId: string): string;  // значения: Fdiges1, Fdiges2, Fdiges3
{$ENDIF}
 end;

implementation[/code:fs2tuymr]

[SIZE=85px][COLOR=greenpt]Отправлено спустя 2 минуты 14 секунды:[/COLOR][/SIZE]
Один из классов для ГИСа
[code:fs2tuymr]{*------------------------------------------------------------------------------
 Экспорт сведений об организациях
-------------------------------------------------------------------------------}

unit ExportOrgRegistry;

interface

uses
 GIS_Interface;

type
 TExportOrgRegistry = class(TInterfacedObject, IGIS)
 private
   FOGRN: string; /// ОГРН
   FAsync: Boolean;
   FDate: string;
   FGUID: string;
   FXML: string;
   function Header(): string;
 public
   constructor Create(const orgPPAGUID, OGRN: string; Async: Boolean = False);
   function Async(): Boolean;
   function Command(): string;
   function Date(): string;
   function HeaderAction(): string;
   function GetObject: TObject;
   function GUID(): string;
   function WebService(): string;
   function XML(): string;
 end;

implementation

uses
 GIS_Query, GIS_Const;

{ TExportOrgRegistry }

function TExportOrgRegistry.Async: Boolean;
begin
 Result := FAsync;
end;

function TExportOrgRegistry.Command: string;
begin
 Result := 'exportOrgRegistry';
 if FAsync then
   Result := Result + '(Async)';
end;

constructor TExportOrgRegistry.Create(const orgPPAGUID, OGRN: string; Async: Boolean = False);
begin
 FAsync := Async;
 FOGRN := OGRN;
 FDate := SetDate;
 FGUID := SetGUID_Message(orgPPAGUID, metExportOrgRegistry);
 FXML := Concat(Header(),
                MakeXMLnode('soapenv:Body', '', BeginNode),
                MakeXMLnode('org:exportOrgRegistryRequest', cVer_ExportOrgRegistry, '', BeginNode),
                MakeXMLnode('org:SearchCriteria', '', BeginNode),
                MakeXMLnode('org1:OGRN', FOGRN, FullNode),
                MakeXMLnode('org:SearchCriteria', '', EndNode),
                MakeXMLnode('org:exportOrgRegistryRequest', '', EndNode),
                MakeXMLnode('soapenv:Body', '', EndNode),
                MakeXMLnode('soapenv:Envelope', '', EndNode));
end;

function TExportOrgRegistry.Date: string;
begin
 Result := FDate;
end;

function TExportOrgRegistry.GetObject: TObject;
begin
 Result := Self;
end;

function TExportOrgRegistry.GUID: string;
begin
 Result := FGUID;
end;

function TExportOrgRegistry.Header: string;
begin
 Result := Concat(cHeader, cNS_ExportOrgRegistry, #10,
                  MakeXMLnode('soapenv:Header', '', BeginNode),
                  MakeXMLnode('base:ISRequestHeader', '', BeginNode),
                  FDate, #10, FGUID, #10,
                  MakeXMLnode('base:ISRequestHeader', '', EndNode),
                  MakeXMLnode('soapenv:Header', '', EndNode));
end;

function TExportOrgRegistry.HeaderAction: string;
begin
 Result := '"urn:exportOrgRegistry"';
end;

function TExportOrgRegistry.WebService: string;
begin
 Result := 'ext-bus-org-registry-common-service/services/OrgRegistryCommon';
 if FAsync then
   Result := Result + 'Async';
end;

function TExportOrgRegistry.XML: string;
begin
 Result := FXML;
end;

end.
[/code:fs2tuymr]

[SIZE=85px][COLOR=greenpt]Отправлено спустя 8 минуты 58 секунды:[/COLOR][/SIZE]
Важно! Загрузка ГОСТа из dll (последняя строка)
[code:fs2tuymr](*
 инициализация библиотеки
*)
procedure LoadSSL;
begin
 OpenSSL_add_all_algorithms;
 OpenSSL_add_all_ciphers;
 OpenSSL_add_all_digests;
 ERR_load_crypto_strings;
 ERR_load_RSA_strings;
 // используется имя файла, указанное в OPENSSL_CONF
 OPENSSL_config(PChar(GetDOSEnvVar('OPENSSL_CONF')));
end;
[/code:fs2tuymr]

[SIZE=85px][COLOR=greenpt]Отправлено спустя 14 минуты 20 секунды:[/COLOR][/SIZE]
Из ИндиЛога заголовок запроса на https (по http похожий):
[I]POST /ext-bus-org-registry-common-service/services/OrgRegistryCommon HTTP/1.0
Content-Type: text/xml; charset=UTF-8
Content-Length: 6333
SOAPAction: "urn:exportOrgRegistry"
Authorization: Basic c2l0OnJaX0dHNzJYU15WZjU1Wlc=
X-Client-Cert-Fingerprint: cb.... (тут мой отпечаток серт.)
Host: 217.107.108.156:10081
Accept: text/html, */*
Accept-Encoding: gzip,deflate, identity
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)[/I]

[SIZE=85px][COLOR=greenpt]Отправлено спустя 5 минуты 19 секунды:[/COLOR][/SIZE]
Для изучения шифрования по ГОСТу помогло изучение "Библиотека libcrypto.Руководство программиста" от КриптоКома.
Всех с наступающим 23 февраля, вспомним как служили!
Поддержка длинных строк
 
Предполагаю один раз взять данные сертификата, записать в инифайл и если нужно беру их оттуда
Серийник берется просто:
[quote:2jlddosl]function SerialNumber(const FileName: string): string;
var
 x: pX509;
begin
 x := X509(FileName);
 Result := BN_bn2dec(ASN1_INTEGER_to_BN(X509_get_serialNumber(x), nil));
 X509_free(x);
end;[/quote:2jlddosl]
Издателя сложнее, но получилось также вытащить, пока остановился на каноникализации.

[SIZE=85px][COLOR=greenpt]Отправлено спустя 2 минуты 15 секунды:[/COLOR][/SIZE]
Забыл еще, так загружаю сертификат
[code:2jlddosl]function X509(const f: string): pX509;
var
 bio_cert: pBIO;
 k: pX509;
begin
 k := X509_new;
 bio_cert := BIO_new_file(PChar(f), 'rb');
 Result := PEM_read_bio_X509(bio_cert, k, nil, nil);
 BIO_free(bio_cert);
end;
[/code:2jlddosl]

[SIZE=85px][COLOR=greenpt]Отправлено спустя 2 минуты 3 секунды:[/COLOR][/SIZE]
Использую документ Криптоком
Библиотека libcrypto.
Руководство программиста

[SIZE=85px][COLOR=greenpt]Отправлено спустя 2 минуты 53 секунды:[/COLOR][/SIZE]
В консоль обращаюсь через StdIn и StdOut, у меня на машине лиценз. DrWeb не обращает внимания
Поддержка длинных строк
 
А я начал делать библиотеку подписания через OpenSSL.
Хэш считаю так:
[code:1mjl2t8v]function GOSTR3411(const msg: string): string;
var
 inBuf, outBuf: array[0..4095] of Char;
 mdctx: EVP_MD_CTX;
 mdValue: array[0..EVP_MAX_MD_SIZE] of byte;
 mdLength: Cardinal;
 b64Length: Integer;
 memout, Base64: pBIO;
begin
 StrPCopy(inbuf, msg);
 EVP_DigestInit(@mdctx, EVP_get_digestbyname(PChar('md_gost94')));
 EVP_DigestUpdate(@mdctx, @inbuf, StrLen(inbuf));
 EVP_DigestFinal(@mdctx, @mdValue, mdLength);
 Base64 := BIO_new(BIO_f_base64); // BIO типа base64
 memout := BIO_new(BIO_s_mem);
 Base64 := BIO_push(Base64, memout);
 BIO_write(Base64, @mdValue, mdLength);
 BIO_flush(Base64);
 b64Length := BIO_read(memout, @outbuf, 4096);
 outbuf[b64Length - 1] := #0;
 Result := StrPas(@outbuf);
end;[/code:1mjl2t8v]

Хэш сертификата можно один раз подсчитать через вызов в консоли:
[code:1mjl2t8v]function GetDigest(const Text: string): string;
begin
 GetDosOutput('openssl dgst -binary -md_gost94 |openssl base64', Text, 30, Result);
 Delete(Result, Length(Result), 1);
end;[/code:1mjl2t8v]
#
[QUOTE]two_oceans пишет:
По идее для вычисления хеша не нужен закрытый ключ, но для вычисления SignatureValue закрытый ключ потребуется.[/QUOTE]
Да, один раз вычисляю дайджест и сохраняю его. Если сертификат не меняется, то дайджест тоже не меняется. Потому то в дальнейшем не нужен *.key.
Fdigest2: string; // Берётся сертификат в x509, декодируется из BASE64, считается от него хеш-сумма и вывод кодируется в BASE64
#
[QUOTE]two_oceans пишет:
Ну отдельный класс для каждого отчета править после смен версий ГИС это немного чересчур.[/QUOTE]
В примере класса можно увидеть, что сама версия ГИС обозначается константой cVer_xxx..., константы эти собраны в отдельном файле. Ну если метод измениться, то придется корректировать класс. На каждый метод свой класс, в главном классе вызов методов класса идет по интерфейсной переменой, что упрощает управление памятью и не трогает основную логику.
#
OpenSSL не сертифицирован это да, насчет устаревания, всегда можно скачать свежую версию и собрать.
КриптоПро использует ту же OpenSSL, сертифицирует и продает, у них то как раз версия будет устаревшая, т.к. на сертификацию требуется время.
Для подписи ключ не нужен, нужны лишь его параметры, которые можно один раз получить и хранить например, в ini-файле. Для IdSSLIOHandlerSocketOpenSSL нужны ключи, в формате *.key и *.pem

[SIZE=85px][COLOR=greenpt]Отправлено спустя 3 минуты 2 секунды:[/COLOR][/SIZE]
В заголовке класса подписи видно, что у меня реализовано 2 конструктора, с параметрами и с чтением ключа

[SIZE=85px][COLOR=greenpt]Отправлено спустя 1 минуту 51 секунды:[/COLOR][/SIZE]
[QUOTE]Programmer пишет:
ГОСПОДИ! Откуда Вы все это знаете?[/QUOTE]
Опыт сын ошибок трудных...
#
Приветствую всех.
Шлю запросы по https с подписью.
Кратко опишу свой путь.
Использовал [B]Delphi 7[/B](лиценз.),
[B]P12FromGostCSP[/B] для получения *.key (закрытый ключ для подписи).
[B]SoapUI[/B] для получения и отладки запросов.
Статья на Хабре "[I]Взаимодействие с ГИС ЖКХ с помощью stunnel и openssl по ГОСТу[/I]".
[B]OpenSSL[/B] с гост, по ссылке той статьи.
[B]Python[/B] + [B]Eclipse[/B] для изучения алгоритма подписи.
Компоненты [B]Indy[/B] поддерживают OpenSSL, т.о. защищенный канал "из коробки".
Каждый метод ГИСа, реализовал отдельным классом, с генерацией каноникализированного xml ручками. Для удобства наследовал от интерфейса.
Для подписи, по алгоритму статьи, написал класс для подписи, процедуры шифрования вызываю из dll, скачал заголовочный файл [U]libeay32.pas[/U], каноникализации в Delphi 7 нет, но т.к. запросы сами каноникализированы, то разобрался с namespace и всё, готов класс.
Парсинг ответных сообщений с помощью [U]SimpleXML.pas[/U], для логирования - [U]LDSLogger.pas[/U].
Задача с ГИСом пока фоновая, есть поважнее проекты.
КриптоПро не использую, это тот же самый OpenSSL + сервисные функции, и за деньги.
stunnel также не нужен использую Indy

[SIZE=85px][COLOR=greenpt]Отправлено спустя 11 минуты 42 секунды:[/COLOR][/SIZE]
Шифрование по ГОСТу (алгоритм)
[code:fs2tuymr]function SignGOST(const Data, KeyFN: string): string;
var
 dlen: Integer;
 slen: Cardinal;
 md: pEVP_MD;
 Key: pEVP_PKEY;
 mdctx: pEVP_MD_CTX;
 memout, Base64: pBIO;
 b64Length: Integer;
 outBuf: array[0..4095] of Char;
 mdValue: array[0..EVP_MAX_MD_SIZE] of byte;
begin
 dlen := Length(Data);
 Key := ReadPrivateKey(KeyFN); // читаем файл закрытого ключа
 slen := EVP_PKEY_size(Key);   // определяем размер ключа
 SetLength(Result, slen);     // размер подписи будет таким же
 md := EVP_get_digestbyname('md_gost94');  // получаем доступ к хэш-функции
 New(mdctx);    // формируем контекст подписи
 EVP_SignInit(mdctx, md);     // устанавливаем хэш-функцию, которая буддет использована
 EVP_SignUpdate(mdctx, PChar(Data), dlen);   // подписываем данные
 EVP_SignFinal(mdctx, @mdValue, slen, Key);   // завершаем формирование подписи
 EVP_PKEY_free(Key);      // освобождаем ресурсы
 Dispose(mdctx);
 // вывод в Base64
 Base64 := BIO_new(BIO_f_base64); // BIO типа base64
 memout := BIO_new(BIO_s_mem);    // BIO в памяти для чтения-записи
 Base64 := BIO_push(Base64, memout);
 BIO_write(Base64, @mdValue, slen);  // Пытается записать в Base64 sLen байт из буфера Result. Возвращает количество записанных байт
 BIO_flush(Base64);
 b64Length := BIO_read(memout, @outbuf, 4096);
 outbuf[b64Length - 1] := #0;
 Result := StrPas(@outbuf);
end;[/code:fs2tuymr]

[SIZE=85px][COLOR=greenpt]Отправлено спустя 2 минуты 23 секунды:[/COLOR][/SIZE]
Заголовок класса подписи
[code:fs2tuymr]unit Xades;

interface

//{$DEFINE TEST}

uses
 Classes;

(*
 Класс TXades подписывает XML,
   пример:
 x: TXades;
 создание при указании файла ключа ->  x := TXades.Create('C:\cert.key');
 создание при передаче параметров  ->  x := TXades.Create(key, digest2, x509_issuer_name, x509_sn);
 возврат текста подписанного XML   ->  mmo1.Text := x.GetSignXML(XML, SignedId);
*)

type
 TXades = class
 private
   FItemXML: TStringList;   // элементы сообщения
   FBodyXML: TStringList;   // тело сообщения
   FSignXML: TStringList;   // подписанный XML
   FNameSpace: TStringList; // пространство имен
   FSignedInfo: TStringList;// информация о подписи
   Fsignature_id: string;   // генерируются
   Fsigned_id: string;      // ID запроса, который указываем, как хотим и на который ориентируемся, подписывая запрос
   Fdigest1: string; // Берётся содержимое тега <ns1:Body>), канонизируется алгоритмом C14N (exclusive=True), считается от неё хеш-сумма по ГОСТу и выводится в виде BASE64
   Fdigest2: string; // Берётся сертификат в x509, декодируется из BASE64, считается от него хеш-сумма и вывод кодируется в BASE64
   Fdigest3: string; // Формируется содержимое тега <xades:SignedProperties>, канонизируется алгоритмом C14N (exclusive=False) и от содержимого считается
   Fsignature_value: string;  // Формируется блок <ds:SignedInfo>, канонизируется алгоритмом C14N (exclusive=False), подписывается и кодируется в BASE64.
   Fx590_cert: string;    // x509 ключ из файла
   Fsigning_time: string; // запоминается текущее время
   Fx509_issuer_name: string; // Данные УЦ, выпустившего сертификат
   Fx509_sn: string;          // номер сертификата
   Fkey: string;              // имя и путь ключа
   procedure GetDigest1();      // Вычисление Fdigest1
   procedure GetDigest3();      // Вычисление Fdigest3
   procedure LoadNameSpace();   // Поиск и загрузка пространства имен
   procedure SetSignatureId();  // Генерация Id
   procedure SetTextSignXML();  // Все полученные значения вносятся в шаблон XML-документа формата XAdES-BES
   procedure Signature();       // Вычисление Fsignature_value
 public
   constructor Create(const key, digest2, x509_issuer_name, x509_sn: string); overload;
   constructor Create(const Key: string); overload;
   destructor Destroy; override;
   function GetSignXML(const XML, SignedId: string): string;
{$IFDEF TEST}
   function GetDigests(const XML, SignedId: string): string;  // значения: Fdiges1, Fdiges2, Fdiges3
{$ENDIF}
 end;

implementation[/code:fs2tuymr]

[SIZE=85px][COLOR=greenpt]Отправлено спустя 2 минуты 14 секунды:[/COLOR][/SIZE]
Один из классов для ГИСа
[code:fs2tuymr]{*------------------------------------------------------------------------------
 Экспорт сведений об организациях
-------------------------------------------------------------------------------}

unit ExportOrgRegistry;

interface

uses
 GIS_Interface;

type
 TExportOrgRegistry = class(TInterfacedObject, IGIS)
 private
   FOGRN: string; /// ОГРН
   FAsync: Boolean;
   FDate: string;
   FGUID: string;
   FXML: string;
   function Header(): string;
 public
   constructor Create(const orgPPAGUID, OGRN: string; Async: Boolean = False);
   function Async(): Boolean;
   function Command(): string;
   function Date(): string;
   function HeaderAction(): string;
   function GetObject: TObject;
   function GUID(): string;
   function WebService(): string;
   function XML(): string;
 end;

implementation

uses
 GIS_Query, GIS_Const;

{ TExportOrgRegistry }

function TExportOrgRegistry.Async: Boolean;
begin
 Result := FAsync;
end;

function TExportOrgRegistry.Command: string;
begin
 Result := 'exportOrgRegistry';
 if FAsync then
   Result := Result + '(Async)';
end;

constructor TExportOrgRegistry.Create(const orgPPAGUID, OGRN: string; Async: Boolean = False);
begin
 FAsync := Async;
 FOGRN := OGRN;
 FDate := SetDate;
 FGUID := SetGUID_Message(orgPPAGUID, metExportOrgRegistry);
 FXML := Concat(Header(),
                MakeXMLnode('soapenv:Body', '', BeginNode),
                MakeXMLnode('org:exportOrgRegistryRequest', cVer_ExportOrgRegistry, '', BeginNode),
                MakeXMLnode('org:SearchCriteria', '', BeginNode),
                MakeXMLnode('org1:OGRN', FOGRN, FullNode),
                MakeXMLnode('org:SearchCriteria', '', EndNode),
                MakeXMLnode('org:exportOrgRegistryRequest', '', EndNode),
                MakeXMLnode('soapenv:Body', '', EndNode),
                MakeXMLnode('soapenv:Envelope', '', EndNode));
end;

function TExportOrgRegistry.Date: string;
begin
 Result := FDate;
end;

function TExportOrgRegistry.GetObject: TObject;
begin
 Result := Self;
end;

function TExportOrgRegistry.GUID: string;
begin
 Result := FGUID;
end;

function TExportOrgRegistry.Header: string;
begin
 Result := Concat(cHeader, cNS_ExportOrgRegistry, #10,
                  MakeXMLnode('soapenv:Header', '', BeginNode),
                  MakeXMLnode('base:ISRequestHeader', '', BeginNode),
                  FDate, #10, FGUID, #10,
                  MakeXMLnode('base:ISRequestHeader', '', EndNode),
                  MakeXMLnode('soapenv:Header', '', EndNode));
end;

function TExportOrgRegistry.HeaderAction: string;
begin
 Result := '"urn:exportOrgRegistry"';
end;

function TExportOrgRegistry.WebService: string;
begin
 Result := 'ext-bus-org-registry-common-service/services/OrgRegistryCommon';
 if FAsync then
   Result := Result + 'Async';
end;

function TExportOrgRegistry.XML: string;
begin
 Result := FXML;
end;

end.
[/code:fs2tuymr]

[SIZE=85px][COLOR=greenpt]Отправлено спустя 8 минуты 58 секунды:[/COLOR][/SIZE]
Важно! Загрузка ГОСТа из dll (последняя строка)
[code:fs2tuymr](*
 инициализация библиотеки
*)
procedure LoadSSL;
begin
 OpenSSL_add_all_algorithms;
 OpenSSL_add_all_ciphers;
 OpenSSL_add_all_digests;
 ERR_load_crypto_strings;
 ERR_load_RSA_strings;
 // используется имя файла, указанное в OPENSSL_CONF
 OPENSSL_config(PChar(GetDOSEnvVar('OPENSSL_CONF')));
end;
[/code:fs2tuymr]

[SIZE=85px][COLOR=greenpt]Отправлено спустя 14 минуты 20 секунды:[/COLOR][/SIZE]
Из ИндиЛога заголовок запроса на https (по http похожий):
[I]POST /ext-bus-org-registry-common-service/services/OrgRegistryCommon HTTP/1.0
Content-Type: text/xml; charset=UTF-8
Content-Length: 6333
SOAPAction: "urn:exportOrgRegistry"
Authorization: Basic c2l0OnJaX0dHNzJYU15WZjU1Wlc=
X-Client-Cert-Fingerprint: cb.... (тут мой отпечаток серт.)
Host: 217.107.108.156:10081
Accept: text/html, */*
Accept-Encoding: gzip,deflate, identity
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)[/I]

[SIZE=85px][COLOR=greenpt]Отправлено спустя 5 минуты 19 секунды:[/COLOR][/SIZE]
Для изучения шифрования по ГОСТу помогло изучение "Библиотека libcrypto.Руководство программиста" от КриптоКома.
Всех с наступающим 23 февраля, вспомним как служили!
#
Предполагаю один раз взять данные сертификата, записать в инифайл и если нужно беру их оттуда
Серийник берется просто:
[quote:2jlddosl]function SerialNumber(const FileName: string): string;
var
 x: pX509;
begin
 x := X509(FileName);
 Result := BN_bn2dec(ASN1_INTEGER_to_BN(X509_get_serialNumber(x), nil));
 X509_free(x);
end;[/quote:2jlddosl]
Издателя сложнее, но получилось также вытащить, пока остановился на каноникализации.

[SIZE=85px][COLOR=greenpt]Отправлено спустя 2 минуты 15 секунды:[/COLOR][/SIZE]
Забыл еще, так загружаю сертификат
[code:2jlddosl]function X509(const f: string): pX509;
var
 bio_cert: pBIO;
 k: pX509;
begin
 k := X509_new;
 bio_cert := BIO_new_file(PChar(f), 'rb');
 Result := PEM_read_bio_X509(bio_cert, k, nil, nil);
 BIO_free(bio_cert);
end;
[/code:2jlddosl]

[SIZE=85px][COLOR=greenpt]Отправлено спустя 2 минуты 3 секунды:[/COLOR][/SIZE]
Использую документ Криптоком
Библиотека libcrypto.
Руководство программиста

[SIZE=85px][COLOR=greenpt]Отправлено спустя 2 минуты 53 секунды:[/COLOR][/SIZE]
В консоль обращаюсь через StdIn и StdOut, у меня на машине лиценз. DrWeb не обращает внимания
#
А я начал делать библиотеку подписания через OpenSSL.
Хэш считаю так:
[code:1mjl2t8v]function GOSTR3411(const msg: string): string;
var
 inBuf, outBuf: array[0..4095] of Char;
 mdctx: EVP_MD_CTX;
 mdValue: array[0..EVP_MAX_MD_SIZE] of byte;
 mdLength: Cardinal;
 b64Length: Integer;
 memout, Base64: pBIO;
begin
 StrPCopy(inbuf, msg);
 EVP_DigestInit(@mdctx, EVP_get_digestbyname(PChar('md_gost94')));
 EVP_DigestUpdate(@mdctx, @inbuf, StrLen(inbuf));
 EVP_DigestFinal(@mdctx, @mdValue, mdLength);
 Base64 := BIO_new(BIO_f_base64); // BIO типа base64
 memout := BIO_new(BIO_s_mem);
 Base64 := BIO_push(Base64, memout);
 BIO_write(Base64, @mdValue, mdLength);
 BIO_flush(Base64);
 b64Length := BIO_read(memout, @outbuf, 4096);
 outbuf[b64Length - 1] := #0;
 Result := StrPas(@outbuf);
end;[/code:1mjl2t8v]

Хэш сертификата можно один раз подсчитать через вызов в консоли:
[code:1mjl2t8v]function GetDigest(const Text: string): string;
begin
 GetDosOutput('openssl dgst -binary -md_gost94 |openssl base64', Text, 30, Result);
 Delete(Result, Length(Result), 1);
end;[/code:1mjl2t8v]

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

Подпишись на рассылку новостей ЖКХ, а также наших статей!

Спасибо, вы успешно подписались на рассылку!