Implementing XAdES signing of data using SecureBlackbox

Working with XAdES

An XAdES (XML Advanced Electronic Signatures) is built upon XML-DSig (XML Digital Signatures) by adding additional information qualifying the signature and the signed data. This qualifying information is arranged in so called “qualifying properties” which are added to the signature as data object. “Qualifying properties“ consist from signed and unsigned properties.

SecureBlackbox has a following component to manage XML-DSig and XAdES signatures: TElXMLSigner and TElXMLVerifier components are capable of creating and verifying XML-DSig signature. TElXAdESSigner and TElXAdESVerifier components are capable for creating, extending and verifying XAdES info. They are used together with TElXMLSigner or TElXMLVerifier components.

XAdES components support all XAdES versions: 1.1.1, 1.2.2, 1.3.2, 1.4.1 (aka 1.4.2), and all XAdES forms: XAdES. XAdES-BES. -EPES, -T, -C, -X, -X-L. -A. They can also extend XAdES signature of a "lower" form (e.g. XAdES-EPES) to an "upper" form (e.g. XAdES-A).

Below you will find the code snippets that illustrate how to create and extend general XAdES signature and a collection of code snippets that illustrate creating/extending each XAdES form.


Content

Creating XAdES signature

This sample shows creation of enveloped XML-DSig signature with XAdES info, though the same components can be used to sign any type of data. XML-DSig signature may be detached from or attached to signed data, may be enveloping (when it contains the signed data within itself) or enveloped (when it comprises a part of the document containing the signed data).

[Delphi]

  1. [Delphi]
  2.  
  3. <span class="comment">// Creating an instance of XML-DSig signer.</span>
  4. Signer := TElXMLSigner.Create(<span class="keyword">nil</span>);
  5. <span class="comment">// Creating an instance of XAdES signer.</span>
  6. XAdESSigner := TElXAdESSigner.Create(<span class="keyword">nil</span>);
  7. <span class="comment">// Setup XAdES processor</span>
  8. Signer.XAdESProcessor := XAdESSigner;
  9. <span class="keyword">try</span>
  10. <span class="comment">// adding a references. For example, adding a reference for a document element.</span>
  11. Ref := TElXMLReference.Create();
  12. Ref.TransformChain.Add(TElXMLEnvelopedSignatureTransform.Create);
  13. Ref.URI := <span class="string">''</span>;
  14. Ref.URINode := XMLDocument.DocumentElement;
  15. Signer.References.Add(Ref);
  16. &nbsp;
  17. <span class="comment">// Setup Signer options.</span>
  18. <span class="comment">// For example, using default ones: enveloped signature, RSA-SHA1 signature method and etc.</span>
  19. &nbsp;
  20. <span class="comment">// Setup signer key data</span>
  21. Signer.KeyData := X509Data;
  22. &nbsp;
  23. <span class="comment">// calculate digest value for references</span>
  24. Signer.UpdateReferencesDigest();
  25. &nbsp;
  26. <span class="comment">// Filling XAdES info</span>
  27. <span class="comment">// Setting XAdES version</span>
  28. XAdESSigner.XAdESVersion := XAdES_v1_4_1;
  29. &nbsp;
  30. <span class="comment">// Place a code to setup Signed properties and Timestamp client</span>
  31. <span class="comment">// [XAdES PLACE #1]</span>
  32. &nbsp;
  33. <span class="comment">// Generating XAdES structure, specify desired XAdES form as parameter</span>
  34. XAdESSigner.Generate(XAdES_BES);
  35. &nbsp;
  36. <span class="comment">// Generating signature structure</span>
  37. Signer.GenerateSignature();
  38. &nbsp;
  39. <span class="comment">// Selecting a target node for the signature</span>
  40. SigNode := XMLDocument.DocumentElement;
  41. <span class="comment">// Signing and saving signature</span>
  42. Signer.Save(SigNode);
  43. &nbsp;
  44. <span class="comment">// Place a code to extend XAdES form immediately after signing. </span>
  45. <span class="comment">// Used, for example, if you want to specify own revocation info not auto collected one.</span>
  46. <span class="comment">// [XAdES PLACE #2]</span>
  47. &nbsp;
  48. <span class="keyword">finally</span>
  49. FreeAndNil(Signer);
  50. FreeAndNil(XAdESSigner);
  51. <span class="keyword">end</span>;

[C#]

  1. [C#]
  2. &nbsp;
  3. <span class="comment">// Creating an instance of XML-DSig signer.</span>
  4. TElXMLSigner Signer = <span class="keyword">new</span> TElXMLSigner();
  5. <span class="comment">// Creating an instance of XAdES signer.</span>
  6. TElXAdESSigner XAdESSigner = <span class="keyword">new</span> TElXAdESSigner();
  7. <span class="comment">// Setup XAdES processor</span>
  8. Signer.XAdESProcessor = XAdESSigner;
  9. <span class="keyword">try</span>
  10. {
  11. <span class="comment">// adding a references. For example, adding a reference for a document element.</span>
  12. TElXMLReference Ref = <span class="keyword">new</span> TElXMLReference();
  13. Ref.TransformChain.Add(<span class="keyword">new</span> TElXMLEnvelopedSignatureTransform());
  14. Ref.URI = <span class="string">""</span>;
  15. Ref.URINode = XMLDocument.DocumentElement;
  16. Signer.References.Add(Ref);
  17. &nbsp;
  18. <span class="comment">// Setup Signer options. </span>
  19. <span class="comment">// For example, using default ones: enveloped signature, RSA-SHA1 signature method and etc.</span>
  20. &nbsp;
  21. <span class="comment">// Setup signer key data</span>
  22. Signer.KeyData = X509Data;
  23. &nbsp;
  24. <span class="comment">// calculate digest value for references</span>
  25. Signer.UpdateReferencesDigest();
  26. &nbsp;
  27. <span class="comment">// Filling XAdES info</span>
  28. <span class="comment">// Setting XAdES version</span>
  29. XAdESSigner.XAdESVersion = SBXMLAdES.Unit.XAdES_v1_4_1;
  30. &nbsp;
  31. <span class="comment">// Place a code to setup Signed properties and Timestamp client</span>
  32. <span class="comment">// [XAdES PLACE #1]</span>
  33. &nbsp;
  34. <span class="comment">// Generating XAdES structure, specify desired XAdES form as parameter</span>
  35. XAdESSigner.Generate(SBXMLAdES.Unit.XAdES_BES);
  36. &nbsp;
  37. <span class="comment">// Generating signature structure</span>
  38. Signer.GenerateSignature();
  39. &nbsp;
  40. <span class="comment">// Selecting a target node for the signature</span>
  41. TElXMLDOMNode SigNode = XMLDocument.DocumentElement;
  42. <span class="comment">// Signing and saving signature</span>
  43. Signer.Save(<span class="keyword">ref</span> SigNode);
  44. &nbsp;
  45. <span class="comment">// Place a code to extend XAdES form immediately after signing.</span>
  46. <span class="comment">// Used, for example, if you want to specify own revocation info not auto collected one.</span>
  47. <span class="comment">// [XAdES PLACE #2]</span>
  48. }
  49. <span class="keyword">finally</span>
  50. {
  51. Signer.Dispose();
  52. XAdESSigner.Dispose();
  53. }

Extending XAdES signature

[Delphi]

  1. [Delphi]
  2. &nbsp;
  3. <span class="comment">// Creating an instance of XML-DSig verifier.</span>
  4. Verifier := TElXMLVerifier.Create(<span class="keyword">nil</span>);
  5. <span class="comment">// Creating an instance of XAdES verifier.</span>
  6. XAdESVerifier := TElXAdESVerifier.Create(<span class="keyword">nil</span>);
  7. <span class="comment">// Setup XAdES processor</span>
  8. Verifier.XAdESProcessor := XAdESVerifier;
  9. <span class="keyword">try</span>
  10. <span class="comment">// load a signature from a specific element</span>
  11. Verifier.Load(SignatureElement);
  12. &nbsp;
  13. <span class="comment">// Validate a signature using Verifier.ValidateSignature method</span>
  14. <span class="comment">// Validate references using Verifier.ValidateReferences or ValidateReference method</span>
  15. &nbsp;
  16. <span class="comment">// check if a signature has XAdES info</span>
  17. <span class="keyword">if</span> XAdESVerifier.IsEnabled <span class="keyword">then</span>
  18. <span class="keyword">begin</span>
  19. <span class="comment">// Validate a signer certificate and timestamps using XAdESVerifier.Validate method</span>
  20. &nbsp;
  21. <span class="comment">// Place a code to extend XAdES form. For example, add new archive time-stamp.</span>
  22. <span class="comment">// [XAdES PLACE #3]</span>
  23. <span class="keyword">end</span>;
  24. <span class="keyword">finally</span>
  25. FreeAndNil(Verifier);
  26. FreeAndNil(XAdESVerifier);
  27. <span class="keyword">end</span>;

[C#]

  1. [C#]
  2. &nbsp;
  3. <span class="comment">// Creating an instance of XML-DSig verifier.</span>
  4. TElXMLVerifier Verifier = <span class="keyword">new</span> TElXMLVerifier();
  5. <span class="comment">// Creating an instance of XAdES verifier.</span>
  6. TElXAdESVerifier XAdESVerifier = <span class="keyword">new</span> TElXAdESVerifier();
  7. <span class="comment">// Setup XAdES processor</span>
  8. Verifier.XAdESProcessor = XAdESVerifier;
  9. <span class="keyword">try</span>
  10. {
  11. <span class="comment">// load a signature from a specific element</span>
  12. Verifier.Load(SignatureElement);
  13. &nbsp;
  14. <span class="comment">// Validate a signature using Verifier.ValidateSignature() method</span>
  15. <span class="comment">// Validate references using Verifier.ValidateReferences() or ValidateReference(..) method</span>
  16. &nbsp;
  17. <span class="comment">// check if a signature has XAdES info</span>
  18. <span class="keyword">if</span> (XAdESVerifier.IsEnabled)
  19. {
  20. <span class="comment">// Validate a signer certificate and timestamps using XAdESVerifier.Validate() method</span>
  21. &nbsp;
  22. <span class="comment">// Place a code to extend XAdES form. For example, add new archive time-stamp.</span>
  23. <span class="comment">// [XAdES PLACE #3]</span>
  24. }
  25. }
  26. <span class="keyword">finally</span>
  27. {
  28. Verifier.Dispose();
  29. XAdESVerifier.Dispose();
  30. }

In the code above, the code for setting XAdES signed properties (XAdES-BES and -EPES forms) can be placed only in [XAdES PLACE #1], that is before signing. The code for setting XAdES unsigned properties like CounterSignature and timestamps could be placed in any [XAdES PLACE]. The code for setting XAdES unsigned properties like adding custom revocation information (if not auto collection is used) could be placed only in [XAdES PLACE #2] and [XAdES PLACE #3].

The XMLDocument object should contain the XML document. The X509Data object should contain a valid signing certificate with a private key. The SignatureElement object should contain a signature element. These requirements apply to all sample code snippets below.


Creating Basic Electronic Signature (XAdES-BES)

Provides basic authentication and integrity protection and satisfies the legal requirements for advanced electronic signatures as defined in the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures. XAdES-BES form (version 1.2.2 or higher) is equivalent to XAdES form in version 1.1.1

[Delphi]

  1. [Delphi]
  2. &nbsp;
  3. <span class="comment">// setting up production place</span>
  4. XAdESSigner.Included := [xipProductionPlace];
  5. XAdESSigner.ProductionPlace.City := <span class="string">'City'</span>;
  6. XAdESSigner.ProductionPlace.StateOrProvince := <span class="string">'State'</span>;
  7. XAdESSigner.ProductionPlace.PostalCode := <span class="string">'Postal code'</span>;
  8. XAdESSigner.ProductionPlace.CountryName := <span class="string">'Country'</span>;
  9. &nbsp;
  10. <span class="comment">// adding claimed roles as text</span>
  11. XAdESSigner.Included := XAdESSigner.Included + [xipSignerRole];
  12. XAdESSigner.SignerRole.ClaimedRoles.AddText(XAdESSigner.XAdESVersion,
  13. XMLDocument, <span class="string">'Claimed Roles text'</span>);
  14. &nbsp;
  15. <span class="comment">// adding signing certificates</span>
  16. <span class="comment">// for this we need to create a memory certificate storage</span>
  17. CertStorage := TElMemoryCertStorage.Create(<span class="keyword">nil</span>);
  18. <span class="comment">// then add a signing certificate into it</span>
  19. CertStorage.Add(SigningCertificate, false);
  20. <span class="comment">// setting up signing certificate storage</span>
  21. XAdESSigner.SigningCertificates := CertStorage;
  22. &nbsp;
  23. <span class="comment">// set signing time</span>
  24. XAdESSigner.SigningTime := UtcNow;
  25. &nbsp;
  26. <span class="comment">// Generate XAdES structure</span>
  27. XAdESSigner.Generate(XAdES_BES);

[C#]

  1. [C<span class="preprocessor">#]</span>
  2. &nbsp;
  3. <span class="comment">// setting up production place</span>
  4. XAdESSigner.Included = SBXMLAdESIntf.Unit.xipProductionPlace;
  5. XAdESSigner.ProductionPlace.City = <span class="string">"City"</span>;
  6. XAdESSigner.ProductionPlace.StateOrProvince = <span class="string">"State"</span>;
  7. XAdESSigner.ProductionPlace.PostalCode = <span class="string">"Postal code"</span>;
  8. XAdESSigner.ProductionPlace.CountryName = <span class="string">"Country"</span>;
  9. &nbsp;
  10. <span class="comment">// adding claimed roles as text</span>
  11. XAdESSigner.Included |= SBXMLAdESIntf.Unit.xipSignerRole;
  12. XAdESSigner.SignerRole.ClaimedRoles.AddText(XAdESSigner.XAdESVersion,
  13. XMLDocument, <span class="string">"Claimed Roles text"</span>);
  14. &nbsp;
  15. <span class="comment">// adding signing certificates</span>
  16. <span class="comment">// for this we need to create a memory certificate storage</span>
  17. CertStorage = <span class="keyword">new</span> TElMemoryCertStorage.Create();
  18. <span class="comment">// then add a signing certificate into it</span>
  19. CertStorage.Add(SigningCertificate, <span class="keyword">false</span>);
  20. <span class="comment">// setting up signing certificate storage</span>
  21. XAdESSigner.SigningCertificates = CertStorage;
  22. &nbsp;
  23. <span class="comment">// set signing time</span>
  24. XAdESSigner.SigningTime = DateTime.UtcNow;
  25. &nbsp;
  26. <span class="comment">// Generate XAdES structure</span>
  27. XAdESSigner.Generate(XAdES_BES);

Additional properties of the XAdESSigner component that could be used while creating XAdES-BES form:

  • SigningCertificatesDigestMethod - use to specify signing certificate digest method (default SHA-1).
  • OwnSigningCertificates - force a component to free SigningCertificates storage.

Adding a CounterSignature (XAdES-BES)

Countersignatures are signatures that are applied one after the other and are used where the order the signatures are applied is important. In these situations the first signature signs the signed data object. Each additional signature may sign in turn the latest previously generated signature, or all the previously generated signatures and the signed document. In the XAdES, countersignatures are embedded within the signatures that they countersign.

[Delphi]

  1. [Delphi]
  2. &nbsp;
  3. <span class="comment">// Creating an instance of XML-DSig signer</span>
  4. CSigner := TElXMLSigner.Create(<span class="keyword">nil</span>);
  5. <span class="comment">// adding custom references...</span>
  6. <span class="comment">// CSigner.UpdateReferencesDigest();</span>
  7. <span class="comment">// adding references pointing to elements inside the main signature </span>
  8. <span class="comment">// (adding a reference to the SignatureValue element)</span>
  9. Ref := TElXMLReference.Create();
  10. Ref.RefType := xmlRefTypeCountersignedSignature;
  11. <span class="comment">// set an URI for SignatureValue element</span>
  12. Ref.URI := <span class="string">'#SignatureValue-0'</span>;
  13. CSigner.References.Add(Ref);
  14. &nbsp;
  15. <span class="comment">// Setup signer key data</span>
  16. CSigner.KeyData := X509KeyData;
  17. <span class="comment">// Setup CSigner options. </span>
  18. <span class="comment">// For example, using default ones: RSA-SHA1 signature method and etc.</span>
  19. &nbsp;
  20. <span class="comment">// Add countersignature</span>
  21. XAdESSigner.AddCounterSignature(CSigner);
  22. &nbsp;
  23. <span class="comment">// Generate signature structure (continue creating XAdES signature sample)</span>
  24. Signer.GenerateSignature();
  25. ...
  26. <span class="comment">// Set an ID for SignatureValue element</span>
  27. Signer.Signature.SignatureValue.ID := <span class="string">'SignatureValue-0'</span>;

[C#]

  1. [C<span class="preprocessor">#]</span>
  2. &nbsp;
  3. <span class="comment">// Creating an instance of XML-DSig signer</span>
  4. TElXMLSigner CSigner = <span class="keyword">new</span> TElXMLSigner();
  5. <span class="comment">// adding custom references...</span>
  6. <span class="comment">// CSigner.UpdateReferencesDigest();</span>
  7. <span class="comment">// adding references pointing to elements inside the main signature </span>
  8. <span class="comment">// (adding a reference to the SignatureValue element)</span>
  9. TElXMLReference Ref = <span class="keyword">new</span> TElXMLReference();
  10. Ref.RefType = SBXMLDefs.Unit.xmlRefTypeCountersignedSignature;
  11. <span class="comment">// set an URI for SignatureValue element</span>
  12. Ref.URI = <span class="string">"#SignatureValue-0"</span>;
  13. CSigner.References.Add(Ref);
  14. &nbsp;
  15. <span class="comment">// Setup signer key data</span>
  16. CSigner.KeyData = X509KeyData;
  17. <span class="comment">// Setup CSigner options. For example, using default ones: </span>
  18. <span class="comment">// RSA-SHA1 signature method and etc.</span>
  19. &nbsp;
  20. <span class="comment">// Add countersignature</span>
  21. XAdESSigner.AddCounterSignature(CSigner);
  22. &nbsp;
  23. <span class="comment">// Generate signature structure (continue creating XAdES signature sample)</span>
  24. Signer.GenerateSignature();
  25. ...
  26. <span class="comment">// Set an ID for SignatureValue element</span>
  27. Signer.Signature.SignatureValue.ID = <span class="string">"SignatureValue-0"</span>;

Creating Explicit Policy Electronic Signatures (XAdES-EPES)

A XAdES-EPES builds up on a XML-DSig or XAdES-BES forms by incorporating the SignaturePolicyIdentifier element. A signature policy is useful to clarify the precise role and commitments that the signer intends to assume with respect to the signed data object, and to avoid claims by the verifier that a different signature policy was implied by the signer.

The electronic signature can contain an explicit and unambiguous identifier of a signature policy together with a hash value of the signature policy:

[Delphi]

  1. [Delphi]
  2. &nbsp;
  3. <span class="comment">// setting policy description</span>
  4. XAdESSigner.PolicyId.SigPolicyId.Description := <span class="string">'Description text'</span>;
  5. <span class="comment">// setting policy identifier</span>
  6. XAdESSigner.PolicyId.SigPolicyId.Identifier := <span class="string">'http://...'</span>;
  7. XAdESSigner.PolicyId.SigPolicyId.IdentifierQualifier := xqtOIDAsURI;
  8. <span class="comment">// calculate signature policy hash value using SHA-1 digest method</span>
  9. XAdESSigner.PolicyId.SigPolicyHash.DigestMethod := DigestMethodToURI(xdmSHA1);
  10. XAdESSigner.PolicyId.SigPolicyHash.DigestValue :=
  11. CalculateDigest(<span class="annotation">@Buf</span>[<span class="number">0</span>], Length(Buf), xdmSHA1);
  12. &nbsp;
  13. <span class="comment">// Generate XAdES structure</span>
  14. XAdESSigner.Generate(XAdES_EPES);

[C#]

  1. [C#]
  2. &nbsp;
  3. // setting policy description
  4. XAdESSigner.PolicyId.SigPolicyId.Description = "Description text”;
  5. // setting policy identifier
  6. XAdESSigner.PolicyId.SigPolicyId.Identifier = "http://...”;
  7. XAdESSigner.PolicyId.SigPolicyId.IdentifierQualifier = SBXMLAdES.Unit.xqtOIDAsURI;
  8. // calculate signature policy hash value using SHA1 digest method
  9. XAdESSigner.PolicyId.SigPolicyHash.DigestMethod =
  10. SBXMLSec.Unit.DigestMethodToURI(SBXMLSec.Unit.xdmSHA1);
  11. XAdESSigner.PolicyId.SigPolicyHash.DigestValue =
  12. SBXMLSec.Unit.CalculateDigest(buf, SBXMLSec.Unit.xdmSHA1);
  13. &nbsp;
  14. // Generate XAdES structure
  15. XAdESSigner.Generate(SBXMLAdES.Unit.XAdES_EPES);

Where the buf object is a byte array that contains policy data/document (for example, downloaded from specified URI).

Alternatively, the electronic signature can avoid the inclusion of the aforementioned identifier and hash value. In this case you need just to call XAdESSigner.Generate method with XAdES_EPES parameter.


Creating electronic signature with Time (XAdES-T)

XAdES-T form extends XAdES-BES or XAdES-EPES forms with an external time-stamp that certifies the time of signing. To be able to create XAdES-T signatures you must have access to an online TSA service that is capable of producing RFC3161-compliant time-stamps.

[Delphi]

  1. [Delphi]
  2. &nbsp;
  3. <span class="comment">// Creating timestamping components.</span>
  4. HttpClient := TElHTTPSClient.Create(<span class="keyword">nil</span>);
  5. <span class="comment">// (!) Remember to handle the HttpClient’s OnCertificateValidate</span>
  6. <span class="comment">// event if the TSA server is accessible via HTTPS protocol.</span>
  7. &nbsp;
  8. TspClient := TElHTTPTSPClient.Create(<span class="keyword">nil</span>);
  9. <span class="keyword">try</span>
  10. TspClient.HTTPClient := HttpClient;
  11. TspClient.URL := “http:<span class="comment">//tsa.myserver.com”;</span>
  12. HttpClient.SocketTimeout := <span class="number">20000</span>; <span class="comment">// 20 seconds</span>
  13. &nbsp;
  14. <span class="comment">// Adding a signature time-stamp</span>
  15. k := XAdESSigner/XAdESVerifier.AddSignatureTimestamp(TspClient);
  16. <span class="keyword">if</span> k &lt;&gt; <span class="number">0</span> <span class="keyword">then</span>
  17. <span class="keyword">raise</span> Exception.CreateFmt(<span class="string">'Failed to time-stamp: %d'</span>, [k]);
  18. &nbsp;
  19. <span class="keyword">finally</span>
  20. <span class="comment">// free components</span>
  21. FreeAndNil(TspClient);
  22. FreeAndNil(HttpClient);
  23. <span class="keyword">end</span>;

[C#]

  1. [C#]
  2. &nbsp;
  3. <span class="comment">// Creating timestamping components.</span>
  4. httpClient = <span class="keyword">new</span> TElHTTPSClient();
  5. <span class="comment">// (!) Remember to handle the httpClient’s OnCertificateValidate</span>
  6. <span class="comment">// event if the TSA server is accessible via HTTPS protocol.</span>
  7. &nbsp;
  8. tspClient = <span class="keyword">new</span> TelHTTPTSPClient();
  9. <span class="keyword">try</span>
  10. {
  11. tspClient.HTTPClient = httpClient;
  12. tspClient.URL = “http:<span class="comment">//tsa.myserver.com”;</span>
  13. httpClient.SocketTimeout = <span class="number">20000</span>; <span class="comment">// 20 seconds</span>
  14. &nbsp;
  15. <span class="comment">// Adding signature time-stamp</span>
  16. <span class="keyword">int</span> k = XAdESSigner/XAdESVerifier.AddSignatureTimestamp(tspClient);
  17. <span class="keyword">if</span> (k != <span class="number">0</span>)
  18. <span class="keyword">throw</span> <span class="keyword">new</span> Exception(“Failed to time-stamp: ” + k.ToString());
  19. }
  20. <span class="keyword">finally</span>
  21. {
  22. <span class="comment">// dispose components</span>
  23. tspClient.Dispose();
  24. httpClient.Dispose();
  25. }

Note: If AddSignatureTimestamp method is called in [XAdES PLACE #1] it will always return 0 (success), but the actual time-stamping would be performed in Signer.Save method after signing. Depending on XAdESSigner.IgnoreTimestampFailure property if an error occurs while time-stamping in Signer.Save method, it would be ignored or exception would be raised/thrown. Also, in this case, tspClient and httpClient objects shouldn't be freed/disposed before Signer.Save method.


Creating electronic signature with Complete validation data references (XAdES-C)

XAdES-C form extends XAdES-T or lower forms with complete certificates and revocation information references. It allows the verifier to reconstruct the PKI environment in revision it used to be in at the moment of signing. This form is useful for those situations where such information is archived by an external source, like a trusted service provider. Only inclusion of the references helps to reduce the signature size.

The XAdES components could automatically collect certificates and revocation information or use custom certificates and revocation information.
Automatic collection in [XAdES PLACE #1] is done by calling XAdESSigner.Generate method with parameter XAdES_C or higher.
Automatic collection in [XAdES PLACE #2] and [XAdES PLACE #3] is done by calling AddValidationDataRefs method:

[Delphi]

  1. [Delphi]
  2. &nbsp;
  3. Validity := XAdESSigner/XAdESVerifier.AddValidationDataRefs();
  4. <span class="keyword">if</span> (Validity &lt;&gt; xsvValid) <span class="keyword">and</span> <span class="keyword">not</span> XAdESVerifier.IgnoreChainValidationErrors <span class="keyword">then</span>
  5. <span class="keyword">raise</span> Exception.Create(<span class="string">'Failed to add validation data references'</span>);

[C#]

  1. [C<span class="preprocessor">#]</span>
  2. &nbsp;
  3. TSBXAdESValidity Validity = XAdESVerifier.AddValidationDataRefs();
  4. <span class="keyword">if</span> ((Validity != TSBXAdESValidity.xsvValid) &amp;&amp; !XAdESVerifier.IgnoreChainValidationErrors)
  5. <span class="keyword">throw</span> <span class="keyword">new</span> Exception(“Failed to add validation data references”);

TElXAdESSigner/TElXAdESVerifier components performs automatic collection of certificates and revocation information by internally validating signing certificate with the use of TElX509CertificateValidator component. To get access to this component and a collection of its tracing events or perform a finer tuning, handle the OnBeforeCertificateValidate event or assign own TElX509CertificateValidator instance to CertificateValidator property.

Custom certificates and revocation information could be added in [XAdES PLACE #2] and [XAdES PLACE #3] using AddCompleteCertificateRefs and AddCompleteRevocationRefs methods.

[Delphi, C#] XAdESSigner/XAdESVerifier.AddCompleteCertificateRefs(Certificates); XAdESSigner/XAdESVerifier.AddCompleteRevocationRefs(CRLs, OCSPResponses);

Where Certificates object is a certificate storage that contains certificates to add. CRLs and OCSPResponses objects are CRL storage and OCSP responses list respectively.

To store certificates and revocation values for archival purposes handle OnStoreCertificate, OnStoreCRL and OnStoreOCSPResponse events. To retrieve certificates and revocation values for validation purposes handle OnRetrieveCertificate, OnRetrieveCRL and OnRetrieveOCSPResponse events.


Creating Extended signatures with time indication forms (XAdES-X)

XAdES-X form extends XAdES-C form with an external time-stamp that certifies the references to the validation data or on the SignatureValue element, signature time-stamps if present and the aforementioned validation data. This time-stamp takes into account the risk that any keys used in the certificate chain or in the revocation status information may be compromised. Depending of what is time-stamped, there are two different types of XAdES-X signatures, namely, XAdES-X type 1 and XAdES-X type 2. To be able to create XAdES-X signatures you must have access to an online TSA service that is capable of producing RFC3161-compliant time-stamps.

[Delphi]

  1. [Delphi]
  2. &nbsp;
  3. <span class="comment">// Creating timestamping components.</span>
  4. HttpClient := TElHTTPSClient.Create(<span class="keyword">nil</span>);
  5. <span class="comment">// (!) Remember to handle the HttpClient’s OnCertificateValidate</span>
  6. <span class="comment">// event if the TSA server is accessible via HTTPS protocol.</span>
  7. &nbsp;
  8. TspClient := TElHTTPTSPClient.Create(<span class="keyword">nil</span>);
  9. <span class="keyword">try</span>
  10. TspClient.HTTPClient := HttpClient;
  11. TspClient.URL := “http:<span class="comment">//tsa.myserver.com”;</span>
  12. HttpClient.SocketTimeout := <span class="number">20000</span>; <span class="comment">// 20 seconds</span>
  13. &nbsp;
  14. <span class="comment">// Adding SigAndRefs time-stamp (XAdES-X type 1)</span>
  15. k := XAdESSigner/XAdESVerifier.AddSigAndRefsTimestamp(TspClient);
  16. <span class="keyword">if</span> k &lt;&gt; <span class="number">0</span> <span class="keyword">then</span>
  17. <span class="keyword">raise</span> Exception.CreateFmt(<span class="string">'Failed to time-stamp: %d'</span>, [k]);
  18. &nbsp;
  19. <span class="comment">// or adding RefsOnly time-stamp (XAdES-X type 2)</span>
  20. k := XAdESSigner/XAdESVerifier.AddRefsOnlyTimestamp(tspClient);
  21. <span class="keyword">if</span> k &lt;&gt; <span class="number">0</span> <span class="keyword">then</span>
  22. <span class="keyword">raise</span> Exception.CreateFmt(<span class="string">'Failed to time-stamp: %d'</span>, [k]);
  23. &nbsp;
  24. <span class="keyword">finally</span>
  25. <span class="comment">// free components</span>
  26. FreeAndNil(TspClient);
  27. FreeAndNil(HttpClient);
  28. <span class="keyword">end</span>;

[C#]

  1. [C#]
  2. &nbsp;
  3. <span class="comment">// Creating timestamping components.</span>
  4. httpClient = <span class="keyword">new</span> TElHTTPSClient();
  5. <span class="comment">// (!) Remember to handle the httpClient’s OnCertificateValidate</span>
  6. <span class="comment">// event if the TSA server is accessible via HTTPS protocol.</span>
  7. &nbsp;
  8. tspClient = <span class="keyword">new</span> TelHTTPTSPClient();
  9. <span class="keyword">try</span>
  10. {
  11. tspClient.HTTPClient = httpClient;
  12. tspClient.URL = “http:<span class="comment">//tsa.myserver.com”;</span>
  13. httpClient.SocketTimeout = <span class="number">20000</span>; <span class="comment">// 20 seconds</span>
  14. &nbsp;
  15. <span class="comment">// Adding SigAndRefs time-stamp (XAdES-X type 1)</span>
  16. <span class="keyword">int</span> k = XAdESSigner/XAdESVerifier.AddSigAndRefsTimestamp(tspClient);
  17. <span class="keyword">if</span> (k != <span class="number">0</span>)
  18. <span class="keyword">throw</span> <span class="keyword">new</span> Exception(“Failed to time-stamp: ” + k.ToString());
  19. &nbsp;
  20. <span class="comment">// or adding RefsOnly time-stamp (XAdES-X type 2)</span>
  21. k = XAdESSigner/XAdESVerifier.AddRefsOnlyTimestamp(tspClient);
  22. <span class="keyword">if</span> (k != <span class="number">0</span>)
  23. <span class="keyword">throw</span> <span class="keyword">new</span> Exception(“Failed to time-stamp: ” + k.ToString());
  24. }
  25. <span class="keyword">finally</span>
  26. {
  27. <span class="comment">// dispose components</span>
  28. tspClient.Dispose();
  29. httpClient.Dispose();
  30. }

Note: If AddSigAndRefsTimestamp or AddRefsOnlyTimestamp methods are called in [XAdES PLACE #1] it will always return 0 (success), but the actual time-stamping would be performed in Signer.Save method after signing. Depending on XAdESSigner.IgnoreTimestampFailure property if an error occurs while time-stamping in Signer.Save method, it would be ignored or exception would be raised/thrown. Also, in this case, tspClient and httpClient objects shouldn't be freed/disposed before Signer.Save method.


Creating Extended Long electronic signatures with time (XAdES-X-L)

XAdES-X-L form extends XAdES-X type 1 or XAdES-X type 2 or lower forms by inserting certificate and revocation information values of the referenced validation data (certificates, CRLs and OCSP responses) to the unsigned properties. XAdES-X-L signature is thus a self-contained signature that does not require any external certificate or revocation provisioning services to be successfully validated. The XAdES components could automatically collect certificates and revocation information or use custom certificates and revocation information. Automatic collection in [XAdES PLACE #1] is done by calling XAdESSigner.Generate method with parameter XAdES_X_L or higher. Automatic collection in [XAdES PLACE #2] and [XAdES PLACE #3] is done by calling AddValidationDataValues method:

[Delphi]

  1. [Delphi]
  2. &nbsp;
  3. Validity := XAdESSigner/XAdESVerifier.AddValidationDataValues();
  4. <span class="keyword">if</span> (Validity &lt;&gt; xsvValid) <span class="keyword">and</span> <span class="keyword">not</span> XAdESVerifier.IgnoreChainValidationErrors <span class="keyword">then</span>
  5. <span class="keyword">raise</span> Exception.Create(<span class="string">'Failed to add validation data values'</span>);

[C#]

  1. [C<span class="preprocessor">#]</span>
  2. &nbsp;
  3. TSBXAdESValidity Validity = XAdESVerifier.AddValidationDataValues();
  4. <span class="keyword">if</span> ((Validity != TSBXAdESValidity.xsvValid) &amp;&amp; !XAdESVerifier.IgnoreChainValidationErrors)
  5. <span class="keyword">throw</span> <span class="keyword">new</span> Exception(“Failed to add validation data values”);

TElXAdESSigner/TElXAdESVerifier components performs automatic collection of certificates and revocation information by internally validating signing certificate with the use of TElX509CertificateValidator component. To get access to this component and a collection of its tracing events or perform a finer tuning, handle the OnBeforeCertificateValidate event or assign own TElX509CertificateValidator instance to CertificateValidator property.

Custom certificates and revocation information could be added in [XAdES PLACE #2] and [XAdES PLACE #3] using AddCertificateValues and AddRevocationValues methods.

[Delphi, C#]

  1. [Delphi, C<span class="preprocessor">#]</span>
  2. &nbsp;
  3. XAdESSigner/XAdESVerifier.AddCertificateValues(Certificates);
  4. XAdESSigner/XAdESVerifier.AddRevocationValues(CRLs, OCSPResponses);

Where Certificates object is a certificate storage that contains certificates to add. CRLs and OCSPResponses objects are CRL storage and OCSP responses list respectively.

To retrieve certificates and revocation values, that were previously stored in XAdES-C form (if XAdES-X-L form is not generated immediately after XAdES-C form), handle OnRetrieveCertificate, OnRetrieveCRL and OnRetrieveOCSPResponse events.


Creating Archival electronic signatures (XAdES-A)

XAdES-A form adds additional time-stamps for archiving signatures in a way that they are protected if the cryptographic data become weak. To be able to create XAdES-A signatures you must have access to an online TSA service that is capable of producing RFC3161-compliant time-stamps.

[Delphi]

  1. [Delphi]
  2. &nbsp;
  3. <span class="comment">// Creating timestamping components.</span>
  4. HttpClient := TElHTTPSClient.Create(<span class="keyword">nil</span>);
  5. <span class="comment">// (!) Remember to handle the HttpClient’s OnCertificateValidate</span>
  6. <span class="comment">// event if the TSA server is accessed via HTTPS protocol.</span>
  7. &nbsp;
  8. TspClient := TElHTTPTSPClient.Create(<span class="keyword">nil</span>);
  9. <span class="keyword">try</span>
  10. TspClient.HTTPClient := HttpClient;
  11. TspClient.URL := “http:<span class="comment">//tsa.myserver.com”;</span>
  12. HttpClient.SocketTimeout := <span class="number">20000</span>; <span class="comment">// 20 seconds</span>
  13. &nbsp;
  14. <span class="comment">// Adding archival time-stamp</span>
  15. k := XAdESSigner/XAdESVerifier.AddArchiveTimestamp/AddArchiveTimestampV141 (TspClient);
  16. <span class="keyword">if</span> k &lt;&gt; <span class="number">0</span> <span class="keyword">then</span>
  17. <span class="keyword">raise</span> Exception.CreateFmt(<span class="string">'Failed to time-stamp: %d'</span>, [k]);
  18. &nbsp;
  19. <span class="keyword">finally</span>
  20. <span class="comment">// free components</span>
  21. FreeAndNil(TspClient);
  22. FreeAndNil(HttpClient);
  23. <span class="keyword">end</span>;

[C#]

  1. [C#]
  2. &nbsp;
  3. <span class="comment">// Creating timestamping components.</span>
  4. httpClient = <span class="keyword">new</span> TElHTTPSClient();
  5. <span class="comment">// (!) Remember to handle the httpClient’s OnCertificateValidate</span>
  6. <span class="comment">// event if the TSA server is accessible via HTTPS protocol.</span>
  7. &nbsp;
  8. tspClient = <span class="keyword">new</span> TelHTTPTSPClient();
  9. <span class="keyword">try</span>
  10. {
  11. tspClient.HTTPClient = httpClient;
  12. tspClient.URL = “http:<span class="comment">//tsa.myserver.com”;</span>
  13. httpClient.SocketTimeout = <span class="number">20000</span>; <span class="comment">// 20 seconds</span>
  14. &nbsp;
  15. <span class="comment">// Adding archival time-stamp</span>
  16. <span class="keyword">int</span> k = XAdESSigner/XAdESVerifier.AddArchiveTimestamp/ AddArchiveTimestampV141(tspClient);
  17. <span class="keyword">if</span> (k != <span class="number">0</span>)
  18. <span class="keyword">throw</span> <span class="keyword">new</span> Exception(“Failed to time-stamp: ” + k.ToString());
  19. }
  20. <span class="keyword">finally</span>
  21. {
  22. <span class="comment">// dispose components</span>
  23. tspClient.Dispose();
  24. httpClient.Dispose();
  25. }

Note: If AddArchiveTimestamp or AddArchiveTimestampV141 methods are called in [XAdES PLACE #1] it will always return 0 (success), but the actual time-stamping would be performed in Signer.Save method after signing. Depending on XAdESSigner.IgnoreTimestampFailure property if an error occurs while time-stamping in Signer.Save method, it would be ignored or exception would be raised/thrown. Also, in this case, tspClient and httpClient objects shouldn't be freed/disposed before Signer.Save method.

Note: If XAdES version is 1.4.1 then AddArchiveTimestamp method will add archival time-stamp of version 1.4.1 (equivalent to calling AddArchiveTimestampV141 method).

Note: AddArchiveTimestampV141 method couldn't be called for XAdES version lower then 1.3.2


Preparing and Tuning TElXAdESSigner and TElXAdESVerifier components

Each PKI environment is different, so you will probably need to tune up TElXAdESSigner and TElXAdESVerifier objects to match your particular one. The table below gives a breakdown of the most important properties.

IgnoreChainValidationErrors Prevents the component from throwing exceptions in case of chain validation errors. Use this property with care in real-world environments, as ignoring certain validation problems may pose a security risk.
ForceCompleteChainValidation Controls whether the component should validate the whole certificate chain up to the trusted certificate. Can be switched off for debug or testing purposes to suppress validation exceptions.
OfflineMode Tells the component that no Internet connections should be attempted when validating the chain. Ensure that appropriate certificates and revocation elements are available to the component (either in the body of the signature or locally) when switching this property on; otherwise, you might come across chain validation issues.
TrustedCertificates Allows to provide a separate list of trusted certificates for using during the validation process.
GracePeriod A period of ‘idle time’ (in milliseconds) between the moments of creation of a XAdES-T signature and collection of validation information for upgrading to a higher form, to allow propagation of possible revocation status update through the PKI environment up to revocation status responders.
ValidationMoment Use this property to set the moment of time at which the signature should be validated. Leave intact to use current time from local computer.

Registering revocation retriever factories

TElXAdESSigner, TElXAdESVerifier and TElX509CertificateValidator classes use revocation information retrievers to obtain various pieces of validation information during the deep validation process. The retrievers are created by four object factories, responsible for different kinds of online services. In most public PKI environments it is enough to register the HTTP OCSP and HTTP CRL factories, while private and corporate environments might require LDAP connectivity as well.

In projects built against .NET, Java and C++ product editions the factories should be populated manually with the following code:

  1. <span class="comment">// Registering HTTP OCSP client </span>
  2. SBHTTPOCSPClient.<span class="keyword">Unit</span>.RegisterHTTPOCSPClientFactory();
  3. &nbsp;
  4. <span class="comment">// Registering HTTP CRL retriever</span>
  5. SBHTTPCRL.<span class="keyword">Unit</span>.RegisterHTTPCRLRetrieverFactory();
  6. &nbsp;
  7. <span class="comment">// Registering LDAP CRL retriever</span>
  8. SBLDAPCRL.<span class="keyword">Unit</span>.RegisterLDAPCRLRetrieverFactory();
  9. &nbsp;
  10. <span class="comment">// Registering LDAP certificate retriever</span>
  11. SBLDAPCertRetriever.<span class="keyword">Unit</span>.RegisterLDAPCertificateRetrieverFactory();

In Delphi environments the retrievers are registered automatically, provided that you’ve referenced the corresponding units in your project’s or form’s uses clause:

  1. <span class="keyword">uses</span>
  2. SBHTTPOCSPClient, SBHTTPCRL, SBLDAPCRL, SBLDAPCertRetriever;

References

[XML-DSig] XML digital signature processing rules and syntax.
[XAdES]: Electronic Signatures and Infrastructures (ESI); XML Advanced Electronic Signatures (XAdES) ETSI TS 101 903 V1.1.1,
V1.2.2, V1.3.2, V1.4.1, V1.4.2

Ready to get started?

Learn more about SecureBlackbox or download a free trial.

Download Now