Validate signatures - Rest PKI
Rest PKI is a legacy product: it still receives bug and security fixes, but new cloud integrations should use Rest PKI Core, which also serves most Rest PKI APIs. This page is for existing Rest PKI integrations. See the Rest PKI quick reference.
Your backend sends a signed file to 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, which uses Lacuna.RestPki.Client 1.24.1.
The same samples exist for other languages: see Samples availability.
Flow
- Create the
RestPkiClientwith your endpoint and access token (see the quick reference). - Create a
PadesSignatureExplorer,CadesSignatureExplorerorXmlSignatureExplorer, and setValidate = true, the signature policy and the security context. - Pass the signed file with
SetSignatureFile(). - Call
OpenAsync()(for CAdES,OpenAndExtractContentAsync()to also get the signed content). - 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:
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:
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()setsextractEncapsulatedContentin the request. Rest PKI keeps the extracted content for one hour, and the client returns it as a file you can read withGetContent()or save withWriteToFile().- 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:
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:
DefaultSignaturePolicyIdvalidates the signatures that have no explicit policy, and those whose explicit policy is not inAcceptableExplicitPolicies. To accept only a list of explicit policies, leave it out.AcceptableExplicitPolicieslists 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, and PkiBrazil otherwise.
On an on-premises instance, LacunaTest may have to be created first (see Enabling Lacuna Test Security Context).
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 itsCertificate,SigningTime,MessageDigest,SignaturePolicy,TimestampsandValidationResults. A PAdES signer also hasIsDocumentTimestampandSignatureFieldName. An XML signature has the same fields, withoutMessageDigest. ValidationResultshasIsValid,Errors,Warnings,PassedChecksandSummary, andToString()lists every check. It is filled only whenValidateistrue.
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,InvalidCadesorInvalidXml(HTTP 422). See Return codes. - When an account limit is set and exceeded, Rest PKI answers HTTP 429 with the headers
X-RateLimit-LimitandX-RateLimit-Remaining. - TODO(docs): how a signature with no acceptable policy is reported.
See also
- Certificate authentication
- ASP.NET MVC samples project: open PAdES, open CAdES, open XML
- Rest PKI quick reference