C# XML digital signature, malformed reference element

Question:

I have a C# code that generates an xml with the digital signature, however when calling the function signedXml.ComputeSignature() it shows the following error:

Malformed Reference element.

However, I researched this error and most sites or forums mention removing the KB3136000 update, but the windows 10 I'm using doesn't have this update installed.

What can it be?

Here's the code below highlighting the error line:

public static void AssinaDocumento(X509Certificate2 certificadoDigital, string Uri, string xmlOrigem)
{
    int countTagsUri;
    XmlDocument xmlDocument = new XmlDocument();
    XmlDocument xmlDocument2 = new XmlDocument();
    xmlDocument.PreserveWhitespace = false;
    XmlNodeList xmlNodeList;
    Reference reference = new Reference();

    xmlDocument.Load(xmlOrigem);

    xmlDocument2 = xmlDocument;

    XmlDocument xmlAssinado = xmlDocument;
    SignedXml signedXml = new SignedXml(xmlDocument);
    signedXml.SigningKey = certificadoDigital.PrivateKey;

    countTagsUri = xmlDocument.GetElementsByTagName(Uri).Count;
    if (countTagsUri == 0)
    {
        throw new Exception("Uri " + Uri + " não encontrada no XML");
    }

    xmlNodeList = xmlDocument.GetElementsByTagName(Uri);

    foreach (XmlNode xmlnl in xmlNodeList)
    {
        XmlAttributeCollection attributeCollection = xmlnl.FirstChild.Attributes;
        reference.Uri = "#" + attributeCollection["id"].InnerText;

        string res = xmlnl.OuterXml;

        XmlDsigEnvelopedSignatureTransform envelope = new XmlDsigEnvelopedSignatureTransform();
        XmlDsigC14NTransform c14NTransform = new XmlDsigC14NTransform();
        KeyInfo keyInfo = new KeyInfo();

        reference.AddTransform(envelope);
        reference.AddTransform(c14NTransform);

        signedXml.AddReference(reference);

        keyInfo.AddClause(new KeyInfoX509Data(certificadoDigital));

        signedXml.KeyInfo = keyInfo;

        signedXml.ComputeSignature(); // O erro Ocorre aqui

        XmlElement xmlDigitalSignature = signedXml.GetXml();

        XmlNode xmlNode = xmlDocument.ImportNode(xmlDigitalSignature, true);


        xmlDocument.FirstChild.NextSibling.LastChild.InsertAfter(xmlNode, xmlnl.LastChild);


        xmlDocument.PreserveWhitespace = true;
        xmlDocument.Save(@"C:\Users\ter0038\Desktop\assinado.xml");
    }
}

Answer:

Try this code:

        private XmlDocument AssinarXml(string arquivo, string tagAssinatura, string tagAtributoId, X509Certificate2 x509Cert)
    {
        StreamReader SR = null;

        try
        {
            SR = File.OpenText(arquivo);
            string xmlString = SR.ReadToEnd();
            SR.Close();
            SR = null;

            // Create a new XML document.
            XmlDocument doc = new XmlDocument();

            // Format the document to ignore white spaces.
            doc.PreserveWhitespace = false;

            // Load the passed XML file using it’s name.
            doc.LoadXml(xmlString);

            if (doc.GetElementsByTagName(tagAssinatura).Count == 0)
            {
                throw new Exception("A tag de assinatura " + tagAssinatura.Trim() + " não existe no XML. (Código do Erro: 5)");
            }
            else if (doc.GetElementsByTagName(tagAtributoId).Count == 0)
            {
                throw new Exception("A tag de assinatura " + tagAtributoId.Trim() + " não existe no XML. (Código do Erro: 4)");
            }
            else
            {
                XmlDocument XMLDoc;

                XmlNodeList lists = doc.GetElementsByTagName(tagAssinatura);
                foreach (XmlNode nodes in lists)
                {
                    foreach (XmlNode childNodes in nodes.ChildNodes)
                    {
                        if (!childNodes.Name.Equals(tagAtributoId))
                            continue;

                        if (childNodes.NextSibling != null && childNodes.NextSibling.Name.Equals("Signature"))
                            continue;

                        // Create a reference to be signed
                        Reference reference = new Reference();
                        reference.Uri = "";

                        XmlElement childElemen = (XmlElement)childNodes;
                        if (childElemen.GetAttributeNode("Id") != null)
                        {
                            //reference.Uri = ""; // "#" + childElemen.GetAttributeNode("Id").Value;
                            reference.Uri = "#" + childElemen.GetAttributeNode("Id").Value;
                        }
                        else if (childElemen.GetAttributeNode("id") != null)
                        {
                            reference.Uri = "#" + childElemen.GetAttributeNode("id").Value;
                        }

                        // Create a SignedXml object.
                        SignedXml signedXml = new SignedXml(doc);

                        // Add the key to the SignedXml document
                        signedXml.SigningKey = x509Cert.PrivateKey;

                        // Add an enveloped transformation to the reference.
                        XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
                        reference.AddTransform(env);

                        XmlDsigC14NTransform c14 = new XmlDsigC14NTransform();
                        reference.AddTransform(c14);

                        // Add the reference to the SignedXml object.
                        signedXml.AddReference(reference);

                        // Create a new KeyInfo object
                        KeyInfo keyInfo = new KeyInfo();

                        // Load the certificate into a KeyInfoX509Data object
                        // and add it to the KeyInfo object.
                        keyInfo.AddClause(new KeyInfoX509Data(x509Cert));

                        // Add the KeyInfo object to the SignedXml object.
                        signedXml.KeyInfo = keyInfo;
                        signedXml.ComputeSignature();

                        // Get the XML representation of the signature and save
                        // it to an XmlElement object.
                        XmlElement xmlDigitalSignature = signedXml.GetXml();

                        nodes.AppendChild(doc.ImportNode(xmlDigitalSignature, true));
                    }
                }

                XMLDoc = new XmlDocument();
                XMLDoc.PreserveWhitespace = false;
                XMLDoc = doc;

                return XMLDoc;
                //string conteudoXMLAssinado = XMLDoc.OuterXml;

                //using (StreamWriter sw = File.CreateText(arquivo))
                //{
                //    sw.Write(conteudoXMLAssinado);
                //    sw.Close();
                //}
            }
        }
        finally
        {
            if (SR != null)
                SR.Close();
        }
    }
Scroll to Top
AllEscort