Atualmente as empresas emitem as notas fiscais em formato eletrônico. Para isso, foi desenvolvido um projeto que especifica e rege a emissão destas notas em ambiente nacional, que é conhecido como Nota Fiscal Eletrônica ou, simplesmente, NF-e. Este projeto faz uso de diversas tecnologias para garantir a segurança e, principalmente, a integridade da mesma.
A integridade é a garantia de que o arquivo XML que a representa não tenha sido alterado desde a sua emissão. Quando uma empresa emite uma nota fiscal, a SEFAZ gera um arquivo XML digitalmente assinado, utilizando o certificado digital da empresa emitente. Como sabemos, esse arquivo XML é a nota fiscal em formato eletrônico, e essa assinatura está embutida nele. A assinatura digital nada mais é que um cálculo matemático que é realizado sobre todo o arquivo XML, e se qualquer mudança ocorrer neste depois da assinatura, a mesma se tornará inválida.
Se você recebe este arquivo e quer garantir que ele não tenha sido alterado, então podemos recorrer à classes que estão dentro do .NET Framework para realizar esta validação. Basicamente devemos carregar o conteúdo XML para o objeto XmlDocument, e em seguida, procurar pelo elemento <Signature /> que é armazena o hash calculado e o certificado serializado que foi utilizado para realizar a assinatura.
var xml = new XmlDocument();
xml.Load(“00000000000000000000000000000000000000000000.xml”);
var nfe = (XmlElement)xml.GetElementsByTagName(“NFe”)[0];
var signature = (XmlElement)nfe.GetElementsByTagName(“Signature”)[0];
var signer = new SignedXml();
signer.LoadXml(signature);
Console.WriteLine(signer.CheckSignature());
Depois de carregado e separado os elementos que serão avaliados, recorrermos a classe SignedXml para validar a assinatura, onde devemos submeter o elemento que contém a assinatura para o método LoadXml, e em seguida, invocar o método CheckSignature, que retorna um valor boleano indicando se ela está ou não válida.
O overload do método CheckSignature utilizado acima (sem parâmetros) analisa o elemento <Signature /> tentando extrair os certificados de forma automática. Caso queira ter um maior controle sobre os certificados utilizados para analisar a assinatura, podemos utilizar um código mais rebuscado para atingir este objetivo:
private static bool ValidateWithCertificate(SignedXml signer)
{
var keyInfoEnumerator = signer.KeyInfo.GetEnumerator();
while (keyInfoEnumerator.MoveNext())
{
var x509Data = keyInfoEnumerator.Current as KeyInfoX509Data;
if (x509Data != null && x509Data.Certificates.Count > 0)
foreach (var cert in x509Data.Certificates)
if (signer.CheckSignature((X509Certificate2)cert, true))
return true;
}
return false;
}
Como o próprio nome sugere, a propriedade KeyInfo contém informações referentes à chave que foi utilizada para realizar a assinatura. E, utilizando um enumerador, identificamos se trata-se de um certificado, e ao iterar pela coleção, invocamos o método CheckSignature, e através de um segundo overload, passamos o certificado que queremos que ele considere para realizer a validação. Apesar de ter o mesmo resultado, aqui é possível extrair informações do certificado utilizado, caso seja necessário.
Importante: um erro bastante comum é que alguns sistemas incluem novas informações no XML depois que ele foi assinado. Ao fazer isso, a assinatura digital é corrompida, e ao submetermos o XML para o código que escrevemos acima, a assinatura será dada como inválida. Entre essas informações, é comum ver namespaces como os que são mostrados abaixo (em negrito), e segundo a Nota Técnica 2010/009 da SEFAZ, eles não devem ser incluídos, nem antes, e muito menos depois, da assinatura.
<?xml version=”1.0″ encoding=”UTF-8″?>
<nfeProc xmlns=”http://www.portalfiscal.inf.br/nfe”
xmlns:ds=”http://www.w3.org/2000/09/xmldsig#”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
versao=”2.00″>
<NFe xmlns=”http://www.portalfiscal.inf.br/nfe”>
<infNFe Id=”NFe…” versao=”2.00″>
Acho que lá no início isso seria o suficiente:
var signature = xml.Descendents("Signature").First() ;
Boas Vitor,
Repare que estou utilizando o – antigo – XmlDocument e XmlElement (DOM), que não são, nativamente, "LINQ To XML friendly". Por mais que existam algumas alternativas para fazer a conversão entre elas, o SignedXml também lida diretamente com as classes Xml*.
Sendo assim, optei por recorrer ao que estas classes disponibilizam sem fazer a tal conversão.
Amigo, esse comando SignedXML nao existe no meu visual studio, o que faço??
Boas Daniel,
Você referenciou o assembly System.Security.dll?