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 Objective-C Downloads
#import <CkoXml.h>
#import <CkoXmlDSigGen.h>
#import <CkoCert.h>
#import <CkoJsonObject.h>
#import <CkoStringBuilder.h>
#import <CkoXmlDSig.h>
BOOL success = NO;
// This example requires the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.
success = YES;
// 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>
CkoXml *xmlToSign = [[CkoXml alloc] init];
xmlToSign.Tag = @"es:Dossier";
[xmlToSign AddAttribute: @"xmlns:xsi" value: @"http://www.w3.org/2001/XMLSchema-instance"];
[xmlToSign AddAttribute: @"xmlns:ds" value: @"http://www.w3.org/2000/09/xmldsig#"];
[xmlToSign AddAttribute: @"xmlns" value: @"http://uri.etsi.org/01903/v1.3.2#"];
[xmlToSign AddAttribute: @"xmlns:es" value: @"https://www.microsec.hu/ds/e-szigno30#"];
[xmlToSign AddAttribute: @"xsi:schemaLocation" value: @"https://www.microsec.hu/ds/e-szigno30# https://www.microsec.hu/ds/e-szigno30.xsd"];
[xmlToSign UpdateAttrAt: @"es:DossierProfile" autoCreate: YES attrName: @"Id" attrValue: @"PObject0"];
[xmlToSign UpdateAttrAt: @"es:DossierProfile" autoCreate: YES attrName: @"OBJREF" attrValue: @"Object0"];
[xmlToSign UpdateChildContent: @"es:DossierProfile|es:Title" value: @"e-akta.es3"];
[xmlToSign UpdateChildContent: @"es:DossierProfile|es:E-category" value: @"electronic dossier"];
[xmlToSign UpdateChildContent: @"es:DossierProfile|es:CreationDate" value: @"2022-12-02T07:55:16Z"];
[xmlToSign UpdateAttrAt: @"es:Documents" autoCreate: YES attrName: @"Id" attrValue: @"Object0"];
CkoXmlDSigGen *gen = [[CkoXmlDSigGen alloc] init];
gen.SigLocation = @"es:Dossier";
gen.SigLocationMod = [NSNumber numberWithInt:0];
gen.SigId = @"S9fe8096e-2cac-415d-9222-f6cf2ecb314b";
gen.SigValueId = @"VS9fe8096e-2cac-415d-9222-f6cf2ecb314b";
gen.SignedInfoId = @"SIS9fe8096e-2cac-415d-9222-f6cf2ecb314b";
gen.SignedInfoCanonAlg = @"EXCL_C14N";
gen.SignedInfoDigestMethod = @"sha256";
// Set the KeyInfoId before adding references..
gen.KeyInfoId = @"KS9fe8096e-2cac-415d-9222-f6cf2ecb314b";
// Create an Object to be added to the Signature.
CkoXml *object1 = [[CkoXml alloc] init];
object1.Tag = @"es:SignatureProfile";
[object1 AddAttribute: @"Id" value: @"PS9fe8096e-2cac-415d-9222-f6cf2ecb314b"];
[object1 AddAttribute: @"OBJREF" value: @"Object0"];
[object1 AddAttribute: @"SIGREF" value: @"S9fe8096e-2cac-415d-9222-f6cf2ecb314b"];
[object1 AddAttribute: @"SIGREFLIST" value: @"#Object0 #PS9fe8096e-2cac-415d-9222-f6cf2ecb314b #PObject0 #XS9fe8096e-2cac-415d-9222-f6cf2ecb314b"];
[object1 UpdateChildContent: @"es:SignerName" value: @"EC Minősített-Tesztelő Péterke"];
[object1 UpdateChildContent: @"es:SDPresented" value: @"false"];
[object1 UpdateChildContent: @"es:Type" value: @"signature"];
[object1 UpdateAttrAt: @"es:Generator|es:Program" autoCreate: YES attrName: @"name" attrValue: @"e-Szigno"];
[object1 UpdateAttrAt: @"es:Generator|es:Program" autoCreate: YES attrName: @"version" attrValue: @"3.3.6.8"];
[object1 UpdateAttrAt: @"es:Generator|es:Device" autoCreate: YES attrName: @"name" attrValue: @"OpenSSL 1.1.1n 15 Mar 2022"];
[object1 UpdateAttrAt: @"es:Generator|es:Device" autoCreate: YES attrName: @"type" attrValue: @""];
[gen AddObject: @"O1S9fe8096e-2cac-415d-9222-f6cf2ecb314b" content: [object1 GetXml] mimeType: @"" encoding: @""];
// Create an Object to be added to the Signature.
CkoXml *object2 = [[CkoXml alloc] init];
object2.Tag = @"QualifyingProperties";
[object2 AddAttribute: @"Target" value: @"#S9fe8096e-2cac-415d-9222-f6cf2ecb314b"];
[object2 AddAttribute: @"Id" value: @"QPS9fe8096e-2cac-415d-9222-f6cf2ecb314b"];
[object2 UpdateAttrAt: @"SignedProperties" autoCreate: YES attrName: @"Id" attrValue: @"XS9fe8096e-2cac-415d-9222-f6cf2ecb314b"];
[object2 UpdateChildContent: @"SignedProperties|SignedSignatureProperties|SigningTime" value: @"TO BE GENERATED BY CHILKAT"];
[object2 UpdateAttrAt: @"SignedProperties|SignedSignatureProperties|SigningCertificateV2|Cert|CertDigest|ds:DigestMethod" autoCreate: YES attrName: @"Algorithm" attrValue: @"http://www.w3.org/2001/04/xmlenc#sha256"];
[object2 UpdateChildContent: @"SignedProperties|SignedSignatureProperties|SigningCertificateV2|Cert|CertDigest|ds:DigestValue" value: @"TO BE GENERATED BY CHILKAT"];
[object2 UpdateChildContent: @"SignedProperties|SignedSignatureProperties|SigningCertificateV2|Cert|IssuerSerialV2" value: @"TO BE GENERATED BY CHILKAT"];
[object2 UpdateChildContent: @"SignedProperties|SignedSignatureProperties|SignaturePolicyIdentifier|SignaturePolicyImplied" value: @""];
[object2 UpdateChildContent: @"SignedProperties|SignedSignatureProperties|SignerRoleV2|ClaimedRoles|ClaimedRole" value: @"tesztelő"];
// Here we have the EncapsulatedTimestamp found in the unsigned signature properties.
[object2 UpdateAttrAt: @"UnsignedProperties|UnsignedSignatureProperties|SignatureTimeStamp" autoCreate: YES attrName: @"Id" attrValue: @"T72cb4961-4326-4319-857a-7cf55e7ef899"];
[object2 UpdateAttrAt: @"UnsignedProperties|UnsignedSignatureProperties|SignatureTimeStamp|ds:CanonicalizationMethod" autoCreate: YES attrName: @"Algorithm" attrValue: @"http://www.w3.org/2001/10/xml-exc-c14n#"];
[object2 UpdateAttrAt: @"UnsignedProperties|UnsignedSignatureProperties|SignatureTimeStamp|EncapsulatedTimeStamp" autoCreate: YES attrName: @"Id" attrValue: @"ET72cb4961-4326-4319-857a-7cf55e7ef899"];
[object2 UpdateChildContent: @"UnsignedProperties|UnsignedSignatureProperties|SignatureTimeStamp|EncapsulatedTimeStamp" value: @"TO BE GENERATED BY CHILKAT"];
[object2 UpdateAttrAt: @"UnsignedProperties|UnsignedSignatureProperties|TimeStampValidationData" autoCreate: YES attrName: @"xmlns" attrValue: @"http://uri.etsi.org/01903/v1.4.1#"];
[object2 UpdateAttrAt: @"UnsignedProperties|UnsignedSignatureProperties|CertificateValues" autoCreate: YES attrName: @"Id" attrValue: @"CV18c7702d-d45b-44bc-853a-a720f41053cd"];
[object2 UpdateAttrAt: @"UnsignedProperties|UnsignedSignatureProperties|CertificateValues|EncapsulatedX509Certificate" autoCreate: YES attrName: @"Id" attrValue: @"EC42db04c8-1422-407b-8c42-189353a55268"];
[object2 UpdateChildContent: @"UnsignedProperties|UnsignedSignatureProperties|CertificateValues|EncapsulatedX509Certificate" value: @"BASE64_CONTENT"];
[object2 UpdateAttrAt: @"UnsignedProperties|UnsignedSignatureProperties|CertificateValues|EncapsulatedX509Certificate[1]" autoCreate: YES attrName: @"Id" attrValue: @"EC04728b44-a32c-46c1-b9bb-85b1f6b3c7d3"];
[object2 UpdateChildContent: @"UnsignedProperties|UnsignedSignatureProperties|CertificateValues|EncapsulatedX509Certificate[1]" value: @"BASE64_CONTENT"];
[gen AddObject: @"O2S9fe8096e-2cac-415d-9222-f6cf2ecb314b" content: [object2 GetXml] mimeType: @"" encoding: @""];
// -------- Reference 1 --------
[gen AddSameDocRef: @"Object0" digestMethod: @"sha256" canonMethod: @"EXCL_C14N" prefixList: @"" refType: @""];
[gen SetRefIdAttr: @"Object0" value: @"Re1f816c4-7898-4544-9b41-f4156dc0c528"];
// -------- Reference 2 --------
[gen AddObjectRef: @"PS9fe8096e-2cac-415d-9222-f6cf2ecb314b" digestMethod: @"sha256" canonMethod: @"EXCL_C14N" prefixList: @"" refType: @""];
[gen SetRefIdAttr: @"PS9fe8096e-2cac-415d-9222-f6cf2ecb314b" value: @"Ra873b616-e568-4c38-ae94-27fbff67cc43"];
// -------- Reference 3 --------
[gen AddSameDocRef: @"PObject0" digestMethod: @"sha256" canonMethod: @"EXCL_C14N" prefixList: @"" refType: @""];
[gen SetRefIdAttr: @"PObject0" value: @"Ra5d85948-5d6a-4914-8c32-242f5d6d9e81"];
// -------- Reference 4 --------
[gen AddObjectRef: @"XS9fe8096e-2cac-415d-9222-f6cf2ecb314b" digestMethod: @"sha256" canonMethod: @"EXCL_C14N" prefixList: @"" refType: @"http://uri.etsi.org/01903#SignedProperties"];
[gen SetRefIdAttr: @"XS9fe8096e-2cac-415d-9222-f6cf2ecb314b" value: @"Ra7412a43-dc05-4e0a-ac84-e9a070214757"];
// Provide a certificate + private key. (PFX password is test123)
CkoCert *cert = [[CkoCert alloc] init];
success = [cert LoadPfxFile: @"qa_data/pfx/cert_test123.pfx" password: @"test123"];
if (success != YES) {
NSLog(@"%@",cert.LastErrorText);
return;
}
[gen SetX509Cert: cert usePrivateKey: YES];
gen.KeyInfoType = @"X509Data";
gen.X509Type = @"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:
// -------------------------------------------------------------------------------------------
CkoJsonObject *jsonTsa = [[CkoJsonObject alloc] init];
[jsonTsa UpdateString: @"timestampToken.tsaUrl" value: @"http://timestamp.digicert.com"];
[jsonTsa UpdateBool: @"timestampToken.requestTsaCert" value: YES];
[gen SetTsa: jsonTsa];
// Load XML to be signed...
CkoStringBuilder *sbXml = [[CkoStringBuilder alloc] init];
[xmlToSign GetXmlSb: sbXml];
gen.Behaviors = @"IndentedSignature,OmitAlreadyDefinedSigNamespace";
// Sign the XML...
success = [gen CreateXmlDSigSb: sbXml];
if (success != YES) {
NSLog(@"%@",gen.LastErrorText);
return;
}
// -----------------------------------------------
// Save the signed XML to a file.
success = [sbXml WriteFile: @"c:/temp/qa_output/signedXml.xml" charset: @"utf-8" emitBom: NO];
NSLog(@"%@",[sbXml GetAsString]);
// ----------------------------------------
// Verify the signatures we just produced...
CkoXmlDSig *verifier = [[CkoXmlDSig alloc] init];
success = [verifier LoadSignatureSb: sbXml];
if (success != YES) {
NSLog(@"%@",verifier.LastErrorText);
return;
}
int numSigs = [verifier.NumSignatures intValue];
int verifyIdx = 0;
while (verifyIdx < numSigs) {
verifier.Selector = [NSNumber numberWithInt: verifyIdx];
BOOL verified = [verifier VerifySignature: YES];
if (verified != YES) {
NSLog(@"%@",verifier.LastErrorText);
return;
}
verifyIdx = verifyIdx + 1;
}
NSLog(@"%@",@"All signatures were successfully verified.");