JWS Serialization & JAdES Compliance Tiers
This page explains the two standards-honest representations an ANKASecure signature can take on the attached sign endpoints, how a client chooses between them with the optional serialization parameter, and how the choice interacts with the backend-authoritative RFC 3161 timestamping policy. It is written for direct REST API clients; SDK and CLI users get the same behavior through ergonomic overloads/flags (see SDK & CLI Overview*).
1. Two Equally-Standard Forms
RFC 7515 (JSON Web Signature) defines two first-class, equally-standard serializations of the same signature:
- JWS Compact Serialization — the familiar three dot-separated segments
base64url(protected).base64url(payload).base64url(signature). Compact, URL-safe, and the default when no timestamp is mandated. It has no unprotected header, so it cannot carry any post-signing metadata. - JWS JSON Serialization — a JSON object that can carry an unprotected header (
header) alongside the protected header and signature, and can hold multiple signatures (used by composite / hybrid keys). Because it has an unprotected header, it can carry post-signing metadata such as a signature timestamp.
Neither form is "more correct" than the other — the choice is a representation decision, not a security one.
2. Why a Timestamp Forces JWS JSON
ETSI TS 119 182-1 (JAdES) places the signature-timestamp sigTst inside the JWS Unprotected Header, at header.etsiU[].sigTst. Only JWS JSON Serialization has an unprotected header. Therefore:
A timestamped (qualified) signature can only be JWS JSON Serialization — never Compact.
This is a standards requirement, not a product opinion. It yields two honest compliance tiers:
| Compliance tier | Serialization | Timestamp | Standard |
|---|---|---|---|
| RFC 7515 JWS | Compact or JSON | none | RFC 7515 |
| JAdES B-T | JSON only | sigTst embedded | ETSI TS 119 182-1 |
3. Two Orthogonal Axes
Output is resolved from two independent inputs:
- serialization — the client's representation choice, an OPTIONAL request field
serialization ∈ {COMPACT, JSON}on the attached sign endpoints. Omit it to let the server pick the standards-correct form. - stamping — the backend-authoritative RFC 3161 TSA usage policy (deployment ceiling/floor + optional per-tenant override), described in TSA RFC 3161 Time-Stamping Architecture*. A client cannot turn stamping on or off; it is governed per tenant/deployment.
The hard rule at the seam: stamping ⇒ output MUST be JWS JSON.
4. Behavior Truth Table (attached sign)
Applies to POST /api/v3/crypto/sign, /api/v3/crypto/resign, and /api/v3/crypto/sign-encrypt (for sign-encrypt the table governs the inner JWS that is then encrypted):
serialization | effective stamping | server action | output | 400? |
|---|---|---|---|---|
| omitted | OFF | server chooses | compact JWS | no |
| omitted | REQUIRED | server chooses (auto-upgrade) | JWS-JSON + sigTst | no |
COMPACT | OFF | honor | compact JWS | no |
COMPACT | REQUIRED | impossible | — | 400 problem+json |
JSON | OFF | honor | JWS-JSON, no sigTst | no |
JSON | REQUIRED | honor | JWS-JSON + sigTst | no |
Two invariants hold on every row:
- An explicit
COMPACTis never silently converted to JSON. - A mandated stamp is never silently dropped.
The COMPACT + REQUIRED row is the only combination this feature rejects.
5. The Single Rejection (COMPACT + REQUIRED)
When a client explicitly asks for COMPACT but the effective stamping policy is REQUIRED, the two cannot be reconciled (a compact JWS cannot carry sigTst), so the request is rejected — loudly, before anything is signed:
{
"type": "https://docs.ankatech.co/errors/serialization-incompatible-with-timestamp",
"title": "Serialization Incompatible With Timestamp",
"status": 400,
"detail": "A required RFC 3161 signature timestamp mandates JWS JSON Serialization; COMPACT serialization cannot carry the timestamp. Omit the serialization field or request JSON.",
"instance": "/api/v3/crypto/sign",
"extensions": { "errorCode": "SERIALIZATION_INCOMPATIBLE_WITH_TIMESTAMP" }
}
Content-Type: application/problem+json(RFC 7807).- The
detailis oracle-safe: it names only the RFC 3161 → JWS-JSON requirement; it never echoes the key id, tenant, or any internal path. - No signature is produced — the compact token is not upgraded and the stamp is not dropped.
instanceis the endpoint that was called (/api/v3/crypto/sign,/resign, or/sign-encrypt); for sign-encrypt no partial JWE is produced on rejection.
Precedence. If the timestamping policy is genuinely unavailable (TSA unreachable, or an unresolved REQUIRED policy), the endpoint returns 503 first — a real outage pre-empts this 400, even for an explicit COMPACT request.
6. What the Client Parses (wire contract)
On the HTTP wire the sign responses always wrap the produced JWS in a typed JWS JSON Serialization object (jwsToken) inside the response metadata envelope (keyRequested, materialVersion, algorithmUsed, warnings). The serialization choice changes only the JWS representation within jwsToken:
- Compact tier — a single-signature JWS-JSON object with no unprotected header and no
sigTst. It is losslessly reducible to the RFC 7515 three-segment compact string; the SDK performs that reduction so asigncall persists a compact token. - JSON / JAdES-B-T tier — a JWS-JSON object; when stamped it carries the JAdES timestamp at
header.etsiU[].sigTst.tstTokens[].val(SIMPLE keys) or on each entry ofsignatures[].header(composite keys).
A client that needs a compact string can reduce a single-signature, no-unprotected-header JWS-JSON to compact; a stamped JWS-JSON cannot be reduced without discarding the timestamp (which is exactly why stamping forces JSON).
7. Streaming Is Unchanged
The streaming sign endpoints (/api/v3/crypto/stream/sign, /stream/resign) do not accept a serialization parameter. They already always emit detached JWS JSON Serialization ({"protected","signature"} for SIMPLE keys, {"signatures":[…],"header":{…}} for composite, payload omitted), stamped or not — they are TSA-native. No compact-detached form exists. See Streaming Operations*.
8. Verify Is Serialization-Agnostic and JAdES-Aware
The verify endpoints — /api/v3/crypto/verify, /api/v3/crypto/stream/verify, and the decrypt-then-verify inside /api/v3/crypto/decrypt-verify — auto-detect the serialization (compact vs JWS-JSON), so a client never has to declare which form it holds. Each verify response surfaces an informational qualifiedTimestamp block:
{
"present": true,
"trustStatus": "VALID",
"genTime": "2026-07-05T10:20:00Z",
"serialNumber": "84215045",
"policyOid": "1.3.6.1.4.1.99999.1.1"
}
trustStatus∈VALID,UNTRUSTED,REVOKED,EXPIRED,TIME_ANOMALY.- The block is omitted when no
sigTstis present. - It is purely informational and never flips the boolean
valid: a cryptographically valid signature whose timestamp is absent or untrusted still verifiesvalid=true.
The timestamp semantics live in TSA Architecture §5.4 (Verify — Extract, Validate, Report)*.
9. Related Documentation
- Core API — API Endpoints*
- TSA RFC 3161 Time-Stamping Architecture*
- JOSE Technical Reference
- Interoperability & Standards
- Detached Signatures & Streaming
- SDK & CLI Overview*
Target Audience: Integration Developers, API Consumers, Compliance Officers