Ключевое слово в защите информации
ключевое слово
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход. Новые регистрации запрещены.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Neotiran  
#1 Оставлено : 13 июля 2015 г. 11:17:53(UTC)
Neotiran

Статус: Новичок

Группы: Участники
Зарегистрирован: 03.07.2015(UTC)
Сообщений: 8
Российская Федерация
Откуда: Ставрополь

Подскажите пожалуйста как подписать правильно SOAP сообщение, никак не получается, отсылаю в ФЭР2/

Спецификация:
c14n;
SHA-1;
ГОСТ 34.11-2001.

Функции:

Код:

function SoapCreateMessage(CryptContainer: WideString; BodyContext: string): string;
var
  DataStream: TStringStream;
  Cert,Hash,Sign: TStringStream;
  SignedInfo,Security,SoapGenID: string;
  TimeStamp: string;
  CertId,KeyId,STRId,SignID,BodyID: string;
  Canon:String;
  MyGUID : TGUID;

 FileXML: TNativeXML;
 root, temp_node: TXMLNode;
 i,j:integer;
begin
  fileXML:=CreateNativeXMLDocument(main.frmExportToFER, '', '');
  root:=FileXML.Root.Nodes[0];


  //Генератор ID для SOAP
  CreateGUID(MyGUID);
  SoapGenID:=StringReplace(StringReplace(LowerCase(GUIDToString(MyGUID)),'{','',[rfReplaceAll, rfIgnoreCase]),'}','',[rfReplaceAll, rfIgnoreCase]);
  CertId:='CertId-'+SoapGenID;
  KeyId:='KeyId-'+SoapGenID;
  STRId:='STRId-'+SoapGenID;
  SignID:='SignID-'+SoapGenID;
  BodyID:='BodyID-'+SoapGenID;
  //обертка данных сообщения блоком <Body>
  BodyContext:=
  '<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" u:Id="BodyID-2ab34c8b-c673-4ee1-85f2-b5f42dc34092">'+
  '<SendRequest xmlns="http://mis.er.atc.ru/ws">'+
  '<MessageData>'+
  '<AppData>'+
  BodyContext+
  '</AppData>'+
  '</MessageData>'+
  '</SendRequest>'+
  '</s:Body>';
  //C14n
  //fileXML.WriteToString
  fileXML.ReadFromString(BodyContext);
  fileXML.Canonicalize;
  DataStream:=TStringStream.Create(Canon,TEncoding.UTF8);
  fileXML.WriteToString;
  fileXML.SaveToStream(DataStream);
  Hash:=TStringStream.Create;
  try
    //вычисление хеша блока <Body>
    GetHashStream(CryptContainer,DataStream,nil,nil,Hash,nil);
    //EncdDecd.EncodeStream(Hash,Hash);
    //блок для подписи
    SignedInfo:=
    '<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>'+
    '<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"/>'+
    '<ds:Reference URI="#'+BodyID+'"><ds:Transforms>'+
    '<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms>'+
    '<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"/><ds:DigestValue>'+
    //хэш элемента <soapenv:Body> по алгоритму ГОСТ Р 34.11-94 в формате base64
    Base64.Base64EncodeString(MemoryStreamToString(Hash))+
    '</ds:DigestValue>'+
    '</ds:Reference>'+
    '</ds:SignedInfo>';

  finally
    DataStream.Free;
    Hash.Free;
  end;
  fileXML.ReadFromString(SignedInfo);
  fileXML.Canonicalize;
  DataStream:=TStringStream.Create(Canon,TEncoding.UTF8);
  fileXML.SaveToStream(DataStream);

  DataStream:=TStringStream.Create(SignedInfo,TEncoding.UTF8);//UTF8);
  Cert:=TStringStream.Create;
  Sign:=TStringStream.Create;
  try

    //подпись <SignedInfo> и получение данных сертификата
    GetHashStream(CryptContainer,DataStream,Cert,nil,nil,Sign);

    TimeStamp:='';


    Security:=
    '<a:Action s:mustUnderstand="1">SendElectronicRegistry</a:Action>'+
    '<h:transportHeader xmlns:h="http://egisz.rosminzdrav.ru" xmlns:a="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" '+
    'xmlns="http://egisz.rosminzdrav.ru" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" '+
    'a:Id="19d5ed0d-bcb8-479c-ac78-ccbb8bc07ff7">'+
    '<authInfo>'+
    '<clientEntityId>'+{frmDBDataModule.DataSetAllLpu.FBN('TokenFER').AsString}'9f5e78db-de97-4f5b-964a-791786734749'+'</clientEntityId>'+
    '</authInfo>'+
    '</h:transportHeader>'+
    '<a:MessageID>urn:uuid:'+{frmDBDataModule.DataSetAllLpu.FBN('TokenFER').AsString}SoapGenID+'</a:MessageID>'+
    '<a:ReplyTo>'+
      '<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>'+
    '</a:ReplyTo>'+
    '<a:To s:mustUnderstand="1" u:Id="_1">https://ips.rosminzdrav.ru/5358bf30e7897</a:To>'+
    '<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">'+
    '<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="'+SignID+'">'+
    //вставим готовый блок <SignedInfo>
    SignedInfo+
    '<ds:SignatureValue>'+
    //электронная подпись для <ds:SignedInfo> по алгоритму ГОСТ Р 34.11-2001 в формате base64
    Base64.Base64EncodeString(MemoryStreamToString(Sign))+
    '</ds:SignatureValue>'+

    '<ds:KeyInfo><wsse:SecurityTokenReference>'+
    '<wsse:Reference URI="#'+CertId+'"/>'+
    '</wsse:SecurityTokenReference></ds:KeyInfo></ds:Signature>'+

    '<wsse:BinarySecurityToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"'+
    'ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"'+
    ' EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" u:Id="'+CertId+'">'+
    //сертификат в формате Base64
    Base64.Base64EncodeString(MemoryStreamToString(Cert))+
    '</wsse:BinarySecurityToken></wsse:Security>';

    //soap envelope
    Canon:=
    '<?xml version="1.0"?>'+
    '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header>'+
    Security+
    '</s:Header>'+
    BodyContext+
    '</s:Envelope>';

    fileXML.ReadFromString(Canon);
    fileXML.Canonicalize;
    Result:=Canon;
  finally
    DataStream.Free;
    Cert.Free;
    Sign.Free;
    fileXML.Free;
  end;
end;

procedure GetHashStream(Container: WideString; DataStream: TStream; CertStream, KeyStream, HashStream, SignStream: TStream);
var
hProv: HCRYPTPROV;
DataLen: DWORD;
hHash: HCRYPTHASH;
hKey: HCRYPTKEY;
dwKeySpec: DWORD;
dwProvType, cbName: DWORD;
InStream, OutStream: TBytesStream;
pbData: array[0..1023] of char;
tempstring: string;
FCryptProvInfo: TCryptProvInfo;
provName: array[0..200] of char;
i:integer;
signKey     : HCRYPTKEY;
 publicKey   : HCRYPTKEY;
 desKey      : HCRYPTKEY;

context_sender, context_receiver: TCryptContext;
crypter_sender, crypter_receiver: TCrypter;

hSenderSignKey,hSenderCrypKey,hRecvSignKey,hRecvCrypKey: HCRYPTKEY;
pbSenderPubKey,pbRecvPubKey: PByte;
cbSenderPubKey,cbRecvPubKey: cardinal;

begin

  //--- создаем криптоконтекстs
  context_sender := TCryptContext.Create('89849302', CP_GR3410_2001_PROV_A,PROV_GOST_2001_DH,[] );

  //--- создаем кpипторs
  crypter_sender := TCrypter.Create(context_sender);

  //--- генерим ключи
  context_sender.GenerateKeyPair(hSenderSignKey,hSenderCrypKey);

  context_sender.ExportPublicKeyBytes(pbSenderPubKey,cbSenderPubKey);

  dwKeySpec:=AT_KEYEXCHANGE;
  InStream:=TBytesStream.Create;
  OutStream:=TBytesStream.Create;
  try
  CopyStream(DataStream,InStream);
  try
  //получаем ключи
  if not CryptGetUserKey(crypter_sender.CryptContext.Provider, dwKeySpec, @hKey) then
  begin
    Exit;
  end;

  if (CertStream<>nil) or (KeyStream<>nil) then
  begin
  try

  //получение сертификата

  if CertStream<>nil then
  begin
    CryptGetKeyParam(hKey, KP_CERTIFICATE, nil, @DataLen, 0);
    OutStream.Size:=DataLen;
    CryptGetKeyParam(hKey, KP_CERTIFICATE, OutStream.Memory, @DataLen, 0);
    CopyStream(OutStream,CertStream);
  end;

  if KeyStream<>nil then
  begin
    CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, nil, @DataLen);
    OutStream.Size:=DataLen;
    CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, OutStream.Memory, @DataLen);
    CopyStream(OutStream,KeyStream);
  end;

  finally
    CryptDestroyKey(hKey);
  end;

  end;

  if (HashStream<>nil) or (SignStream<>nil) then
  begin

  CryptCreateHash(crypter_sender.CryptContext.Provider, CALG_GR3411, 0, 0, @hHash);
  try

  CryptHashData(hHash, InStream.Memory, InStream.Size, 0);

  //получение хеша

  if HashStream<>nil then
  begin
    CryptGetHashParam(hHash, HP_HASHVAL, nil, @DataLen, 0);
    OutStream.Size:=DataLen;
    CryptGetHashParam(hHash, HP_HASHVAL, OutStream.Memory, @DataLen, 0);
    CopyStream(OutStream,HashStream);
  end;

  //подпись хеша

  if SignStream<>nil then
  begin
    CryptSignHash(hHash, dwKeySpec, nil, 0, nil, @DataLen);
    OutStream.Size:=DataLen;
    CryptSignHash(hHash, dwKeySpec, nil, 0, OutStream.Memory, @DataLen);
    CopyStream(OutStream,SignStream,true);
  end;

  finally
  CryptDestroyHash(hHash);
  end;
  end;

finally
CryptReleaseContext(crypter_sender.CryptContext.Provider, 0);
end;

finally
InStream.Free;
OutStream.Free;
end;

end;


Все время приходит ошибка что не правильная сигнатура:
Код:

<e:Fault>
<e:Code>
<e:Value>e:Sender</e:Value>
<e:Subcode>
<e:Value xmlns:ips="http://ips.rosminzdrav.ru/errors/codes">ips:1.3.1.1</e:Value>
</e:Subcode>
</e:Code>
<e:Reason>
<e:Text xml:lang="ru">Входящее сообщение. Проверка блока security. Ошибка при проверке подписи. -2147352567 Source: CryptoIntegrationCOM
Description: Error during checkSignature. Cannot find the requested object.</e:Text>
</e:Reason>
</e:Fault>

RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.