Sample code for 30+ languages & platforms
PureBasic

Create JPK_VAT XaDES-BES Signed XML

See more XAdES Examples

Demonstrates how to sign XML for JPK_VAT.

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkCert.pb"
IncludeFile "CkXml.pb"
IncludeFile "CkXmlDSigGen.pb"
IncludeFile "CkXmlDSig.pb"
IncludeFile "CkStringBuilder.pb"

Procedure ChilkatExample()

    success.i = 0

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

    ; This example will sign the following XML document:

    ; <?xml version="1.0" encoding="utf-8"?>
    ; <InitUpload xmlns="http://e-dokumenty.mf.gov.pl">
    ;     <DocumentType>JPK</DocumentType>
    ;     <Version>01.02.01.20160617</Version>
    ;     <EncryptionKey algorithm="RSA" encoding="Base64" mode="ECB" padding="PKCS#1">...</EncryptionKey>
    ;     <DocumentList>
    ;         <Document>
    ;             <FormCode schemaVersion="1-1" systemCode="JPK_VAT (3)">JPK_VAT</FormCode>
    ;             <FileName>JPK_VAT_3_v1-1_20181208.xml</FileName>
    ;             <ContentLength>8736</ContentLength>
    ;             <HashValue algorithm="SHA-256" encoding="Base64">JEEI1pItwh6dj/Xe1uts/x61qnjZ4DLHpkRMhmf1oQQ=</HashValue>
    ;             <FileSignatureList filesNumber="1">
    ;                 <Packaging>
    ;                     <SplitZip mode="zip" type="split"/>
    ;                 </Packaging>
    ;                 <Encryption>
    ;                     <AES block="16" mode="CBC" padding="PKCS#7" size="256">
    ;                         <IV bytes="16" encoding="Base64">FFsCRAPYJD3J6cRvd44UDA==</IV>
    ;                     </AES>
    ;                 </Encryption>
    ;                 <FileSignature>
    ;                     <OrdinalNumber>1</OrdinalNumber>
    ;                     <FileName>JPK_VAT_3_v1-1_20181208-000.xml.zip.aes</FileName>
    ;                     <ContentLength>16</ContentLength>
    ;                     <HashValue algorithm="MD5" encoding="Base64">BX2DTD3ASC/zF6aq/012Cg==</HashValue>
    ;                 </FileSignature>
    ;             </FileSignatureList>
    ;         </Document>
    ;     </DocumentList>
    ; </InitUpload>

    ; First we build the XML to be signed.
    ; 
    ; Use this online tool to generate the code from sample XML: 
    ; Generate Code to Create XML

    success = 1
    xmlToSign.i = CkXml::ckCreate()
    If xmlToSign.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkXml::setCkTag(xmlToSign, "InitUpload")
    CkXml::ckAddAttribute(xmlToSign,"xmlns","http://e-dokumenty.mf.gov.pl")
    CkXml::ckUpdateChildContent(xmlToSign,"DocumentType","JPK")
    CkXml::ckUpdateChildContent(xmlToSign,"Version","01.02.01.20160617")
    CkXml::ckUpdateAttrAt(xmlToSign,"EncryptionKey",1,"algorithm","RSA")
    CkXml::ckUpdateAttrAt(xmlToSign,"EncryptionKey",1,"encoding","Base64")
    CkXml::ckUpdateAttrAt(xmlToSign,"EncryptionKey",1,"mode","ECB")
    CkXml::ckUpdateAttrAt(xmlToSign,"EncryptionKey",1,"padding","PKCS#1")
    CkXml::ckUpdateChildContent(xmlToSign,"EncryptionKey","...")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FormCode",1,"schemaVersion","1-1")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FormCode",1,"systemCode","JPK_VAT (3)")
    CkXml::ckUpdateChildContent(xmlToSign,"DocumentList|Document|FormCode","JPK_VAT")
    CkXml::ckUpdateChildContent(xmlToSign,"DocumentList|Document|FileName","JPK_VAT_3_v1-1_20181208.xml")
    CkXml::ckUpdateChildContent(xmlToSign,"DocumentList|Document|ContentLength","8736")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|HashValue",1,"algorithm","SHA-256")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|HashValue",1,"encoding","Base64")
    CkXml::ckUpdateChildContent(xmlToSign,"DocumentList|Document|HashValue","JEEI1pItwh6dj/Xe1uts/x61qnjZ4DLHpkRMhmf1oQQ=")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FileSignatureList",1,"filesNumber","1")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FileSignatureList|Packaging|SplitZip",1,"mode","zip")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FileSignatureList|Packaging|SplitZip",1,"type","split")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FileSignatureList|Encryption|AES",1,"block","16")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FileSignatureList|Encryption|AES",1,"mode","CBC")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FileSignatureList|Encryption|AES",1,"padding","PKCS#7")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FileSignatureList|Encryption|AES",1,"size","256")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FileSignatureList|Encryption|AES|IV",1,"bytes","16")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FileSignatureList|Encryption|AES|IV",1,"encoding","Base64")
    CkXml::ckUpdateChildContent(xmlToSign,"DocumentList|Document|FileSignatureList|Encryption|AES|IV","FFsCRAPYJD3J6cRvd44UDA==")
    CkXml::ckUpdateChildContent(xmlToSign,"DocumentList|Document|FileSignatureList|FileSignature|OrdinalNumber","1")
    CkXml::ckUpdateChildContent(xmlToSign,"DocumentList|Document|FileSignatureList|FileSignature|FileName","JPK_VAT_3_v1-1_20181208-000.xml.zip.aes")
    CkXml::ckUpdateChildContent(xmlToSign,"DocumentList|Document|FileSignatureList|FileSignature|ContentLength","16")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FileSignatureList|FileSignature|HashValue",1,"algorithm","MD5")
    CkXml::ckUpdateAttrAt(xmlToSign,"DocumentList|Document|FileSignatureList|FileSignature|HashValue",1,"encoding","Base64")
    CkXml::ckUpdateChildContent(xmlToSign,"DocumentList|Document|FileSignatureList|FileSignature|HashValue","BX2DTD3ASC/zF6aq/012Cg==")

    ; Also see the online tool to generate the code from sample already-signed XML: 
    ; Generate XML Signature Creation Code from an Already-Signed XML Sample

    gen.i = CkXmlDSigGen::ckCreate()
    If gen.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkXmlDSigGen::setCkSigLocation(gen, "InitUpload")
    CkXmlDSigGen::setCkSigId(gen, "id-1234")
    CkXmlDSigGen::setCkSigNamespacePrefix(gen, "ds")
    CkXmlDSigGen::setCkSigNamespaceUri(gen, "http://www.w3.org/2000/09/xmldsig#")
    CkXmlDSigGen::setCkSignedInfoCanonAlg(gen, "EXCL_C14N")
    CkXmlDSigGen::setCkSignedInfoDigestMethod(gen, "sha256")

    ; Create an Object to be added to the Signature.
    object1.i = CkXml::ckCreate()
    If object1.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkXml::setCkTag(object1, "xades:QualifyingProperties")
    CkXml::ckAddAttribute(object1,"Target","#id-1234")
    CkXml::ckAddAttribute(object1,"xmlns:xades","http://uri.etsi.org/01903/v1.3.2#")
    CkXml::ckUpdateAttrAt(object1,"xades:SignedProperties",1,"Id","xades-id-1234")
    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")
    CkXml::ckUpdateAttrAt(object1,"xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat",1,"ObjectReference","#r-id-1")
    CkXml::ckUpdateChildContent(object1,"xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:MimeType","text/xml")

    CkXmlDSigGen::ckAddObject(gen,"",CkXml::ckGetXml(object1),"","")

    ; -------- Reference 1 --------
    xml1.i = CkXml::ckCreate()
    If xml1.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkXml::setCkTag(xml1, "ds:Transforms")
    CkXml::ckUpdateAttrAt(xml1,"ds:Transform",1,"Algorithm","http://www.w3.org/TR/1999/REC-xpath-19991116")
    CkXml::ckUpdateChildContent(xml1,"ds:Transform|ds:XPath","not(ancestor-or-self::ds:Signature)")
    CkXml::ckUpdateAttrAt(xml1,"ds:Transform[1]",1,"Algorithm","http://www.w3.org/2001/10/xml-exc-c14n#")

    CkXmlDSigGen::ckAddSameDocRef2(gen,"","sha256",xml1,"")
    CkXmlDSigGen::ckSetRefIdAttr(gen,"","r-id-1")

    ; -------- Reference 2 --------
    xml2.i = CkXml::ckCreate()
    If xml2.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkXml::setCkTag(xml2, "ds:Transforms")
    CkXml::ckUpdateAttrAt(xml2,"ds:Transform",1,"Algorithm","http://www.w3.org/2001/10/xml-exc-c14n#")

    CkXmlDSigGen::ckAddObjectRef2(gen,"xades-id-1234","sha256",xml2,"http://uri.etsi.org/01903#SignedProperties")

    ; Provide a certificate + private key. (PFX password is test123)
    ; See Load Certificate on Smartcard for an example showing how to load the cert from a smartcard..
    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)
        CkXml::ckDispose(xmlToSign)
        CkXmlDSigGen::ckDispose(gen)
        CkXml::ckDispose(object1)
        CkXml::ckDispose(xml1)
        CkXml::ckDispose(xml2)
        CkCert::ckDispose(cert)
        ProcedureReturn
    EndIf

    CkXmlDSigGen::ckSetX509Cert(gen,cert,1)

    CkXmlDSigGen::setCkKeyInfoType(gen, "X509Data")
    CkXmlDSigGen::setCkX509Type(gen, "Certificate")

    ; Load XML to be signed...
    sbXml.i = CkStringBuilder::ckCreate()
    If sbXml.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkXml::ckGetXmlSb(xmlToSign,sbXml)

    CkXmlDSigGen::setCkBehaviors(gen, "IndentedSignature,TransformSignatureXPath,IssuerSerialHex")

    ; Sign the XML...
    success = CkXmlDSigGen::ckCreateXmlDSigSb(gen,sbXml)
    If success <> 1
        Debug CkXmlDSigGen::ckLastErrorText(gen)
        CkXml::ckDispose(xmlToSign)
        CkXmlDSigGen::ckDispose(gen)
        CkXml::ckDispose(object1)
        CkXml::ckDispose(xml1)
        CkXml::ckDispose(xml2)
        CkCert::ckDispose(cert)
        CkStringBuilder::ckDispose(sbXml)
        ProcedureReturn
    EndIf

    ; Save the signed XMl to a file.
    success = CkStringBuilder::ckWriteFile(sbXml,"qa_output/signedXml.xml","utf-8",0)

    Debug CkStringBuilder::ckGetAsString(sbXml)

    ; ----------------------------------------
    ; Verify the signature we just produced...
    verifier.i = CkXmlDSig::ckCreate()
    If verifier.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkXmlDSig::ckLoadSignatureSb(verifier,sbXml)
    If success <> 1
        Debug CkXmlDSig::ckLastErrorText(verifier)
        CkXml::ckDispose(xmlToSign)
        CkXmlDSigGen::ckDispose(gen)
        CkXml::ckDispose(object1)
        CkXml::ckDispose(xml1)
        CkXml::ckDispose(xml2)
        CkCert::ckDispose(cert)
        CkStringBuilder::ckDispose(sbXml)
        CkXmlDSig::ckDispose(verifier)
        ProcedureReturn
    EndIf

    verified.i = CkXmlDSig::ckVerifySignature(verifier,1)
    If verified <> 1
        Debug CkXmlDSig::ckLastErrorText(verifier)
        CkXml::ckDispose(xmlToSign)
        CkXmlDSigGen::ckDispose(gen)
        CkXml::ckDispose(object1)
        CkXml::ckDispose(xml1)
        CkXml::ckDispose(xml2)
        CkCert::ckDispose(cert)
        CkStringBuilder::ckDispose(sbXml)
        CkXmlDSig::ckDispose(verifier)
        ProcedureReturn
    EndIf

    Debug "This signature was successfully verified."


    CkXml::ckDispose(xmlToSign)
    CkXmlDSigGen::ckDispose(gen)
    CkXml::ckDispose(object1)
    CkXml::ckDispose(xml1)
    CkXml::ckDispose(xml2)
    CkCert::ckDispose(cert)
    CkStringBuilder::ckDispose(sbXml)
    CkXmlDSig::ckDispose(verifier)


    ProcedureReturn
EndProcedure