Signature Library (SignLib) Programmer's Manual
How to create and verify digital signatures from .NET code: PDF (PAdES), CAdES / PKCS#7 (.p7m, .p7s), XMLDSig and XAdES, Office documents and ASiC-E containers, with time stamps, long term validation data and certificates from files, from the Windows store, from smart cards and from HSMs.
For .NET developers who add digital signatures to an application, a service or a script. You should know C# or VB.NET and what a digital certificate is. The concepts of electronic signatures are explained where they change what you write in code. Each chapter has a reference part (the properties and the methods, with their defaults) and examples that you can paste in a project.
1. Introduction
1.1 What the library is
SignLib, the Signature Library, is a single managed assembly (SignLib.dll) that creates and verifies electronic signatures. It does not need Adobe software, Microsoft Office, the Windows cryptographic UI or any native component: the documents are processed in memory, by your own process. The library is written in C#; the structure of the PDF documents is read and written with a modified version of iTextSharp 4.1.6 (iTextSharp-4.1.6.dll, delivered with the library).
The classes of the library, grouped by what they do:
| Task | Classes | What you get |
|---|---|---|
| Sign a PDF document | PdfSignature | PKCS#7 (adbe.pkcs7.detached) and PAdES signatures (ETSI.CAdES.detached): B-B, B-LT and B-LTA; visible or invisible; certification signatures; signature fields; document time-stamps. section 6 |
| Encrypt, merge and change PDF documents | PdfEncrypt, PdfMerge, PdfInsertObject | Password and certificate encryption, merging, text and images added to the pages. section 6.10 |
| Sign any file as CMS / CAdES | CadesSignature, CadesVerify | .p7m (attached) and .p7s (detached) files: CMS, CAdES-BES, -C, -X Long, -LT and -A; co-signatures. section 7 |
| Sign XML documents | XmlSignature, XadesSignature | Enveloped XMLDSig with RSA or ECDSA; XAdES B-B, B-T, B-LT and B-LTA, enveloped or detached. section 8 |
| Sign Office documents | OfficeSignature | Package signatures of .docx, .xlsx, .pptx (and the macro-enabled types), invisible or visible (signature lines in Word). section 9 |
| Container with signed files | AsicSignature | ASiC-E (.asice) containers with XAdES signatures. section 10 |
| Time-stamps | TimestampClient, TimestampSettings, TimestampInfo | RFC 3161 time-stamps for signatures and for files (.tsr, .tst, .tsd), and their verification. section 11 |
| Certificates | DigitalCertificate, X509CertificateGenerator | Load certificates (PFX, Windows store, smart cards), check their validity and revocation (CRL, OCSP), generate self-signed, CA and end-user certificates and certificates for a CSR. section 5 |
| Keys outside the application | IExternalSignature | Signing with PKCS#11 tokens, HSMs, cloud key vaults and remote signing services, in one step or in two phases. section 13 |
1.2 Supported platforms
The library is built from one source tree for these targets:
- .NET Framework 4.6.2 and .NET Framework 4.8 (the .NET Framework builds of
SignLib.dll; the 4.6.2 build runs on every later version of .NET Framework 4); - .NET 8, .NET 9 and .NET 10 (the .NET builds of
SignLib.dll).
Use the assembly that matches the target framework of your project. All the builds have the same public API.
The signing and verification code is managed and it does not depend on the operating system. Some functions use the Windows APIs and they are available only on Windows:
| Function | Windows only because |
|---|---|
Selecting a certificate in a window (DigitalCertificate.LoadCertificate without a criterion) | It shows the Windows certificate selection dialog. |
| Certificates of the Windows store and of the smart cards that Windows exposes (CAPI/CNG) | The Windows certificate stores. On the other systems load a PFX file or use a PKCS#11 module (section 13). |
Setting the PIN of a smart card key (DigitalCertificate.SmartCardPin, SmartCardPinExtensions.SetPinForPrivateKey) | CNG and CAPI keys (PlatformNotSupportedException on Linux and macOS). |
| Visible signatures of Office documents (signature lines) | The images of the signature lines are drawn with System.Drawing (PlatformNotSupportedException on the other systems). |
CRL download from an LDAP URL (VerificationType.LDAP) | System.DirectoryServices. |
1.3 How the manual is organized
- section 2 shows how to add the library to a project and how to register it. section 3 signs and verifies a PDF document in a few lines.
- section 4 describes what is common to all the signature classes: the usage pattern, the hash algorithms, the signature levels, what “valid” means, the exceptions, the threads and the network access. Read it once.
- section 5 explains the certificates; then one chapter for every kind of document: section 6, section 7, section 8, section 9, section 10.
- section 11, section 12 and section 13 are about the features that every format shares.
- section 14 explains what the library gives for eIDAS signatures. section 15 shows complete solutions: services, batches, parallel signing, two-phase signing over HTTP. section 16 lists the sample projects.
- section 17 lists the errors you can meet and what to do. section 18 is the reference of all the public types and members.
1.4 Conventions
- The examples are in C#, with the exceptions that say otherwise. They use the namespaces of the library (
SignLib,SignLib.Pdf,SignLib.Cades,SignLib.Xml,SignLib.Office,SignLib.Asic,SignLib.Certificates,SignLib.Timestamping) and the namespaces of .NET that appear in the first lines of the example. - Two names are assumed by the short examples: the constant
LibrarySerialNumber(the serial number string, section 2.4) and the variablesigningCertificate, anX509Certificate2with a private key (section 5.2). The examples that are complete programs define everything they use. - Names in
this fontlink to the API reference when the library has such a member. Types are written without the namespace. - Property and method names are the real ones. Defaults are written as in the documentation of the library; a property that is not mentioned has the default of its type (
false,null,0). - Indexes of signatures are 0-based in the whole library.
- Example files (
source.pdf,cert.pfxwith the password123456,test.txt) are the ones of the sample projects (section 16).
The manual explains the technical side of the electronic signatures of the eIDAS Regulation (EU) 910/2014. Whether a signature has the legal effect of a qualified electronic signature depends on the certificate, on the device that holds its key and on the law that applies to you, not on the library. See section 14.
1.5 Resources
- The library page: https://www.signfiles.com/signature-library/
- The download (library, sample projects, scripts): https://www.signfiles.com/sdk/SignatureLibrary.zip
- This manual online: https://www.signfiles.com/manuals/signature-library/
2. Installation and project setup
2.1 What is delivered
| File | Purpose |
|---|---|
SignLib.dll | The library. There is one build for each target framework: .NET Framework 4.6.2, .NET Framework 4.8, .NET 8, .NET 9 and .NET 10. The assembly is strong-named (public key token ffdaa12fb4cf4a55). |
iTextSharp-4.1.6.dll | Used by SignLib.dll to read and write the structure of the PDF documents. It must be in the folder of SignLib.dll; the build of your project copies it to the output folder. |
SignLib.xml | The documentation of the members. Keep it next to SignLib.dll: Visual Studio shows it as IntelliSense (summaries, parameters, exceptions). |
| Sample projects | One folder for .NET 8 and one for .NET Framework 4.6.2, each with its own copy of the files above in the folder SignLib. See section 16. |
The library has no installer and no native files. To install it, copy the files into a folder of your solution and reference SignLib.dll.
2.2 A .NET 8, .NET 9 or .NET 10 project
Reference the assembly with a HintPath and add the NuGet packages that the library uses. The library is referenced as a file, so the packages that it uses are not added automatically: add them to your project (the versions are the ones the library was built with; they are the same for .NET 8, .NET 9 and .NET 10, and the build for your target framework is the one in the folder net8.0, net9.0 or net10.0 of the library):
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<!-- Used by every signature class -->
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="10.0.12" />
<PackageReference Include="System.Security.Cryptography.Xml" Version="10.0.12" />
<PackageReference Include="System.Windows.Extensions" Version="10.0.12" />
<!-- Office signatures (and the images of the signature lines), and the LDAP downloads of CRLs -->
<PackageReference Include="System.IO.Packaging" Version="10.0.12" />
<PackageReference Include="System.Drawing.Common" Version="10.0.12" />
<PackageReference Include="System.DirectoryServices" Version="10.0.12" />
</ItemGroup>
<ItemGroup>
<Reference Include="SignLib">
<HintPath>..\SignLib\SignLib.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
| Package | Needed for |
|---|---|
System.Security.Cryptography.Pkcs, System.Security.Cryptography.Xml, System.Windows.Extensions | All the projects: CMS / CAdES and PDF signatures, XML signatures, the certificate dialogs. |
System.IO.Packaging, System.Drawing.Common | Office documents: the package parts, and the images of the signature lines. Not needed by the PDF, CAdES, XML, XAdES and ASiC-E classes. |
System.DirectoryServices | Downloading CRLs from an LDAP address (Windows). |
Pkcs11Interop (not a dependency of the library) | Only in the samples that talk to a PKCS#11 module: the sample class Pkcs11ExternalSignature uses it (section 13.3). |
In Visual Studio the same is done with Project > Add Project Reference > Browse, selecting SignLib.dll, and with Manage NuGet Packages.
2.3 A .NET Framework 4.6.2 project
Add the reference to the .NET Framework build of SignLib.dll and the framework assemblies that the features need:
<ItemGroup>
<Reference Include="SignLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=ffdaa12fb4cf4a55, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\SignLib\SignLib.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Security" />
<Reference Include="System.Xml" />
<!-- Office signatures: WindowsBase; ASiC-E containers: System.IO.Compression -->
<Reference Include="WindowsBase" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
</ItemGroup>
The source code of the library is C# 7.3, so every public member can be used from a .NET Framework 4.6.2 project with the language version of that framework. No NuGet package is needed on .NET Framework.
The time-stamp, OCSP and CRL requests use HttpWebRequest on .NET Framework. The TLS versions can be set only for the whole application (ServicePointManager.SecurityProtocol). The library adds the missing TLS versions only when the application does not leave the choice to the operating system. If a server accepts TLS 1.2 only and a request fails, set ServicePointManager.SecurityProtocol yourself at the start of the program. On .NET the requests are sent with a HttpClient of the library, and its TLS settings do not affect the rest of the application.
2.4 The serial number
Every class that creates or verifies signatures takes the serial number of the library as the parameter of its constructor:
const string LibrarySerialNumber = "YourSerialNumber";
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
CadesSignature cadesSignature = new CadesSignature(LibrarySerialNumber);
XadesSignature xadesSignature = new XadesSignature(LibrarySerialNumber);
- Replace
YourSerialNumberwith the serial number that you received when you purchased the library. The serial number is checked when the first object is created; a valid serial number registers the library for the whole process, so the objects created later work in the licensed mode, whatever serial number they receive. - An invalid or missing serial number is not an error: the library runs as the demo version. The demo version has the same functions as the licensed one, with these limits:
- a message is written to the console (
Consoleis not required: the message is skipped when the process has no console); - the PDF documents loaded for signing, that have no signature yet, get the text
SignLib.dll DEMO VERSIONon the first page; - every signature creation or verification of CAdES, XML, XAdES, Office and ASiC-E documents and every time-stamp request wait 10 seconds before it starts;
- the certificates created with
X509CertificateGeneratorare valid for 30 days at most (the validity is cut to 30 days; the call waits 10 seconds when it has to cut it).
- a message is written to the console (
- The demo version is meant for the evaluation of the library: the results are correct signatures, only the demonstration marks are added.
The samples keep it in a constant, to stay short. In an application read it from the configuration (a settings file, an environment variable, a secret store) and pass it to the constructors. The serial number is not a secret of the signed documents, but it identifies your license: do not publish it in a public repository.
string serialNumber = Environment.GetEnvironmentVariable("SIGNLIB_SERIAL"); // null: the demo version
PdfSignature pdfSignature = new PdfSignature(serialNumber);
2.5 Check the installation
A program that prints the version of the assembly and signs nothing:
using System;
using SignLib.Pdf;
class Program
{
static void Main()
{
// The assembly of any public class of the library.
System.Reflection.AssemblyName name = typeof(PdfSignature).Assembly.GetName();
Console.WriteLine(name.Name + " " + name.Version);
Console.WriteLine("Runtime: " + Environment.Version);
}
}
If the program starts, the assembly and its dependencies are found. The most frequent mistakes at this point are in section 17 (a missing iTextSharp-4.1.6.dll, the wrong build for the target framework).
2.6 Deployment
- Deploy
SignLib.dllandiTextSharp-4.1.6.dllwith your application (both are copied by the build when they are in the same folder). - The 32-bit or 64-bit process is not a constraint of the library. It matters only for the PKCS#11 modules and for the smart card middleware: a 64-bit process needs the 64-bit module (section 13.3).
- The library does not write files by itself and it does not keep the documents after the call returns. The signed document is returned as
byte[]; you decide where it is stored. - Allow the outgoing HTTP and HTTPS connections of the process to the time-stamping servers, to the OCSP responders and to the CRL addresses of the certificates, when you use these features (section 4.10).
The library includes parts of the Bouncy Castle C# API (MIT license), see Appendix D.
3. Quick start
This chapter signs a PDF document with a certificate from a PFX file and verifies the result, in C#, in VB.NET and in PowerShell. It uses the files of the sample projects: source.pdf and cert.pfx (a self-signed test certificate, the password is 123456). Replace YourSerialNumber with your serial number (section 2.4).
3.1 Sign and verify a PDF document
using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using SignLib.Certificates;
using SignLib.Pdf;
class Program
{
private const string LibrarySerialNumber = "YourSerialNumber";
static void Main()
{
// 1. The signing certificate, with its private key, from a PFX file.
X509Certificate2 certificate = DigitalCertificate.LoadCertificate("cert.pfx", "123456");
// 2. Load the document and set the signature.
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = certificate;
pdfSignature.SigningReason = "I approve this document";
pdfSignature.SignaturePosition = SignaturePosition.TopLeft;
// 3. Sign: the result is the signed PDF document.
byte[] signedPdf = pdfSignature.ApplyDigitalSignature();
File.WriteAllBytes("source[signed].pdf", signedPdf);
// 4. Verify: load the signed document and read its signatures.
PdfSignature verifier = new PdfSignature(LibrarySerialNumber);
verifier.LoadPdfDocument(signedPdf);
foreach (PdfSignatureInfo info in verifier.DocumentProperties.DigitalSignatures)
{
Console.WriteLine(info.SignatureName + ": signed by " + info.SignatureCertificate.GetNameInfo(X509NameType.SimpleName, false)
+ ", intact: " + info.SignatureIsValid);
}
}
}
What the code does:
DigitalCertificate.LoadCertificate(file, password)returns anX509Certificate2with the private key. Other sources are in section 5.2.- A
PdfSignatureobject holds the settings of the signature. You load the document, set the certificate and the options of the visible signature. ApplyDigitalSignature()returns the signed document as abyte[]. The library never overwrites the input file.- The verification is done with the same class.
SignatureIsValidsays that the document was not changed after it was signed and that the signature value matches the certificate in the signature. It does not say that you can trust the signer: see section 4.5.
3.2 The same in VB.NET
Imports System
Imports System.IO
Imports System.Security.Cryptography.X509Certificates
Imports SignLib.Certificates
Imports SignLib.Pdf
Module Program
Private Const LibrarySerialNumber As String = "YourSerialNumber"
Sub Main()
Dim certificate As X509Certificate2 = DigitalCertificate.LoadCertificate("cert.pfx", "123456")
Dim pdfSignature As New PdfSignature(LibrarySerialNumber)
pdfSignature.LoadPdfDocument("source.pdf")
pdfSignature.DigitalSignatureCertificate = certificate
pdfSignature.SigningReason = "I approve this document"
pdfSignature.SignaturePosition = SignaturePosition.TopLeft
Dim signedPdf As Byte() = pdfSignature.ApplyDigitalSignature()
File.WriteAllBytes("source[signed].pdf", signedPdf)
Dim verifier As New PdfSignature(LibrarySerialNumber)
verifier.LoadPdfDocument(signedPdf)
For Each info As PdfSignatureInfo In verifier.DocumentProperties.DigitalSignatures
Console.WriteLine(info.SignatureName & ": intact: " & info.SignatureIsValid.ToString())
Next
End Sub
End Module
All the examples of this manual are in C#; the VB.NET code is the same calls with the syntax of the language. The sample set for .NET Framework contains a complete VB.NET project (section 16).
3.3 The same in PowerShell
Windows PowerShell 5.1 runs on .NET Framework, so it uses the .NET Framework build of the library. Load iTextSharp-4.1.6.dll before SignLib.dll (the loader of PowerShell does not search the folder of the script for the dependencies):
$dir = $PSScriptRoot
[Reflection.Assembly]::LoadFrom("$dir\iTextSharp-4.1.6.dll") | Out-Null
[Reflection.Assembly]::LoadFrom("$dir\SignLib.dll") | Out-Null
$serial = "YourSerialNumber"
$certificate = [SignLib.Certificates.DigitalCertificate]::LoadCertificate("$dir\cert.pfx", "123456")
$signature = New-Object SignLib.Pdf.PdfSignature($serial)
$signature.LoadPdfDocument("$dir\source.pdf")
$signature.DigitalSignatureCertificate = $certificate
$signature.SigningReason = "I approve this document"
[IO.File]::WriteAllBytes("$dir\source[signed].pdf", $signature.ApplyDigitalSignature())
$check = New-Object SignLib.Pdf.PdfSignature($serial)
$check.LoadPdfDocument("$dir\source[signed].pdf")
foreach ($info in $check.DocumentProperties.DigitalSignatures) {
"{0}: intact = {1}" -f $info.SignatureName, $info.SignatureIsValid
}
Run it with powershell.exe -File sign.ps1. Enumerations are written [SignLib.Pdf.SignaturePosition]::TopLeft. PowerShell 7 runs on .NET: use the .NET build of the library and the same loading lines.
3.4 Sign any file as .p7m
The same pattern with CadesSignature signs a file of any type; the result is a .p7m file that contains the file and its signature. CadesVerify verifies it and returns the signers and the original file:
CadesSignature cadesSignature = new CadesSignature(LibrarySerialNumber);
cadesSignature.DigitalSignatureCertificate = signingCertificate;
File.WriteAllBytes("test.txt.p7m", cadesSignature.ApplyDigitalSignature("test.txt"));
CadesVerify cadesVerify = new CadesVerify("test.txt.p7m", LibrarySerialNumber);
foreach (CadesSignatureInfo signer in cadesVerify.Signatures)
Console.WriteLine(signer.SignatureCertificate.Subject + ", intact: " + signer.SignatureIsValid);
File.WriteAllBytes("test.txt.verified", cadesVerify.UnsignedDocument); // the signed file, extracted
The XML, Office and ASiC-E classes follow the same pattern: set the certificate and the level, call ApplyDigitalSignature, and verify with VerifyDigitalSignature (section 8, section 9, section 10).
- The common behavior of all the classes: section 4.
- Certificates from the Windows store, from a smart card or from a key vault: section 5 and section 13.
- A signature that stays valid for years (time-stamp, validation data): section 12.
- Complete samples to run: section 16.
4. Concepts common to all the signature classes
This chapter describes what you need to know once, before the chapters about the formats: the usage pattern of the classes, the hash algorithms, the signature levels, what a verification result means, the exceptions, the threads and the network access.
4.1 The usage pattern
Every format has a class that signs (and, for most formats, verifies) with the same steps:
- create the object with the serial number of the library;
- set the signing certificate (
DigitalSignatureCertificate) and the options of the signature (properties); - call
ApplyDigitalSignature; - to verify, call
VerifyDigitalSignature, or read the information of the signatures.
The objects keep their settings between the calls, so you can set the certificate and the options once and sign many documents with the same object (but not from several threads at the same time, section 4.9). The signing methods return the signed document or write it to the output you give; they never change the input.
| Class | Document in | Signing method | Result |
|---|---|---|---|
PdfSignature | LoadPdfDocument(string | byte[] | Uri) | ApplyDigitalSignature() | byte[], the signed PDF |
CadesSignature | the parameter | ApplyDigitalSignature(string file | byte[] data) | byte[], the .p7m (or the .p7s of a detached signature) |
XmlSignature | the parameters | ApplyDigitalSignature(string in, string out), ApplyDigitalSignature(Stream in, Stream out) | the signed XML, written to the output |
XadesSignature | the parameters | ApplyDigitalSignature(string in, string out) | the signed XML, or the signature file (detached) |
OfficeSignature | the parameters | ApplyDigitalSignature(string in, string out), (byte[]), (Stream) | the signed document |
AsicSignature | the files | CreateContainer(...), AddSignature(...) | the .asice container |
The classes that sign XML and Office documents write the result to the output file, and delete a partially written output file when the signature fails (the input file is never deleted: the input and the output can be the same file).
4.2 Formats and standards
| Class | Signature | Standard |
|---|---|---|
PdfSignature | PKCS#7 detached (adbe.pkcs7.detached); PAdES B-B, B-LT and B-LTA (ETSI.CAdES.detached with the document security store) | ISO 32000-1 (PDF), ETSI EN 319 142-1 (PAdES), RFC 5652 (CMS) |
CadesSignature | CMS / PKCS#7; CAdES-BES, -C, -X Long, -LT, -A; attached (.p7m) or detached (.p7s) | RFC 5652, ETSI EN 319 122-1 (CAdES), ETSI TS 101 733 |
XmlSignature | XMLDSig enveloped, RSA or ECDSA | W3C XML Signature, RFC 6931 (ECDSA) |
XadesSignature | XAdES B-B, B-T, B-LT, B-LTA; enveloped or detached | ETSI EN 319 132-1 |
OfficeSignature | Office Open XML package signatures with XAdES properties (B-B, B-T, B-LT) | ECMA-376 Part 2, [MS-OFFCRYPTO] |
AsicSignature | ASiC-E container with XAdES signatures (B-B, B-T, B-LT, B-LTA) | ETSI EN 319 162-1 |
TimestampClient | RFC 3161 time-stamps: .tsr, .tst, .tsd | RFC 3161, RFC 5544 (TimeStampedData) |
4.3 Hash algorithms
The enumeration HashAlgorithm has SHA1, SHA256, SHA384 and SHA512. Every signature class has a HashAlgorithm property; the default is SHA-256. The time-stamp requests have their own setting (TimestampSettings.HashAlgorithm, default SHA-256).
- SHA-1 is not considered secure for new signatures. The PDF and CMS signature classes still accept it, to interoperate with old systems. The XML, XAdES, Office and ASiC-E classes do not create SHA-1 signatures (
NotSupportedException); they verify them. - The signature algorithm follows the key of the certificate: RSA (PKCS#1 v1.5) or ECDSA (the curve of the key). The key size or the curve are not set by the signature classes. They are chosen when the certificate is created (section 5.5).
4.4 Signature levels
The ETSI standards define profiles of increasing durability. They are called B-B (basic), B-T (with a time-stamp), B-LT (with long term validation data) and B-LTA (with archival time-stamps). The names of the levels differ in the libraries of the classes, but the idea is the same:
- B-B proves who signed and that the document was not changed. Its validity depends on the certificate of the signer at the moment of the verification: after the certificate expires or is revoked, a B-B signature cannot be validated any more.
- B-T adds a time-stamp (RFC 3161) from a time-stamping authority: it proves that the signature existed at that time. The signing time written by the signer is only a claim of the signer; the time of the time-stamp is a proof.
- B-LT embeds the certificates of the chain and the revocation information (CRLs and OCSP responses) that existed when the signature was made, so the signature can be validated after the servers of the certification authority are no longer available.
- B-LTA adds a time-stamp over the signature and its validation data. It is renewed periodically with a new time-stamp, before the previous one becomes weak or its certificate expires (section 12.4).
4.5 What “valid” means
The verification methods of the library (PdfSignatureInfo.SignatureIsValid, CadesSignatureInfo.SignatureIsValid, XmlSignature.VerifyDigitalSignature, XadesSignature.VerifyDigitalSignature, OfficeSignature.VerifyDigitalSignature, AsicSignature.VerifyDigitalSignature) answer one question: is the signature intact? They verify that
- the signed data was not changed after it was signed (the digests of the signed content and of the signed attributes);
- the signature value was created with the private key of the certificate that is in the signature.
They do not verify that you can trust the signer. A complete verification has more questions, and each one has its own tool:
| Question | How to answer it |
|---|---|
| Is the signature intact? | SignatureIsValid, VerifyDigitalSignature. |
| Was the certificate valid when the document was signed (period of validity)? | Compare the signing time with NotBefore and NotAfter of the certificate. For a time-stamped signature use the time of the time-stamp (PdfSignatureInfo.SignatureTime returns it). |
| Was the certificate revoked? | DigitalCertificate.VerifyDigitalCertificate with VerificationType.OCSP or VerificationType.CRL (section 5.4). For a signature that includes the validation data, use the revocation data that it contains. |
| Does the chain of the certificate end in a root that you trust? | The trust is a decision of the application: the Windows store (X509Chain), your own list of roots, or the EU trusted lists for qualified certificates. The library gives the certificates that are in the signature. |
| Is the time reliable? | The time-stamp of the signature (TimestampInfo), and the certificate of the time-stamping authority. |
| Is the signature qualified, and which level is it in eIDAS? | An eIDAS validation service (for example the EU DSS validator) with the trusted lists. section 14. |
A self-signed certificate created in a minute produces signatures that are intact. If your application shows the result to a person, add the checks of the certificate and say what was verified. A full verification routine is in section 6.11.
4.6 The time of a signature
Signatures have two different times, and the property names say which one you read:
- the signing time declared by the signer: it is the clock of the computer that signs (UTC).
PdfSignature.SignatureDateis the value that is written in the PDF signature;CadesSignatureInfo.SignatureTimeandOfficeSignatureInfo.SigningTimeread it. Anyone can set the clock of a computer: this time is not a proof; - the time-stamp time: the time put in the signature by a time-stamping authority (
TimestampInfo.SignatureTime). It is a proof that the signature existed at that moment.
PdfSignatureInfo.SignatureTime returns the time of the time-stamp when the signature has one, and the time declared by the signer otherwise (check SignatureIsTimestamped).
4.7 Files, byte arrays and streams
The library works in memory. A document is read completely, processed and returned as byte[] (or written to the output you give). Plan the memory of your process for the size of the documents and for the number of documents that you sign in parallel. The classes that sign XML and Office documents and the ASiC-E container have overloads for files, byte arrays and streams; use the byte array or the stream version in a web application, so that the documents do not touch the disk.
PdfSignature.LoadPdfDocument(Uri) downloads the document with an HTTP request; the time-out of the download is DigitalCertificate.Timeout.
4.8 Exceptions
The methods of the library throw the standard .NET exceptions; the message describes the cause. These are the ones that you should expect, with their usual causes:
| Exception | When |
|---|---|
NullReferenceException | The signing certificate (Digital certificate is not set.) or the document (Document is not loaded.) was not set before the call. The library uses this exception for these two mistakes of the caller. |
ArgumentException, ArgumentNullException, ArgumentOutOfRangeException | A parameter or a property has a value that is not valid: a missing value, a page that does not exist (Invalid signature page number.), a name or a URL that is not valid, a serial number that cannot be checked. |
FileNotFoundException | An input file does not exist. |
CryptographicException | The signature, the certificate or the document cannot be processed: no private key, the key cannot be used, a PIN is wrong, the file is not a CMS signature, a signature does not fit in the space reserved for it, a PFX file cannot be loaded, a password is wrong, an already signed PDF document is encrypted. Most of the errors of the signature creation are reported with this type. |
WebException | The time-stamping server did not answer, it answered with an error or its response is not valid (Invalid time stamping response. and the details). |
NotSupportedException | The combination of options is not supported: SHA-1 for a new XML, XAdES, Office or ASiC-E signature, the level XAdES-LTA for an Office document. |
InvalidOperationException | The operation is not allowed in the state of the document: for example a signature line added to an Office document that is already signed. |
PlatformNotSupportedException | A function that needs Windows, on another operating system (section 1.2). |
Catch the exceptions at the level where you can act on them, and show or log ex.Message. The library reports the original failure as the message or as the inner exception. When the signing of a file fails, the partial output file is deleted (the original is never deleted).
try
{
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = signingCertificate;
File.WriteAllBytes("source[signed].pdf", pdfSignature.ApplyDigitalSignature());
}
catch (WebException ex)
{
// The time-stamping server (when TimeStamping.ServerUrl is set) is not reachable: retry later or use another server.
Console.WriteLine("Time-stamp: " + ex.Message);
}
catch (CryptographicException ex)
{
// The key, the certificate or the document cannot be used.
Console.WriteLine("Signature: " + ex.Message);
}
4.9 Threads and static state
- The signature objects (
PdfSignature,CadesSignature,XadesSignature,OfficeSignature...) are not thread-safe. Use one object for every thread (or every request) and never share an object between threads that run at the same time. Creating an object is cheap. - An
X509Certificate2with a private key from a PFX file can be shared by the threads. A certificate on a smart card cannot, usually: the sessions of the token are limited. DigitalCertificate.UseExternalSignatureProviderandDigitalCertificate.SmartCardPinare thread-local and the library releases them after every signing operation. Set them on the thread that signs, immediately before the call, every time (section 13.1).- The license is process-wide: a valid serial number switches the whole process to the licensed mode (section 2.4).
DigitalCertificate.Timeoutis a static field: it applies to all the threads.
A complete example of parallel signing is in section 15.3.
4.10 Network access
The library opens network connections only for these functions:
| Function | Connection |
|---|---|
Signatures with a time-stamp (TimeStamping.ServerUrl set), B-T and higher levels, TimestampClient | HTTP POST to the time-stamping server (RFC 3161). Time-out: TimestampSettings.ServerTimeout, 20 seconds by default. |
Long term validation data (PadesLtvLevel, LtvLevel, the CAdES levels C, X Long, LT and A) | Downloads of the CRLs and of the OCSP responses of the certificate chain, and of the certificates of the issuers, from the addresses written in the certificates. |
DigitalCertificate.VerifyDigitalCertificate with OCSP, CRL or LDAP | HTTP (or LDAP) to the address of the certificate. |
PdfSignature.LoadPdfDocument(Uri), PdfEncrypt.LoadPdfDocument(Uri) | HTTP GET of the document. |
The time-out of the downloads (CRL, OCSP, documents) is DigitalCertificate.Timeout (milliseconds, 20000 by default). The requests use the proxy settings of the platform; the user agent is SignLib. A server that requires authentication is supported for the time-stamping (TimestampSettings.UserName, Password, AuthenticationCertificate). The signing and verification of a signature without these functions do not use the network.
When a document is signed with the long term validation data, the CRL and the OCSP downloads add seconds to the call and they depend on servers that you do not control. Sign with a time limit (a task with a time-out), handle the exceptions of the time-stamping server and, when the volume is large, use a local time-stamping server. A signature without the time-stamp and the validation data is created without any network access.
5. Digital certificates
A signature is created with the private key of a certificate. This chapter shows how to get an X509Certificate2 for the signature classes, how to inspect and validate certificates, and how to create certificates for tests and for internal use. The classes are DigitalCertificate (static methods, no serial number needed) and X509CertificateGenerator.
5.1 What the signature classes need
- An
X509Certificate2with a private key (HasPrivateKeyis true), set in the propertyDigitalSignatureCertificateof the signature class. Exception: when the key is outside the process (a PKCS#11 token, an HSM, a key vault, a remote service) the certificate has only the public part and an external signature provider creates the signature value (section 13). - An RSA or an ECDSA key. The XML, XAdES, Office and ASiC-E classes accept only these two key types.
- The library does not check the key usages of the certificate when it signs. The validators do: a certificate used for document signing should have the key usage digitalSignature and/or nonRepudiation (content commitment). A certificate issued for a person or an organization by a certification authority has them.
- The signing does not check that the certificate is valid or trusted, either. Check it before you sign when your application must not sign with an expired or a revoked certificate (section 5.4).
5.2 Loading a certificate
From a PFX (PKCS#12) file
DigitalCertificate.LoadCertificate(string file, string password) and LoadCertificate(byte[] content, string password) load the certificate with its private key. On .NET the library asks the platform to keep the private key in memory (an ephemeral key set), so that it is not written to the disk; on .NET Framework the key is kept in a temporary key container that is deleted when the certificate is disposed.
X509Certificate2 fromFile = DigitalCertificate.LoadCertificate("cert.pfx", "123456");
X509Certificate2 fromBytes = DigitalCertificate.LoadCertificate(File.ReadAllBytes("cert.pfx"), "123456");
Console.WriteLine(fromFile.Subject + ", private key: " + fromFile.HasPrivateKey);
// Dispose the certificate when you do not need it any more (it releases the private key).
fromFile.Dispose();
fromBytes.Dispose();
A wrong password, or a file that is not a PFX file, throws CryptographicException; a missing file throws FileNotFoundException.
From the Windows certificate store
The certificates of the current user (or of the local computer) are available to the library, together with the certificates that a smart card or a USB token makes available through its Windows driver (the “minidriver”). The overloads of LoadCertificate either show a selection window or find the certificate by code:
| Call | Result |
|---|---|
LoadCertificate() | The Windows selection window with all the certificates of the current user; returns the selected certificate, or null when the user cancels. |
LoadCertificate(string subject) | The window, with the certificates whose subject contains the text. |
LoadCertificate(bool validOnly, string issuerName, string title, string description) | The window, with the certificates of an issuer. validOnly keeps only the certificates that are in their validity period. Overloads with fromLocalMachine use the computer store; overloads with smartCardPin set the PIN so that the PIN window does not appear. |
LoadCertificate(bool validOnly, DigitalCertificateSearchCriteria criterion, string value) | No window: the first certificate that matches. The criteria: a field of the subject (CommonNameCN, OrganizationO, OrganizationUnitOU, EmailE, LocalityL, CountryC, StateS, TitleT), Thumbprint or SerialNumber. |
// With a window: the user selects the certificate.
X509Certificate2 selected = DigitalCertificate.LoadCertificate(false, string.Empty, "Select Certificate", "Select the certificate for the digital signature");
// Without a window (services, batch programs): by thumbprint, by serial number or by a field of the subject.
X509Certificate2 byThumbprint = DigitalCertificate.LoadCertificate(true, DigitalCertificateSearchCriteria.Thumbprint, "FAC4D3EF766A59BB068DD90877267EBC56B4232A");
X509Certificate2 byName = DigitalCertificate.LoadCertificate(true, DigitalCertificateSearchCriteria.CommonNameCN, "John Smith");
// The certificates of the local computer (a service account has no user store).
X509Certificate2 machineCert = DigitalCertificate.LoadCertificate(true, DigitalCertificateSearchCriteria.Thumbprint, "FAC4D3EF766A59BB068DD90877267EBC56B4232A", true);
if (byThumbprint == null)
throw new InvalidOperationException("The certificate was not found in the store.");
The store overloads work on Windows. The selection window cannot be shown by a service or by a web application: use the criteria without a window, and set the PIN of a smart card from code. The thumbprint is displayed by the Windows certificate viewer (Details > Thumbprint) and by X509Certificate2.Thumbprint.
A certificate on a smart card or on a USB token
A token whose certificate is in the Windows store is used like any other certificate of the store. The driver of the token asks for the PIN in a window the first time the key is used. To avoid the window, give the PIN to the library:
X509Certificate2 tokenCertificate = DigitalCertificate.LoadCertificate(true, DigitalCertificateSearchCriteria.Thumbprint, "FAC4D3EF766A59BB068DD90877267EBC56B4232A");
string pin = Environment.GetEnvironmentVariable("TOKEN_PIN"); // read the PIN from a protected source
// The PIN is used for the next signing operation of this thread, then the library forgets it.
DigitalCertificate.SmartCardPin = pin;
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = tokenCertificate;
byte[] signedPdf = pdfSignature.ApplyDigitalSignature();
DigitalCertificate.SmartCardPinis thread-local and it is cleared as soon as the signing operation uses it, so a PIN is never applied to another card by mistake. Set it again before the next signature. A wrong PIN that is sent again and again can block the token.- The same can be done when the certificate is loaded (the
smartCardPinoverloads), or for a certificate you already have with the extension methodcertificate.SetPinForPrivateKey(pin)(SmartCardPinExtensions). - Not every token accepts the PIN from the application; for the tokens that do not, and for non-Windows systems, use the PKCS#11 module of the token with an external signature provider (section 13.3).
- Never store the PIN in the source code or in a configuration file that is not protected.
5.3 Reading the certificate
The X509Certificate2 class has the common properties (Subject, Issuer, NotBefore, NotAfter, Thumbprint, SerialNumber). DigitalCertificate adds the checks that the .NET class does not have:
// The key usages: null when the certificate has no key usage extension.
List<CertificateKeyUsage> usages = DigitalCertificate.GetKeyUsage(signingCertificate);
bool canSignDocuments = usages == null || usages.Contains(CertificateKeyUsage.DigitalSignature) || usages.Contains(CertificateKeyUsage.NonRepudiation);
// A certificate that declares itself qualified (the qcStatements extension, ETSI EN 319 412-5).
// The qualified status itself is given by the EU trusted lists, not by this extension.
bool declaresQualified = DigitalCertificate.IsQualifiedCertificate(signingCertificate);
// The chain of the certificate is built with the standard .NET class.
X509Chain chain = new X509Chain();
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
bool chainBuilt = chain.Build(signingCertificate);
foreach (X509ChainElement element in chain.ChainElements)
Console.WriteLine(element.Certificate.Subject);
5.4 Validating a certificate
DigitalCertificate.VerifyDigitalCertificate(certificate, type) returns a CertificateStatus. The type of the verification selects how the status is obtained:
VerificationType | What it checks |
|---|---|
LocalTime | The validity period of the certificate, with the clock of the computer. No network. Returns Valid or Expired (not yet valid or expired). |
OCSP | Asks the OCSP responder that is written in the certificate (the Authority Information Access extension). Returns Valid, Revoked, Unknown (the answer could not be obtained) or NotPresent (the certificate has no OCSP responder). |
CRL | Downloads the HTTP CRL of the certificate (CRL distribution points) and looks for the certificate in it. NotPresent when the certificate has no CRL. |
LDAP | The same, with the LDAP address of the CRL (Windows). |
DigitalCertificate.Timeout = 20000; // milliseconds, for the downloads of the CRL and of the OCSP responses
if (DigitalCertificate.VerifyDigitalCertificate(signingCertificate, VerificationType.LocalTime) != CertificateStatus.Valid)
throw new InvalidOperationException("The certificate is expired or not yet valid.");
CertificateStatus ocsp = DigitalCertificate.VerifyDigitalCertificate(signingCertificate, VerificationType.OCSP);
if (ocsp == CertificateStatus.Revoked)
{
// The date of the revocation is read from the CRL of the certificate.
DateTime revokedOn = DigitalCertificate.GetCertificateRevocationDate(signingCertificate);
Console.WriteLine("Revoked on " + revokedOn);
}
else if (ocsp == CertificateStatus.NotPresent)
{
// The certificate has no OCSP responder: try the CRL.
CertificateStatus crl = DigitalCertificate.VerifyDigitalCertificate(signingCertificate, VerificationType.CRL);
Console.WriteLine("CRL: " + crl);
}
Unknownis notValid: the server could not be reached, or it did not answer. Decide, for your application, if an unknown status blocks the operation.- The method checks one certificate. It does not build the chain and it does not check the certificates of the issuers: validate the certificates of the chain, or use
X509Chainwith the revocation mode that you need. It does not decide that a root is trusted. - The self-signed test certificates and the certificates created by
X509CertificateGeneratorhave no CRL and no OCSP responder, unless you add them to the certificate (section 5.5): the revocation checks returnNotPresent.
5.5 Creating certificates
X509CertificateGenerator creates X.509 certificates with RSA or ECDSA keys, in memory, and returns them as PFX (PKCS#12) bytes protected by a password. Use it for tests, for internal use, for the signing of your own documents, and in a small internal certification authority. The certificates are not trusted by the other computers until the root certificate is installed on them. A certificate for the legal signature of documents is issued by a certification authority, after the identification of the person.
The generator needs the serial number of the library. The certificates created by the demo version are valid for 30 days at most (section 2.4).
A self-signed certificate
X509CertificateGenerator generator = new X509CertificateGenerator(LibrarySerialNumber);
generator.ValidFrom = DateTime.Now;
generator.ValidTo = DateTime.Now.AddYears(2);
generator.KeySize = KeySize.KeySize2048Bit;
generator.SignatureAlgorithm = SignatureAlgorithm.SHA256WithRSA;
// The subject as one string, or attribute by attribute with AddToSubject(SubjectType.CN, "...").
generator.Subject = "CN=John Smith, O=Example Ltd, C=RO, E=john@example.com";
// What the certificate can be used for.
generator.Extensions.AddKeyUsage(CertificateKeyUsage.DigitalSignature);
generator.Extensions.AddKeyUsage(CertificateKeyUsage.NonRepudiation);
generator.Extensions.AddEnhancedKeyUsage(CertificateEnhancedKeyUsage.DocumentSigning);
// The PFX file: the certificate and the private key, protected by the password.
byte[] pfx = generator.GenerateCertificate("123456", false);
File.WriteAllBytes("john.pfx", pfx);
// The public part, to give to the people who verify the signatures.
X509Certificate2 certificate = new X509Certificate2(pfx, "123456");
File.WriteAllBytes("john.cer", certificate.RawData);
The second parameter of GenerateCertificate(password, isRootCertificate) is false for an end-entity certificate and true for a CA certificate. When no root certificate is loaded, the certificate is signed with its own key (self-signed).
Settings of the generator
| Property / method | Meaning and default |
|---|---|
Subject, AddToSubject | The subject. AddToSubject(SubjectType, value) builds it attribute by attribute (CN, O, OU, C, E, SERIALNUMBER, GIVENNAME...). When Subject is set, it replaces the attributes. One of them is required. |
ValidFrom, ValidTo | The validity, in local time. Defaults: now, and one year later (30 days at most on the demo version). |
KeyAlgorithm, KeySize, EllipticCurve | RSA (default) or ECDSA. The RSA size is KeySize2048Bit by default (use KeySize4096Bit for CA certificates; the 512 and 1024 bit sizes are obsolete). The ECDSA curves: NistP256 (the default), NistP384, NistP521, BrainpoolP256r1, BrainpoolP384r1, BrainpoolP512r1. |
SignatureAlgorithm | The hash of the signature of the certificate (SHA-1 not recommended; SHA-256, SHA-384, SHA-512). The signature is RSA or ECDSA by the key of the issuer. |
SerialNumber | The serial number of the certificate; a random 128-bit number when it is not set. |
FriendlyName | The name in the PFX file; a unique name when it is empty. |
SubjectAlternativeNames, AddSubjectAlternativeName | The alternative names (DNS, IP address, e-mail, URI). The type is detected from the value, or given explicitly with SubjectAlternativeNameType. |
Extensions | Key usages, enhanced key usages, CRL addresses, OCSP, CA issuers, policies, QC statements, path length (section 5.5). |
LoadRootCertificate(byte[] pfx, string password) | The issuer: the next certificates are signed with this CA certificate. |
An ECDSA certificate
X509CertificateGenerator generator = new X509CertificateGenerator(LibrarySerialNumber);
generator.KeyAlgorithm = KeyAlgorithm.ECDSA;
generator.EllipticCurve = EllipticCurve.NistP384;
generator.SignatureAlgorithm = SignatureAlgorithm.SHA384WithECDSA; // the hash; the algorithm follows the key of the issuer
generator.Subject = "CN=ECDSA signer, O=Example Ltd";
generator.Extensions.AddKeyUsage(CertificateKeyUsage.DigitalSignature);
byte[] pfx = generator.GenerateCertificate("123456", false);
The key usages of an ECDSA key are checked against RFC 5480: KeyEncipherment and DataEncipherment are not allowed for these keys.
A root certificate and a certificate that it issues
// 1. The root (CA) certificate.
X509CertificateGenerator root = new X509CertificateGenerator(LibrarySerialNumber);
root.ValidTo = DateTime.Now.AddYears(10);
root.KeySize = KeySize.KeySize4096Bit;
root.Subject = "CN=Example Root CA, O=Example Ltd";
root.Extensions.AddKeyUsage(CertificateKeyUsage.CertificateSigning);
root.Extensions.AddKeyUsage(CertificateKeyUsage.CRLSigning);
root.Extensions.PathLengthConstraint = 0; // the CA issues only end-entity certificates
byte[] rootPfx = root.GenerateCertificate("rootPassword", true);
// 2. An end-entity certificate issued by the root.
X509CertificateGenerator user = new X509CertificateGenerator(LibrarySerialNumber);
user.LoadRootCertificate(rootPfx, "rootPassword");
user.ValidTo = DateTime.Now.AddYears(2);
user.Subject = "CN=Mary Jones, O=Example Ltd";
user.Extensions.AddKeyUsage(CertificateKeyUsage.DigitalSignature);
user.Extensions.AddKeyUsage(CertificateKeyUsage.NonRepudiation);
user.Extensions.KeyUsageIsCritical = true;
byte[] userPfx = user.GenerateCertificate("userPassword", false);
// The PFX of the user also contains the root certificate: a signature that is created with it can include the chain.
X509Certificate2 userCertificate = new X509Certificate2(userPfx, "userPassword");
To install the root certificate on the computers that must trust the certificates (the Windows store Trusted Root Certification Authorities), distribute its public part (rootCertificate.RawData, a .cer file), never the PFX.
Extensions: revocation addresses, policies, qualified statements
The validators use the addresses in the certificate to check its revocation. A certificate that you issue for a test of the long term validation features needs them (and CRL and OCSP servers that answer at these addresses):
X509CertificateGenerator generator = new X509CertificateGenerator(LibrarySerialNumber);
generator.Subject = "CN=Test signer, O=Example Ltd";
generator.Extensions.AddKeyUsage(CertificateKeyUsage.DigitalSignature);
generator.Extensions.AddCrlDistributionPoint("http://crl.example.com/ca.crl"); // where the CRL is published
generator.Extensions.AddOcspUrl("http://ocsp.example.com"); // the OCSP responder
generator.Extensions.AddCaIssuersUrl("http://www.example.com/ca.cer"); // where the certificate of the issuer is
// A certificate policy, with optional qualifiers (the address of the CPS and a user notice).
generator.Extensions.AddCertificatePolicy("1.2.3.4.5", "https://www.example.com/cps", "Certificate for tests");
generator.SubjectAlternativeNames = "john@example.com";
For the tests of an eIDAS application, the generator can write the QCStatements extension (ETSI EN 319 412-5), so that the certificate declares itself as qualified, with the private key in a qualified device. Such a certificate is not a qualified certificate (it is not issued by a qualified trust service provider): it exists to test the code that reads these statements (DigitalCertificate.IsQualifiedCertificate).
X509CertificateGenerator generator = new X509CertificateGenerator(LibrarySerialNumber);
generator.AddToSubject(SubjectType.CN, "Test Qualified Signer");
generator.AddToSubject(SubjectType.SERIALNUMBER, "PNORO-1234567890123");
generator.Extensions.AddKeyUsage(CertificateKeyUsage.NonRepudiation);
generator.Extensions.QcStatements = new QualifiedCertificateStatements
{
QcCompliance = true, // an EU qualified certificate
QcSscd = true, // the key is in a qualified signature creation device
QcType = QualifiedCertificateType.ESign, // a certificate for electronic signatures
SemanticsIdentifier = QcSemanticsIdentifier.NaturalPerson,
RetentionPeriod = 10 // years
};
generator.Extensions.QcStatements.AddPdsLocation("https://www.example.com/pds_en.pdf", "en");
generator.Extensions.AddCertificatePolicy("0.4.0.194112.1.2"); // QCP-n-qscd
byte[] pfx = generator.GenerateCertificate("123456", false);
A certificate for a certificate signing request (CSR)
A small internal certification authority issues certificates for the keys that the users generate themselves: the user sends a PKCS#10 request (PEM text) and gets the certificate, without the private key leaving the user.
X509CertificateGenerator ca = new X509CertificateGenerator(LibrarySerialNumber);
ca.LoadRootCertificate(File.ReadAllBytes("root.pfx"), "rootPassword");
ca.ValidTo = DateTime.Now.AddYears(1);
ca.Extensions.AddKeyUsage(CertificateKeyUsage.DigitalSignature);
ca.Extensions.AddKeyUsage(CertificateKeyUsage.NonRepudiation);
string csrPem = File.ReadAllText("request.csr"); // -----BEGIN CERTIFICATE REQUEST----- ...
byte[] certificateDer = ca.GenerateCertificateFromCSR(csrPem);
File.WriteAllBytes("issued.cer", certificateDer);
5.6 Installing certificates in the Windows store
The certificates in the Windows store are used by the programs of the computer, and they are the way to make a certificate trusted (a root certificate) or available to a service (a signing certificate). The Windows tools are certmgr.msc (the current user) and certlm.msc (the local computer); a PFX file is installed by double-clicking it, or with the PowerShell cmdlet Import-PfxCertificate. From code, use the X509Store class of .NET:
// A PFX certificate (with its private key) in the Personal store of the current user.
X509Certificate2 signingCert = new X509Certificate2("cert.pfx", "123456", X509KeyStorageFlags.PersistKeySet);
using (X509Store personal = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
personal.Open(OpenFlags.ReadWrite);
personal.Add(signingCert);
}
// The same for the Local Computer store (needs administrator rights): a service account can then use the certificate.
using (X509Store machine = new X509Store(StoreName.My, StoreLocation.LocalMachine))
{
machine.Open(OpenFlags.ReadWrite);
machine.Add(signingCert);
}
// A root certificate (the public part only) in the Trusted Root Certification Authorities store.
// For the current user Windows asks the user to confirm; for the local computer it needs administrator rights.
using (X509Store roots = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
{
roots.Open(OpenFlags.ReadWrite);
roots.Add(new X509Certificate2("root.cer"));
}
- The certificates that a smart card or a token publishes appear in the Personal store when its driver is installed and the card is inserted. They are not copied by the library.
- Windows (and the programs that use its trust, such as
X509Chain) trusts a certificate when its chain ends in a certificate of the Trusted Root Certification Authorities store. Adobe Acrobat has its own list of trusted certificates (section 6.14). - Installing a self-signed or a private root certificate on a computer makes all the certificates that it issues trusted by that computer: do it only for a root that you control, and never for a certificate of unknown origin.
- The password of a PFX file and the PIN of a token are secrets: do not put them in the source code of an application that you distribute.
- The PFX of a root certificate is the key of your whole internal PKI. Keep it offline, or in an HSM, and use it only to issue certificates.
- A self-signed certificate proves nothing to a recipient who does not already trust it.
6. PDF signatures
The class PdfSignature signs PDF documents. It creates the signatures that Adobe Acrobat and the other PDF readers show in the signature panel: the classic PKCS#7 signature (adbe.pkcs7.detached) and the PAdES signatures of ETSI EN 319 142-1 (ETSI.CAdES.detached), with a time-stamp, with the validation data for the long term (PAdES-B-LT) and with a document time-stamp for archiving (PAdES-B-LTA). The same class reads the signatures of a document and verifies them. Related classes: PdfEncrypt (encryption), PdfMerge and PdfInsertObject (merging and adding text and images).
6.1 How a PDF signature works
A PDF signature is a signature field in the document. The library does not rewrite the document: it appends a new revision to the end of the file (an incremental update) that contains the signature field, its appearance and the signature value. The bytes of the document that existed before are not changed, so the signatures that were already in the document remain valid (PdfSignature.AppendSignature is true by default). The signature value covers the whole file, except the space that holds the signature itself (the /ByteRange).
The steps of the code are always the same: LoadPdfDocument → set the certificate and the options → ApplyDigitalSignature() → the signed document as byte[].
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf"); // or a byte[] or a Uri
pdfSignature.DigitalSignatureCertificate = signingCertificate;
byte[] signedPdf = pdfSignature.ApplyDigitalSignature();
File.WriteAllBytes("source[signed].pdf", signedPdf);
6.2 Loading the document
LoadPdfDocument(string file),LoadPdfDocument(byte[] pdf)andLoadPdfDocument(Uri url)(an HTTP download).- After the load,
pdfSignature.DocumentProperties(PdfDocumentProperties) has the number of pages, the size of the file, the certification level, and the signatures of the document (DigitalSignatures).DocumentPageSize(page)returns the size of a page in points (1 point = 1/72 inch), with the rotation of the page applied. - A document protected by a password is opened with the password: set
DocumentProperties.PasswordbeforeLoadPdfDocument. A document with an unknown password cannot be signed. - A PDF file that is damaged can sometimes be rebuilt:
PdfSignature.RepairPdf(file)orRepairPdf(bytes)returns the rebuilt document. A repair rewrites the file: do not repair a document that is already signed, its signatures would become invalid.
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
// The password of an encrypted document: before the document is loaded.
pdfSignature.DocumentProperties.Password = "document password";
pdfSignature.LoadPdfDocument("encrypted.pdf");
PdfDocumentProperties properties = pdfSignature.DocumentProperties;
Console.WriteLine("Pages: " + properties.NumberOfPages + ", size: " + properties.FileSize + " bytes");
Console.WriteLine("Signatures: " + properties.DigitalSignatures.Count + ", certification: " + properties.CertificationLevel);
System.Drawing.Point firstPage = properties.DocumentPageSize(1); // X = width, Y = height, in points
Console.WriteLine("Page 1: " + firstPage.X + " x " + firstPage.Y);
A document can be loaded from a web address and checked before it is signed, for example to sign only the documents that have no signature yet:
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument(new Uri("https://www.example.com/documents/contract.pdf")); // an HTTP download
if (pdfSignature.DocumentProperties.DigitalSignatures.Count == 0)
{
pdfSignature.DigitalSignatureCertificate = signingCertificate;
File.WriteAllBytes("contract[signed].pdf", pdfSignature.ApplyDigitalSignature());
}
else
{
Console.WriteLine("The document is already signed " + pdfSignature.DocumentProperties.DigitalSignatures.Count + " time(s).");
}
6.3 Signature formats
The property SignatureStandard (PdfSignatureStandard) selects the format. The default is the classic PKCS#7:
| Value | What is created | Use it when |
|---|---|---|
Default | PKCS#7 detached (adbe.pkcs7.detached). | The signature must be recognized by every PDF reader, also the old ones. The format of most of the signatures in use. |
Pades | PAdES baseline B-B (ETSI.CAdES.detached, the signing certificate is a signed attribute). | A regulation or a validator asks for PAdES (the eIDAS signatures). Recognized by Adobe Reader X and later. PAdES requires a hash of the SHA-2 family. |
PadesLT | PAdES B-LT: the signature, plus the certificates and the revocation data (CRL, OCSP) in the document security store (/DSS). | The signature must be validated later, after the certificate expires or the servers of the certification authority are gone. Needs the network when the signature is created. (→ section 12) |
PadesLTA | PAdES B-LTA: PAdES-LT followed by a document time-stamp that protects the document and its validation data. | Archiving for many years. Needs a time-stamping server (TimeStamping.ServerUrl). The time-stamp can be renewed (section 12.4). |
A time-stamp on the signature (B-T) is added with any of the formats when TimeStamping.ServerUrl is set (section 6.8).
The hash algorithm is HashAlgorithm (SignLib.HashAlgorithm: SHA256 by default, SHA384, SHA512, SHA1 for old systems). The algorithm of the signature follows the key of the certificate: RSA (PKCS#1 v1.5) or ECDSA.
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = signingCertificate;
pdfSignature.SignatureStandard = PdfSignatureStandard.Pades;
pdfSignature.HashAlgorithm = SignLib.HashAlgorithm.SHA384;
File.WriteAllBytes("source[pades].pdf", pdfSignature.ApplyDigitalSignature());
For a signature that a person opens in Adobe Reader and that has no regulatory requirement, Default (PKCS#7) is recognized everywhere. For signatures in the European Union, where a qualified or an advanced signature is required and validated with the EU DSS validator, use PAdES. Old PDF readers and some verification programs do not recognize PAdES.
6.4 Visible and invisible signatures, position
A signature is visible by default: it has a rectangle on a page with the name of the signer, the date, the reason and the location. To sign without a visible appearance set VisibleSignature = false: the signature is only in the signature panel of the PDF reader.
Position by the corner of the page
SignaturePosition places a rectangle of 100 × 50 points at 50 points from the edges of the page. The default is TopRight; the other values are TopMiddle, TopLeft, BottomRight, BottomMiddle and BottomLeft.
Position by rectangle
SignatureAdvancedPosition (a System.Drawing.Rectangle, write-only) sets the rectangle. The coordinates are in points and the origin is the bottom left corner of the page: X and Y are the position of the bottom left corner of the rectangle, Width and Height its size. It replaces SignaturePosition.
DocumentPageSize(page) to know the size that you see.PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = signingCertificate;
// 400 x 150 points, 10 points from the left edge and from the bottom edge of the page.
pdfSignature.SignatureAdvancedPosition = new System.Drawing.Rectangle(10, 10, 400, 150);
File.WriteAllBytes("source[signed].pdf", pdfSignature.ApplyDigitalSignature());
The page
| Property | Effect |
|---|---|
SignaturePage | The page of the signature, numbered from 1. The default is 1. int.MaxValue means the last page. A page that does not exist throws ArgumentOutOfRangeException. |
SignaturePages (List<int>) | The appearance of the signature on several pages (a page listed twice gets it once; int.MaxValue is the last page). The rectangle is the same on every page. The signature stays a single signature. |
SignatureAppearsOnAllPages | true: the appearance on every page, once on each page. It has priority over SignaturePages. |
// pdfSignature: the PdfSignature object of the previous examples (certificate set, document loaded)
// The appearance on the first page and on the last page.
pdfSignature.SignaturePages = new List<int> { 1, int.MaxValue };
// Or on every page of the document.
pdfSignature.SignatureAppearsOnAllPages = true;
6.5 The appearance of the signature
Text
By default the rectangle shows, on separate lines, the name of the signer (the common name of the certificate), the date and time (yyyy.MM.dd HH:mm), the reason and the location. SignatureText replaces the whole text. SigningReason and SigningLocation are also written in the properties of the signature, where the PDF readers show them (the Reason and the Location of the signature panel).
// pdfSignature: the PdfSignature object of the previous examples (certificate set, document loaded)
pdfSignature.SigningReason = "I approve this document";
pdfSignature.SigningLocation = "Accounting department";
// A custom text (the lines are separated with a new line).
pdfSignature.SignatureText = "Signed by: " + signingCertificate.GetNameInfo(X509NameType.SimpleName, false)
+ Environment.NewLine + "Date: " + DateTime.Now.ToString("dd.MM.yyyy HH:mm");
Font
FontNameselects one of the standard PDF fonts (FontName.Helveticaby default,Courier,Times_Romanand their bold and italic variants). The standard fonts use a Latin (Central European) code page: they have the characters of the Western and Central European languages, and not Greek, Cyrillic, Hebrew, Arabic or Asian characters.FontFileis the path of a TrueType font file. The font is embedded in the document, so any script that the font has can be written. When it is set,FontNameis not used. A path that does not exist throwsFileNotFoundException.FontSizesets the size of the text.TextDirection(write-only) isTextDirection.Normal(left to right) orTextDirection.RightToLeft, for the Hebrew and Arabic texts.
// pdfSignature: the PdfSignature object of the previous examples (certificate set, document loaded)
// Greek and Cyrillic text, with an embedded TrueType font.
pdfSignature.FontFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "arial.ttf");
pdfSignature.FontSize = 11;
pdfSignature.SignatureText = "Υπογράφηκε ψηφιακά" + Environment.NewLine + "Подписано цифровой подписью";
// A right to left text.
pdfSignature.TextDirection = TextDirection.RightToLeft;
Image
SignatureImage (a byte[] with a JPG, PNG, GIF, BMP or TIFF image) adds a graphic to the signature. SignatureImageType says how it is shown:
| Value | Appearance |
|---|---|
ImageAndText (default) | The image on the left and the text on the right. |
ImageAsBackground | The image is the background of the text. |
ImageWithNoText | Only the image; the text is not shown (the signer information is still in the signature). |
// pdfSignature: the PdfSignature object of the previous examples (certificate set, document loaded)
pdfSignature.SignatureImage = File.ReadAllBytes("signature_image.jpg");
pdfSignature.SignatureImageType = SignatureImageType.ImageAndText;
pdfSignature.SignatureAdvancedPosition = new System.Drawing.Rectangle(10, 10, 400, 150);
Other properties of the appearance and of the signer
| Property | Meaning |
|---|---|
OldStyleAdobeSignature | true: the old Adobe Acrobat 6 appearance (a large question mark on the signatures that are not trusted, and a check mark on the valid ones). The default is false. |
SignerContactInformation | The contact information of the signer, in the signature. By default the e-mail address of the certificate. |
SigningApplicationName, SigningApplicationVersion | The name and the version of your application, written in the signature build properties. Adobe Reader shows them in the advanced properties of the signature (“Signature was created using ...”); without them it shows “Not available”. The name has at most 127 bytes in UTF-8, without control characters (ArgumentException otherwise). |
// pdfSignature: the PdfSignature object of the previous examples (certificate set, document loaded)
pdfSignature.SigningApplicationName = "Invoice Portal";
pdfSignature.SigningApplicationVersion = "3.2.1";
An invisible signature
// pdfSignature: the PdfSignature object of the previous examples (certificate set, document loaded)
pdfSignature.VisibleSignature = false; // no rectangle on the page; the signature panel shows it
6.6 Certification signatures
A certification signature is the first signature of a document, made by the author, that says which changes are allowed after it (the DocMDP permission). The property CertifySignature (CertifyMethod) sets it:
| Value | After the certification signature |
|---|---|
NotCertified (default) | A normal approval signature. |
NoChangesAllowed | No changes. No other signature can be added. |
FormFilling | Filling the form fields and signing are allowed. |
AnnotationsAndFormFilling | Annotations, form filling and signing are allowed. |
A document has at most one certification signature and it must be the first. The certification level of a loaded document is DocumentProperties.CertificationLevel.
PdfSignature author = new PdfSignature(LibrarySerialNumber);
author.LoadPdfDocument("source.pdf");
author.DigitalSignatureCertificate = signingCertificate;
author.CertifySignature = CertifyMethod.AnnotationsAndFormFilling;
byte[] certified = author.ApplyDigitalSignature();
// A second signer approves the certified document.
PdfSignature approver = new PdfSignature(LibrarySerialNumber);
approver.LoadPdfDocument(certified);
approver.DigitalSignatureCertificate = signingCertificate;
approver.SignaturePosition = SignaturePosition.BottomLeft;
byte[] approved = approver.ApplyDigitalSignature();
6.7 Several signatures and signature fields
- Several signers. Load the signed document in a new
PdfSignatureand sign again. Each signature is a new revision; the previous ones remain valid. Give each signer another rectangle (SignaturePositionorSignatureAdvancedPosition), or the rectangles overlap. - An existing signature field. A form can have empty signature fields (created in Acrobat or by
AddSignatureField).ApplyDigitalSignature(string fieldName)signs that field: the signature has the position and the size of the field. WithApplyDigitalSignature()a new field is created. - Signature fields created by code.
AddSignatureField(name, page, rectangle)returns the document with an empty signature field (the rectangle has the semantics ofSignatureAdvancedPosition). It is used to prepare a contract that is signed later by several people.
// 1. Prepare: a document with two empty signature fields.
PdfSignature prepare = new PdfSignature(LibrarySerialNumber);
prepare.LoadPdfDocument("source.pdf");
byte[] withField1 = prepare.AddSignatureField("Customer", 1, new System.Drawing.Rectangle(50, 100, 200, 60));
prepare = new PdfSignature(LibrarySerialNumber);
prepare.LoadPdfDocument(withField1);
byte[] withFields = prepare.AddSignatureField("Supplier", 1, new System.Drawing.Rectangle(300, 100, 200, 60));
// 2. Later, every signer signs the field with its name.
PdfSignature customer = new PdfSignature(LibrarySerialNumber);
customer.LoadPdfDocument(withFields);
customer.DigitalSignatureCertificate = signingCertificate;
byte[] signedByCustomer = customer.ApplyDigitalSignature("Customer");
PdfSignature supplier = new PdfSignature(LibrarySerialNumber);
supplier.LoadPdfDocument(signedByCustomer);
supplier.DigitalSignatureCertificate = signingCertificate;
byte[] signedByBoth = supplier.ApplyDigitalSignature("Supplier");
6.8 Time-stamps in PDF documents
A time-stamp proves the time. There are two kinds in a PDF document:
- The time-stamp of the signature (inside the signature): set
TimeStamping.ServerUrlbeforeApplyDigitalSignature. The signature has then the level B-T, andPdfSignatureInfo.SignatureIsTimestampedis true. - A document time-stamp (
ETSI.RFC3161), an invisible signature of the time-stamping authority over the whole document:ApplyTimestampSignature(). It is the last element of a PAdES-LTA document, and it can be added alone, or again, to extend the protection of an archived document. It does not need a signing certificate.
// The signature is time-stamped.
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = signingCertificate;
pdfSignature.TimeStamping.ServerUrl = new Uri("https://ca.signfiles.com/TSAServer.aspx");
File.WriteAllBytes("source[signed-T].pdf", pdfSignature.ApplyDigitalSignature());
// A document time-stamp on the signed document.
PdfSignature stamper = new PdfSignature(LibrarySerialNumber);
stamper.LoadPdfDocument("source[signed-T].pdf");
stamper.TimeStamping.ServerUrl = new Uri("https://ca.signfiles.com/TSAServer.aspx");
File.WriteAllBytes("source[stamped].pdf", stamper.ApplyTimestampSignature());
The settings of the time-stamping server (authentication, policy, hash, time-out) are in section 11. The time-stamp requests use SHA-256 by default.
6.9 PAdES-LT and PAdES-LTA
SignatureStandard = PdfSignatureStandard.PadesLT embeds, in the document security store of the PDF, the certificates of the chain and the revocation information that the library downloads when it signs. PdfSignatureStandard.PadesLTA adds the document time-stamp. The property PadesLtvLevel selects the revocation data:
PadesLtvLevel | Embedded revocation data |
|---|---|
IncludeOcspOnly (default) | The OCSP response of the signing certificate, when available (otherwise its CRL, so that the signature always has revocation data), and the CRLs of the CA certificates. The smallest result. |
IncludeCrlAndOcsp | The CRLs of the whole chain and the OCSP responses of the signing certificate and of its issuer. |
IncludeCrl | The CRLs of the chain. |
None | No revocation data (only the certificates). |
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = signingCertificate;
pdfSignature.SignatureStandard = PdfSignatureStandard.PadesLTA; // signature + validation data + document time-stamp
pdfSignature.PadesLtvLevel = PadesLtvLevel.IncludeCrlAndOcsp;
pdfSignature.TimeStamping.ServerUrl = new Uri("https://ca.signfiles.com/TSAServer.aspx");
pdfSignature.TimeStamping.HashAlgorithm = SignLib.HashAlgorithm.SHA256;
File.WriteAllBytes("source[lta].pdf", pdfSignature.ApplyDigitalSignature());
The signing certificate must have a CRL or an OCSP responder for the revocation data to exist; a self-signed certificate has none, and then only the certificate is embedded. How the long term features work and how to renew the time-stamp is in section 12.
6.10 Encryption
Signing and encrypting in one operation
The property PdfSignature.Encryption (PdfEncryptionSettings) encrypts the document while it is signed. The signature is created over the encrypted document, so it stays valid. An encrypted document that is signed again is a problem: the encryption cannot be changed after a signature exists, and a document that is already signed (or certified) cannot be encrypted: it throws CryptographicException. Encrypt first, sign after, or do both together.
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = signingCertificate;
pdfSignature.Encryption.EncryptionMethod = PdfEncryptionMethod.PasswordSecurity;
pdfSignature.Encryption.EncryptionAlgorithm = PdfEncryptionAlgorithm.EnhancedEncryption128BitAES;
pdfSignature.Encryption.UserPassword = "user_passw0rd"; // opens the document
pdfSignature.Encryption.OwnerPassword = "owner_passw0rd"; // all the actions
pdfSignature.Encryption.DocumentRestrictions = PdfDocumentRestrictions.AllowPrinting;
File.WriteAllBytes("source[signed-encrypted].pdf", pdfSignature.ApplyDigitalSignature());
Encrypting a document: PdfEncrypt
PdfEncrypt encrypts a document (without signing it). The settings are the same:
| Property | Meaning |
|---|---|
EncryptionMethod | PasswordSecurity; CertificateSecurity (the document is opened only with the private key of a certificate); NoEncryption (default). |
EncryptionAlgorithm | EnhancedEncryption128BitAES (AES-128, recommended); StandardEncryption128BitRC4 (weak) and StandardEncryption40BitRC4 (insecure), only for very old readers. The AES-256 encryption of PDF 2.0 is not supported. |
UserPassword, OwnerPassword | The password to open the document, and the password that allows all the actions. |
EncryptionCertificate | For CertificateSecurity: the certificate of the recipient (the public part is enough). |
DocumentRestrictions | The allowed actions, combined: AllowPrinting, AllowContentCopying, AllowFillingOfFormFields, AllowContentCopyingForAccessibility, AllowDocumentAssembly; AllowNone. |
LoadedDocumentPassword | The password of the document that is already encrypted and that you encrypt again. |
// Passwords.
PdfEncrypt byPassword = new PdfEncrypt();
byPassword.LoadPdfDocument("source.pdf");
byPassword.EncryptionMethod = PdfEncryptionMethod.PasswordSecurity;
byPassword.EncryptionAlgorithm = PdfEncryptionAlgorithm.EnhancedEncryption128BitAES;
byPassword.UserPassword = "user_passw0rd";
byPassword.OwnerPassword = "owner_passw0rd";
byPassword.DocumentRestrictions = PdfDocumentRestrictions.AllowPrinting | PdfDocumentRestrictions.AllowFillingOfFormFields;
File.WriteAllBytes("source[encrypted].pdf", byPassword.EncryptPDFFile());
// A certificate: only the owner of its private key opens the document, without a password.
PdfEncrypt byCertificate = new PdfEncrypt();
byCertificate.LoadPdfDocument("source.pdf");
byCertificate.EncryptionMethod = PdfEncryptionMethod.CertificateSecurity;
byCertificate.EncryptionCertificate = new X509Certificate2(signingCertificate.RawData); // the public part
File.WriteAllBytes("source[encrypted-cert].pdf", byCertificate.EncryptPDFFile());
PdfEncrypt can encrypt a document that has signatures, but the rewrite of the file invalidates them. Sign and encrypt in one operation with PdfSignature.Encryption when the result must be an encrypted and signed document.
6.11 Reading and verifying the signatures
After LoadPdfDocument, DocumentProperties.DigitalSignatures lists the signatures and the document time-stamps, sorted by signing time. Every item is a PdfSignatureInfo:
| Property | Meaning |
|---|---|
SignatureType | DigitalSignature, or TimestampSignature for a document time-stamp. |
SignatureName | The name of the signature field. |
SignatureIsValid | The integrity of the signature (not the trust of the certificate, section 4.5). |
SignatureCertificate | The signing certificate (for a document time-stamp: the certificate of the time-stamping authority). |
SignatureTime, SignatureIsTimestamped, TimestampInfo | The signing time (the time of the time-stamp when there is one) and the information of the time-stamp (TimestampInfo, section 11.3). |
HashAlgorithm, DigestAlgorithm, SignatureAlgorithm | The hash (SHA256), the signature algorithm (SHA256withRSA, SHA256withECDSA) and the algorithm of the key (RSA, DSA, ECC). |
SigningReason, SigningLocation | The reason and the location written by the signer. |
SignatureBytes, SignatureHash | The encoded PKCS#7 / CMS structure of the signature, and the signature value. |
A complete verification of a document answers more than SignatureIsValid. These checks are a good minimum; the first one is the library, the others are your decision:
- every signature is intact (
SignatureIsValid); - the last signature covers the whole file: bytes added after the last signature are not signed, although the signature is still intact (the check reads the
/ByteRangeof the signatures); - the signing certificate was valid at the signing time (the time of the time-stamp when there is one), its chain ends in a root that the application trusts, and it was not revoked;
- the time-stamps are not altered (
TimestampInfo.IsTimestampAltered).
public static class PdfVerifier
{
// Returns true when the signatures of the document are intact, the last signature covers the whole file,
// the certificates were valid at the signing time and they are not revoked.
public static bool Verify(byte[] pdf, string serialNumber)
{
PdfSignature pdfSignature = new PdfSignature(serialNumber);
pdfSignature.LoadPdfDocument(pdf);
List<PdfSignatureInfo> signatures = pdfSignature.DocumentProperties.DigitalSignatures;
if (signatures.Count == 0)
return false;
long[] coveredEnds = GetSignedByteRangeEnds(pdf);
bool passed = true;
for (int index = 0; index < signatures.Count; index++)
{
PdfSignatureInfo info = signatures[index];
Console.WriteLine(info.SignatureName + " (" + info.SignatureType + "), signer: " + info.SignatureCertificate.Subject);
// 1. The integrity of the signature.
passed &= info.SignatureIsValid;
// 2. The last signature must cover the end of the file (a trailing line break is accepted).
if (index == signatures.Count - 1 && index < coveredEnds.Length && coveredEnds[index] < pdf.Length)
{
Console.WriteLine(" Data was added after the last signature.");
passed = false;
}
// 3. The certificate at the signing time.
DateTime signingTime = info.SignatureTime.ToUniversalTime();
bool inPeriod = signingTime >= info.SignatureCertificate.NotBefore.ToUniversalTime()
&& signingTime <= info.SignatureCertificate.NotAfter.ToUniversalTime();
passed &= inPeriod;
using (X509Chain chain = new X509Chain())
{
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.VerificationTime = info.SignatureTime.ToLocalTime();
bool trusted = chain.Build(info.SignatureCertificate); // is the root trusted by this computer?
Console.WriteLine(" Chain to a trusted root: " + trusted);
}
// The revocation status now: Valid, Revoked, Unknown (server not available) or NotPresent (no CRL/OCSP).
// For the status at the signing time, use the validation data of a PAdES-LT document.
CertificateStatus status = DigitalCertificate.VerifyDigitalCertificate(info.SignatureCertificate, VerificationType.OCSP);
passed &= status != CertificateStatus.Revoked;
// 4. The time-stamp of the signature.
if (info.SignatureIsTimestamped)
passed &= !info.TimestampInfo.IsTimestampAltered;
}
return passed;
}
// The end of the bytes covered by each signature: the last range of its /ByteRange (offset + length).
private static long[] GetSignedByteRangeEnds(byte[] pdf)
{
string text = System.Text.Encoding.GetEncoding("ISO-8859-1").GetString(pdf);
System.Text.RegularExpressions.MatchCollection ranges = System.Text.RegularExpressions.Regex.Matches(text,
@"/ByteRange\s*\[\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s*\]");
long[] ends = new long[ranges.Count];
for (int i = 0; i < ranges.Count; i++)
ends[i] = long.Parse(ranges[i].Groups[3].Value) + long.Parse(ranges[i].Groups[4].Value);
if (ends.Length > 0 && pdf.Length - ends[ends.Length - 1] <= 2)
ends[ends.Length - 1] = pdf.Length;
return ends;
}
}
The routine is a base to adapt: the decision about the trust of the root (trusted) and about an unknown revocation status belongs to your application. The sample project PDF Signature Verification is a complete program that also detects the format of the signature (PKCS#7 or PAdES, with a time-stamp, with validation data, with a document time-stamp). For the signatures that must be validated against the EU trusted lists, use the DSS validator (section 14.5).
6.12 Merging, adding texts and images
PdfMerge.MergePdfFiles(List<byte[]>) merges documents (the metadata of the first one is kept). PdfInsertObject adds images (over or under the content, as a stamp or a full-page watermark) and texts to the pages. Do it before the document is signed: a change after the signature invalidates it.
// Merge two documents.
byte[] merged = PdfMerge.MergePdfFiles(new List<byte[]>
{
File.ReadAllBytes("contract.pdf"),
File.ReadAllBytes("annex.pdf")
});
// Add a text and a stamp image.
PdfInsertObject insert = new PdfInsertObject();
insert.LoadPdfDocument(merged);
CustomText text = new CustomText();
text.Text = "APPROVED";
text.FontSize = 24;
text.PageNumber = 1;
text.StartingPointPosition = new System.Drawing.Point(100, 700);
insert.AddText(text);
insert.AddImage(File.ReadAllBytes("stamp.png"), new System.Drawing.Point(400, 50), 1, ImagePosition.ImageOverContent); // page 1; page 0 = all the pages
byte[] stamped = insert.InsertObjects();
The page number 0 of an image means all the pages. An image can also cover the page (AddImage(image, page, position)), for a watermark under the content (ImagePosition.ImageUnderContent). A text can use a TrueType font (CustomText.FontFile), a color (TextColor, an iTextSharp color), an alignment (TextAlign) and a direction (TextDirection).
6.13 Signature policy
A regulation can require an explicit signature policy in the signature. SetSignaturePolicyInformation(oid, policyHash, hashAlgorithmOid, url) adds the signature-policy-identifier attribute to the signatures created by the object; the same method exists in CadesSignature, XadesSignature, OfficeSignature and AsicSignature. policyHash is the hash of the policy document that you published or got from the authority; calling the method with null removes the policy.
// pdfSignature: the PdfSignature object of the previous examples (certificate set, document loaded)
byte[] policyDocument = File.ReadAllBytes("policy.pdf");
byte[] policyHash = SHA256.Create().ComputeHash(policyDocument);
pdfSignature.SignatureStandard = PdfSignatureStandard.Pades;
pdfSignature.SetSignaturePolicyInformation("2.16.76.1.7.1.5.2.3", policyHash, "2.16.840.1.101.3.4.2.1", "http://ca.example.com/policy.pdf");
6.14 PDF readers and validators
- Trust. Adobe Reader shows a signature as valid (a green mark) when the certificate chain ends in a root that Adobe trusts (the Adobe Approved Trust List, or the Windows store when the user enables it), and as validity unknown (a yellow mark) when it does not. Signatures made with a self-signed certificate show “validity unknown” until the user adds the certificate to the trusted identities. This is the validation procedure of the reader, not a defect of the signature.
- The time-stamp is trusted when the certificate of the time-stamping authority is trusted by the reader.
- LTV. A signature is shown as an LTV-enabled signature when the document has the revocation information that is needed to validate it without the network.
- eIDAS. The EU DSS validator (section 14.5) validates the PAdES signatures against the trusted lists of the member states.
7. CAdES and PKCS#7 signatures (.p7m, .p7s)
CadesSignature signs any file or data (a PDF, an image, an archive, an XML file, text) as a CMS / PKCS#7 or CAdES signature. The result is a file with the extension .p7m when it contains the signed document (an attached signature) or .p7s when it contains only the signature (a detached signature). CadesVerify reads and verifies these files. CAdES (ETSI EN 319 122-1) is the format that the eIDAS Regulation uses for the signatures of files of any type.
7.1 Creating a signature
CadesSignature cadesSignature = new CadesSignature(LibrarySerialNumber);
cadesSignature.DigitalSignatureCertificate = signingCertificate;
cadesSignature.HashAlgorithm = SignLib.HashAlgorithm.SHA256;
cadesSignature.SignatureStandard = CadesSignatureStandard.CadesBes;
// A file: the result is the content of the .p7m file (the signed file is inside).
byte[] p7m = cadesSignature.ApplyDigitalSignature("contract.pdf");
File.WriteAllBytes("contract.pdf.p7m", p7m);
// Data in memory.
byte[] data = File.ReadAllBytes("contract.pdf");
byte[] p7mFromData = cadesSignature.ApplyDigitalSignature(data);
| Property | Meaning |
|---|---|
DigitalSignatureCertificate | The signing certificate (section 5.2); the missing certificate throws NullReferenceException. |
SignatureStandard | The format: CadesBes (the default), Cms, CadesC, CadesXL, CadesLT, CadesA (section 7.2). |
HashAlgorithm | SHA256 by default (SHA384, SHA512; SHA1 only for old systems). |
IsDetachedSignature | true: the signature does not contain the document (.p7s). Default false (.p7m). |
TimeStamping | The time-stamping server (section 11). When TimeStamping.ServerUrl is set, the signature is time-stamped. |
MaxCrlSize | The CRLs larger than this value (in bytes, 20 MB by default) are not embedded in the long term levels. |
SetSignaturePolicyInformation(...) | An explicit signature policy (section 7.6). |
The method returns the bytes of the signature; the library writes nothing on the disk. The signature algorithm follows the key of the certificate (RSA, or ECDSA; for ECDSA certificates the signature value is converted to the DER form that CMS requires).
7.2 The levels of CAdES
The enumeration CadesSignatureStandard contains the formats that the older and the newer specifications define:
| Value | Content of the signature | Network |
|---|---|---|
Cms | CMS / PKCS#7 signature (RFC 5652), recognized by the older software. No ETSI attribute. | No (except the time-stamp) |
CadesBes | CAdES-B-B (basic electronic signature): the signing certificate is referenced by the signed attribute signing-certificate-v2 (signing-certificate for SHA-1). With TimeStamping.ServerUrl: CAdES-B-T. | The TSA, when it is used |
CadesC | CAdES-C: the complete references of the certificates and of the revocation data, with their values. | CRL, OCSP |
CadesXL | CAdES-X Long: CAdES-C and a time-stamp of the references (escTimeStamp). | CRL, OCSP, TSA (required) |
CadesLT | CAdES-B-LT (long term): the values of the certificates and of the revocation data (CRL and OCSP responses), without the references of CAdES-C. | CRL, OCSP |
CadesA | CAdES-B-LTA (long term archival): CAdES-LT and an archive time-stamp (version 3, ETSI EN 319 122-1) of the signature and of its validation data. Without a time-stamping server only the certificate and revocation values are added. | CRL, OCSP, TSA |
CAdES-EPES (explicit policy) is a CadesBes signature with a policy set by SetSignaturePolicyInformation. The validation data is collected from the addresses in the certificates; for a certificate without a CRL and an OCSP responder (a self-signed certificate) only the certificate is embedded. The idea of the levels and the renewal of the archive time-stamp are in section 12.
// The same file, signed with every level (the levels with a time-stamp need the server).
CadesSignatureStandard[] levels =
{
CadesSignatureStandard.Cms, CadesSignatureStandard.CadesBes, CadesSignatureStandard.CadesC,
CadesSignatureStandard.CadesXL, CadesSignatureStandard.CadesLT, CadesSignatureStandard.CadesA
};
foreach (CadesSignatureStandard level in levels)
{
CadesSignature cadesSignature = new CadesSignature(LibrarySerialNumber);
cadesSignature.DigitalSignatureCertificate = signingCertificate;
cadesSignature.SignatureStandard = level;
cadesSignature.TimeStamping.ServerUrl = new Uri("https://ca.signfiles.com/TSAServer.aspx");
File.WriteAllBytes("test.txt[" + level + "].p7m", cadesSignature.ApplyDigitalSignature("test.txt"));
}
7.3 Detached signatures (.p7s)
With IsDetachedSignature = true the result is only the signature. The signed file is not changed, and it is needed to verify the signature. This is the convenient form for large files or when the original must stay untouched; the attached form (.p7m) is one file that cannot lose its document.
CadesSignature cadesSignature = new CadesSignature(LibrarySerialNumber);
cadesSignature.DigitalSignatureCertificate = signingCertificate;
cadesSignature.IsDetachedSignature = true;
File.WriteAllBytes("contract.pdf.p7s", cadesSignature.ApplyDigitalSignature("contract.pdf"));
7.4 Co-signatures
When the data that you give to ApplyDigitalSignature is itself a CMS signature (a .p7m file), the library adds a new signature to it, instead of signing the signature again: the result is one file with all the signers, and the existing signatures stay valid. Call it once for every co-signer, with the certificate of that signer.
// The first signer.
CadesSignature first = new CadesSignature(LibrarySerialNumber);
first.DigitalSignatureCertificate = signingCertificate;
byte[] signed = first.ApplyDigitalSignature("contract.pdf");
// The second and the third signer add their signatures to the same file.
X509Certificate2 secondCertificate = DigitalCertificate.LoadCertificate("second.pfx", "123456");
X509Certificate2 thirdCertificate = DigitalCertificate.LoadCertificate("third.pfx", "123456");
foreach (X509Certificate2 coSigner in new[] { secondCertificate, thirdCertificate })
{
CadesSignature next = new CadesSignature(LibrarySerialNumber);
next.DigitalSignatureCertificate = coSigner;
signed = next.ApplyDigitalSignature(signed);
}
File.WriteAllBytes("contract.pdf.p7m", signed);
Because a CMS signature is recognized as a signature to co-sign, a .p7m file cannot be signed as an ordinary file by this method (a signature of a signature). To keep an independent signature of the file that contains a signature, sign the original document in another file, or wrap the .p7m in a container (for example ASiC-E, section 10).
7.5 Verifying a signature
The constructor of CadesVerify reads and verifies the signature; the object then has the result. A signature can be in binary (DER) form or in Base64 text, with or without the -----BEGIN ...----- lines.
| Constructor | Use |
|---|---|
CadesVerify(string signedFile, string serialNumber) | A .p7m file (attached) from the disk. DocumentName is the name of the signed document taken from the file name (contract.pdf.p7m → contract.pdf), or from the signature. |
CadesVerify(byte[] signedArray, string serialNumber) | A .p7m in memory. |
CadesVerify(byte[] detachedSignature, byte[] originalFile, string serialNumber) | A detached signature (.p7s) and the document that it signs. |
| Member | Meaning |
|---|---|
Signatures (List<CadesSignatureInfo>) | The signers, in the order of the signature. |
SignatureStandard | The format, detected from the attributes of the signers (Cms, CadesBes, ... CadesA). |
UnsignedDocument | The signed document (byte[]) of an attached signature: the way to extract the file from a .p7m. null for a detached signature verified without the document. |
CadesSignatureInfo.SignatureIsValid | The integrity: the signed data was not changed and the signature matches the certificate (not the trust of the certificate). |
SignatureCertificate | The signing certificate, or null when the signature does not contain it. |
SignatureTime | The signing time that the signer declared (UTC), or DateTime.MinValue when there is none. Not a proof (section 4.6). |
SignatureIsTimestamped, TimestampInfo | The time-stamp of the signature, when it has one (section 11.3). |
HashAlgorithm (Oid), SignatureHash | The hash algorithm of the signer (HashAlgorithm.FriendlyName: sha256) and the signature value. |
CadesVerify cadesVerify = new CadesVerify("contract.pdf.p7m", LibrarySerialNumber);
Console.WriteLine("Format: " + cadesVerify.SignatureStandard + ", signers: " + cadesVerify.Signatures.Count);
foreach (CadesSignatureInfo signer in cadesVerify.Signatures)
{
string name = signer.SignatureCertificate != null
? signer.SignatureCertificate.GetNameInfo(X509NameType.SimpleName, false)
: "(the certificate is not in the signature)";
Console.WriteLine(name + ", hash " + signer.HashAlgorithm.FriendlyName + ", intact: " + signer.SignatureIsValid
+ (signer.SignatureIsTimestamped ? ", time-stamped " + signer.TimestampInfo.SignatureTime.ToLocalTime() : string.Empty));
}
// Extract the signed document.
File.WriteAllBytes(cadesVerify.DocumentName ?? "document", cadesVerify.UnsignedDocument);
// A detached signature: the document is a parameter.
CadesVerify detached = new CadesVerify(File.ReadAllBytes("contract.pdf.p7s"), File.ReadAllBytes("contract.pdf"), LibrarySerialNumber);
bool allIntact = detached.Signatures.All(s => s.SignatureIsValid);
- A file that is not a CMS signature throws
CryptographicException(Invalid or corrupt CAdES/PKCS#7 signed data.); a missing file,FileNotFoundException. - The certificate check (the period of validity, the revocation, the trust) is your decision, section 4.5. Use the time of the time-stamp when the signature has one.
- In the demo version every
CadesVerifyconstructor waits 10 seconds (section 2.4).
7.6 Signature policy
A policy that a regulation requires is added with SetSignaturePolicyInformation. The OID of the policy, the hash of the policy document and the hash algorithm (as an OID) are written in the signed attributes; the URL of the document is optional.
byte[] policyHash = SHA256.Create().ComputeHash(File.ReadAllBytes("policy.pdf"));
CadesSignature cadesSignature = new CadesSignature(LibrarySerialNumber);
cadesSignature.DigitalSignatureCertificate = signingCertificate;
cadesSignature.SetSignaturePolicyInformation("2.16.76.1.7.1.5.2.3", policyHash, "2.16.840.1.101.3.4.2.1", "http://ca.example.com/policy.pdf");
byte[] p7m = cadesSignature.ApplyDigitalSignature("contract.pdf");
7.7 Notes
- Time-stamps and the TSA. A signature with
TimeStamping.ServerUrlcontains the time-stamp token (signature-time-stamp) of the signature value. For the long term levels the time-stamp of the archive protects the validation data (section 12). - ECDSA. RSA and ECDSA certificates are supported. A PKCS#11 token or an HSM that returns the raw signature value of ECDSA (r || s) is supported: the library converts it (section 13.4).
- Interoperability. The signatures can be validated with the EU DSS validator (section 14.5). Programs that expect .p7m files that contain a signed PDF, such as the Italian verification tools, open the attached signatures; a detached time-stamp is saved as .tsr or .tsd for them (section 11.2).
- Batch signing. One
CadesSignatureobject can sign many files in a loop; see section 15.2 and section 15.3.
8. XML signatures: XMLDSig and XAdES
Two classes sign XML:
XmlSignaturecreates XMLDSig signatures (W3C XML Signature), enveloped in the XML document, with RSA or ECDSA keys.XadesSignaturecreates XAdES signatures (ETSI EN 319 132-1): XMLDSig with signed properties (the signing time, the signing certificate) and the baseline levels B-B, B-T, B-LT and B-LTA. The signature can be enveloped in an XML document or detached, in a separate XML file, for a file of any type.
Both classes use the same technique for the signatures, which allows several signatures in the same document, and the same methods to read and verify them.
8.1 XMLDSig: sign and verify
XmlSignature xmlSignature = new XmlSignature(LibrarySerialNumber);
xmlSignature.DigitalSignatureCertificate = signingCertificate;
xmlSignature.HashAlgorithm = SignLib.HashAlgorithm.SHA256;
// The signed document: the signature element is added inside it.
xmlSignature.ApplyDigitalSignature("test.xml", "test[signed].xml");
// Verification.
Console.WriteLine("Signatures: " + xmlSignature.GetNumberOfSignatures("test[signed].xml"));
Console.WriteLine("Algorithm: " + xmlSignature.GetSignatureAlgorithm("test[signed].xml")); // for example RSA-SHA256
Console.WriteLine("All valid: " + xmlSignature.VerifyDigitalSignature("test[signed].xml"));
| Property | Meaning |
|---|---|
HashAlgorithm | SHA256 (default), SHA384, SHA512. SHA1 is not supported for new signatures (NotSupportedException); the existing SHA-1 signatures are verified. |
SignatureType (XmlSignatureType) | The canonicalization of the signed data: Default (Canonical XML 1.0, the default), DefaultWithComments, Exclusive (Exclusive XML Canonicalization), ExclusiveWithComments. The signature method follows the key: rsa-sha256/384/512 or ecdsa-sha256/384/512 (RFC 6931). |
IncludeKeyInfo | Include the key of the signer in the signature (true by default): the RSA key value, or the certificate for an ECDSA key. |
IncludeSignatureCertificate | Include the signing certificate (X509Certificate in KeyInfo), true by default. Without it, verification with VerifyDigitalSignature(file, certificate) needs the certificate. |
PreserveWhitespace | true (default): the white space of the document is kept exactly, and the signed document is written as it was. false: the insignificant white space is removed when the document is loaded and the result is indented. |
The result is an XML document with a Signature element (shortened):
<Signature Id="Signature-c5ebc05f5292a6e2" xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
<XPath xmlns:ds="http://www.w3.org/2000/09/xmldsig#">not(ancestor-or-self::ds:Signature)</XPath>
</Transform>
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>ljCeDlHjth920eC4V7sbhf2ohGqrtkDXa4oQ/1ZerMs=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>eqfjZXq9igQEaxqs...</SignatureValue>
<KeyInfo>
<KeyValue><RSAKeyValue><Modulus>la21u9LP...</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue>
<X509Data><X509Certificate>MIIDZTCCAk2gAwIB...</X509Certificate></X509Data>
</KeyInfo>
</Signature>
The signature references the whole document (URI="") with an XPath transform that removes all the Signature elements, instead of the usual enveloped-signature transform that removes only the signature that contains it. This is the standard construction for parallel signatures: a signature that is added later is not part of the digest of the first one, so every signature stays valid.
Several signatures, reading and verifying
- To add a signature, sign again the signed document (the input and the output can be the same file). The existing signatures are not changed.
- If a signature that was created by another program with the enveloped-signature transform exists in the document, a new signature would invalidate it: the library refuses (
CryptographicException, A new signature cannot be added because it would invalidate an existing XML signature). VerifyDigitalSignature(file)verifies all the signatures and returnstruewhen they are all valid.VerifyDigitalSignature(file, index)verifies one (the indexes are 0-based, in the order of the document).VerifyDigitalSignature(file, certificate)istruewhen a valid signature of the document was created with that certificate: use it to check that the expected person signed.GetDigitalSignatureCertificate(file, index)returns the certificate of a signature.- A document without signatures throws
CryptographicException(No digital signature was found in the document). - All the methods have
Streamoverloads, for web applications.
XmlSignature xmlSignature = new XmlSignature(LibrarySerialNumber);
// Add a second signer to the document that is already signed.
X509Certificate2 secondSigner = DigitalCertificate.LoadCertificate("second.pfx", "123456");
xmlSignature.DigitalSignatureCertificate = secondSigner;
xmlSignature.ApplyDigitalSignature("test[signed].xml", "test[signed].xml");
int count = xmlSignature.GetNumberOfSignatures("test[signed].xml");
for (int index = 0; index < count; index++)
{
X509Certificate2 signer = xmlSignature.GetDigitalSignatureCertificate("test[signed].xml", index);
Console.WriteLine(index + ": " + signer.GetNameInfo(X509NameType.SimpleName, false)
+ ", valid: " + xmlSignature.VerifyDigitalSignature("test[signed].xml", index));
}
// Was the document signed by the expected certificate?
bool signedBySecond = xmlSignature.VerifyDigitalSignature("test[signed].xml", secondSigner);
// In memory (a web application).
using (MemoryStream input = new MemoryStream(File.ReadAllBytes("test.xml")))
using (MemoryStream output = new MemoryStream())
{
xmlSignature.DigitalSignatureCertificate = signingCertificate;
xmlSignature.ApplyDigitalSignature(input, output);
byte[] signedXml = output.ToArray();
}
A signature covers the canonical form of the XML. Changing a value, the order of the elements or the text of the document (including re-saving it with another encoding) invalidates it. The white space between the elements is part of the signed data: reformatting or indenting a signed document changes it. Keep the signed file as it is, and load and save it with the encoding that its XML declaration declares.
8.2 XAdES
XadesSignature follows the same pattern as XmlSignature, with the properties of the ETSI standard:
| Property | Meaning |
|---|---|
SignatureStandard (XadesSignatureStandard) | XadesB (B-B, the default), XadesT (+ time-stamp), XadesLT (+ validation data), XadesLTA (+ archive time-stamp). T, LT and LTA require TimeStamping.ServerUrl (ArgumentException otherwise). A XadesB signature is also time-stamped (B-T) when the server is set. |
SignaturePackaging | Enveloped (default): the signature is in the XML document, only an XML document can be signed. Detached: the signature is a separate XML file that references the signed file, of any type; the signed file is needed to verify it. |
HashAlgorithm | SHA256 (default), SHA384, SHA512 (not SHA-1). |
CommitmentType (XadesCommitmentType) | What the signer declares: None (default, not written), ProofOfOrigin, ProofOfReceipt, ProofOfDelivery, ProofOfSender, ProofOfApproval, ProofOfCreation. It is a signed property: the signer commits to it. |
SignatureProductionPlace (XadesProductionPlace) | City, street address, state or province, postal code and country (an ISO code such as RO). All the fields are optional. |
LtvLevel (XadesLtvLevel) | The revocation data of the LT and LTA levels: None, IncludeCrl, IncludeCrlAndOcsp, IncludeOcspOnly (see section 12). |
MaxCrlSize | The CRLs larger than this value are not included (1 MB by default). |
SetSignaturePolicyInformation | An explicit signature policy (section 6.13). |
XadesSignature xadesSignature = new XadesSignature(LibrarySerialNumber);
xadesSignature.DigitalSignatureCertificate = signingCertificate;
xadesSignature.SignatureStandard = XadesSignatureStandard.XadesB;
xadesSignature.SignaturePackaging = XadesSignaturePackaging.Enveloped;
xadesSignature.CommitmentType = XadesCommitmentType.ProofOfApproval;
xadesSignature.SignatureProductionPlace = new XadesProductionPlace { City = "Bucharest", CountryName = "RO" };
xadesSignature.ApplyDigitalSignature("test.xml", "test[xades].xml");
Console.WriteLine("Valid: " + xadesSignature.VerifyDigitalSignature("test[xades].xml"));
A time-stamp and the long term levels
XadesSignature xadesSignature = new XadesSignature(LibrarySerialNumber);
xadesSignature.DigitalSignatureCertificate = signingCertificate;
xadesSignature.SignatureStandard = XadesSignatureStandard.XadesLT; // XadesT, XadesLT or XadesLTA
xadesSignature.LtvLevel = XadesLtvLevel.IncludeCrlAndOcsp;
xadesSignature.TimeStamping.ServerUrl = new Uri("https://ca.signfiles.com/TSAServer.aspx");
xadesSignature.ApplyDigitalSignature("test.xml", "test[xades-lt].xml");
Detached signatures
The signature is saved in an XML file and the signed file is not changed. The signature file must be a different file from the signed one. To verify, give both the signature and the original file (the original can have been renamed: with a single signed file the data is matched whatever its name; its integrity is guaranteed by the digest of the reference).
XadesSignature xadesSignature = new XadesSignature(LibrarySerialNumber);
xadesSignature.DigitalSignatureCertificate = signingCertificate;
xadesSignature.SignaturePackaging = XadesSignaturePackaging.Detached;
xadesSignature.ApplyDigitalSignature("contract.pdf", "contract.pdf[signature].xml");
bool valid = xadesSignature.VerifyDigitalSignature("contract.pdf[signature].xml", "contract.pdf");
X509Certificate2 signer = xadesSignature.GetDigitalSignatureCertificate("contract.pdf[signature].xml");
Several signers of the same file create separate signature files. To put several signed files and their signatures in one file, use an ASiC-E container (section 10).
Verifying XAdES signatures
VerifyDigitalSignature, GetNumberOfSignatures, GetDigitalSignatureCertificate and GetSignatureAlgorithm work as for XmlSignature. The verification checks the digest of the signed data, the digest of the signed properties and the signature value, and that the signing certificate of the signed properties is the certificate of the signature. The method verifies the signature; it does not validate the time-stamp tokens, the revocation data or the trust of the certificates of the higher levels: that is a decision of your application, or of a validator (section 14.5).
8.3 ECDSA
RSA and ECDSA certificates are supported for XMLDSig and XAdES. The signature value of ECDSA in XML is the raw concatenation r || s (RFC 4051), different from the DER form of CMS; the library produces the right form for every format. The ECDSA signature methods of RFC 6931 are registered when the runtime does not have them.
8.4 Notes
- Encoding. The signed document is saved in the encoding that its XML declaration declares (UTF-8 without a byte order mark when no encoding is declared). Do not re-save the signed document with another encoding.
- Only XML. Enveloped signatures need an XML document. For other files use the detached XAdES signature, the CAdES signature (section 7) or an ASiC-E container.
- Interoperability. The XAdES signatures follow the baseline profiles of ETSI EN 319 132-1 and are validated by the EU DSS validator (section 14.5).
- Demo version. Every signing and verification call waits 10 seconds (section 2.4).
9. Office documents
OfficeSignature signs Office Open XML documents: Word (.docx, .docm), Excel (.xlsx, .xlsm) and PowerPoint (.pptx, .pptm). It creates the package signatures that Microsoft Office 2010 and later create and verify (File > Info > Protect Document > Add a Digital Signature): a XAdES signature in the part /_xmlsignatures/sigN.xml of the package. Office, and the library, show the signatures in the same way. The signature can be invisible, or visible in a Word document, as a signature line.
The library does not need Office installed. The documents are processed as Open Packaging Conventions packages (System.IO.Packaging).
9.1 Signing a document
OfficeSignature officeSignature = new OfficeSignature(LibrarySerialNumber);
officeSignature.DigitalSignatureCertificate = signingCertificate;
officeSignature.SignatureComments = "I approve this document"; // "Purpose for signing this document" in Office
officeSignature.ApplyDigitalSignature("contract.docx", "contract[signed].docx"); // the output can be the input file
Console.WriteLine("Signatures: " + officeSignature.GetNumberOfSignatures("contract[signed].docx"));
Console.WriteLine("Valid: " + officeSignature.VerifyDigitalSignature("contract[signed].docx"));
| Property | Meaning |
|---|---|
SignatureStandard (XadesSignatureStandard) | XadesB (default), XadesT, XadesLT. T and LT need TimeStamping.ServerUrl. XadesLTA is not supported for Office documents (NotSupportedException). |
HashAlgorithm | SHA256 (default), SHA384, SHA512. SHA-1 is not supported for new signatures (NotSupportedException). |
SignatureComments | The purpose of the signature, shown by Office as “Purpose for signing this document”. |
CommitmentType | The commitment of the signer, shown by Office: for example ProofOfApproval is “Approved this document”. |
SignerRole | The role or the title of the signer (the claimed role). |
SignatureProductionPlace | The city, the state or province, the postal code and the country (the street address is not used by Office). |
TimeStamping, LtvLevel, MaxCrlSize | The time-stamp and the validation data of the levels T and LT (section 12). |
SignatureLine | The visible signature, a signature line of a Word document (section 9.2). null (default): invisible. |
SetSignaturePolicyInformation | An explicit signature policy. By default the policy is implied, as for the signatures that Office creates. |
The signed parts of the package are the main part and all the parts that it uses, with their relationships. A document with signatures cannot be changed: any change invalidates them. A second signature does not invalidate the first.
// Several signers: the document is signed again; the previous signatures stay valid.
OfficeSignature secondSigner = new OfficeSignature(LibrarySerialNumber);
secondSigner.DigitalSignatureCertificate = DigitalCertificate.LoadCertificate("second.pfx", "123456");
secondSigner.SignerRole = "Reviewer";
secondSigner.CommitmentType = XadesCommitmentType.ProofOfApproval;
secondSigner.ApplyDigitalSignature("contract[signed].docx", "contract[signed].docx");
A time-stamp and validation data
OfficeSignature officeSignature = new OfficeSignature(LibrarySerialNumber);
officeSignature.DigitalSignatureCertificate = signingCertificate;
officeSignature.SignatureStandard = XadesSignatureStandard.XadesLT; // XadesT: the time-stamp only
officeSignature.LtvLevel = XadesLtvLevel.IncludeCrlAndOcsp;
officeSignature.TimeStamping.ServerUrl = new Uri("https://ca.signfiles.com/TSAServer.aspx");
officeSignature.ApplyDigitalSignature("report.xlsx", "report[signed-lt].xlsx");
In memory
The byte array and the stream overloads avoid the files. A stream is signed in place: the signed document replaces its content, so the stream must be readable, writable, seekable and expandable: a MemoryStream created from a byte array has a fixed size, create an empty one and write the document in it.
OfficeSignature officeSignature = new OfficeSignature(LibrarySerialNumber);
officeSignature.DigitalSignatureCertificate = signingCertificate;
// A byte array.
byte[] signedArray = officeSignature.ApplyDigitalSignature(File.ReadAllBytes("contract.docx"));
// A stream (in place).
using (MemoryStream stream = new MemoryStream())
{
byte[] unsigned = File.ReadAllBytes("contract.docx");
stream.Write(unsigned, 0, unsigned.Length);
stream.Position = 0;
officeSignature.ApplyDigitalSignature(stream);
File.WriteAllBytes("contract[signed].docx", stream.ToArray());
}
9.2 Visible signatures: signature lines (Word, Windows)
A signature line is the place in a Word document where a person signs: a rectangle with a line, the name and the title of the signer. When the document is signed, Word shows the signature on the line and marks it as invalid if the document is changed. OfficeSignatureLine describes it, and the property OfficeSignature.SignatureLine makes the signature visible. Signature lines work for Word documents only (.docx, .docm) and on Windows (the images are drawn with System.Drawing; PlatformNotSupportedException on the other systems); a visible signature on a workbook or a presentation throws NotSupportedException.
OfficeSignatureLine | Meaning |
|---|---|
Placement | UseExistingOrAddNew: signs the first unsigned line, or adds a new line at the end of the document when there is none. UseExisting: signs an existing unsigned line (the one with SetupId, or the first one) and fails when there is none. AddNew: adds a new line at the end and signs it (the document must not be signed yet). |
SetupId | The identifier of the line to sign (a GUID), as returned by AddSignatureLine or listed by GetSignatureLines. |
SuggestedSigner, SuggestedSignerTitle, SuggestedSignerEmail, SigningInstructions | The data shown on a new line and in the signing window of Word. Empty SuggestedSigner: the name of the certificate is shown. |
SignatureText, SignatureImage, ShowSignDate | What is shown above the line when it is signed: a text (the name of the signer), a handwritten image (PNG, JPEG, BMP, GIF) and the date. |
Alignment (OfficeSignatureLineAlignment), Width, Height | The alignment of a new line, and its size in points (default 192 × 96). |
OfficeSignature officeSignature = new OfficeSignature(LibrarySerialNumber);
officeSignature.DigitalSignatureCertificate = signingCertificate;
officeSignature.SignatureLine = new OfficeSignatureLine
{
Placement = OfficeSignatureLinePlacement.UseExistingOrAddNew,
SuggestedSigner = "John Smith",
SuggestedSignerTitle = "Accounting manager",
SigningInstructions = "Sign only after the verification of the document.",
SignatureText = "John Smith",
SignatureImage = File.ReadAllBytes("signature_image.jpg"),
ShowSignDate = true
};
officeSignature.ApplyDigitalSignature("contract.docx", "contract[signed].docx");
A document for several signers
Add the signature lines of all the signers before the first signature (a signed document cannot be changed: InvalidOperationException), then every signer signs the line with the identifier that was returned. The lines can also be created in Word (Insert > Signature Line).
OfficeSignature prepare = new OfficeSignature(LibrarySerialNumber);
string managerLine = prepare.AddSignatureLine("contract.docx", "contract[lines].docx", new OfficeSignatureLine
{
SuggestedSigner = "John Smith", SuggestedSignerTitle = "Manager"
});
string accountantLine = prepare.AddSignatureLine("contract[lines].docx", "contract[lines].docx", new OfficeSignatureLine
{
SuggestedSigner = "Mary Jones", SuggestedSignerTitle = "Accountant", Alignment = OfficeSignatureLineAlignment.Right
});
foreach (OfficeSignatureLineInfo line in prepare.GetSignatureLines("contract[lines].docx"))
Console.WriteLine(line.SetupId + ": " + line.SuggestedSigner + ", signed: " + line.IsSigned);
// Every signer signs his line.
OfficeSignature manager = new OfficeSignature(LibrarySerialNumber);
manager.DigitalSignatureCertificate = signingCertificate;
manager.SignatureLine = new OfficeSignatureLine { Placement = OfficeSignatureLinePlacement.UseExisting, SetupId = managerLine, ShowSignDate = true };
manager.ApplyDigitalSignature("contract[lines].docx", "contract[lines].docx");
OfficeSignature accountant = new OfficeSignature(LibrarySerialNumber);
accountant.DigitalSignatureCertificate = DigitalCertificate.LoadCertificate("accountant.pfx", "123456");
accountant.SignatureLine = new OfficeSignatureLine { Placement = OfficeSignatureLinePlacement.UseExisting, SetupId = accountantLine };
accountant.ApplyDigitalSignature("contract[lines].docx", "contract[lines].docx");
9.3 Reading and verifying the signatures
| Method | Result |
|---|---|
GetNumberOfSignatures(file | stream) | The number of signatures. |
VerifyDigitalSignature(file | stream) | true when all the signatures are valid; a document without signatures throws CryptographicException. |
VerifyDigitalSignature(file, int index) | One signature (0-based). |
VerifyDigitalSignature(file, X509Certificate2 certificate) | true when a valid signature of the document was created with the certificate. |
GetDigitalSignatureCertificate(file, index), GetSignatureAlgorithm(file, index) | The certificate and the algorithm (for example RSA-SHA256, ECDSA-SHA384) of a signature. |
GetSignatures(file | stream) | A List<OfficeSignatureInfo>: every signature with its information and the result of its verification. |
GetSignatureLines(file | stream) | The signature lines of a Word document (OfficeSignatureLineInfo: SetupId, SuggestedSigner, IsSigned); an empty list for the other documents. |
OfficeSignatureInfo: Index; Status (Success; ContentModified when the document was changed after it was signed; ReferenceNotFound when a signed part is missing; InvalidSignature); IsValid; Certificate, SignerName; SigningTime (UTC, declared by the signer); HasTimestamp, TimestampTime; HasValidationData (XAdES-LT); SignatureAlgorithm; SignatureComments, CommitmentType, SignerRole; IsVisible and SetupId of the signature line.
OfficeSignature officeSignature = new OfficeSignature(LibrarySerialNumber);
foreach (OfficeSignatureInfo info in officeSignature.GetSignatures("contract[signed].docx"))
{
Console.WriteLine(info.Index + ": " + info.SignerName + ", " + info.Status + ", " + info.SignatureAlgorithm);
if (info.SigningTime.HasValue)
Console.WriteLine(" signed " + info.SigningTime.Value.ToLocalTime() + ", purpose: " + info.SignatureComments);
if (info.HasTimestamp)
Console.WriteLine(" time-stamp " + info.TimestampTime.Value.ToLocalTime() + ", validation data: " + info.HasValidationData);
}
The verification checks the XML signature, the binding of the signing certificate of the XAdES signature and the digests of all the signed parts and relationships. A document that was changed after it was signed gives ContentModified. The trust of the signing certificate and the revocation are not checked (section 4.5); Office warns when the certificate is not trusted.
9.4 Notes
- Macro-enabled documents (
.docm,.xlsm,.pptm) are signed as the other documents. - External keys. An external signature provider (a PKCS#11 token, an HSM, a key vault) is used as for the other classes, by setting
DigitalCertificate.UseExternalSignatureProviderbefore the signing call (section 13). - Only the Office Open XML formats are signed. The binary formats of Office 2003 and earlier (
.doc,.xls,.ppt) are not packages and they are not supported. - XPS documents cannot be signed by this version of the library.
- Packages and drawing. A project that signs Office documents needs the references of section 2.2 (
System.IO.PackagingandSystem.Drawing.Commonon .NET;WindowsBaseandSystem.Drawingon .NET Framework).
10. ASiC-E containers
An ASiC-E container (Associated Signature Container, Extended; ETSI EN 319 162-1) is a single ZIP file (.asice) that holds any number of files, of any type, and their XAdES signatures. It is the container that the eIDAS regulation recommends and that many e-government systems use for e-invoicing, e-procurement, e-tax and court filings. AsicSignature creates the containers, adds signatures (co-signatures), verifies them, reads their contents and renews their time-stamps. Every signature covers all the files of the container.
10.1 Creating a container
CreateContainer signs the files and writes the container in one operation. The files are stored under their names; with the dictionary overload the name is the path inside the container (for example annexes/annex1.pdf), and no file touches the disk.
AsicSignature asicSignature = new AsicSignature(LibrarySerialNumber);
asicSignature.DigitalSignatureCertificate = signingCertificate;
// From files: the container is written to the output path (and deleted when the signature fails).
asicSignature.CreateContainer(new[] { "contract.pdf", "data.xml" }, "documents.asice");
// From memory: the names are the paths in the container.
IDictionary<string, byte[]> files = new Dictionary<string, byte[]>
{
{ "contract.pdf", File.ReadAllBytes("contract.pdf") },
{ "annexes/annex1.pdf", File.ReadAllBytes("annex1.pdf") }
};
byte[] container = asicSignature.CreateContainer(files);
File.WriteAllBytes("documents[memory].asice", container);
The names must be safe relative paths: no absolute path, no .., no backslash, no META-INF or mimetype, and unique (ArgumentException otherwise). A file that does not exist throws FileNotFoundException.
| Property | Meaning |
|---|---|
SignatureStandard (XadesSignatureStandard) | XadesB (default), XadesT, XadesLT, XadesLTA. T, LT and LTA need TimeStamping.ServerUrl. |
HashAlgorithm | SHA256 (default), SHA384, SHA512 (not SHA-1). |
TimeStamping, LtvLevel, MaxCrlSize | The time-stamp and the validation data (section 12). |
CommitmentType, SignatureProductionPlace | The signed properties of XAdES (section 8.2). |
SetSignaturePolicyInformation | An explicit signature policy. |
AsicSignature asicSignature = new AsicSignature(LibrarySerialNumber);
asicSignature.DigitalSignatureCertificate = signingCertificate;
asicSignature.SignatureStandard = XadesSignatureStandard.XadesLT;
asicSignature.LtvLevel = XadesLtvLevel.IncludeCrlAndOcsp;
asicSignature.TimeStamping.ServerUrl = new Uri("https://ca.signfiles.com/TSAServer.aspx");
asicSignature.HashAlgorithm = SignLib.HashAlgorithm.SHA384;
asicSignature.CommitmentType = XadesCommitmentType.ProofOfApproval;
asicSignature.SignatureProductionPlace = new XadesProductionPlace { City = "Bucharest", CountryName = "RO" };
asicSignature.CreateContainer(new[] { "contract.pdf", "data.xml" }, "documents[lt].asice");
10.2 Co-signatures
AddSignature adds a signature of another signer. The new signature covers all the files and goes to a new signature file; the existing signatures are not changed. Set the certificate of the new signer on the object first.
AsicSignature secondSigner = new AsicSignature(LibrarySerialNumber);
secondSigner.DigitalSignatureCertificate = DigitalCertificate.LoadCertificate("second.pfx", "123456");
// Files (the output can be the input container).
secondSigner.AddSignature("documents.asice", "documents[cosigned].asice");
// In memory.
byte[] cosigned = secondSigner.AddSignature(File.ReadAllBytes("documents.asice"));
10.3 Reading and verifying a container
| Method | Result |
|---|---|
GetNumberOfSignatures(container) | The number of signatures. |
GetDigitalSignatureCertificate(container, index) | The certificate of a signature (0-based, the signature files in name order). |
GetDataFileNames(container) | The names of the signed files. |
ExtractDataFile(container, name) | The content of a signed file (byte[]). |
VerifyDigitalSignature(container) | true when the container has at least one signature, all the signatures are valid and each one covers all the files of the container. A file added to the container after it was signed makes the verification fail; so does a changed file. |
VerifyDigitalSignature(container, certificate) | true when a valid signature that covers all the files was created with the certificate. |
The container is a path or a byte[] in all the methods.
AsicSignature asicSignature = new AsicSignature(LibrarySerialNumber);
int signatures = asicSignature.GetNumberOfSignatures("documents[cosigned].asice");
for (int index = 0; index < signatures; index++)
Console.WriteLine("Signer " + index + ": " + asicSignature.GetDigitalSignatureCertificate("documents[cosigned].asice", index).Subject);
foreach (string name in asicSignature.GetDataFileNames("documents[cosigned].asice"))
Console.WriteLine("File: " + name);
byte[] contract = asicSignature.ExtractDataFile("documents[cosigned].asice", "contract.pdf");
File.WriteAllBytes("extracted contract.pdf", contract);
Console.WriteLine("Valid: " + asicSignature.VerifyDigitalSignature("documents[cosigned].asice"));
The method verifies the integrity of the signatures and the coverage of the files; it does not decide that the signers can be trusted (section 4.5). A container that has signature files that are not XAdES (for example CAdES *.p7s files) is not verified by this class.
10.4 Renewing the archive time-stamp
An XadesLTA container is protected for the long term by an archive time-stamp. AddArchiveTimestamp adds a new archive time-stamp to every XAdES-LTA signature of the container, with the validation data that is needed to validate the previous time-stamps. Call it before the certificate of the time-stamping authority of the last time-stamp expires (section 12.4). It needs TimeStamping.ServerUrl and it does not need the certificate of the signers.
AsicSignature asicSignature = new AsicSignature(LibrarySerialNumber);
asicSignature.TimeStamping.ServerUrl = new Uri("https://ca.signfiles.com/TSAServer.aspx");
asicSignature.LtvLevel = XadesLtvLevel.IncludeCrlAndOcsp;
asicSignature.AddArchiveTimestamp("documents[lta].asice", "documents[lta-renewed].asice");
The signatures cover the files in the container, so a container is verified as a whole. Do not repack the ZIP file with another tool (the mimetype entry must be the first one and not compressed). To use the signed files, extract them with ExtractDataFile.
10.5 Notes
- The container is created in memory. The size limit of the ZIP writer is 4 GB and 65535 entries (no ZIP64).
- An external signature provider (PKCS#11, HSM, remote service) is used as for the other classes: set
DigitalCertificate.UseExternalSignatureProviderbefore the signing call (section 13). - The container is a ZIP file written by the library: a .NET Framework project needs the reference
System.IO.Compression(section 2.3); no extra package is needed on .NET.
11. Time-stamps
A time-stamp (RFC 3161) is a proof, signed by a time-stamping authority (TSA), that some data existed at a given time. The application sends the hash of the data to the TSA server (the data itself is never sent) and receives a signed time-stamp token. The library uses time-stamps in two ways:
- inside the signatures: PDF, CAdES, XAdES, Office and ASiC-E signatures with the level T and above get a time-stamp when you set
TimeStamping.ServerUrlon the signature object (section 11.1); - of a file:
TimestampClienttime-stamps any file or data and saves the result as a.tsr,.tstor.tsdfile (section 11.2).
11.1 Time-stamping settings
Every signature class has a property TimeStamping (TimestampSettings), and TimestampClient has one too. When the signature classes find ServerUrl set, they time-stamp the signature; when it is null (the default), they do not use the network for the time.
TimestampSettings | Meaning |
|---|---|
ServerUrl | The Uri of the RFC 3161 server (HTTP or HTTPS). |
UserName, Password | HTTP basic authentication, for the servers that require it. |
AuthenticationCertificate | A certificate for TLS client authentication, for the servers that require it. |
PolicyOid (Oid) | The policy that is requested from the server. Set it only when the server requires it. |
UseNonce | Add a nonce to the request, to match the response with the request. true by default. |
HashAlgorithm | The hash of the request: SHA256 by default (SHA384, SHA512, SHA1). PAdES and the other long term formats should use SHA-256 or stronger. |
ServerTimeout | The time-out of the request in milliseconds, 20000 by default. |
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = signingCertificate;
pdfSignature.TimeStamping.ServerUrl = new Uri("https://ca.signfiles.com/TSAServer.aspx");
pdfSignature.TimeStamping.HashAlgorithm = SignLib.HashAlgorithm.SHA256;
pdfSignature.TimeStamping.ServerTimeout = 30000;
// A server with authentication.
pdfSignature.TimeStamping.UserName = "account";
pdfSignature.TimeStamping.Password = "secret";
// Or a server that requires a TLS client certificate.
pdfSignature.TimeStamping.AuthenticationCertificate = DigitalCertificate.LoadCertificate("tsa-client.pfx", "123456");
// A policy that the server requires.
pdfSignature.TimeStamping.PolicyOid = new System.Security.Cryptography.Oid("1.3.6.1.4.1.13762.3");
File.WriteAllBytes("source[signed-T].pdf", pdfSignature.ApplyDigitalSignature());
- An unreachable server, a server that refuses the request or an invalid response throw
WebException(Invalid time stamping response. with the status and the reason). The signature is not created without the time-stamp when one is requested. - The address
https://ca.signfiles.com/TSAServer.aspxis a free server for tests and for the samples of the library. For production use a time-stamping service that you choose and that has the service level that you need: a qualified time-stamping service for the eIDAS qualified signatures. - The time-stamp requests of the library are sent with the platform HTTP client (section 4.10); the time-out of the certificate and revocation downloads is another setting (
DigitalCertificate.Timeout). - In the demo version every time-stamp operation waits 10 seconds.
11.2 Time-stamping a file: TimestampClient
TimestampClient returns the time-stamp of a file or of data. The property TimestampFormat chooses the format of the result:
TimestampFormat | Result |
|---|---|
DetachedTimestamp (default) | The time-stamp response (RFC 3161 TimeStampResp) in a separate .tsr file. The original file is needed to verify it. |
TimestampToken | Only the time-stamp token (a CMS SignedData), without the status of the response, in a .tst file. The detached format that the EU DSS validator accepts. |
EmbeddedTimestamp | A .tsd file (RFC 5544, Time Stamped Data) that contains the original content, its name and the time-stamp in one file. |
TimestampClient timestampClient = new TimestampClient(LibrarySerialNumber);
timestampClient.TimeStamping.ServerUrl = new Uri("https://ca.signfiles.com/TSAServer.aspx");
// A .tsr file.
timestampClient.TimestampFormat = TimestampFormat.DetachedTimestamp;
File.WriteAllBytes("contract.pdf.tsr", timestampClient.ObtainTimestamp("contract.pdf"));
// A .tsd file: the file and its time-stamp.
timestampClient.TimestampFormat = TimestampFormat.EmbeddedTimestamp;
File.WriteAllBytes("contract.pdf.tsd", timestampClient.ObtainTimestamp("contract.pdf"));
// Data in memory.
byte[] timestamp = timestampClient.ObtainTimestamp(File.ReadAllBytes("contract.pdf"));
A time-stamped file proves that the file existed at the time of the time-stamp. The time-stamp of a file is not a signature of a person: it does not say who created the file.
11.3 Reading and verifying a time-stamp
TimestampInfo.GetInfoFromTsaResponse(bytes) reads a .tsr, .tst or .tsd file. TimestampInfo.IsTsaReponseFileValid(originalFile, timestamp) verifies it against the original file and throws an exception when the file was changed or the time-stamp was altered; it returns true otherwise. The same TimestampInfo is the property TimestampInfo of the signatures that have a time-stamp (PdfSignatureInfo, CadesSignatureInfo).
TimestampInfo | Meaning |
|---|---|
SignatureTime | The time of the time-stamp (UTC). |
Accuracy | The accuracy of the time (Seconds, Milliseconds, Microseconds; a value is null when the server does not set it). |
IsTimestampAltered | true when the signature of the time-stamp token is not valid: the token was changed. |
TsaCertificate, TsaServerName | The certificate of the time-stamping authority (when it is in the token) and its name. |
HashAlgorithm (Oid), OriginalDataHash | The algorithm and the value of the hash that was time-stamped (the message imprint). |
Policy (Oid), SerialNumber, Nonce | The policy of the server, the serial number of the time-stamp and the nonce of the request. |
IsQualifiedTimestamp | true when the token declares itself a qualified electronic time-stamp (ETSI EN 319 422). The qualified status is given by the EU trusted lists: a qualified server can issue time-stamps without this statement. |
TimestampedDataContent, TimestampedDataFileName | For a .tsd file: the embedded original content and its name (null when it is not embedded). |
TimestampToken | The encoded time-stamp token. |
byte[] timestampFile = File.ReadAllBytes("contract.pdf.tsr");
TimestampInfo info = TimestampInfo.GetInfoFromTsaResponse(timestampFile);
Console.WriteLine("Time: " + info.SignatureTime.ToLocalTime());
Console.WriteLine("Authority: " + info.TsaCertificate.Subject + ", hash " + info.HashAlgorithm.FriendlyName);
Console.WriteLine("Altered: " + info.IsTimestampAltered + ", qualified: " + info.IsQualifiedTimestamp);
try
{
TimestampInfo.IsTsaReponseFileValid(File.ReadAllBytes("contract.pdf"), timestampFile);
Console.WriteLine("The time-stamp matches the file.");
}
catch (Exception ex)
{
Console.WriteLine("The verification failed: " + ex.Message); // the file or the time-stamp was changed
}
The checks above verify the time-stamp token and its link with the data. As for the signatures, the decision that the time-stamping authority can be trusted is yours: check that the certificate of the authority was valid at the time of the time-stamp, that its chain ends in a root that you trust (or in the EU trusted list for qualified time-stamps), and its revocation status (section 5.4).
11.4 Time-stamps of the signatures
| Format | What the time-stamp covers | How to read it |
|---|---|---|
The signature (signature time-stamp) and, in PAdES-LTA, the whole document (document time-stamp, ApplyTimestampSignature). | PdfSignatureInfo.SignatureIsTimestamped, TimestampInfo; a document time-stamp is a PdfSignatureInfo with SignatureType.TimestampSignature. | |
| CAdES | The signature value (CAdES-T); the references (CAdES-X Long); the signature and its validation data (CAdES-A, archive time-stamp). | CadesSignatureInfo.SignatureIsTimestamped, TimestampInfo. |
| XAdES, ASiC-E | The signature value (SignatureTimeStamp); the archive time-stamps (xades141:ArchiveTimeStamp) of the LTA level. | The elements of the signature XML. |
| Office | The signature value (XAdES-T). | OfficeSignatureInfo.HasTimestamp, TimestampTime. |
How the time-stamps make a signature last, and how to renew them, is in section 12.
12. Long term validation and archiving
A signature has to be validated when it is read, maybe years after it was made, and by then the certificate of the signer has expired, the certification authority may no longer publish the revocation information, and the algorithms of the time may be weak. The long term levels of the signatures (B-T, B-LT, B-LTA) keep the evidence that is needed to validate the signature as of the time when it was created. This chapter explains what the library embeds in the signatures, how to create the levels in every format, and how to renew the time-stamps of an archive.
12.1 What each level adds
- B-T. The time-stamp proves the signing time. With it, a validator can verify that the certificate was valid at that time, even if it expires later. A time-stamp is required by every long term level.
- B-LT. The certificates of the chain and the revocation information (CRL and OCSP responses) are embedded. A validator does not have to download them, and they exist when the servers are gone.
- B-LTA. An archive time-stamp over the signature and its validation data protects them against the weakening of the algorithms and against the expiry of the certificates of the validation data. It is renewed from time to time with a new time-stamp, over the previous ones.
12.2 Creating the levels
| Format | B-T | B-LT | B-LTA |
|---|---|---|---|
TimeStamping.ServerUrl | SignatureStandard = PadesLT, PadesLtvLevel | SignatureStandard = PadesLTA | |
| CAdES | CadesBes + TimeStamping.ServerUrl | SignatureStandard = CadesLT (also CadesC, CadesXL) | SignatureStandard = CadesA |
| XAdES | XadesT | XadesLT, LtvLevel | XadesLTA |
| ASiC-E | XadesT | XadesLT, LtvLevel | XadesLTA |
| Office | XadesT | XadesLT, LtvLevel | not supported |
In every case TimeStamping.ServerUrl must be set for T, LT and LTA (section 11.1). Examples: section 6.9 (PDF), section 7.2 (CAdES), section 8.2 (XAdES), section 10.1 (ASiC-E), section 9.1 (Office).
12.3 The validation data
When it signs at the LT or LTA level, the library collects the revocation information from the addresses that are written in the certificates (the CRL distribution points and the Authority Information Access extension, for the CRLs, the OCSP responders and the certificates of the issuers). It embeds the data of the whole chain of the signing certificate and of the time-stamping authority. The selection of the revocation data is the same enumeration, with the same values, in the formats:
Value (PadesLtvLevel, XadesLtvLevel) | Embedded data |
|---|---|
IncludeCrlAndOcsp | The CRLs and the OCSP responses of the certificate chains, when they are available. |
IncludeOcspOnly | The OCSP responses of the chains. The CRL of an end-entity certificate is included only when its OCSP response is not available; the CRLs of the CA certificates are included. The smallest result. It is the default of PDF, XAdES, Office and ASiC-E. |
IncludeCrl | The CRLs of the chains. |
None | No revocation data (only the certificates). |
- The data that cannot be obtained is skipped: a server that does not answer, a CRL that is larger than
MaxCrlSizeor that cannot be read. The signature is created anyway, with what could be collected. If the validation data is important, check the result after the signing (see below), and retry later when it is missing. - A certificate without a CRL address and without an OCSP responder, such as a self-signed certificate or a certificate that you generated without them, has no revocation data: only the certificate is embedded. For the tests of the long term features use a certificate issued by a certification authority that publishes its revocation information.
- The size of the signature grows with the validation data: the CRLs of some certification authorities have megabytes.
MaxCrlSize(the property ofXadesSignature,OfficeSignature,AsicSignatureandCadesSignature) skips the CRLs that are larger than the limit (1 MB; for CAdES 20 MB), andIncludeOcspOnlyavoids most of them. - The downloads use
DigitalCertificate.Timeout(section 4.10).
To check that a signed PDF document has the validation data, look for the document security store. For the other formats, read the format that the library detects (CadesVerify.SignatureStandard) or the information of the signature (OfficeSignatureInfo.HasValidationData):
byte[] signedPdf = File.ReadAllBytes("source[lta].pdf");
// The document security store (/DSS) holds the certificates and the revocation data of the PAdES-LT and PAdES-LTA signatures.
bool hasValidationData = Encoding.GetEncoding("ISO-8859-1").GetString(signedPdf).Contains("/DSS");
PdfSignature verifier = new PdfSignature(LibrarySerialNumber);
verifier.LoadPdfDocument(signedPdf);
bool hasDocumentTimestamp = verifier.DocumentProperties.DigitalSignatures.Any(s => s.SignatureType == SignatureType.TimestampSignature);
Console.WriteLine("Validation data: " + hasValidationData + ", document time-stamp: " + hasDocumentTimestamp);
// CAdES: the level that was detected from the attributes of the signature.
CadesVerify cades = new CadesVerify("contract.pdf.p7m", LibrarySerialNumber);
Console.WriteLine("CAdES level: " + cades.SignatureStandard);
12.4 Renewing the time-stamps of an archive
An archive time-stamp is valid while the certificate of the time-stamping authority is valid and while its algorithms are strong. Before one of them ends, a new time-stamp is added over the whole document and over the validation data of the previous time-stamp; the protection continues for another period. The operation is repeated for the whole archiving period. It does not need the certificates or the keys of the signers.
| Format | How to renew |
|---|---|
PdfSignature.ApplyTimestampSignature() adds a new document time-stamp (ETSI.RFC3161) to the PAdES-LTA document. The previous signatures and time-stamps stay valid. | |
| ASiC-E | AsicSignature.AddArchiveTimestamp(...) adds a new archive time-stamp to every XAdES-LTA signature of the container (section 10.4). |
| XAdES | XadesSignature.AddArchiveTimestamp(...), for enveloped signatures, and the overload with the original file for detached signatures. |
| CAdES | This version has no method that adds an archive time-stamp to an existing CAdES-A signature. Keep a time-stamp of the archived file (TimestampClient, a .tsr or a .tsd file) and renew it by time-stamping the file again with its previous time-stamp. |
The decision when to renew is the policy of your archive. A usual rule: renew when the certificate of the time-stamping authority of the last time-stamp expires in less than a margin that gives you time to react (a year, for example), or immediately when an algorithm in use is no longer acceptable. A scheduled task reads every archived document, applies the rule and renews the documents that need it:
public static class ArchiveRenewal
{
private static readonly TimeSpan RenewalMargin = TimeSpan.FromDays(365);
// True when the certificate of the TSA of the last document time-stamp expires in less than the margin
// (or the document has no time-stamp).
public static bool IsRenewalNeeded(byte[] signedPdf, string serialNumber)
{
PdfSignature pdfSignature = new PdfSignature(serialNumber);
pdfSignature.LoadPdfDocument(signedPdf);
X509Certificate2 lastTsaCertificate = null;
foreach (PdfSignatureInfo info in pdfSignature.DocumentProperties.DigitalSignatures)
{
if (info.SignatureType == SignatureType.TimestampSignature)
lastTsaCertificate = info.SignatureCertificate;
}
return lastTsaCertificate == null || lastTsaCertificate.NotAfter - DateTime.Now < RenewalMargin;
}
// Adds a new document time-stamp: no signing certificate is needed.
public static byte[] Renew(byte[] signedPdf, string serialNumber, Uri timestampServer)
{
PdfSignature pdfSignature = new PdfSignature(serialNumber);
pdfSignature.LoadPdfDocument(signedPdf);
pdfSignature.TimeStamping.ServerUrl = timestampServer;
return pdfSignature.ApplyTimestampSignature();
}
}
The same loop for XAdES and ASiC-E:
Uri timestampServer = new Uri("https://ca.signfiles.com/TSAServer.aspx");
// A XAdES-LTA XML document with an enveloped signature.
XadesSignature xades = new XadesSignature(LibrarySerialNumber);
xades.TimeStamping.ServerUrl = timestampServer;
xades.LtvLevel = XadesLtvLevel.IncludeCrlAndOcsp;
xades.AddArchiveTimestamp("invoice[lta].xml", "invoice[lta-renewed].xml");
// A detached XAdES-LTA signature: the signed file is also needed.
xades.AddArchiveTimestamp("contract.pdf[signature].xml", "contract.pdf[signature-renewed].xml", "contract.pdf");
// An ASiC-E container.
AsicSignature asic = new AsicSignature(LibrarySerialNumber);
asic.TimeStamping.ServerUrl = timestampServer;
asic.LtvLevel = XadesLtvLevel.IncludeCrlAndOcsp;
asic.AddArchiveTimestamp("documents[lta].asice", "documents[lta-renewed].asice");
Before the new archive time-stamp, the library adds the certificates and the current revocation data that are needed to validate the previous time-stamps (xades141:TimeStampValidationData). AddArchiveTimestamp throws when a signature is not valid or when the document has no XAdES-LTA signature, and ArgumentException when the time-stamping server is not set.
The complete sample Timestamp Renewal (section 16) renews the time-stamps of a PDF document, of an ASiC-E container and of an XAdES document.
12.5 Recommendations
- Sign with a time-stamp whenever the signature must be validated later than the validity of the certificate. A B-B signature of a certificate that expires in a year is not validated after that year, unless the validation data was preserved elsewhere.
- Use B-LT or B-LTA for the archives, and a certificate that has a CRL or an OCSP responder, so that there is validation data to embed.
- Check the result after the signing: the validation data is skipped when a server did not answer.
- Plan the renewal when the archive is created: the time (the margin), the owner of the task and the time-stamping service that will be used (a server that may not exist after the validity of its certificate).
- Use SHA-256 or stronger for the signatures and the time-stamps.
- Validate with an independent validator (section 14.5) when the signatures are meant for the eIDAS context.
13. External keys: tokens, HSMs and remote signing
In many deployments the private key cannot be loaded in the process of your application: it is on a smart card or a USB token, in a hardware security module (HSM), in a cloud key vault or in a remote signing service, and it never leaves that device. The library supports these keys with two mechanisms:
- An external signature provider (
IExternalSignature): you give the library a small object that signs the data with the key. The library prepares the signature, calls the provider and completes the signature. Used withPdfSignature,CadesSignature,XmlSignature,XadesSignature,OfficeSignatureandAsicSignature. - Two-phase PDF signing (
PrepareExternalSignature/FinalizeExternalSignature): the signature is split in two calls, and the signing of the data can happen hours later, in another process, on another computer, with a person. Used when the signer is not available during the call (section 13.5).
13.1 The signature provider
The interface has one method:
public interface IExternalSignature
{
byte[] ApplySignature(byte[] message, Oid hashAlgorithm);
}
messageis the data to sign. It is not a hash: the provider (or the device) hashes it with the algorithm that it receives, then signs the hash. For the PDF and CAdES signatures it is the DER encoding of the signed attributes of the CMS signature; for the XML signatures (XMLDSig, XAdES, ASiC-E) it is the canonicalizedSignedInfo. The document is not sent to the provider: the data contains its hash.hashAlgorithmis the OID of the hash algorithm that the library selected (for example2.16.840.1.101.3.4.2.1for SHA-256;1.3.14.3.2.26SHA-1;...2.2SHA-384;...2.3SHA-512).- The return value is the signature value: PKCS#1 v1.5 for an RSA key; for an ECDSA key either the raw value r || s (what most PKCS#11 modules, HSMs and cloud services return) or the DER SEQUENCE { r, s }. The library converts it to the form that the format requires (section 13.4).
The certificate that you give to the signature object needs only the public part. The key stays in the device:
// A provider and the public certificate of the signer.
IExternalSignature provider = new CertificateKeyExternalSignature(signingCertificate); // see the example below
X509Certificate2 publicCertificate = new X509Certificate2(File.ReadAllBytes("signer.cer"));
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = publicCertificate; // no private key
// Bind the provider to the NEXT signature of this thread. The library releases it at the end of the operation.
DigitalCertificate.UseExternalSignatureProvider = provider;
File.WriteAllBytes("source[signed].pdf", pdfSignature.ApplyDigitalSignature());
The same property is used with the other classes: set it, then call CadesSignature.ApplyDigitalSignature, XmlSignature.ApplyDigitalSignature, XadesSignature.ApplyDigitalSignature, OfficeSignature.ApplyDigitalSignature, or the methods of AsicSignature that sign.
Rules of the provider
- Set it before every signature.
DigitalCertificate.UseExternalSignatureProviderapplies to the next signing operation of the current thread and is released when the operation ends, also when it fails. To sign two documents, set it two times. - It is thread-local. In a parallel loop set it inside the body, on the thread that signs. Do not share a provider object that is not thread-safe (a PKCS#11 session, for example) between threads.
- The key must match the certificate. For the XML signatures the library verifies the value with the public key of the certificate before it uses it; with every format, a value that was made with another key gives an invalid signature.
- Report errors as exceptions (
CryptographicException): the library does not change them. Close the sessions of the device in afinallyblock. - Do not keep the PIN in the code. Read it from a protected source when the application starts.
13.2 A provider with a .NET key
The simplest provider uses a key that .NET can use (a key that is not exportable, a CNG key, a key that another process holds). It shows what the method has to do and it is a model for the others:
public class CertificateKeyExternalSignature : IExternalSignature
{
private readonly X509Certificate2 _certificateWithPrivateKey;
public CertificateKeyExternalSignature(X509Certificate2 certificateWithPrivateKey)
{
_certificateWithPrivateKey = certificateWithPrivateKey;
}
public byte[] ApplySignature(byte[] message, Oid hashAlgorithm)
{
HashAlgorithmName hash = GetHashAlgorithmName(hashAlgorithm.Value);
// RSA: PKCS#1 v1.5 over the hash of the message.
using (RSA rsa = _certificateWithPrivateKey.GetRSAPrivateKey())
{
if (rsa != null)
return rsa.SignData(message, hash, RSASignaturePadding.Pkcs1);
}
// ECDSA: the raw value r || s. The library converts it to the form of the signature format.
using (ECDsa ecdsa = _certificateWithPrivateKey.GetECDsaPrivateKey())
{
if (ecdsa != null)
return ecdsa.SignData(message, hash);
}
throw new CryptographicException("The private key of the certificate was not found or its algorithm is not supported.");
}
private static HashAlgorithmName GetHashAlgorithmName(string oid)
{
switch (oid)
{
case "1.3.14.3.2.26": return HashAlgorithmName.SHA1;
case "2.16.840.1.101.3.4.2.1": return HashAlgorithmName.SHA256;
case "2.16.840.1.101.3.4.2.2": return HashAlgorithmName.SHA384;
case "2.16.840.1.101.3.4.2.3": return HashAlgorithmName.SHA512;
default: throw new NotSupportedException("The hash algorithm " + oid + " is not supported.");
}
}
}
13.3 PKCS#11 tokens and HSMs
PKCS#11 (Cryptoki) is the standard programming interface of smart cards, USB tokens and HSMs. Every manufacturer supplies a module (a DLL on Windows, a .so file on Linux) that implements it, and the provider calls the module to sign with the key that stays on the device. This works on any operating system, without the Windows smart card minidriver and without the PIN window of Windows, and it is the way for services and servers.
| Device | Typical PKCS#11 module |
|---|---|
| SafeNet / Thales eToken | C:\Windows\System32\eTPKCS11.dll |
| OpenSC (many smart cards) | C:\Program Files\OpenSC Project\OpenSC\pkcs11\opensc-pkcs11.dll |
| Thales Luna HSM | C:\Program Files\SafeNet\LunaClient\cryptoki.dll |
A 64-bit process needs the 64-bit module and a 32-bit process the 32-bit one. The samples PDF Digital Signature with PKCS11 Smart Card, P7M P7S CAdES Digital Signature with PKCS11 Smart Card and PDF Digital Signature with PKCS11 Driver for HSM contain the class Pkcs11ExternalSignature, a complete provider written with the library Pkcs11Interop (NuGet Pkcs11Interop): copy it into your project. It does what a provider has to do:
- loads the module, finds the slot of the token (
SlotIndex: the index among the slots that have a token) and opens a session with the PIN; - finds the certificates that have a private key on the token (
GetCertificatesFromToken()), and the private key of the signing certificate (the certificate and its key share the attributeCKA_ID); - in
ApplySignature: for RSA, signs with the mechanism that hashes and signs (CKM_SHA256_RSA_PKCSand the like), and, for tokens that do not have it, hashes the data and signs the DigestInfo withCKM_RSA_PKCS; for ECDSA, hashes the data and signs the hash withCKM_ECDSA(the result is the raw r || s).
// Excerpt of the samples that use a token. The constants are set by the application; the PIN is read from a protected source.
private const string Pkcs11LibraryPath = @"C:\Windows\System32\eTPKCS11.dll";
private const string TokenPin = ""; // do not store a PIN in the source code of a real application
private const int SlotIndex = 0; // the index of the token among the slots that have a token present
// The thumbprint of the signing certificate. When it is set, the certificate is found on the token without a window
// (a service); when it is empty, the user selects the certificate when the token has several.
private const string CertificateThumbprint = "";
Pkcs11ExternalSignature externalSignature = new Pkcs11ExternalSignature(Pkcs11LibraryPath, TokenPin, SlotIndex);
externalSignature.SigningCertificate = SelectCertificate(externalSignature.GetCertificatesFromToken()); // by thumbprint or by window
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = externalSignature.SigningCertificate; // the public part
DigitalCertificate.UseExternalSignatureProvider = externalSignature; // before every signature
File.WriteAllBytes("source[signed].pdf", pdfSignature.ApplyDigitalSignature());
- The token is opened for every signature (the session is closed after it). A token that can be used by one process at a time needs a lock around the signing calls in a service with several threads.
- A wrong PIN repeated can block the token: do not retry in a loop.
- A certificate that is also visible in the Windows store can be used without PKCS#11 (section 5.2): load it from the store and set
DigitalCertificate.SmartCardPin. PKCS#11 is the choice for non-Windows systems, for services, for the tokens whose minidriver does not take the PIN from the application, and for HSMs.
13.4 ECDSA signature values
The ECDSA signature value has two encodings. CMS (PDF, CAdES) requires the DER form SEQUENCE { INTEGER r, INTEGER s } (RFC 5753); XMLDSig (XML, XAdES, ASiC-E) requires the raw form r || s (RFC 4051). PKCS#11 modules, HSMs and cloud services usually return the raw form, and .NET's ECDsa.SignData too. A provider returns either form: the library accepts both and writes the form that the signature format needs. It does not change the signatures of RSA keys.
13.5 Two-phase PDF signing
When the signer cannot sign during the call, the PDF signature is created in three steps, which can be in different processes and at different times:
PdfSignature.PrepareExternalSignature(fieldName)prepares the document exactly asApplyDigitalSignaturedoes (the signature field, the appearance, the space for the signature) and computes the data to sign. No private key is used. The result is aPendingExternalSignature:DataToSign(the DER signed attributes),DigestAlgorithmOidand everything that is needed to complete the signature. Passnullas the field name for a new field.- The signer hashes
DataToSignwithDigestAlgorithmOidand signs the hash. The value is the same thatIExternalSignature.ApplySignaturereturns. PdfSignature.FinalizeExternalSignature(pending, signatureValue)inserts the signature in the prepared document and returns the signed PDF. No private key is needed. IfTimeStamping.ServerUrlis set on the object of this step, the signature is time-stamped; for PAdES-LT and PAdES-LTA the validation data and the document time-stamp are completed in this step.
The signature must be made over the signature settings that you choose in step 1 (the standard, the hash, the appearance): they are fixed by PrepareExternalSignature. PendingExternalSignature has no private data, and it can be serialized (for example as JSON: the byte arrays are written as Base64 text) and stored between the steps. Do not use BinaryFormatter.
// Step 1: prepare. Only the public certificate of the signer is needed.
PdfSignature prepare = new PdfSignature(LibrarySerialNumber);
prepare.LoadPdfDocument("source.pdf");
prepare.DigitalSignatureCertificate = new X509Certificate2(File.ReadAllBytes("signer.cer"));
prepare.SignatureStandard = PdfSignatureStandard.Pades;
prepare.SigningReason = "I approve this document";
prepare.SignaturePosition = SignaturePosition.TopLeft;
PendingExternalSignature pending = prepare.PrepareExternalSignature(null);
Console.WriteLine("Sign " + pending.DataToSign.Length + " bytes with the hash algorithm " + pending.DigestAlgorithmOid);
// Step 2: the signer signs the data. Here: a certificate with a private key, as a stand-in for a remote signer.
X509Certificate2 signerWithKey = DigitalCertificate.LoadCertificate("cert.pfx", "123456");
byte[] signatureValue = new CertificateKeyExternalSignature(signerWithKey)
.ApplySignature(pending.DataToSign, new System.Security.Cryptography.Oid(pending.DigestAlgorithmOid));
// Step 3: finalize (the same or another process, later).
PdfSignature finalize = new PdfSignature(LibrarySerialNumber);
byte[] signedPdf = finalize.FinalizeExternalSignature(pending, signatureValue);
File.WriteAllBytes("source[signed].pdf", signedPdf);
If the signer is a person or a remote service that you do not control, keep PendingExternalSignature on your server and give the signer only an identifier and the data to sign: the signer cannot change the document that you finalize. The sample PDF Signing Web Service (section 15.5) is a complete client and server pair built this way. When the signer is the one who owns the document, serializing the pending signature (JSON) and sending it with the data is also possible.
13.6 Cloud key vaults and remote services
The pattern is the same for every service: the certificate (public) is read from the service, and the provider sends the data to the sign operation of the service.
- Azure Key Vault. The samples PDF Digital Signature with Azure Key Vault Certificate (a certificate with an exportable key, stored as a secret: the PFX is downloaded and loaded as any PFX certificate) and PDF Digital Signature with Azure Key Vault Nonexportable HSM Certificate (the key never leaves the vault: the provider calls
CryptographyClient.SignDatawith the algorithmRS256,RS384orRS512that matches the hash OID). - A remote signing web service. The samples PDF Remote External Digital Signature and P7M P7S CAdES Remote External Digital Signature call the demo service of the library vendor (a WCF client) from a provider: the service has a method that returns the public certificate and a method that signs the data. To use your own service, replace the calls of the provider.
- Other services (AWS KMS, Google Cloud KMS, signing services of qualified trust service providers). Implement
ApplySignaturewith the signing operation of the service. Check what the service signs: some sign a digest that you compute (hashmessagewith the OID that you received, then send the hash), others hash the data themselves. For RSA, use the PKCS#1 v1.5 scheme of the service (not PSS), and for ECDSA the algorithm of the hash that you were given.
// A provider for a service that signs a digest: the provider hashes the message, the service signs the hash.
public class DigestSigningServiceSignature : IExternalSignature
{
private readonly Func<byte[], string, byte[]> _signDigest; // the call of your service: (digest, hashAlgorithmOid) -> the signature value
public DigestSigningServiceSignature(Func<byte[], string, byte[]> signDigest)
{
_signDigest = signDigest;
}
public byte[] ApplySignature(byte[] message, Oid hashAlgorithm)
{
byte[] digest;
switch (hashAlgorithm.Value)
{
case "2.16.840.1.101.3.4.2.1": digest = SHA256.Create().ComputeHash(message); break;
case "2.16.840.1.101.3.4.2.2": digest = SHA384.Create().ComputeHash(message); break;
case "2.16.840.1.101.3.4.2.3": digest = SHA512.Create().ComputeHash(message); break;
default: throw new NotSupportedException("The hash algorithm " + hashAlgorithm.Value + " is not supported.");
}
return _signDigest(digest, hashAlgorithm.Value);
}
}
14. eIDAS signatures
The eIDAS Regulation (EU) No 910/2014 on electronic identification and trust services (as amended) defines the legal effect of electronic signatures in the European Union. This chapter explains, technically, what the library gives to an application that must create or check eIDAS signatures. It is a simplified explanation and it is not legal advice.
14.1 The levels and what produces them
| Level | What it needs | The library |
|---|---|---|
| Electronic signature | Any data in electronic form that is attached to other data and used to sign. | Any signature that the library creates. |
| Advanced electronic signature (AdES) | It is uniquely linked to the signatory, it identifies the signatory, it is created with data that the signatory can use under his sole control, and it detects any later change of the data. In practice: a signature in a standard format (PAdES, XAdES, CAdES) made with a certificate issued to the signatory. | The formats PAdES (PdfSignature), CAdES (CadesSignature), XAdES (XadesSignature) and the container ASiC-E (AsicSignature), with the baseline levels B-B, B-T, B-LT, B-LTA. |
| Qualified electronic signature (QES) | An advanced signature, created by a qualified signature creation device (QSCD), and based on a qualified certificate issued by a qualified trust service provider. It has the legal effect of a handwritten signature in the member states. | The library signs with the key that is in the QSCD (a token or an HSM, through the Windows driver or PKCS#11, or a remote qualified signing service, section 13). It does not make a signature qualified: the certificate and the device do. |
| Qualified electronic seal | The same for a legal person (a certificate of an organization). | The same formats; the certificate is a seal certificate. |
| Qualified time-stamp | A time-stamp issued by a qualified trust service provider. | TimestampSettings with the server of a qualified provider; TimestampInfo.IsQualifiedTimestamp reads the statement of the token. |
A signature is advanced or qualified because of the certificate (who issued it and with which identification), the device (where the key is) and the validation (that the certificate was qualified when the signature was made, according to the trusted lists). The library creates the signature in the right format and gives you the data to validate it; the legal level is a property of the whole.
14.2 Which format for what
| Document | Format | Class |
|---|---|---|
| PDF document | PAdES (B-B, B-LT, B-LTA); the classic PKCS#7 PDF signature (Default) is not a PAdES format | PdfSignature |
| A file of any type | CAdES, attached (.p7m) or detached (.p7s); or XAdES detached | CadesSignature, XadesSignature |
| An XML document (invoice, e-government message) | XAdES enveloped (B-B, B-T, B-LT, B-LTA) | XadesSignature |
| Several files, signed together | ASiC-E container with XAdES | AsicSignature |
| Office document | Package signature with XAdES (the format of Microsoft Office) | OfficeSignature |
A national or sectorial regulation can require an explicit signature policy or a given level: set the policy with SetSignaturePolicyInformation (section 6.13) and use the level that it asks, usually B-LT or B-LTA with a time-stamp from a qualified provider.
14.3 Creating a qualified signature
- The signatory has a qualified certificate on a QSCD: a token or a smart card from a qualified trust service provider (or a remote QSCD service). The qualified certificates have the qcStatements extension with QcCompliance and QcSSCD.
- The application gets the certificate: from the Windows store (the driver of the card publishes it, section 5.2) or from the PKCS#11 module of the card (section 13.3). The PIN is entered by the signatory, or it is set from code only when the device and the policy of the provider allow it.
- The signature is created with PAdES, CAdES or XAdES, SHA-256 or stronger, with a time-stamp. For a long term validity use the B-LT or B-LTA level.
- The signature is validated with a validator that uses the EU trusted lists (section 14.5).
// A PAdES-B-LT signature with the certificate of a qualified token (the PIN window of the driver appears when the PIN is not set).
X509Certificate2 qualifiedCertificate = DigitalCertificate.LoadCertificate(true, DigitalCertificateSearchCriteria.Thumbprint, "FAC4D3EF766A59BB068DD90877267EBC56B4232A");
Console.WriteLine("The certificate declares itself qualified: " + DigitalCertificate.IsQualifiedCertificate(qualifiedCertificate));
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("contract.pdf");
pdfSignature.DigitalSignatureCertificate = qualifiedCertificate;
pdfSignature.SignatureStandard = PdfSignatureStandard.PadesLT;
pdfSignature.HashAlgorithm = SignLib.HashAlgorithm.SHA256;
pdfSignature.TimeStamping.ServerUrl = new Uri("https://tsa.example.com/qualified"); // the server of a qualified time-stamping provider
File.WriteAllBytes("contract[signed].pdf", pdfSignature.ApplyDigitalSignature());
DigitalCertificate.IsQualifiedCertificate is true when the certificate has the qcStatements extension: the certificate declares itself as qualified. That a certificate is really qualified depends on its issuer being a qualified trust service on the trusted list of a member state, at the time of the signature. A qualified time-stamp has, by the same logic, TimestampInfo.IsQualifiedTimestamp as a declaration, and the trusted lists as the proof.
14.4 Test certificates
For the development of an application that handles qualified certificates, X509CertificateGenerator can create a test certificate with the qcStatements, the certificate policies and the subject identifiers of ETSI EN 319 412 (section 5.5). The signatures made with it have the correct structure, and they are not qualified: a validator reports that the certificate is not on a trusted list.
14.5 Validation with the EU DSS validator
The European Commission publishes the DSS (Digital Signature Service) library and a web validator that checks the signatures against the EU trusted lists and reports the level of the signature (AdES, AdES-QC, QESig, ...), the indications (TOTAL_PASSED, INDETERMINATE, TOTAL_FAILED) and the details of every check (certificate chain, revocation, time-stamps, format). To test a signature that the library created:
- Open the DSS demo validator: https://ec.europa.eu/digital-building-blocks/DSS/webapp-demo/validation.
- Upload the signed document: the PDF, the .p7m, the XML, the .asice. For a detached signature (.p7s, detached XAdES) upload also the original file.
- Read the simple report (the result of every signature) and the detailed report (every check, and why a check failed).
The results depend on the certificate: a signature with a qualified certificate on a QSCD, from a provider on the trusted list, is reported as a qualified signature (QESig); a signature with a certificate that is not on a trusted list, as the self-signed test certificates, has the indication INDETERMINATE (the signature is intact, the chain is not trusted); a document that was changed after it was signed has TOTAL_FAILED. The signatures of the long term levels (B-LT, B-LTA) show that the validation data and the time-stamps are present and valid.
- Do not send confidential documents to a public validator: use a copy without confidential data, or the DSS library on your own server.
- The DSS library (open source, Java) can be run on your own computer or server, with the same checks. A .NET application can call its REST service.
15. Recipes
Complete solutions for the usual deployments: services without a user, batches, parallel signing, web services, and the handling of the network errors.
15.1 Signing without user intervention
A service, a scheduled task or a web application has no user who can select a certificate or type a PIN. Rules:
- No windows. Do not use the overloads of
LoadCertificatethat show the selection window. Load the certificate from a PFX file or bytes, from the store by criterion (thumbprint, serial number, name), or take it from a PKCS#11 module by its thumbprint. - The store of the service account. The certificates of the current user are those of the account that runs the process; a service account has its own (usually empty) store. Install the certificate for that account, or in the Local Computer store and load it with
fromLocalMachine = true. The account needs the permission to use the private key (the key permissions incertlm.msc). - The PIN of a token is given with
DigitalCertificate.SmartCardPin(or in the overload ofLoadCertificate) when the driver accepts it, otherwise use PKCS#11 (section 13.3). A token in a service must be dedicated to it, and its middleware must work without a user interface. - No dialogs from the signature classes. The library shows none, except the PIN window of the smart card driver when the PIN was not given.
// A service: the certificate by its thumbprint from the Local Computer store, the PIN from a protected source.
X509Certificate2 certificate = DigitalCertificate.LoadCertificate(true, DigitalCertificateSearchCriteria.Thumbprint, "FAC4D3EF766A59BB068DD90877267EBC56B4232A", true);
if (certificate == null)
throw new InvalidOperationException("The signing certificate was not found in the Local Computer store.");
DigitalCertificate.SmartCardPin = Environment.GetEnvironmentVariable("TOKEN_PIN"); // only when the certificate is on a token
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = certificate;
byte[] signedPdf = pdfSignature.ApplyDigitalSignature();
15.2 Signing a folder
One signature object signs many documents: the certificate and the options are set once. A document that cannot be signed (a damaged file, a password-protected file without the password) must not stop the batch: catch the exception for each file and report it.
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.DigitalSignatureCertificate = signingCertificate;
pdfSignature.SigningReason = "I approve this document";
string[] files = Directory.GetFiles("source_folder", "*.pdf");
Directory.CreateDirectory("destination_folder");
int signed = 0;
for (int index = 0; index < files.Length; index++)
{
try
{
pdfSignature.LoadPdfDocument(files[index]);
File.WriteAllBytes(Path.Combine("destination_folder", Path.GetFileName(files[index])), pdfSignature.ApplyDigitalSignature());
signed++;
}
catch (Exception ex)
{
Console.WriteLine(Path.GetFileName(files[index]) + " was NOT signed: " + ex.Message);
}
Console.WriteLine("Progress: " + (index + 1) + " of " + files.Length);
}
Console.WriteLine("Signed: " + signed + " of " + files.Length);
The same loop signs any file as .p7m with a CadesSignature object: File.WriteAllBytes(name + ".p7m", cadesSignature.ApplyDigitalSignature(file)).
15.3 Signing in parallel
The signing of a document with a software key uses the processor, and the time-stamp and the validation data wait for the network: many documents are signed faster in parallel. The rules of section 4.9 apply:
- One signature object for every thread. The overload of
Parallel.ForEachwithlocalInitcreates onePdfSignatureper worker task and reuses it for all the files of the task. - The certificate (a PFX) can be shared. A token or an HSM session cannot be shared: with a token use one thread, or one provider and session per thread.
- External providers and the PIN are thread-local: set
DigitalCertificate.UseExternalSignatureProviderandSmartCardPininside the body, before every file. - Limit the threads (
MaxDegreeOfParallelism): the number of processors for the software keys; the number that the HSM, the TSA and the CRL servers accept for the others. - Count the progress with
Interlocked, and collect the errors in a thread-safe collection.
X509Certificate2 certificate = DigitalCertificate.LoadCertificate("cert.pfx", "123456"); // shared by the threads
string[] files = Directory.GetFiles("source_folder", "*.pdf");
Directory.CreateDirectory("destination_folder");
ConcurrentQueue<string> errors = new ConcurrentQueue<string>();
int signed = 0;
int processed = 0;
ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = Math.Min(4, Environment.ProcessorCount) };
Parallel.ForEach(
files,
options,
// localInit: one PdfSignature object for every worker task.
() =>
{
PdfSignature threadSignature = new PdfSignature(LibrarySerialNumber);
threadSignature.DigitalSignatureCertificate = certificate;
return threadSignature;
},
(file, loopState, index, threadSignature) =>
{
try
{
// With an external provider or a PIN, set them here, on the thread that signs, before every file:
// DigitalCertificate.UseExternalSignatureProvider = provider;
threadSignature.LoadPdfDocument(file);
File.WriteAllBytes(Path.Combine("destination_folder", Path.GetFileName(file)), threadSignature.ApplyDigitalSignature());
Interlocked.Increment(ref signed);
}
catch (Exception ex)
{
errors.Enqueue(Path.GetFileName(file) + ": " + ex.Message);
}
Console.WriteLine("Processed " + Interlocked.Increment(ref processed) + " of " + files.Length);
return threadSignature;
},
threadSignature => { });
foreach (string error in errors)
Console.WriteLine("NOT signed: " + error);
Stopping the loop: pass a CancellationToken in ParallelOptions (for example one that the user cancels with Ctrl+C); the files in progress are finished and the others are skipped. The sample Batch Signing with Parallelism shows the cancellation, the comparison with the sequential loop and the damaged file.
The signing of PDF documents is not slowed in the demo version, but the CAdES, XML, XAdES, Office and ASiC-E operations wait 10 seconds before each signature or verification (section 2.4). A parallel batch of these formats is still faster than a sequential one, but the times do not show the speed of the licensed library.
15.4 Network errors: retry and time limits
The time-stamp and the validation data depend on servers that you do not control. A server that does not answer throws WebException (a time-stamp) or yields a signature without validation data (a CRL or an OCSP response that could not be downloaded). A batch should retry the transient failures with a pause, and not retry the errors of the document or of the key:
public static class Retry
{
// Runs the signing and retries it when the time-stamping server fails (a transient error), with a growing pause.
public static byte[] SignWithRetry(Func<byte[]> sign, int attempts = 3)
{
for (int attempt = 1; ; attempt++)
{
try
{
return sign();
}
catch (WebException) when (attempt < attempts)
{
Thread.Sleep(TimeSpan.FromSeconds(2 * attempt));
}
}
}
}
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber);
pdfSignature.LoadPdfDocument("source.pdf");
pdfSignature.DigitalSignatureCertificate = signingCertificate;
pdfSignature.SignatureStandard = PdfSignatureStandard.PadesLT;
pdfSignature.TimeStamping.ServerUrl = new Uri("https://ca.signfiles.com/TSAServer.aspx");
pdfSignature.TimeStamping.ServerTimeout = 15000; // milliseconds
byte[] signedPdf = Retry.SignWithRetry(() => pdfSignature.ApplyDigitalSignature());
The signing time of a document that is signed again in a retry is the time of the last attempt. CryptographicException (a key that cannot be used, a damaged document) and ArgumentException are not transient: do not retry them.
15.5 A signing web service
A web application receives documents, signs them and returns them, without temporary files: byte[] in, byte[] out. The rules: a signature object per request, the certificate loaded once and shared, the serial number and the certificate password from the configuration, and the authentication and the authorization of the callers: a signing endpoint that anyone can call signs for anyone. The sample PDF Signing Web Service ASP.NET Core (.NET 8) is a minimal API with these endpoints:
| Endpoint | What it does |
|---|---|
POST /api/sign-pdf | Signs the PDF in the body with the certificate of the server and returns the signed PDF. |
POST /api/verify-pdf | Returns the signatures of the PDF as JSON. |
POST /api/prepare, POST /api/finalize | The two-phase signature for a client that owns the private key: the server prepares the signature and keeps it; the client signs the data locally; the server completes the document. |
// Excerpt of the sample "PDF Signing Web Service ASP.NET Core" (the whole project is in the sample set for .NET 8).
X509Certificate2 serverCertificate = DigitalCertificate.LoadCertificate(Path.Combine(AppContext.BaseDirectory, "cert.pfx"), CertificatePassword); // loaded once
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
WebApplication app = builder.Build();
app.MapPost("/api/sign-pdf", async (HttpRequest request) =>
{
try
{
PdfSignature pdfSignature = new PdfSignature(LibrarySerialNumber); // an object per request
pdfSignature.LoadPdfDocument(await ReadBodyAsync(request));
pdfSignature.DigitalSignatureCertificate = serverCertificate;
pdfSignature.SignatureStandard = PdfSignatureStandard.Pades;
return Results.File(pdfSignature.ApplyDigitalSignature(), "application/pdf", "signed.pdf");
}
catch (Exception ex)
{
return Results.BadRequest("The document cannot be signed: " + ex.Message);
}
});
app.Run();
The matching client (the sample PDF Signing Web Service Client, .NET 8 and .NET Framework 4.6.2) signs the data of the two-phase signature with its own key:
POST /api/preparewith the PDF and the public certificate; the response has a session identifier and the data to sign;- the client signs the data with its private key (a PFX file, a token) and sends the signature value;
POST /api/finalizewith the identifier and the signature value; the response is the signed PDF.
In the sample the prepared signature is kept in the memory of the server (a session of ten minutes, used one time). A production service stores it in a database or a distributed cache (PendingExternalSignature is serializable as JSON), authenticates the callers, uses HTTPS and limits the size of the requests. Kestrel does not allow synchronous reads of the body: read it with CopyToAsync.
15.6 Linux and containers
- Load the certificate from a PFX file (
DigitalCertificate.LoadCertificate(file, password)) or use a PKCS#11 module (section 13.3). The Windows store overloads,SmartCardPinand the selection window do not exist there. - The 14 standard PDF fonts (
FontName) need no files. A TrueType font set inFontFilemust exist in the container, at the path that you give. - The visible signature lines of Office documents need Windows; the invisible Office signatures, PDF, CAdES, XML, XAdES and ASiC-E signatures do not.
- Give the container the access to the time-stamping server and to the CRL and OCSP addresses of the certificates.
15.7 Check the certificate before signing
Many failures in production are a certificate that expired yesterday. A cheap check at the start of the application and before every batch avoids signing with a certificate that every validator will reject:
public static class CertificateGuard
{
// Throws when the certificate cannot be used to sign today.
public static void EnsureCanSign(X509Certificate2 certificate, TimeSpan warnBefore)
{
if (!certificate.HasPrivateKey)
throw new InvalidOperationException("The certificate has no private key.");
if (DigitalCertificate.VerifyDigitalCertificate(certificate, VerificationType.LocalTime) != CertificateStatus.Valid)
throw new InvalidOperationException("The certificate is expired or not yet valid: " + certificate.NotBefore + " - " + certificate.NotAfter);
if (certificate.NotAfter - DateTime.Now < warnBefore)
Console.WriteLine("WARNING: the certificate expires on " + certificate.NotAfter.ToShortDateString());
// Optional: the revocation status (an OCSP or CRL request).
if (DigitalCertificate.VerifyDigitalCertificate(certificate, VerificationType.OCSP) == CertificateStatus.Revoked)
throw new InvalidOperationException("The certificate was revoked.");
}
}
16. Sample projects
The download of the library has two sets of sample projects with the same structure: .NET 8 (SDK-style projects, net8.0) and .NET Framework 4.6.2. Every project is a small program with a comment at the beginning that says what it shows, with the link of this manual. Every project has the input files that it needs (cert.pfx, source.pdf, test.txt...) in its output folder, and a solution file; the library is referenced from the folder SignLib of the set.
- To run a sample, replace the constant
LibrarySerialNumber(YourSerialNumber) with your serial number, build and run. Without it the sample runs in the demo version (section 2.4). - The samples that need a token, a vault or a remote service have constants (the module of the PKCS#11 driver, the PIN, the address of the vault) that you must set for your environment.
- The samples that use the network (time-stamps, revocation data, the remote services) need an internet connection.
16.1 PDF
| Sample | What it shows | .NET 8 | .NET Framework |
|---|---|---|---|
| PDF Digital Signature | The first sample: a certification signature, a second PAdES signature with an image, a signature on several pages, the list of the signatures. → section 6.4 | yes | yes |
| PDF Digital Signature with PFX Certificate | Signing with a certificate from a PFX file. → section 5.2 | yes | — |
| PDF Digital Signature Multiple Pages and Signers | The pages of the signature, three signers, fonts, right to left text, an invisible signature. → section 6.4 | yes | yes |
| PDF Digital Signature - Adobe Signature Field | Signing an existing signature field of a form. → section 6.7 | yes | yes |
| PDF Digital Signature Long-Term Validation PAdES-LTV | PAdES-LT: the validation data in the document. → section 6.9 | yes | yes |
| PDF Digital Signature Long-Term Archival PAdES-LTA | PAdES-LTA and the renewal of the document time-stamp. → section 12.4 | yes | yes |
| PDF Timestamp Signature | A document time-stamp. → section 6.8 | yes | yes |
| PDF Digital Signature with Encryption | Password and certificate encryption, signing and encrypting, opening encrypted documents. → section 6.10 | yes | yes |
| PDF Signature Verification | A standalone verifier: integrity, covered bytes, certificate, chain, revocation, the kind of signature. → section 6.11 | yes | yes |
16.2 CAdES / PKCS#7
| Sample | What it shows | .NET 8 | .NET Framework |
|---|---|---|---|
| P7M P7S CAdES Digital Signature | Signing any file as .p7m or .p7s, verification. → section 7.1 | yes | yes |
| P7M P7S CAdES Long-Term and Co-Signature | The CAdES levels, a time-stamped signature, co-signatures. → section 7.2 | yes | yes |
16.3 XML
| Sample | What it shows | .NET 8 | .NET Framework |
|---|---|---|---|
| XML Digital Signature - XMLDSig | Enveloped XMLDSig, hash and canonicalization options, a second signature, verification. → section 8.1 | yes | — |
| XML Digital Signature SHA256 - XMLDSig | The XMLDSig sample of the .NET Framework set (SHA-256). → section 8.1 | — | yes |
| XML Digital Signature SHA256 - XMLDSig Streams | Signing and verifying XML documents in memory. → section 8.1 | — | yes |
| XML Digital Signature - XAdES | XAdES B-B, B-T, detached, signature policy, LTA and the renewal of the archive time-stamp. → section 8.2 | yes | — |
| XML Digital Signature SHA256 - XAdES | The XAdES sample of the .NET Framework set. → section 8.2 | — | yes |
16.4 Office and ASiC-E
| Sample | What it shows | .NET 8 | .NET Framework |
|---|---|---|---|
| Office Digital Signature (DOCX, XLSX, PPTX) | All the features of OfficeSignature: levels, signature lines, several signers, in memory, verification. → section 9 | yes | yes |
| ASiC-E Container Digital Signature | All the features of AsicSignature: creation, options, co-signatures, renewal, reading, tamper detection. → section 10 | yes | yes |
16.5 Time-stamps
| Sample | What it shows | .NET 8 | .NET Framework |
|---|---|---|---|
| TSR Timestamp a File | Time-stamping a file (.tsr, .tsd) and verifying it. → section 11.2 | yes | yes |
| Timestamp Renewal PDF ASiC XAdES | The renewal of the archive time-stamps of PDF, ASiC-E and XAdES, with a renewal rule. → section 12.4 | yes | yes |
16.6 Certificates
| Sample | What it shows | .NET 8 | .NET Framework |
|---|---|---|---|
| Create PFX Digital Certificates | Root, issued, self-signed and ECDSA certificates. → section 5.5 | yes | yes |
| Certificate Validation | Validity period, CRL, OCSP, the revocation date, key usages. → section 5.4 | yes | yes |
| Custom Certificate Selection | A custom selection of the certificate from the Windows store. → section 5.2 | — | yes |
| Certificate Selector | A selection window for the certificates (a component used by the Windows Forms samples). → section 5.2 | — | yes |
16.7 External keys
| Sample | What it shows | .NET 8 | .NET Framework |
|---|---|---|---|
| PDF Digital Signature with PKCS11 Smart Card | A token or a smart card through its PKCS#11 module; the certificate by thumbprint. → section 13.3 | yes | yes |
| P7M P7S CAdES Digital Signature with PKCS11 Smart Card | The same for a .p7m file. → section 13.3 | yes | yes |
| PDF Digital Signature with PKCS11 Driver for HSM | An HSM through its PKCS#11 module. → section 13.3 | yes | yes |
| PDF Digital Signature - External Signature | A custom signature engine as IExternalSignature. → section 13.1 | yes | — |
| PDF Remote External Digital Signature | A remote signing service (the demo service of the vendor). → section 13.6 | yes | yes |
| P7M P7S CAdES Remote External Digital Signature | The same for a .p7m file. → section 13.6 | yes | yes |
| PDF Remote External Digital Signature (Sample) | The two-phase signature (Prepare / Finalize) with a simulated signer. → section 13.5 | yes | — |
| PDF Digital Signature with Azure Key Vault Certificate | An exportable certificate stored in Azure Key Vault. → section 13.6 | yes | — |
| PDF Digital Signature with Azure Key Vault Nonexportable HSM Certificate | A key that never leaves Azure Key Vault or Managed HSM. → section 13.6 | yes | — |
16.8 Batches and services
| Sample | What it shows | .NET 8 | .NET Framework |
|---|---|---|---|
| Batch PDF Signature Without User Intervention | A folder signed with a certificate from the Windows store, without windows. → section 15.1 | yes | yes |
| Batch P7M P7S CAdES and PDF Signatures | A folder signed as PDF and as .p7m; progress; a parallel loop. → section 15.2 | yes | yes |
| Batch Signing with Parallelism | Sequential and parallel signing, progress, cancellation, errors. → section 15.3 | yes | yes |
| PDF Signing Web Service ASP.NET Core | A signing web service (minimal API), in memory, with two-phase signing. → section 15.5 | yes | — |
| PDF Signing Web Service Client | The client of the service: server-side signing, verification, two-phase signing with the key of the client. → section 15.5 | yes | yes |
16.9 Applications with a user interface and VB.NET
| Sample | What it shows | .NET 8 | .NET Framework |
|---|---|---|---|
| P7M P7S CAdES Signer Windows Forms | A Windows Forms application that signs files as .p7m / .p7s. | yes | yes |
| PDF Signer Windows Forms | A Windows Forms application that signs PDF documents. | — | yes |
| DOCX Signer Windows Forms | A Windows Forms application that signs Office documents. | — | yes |
| VB.NET Digitally Sign a PDF File | The PDF signature in VB.NET. | — | yes |
| VB.NET CAdES and PKCS#7 Digital Signature | The CAdES signature in VB.NET. | — | yes |
| VB.NET Office Digital Signature (DOCX, XLSX, PPTX) | The Office signature in VB.NET. | — | yes |
The projects that exist in one set only were written for the platform of that set: the Azure samples, the web service and the two-phase sample use .NET 8 packages, and the Windows Forms applications and the VB.NET projects are in the .NET Framework set. The samples that exist in both sets do the same thing.
17. Problems and solutions
The messages are the ones that the library writes in the exception; part of a message is enough to find the line. When the cause is not in the table, read the inner exception (ex.InnerException) and the full text of ex.ToString().
17.1 Project and installation
| Symptom | Cause | Solution |
|---|---|---|
FileNotFoundException: Could not load file or assembly 'iTextSharp-4.1.6' when a PdfSignature is created | iTextSharp-4.1.6.dll is not in the folder of the application. | Keep it in the same folder as SignLib.dll when you reference the library (the build copies it), or add it to the project. In PowerShell load it before SignLib.dll (section 3.3). |
FileNotFoundException or TypeLoadException for System.Security.Cryptography.Pkcs, System.IO.Packaging, System.Drawing.Common... | A .NET project that references SignLib.dll as a file does not get the packages that the library uses. | Add the NuGet packages of section 2.2. |
The signed PDF has the text SignLib.dll DEMO VERSION on the first page; the console shows a red message; every operation waits 10 seconds | The library runs as the demo version: the serial number is missing or it is not valid. | Pass the serial number of your license to the constructors (section 2.4). Check that no space or line break is in the string (the library trims the spaces at the ends). |
| The PKCS#11 module cannot be loaded (a bad image format error) | A 64-bit process loads a 32-bit module or the reverse, or the path of the module is wrong. | Use the module that matches the process (section 13.3). |
| The assembly is not found at run time, or a method is missing | The .NET Framework build of SignLib.dll is used in a .NET project, or the reverse; or an older SignLib.dll stays in the output folder. | Reference the build for the target framework of the project and delete the old copies of the DLL. |
17.2 Signing
| Symptom | Cause | Solution |
|---|---|---|
NullReferenceException: Digital certificate is not set. | DigitalSignatureCertificate was not set (or LoadCertificate returned null because the user cancelled, or no certificate matched). | Check the result of LoadCertificate before you use it. |
NullReferenceException: Document is not loaded. | LoadPdfDocument was not called before ApplyDigitalSignature (or before AddSignatureField). | Load the document first. |
CryptographicException: The private key for this certificate was not found. / RSA private key not found on certificate. | The certificate has no private key: it was loaded from a .cer file or the key is not accessible to the process. | Load the PFX file, or the certificate from the store of the account that runs the process. For a key outside the process use an external provider (section 13). |
CryptographicException when a PFX is loaded (The specified network password is not correct, Failed to load certificate with provided data/password.) | A wrong password or a damaged PFX file; or a PFX with a key algorithm that the platform cannot import. | Check the password and the file; open it with certmgr to see if it is valid. |
| The PIN window of the token appears on every signature, or in a service the call waits for the PIN | The PIN was not given to the library, or the driver does not accept it from the application. | Set DigitalCertificate.SmartCardPin before every signature on the thread that signs; for the tokens that do not take it use PKCS#11 (section 5.2). |
CryptographicException: Bypassing PIN Exception ... | The PIN cannot be set for the key (an unsupported provider, or a key that is not a smart card key). | Remove SmartCardPin and let the driver ask, or use PKCS#11. |
CryptographicException: The signature ... does not fit in the space reserved for it (PDF) | The signature, with the validation data or the certificates, is larger than the space reserved in the document. | Use a smaller revocation level (PadesLtvLevel.IncludeOcspOnly), or a certificate with a smaller chain; avoid the CRLs that are very large. |
ArgumentOutOfRangeException: Invalid signature page number. | SignaturePage or an item of SignaturePages is not a page of the document. | Use a page from 1 to the number of pages, or int.MaxValue for the last page. |
CryptographicException: A document that is already signed or certified cannot be encrypted. | PdfSignature.Encryption is set for a document that already has signatures. | Encrypt before the first signature, or sign and encrypt in one operation (section 6.10). |
InvalidOperationException: Only a single document certification is allowed ... | A second certification signature (CertifySignature other than NotCertified). | A document has one certification signature, the first one. The other signers use NotCertified. |
| A password-protected PDF cannot be loaded | The password was set after LoadPdfDocument, or it is wrong. | Set DocumentProperties.Password before the load. |
The visible signature shows ? instead of the characters of a language | The standard font (FontName) has no glyphs for that script. | Set FontFile to a TrueType font that has them (section 6.5). |
NotSupportedException for SHA-1 | XML, XAdES, Office and ASiC-E signatures are not created with SHA-1. | Use SHA256 (the default) or stronger. |
ArgumentException: TimeStamping.ServerUrl must be set for XAdES-T, XAdES-LT and XAdES-LTA signatures. | A level with a time-stamp without a time-stamping server (the same for Office and ASiC-E). | Set TimeStamping.ServerUrl, or use XadesB. |
NotSupportedException: XAdES-LTA is not supported for Office documents ... | Office documents have the levels B, T and LT. | Use XadesLT, or an ASiC-E container for the LTA level. |
NotSupportedException: Visible signatures (signature lines) are supported only for Word documents (docx). / PlatformNotSupportedException: ... require Windows | A signature line on a workbook, on a presentation, or on a system that is not Windows. | Sign them without SignatureLine (an invisible signature). |
InvalidOperationException: The document is already signed: adding a signature line would invalidate its signatures. | The signature lines were added after the first signature. | Add the lines of all the signers before the first signature (section 9.2). |
CryptographicException: A new signature cannot be added because it would invalidate an existing XML signature. | The document has a signature made by another program with the enveloped-signature transform. | Sign a copy of the document in another file, or keep one signature per document. |
ArgumentException: For a detached signature the output (signature) file must be different from the signed file. | The output path of a detached XAdES signature is the path of the signed file. | Use another path for the signature file. |
CryptographicException: The external signature provider returned an empty signature. / The signature returned by the external signature provider is not valid for the ... | The provider signed with another key, with another hash algorithm, or returned a wrong encoding. | Hash message with the algorithm of the OID that you receive; use the key of the certificate that you set; return PKCS#1 v1.5 (RSA) or r || s / DER (ECDSA) (section 13). |
CryptographicException: The private key is held by the external signature provider. | An operation that needs the private key (for example the use of SignData) with a certificate that has none. | Use the signature classes with UseExternalSignatureProvider. |
17.3 Verification
| Symptom | Cause | Solution |
|---|---|---|
SignatureIsValid is false for a document that was just signed | The document was changed after the signature: a re-save, a conversion, a repair of the PDF, an added byte, another encoding of an XML file, a download that changed the line ends. | Keep the signed bytes as they are. Compare the checksum before and after the transfer; transfer in binary mode. |
SignatureIsValid is true but Adobe Reader shows the signature as validity unknown | The certificate of the signer (or its root) is not trusted by the reader. It is the trust, not the integrity. | Use a certificate issued by a trusted certification authority, or add the certificate to the trusted identities of the reader (section 6.14). |
| The document is intact but the last signature does not cover the whole file | Data was appended after the signature (a revision that is not signed). | Check the /ByteRange as in section 6.11. |
CryptographicException: Invalid or corrupt CAdES/PKCS#7 signed data. | The file is not a CMS signature (a .p7m that was damaged, or a file with another format). | Check the origin of the file; open it with another tool. |
A detached .p7s verifies as invalid or its document is null | The original document was not given. | Use new CadesVerify(signature, originalDocument, serial) (section 7.5). |
CryptographicException: Verification failed: No digital signature was found in the document. | The XML (or Office) document has no signature. | Check GetNumberOfSignatures first. |
CryptographicException: The signature is detached: the signed data is not included in the XML document. | A detached XAdES signature verified without the signed file. | Use VerifyDigitalSignature(signatureFile, originalFile). |
An ASiC-E container is false after a file was added or changed | Every signature covers all the files of the container: it is the expected result. | Create a new container, or add a signature with AddSignature (it covers the new content). |
NotSupportedException: The container has CAdES signatures (*.p7s); only XAdES signatures are supported. | An ASiC-E container with CAdES signatures. | Verify it with another tool. |
17.4 Time-stamps, revocation data, network
| Symptom | Cause | Solution |
|---|---|---|
WebException: Invalid time stamping response. (with a status or a reason) | The time-stamping server is unreachable, it refused the request (authentication, policy, hash algorithm), or it is not an RFC 3161 server. | Open the address in a browser; check UserName, Password, PolicyOid and HashAlgorithm (try SHA-256); check the proxy and the firewall; use Retry (section 15.4). |
| The request waits and fails after 20 seconds | The default time-out of the server (ServerTimeout) or of the downloads (DigitalCertificate.Timeout). | Increase the value, or fix the network access. |
| A request fails on .NET Framework with an error about the secure channel | The server requires TLS 1.2 and the application does not enable it. | Set ServicePointManager.SecurityProtocol at the start of the program (section 2.3). |
| The PAdES-LT or XAdES-LT signature has no revocation data | The certificate has no CRL or OCSP address, the servers did not answer, or the CRLs are larger than MaxCrlSize. | Use a certificate that publishes them; check the connection; set MaxCrlSize higher or IncludeOcspOnly (section 12.3). |
CertificateStatus.NotPresent | The certificate has no CRL address, or no OCSP responder, for the verification type that you asked. | It is normal for self-signed certificates; try the other type. |
CertificateStatus.Unknown | The CRL or the OCSP server could not be reached or its response could not be read. | Retry; do not treat it as Valid. |
ArgumentException from AddArchiveTimestamp | The time-stamping server is not set, or the output is the original file. | Set TimeStamping.ServerUrl; use another output path. |
17.5 Certificates
| Symptom | Cause | Solution |
|---|---|---|
LoadCertificate by criterion returns null | No certificate in that store matches (the store of the current user versus the local computer; a thumbprint with spaces or invisible characters; validOnly filters the expired certificates). | Check the store and the value; paste the thumbprint without spaces; try validOnly = false. |
| A certificate imported in Windows works for a user and not for a service | The service account has another certificate store and no permission for the key. | Install the certificate in the Local Computer store and give the account the permission to use the key; load with fromLocalMachine = true (section 15.1). |
CryptographicException: KeyEncipherment and DataEncipherment cannot be used with an ECDSA key (RFC 5480). | A generated ECDSA certificate with an RSA-only key usage. | Use DigitalSignature and NonRepudiation for ECDSA keys. |
| The certificates created with the demo version expire in 30 days | The demo version limits the validity. | Register the library (section 2.4). |
CryptographicException: The certificate serial number does not appear on the CRL. | GetCertificateRevocationDate was called for a certificate that is not revoked. | Call it only when VerifyDigitalCertificate returned Revoked. |
CryptographicException: The CSR could not be parsed. / Root certificate is not loaded. | The CSR is not a PKCS#10 request in PEM, or LoadRootCertificate was not called before GenerateCertificateFromCSR. | Check the text of the request and load the CA first. |
17.6 If the problem remains
- Reduce it to a small program with the sample document and the PFX certificate of the samples: if it works there, the cause is in the document, in the certificate or in the environment.
- Run the same signature with the demo version and a PFX certificate to separate the problems of the key (token, store, PIN) from the problems of the document.
- Send the exception text (
ex.ToString()), the version of the library, the target framework, the operating system and, when possible, the document that fails, to the support of the library (section 1.5).
18. API reference
This reference lists the public types of the library by namespace. It is generated from the assembly and from its XML documentation (SignLib.xml), so it has the exact signatures. The members that are marked as hidden from IntelliSense in the library are not listed. In the guide chapters, a name written in this font is a link to its entry here; use the search box of the contents to find a member.
Conventions: the indexes of the signatures are 0-based; a default value is the value that a property has until you set it; time values are UTC unless the description says local time; the methods that have a Stream, byte[] and path overloads do the same with every kind of input.
18.1 Namespace SignLib
| Type | Description |
|---|---|
OfficeSignature class | Signs Office Open XML documents (docx, xlsx, pptx and their macro-enabled versions) with package digital signatures compatible with Microsoft Office: XAdES signatures (the levels B, T and LT), invisible or visible (an Office signature line of a Word document), and verifies them. |
HashAlgorithm enum | Hash algorithms used to create digital signatures and time-stamp requests. |
OfficeSignature class
Namespace: SignLib · Assembly: SignLib.dll
public class OfficeSignature
Signs Office Open XML documents (docx, xlsx, pptx and their macro-enabled versions) with package digital signatures compatible with Microsoft Office: XAdES signatures (the levels B, T and LT), invisible or visible (an Office signature line of a Word document), and verifies them. A document can have several signatures: a new signature does not invalidate the existing ones.
Constructors
public OfficeSignature(string librarySerialNumberLicense)Initializes a new instance of the OfficeSignature class.
librarySerialNumberLicense- The serial number provided to register the library.
Properties
public XadesCommitmentType CommitmentType { get; set; }Gets or sets the commitment type declared by the signer (shown by Office as "Commitment type", e.g. ProofOfApproval: "Approved this document"). The default value is XadesCommitmentType.None.
public X509Certificate2 DigitalSignatureCertificate { get; set; }Gets or sets the signing certificate (see the DigitalCertificate class).
public HashAlgorithm HashAlgorithm { get; set; }Gets or sets the hash algorithm of the signature: SHA256 (the default), SHA384 or SHA512. It is used for the signature method, the digests of the signed parts and the digest of the signing certificate. SHA1 is not supported for new signatures (NotSupportedException).
public XadesLtvLevel LtvLevel { get; set; }Gets or sets the revocation data included in the XAdES-LT signatures. The default value is XadesLtvLevel.IncludeOcspOnly.
public int MaxCrlSize { get; set; }Gets or sets the maximum size, in bytes, of a CRL included in the XAdES-LT signatures: larger CRLs are skipped. The default value is 1 MB.
public string SignatureComments { get; set; }Gets or sets the purpose of the signature (shown by Office as "Purpose for signing this document"), or null.
public OfficeSignatureLine SignatureLine { get; set; }Gets or sets the visible signature: an Office signature line of a Word document (docx, docm). The default value is null: the signature is invisible. The visible signatures require Windows (their images are drawn with System.Drawing): on the other platforms they throw PlatformNotSupportedException.
public XadesProductionPlace SignatureProductionPlace { get; set; }Gets or sets the place where the signature is created (xades:SignatureProductionPlace: city, state or province, postal code and country; the street address is not used by Office). The default value is null.
public XadesSignatureStandard SignatureStandard { get; set; }Gets or sets the XAdES level of the signature. The default value is XadesSignatureStandard.XadesB. XadesT and XadesLT require TimeStamping.ServerUrl. As for the XAdES signatures, a XadesB signature is also time-stamped (XAdES-T) when TimeStamping.ServerUrl is set. XadesLTA is not supported for Office documents (NotSupportedException).
public string SignerRole { get; set; }Gets or sets the role or the title of the signer (xades:ClaimedRole), or null.
public TimestampSettings TimeStamping { get; set; }Gets or sets the time-stamping settings (required for the XAdES-T and XAdES-LT signatures).
Methods
public string AddSignatureLine(string inputFile, string outputFile, OfficeSignatureLine signatureLine)Adds an unsigned signature line at the end of a Word document, for a signer who will sign it later (with this library, OfficeSignatureLinePlacement.UseExisting, or in Word). Add the signature lines of all the signers before the first signature: a document that is already signed cannot be changed (InvalidOperationException). It requires Windows (the image of the signature line is drawn with System.Drawing).
inputFile- The path of the Word document.
outputFile- The path of the document with the new signature line (it can be the input file).
signatureLine- The suggested signer, title, e-mail, signing instructions, size and alignment.
Returns. The identifier (SetupId) of the new signature line.
Exceptions.
FileNotFoundException: The input file does not exist.
public void ApplyDigitalSignature(Stream streamToSign)Signs an Office document (docx, xlsx, pptx) in place: the signed document is written to the same stream.
streamToSign- The document to sign: a readable, writable and seekable stream.
public byte[] ApplyDigitalSignature(byte[] inputArray)Signs an Office document (docx, xlsx, pptx).
inputArray- The document to sign.
Returns. The signed document.
public void ApplyDigitalSignature(string inputFile, string outputFile)Signs an Office document (docx, xlsx, pptx). The signatures already present in the document are kept. The output file is deleted when the signature fails (unless it is the input file).
inputFile- The path of the document to sign.
outputFile- The path of the signed document (it can be the input file).
Exceptions.
FileNotFoundException: The input file does not exist.ArgumentException: The time-stamping server is required.NotSupportedException: The hash algorithm is SHA1, the level is XAdES-LTA, or a visible signature is requested for a document that is not a Word document.PlatformNotSupportedException: A visible signature is requested on a platform other than Windows.
public X509Certificate2 GetDigitalSignatureCertificate(string inputFile)Gets the signing certificate of the first signature of an Office document.
inputFile- The path of the document.
Returns. The signing certificate.
public X509Certificate2 GetDigitalSignatureCertificate(Stream inputFile)Gets the signing certificate of the first signature of an Office document.
inputFile- The document.
Returns. The signing certificate.
public X509Certificate2 GetDigitalSignatureCertificate(string inputFile, int signatureIndex)Gets the signing certificate of a signature of an Office document.
inputFile- The path of the document.
signatureIndex- The 0-based index of the signature.
Returns. The signing certificate.
public X509Certificate2 GetDigitalSignatureCertificate(Stream inputFile, int signatureIndex)Gets the signing certificate of a signature of an Office document.
inputFile- The document.
signatureIndex- The 0-based index of the signature.
Returns. The signing certificate.
public int GetNumberOfSignatures(string inputFile)Gets the number of signatures of an Office document.
inputFile- The path of the document.
Returns. The number of signatures.
public int GetNumberOfSignatures(Stream inputFile)Gets the number of signatures of an Office document.
inputFile- The document.
Returns. The number of signatures.
public string GetSignatureAlgorithm(string inputFile)Gets the signature algorithm of the first signature of an Office document (e.g. RSA-SHA256).
inputFile- The path of the document.
Returns. The signature algorithm.
public string GetSignatureAlgorithm(Stream inputFile)Gets the signature algorithm of the first signature of an Office document (e.g. RSA-SHA256).
inputFile- The document.
Returns. The signature algorithm.
public string GetSignatureAlgorithm(string inputFile, int signatureIndex)Gets the signature algorithm of a signature of an Office document (e.g. RSA-SHA256, ECDSA-SHA384).
inputFile- The path of the document.
signatureIndex- The 0-based index of the signature.
Returns. The signature algorithm.
public string GetSignatureAlgorithm(Stream inputFile, int signatureIndex)Gets the signature algorithm of a signature of an Office document (e.g. RSA-SHA256, ECDSA-SHA384).
inputFile- The document.
signatureIndex- The 0-based index of the signature.
Returns. The signature algorithm.
public List<OfficeSignatureLineInfo> GetSignatureLines(string inputFile)Gets the signature lines of a Word document (an empty list for the other Office documents), and whether each one is signed.
inputFile- The path of the document.
Returns. The signature lines, in document order.
public List<OfficeSignatureLineInfo> GetSignatureLines(Stream inputFile)Gets the signature lines of a Word document (an empty list for the other Office documents), and whether each one is signed.
inputFile- The document.
Returns. The signature lines, in document order.
public List<OfficeSignatureInfo> GetSignatures(string inputFile)Gets the signatures of an Office document and verifies them: the signer, the signing time, the time-stamp, the purpose, the signature line and the result of the verification of each signature.
inputFile- The path of the document.
Returns. The signatures, in the order of their indexes.
public List<OfficeSignatureInfo> GetSignatures(Stream inputFile)Gets the signatures of an Office document and verifies them: the signer, the signing time, the time-stamp, the purpose, the signature line and the result of the verification of each signature.
inputFile- The document.
Returns. The signatures, in the order of their indexes.
public void SetSignaturePolicyInformation(string policyIdentifier, byte[] policyHash, string policyDigestAlgorithm, string policyUrl)Sets the explicit signature policy of the signatures (xades:SignaturePolicyIdentifier), when a regulation or a relying party requires one. By default the policy is implied, as for the signatures created by Office.
policyIdentifier- The identifier of the policy: an OID (e.g. 2.16.724.1.3.1.1.2.1.9, with or without the urn:oid: prefix) or a URI. Null removes the policy.
policyHash- The digest of the policy document.
policyDigestAlgorithm- The digest algorithm of policyHash: an OID (e.g. 2.16.840.1.101.3.4.2.1) or a name (SHA1, SHA256, SHA384, SHA512).
policyUrl- The URL of the policy document (xades:SPURI), or null.
public bool VerifyDigitalSignature(string inputFile)Verifies all the signatures of an Office document. The trust of the signing certificates is not verified (see DigitalCertificate.VerifyDigitalCertificate).
inputFile- The path of the document.
Returns. True if every signature is valid.
Exceptions.
CryptographicException: The document has no signature.
public bool VerifyDigitalSignature(Stream inputFile)Verifies all the signatures of an Office document. The trust of the signing certificates is not verified.
inputFile- The document.
Returns. True if every signature is valid.
Exceptions.
CryptographicException: The document has no signature.
public bool VerifyDigitalSignature(string inputFile, int signatureIndex)Verifies a signature of an Office document. The trust of the signing certificate is not verified.
inputFile- The path of the document.
signatureIndex- The 0-based index of the signature.
Returns. True if the signature is valid.
public bool VerifyDigitalSignature(Stream inputFile, int signatureIndex)Verifies a signature of an Office document. The trust of the signing certificate is not verified.
inputFile- The document.
signatureIndex- The 0-based index of the signature.
Returns. True if the signature is valid.
public bool VerifyDigitalSignature(string inputFile, X509Certificate2 certificate)Verifies that an Office document has a valid signature created with a certificate.
inputFile- The path of the document.
certificate- The certificate of the expected signer.
Returns. True if a signature of the document is valid for the certificate.
public bool VerifyDigitalSignature(Stream inputFile, X509Certificate2 certificate)Verifies that an Office document has a valid signature created with a certificate.
inputFile- The document.
certificate- The certificate of the expected signer.
Returns. True if a signature of the document is valid for the certificate.
HashAlgorithm enum
Namespace: SignLib · Assembly: SignLib.dll
public enum HashAlgorithm
Hash algorithms used to create digital signatures and time-stamp requests.
| Member | Value | Description |
|---|---|---|
SHA1 | 0 | SHA-1 (160 bits). Not recommended for new signatures: SHA-1 is no longer considered collision resistant. |
SHA256 | 1 | SHA-256 (256 bits). The recommended default. |
SHA384 | 2 | SHA-384 (384 bits). |
SHA512 | 3 | SHA-512 (512 bits). |
18.2 Namespace SignLib.Pdf
| Type | Description |
|---|---|
CustomImage class | An image added to a PDF document by PdfInsertObject. |
CustomText class | A text added to a PDF document by PdfInsertObject. |
PdfDocumentProperties class | Properties of a loaded PDF document: number of pages, certification level, file size and digital signatures. |
PdfEncrypt class | Encrypts PDF documents, with passwords or with a certificate. |
PdfEncryptionSettings class | Encryption of a PDF document signed with PdfSignature. |
PdfInsertObject class | Adds images, watermarks and texts to a PDF document. |
PdfMerge class | Merges PDF documents. |
PdfSignature class | Digitally signs PDF documents (PKCS#7 and PAdES signatures, with or without time-stamp and long term validation data) and adds document time-stamps. |
PdfSignatureInfo class | Information about a digital signature or a document time-stamp of a PDF document. |
PendingExternalSignature class | A prepared PDF signature, returned by PdfSignature.PrepareExternalSignature: everything needed to complete a deferred (two-phase) external signature later, possibly in another process, hours or days afterwards, with PdfSignature.FinalizeExternalSignature. |
CertifyMethod enum | Certification level of a PDF document: the changes allowed after the certification signature. |
FontName enum | Standard PDF fonts (the 14 fonts that every PDF reader has) for the text of the visible signature. |
ImagePosition enum | Position of an image relative to the content of a PDF page. |
PadesLtvLevel enum | Revocation data embedded in a PDF signature, for its long term validation. |
PdfDocumentRestrictions enum | Actions allowed on an encrypted PDF document. |
PdfEncryptionAlgorithm enum | Encryption algorithm of a PDF document. |
PdfEncryptionMethod enum | Encryption method of a PDF document. |
PdfSignatureStandard enum | Signature format of a PDF signature. |
SignatureImageType enum | How the image of a visible signature is displayed. |
SignaturePosition enum | Position of the visible signature on the page. |
SignatureType enum | Type of a signature of a PDF document. |
TextAlign enum | Alignment of a text relative to its starting point. |
TextDirection enum | Direction of a text. |
CustomImage class
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public class CustomImage
An image added to a PDF document by PdfInsertObject.
Constructors
public CustomImage()Initializes a new instance of the CustomImage class.
Properties
public bool AddImageAsWatermark { get; set; }Gets or sets a value indicating whether the image covers the entire page.
public byte[] Image { get; set; }Gets or sets the image (e.g. the content of a JPG or PNG file).
public ImagePosition ImagePosition { get; set; }Gets or sets the position of the image: over the content or under the content (as background).
public int PageNumber { get; set; }Gets or sets the page of the image, or 0 for all the pages.
public Rectangle RectangePosition { get; set; }Gets or sets the rectangle of the image on the page.
public Point StartingPointPosition { get; set; }Gets or sets the position of the lower left corner of the image on the page.
CustomText class
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public class CustomText
A text added to a PDF document by PdfInsertObject.
Constructors
public CustomText()Initializes a new instance of the CustomText class.
Properties
public TextAlign Align { get; set; }Gets or sets the alignment of the text relative to its starting point.
public string FontFile { get; set; }Gets or sets the path of a TrueType font file, or null for Helvetica Bold.
public int FontSize { get; set; }Gets or sets the font size.
public int PageNumber { get; set; }Gets or sets the page of the text.
public Point StartingPointPosition { get; set; }Gets or sets the starting point of the text on the page.
public string Text { get; set; }Gets or sets the text.
public Color TextColor { get; set; }Gets or sets the color of the text, or null for black.
public TextDirection TextDirection { get; set; }Gets or sets the direction of the text. The default value is TextDirection.Normal.
PdfDocumentProperties class
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public class PdfDocumentProperties
Properties of a loaded PDF document: number of pages, certification level, file size and digital signatures.
Constructors
public PdfDocumentProperties()Initializes a new instance of the PdfDocumentProperties class.
Properties
public CertifyMethod CertificationLevel { get; }Gets the certification level of the loaded PDF document.
public List<PdfSignatureInfo> DigitalSignatures { get; }Gets the digital signatures and the document time-stamps of the PDF document, sorted by signing time.
public long FileSize { get; }Gets the size of the PDF file, in bytes.
public int NumberOfPages { get; }Gets the number of pages of the loaded PDF document.
public string Password { get; set; }Gets or sets the password of the PDF document. A document with an unknown password cannot be signed.
Methods
public Point DocumentPageSize(int pageNumber)Gets the size of a page of the loaded PDF document (the page rotation included).
pageNumber- The page number (1 for the first page).
Returns. The width (X) and the height (Y) of the page.
Exceptions.
ArgumentOutOfRangeException: The document is not loaded or the page does not exist.
PdfEncrypt class
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public class PdfEncrypt
Encrypts PDF documents, with passwords or with a certificate.
Constructors
public PdfEncrypt()Initializes a new instance of the PdfEncrypt class.
Properties
public PdfDocumentRestrictions DocumentRestrictions { get; set; }Gets or sets the actions allowed on the encrypted document (e.g. AllowPrinting | AllowFillingOfFormFields). The default value is PdfDocumentRestrictions.AllowNone.
public PdfEncryptionAlgorithm EncryptionAlgorithm { get; set; }Gets or sets the encryption algorithm. The default value is PdfEncryptionAlgorithm.EnhancedEncryption128BitAES.
public X509Certificate2 EncryptionCertificate { get; set; }Gets or sets the certificate used to encrypt the document (PdfEncryptionMethod.CertificateSecurity).
public PdfEncryptionMethod EncryptionMethod { get; set; }Gets or sets the encryption method. The default value is PdfEncryptionMethod.NoEncryption.
public string LoadedDocumentPassword { get; set; }Gets or sets the password of the loaded PDF document. A document with an unknown password cannot be encrypted.
public string OwnerPassword { get; set; }Gets or sets the owner password: the password that allows all the actions on the document.
public string UserPassword { get; set; }Gets or sets the user password: the password required to open the document (PdfEncryptionMethod.PasswordSecurity).
Methods
public byte[] EncryptPDFFile()Encrypts the loaded PDF document.
Returns. The encrypted PDF document.
Exceptions.
NullReferenceException: The document is not loaded or the encryption certificate is not set.ArgumentException: The encryption method is not set.
public void LoadPdfDocument(byte[] pdfArray)Loads the PDF document to encrypt.
pdfArray- The PDF document.
public void LoadPdfDocument(string PdfFile)Loads the PDF document to encrypt from a file.
PdfFile- The path of the PDF document.
Exceptions.
FileNotFoundException: The file does not exist.
public void LoadPdfDocument(Uri PdfUrl)Loads the PDF document to encrypt from a URL.
PdfUrl- The URL of the PDF document.
PdfEncryptionSettings class
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public class PdfEncryptionSettings
Encryption of a PDF document signed with PdfSignature. A document that is already signed cannot be encrypted.
Constructors
public PdfEncryptionSettings()Initializes a new instance of the PdfEncryptionSettings class, without encryption.
Properties
public PdfDocumentRestrictions DocumentRestrictions { get; set; }Gets or sets the actions allowed on the encrypted document (e.g. AllowPrinting | AllowFillingOfFormFields). The default value is PdfDocumentRestrictions.AllowNone.
public PdfEncryptionAlgorithm EncryptionAlgorithm { get; set; }Gets or sets the encryption algorithm. The default value is PdfEncryptionAlgorithm.EnhancedEncryption128BitAES.
public X509Certificate2 EncryptionCertificate { get; set; }Gets or sets the certificate used to encrypt the document (PdfEncryptionMethod.CertificateSecurity).
public PdfEncryptionMethod EncryptionMethod { get; set; }Gets or sets the encryption method. The default value is PdfEncryptionMethod.NoEncryption.
public string OwnerPassword { get; set; }Gets or sets the owner password: the password that allows all the actions on the document.
public string UserPassword { get; set; }Gets or sets the user password: the password required to open the document (PdfEncryptionMethod.PasswordSecurity).
PdfInsertObject class
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public class PdfInsertObject
Adds images, watermarks and texts to a PDF document.
Constructors
public PdfInsertObject()Initializes a new instance of the PdfInsertObject class.
Properties
public PdfDocumentProperties DocumentProperties { get; set; }Gets or sets the properties of the loaded PDF document (number of pages, digital signatures, password).
Methods
public void AddImage(byte[] image, int pageNumber, ImagePosition imagePostition)Adds an image that covers the entire page (e.g. a watermark) to the PDF document.
image- The image (e.g. the content of a JPG or PNG file).
pageNumber- The page of the image, or 0 for all the pages.
imagePostition- The position of the image: over the content or under the content (as background).
public void AddImage(byte[] image, Rectangle imageLocation, int pageNumber, ImagePosition imagePostition)Adds an image, in a rectangle, to the PDF document.
image- The image (e.g. the content of a JPG or PNG file).
imageLocation- The rectangle of the image on the page.
pageNumber- The page of the image, or 0 for all the pages.
imagePostition- The position of the image: over the content or under the content (as background).
public void AddImage(byte[] image, Point imageLocation, int pageNumber, ImagePosition imagePostition)Adds an image, at its original size, to the PDF document.
image- The image (e.g. the content of a JPG or PNG file).
imageLocation- The position of the lower left corner of the image on the page.
pageNumber- The page of the image, or 0 for all the pages.
imagePostition- The position of the image: over the content or under the content (as background).
public void AddText(CustomText customText)Adds a text to the PDF document.
customText- The text and its properties.
public byte[] InsertObjects()Adds the images and the texts to the PDF document.
Returns. The PDF document with the images and the texts.
Exceptions.
NullReferenceException: The document is not loaded.
public void LoadPdfDocument(byte[] pdfArray)Loads the PDF document.
pdfArray- The PDF document.
public void LoadPdfDocument(string PdfFile)Loads the PDF document from a file.
PdfFile- The path of the PDF document.
Exceptions.
FileNotFoundException: The file does not exist.
public void LoadPdfDocument(Uri PdfUrl)Loads the PDF document from a URL.
PdfUrl- The URL of the PDF document.
PdfMerge class
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public class PdfMerge
Merges PDF documents.
Methods
public static byte[] MergePdfFiles(List<byte[]> sourceFiles)Merges PDF documents into a single one. The metadata (title, author, subject, keywords and creator) of the merged document are taken from the first document.
sourceFiles- The PDF documents, in the order in which their pages are added to the merged document.
Returns. The merged PDF document.
PdfSignature class
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public class PdfSignature
Digitally signs PDF documents (PKCS#7 and PAdES signatures, with or without time-stamp and long term validation data) and adds document time-stamps.
Constructors
public PdfSignature(string librarySerialNumberLicense)Initializes a new instance of the PdfSignature class.
librarySerialNumberLicense- The serial number provided to register the library.
Properties
public CertifyMethod CertifySignature { get; set; }Gets or sets the certification level of the signature. The default value is CertifyMethod.NotCertified.
public X509Certificate2 DigitalSignatureCertificate { get; set; }Gets or sets the signing certificate (see the DigitalCertificate class).
public PdfDocumentProperties DocumentProperties { get; set; }Gets or sets the properties of the loaded PDF document (number of pages, digital signatures, password).
public PdfEncryptionSettings Encryption { get; set; }Gets or sets the encryption of the signed document.
public string FontFile { get; set; }Gets or sets the path of a TrueType font file for the text of the visible signature (e.g. "C:\\WINDOWS\\FONTS\\times.TTF"). When it is set, PdfSignature.FontName is not used.
public FontName FontName { get; set; }Gets or sets the standard PDF font of the text of the visible signature. The default font is Helvetica.
public int FontSize { get; set; }Gets or sets the font size of the text of the visible signature.
public HashAlgorithm HashAlgorithm { get; set; }Gets or sets the hash algorithm of the signature. The default value is SHA256.
public bool OldStyleAdobeSignature { get; set; }Gets or sets a value indicating whether the visible signature uses the old Adobe Acrobat style (a question mark for the unknown signatures, a check mark for the valid ones). The default value is false.
public PadesLtvLevel PadesLtvLevel { get; set; }Gets or sets the revocation data embedded in the signature for its long term validation. The default value is PadesLtvLevel.IncludeOcspOnly.
public Rectangle SignatureAdvancedPosition { set; }Sets the rectangle of the visible signature on the page (instead of PdfSignature.SignaturePosition).
public bool SignatureAppearsOnAllPages { get; set; }Gets or sets a value indicating whether the visible signature appears on all the pages, once on each page. The default value is false.
public byte[] SignatureImage { get; set; }Gets or sets the image of the visible signature (e.g. the content of a JPG or PNG file).
public SignatureImageType SignatureImageType { get; set; }Gets or sets how the image of the visible signature is displayed. The default value is SignatureImageType.ImageAndText.
public int SignaturePage { get; set; }Gets or sets the page of the visible signature. The default value is 1; int.MaxValue means the last page. The signature rectangle is computed on this page, also when the signature appears on several pages.
public List<int> SignaturePages { get; set; }Gets or sets the pages on which the visible signature appears, instead of PdfSignature.SignaturePage. The page numbers start at 1 and int.MaxValue means the last page; a page listed more than once gets a single signature. The signature rectangle is the same on every page. Ignored when PdfSignature.SignatureAppearsOnAllPages is true. The default value is an empty list (null is the same).
public SignaturePosition SignaturePosition { get; set; }Gets or sets the position of the visible signature on the page. The default value is SignaturePosition.TopRight.
public PdfSignatureStandard SignatureStandard { get; set; }Gets or sets the signature format. The default value is PdfSignatureStandard.Default (PKCS#7), which is recognized by the older PDF readers.
public string SignatureText { get; set; }Gets or sets the text of the visible signature, instead of the default text (the signer name, the signing time, the reason and the location).
public string SigningApplicationName { get; set; }Gets or sets the name of the application that creates the signature (e.g. "My Application"). It is written in the signature build properties (/Prop_Build /App /Name) of the signatures and of the document time-stamps, and Adobe Reader shows it in the advanced signature properties as "Signature was created using [name] [version]". The default value is null: nothing is written and Adobe Reader shows "Not available". At most 127 bytes in UTF-8 encoding.
Exceptions.
ArgumentException: The name is too long or it contains control characters.
public string SigningApplicationVersion { get; set; }Gets or sets the version of the application that creates the signature (e.g. "8.0.1"), written in the signature build properties (/Prop_Build /App /REx) and shown by Adobe Reader after the application name. It is used only when PdfSignature.SigningApplicationName is set. The default value is null.
public string SigningLocation { get; set; }Gets or sets the signing location.
public string SigningReason { get; set; }Gets or sets the signing reason.
public TextDirection TextDirection { set; }Sets the direction of the text of the visible signature. The default value is TextDirection.Normal.
public TimestampSettings TimeStamping { get; set; }Gets or sets the time-stamping settings. When the server URL is set, the signatures are time-stamped.
public bool VisibleSignature { get; set; }Gets or sets a value indicating whether the signature is visible on the document. The default value is true.
Methods
public byte[] ApplyDigitalSignature()Signs the loaded PDF document.
Returns. The signed PDF document.
Exceptions.
ArgumentOutOfRangeException: A page of the visible signature (PdfSignature.SignaturePageorPdfSignature.SignaturePages) does not exist in the document.
public byte[] ApplyDigitalSignature(string signatureField)Signs the loaded PDF document.
signatureField- The name of an existing empty signature field to sign, or null for a new signature field.
Returns. The signed PDF document.
Exceptions.
ArgumentOutOfRangeException: A page of the visible signature (PdfSignature.SignaturePageorPdfSignature.SignaturePages) does not exist in the document.
public byte[] ApplyTimestampSignature()Adds a document time-stamp (ETSI.RFC3161) to the loaded PDF document.
Returns. The time-stamped PDF document.
Exceptions.
NullReferenceException: The document is not loaded or the time-stamping server is not set.
public byte[] FinalizeExternalSignature(PendingExternalSignature pending, byte[] externalSignatureBytes)Phase 2 of a deferred external signature: completes the CMS signature with the signature value created by the external signer and inserts it in the PDF document prepared by PdfSignature.PrepareExternalSignature. No private key is needed. When TimestampSettings.ServerUrl is set on this instance, the signature is time-stamped; PAdES-LT and PAdES-LTA (from the prepared signature) are completed afterwards.
pending- The prepared signature returned by PrepareExternalSignature.
externalSignatureBytes- The signature value created by the external signer over pending.DataToSign, with the hash algorithm pending.DigestAlgorithmOid (what
IExternalSignature.ApplySignaturereturns).
Returns. The signed PDF document.
Exceptions.
CryptographicException: The signature does not fit in the space reserved for it.
public void LoadPdfDocument(byte[] pdfArray)Loads the PDF document to sign.
pdfArray- The PDF document.
public void LoadPdfDocument(string PdfFile)Loads the PDF document to sign from a file.
PdfFile- The path of the PDF document.
Exceptions.
FileNotFoundException: The file does not exist.
public void LoadPdfDocument(Uri PdfUrl)Loads the PDF document to sign from a URL.
PdfUrl- The URL of the PDF document.
public PendingExternalSignature PrepareExternalSignature(string signatureField)Phase 1 of a deferred external signature: prepares the PDF document exactly as ApplyDigitalSignature does and computes the data to sign, without signing it (no private key is used and no external signature provider is called). The result contains everything needed to complete the signature later, even in another process, with PdfSignature.FinalizeExternalSignature.
signatureField- The name of an existing empty signature field to sign, or null for a new signature field.
Returns. The prepared signature.
Exceptions.
ArgumentOutOfRangeException: A page of the visible signature (PdfSignature.SignaturePageorPdfSignature.SignaturePages) does not exist in the document.
public static byte[] RepairPdf(byte[] pdfContent)Tries to repair a damaged PDF document, by rebuilding it.
pdfContent- The PDF document.
Returns. The rebuilt PDF document.
public static byte[] RepairPdf(string pdfFile)Tries to repair a damaged PDF document, by rebuilding it.
pdfFile- The path of the PDF document.
Returns. The rebuilt PDF document.
public void SetSignaturePolicyInformation(string policyIdentifier, byte[] policyHash, string policyDigestAlgorithm, string policyUrl)Sets the explicit signature policy (the signature-policy-identifier signed attribute) of the signatures created with this instance. By default there is no policy.
policyIdentifier- The OID of the policy (e.g. 2.16.76.1.7.1.5.2.3), or null to remove the policy.
policyHash- The hash of the policy document.
policyDigestAlgorithm- The OID of the hash algorithm of the policy document (e.g. 2.16.840.1.101.3.4.2.1).
policyUrl- The URL of the policy document (e.g. http://ca.signfiles.com/CaPolicy.html), or null.
PdfSignatureInfo class
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public class PdfSignatureInfo
Information about a digital signature or a document time-stamp of a PDF document.
Constructors
public PdfSignatureInfo()Initializes a new instance of the PdfSignatureInfo class.
Properties
public string DigestAlgorithm { get; }Gets the algorithm of the signature (e.g. SHA256withRSA or SHA256withECDSA).
public string HashAlgorithm { get; }Gets the hash algorithm of the signature (e.g. SHA256).
public string SignatureAlgorithm { get; }Gets the algorithm of the key of the signing certificate (RSA, DSA or ECC).
public byte[] SignatureBytes { get; }Gets the signature, as an encoded PKCS#7 (CMS) signed message.
public X509Certificate2 SignatureCertificate { get; }Gets the signing certificate.
public byte[] SignatureHash { get; }Gets the signature value of the signer.
public bool SignatureIsTimestamped { get; }Gets a value indicating whether the signature is time-stamped.
public bool SignatureIsValid { get; }Gets a value indicating whether the signature is valid. Use it with caution: only the integrity of the signature is verified, not the certificate chain or the revocation status of the signing certificate.
public string SignatureName { get; }Gets the name of the signature field.
public DateTime SignatureTime { get; }Gets the signing time: the time of the time-stamp when the signature is time-stamped, otherwise the time declared by the signer.
public SignatureType SignatureType { get; }Gets the type of the signature: a digital signature or a document time-stamp.
public string SigningLocation { get; }Gets the signing location.
public string SigningReason { get; }Gets the signing reason.
public TimestampInfo TimestampInfo { get; }Gets the information about the time-stamp of the signature, or null.
PendingExternalSignature class
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public class PendingExternalSignature
A prepared PDF signature, returned by PdfSignature.PrepareExternalSignature: everything needed to complete a deferred (two-phase) external signature later, possibly in another process, hours or days afterwards, with PdfSignature.FinalizeExternalSignature. No value depends on a live iTextSharp object or on a private key, so the object can be serialized (e.g. as JSON) and stored. Do not use BinaryFormatter for this.
Properties
public byte[][] CertificateChainRawData { get; set; }Gets or sets the certificate chain (from the signing certificate to the root), DER encoded.
public int ContentsByteBlockSize { get; set; }Gets or sets the size, in bytes, reserved for the CMS signature (before the hexadecimal encoding).
public int ContentsPosition { get; set; }Gets or sets the position, in bytes, of the /Contents placeholder in PendingExternalSignature.PendingDocument.
public int ContentsPosLength { get; set; }Gets or sets the length, in bytes, of the hexadecimal /Contents placeholder.
public string ContentTypeOid { get; set; }Gets or sets the OID of the content type of the CMS signature.
public byte[] DataToSign { get; set; }Gets or sets the data that the external signer must hash and sign: the DER encoded CMS signed attributes (not the PDF content and not a hash), exactly what IExternalSignature.ApplySignature receives.
public string DigestAlgorithmOid { get; set; }Gets or sets the OID of the hash algorithm that the external signer must use (e.g. SHA-256).
public string DigestOid { get; set; }Gets or sets the OID of the digest algorithm of the CMS signer.
public bool Encapsulate { get; set; }Gets or sets a value indicating whether the content is encapsulated in the CMS signature (false for the PDF signatures).
public string EncryptionOid { get; set; }Gets or sets the OID of the signature algorithm of the CMS signer.
public byte[] PendingDocument { get; set; }Gets or sets the prepared PDF document: with the final /ByteRange and an empty /Contents placeholder of the reserved size. It is not a valid signed PDF until it is completed by FinalizeExternalSignature.
public string SignatureFieldName { get; set; }Gets or sets the name of the signature field: FinalizeExternalSignature uses it to find this signature among the signatures of the document for PAdES-LT and PAdES-LTA.
public PdfSignatureStandard SignatureStandard { get; set; }Gets or sets the signature format.
public byte[] SignedContent { get; set; }Gets or sets the signed PDF bytes (the /ByteRange content) covered by the message digest of PendingExternalSignature.DataToSign.
public byte[] SigningCertificateRawData { get; set; }Gets or sets the signing certificate (public data only).
CertifyMethod enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum CertifyMethod
Certification level of a PDF document: the changes allowed after the certification signature.
| Member | Value | Description |
|---|---|---|
NotCertified | 0 | The document is not certified. |
NoChangesAllowed | 1 | No changes are allowed. |
FormFilling | 2 | Filling the form fields (and signing) is allowed. |
AnnotationsAndFormFilling | 3 | Adding annotations and filling the form fields (and signing) are allowed. |
FontName enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum FontName
Standard PDF fonts (the 14 fonts that every PDF reader has) for the text of the visible signature.
| Member | Value | Description |
|---|---|---|
Helvetica | 0 | Helvetica. |
Helvetica_Bold | 1 | Helvetica Bold. |
Helvetica_Oblique | 2 | Helvetica Oblique. |
Helvetica_BoldOblique | 3 | Helvetica Bold Oblique. |
Courier | 4 | Courier. |
Courier_Bold | 5 | Courier Bold. |
Courier_Oblique | 6 | Courier Oblique. |
Courier_BoldOblique | 7 | Courier Bold Oblique. |
Times_Roman | 8 | Times Roman. |
Times_Bold | 9 | Times Bold. |
Times_Italic | 10 | Times Italic. |
Times_BoldItalic | 11 | Times Bold Italic. |
ImagePosition enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum ImagePosition
Position of an image relative to the content of a PDF page.
| Member | Value | Description |
|---|---|---|
ImageUnderContent | 0 | The image is inserted under the content of the page (as background). |
ImageOverContent | 1 | The image is inserted over the content of the page. |
PadesLtvLevel enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum PadesLtvLevel
Revocation data embedded in a PDF signature, for its long term validation.
| Member | Value | Description |
|---|---|---|
None | 0 | No revocation data. |
IncludeCrl | 1 | The CRLs of the certificate chain, when available. |
IncludeCrlAndOcsp | 2 | The CRLs of the certificate chain and the OCSP responses of the signing certificate and of its issuer, when available. |
IncludeOcspOnly | 3 | The OCSP response of the signing certificate, when available (otherwise its CRL, so that the signature is not left without revocation data), and the CRLs of the CA certificates. |
PdfDocumentRestrictions enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum PdfDocumentRestrictions
Actions allowed on an encrypted PDF document. The values can be combined (e.g. AllowPrinting | AllowFillingOfFormFields).
| Member | Value | Description |
|---|---|---|
AllowNone | 0 | No action is allowed. |
AllowContentCopying | 16 | Allows copying the content. |
AllowFillingOfFormFields | 256 | Allows filling the form fields. |
AllowContentCopyingForAccessibility | 512 | Allows copying the content for accessibility. |
AllowDocumentAssembly | 1024 | Allows the assembly of the document (inserting, rotating or deleting pages). |
AllowPrinting | 2052 | Allows printing. |
PdfEncryptionAlgorithm enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum PdfEncryptionAlgorithm
Encryption algorithm of a PDF document. The 256-bit AES encryption of PDF 2.0 (ISO 32000-2, revision 6) is not supported.
| Member | Value | Description |
|---|---|---|
StandardEncryption40BitRC4 | 0 | 40-bit RC4 (revision 2). Insecure: it is easily broken. Deprecated by ISO 32000-2 (PDF 2.0); use it only for very old PDF readers. |
StandardEncryption128BitRC4 | 1 | 128-bit RC4 (revision 3). Weak. Deprecated by ISO 32000-2 (PDF 2.0). |
EnhancedEncryption128BitAES | 2 | 128-bit AES (revision 4). The strongest supported algorithm and the recommended one; it is opened by all current PDF readers. |
PdfEncryptionMethod enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum PdfEncryptionMethod
Encryption method of a PDF document.
| Member | Value | Description |
|---|---|---|
CertificateSecurity | 0 | The document is encrypted for a certificate: it can be opened only where the private key of the certificate is available. |
PasswordSecurity | 1 | The document is encrypted with passwords. |
NoEncryption | 2 | The document is not encrypted. |
PdfSignatureStandard enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum PdfSignatureStandard
Signature format of a PDF signature.
| Member | Value | Description |
|---|---|---|
Default | 0 | PKCS#7 (adbe.pkcs7.detached), recognized by the older PDF readers. |
Pades | 1 | PAdES baseline (ETSI.CAdES.detached, ETSI EN 319 142-1), recognized by Adobe Reader X and later. |
PadesLT | 2 | PAdES with long term validation data (PAdES-B-LT): the certificates and the revocation data are added to the document security store. |
PadesLTA | 3 | PAdES for long term archival (PAdES-B-LTA): PAdES-LT followed by a document time-stamp. |
SignatureImageType enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum SignatureImageType
How the image of a visible signature is displayed.
| Member | Value | Description |
|---|---|---|
ImageAsBackground | 0 | The image is the background of the signature text. |
ImageWithNoText | 1 | Only the image is displayed. |
ImageAndText | 2 | The image is displayed on the left and the signature text on the right. |
SignaturePosition enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum SignaturePosition
Position of the visible signature on the page.
| Member | Value | Description |
|---|---|---|
TopRight | 0 | The top right corner of the page. |
TopMiddle | 1 | The top middle of the page. |
TopLeft | 2 | The top left corner of the page. |
BottomRight | 3 | The bottom right corner of the page. |
BottomMiddle | 4 | The bottom middle of the page. |
BottomLeft | 5 | The bottom left corner of the page. |
SignatureType enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum SignatureType
Type of a signature of a PDF document.
| Member | Value | Description |
|---|---|---|
DigitalSignature | 0 | A digital signature. |
TimestampSignature | 1 | A document time-stamp (RFC 3161). |
TextAlign enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum TextAlign
Alignment of a text relative to its starting point.
| Member | Value | Description |
|---|---|---|
Left | 0 | The text starts at the starting point. |
Right | 1 | The text ends at the starting point. |
Center | 2 | The text is centered on the starting point. |
TextDirection enum
Namespace: SignLib.Pdf · Assembly: SignLib.dll
public enum TextDirection
Direction of a text.
| Member | Value | Description |
|---|---|---|
Normal | 0 | Left to right. |
RightToLeft | 1 | Right to left. |
18.3 Namespace SignLib.Cades
| Type | Description |
|---|---|
CadesSignature class | Creates CMS / PKCS#7 and CAdES signatures of any document, attached or detached, with an optional time-stamp and long term validation data. |
CadesSignatureInfo class | A signer of a CMS / CAdES signature verified by CadesVerify. |
CadesVerify class | Verifies a CMS / PKCS#7 or CAdES signature (attached or detached, binary or Base64 encoded) and gets the information about its signers. |
CadesSignatureStandard enum | The format of the signatures created by CadesSignature. |
CadesSignature class
Namespace: SignLib.Cades · Assembly: SignLib.dll
public class CadesSignature
Creates CMS / PKCS#7 and CAdES signatures of any document, attached or detached, with an optional time-stamp and long term validation data. When the signed data is itself a CMS signature, the new signature is added to it (co-signature).
Constructors
public CadesSignature(string librarySerialNumberLicense)Initializes a new instance of the CadesSignature class.
librarySerialNumberLicense- The serial number provided to register the library.
Properties
public X509Certificate2 DigitalSignatureCertificate { get; set; }Gets or sets the signing certificate (see the DigitalCertificate class).
public HashAlgorithm HashAlgorithm { get; set; }Gets or sets the hash algorithm of the signature. The default value is SHA256.
public bool IsDetachedSignature { get; set; }Gets or sets a value indicating whether the signature is detached: the signed document is not included in the signature. The default value is false.
public int MaxCrlSize { get; set; }Gets or sets the maximum size, in bytes, of a CRL included in the long term validation data: larger CRLs are skipped. The default value is 20 MB.
public CadesSignatureStandard SignatureStandard { get; set; }Gets or sets the signature format. The default value is CadesSignatureStandard.CadesBes.
public TimestampSettings TimeStamping { get; set; }Gets or sets the time-stamping settings. When the server URL is set, the signatures are time-stamped.
Methods
public byte[] ApplyDigitalSignature(string inputFile)Signs a file.
inputFile- The path of the file to sign, or of a CMS signature to co-sign.
Returns. The signature (with the file, unless the signature is detached).
Exceptions.
FileNotFoundException: The file does not exist.CryptographicException: The signature cannot be created.
public byte[] ApplyDigitalSignature(byte[] unsignedArray)Signs data.
unsignedArray- The data to sign, or a CMS signature to co-sign.
Returns. The signature (with the data, unless the signature is detached).
Exceptions.
CryptographicException: The signature cannot be created.
public void SetSignaturePolicyInformation(string policyIdentifier, byte[] policyHash, string policyDigestAlgorithm, string policyUrl)Sets the explicit signature policy (the signature-policy-identifier signed attribute) of the signatures created with this instance. By default there is no policy.
policyIdentifier- The OID of the policy (e.g. 2.16.76.1.7.1.5.2.3), or null to remove the policy.
policyHash- The hash of the policy document.
policyDigestAlgorithm- The OID of the hash algorithm of the policy document (e.g. 2.16.840.1.101.3.4.2.1).
policyUrl- The URL of the policy document (e.g. http://ca.signfiles.com/CaPolicy.html), or null.
CadesSignatureInfo class
Namespace: SignLib.Cades · Assembly: SignLib.dll
public class CadesSignatureInfo
A signer of a CMS / CAdES signature verified by CadesVerify.
Properties
public Oid HashAlgorithm { get; }Gets the hash algorithm of the signature (e.g. SHA256).
public X509Certificate2 SignatureCertificate { get; }Gets the signing certificate, or null when the signature does not contain it.
public byte[] SignatureHash { get; }Gets the signature value.
public bool SignatureIsTimestamped { get; }Gets a value indicating whether the signature is time-stamped.
public bool SignatureIsValid { get; }Gets a value indicating whether the signature is valid: the signed data was not changed and the signature value matches the signing certificate. The certificate itself (validity, revocation) is not verified.
public DateTime SignatureTime { get; }Gets the signing time claimed by the signer (the time of the signer's computer, in UTC), or DateTime.MinValue when the signature has no signing time. For a time-stamped signature, the trusted time is TimestampInfo.SignatureTime of CadesSignatureInfo.TimestampInfo.
public TimestampInfo TimestampInfo { get; }Gets the time-stamp of the signature, or null when the signature is not time-stamped.
CadesVerify class
Namespace: SignLib.Cades · Assembly: SignLib.dll
public class CadesVerify
Verifies a CMS / PKCS#7 or CAdES signature (attached or detached, binary or Base64 encoded) and gets the information about its signers.
Constructors
public CadesVerify(string signedFile, string librarySerialNumberLicense)Initializes a new instance of the CadesVerify class and verifies a signed file.
signedFile- The path of the signed file (e.g. document.pdf.p7s).
librarySerialNumberLicense- The serial number provided to register the library.
Exceptions.
FileNotFoundException: The file does not exist.CryptographicException: The file is not a CMS / PKCS#7 signature.
public CadesVerify(byte[] signedArray, string librarySerialNumberLicense)Initializes a new instance of the CadesVerify class and verifies a signature.
signedArray- The signature, with the signed document.
librarySerialNumberLicense- The serial number provided to register the library.
Exceptions.
CryptographicException: The data is not a CMS / PKCS#7 signature.
public CadesVerify(byte[] detachedSignedArray, byte[] originalUnsignedFile, string librarySerialNumberLicense)Initializes a new instance of the CadesVerify class and verifies a detached signature.
detachedSignedArray- The detached signature.
originalUnsignedFile- The signed document.
librarySerialNumberLicense- The serial number provided to register the library.
Exceptions.
CryptographicException: The data is not a CMS / PKCS#7 signature.
Properties
public string DocumentName { get; }Gets the name of the signed document: the document name signed attribute, or the name of the signed file without its extension (e.g. document.pdf for document.pdf.p7s). It is null when it is not known.
public List<CadesSignatureInfo> Signatures { get; }Gets the signers of the signature.
public CadesSignatureStandard SignatureStandard { get; }Gets the format of the signature, detected from the attributes of its signers.
public byte[] UnsignedDocument { get; }Gets the signed document, or null for a detached signature verified without the document.
CadesSignatureStandard enum
Namespace: SignLib.Cades · Assembly: SignLib.dll
public enum CadesSignatureStandard
The format of the signatures created by CadesSignature.
| Member | Value | Description |
|---|---|---|
Cms | 0 | CMS / PKCS#7 signature, recognized by the older software. |
CadesBes | 1 | CAdES-BES signature: the signing certificate is referenced by the ESS signing-certificate-v2 signed attribute (signing-certificate for SHA-1). No other ETSI attribute is added. |
CadesC | 2 | CAdES-C signature: adds the complete certificate and revocation references, together with the certificate and revocation values. |
CadesXL | 3 | CAdES-X Long signature: the CAdES-C attributes plus the time-stamp of the references (escTimeStamp). The time-stamps require a time-stamping server. |
CadesA | 4 | CAdES-A (long term archival) signature: the CAdES-LT attributes plus an archive time-stamp (v3, ETSI EN 319 122-1) of the signature and of its validation data. The time-stamps require a time-stamping server; without one, only the certificate and revocation values are added. |
CadesLT | 5 | CAdES-LT (long term) signature: adds the certificate and revocation values, for the long term validation of the signature, without the references of CAdES-C. |
18.4 Namespace SignLib.Xml
| Type | Description |
|---|---|
XadesProductionPlace class | Place where a XAdES signature was produced (xades:SignatureProductionPlaceV2, ETSI EN 319 132-1). |
XadesSignature class | Signs documents with XAdES signatures (the baseline levels B, T, LT and LTA of ETSI EN 319 132-1), enveloped in an XML document or detached from a file of any type, and verifies them. |
XmlSignature class | Signs XML documents with enveloped XMLDSig signatures (RSA or ECDSA) and verifies them. |
XadesCommitmentType enum | Commitment type of a XAdES signature (xades:CommitmentTypeIndication, ETSI EN 319 132-1 and ETSI TS 119 172-1): what the signer declares by signing. |
XadesLtvLevel enum | The revocation data included in the XAdES-LT and XAdES-LTA signatures. |
XadesSignaturePackaging enum | How a XAdES signature is packaged with the signed data. |
XadesSignatureStandard enum | The XAdES baseline levels (ETSI EN 319 132-1). |
XmlSignatureType enum | Canonicalization method used by the XmlSignature class. |
XadesProductionPlace class
Namespace: SignLib.Xml · Assembly: SignLib.dll
public class XadesProductionPlace
Place where a XAdES signature was produced (xades:SignatureProductionPlaceV2, ETSI EN 319 132-1). All the fields are optional and the empty fields are not written. The country should be an ISO 3166 code (e.g. "RO").
Properties
public string City { get; set; }Gets or sets the city.
public string CountryName { get; set; }Gets or sets the country (an ISO 3166 code is recommended, e.g. "RO").
public string PostalCode { get; set; }Gets or sets the postal code.
public string StateOrProvince { get; set; }Gets or sets the state or province.
public string StreetAddress { get; set; }Gets or sets the street address.
XadesSignature class
Namespace: SignLib.Xml · Assembly: SignLib.dll
public class XadesSignature
Signs documents with XAdES signatures (the baseline levels B, T, LT and LTA of ETSI EN 319 132-1), enveloped in an XML document or detached from a file of any type, and verifies them. A document can have several parallel signatures: a new signature does not invalidate the existing ones.
Constructors
public XadesSignature(string librarySerialNumberLicense)Initializes a new instance of the XadesSignature class.
librarySerialNumberLicense- The serial number provided to register the library.
Properties
public XadesCommitmentType CommitmentType { get; set; }Gets or sets the commitment type declared by the signer (xades:CommitmentTypeIndication), e.g. ProofOfApproval or ProofOfOrigin. The default value is XadesCommitmentType.None: the commitment is a signed statement that only the signer can choose (it is optional in ETSI EN 319 132-1 and not required by eIDAS).
public X509Certificate2 DigitalSignatureCertificate { get; set; }Gets or sets the signing certificate (see the DigitalCertificate class).
public HashAlgorithm HashAlgorithm { get; set; }Gets or sets the hash algorithm of the signature: SHA256 (the default), SHA384 or SHA512. It is used for the signature method, the reference digests and the digest of the signing certificate. SHA1 is not supported for new signatures (NotSupportedException), but the existing SHA-1 signatures can be verified.
public XadesLtvLevel LtvLevel { get; set; }Gets or sets the revocation data included in the XAdES-LT and XAdES-LTA signatures. The default value is XadesLtvLevel.IncludeOcspOnly.
public int MaxCrlSize { get; set; }Gets or sets the maximum size, in bytes, of a CRL included in the XAdES-LT and XAdES-LTA signatures: larger CRLs are skipped. The default value is 1 MB.
public XadesSignaturePackaging SignaturePackaging { get; set; }Gets or sets how the signature is packaged. XadesSignaturePackaging.Enveloped (the default): the signature is added to the signed XML document. XadesSignaturePackaging.Detached: the signature is a separate XML file that references the signed file; the signed file can be of any type (PDF, DOCX, ZIP...), it is not changed, and it is needed to verify the signature. Several signers of the same file create separate signature files.
public XadesProductionPlace SignatureProductionPlace { get; set; }Gets or sets the place where the signature is created (xades:SignatureProductionPlaceV2). The default value is null: the property is not added.
public XadesSignatureStandard SignatureStandard { get; set; }Gets or sets the XAdES baseline level of the signature (ETSI EN 319 132-1). The default value is XadesSignatureStandard.XadesB. XadesT, XadesLT and XadesLTA require TimeStamping.ServerUrl. As for the PDF signatures, a XadesB signature is also time-stamped (XAdES-T) when TimeStamping.ServerUrl is set.
public TimestampSettings TimeStamping { get; set; }Gets or sets the time-stamping settings (required for the XAdES-T, XAdES-LT and XAdES-LTA signatures).
Methods
public void AddArchiveTimestamp(string inputFile, string outputFile)Adds a new archive time-stamp to every XAdES-LTA signature of an XML document (re-time-stamping). Before the new xades141:ArchiveTimeStamp, the certificates and the current revocation data needed to validate the previous time-stamps are added (xades141:TimeStampValidationData). Call it periodically, before the certificate of the time-stamping authority of the last archive time-stamp expires (or its algorithms become weak), to keep the signatures verifiable in the long term. It requires TimeStamping.ServerUrl and uses LtvLevel and MaxCrlSize; the signing certificate is not needed. The other signatures are not changed.
inputFile- The path of the XML document with XAdES-LTA signatures.
outputFile- The path of the re-time-stamped document (it can be the input file).
public void AddArchiveTimestamp(string signatureFile, string outputFile, string originalFile)Adds a new archive time-stamp to every XAdES-LTA signature of a detached signature file (re-time-stamping), as AddArchiveTimestamp(inputFile, outputFile) does for enveloped signatures. The original file is needed because it is part of the time-stamped data.
signatureFile- The path of the detached XAdES-LTA signature (XML).
outputFile- The path of the re-time-stamped signature file (it can be the signature file).
originalFile- The path of the signed file.
Exceptions.
FileNotFoundException: The original file does not exist.ArgumentException: The output file is the original file.
public void ApplyDigitalSignature(string inputFile, string outputFile)Signs a document. The output file is deleted when the signature fails (unless it is the input file).
inputFile- The path of the document to sign: an XML document (Enveloped) or any file (Detached).
outputFile- The path of the signed XML document (Enveloped) or of the signature file (Detached).
Exceptions.
FileNotFoundException: The input file does not exist.ArgumentException: The time-stamping server is required, or the signature file of a detached signature is the signed file.NotSupportedException: The hash algorithm is SHA1.
public X509Certificate2 GetDigitalSignatureCertificate(string inputFile)Gets the signing certificate of the first signature of an XML document.
inputFile- The path of the document.
Returns. The signing certificate.
public X509Certificate2 GetDigitalSignatureCertificate(Stream inputFile)Gets the signing certificate of the first signature of an XML document.
inputFile- The document.
Returns. The signing certificate.
public X509Certificate2 GetDigitalSignatureCertificate(string inputFile, int signatureIndex)Gets the signing certificate of a signature of an XML document.
inputFile- The path of the document.
signatureIndex- The 0-based index of the signature, in document order.
Returns. The signing certificate.
public X509Certificate2 GetDigitalSignatureCertificate(Stream inputFile, int signatureIndex)Gets the signing certificate of a signature of an XML document.
inputFile- The document.
signatureIndex- The 0-based index of the signature, in document order.
Returns. The signing certificate.
public int GetNumberOfSignatures(string inputFile)Gets the number of signatures of an XML document.
inputFile- The path of the document.
Returns. The number of signatures.
public int GetNumberOfSignatures(Stream inputFile)Gets the number of signatures of an XML document.
inputFile- The document.
Returns. The number of signatures.
public string GetSignatureAlgorithm(string inputFile)Gets the signature algorithm of the first signature of an XML document (e.g. RSA-SHA256).
inputFile- The path of the document.
Returns. The signature algorithm.
public string GetSignatureAlgorithm(Stream inputFile)Gets the signature algorithm of the first signature of an XML document (e.g. RSA-SHA256).
inputFile- The document.
Returns. The signature algorithm.
public void SetSignaturePolicyInformation(string policyIdentifier, byte[] policyHash, string policyDigestAlgorithm, string policyUrl)Sets the explicit signature policy of the signatures (xades:SignaturePolicyIdentifier), when a regulation or a relying party requires one. By default there is no policy.
policyIdentifier- The identifier of the policy: an OID (e.g. 2.16.724.1.3.1.1.2.1.9, with or without the urn:oid: prefix) or a URI. Null removes the policy.
policyHash- The digest of the policy document.
policyDigestAlgorithm- The digest algorithm of policyHash: an OID (e.g. 2.16.840.1.101.3.4.2.1) or a name (SHA1, SHA256, SHA384, SHA512). SHA1 is accepted because many published policies are referenced by a SHA-1 digest.
policyUrl- The URL of the policy document (xades:SPURI), or null.
public bool VerifyDigitalSignature(string inputFile)Verifies all the signatures of an XML document.
inputFile- The path of the document.
Returns. True if every signature is valid.
Exceptions.
CryptographicException: The document has no signature.
public bool VerifyDigitalSignature(Stream inputFile)Verifies all the signatures of an XML document.
inputFile- The document.
Returns. True if every signature is valid.
Exceptions.
CryptographicException: The document has no signature.
public bool VerifyDigitalSignature(string inputFile, int signatureIndex)Verifies a signature of an XML document.
inputFile- The path of the document.
signatureIndex- The 0-based index of the signature, in document order.
Returns. True if the signature is valid.
public bool VerifyDigitalSignature(Stream inputFile, int signatureIndex)Verifies a signature of an XML document.
inputFile- The document.
signatureIndex- The 0-based index of the signature, in document order.
Returns. True if the signature is valid.
public bool VerifyDigitalSignature(string inputFile, X509Certificate2 certificate)Verifies that an XML document has a valid signature created with a certificate.
inputFile- The path of the document.
certificate- The certificate of the expected signer.
Returns. True if a signature of the document is valid for the certificate.
public bool VerifyDigitalSignature(Stream inputFile, X509Certificate2 certificate)Verifies that an XML document has a valid signature created with a certificate.
inputFile- The document.
certificate- The certificate of the expected signer.
Returns. True if a signature of the document is valid for the certificate.
public bool VerifyDigitalSignature(string signatureFile, string originalFile)Verifies a detached signature: all the signatures of the signature file must be valid for the original file.
signatureFile- The path of the detached signature (XML).
originalFile- The path of the signed file (it can have been renamed).
Returns. True if every signature is valid.
Exceptions.
FileNotFoundException: The original file does not exist.
public bool VerifyDigitalSignature(string signatureFile, string originalFile, X509Certificate2 certificate)Verifies that a detached signature file has a valid signature of the original file, created with a certificate.
signatureFile- The path of the detached signature (XML).
originalFile- The path of the signed file (it can have been renamed).
certificate- The certificate of the expected signer.
Returns. True if a signature is valid for the certificate.
Exceptions.
FileNotFoundException: The original file does not exist.
XmlSignature class
Namespace: SignLib.Xml · Assembly: SignLib.dll
public class XmlSignature
Signs XML documents with enveloped XMLDSig signatures (RSA or ECDSA) and verifies them. A document can have several parallel signatures: a new signature does not invalidate the existing ones.
Constructors
public XmlSignature(string librarySerialNumberLicense)Initializes a new instance of the XmlSignature class.
librarySerialNumberLicense- The serial number provided to register the library.
Properties
public X509Certificate2 DigitalSignatureCertificate { get; set; }Gets or sets the signing certificate (see the DigitalCertificate class).
public HashAlgorithm HashAlgorithm { get; set; }Gets or sets the hash algorithm of the signature: SHA256 (the default), SHA384 or SHA512. SHA1 is not supported for new signatures (NotSupportedException), but the existing SHA-1 signatures can be verified.
public bool IncludeKeyInfo { get; set; }Gets or sets a value indicating whether the key of the signer is included in the signature: the RSA key value (modulus and exponent) or, for an ECDSA key, the signing certificate (SignedXml does not support the ECDSA key values). The default value is true.
public bool IncludeSignatureCertificate { get; set; }Gets or sets a value indicating whether the signing certificate is included in the signature. The default value is true.
public bool PreserveWhitespace { get; set; }Gets or sets a value indicating whether the white space of the documents is preserved when they are signed and verified: the signed document is saved as it is. When it is false, the insignificant white space is removed when a document is loaded, and the signed document is saved indented. The default value is true.
public XmlSignatureType SignatureType { get; set; }Gets or sets the canonicalization of the signature. The default value is XmlSignatureType.Default (http://www.w3.org/TR/2001/REC-xml-c14n-20010315).
Methods
public void ApplyDigitalSignature(string inputFile, string outputFile)Signs an XML document. The output file is deleted when the signature fails (unless it is the input file).
inputFile- The path of the XML document to sign.
outputFile- The path of the signed document (it can be the input file).
Exceptions.
FileNotFoundException: The input file does not exist.
public void ApplyDigitalSignature(Stream inputStream, Stream outputStream)Signs an XML document.
inputStream- The XML document to sign.
outputStream- The stream where the signed document is written.
public X509Certificate2 GetDigitalSignatureCertificate(string inputFile)Gets the signing certificate of the first signature of an XML document.
inputFile- The path of the document.
Returns. The signing certificate.
public X509Certificate2 GetDigitalSignatureCertificate(Stream inputFile)Gets the signing certificate of the first signature of an XML document.
inputFile- The document.
Returns. The signing certificate.
public X509Certificate2 GetDigitalSignatureCertificate(string inputFile, int signatureIndex)Gets the signing certificate of a signature of an XML document.
inputFile- The path of the document.
signatureIndex- The 0-based index of the signature, in document order.
Returns. The signing certificate.
public X509Certificate2 GetDigitalSignatureCertificate(Stream inputFile, int signatureIndex)Gets the signing certificate of a signature of an XML document.
inputFile- The document.
signatureIndex- The 0-based index of the signature, in document order.
Returns. The signing certificate.
public int GetNumberOfSignatures(string inputFile)Gets the number of signatures of an XML document.
inputFile- The path of the document.
Returns. The number of signatures.
public int GetNumberOfSignatures(Stream inputFile)Gets the number of signatures of an XML document.
inputFile- The document.
Returns. The number of signatures.
public string GetSignatureAlgorithm(string inputFile)Gets the signature algorithm of the first signature of an XML document (e.g. RSA-SHA256).
inputFile- The path of the document.
Returns. The signature algorithm.
public string GetSignatureAlgorithm(Stream inputFile)Gets the signature algorithm of the first signature of an XML document (e.g. RSA-SHA256).
inputFile- The document.
Returns. The signature algorithm.
public bool VerifyDigitalSignature(string inputFile)Verifies all the signatures of an XML document.
inputFile- The path of the document.
Returns. True if every signature is valid.
Exceptions.
CryptographicException: The document has no signature.
public bool VerifyDigitalSignature(Stream inputFile)Verifies all the signatures of an XML document.
inputFile- The document.
Returns. True if every signature is valid.
Exceptions.
CryptographicException: The document has no signature.
public bool VerifyDigitalSignature(string inputFile, int signatureIndex)Verifies a signature of an XML document.
inputFile- The path of the document.
signatureIndex- The 0-based index of the signature, in document order.
Returns. True if the signature is valid.
public bool VerifyDigitalSignature(Stream inputFile, int signatureIndex)Verifies a signature of an XML document.
inputFile- The document.
signatureIndex- The 0-based index of the signature, in document order.
Returns. True if the signature is valid.
public bool VerifyDigitalSignature(string inputFile, X509Certificate2 certificate)Verifies that an XML document has a valid signature created with a certificate.
inputFile- The path of the document.
certificate- The certificate of the expected signer.
Returns. True if a signature of the document is valid for the certificate.
public bool VerifyDigitalSignature(Stream inputFile, X509Certificate2 certificate)Verifies that an XML document has a valid signature created with a certificate.
inputFile- The document.
certificate- The certificate of the expected signer.
Returns. True if a signature of the document is valid for the certificate.
XadesCommitmentType enum
Namespace: SignLib.Xml · Assembly: SignLib.dll
public enum XadesCommitmentType
Commitment type of a XAdES signature (xades:CommitmentTypeIndication, ETSI EN 319 132-1 and ETSI TS 119 172-1): what the signer declares by signing. It is a signed property, so it is part of what the signer commits to.
| Member | Value | Description |
|---|---|---|
None | 0 | No commitment type is declared (the CommitmentTypeIndication property is not added). |
ProofOfOrigin | 1 | The signer recognizes to have created, approved and sent the signed data. |
ProofOfReceipt | 2 | The signer recognizes to have received the content of the signed data. |
ProofOfDelivery | 3 | A trusted service provider indicates that the signed data has been delivered to a recipient. |
ProofOfSender | 4 | The entity signing has sent the signed data (but not necessarily created it). |
ProofOfApproval | 5 | The signer has approved the content of the signed data. |
ProofOfCreation | 6 | The signer has created the signed data (but not necessarily approved nor sent it). |
XadesLtvLevel enum
Namespace: SignLib.Xml · Assembly: SignLib.dll
public enum XadesLtvLevel
The revocation data included in the XAdES-LT and XAdES-LTA signatures.
| Member | Value | Description |
|---|---|---|
None | 0 | No revocation data (only the certificates). |
IncludeCrl | 1 | The CRLs of the certificate chains, when they are available. |
IncludeCrlAndOcsp | 2 | The CRLs and the OCSP responses of the certificate chains, when they are available. |
IncludeOcspOnly | 3 | The OCSP responses of the certificate chains, when they are available. The CRL of an end-entity certificate is included only when its OCSP response is not available; the CRLs of the CA certificates are included. |
XadesSignaturePackaging enum
Namespace: SignLib.Xml · Assembly: SignLib.dll
public enum XadesSignaturePackaging
How a XAdES signature is packaged with the signed data.
| Member | Value | Description |
|---|---|---|
Enveloped | 0 | The signature is added to the signed XML document (only XML documents can be signed). |
Detached | 1 | The signature is a separate XML file that references the signed file (of any type); the signed file is not changed, and it is needed to verify the signature. |
XadesSignatureStandard enum
Namespace: SignLib.Xml · Assembly: SignLib.dll
public enum XadesSignatureStandard
The XAdES baseline levels (ETSI EN 319 132-1).
| Member | Value | Description |
|---|---|---|
XadesB | 0 | XAdES-B-B: the signing time, the signing certificate and the format of the signed data. |
XadesT | 1 | XAdES-B-T: XAdES-B-B with a signature time-stamp. Requires TimeStamping.ServerUrl. |
XadesLT | 2 | XAdES-B-LT (long term validation): XAdES-B-T with the certificates and the revocation data (CRL, OCSP) of the signing certificate and of the time-stamping authority. Requires TimeStamping.ServerUrl. |
XadesLTA | 3 | XAdES-B-LTA (long term archival): XAdES-B-LT with an archive time-stamp. Requires TimeStamping.ServerUrl. |
XmlSignatureType enum
Namespace: SignLib.Xml · Assembly: SignLib.dll
public enum XmlSignatureType
Canonicalization method used by the XmlSignature class.
| Member | Value | Description |
|---|---|---|
Default | 0 | Canonical XML 1.0 without comments (http://www.w3.org/TR/2001/REC-xml-c14n-20010315). |
DefaultWithComments | 1 | Canonical XML 1.0 with comments (http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments). |
Exclusive | 2 | Exclusive XML canonicalization without comments (http://www.w3.org/2001/10/xml-exc-c14n#). |
ExclusiveWithComments | 3 | Exclusive XML canonicalization with comments (http://www.w3.org/2001/10/xml-exc-c14n#WithComments). |
18.5 Namespace SignLib.Office
| Type | Description |
|---|---|
OfficeSignatureInfo class | A signature of an Office document and the result of its verification. |
OfficeSignatureLine class | A visible signature of a Word document (docx): an Office signature line. |
OfficeSignatureLineInfo class | A signature line of a Word document. |
OfficeSignatureLineAlignment enum | The horizontal alignment of a new signature line. |
OfficeSignatureLinePlacement enum | Where the visible signature is placed in the document. |
OfficeSignatureInfo class
Namespace: SignLib.Office · Assembly: SignLib.dll
public class OfficeSignatureInfo
A signature of an Office document and the result of its verification.
Properties
public X509Certificate2 Certificate { get; }Gets the signing certificate, or null.
public string CommitmentType { get; }Gets the commitment type (e.g. Approved this document), or null.
public bool HasTimestamp { get; }Gets a value indicating whether the signature has a time-stamp (XAdES-T or higher).
public bool HasValidationData { get; }Gets a value indicating whether the signature includes the certificates and the revocation data (XAdES-LT).
public int Index { get; }Gets the 0-based index of the signature, in the order of the signature parts of the document.
public bool IsValid { get; }Gets a value indicating whether the signature is valid (the document was not changed after it was signed).
public bool IsVisible { get; }Gets a value indicating whether the signature is visible (it signs a signature line).
public string SetupId { get; }Gets the identifier of the signature line signed by this signature, or null for an invisible signature.
public string SignatureAlgorithm { get; }Gets the signature algorithm (e.g. RSA-SHA256).
public string SignatureComments { get; }Gets the purpose of the signature (the comments of the signer), or null.
public string SignerName { get; }Gets the name of the signer (the common name of the signing certificate).
public string SignerRole { get; }Gets the role (title) claimed by the signer, or null.
public DateTime? SigningTime { get; }Gets the signing time claimed by the signer (UTC), or null.
public string Status { get; }Gets the result of the verification: Success for a valid signature, ContentModified when the document was changed after it was signed, ReferenceNotFound when a signed part is missing, InvalidSignature otherwise. The trust of the signing certificate is not verified.
public DateTime? TimestampTime { get; }Gets the time of the time-stamp (UTC), or null.
OfficeSignatureLine class
Namespace: SignLib.Office · Assembly: SignLib.dll
public class OfficeSignatureLine
A visible signature of a Word document (docx): an Office signature line. Word shows the signature line with the signature of the signer when the signature is valid, and marks it as invalid when the document is changed.
Constructors
public OfficeSignatureLine()Initializes a new instance of the OfficeSignatureLine class.
Properties
public OfficeSignatureLineAlignment Alignment { get; set; }Gets or sets the alignment of a new signature line.
public int Height { get; set; }Gets or sets the height of a new signature line, in points (1/72 inch). Default: 96.
public OfficeSignatureLinePlacement Placement { get; set; }Gets or sets where the visible signature is placed.
public string SetupId { get; set; }Gets or sets the identifier of the existing signature line to sign (a GUID, e.g. from OfficeSignature.GetSignatureLines), or null for the first unsigned signature line.
public bool ShowSignDate { get; set; }Gets or sets a value indicating whether the signing date is shown on the signature line.
public byte[] SignatureImage { get; set; }Gets or sets the image of the handwritten signature drawn above the line (PNG, JPEG, BMP or GIF), or null.
public string SignatureText { get; set; }Gets or sets the text written above the line (usually the name of the signer). When it is empty and there is no OfficeSignatureLine.SignatureImage, the name of the signing certificate is written.
public string SigningInstructions { get; set; }Gets or sets the instructions shown to the signer of a new signature line (in Word).
public string SuggestedSigner { get; set; }Gets or sets the name of the signer shown under the line of a new signature line (e.g. John Smith). When it is empty, the name of the signing certificate is shown.
public string SuggestedSignerEmail { get; set; }Gets or sets the e-mail address of the signer of a new signature line.
public string SuggestedSignerTitle { get; set; }Gets or sets the title of the signer shown under the name of a new signature line (e.g. Manager).
public int Width { get; set; }Gets or sets the width of a new signature line, in points (1/72 inch). Default: 192.
OfficeSignatureLineInfo class
Namespace: SignLib.Office · Assembly: SignLib.dll
public class OfficeSignatureLineInfo
A signature line of a Word document.
Properties
public bool IsSigned { get; }Gets a value indicating whether the signature line is already signed.
public string SetupId { get; }Gets the identifier of the signature line (a GUID, e.g. {5B4C1E3A-...}).
public string SuggestedSigner { get; }Gets the suggested signer (the name shown under the line).
public string SuggestedSignerEmail { get; }Gets the e-mail address of the suggested signer.
public string SuggestedSignerTitle { get; }Gets the title of the suggested signer.
Methods
public string ToString()OfficeSignatureLineAlignment enum
Namespace: SignLib.Office · Assembly: SignLib.dll
public enum OfficeSignatureLineAlignment
The horizontal alignment of a new signature line.
| Member | Value | Description |
|---|---|---|
Left | 0 | |
Center | 1 | |
Right | 2 |
OfficeSignatureLinePlacement enum
Namespace: SignLib.Office · Assembly: SignLib.dll
public enum OfficeSignatureLinePlacement
Where the visible signature is placed in the document.
| Member | Value | Description |
|---|---|---|
UseExistingOrAddNew | 0 | The first unsigned signature line of the document (created in Word with Insert - Signature Line, or by OfficeSignature.AddSignatureLine) is signed; when the document has no unsigned signature line, a new one is added at the end of the document. |
UseExisting | 1 | An unsigned signature line of the document is signed (the one with OfficeSignatureLine.SetupId, or the first one). The signature fails when the document has no unsigned signature line. |
AddNew | 2 | A new signature line is added at the end of the document and signed. The document must not be signed yet: adding the signature line changes the document and would invalidate the existing signatures. |
18.6 Namespace SignLib.Asic
| Type | Description |
|---|---|
AsicSignature class | Creates, co-signs, verifies and re-time-stamps ASiC-E containers with XAdES signatures (ETSI EN 319 162-1): a single ZIP file (.asice) with the signed files (any number, of any type) and their XAdES signatures. |
AsicSignature class
Namespace: SignLib.Asic · Assembly: SignLib.dll
public class AsicSignature
Creates, co-signs, verifies and re-time-stamps ASiC-E containers with XAdES signatures (ETSI EN 319 162-1): a single ZIP file (.asice) with the signed files (any number, of any type) and their XAdES signatures. Every signature covers all the files of the container.
Constructors
public AsicSignature(string librarySerialNumberLicense)Initializes a new instance of the AsicSignature class.
librarySerialNumberLicense- The serial number provided to register the library.
Properties
public XadesCommitmentType CommitmentType { get; set; }Gets or sets the commitment type declared by the signer (xades:CommitmentTypeIndication), e.g. ProofOfApproval or ProofOfOrigin. The default value is XadesCommitmentType.None: the commitment is a signed statement that only the signer can choose (it is optional in ETSI EN 319 132-1 and not required by eIDAS).
public X509Certificate2 DigitalSignatureCertificate { get; set; }Gets or sets the signing certificate (see the DigitalCertificate class).
public HashAlgorithm HashAlgorithm { get; set; }Gets or sets the hash algorithm of the signatures: SHA256 (the default), SHA384 or SHA512. It is used for the signature method, the reference digests and the digest of the signing certificate. SHA1 is not supported for new signatures (NotSupportedException), but the existing SHA-1 signatures can be verified.
public XadesLtvLevel LtvLevel { get; set; }Gets or sets the revocation data included in the XAdES-LT and XAdES-LTA signatures. The default value is XadesLtvLevel.IncludeOcspOnly.
public int MaxCrlSize { get; set; }Gets or sets the maximum size, in bytes, of a CRL included in the XAdES-LT and XAdES-LTA signatures: larger CRLs are skipped. The default value is 1 MB.
public XadesProductionPlace SignatureProductionPlace { get; set; }Gets or sets the place where the signatures are created (xades:SignatureProductionPlaceV2). The default value is null: the property is not added.
public XadesSignatureStandard SignatureStandard { get; set; }Gets or sets the XAdES baseline level of the signatures. The default value is XadesSignatureStandard.XadesB. XadesT, XadesLT and XadesLTA require TimeStamping.ServerUrl. A XadesB signature is also time-stamped when TimeStamping.ServerUrl is set.
public TimestampSettings TimeStamping { get; set; }Gets or sets the time-stamping settings (required for the XAdES-T, XAdES-LT and XAdES-LTA signatures).
Methods
public byte[] AddArchiveTimestamp(byte[] container)Adds a new archive time-stamp to every XAdES-LTA signature of an ASiC-E container (re-time-stamping).
container- The container.
Returns. The re-time-stamped container.
Exceptions.
ArgumentException: The time-stamping server is not set.CryptographicException: A signature is not valid, or the container has no XAdES-LTA signature.
public void AddArchiveTimestamp(string inputContainer, string outputContainer)Adds a new archive time-stamp to every XAdES-LTA signature of an ASiC-E container (re-time-stamping), with the validation data of the previous time-stamps (xades141:TimeStampValidationData). It requires TimeStamping.ServerUrl.
inputContainer- The path of the container.
outputContainer- The path of the re-time-stamped container (it can be the input container).
Exceptions.
FileNotFoundException: The input container does not exist.
public byte[] AddSignature(byte[] container)Adds a new signature (co-signature) to an ASiC-E container.
container- The ASiC-E container.
Returns. The co-signed container.
Exceptions.
CryptographicException: The container has no files.
public void AddSignature(string inputContainer, string outputContainer)Adds a new signature (co-signature) to an ASiC-E container. The new signature covers all the files of the container and it is written to a new signature file; the existing signatures are not changed.
inputContainer- The path of the ASiC-E container.
outputContainer- The path of the co-signed container (it can be the input container).
Exceptions.
FileNotFoundException: The input container does not exist.
public byte[] CreateContainer(IDictionary<string, byte[]> dataFiles)Creates a signed ASiC-E container with files and one signature.
dataFiles- The files to sign: the name in the container (e.g. contract.pdf or annexes/annex1.pdf) and the content.
Returns. The ASiC-E container (.asice).
public void CreateContainer(string[] dataFiles, string outputContainer)Creates a signed ASiC-E container with files (stored with their file names) and one signature. The output container is deleted when the signature fails.
dataFiles- The paths of the files to sign (of any type).
outputContainer- The path of the ASiC-E container (.asice) to create.
Exceptions.
FileNotFoundException: A file does not exist.
public byte[] ExtractDataFile(string container, string dataFileName)Extracts a signed file from an ASiC-E container.
container- The path of the container.
dataFileName- The name of the file in the container.
Returns. The content of the file.
public byte[] ExtractDataFile(byte[] container, string dataFileName)Extracts a signed file from an ASiC-E container.
container- The container.
dataFileName- The name of the file in the container.
Returns. The content of the file.
Exceptions.
FileNotFoundException: The container has no file with this name.
public string[] GetDataFileNames(string container)Gets the names of the signed files of an ASiC-E container.
container- The path of the container.
Returns. The names of the files.
public string[] GetDataFileNames(byte[] container)Gets the names of the signed files of an ASiC-E container.
container- The container.
Returns. The names of the files.
public X509Certificate2 GetDigitalSignatureCertificate(string container, int signatureIndex)Gets the signing certificate of a signature of an ASiC-E container.
container- The path of the container.
signatureIndex- The 0-based index of the signature (the signature files in name order).
Returns. The signing certificate.
public X509Certificate2 GetDigitalSignatureCertificate(byte[] container, int signatureIndex)Gets the signing certificate of a signature of an ASiC-E container.
container- The container.
signatureIndex- The 0-based index of the signature (the signature files in name order).
Returns. The signing certificate.
Exceptions.
CryptographicException: The container has no signature.ArgumentOutOfRangeException: The index is not valid.
public int GetNumberOfSignatures(string container)Gets the number of signatures of an ASiC-E container.
container- The path of the container.
Returns. The number of signatures.
public int GetNumberOfSignatures(byte[] container)Gets the number of signatures of an ASiC-E container.
container- The container.
Returns. The number of signatures.
public void SetSignaturePolicyInformation(string policyIdentifier, byte[] policyHash, string policyDigestAlgorithm, string policyUrl)Sets the explicit signature policy of the signatures (xades:SignaturePolicyIdentifier), when a regulation or a relying party requires one. By default there is no policy.
policyIdentifier- The identifier of the policy: an OID (with or without the urn:oid: prefix) or a URI. Null removes the policy.
policyHash- The digest of the policy document.
policyDigestAlgorithm- The digest algorithm of policyHash: an OID or a name (SHA1, SHA256, SHA384, SHA512).
policyUrl- The URL of the policy document (xades:SPURI), or null.
public bool VerifyDigitalSignature(string container)Verifies an ASiC-E container.
container- The path of the container.
Returns. True if the container has at least one signature, all its signatures are valid, and every signature covers all the files of the container (a file added to a signed container makes the verification fail).
public bool VerifyDigitalSignature(byte[] container)Verifies an ASiC-E container.
container- The container.
Returns. True if the container has at least one signature, all its signatures are valid, and every signature covers all the files of the container (a file added to a signed container makes the verification fail).
public bool VerifyDigitalSignature(string container, X509Certificate2 certificate)Verifies that an ASiC-E container has a valid signature of all its files, created with a certificate.
container- The path of the container.
certificate- The certificate of the expected signer.
Returns. True if a signature of the container is valid for the certificate.
public bool VerifyDigitalSignature(byte[] container, X509Certificate2 certificate)Verifies that an ASiC-E container has a valid signature of all its files, created with a certificate.
container- The container.
certificate- The certificate of the expected signer.
Returns. True if a signature of the container is valid for the certificate.
18.7 Namespace SignLib.Certificates
| Type | Description |
|---|---|
DigitalCertificate class | Loads, verifies and uses the certificates for signing: certificates from PFX files, from the Windows certificate store or from smart cards, and external signature providers (HSM, PKCS#11 modules, remote signing services). |
Extensions class | Extensions of the certificates created by X509CertificateGenerator: key usages, enhanced key usages, CRL distribution points, Authority Information Access, certificate policies, QC statements and the path length constraint of the CA certificates. |
IExternalSignature interface | An external signature provider (e.g. |
QualifiedCertificateStatements class | QCStatements extension of a certificate (ETSI EN 319 412-5). |
X509CertificateGenerator class | Generates X.509 certificates (RSA or ECDSA keys): self-signed certificates, certificates issued by a root (CA) certificate, and certificates issued for a certificate signing request (CSR). |
CertificateEnhancedKeyUsage enum | Enhanced (extended) key usages of a certificate (the extended key usage extension, RFC 5280 4.2.1.12). |
CertificateKeyUsage enum | Key usages of a certificate (the key usage extension, RFC 5280 4.2.1.3). |
CertificateStatus enum | Status of a certificate, returned by DigitalCertificate.VerifyDigitalCertificate. |
DigitalCertificateSearchCriteria enum | Criterion used to find a certificate in the Windows certificate store (e.g. |
EllipticCurve enum | Elliptic curve of an ECDSA key pair (named curves, RFC 5480 and RFC 5639). |
KeyAlgorithm enum | Algorithm of the key pair generated by X509CertificateGenerator. |
KeySize enum | Size of an RSA key pair, in bits. |
QcSemanticsIdentifier enum | Semantics identifier of the serialNumber or organizationIdentifier of the subject (ETSI EN 319 412-1). |
QualifiedCertificateType enum | Type of a qualified certificate (QcType statement, ETSI EN 319 412-5). |
SignatureAlgorithm enum | Algorithm of the certificate signature. |
SubjectAlternativeNameType enum | Type of a Subject Alternative Name. |
SubjectType enum | Attribute types of the subject of a certificate (see X509CertificateGenerator.AddToSubject). |
VerificationType enum | Type of the verification of a certificate (see DigitalCertificate.VerifyDigitalCertificate). |
DigitalCertificate class
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public class DigitalCertificate
Loads, verifies and uses the certificates for signing: certificates from PFX files, from the Windows certificate store or from smart cards, and external signature providers (HSM, PKCS#11 modules, remote signing services).
Fields
public static int TimeoutThe timeout, in milliseconds, of the download of a CRL, of an OCSP response and of the other downloads of the library (e.g. a PDF document loaded from a URL). The default value is 20000 (20 seconds).
Properties
public static string SmartCardPin { get; set; }Gets or sets the PIN of the signing certificate stored on a smart card. Some smart cards do not support this feature. The value is thread-local: it must be set on the thread that creates the signature.
public static IExternalSignature UseExternalSignatureProvider { set; }Sets an external signature provider (e.g. a PKCS#11 module or an HSM) for the next signature created on the same thread by PdfSignature, CadesSignature, XmlSignature, XadesSignature or AsicSignature. The signing certificate (DigitalSignatureCertificate) needs no private key. The provider is thread-local and it is released at the end of the signing operation (also when the operation fails).
Methods
public static DateTime GetCertificateRevocationDate(X509Certificate2 certificate)Gets the revocation date of a revoked certificate, from its CRL.
certificate- The revoked certificate.
Returns. The revocation date, in local time.
Exceptions.
CryptographicException: The certificate has no CRL, or it is not in its CRL.
public static List<CertificateKeyUsage> GetKeyUsage(X509Certificate2 certificate)Gets the key usages of a certificate.
certificate- The certificate.
Returns. The key usages, or null when the certificate has no key usage extension.
public static bool IsQualifiedCertificate(X509Certificate2 certificate)Gets a value indicating whether a certificate declares itself as a qualified certificate: it has the qcStatements extension (1.3.6.1.5.5.7.1.3, ETSI EN 319 412-5). The qualified status itself is given by the EU Trusted Lists.
certificate- The certificate.
Returns. True if the certificate has the qcStatements extension.
public static X509Certificate2 LoadCertificate()Loads a certificate from the certificate store of the current user. When more certificates match, the user selects one.
Returns. The certificate, or null when no certificate is selected.
public static X509Certificate2 LoadCertificate(string certificateSubject)Loads a certificate from the certificate store of the current user, by subject name. When more certificates match, the user selects one.
certificateSubject- The subject name of the certificate. Use "" for all the certificates.
Returns. The certificate, or null when no certificate is selected.
public static X509Certificate2 LoadCertificate(byte[] certificate, string password)Loads a certificate from the content of a PFX (PKCS#12) file. Dispose the certificate when it is not needed anymore: on .NET Framework, its private key is then deleted from the temporary key container.
certificate- The content of the PFX file.
password- The password of the PFX file.
Returns. The certificate, with its private key.
Exceptions.
CryptographicException: The certificate cannot be loaded.
public static X509Certificate2 LoadCertificate(string certificateFile, string password)Loads a certificate from a PFX (PKCS#12) file.
certificateFile- The path of the PFX file.
password- The password of the PFX file.
Returns. The certificate, with its private key.
Exceptions.
CryptographicException: The certificate cannot be loaded.FileNotFoundException: The file does not exist.
public static X509Certificate2 LoadCertificate(bool validOnly, DigitalCertificateSearchCriteria selectionType, string searchString)Gets, without user intervention, the first certificate of the certificate store of the current user that matches a criterion.
validOnly- True to use only valid certificates.
selectionType- The criterion (a field of the subject, the thumbprint or the serial number).
searchString- The value searched for.
Returns. The certificate, or null when no certificate matches.
public static X509Certificate2 LoadCertificate(bool validOnly, string issuerName, string windowTitle, string windowDescription)Loads a certificate from the certificate store of the current user, by issuer name. When more certificates match, the user selects one.
validOnly- True to use only valid certificates.
issuerName- The issuer name. Use "" for any issuer.
windowTitle- The title of the certificate selection window.
windowDescription- The description of the certificate selection window.
Returns. The certificate, or null when no certificate is selected.
public static X509Certificate2 LoadCertificate(bool validOnly, DigitalCertificateSearchCriteria selectionType, string searchString, bool fromLocalMachine)Gets, without user intervention, the first certificate of the Windows certificate store that matches a criterion.
validOnly- True to use only valid certificates.
selectionType- The criterion (a field of the subject, the thumbprint or the serial number).
searchString- The value searched for.
fromLocalMachine- True to use the certificates of the local machine instead of the current user.
Returns. The certificate, or null when no certificate matches.
public static X509Certificate2 LoadCertificate(bool validOnly, DigitalCertificateSearchCriteria selectionType, string searchString, string smartCardPin)Gets, without user intervention, the first certificate of the certificate store of the current user that matches a criterion.
validOnly- True to use only valid certificates.
selectionType- The criterion (a field of the subject, the thumbprint or the serial number).
searchString- The value searched for.
smartCardPin- The PIN of the smart card, or null. When it is set, the PIN window does not appear.
Returns. The certificate, or null when no certificate matches.
public static X509Certificate2 LoadCertificate(string certificateSubject, string windowTitle, string windowDescription, bool fromLocalMachine, string smartCardPin)Loads a certificate from the Windows certificate store, by subject name. When more certificates match, the user selects one.
certificateSubject- The subject name of the certificate. Use "" for all the certificates.
windowTitle- The title of the certificate selection window.
windowDescription- The description of the certificate selection window.
fromLocalMachine- True to use the certificates of the local machine instead of the current user.
smartCardPin- The PIN of the smart card, or null. When it is set, the PIN window does not appear.
Returns. The certificate, or null when no certificate is selected.
public static X509Certificate2 LoadCertificate(bool validOnly, string issuerName, string windowTitle, string windowDescription, bool fromLocalMachine)Loads a certificate from the Windows certificate store, by issuer name. When more certificates match, the user selects one.
validOnly- True to use only valid certificates.
issuerName- The issuer name. Use "" for any issuer.
windowTitle- The title of the certificate selection window.
windowDescription- The description of the certificate selection window.
fromLocalMachine- True to use the certificates of the local machine instead of the current user.
Returns. The certificate, or null when no certificate is selected.
public static X509Certificate2 LoadCertificate(bool validOnly, string issuerName, string windowTitle, string windowDescription, string smartCardPin)Loads a certificate from the certificate store of the current user, by issuer name. When more certificates match, the user selects one.
validOnly- True to use only valid certificates.
issuerName- The issuer name. Use "" for any issuer.
windowTitle- The title of the certificate selection window.
windowDescription- The description of the certificate selection window.
smartCardPin- The PIN of the smart card, or null. When it is set, the PIN window does not appear.
Returns. The certificate, or null when no certificate is selected.
public static X509Certificate2 LoadCertificate(bool validOnly, DigitalCertificateSearchCriteria selectionType, string searchString, bool fromLocalMachine, string smartCardPin)Gets, without user intervention, the first certificate of the Windows certificate store that matches a criterion.
validOnly- True to use only valid certificates.
selectionType- The criterion (a field of the subject, the thumbprint or the serial number).
searchString- The value searched for.
fromLocalMachine- True to use the certificates of the local machine instead of the current user.
smartCardPin- The PIN of the smart card, or null. When it is set, the PIN window does not appear.
Returns. The certificate, or null when no certificate matches.
public static X509Certificate2 LoadCertificate(bool validOnly, string issuerName, string windowTitle, string windowDescription, bool fromLocalMachine, string smartCardPin)Loads a certificate from the Windows certificate store, by issuer name. When more certificates match, the user selects one.
validOnly- True to use only valid certificates.
issuerName- The issuer name. Use "" for any issuer.
windowTitle- The title of the certificate selection window.
windowDescription- The description of the certificate selection window.
fromLocalMachine- True to use the certificates of the local machine instead of the current user.
smartCardPin- The PIN of the smart card, or null. When it is set, the PIN window does not appear.
Returns. The certificate, or null when no certificate is selected.
public static CertificateStatus VerifyDigitalCertificate(X509Certificate2 certificate, VerificationType verificationType)Verifies a certificate: its validity period, or its revocation status with OCSP or with the CRL.
certificate- The certificate.
verificationType- The type of the verification.
Returns. The status of the certificate.
Exceptions.
CryptographicException: The certificate cannot be verified.
Extensions class
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public class Extensions
Extensions of the certificates created by X509CertificateGenerator: key usages, enhanced key usages, CRL distribution points, Authority Information Access, certificate policies, QC statements and the path length constraint of the CA certificates.
Constructors
public Extensions()Initializes a new instance of the Extensions class, without extensions.
Properties
public bool EnhancedKeyUsageIsCritical { get; set; }Gets or sets a value indicating whether the enhanced key usage extension is critical. The default value is false.
public bool KeyUsageIsCritical { get; set; }Gets or sets a value indicating whether the key usage extension is critical. The default value is false. The key usage extension of a CA certificate is always critical.
public int PathLengthConstraint { get; set; }Gets or sets the path length constraint of the Basic Constraints extension of a CA certificate (generated with isRootCertificate = true): the maximum number of intermediate CA certificates that may follow it in a certification path (0 = only end-entity certificates may be issued). The default value is -1 (no constraint). When a CA certificate is issued by a loaded root certificate, the value must be smaller than the path length constraint of the root certificate.
public QualifiedCertificateStatements QcStatements { get; set; }Gets or sets the QCStatements extension (ETSI EN 319 412-5) of the certificate. Nothing is added by default.
Methods
public void AddCaIssuersUrl(string caIssuersUrl)Adds the URL of the issuer certificate (CA Issuers, e.g. http://www.example.com/ca.cer) to the Authority Information Access extension of the certificate.
caIssuersUrl- The absolute URL of the issuer certificate.
Exceptions.
ArgumentException: The value is not an absolute URL.
public void AddCertificatePolicy(string policyOid)Adds a certificate policy (e.g. 0.4.0.194112.1.2 for QCP-n-qscd) to the Certificate Policies extension.
policyOid- The OID of the policy.
Exceptions.
ArgumentException: The OID is not valid.
public void AddCertificatePolicy(string policyOid, string cpsUrl, string userNotice)Adds a certificate policy, with optional policy qualifiers, to the Certificate Policies extension.
policyOid- The OID of the policy.
cpsUrl- The URL of the Certification Practice Statement (CPS qualifier), or null.
userNotice- The explicit text of a User Notice qualifier (at most 200 characters), or null.
Exceptions.
ArgumentException: The OID, the URL or the text of the user notice is not valid.
public void AddCrlDistributionPoint(string crlUrl)Adds a CRL distribution point (the URL of the CRL, e.g. http://crl.example.com/ca.crl) to the certificate.
crlUrl- The absolute URL of the CRL.
Exceptions.
ArgumentException: The value is not an absolute URL.
public void AddEnhancedKeyUsage(CertificateEnhancedKeyUsage enhancedKeyUsage)Adds an enhanced (extended) key usage to the certificate.
enhancedKeyUsage- The enhanced key usage.
Exceptions.
ArgumentException: The value is not a known enhanced key usage.
public void AddEnhancedKeyUsage(Oid extensionOID)Adds an enhanced (extended) key usage, given by its OID, to the certificate (e.g. 1.3.6.1.4.1.311.10.3.12).
extensionOID- The OID of the enhanced key usage.
public void AddKeyUsage(CertificateKeyUsage keyUsage)Adds a key usage to the certificate.
keyUsage- The key usage.
public void AddOcspUrl(string ocspUrl)Adds the URL of an OCSP responder to the Authority Information Access extension of the certificate.
ocspUrl- The absolute URL of the OCSP responder.
Exceptions.
ArgumentException: The value is not an absolute URL.
IExternalSignature interface
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public interface IExternalSignature
An external signature provider (e.g. a PKCS#11 module, an HSM or a remote signing service), set with DigitalCertificate.UseExternalSignatureProvider.
Methods
public byte[] ApplySignature(byte[] message, Oid hashAlgorithm)Signs a message: hashes it with the hash algorithm, then signs the hash with the private key of the signing certificate.
message- The data to sign: the DER encoded CMS signed attributes (PDF and CAdES signatures) or the canonicalized ds:SignedInfo (XML signatures: XMLDSig, XAdES, ASiC-E).
hashAlgorithm- The OID of the hash algorithm (e.g. 2.16.840.1.101.3.4.2.1 for SHA-256).
Returns. The signature value: PKCS#1 v1.5 for RSA; for ECDSA either the raw value r || s (as most PKCS#11 modules return it) or the DER SEQUENCE { r, s }. SignLib converts it to the form required by the signature format.
QualifiedCertificateStatements class
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public class QualifiedCertificateStatements
QCStatements extension of a certificate (ETSI EN 319 412-5). The statements declare the certificate as an EU qualified certificate; a certificate is recognized as qualified only when its issuer is a qualified trust service on an EU Trusted List. Nothing is added by default.
Properties
public bool QcCompliance { get; set; }Gets or sets a value indicating whether the certificate is an EU qualified certificate (QcCompliance statement). The default value is false.
public bool QcSscd { get; set; }Gets or sets a value indicating whether the private key resides in a qualified signature or seal creation device (QcSSCD statement). The default value is false.
public QualifiedCertificateType QcType { get; set; }Gets or sets the type of the qualified certificate (QcType statement). The default value is QualifiedCertificateType.None.
public int RetentionPeriod { get; set; }Gets or sets the number of years the registration information is kept after the certificate expires (QcRetentionPeriod statement). The default value is 0 (not added).
public QcSemanticsIdentifier SemanticsIdentifier { get; set; }Gets or sets the semantics identifier of the subject identifier (id-qcs-pkixQCSyntax-v2 statement). The default value is QcSemanticsIdentifier.None.
Methods
public void AddPdsLocation(string url, string language)Adds the location of a PKI Disclosure Statement (QcPDS statement).
url- The https URL of the PDS.
language- The language of the PDS, as an ISO 639-1 code (e.g. en).
Exceptions.
ArgumentException: The URL or the language is not valid.
X509CertificateGenerator class
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public class X509CertificateGenerator
Generates X.509 certificates (RSA or ECDSA keys): self-signed certificates, certificates issued by a root (CA) certificate, and certificates issued for a certificate signing request (CSR).
Constructors
public X509CertificateGenerator(string librarySerialNumberLicense)Initializes a new instance of the X509CertificateGenerator class.
librarySerialNumberLicense- The serial number provided to register the library.
Properties
public EllipticCurve EllipticCurve { get; set; }Gets or sets the elliptic curve of an ECDSA key pair. The default value is EllipticCurve.NistP256. Not used for RSA keys.
public Extensions Extensions { get; set; }Gets or sets the extensions of the certificate (key usages, CRL distribution points, policies, etc.).
public string FriendlyName { get; set; }Gets or sets the friendly name of the certificate in the PFX file. The default value is an empty string: the PFX file then gets a unique name, which Windows uses as the name of the key container when the certificate is installed in a certificate store.
public KeyAlgorithm KeyAlgorithm { get; set; }Gets or sets the algorithm of the generated key pair: RSA (default) or ECDSA.
public KeySize KeySize { get; set; }Gets or sets the size of an RSA key pair. The default value is KeySize.KeySize2048Bit. Not used for ECDSA keys (the size is given by X509CertificateGenerator.EllipticCurve). KeySize512Bit and KeySize1024Bit are obsolete (insecure).
public long SerialNumber { get; set; }Gets or sets the serial number of the certificate (a positive value). When it is not set, a random 128-bit serial number is generated.
public SignatureAlgorithm SignatureAlgorithm { get; set; }Gets or sets the hash algorithm of the certificate signature. The default value is SignatureAlgorithm.SHA256WithRSA. Only the hash algorithm is taken from this value: the signature is RSA or ECDSA according to the key of the issuer (the root certificate, or the certificate itself when it is self-signed), e.g. SHA256WithRSA with an ECDSA issuer creates an ecdsa-with-SHA256 signature.
public string Subject { get; set; }Gets or sets the subject of the certificate (e.g. "CN=John Doe, O=Company, C=RO"). The subject can also be built with X509CertificateGenerator.AddToSubject.
public string SubjectAlternativeNames { get; set; }Gets or sets the Subject Alternative Names, comma separated. The type of each name is detected from its value: an IPv4 or IPv6 address is added as iPAddress, an absolute URI (e.g. https://www.example.com/ or urn:...) as uniformResourceIdentifier, a value that contains '@' as rfc822Name (email) and any other value as dNSName. Use X509CertificateGenerator.AddSubjectAlternativeName to set the type explicitly (e.g. for an URI that contains a comma).
public DateTime ValidFrom { get; set; }Gets or sets the date, in local time, on which the certificate becomes valid. The default value is the current date and time.
public DateTime ValidTo { get; set; }Gets or sets the date, in local time, after which the certificate is no longer valid. The default value is X509CertificateGenerator.ValidFrom + 1 year (at most X509CertificateGenerator.ValidFrom + 30 days on the demo version).
Methods
public void AddSubjectAlternativeName(SubjectAlternativeNameType nameType, string value)Adds a Subject Alternative Name of the given type to the certificate (in addition to the names of the X509CertificateGenerator.SubjectAlternativeNames property).
nameType- The type of the name.
value- The name: a DNS name (e.g. www.example.com), an IPv4 or IPv6 address, an email address or an absolute URI.
Exceptions.
ArgumentException: The name is empty or it is not valid for its type.
public void AddToSubject(SubjectType subjectType, string subjectTypeValue)Adds an attribute to the subject of the certificate (e.g. E=email@email.com, L=My locality). The attributes are used when X509CertificateGenerator.Subject is not set, in the order in which they are added.
subjectType- The type of the attribute.
subjectTypeValue- The value of the attribute.
public byte[] GenerateCertificate(string PFXFilePassword)Generates a certificate and its key pair.
PFXFilePassword- The password of the generated PFX file.
Returns. The PFX file with the certificate and its private key.
Exceptions.
CryptographicException: The certificate cannot be generated.
public byte[] GenerateCertificate(string PFXFilePassword, bool isRootCertificate)Generates a certificate and its key pair.
PFXFilePassword- The password of the generated PFX file.
isRootCertificate- True to generate a CA certificate (a root certificate or, when a root certificate is loaded, an intermediate CA certificate).
Returns. The PFX file with the certificate, its private key and, when a root certificate is loaded, the root certificate.
Exceptions.
CryptographicException: The certificate cannot be generated.
public byte[] GenerateCertificateFromCSR(string CSR)Issues a certificate for a certificate signing request (CSR), signed by the loaded root certificate.
CSR- The certificate signing request (PKCS#10), PEM encoded.
Returns. The DER encoded certificate.
Exceptions.
CryptographicException: The CSR is not valid or no root certificate is loaded.
public void LoadRootCertificate(byte[] RootPFXCertificate, string PFXFilePassword)Loads the root (CA) certificate used to sign the generated certificates.
RootPFXCertificate- The content of the PFX file of the root certificate.
PFXFilePassword- The password of the PFX file.
Exceptions.
CryptographicException: The PFX file has no private key or no certificate chain.
CertificateEnhancedKeyUsage enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum CertificateEnhancedKeyUsage
Enhanced (extended) key usages of a certificate (the extended key usage extension, RFC 5280 4.2.1.12).
| Member | Value | Description |
|---|---|---|
AnyPurpose | 0 | Any extended key usage. |
ClientAuthentication | 1 | TLS client authentication. |
CodeSigning | 2 | Code signing. |
SecureEmail | 3 | Email protection (S/MIME). |
IpsecEndSystem | 4 | IPsec end system. |
IpsecTunnel | 5 | IPsec tunnel. |
IpsecUser | 6 | IPsec user. |
OcspSigning | 7 | Signing of OCSP responses. |
ServerAuthentication | 8 | TLS server authentication. |
SmartcardLogon | 9 | Windows smart card logon. |
TimeStamping | 10 | Signing of RFC 3161 time-stamps. |
DocumentSigning | 11 | Document signing (Microsoft, 1.3.6.1.4.1.311.10.3.12). |
NetscapeServerGatedCrypto | 12 | Netscape Server Gated Crypto (nsSGC), a legacy step-up of the encryption of old browsers. |
MicrosoftServerGatedCrypto | 13 | Microsoft Server Gated Crypto (msSGC), a legacy step-up of the encryption of old browsers. |
CertificateKeyUsage enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum CertificateKeyUsage
Key usages of a certificate (the key usage extension, RFC 5280 4.2.1.3).
| Member | Value | Description |
|---|---|---|
DataEncipherment | 16 | The public key is used to encipher user data, other than cryptographic keys. |
DigitalSignature | 128 | The public key is used to verify digital signatures, other than signatures on certificates and CRLs (e.g. authentication). |
KeyEncipherment | 32 | The public key is used for key transport (not allowed for ECDSA keys). |
NonRepudiation | 64 | The public key is used to verify digital signatures that provide a non-repudiation service (content commitment), e.g. the signatures of documents. |
CRLSigning | 2 | The public key is used to verify the signatures of CRLs. |
CertificateSigning | 4 | The public key is used to verify the signatures of certificates. |
KeyAgreement | 8 | The public key is used for key agreement. |
EncipherOnly | 1 | With KeyAgreement: the public key may be used only to encipher data while performing key agreement. |
DecipherOnly | 32768 | With KeyAgreement: the public key may be used only to decipher data while performing key agreement. |
CertificateStatus enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum CertificateStatus
Status of a certificate, returned by DigitalCertificate.VerifyDigitalCertificate.
| Member | Value | Description |
|---|---|---|
Valid | 0 | The certificate is valid (in its validity period, or not revoked). |
Revoked | 1 | The certificate is revoked. |
Expired | 2 | The certificate is not in its validity period (expired or not yet valid). |
Unknown | 3 | The status cannot be determined (e.g. the OCSP responder or the CRL is not available). |
NotPresent | 4 | The certificate has no OCSP responder or no CRL. |
DigitalCertificateSearchCriteria enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum DigitalCertificateSearchCriteria
Criterion used to find a certificate in the Windows certificate store (e.g. CommonNameCN searches the CN= field of the subject).
| Member | Value | Description |
|---|---|---|
CommonNameCN | 0 | The "CN=" field of the subject. |
OrganizationO | 1 | The "O=" field of the subject. |
OrganizationUnitOU | 2 | The "OU=" field of the subject. |
EmailE | 3 | The "E=" field of the subject. |
LocalityL | 4 | The "L=" field of the subject. |
CountryC | 5 | The "C=" field of the subject. |
StateS | 6 | The "S=" field of the subject. |
TitleT | 7 | The "T=" field of the subject. |
Thumbprint | 8 | The thumbprint of the certificate. |
SerialNumber | 9 | The serial number of the certificate. |
EllipticCurve enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum EllipticCurve
Elliptic curve of an ECDSA key pair (named curves, RFC 5480 and RFC 5639).
| Member | Value | Description |
|---|---|---|
NistP256 | 0 | NIST P-256 (secp256r1, prime256v1), 256 bits. The most widely supported curve. |
NistP384 | 1 | NIST P-384 (secp384r1), 384 bits. |
NistP521 | 2 | NIST P-521 (secp521r1), 521 bits. |
BrainpoolP256r1 | 3 | Brainpool P-256r1 (RFC 5639), 256 bits. |
BrainpoolP384r1 | 4 | Brainpool P-384r1 (RFC 5639), 384 bits. |
BrainpoolP512r1 | 5 | Brainpool P-512r1 (RFC 5639), 512 bits. |
KeyAlgorithm enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum KeyAlgorithm
Algorithm of the key pair generated by X509CertificateGenerator.
| Member | Value | Description |
|---|---|---|
RSA | 0 | An RSA key, of the size set by X509CertificateGenerator.KeySize. |
ECDSA | 1 | An ECDSA key, on the curve set by X509CertificateGenerator.EllipticCurve. |
KeySize enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum KeySize
Size of an RSA key pair, in bits.
| Member | Value | Description |
|---|---|---|
KeySize512Bit obsolete | 512 | 512 bits. Obsolete: 512-bit RSA keys are insecure and are rejected by current validators. |
KeySize1024Bit obsolete | 1024 | 1024 bits. Obsolete: 1024-bit RSA keys are considered weak and are rejected by current validators. |
KeySize2048Bit | 2048 | 2048 bits. Recommended for user certificates. |
KeySize4096Bit | 4096 | 4096 bits. Recommended for CA certificates. |
KeySize8192Bit | 8192 | 8192 bits. |
QcSemanticsIdentifier enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum QcSemanticsIdentifier
Semantics identifier of the serialNumber or organizationIdentifier of the subject (ETSI EN 319 412-1).
| Member | Value | Description |
|---|---|---|
None | 0 | The semantics identifier is not added. |
NaturalPerson | 1 | Natural person identifier (id-etsi-qcs-semanticsId-Natural), e.g. serialNumber=PNORO-1234567890123. |
LegalPerson | 2 | Legal person identifier (id-etsi-qcs-semanticsId-Legal), e.g. organizationIdentifier=VATRO-12345678. |
EidasNaturalPerson | 3 | eIDAS natural person identifier (id-etsi-qcs-semanticsId-eIDASNatural). |
EidasLegalPerson | 4 | eIDAS legal person identifier (id-etsi-qcs-semanticsId-eIDASLegal). |
QualifiedCertificateType enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum QualifiedCertificateType
Type of a qualified certificate (QcType statement, ETSI EN 319 412-5).
| Member | Value | Description |
|---|---|---|
None | 0 | The QcType statement is not added. |
ESign | 1 | Certificate for electronic signatures (id-etsi-qct-esign). |
ESeal | 2 | Certificate for electronic seals (id-etsi-qct-eseal). |
Web | 3 | Certificate for website authentication (id-etsi-qct-web). |
SignatureAlgorithm enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum SignatureAlgorithm
Algorithm of the certificate signature. Only the hash algorithm is taken from this value: the signature is RSA or ECDSA according to the key of the issuer.
| Member | Value | Description |
|---|---|---|
SHA1WithRSA | 0 | SHA-1. Not recommended: SHA-1 is no longer considered secure for certificate signatures. |
SHA256WithRSA | 1 | SHA-256. |
SHA384WithRSA | 2 | SHA-384. |
SHA512WithRSA | 3 | SHA-512. |
SHA256WithECDSA | 4 | SHA-256 (ecdsa-with-SHA256 with an ECDSA issuer key). |
SHA384WithECDSA | 5 | SHA-384 (ecdsa-with-SHA384 with an ECDSA issuer key). |
SHA512WithECDSA | 6 | SHA-512 (ecdsa-with-SHA512 with an ECDSA issuer key). |
SubjectAlternativeNameType enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum SubjectAlternativeNameType
Type of a Subject Alternative Name.
| Member | Value | Description |
|---|---|---|
DnsName | 0 | DNS name (dNSName), e.g. www.example.com. |
IPAddress | 1 | IPv4 or IPv6 address (iPAddress). |
Email | 2 | Email address (rfc822Name). |
Uri | 3 | Absolute URI (uniformResourceIdentifier), e.g. https://www.example.com/. |
SubjectType enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum SubjectType
Attribute types of the subject of a certificate (see X509CertificateGenerator.AddToSubject).
| Member | Value | Description |
|---|---|---|
C | 0 | Country (C), a two-letter ISO 3166 code. |
E | 1 | Email address (E). |
L | 2 | Locality name (L). |
O | 3 | Organization name (O). |
T | 4 | Title (T). |
CN | 5 | Common name (CN). |
DC | 6 | Domain component (DC). |
OU | 7 | Organizational unit name (OU). |
ST | 8 | State or province name (ST). |
UID | 9 | User ID (UID, LDAP). |
STREET | 10 | Street address (STREET). |
PSEUDONYM | 11 | Pseudonym (RFC 3039). |
NAME | 12 | Name. |
EMAILADDRESS | 13 | Email address (PKCS#9 emailAddress, an IA5String). |
SERIALNUMBER | 14 | Serial number of the subject (SERIALNUMBER), e.g. PNORO-1234567890123. |
SURNAME | 15 | Surname. |
GIVENNAME | 16 | Given name. |
INITIALS | 17 | Initials. |
VerificationType enum
Namespace: SignLib.Certificates · Assembly: SignLib.dll
public enum VerificationType
Type of the verification of a certificate (see DigitalCertificate.VerifyDigitalCertificate).
| Member | Value | Description |
|---|---|---|
LocalTime | 0 | The validity period of the certificate, compared with the local time. |
OCSP | 1 | The revocation status from the OCSP responder of the certificate. |
CRL | 2 | The revocation status from the HTTP CRL of the certificate. |
LDAP | 3 | The revocation status from the LDAP CRL of the certificate (supported on Windows). |
18.8 Namespace SignLib.Timestamping
| Type | Description |
|---|---|
TimestampAccuracy class | Accuracy of the time of a time-stamp (RFC 3161 Accuracy): the time deviation around the time of the time-stamp. |
TimestampClient class | Creates RFC 3161 time-stamps for files and data: time-stamp responses (.TSR), time-stamp tokens (.TST) or Time Stamped Data files with the embedded content (.TSD, RFC 5544). |
TimestampInfo class | Information about a time-stamp: a time-stamp response (.TSR), a time-stamp token (.TST) or a Time Stamped Data file (.TSD, RFC 5544). |
TimestampSettings class | Settings of the time-stamping server (RFC 3161) used to time-stamp signatures and documents. |
TimestampFormat enum | Format of the time-stamps created by TimestampClient. |
TimestampAccuracy class
Namespace: SignLib.Timestamping · Assembly: SignLib.dll
public class TimestampAccuracy
Accuracy of the time of a time-stamp (RFC 3161 Accuracy): the time deviation around the time of the time-stamp. Each value is null when it is not set by the time-stamping server.
Properties
public string Microseconds { get; }Gets the microseconds of the accuracy.
public string Milliseconds { get; }Gets the milliseconds of the accuracy.
public string Seconds { get; }Gets the seconds of the accuracy.
TimestampClient class
Namespace: SignLib.Timestamping · Assembly: SignLib.dll
public class TimestampClient
Creates RFC 3161 time-stamps for files and data: time-stamp responses (.TSR), time-stamp tokens (.TST) or Time Stamped Data files with the embedded content (.TSD, RFC 5544).
Constructors
public TimestampClient(string librarySerialNumberLicense)Initializes a new instance of the TimestampClient class.
librarySerialNumberLicense- The serial number provided to register the library.
Properties
public TimestampFormat TimestampFormat { get; set; }Gets or sets the format of the result of TimestampClient.ObtainTimestamp. The default value is TimestampFormat.DetachedTimestamp (.TSR file).
public TimestampSettings TimeStamping { get; set; }Gets or sets the settings of the time-stamping server.
Methods
public byte[] ObtainTimestamp(byte[] dataToBeTimestamped)Time-stamps data.
dataToBeTimestamped- The data to time-stamp.
Returns. The time-stamp, in the format set by TimestampClient.TimestampFormat.
Exceptions.
WebException: The time-stamping server is not available or rejected the request.
public byte[] ObtainTimestamp(string fileToBeTimestamped)Time-stamps a file.
fileToBeTimestamped- The path of the file to time-stamp.
Returns. The time-stamp, in the format set by TimestampClient.TimestampFormat. A .TSD file also contains the content and the name of the file.
Exceptions.
WebException: The time-stamping server is not available or rejected the request.
TimestampInfo class
Namespace: SignLib.Timestamping · Assembly: SignLib.dll
public class TimestampInfo
Information about a time-stamp: a time-stamp response (.TSR), a time-stamp token (.TST) or a Time Stamped Data file (.TSD, RFC 5544).
Constructors
public TimestampInfo(byte[] timestampToken)Initializes a new instance of the TimestampInfo class from a time-stamp token.
timestampToken- The encoded time-stamp token (RFC 3161 TimeStampToken).
Properties
public TimestampAccuracy Accuracy { get; }Gets the accuracy of the time of the time-stamp.
public Oid HashAlgorithm { get; }Gets the hash algorithm of the time-stamped data (SHA-1, SHA-256, etc.).
public bool IsQualifiedTimestamp { get; }Gets a value indicating whether the time-stamp token declares itself as a qualified electronic time-stamp (ETSI EN 319 422): the qcStatements extension (1.3.6.1.5.5.7.1.3) of TSTInfo contains the esi4-qtstStatement-1 statement (0.4.0.19422.1.1). The qualified status itself is given by the EU Trusted Lists: a qualified time-stamping server may issue time-stamps without this statement.
public bool IsTimestampAltered { get; }Gets a value indicating whether the signature of the time-stamp token is not valid (the token was altered).
public string Nonce { get; }Gets the nonce of the time-stamp request, or null when the request had no nonce.
public byte[] OriginalDataHash { get; }Gets the hash of the time-stamped data (the message imprint of the time-stamp).
public Oid Policy { get; }Gets the policy of the time-stamping server (e.g. 1.3.6.1.4.1.13762.3).
public string SerialNumber { get; }Gets the serial number of the time-stamp.
public DateTime SignatureTime { get; }Gets the time of the time-stamp, in UTC.
public byte[] TimestampedDataContent { get; }Gets, for a Time Stamped Data file (.TSD), the original (time-stamped) content embedded in the file, or null when the content is not embedded.
public string TimestampedDataFileName { get; }Gets, for a Time Stamped Data file (.TSD), the original file name, or null when it is not set.
public byte[] TimestampToken { get; }Gets the time-stamp token.
public X509Certificate2 TsaCertificate { get; }Gets the certificate of the time-stamping server (the certificate that signed the time-stamp token), or null when the token does not contain it.
public string TsaServerName { get; }Gets the name of the time-stamping server, or null when it is not set in the time-stamp.
Methods
public static TimestampInfo GetInfoFromTsaResponse(byte[] timestampToken)Reads a time-stamp file: a time-stamp response (.TSR), a time-stamp token (.TST) or a Time Stamped Data file (.TSD, RFC 5544). For a .TSD file, TimestampInfo.TimestampedDataContent and TimestampInfo.TimestampedDataFileName are also set.
timestampToken- The content of the time-stamp file.
Returns. The information about the time-stamp.
public static bool IsTsaReponseFileValid(byte[] originalFile, byte[] timestampToken)Verifies a time-stamp file: a time-stamp response (.TSR), a time-stamp token (.TST) or a Time Stamped Data file (.TSD). If the file was changed or the time-stamp is altered, an exception is thrown.
originalFile- The original (time-stamped) file. For a .TSD file that contains the original content it can be null; when it is set, it must be identical with the embedded content.
timestampToken- The content of the time-stamp file.
Returns. True if the time-stamp is valid.
Exceptions.
CryptographicException: The time-stamp is altered or it does not match the original file.
TimestampSettings class
Namespace: SignLib.Timestamping · Assembly: SignLib.dll
public class TimestampSettings
Settings of the time-stamping server (RFC 3161) used to time-stamp signatures and documents.
Constructors
public TimestampSettings()Initializes a new instance of the TimestampSettings class.
Properties
public X509Certificate2 AuthenticationCertificate { get; set; }Gets or sets the certificate used for TLS client authentication to the time-stamping server, or null.
public HashAlgorithm HashAlgorithm { get; set; }Gets or sets the hash algorithm of the time-stamp request. The default value is SHA256.
public string Password { get; set; }Gets or sets the password for the HTTP basic authentication to the time-stamping server.
public Oid PolicyOid { get; set; }Gets or sets the policy requested from the time-stamping server. Set it only when the server requires it.
public int ServerTimeout { get; set; }Gets or sets the timeout of the time-stamping server, in milliseconds. The default value is 20000 milliseconds (20 seconds).
public Uri ServerUrl { get; set; }Gets or sets the URL of the time-stamping server (e.g. https://ca.signfiles.com/tsa/get.aspx).
public bool UseNonce { get; set; }Gets or sets a value indicating whether a nonce is added to the time-stamp request, to match the response with the request. The default value is true.
public string UserName { get; set; }Gets or sets the user name for the HTTP basic authentication to the time-stamping server, or null.
TimestampFormat enum
Namespace: SignLib.Timestamping · Assembly: SignLib.dll
public enum TimestampFormat
Format of the time-stamps created by TimestampClient.
| Member | Value | Description |
|---|---|---|
DetachedTimestamp | 0 | The time-stamp response (RFC 3161 TimeStampResp) is saved in a separate file (.TSR file). |
EmbeddedTimestamp | 1 | The time-stamp is saved together with the original file, in the Time Stamped Data format of RFC 5544 (.TSD file). The original file name is saved in the MetaData of the file. |
TimestampToken | 2 | Only the time-stamp token (RFC 3161 TimeStampToken, a CMS SignedData) is saved in a separate file (.TST file), without the response status. This is the detached time-stamp format accepted by validators like EU DSS. Italian verifiers (e.g. VOL of Consiglio Nazionale del Notariato) expect a .TSR (TimestampFormat.DetachedTimestamp) or a .TSD (TimestampFormat.EmbeddedTimestamp) file instead. |
Appendix A. Default values and limits
A.1 Default values of the settings
The values that a property has until you set it:
| Class | Defaults |
|---|---|
PdfSignature | SignatureStandard = Default (PKCS#7); HashAlgorithm = SHA256; PadesLtvLevel = IncludeOcspOnly; CertifySignature = NotCertified; VisibleSignature = true; SignaturePosition = TopRight (a rectangle of 100 × 50 points, 50 points from the edges); SignaturePage = 1; SignaturePages empty; SignatureAppearsOnAllPages = false; SignatureImageType = ImageAndText; FontName = Helvetica; OldStyleAdobeSignature = false; no encryption; no time-stamp (TimeStamping.ServerUrl = null). |
CadesSignature | SignatureStandard = CadesBes; HashAlgorithm = SHA256; IsDetachedSignature = false; MaxCrlSize 20 MB; no time-stamp. |
XmlSignature | HashAlgorithm = SHA256; SignatureType = Default (Canonical XML 1.0); IncludeKeyInfo = true; IncludeSignatureCertificate = true; PreserveWhitespace = true. |
XadesSignature | SignatureStandard = XadesB; SignaturePackaging = Enveloped; HashAlgorithm = SHA256; LtvLevel = IncludeOcspOnly; MaxCrlSize 1 MB; CommitmentType = None; no production place; no policy; no time-stamp. |
OfficeSignature | SignatureStandard = XadesB; HashAlgorithm = SHA256; LtvLevel = IncludeOcspOnly; MaxCrlSize 1 MB; CommitmentType = None; SignatureLine = null (invisible). |
AsicSignature | SignatureStandard = XadesB; HashAlgorithm = SHA256; LtvLevel = IncludeOcspOnly; MaxCrlSize 1 MB; CommitmentType = None. |
TimestampSettings | UseNonce = true; HashAlgorithm = SHA256; ServerTimeout = 20000 ms; no server, no authentication, no policy. |
TimestampClient | TimestampFormat = DetachedTimestamp (.tsr). |
DigitalCertificate | Timeout = 20000 ms (the downloads of the CRLs, of the OCSP responses and of documents). |
X509CertificateGenerator | ValidFrom = now; ValidTo = one year later (30 days in the demo version); KeyAlgorithm = RSA; KeySize = KeySize2048Bit; EllipticCurve = NistP256; random 128-bit serial number; no extensions. |
PdfEncrypt, PdfEncryptionSettings | EncryptionMethod = NoEncryption. |
A.2 Limits and what is not supported
| Area | Limit in SignLib 8.3 |
|---|---|
| Hash algorithms | SHA-1, SHA-256, SHA-384, SHA-512. SHA-1 does not create new XML, XAdES, Office and ASiC-E signatures (it verifies them). |
| Key types | RSA and ECDSA for signing. XML, XAdES, Office and ASiC-E: RSA and ECDSA only. RSA signatures are PKCS#1 v1.5 (not PSS). |
| PDF encryption | RC4 40/128 bit and AES-128. AES-256 (PDF 2.0) is not supported. A signed document cannot be encrypted by PdfSignature. |
| PDF signature formats | PKCS#7 detached, PAdES B-B, B-LT, B-LTA; document time-stamps. A document has one certification signature, the first. |
| CAdES | All the levels of CadesSignatureStandard. No method adds an archive time-stamp to an existing CAdES-A signature. |
| XAdES | B-B, B-T, B-LT, B-LTA, enveloped and detached. |
| Office | Office Open XML documents; levels B, T, LT (not LTA). Visible signatures: Word documents, Windows only. XPS is not supported. |
| ASiC-E | XAdES signatures. CAdES signature files in a container are not supported. At most 65535 files and 4 GB. |
| Time-stamps | RFC 3161 over HTTP or HTTPS; the formats .tsr, .tst and .tsd. |
| Threads | The signature objects are not thread-safe; UseExternalSignatureProvider and SmartCardPin are thread-local. |
| Memory | The documents are processed in memory: the memory needed is a multiple of the size of the document. |
| Platforms | .NET Framework 4.6.2 and 4.8, .NET 8, .NET 9 and .NET 10. Windows-only functions: section 1.2. |
Appendix B. OIDs, URIs and standards
B.1 Identifiers that you meet in the API
| Identifier | Value |
|---|---|
Hash algorithms (OIDs of IExternalSignature.ApplySignature, of policies and of time-stamps) | SHA-1 1.3.14.3.2.26; SHA-256 2.16.840.1.101.3.4.2.1; SHA-384 2.16.840.1.101.3.4.2.2; SHA-512 2.16.840.1.101.3.4.2.3 |
PDF signature filters (/SubFilter) | adbe.pkcs7.detached (PdfSignatureStandard.Default); ETSI.CAdES.detached (Pades, PadesLT, PadesLTA); ETSI.RFC3161 (a document time-stamp) |
XMLDSig canonicalization (XmlSignatureType) | Default: http://www.w3.org/TR/2001/REC-xml-c14n-20010315; DefaultWithComments: the same with #WithComments; Exclusive: http://www.w3.org/2001/10/xml-exc-c14n#; ExclusiveWithComments: the same with WithComments |
| XML signature methods | http://www.w3.org/2001/04/xmldsig-more#rsa-sha256, rsa-sha384, rsa-sha512; http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256, ecdsa-sha384, ecdsa-sha512 |
| XML digest methods | http://www.w3.org/2001/04/xmlenc#sha256, http://www.w3.org/2001/04/xmldsig-more#sha384, http://www.w3.org/2001/04/xmlenc#sha512 |
XAdES commitment types (XadesCommitmentType) | http://uri.etsi.org/01903/v1.2.2#ProofOfOrigin, #ProofOfReceipt, #ProofOfDelivery, #ProofOfSender, #ProofOfApproval, #ProofOfCreation |
| CAdES unsigned attributes | signature-time-stamp 1.2.840.113549.1.9.16.2.14; complete-certificate-references ...2.21; complete-revocation-references ...2.22; certificate-values ...2.23; revocation-values ...2.24; escTimeStamp ...2.25; archive-time-stamp-v3 0.4.0.1733.2.4 |
Extended key usages (CertificateEnhancedKeyUsage) | DocumentSigning 1.3.6.1.4.1.311.10.3.12; SecureEmail 1.3.6.1.5.5.7.3.4; ClientAuthentication 1.3.6.1.5.5.7.3.2; ServerAuthentication 1.3.6.1.5.5.7.3.1; CodeSigning 1.3.6.1.5.5.7.3.3; TimeStamping 1.3.6.1.5.5.7.3.8; OcspSigning 1.3.6.1.5.5.7.3.9 |
| Qualified certificates and time-stamps | qcStatements extension 1.3.6.1.5.5.7.1.3; QCP-n-qscd policy 0.4.0.194112.1.2; qualified time-stamp statement (esi4-qtstStatement-1) 0.4.0.19422.1.1 |
| Public key algorithms | RSA 1.2.840.113549.1.1.1; id-ecPublicKey 1.2.840.10045.2.1 |
B.2 Standards and specifications
| Document | Topic |
|---|---|
| Regulation (EU) No 910/2014 (eIDAS), as amended | Electronic identification and trust services. |
| ETSI EN 319 142-1 / -2 | PAdES: PDF advanced electronic signatures. |
| ETSI EN 319 122-1 / -2 (and ETSI TS 101 733) | CAdES: CMS advanced electronic signatures. |
| ETSI EN 319 132-1 / -2 (and ETSI TS 101 903) | XAdES: XML advanced electronic signatures. |
| ETSI EN 319 162-1 / -2 | ASiC: associated signature containers. |
| ETSI EN 319 412-1 ... -5 | Certificate profiles (identifiers, QCStatements). |
| ETSI EN 319 421, ETSI EN 319 422 | Time-stamping policy and profiles (qualified time-stamps). |
| ISO 32000-1, ISO 32000-2 | PDF 1.7 and PDF 2.0. |
| RFC 5652; RFC 5126 | Cryptographic Message Syntax (CMS); CMS advanced electronic signatures. |
| RFC 3161; RFC 5544 | Time-stamp protocol; Time Stamped Data (.tsd). |
| RFC 5280; RFC 6960 | X.509 certificates and CRLs; OCSP. |
| RFC 8017; RFC 5753; RFC 5480; RFC 4051; RFC 6931 | PKCS#1 (RSA); ECDSA in CMS; EC keys in X.509; ECDSA in XML signatures. |
| W3C XML Signature Syntax and Processing; Canonical XML 1.0; Exclusive XML Canonicalization 1.0 | XMLDSig. |
| ECMA-376 Part 2 (Open Packaging Conventions); [MS-OFFCRYPTO] | Office package signatures. |
| PKCS #11 v2.40 | The interface of tokens and HSMs. |
Appendix C. Glossary
| Term | Meaning |
|---|---|
| AdES | Advanced electronic signature: the formats PAdES, CAdES, XAdES of ETSI. |
| Archive time-stamp | A time-stamp over a signature and its validation data; the last element of the LTA level; it is renewed periodically. |
| ASiC-E | Associated Signature Container, Extended: a ZIP file with files and their XAdES signatures. |
| Attached / detached / enveloped | Where the signed data is: attached, in the signature file (.p7m); detached, outside it (.p7s, a detached XAdES file); enveloped, the signature is inside the signed XML document. |
| B-B, B-T, B-LT, B-LTA | The baseline levels of AdES signatures: basic, with a time-stamp, with long term validation data, with archive time-stamps. |
| CA | Certification authority: issues certificates. |
| CAdES | CMS Advanced Electronic Signatures. |
| Canonicalization (C14N) | The conversion of an XML document to a standard byte sequence before it is signed. |
| CMS | Cryptographic Message Syntax (RFC 5652), the successor of PKCS#7. |
| Certification signature | The first signature of a PDF document, that says which changes are allowed later (DocMDP). |
| CRL | Certificate revocation list: the list of the certificates that the CA revoked. |
| CSR | Certificate signing request (PKCS#10): the request for a certificate, with the public key. |
| DER | Distinguished Encoding Rules: the binary encoding of the ASN.1 structures of certificates and signatures. |
| DSS | The Digital Signature Service of the European Commission (a validation library and web application); not the document security store of PDF. |
Document security store (/DSS) | The part of a PDF document that holds the certificates and the revocation data of the long term signatures. |
| eIDAS | Regulation (EU) 910/2014 on electronic identification and trust services. |
| HSM | Hardware security module: a device that keeps keys and signs with them. |
| Hash | The fixed-size digest of data (SHA-256, ...). A signature signs the hash. |
| LTV | Long term validation: the signature contains what is needed to validate it later. |
| Message imprint | The hash that a time-stamp covers. |
| Nonce | A random number in a time-stamp request, repeated in the response. |
| OCSP | Online Certificate Status Protocol: a server that answers whether a certificate is revoked. |
| OID | Object identifier: a dotted number that identifies an algorithm, a policy or an extension. |
| PAdES | PDF Advanced Electronic Signatures. |
| PFX / P12 / PKCS#12 | A file with a certificate, its private key and its chain, protected by a password. |
| PKCS#7 | The older name of CMS; the adbe.pkcs7.detached PDF signature is a CMS signature. |
| PKCS#11 (Cryptoki) | The programming interface of the tokens and HSMs. |
| QSCD | Qualified signature (or seal) creation device. |
| QES | Qualified electronic signature: with a qualified certificate, created in a QSCD. |
| Signature policy | A document that states the rules for the creation and the validation of a signature, identified by an OID and its hash. |
| Signature field | The form field of a PDF document that holds a signature. |
| Thumbprint | The SHA-1 hash of a certificate: a short identifier of it. |
| Time-stamp (.tsr, .tst, .tsd) | A signed proof of the time of some data, from a TSA: a response (.tsr), a token (.tst), or the data with its time-stamp (.tsd). |
| TSA | Time-stamping authority. |
| Trusted list | The list of qualified trust service providers that a member state of the EU publishes. |
| XAdES | XML Advanced Electronic Signatures. |
| XMLDSig | The W3C standard of XML signatures. |
Appendix D. Warning and disclaimer, licenses, trademarks
Every effort has been made to make this manual as complete and accurate as possible, but no warranty or fitness is implied. The information provided is on an “as is” basis. The author shall have neither liability nor responsibility to any person or entity with respect to any loss or damages arising from the information contained in this manual. The information about the eIDAS Regulation is a simplified explanation and it is not legal advice.
D.1 Third-party components
- The library includes parts of the Bouncy Castle Cryptographic C# API, which is distributed under the Bouncy Castle License (an MIT-style license, Copyright (c) 2000-2018 The Legion of the Bouncy Castle Inc., https://www.bouncycastle.org). The copyright notice and the license text must be included in the redistributions of that code.
- The library uses a modified version of iTextSharp 4.1.6, which is distributed under the Mozilla Public License 1.1 and the GNU Lesser General Public License. The changes made to iTextSharp 4.1.6 are described in the source distribution.
D.2 Trademarks
.NET, Windows, PowerShell, Visual Studio, Microsoft Office, Word, Excel, PowerPoint and Azure are trademarks of Microsoft Corporation. Adobe, Acrobat and Acrobat Reader are trademarks of Adobe Inc. All the other names are trademarks of their owners.