I am trying to digitally sign a XML document using SHA-1 algorithm, but the resulting signed XML has SHA-256 parts in it. I saw this question and tried to adapt it to my function, but it does not work, as it references both SHA-1 and SHA-256 on the resulting XML.
Here is my actual code:
private void AssinarXml(string arquivo, string tagAssinatura, string tagAtributoId, X509Certificate2 x509Cert)
{
StreamReader SR = null;
try
{
SR = System.IO.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;
}
else if (childElemen.GetAttributeNode("id") != null)
{
reference.Uri = "#" + childElemen.GetAttributeNode("id").Value;
}
//reference.DigestMethod = "http://www.w3.org/2000/09/xmldsig#sha1";
// Create a SignedXml object.
SignedXml signedXml = new SignedXml(doc);
// Add the key to the SignedXml document
signedXml.SigningKey = x509Cert.PrivateKey;
signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
// 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;
string conteudoXMLAssinado = XMLDoc.OuterXml;
using (StreamWriter sw = System.IO.File.CreateText(arquivo))
{
sw.Write(conteudoXMLAssinado);
sw.Close();
}
}
}
finally
{
if (SR != null)
SR.Close();
}
}
How to make this function sign just as SHA1?
Here is an example of the output signature:
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>pp8br9Yd9SdFWQhFdCOJmJlEsKGnlbpovZ6Ssp7VwC4=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>ZSWsXhFu6qw5NGy8+hVAA8oW7nUp1vX2Wv+YpnFiC9UWTdRdYlUDjAiah9symfOX2tOEUk69aJjaL/bSZoc5BFFYqQOm2kBVnlbEYQ0lQpvy4sEJodTWiVGaikVldFWUjPkhjwxy9SpreOKBHpEOPkdkyb8SS8k5bE1yA6IbTE3JfyCmeojDSha3lVZzbX8rBN6R2Mwkwg9Eh9dOPjk4+Wu/V5APDQfDa9viQlDAG+gtBTQacMb2aZrNR8fYqm8fSbwhfxgBaMbCqp3A/KqEm9M5Tj8ql/5flRRJ1zmlrwvByfff5+unhdhMzhKcPeoEAkBBJu4RlJVDgf1BNnexNw==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>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</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
EDIT
Using the suggested code, it returned an error in the line
Reference reference = new Reference($"#{list[0].Attributes["id"].Value}");
:
NullReferenceException: Object reference not set to an instance of an object.
I'm using the function this way:
SignXmlFile("E:\\nota.xml", "InfDeclaracaoPrestacaoServico", EscolherCertificado());
And here is an example of XML file I'm using with the function:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.issweb.fiorilli.com.br/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Header />
<soapenv:Body>
<ws:gerarNfse>
<GerarNfseEnvio xmlns="http://www.abrasf.org.br/nfse.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Rps>
<InfDeclaracaoPrestacaoServico>
<Rps>
<IdentificacaoRps>
<Numero>1</Numero>
<Serie>999</Serie>
<Tipo>1</Tipo>
</IdentificacaoRps>
<DataEmissao>2018-11-27</DataEmissao>
<Status>1</Status>
</Rps>
<Competencia>2018-11-27</Competencia>
<Servico>
<Valores>
<ValorServicos>209000</ValorServicos>
</Valores>
<IssRetido>2</IssRetido>
<ItemListaServico>01.05</ItemListaServico>
<Discriminacao>Discriminacao teste blablabla</Discriminacao>
<CodigoMunicipio>3504800</CodigoMunicipio>
<ExigibilidadeISS>1</ExigibilidadeISS>
</Servico>
<Prestador>
<CpfCnpj>
<Cnpj>01001001000113</Cnpj>
</CpfCnpj>
<InscricaoMunicipal>15000</InscricaoMunicipal>
</Prestador>
<Tomador>
<IdentificacaoTomador>
<CpfCnpj>
<Cpf>35770121025</Cpf>
</CpfCnpj>
</IdentificacaoTomador>
<RazaoSocial>DADOS TOMADOR</RazaoSocial>
<Endereco>
<Endereco>RUA TOMADOR</Endereco>
<Numero>23</Numero>
<Complemento>COMPLEMENTO TOMADOR</Complemento>
<Bairro>BAIRRO TOMADOR</Bairro>
<Uf>MG</Uf>
<CodigoPais>1058</CodigoPais>
<Cep>37170000</Cep>
</Endereco>
<Contato>
<Telefone>(35) 38511836</Telefone>
<Email>[email protected]</Email>
</Contato>
</Tomador>
<OptanteSimplesNacional>2</OptanteSimplesNacional>
<IncentivoFiscal>2</IncentivoFiscal>
</InfDeclaracaoPrestacaoServico>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>s8BhRVqeQKRh4H6nlHJEQudBJ+w=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>IxrI+sqg6XEg7Dl0utAlJviTKT5fTu1NTErntiSjb61B5q/nP68r4wZ12vqXW5/G92pr+ZUZfLVwnG8vrFx8tsX/eObfpwOxZRfissuuOVQrLmFmHOvLs08VpbkffQpvLIhkpDzLV3pcIPsjgo7UQu+99mB4K+iEZYnfedgmJ8s/6EIcJLoWs9TvJHfpANgbEXSndi0nua1uDr9/FN4oO0jD2lRX+JHp7XJNjcjzS1N/kFG+JSyq0R017Ul0F/qR7dcOsBlFvbXtPcYfT6jiZxHjNf5n0xuK1vBHiwGgFHRFf2oF+2/LwqrCVZxiIMZK3ICdGWfdKkc3YCJ5A4px/g==</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>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</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</Rps>
</GerarNfseEnvio>
<username>01001001000113</username>
<password>123456</password>
</ws:gerarNfse>
</soapenv:Body>
</soapenv:Envelope>
For the problem you are pointing out, the reason is that you are informing the
SignatureMethod
as SHA-1:but you are not informing the
reference.DigestMethod
as SHA-1, you can see that's just the XML part that is going out as SHA-256, so you have to add this line (actually you did, but it's commented out):That a look at this answer (on Stack Overflow in Portuguese, but the code part is all in english), it uses SHA-256, but the idea is the same:
However, your code is a little bit confusing and you are doing things that don't seem necessary, like opening the XML file as a stream, then loading a
XmlDocument
using the string read from the stream (why not open the XML file direct as aXmlDocument
?), and them you open anotherXmlDocument
again in the end...But I think that the most important part is that you are expecting that a
Signature
tag already exists in your input XML, but it should not be that way, you should sign a non-signed XML file, and if a signature already exists in the file, you should remove the old signature before signing it again, since the sign process take the whole document to generate a signature.Here is a suggestion of how you could do your function for signing a XML file using SHA-1 algorithm:
You can use it like this: