Pascal (Lazarus/Delphi)
Pascal (Lazarus/Delphi)
XML Signature Multiple External References
See more XML Digital Signatures Examples
Demonstrates how to add multiple external references to an XML digital signature.Chilkat Pascal (Lazarus/Delphi) Downloads
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.XmlDSigGen,
Chilkat.XmlDSig,
Chilkat.StringBuilder,
Chilkat.BinData,
Chilkat.Cert,
Chilkat.Http,
Chilkat.Xml;
// ---------------------------------------------------------------------------
procedure RunDemo;
var
success: Boolean;
gen: TXmlDSigGen;
object1: TXml;
http: THttp;
bd: TBinData;
url: string;
cert: TCert;
sbXml: TStringBuilder;
verifier: TXmlDSig;
verified: Boolean;
begin
success := False;
// This example requires the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.
// This example creates the following signed XML with multiple external references:
// <?xml version="1.0" encoding="UTF-8"?>
// <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4">
// <ds:SignedInfo>
// <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
// <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
// <ds:Reference Id="xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-ref0" URI="https://isus.ezdrowie.gov.pl/fhir/Patient/123/_history/456">
// <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
// <ds:DigestValue>...</ds:DigestValue>
// </ds:Reference>
// <ds:Reference Id="xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-ref1" URI="https://isus.ezdrowie.gov.pl/fhir/Encounter/124/_history/22">
// <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
// <ds:DigestValue>...</ds:DigestValue>
// </ds:Reference>
// <ds:Reference Id="xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-ref2" URI="https://isus.ezdrowie.gov.pl/fhir/Condition/125/_history/1">
// <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
// <ds:DigestValue>...</ds:DigestValue>
// </ds:Reference>
// <ds:Reference Id="xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-ref3" URI="https://isus.ezdrowie.gov.pl/fhir/Procedure/126/_history/1">
// <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
// <ds:DigestValue>...</ds:DigestValue>
// </ds:Reference>
// <ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-signedprops">
// <ds:Transforms>
// <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
// </ds:Transforms>
// <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
// <ds:DigestValue>...</ds:DigestValue>
// </ds:Reference>
// </ds:SignedInfo>
// <ds:SignatureValue Id="xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-sigvalue">...</ds:SignatureValue>
// <ds:KeyInfo>
// <ds:X509Data>
// <ds:X509Certificate>...</ds:X509Certificate>
// <ds:X509SubjectName>...</ds:X509SubjectName>
// <ds:X509IssuerSerial>
// <ds:X509IssuerName>...</ds:X509IssuerName>
// <ds:X509SerialNumber>...</ds:X509SerialNumber>
// </ds:X509IssuerSerial>
// </ds:X509Data>
// </ds:KeyInfo>
// <ds:Object>
// <xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" Target="#xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4">
// <xades:SignedProperties Id="xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-signedprops">
// <xades:SignedSignatureProperties>
// <xades:SigningTime>2021-06-02T07:10:13.306+02:00</xades:SigningTime>
// <xades:SigningCertificate>
// <xades:Cert>
// <xades:CertDigest>
// <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
// <ds:DigestValue>...</ds:DigestValue>
// </xades:CertDigest>
// <xades:IssuerSerial>
// <ds:X509IssuerName>...</ds:X509IssuerName>
// <ds:X509SerialNumber>...</ds:X509SerialNumber>
// </xades:IssuerSerial>
// </xades:Cert>
// <xades:Cert>
// <xades:CertDigest>
// <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
// <ds:DigestValue>...</ds:DigestValue>
// </xades:CertDigest>
// <xades:IssuerSerial>
// <ds:X509IssuerName>...</ds:X509IssuerName>
// <ds:X509SerialNumber>...</ds:X509SerialNumber>
// </xades:IssuerSerial>
// </xades:Cert>
// <xades:Cert>
// <xades:CertDigest>
// <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
// <ds:DigestValue>...</ds:DigestValue>
// </xades:CertDigest>
// <xades:IssuerSerial>
// <ds:X509IssuerName>...</ds:X509IssuerName>
// <ds:X509SerialNumber>...</ds:X509SerialNumber>
// </xades:IssuerSerial>
// </xades:Cert>
// </xades:SigningCertificate>
// </xades:SignedSignatureProperties>
// </xades:SignedProperties>
// </xades:QualifyingProperties>
// </ds:Object>
// </ds:Signature>
//
success := True;
gen := TXmlDSigGen.Create;
gen.SigLocation := '';
gen.SigLocationMod := 0;
// Note: ID's simply need to be unique values in the signed XML document. They don't necessarily need to be GUID/UUID formatted.
gen.SigId := 'xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4';
gen.SigNamespacePrefix := 'ds';
gen.SigNamespaceUri := 'http://www.w3.org/2000/09/xmldsig#';
gen.SigValueId := 'xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-sigvalue';
gen.SignedInfoCanonAlg := 'C14N';
gen.SignedInfoDigestMethod := 'sha256';
// 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('xmlns:xades141','http://uri.etsi.org/01903/v1.4.1#');
object1.AddAttribute('Target','#xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4');
object1.UpdateAttrAt('xades:SignedProperties',True,'Id','xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-signedprops');
object1.UpdateChildContent('xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningTime','TO BE GENERATED BY CHILKAT');
// This assumes there are 3 certs in the certificate chain: The signing certificate, an intermediate root, and the root CA.
// Remove the lines with "Cert[2]" if there is no intermediate root...
object1.UpdateAttrAt('xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:CertDigest|ds:DigestMethod',True,'Algorithm','http://www.w3.org/2001/04/xmlenc#sha256');
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');
gen.AddObject('',object1.GetXml(),'','');
http := THttp.Create;
bd := TBinData.Create;
url := 'https://isus.ezdrowie.gov.pl/fhir/Patient/123/_history/456';
success := http.QuickGetBd(url,bd);
if (success <> True) then
begin
WriteLn(http.LastErrorText);
Exit;
end;
// -------- Reference 1 --------
gen.AddExternalBinaryRef(url,bd,'sha256','');
gen.SetRefIdAttr(url,'xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-ref0');
// -------- Reference 2 --------
bd.Clear();
url := 'https://isus.ezdrowie.gov.pl/fhir/Encounter/789/_history/1';
success := http.QuickGetBd(url,bd);
if (success <> True) then
begin
WriteLn(http.LastErrorText);
Exit;
end;
gen.AddExternalBinaryRef(url,bd,'sha256','');
gen.SetRefIdAttr(url,'xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-ref1');
// -------- Reference 3 --------
bd.Clear();
url := 'https://isus.ezdrowie.gov.pl/fhir/Condition/123456/_history/1';
success := http.QuickGetBd(url,bd);
if (success <> True) then
begin
WriteLn(http.LastErrorText);
Exit;
end;
gen.AddExternalBinaryRef(url,bd,'sha256','');
gen.SetRefIdAttr(url,'xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-ref2');
// -------- Reference 4 --------
bd.Clear();
url := 'https://isus.ezdrowie.gov.pl/fhir/Procedure/123456/_history/1';
success := http.QuickGetBd(url,bd);
if (success <> True) then
begin
WriteLn(http.LastErrorText);
Exit;
end;
gen.AddExternalBinaryRef(url,bd,'sha256','');
gen.SetRefIdAttr(url,'xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-ref3');
// -------- Reference 5 --------
gen.AddObjectRef('xmldsig-2dde88a8-def0-43e4-8570-b031015a46b4-signedprops','sha256','C14N','','http://uri.etsi.org/01903#SignedProperties');
// 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';
gen.X509Type := 'IssuerSerial,SubjectName,Certificate';
// This will be an enveloping signature where the Signature element
// is the XML document root, the signed data is contained within Object
// tag(s) within the Signature.
// Therefore, pass an empty sbXml to CreateXmlDsigSb.
sbXml := TStringBuilder.Create;
gen.Behaviors := 'IndentedSignature';
// 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.xml','utf-8',False);
WriteLn(sbXml.GetAsString());
// ----------------------------------------
// Verify the signature we just produced...
verifier := TXmlDSig.Create;
success := verifier.LoadSignatureSb(sbXml);
if (success <> True) then
begin
WriteLn(verifier.LastErrorText);
Exit;
end;
verified := verifier.VerifySignature(True);
if (verified <> True) then
begin
WriteLn(verifier.LastErrorText);
Exit;
end;
WriteLn('This signature was successfully verified.');
gen.Free;
object1.Free;
http.Free;
bd.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.