Click here to Skip to main content
15,887,336 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello, I have a problem with creating a signed file with a x509 certificate. I did create a selfsigned SSL certficate that I use to test my code.
My code produces a xml that looks like the demo file and a signed file from signing API yet when I try do verify my generated file in a JAVA API gateway where I need to send it, I get error invalid signature.
I use the XmlDsigXPathTransform, XmlDsigExcC14NTransform and XadES. Yet when I run the verification check I get always a false result from XPATH transform. I'm going on for weeks with this problem yet no solution....

Is there any way to find why the signature is invalid?


C#
 private static XmlElement SignXMLDocument(string xml, X509Certificate2 certificate, string signedXMLPath)
        {
            string XPathString = "not(ancestor-or-self::Signature)";

            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.PreserveWhitespace = false;
            xmlDocument.Load(xml);
 
            
            var signedXml = new XadesSignedXml(xmlDocument);
            signedXml.Signature.Id = SignatureId;
            signedXml.SigningKey = certificate.PrivateKey;
            signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
            signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";
            //signedXml.SignatureValue. = "SignatureValue" + SignatureId;
            
            var signatureReference = new Reference { Uri = "", };
            XmlDsigXPathTransform XPathTransform = CreateXPathTransform(XPathString);
            signatureReference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
            signatureReference.AddTransform(XPathTransform);
            signedXml.AddReference(signatureReference);
            
            var signatureReference2 = new Reference { Uri = "", };
            signatureReference2.AddTransform(new XmlDsigExcC14NTransform());
            //signatureReference2.Uri = SignaturePropertiesId;
            signatureReference2.Type = "http://uri.etsi.org/01903#SignedProperties";
            signatureReference2.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
            signedXml.AddReference(signatureReference2);
            
            var keyInfo = new KeyInfo();
            keyInfo.AddClause(new KeyInfoX509Data(certificate));

            signedXml.KeyInfo = keyInfo;
            AddXAdESProperties(xmlDocument, signedXml, certificate);

            signedXml.ComputeSignature();
            signedXml.CheckSignature(certificate, true);

            signedXml.CheckSignature();
            bool result = VerifyXmlFile(signedXMLPath);
            // Add prefix "ds:" to signature
            XmlElement signature = signedXml.GetXml();
            
            signedXml.ComputeSignature();
            string recomputedSignature = Convert.ToBase64String(signedXml.SignatureValue);

           xmlDocument.DocumentElement.AppendChild(xmlDocument.ImportNode(signature, true));
            xmlDocument.DocumentElement.AppendChild(xmlDocument.ImportNode(signature, true));
            signedXml.CheckSignature(certificate, true);

            signedXml.CheckSignature();
            XmlTextWriter xmltw = new XmlTextWriter(signedXMLPath, new UTF8Encoding(false));
            xmlDocument.WriteTo(xmltw);
            xmltw.Close();

            //xmlDocument.Save(signedXMLPath);
            return signedXml.GetXml();
        }
        // Adding Xpath for transformation
        private static XmlDsigXPathTransform CreateXPathTransform(string XPathString)
        {
            // Create a new XMLDocument object.
            XmlDocument doc = new XmlDocument();

            // Create a new XmlElement.
            XmlElement xPathElem = doc.CreateElement("XPath");

            // Set the element text to the value
            // of the XPath string.
            xPathElem.InnerText = XPathString;

            // Create a new XmlDsigXPathTransform object.
            XmlDsigXPathTransform xForm = new XmlDsigXPathTransform();

            // Load the XPath XML from the element.
            xForm.LoadInnerXml(xPathElem.SelectNodes("."));

            // Ensure the transform is using the proper algorithm.
            xForm.Algorithm = SignedXml.XmlDsigXPathTransformUrl;

            XmlElement xmlInTransform = xForm.GetXml();

            // Return the XML that represents the transform.
            return xForm;
        }
public class XadesSignedXml : SignedXml
        {
            #region Public fields
            public const string XmlDsigSignatureProperties = "http://uri.etsi.org/01903#SignedProperties";
            public const string XadesProofOfApproval = "http://uri.etsi.org/01903/v1.2.2#ProofOfApproval";
            public const string XadesPrefix = "xades";
            public const string XadesNamespaceUrl = "http://uri.etsi.org/01903/v1.3.2#";
            public XmlElement PropertiesNode { get; set; }
            #endregion Public fields

            #region Private fields
            private readonly List<DataObject> _dataObjects = new List<DataObject>();
            #endregion Private fields

            #region Constructor
            public XadesSignedXml(XmlDocument document) : base(document) { }
            #endregion Constructor

            #region SignedXml
            public override XmlElement GetIdElement(XmlDocument document, string idValue)
            {
                if (String.IsNullOrEmpty(idValue)) return null;

                XmlElement xmlElement = base.GetIdElement(document, idValue);
                if (xmlElement != null) return xmlElement;


                foreach (DataObject dataObject in _dataObjects)
                {
                    XmlElement nodeWithSameId = findNodeWithAttributeValueIn(dataObject.Data, "Id", idValue);
                    if (nodeWithSameId != null)
                        return nodeWithSameId;
                }
                if (KeyInfo != null)
                {
                    XmlElement nodeWithSameId = findNodeWithAttributeValueIn(KeyInfo.GetXml().SelectNodes("."), "Id", idValue);
                    if (nodeWithSameId != null)
                        return nodeWithSameId;
                }
                return null;
            }
            public XmlElement findNodeWithAttributeValueIn(XmlNodeList nodeList, string attributeName, string value)
            {
                if (nodeList.Count == 0) return null;
                foreach (XmlNode node in nodeList)
                {
                    XmlElement nodeWithSameId = findNodeWithAttributeValueIn(node, attributeName, value);
                    if (nodeWithSameId != null) return nodeWithSameId;
                }
                return null;
            }

            private XmlElement findNodeWithAttributeValueIn(XmlNode node, string attributeName, string value)
            {
                string attributeValueInNode = getAttributeValueInNodeOrNull(node, attributeName);
                if ((attributeValueInNode != null) && (attributeValueInNode.Equals(value))) return (XmlElement)node;
                return findNodeWithAttributeValueIn(node.ChildNodes, attributeName, value);
            }

            private string getAttributeValueInNodeOrNull(XmlNode node, string attributeName)
            {
                if (node.Attributes != null)
                {
                    XmlAttribute attribute = node.Attributes[attributeName];
                    if (attribute != null) return attribute.Value;
                }
                return null;
            }
            
            public new void AddObject(DataObject dataObject)
            {
                base.AddObject(dataObject);
                _dataObjects.Add(dataObject);
            }
            #endregion SignedXml
        }


What I have tried:

Removing Xpath transformation reuslt validatuin true result yet still it don't pass API gateway. The documentation states below transformations to be used yet in demo I don't see the fillter2 transfotmarion and im not sure about ds: prefix. Many states that its not need for signatures. I'm not sure if the values are calculated good or not. Nothing I found on the internet for past weeks worked. Any possible help?

http://www.w3.org/TR/1999/REC-xpath-19991116 - not(ancestor-or-self::ds:Signature)
http://www.w3.org/2002/06/xmldsig-filter2
http://www.w3.org/2000/09/xmldsig#enveloped-signature
Posted
Updated 28-Jun-22 22:48pm
Comments
[no name] 29-Jun-22 11:08am    
https://docs.microsoft.com/en-us/dotnet/standard/security/how-to-sign-xml-documents-with-digital-signatures
https://docs.microsoft.com/en-us/dotnet/standard/security/how-to-verify-the-digital-signatures-of-xml-documents

1 solution

Maybe you can use this tool: tekcert[^]
 
Share this answer
 
Comments
Radosław Mierzejewski 29-Jun-22 4:59am    
I need to generate, sign and send the file in one go using a API. I don't think it will help here.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900