What ETSI TS 103 097 specifies
TS 103 097 is the wire-level cryptographic contract for C-ITS. It defines:
- The certificate format — Explicit vs Implicit ECC certs, COER-encoded, with a strictly enumerated set of subject attributes (PSIDs allowed to sign, SSPs constraining each PSID, geographic validity region, time validity window).
- SignedData — the wrapper that surrounds every signed application message (CAM, DENM, CPM, signed EC/AT requests). It carries the signer reference (digest, hashedId8 or certificate-by-value), the signature, and the payload.
- EncryptedData — the wrapper used for confidentiality-bearing payloads, notably the inner enrolment and authorization requests of TS 102 941.
- Header fields — generationTime, expiryTime, generationLocation, the signer identifier and the PSID/SSP claim used to authorize the message.
The spec is built on top of IEEE 1609.2 cryptographic primitives. Where 1609.2 defines "how do you sign with ECDSA on curve X", TS 103 097 defines "what does a signed CAM actually look like on the wire, and what does its issuer cert look like".
Explicit vs implicit certificates
TS 103 097 inherits two cert flavours from 1609.2:
Explicit certs
The public key is carried directly in the cert body, as a PublicVerificationKey CHOICE with the curve and the encoded point. Verification is the straightforward ECDSA flow: hash the to-be-signed bytes, run ecdsa-verify with the carried key, accept or reject.
Implicit certs
The cert body carries a reconstructionValue instead of a key. The actual public key is derived by combining the reconstruction value with the issuer's public key — an ECQV (Elliptic Curve Qu-Vanstone) reconstruction. Implicit certs are smaller on the wire (no full pubkey, just a single point) at the cost of an extra reconstruction step before any signature can be verified.
Castell issues Explicit only. Implicit support is not implemented. This is a deliberate scope choice: Explicit certs are sufficient for the integrator workflows the testbed serves, and Implicit reconstruction adds significant complexity for marginal wire savings. The choice also dodges the IEEE 1609.2 P-384 implicit constraint — see the multi-curve page for that specific edge case.
How Castell signs to TS 103 097
Wire version
Castell declares conformance to TS 103 097 v1.3.1 cert format COER. v1.3.1 is the wire-stable cert encoding currently produced by the deployed ITS-G5 ecosystem. Newer versions (v2.1.1, v2.2.1) add fields and CHOICE entries but retain backward compatibility for the v1.3.1 subset; pinning to v1.3.1 means anything in the wild can parse Castell's certs without spec version negotiation.
What gets signed
Every artefact Castell publishes is signed end-to-end:
- Root CA cert at
/trustanchor— Explicit, self-signed under the Root CA's own key. - TLM cert at
/tlm— Explicit, self-signed under the TLM's own key (TS 102 940 §6.2.4). - MA cert at
/ma— Explicit, signed by the Root CA. - EC and AT certs issued via
POST /ec-requestandPOST /at-request— Explicit, signed by the EA and AA respectively. - The ECTL at
/getectl— wrapped in SignedData with the TLM as signer.
PSID and SSP — what each cert can sign
Every cert carries an appPermissions field enumerating the PSIDs (Provider Service Identifiers) the cert is authorized to claim, and the SSP (Service-Specific Permissions) constraining what within each PSID. A signed CAM must reference a PSID for which the signing cert holds permission; receivers reject signatures whose PSID isn't covered.
Castell's AT-2 release (v0.6.1, see changelog) widened the AA's certIssue permission set to cover all Day-1 services — CAM, DENM, SPATEM, MAPEM, IVIM, SREM, SSEM, VAM, CPM, GN-MGMT. Stacks running e.g. VAM (PSID 638) can now request an AT from Castell without hitting strict subset-chain validation rejections.
generationTime and the freshness window
Every signed message carries generationTime. A receiver rejects signatures whose generationTime falls outside an acceptable window from local time — typically ±5 minutes. Castell enforces this on incoming requests too: see Castell v0.8.3 in the changelog for the default window and the rationale.
Decoding TS 103 097 messages
Castell exposes a couple of debug endpoints that parse incoming TS 103 097 wire bytes and return their structure as JSON. They are deliberately public so any integrator can sanity-check what their stack is producing:
# Decode an EC request you just built — see what the wire looks like
curl -X POST https://pki.skyv2x.com/v221/ec-request-decode \
-H 'Content-Type: application/octet-stream' \
--data-binary @your-ec-request.coer
# Same for AT request (v2.2.1 strict decode)
curl -X POST https://pki.skyv2x.com/v221/at-request-decode \
-H 'Content-Type: application/octet-stream' \
--data-binary @your-at-request.coer
The decoded JSON exposes every CHOICE tag, every option field, the signer reference and the PSIDs/SSPs the signing cert holds. It's the fastest way to debug a v2.2.1 conformance failure without standing up your own parser.
Related material
- ETSI TS 102 941 — the trust management protocol that uses these cert and message formats.
- Multi-curve support — which ECC curves Castell accepts in the
PublicVerificationKeyCHOICE. - Trust anchors — the explicit Root CA, TLM and MA certs all conform to this format.
- Integration walkthrough — end-to-end EC + AT + sign-a-CAM showing the wire shape live.