Safe Communication Framework 0.1.0 build feea4f9
ERTMS/ETCS safe communication (Subset-037 EuroRadio, Subset-098 RBC/RBC), CENELEC EN 50128 SIL 4 oriented
Loading...
Searching...
No Matches
Software Requirements Specification — safeCommFramework

Skeleton. Each requirement is traced from a subset clause (docs/safety/SUBSET_MAPPING.dox) and referenced by a REQ-... tag in the public headers. Expand as modules are implemented; a public-header change updates the matching row here in the same commit.

SIL boundary (ADR-002)

Module Target SIL Rationale
SFM safecomm::safety SIL 4 (vital) produces/verifies the MAC that is the safety property; runs in A and B
CFM safecomm::cfm vital context, deterministic interface upward bearer I/O timing must not reach the 2oo2 cross-compared path — quarantined behind a discrete whole-PDU interface
ALE safecomm::ale non-vital holds no KSMAC; can drop/misroute (SFM times out safe-side) but cannot inject an authenticated message
config safecomm::config non-vital syntax parse only; every value range-checked by its vital consumer at init, bad value → refuse to start (safe)

Core

ID Requirement
REQ-SC-CORE-001 Every public function that can fail returns safecomm_status_t; SAFECOMM_STATUS_OK is 0.
REQ-SC-CORE-002 The library exposes its version as macros (SAFECOMM_VERSION_*) and safecomm_version().
REQ-SC-CORE-003 No dynamic memory allocation after initialisation; no variadic functions in library code (MISRA 17.1).

MAC (Subset-037 §7.3)

ID Requirement
REQ-SC-MAC-001 KMAC and KSMAC are 24 bytes (3 x 8-byte DES keys).
REQ-SC-MAC-003 safecomm_mac_derive_ksmac() derives KSMAC from KMAC, RA and RB per Subset-037-2 §6.2.3.2.3.13-16 (RA/RB split into 32-bit left/right halves; KS3 uses the key order reversed).
REQ-SC-MAC-005 safecomm_mac_compute() produces the 8-byte CBC-MAC over the given bytes per Subset-037-2 §6.2.2 ("single DES with modified MAC algorithm 3": every block but the last under K1 only, the last block E(K3,D(K2,E(K1,·))); ISO/IEC 9797-1 Padding Method 1 zero-padding, no extra block when already 64-bit aligned).
REQ-SC-MAC-006 safecomm_mac_verify() compares in constant time and never short-circuits on the first differing byte.
REQ-SC-MAC-010 The CBC-MAC reproduces the official Subset-037-2 Annex B worked example byte-for-byte (tests/test_mac_kat.c). The KSMAC derivation has no official worked example to check against; it is verified only for internal consistency.

Transport

ID Requirement
REQ-SC-TRANSPORT-001 The SaF layer performs no socket calls; all I/O goes through safecomm_transport_t.
REQ-SC-TRANSPORT-004 safecomm_transport_oal_tcp() provides a Platform_RTE-backed TCP transport with a per-recv supervision timeout.
REQ-SC-TRANSPORT-006 A recv returning 0 bytes / EOF is reported as SAFECOMM_STATUS_PEER_DISCONNECT.

Safety Functional sub-layer (Subset-037 §7.2 / §7.4 / §7.5 / §7.6)

ID Requirement
REQ-SC-SAF-002 safecomm_saf_init() fully overwrites the connection object and validates the transport callbacks.
REQ-SC-SAF-010 safecomm_saf_connect() runs AU1/AU2/AU3 per role and, on success, leaves the connection in DATA with a derived KSMAC.
REQ-SC-SAF-015 safecomm_saf_send() frames the PDU as a Subset-037-2 §6.2.5.3 DT SaPDU (packed header, MAC), with a project-specific 4-byte sequence number inside the MAC-covered user-data area (Subset-037-2's own DT carries no sequence field — see docs/safety/SUBSET_MAPPING.dox).
REQ-SC-SAF-018 safecomm_saf_recv() rejects a PDU whose MAC does not verify (MAC_MISMATCH), whose sequence is outside the accepted window (SEQ_ERROR), or whose direction flag is wrong (AUTH_FAILED, the reflection-attack defence of §6.2.5.1.7), and drops the connection to IDLE.
REQ-SC-SAF-020 safecomm_saf_set_time() supplies the current time; the library reads no clock (it must not call the OS).
REQ-SC-SAF-021 safecomm_saf_supervise() declares the link lost (TIMEOUT, connection to IDLE) when no valid frame arrived for t_supervision_ms; the first call arms the timer, 0 disables it, the comparison is wrap-around safe.
REQ-SC-SAF-022 safecomm_saf_connect() fails with TIMEOUT (connection to IDLE) when the handshake takes longer than t_connect_ms on the caller-supplied clock; 0 disables it, the comparison is wrap-around safe. The transport must keep the clock current while it blocks.
REQ-SC-SAF-023 safecomm_saf_recv() acts on any well-formed Sa-DISCONNECT (right length and message type; PEER_DISCONNECT, connection to IDLE) with no MAC or identity check, per Subset-037-2 §6.2.3.3.3.2 ("authentication of the connection release phase is not required" — a forged one can only end the connection early, never inject or alter safety data). A malformed one returns TRANSPORT and leaves the connection unchanged.
REQ-SC-SAF-020 safecomm_saf_disconnect() always leaves the object in IDLE, best-effort emitting Sa-DISCONNECT first.
REQ-SC-SAF-025 A supervision timer expiry in any state transitions the connection to IDLE and returns SAFECOMM_STATUS_TIMEOUT.
REQ-SC-SAF-026 A Sa-DATA frame carries up to SAFECOMM_SAF_MAX_PDU user bytes in both directions (the MAC input buffer is sized from it; before 2026-09-28 a fixed 64-byte buffer capped the user data at 54 bytes).

Frame-driven responder (2026-09-28)

For a caller that owns its I/O and cannot block (a cyclic executive, one relay link shared by many connections). None of these functions touches conn->transport; they share their checks with the blocking calls above.

ID Requirement
REQ-SC-SAF-040 safecomm_saf_frame_kind() classifies a received frame by its header MTI (AU1/AU2/AU3/DATA/DISCONNECT/AR, else UNKNOWN) without any MAC check.
REQ-SC-SAF-041 safecomm_saf_au1_fields() returns the source ETCS identity and the initiator random RA of a well-formed AU1 (SAFECOMM_SAF_AU1_LEN bytes, MTI AU1, DF 0), else AUTH_FAILED; AU1 carries no MAC, so both are unauthenticated until AU3 verifies.
REQ-SC-SAF-042 safecomm_saf_responder_on_au1() accepts an AU1 from the configured peer in any state (a fresh AU1 restarts the connection; unauthenticated, so a forged one only affects availability, as for Sa-DISCONNECT), uses the caller's RB, derives KSMAC and builds AU2; it ends in WAIT_AU3 and starts the connect budget at the current now_ms, or in IDLE with AUTH_FAILED on a malformed AU1 or unexpected peer identity. The caller must supply RB from a cryptographically secure source, and in a 2oo2 system the same RB to both channels.
REQ-SC-SAF-043 safecomm_saf_responder_on_au3() in WAIT_AU3 returns TIMEOUT (to IDLE) once more than t_connect_ms has passed since AU1, AUTH_FAILED (to IDLE) on a bad AU3 or MAC, else builds AR and enters DATA with both sequence counters at 1.
REQ-SC-SAF-044 safecomm_saf_accept_frame() applies exactly safecomm_saf_recv()'s checks (Sa-DISCONNECT handling, header, MAC, sequence window, supervision refresh) to a frame the caller already received; safecomm_saf_recv() is implemented on top of it.
REQ-SC-SAF-045 safecomm_saf_frame_sent() in DATA advances the send sequence exactly as a successful safecomm_saf_commit_send() does, for a frame from safecomm_saf_prepare_send() that the caller transmitted itself.
REQ-SC-SAF-046 safecomm_saf_disconnect_frame() builds a Sa-DISCONNECT (reason 0, sub-reason 0, direction flag from the given role) with no connection state, for a responder releasing a Sa-DATA frame that belongs to no connection it holds; safecomm_saf_disconnect() sends the same frame.

The blocking responder in safecomm_saf_connect() still draws RB from this module's internal linear congruential generator: predictable, and process-global (two processes diverge after either restarts). It is for tests and tools only; a vital responder uses safecomm_saf_responder_on_au1() with a secure RB (RBC_GP draws it through Platform_RTE's rte_random_fill()).

Subset-037 profile

ID Requirement
REQ-SC-ER-003 safecomm_er_make_saf_config() maps EVC->initiator / RBC->responder and fills the Subset-037 T_CONNECT and supervision timeouts.

Subset-098 profile

ID Requirement
REQ-SC-RR-003 safecomm_rr_make_saf_config() maps handing-over->initiator / accepting->responder and fills the Subset-098 timeouts.

Configuration (file-based)

ID Requirement
REQ-SC-CFG-001 Every runtime parameter of the stack is read from a text file; none is hard-coded or required on the command line.
REQ-SC-CFG-002 safecomm_config_load() parses key = value lines, # full-line and inline comments, trims surrounding whitespace, has no sections, and allocates nothing dynamically.
REQ-SC-CFG-003 The loader performs syntax parsing ONLY — no semantic / range validation — so it is non-vital.
REQ-SC-CFG-005..007 Typed accessors _get_str / _get_u32 / _get_bool; absent key or bad conversion returns a distinct error, never a silent default.
REQ-SC-CFG-010 A vital component range-checks every value it reads at init and returns an error (refuse to start) on any out-of-range or missing mandatory value.
REQ-SC-CFG-012 KMAC is never stored in the main config file; keys.kmac_file names a separate file of 48 hex characters.

CFM (Communication Functional Module)

ID Requirement
REQ-SC-CFM-003 safecomm_cfm_from_config() reads and range-checks the cfm.* keys and selects the SS-037 or SS-098 communication-layer profile.
REQ-SC-CFM-008 safecomm_cfm_transport() exposes the CFM upward as a safecomm_transport_t whose send/recv carry whole SaF PDUs; framing, keep-alive and reconnect are hidden below it.
REQ-SC-CFM-012 The CFM's interface to the SFM is discrete and drained at RBC-cycle boundaries; bearer I/O timing never enters the 2oo2 cross-compared path.

ALE (Application Layer Entity, Gateway)

ID Requirement
REQ-SC-ALE-003 safecomm_ale_from_config() reads ale.* and loads ale.peer_map_file into a fixed peer table.
REQ-SC-ALE-006 safecomm_ale_lookup() resolves a peer id (NID_ENGINE / RBC-ID) to its A and B endpoints.
REQ-SC-ALE-009 The ALE relays the raw bearer byte stream to BOTH A and B and never parses, stores or modifies a SaF PDU; it holds no KSMAC.
REQ-SC-ALE-010 A bearer connection with no identifiable peer within ale.accept_timeout_ms is dropped.

KM (Subset-114, Subset-038)

Moved out to their own standalone products on 2026-09-23: Platform_Protocol_KM114 (Subset-114, KMC-to-entity) and Platform_Protocol_KM038 (Subset-038, KMC-to-KMC interworking) — KM is administrative/non-vital, distinct from this project's own vital safety layer, and this workspace's own pattern is one product per protocol. Each carries its own docs/requirements/SRS.dox. See MISRA_COMPLIANCE_REPORT.dox Update 9 in this project for the removal record, and REQ-SC-MAC-011's own removal note (the 3DES block primitive it named went with them - each new product ported its own copy instead).

All 4 off-line KM message types plus their confirmations are now implemented (as of 2026-09-23).