Ir para conteúdo
  • Cadastre-se

dev botao

Método VerificarAssinatura com CAPICOM


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

Recommended Posts

Olá,

Gostaria de saber qual o método correto para verificar Assinaturas Digitais em arquivos XML.

Meu sistema precisa receber e enviar arquivos XML assinados. Para os arquivos que o sistema recebe, é necessária a validação das assinaturas.

Fiz um projeto para Assinar arquivos XML e enviar ao servidor. A assinatura está válida.

Então peguei esse mesmo arquivo assinado e tentei utilizar o método VerificarAssinatura da classe TDFeSSL (utilizando CAPICOM) para ver se o componente validava a assinatura que ele mesmo fez... mas um erro ocorre:
Assinatura inválida: Erro ao verificar assinatura do arquivo: Invalid Signature.

Poderiam me ajudar?

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

Link para o comentário
Compartilhar em outros sites

  • Consultores

Desculpe se a pergunta for boba, porque eu não pude verificar todo seu código ainda.

Me parece que seu código adiciona a assinatura no XML original e cria um novo XML. Na hora de verificar a assinatura, você está verificando utilizando o XML original ou está verificando a assinatura no arquivo criado? Tentou fazer com o arquivo original?

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

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

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Link para o comentário
Compartilhar em outros sites

Olá Elton,

Estou verificando o XML final, já com a assinatura.

No código do post anterior eu tive que usar um "XML Template" pois o ACBr não estava conseguindo gerar os nós para a assinatura (não sei se o motivo é porque estou utilizando Lazarus e pode haver alguma variação nessa parte em relação ao Delphi).

Após utilizar o XML de Template, retiro todos os espaços em branco. Depois aplico a Assinatura. O XML gerado, final, é o que estou querendo Validar... e também obter o CPF do assinador (ainda não tentei essa parte).

Obrigado.

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

Link para o comentário
Compartilhar em outros sites

  • Consultores

Na realidade, pelo log do SVN não parece que nada foi alterado...

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

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

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Link para o comentário
Compartilhar em outros sites

Hmm, certo.

Então não foi hoje e o meu código deveria estar mesmo desatualizado. :?

 

A parte do CPF, bem... se puder ajudar... é que eu preciso carregar o certificado através do XML recebido e não através do arquivo PFX. Tem alguma maneira ou terei que alterar os fontes do ACBr?

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

Link para o comentário
Compartilhar em outros sites

  • Consultores
12 horas atrás, mdbs99 disse:

Verifiquei e constatei que minha versão era de 25/06/2016.

 

11 horas atrás, mdbs99 disse:

Continua com o mesmo erro. Está funcionando/validando com OpenSSL. Com CAPICOM continua a mesma mensagem.

Como estava fazendo testes não tinha notado que tinha alterado para OpenSSL.

01/07/2016:

-- ACBrDFeOpenSSL --
[*] Adicionado métodos internos para busca de nós a fim de melhorar a detecção
    do nó a ser assinado e o nó de assinatura, a fim de suportar os diversos
    tipos de XMLs da NFSe (por: DSA)

 

15 horas atrás, mdbs99 disse:

A parte do CPF, bem... se puder ajudar... é que eu preciso carregar o certificado através do XML recebido e não através do arquivo PFX. Tem alguma maneira ou terei que alterar os fontes do ACBr?

Acho que não entendi o que você está querendo fazer...

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

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

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Link para o comentário
Compartilhar em outros sites

1 minuto atrás, EMBarbosa disse:

 

01/07/2016:

-- ACBrDFeOpenSSL --
[*] Adicionado métodos internos para busca de nós a fim de melhorar a detecção
    do nó a ser assinado e o nó de assinatura, a fim de suportar os diversos
    tipos de XMLs da NFSe (por: DSA)

 

Acho que não entendi o que você está querendo fazer...

Quero fazer algo não convencional para quem utiliza apenas NF-e, eu acho.

Preciso receber o XML assinado e, a partir dele, obter o CPF de quem assinou. 

No ACBr atual existem métodos para obter tais dados. O CPF/CNPJ é obtido através do método CertCNPF... porém o componente espera que o certificado esteja carregado (através de arquivo ou utilizando a interface do capicom). Mas eu não tenho o arquivo do certificado, apenas a assinatura no XML.

  • Curtir 1

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

Link para o comentário
Compartilhar em outros sites

  • Consultores
13 minutos atrás, mdbs99 disse:

No ACBr atual existem métodos para obter tais dados. O CPF/CNPJ é obtido através do método CertCNPF... porém o componente espera que o certificado esteja carregado (através de arquivo ou utilizando a interface do capicom). Mas eu não tenho o arquivo do certificado, apenas a assinatura no XML.

Mas a essa sua assinatura no XML possui CPF? Porque, até onde eu entendo, uma assinatura não possui esse tipo de identificação.

  • Curtir 1

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

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

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Link para o comentário
Compartilhar em outros sites

Olá EMBarbosa,

Acredito que na tag de Assinatura <SignatureValue> esta informação realmente não esta disponível mas se olharmos para a tag <X509Certificate> não iremos encontrar a identificação do contribuinte (CPF/CNPJ) aqui ? 

Digo isso, porque ao enviarmos um documento para um WS de órgão publico eles são capazes de identificar e certificar de que o documento é realmente daquele contribuinte.

Abraços, 

André Medeiros

Link para o comentário
Compartilhar em outros sites

  • Consultores
3 horas atrás, almp1 disse:

Olá EMBarbosa,

Acredito que na tag de Assinatura <SignatureValue> esta informação realmente não esta disponível mas se olharmos para a tag <X509Certificate> não iremos encontrar a identificação do contribuinte (CPF/CNPJ) aqui ?

Sim, no certificado, pode ser que tenha sim. Eu tinha entendido só da assinatura...

3 horas atrás, mdbs99 disse:

Concordo com o André, tendo fé nisso... pois preciso que seja assim! :-D

Veja os arquivos ACBrDFeCapicom.pas e ACBrDFeOpenSSL.pas. Estas duas units declaram as classes TDFeCapicom e TDFeOpenSSL, que são descendentes da TDFeSSLClass. Esta é quem trabalha com os certificados.

A implementação da leitura dos certificados é feita nos métodos destas classes (exemplo CarregarCertificado).

Talvez você consiga alterar e criar um método ou uma outra classe que utilize o arquivo XML. Mas não sei quais as implicações e limitações dessa situação...

 

  • Curtir 1

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

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

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Link para o comentário
Compartilhar em outros sites

7 minutos atrás, EMBarbosa disse:

Sim, no certificado, pode ser que tenha sim. Eu tinha entendido só da assinatura...

Veja os arquivos ACBrDFeCapicom.pas e ACBrDFeOpenSSL.pas. Estas duas units declaram as classes TDFeCapicom e TDFeOpenSSL, que são descendentes da TDFeSSLClass. Esta é quem trabalha com os certificados.

A implementação da leitura dos certificados é feita nos métodos destas classes (exemplo CarregarCertificado).

Talvez você consiga alterar e criar um método ou uma outra classe que utilize o arquivo XML. Mas não sei quais as implicações e limitações dessa situação...

 

Era o que eu temia. Não há esse suporte (atualmente) no ACBr, então terei que alterar o ACBr ou extrair parte do código que faria isso...

Elton, vocês tem interesse em separar toda a parte de Assinatura Digital do ACBr como um pacote independente? Ainda não sei se é possível (só depois de uma análise do código) mas seria bem interessante ter um pacote somente para Assinatura sem as dependências de NF-e.

  • Curtir 1

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

Link para o comentário
Compartilhar em outros sites

  • Consultores
Em 19/07/2016 at 15:29, mdbs99 disse:

Era o que eu temia. Não há esse suporte (atualmente) no ACBr, então terei que alterar o ACBr ou extrair parte do código que faria isso...

Elton, vocês tem interesse em separar toda a parte de Assinatura Digital do ACBr como um pacote independente? Ainda não sei se é possível (só depois de uma análise do código) mas seria bem interessante ter um pacote somente para Assinatura sem as dependências de NF-e.

Sim. Temos feito o máximo para reduzir códigos repetidos e criar componentes que possam ser utilizados nas mais variadas situações. A criação do TACBrDFe em si é uma prova disso. Ele não depende em si do NFe, tanto que é base para o NFSe que tem regras bem diferentes.

O maior problema é justamente o tempo pra fazer essa separação. Precisamos tomar cuidado pra não quebrar a compatibilidade atual dos componentes.

  • Curtir 1

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

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

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Link para o comentário
Compartilhar em outros sites

6 minutos atrás, EMBarbosa disse:

O maior problema é justamente o tempo pra fazer essa separação. Precisamos tomar cuidado pra não quebrar a compatibilidade atual dos componentes.

Entendo.

Uma boa técnica é utilizar UnitTests para verificar se nada foi quebrado. No entanto o projeto deve "nascer" assim ou é bem difícil incorporar os testes após as funcionalidades já terem sido criadas, pois haveria dependências entre as classes que não seriam compatíveis com testes "fake".

É uma decisão do time do projeto.

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

Link para o comentário
Compartilhar em outros sites

  • Consultores
4 minutos atrás, mdbs99 disse:

Entendo.

Uma boa técnica é utilizar UnitTests para verificar se nada foi quebrado. No entanto o projeto deve "nascer" assim ou é bem difícil incorporar os testes após as funcionalidades já terem sido criadas, pois haveria dependências entre as classes que não seriam compatíveis com testes "fake".

É uma decisão do time do projeto.

Mais uma vez, o problema é o tempo e não o time... Se estiver interessado em ajudar, ficaríamos muito gratos com a adição de testes.

Você pode notar que já existem alguns testes unitários no projeto. Mas são poucos em comparação com a real necessidade.

Por outro lado, a quebra de compatibilidade dos componentes que eu mencionei é mais relacionada com o uso do componente em si. Acho que a separação da assinatura em um pacote separado não necessariamente causaria algum problema, desde que os métodos atuais do componente fossem mantidos.

[]'s

Consultor SAC ACBr

Elton
Profissionalize o ACBr na sua empresa, conheça o ACBr Pro.

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

Um engenheiro de Controle de Qualidade(QA) entra num bar. Pede uma cerveja. Pede zero cervejas.
Pede 99999999 cervejas. Pede -1 cervejas. Pede um jacaré. Pede asdfdhklçkh.
Link para o comentário
Compartilhar em outros sites

  • 4 semanas depois ...
  • Fundadores

Em: TDFeOpenSSL.LerPFXInfo, você tem um exemplo de como ler a informação do Certificado da Tag <X509Certificate>, da NFe assinada, e transformar o mesmo no formato "DER" (subprocedure "CertToDER")

Nesse mesmo método, ele também tem uma subprocedure, que le a informação CNPJ de um Certificado (cert: pX509)...

Isso porém, só funcionará em OpenSSL...

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

  • 5 semanas depois ...

Olá,

Não consigo fazer o load do certificado através do XML — node X509Certificate.

Dentro do método TDFeOpenSSL.LerPFXInfo, parece que só há uma função que obtém o ponteiro para um cert: pX509

Essa função é a : PKCS12parse(p12, FpDFeSSL.Senha, FPrivKey, cert, ca)

Procurei por outras funções e não achei nenhuma que pudesse me retornar uma "instância" de cert.

Eu tentei utilizar esse código:

var
  A: TDFeSSL;
begin
  A := TDFeSSL.Create;
  try
    A.SSLLib := libOpenSSL;
    with TXMLComponent.Create(TFile.New('entrada.xml').Stream) do
    try
      A.DadosPFX :=
        DecodeBase64
        (
          Document.DocumentElement
            .FindNode('Assinatura')
            .FindNode('Signature')
            .FindNode('KeyInfo')
            .FindNode('X509Data')
            .FindNode('X509Certificate').TextContent
        );
      ShowMessage(A.CertSubjectName);
    finally
      Free;
    end;
  finally
    A.Free;
  end;
end;

Através de um XML pré-gerado, já assinado, chamado "entrada.xml", tento decodificar a Base64 passando o resultado para a propriedade DadosPFX. Infelizmente obtenho um erro de leitura do certificado "provavelmente a senha está errada" (esse certificado nem tem senha) na chama a A.CertSubjectName.

Estou usando a Revision 12221.

Eu estive fazendo uma pesquisa e constatei que a informação que eu quero está, sim, dentro do nó X509Certificate. A prova disso é esse site: https://www.sslshopper.com/certificate-decoder.html

Apenas copiando e colando o conteúdo do nó, em Base64 mesmo, ele decodifica exibe todas as informações como nome, CPF, etc.

Restando apenas esse item para que eu conclua meu projeto, peço a ajuda dos senhores novamente.

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

Link para o comentário
Compartilhar em outros sites

  • Fundadores

Marcos,

Acredito que algo muito semelhante, é feito em: "TDFeOpenSSL.VerificarAssinatura"

Ele lê o conteúdo de  "X509Certificate", e carrega o mesmo em uma estrutura de Certificado do XMLSec (xmlSecKeysMngrPtr)

 

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

Daniel,

Analisei a "TDFeOpenSSL.VerificarAssinatura".

Basicamente ela carrega o certificado a partir do XML, utilizando várias funções... e depois chama xmlSecDSigCtxVerify() para verificar a assinatura.

A função que eu preciso, no entanto, está em ACBrDFeOpenSSL, linha 866:

  function GetSubjectName( cert: pX509 ): String;
  var
    s: AnsiString;
  begin
    setlength(s, 4096);
    {$IFDEF USE_libeay32}
     Result := X509_NAME_oneline(X509_get_subject_name(cert), PAnsiChar(s), Length(s));
    {$ELSE}
     Result := X509NameOneline(X509GetSubjectName(cert), s, Length(s));
    {$ENDIF}
    if copy(Result,1,1) = '/' then
      Result := Copy(Result,2,Length(Result));

    Result := StringReplace(Result, '/', ', ', [rfReplaceAll]);
  end;

Essa função irá trazer o SubjectName, que é a informação que preciso.

Mas veja que a função necessita de uma cert: pX509, declarada em OpenSSLExt... que é outra unit.

Até agora eu tenho uma parte de lê o XML encodado em BASE64, mas não tenho funções para ler as informações. E também tenho funções para ler a informação, mas tenho que ter antes uma instância de pX509.

Ainda não entendi como isso tudo funciona... estou tentando, mas ainda não consegui ver. 

Se puder me ajudar, agradeço.

Editado por mdbs99

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

Link para o comentário
Compartilhar em outros sites

  • Fundadores

para usar "PKCS12_parse", primeiro você precisará da uma instância de "p12" que pode ser obtida no bloco do mesmo método citado

     BioWrite(b, pfxdata, Length(PfxData));
     p12 := d2iPKCS12bio(b, nil);

O PFXData, é um AnsiString, contendo a representação binária do Certificado, no formato PFX... no exemplo acima, você atribuiu ela no formato "DER", quando o esperado seria "PFX"

https://myonlineusb.wordpress.com/2011/06/19/how-to-convert-certificates-between-pem-der-p7bpkcs7-pfxpkcs12/

o segredo será achar um método que faça a conversão do tipo de certificado, antes de atribuir a DadosPXF

 

Parece ter algumas dicas nesse link... (no final)

http://stackoverflow.com/questions/6371775/how-to-load-a-pkcs12-file-in-openssl-programmatically

 

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á 2880 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.