EDF-Reinf: Error Signature - An XmlDocument Context is required for enveloped transformations

0

I'm developing a C # application for EFD-REINF and at the time of sending my R-1000 event I'm getting the following message: "An XmlDocument Context is required for enveloped transformations."

Below is my code:

public XmlDocument Assinar(string XMLString, X509Certificate2 X509Cert)
    {
        //XmlDocument XMLDoc = null;

        string x = X509Cert.GetKeyAlgorithm().ToString();

        // 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.PreserveWhitespace = false;

        byte[] encodedString = Encoding.UTF8.GetBytes(XMLString.Trim());
        MemoryStream ms = new MemoryStream(encodedString);
        ms.Flush();
        ms.Position = 0;

        doc.Load(ms);

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

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

        // Create a reference to be signed.
        Reference reference = new Reference();
        // pega o uri que deve ser assinada
        XmlAttributeCollection _Uri = doc.GetElementsByTagName("ReinfEvtInfoContriInfoContri").Item(0).Attributes;

        foreach (XmlAttribute _atributo in _Uri)
        {
            if (_atributo.Name == "id")
            {
                reference.Uri = "#" + _atributo.InnerText;
            }
        }

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

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


        // Add an RSAKeyValue KeyInfo (optional; helps recipient find key to validate).
        KeyInfo keyInfo = new KeyInfo();
        keyInfo.AddClause(new KeyInfoX509Data(X509Cert));
        signedXml.KeyInfo = keyInfo;

        // Compute the signature.
        signedXml.ComputeSignature();

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

        // Append the element to the XML document.
        doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, true));

        if (doc.FirstChild is XmlDeclaration)
        {
            doc.RemoveChild(doc.FirstChild);
        }

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

        return XMLDoc;
    }

Does anyone know why I'm getting this error?

    
asked by anonymous 10.12.2018 / 22:01

1 answer

0

You've made some mistakes in this routine:

  • You are only applying the EnvelopedSignature fault transformation but you are not applying to C14N ;
  • You are not reporting on the SignatureMethod and DigestMethod properties of the algorithm to be used, which is SHA-256;
  • And, it is not an error, but it is unnecessary to create another object XmlDocument at the end of the routine, and it is also unnecessary to report the property PreserveWhitespace 3 times during the function.

You can do this (I copied and modified the function of this other answer ):

public void Assinar(XmlDocument xmlDoc, X509Certificate2 certificate, string refUri)
{
   // Cria o objeto SignedXml baseado no XmlDocument passado.
   SignedXml signedXml = new SignedXml(xmlDoc);

   // Adiciona a chave privada do certificado ao documento SignedXml.
   signedXml.SigningKey = certificate.GetRSAPrivateKey();
   // O método de extensão GetRSAPrivateKey() está disponível a partir
   // do .NET Framework 4.6, se for anterior a isso, use a linha abaixo:
   //signedXml.SigningKey = certificate.PrivateKey;

   // https://docs.microsoft.com/en-us/dotnet/framework/whats-new/#Crypto462
   // The .NET Framework 4.6.2 adds support to the SignedXml class for RSA-SHA256,
   // RSA-SHA384, and RSA-SHA512 PKCS#1 signature methods, and SHA256, SHA384,
   // and SHA512 reference digest algorithms.
   signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA256Url;        
   // O campo 'SignedXml.XmlDsigRSASHA256Url' só está disponível a partir
   // do .NET Framework 4.6.2, se for anterior a isso, use a linha abaixo:
   //signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";

   // Checa se foi informado um URI para a referência, se foi acrescenta o "#" no começo.
   refUri = String.IsNullOrEmpty(refUri) ? "" : $"#{refUri}";

   var reference = new Reference(refUri);
   reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
   reference.AddTransform(new XmlDsigC14NTransform());
   reference.DigestMethod = SignedXml.XmlDsigSHA256Url;
   // O campo 'SignedXml.XmlDsigSHA256Url' só está disponível a partir
   // do .NET Framework 4.6.2, se for anterior a isso, use a linha abaixo:
   //reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";

   signedXml.AddReference(reference);

   // Carrega o certificado em um objeto KeyInfoX509Data e o adiciona ao objeto KeyInfo.
   signedXml.KeyInfo = new KeyInfo();
   signedXml.KeyInfo.AddClause(new KeyInfoX509Data(certificate));

   // Calcula a assinatura.
   signedXml.ComputeSignature();

   // Obtém a representação XML da assinatura e a armazena em um objeto XmlElement.
   XmlElement xmlDigitalSignature = signedXml.GetXml();

   // Acrescenta o elemento ao documento XML.
   xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));

   // Se o primeiro nó do documento for o nó de declaração XML
   // '<?xml version="1.0" encoding="utf-8"?>', remove ele.
   if (xmlDoc.FirstChild is XmlDeclaration)
      xmlDoc.RemoveChild(xmlDoc.FirstChild);
}

I have chosen to pass the event ID, which goes in the Reference.URI attribute, as a function parameter, which makes life much easier.

The function receives an object XmlDocument and appends the signature to the same object, so it returns nothing. If you are creating XmlDocument from a string object, you can load it like this before calling this function:

var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(stringXmlEvento);

But it may also be that this error is occurring because you are signing the wrong XML snippet of the event. Here are two other answers to see exactly what needs to be signed:

Taking advantage of these other answers, which may help you:

11.12.2018 / 05:47