A introdução da Nota Fiscal Eletrônica e da Escrituração Digital está dando um grande impulso no uso de Certificados Digitais, já que praticamente todas as empresas terão que adotá-los para assinar os documentos eletrônicos exigidos pela Receita Federal. O formato adotado pela Receita para seus documentos eletrônicos é o XML – daí a importância de conhecer o processo de assiná-lo.
Depois de adquirir um Certificado Digital (nos Correios ou no Serasa, por exemplo), o primeiro passo para a assinatura é saber como localizar esse Certificado. Mas, o que é na prática um Certificado Digital? Como é que o Windows trabalha com isso?
O Certificado em si, a grosso modo, é apenas um arquivo onde são armazenadas informações sobre quem outorgou o certificado (uma CA, ou Certificate Authority) e a quem é que foi outorgado o certificado (uma pessoa física ou jurídica ou ainda um computador) bem como um código público (a chave). O Certificado, portanto, associa uma chave pública a uma entidade (empresa, pessoa ou computador). Há um artigo no Wikipedia mais detalhado sobre esse assunto.
Se você (ou sua empresa ou seu computador) é quem recebeu o certificado, você também possui a chave privada, isto é, o código que só você conhece e que será usado para assinar um documento digital, garantindo-lhe a integridade, a autenticidade e conferindo validade jurídica ao documento.
No Windows, o acesso aos Certificados disponíveis se dá de forma centralizada, através do Armazém de Certificados Digitais (ou Certificate Store) . Isto é, uma vez que o certificado foi registrado no computador, não importa onde ele está armazenado : o acesso deve ser feito a partir do store. Para acessá-lo a partir do Windows, vá em Iniciar -> Executar e digite
mmc \windows\system32\certmgr.msc
Esse programa mostra de forma estruturada quais são os certificados presentes em seu computador: aqueles de uso exclusivo de seu usuário (Personal), as Autoridadades Certificadoras (tanto as de nível mais alto na hierarquia certificadora – as root ou raíz – quanto as intermediárias, que dependem da root), etc.
Via programação, o framework do .NET também fornece uma forma estruturada de acessar o Store, através do namespace System.Security.Cryptography.X509Certificates. São basicamente 3 classes para acessar os certificados :
- X509Store : Representa o acesso ao Store. O construtor dela exige que se estipule qual parte da estrutura deve ser acessada. Use as definições na classe StoreName para identificar, por exemplo, os certificados particulares (“My”) ou as Autoridades Certificadoras (“CA”). Pode optar também por informar apenas a localização, através da classe StoreLocation (somente os meus certicados ou todos os certificados presentes no computador).
- X509Certificate2Collection : Uma lista dos certificados armazenados no Store aberto com a classe anterior.
- X509Certificate2: Representa um certificado na coleção.
O exemplo abaixo em C# percorre a lista de certificados na Store “My”, procurando os válidos e que possuam chave privada.
X509Certificate2Collection lcerts;
X509Store lStore = new X509Store (StoreName.My, StoreLocation.CurrentUser);
// Abre o Store
lStore.Open(OpenFlags.ReadOnly);
// Lista os certificados
lcerts = lStore.Certificates;
foreach (X509Certificate2 cert in lcerts)
{
if (cert.HasPrivateKey && cert.NotAfter > DateTime.Now && cert.NotBefore < DateTime.Now)
{
// Faz o uso do certificado….
// Por exemplo, assinar um docto.
}
}
lStore.Close();
Agora que sabemos localizar um Certificado válido, podemos partir para a assinatura propriamente dita. Para facilitar, reproduzo abaixo um excerto do XML que representa uma Nota Fiscal Eletrônica:
<enviNFe versao=”1.10“ xmlns=”http://www.portalfiscal.inf.br/nfe“>
<idLote>71</idLote>
<NFe>
<infNFe Id=”NFe3508059978“versao=”1.10“>
<cUF>35</cUF>
<cNF>518005127</cNF>
<natOp>Venda a vista</natOp>
<mod>55</mod>
<serie>1</serie>
<dEmi>2008-05-06</dEmi>
<tpAmb>2</tpAmb>
</infNFe>
</NFe>
</enviNFe>
A Receita Federal usou um subconjunto do padrão do W3C para estipular as regras de assinatura digital da NFe. Devem ser assinados todos os elementos infNFe de um lote XML de Notas Fiscais segundo essas regras. Considerando uma variável do tipo XmlDocument de nome doc, já montada com a estrutura correta da NFe, segue um exemplo em C# de como chegar a esse nó:
Há uma classe no namespace System.Security.Cryptography.Xml do framework .NET chamada SignedXml, que implementa o padrão W3C para assinatura de documentos e verificação de documentos assinados. O trecho de código abaixo exemplifica a configuração básica desta classe:
{
string id = infNFe.Attributes.GetNamedItem(“Id”).Value;
signedXml = new SignedXml(infNFe);
signedXml.SigningKey = ObtemCertificado().PrivateKey;
O id obtido é um código calculado segundo regras estipuladas pela Receita Federal e serve para identificar cada Nota. Esse id é inserido como um atributo no elemento infNFe. Ele será usado mais adiante, quando for preciso referenciar o elemento infNFe na assinatura. A função ObtemCertificado é minha: ela usa os conceitos descritos no início desse artigo. A propriedade SigningKey é a chave quer será usada para calcular a assinatura; por isso, é atribuido a ela a chave privada do certificado obtido.
Parte da assinatura é dedicada a descrever o nó a partir do qual a assinatura foi feita e quais transformações esse nó e seus filhos sofreram antes da assinatura ser efetivamente calculada. De acordo com a documentação da Receita Federal, as transformações a serem aplicadas são duas:
- a que indica que a assinatura é “envelopada”, ou seja, o trecho assinado é incluído na assinatura. Aqui cabe um esclarecimento: o elemento infNFe não é o elemento assinado; ele na verdade é usado para calcular um valor chamado de DigestValue, este sim inserido no trecho assinado, de forma que qualquer alteração no conteúdo de infNFe ou de seus filhos resultará num DigestValue diferente e, por fim, a assinatura também não será válida.
- a que indica que o XML deve ser colocado na forma canônica antes do processamento.
A classe Reference cuida dessa parte do processo, incluindo a identificação do nó infNFe e as transformações exigidas:
Reference reference = new Reference(“#” + id);
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigC14NTransform());
signedXml.AddReference(reference);
Antes de computar a assinatura, falta configurar o tratamento das informações a respeito do certificado digital utilizado. É com base nesses dados que a Receita Federal consegue validar a assinatura e atestar que nenhuma informação foi modificada depois que o emissor da Nota Fiscal a assinou. Devemos incluir uma cláusula com os dados do certificado:
keyInfo.AddClause(new KeyInfoX509Data(ObtemCertificado()));
signedXml.KeyInfo = keyInfo;
Agora, só falta computar a assinatura:
Neste ponto, a variável signedXml contém todos os dados para criar o elemento Signature (a assinatura) que deve ser incluído na NFe antes do envio à Receita Federal. Esse elemento deve ser incluído como um nó filho do elemento NFe, no mesmo nível do nó infNFe
Considere a variável xmlNFe do tipo XmlElement criada de acordo com o descrito no post sobre criação de nós no XML. Considere também uma instância da classe SignedXml chamada signedXml e preparada da forma descrita acima. Vou usá-las no exemplo a seguir.
Primeiro, criarei um nó para conter o elemento Signature. Depois, vou usar as propriedades SignedInfo e KeyInfo do signedXml para obter nós XML contendo respectivamente dados sobre a informação que foi assinada e sobre a chave usada nessa assinatura:
XmlElement xmlSignedInfo = signedXml.SignedInfo.GetXml();
XmlElement xmlKeyInfo = signedXml.KeyInfo.GetXml();
Note que o namespace passado para a criação do nó Signature é diferente daquele usado para criar as informações da Receita Federal que usei no post sobre a criação de nós. O namespace “http://www.w3.org/2000/09/xmldsig#” indica que vamos usar a sintaxe de assinatura descrita no link do W3C, conforme especificado na documentação da Receita Federal.
Além dos dados que já obtivemos, é necessário ainda acrescentar a assinatura em si como nó filho do elemento Signature. De acordo com a documentação, a assinatura – que é uma sequência de bytes – deve ser representada como um texto utilizando a codificação Base 64. A criação do nó SignatureValue, sua conversão para Base 64 e a adição do nó ao elemento Signature estão no trecho de código abaixo:
string signBase64 = Convert.ToBase64String(signedXml.Signature.SignatureValue);
XmlText text = doc.CreateTextNode(signBase64);
xmlSignatureValue.AppendChild(text);
xmlSignature.AppendChild(xmlSignatureValue);
O trecho signedXml.Signature.SignatureValue é onde se recupera o valor da assinatura computada.
Agora, só falta importar os dados contidos nos elementos xmlSignedInfo e xmlKeyInfo obtidos no primeiro passo, acrescentado-os ao elemento NFe:
xmlSignature.AppendChild(doc.ImportNode(xmlSignedInfo, true));
xmlSignature.AppendChild (doc.ImportNode(xmlKeyInfo, true));
xmlNfe.AppendChild(xmlSignature);
Depois de acrescentar o xmlNfe ao documento XML final, deve-se transformar o XmlDocument doc em texto para ser enviado à Receita Federal.
Referência: Blog Balaio Tecnológico





















19:28 em 22 de outubro de 2010
Ao enviar a NF-e para a “fazenda” ela retorna com o erro 404 – rejeição uso de prefixo de namespace não permitido.
…???
O que eu faço para resolver este problema.
OBS: estou usando o emissor gratuito (fornecido pela sefaz)
9:56 em 25 de outubro de 2010
Anderson
Essa mensagem do SEFAZ indica que o seu XML foi criado com namespace num nó em que ele não é esperado. Reveja a criação do XML, verificando onde está sendo inserido namespaces e remova os sobressalentes.
Se não conseguir, poste uma parte do XML que você criou para que possamos analisá-lo ou envie-o para o email do meu blog :
11:50 em 8 de dezembro de 2010
Estou encontrando o mesmo problema que o anderson relatou: erro 404 – rejeição uso de prefixo de namespace não permitido. Estou tentando usar a versão 2.0 do Webservice. Alguém poderia me orientar no que pode ser esse problema? Isso só acontece quando faço a consulta de um processamento de lote. No envio está tudo ok.
14:18 em 8 de dezembro de 2010
Marcílio
Poste o XML que está sendo enviado à Receita Federal para gente poder dar uma olhada. Ou, se prefererir, envio-o ao email
balaiotecnologico@gmail.com
12:04 em 6 de setembro de 2011
Ótimo artigo!
Me ajudou muito, eu estava com alguns problemas na rotina de assinatura. Após seguir o exemplo passo-a-passo ficou tudo ok.
Abraços!
17:42 em 22 de setembro de 2011
Olá Luís Gustavo,
Esse exemplo só funciona em aplicações desktop correto? E se a aplicação for web?
Um abraço
16:42 em 23 de setembro de 2011
Fábio
O código que está no post não está restrito a aplicações desktop – ele funciona para aplicações web também. Aqui na ABC71 nós construímos um serviço centralizado via web para processar as notas fiscais, aí incluindo a assinatura digital nos mesmos moldes do post.
A única ressalva é a forma de localizar o certificado digital. O código do post procura apenas no store do usuário atual mas um serviço ou uma aplicação ASP/ASP.Net normalmente se logam no Windows com o usuário System. Portanto, você teria que instalar o certificado no store do LocalMachine e buscá-lo aí ao invés do StoreLocation.CurrentUser.
Se essa explicação não ficou clara, dê uma olhada no post Funcionamento do Certificate Store do Windows para entender melhor esse recurso do Windows.