Ir para conteúdo
  • Cadastre-se

dev botao

Problemas com PIN A3 + Assinatura de XML


Data Lider
Ver Solução Respondido por Daniel Simoes,
  • Este tópico foi criado há 2367 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Recommended Posts

Contextualizando 

Prezados, devido nossa aplicação ser em 3 camadas, a parte de assinatura do XML fica em uma aplicação externa em outra linguagem de programação, e no que diz respeito a parte de ENVIO basta mencionar o excelente trabalho que o projeto fez com a WinCrypt.

obs: se você não sabe o porque de fazermos assim, segue o tópico EXCELENTE do Daniel 

O Problema

Essa semana obtivemos um certificado A3 da Perto (SmartCard) e ele está pedindo PIN no servidor, e no DEBUG descobri que não era na nossa rotina de assinatura mas sim no momento do envio pela ACBr.

A Causa

Na unit "ACBrNFeNotasFiscais.pas", na linha 252, onde temos:

  TACBrNFe(TNotasFiscais(Collection).ACBrNFe).SSL.ValidarCNPJCertificado( NFe.Emit.CNPJCPF );

1º Ele acaba inicializando todo contexto e enviando o PIN para o SmartCard (ou Token) previamente, antes da assinatura e antes do envio.

2º Quando o evento "OnAntesDeAssinar" é disparado nosso código externo realiza a assinatura do XML nessa biblioteca externa. 

3º (Não tenho certeza) É provável que ao adquirir o contexto do certificado A3 nessa aplicação nossa, e enviar o PIN tem removido o contexto da ACBR ou algo semelhante, isso já vai um pouco além do que conheço do assunto.

4º Quando o código volta para a ACBR realizar o Envio, a janela de PIN aparece.

5º Quando debugando eu faço um Jump para a próxima linha pulando a linha 252 conforme destacada acima, tudo funciona normalmente, porque não houve um contexto anteriormente adquirido acima, então no momento do envio o código para obter a chave privada funciona como se fosse executado a primeira vez.  

Obs: CertFreeCertificateContext também é chamado em nossa aplicação depois da assinatura do XML ser concluída, e o Store dos certificados é fechada. 

Possíveis Soluções 

Aqui que venho pedir ajuda ao pessoal responsável pelo projeto para não fazer alterações desnecessária ou que não serão aceitas.

De imediato pensei em para as pessoas que assinam os XMLs em aplicações externas fica a responsabilidade da validação do CNPJ e o certificado, assim adicionando uma verificação se o evento OnAntesDeAssinar está "Assigned" antes linha 252 e resolvendo esse problema.

Ou então a rotina que verifica se o CNPJ é o mesmo do certificado não realizar o envio do PIN quando o tipo for A3 por exemplo

// Talvez adicionar um parametro padrão como 

TDFeWinCrypt.CarregarCertificado;

Para

TDFeWinCrypt.CarregarCertificado(const EnviarPinSeExistir: Boolean = True);

 E aqui seguindo a lógica de enviar o parâmetro falso para o CNPJ, até chegar na unit que verifica se os dois CNPJ são os mesmos. 


function TDFeSSLCryptClass.GetCertCNPJ: String;
begin
  CarregarCertificadoSeVazio(False);
  Result := FpDadosCertificado.CNPJ;
end;

Desculpe se ficou muito extenso. 

 www.datalider.com.br - [email protected] - Macgayver Armini

 

Link para o comentário
Compartilhar em outros sites

  • Fundadores

A opção 1, parece fazer mais sentido... (verificar se há um evento externo para assinar)

procedure NotaFiscal.Assinar;
var
  XMLStr: String;
  XMLUTF8: AnsiString;
  Leitor: TLeitor;
begin
  with TACBrNFe(TNotasFiscais(Collection).ACBrNFe) do
  begin
    if not Assigned(SSL.AntesDeAssinar) then
      SSL.ValidarCNPJCertificado( NFe.Emit.CNPJCPF );
  end;   

mas isso não apenas adiaria o problema ?  Pois ambas aplicações precisam usar o certificado.. e acho que depois do ACBr atribuir o PIN, para efetuar o envio... provavelmente sua aplicação tenha problemas para usar o certificado, na próxima assinatura...

Consultor SAC ACBr

Daniel Simões de Almeida
O melhor TEF, é com o Projeto ACBr - Clique e Conheça
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Link para o comentário
Compartilhar em outros sites

Em 18/08/2017 at 13:43, Daniel Simoes disse:

A opção 1, parece fazer mais sentido... (verificar se há um evento externo para assinar)


procedure NotaFiscal.Assinar;
var
  XMLStr: String;
  XMLUTF8: AnsiString;
  Leitor: TLeitor;
begin
  with TACBrNFe(TNotasFiscais(Collection).ACBrNFe) do
  begin
    if not Assigned(SSL.AntesDeAssinar) then
      SSL.ValidarCNPJCertificado( NFe.Emit.CNPJCPF );
  end;   

mas isso não apenas adiaria o problema ?  Pois ambas aplicações precisam usar o certificado.. e acho que depois do ACBr atribuir o PIN, para efetuar o envio... provavelmente sua aplicação tenha problemas para usar o certificado, na próxima assinatura...

Olá Daniel, obrigado pela atenção, e realmente, com duas notas seguidas o problema acaba acontecendo, você tem alguma sugestão? 

Talvez adicionar uma propriedade TDFeSSL e em TDFeSSLCryptClass para definir se mantem o certificado carregado, ou não, então sempre que pedir o carregamento e após fazer o uso liberar. 

Ou então tentar manter o mesmo contexto em duas aplicações diferentes usando o mesmo handle (não sei se é possível). 

 www.datalider.com.br - [email protected] - Macgayver Armini

 

Link para o comentário
Compartilhar em outros sites

Veja a seguinte situação:

Primeiro, descarregando o certificado após a verificação do CNPJ

procedure NotaFiscal.Assinar;
var
  XMLStr: String;
  XMLUTF8: AnsiString;
  Leitor: TLeitor;
begin
  with TACBrNFe(TNotasFiscais(Collection).ACBrNFe) do
  begin
    SSL.ValidarCNPJCertificado( NFe.Emit.CNPJCPF );
    if Assigned(SSL.AntesDeAssinar) then
      SSL.DescarregarCertificado;
  end;

Quando descarrega o contexto, remove a trava do pin

procedure TDFeWinCrypt.DescarregarCertificado;
var
  PosA3Pin: integer;
begin
  // Limpando objetos da MS CryptoAPI //
  if Assigned(FpCertContext) then
  begin
    if Assigned(FpDadosCertificado) then
    begin
      PosA3Pin := pos(FpDadosCertificado.NumeroSerie, CertificadosA3ComPin);
      if PosA3Pin > 0 then
        Delete(CertificadosA3ComPin, PosA3Pin, Length(FpDadosCertificado.NumeroSerie + ','));
    end;

    CertFreeCertificateContext(FpCertContext);
  end;

 

Desta forma, duas nota seguidas foram enviadas sem pedir o PIN ou apresentar o erro, é claro que é apenas um teste, e de forma nenhum trata todas as possibilidades. Nesse caso foi testado com um Leitor Perto (SafeSign) e com um SafeNet Token 1500.

Eu vi também no MSDN que é possível liberar o cache do pin enviando nulo para NCryptSetProperty ou mesmo CryptSetProvParam.

 www.datalider.com.br - [email protected] - Macgayver Armini

 

Link para o comentário
Compartilhar em outros sites

  • Fundadores

No objeto DFeSSL há métodos para carregar e descarregar o certificado...

Deve funcionar, se aplicarmos a modificação sugerida ( não validar o CNPJ, para quem programou o evento ) e você descarregar o certificado de DFeSSL, após o envio... 

Consultor SAC ACBr

Daniel Simões de Almeida
O melhor TEF, é com o Projeto ACBr - Clique e Conheça
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Link para o comentário
Compartilhar em outros sites

1 hora atrás, Daniel Simoes disse:

No objeto DFeSSL há métodos para carregar e descarregar o certificado...

Deve funcionar, se aplicarmos a modificação sugerida ( não validar o CNPJ, para quem programou o evento ) e você descarregar o certificado de DFeSSL, após o envio... 

  1. Fiz a reversão de todos os fontes da ACBR na nossa cópia de trabalho.
  2. Fiz a seguinte alteração postada por você
    Em 18/08/2017 at 13:43, Daniel Simoes disse:

    A opção 1, parece fazer mais sentido... (verificar se há um evento externo para assinar)

    
    procedure NotaFiscal.Assinar;
    var
      XMLStr: String;
      XMLUTF8: AnsiString;
      Leitor: TLeitor;
    begin
      with TACBrNFe(TNotasFiscais(Collection).ACBrNFe) do
      begin
        if not Assigned(SSL.AntesDeAssinar) then
          SSL.ValidarCNPJCertificado( NFe.Emit.CNPJCPF );
      end;   

    mas isso não apenas adiaria o problema ?  Pois ambas aplicações precisam usar o certificado.. e acho que depois do ACBr atribuir o PIN, para efetuar o envio... provavelmente sua aplicação tenha problemas para usar o certificado, na próxima assinatura...

  3. Então em nosso código adicionei 
    Result := FACBR.Enviar(Lote, False);
    FACBR.SSL.DescarregarCertificado;
  4. Ao enviar duas notas fiscais, a segunda travou e pediu o PIN.
  5. Então ainda no nosso código adicionei mais uma linha 
    Result := FACBR.Enviar(Lote, False);
    FACBR.SSL.DescarregarCertificado;
    // Identifica a posição do certificado na lista
    vPosCertPinCache := pos(FACBR.Configuracoes.Certificados.NumeroSerie, ACBrDFeWinCrypt.CertificadosA3ComPin);
    // Se foi identificado, então remove apenas ele.
    if vPosCertPinCache > 0 then
         Delete(CertificadosA3ComPin, vPosCertPinCache, Length(FACBR.Configuracoes.Certificados.NumeroSerie + ','));

     

  6. Enviei 3 notas e nenhuma delas deu erro ou pediu o PIN, tanto no Token quando no SmartCard.

    Se quiser, posso fazer a alteração em todos os valida CNPJ de todas as classes que herdam a DFe e modificar de acordo com seu código e postar aqui para subir.
Editado por Data Lider

 www.datalider.com.br - [email protected] - Macgayver Armini

 

Link para o comentário
Compartilhar em outros sites

  • Fundadores

Hum.. então o que faltou, foi que ao Descarregar o Certificado, devemos remover ele da Lista de Pins salvos... correto ?

Consultor SAC ACBr

Daniel Simões de Almeida
O melhor TEF, é com o Projeto ACBr - Clique e Conheça
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Link para o comentário
Compartilhar em outros sites

1 hora atrás, Daniel Simoes disse:

Hum.. então o que faltou, foi que ao Descarregar o Certificado, devemos remover ele da Lista de Pins salvos... correto ?

Perfeito, e caso precise de confirmar alguma situação, estaremos com o Leitor de cartão até quarta-feira. 

  • Curtir 1

 www.datalider.com.br - [email protected] - Macgayver Armini

 

Link para o comentário
Compartilhar em outros sites

  • Fundadores
  • Solution

ok.. já no SVN...

Citar

-- ACBrDFeWinCrypt --
[-] Correção para remover o numero de Série do Certificado, de "CertificadosA3ComPin",
    quando Descarregar o Certificado.
    http://www.projetoacbr.com.br/forum/topic/38349-problemas-com-pin-a3-assinatura-de-xml/
    (por: DSA)  

 

  • Obrigado 1
Consultor SAC ACBr

Daniel Simões de Almeida
O melhor TEF, é com o Projeto ACBr - Clique e Conheça
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Link para o comentário
Compartilhar em outros sites

2 horas atrás, Daniel Simoes disse:

ok.. já no SVN...

 

Fiz o update e os seguintes testes: 

  • Emitir duas NF-e com A1 sem aplicativo externo, Tudo OK
  • Emitir duas NF-e com A3 Token sem aplicativo externo, Tudo OK.
  • Emitir duas NF-e com A3 SmartCard com aplicativo externo, Tudo OK.
  • Emitir uma MDF-e com A3 SmartCard com aplicativo externo, Tudo OK.

 

  • Obrigado 1

 www.datalider.com.br - [email protected] - Macgayver Armini

 

Link para o comentário
Compartilhar em outros sites

  • 1 mês depois ...
  • Fundadores

@Data Lider,

Após analisar o tópico abaixo, notei que a modificação que efetuamos aqui.. ocasionou efeitos colaterais...

Pensando nisso, aplique modificações na Unit ACBrDFeWinCrypt.pas, a fim de tentar resolver o problema... porém gostaria que você verificasse se essas modificações funcionarão para o caso relatado aqui nesse post.

Por favor teste seus fontes, com a Unit em anexo...

ACBrDFeWinCrypt.pas

  • Curtir 1
Consultor SAC ACBr

Daniel Simões de Almeida
O melhor TEF, é com o Projeto ACBr - Clique e Conheça
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Link para o comentário
Compartilhar em outros sites

19 horas atrás, Daniel Simoes disse:

@Data Lider,

Após analisar o tópico abaixo, notei que a modificação que efetuamos aqui.. ocasionou efeitos colaterais...

Pensando nisso, aplique modificações na Unit ACBrDFeWinCrypt.pas, a fim de tentar resolver o problema... porém gostaria que você verificasse se essas modificações funcionarão para o caso relatado aqui nesse post.

Por favor teste seus fontes, com a Unit em anexo...

ACBrDFeWinCrypt.pas

Olá @Daniel Simoes, tomei a liberdade de testar o arquivo com a modificação. Ao consultar o status por exemplo não retorna mais o erro de canais seguros mas retorna o "Falha ao Definir PIN do Certificado." vide imagem.

Att, Lucas.

 

Falha ao Definir PIN.JPG

Link para o comentário
Compartilhar em outros sites

19 horas atrás, Daniel Simoes disse:

@Data Lider,

Após analisar o tópico abaixo, notei que a modificação que efetuamos aqui.. ocasionou efeitos colaterais...

Pensando nisso, aplique modificações na Unit ACBrDFeWinCrypt.pas, a fim de tentar resolver o problema... porém gostaria que você verificasse se essas modificações funcionarão para o caso relatado aqui nesse post.

Por favor teste seus fontes, com a Unit em anexo...

ACBrDFeWinCrypt.pas

Daniel, após as alterações, nós inserimos a aplicação para produção em alguns clientes, para ver como reagiria, e todos os clientes com o Windows 10 e Windows Server 2012R2 funcionou muito perfeito, até mesmo assinaturas com o aplicativo rodando como serviço funcionaram bem, mesmo com A3, porém em Windows 7 a aplicação de assinatura externa falhava por diversas vezes, por esse motivo removemos o assinador externo do projeto, e todas suas chamadas.

 www.datalider.com.br - [email protected] - Macgayver Armini

 

Link para o comentário
Compartilhar em outros sites

  • Fundadores
1 hora atrás, Lucas L. disse:

Olá @Daniel Simoes, tomei a liberdade de testar o arquivo com a modificação. Ao consultar o status por exemplo não retorna mais o erro de canais seguros mas retorna o "Falha ao Definir PIN do Certificado." vide imagem.

Att, Lucas.

 

Falha ao Definir PIN.JPG

parece ser uma exceção controlada... quando ele vai descarregar o certificado, ele tenta atribuir "Nul" a senha previamente definida...  Observe que está entre um bloco try/except

1 hora atrás, Data Lider disse:

Daniel, após as alterações, nós inserimos a aplicação para produção em alguns clientes, para ver como reagiria, e todos os clientes com o Windows 10 e Windows Server 2012R2 funcionou muito perfeito, até mesmo assinaturas com o aplicativo rodando como serviço funcionaram bem, mesmo com A3, porém em Windows 7 a aplicação de assinatura externa falhava por diversas vezes, por esse motivo removemos o assinador externo do projeto, e todas suas chamadas.

Desculpe.. mas não compreendi se o problema relatado inicialmente nesse tópico, retornou...

  • Obrigado 1
Consultor SAC ACBr

Daniel Simões de Almeida
O melhor TEF, é com o Projeto ACBr - Clique e Conheça
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.

Link para o comentário
Compartilhar em outros sites

  • Este tópico foi criado há 2367 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora
×
×
  • Criar Novo...

Informação Importante

Colocamos cookies em seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies, caso contrário, assumiremos que você está bem para continuar.

The popup will be closed in 10 segundos...