16 de maio de 2012

Preparando o Certificado Digital para inclusão no XML com CAPICOM e Delphi

Há algum tempo, publiquei uma série de posts sobre a manipulação de XMLs e a criação de assinatura digital para eles. Como a plataforma .NET da Microsoft traz classes prontas para realizar o grosso das tarefas envolvidas, eu usei o C# para montar os exemplos contidos naqueles posts.

Mas muita gente não pode usar a solução com .Net, principalmente quem já têm aplicações desenvolvidas em outras linguagens. Algumas dessas pessoas entraram em contato pra saber como fazer esse mesmo procedimento usando a biblioteca de criptografia da Microsoft - o CAPICOM. Uma dúvida bastante frequente é relativa ao conteúdo a ser inserido na tag X509Certificate do XML assinado. O quadro abaixo mostra o trecho de um XML assinado de Nota Fiscal Eletrônica que inclui a tag em questão:
<?xml version="1.0" encoding="UTF-8" ?>
<enviNFe versao="2.00" xmlns="http://www.portalfiscal.inf.br/nfe">
<idLote>71</idLote>
<NFe>
<infNFe Id="NFe3508059978" versao="2.00">
<cUF>35</cUF>
<cNF>518005127</cNF>
<natOp>Venda a vista</natOp>
<mod>55</mod>
<serie>1</serie>
<dEmi>2012-05-06</dEmi>
<tpAmb>2</tpAmb>
</infNFe>
<Signature>
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="#NFe3508059978"
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>4aXU7m8rl14ALy6X...=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>Igq7eI/Fy3PyjjSW...=</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIIGxDCCBaygAwIBAgIIN6q4...=</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</NFe>
</enviNFe>

Como podemos ver, a tag X509Certificate é parte da estrutura que traz as informações sobre a chave usada pela assinatura e é incluída no fim do XML, junto com a área reservada para a assinatura em si. O valor armazenado na X509Certificate descreve o certificado usado na assinatura, codificado na Base64. Esse valor representa a chave do certificado e é parte imprescindível para a validação do documento XML, isso é, ele ajuda a garantir que o XML não foi adulterado depois de ter sido assinado.

E como calcular esse valor com CAPICOM? Após recuperar o certificado digital de acordo com as instruções do post Acessando o Certificate Store do Windows com CAPICOM, podemos conseguir o conteúdo desse certificado já na Base64 em um único comando:
var cert : TCertificate;
certBase64 : WideString;
begin
{ ... }
certBase64 := cert.Export(CAPICOM_ENCODE_BASE64);
{ ... }
A função export da interface ICertificate2 aceita como parâmetro o tipo de codificação que se deseja como resultado da exportaçao. Os valores permitidos para esse parâmetros são os definidos no tipo enumerado CAPICOM_ENCODING_TYPE. Ele pode assumir basicamente dois tipo de codificação : a Base64 ou a informação binária pura, sem codificação.

O código utilizado no exemplo - CAPICOM_ENCODE_BASE64 - faz a exportação de todas as informações necessárias para inclusão na tag X509Certificate do XML assinado. Há, no entanto, um detalhe no qual é preciso prestar atenção: o texto exportado está quebrado em diversas linhas.
MIIGNjCCBR6gAwIBAgIITDgm4uwI+60wDQYJKoZIhvcNAQEFBQAwTDELMAkGA1UE
BhMCQlIxEzARBgNVBAoTCklDUC1CcmFzaWwxKDAmBgNVBAMTH1NFUkFTQSBDZXJ0
aWZpY2Fkb3JhIERpZ2l0YWwgdjEwHhcNMTEwNzA3MTMxMDA0WhcNMTIwNzA2MTMx
MDA0WjCB7jELMAkGA1UEBhMCQlIxEzARBgNVBAoTCklDUC1CcmFzaWwxFDASBgNV
BAsTCyhFTSBCUkFOQ08pMRgwFgYDVQQLEw8wMDAwMDEwMDE5NjExNzIxFDASBgNV
BAsTCyhFTSBCUkFOQ08pMRQwEgYDVQQLEwsoRU0gQlJBTkNPKTEUMBIGA1UECxML
.
.
.
aXRhbC5jb20uYnIvc2VyYXNhY2R2MTANBgkqhkiG9w0BAQUFAAOCAQEAY8NBFO6e
kPTHirS8DHnlsx1kTJfmsHoUR1QgnDMNdChQjW7ctAn5nIpPYXdhf26om+Us80D/
5RA2iXHhXFT5eL7Crqq0DQ73zWbdn8e81dIDFqYjxIt4LBMy4CO0lJeiT9YHkmYB
XSuADpElqwXA0rzx7bBeIOzuVUGMoYQBduViByI813XIQ2i86Z9VgRLO5KuPUNPn
0RkZS2rSpX1/wLkef8ura++dZEYmbVWpu3g2yCLQJfCArYy/fzsIDwBKruSWnY/O
NK/1AgUaceVAcxxvVmuECwCBqtpfmHqAOXC/uEOXiKefF7L++j0Xc+Okew1SMkHJ
sNNJ+AcX4VfQrw==

Como o conteúdo da tag X509Certificate deve estar numa única linha, o texto retornado pelo export deve ser tratado, removendo-se os espaços em branco do fim e as quebras de linha:
certBase64 := Trim (ReplaceStr (certBase64, #13#10, ''));

O valor da variável certBase64 agora pode ser incluído sem problemas como conteúdo da tag X509Certificate em seu XML assinado.

4 comentários :

Marcelo Tamanhao disse...

Perfeito o exemplo e a explicação. Simples e de fácil implementação. Estou usando (e muito) o seu blog como ferramenta de estudo para aprender a assinar um XML utilizado para troca de informação entre hospitais e operadoras de saúde, tudo regulamentado pela ANS. Luís, há possibilidade de obter os conteúdos das tags DigestValue e SignatureValue, em WideString, usando Delphi + (Capicom ou MSXML)?
[]s
Marcelo

Luís Gustavo Fabbro disse...

Marcelo

Embora eu não tenha feito teste com esses cálculos no CAPICOM, creio que seja possível sim. Não foi preciso me aprofundar neles porque aqui na ABC71 nós optamos por usar as classes prontas do .NET (veja Assinando um documento XML).

[]s

Marcelo Tamanhao disse...

Creio que irei pelo mesmo caminho que vocês adotaram na ABC71. Irei dar uma olha nos outros posts. Muito obrigado.
[]s

Luís Gustavo Fabbro disse...

Inclui um post neste endereço tratando a questão da assinatura usando CAPICOM e MSXML5.

[]s

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.