How to sign documents with digital certificate?

Asked

Viewed 7,789 times

8

I would like to know how to sign documents with digital certificate using Delphi or Lazarus. If someone knows of some component, free preference, or some function that I can use would help a lot.

  • What type of signature? What type of certificate?

1 answer

8

Reply withdrawn from that link.

Signing XML documents with CAPICOM and Delphi

Microsoft makes available for Windows a library with COM technology to handle the creation and manipulation of XML files. The library, called MSXML, is currently in version 6 and also supports XSLT transformations and validation through XSD schemes. In only one of the versions (MSXML5), resources were also included to make digital signature of Xmls.

Version 5 was distributed exclusively with Microsoft Office so that developers of this platform could subscribe to Xmls. However, an Internet search reveals that the library is widely used outside this context.

This is good news for those who use Delphi (or another language that supports COM) because MSXML5, in association with CAPICOM, makes it much easier to sign Xmls. In this post I show you how to perform this process, considering that you have already mounted the XML you want to sign. The table below shows part of the XML of a Invoice that I will use as an example:

<?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>
   </NFe>
</enviNFe>

The first step is to import the sources of Activex MSXML5 and CAPICOM so that we can use them in the Delphi project. There is a summary of how to make this import at this address; for MSXML5, the description of the Type Library is Microsoft XML, v5.0. Both generated sources should be included in the Unit uses clause that will make the signature.

Obviously, we will need a digital certificate to perform the signature. Using CAPICOM, we can access the Certificate Store do Windows and locate an appropriate one, which has been generated for your company. However, the interfaces available in MSXML5 require you to report a Certificate Store with the certificate that will be used, as well as its validation chain, if necessary. This extra step is shown in the table below.

var store : IStore3;
    cert : TCertificate;
    lKey : IPrivateKey;
begin
    cert := getCert;
    lKey := Cert.PrivateKey;

    { Monta um Store em memória com o Certificado obtido antes }
    store := CoStore.Create;
    store.Open(CAPICOM_CURRENT_USER_STORE, 'My', CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED);
    store.Add(cert.DefaultInterface);
    { ... }

The Getcert function used above is mine and follows the instructions described in the post on access to Certificate Store with CAPICOM. Moreover, the code only creates a Store in memory and adds to it the found certificate. The section also saves the private key of this certificate, information that will be used later to generate the signature itself.

Next, we need to prepare the example XML to receive the signature. The MSXML5 interface responsible for this step is based on an XML Signature node. This node describes the transformations by which the XML must be submitted before it is actually signed. The Signature node should be created as shown below:

<?xml version="1.0" encoding="UTF-8" ?>
<enviNFe versao="2.00" xmlns="http://www.portalfiscal.inf.br/nfe">
   <idLote>71</idLote>
   <NFe>
         { ... }
      <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></DigestValue>
            </Reference>
         </SignedInfo>
         <SignatureValue><SignatureValue>
      </Signature>
   </NFe>
</enviNFe>

As we can see above, the node also leaves aside one location to receive the hash (Digestvalue) and another for the signature itself (Signaturevalue), which will be filled automatically. The only variable part of the block prepared above is the URI attribute of the Reference tag, which reflects the identification of the Invoice contained in the XML. That is, you must mount the value of this attribute from the value of the attribute Id of the infNFe tag, preceding this value with the sign #. As the name says, this part of XML references the node (and its children) that will be saved by digital signature.

Once XML is ready, we can move on to the signature itself, which is achieved through the interface Ixmldigitalsignature MSXML5. So, we need to create an instance of it and provide you with the signature data:

var {...}
      xmlDoc: IXmlDomDocument3;
      noSignature : IXMLDOMElement;
      xmlSign : IXMLDigitalSignature;
      xmlDsigKey: IXMLDSigKey;
begin
      {...}
      { Monta o XML e prepara a tag Signature }
      xmlDoc := PreparaXML ();
      noSignature := EncontraNodeSignature (xmlDoc);

      if (noSignature <> Nil) then begin
      xmlSign := CoMXDigitalSignature50.Create;
      xmlSign.signature := noSignature;
      xmlSign.store := store;

      { Monta a chave com o tipo exigido pelo método Sign }
      xmlDsigKey := xmlSign.createKeyFromCSP(lKey.ProviderType, lKey.ProviderName, lKey.ContainerName, 0);
      { Assina o XML }
      xmlSign.sign(xmlDsigKey, NOKEYINFO);
      {...}
   end;
end;

As we can see from the code snippet above, Ixmldigitalsignature needs us to indicate which is the Signature node of our Xmldomdocument and the Certificate Store we built at the beginning of the post. Now, we have to call the method Sign to complete the service. To work, it needs some information based on the private key of the certificate. In the above example, I used the recovered key from the certificate to create an interface instance Ixmldsigkey containing the necessary information.

The second parameter of the Sign function determines how key data will be included in the XML structure. In the example, I used the value NOKEYINFO so that such data are not automatically included.

After calling Sign, the tags we leave reserved in the Signature node are automatically calculated and filled in. Finally, for XML to be in the required standard for Fiscal Notes by the Federal Revenue Service, just need to include a node with the certificate data used to sign. I showed you how to do this in the post Digital Certificate for XML inclusion with CAPICOM and Delphi.

  • That’s what you were looking for?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.