Security contexts and signature policies - Rest PKI Core
When it signs or validates, Rest PKI Core answers two independent questions:
| Security context | Signature policy | |
|---|---|---|
| Question | Whom to trust? | How must the signature be made, or have been made? |
| Decides | Which roots the signer's certificate chain must end at | The format (PAdES, CAdES, XML), the required and forbidden attributes, the accepted algorithms, the timestamp and the LTV data |
| Examples | PkiBrazil, GovBR, PkiBrazilWithGovBrAndENotariado, a security context created on the dashboard | PAdES basic, ICP-Brasil AD-RB, Adobe Reader |
| Parameter | securityContextId | signaturePolicyId, defaultSignaturePolicyId and acceptableExplicitPolicies, on the Rest PKI routes only |
A signature is valid only when both checks pass: the certificate must be trusted in the security context, and the signature must follow the policy. Neither replaces the other. Changing the policy doesn't make Rest PKI Core trust more certificates, and changing the security context doesn't make it accept a format the policy rejects.
Whether a signature is qualified doesn't depend on the policy either: it depends on the certificate. A signature made with an ICP-Brasil certificate is qualified even if it doesn't follow the ICP-Brasil PAdES standard. The policy only decides whether that format is accepted.
See Security contexts for the standard security contexts and for creating your own.
An example: a signature made in Adobe Acrobat
A PDF signed in Adobe Acrobat with an ICP-Brasil certificate, validated with the PAdES basic policy and the PkiBrazil security context, may
come back with this error:
"errors": [
{
"type": "RequiredSignedAttributeMissing",
"message": "A required signed attribute is missing",
"detail": "signing-certificate",
"innerValidationResults": null
}
]
The certificate is fine: its chain ends at the ICP-Brasil root, which the PkiBrazil security context trusts. The format is what fails. PAdES
requires the signing-certificate signed attribute, and Acrobat's default signature format (adbe.pkcs7.detached) doesn't include it. To
accept this PDF, keep the security context and switch the policy to Adobe Reader.
How they work together in each API
Rest PKI routes
On the Rest PKI routes that Rest PKI Core serves, you choose the policy. That applies to starting a PAdES
signature (Api/PadesSignatures) and to validation (Api/PadesSignatures/Open, which the client libraries' PadesSignatureExplorer calls):
- With
securityContextId: the security context decides whom to trust, and the policy decides the rest. The security context replaces the roots the policy brings, the ICP-Brasil policies included. - Without
securityContextId: the policy's trust applies. The ICP-Brasil policies trust ICP-Brasil. The others trust no root, and the call fails withSecurityContextRequired.
Rest PKI Core APIs
Signature sessions, two-step signatures and signature inspection take no policy:
- When signing, the instance settings choose the policy.
General:DefaultSignaturePolicy(Basic, the default, orWithTime) says whether the signature gets a timestamp. WithGeneral:UseBrazilianPdfSigningPolicieson, PDF signatures follow ICP-Brasil (AD-RB or AD-RT). With it off, the default, they follow PAdES basic (or PAdES-T). - When validating, inspection uses the basic policy of the format, PAdES basic for PDF. It rejects signatures in Adobe's format with the
error in the example above. To accept them, validate through the
Api/PadesSignatures/Openroute with the Adobe Reader policy. - Trust always comes from the security context: the one given in the call or, without it, the subscription's or the instance's default.
Policies for PDF
These are the PAdES policies. In .NET they're in StandardPadesSignaturePolicies (namespace Lacuna.RestPki.Api). In Python, the
StandardSignaturePolicies constants (package restpki_client) don't include Adobe Reader or the one without LTV: pass the ID.
| Policy | ID | What it defines | Without a security context, trusts |
|---|---|---|---|
Basic | 78d20b33-014d-440e-ad07-929f05d00cdf | PAdES basic, with LTV data | No root: requires a security context |
BasicWithoutLtv | ed93a777-ad5a-49a0-8b67-5aa5dfad1c98 | PAdES basic, without LTV data | No root: requires a security context |
AdobeReader | aaed831b-fa9d-4732-82fc-8d25f2c16c57 | PAdES basic without the attribute and algorithm requirements; accepts Adobe's format (see below) | No root: requires a security context |
PkiBrazil.AdrBasica | 531d5012-4c0d-4b6f-89e8-ebdcc605d7c2 | ICP-Brasil AD-RB (explicit policy) | ICP-Brasil |
PkiBrazil.AdrTempo | 10f0d9a5-a0a9-42e9-9523-e181ce05a25b | ICP-Brasil AD-RT, with a timestamp (explicit policy) | ICP-Brasil |
PkiBrazil.BasicWithPkiBrazilCerts | 3fec800c-366c-49bf-82c5-2e72154e70f6 | PAdES basic | ICP-Brasil |
PkiBrazil.PadesTWithPkiBrazilCerts | 6a39aeea-a2d0-4754-bf8c-19da15296ddb | PAdES-T, with a timestamp | ICP-Brasil |
The policies with a timestamp use the security context's timestamp plan (see Settings of a security context).
StandardPadesSignaturePolicies.PkiBrazil also has AdrCompleta and AdrArquivamento, but the server doesn't accept them: the call fails
with SignaturePolicyNotFound.
Default policy and explicit policies
On validation, the PDF may declare an explicit policy (ICP-Brasil AD-RB or AD-RT) or none. Two parameters decide how each signature is validated:
acceptableExplicitPolicieslists the explicit policies to accept. OnlyPkiBrazil.AdrBasicaandPkiBrazil.AdrTempocan be on the list. The others are implicit, and the call fails withInvalidRequest.defaultSignaturePolicyIdvalidates the signatures that declare no policy and those that declare a policy not on the list. Without it, those signatures fail validation.
With Adobe Reader as the defaultSignaturePolicyId, ICP-Brasil PAdES signatures pass too, because Adobe Reader requires less than AD-RB. To
require the ICP-Brasil standard, use acceptableExplicitPolicies without defaultSignaturePolicyId (see the
example).
The Adobe Reader policy
The Adobe Reader policy (aaed831b-fa9d-4732-82fc-8d25f2c16c57) starts from PAdES basic and relaxes the format checks:
- It doesn't require the mandatory signed attributes, such as
signing-certificate. - It accepts unknown attributes and attributes PAdES forbids, such as
signing-timeinside the CMS signature. - It accepts any hash and signature algorithm.
The rest of the validation is unchanged: the document's integrity, the certificate chain, revocation and trust in the security context. That's why the policy requires a security context, and a certificate outside it is still rejected.
It's an implicit policy: use it as defaultSignaturePolicyId, never in acceptableExplicitPolicies.
When signing, Adobe Reader produces the signature in Adobe's format (subfilter adbe.pkcs7.detached) and without LTV data. That works on
Rest PKI Core 4.1.2 and later, through the Rest PKI PAdES signature start route. On Rest PKI, Adobe Reader is for validation only.
The policy's name has nothing to do with what Adobe Reader shows when it opens the PDF. Adobe Reader validates with Adobe's own list of roots (AATL) and its settings, not with the Rest PKI Core security context. A signature valid on Rest PKI Core may show as not verified in Adobe Reader. See Certificates trusted by Adobe and Adobe Reader validation.
Examples
The examples validate through the Api/PadesSignatures/Open route. In the Rest PKI client libraries, which work with a Rest PKI Core key, the
PadesSignatureExplorer calls it (see Moving from Rest PKI).
Accepting Adobe signatures from several hierarchies
A PDF has signatures from ICP-Brasil (some made in Adobe Acrobat), gov.br and e-Notariado, and you want to validate all of them. Use the
PkiBrazilWithGovBrAndENotariado security context, which trusts the three hierarchies, and the Adobe Reader policy as the default.
Python
With the restpki-client package:
from restpki_client import PadesSignatureExplorer, RestPkiClient
ADOBE_READER = 'aaed831b-fa9d-4732-82fc-8d25f2c16c57'
PKI_BRAZIL_WITH_GOVBR_AND_ENOTARIADO = '4bf4409f-db45-4aab-91bf-2c73930ca556'
client = RestPkiClient('https://your-instance.example.com/', 'YOUR_API_KEY')
explorer = PadesSignatureExplorer(client)
explorer.signature_file_path = 'signed-document.pdf'
explorer.validate = True
explorer.default_signature_policy_id = ADOBE_READER
explorer.security_context_id = PKI_BRAZIL_WITH_GOVBR_AND_ENOTARIADO
signature = explorer.open()
for signer in signature.signers:
name = signer.certificate.subject_name.common_name
results = signer.validation_results
if results is None:
print(name, '- not validated')
elif results.is_valid:
print(name, '- valid')
else:
print(name, '- invalid')
for error in results.errors:
print(' ', error.item_type, error.message, error.detail)
.NET
With the Lacuna.RestPkiCore.Client package, which brings Lacuna.RestPki.Client:
var client = new RestPkiClient("https://your-instance.example.com/", "YOUR_API_KEY");
var explorer = new PadesSignatureExplorer(client) {
Validate = true,
DefaultSignaturePolicyId = StandardPadesSignaturePolicies.AdobeReader,
SecurityContextId = StandardSecurityContexts.PkiBrazilWithGovBrAndENotariado,
};
explorer.SetSignatureFile("signed-document.pdf");
var signature = await explorer.OpenAsync();
foreach (var signer in signature.Signers) {
var name = signer.Certificate.SubjectName.CommonName;
if (signer.ValidationResults == null) {
Console.WriteLine($"{name} - not validated");
} else if (signer.ValidationResults.IsValid) {
Console.WriteLine($"{name} - valid");
} else {
Console.WriteLine($"{name} - invalid");
Console.WriteLine(signer.ValidationResults);
}
}
REST
curl -X POST "https://your-instance.example.com/Api/PadesSignatures/Open" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file": { "content": "<PDF in Base64>", "mimeType": "application/pdf" },
"validate": true,
"defaultSignaturePolicyId": "aaed831b-fa9d-4732-82fc-8d25f2c16c57",
"securityContextId": "4bf4409f-db45-4aab-91bf-2c73930ca556"
}'
Each signer comes back with its own validation results. A signer whose certificate doesn't end at any of the three roots fails with
CertificateChainRootNotTrusted, without affecting the others.
Validating one hierarchy only
To check only the signatures of one hierarchy, use a security context that trusts only that one, such as GovBR
(5d323217-c031-4eed-9001-1cd82d86a8b5) or PkiBrazil (201856ce-273c-4058-a872-8937bd547d36), and keep the policy. With GovBR, the
gov.br signatures pass, and the ICP-Brasil ones in the same PDF come back with CertificateChainRootNotTrusted. That's expected: the security
context doesn't trust them.
To tell the signatures apart by hierarchy in a single call, use the security context that trusts all of them and look at each signer's certificate issuer.
Requiring the ICP-Brasil PAdES standard
To accept only signatures that follow the ICP-Brasil AD-RB or AD-RT policies, list them in acceptableExplicitPolicies and leave out
defaultSignaturePolicyId. A signature made in Adobe, which declares no policy, fails.
var explorer = new PadesSignatureExplorer(client) {
Validate = true,
AcceptableExplicitPolicies = SignaturePolicyCatalog.GetPkiBrazilPades(),
SecurityContextId = StandardSecurityContexts.PkiBrazil,
};
In the REST API, send "acceptableExplicitPolicies": ["531d5012-4c0d-4b6f-89e8-ebdcc605d7c2", "10f0d9a5-a0a9-42e9-9523-e181ce05a25b"].
Signing in Adobe's format
To produce a signature in Adobe's format, without LTV data, start the PAdES signature with the Adobe Reader policy and a security context:
var starter = new PadesSignatureStarter(client) {
SignaturePolicyId = StandardPadesSignaturePolicies.AdobeReader,
SecurityContextId = StandardSecurityContexts.PkiBrazil,
};
The rest of the flow is that of a Rest PKI PAdES signature (see Using Rest PKI on .NET). Prefer the PAdES basic or AD-RB policy unless a system requires Adobe's format.
Common errors
| Error | Cause | What to do |
|---|---|---|
SecurityContextRequired | The policy trusts no root (Basic, BasicWithoutLtv, AdobeReader) and the call gave no securityContextId | Pass the security context |
InvalidRequest (implicit policy) | An implicit policy, such as Adobe Reader, was passed in acceptableExplicitPolicies | Pass it in defaultSignaturePolicyId |
SignaturePolicyNotFound | The ID isn't a policy the server accepts, such as AD-RC or AD-RA for PDF | Use a policy from the table |
RequiredSignedAttributeMissing (signing-certificate) | The signature doesn't follow PAdES, like those made in Adobe Acrobat | Validate with the Adobe Reader policy |
CertificateChainRootNotTrusted | The certificate doesn't end at a root of the security context | Use a security context that trusts the certificate's hierarchy |
Validation covers only the first signers of each file (10 by default; see Signature inspection). The rest come back without validation results. And a file signed on the instance itself comes back as stored when it was signed, without a new validation: the call's security context and policy aren't used.
On Rest PKI
On Rest PKI the relationship is the same, with these differences:
- The Adobe Reader policy is for validation only.
- The standard security contexts are only
PkiBrazil,PkiItaly,WindowsServerandLacunaTest, without the gov.br and e-Notariado ones.