Sample code for 30+ languages & platforms
Pascal (Lazarus/Delphi)

TicketBAI Sign XML Example 2

See more TicketBAI Examples

Second example to demonstrate how to sign XML for TicketBAI.

Chilkat Pascal (Lazarus/Delphi) Downloads

Pascal (Lazarus/Delphi)
program ChilkatDemo;

// Demonstrates using the Chilkat Pascal wrapper via the C bridge DLL.
// Builds as a console application under Lazarus (FPC) or Delphi.

{$IFDEF FPC}
  {$MODE DELPHI}
{$ENDIF}
{$APPTYPE CONSOLE}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  SysUtils,
  CkDllLoader,
  Chilkat.StringBuilder,
  Chilkat.XmlDSigGen,
  Chilkat.Xml,
  Chilkat.XmlDSig,
  Chilkat.Cert;

// ---------------------------------------------------------------------------

procedure RunDemo;
var
  success: Boolean;
  xmlToSign: TXml;
  gen: TXmlDSigGen;
  object1: TXml;
  cert: TCert;
  sbXml: TStringBuilder;
  verifier: TXmlDSig;
  numSigs: Integer;
  verifyIdx: Integer;
  verified: Boolean;

begin
  success := False;

  //  This example requires the Chilkat API to have been previously unlocked.
  //  See Global Unlock Sample for sample code.

  success := True;
  //  Create the XML to be signed...
  xmlToSign := TXml.Create;
  xmlToSign.Tag := 'T:TicketBai';
  xmlToSign.AddAttribute('xmlns:T','urn:ticketbai:emision');
  xmlToSign.UpdateChildContent('Cabecera|IDVersionTBAI','1.2');
  xmlToSign.UpdateChildContent('Sujetos|Emisor|NIF','79732487C');
  xmlToSign.UpdateChildContent('Sujetos|Emisor|ApellidosNombreRazonSocial','ARRIOLA LEJARDI ANE');
  xmlToSign.UpdateChildContent('Sujetos|Destinatarios|IDDestinatario|NIF','A48012363');
  xmlToSign.UpdateChildContent('Sujetos|Destinatarios|IDDestinatario|ApellidosNombreRazonSocial','ACADEMIA ESKOLA');
  xmlToSign.UpdateChildContent('Factura|CabeceraFactura|SerieFactura','A2022');
  xmlToSign.UpdateChildContent('Factura|CabeceraFactura|NumFactura','0400');
  xmlToSign.UpdateChildContent('Factura|CabeceraFactura|FechaExpedicionFactura','12-05-2022');
  xmlToSign.UpdateChildContent('Factura|CabeceraFactura|HoraExpedicionFactura','12:20:15');
  xmlToSign.UpdateChildContent('Factura|DatosFactura|DescripcionFactura','Venta maquinaria y existencias');
  xmlToSign.UpdateChildContent('Factura|DatosFactura|ImporteTotalFactura','1936.00');
  xmlToSign.UpdateChildContent('Factura|DatosFactura|Claves|IDClave|ClaveRegimenIvaOpTrascendencia','01');
  xmlToSign.UpdateChildContent('Factura|TipoDesglose|DesgloseFactura|Sujeta|NoExenta|DetalleNoExenta|TipoNoExenta','S1');
  xmlToSign.UpdateChildContent('Factura|TipoDesglose|DesgloseFactura|Sujeta|NoExenta|DetalleNoExenta|DesgloseIVA|DetalleIVA|BaseImponible','1600.00');
  xmlToSign.UpdateChildContent('Factura|TipoDesglose|DesgloseFactura|Sujeta|NoExenta|DetalleNoExenta|DesgloseIVA|DetalleIVA|TipoImpositivo','21.00');
  xmlToSign.UpdateChildContent('Factura|TipoDesglose|DesgloseFactura|Sujeta|NoExenta|DetalleNoExenta|DesgloseIVA|DetalleIVA|CuotaImpuesto','336.00');
  xmlToSign.UpdateChildContent('HuellaTBAI|EncadenamientoFacturaAnterior|SerieFacturaAnterior','A2022');
  xmlToSign.UpdateChildContent('HuellaTBAI|EncadenamientoFacturaAnterior|NumFacturaAnterior','0399');
  xmlToSign.UpdateChildContent('HuellaTBAI|EncadenamientoFacturaAnterior|FechaExpedicionFacturaAnterior','06-05-2022');
  xmlToSign.UpdateChildContent('HuellaTBAI|EncadenamientoFacturaAnterior|SignatureValueFirmaFacturaAnterior','KdxKFNXeNJuBZNjgvKEa9lICamXs9MHuin6R+yuFHZw9aMewuBvdhaMr7g0eUz8aNYEa1elpCTr7aLgVZjQrFQK/TjIg353iAVxA');
  xmlToSign.UpdateChildContent('HuellaTBAI|Software|LicenciaTBAI','TBAIPRUEBA');
  xmlToSign.UpdateChildContent('HuellaTBAI|Software|EntidadDesarrolladora|NIF','A48119820');
  xmlToSign.UpdateChildContent('HuellaTBAI|Software|Nombre','DFBTBAI');
  xmlToSign.UpdateChildContent('HuellaTBAI|Software|Version','1.04.00');
  xmlToSign.UpdateChildContent('HuellaTBAI|NumSerieDispositivo','GP4FC5J');

  gen := TXmlDSigGen.Create;

  gen.SigLocation := 'T:TicketBai';
  gen.SigLocationMod := 0;
  gen.SigId := 'Signature-43861174-a0e6-45f9-afbf-8b48c46c6c13-Signature';
  gen.SigNamespacePrefix := 'ds';
  gen.SigNamespaceUri := 'http://www.w3.org/2000/09/xmldsig#';
  gen.SigValueId := 'Signature-43861174-a0e6-45f9-afbf-8b48c46c6c13-SignatureValue';
  gen.SignedInfoCanonAlg := 'C14N';
  gen.SignedInfoDigestMethod := 'sha256';

  //  Set the KeyInfoId before adding references..
  gen.KeyInfoId := 'Signature-43861174-a0e6-45f9-afbf-8b48c46c6c13-KeyInfo';

  //  Create an Object to be added to the Signature.
  object1 := TXml.Create;
  object1.Tag := 'xades:QualifyingProperties';
  object1.AddAttribute('xmlns:xades','http://uri.etsi.org/01903/v1.3.2#');
  object1.AddAttribute('Id','Signature-43861174-a0e6-45f9-afbf-8b48c46c6c13-QualifyingProperties');
  object1.AddAttribute('Target','#Signature-43861174-a0e6-45f9-afbf-8b48c46c6c13-Signature');
  object1.AddAttribute('xmlns:ds','http://www.w3.org/2000/09/xmldsig#');
  object1.UpdateAttrAt('xades:SignedProperties',True,'Id','Signature-43861174-a0e6-45f9-afbf-8b48c46c6c13-SignedProperties');
  object1.UpdateChildContent('xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningTime','TO BE GENERATED BY CHILKAT');
  object1.UpdateAttrAt('xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:CertDigest|ds:DigestMethod',True,'Algorithm','http://www.w3.org/2001/04/xmlenc#sha512');
  object1.UpdateChildContent('xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:CertDigest|ds:DigestValue','TO BE GENERATED BY CHILKAT');
  object1.UpdateChildContent('xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:IssuerSerialV2','TO BE GENERATED BY CHILKAT');
  object1.UpdateChildContent('xades:SignedProperties|xades:SignedSignatureProperties|xades:SignaturePolicyIdentifier|xades:SignaturePolicyId|xades:SigPolicyId|xades:Identifier','https://www.batuz.eus/fitxategiak/batuz/ticketbai/sinadura_elektronikoaren_zehaztapenak_especificaciones_de_la_firma_electronica_v1_0.pdf');
  object1.UpdateChildContent('xades:SignedProperties|xades:SignedSignatureProperties|xades:SignaturePolicyIdentifier|xades:SignaturePolicyId|xades:SigPolicyId|xades:Description','');
  object1.UpdateAttrAt('xades:SignedProperties|xades:SignedSignatureProperties|xades:SignaturePolicyIdentifier|xades:SignaturePolicyId|xades:SigPolicyHash|ds:DigestMethod',True,'Algorithm','http://www.w3.org/2001/04/xmlenc#sha256');
  object1.UpdateChildContent('xades:SignedProperties|xades:SignedSignatureProperties|xades:SignaturePolicyIdentifier|xades:SignaturePolicyId|xades:SigPolicyHash|ds:DigestValue','Quzn98x3PMbSHwbUzaj5f5KOpiH0u8bvmwbbbNkO9Es=');
  object1.UpdateChildContent('xades:SignedProperties|xades:SignedSignatureProperties|xades:SignaturePolicyIdentifier|xades:SignaturePolicyId|xades:SigPolicyQualifiers|xades:SigPolicyQualifier|xades:SPURI','https://www.batuz.eus/fitxategiak/batuz/ticketbai/sinadura_elektronikoaren_zehaztapenak_especificaciones_de_la_firma_electronica_v1_0.pdf');
  object1.UpdateAttrAt('xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat',True,'ObjectReference','#Reference-43b5c8a3-7ce0-4056-bdbe-d2076d8ac825');
  object1.UpdateChildContent('xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:Description','');
  object1.UpdateAttrAt('xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:Identifier',True,'Qualifier','OIDAsURN');
  object1.UpdateChildContent('xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:Identifier','urn:oid:1.2.840.10003.5.109.10');
  object1.UpdateChildContent('xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:Description','');
  object1.UpdateChildContent('xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:MimeType','text/xml');
  object1.UpdateChildContent('xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:Encoding','');

  gen.AddObject('',object1.GetXml(),'','');

  //  -------- Reference 1 --------
  gen.AddSameDocRef('','sha512','C14N','','http://www.w3.org/2000/09/xmldsig#Object');
  gen.SetRefIdAttr('','Reference-43b5c8a3-7ce0-4056-bdbe-d2076d8ac825');

  //  -------- Reference 2 --------
  gen.AddObjectRef('Signature-43861174-a0e6-45f9-afbf-8b48c46c6c13-SignedProperties','sha512','','','http://uri.etsi.org/01903#SignedProperties');

  //  -------- Reference 3 --------
  gen.AddSameDocRef('Signature-43861174-a0e6-45f9-afbf-8b48c46c6c13-KeyInfo','sha512','','','');

  //  Provide a certificate + private key. (PFX password is test123)
  cert := TCert.Create;
  success := cert.LoadPfxFile('qa_data/pfx/cert_test123.pfx','test123');
  if (success <> True) then
    begin
      WriteLn(cert.LastErrorText);
      Exit;
    end;
  gen.SetX509Cert(cert,True);

  gen.KeyInfoType := 'X509Data+KeyValue';
  gen.X509Type := 'Certificate';

  //  Load XML to be signed...
  sbXml := TStringBuilder.Create;
  xmlToSign.GetXmlSb(sbXml);

  gen.Behaviors := 'IndentedSignature,TransformSignatureXPath';

  //  Sign the XML...
  success := gen.CreateXmlDSigSb(sbXml);
  if (success <> True) then
    begin
      WriteLn(gen.LastErrorText);
      Exit;
    end;
  //  -----------------------------------------------

  //  Save the signed XML to a file.
  success := sbXml.WriteFile('qa_output/signedXml_2.xml','utf-8',False);

  WriteLn(sbXml.GetAsString());

  //  ----------------------------------------
  //  Verify the signatures we just produced...
  verifier := TXmlDSig.Create;
  success := verifier.LoadSignatureSb(sbXml);
  if (success <> True) then
    begin
      WriteLn(verifier.LastErrorText);
      Exit;
    end;

  numSigs := verifier.NumSignatures;
  verifyIdx := 0;
  while verifyIdx < numSigs do
    begin
      verifier.Selector := verifyIdx;
      verified := verifier.VerifySignature(True);
      if (verified <> True) then
        begin
          WriteLn(verifier.LastErrorText);
          Exit;
        end;
      verifyIdx := verifyIdx + 1;
    end;

  WriteLn('All signatures were successfully verified.');


  xmlToSign.Free;
  gen.Free;
  object1.Free;
  cert.Free;
  sbXml.Free;
  verifier.Free;

end;

// ---------------------------------------------------------------------------

begin

  try
    RunDemo;
  except
    on E: Exception do
      WriteLn('Unhandled exception: ', E.ClassName, ': ', E.Message);
  end;

  WriteLn;
  {$IFDEF MSWINDOWS}
  WriteLn('Press Enter to exit...');
  ReadLn;
  {$ENDIF}
end.