Tcl
Tcl
Signed Zip as Base64 with XAdES-BES
See more XAdES Examples
This example is to help companies implement a solution for sending XAdES-BES to the Polish government for reporting purposes. Specifically:Przed podpisaniem deklaracja zbiorcza (PIT-11Z, PIT-8CZ, PIT-40Z, PIT-RZ) musi zostać
umieszczona w archiwum ZIP. W tym przypadku, podpisywany jest plik archiwum ZIP,
przyjmujący w podpisie XAdES-BES formę zakodowaną base64.
The example demonstrates the following:
- Zip an XML file (PIT-11Z.xml is zipped to PIT-11Z.zip)
- Create XML to be signed, where the XML contains the base64 encoded content of the PIT-11Z.zip archive.
- XAdES-BES sign the XML containing the base64 zip.
This example will also show the reverse:
- Verify the signed XML.
- Extract the PIT-11z.zip from the signed XML.
- Unzip the PIT-11Z.zip to get the original PIT-11Z.xml
Chilkat Tcl Downloads
load ./chilkat.dll
set success 0
# This example assumes the Chilkat API to have been previously unlocked.
# See Global Unlock Sample for sample code.
# Zip the PIT-11Z.xml to create PIT-11Z.zip (not as a .zip file, but in-memory).
set sbXmlToZip [new_CkStringBuilder]
set success [CkStringBuilder_LoadFile $sbXmlToZip "qa_data/xml/PIT-11Z.xml" "utf-8"]
if {$success != 1} then {
puts "Failed to load the XML to be zipped."
delete_CkStringBuilder $sbXmlToZip
exit
}
set zip [new_CkZip]
# Initialize the zip object. No file is created in this call.
# It should always return 1.
set success [CkZip_NewZip $zip "PIT-11Z.zip"]
# Add the XML to be zipped.
CkZip_AddSb $zip "PIT-11Z.xml" $sbXmlToZip "utf-8"
# Write the zip to a BinData object.
set bdZip [new_CkBinData]
CkZip_WriteBd $zip $bdZip
# The contents of the bdZip will be retrieved in base64 format when needed below..
set gen [new_CkXmlDSigGen]
CkXmlDSigGen_put_SigLocation $gen ""
CkXmlDSigGen_put_SigLocationMod $gen 0
CkXmlDSigGen_put_SigId $gen "Signature_2a8df7f8-b958-40cc-83f6-edb53b837347_19"
CkXmlDSigGen_put_SigNamespacePrefix $gen "ds"
CkXmlDSigGen_put_SigNamespaceUri $gen "http://www.w3.org/2000/09/xmldsig#"
CkXmlDSigGen_put_SigValueId $gen "SignatureValue_2a8df7f8-b958-40cc-83f6-edb53b837347_52"
CkXmlDSigGen_put_SignedInfoId $gen "SignedInfo_2a8df7f8-b958-40cc-83f6-edb53b837347_41"
CkXmlDSigGen_put_SignedInfoCanonAlg $gen "C14N"
CkXmlDSigGen_put_SignedInfoDigestMethod $gen "sha1"
# Set the KeyInfoId before adding references..
CkXmlDSigGen_put_KeyInfoId $gen "KeyInfo_2a8df7f8-b958-40cc-83f6-edb53b837347_24"
# Create an Object to be added to the Signature.
set object1 [new_CkXml]
CkXml_put_Tag $object1 "xades:QualifyingProperties"
CkXml_AddAttribute $object1 "xmlns:xades" "http://uri.etsi.org/01903/v1.3.2#"
CkXml_AddAttribute $object1 "Id" "QualifyingProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_43"
CkXml_AddAttribute $object1 "Target" "#Signature_2a8df7f8-b958-40cc-83f6-edb53b837347_19"
CkXml_UpdateAttrAt $object1 "xades:SignedProperties" 1 "Id" "SignedProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_4e"
CkXml_UpdateAttrAt $object1 "xades:SignedProperties|xades:SignedSignatureProperties" 1 "Id" "SignedSignatureProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_0a"
# Chilkat will replace the strings "TO BE GENERATED BY CHILKAT" with actual values when the signature is created.
CkXml_UpdateChildContent $object1 "xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningTime" "TO BE GENERATED BY CHILKAT"
# Note: It may be that http://www.w3.org/2001/04/xmlenc#sha256 is needed in the following line instead of http://www.w3.org/2000/09/xmldsig#sha1
CkXml_UpdateAttrAt $object1 "xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:CertDigest|ds:DigestMethod" 1 "Algorithm" "http://www.w3.org/2000/09/xmldsig#sha1"
CkXml_UpdateChildContent $object1 "xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:CertDigest|ds:DigestValue" "TO BE GENERATED BY CHILKAT"
CkXml_UpdateChildContent $object1 "xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:IssuerSerialV2" "TO BE GENERATED BY CHILKAT"
CkXml_UpdateAttrAt $object1 "xades:SignedProperties|xades:SignedDataObjectProperties" 1 "Id" "SignedDataObjectProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_4b"
CkXml_UpdateAttrAt $object1 "xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat" 1 "ObjectReference" "#Reference1_2a8df7f8-b958-40cc-83f6-edb53b837347_27"
CkXml_UpdateChildContent $object1 "xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:Description" "MIME-Version: 1.0\r\nContent-Type: application/zip\r\nContent-Transfer-Encoding: binary\r\nContent-Disposition: filename="PIT-11Z.zip""
CkXml_UpdateAttrAt $object1 "xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:Identifier" 1 "Qualifier" "OIDAsURI"
CkXml_UpdateChildContent $object1 "xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:Identifier" "http://www.certum.pl/OIDAsURI/signedFile/1.2.616.1.113527.3.1.1.3.1"
CkXml_UpdateChildContent $object1 "xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:Description" "Opis formatu dokumentu oraz jego pelna nazwa"
CkXml_UpdateChildContent $object1 "xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:DocumentationReferences|xades:DocumentationReference" "http://www.certum.pl/OIDAsURI/signedFile.pdf"
CkXml_UpdateChildContent $object1 "xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:MimeType" "application/zip"
CkXml_UpdateChildContent $object1 "xades:SignedProperties|xades:SignedDataObjectProperties|xades:CommitmentTypeIndication|xades:CommitmentTypeId|xades:Identifier" "http://uri.etsi.org/01903/v1.2.2#ProofOfApproval"
CkXml_UpdateChildContent $object1 "xades:SignedProperties|xades:SignedDataObjectProperties|xades:CommitmentTypeIndication|xades:AllSignedDataObjects" ""
CkXml_UpdateAttrAt $object1 "xades:UnsignedProperties" 1 "Id" "UnsignedProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_55"
# Emit XML in compact (single-line) format to avoid whitespace problems.
CkXml_put_EmitCompact $object1 1
CkXmlDSigGen_AddObject $gen "" [CkXml_getXml $object1] "" ""
# Create an Object to be added to the Signature.
# This is where we add the base64 representation of the PIT-11Z.zip
CkXmlDSigGen_AddObject $gen "Object1_2a8df7f8-b958-40cc-83f6-edb53b837347" [CkBinData_getEncoded $bdZip "base64"] "" "http://www.w3.org/2000/09/xmldsig#base64"
# -------- Reference 1 --------
CkXmlDSigGen_AddObjectRef $gen "Object1_2a8df7f8-b958-40cc-83f6-edb53b837347" "sha1" "C14N_WithComments" "" ""
CkXmlDSigGen_SetRefIdAttr $gen "Object1_2a8df7f8-b958-40cc-83f6-edb53b837347" "Reference1_2a8df7f8-b958-40cc-83f6-edb53b837347_27"
# -------- Reference 2 --------
CkXmlDSigGen_AddObjectRef $gen "SignedProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_4e" "sha1" "" "" "http://uri.etsi.org/01903#SignedProperties"
CkXmlDSigGen_SetRefIdAttr $gen "SignedProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_4e" "SignedProperties-Reference_2a8df7f8-b958-40cc-83f6-edb53b837347_28"
# Provide a certificate + private key. (PFX password is test123)
set cert [new_CkCert]
set success [CkCert_LoadPfxFile $cert "qa_data/pfx/cert_test123.pfx" "test123"]
if {$success == 0} then {
puts [CkCert_lastErrorText $cert]
delete_CkStringBuilder $sbXmlToZip
delete_CkZip $zip
delete_CkBinData $bdZip
delete_CkXmlDSigGen $gen
delete_CkXml $object1
delete_CkCert $cert
exit
}
CkXmlDSigGen_SetX509Cert $gen $cert 1
CkXmlDSigGen_put_KeyInfoType $gen "X509Data"
CkXmlDSigGen_put_X509Type $gen "Certificate"
# This will be an enveloping signature where the Signature element
# is the XML document root, the signed data is contained within Object
# tag(s) within the Signature.
# Therefore, pass an empty sbXml to CreateXmlDsigSb.
set sbXml [new_CkStringBuilder]
# The Polish government's XmlDSig implementation requires that we reproduce an attribute-sorting error.
# (This is an error in the XML canonicalization that is not noticed when both the signature-creation code and signature-verification code use
# the same XML canonicalization implementation w/ the bug.)
CkXmlDSigGen_put_Behaviors $gen "AttributeSortingBug,CompactSignedXml"
# Sign the XML...
set success [CkXmlDSigGen_CreateXmlDSigSb $gen $sbXml]
if {$success == 0} then {
puts [CkXmlDSigGen_lastErrorText $gen]
delete_CkStringBuilder $sbXmlToZip
delete_CkZip $zip
delete_CkBinData $bdZip
delete_CkXmlDSigGen $gen
delete_CkXml $object1
delete_CkCert $cert
delete_CkStringBuilder $sbXml
exit
}
# -----------------------------------------------
# Save the signed XML to a file.
set success [CkStringBuilder_WriteFile $sbXml "qa_output/signedXml.xml" "utf-8" 0]
puts [CkStringBuilder_getAsString $sbXml]
# ----------------------------------------
# Verify the signature we just produced...
set verifier [new_CkXmlDSig]
set success [CkXmlDSig_LoadSignatureSb $verifier $sbXml]
if {$success == 0} then {
puts [CkXmlDSig_lastErrorText $verifier]
delete_CkStringBuilder $sbXmlToZip
delete_CkZip $zip
delete_CkBinData $bdZip
delete_CkXmlDSigGen $gen
delete_CkXml $object1
delete_CkCert $cert
delete_CkStringBuilder $sbXml
delete_CkXmlDSig $verifier
exit
}
set verified [CkXmlDSig_VerifySignature $verifier 1]
if {$verified != 1} then {
puts [CkXmlDSig_lastErrorText $verifier]
delete_CkStringBuilder $sbXmlToZip
delete_CkZip $zip
delete_CkBinData $bdZip
delete_CkXmlDSigGen $gen
delete_CkXml $object1
delete_CkCert $cert
delete_CkStringBuilder $sbXml
delete_CkXmlDSig $verifier
exit
}
puts "This signature was successfully verified."
# ------------------------------------
# Finally, let's extract the .zip from the signed XML, and then unzip the original PIT-11Z.xml from the in-memory zip.
set xml [new_CkXml]
CkXml_LoadSb $xml $sbXml 1
# The base64 image of the PIT-11Z.zip is in the 2nd ds:Object child of the ds:Signature (the ds:Signature is the root element of the signed XML).
# (ds:Object[0] would be the 1st ds:Object child. Index 1 is the 2nd ds:Object child.)
set strZipBase64 [CkXml_getChildContent $xml "ds:Object[1]"]
CkBinData_Clear $bdZip
CkBinData_AppendEncoded $bdZip $strZipBase64 "base64"
if {[CkBinData_get_NumBytes $bdZip] == 0} then {
puts "Something went wrong.. we dont' have any data.."
delete_CkStringBuilder $sbXmlToZip
delete_CkZip $zip
delete_CkBinData $bdZip
delete_CkXmlDSigGen $gen
delete_CkXml $object1
delete_CkCert $cert
delete_CkStringBuilder $sbXml
delete_CkXmlDSig $verifier
delete_CkXml $xml
exit
}
set success [CkZip_OpenBd $zip $bdZip]
if {$success == 0} then {
puts [CkZip_lastErrorText $zip]
delete_CkStringBuilder $sbXmlToZip
delete_CkZip $zip
delete_CkBinData $bdZip
delete_CkXmlDSigGen $gen
delete_CkXml $object1
delete_CkCert $cert
delete_CkStringBuilder $sbXml
delete_CkXmlDSig $verifier
delete_CkXml $xml
exit
}
# Get the 1st file in the zip, which should be the PIT-11Z.xml
set entry [new_CkZipEntry]
set success [CkZip_EntryAt $zip 0 $entry]
if {$success == 0} then {
puts "Zip contains no files..."
delete_CkStringBuilder $sbXmlToZip
delete_CkZip $zip
delete_CkBinData $bdZip
delete_CkXmlDSigGen $gen
delete_CkXml $object1
delete_CkCert $cert
delete_CkStringBuilder $sbXml
delete_CkXmlDSig $verifier
delete_CkXml $xml
delete_CkZipEntry $entry
exit
}
# Get the XML:
set origXml [CkZipEntry_unzipToString $entry 0 "utf-8"]
puts "Original XML extracted from base64 zip:"
puts "$origXml"
delete_CkStringBuilder $sbXmlToZip
delete_CkZip $zip
delete_CkBinData $bdZip
delete_CkXmlDSigGen $gen
delete_CkXml $object1
delete_CkCert $cert
delete_CkStringBuilder $sbXml
delete_CkXmlDSig $verifier
delete_CkXml $xml
delete_CkZipEntry $entry