- 5. Utilidades
5.2. Assinar - 5.1. Pega propriedades de um certificado digital
« Anterior - 5.3. Validar Schema XML
Próximo »
5.2. Assinar
Assinatura Digital XML no padrão do Projeto MDF-e
Assinatura
string Assinar(string XMLString, string tag, string atributo, string NomeCertificado, out int resultado, out string msgResultado)
Descrição:
Funcionalidade para realizar a assinatura digital no padrão XML Digital Signature enveloped em um documento XML.
A assinatura é realizada na tag informada no parâmetro tag identificada pelo parâmetro atributo do XML existente no conteúdo do parâmetro: XMLString.
É necessário informar o certificado digital que será utilizado para assinatura no parâmetro NomeCertificado.
A DLL oferece 3 forma de uso do certificado digital:
1. uso de certificado digital existente no repositório MY do CSP do usuário corrente (currentuser)
É a forma de mais comum de uso, cabe ressaltar que é a única forma de uso de certificado digital do tipo A3 que a DLL oferece.
O usuário deve passar como parâmetro o campo assunto do certificado no parâmetro NomeCertificado para que a DLL localize um certificado digital com mesmo assunto no repositório MY do currentuser do equipamento.
Esta forma de uso requer a prévia instalação do certificado digital na conta do usuário do Windows (logon) que irá utilizar o certificado digital.
2. uso de certificado digital em arquivo no formato pfx
Permite o de uso de certificado digital em arquivo formato pfx.
O caminho da localização (path) do arquivo pfx deve ser passado para a DLL no formato: ARQUIVO | [nome do arquivo pfx com caminho completo] | [senha do arquivo] no parâmetro NomeCertificado, ex.: "ARQUIVO|c:\certificado.pfx|senha".
Esta opção só funciona com certificado digital do tipo A1.
3. uso de certificado digital em string base64
Permite uso o arquivo do certificado digital em formato pfx convertido em uma string base64. O certificado digital em string base64 deve ser passado para a DLL no formato: CERTIFICADO | [string base64 do arquivo pfx] | [senha do arquivo] no parâmetro NomeCertificado, ex.: "CERTIFICADO|MIIGoDCCBYigAwIBAgIQep(arquivo pfx do certificado digital convertido em base64...)QQDExNBQy|senha".
Esta opção só funciona com certificado digital do tipo A1. É uma opção de uso que oferece maior versatilidade, pois permite o armazenamento do certificado digital em banco de dados na aplicação. É a forma mais indicada para uso em ASP.NET.
Validade do Certificado Digital
A DLL só trabalha com certificados digitais que estão dentro do período de validade. Assim, os certificados digitais que não se encontram dentro do período de validade não serão utilizados. Algumas AC emitem certificados digitais com data de início de validade futura, neste caso o certificado digital só vai ser mostrado a partir da data e hora que constar como data de início de validade, da mesma forma os certificados digitais expirados não serão mostrados.
Repositório de Certificado Digital
A DLL pesquisa o repositório de certificados digitais do usuário corrente, isto é, somente os certificados digitais instalados no repositório de certificados digitais do logon do usuário estarão disponíveis. Caso a aplicação seja um serviço windows ou seja executada como um serviço (aplicação ASP), pode ser necessária a instalação do certificado digital no repositório local machine e uma versão diferente da DLL.
Certificado Digital com chave privada
Quando falamos de certificado digital válido, estamos falando de um certificado digital com chave privada. Já aconteceu do desenvolvedor receber o certificado digital do cliente, que mesmo após a instalação não aparecia no repositório de certificados digitais por não possuir a chave privada. A chave pública do certificado digital não tem a chave privada e geralmente tem a extensão cer, assim caso receba um arquivo com esta extensão, existe uma grande possibilidade de ser uma chave pública que não serve para autenticar e nem para assinatura digital.
Também é possível verificar se o certificado digital tem chave privada ou não pela sua propriedade na opção Ferramentas/Opções da Internet/Conteúdo/Certificados/Exibir do menu do Internet Explorer:
Parâmetros:
nome | tipo | fluxo | descrição |
---|---|---|---|
XMLString | string | entrada | informar uma string com o XML que será assinado. |
tag | string | entrada | informar a tag que será assinada Ex. infMDFe para MDFe. |
atributo | string | entrada | informar o atributo da tag que será utilizado para identificar a assinatura, Ex. "Id". |
NomeCertificado | string | entrada | informar o certificado digital que será utilizado para assinatura: 1. informar o assunto do certificado digital que deve existir no repositório MY do current user, ex.: "CN=NFe - Associacao NF-e:99999090910270, C=BR, L=PORTO ALEGRE, O=Teste Projeto NFe RS, OU=Teste Projeto NFe RS, S=RS". 2. informar: ARQUIVO | [nome do arquivo pfx com caminho completo] | [senha do arquivo] para uso do certificado digital em arquivo pfx, ex.: "ARQUIVO|c:\certificado.pfx|senha". 3. informar: CERTIFICADO | [string base64 do arquivo pfx] | [senha do arquivo] no parâmetro NomeCertificado para passar uma string contendo um certificado digital em base64, ex.:"CERTIFICADO|MIIGoDCCBYigAwIBAgIQep(arquivo pfx do certificado digital convertido em base64...)QQDExNBQy|senha". |
resultado | inteiro | saída | retorna o código do resultado da chamada do WS |
msgResultado | string | saída | retorna a literal do resultado da chamada do WS |
Retorno:
O resultado da chamada da assinatura é uma string com o XML assinado.
Integridade da Assinatura Digital
A assinatura digital é o resultado da aplicação de critografia assimétrica no resumo da mensagem (message digest) com a chave privada do assinante. Qualquer alteração do conteúdo do XML da MDF-e tem reflexo no resumo da mensagem e invalida a assinatura digital. A DLL elimina todos os espaços em branco e outros caracteres de formatação como tab/CR/LF do XML da MDF-e antes de aplicar a assinatura digital, assim o arquivo XML assinado não deve ser modificado em nenhuma hipótese para não invalidar a assinatura digital.
Outras causas que comprometem a validade da assinatura digital
O projeto da assinatua digital prevê que os arquivos XML utilizem a codificação UTF-8. A maioria das aplicações trabalham com a codificação ANSI que tem divergência na representação dos caracteres especiais (Ex. Ç, º, Á, etc). A forma mais simples de evitar os reflexos do uso de caracteres especiais é vedar a sua utilização como faz o aplicativo emissor de NF-e de SP, existem UF que não aceitam caracteres especiais como é o caso do MT. Em geral, o problema acontece quando o destinatário da NF-e tenta importar o arquivo XML da NF-e no aplicativo visualizador da RFB e o provedor de solução é acionado que aciona o nosso suporte... Conhecendo estas particularidades é possível conviver com os caracteres especiais, o problema todo está na fase que o XML é gerado em arquivo, como já dito as aplicações trabalham em uma codificação diferente do UTF-8 e gravamos o arquivo sem alterar a codificação e o arquivo XML tem a declaração XML no início do arquivo onde dizemos que estamos adotando a codificação UTF-8. A codificação ANSI e UTF-8 é igual até o caractere 127, os caracteres especias tem codificação diferente, por exemplo o caractere º tem representação diferente no ANSI (ba em hexadecimal) e no UTF-8 (c2 ba em hexadecimal), o grande problema é que o UTF-8 é multibyte e alguns caracteres são representados com 2, 3 ou 4 bytes e neste processo pode ocorrer o acréscimo de algum byte com reflexo na assinatura digital.
Caractere símbolo código ANSI (hexadecimal) código UTF-8 (hexadecimal) símbolo de numeral º ba c2 ba A com til à c3 c3 83 a com til ã e3 c3 a3 cecedilha minúsculo ç e7 c3 A7 cecedilha maiúsculo Ç c7 c3 87 Para evitar este tipo de problema, basta fazer a conversão da codificação de ANSI para UTF-8 na string antes da gravação do arquivo XML, para outros detalhes vide o post: Distribuição da NF-e para o Destinatário.
Obs: A aplicação da conversão da codificação só deve ser feita de ANSI para UTF-8, se a string já estiver em UTF-8 a aplicação da conversão vai corromper o conteúdo da string!
Assinatura de MDF-e em uma estrutura de lote
A DLL não permite a assinatura de uma MDF-e contida em uma estrutura de lote de MDF-e, assim, a assinatura da MDF-e deve ser realizada individualmente.
O uso de namespaces
A tag raiz do XML deve ter o namespace do projeto (xmlns="http://www.portalfiscal.inf.br/nfe") e nada mais, evite o uso de outros namespaces, pois apesar de aceitos em algumas UF, podem causar falhas na validação da assinatura digital.
Exemplo de uso de namespace recomendado: <NFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="2.00">
Armazenamento do MDF-e
Recomendamos fortemente que grave o arquivo XML assinado, pois ele poderá ser útil no futuro em caso de algum problema. Não converta a string do XML assinado em UTF-8, pois este processo altera a codificação dos caracteres especiais para a codificação UTF-8 e muitos usuários importam arquivo convertido em UTF-8 para a aplicação sem converter a string lida para ANSI que é a codificação padrão de muitos ambientes de programação e acabam corrompendo o arquivo sem perceber.
O usuário deve arquivar o XML da MDF-e assinado da forma que entender mais conveniente, como por exemplo:
. campo tipo blob do BD;
. arquivo no file system.Também é conveniente que exista alguma forma simples e automática de armazenamento de segurança, como por exemplo:
. envio do arquivo via e-mail para uma conta de e-mail do tipo gmail;
. uso de disco virtual do tipo dropbox.
O resultado da assinatura é o código numérico devolvido no parâmetro resultado com os seguintes significados:
código | Mensagem | origem | regra |
---|---|---|---|
5300 | Assinatura realizada com sucesso | DLL | - |
5301 | Erro: Certificado digital inexistente para [nome informado], verifique se o Assunto (subject name) está correto), ou talvez o certificado digital esteja fora do prazo de validade ou não esteja instalado para o usuário.. | DLL | - |
5302 | Erro: A tag de assinatura [nome da tag informada para a DLL] inexiste, verifique o nome da tag informada, Ex. de tag válida: infNFe | DLL | - |
5303 | Erro: A tag de assinatura [nome da tag informada para a DLL] não é unica, a assinatura deve ser realizada em uma MDF-e, a MDF-e deve ser inserida no lote somente após o processo de assinatura. | DLL | - |
5304 | Erro: Tentativa de assinar uma MDF-e contida em um lote, a assinatura deve ser realizada em uma MDF-e fora do lote, devendo ser inserida no lote somente após o processo de assinatura. | DLL | - |
5305 | Erro: Falha no acesso ao XML, XML mal formado ou XML vazio: [mensagem de erro] | DLL | - |
5306 | Erro: Falha no acesso do certificado digital: [mensagem de ERRO DO WINDOWS] | DLL | - |
5307 | Erro: Falha na Assinatura: [mensagem do ERRO DO WINDOWS] - vide guia de uso da DLL - https://www.flexdocs.net/guiaNFe/FAQ.assinatura.html | DLL | - |
5403 | Erro: Falha ao acessar certificado digital [mensagem de ERRO DO WINDOWS] | DLL | - |
5404 | Erro: Nenhum certificado digital selecionado | DLL | |
5405 | Erro: Nenhum certificado válido foi encontrado com o nome [NomeCertificado] informado no repositório [MY do CurrentUser] | DLL | - |
5406 | Erro: Falha no tratamento do parâmetro nome: [nome informado] | DLL | - |
5407 | Erro: Quantidade de parâmetos inválido: [nome informado] | DLL | - |
5408 | Erro: Falha na criação do objeto certificate: [mensagem do ERRO DO WINDOWS] | DLL | - |
5307 - Falha na Assinatura: [mensagem do ERRO DO WINDOWS]
O Erro 5307 é uma falha do certificado digital, ele pode não ter sido corretamente instalado ou não estar disponível para uso se for um token ou smart card.
A DLL acessa os certificados digitais existentes no provedor de certificados digitais (CSP) do Windows do usuário corrente (o que está logado no equipamento), desta forma para a DLL é indiferente se o certificado digital é do tipo A1 ou A3, desde que o certificado digital esteja corretamente instalado no CSP do Windows.
Assim, o problema de incompatibilidade do certificado digital ou do hardware criptográfico (smartcard/token) é com o framework .NET do Windows e não tem relação com a DLL, todas as aplicações que utilizam o framework .NET (Ex.: assinador da SEFAZ/RS) terão problema para usar o certificado digital se ele não for compatível com o Windows e não oferecer suporte necessário para o .NET Framework acessar a funcionalidade de cálculo de hash e criptográfia.
Compatibilidade do Certificado Digital com a versão do Windows
O usuário deve verificar se o smartcard/token adquirido é compatível com a versão do Windows e não tem incompatibilidade na assinatura XML com uso do framework .NET 2.0.
Teste do Certificado Digital
Os testes que são realizados pelo atendimento do fornecedor do certificado digital, em geral, limita-se a testar funcionalidade autenticação do usuário no e-CAC em algum outro Portal que exige autenticação mútua com envio do certificado digital e não faz o teste de assinatura digital XML que é a causa do Erro 5307.
Utilize aplicativos que utilizam o framework .NET 2.00, como por exemplo o assinador da SEFAZ/RS para ter uma segunda opinão. Uma aplicação que utiliza a biblioteca CAPICOM não serve de parâmetro para comparação.
Solução do problema
Desinstale o certificado digital e instale novamente conforme instruções do fornecedor do certificado digital.
Certificado Digital A1
A instalação de um certificado digital do tipo A1 requer o arquivo pfx (o arquivo com extensão cer não tem chave privada). Arquivos com extensão cer são arquivos de chave pública do certificado digital e não servem para uso em assinatura digital.
Certificado Digital A3
Se for um dispositivo A3 (token/smart card) verifique se os drivers e gerenciador criptográfico do seu dispositivo são compatíveis com a versão do Windows em uso.
drivers/gerenciadores para TOKEN
drivers/gerenciadores para SMARTCARD
O fornecedor do dispositivo também deve ser consultado para obter os drivers e gerenciadores corretos.
Certificado Digital CEF - CAIXA
Veja uma possível solução para certificado digital da CEF - CAIXA.
Histórico de atualização:
- 2012-10-10 - Versão preliminar.
Exemplos:
Visual Basic
' declaração das variáveis que serão utilizadas na passagem de parâmetros da DLL ' Dim XMLString As String ' informar o xml a ser assinado Dim tag As String ' nome da tag que será assinada (Ex. infNFe) Dim atributo As Strubg ' nome do atributo que sera utilizado para identificar a assinatura no URI (Id, id, etc.) Dim nomeCertificado As String ' nome (assunto) do certificado digita Dim XMLAssinado As String ' retorna com o xml assinado Dim msgResultado As String ' literal com resultado da chamada da DLL Dim Resultado As Long ' código do resultado da chamada da DLL ' ' ' IMPORTANTE: todas as variáveis utilizadas como parâmetro da DLL devem ser inicializadas ' ' Dim nomeArquivo As String ' nome do arquivo que será assinado ' nomeArquivo = "c:\exemplo.xml" ' ' importante: verificar a existência do arquivo solicitado na pasta do VB e indicar o caminho correto para ele ' Carrega o conteúdo do nome do arquivo em XMLString ' Open nomeArquivo For Input As #1 XMLString = Input$(LOF(1), 1) Close #1 ' tag = "infMDFe" ' indica a tag a ser assinada atributo = "Id" ' indica o atributo msgResultado = "" nomeCertificado = "CN=NFe - Associacao NF-e:99999090910270, C=BR, L=PORTO ALEGRE, O=Teste Projeto NFe RS, OU=Teste Projeto NFe RS, S=RS" ' ' importante: indicar aqui assunto do certificado digital válido, este da associacao trata-se apenas de um exemplo para testes ' ' EXEMPLO PARA USO DE ARQUIVO PFX ' 'nomeCertificado = "ARQUIVO|c:\certificado.pfx|associacao" ' ' onde: ' ARQUIVO --> indica opção de uso de arquivo PFX ' c:\certificado.pfx --> nome e caminho do arquivo PFX ' associacao --> senha do arquivo PFX ' ' ' EXEMPLO PARA USO DE ARQUIVO PFX EM STRING BASE64 ' 'nomeCertificado = "CERTIFICADO|MIIGoDCCBYigAwIBAgIQep(arquivo pfx do certificado digital convertido em base64...)QQDExNBQy|senha" ' ' onde: ' CERTIFICADO --> indica opção de uso de arquivo PFX em base64 ' MIIGoDCCBYigAwIBAgIQep(arquivo pfx do certificado digital convertido em base64...)QQDExNBQy --> arquivo PFX em base64 ' senha --> senha do arquivo PFX ' ' utilize a funcioalidade string ConverteArquivoBase64(string nomeArquivo, out int cResultado, out string msgResultado) para criar a string base64 do arquivo pfx ' Dim objMDFeUtil As Object ' ' instancia a DLL ' Set objMDFeUtil = CreateObject("MDFe_Util.util") ' Resultado = 0 ' ' Aplica a assinatura ' XMLAssinado = objMDFeUtil.Assinar(XMLString, tag, atributo, nomeCertificado, Resultado, msgResultado) ' ' tratar retorno ' If Resultado = 5300 Then MsgBox msgResultado, vbInformation, "Informação" Else MsgBox "Processo de assinatura falhou..." & vbCrLf & msgResultado, vbExclamation, "Atenção" End If ' ' liberar DLL ' Set objMDFeUtil = Nothing
- 5.2. Assinar
5. Utilidades - « Anterior
5.1. Pega propriedades de um certificado digital - Próximo »
5.3. Validar Schema XML