XAdES (XML Advanced Electronic Signatures, ETSI EN 319 132) is the XML signature format of the eIDAS Regulation: an XMLDSig signature with signed properties such as the signing time, the signing certificate, the commitment type and the signature production place. It is used for e-invoicing, e-procurement and e-government documents. This C# sample creates XAdES signatures with the class XadesSignature of the .NET Digital Signature Library.
XAdES baseline levels
| Level | SignatureStandard | What the signature contains |
|---|---|---|
| XAdES-B-B | XadesB (default) | The signing time and the signing certificate |
| XAdES-B-T | XadesT | B-B plus a time-stamp (RFC 3161): a trusted signing time |
| XAdES-B-LT | XadesLT | B-T plus the validation data: the certificates and the revocation information (CRL, OCSP) |
| XAdES-B-LTA | XadesLTA | B-LT plus an archive time-stamp, renewable: see XAdES-LTA |
The levels T, LT and LTA need a time-stamping server (TimeStamping.ServerUrl). SignaturePackaging selects an enveloped signature (inside the XML document, the default) or a detached signature (a separate XML file that references a file of any type).
C# code: enveloped XAdES-B-B signature
/// <summary>
/// Gets the certificate used to sign the documents. A certificate can be loaded from various sources: choose one.
/// </summary>
static X509Certificate2 LoadSigningCertificate()
{
// 1. Load the certificate (with its private key) from a PFX or P12 file.
return DigitalCertificate.LoadCertificate(SampleFile("cert.pfx"), CertificatePassword);
// 2. Select a certificate from the Windows certificate store (Current User). Smart cards and USB tokens
// usually publish their certificates in this store (start - run - certmgr.msc). If the certificate of a
// smart card is not visible in the Windows store, the library cannot use it with this method.
// The user selects the certificate from a dialog window:
// return DigitalCertificate.LoadCertificate(false, string.Empty, "Select Certificate", "Select the certificate for digital signature");
}
/// <summary>
/// Signs an XML document with an enveloped XAdES-B-B signature.
/// </summary>
static void SignXmlWithXades(string unsignedXmlFile, string signedXmlFile)
{
XadesSignature xadesSignature = new XadesSignature(LibrarySerialNumber);
xadesSignature.DigitalSignatureCertificate = LoadSigningCertificate();
// The baseline level of the signature: XAdES-B-B (the signing time and the signing certificate).
xadesSignature.SignatureStandard = XadesSignatureStandard.XadesB;
// The signature is added to the signed XML document (the default).
xadesSignature.SignaturePackaging = XadesSignaturePackaging.Enveloped;
// The hash algorithm of the signature: SHA256 (the default), SHA384 or SHA512.
xadesSignature.HashAlgorithm = SignLib.HashAlgorithm.SHA256;
// Optional signed properties: what the signer declares by signing...
xadesSignature.CommitmentType = XadesCommitmentType.ProofOfApproval;
// ...and the place where the signature is created. All the fields are optional.
xadesSignature.SignatureProductionPlace = new XadesProductionPlace
{
City = "Bucharest",
CountryName = "RO"
};
// An explicit signature policy can be set when a regulation requires it:
// xadesSignature.SetSignaturePolicyInformation("2.16.724.1.3.1.1.2.1.9", policyDocumentHash, "2.16.840.1.101.3.4.2.1", "https://example.com/policy.pdf");
xadesSignature.ApplyDigitalSignature(unsignedXmlFile, signedXmlFile);
Console.WriteLine("The XAdES signature was created." + Environment.NewLine);
}
C# code: XAdES-B-T, time-stamped
/// <summary>
/// Signs an XML document with a XAdES-B-T signature: the signature is time-stamped.
/// </summary>
static void SignXmlWithXadesTimestamp(string unsignedXmlFile, string signedXmlFile)
{
XadesSignature xadesSignature = new XadesSignature(LibrarySerialNumber);
xadesSignature.DigitalSignatureCertificate = LoadSigningCertificate();
// XAdES-B-T: the signature has a time-stamp (RFC 3161), so it proves the time when it was created.
xadesSignature.SignatureStandard = XadesSignatureStandard.XadesT;
// The time-stamping server is required for XadesT, XadesLT and XadesLTA.
xadesSignature.TimeStamping.ServerUrl = TimestampServerUrl;
xadesSignature.ApplyDigitalSignature(unsignedXmlFile, signedXmlFile);
Console.WriteLine("The XAdES-T signature was created." + Environment.NewLine);
}
C# code: detached XAdES signature of any file
The signed file (a PDF, a DOCX, a ZIP file) is not changed; the signature is saved in a separate XML file and the signed file is needed to verify it.
/// <summary>
/// Signs a file of any type with a detached XAdES signature. The signature is saved in a separate XML file.
/// </summary>
static void SignFileWithDetachedXades(string fileToSign, string signatureFile)
{
XadesSignature xadesSignature = new XadesSignature(LibrarySerialNumber);
xadesSignature.DigitalSignatureCertificate = LoadSigningCertificate();
// The signature is a separate XML file that references the signed file. The signed file (a PDF file, a DOCX file,
// a ZIP file, etc.) is not changed, but it is needed to verify the signature.
xadesSignature.SignaturePackaging = XadesSignaturePackaging.Detached;
xadesSignature.ApplyDigitalSignature(fileToSign, signatureFile);
Console.WriteLine("The detached XAdES signature was created." + Environment.NewLine);
}
C# code: XAdES with a signature policy
Some regulations (for example national e-invoicing systems) require an explicit signature policy: an OID or URI and the digest of the policy document.
/// <summary>
/// Signs an XML document with an explicit signature policy (xades:SignaturePolicyIdentifier). A regulation or a relying party can
/// require one (for example the signature policy of a national e-invoicing system).
/// </summary>
static void SignXmlWithSignaturePolicy(string unsignedXmlFile, string signedXmlFile)
{
XadesSignature xadesSignature = new XadesSignature(LibrarySerialNumber);
xadesSignature.DigitalSignatureCertificate = LoadSigningCertificate();
// The policy is identified by an OID or by a URI and by the digest of the policy document. The digest is computed over the
// published policy document (download it and hash it, or use the digest published by the authority). Here a text is hashed only to
// show the call: it is not a real policy.
byte[] policyDocument = Encoding.UTF8.GetBytes("The text of the signature policy.");
byte[] policyHash;
using (SHA256 sha256 = SHA256.Create())
policyHash = sha256.ComputeHash(policyDocument);
xadesSignature.SetSignaturePolicyInformation("1.2.3.4.5.6.7.8.1", policyHash, "SHA256", "https://example.com/policy.txt");
xadesSignature.ApplyDigitalSignature(unsignedXmlFile, signedXmlFile);
Console.WriteLine("The XAdES signature with a signature policy was created." + Environment.NewLine);
}
C# code: verify XAdES signatures
/// <summary>
/// Verifies the signatures of a signed XML document and displays their information.
/// </summary>
static void VerifyXadesSignatures(string signedXmlFile)
{
XadesSignature xadesSignature = new XadesSignature(LibrarySerialNumber);
Console.WriteLine("Number of signatures: " + xadesSignature.GetNumberOfSignatures(signedXmlFile));
Console.WriteLine("Signature algorithm: " + xadesSignature.GetSignatureAlgorithm(signedXmlFile));
// The signer certificate of the first signature (the index of the signature can also be given).
Console.WriteLine("Signer: " + xadesSignature.GetDigitalSignatureCertificate(signedXmlFile).Subject);
// Verifies every signature of the document. It returns true if all of them are valid.
// This method verifies the integrity of the signatures. It does not verify the certificate chain or the
// revocation status of the signing certificate (see the sample "Certificate Validation").
Console.WriteLine("All the signatures are valid: " + xadesSignature.VerifyDigitalSignature(signedXmlFile));
Console.WriteLine();
}
/// <summary>
/// Verifies a detached XAdES signature against the signed file.
/// </summary>
static void VerifyDetachedXadesSignature(string signatureFile, string signedFile)
{
XadesSignature xadesSignature = new XadesSignature(LibrarySerialNumber);
Console.WriteLine("Signer: " + xadesSignature.GetDigitalSignatureCertificate(signatureFile).Subject);
// The signature file and the original (signed) file are needed to verify a detached signature.
Console.WriteLine("The detached signature is valid: " + xadesSignature.VerifyDigitalSignature(signatureFile, signedFile));
Console.WriteLine();
}
The verification methods check the integrity of the signatures; check the signing certificate with the certificate validation methods. To sign several files together with XAdES signatures, use an ASiC-E container.
Run the full sample. The complete Visual Studio project XML Digital Signature - XAdES is included in the library download, in the folder NET Sample Projects (.NET 8, .NET 9 and .NET 10), with the test files and a test certificate. Without a serial number the library runs in demo mode. Download the library and the samples · User manual
Frequently asked questions
Can I create qualified XAdES signatures (eIDAS)?
Yes. A qualified electronic signature is a XAdES signature created with a qualified certificate on a qualified signature creation device (QSCD): a smart card, a USB token or an HSM. The library signs with the certificates of the Windows store, PKCS#11 devices and external signature providers.
What is the difference between XAdES and XMLDSig?
XMLDSig is the basic W3C XML signature. XAdES adds signed properties (signing time, signing certificate, commitment type) and the long-term levels. See XMLDSig in C#.
Can several people sign the same XML document?
Yes. Sign the signed document again: the new signature is added and the existing signatures remain valid.