Ir para conteúdo
  • Cadastre-se

dev botao

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

Recommended Posts

Postado

Olá,

Estou trabalhando com assinatura digital em XML, no Lazarus, e estou utilizando o código abaixo para testar (CÓDIGO 1)

Parece estar funcionando. No entanto preciso que o CAPICOM insira mais um "nó" chamado SigningTime na assinatura (CÓDIGO 2).

Alguém sabe como fazer?

 

CÓDIGO 1

procedure TMainForm.Assinar;
var
  A: TDFeSSL;
begin
  A := TDFeSSL.Create;
  A.SSLLib := libCapicom;
  A.SelecionarCertificado;
  with TStringList.Create do
  try
    LoadFromFile('template.xml');
    Text :=
      UTF8Encode(
        '<?xml version="1.0" encoding="iso-8859-1"?>' +
        A.Assinar(Text, 'Assinatura', '')
      );
    SaveToFile('assinado.xml');
  finally
    Free;
  end;
  A.Free;
end;

 

CÓDIGO 2

 
[...]
</KeyInfo>
<Object Id="Info">
<SigningTime>29/06/2016 10:52:48</SigningTime>
</Object>
</Signature>
 
  • Curtir 1

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

Postado (editado)

Daniel,

Já nos falamos por e-mail, meio que no início do ACBr e/ou NFe. Agradeço seu tempo previamente.

Vamos lá.
Arquivo XML assinado em anexo. Assinei sem considerar o novo nó.

A saber:
1- Utilizo FPC 2.6 e Lazarus 1.5.
2- O sistema é para Windows, mas tentei utilizar a lib xmlsec e não funcionou (não fez o load do A3)
3- Estou utilizando um template (original.xml) para o arquivo e assinatura (em anexo) porque dá erro se o componente tentar adicionar o <signature> sem existir no XML original.
4- Meu .pfx é sem assinatura, para testes, porém não posso disponibilizar porque não é meu.
5- Já tentei adicionar o novo nó depois de assinar, mas é claro que invalidou.
6- Já tentei adicionar o novo nó no template (colocando a data/hora em hardcode mesmo só pra testar) mas o Assinador remove todos os espaços, inclusive no no <Object...> e seu conteúdo (data/hora).
7- Já tentei adicionar o novo nó no template, deixar a assinatura assinar e depois altera o conteúdo do nó (manualmente) colocando os espaços e nada.

Acredito que o nó deva ser enviado ao CAPICOM antes de assinar, mas não sei como fazer isso.

Em tempo, não estou trabalhando com NFe, somente com arquivos XML assinados digitalmente sendo enviados entre WebServices.

assinado.xml

original.xml

Editado por Marcos Douglas Santos
  • Curtir 1

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

  • Fundadores
Postado

Não encontrei o elemento <SigningTime> no arquivo "assinado.xml"... Você tem exemplo deu um arquivo já assinado com essa tag ?

A ideia é ver como foi montado o bloco "<Signature>"

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.

Postado

Mas como o  <SigningTime> faz parte da assinatura, acredito que isso deve ser montado pela CAPICOM.

Você está me dizendo que se eu adicionar um  <SigningTime/> no template a CAPICOM irá adicionar a informação automaticamente?

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

  • Fundadores
Postado

Acredito que SIM... é exatamente isso que fazemos no ACBr... geramos as Tags vazias, para a CAPICOM preencher

Veja:  TDFeSSLClass.SignatureElement

tente modificar ela para inserir as tags que vc deseja...

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.

Postado

Não funcionou (sem alterar nenhum fonte).

Em anexo template e assinado (tem algum limite de anexos aqui?).

Repare que no assinado.xml o nó <SigningTime>, além de não constar nenhum valor, foi alterado pela função RemoveEspacos (o correto seria <Object Id="Info"...).

...EY8eeLEHD53dbw==</SignatureValue><ObjectId="Info"><SigningTime/></Object><KeyInfo><X509Data>...

 

Vou tentar fazer alguma alteração no SignatureElement... mas qualquer outra ajuda ou dica será bem vinda!

assinado.xml

original.xml

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

Postado (editado)
48 minutos atrás, Daniel Simoes disse:

Veja:  TDFeSSLClass.SignatureElement

tente modificar ela para inserir as tags que vc deseja...

Essa função não é chamada porque o XML já contém o nó Signature.

Se eu não adiciono o nó Signature antes de chamar o CAPICOM, o sistema não consegue fazer o load do XML, caindo nessa exception:
 
      // Carregando o AXml em XMLDOC
      if (not xmldoc.loadXML( WideString(AXml) )) then
        raise EACBrDFeException.Create('Não foi possível carregar XML'+sLineBreak+ AXml);
 
 
E mesmo que essa função fosse chamada e o XMLDOC conseguisse fazer o load do XML, ainda assim no final a função remove espaços iria quebrar o nó <Object...>
 
Não tenho certeza se tenho que adicionar a data+hora antes da assinatura ou se é a assinatura que deveria fazer isso. Acho que é a última opção mas não sei como fazer o CAPICOM adicionar esse parâmetro.
Seria algo como tentaram fazer aqui:
 
Veja a parte
 
    Signobj := CoSignedData.Create;
    Signobj.Content := Texto;

    SigningTime := CoAttribute.Create;
    SigningTime.Name  := CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME;
    SigningTime.Value := Now;
    Assinador.AuthenticatedAttributes.Add(SigningTime);

    s := Signobj.Sign(Assinador, True, CAPICOM_ENCODE_BASE64) ;

 

Mas as Interfaces são bem diferentes da ACBr... então, não sei como fazer isso funcionar (e o próprio comentário do programador diz que fica diferente).

 
 
Editado por mdbs99

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

Postado

OK Daniel.

Só mais uma informação: se for possível adicionar esse nó utilizando OpenSSL, resolveria meu problema. Mas é claro que seria bom termos isso solucionado em ambos e eu estou a disposição para ajudar no que for preciso. Obrigado.

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

  • Fundadores
Postado

Marcos,

Notei que as Tags que você deseja inserir, não fazem parte dos elementos previstos  na especificação de: XMLSign:  https://www.w3.org/TR/xmldsig-core/

Ou seja, provavelmente a XMLSec e CAPICOM nunca processem essas Tags.

Entretanto o conteúdo assinado de um XML é o elemento que consta em <Reference URI="">.. Ou seja, não é todo o XML que é assinado, apenas o Elemento referenciado pela URI...

Considere o XML em anexo. Eu modifiquei ele com o NotePad++ e adicionei manualmente as tags que você deseja (copiei e colei)... O ACBr continua validando o XML com sucesso, pois o conteúdo de "infNFe" não foi alterado... Agora, se você modifica qualquer coisa, dentro de "infNFe", verá que a assinatura fica inválida.

Se você validar o XML no portal do SEFAZ, verá que está valido... mesmo no portal ele critica os elementos novos, que não constam no XSD da NFe

https://www.sefaz.rs.gov.br/nfe/nfe-val.aspx

 

Minha sugestão é você anexar manualmente as tags, com o TimeStamp da máquina, antes de chamar a assinatura...

 

35160605481336000137550010000003411000003418-nfe.xml

  • Curtir 2
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.

Postado
21 horas atrás, Daniel Simoes disse:

Minha sugestão é você anexar manualmente as tags, com o TimeStamp da máquina, antes de chamar a assinatura...

Eu tentei fazer isso antes mesmo de postar aqui.

  1. Tentei inserir após a assinatura e o sistema me diz que ela está inválida.
  2. Tentei inserir antes de assinatura, e vi que o ACBr retira os espaços do nó <Object...> e de seu conteúdo... e o sistema me diz que ela está inválida.
  3. Tentei fazer o item #2 acima mas no fim inserir os espaços em branco novamente... e o sistema me diz que ela está inválida.
21 horas atrás, Daniel Simoes disse:

Entretanto o conteúdo assinado de um XML é o elemento que consta em <Reference URI="">.. Ou seja, não é todo o XML que é assinado, apenas o Elemento referenciado pela URI...

Veja se estou entendendo certo. Você diz que somente o elemento que consta em <Reference URI=""> é assinado.

No seu XML de exemplo tem:

<infNFe versao="3.10" Id="NFe35160605481336000137550010000003411000003418" 
...
<Reference URI="#NFe35160605481336000137550010000003411000003418">

O que há em comum entre os nós acima é o número da NFe. 

Então você está dizendo que a assinatura irá percorrer o XML, encontrar o nó que tem o "Id" que foi sinalizado em Reference (no seu caso está em <infNFe... Id="NFe..."> e no meu está em <SolicitacaoServico Id="10000"> e assinar somente esse nó e ignorar todo o resto do arquivo?

Nesse caso não deveria funcionar as opções #1 e #3 que descrevi acima, já que todo o resto do XML deveria ser ignorado?

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

  • Fundadores
Postado

Sim, pois não como assinar o XML todo, sendo que a propria assinatura faz parte do XML.. apenas o conteúdo do nó referenciado pela URI é assinado

Acredito que você deva solicitar mais informações ao Provedor que consome esse WebService, a respeito do formato de assinatura dele...

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.

Postado (editado)

Daniel,

Consegui fazer a assinatura!

Para que funcione eu preciso fazer 3 coisas:

  1. No XML template, adicionar o nó <Object Id="Info"><SigningTime>[[data+hora]]</SigningTime></Object> dentro de <Signature>
  2. Deixar o XML de template em apenas 1 linha, sem espaços e quebra de linhas;
  3. Alterar o ACBr para que a rotina de "Ajuste da Assinatura" não altere a informação de determinados nós (Ex: <Object Id...>

O código de teste está abaixo, modificado do primeiro post.
Antes de passar a informação para o método A.Assinar, eu faço a "limpeza" descrita no item #2.

Após o XML ter sido gerado, eu incluo novamente (manualmente) os espaços que o ACBr retirou do nó <Object Id="Info">.

Depois eu envio para o servidor e a assinatura é validada.

Quero alterar o ACBr para que ele aceite nós "customizados" no template e que ele não altere essas informações após a assinatura.

Como não conheço completamente o código, gostaria que me desse alguma dica para que essa alteração fosse implementada da forma mais genérica possível. Assim poderei lhe enviar um patche para que possa incluir no projeto original e disponibilizar à outros desenvolvedores. O que acha?

procedure TMainForm.Assinar;
var
  A: TDFeSSL;
  S: AnsiString;
  I: Integer;
begin
  A := TDFeSSL.Create;
  A.SSLLib := libCapicom;
  A.SelecionarCertificado;
  with TStringList.Create do
  try
    LoadFromFile(TemplateFileNameEdit.FileName);
    S := '';
    for I := 0 to Count-1 do
    begin
      S := S + Trim(
        StringReplace(
          StringReplace(Strings[I], #13, '', [rfReplaceAll]),
          #10, '', [rfReplaceAll]
        )
      )
    end;
    Text := '<?xml version="1.0" encoding="iso-8859-1"?>'
          + A.Assinar(S, 'AssinaturaConvenio', '');
    SaveToFile(OutFileNameEdit.FileName);
    OutMemo.Lines.Text := Text;
  finally
    Free;
  end;
  A.Free;
end; 

 

Apenas para o meu caso, alterei as linhas abaixo:

unit ACBrDFeSSL;

function TDFeSSLClass.AjustarXMLAssinado(const ConteudoXML: String;
  X509DER: String): String;

[...]

  // CAPICOM insere espaços em alguns Elementos da Assinatura //
  //XmlAss := RemoveEspacos(XmlAss, '<SignatureValue>', '</Signature>');
  XmlAss := RemoveEspacos(XmlAss, '<SignatureValue>', '</KeyInfo>');

[...]
end;

Ou seja, o RemoveEspacos não vai até o fim da assinatura, deixando os nós abaixo de <KeyInfo> inalterados.

Editado por mdbs99

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

  • Fundadores
Postado

Acho que poderíamos modificar os fontes do ACBr para suportar esse recurso, usando alguns parâmetros com valores "default", para não impactar em aplicações já existentes...
(Assim como já existe em TDFeSSLClass.SignatureElement o parâmetro "AddX509Data: Boolean")

A remoção de espaços indevidos, é realmente uma deficiência "TDFeSSLClass.AjustarXMLAssinado" e pode ser corrigida.

 

Não ficou claro para mim, se a OpenSSL/CAPICOM estão preenchendo o TimeStamp, ou se você mesmo está fazendo isso...

 

  • 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.

Postado
8 minutos atrás, Daniel Simoes disse:

Não ficou claro para mim, se a OpenSSL/CAPICOM estão preenchendo o TimeStamp, ou se você mesmo está fazendo isso...

Eu mesmo estou adicionando no XML de template antes de chamar a Assinatura.

Pelo que vi de exemplos em outras linguagens, são nós que devem ser adicionados manualmente (através da interface da classe) mesmo por não fazerem parte da assinatura padrão. Mas se não forem adicionados antes, a assinatura fica inválida.

Concordo plenamente sobre adicionar esse recurso na ACBr.

Marcos Douglas B. Santos
www.ObjectPascalProgramming.com

  • Este tópico foi criado há 3070 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.