Digital signatures for .NET
PAdES · CAdES · XAdES — sign, validate, inspect.
SimpleSign creates and validates PAdES (ETSI EN 319 142), CAdES (ETSI EN 319 122) and XAdES (ETSI EN 319 132) signatures.
- All cryptography uses
System.Security.Cryptography: no BouncyCastle, no third-party crypto. - Native AOT compatible; .NET 8 and .NET 10 on Windows, macOS and Linux.
- MIT licensed.
dotnet add package SimpleSign # PAdES + CAdES + XAdES
dotnet add package SimpleSign.Brazil.IcpBrasil # ICP-Brasil, Lei 14.063
dotnet add package SimpleSign.Brazil.GovBr # Gov.br
dotnet add package SimpleSign.Peru.Iofe # IOFE (Peru), INDECOPI policies
dotnet add package SimpleSign.Signers.Pkcs11 # A3 tokens, smartcards, HSMs
dotnet add package SimpleSign.Signers.Cloud # cloud certificates (PSC, CSC v2)
dotnet tool install -g SimpleSign.Cli # command line| Package | What it does |
|---|---|
SimpleSign |
Meta-package: PAdES, CAdES and XAdES |
SimpleSign.PAdES |
PDF signing, validation and inspection (B-B/T/LT/LTA) |
SimpleSign.CAdES |
Standalone CMS/PKCS#7 signatures |
SimpleSign.XAdES |
XML signatures; ETSI trusted lists (TrustedList) |
SimpleSign.Core |
CMS, TSA, OCSP, CRL (HTTP; LDAP opt-in), signing and validation policies, trust store (used by the above) |
SimpleSign.Brazil.IcpBrasil |
ICP-Brasil chain, roots and policies, Lei 14.063 |
SimpleSign.Brazil.GovBr |
Gov.br chain and assurance level, Lei 14.063 |
SimpleSign.Brazil |
Shared: CPF/CNPJ, Lei 14.063 levels, AEA manifest (pulled in by both) |
SimpleSign.Peru.Iofe |
IOFE (Ley 27269): anchors from INDECOPI's signed trusted list, INDECOPI signing and validation policies |
SimpleSign.Brazil.Fiscal |
XML-DSig for NF-e, CT-e, MDF-e, NFS-e, eSocial, EFD-Reinf |
SimpleSign.Signers.Pkcs11 |
Sign through a token's PKCS#11 driver |
SimpleSign.Signers.Cloud |
Sign with cloud certificates (ICP-Brasil PSCs, CSC API v2) |
SimpleSign.HtmlToPdf |
Pure .NET HTML→PDF (independent of signing) |
Sign a PDF with a .pfx file:
using SimpleSign.PAdES;
await PadesSigner.SignFileAsync("contract.pdf", "contract-signed.pdf", "me.pfx", password);With the fluent builder (PAdES B-LT, with a timestamp and revocation data):
using SimpleSign.Core.Signing;
using SimpleSign.PAdES;
var signedPdf = await PadesSigner
.Document(pdfBytes)
.WithCertificate(certificate)
.WithLevel(AdesBaselineProfile.LongTerm(TimestampOptions.DigiCert, new LongTermValidationOptions()))
.SignAsync();Before anything is signed, the default SigningPolicy refuses a certificate without the digitalSignature or
nonRepudiation key usage, an RSA key under 2048 bits, an expired certificate in the chain and SHA-1/MD5.
Policies are JSON files (SigningPolicy.Load, ValidationPolicy.Load) with a level per constraint (FAIL, WARN,
INFORM, IGNORE): a signing policy with NotRevoked and RevocationDataAvailable at FAIL also checks the revocation of
the whole chain, and ValidationPolicy.Default is the validation policy SimpleSign recommends (ADR 0024).
Validate:
using SimpleSign.Core.Validation;
using SimpleSign.PAdES.Validation;
var validator = new PdfSignatureValidator(new ValidationOptions { CheckRevocation = true, TrustSystemRoots = true });
foreach (var r in await validator.ValidateAsync(File.OpenRead("signed.pdf")))
{
Console.WriteLine($"{r.FieldName}: {r.Indication} {r.SubIndication} — {r.SignerName} at {r.SigningTime}");
}Each result carries the ETSI EN 319 102-1 indication and sub-indication and the list of checks (Constraints);
ValidationOptions.Policy (ValidationPolicy.Load("policy.json")) sets the accepted algorithms, key sizes and key usage.
CAdES and XAdES use the same builder and profiles:
byte[] p7s = await CadesSigner.Document(data).WithCertificate(certificate).SignAsync();
byte[] xml = await XadesSigner.Document(xmlBytes).WithCertificate(certificate).SignAsync();Sign with a key that is not in memory (token, HSM, cloud, browser) through IExternalSigner:
using var token = Pkcs11Signer.Open(new Pkcs11SignerOptions { LibraryPath = "/usr/lib/libeToken.so", Pin = pin });
var signedPdf = await PadesSigner.Document(pdfBytes)
.WithExternalSigner(token.Certificate, token, token.Chain)
.SignAsync();| Guide | |
|---|---|
| Getting started | First signature, validation, appearance |
| PAdES signing | Levels, appearance, batch, TSA pool, logging |
| CAdES and XAdES | Detached/enveloped CMS, XML forms, validation |
| Inspection and validation | Validation results and fast inspection |
| Deferred signing | Two-phase signing for web apps |
| Remote signing | The generic interface for keys outside the engine |
| PKCS#11 / Cloud signing | Tokens, HSMs and cloud certificates |
| HTML to PDF | The layout engine |
| ICP-Brasil / Fiscal XML | Brazilian PKI and NF-e/eSocial signing |
| CLI | simplesign sign, validate, cades, xades… |
| Signing agent / TestBench | Tray app with a local signing API; local web app to try every option |
| Standard coverage | Every option with the clause that defines it, and what is not implemented |
| Conformance / ADRs | Standards coverage and design decisions |
| Sandbox | A test PKI with real CRL (HTTP, HTTPS, LDAP), OCSP, TSA and CSC endpoints and failures to switch on |
| Playbook | Runs a playbook of CLI commands against a Sandbox, checks each result and records the runs |
ITrustAnchorProvider (trust roots; DirectoryTrustAnchorProvider and TrustedList are ready-made),
IChainValidationProvider (chain rules), IExternalSigner (remote keys), IHttpClientProvider (TSA/OCSP/CRL HTTP),
IChainRevocationChecker and IRevocationCache (revocation of a chain), ICertificateCache, ICertificateStore
and ICountryExtension (country packages such as SimpleSign.Brazil.IcpBrasil and SimpleSign.Peru.Iofe).
See CONTRIBUTING.md, SECURITY.md and the changelog. If SimpleSign is useful to you, consider sponsoring the project.