Chilkat HOME .NET Core C# Android™ AutoIt C C# C++ Chilkat2-Python CkPython Classic ASP DataFlex Delphi ActiveX Delphi DLL Go Java Lianja Mono C# Node.js Objective-C PHP ActiveX PHP Extension Perl PowerBuilder PowerShell PureBasic Ruby SQL Server Swift 2 Swift 3,4,5... Tcl Unicode C Unicode C++ VB.NET VBScript Visual Basic 6.0 Visual FoxPro Xojo Plugin
(Objective-C) Signed Zip as Base64 with XAdES-BESThis 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ć The example demonstrates the following:
This example will also show the reverse:
#import <CkoStringBuilder.h> #import <CkoZip.h> #import <CkoZipEntry.h> #import <CkoBinData.h> #import <CkoXmlDSigGen.h> #import <CkoXml.h> #import <CkoCert.h> #import <CkoXmlDSig.h> #import <NSString.h> // 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). CkoStringBuilder *sbXmlToZip = [[CkoStringBuilder alloc] init]; BOOL success = [sbXmlToZip LoadFile: @"qa_data/xml/PIT-11Z.xml" charset: @"utf-8"]; if (success != YES) { NSLog(@"%@",@"Failed to load the XML to be zipped."); return; } CkoZip *zip = [[CkoZip alloc] init]; // Initialize the zip object. No file is created in this call. // It should always return YES. success = [zip NewZip: @"PIT-11Z.zip"]; // Add the XML to be zipped. CkoZipEntry *entry = [zip AppendString: @"PIT-11Z.xml" str: [sbXmlToZip GetAsString]]; // Write the zip to a BinData object. CkoBinData *bdZip = [[CkoBinData alloc] init]; [zip WriteBd: bdZip]; // The contents of the bdZip will be retrieved in base64 format when needed below.. CkoXmlDSigGen *gen = [[CkoXmlDSigGen alloc] init]; gen.SigLocation = @""; gen.SigLocationMod = [NSNumber numberWithInt:0]; gen.SigId = @"Signature_2a8df7f8-b958-40cc-83f6-edb53b837347_19"; gen.SigNamespacePrefix = @"ds"; gen.SigNamespaceUri = @"http://www.w3.org/2000/09/xmldsig#"; gen.SigValueId = @"SignatureValue_2a8df7f8-b958-40cc-83f6-edb53b837347_52"; gen.SignedInfoId = @"SignedInfo_2a8df7f8-b958-40cc-83f6-edb53b837347_41"; gen.SignedInfoCanonAlg = @"C14N"; gen.SignedInfoDigestMethod = @"sha1"; // Set the KeyInfoId before adding references.. gen.KeyInfoId = @"KeyInfo_2a8df7f8-b958-40cc-83f6-edb53b837347_24"; // Create an Object to be added to the Signature. CkoXml *object1 = [[CkoXml alloc] init]; object1.Tag = @"xades:QualifyingProperties"; [object1 AddAttribute: @"xmlns:xades" value: @"http://uri.etsi.org/01903/v1.3.2#"]; [object1 AddAttribute: @"Id" value: @"QualifyingProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_43"]; [object1 AddAttribute: @"Target" value: @"#Signature_2a8df7f8-b958-40cc-83f6-edb53b837347_19"]; [object1 UpdateAttrAt: @"xades:SignedProperties" autoCreate: YES attrName: @"Id" attrValue: @"SignedProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_4e"]; [object1 UpdateAttrAt: @"xades:SignedProperties|xades:SignedSignatureProperties" autoCreate: YES attrName: @"Id" attrValue: @"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. [object1 UpdateChildContent: @"xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningTime" value: @"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 [object1 UpdateAttrAt: @"xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:CertDigest|ds:DigestMethod" autoCreate: YES attrName: @"Algorithm" attrValue: @"http://www.w3.org/2000/09/xmldsig#sha1"]; [object1 UpdateChildContent: @"xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:CertDigest|ds:DigestValue" value: @"TO BE GENERATED BY CHILKAT"]; [object1 UpdateChildContent: @"xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCertificateV2|xades:Cert|xades:IssuerSerialV2" value: @"TO BE GENERATED BY CHILKAT"]; [object1 UpdateAttrAt: @"xades:SignedProperties|xades:SignedDataObjectProperties" autoCreate: YES attrName: @"Id" attrValue: @"SignedDataObjectProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_4b"]; [object1 UpdateAttrAt: @"xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat" autoCreate: YES attrName: @"ObjectReference" attrValue: @"#Reference1_2a8df7f8-b958-40cc-83f6-edb53b837347_27"]; [object1 UpdateChildContent: @"xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:Description" value: @"MIME-Version: 1.0\r\nContent-Type: application/zip\r\nContent-Transfer-Encoding: binary\r\nContent-Disposition: filename="PIT-11Z.zip""]; [object1 UpdateAttrAt: @"xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:Identifier" autoCreate: YES attrName: @"Qualifier" attrValue: @"OIDAsURI"]; [object1 UpdateChildContent: @"xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:Identifier" value: @"http://www.certum.pl/OIDAsURI/signedFile/1.2.616.1.113527.3.1.1.3.1"]; [object1 UpdateChildContent: @"xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:Description" value: @"Opis formatu dokumentu oraz jego pelna nazwa"]; [object1 UpdateChildContent: @"xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:DocumentationReferences|xades:DocumentationReference" value: @"http://www.certum.pl/OIDAsURI/signedFile.pdf"]; [object1 UpdateChildContent: @"xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:MimeType" value: @"application/zip"]; [object1 UpdateChildContent: @"xades:SignedProperties|xades:SignedDataObjectProperties|xades:CommitmentTypeIndication|xades:CommitmentTypeId|xades:Identifier" value: @"http://uri.etsi.org/01903/v1.2.2#ProofOfApproval"]; [object1 UpdateChildContent: @"xades:SignedProperties|xades:SignedDataObjectProperties|xades:CommitmentTypeIndication|xades:AllSignedDataObjects" value: @""]; [object1 UpdateAttrAt: @"xades:UnsignedProperties" autoCreate: YES attrName: @"Id" attrValue: @"UnsignedProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_55"]; // Emit XML in compact (single-line) format to avoid whitespace problems. object1.EmitCompact = YES; [gen AddObject: @"" content: [object1 GetXml] mimeType: @"" encoding: @""]; // Create an Object to be added to the Signature. // This is where we add the base64 representation of the PIT-11Z.zip [gen AddObject: @"Object1_2a8df7f8-b958-40cc-83f6-edb53b837347" content: [bdZip GetEncoded: @"base64"] mimeType: @"" encoding: @"http://www.w3.org/2000/09/xmldsig#base64"]; // -------- Reference 1 -------- [gen AddObjectRef: @"Object1_2a8df7f8-b958-40cc-83f6-edb53b837347" digestMethod: @"sha1" canonMethod: @"C14N_WithComments" prefixList: @"" refType: @""]; [gen SetRefIdAttr: @"Object1_2a8df7f8-b958-40cc-83f6-edb53b837347" value: @"Reference1_2a8df7f8-b958-40cc-83f6-edb53b837347_27"]; // -------- Reference 2 -------- [gen AddObjectRef: @"SignedProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_4e" digestMethod: @"sha1" canonMethod: @"" prefixList: @"" refType: @"http://uri.etsi.org/01903#SignedProperties"]; [gen SetRefIdAttr: @"SignedProperties_2a8df7f8-b958-40cc-83f6-edb53b837347_4e" value: @"SignedProperties-Reference_2a8df7f8-b958-40cc-83f6-edb53b837347_28"]; // 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"; // 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. CkoStringBuilder *sbXml = [[CkoStringBuilder alloc] init]; // 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.) gen.Behaviors = @"AttributeSortingBug,CompactSignedXml"; // Sign the XML... success = [gen CreateXmlDSigSb: sbXml]; if (success != YES) { NSLog(@"%@",gen.LastErrorText); return; } // ----------------------------------------------- // Save the signed XML to a file. success = [sbXml WriteFile: @"qa_output/signedXml.xml" charset: @"utf-8" emitBom: NO]; NSLog(@"%@",[sbXml GetAsString]); // ---------------------------------------- // Verify the signature we just produced... CkoXmlDSig *verifier = [[CkoXmlDSig alloc] init]; success = [verifier LoadSignatureSb: sbXml]; if (success != YES) { NSLog(@"%@",verifier.LastErrorText); return; } BOOL verified = [verifier VerifySignature: YES]; if (verified != YES) { NSLog(@"%@",verifier.LastErrorText); return; } NSLog(@"%@",@"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. CkoXml *xml = [[CkoXml alloc] init]; [xml LoadSb: sbXml autoTrim: YES]; // 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.) NSString *strZipBase64 = [xml GetChildContent: @"ds:Object[1]"]; [bdZip Clear]; [bdZip AppendEncoded: strZipBase64 encoding: @"base64"]; if ([bdZip.NumBytes intValue] == 0) { NSLog(@"%@",@"Something went wrong.. we dont' have any data.."); return; } success = [zip OpenBd: bdZip]; if (success != YES) { NSLog(@"%@",zip.LastErrorText); return; } // Get the 1st file in the zip, which should be the PIT-11Z.xml entry = [zip GetEntryByIndex: [NSNumber numberWithInt: 0]]; if (zip.LastMethodSuccess != YES) { NSLog(@"%@",@"Zip contains no files..."); return; } // Get the XML: NSString *origXml = [entry UnzipToString: [NSNumber numberWithInt: 0] srcCharset: @"utf-8"]; NSLog(@"%@",@"Original XML extracted from base64 zip:"); NSLog(@"%@",origXml); |
© 2000-2024 Chilkat Software, Inc. All Rights Reserved.