Processo de Assinatura de Rps/Lote - Nota Fiscal Eletrônica

Lendo aquele bolo de especificação da ABRASF muitos devem perguntar: "Certo, sei quais campos colocar no XML mas qual a ordem do processo de assinatura?". A documentação não fica claro realmente como e qual a melhor forma de assinar. Realize a seguinte ordem:
  1. Gere o XML da Rps e assine;
  2. Se for enviar mais de uma Rps em um mesmo lote, repita o passo 1 para cada Rps;
  3. Anexe todas as Rps já assinadas no XML do Lote;
  4. Assine o Lote e faça o envio.
Seu XML de envio deve ficar semelhante à figura abaixo:


Para fazer a assinatura dos XMLs, utilize a função abaixo:

private XmlDocument AplicaAssinatura(string xml, string uri)
{
try
{
// Obtem o certificado
X509Certificate2 X509Cert = ObtemCertificado();
// Cria um documento XML para carregar o XML
XmlDocument docXML = new XmlDocument();
docXML.PreserveWhitespace = true;
// Carrega o documento XML
docXML.LoadXml(xml);
// Cria o objeto XML assinado
SignedXml signedXml = new SignedXml(docXML);
// Assina com a chave privada
signedXml.SigningKey = X509Cert.PrivateKey;
// Atribui o método de canonização
signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
// Atribui o método para assinatura
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
// Cria a referencia
Reference reference = new Reference();
// Pega a URI para ser assinada
XmlAttributeCollection _Uri = docXML.GetElementsByTagName(uri).Item(0).Attributes;
foreach (XmlAttribute _atributo in _Uri)
{
if (_atributo.Name == "id")
reference.Uri = "#" + _atributo.InnerText;
}
// Adiciona o envelope à referência
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
// Atribui o método do Hash
reference.DigestMethod = "http://www.w3.org/2000/09/xmldsig#sha1";
// Adiciona a referencia ao XML assinado
signedXml.AddReference(reference);
// Cria o objeto keyInfo
KeyInfo keyInfo = new KeyInfo();
// Carrega a informação da KeyInfo
KeyInfoClause rsaKeyVal = new RSAKeyValue((System.Security.Cryptography.RSA)X509Cert.PrivateKey);
KeyInfoX509Data x509Data = new KeyInfoX509Data(X509Cert);
x509Data.AddSubjectName(X509Cert.SubjectName.Name.ToString());
keyInfo.AddClause(x509Data);
keyInfo.AddClause(rsaKeyVal);
// Adiciona a KeyInfo
signedXml.KeyInfo = keyInfo;
// Atribui uma ID à assinatura
signedXml.Signature.Id = "Assigned" + uri;
// Efetiva a assinatura
signedXml.ComputeSignature();
// Obtem o XML assinado
XmlElement xmlDigitalSignature = signedXml.GetXml();
// Adiciona o elemento assinado ao XML
docXML.DocumentElement.AppendChild(docXML.ImportNode(xmlDigitalSignature, true));
// Retorna o XML
return docXML;
}
catch (Exception erro) { throw erro; }
}

O parâmetro URI é o nome da tag geral que deve ser assinada de um XML, no caso deverá assinar as tags InfRps (cada uma) e LoteRps. A função ObtemCertificado já foi exibida aqui em um tópico anterior que serve para captura do certificado digital.

2 comentários:

Anônimo disse...

parabens pelo blog, cara tive um problema com a assinatura, na hora do ComputeSignature() aparece a seguinte mensagem: "Um contexto XmlDocument é necessário para transformações envelopadas."
Já pesquisei bastante mas não achei muita coisa. Se vc tiver uma dica eu agradeço. Valeu

Rodrigo de Freitas Oliveira disse...

Estou tendo o mesmo problema

Postar um comentário