У меня есть проект SOAPUI, который использует клиентский сертификат X509 для цифровой подписи метки времени в заголовке SOAP. Мне нужно программно создать цифровую подпись в сообщениях SOAP, отправляемых на сервер с использованием .NET (без использования WCF).
SOAPUI-сгенерированное SOAP-сообщение:
<soap:Envelope xmlns:cmaw="http://estarstation.com/cmaWS/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://estarstation.com/xsd">
<soap:Header>
<wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-0EDE7F54075E85BDF615420409942248">
<wsse:Username>528725.RTCMACERT</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">tGupsbJwWtnQU1usa9hBFYWfnRk=</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">utFyPzosQNlMFihkXMCZuw==</wsse:Nonce>
<wsu:Created>2018-11-12T16:43:14.224Z</wsu:Created>
</wsse:UsernameToken>
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="X509-0EDE7F54075E85BDF615420409941614">MIIGIDCCBQigAwIBAgIQ ... OQl+57Pa5lM1Mj</wsse:BinarySecurityToken>
<ds:Signature Id="SIG-0EDE7F54075E85BDF615420409941897" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="cmaw soap xsd" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<ds:Reference URI="#TS-0EDE7F54075E85BDF615420409941283">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="wsse cmaw soap xsd" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<ds:DigestValue>fM/i6lk0onD4vDQtHrKKrv8JeT6IgqFwV3FBBeymS28=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>e9+LmcpbcgZ+m282+57rIJjsU8oWjkrQrql5u9qmPxTkDjjjqOq0O8OOj+Ud3/L0p8w8bg07ByPK7RwfDCiZOZMvuqLup4wR+l7IKm ... LCakMIqQpuESXw==</ds:SignatureValue>
<ds:KeyInfo Id="KI-0EDE7F54075E85BDF615420409941825">
<wsse:SecurityTokenReference wsu:Id="STR-0EDE7F54075E85BDF615420409941836">
<wsse:Reference URI="#X509-0EDE7F54075E85BDF615420409941614" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" />
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
<wsu:Timestamp wsu:Id="TS-0EDE7F54075E85BDF615420409941283">
<wsu:Created>2018-11-12T16:43:14Z</wsu:Created>
<wsu:Expires>2018-11-12T16:43:44Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</soap:Header>
<soap:Body>
<xsd:cardInqMaintDisplayParam>
<cmaw:cardNumber>5287250200316234</cmaw:cardNumber>
<cmaw:memberNumber>0</cmaw:memberNumber>
<cmaw:endUser>RTCMA</cmaw:endUser>
</xsd:cardInqMaintDisplayParam>
</soap:Body>
</soap:Envelope>
SOAP-сообщение, сгенерированное кодом:
<soap:Envelope xmlns:cmaw="http://estarstation.com/cmaWS/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://estarstation.com/xsd">
<soap:Header>
<wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-0EDE7F54075E85BDF615420409942248">
<wsse:Username>528725.RTCMACERT</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">tGupsbJwWtnQU1usa9hBFYWfnRk=</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">utFyPzosQNlMFihkXMCZuw==</wsse:Nonce>
<wsu:Created>2018-11-12T16:43:14.224Z</wsu:Created>
</wsse:UsernameToken>
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="X509-0EDE7F54075E85BDF615420409941614">MIIGIDCCBQigAwIBAgIQ ... OQl+57Pa5lM1Mj</wsse:BinarySecurityToken>
<ds:Signature Id="SIG-0EDE7F54075E85BDF615420409941897" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="cmaw soap xsd" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<ds:Reference URI="#TS-0EDE7F54075E85BDF615420409941283">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces PrefixList="wsse cmaw soap xsd" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<ds:DigestValue>fM/i6lk0onD4vDQtHrKKrv8JeT6IgqFwV3FBBeymS28=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>AvZBW8ejFNfnDFuWzAoNFBwXYjrQ2NVW/Ldj17E5D8XydWLskZTROMvaaSgcu72cgEgHUrC8mlhePduzvrjzP3Fuf18oRMaLhqGs85 ... eOegQ8EZHEp1ZQ==</ds:SignatureValue>
<ds:KeyInfo Id="KI-0EDE7F54075E85BDF615420409941825">
<wsse:SecurityTokenReference wsu:Id="STR-0EDE7F54075E85BDF615420409941836">
<wsse:Reference URI="#X509-0EDE7F54075E85BDF615420409941614" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" />
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
<wsu:Timestamp wsu:Id="TS-0EDE7F54075E85BDF615420409941283">
<wsu:Created>2018-11-12T16:43:14Z</wsu:Created>
<wsu:Expires>2018-11-12T16:43:44Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</soap:Header>
<soap:Body>
<xsd:cardInqMaintDisplayParam>
<cmaw:cardNumber>5287250200316234</cmaw:cardNumber>
<cmaw:memberNumber>0</cmaw:memberNumber>
<cmaw:endUser>RTCMA</cmaw:endUser>
</xsd:cardInqMaintDisplayParam>
</soap:Body>
</soap:Envelope>
Хотя я могу сгенерировать совпадение DigestValue в подписи, я не могу сопоставить SignatureValue. И программа SOAPUI, и программа .NET используют один и тот же клиентский сертификат X509.
Фрагмент кода, использованный для создания элемента Signature в заголовке SOAP.
X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(Settings.Default.CertFilePFX), Settings.Default.CertPassword, X509KeyStorageFlags.Exportable);
XmlDsigDocument xmlHeader = new XmlDsigDocument(); // Create a new XML document.
xmlHeader.Load ( new XmlTextReader ( FileName ) ); // Load the passed XML file using its name.
XmlNamespaceManager nSpMgr = new XmlNamespaceManager(xmlHeader.NameTable);
nSpMgr.AddNamespace ( "soap", CustomSignedXml.xmlSoapEnvelopeUrl );
nSpMgr.AddNamespace ( "wsu", CustomSignedXml.xmlOasisWSSSecurityUtilUrl );
nSpMgr.AddNamespace ( "wsse", CustomSignedXml.xmlOasisWSSSecurityExtUrl );
nSpMgr.AddNamespace ( "ec", CustomSignedXml.xmlOasisWSSSecurityExtUrl );
XPathNavigator docNav = xmlHeader.CreateNavigator();
XPathNavigator timestampNav = docNav.SelectSingleNode("/soap:Envelope/soap:Header/wsse:Security/wsu:Timestamp", nSpMgr);
XPathNavigator binarysecuritytokenNav = docNav.SelectSingleNode("/soap:Envelope/soap:Header/wsse:Security/wsse:BinarySecurityToken", nSpMgr);
string timestampID = timestampNav.GetAttribute ( "Id", CustomSignedXml.xmlOasisWSSSecurityUtilUrl );
string binarySecurityTokenID = binarysecuritytokenNav.GetAttribute ( "Id", CustomSignedXml.xmlOasisWSSSecurityUtilUrl );
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(new CspParameters(24));
rsaKey.PersistKeyInCsp = false;
string exportedKeyMaterial = cert.PrivateKey.ToXmlString(true);
rsaKey.FromXmlString ( exportedKeyMaterial );
CustomSignedXml signedXml = new CustomSignedXml(xmlHeader);
signedXml.SigningKey = rsaKey;
signedXml.Signature.Id = "SIG-0EDE7F54075E85BDF615420409941897";
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
XmlDsigExcC14NTransform canMethod = (XmlDsigExcC14NTransform)signedXml.SignedInfo.CanonicalizationMethodObject;
canMethod.InclusiveNamespacesPrefixList = "cmaw soap xsd";
Reference reference = new Reference();
reference.Uri = "#" + timestampID;
reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
XmlDsigExcC14NTransform transformDataTS = new XmlDsigExcC14NTransform();
transformDataTS.InclusiveNamespacesPrefixList = "wsse cmaw soap xsd";
byte[] dataToHashTS = Encoding.UTF8.GetBytes(timestampNav.OuterXml);
transformDataTS.LoadInput ( new MemoryStream ( dataToHashTS ) );
reference.AddTransform ( transformDataTS );
signedXml.AddReference ( reference );
KeyInfo keyInfo = new KeyInfo();
keyInfo.Id = "KI-0EDE7F54075E85BDF615420409941825";
SecurityTokenReference skr = new SecurityTokenReference();
skr.Id = "STR-0EDE7F54075E85BDF615420409941836";
skr.Reference = binarySecurityTokenID; // Binary Security Token ID
skr.ValueType = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
keyInfo.AddClause ( skr );
signedXml.KeyInfo = keyInfo;
signedXml.ComputeSignature ( ); // Compute the signature
XmlElement xmlDigitalSignature = signedXml.GetXml();
Настройки SOAPUI WSS
Как видите, подпись генерируется с использованием этих свойств:
Алгоритм подписи: rsa-sha256
Подпись Каноникализация: xml-exc-c14n #
Алгоритм дайджеста: xmlenc # sha256
Или кто-то знает, как генерировать SignatureValue с учетом DigestValue? Если да, используете ли вы Base64 DigitalValue или конвертируете Base64 DigestValue в байтовый массив для расчета SignatureValue.
Буду признателен за любые рекомендации, потому что я работаю над этим в течение нескольких недель, чтобы получить правильное значение SignatureValue.