PureBasic
PureBasic
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 PureBasic Downloads
IncludeFile "CkJsonObject.pb"
IncludeFile "CkHttp.pb"
IncludeFile "CkXml.pb"
IncludeFile "CkXmlDSigGen.pb"
IncludeFile "CkStringBuilder.pb"
IncludeFile "CkCert.pb"
Procedure ChilkatExample()
success.i = 0
; This example requires the Chilkat API to have been previously unlocked.
; See Global Unlock Sample for sample code.
success = 1
; 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.)
sbXml.i = CkStringBuilder::ckCreate()
If sbXml.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
success = CkStringBuilder::ckLoadFile(sbXml,"xmlToSign.xml","utf-8")
gen.i = CkXmlDSigGen::ckCreate()
If gen.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkXmlDSigGen::setCkSigLocation(gen, "TransakcniLogSystemu")
CkXmlDSigGen::setCkSigLocationMod(gen, 0)
CkXmlDSigGen::setCkSigId(gen, "SignatureID-Signature1")
CkXmlDSigGen::setCkSigNamespacePrefix(gen, "ds")
CkXmlDSigGen::setCkSigNamespaceUri(gen, "http://www.w3.org/2000/09/xmldsig#")
CkXmlDSigGen::setCkSignedInfoCanonAlg(gen, "C14N")
CkXmlDSigGen::setCkSignedInfoDigestMethod(gen, "sha256")
; Set the KeyInfoId before adding references..
CkXmlDSigGen::setCkKeyInfoId(gen, "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.
object1.i = CkXml::ckCreate()
If object1.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkXml::setCkTag(object1, "xades:QualifyingProperties")
CkXml::ckAddAttribute(object1,"xmlns:xades","http://uri.etsi.org/01903/v1.3.2#")
CkXml::ckAddAttribute(object1,"Target","#Signature1")
CkXml::ckUpdateAttrAt(object1,"xades:SignedProperties",1,"Id","SignedProperties-Signature-Signature1")
CkXml::ckUpdateChildContent(object1,"xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningTime","TO BE GENERATED BY CHILKAT")
CkXml::ckUpdateAttrAt(object1,"xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:CertDigest|ds:DigestMethod",1,"Algorithm","http://www.w3.org/2001/04/xmlenc#sha256")
CkXml::ckUpdateChildContent(object1,"xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:CertDigest|ds:DigestValue","TO BE GENERATED BY CHILKAT")
CkXml::ckUpdateChildContent(object1,"xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:IssuerSerialV2","TO BE GENERATED BY CHILKAT")
; The EncapsulatedTimestamp will be included in the unsigned properties.
CkXml::ckUpdateAttrAt(object1,"xades:UnsignedProperties|xades:UnsignedSignatureProperties|xades:SignatureTimeStamp",1,"Id","signature-timestamp-5561-8212-3316-5191")
CkXml::ckUpdateAttrAt(object1,"xades:UnsignedProperties|xades:UnsignedSignatureProperties|xades:SignatureTimeStamp|ds:CanonicalizationMethod",1,"Algorithm","http://www.w3.org/2001/10/xml-exc-c14n#")
CkXml::ckUpdateAttrAt(object1,"xades:UnsignedProperties|xades:UnsignedSignatureProperties|xades:SignatureTimeStamp|xades:EncapsulatedTimeStamp",1,"Encoding","http://uri.etsi.org/01903/v1.2.2#DER")
CkXml::ckUpdateChildContent(object1,"xades:UnsignedProperties|xades:UnsignedSignatureProperties|xades:SignatureTimeStamp|xades:EncapsulatedTimeStamp","TO BE GENERATED BY CHILKAT")
CkXmlDSigGen::ckAddObject(gen,"XadesObjectId-Signature1",CkXml::ckGetXml(object1),"","")
; -------- Reference 1 --------
CkXmlDSigGen::ckAddObjectRef(gen,"SignedProperties-Signature-Signature1","sha256","EXCL_C14N","","http://uri.etsi.org/01903#SignedProperties")
; -------- Reference 2 --------
CkXmlDSigGen::ckAddSameDocRef(gen,"KeyInfoId-Signature-Signature1","sha256","EXCL_C14N","","")
CkXmlDSigGen::ckSetRefIdAttr(gen,"KeyInfoId-Signature-Signature1","ReferenceKeyInfo")
; -------- Reference 3 --------
CkXmlDSigGen::ckAddSameDocRef(gen,"","sha256","EXCL_C14N","","")
CkXmlDSigGen::ckSetRefIdAttr(gen,"","Reference-Signature1")
; Provide a certificate + private key. (PFX password is test123)
cert.i = CkCert::ckCreate()
If cert.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
success = CkCert::ckLoadPfxFile(cert,"qa_data/pfx/cert_test123.pfx","test123")
If success <> 1
Debug CkCert::ckLastErrorText(cert)
CkStringBuilder::ckDispose(sbXml)
CkXmlDSigGen::ckDispose(gen)
CkXml::ckDispose(object1)
CkCert::ckDispose(cert)
ProcedureReturn
EndIf
CkXmlDSigGen::ckSetX509Cert(gen,cert,1)
CkXmlDSigGen::setCkKeyInfoType(gen, "X509Data")
CkXmlDSigGen::setCkX509Type(gen, "Certificate")
CkXmlDSigGen::setCkBehaviors(gen, "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:
; -------------------------------------------------------------------------------------------
jsonTsa.i = CkJsonObject::ckCreate()
If jsonTsa.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkJsonObject::ckUpdateString(jsonTsa,"timestampToken.tsaUrl","https://www3.postsignum.cz/TSS/TSS_crt/")
CkJsonObject::ckUpdateBool(jsonTsa,"timestampToken.requestTsaCert",1)
CkXmlDSigGen::ckSetTsa(gen,jsonTsa)
; -------------------------------------------------------------------------------------------
; 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.
; -------------------------------------------------------------------------------------------
http.i = CkHttp::ckCreate()
If http.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
success = CkHttp::ckSetSslClientCertPfx(http,"/home/bob/pfxFiles/myClientSideCertWithPrivateKey.pfx","pfxPassword")
If success <> 1
Debug CkHttp::ckLastErrorText(http)
CkStringBuilder::ckDispose(sbXml)
CkXmlDSigGen::ckDispose(gen)
CkXml::ckDispose(object1)
CkCert::ckDispose(cert)
CkJsonObject::ckDispose(jsonTsa)
CkHttp::ckDispose(http)
ProcedureReturn
EndIf
; Tell the XmlDSigGen object to use the above HTTP object for TSA communications.
CkXmlDSigGen::ckSetHttpObj(gen,http)
; Sign the XML...
success = CkXmlDSigGen::ckCreateXmlDSigSb(gen,sbXml)
If success <> 1
Debug CkXmlDSigGen::ckLastErrorText(gen)
CkStringBuilder::ckDispose(sbXml)
CkXmlDSigGen::ckDispose(gen)
CkXml::ckDispose(object1)
CkCert::ckDispose(cert)
CkJsonObject::ckDispose(jsonTsa)
CkHttp::ckDispose(http)
ProcedureReturn
EndIf
; -----------------------------------------------
; Save the signed XML to a file.
success = CkStringBuilder::ckWriteFile(sbXml,"c:/temp/qa_output/signedXml.xml","utf-8",0)
Debug CkStringBuilder::ckGetAsString(sbXml)
CkStringBuilder::ckDispose(sbXml)
CkXmlDSigGen::ckDispose(gen)
CkXml::ckDispose(object1)
CkCert::ckDispose(cert)
CkJsonObject::ckDispose(jsonTsa)
CkHttp::ckDispose(http)
ProcedureReturn
EndProcedure