How does SOAPUI calculate the SignatureValue for a SignedInfo section in SOAP header
I have a SOAPUI project setup with outgoing WSS configuration to insert a header with a Signature section that includes the digital signature of the Timestamp element. Using this project, it successfully generates the correct SOAP header with the digital signature elements and the host processes the request successfully. Here is the SOAPUI configuration setup to add the SOAP header.
The generated SOAP message resembles the following.
<?xml version="1.0" encoding="utf-8"?>
<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">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</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+l7IKmDmcXvrNx/7nCkFCp3UUV6B0o+Z5cuTWTk6VjZkcLphKN6ZebDQFGwX2N4CVAsju+BsF26BHbf430indaEbCu59ClBkdZxXnmJCTdNeYW1P0967RK2gJF9iPG7FPZrY+bJzHpgm9AfVrAEtyNfW6pL24IZtrOs/D/9c6w6dCpYLYo4sdWLmhCvpf+ehfc2vDJ4OjVRJNOCma6L7laJS3Guyory45o2flALhLCakMIqQpuESXw==</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>
Now that I can successfully use SOAPUI to communicate with the host server, I need to programmatically generated the SOAP header to send to the host server. I am programming using .NET 4.6.2 framework and C# language. While I have successfully generated and matched most of the SOAPUI generated header elements (including the 'DigestValue'), I cannot get a match on 'SignatureValue'.
- Does anyone know how the 'SignatureValue' is generated?
- Does it simply sign the Base64 'DigestValue'? Or does it sign the converted Base64 (byte array) of 'DigestValue'?
- Best yet, does some on know the C# logic used to generate the Signature element such that I generate a 'SignatureValue' that will match that generated in SOAPUI.
Here is a code snippet of how I am generating the values in the Signature element:
public static void SignXmlFile ( string FileName, string SignedFileName ) { X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(Settings.Default.CertFilePFX), Settings.Default.CertPassword, X509KeyStorageFlags.Exportable); XmlDsigDocument xmlHeader = new XmlDsigDocument(); // Create a new XML document. // xmlHeader.PreserveWhitespace = true; 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 ); RSAPKCS1SHA256SignatureDescription.Register ( ); RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(new CspParameters(24)); rsaKey.PersistKeyInCsp = false; string exportedKeyMaterial = cert.GetRSAPrivateKey().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(); // Append the element to the XML document, within <wsse:Security/> node XPathNavigator headerNode = docNav.SelectSingleNode("soap:Envelope/soap:Header", nSpMgr); nSpMgr.AddNamespace ( "wsse", CustomSignedXml.xmlOasisWSSSecurityExtUrl ); nSpMgr.AddNamespace ( "wsse", CustomSignedXml.xmlSoapSecurityUrl ); XPathNavigator secNode = headerNode.SelectSingleNode("wsse:Security", nSpMgr); // Append the Signature element XPathNavigator navSignature = xmlDigitalSignature.CreateNavigator(); secNode.AppendChild ( navSignature ); // Save the signed XML document to a file specified using the passed string XmlTextWriter xmltw = new XmlTextWriter(SignedFileName, new UTF8Encoding(false)); xmltw.Formatting = Formatting.Indented; xmlHeader.WriteTo ( xmltw ); xmltw.Close ( ); Console.Write ( File.ReadAllText ( SignedFileName ) ); }