Create XAdES-T Signed XML
See more XAdES Examples
This example signs XML using the XAdES-T profile. XAdES-T is a profile within the XAdES standard that adds support for secure timestamping of signatures.Secure timestamping involves adding a timestamp to the signature, indicating the exact time when the signature was applied.
Timestamping enhances the long-term validity of signatures by providing evidence that the signature existed at a specific point in time, even if the signer's certificate has expired or been revoked.
XAdES-T signatures include elements for embedding timestamp data within the XML signature, along with information about the timestamp authority and the timestamp verification process.
XAdES-T signatures are suitable for scenarios where long-term validity and integrity of signatures are essential, such as in legal and regulatory contexts where archived documents may need to be validated years or decades later.
Chilkat Unicode C++ Downloads
#include <CkXmlW.h>
#include <CkXmlDSigGenW.h>
#include <CkCertW.h>
#include <CkJsonObjectW.h>
#include <CkStringBuilderW.h>
#include <CkXmlDSigW.h>
void ChilkatSample(void)
{
bool 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...
// Use this online tool to generate code from sample XML:
// Generate Code to Create XML
// <?xml version="1.0" encoding="UTF-8"?>
// <es:Dossier xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns="http://uri.etsi.org/01903/v1.3.2#" xmlns:es="https://www.microsec.hu/ds/e-szigno30#" xsi:schemaLocation="https://www.microsec.hu/ds/e-szigno30# https://www.microsec.hu/ds/e-szigno30.xsd">
// <es:DossierProfile Id="PObject0" OBJREF="Object0">
// <es:Title>e-akta.es3</es:Title>
// <es:E-category>electronic dossier</es:E-category>
// <es:CreationDate>2022-12-02T07:55:16Z</es:CreationDate>
// </es:DossierProfile>
// <es:Documents Id="Object0"/>
// </es:Dossier>
CkXmlW xmlToSign;
xmlToSign.put_Tag(L"es:Dossier");
xmlToSign.AddAttribute(L"xmlns:xsi",L"http://www.w3.org/2001/XMLSchema-instance");
xmlToSign.AddAttribute(L"xmlns:ds",L"http://www.w3.org/2000/09/xmldsig#");
xmlToSign.AddAttribute(L"xmlns",L"http://uri.etsi.org/01903/v1.3.2#");
xmlToSign.AddAttribute(L"xmlns:es",L"https://www.microsec.hu/ds/e-szigno30#");
xmlToSign.AddAttribute(L"xsi:schemaLocation",L"https://www.microsec.hu/ds/e-szigno30# https://www.microsec.hu/ds/e-szigno30.xsd");
xmlToSign.UpdateAttrAt(L"es:DossierProfile",true,L"Id",L"PObject0");
xmlToSign.UpdateAttrAt(L"es:DossierProfile",true,L"OBJREF",L"Object0");
xmlToSign.UpdateChildContent(L"es:DossierProfile|es:Title",L"e-akta.es3");
xmlToSign.UpdateChildContent(L"es:DossierProfile|es:E-category",L"electronic dossier");
xmlToSign.UpdateChildContent(L"es:DossierProfile|es:CreationDate",L"2022-12-02T07:55:16Z");
xmlToSign.UpdateAttrAt(L"es:Documents",true,L"Id",L"Object0");
CkXmlDSigGenW gen;
gen.put_SigLocation(L"es:Dossier");
gen.put_SigLocationMod(0);
gen.put_SigId(L"S9fe8096e-2cac-415d-9222-f6cf2ecb314b");
gen.put_SigValueId(L"VS9fe8096e-2cac-415d-9222-f6cf2ecb314b");
gen.put_SignedInfoId(L"SIS9fe8096e-2cac-415d-9222-f6cf2ecb314b");
gen.put_SignedInfoCanonAlg(L"EXCL_C14N");
gen.put_SignedInfoDigestMethod(L"sha256");
// Set the KeyInfoId before adding references..
gen.put_KeyInfoId(L"KS9fe8096e-2cac-415d-9222-f6cf2ecb314b");
// Create an Object to be added to the Signature.
CkXmlW object1;
object1.put_Tag(L"es:SignatureProfile");
object1.AddAttribute(L"Id",L"PS9fe8096e-2cac-415d-9222-f6cf2ecb314b");
object1.AddAttribute(L"OBJREF",L"Object0");
object1.AddAttribute(L"SIGREF",L"S9fe8096e-2cac-415d-9222-f6cf2ecb314b");
object1.AddAttribute(L"SIGREFLIST",L"#Object0 #PS9fe8096e-2cac-415d-9222-f6cf2ecb314b #PObject0 #XS9fe8096e-2cac-415d-9222-f6cf2ecb314b");
object1.UpdateChildContent(L"es:SignerName",L"EC Minősített-Tesztelő Péterke");
object1.UpdateChildContent(L"es:SDPresented",L"false");
object1.UpdateChildContent(L"es:Type",L"signature");
object1.UpdateAttrAt(L"es:Generator|es:Program",true,L"name",L"e-Szigno");
object1.UpdateAttrAt(L"es:Generator|es:Program",true,L"version",L"3.3.6.8");
object1.UpdateAttrAt(L"es:Generator|es:Device",true,L"name",L"OpenSSL 1.1.1n 15 Mar 2022");
object1.UpdateAttrAt(L"es:Generator|es:Device",true,L"type",L"");
gen.AddObject(L"O1S9fe8096e-2cac-415d-9222-f6cf2ecb314b",object1.getXml(),L"",L"");
// Create an Object to be added to the Signature.
CkXmlW object2;
object2.put_Tag(L"QualifyingProperties");
object2.AddAttribute(L"Target",L"#S9fe8096e-2cac-415d-9222-f6cf2ecb314b");
object2.AddAttribute(L"Id",L"QPS9fe8096e-2cac-415d-9222-f6cf2ecb314b");
object2.UpdateAttrAt(L"SignedProperties",true,L"Id",L"XS9fe8096e-2cac-415d-9222-f6cf2ecb314b");
object2.UpdateChildContent(L"SignedProperties|SignedSignatureProperties|SigningTime",L"TO BE GENERATED BY CHILKAT");
object2.UpdateAttrAt(L"SignedProperties|SignedSignatureProperties|SigningCertificateV2|Cert|CertDigest|ds:DigestMethod",true,L"Algorithm",L"http://www.w3.org/2001/04/xmlenc#sha256");
object2.UpdateChildContent(L"SignedProperties|SignedSignatureProperties|SigningCertificateV2|Cert|CertDigest|ds:DigestValue",L"TO BE GENERATED BY CHILKAT");
object2.UpdateChildContent(L"SignedProperties|SignedSignatureProperties|SigningCertificateV2|Cert|IssuerSerialV2",L"TO BE GENERATED BY CHILKAT");
object2.UpdateChildContent(L"SignedProperties|SignedSignatureProperties|SignaturePolicyIdentifier|SignaturePolicyImplied",L"");
object2.UpdateChildContent(L"SignedProperties|SignedSignatureProperties|SignerRoleV2|ClaimedRoles|ClaimedRole",L"tesztelő");
// Here we have the EncapsulatedTimestamp found in the unsigned signature properties.
object2.UpdateAttrAt(L"UnsignedProperties|UnsignedSignatureProperties|SignatureTimeStamp",true,L"Id",L"T72cb4961-4326-4319-857a-7cf55e7ef899");
object2.UpdateAttrAt(L"UnsignedProperties|UnsignedSignatureProperties|SignatureTimeStamp|ds:CanonicalizationMethod",true,L"Algorithm",L"http://www.w3.org/2001/10/xml-exc-c14n#");
object2.UpdateAttrAt(L"UnsignedProperties|UnsignedSignatureProperties|SignatureTimeStamp|EncapsulatedTimeStamp",true,L"Id",L"ET72cb4961-4326-4319-857a-7cf55e7ef899");
object2.UpdateChildContent(L"UnsignedProperties|UnsignedSignatureProperties|SignatureTimeStamp|EncapsulatedTimeStamp",L"TO BE GENERATED BY CHILKAT");
object2.UpdateAttrAt(L"UnsignedProperties|UnsignedSignatureProperties|TimeStampValidationData",true,L"xmlns",L"http://uri.etsi.org/01903/v1.4.1#");
object2.UpdateAttrAt(L"UnsignedProperties|UnsignedSignatureProperties|CertificateValues",true,L"Id",L"CV18c7702d-d45b-44bc-853a-a720f41053cd");
object2.UpdateAttrAt(L"UnsignedProperties|UnsignedSignatureProperties|CertificateValues|EncapsulatedX509Certificate",true,L"Id",L"EC42db04c8-1422-407b-8c42-189353a55268");
object2.UpdateChildContent(L"UnsignedProperties|UnsignedSignatureProperties|CertificateValues|EncapsulatedX509Certificate",L"BASE64_CONTENT");
object2.UpdateAttrAt(L"UnsignedProperties|UnsignedSignatureProperties|CertificateValues|EncapsulatedX509Certificate[1]",true,L"Id",L"EC04728b44-a32c-46c1-b9bb-85b1f6b3c7d3");
object2.UpdateChildContent(L"UnsignedProperties|UnsignedSignatureProperties|CertificateValues|EncapsulatedX509Certificate[1]",L"BASE64_CONTENT");
gen.AddObject(L"O2S9fe8096e-2cac-415d-9222-f6cf2ecb314b",object2.getXml(),L"",L"");
// -------- Reference 1 --------
gen.AddSameDocRef(L"Object0",L"sha256",L"EXCL_C14N",L"",L"");
gen.SetRefIdAttr(L"Object0",L"Re1f816c4-7898-4544-9b41-f4156dc0c528");
// -------- Reference 2 --------
gen.AddObjectRef(L"PS9fe8096e-2cac-415d-9222-f6cf2ecb314b",L"sha256",L"EXCL_C14N",L"",L"");
gen.SetRefIdAttr(L"PS9fe8096e-2cac-415d-9222-f6cf2ecb314b",L"Ra873b616-e568-4c38-ae94-27fbff67cc43");
// -------- Reference 3 --------
gen.AddSameDocRef(L"PObject0",L"sha256",L"EXCL_C14N",L"",L"");
gen.SetRefIdAttr(L"PObject0",L"Ra5d85948-5d6a-4914-8c32-242f5d6d9e81");
// -------- Reference 4 --------
gen.AddObjectRef(L"XS9fe8096e-2cac-415d-9222-f6cf2ecb314b",L"sha256",L"EXCL_C14N",L"",L"http://uri.etsi.org/01903#SignedProperties");
gen.SetRefIdAttr(L"XS9fe8096e-2cac-415d-9222-f6cf2ecb314b",L"Ra7412a43-dc05-4e0a-ac84-e9a070214757");
// Provide a certificate + private key. (PFX password is test123)
CkCertW cert;
success = cert.LoadPfxFile(L"qa_data/pfx/cert_test123.pfx",L"test123");
if (success != true) {
wprintf(L"%s\n",cert.lastErrorText());
return;
}
gen.SetX509Cert(cert,true);
gen.put_KeyInfoType(L"X509Data");
gen.put_X509Type(L"Certificate");
// -------------------------------------------------------------------------------------------
// To have the EncapsulatedTimeStamp automatically added, we only need to do 2 things.
// 1) Add the <xades:EncapsulatedTimeStamp Encoding="http://uri.etsi.org/01903/v1.2.2#DER">TO BE GENERATED BY CHILKAT</xades:EncapsulatedTimeStamp>
// to the unsigned properties.
// 2) Specify the TSA URL (Timestamping Authority URL).
// Here we specify the TSA URL:
// -------------------------------------------------------------------------------------------
CkJsonObjectW jsonTsa;
jsonTsa.UpdateString(L"timestampToken.tsaUrl",L"http://timestamp.digicert.com");
jsonTsa.UpdateBool(L"timestampToken.requestTsaCert",true);
gen.SetTsa(jsonTsa);
// Load XML to be signed...
CkStringBuilderW sbXml;
xmlToSign.GetXmlSb(sbXml);
gen.put_Behaviors(L"IndentedSignature,OmitAlreadyDefinedSigNamespace");
// Sign the XML...
success = gen.CreateXmlDSigSb(sbXml);
if (success != true) {
wprintf(L"%s\n",gen.lastErrorText());
return;
}
// -----------------------------------------------
// Save the signed XML to a file.
success = sbXml.WriteFile(L"c:/temp/qa_output/signedXml.xml",L"utf-8",false);
wprintf(L"%s\n",sbXml.getAsString());
// ----------------------------------------
// Verify the signatures we just produced...
CkXmlDSigW verifier;
success = verifier.LoadSignatureSb(sbXml);
if (success != true) {
wprintf(L"%s\n",verifier.lastErrorText());
return;
}
int numSigs = verifier.get_NumSignatures();
int verifyIdx = 0;
while (verifyIdx < numSigs) {
verifier.put_Selector(verifyIdx);
bool verified = verifier.VerifySignature(true);
if (verified != true) {
wprintf(L"%s\n",verifier.lastErrorText());
return;
}
verifyIdx = verifyIdx + 1;
}
wprintf(L"All signatures were successfully verified.\n");
}