Signing Worker Protocol
Signature formats
Choose between raw signature values and complete CMS signatures, what each one signs, and what SignatureAPI checks and changes in a CMS
Private beta. Qualified signatures are available on request. Request access and we enable them for your account. SWP/1 is in beta and may change.
Providers return signatures in one of two shapes. Some sign a hash and return the bare signature value. Others build the whole signature themselves and return a CMS (also called PKCS#7) object. SWP/1 accepts both. Your worker picks one per credential with signature_format.
raw | cms | |
|---|---|---|
| Your provider returns | A bare signature value over a hash | A complete detached CMS signature |
| Who builds the CMS | SignatureAPI | Your provider |
| The digest is the SHA-256 of | The signed attributes SignatureAPI builds | The PDF’s signed byte range |
| Signer certificate needed | In the credential response | In the sign response; optional in credential |
sign returns | signatures | signatures and certificates |
| Static certificate | Supported | Not supported |
Choose a format
- Use
rawwhen your provider has a “sign hash” call that returns a signature value. This is the default: a credential that doesn’t declare a format israw. - Use
cmswhen your provider’s API returns a finished CMS or PKCS#7 signature and doesn’t expose the bare value. Some remote signing services, which keep the signer’s key in their own qualified signature creation device, work this way. So do some providers that issue the signer’s certificate only at signing time.
You never need to unpack a provider’s CMS to fit the raw format. Return it as it is, with cms.
The format also decides when your worker needs the certificate, which matters for one-shot certificates. See Choose your provider’s model.
Declare the format
Set signature_format in the credential response:
{
"status": "completed",
"credential": {
"id": "cred_7Qk...",
"signature_format": "cms",
"max_signature_size": 16384
}
}
SignatureAPI then sends "signature_format": "cms" in that session’s sign request. It sends the field on a cms sign only, so a sign request without it is raw. authorize carries no format.
What you sign
Every digest is SHA-256, in both formats. Only its input differs.
raw. The SHA-256 of the DER-encoded signed attributes that SignatureAPI builds: content type, message digest and the signing-certificate attribute that names your certificate. That attribute is why arawcredential must return its certificate first.cms. The SHA-256 of the PDF’s signed byte range: the whole document except the space reserved for the signature. Your provider uses it as the CMSmessage-digestattribute, and builds the rest of the signed attributes itself.
The worker still never sees the document. In both formats it receives one digest.
Requirements on a CMS signature
For cms, each value in signatures is a complete CMS ContentInfo, base64. SignatureAPI checks it before it touches the PDF.
| Requirement | Failure reason |
|---|---|
| The value decodes as CMS. DER is preferred. BER is accepted and converted to DER before any other check. | cms-malformed |
Detached signed data: content type id-data, no encapsulated content, exactly one signer, signed attributes present. | cms-structure |
The signer is the first certificate in your certificates. | cms-signer-certificate |
The message-digest attribute equals the digest SignatureAPI sent. | cms-message-digest |
The signing-certificate-v2 attribute is present and names the signer certificate. | cms-signing-certificate |
| The signature verifies over the signed attributes with the signer certificate’s key. | cms-signature |
SignatureAPI also accepts these variations:
signing-time. Accepted and recorded as evidence. Some validators then label the result PAdES non-baseline and may warn. The signature is still valid.- Other signed attributes, such as
CMSAlgorithmProtection, are tolerated. id-ecPublicKeyas the signature algorithm. SignatureAPI rewrites it to the matchingecdsa-with-SHA*algorithm before it verifies.
What SignatureAPI changes
- Timestamp. SignatureAPI removes any signature timestamp your provider added and adds one from its own timestamp authority. Every certificate you declared must be valid at that timestamp’s time, or the session fails with
certificate-not-valid-at-timestamp. - Revocation data. Don’t include CRLs or OCSP responses. SignatureAPI adds revocation data to the PDF itself.
SignatureAPI never changes the signed attributes or the signature value.
Signature size
A PDF reserves a fixed space for each signature before the digest is computed. For cms, declare the largest CMS your provider can return, in bytes, with max_signature_size:
- Allowed values: 1 to 53,248.
- Default: 24,576, when you leave it out.
- Headroom: SignatureAPI adds room for its own timestamp and certificates on top.
A CMS larger than the declared size, or the default, fails the session with signature-too-large. Nothing is ever cut short. Declare the largest size your provider really returns, not the smallest you have seen.
raw credentials don’t declare a size. SignatureAPI sizes the space from the certificate chain.
Certificates
A cms sign response must list the certificates, signer first, in certificates. SignatureAPI checks this chain like any other: each certificate is signed by the next, and each was valid when the sign response arrived.
certificates in credential is optional for cms. When you do return it there, the signer certificate in sign must be the same one, or the session fails with signer-certificate-mismatch. Leave it out when your provider issues the certificate during signing.
The signer certificate can then be newer than the signing date written in the PDF, because that date is fixed before the provider signs. The trusted time of the signature is SignatureAPI’s timestamp. Some validators warn about the earlier date. That’s how the format works, not a defect in your worker.