---
title: "Validate signatures - Rest PKI"
description: "Validating PAdES, CAdES and XML signatures with Rest PKI (legacy), for existing integrations: the signature explorers, validation policies, security contexts and the results per signer."
canonical: "https://docs.lacunasoftware.com/en-us/articles/rest-pki/validate-signatures"
locale: "en"
product: "Rest PKI (legacy)"
last_updated: "2026-10-12"
---

# Validate signatures - Rest PKI

> **Warning: Legacy product**
>
> Rest PKI is a legacy product: it still receives bug and security fixes, but new cloud integrations should use
> [Rest PKI Core](https://docs.lacunasoftware.com/en-us/articles/rest-pki/core), which also serves most Rest PKI APIs. This page is for existing Rest PKI integrations.
> See the [Rest PKI quick reference](https://docs.lacunasoftware.com/en-us/articles/rest-pki/quick-reference).

Your backend sends a signed file to [Rest PKI](https://docs.lacunasoftware.com/en-us/articles/rest-pki), which opens it, lists its signers and validates each signature. There is no
browser step. Rest PKI opens PDF signatures (PAdES), CMS/CAdES files (`.p7s`) and XML signatures. 

The code on this page is C#, from the [ASP.NET MVC samples project](https://docs.lacunasoftware.com/en-us/articles/rest-pki/dotnet/mvc), which uses `Lacuna.RestPki.Client` 1.24.1. 
The same samples exist for other languages: see [Samples availability](https://docs.lacunasoftware.com/en-us/articles/rest-pki/samples-availability).

## Flow

1. Create the `RestPkiClient` with your endpoint and access token (see the [quick reference](https://docs.lacunasoftware.com/en-us/articles/rest-pki/quick-reference)).
1. Create a `PadesSignatureExplorer`, `CadesSignatureExplorer` or `XmlSignatureExplorer`, and set `Validate = true`, the signature
   policy and the security context.
1. Pass the signed file with `SetSignatureFile()`.
1. Call `OpenAsync()` (for CAdES, `OpenAndExtractContentAsync()` to also get the signed content).
1. Read each signer's certificate, signing time and `ValidationResults`.

| Explorer | Endpoint | Response |
|---|---|---|
| `PadesSignatureExplorer` | `POST Api/PadesSignatures/Open` | `PadesSignatureModel` |
| `CadesSignatureExplorer` | `POST Api/CadesSignatures/Open` | `CadesSignatureModel` |
| `XmlSignatureExplorer` | `POST Api/XmlSignatures/Open` | a list of `XmlSignatureModel` |

## PDF signatures (PAdES)

The sample accepts any PAdES signature (`StandardPadesSignaturePolicies.Basic`) whose certificate the security context trusts: 

```cs
var sigExplorer = new PadesSignatureExplorer(Util.GetRestPkiClient()) {
	Validate = true,
	DefaultSignaturePolicyId = StandardPadesSignaturePolicies.Basic,
	SecurityContextId = Util.GetSecurityContextId()
};
sigExplorer.SetSignatureFile(userfilePath);
var signature = await sigExplorer.OpenAsync();
```

## CAdES signatures

The CAdES sample accepts the ICP-Brasil CAdES policies in `SignaturePolicyCatalog.GetPkiBrazilCades()` (AD-RB, AD-RT and AD-RC), and
also gets the signed content when the file carries it: 

```cs
var sigExplorer = new CadesSignatureExplorer(Util.GetRestPkiClient()) {
	Validate = true,
	AcceptableExplicitPolicies = SignaturePolicyCatalog.GetPkiBrazilCades(),
	SecurityContextId = Util.GetSecurityContextId(),
};
sigExplorer.SetSignatureFile(userfilePath);
var data = await sigExplorer.OpenAndExtractContentAsync();
var signature = data.Signature;
var encapsulatedContent = data.Signature.HasEncapsulatedContent ? data.EncapsulatedContent : null;
```

* `OpenAndExtractContentAsync()` sets `extractEncapsulatedContent` in the request. Rest PKI keeps the extracted content for one hour,
  and the client returns it as a file you can read with `GetContent()` or save with `WriteToFile()`. 
* Rest PKI doesn't report the content's file type: the sample assumes a PDF. 
* For a detached signature, the client also has `SetDataFile()`. 
  TODO(docs): no sample shows how to validate a detached CAdES signature.

## XML signatures

The XML sample accepts any XmlDSig signature (`StandardXmlSignaturePolicies.XmlDSigBasic`) whose certificate the security context
trusts. `OpenAsync()` returns a list, one item per signature in the document: 

```cs
var sigExplorer = new XmlSignatureExplorer(Util.GetRestPkiClient()) {
	Validate = true,
	DefaultSignaturePolicyId = StandardXmlSignaturePolicies.XmlDSigBasic,
	SecurityContextId = Util.GetSecurityContextId()
};
sigExplorer.SetSignatureFile(userfilePath);
var signatures = await sigExplorer.OpenAsync();
```

Each XML signature also has a `Type` (`FullXml`, `XmlElement` or `DetachedResource`) and the `SignedElement`. 

## Signature policies

Each signature is validated against a signature policy: 

* `DefaultSignaturePolicyId` validates the signatures that have no explicit policy, and those whose explicit policy is not in
  `AcceptableExplicitPolicies`. To accept only a list of explicit policies, leave it out.
* `AcceptableExplicitPolicies` lists the explicit policies to accept, such as the ICP-Brasil ones.
* A signature with no explicit policy, when no default is given, fails validation.

Standard policies are in `StandardPadesSignaturePolicies` (`Basic`, `BasicWithoutLtv`, `AdobeReader`), `StandardCadesSignaturePolicies`
(`CadesBes`, `CadesBesWithSigningTimeAndNoCrls`, `CmsPermissive`) and `StandardXmlSignaturePolicies` (`XadesBes`, `XmlDSigBasic`,
`CodSha1`, `CodSha256`), each with the ICP-Brasil policies nested under `PkiBrazil`; `SignaturePolicyCatalog` groups the ICP-Brasil
ones. 

## Security context

The security context decides which root certificates are trusted. 
The PAdES `Basic`, CAdES `CadesBes` and XML `XmlDSigBasic` and `XadesBes` policies need one, or the call fails with `SecurityContextRequired`; the ICP-Brasil policies bring their own, which a security context you pass replaces. 

| Security context | Trusts | Id |
|---|---|---|
| `StandardSecurityContexts.PkiBrazil` | ICP-Brasil roots | `201856ce-273c-4058-a872-8937bd547d36` |
| `StandardSecurityContexts.PkiItaly` | Italian PKI roots | `c438b17e-4862-446b-86ad-6f85734f0bfe` |
| `StandardSecurityContexts.WindowsServer` | Roots trusted by Windows | `3881384c-a54d-45c5-bbe9-976b674f5ec7` |
| `StandardSecurityContexts.LacunaTest` | ICP-Brasil, Windows and Lacuna test roots; development only | `803517ad-3bbc-4169-b085-60053a8f6dbf` |

The samples use `LacunaTest` in debug builds, to accept the [test certificates](https://docs.lacunasoftware.com/en-us/articles/pki-guide/test-certs), and `PkiBrazil` otherwise.
On an on-premises instance, `LacunaTest` may have to be created first (see [Enabling Lacuna Test Security Context](https://docs.lacunasoftware.com/en-us/articles/rest-pki/on-premises/test-security)). 

```cs
public static Guid GetSecurityContextId() {
#if DEBUG
	return StandardSecurityContexts.LacunaTest;
#else
	return Lacuna.RestPki.Api.StandardSecurityContexts.PkiBrazil;
#endif
}
```

Two more options relax validation: `IgnoreRevocationStatusUnknown` ignores errors due to an unknown revocation status (default `false`,
since Rest PKI 1.16.0), and `TrustUncertifiedSigningTime` takes the signer's signing time as the validation date reference (since
1.22.0). None of the samples sets them. 

## Read the results

* A PAdES or CAdES signature has `Signers`; each signer has its `Certificate`, `SigningTime`, `MessageDigest`, `SignaturePolicy`,
  `Timestamps` and `ValidationResults`. A PAdES signer also has `IsDocumentTimestamp` and `SignatureFieldName`. An XML signature has the
  same fields, without `MessageDigest`.
* `ValidationResults` has `IsValid`, `Errors`, `Warnings`, `PassedChecks` and `Summary`, and `ToString()` lists every check. It is
  filled only when `Validate` is `true`.

The sample's page shows, for each signer, the subject's common name, a "valid" or "invalid" badge from `ValidationResults.IsValid`, the
signing time, the message digest, the policy, the ICP-Brasil certificate fields and the full `ValidationResults.ToString()`. 

## Errors

* A file that is not a valid PDF, CAdES or XML fails with `InvalidPdf`, `InvalidCades` or `InvalidXml` (HTTP 422). See
  [Return codes](https://docs.lacunasoftware.com/en-us/articles/rest-pki/return-codes). 
* When an account limit is set and exceeded, Rest PKI answers HTTP 429 with the headers `X-RateLimit-Limit` and `X-RateLimit-Remaining`. 
* TODO(docs): how a signature with no acceptable policy is reported.

## See also

* [Certificate authentication](https://docs.lacunasoftware.com/en-us/articles/rest-pki/certificate-authentication)
* ASP.NET MVC samples project: [open PAdES](https://docs.lacunasoftware.com/en-us/articles/rest-pki/dotnet/mvc#open-pades), [open CAdES](https://docs.lacunasoftware.com/en-us/articles/rest-pki/dotnet/mvc#open-cades), [open XML](https://docs.lacunasoftware.com/en-us/articles/rest-pki/dotnet/mvc#open-xml)
* [Rest PKI quick reference](https://docs.lacunasoftware.com/en-us/articles/rest-pki/quick-reference)

**Demos and samples**

- Live demo: [Validate a signed file](https://try.lacunasoftware.com/en/pki-suite/validate-a-signed-file)
- Validate a signed PDF using Rest PKI: [.NET](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/dotnet/mvc/PkiSuiteAspNetMvcSample/Controllers/OpenPadesSignatureRestController.cs) · [Java](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/java/springmvc/src/main/java/com/lacunasoftware/pkisuite/controller/OpenPadesRestController.java) · [Node.js](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/nodejs/expressmvc/routes/open-pades-restpki.js) · [PHP](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/php/plain/public/open-pades-rest/index.php) · [Python](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/python/flask/sample/views/open_pades_rest.py) · [Ruby](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/ruby/rails/app/controllers/open_pades_rest_controller.rb)
- Validate a CMS/CAdES signature using Rest PKI: [.NET](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/dotnet/mvc/PkiSuiteAspNetMvcSample/Controllers/OpenCadesSignatureRestController.cs) · [Node.js](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/nodejs/expressmvc/routes/open-cades-restpki.js) · [PHP](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/php/plain/public/open-cades-rest/index.php)
- Validate a signed XML using Rest PKI: [.NET](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/dotnet/mvc/PkiSuiteAspNetMvcSample/Controllers/OpenXmlSignatureRestController.cs) · [Java](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/java/springmvc/src/main/java/com/lacunasoftware/pkisuite/controller/OpenXmlRestController.java) · [PHP](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/php/plain/public/open-xml-rest/index.php)
