Статус: Новичок
Группы: Участники
Зарегистрирован: 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>
|