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 windowssystem32certmgr.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
28 Comentários
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)
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 :
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.
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
Ó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!
Olá Luís Gustavo,
Esse exemplo só funciona em aplicações desktop correto? E se a aplicação for web?
Um abraço
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.
Opa, fiz um esquema de XML Hierarquico, mas estou com um pequeno erro será que vc pode me ajudar?
– 71 – – 35 aaa 518005127 -518005127010101019000152XXXXl LTDA – MEXXXXX-R. XX Poa3011116983411411117417
Como vc pode ver o valor 518005127 deveria esta na Tag , mas esta na Tag EMIT perdido.
César
Acho que seu comentário ficou truncado e não deu pra entender direito qual é o erro que você está tendo… Poste-o novamente, junto com o trecho de seu código que está criando o XML ou envie email com esses dados para meu blog :
balaiotecnologico@gmail.com
Luis obrigado, acabei de enviar para o email [email protected].
bom dia , estou com um problema de assinatura do XML , mesmo utilizando os processos informados
quando valido no site https://www.sefaz.rs.gov.br/cte/cte-val.aspx
me retorna a mensagem Assinatura Invalida para Lote Cte , gostaria de saber se para a assinatura Cte difere da assinatura Nfe
Pessoal meu XML está com um erro que está me assombrando ah dias!
297 – [Simulacao] Rejeicao: Assinatura difere do calculado
Estou fazendo os testes aqui: https://www.sefaz.rs.gov.br/NFE/NFE-VAL.aspx
Já fiz de tudo! verifiquei caracteres especiais, limpei o arquivo, verifiquei as tags, eu já não sei mais o que fazer.
Se alguém estiver disposto a ajudar, eu mando o XML por e-mail, obg.
Danilo
O erro “Assinatura difere do calculado” pode ocorrer quando a tag XML passada para a função de assinatura não é a esperada. Também pode ocorrer se as “transformações” exigidas não forem respeitadas (como a canonicalização e o envelopamento descritos no post). Chegou a depurar esses pontos para garantir que as tags usadas são as corretas e estão montadas conforme o manual ?
Se está certo de ter usado as tags corretas, poste um exemplo de XML assinado por seu programa, junto com o trecho de código que faz a assinatura ou envie email com esses dados para meu blog :
balaiotecnologico@gmail.com
[]s
Muito bom! Parabéns!
Bom dia,
Gostaria de saber como eu gero o código calculado que vai no atributo ID da Tag infNFe ?
Estou gerando a nota sem essa informação e na hora da transmissão ele retorna assinatura inválida.
Aguardo.
Bom dia, estou tentando assinar uma nota eletrônica de serviço (Municipal) e a tag que preciso assinar, não tem o atributo “id”, como faço pra alterar o assinador para considerar essa diferença?
Boa tarde Luis Gustavo.
Estou utilizando uma rotina que você postou para validação de um XML de um CTe.
na linha
settings.Schemas.Add(edNamespace.Text, edXSD.Text); está dando um erro:
Acesso ao Caminho ‘C:\GLSISTEM\Schemas’, foi negado.
O que pode está acontecendo. Já estou executando como Administrador.
Garibaldo
Boa tarde,
Alguém poderia me informar um modelo de xml para envio de solicitação para o Webservice da Sefaz (nfeDistDFeInteresse AN) ?
Estou desenvolvendo software para emitir NF-e, porem consigo o certificado. Como eu faço para ter um certificado de homologação. Este tipo de certificado também é pago. Existe algum lugar na WEB que possa me gerar este tipo de certificado para instalar nas maquinas, apenas para DESENVOLVIMENTO ou seja para ser usado no ambiente de homologação da receita.
Muito obrigado, era isso que eu precisava. Apanhei um pouco mas consegui assinar um documento eletrônicamente. Valeu!
Boa noite.
Estou com o problema comum para quem precisa assinar o documento XML com certificado A3 para envio da nota fiscal eletrônica em sistema ASP.net Web.
Estava estudando instalar uma aplicação no cliente e executar pelo browser no momento da solicitação do envio… mas tem vários problemas de permissão e o controle ActiveX pode não atender a todos os browsers.
Como o Java Applet está se tornando obsoleto, não podemos utilizá-lo, seria uma boa opção.
Que tipo de solução estão implementando para fazer a assinatura do XML, nem que seja no lado cliente, e posteriormente o envio da nota ao Sefaz?
Olá, Estou desenvolvendo xml para envio do SEFAZ SP , segui todas as orientações postadas, quando envio o xml para receita ele é rejeitado por assinatura invalida . Podem me ajudar ? Estou vários dias tentado achar o problema . O cerificado esta dentro da validade , consigo vê-lo através do debug. As tags de assinatura foram todas criadas corretamente no xml.
Olá Luís.
Obrigado por compartilhar o seu conhecimento, e parabéns pelo post.
Até esse momento eu exportava o xml que foi gerado pelo meu programa, para o sistema da receita, e de lá os usuários faziam toda a parte de comunicação com a receita.
Porém, a partir de agora, eu terei que fazer tudo.
Por favor, se não for incomodo, há algum lugar onde você postou todo o código (C#) do artigo, para que eu possa estudar como se faz esse processo?
Novamente obrigado e um forte abraço!
Olá. Estou com um problema. Sigo os passos para fazer o DigestValue, mas na hora de executar o signedXml.ComputeSignature(); ocorre um erro:Malforme
d reference element. Quando assino um Lote de notas fiscais, ai funciona.
Ao assinar notas individuais, se eu colocar o id como “#lote” ao invés do id da nota, ele gera o digestvalue. Alguma idéia do que possa ser o problema? Qualquer ajuda eu agradeço. Parabéns pelo Post.
System.Security.Cryptography.CryptographicException: Malforme
d reference element.
at System.Security.Cryptography.Xml.Reference.CalculateHashValue(XmlDocument
document, CanonicalXmlNodeList refList)
at System.Security.Cryptography.Xml.SignedXml.BuildDigestedReferences()
at System.Security.Cryptography.Xml.SignedXml.ComputeSignature()
at escolhercertificadosimples.Program.Main(String[] args) in C:\Users\user\Do
cuments\Visual Studio 2015\Projects\assinaturalote\assinaturalote\Program.cs:lin
e 143
Luis, trabalho em uma software house, com uma solução em asp.net(c#) , transmitimos as notas para Sefaz, quando o certificado do cliente e a1 ele fica em nosso servidor, quando é a3 instalamos um aplicação nossa desktop para ler, assinar e transmitir o arquivo pela máquina do cliente.
Me falaram que é possível assinar e transmitir direto pela minha aplicação web acessando o certificado local A3 do cliente.
Tentamos de tudo e nunca conseguimos.
Você sabe como fazer, estamos dispostos a pagar por tal informação.
Desde já agradeço.
Se for sim por favor enviar um e-mail.
[email protected]
Boa Tarde !
Preciso de um assinador que funcione com certificado A1 e A3 (toquem e smartcard) para assinar um xml, sera que vocês tem um fonte funcionando para eu utilizar em C# ou Java ?
Obrigado.
Cara seu post caiu do céu, meus parabéns, que bom serviço prestado a comunidade, muito obrigado!
Luis, estou tentando usar esse código e estou tendo erro, poderia dar uma olhadinha e ver se eu fiz algo errado, me ajudaria muito…
Segue o repositório com o código e o xml de exemplo:
https://github.com/almcarvalho/nfec