生成无效数字签名的函数

Function generating invalid digital signature

我正在尝试使用 SHA-1 算法对 XML 文档进行数字签名,但生成的签名 XML 中包含 SHA-256 部分。我看到了这个 并试图使其适应我的功能,但它不起作用,因为它在结果 XML.

上同时引用了 SHA-1 和 SHA-256

这是我的实际代码:

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();
    }
}

如何让这个函数像SHA1一样签名?
这是输出签名的示例:

<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>

编辑

使用建议的代码,它在行中返回了一个错误 Reference reference = new Reference($"#{list[0].Attributes["id"].Value}");:

NullReferenceException: Object reference not set to an instance of an object.

我是这样使用函数的:

SignXmlFile("E:\nota.xml", "InfDeclaracaoPrestacaoServico", EscolherCertificado());

这里是 XML 文件的示例,我正在使用函数:

<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>mariana@live.com</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>

对于您指出的问题,原因是您将 SignatureMethod 通知为 SHA-1:

signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;

但是您没有通知 reference.DigestMethod 作为 SHA-1,您可以看到那只是作为 SHA- 输出的 XML 部分256,所以你必须添加这一行(实际上你添加了,但它被注释掉了):

reference.DigestMethod = SignedXml.XmlDsigSHA1Url;

看看这个答案(葡萄牙语的Stack Overflow,但代码部分都是英文),它使用SHA-256,但思路是一样的:

E-Social. Assinatura do evento inválida

但是,您的代码有点混乱,您正在做一些似乎没有必要的事情,例如将 XML 文件作为流打开,然后使用字符串加载 XmlDocument从流中读取(为什么不直接打开 XML 文件作为 XmlDocument?),最后你再次打开另一个 XmlDocument...

但我认为最重要的部分是您期望输入 XML 中已经存在 Signature 标记,但不应该那样,您应该签署一个非-signed XML 文件,如果文件中已经存在签名,您应该在再次签名之前删除旧签名,因为签名过程需要整个文档来生成签名。


这里有一个关于如何使用 SHA-1 算法对 XML 文件进行签名的功能的建议:

using System;
using System.Xml;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;

private void SignXmlNodes(
   string filename,
   string mainChildTag,
   string idAttributeTag,
   X509Certificate2 x509Cert)
{
   XmlDocument xmlDoc = new XmlDocument();
   // Format the document to ignore white spaces.
   xmlDoc.PreserveWhitespace = false;
   xmlDoc.Load(filename);

   XmlNodeList mainChildList = xmlDoc.GetElementsByTagName(mainChildTag);
   // Loop through the nodes that need to be signed.
   foreach (XmlNode mainChildNode in mainChildList)
   {
      XmlNode nodeForSigning = mainChildNode.ParentNode;

      // It's necessary to create a namespace manager to use with SelectNode methods,
      // otherwise they won't work, because the node has a specific namespace.
      var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
      nsmgr.AddNamespace("ns", nodeForSigning.NamespaceURI);
      nsmgr.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);

      XmlNode nodeWithTheId = nodeForSigning.SelectSingleNode($"ns:{idAttributeTag}", nsmgr);
      if (nodeWithTheId == null)
      {
         throw new Exception($"The tag with ID attribute '{idAttributeTag}' does not exist in the XML file. (Error code: 4)");
      }
      // Uses null-conditional (?.) and null-coalescing (??) operators to set the reference Uri.
      string refUri = nodeWithTheId.Attributes?["id"]?.Value ?? "";
      if (!string.IsNullOrEmpty(refUri))
      {
         refUri = $"#{refUri}";
      }

      // Remove existing signatures in the node, if there's any.
      foreach (XmlNode node in nodeForSigning.SelectNodes("ds:Signature", nsmgr))
      {
         node.ParentNode.RemoveChild(node);
      }

      SignedXml signedXml = new SignedXml((XmlElement) nodeForSigning);
      // Add the key to the SignedXml document
      signedXml.SigningKey = x509Cert.PrivateKey;
      signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;

      // Create a reference with the specified Uri (id of the informed tag).
      Reference reference = new Reference(refUri);
      reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
      reference.AddTransform(new XmlDsigC14NTransform());
      reference.DigestMethod = SignedXml.XmlDsigSHA1Url;
      // Add the reference to the SignedXml object.
      signedXml.AddReference(reference);

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

      // 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 signature element to the XML document.
      //xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
      nodeForSigning.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
   }

   xmlDoc.Save(filename);
}

你可以这样使用它:

SignXmlNodes("E:\nota.xml",
             "InfDeclaracaoPrestacaoServico",
             "InfDeclaracaoPrestacaoServico",
             SelectCertificate());