C# signature SOAP error "Hash values do not match"

Viewed 24

Please help, if anyone knows why the "Hash values ​​do not match" error occurs, I am sending a self-signed XML, but when consuming the service it presents the error indicated below.

         <faultcode>env:Server</faultcode>
         <faultstring>0x00d30003: Hash values do not match.</faultstring>
         <detail>
            <errorCode>0x00d30003</errorCode>
            <errorMessage>Hash values do not match.</errorMessage>
            <RqUID/>
         </detail>

This is the code with which I am creating the XML file, from .net, in which the document with the header is already fully created, as requested by the service to consume.

public static void firmarxmlconcertificado(XmlDocument xmlSalida, X509Certificate2 cert)
        {
            const string STR_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
            const string STR_WSSE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
            const string STR_WSU = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
            const string STR_DS = "http://www.w3.org/2000/09/xmldsig#";
            const string STR_EC = "http://www.w3.org/2001/10/xml-exc-c14n#";

            var ns = new XmlNamespaceManager(xmlSalida.NameTable);
            ns.AddNamespace("soapenv", STR_SOAPENV);
            ns.AddNamespace("wsse", STR_WSSE);
            ns.AddNamespace("wsu", STR_WSU);
            ns.AddNamespace("ds", STR_DS);
            ns.AddNamespace("ec", STR_EC);

            var idKeyInfo = "KI-" + Guid.NewGuid().ToString("N").ToUpper();
            var idWsu = "STR-" + Guid.NewGuid().ToString("N").ToUpper();
            var idwsseRef = "X509-" + Guid.NewGuid().ToString("N").ToUpper();
            var IdUriRef = "id-" + Guid.NewGuid().ToString("N").ToUpper() + Guid.NewGuid().ToString("N").Substring(0, 2).ToUpper();
            var IdSecTok = "SIG-" + Guid.NewGuid().ToString("N").ToUpper();

            const String RSA = "1.2.840.113549.1.1.1";
            const String DSA = "1.2.840.10040.4.1";
            const String ECC = "1.2.840.10045.2.1";


            //SignedXml PrivateKey

            SignedXml signedXml = new SignedXml(xmlSalida);
            RSA rsa = cert.GetRSAPrivateKey();
            signedXml.SigningKey = rsa;
            signedXml.SigningKeyName = cert.SubjectName.Name;
            signedXml.Signature.Id = IdSecTok;

            //Soap Body
            XmlElement soapbody = xmlSalida.DocumentElement.SelectSingleNode(@"//soapenv:Body", ns) as XmlElement;
            soapbody.SetAttribute("wsu:Id", IdUriRef);
            soapbody.SetAttribute("xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

            //Reference
            Reference reference = new Reference();
            reference.DigestMethod = SignedXml.XmlDsigSHA256Url;
            reference.Uri = "";           
            XmlDsigExcC14NTransform transform = new XmlDsigExcC14NTransform();
            reference.AddTransform(transform);
            transform.InclusiveNamespacesPrefixList = "ifx v1 v2";

            //SignedXml
            signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA256Url;
            signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
            XmlDsigExcC14NTransform canMethod = (XmlDsigExcC14NTransform)signedXml.SignedInfo.CanonicalizationMethodObject;
            canMethod.InclusiveNamespacesPrefixList = "ifx soapenv v1 v2";
            signedXml.AddReference(reference);

            //KeyInfo
            KeyInfo keyInfo = new KeyInfo();
            keyInfo.Id = idKeyInfo;            
            KeyInfoNode keyInfoNode = new KeyInfoNode();
            XmlElement wsseSec = xmlSalida.CreateElement("wsse","SecurityTokenReference", string.Empty);
            XmlElement wsseRef = xmlSalida.CreateElement("wsse", "Reference", string.Empty);
            wsseSec.SetAttribute("wsu:Id", idWsu);
            wsseRef.SetAttribute("URI","#" + idwsseRef);
            wsseRef.SetAttribute("ValueType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");
            wsseSec.AppendChild(wsseRef);
            keyInfoNode.Value = wsseSec;
            keyInfo.AddClause(keyInfoNode);
            signedXml.KeyInfo = keyInfo;
            signedXml.ComputeSignature();            
            XmlElement xmlsig = signedXml.GetXml();

            //Header 
            //Wsse:security
            XmlElement soapSignature = xmlSalida.DocumentElement.SelectSingleNode(@"//wsse:Security", ns) as XmlElement;
            XmlAttribute sId = xmlSalida.CreateAttribute("Id");
            sId.Value = IdSecTok;
            xmlsig.Attributes.Append(sId);
            // *** And add our signature as content            
            soapSignature.AppendChild(xmlsig);

            //wsse:BinarySecurityToken
            XmlElement soapBinSecTok = xmlSalida.DocumentElement.SelectSingleNode(@"//wsse:BinarySecurityToken", ns) as XmlElement;
            soapBinSecTok.SetAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
            soapBinSecTok.SetAttribute("ValueType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");
            soapBinSecTok.SetAttribute("wsu:Id", idwsseRef);
            var export = cert.Export(X509ContentType.Cert);
            var base64 = Convert.ToBase64String(export);
            soapBinSecTok.InnerText = base64;

            XmlElement referenceUri = xmlSalida.DocumentElement.SelectSingleNode(@"//ds:Reference", ns) as XmlElement;
            referenceUri.SetAttribute("URI", "#" + IdUriRef);

            //Prefix
            SetPrefix("ds", xmlsig);            
            signedXml.LoadXml(xmlsig);            
            signedXml.SignedInfo.References.Clear();            
            signedXml.ComputeSignature();
            string recomputedSignature = Convert.ToBase64String(signedXml.SignatureValue);
            // Replace value of the signature with recomputed one
            ReplaceSignature(xmlsig, recomputedSignature);

            //doc.DocumentElement.AppendChild(doc.ImportNode(xmlsig, true));
        }

        private static void SetPrefix(string prefix, XmlNode node)
        {
            node.Prefix = prefix;
            foreach (XmlNode n in node.ChildNodes)
            {

                SetPrefix(prefix, n);
            }

            if (node.NamespaceURI == "http://www.w3.org/2001/10/xml-exc-c14n#")
                node.Prefix = "ec";
            else if ((node.NamespaceURI == "http://www.w3.org/2000/09/xmldsig#") || (string.IsNullOrEmpty(node.Prefix)))
                node.Prefix = prefix;

        }
        //xmlDSignSecurityUrl

        private static void ReplaceSignature(XmlElement signature, string newValue)
        {
            if (signature == null) throw new ArgumentNullException(nameof(signature));
            if (signature.OwnerDocument == null) throw new ArgumentException("No owner document", nameof(signature));

            XmlNamespaceManager nsm = new XmlNamespaceManager(signature.OwnerDocument.NameTable);
            nsm.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);

            XmlNode signatureValue = signature.SelectSingleNode("ds:SignatureValue", nsm);

            if (signatureValue == null)
                throw new Exception("Signature does not contain 'ds:SignatureValue'");

            signatureValue.InnerXml = newValue;
        }
0 Answers
Related