Sample code for 30+ languages & platforms
Zig

XAdES using TSA Requiring Client Certificate

See more XML Digital Signatures Examples

Demonstrates how to create an XMLDSig (XAdES) signed document which includes an EncapsulatedTimestamp using a TSA (TimeStamp Authority) server requiring client certificate authentication. One such TSA is https://www3.postsignum.cz/TSS/TSS_crt/

Chilkat Zig Downloads

Zig
const std = @import("std");
const chilkat = @import("chilkat");

pub fn main(init: std.process.Init) !void {
    const alloc = init.arena.allocator();

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

    // Load the XML to be signed.  For example, the XML to be signed might contain something like this:

    // <?xml version="1.0" encoding="utf-8"?>
    // <TransakcniLogSystemu xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://nsess.public.cz/erms_trans/v_01_01" Id="Signature1">
    //   <TransLogInfo>
    //     <Identifikator>XYZ ABC</Identifikator>
    //     <DatumVzniku>2022-12-20T14:39:02.3625922+01:00</DatumVzniku>
    //     <DatumCasOd>2022-12-20T14:26:26.88</DatumCasOd>
    //     <DatumCasDo>2022-12-20T14:39:02.287</DatumCasDo>
    //     <Software>XYZ</Software>
    //     <VerzeSoftware>2.0.19.32</VerzeSoftware>
    //   </TransLogInfo>
    //   <Udalosti>
    //     <Udalost>
    //       <Poradi>1</Poradi>
    // ...

    // Load the XML to be signed from a file.
    // (XML can be loaded from other source, such as a string variable.)
    const sb_xml = try chilkat.StringBuilder.init();
    defer sb_xml.deinit();
    try sb_xml.loadFile("xmlToSign.xml", "utf-8");

    const gen = try chilkat.XmlDSigGen.init();
    defer gen.deinit();

    gen.setSigLocation("TransakcniLogSystemu");
    gen.setSigLocationMod(0);
    gen.setSigId("SignatureID-Signature1");
    gen.setSigNamespacePrefix("ds");
    gen.setSigNamespaceUri("http://www.w3.org/2000/09/xmldsig#");
    gen.setSignedInfoCanonAlg("C14N");
    gen.setSignedInfoDigestMethod("sha256");

    // Set the KeyInfoId before adding references..
    gen.setKeyInfoId("KeyInfoId-Signature-Signature1");

    // Create an Object to be added to the Signature.

    // Note: Chilkat will automatically fill in the values marked as "TO BE GENERATED BY CHILKAT" at the time of signing.
    // The EncapsulatedTimestamp will be automatically generated.

    const object1 = try chilkat.Xml.init();
    defer object1.deinit();
    object1.setTag("xades:QualifyingProperties");
    object1.addAttribute("xmlns:xades", "http://uri.etsi.org/01903/v1.3.2#") catch {};
    object1.addAttribute("Target", "#Signature1") catch {};

    object1.updateAttrAt("xades:SignedProperties", true, "Id", "SignedProperties-Signature-Signature1") catch {};
    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#sha256") catch {};
    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");

    // The EncapsulatedTimestamp will be included in the unsigned properties.
    object1.updateAttrAt("xades:UnsignedProperties|xades:UnsignedSignatureProperties|xades:SignatureTimeStamp", true, "Id", "signature-timestamp-5561-8212-3316-5191") catch {};
    object1.updateAttrAt("xades:UnsignedProperties|xades:UnsignedSignatureProperties|xades:SignatureTimeStamp|ds:CanonicalizationMethod", true, "Algorithm", "http://www.w3.org/2001/10/xml-exc-c14n#") catch {};
    object1.updateAttrAt("xades:UnsignedProperties|xades:UnsignedSignatureProperties|xades:SignatureTimeStamp|xades:EncapsulatedTimeStamp", true, "Encoding", "http://uri.etsi.org/01903/v1.2.2#DER") catch {};
    object1.updateChildContent("xades:UnsignedProperties|xades:UnsignedSignatureProperties|xades:SignatureTimeStamp|xades:EncapsulatedTimeStamp", "TO BE GENERATED BY CHILKAT");

    gen.addObject("XadesObjectId-Signature1", try object1.getXml(alloc), "", "") catch {};

    // -------- Reference 1 --------
    gen.addObjectRef("SignedProperties-Signature-Signature1", "sha256", "EXCL_C14N", "", "http://uri.etsi.org/01903#SignedProperties") catch {};

    // -------- Reference 2 --------
    gen.addSameDocRef("KeyInfoId-Signature-Signature1", "sha256", "EXCL_C14N", "", "") catch {};
    gen.setRefIdAttr("KeyInfoId-Signature-Signature1", "ReferenceKeyInfo") catch {};

    // -------- Reference 3 --------
    gen.addSameDocRef("", "sha256", "EXCL_C14N", "", "") catch {};
    gen.setRefIdAttr("", "Reference-Signature1") catch {};

    // Provide a certificate + private key. (PFX password is test123)
    const cert = try chilkat.Cert.init();
    defer cert.deinit();
    cert.loadPfxFile("qa_data/pfx/cert_test123.pfx", "test123") catch {
        std.debug.print("{s}\n", .{try cert.getLastErrorText(alloc)});
        return;
    };

    gen.setX509Cert(cert, true) catch {};

    gen.setKeyInfoType("X509Data");
    gen.setX509Type("Certificate");

    gen.setBehaviors("IndentedSignature");

    // -------------------------------------------------------------------------------------------
    // To have the EncapsulatedTimeStamp automatically added...
    // 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.  (This was accomplished in the above code.)
    // 2) Specify the TSA URL (Timestamping Authority URL).
    //    Here we specify the TSA URL:
    // -------------------------------------------------------------------------------------------

    const json_tsa = try chilkat.JsonObject.init();
    defer json_tsa.deinit();
    json_tsa.updateString("timestampToken.tsaUrl", "https://www3.postsignum.cz/TSS/TSS_crt/") catch {};
    json_tsa.updateBool("timestampToken.requestTsaCert", true) catch {};
    gen.setTsa(json_tsa) catch {};

    // -------------------------------------------------------------------------------------------
    // In this case, the TSA requires client certificate authentication.
    // To provide your client certificate, the application will instantiate a Chilkat HTTP object,
    // then set it up with a SSL/TLS client certificate, and then tell the XmlDSigGen object
    // to use the HTTP object for connections to the TSA server.
    // -------------------------------------------------------------------------------------------
    const http = try chilkat.Http.init();
    defer http.deinit();
    http.setSslClientCertPfx("/home/bob/pfxFiles/myClientSideCertWithPrivateKey.pfx", "pfxPassword") catch {
        std.debug.print("{s}\n", .{try http.getLastErrorText(alloc)});
        return;
    };

    // Tell the XmlDSigGen object to use the above HTTP object for TSA communications.
    gen.setHttpObj(http);

    // Sign the XML...
    gen.createXmlDSigSb(sb_xml) catch {
        std.debug.print("{s}\n", .{try gen.getLastErrorText(alloc)});
        return;
    };

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

    // Save the signed XML to a file.
    try sb_xml.writeFile("c:/temp/qa_output/signedXml.xml", "utf-8", false);

    std.debug.print("{s}\n", .{try sb_xml.getAsString(alloc)});
}