Craton Shield
vs-v2x
Part of Craton Shield Auto | Architecture
Craton Shield V2X communication security: validation helpers for IEEE 1609.2 / ETSI TS 103 097 message-flavoured payloads.
Overview
This crate provides a policy validator for Vehicle-to-Everything (V2X) messages in the style of IEEE 1609.2. The validator enforces a fail-closed policy, rejecting messages unless they pass ECDSA P-256 signature verification, replay detection via generation-time windows, and kinematic plausibility checks (speed, position bounds).
Scope and limitations
This crate implements a subset of IEEE 1609.2-2022 §5–6 SPDU validation. The standards are referenced for context; this is not a conformant implementation of either IEEE 1609.2 or ETSI TS 103 097. The following gaps are intentional and should be understood before deployment:
- No ASN.1 OER decoder. Callers must supply already-parsed
V2xMessageandV2xCertificatestructs. Wire-format decoding fromIeee1609Dot2Data/EtsiTs103097Databyte streams is out of scope and must be performed by an upstream component. - Custom certificate TBS digest format. The to-be-signed bytes hashed for certificate signature verification are a fixed-layout craton-shield encoding (little-endian, 119 bytes), not canonical IEEE/ETSI OER. As a result, certificates issued by, and signatures produced for, production SCMS PKIs (CAMP SCMS, ETSI C-ITS Trust List, etc.) will not interoperate with this crate. The signature primitives (ECDSA P-256 over SHA-256) are standard; only the TBS serialization is custom.
- No SCMS lifecycle. Pseudonym certificate rotation, butterfly-key expansion, linkage values, and the Enrollment/Authorization CA split from IEEE 1609.2.1 / SCMS are not implemented. Certificates are treated as opaque long-term identities.
- Fixed-size replay window. Replay detection uses a power-of-two
LRU ring buffer with a bloom-filter fast path. An adversary capable
of injecting signatures from a large number of distinct signers can
evict legitimate digests; the validator fails closed once the
eviction count exceeds
max_eviction_threshold. The default sizing targets roughly 64 simultaneous signers at typical 10 Hz BSM rates and is not appropriate for high-cardinality fleets without reconfiguration.
Treat the public API here as a policy validator over pre-decoded V2X structures rather than a drop-in 1609.2 stack.
Key Types
V2xValidator<C>— validates V2X signed protocol data units (SPDUs)V2xMessage— incoming SPDU with signature, signer public key, and payloadV2xPayload— BSM-like payload with latitude, longitude, speed, and headingValidatedV2xMessage— type-safe wrapper guaranteeing validation has passedPlausibilityLimits— configurable bounds for speed and position plausibility checksTrustStore— certificate chain verification for root CA trust anchorsCertificateRevocationList— revoked signer trackingPsidPolicy— PSID-based service-level message filteringGeoRegion— geographic region constraint (Global,Circle,Rectangle)MisbehaviorDetector— tracks sender rate limiting and impossible-acceleration detection
Feature Flags
stub— Replaces validation with a permissive stub that accepts all messages. A compile-time error prevents this feature from being enabled in release builds.
See core/docs/feature-flags.md for the full workspace feature reference.
Usage
use vs_v2x::{V2xValidator, PlausibilityLimits};
// `crypto` is a caller-supplied `CryptoProvider` (ECDSA P-256 + SHA-256).
// `message` is an already-decoded `V2xMessage` and `now_us` the current
// time in microseconds since the Unix epoch.
// Default plausibility limits (250 km/h max speed, 5 s max age).
let mut validator = V2xValidator::with_limits(crypto, PlausibilityLimits {
max_speed_cm_s: 5_556, // 200 km/h = 55.56 m/s
..PlausibilityLimits::default()
});
// `validate` enforces signature, replay, plausibility, and geo checks.
// It does NOT check PSID; use `validate_with_chain` for PSID enforcement
// (note: `V2xValidator::new` defaults to a deny-all PSID policy).
match validator.validate(&message, now_us) {
Ok(validated) => { /* forward validated.payload() to application */ }
Err(err) => { /* log rejection: err is a VsError */ }
}
License
Apache-2.0. See LICENSE.