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
MISRA C:2012 Compliance Report — safeCommFramework

Guideline: MISRA C:2012 (with Amendment 1). Target: EN 50128 SIL 4 oriented. This report tracks deviations; the skeleton has none yet.

Update log

Update 10 — 2026-09-28 — frame-driven responder API

saf/saf.h / saf/saf.c: safecomm_saf_frame_kind(), _au1_fields(), _responder_on_au1(), _responder_on_au3(), _accept_frame(), _frame_sent(), _disconnect_frame() (REQ-SC-SAF-040..046). The responder half of safecomm_saf_connect() and the body of safecomm_saf_recv() were moved into shared code (responder_process_au1(), responder_process_au3(), safecomm_saf_accept_frame()) so the blocking and frame-driven paths run the same checks. mac_over_da_body()'s MAC input buffer grew from a fixed 64 bytes to 5 + 1 + 4 + SAFECOMM_SAF_MAX_PDU (REQ-SC-SAF-026; it capped Sa-DATA user data at 54 bytes). Frame buffers now use the new SAFECOMM_SAF_DATA_OVERHEAD.

cppcheck --enable=all --addon=misra --std=c99 on src/saf/saf.c, before -> after: 10.4 6 -> 6, 7.3 4 -> 4, 15.5 58 -> 75, 8.7 10 -> 15. The increases are the new functions' guard-clause returns (15.5) and new external API referenced from one translation unit (8.7) - the categories this file already carries; no new rule. No allocation, no OS call, fixed-size stack buffers only. ctest 10/10 (new test_saf_frame_driven: the library's blocking initiator against two frame-driven responders given one RB - identical AU2/AR/DT frames, a 300-byte PDU both ways, replay rejection, restart by a fresh AU1, disconnect; a second RB makes the two channels diverge; connect budget, wrong peer, buffer and argument checks).

Update 9 — 2026-09-23 — KM split out to Platform_Protocol_KM114 / Platform_Protocol_KM038

kmc/ (Subset-114) and kmc_kmc/ (Subset-038) - message header, K-STRUCT, all 7/4 request types, confirmations, off-line filename convention (Updates 5-8) - removed from this project and moved to two new standalone products, Platform_Protocol_KM114 and Platform_Protocol_KM038, on direct request. Reasoning: KM is administrative/non-vital, distinct from this project's own vital safety layer (mac/saf/euroradio/rbc_rbc/adapter); bundling the two blurred that line and didn't match this workspace's own one-product-per-protocol pattern.

Each new product carries its own independently-verified copy of the crypto this code needs (the CBC-MAC and the Triple-DES block cipher), on direct request, rather than a dependency on this project - safecomm_mac_3des_encrypt_block()/_decrypt_block() (added in Update 4 specifically for Subset-114's KMAC encryption) are removed from mac.h/mac.c along with their KAT in test_mac_kat.c, since this project no longer has any consumer of them; each new product's own des3.c carries an equivalent pair instead, independently verified against the same official Subset-114 §6.5.1.8 vector.

Verified: ctest 9/9 after removal (back to the pre-KMC baseline count) - standalone build. RBC_GP's own consuming build + ctest (14/14) confirmed unaffected (it never called into kmc/ or kmc_kmc/ directly). See Platform_Protocol_KM114's and Platform_Protocol_KM038's own MISRA_COMPLIANCE_REPORT.dox for the continuation of this history in their new home.

Update 8 — 2026-09-23 — Subset-038: the remaining message types (kmc/kmc_kmc.c)

kmc_kmc.c now implements all 4 off-line KM message types plus their confirmations (up from 1 in Update 6): KMAC-DELETION/CONF-KMAC-DELETION (§8.4.3), KMAC-UPDATE/CONF-KMAC-UPDATE (§8.4.4), KMAC-NEGACK (§8.4.5, no confirmation of its own). Refactored the confirmation builder/parser into one shared static pair (build_confirm()/parse_confirm(), parameterized by message-type code) since CONF-KMAC-EXCHANGE, CONF-KMAC-DELETION and CONF-KMAC-UPDATE are byte-identical in field layout — safecomm_kmc_kmc_build_exchange_confirm() (public API, unchanged signature) is now a thin wrapper over it, alongside the two new confirmation functions; verified this refactor changed no observable behaviour (test_kmc_kmc's existing exchange-confirm tests still pass unmodified).

Same posture as every prior KMC update: no dynamic memory, fixed-size buffers, every encode bounds-checks the caller's buffer, every decode checks length before indexing variable-length fields. Reuses safecomm_mac_compute()/_verify() for every CBC-MAC — no new crypto logic. cppcheck --enable=warning,performance,portability clean; MISRA addon still not run (no licensed rule text).

No official worked example exists for these message types (only KMAC-EXCHANGE/CONF-KMAC-EXCHANGE got one, in §8.4.2.7 — see Update 6); tests/test_kmc_kmc.c extended with round-trip + explicit tamper tests for all of them. ctest 11/11 (standalone build, test_kmc_kmc itself now covers the full Subset-038 message set); RBC_GP's own consuming build and ctest (14/14) confirmed unaffected. No new deviations.

Update 7 — 2026-09-23 — Subset-114: the remaining 5 request types (kmc/kmc.c)

kmc.c now implements all 7 Subset-114 request types (up from 2 in Update 5): REPLACE_ALL_KEYS (§6.2.1 — a K-STRUCT array, reusing the existing safecomm_kmc_encode_kstruct()/ _decode_kstruct() per-entry), DELETE_ALL_KEYS (§6.2.2), DELETE_KEY (§6.2.4), REPLACE_ETCS_ENTITIES (§6.2.5), UPDATE_KEY_VALIDITY_PERIOD (§6.2.6). Same posture as every prior KMC update: no dynamic memory, fixed-size buffers (SAFECOMM_KMC_MAX_KSTRUCTS, an implementation bound), every encode bounds-checks the caller's buffer, every decode checks length before indexing variable-length fields (K-NUM, PEER-NUM), and the spec's own "shall be greater than or equal to '1'" minimums (K-NUM, PEER-NUM) are enforced, not silently accepted at 0. Reuses safecomm_mac_compute()/_verify() for every CBC-MAC — no new crypto logic. cppcheck --enable=warning,performance,portability clean; MISRA addon still not run (no licensed rule text).

No official worked example exists for these 5 message types (only INSTALL_TRANSPORT_KEY / ADD_AUTHENTICATION_KEY / RESPONSE_NOTIF got one, and Subset-114 doesn't publish one at all — Subset-038's own example, used for kmc_kmc.c, is the only worked example either spec provides). tests/test_kmc.c extended with round-trip + explicit tamper tests (a post-MAC byte flip must fail SAFECOMM_STATUS_MAC_MISMATCH) for all 5, plus the K-NUM/PEER-NUM-minimum rejection tests. ctest 11/11 (standalone build, test_kmc itself now covers all 7 + RESPONSE_NOTIF); RBC_GP's own consuming build and ctest (14/14) confirmed unaffected. No new deviations.

Update 6 — 2026-09-23 — Subset-038 KMC-KMC interworking format (kmc/kmc_kmc.c)

New module kmc/kmc_kmc.c alongside kmc/kmc.c (Update 5), implementing a real, verified slice of Subset-038 v4.0.0 (Off-line Key Management FIS — KMC-KMC interworking; off-line per its own GREQ-1, not "online" despite the root TODO.dox item's wording — see kmc_kmc.h's own doc): KMAC-EXCHANGE/CONF-KMAC-EXCHANGE (§8.4.2). Also promoted kmc.c's previously-static ETCS-ID- expanded encode/decode to public (safecomm_kmc_encode_etcs_id()/_decode_etcs_id(), in kmc.h) since Subset-038 uses the byte-identical encoding (§8.1.1.3 = Subset-114 §6.1.1.3) and this avoids a second copy of a security-relevant identity encoder.

Same posture as Update 5: no dynamic memory, fixed-size buffers (SAFECOMM_KMC_KMC_MAX_TRACKSIDE, an implementation bound), every encode bounds-checks the caller's buffer, every decode checks length before indexing variable-length fields (tr_quant). Reuses safecomm_mac_compute()/_verify() (CBC-MAC, K-KMC1) and safecomm_mac_3des_encrypt_block()/_decrypt_block() (KMAC encryption, K-KMC2) directly — no new crypto logic. cppcheck --enable=warning,performance,portability clean; MISRA addon still not run (no licensed rule text).

Verified against Subset-038 §8.4.2.7's own worked hex example (Tables 10 and 11) — a real, controlled-document layout check (field order, byte width, BCD dates), reproduced byte-for-byte in tests/test_kmc_kmc.c, plus round-trip and explicit tamper tests (flipped byte / wrong key -> SAFECOMM_STATUS_MAC_MISMATCH) for the parts the worked example can't check (its CBC-MAC/ ENC(KMAC) content depends on K-KMC material the spec text doesn't give). ctest 11/11 (standalone build); RBC_GP's own consuming build and ctest (14/14) confirmed unaffected. No new deviations.

Update 5 — 2026-09-23 — Subset-114 KMC message format (kmc/kmc.c)

New module kmc/ (header, K-STRUCT, INSTALL_TRANSPORT_KEY, ADD_AUTHENTICATION_KEY, RESPONSE_NOTIF, §6.4 off-line file naming — see kmc/kmc.h's own doc for exactly which of the 7 request types this covers). No dynamic memory: every buffer is fixed-size (SAFECOMM_KMC_MAX_PEERS/SAFECOMM_KMC_MAX_TEXT implementation bounds, not spec ones, documented as such); every encode function checks the caller's buffer capacity before writing (SAFECOMM_STATUS_BUFFER_TOO_SMALL, never an overrun); every decode function checks the input length against both a fixed minimum and the variable-length fields it reads (peer_num, text_len) before indexing past them. Fixed-width types throughout; big-endian wire packing done by hand (no htonl-family portability assumption). cppcheck --enable=warning,performance,portability clean; MISRA addon still not run (no licensed rule text).

Reuses safecomm_mac_compute()/_verify() directly (constructing a safecomm_mac_ctx_t with the caller-supplied key, no derivation) for every CBC-MAC — no new MAC logic, no new DES engine. No official Subset-114 message-level worked example exists to check against (unlike the CBC-MAC and the 3DES block-cipher primitive, both checked against real controlled-document text in test_mac_kat.c); tests/test_kmc.c is therefore round-trip/self-consistency verification (build → parse → fields and MAC agree) plus explicit tamper tests (a flipped body byte or a wrong key must fail with SAFECOMM_STATUS_MAC_MISMATCH, not silently parse) — the same posture the KSMAC derivation already takes for its own no-official-vector case. ctest 10/10 (standalone build); RBC_GP's own consuming build and ctest (14/14) confirmed unaffected. No new deviations.

Update 4 — 2026-09-23 — Subset-114 3DES block encrypt/decrypt primitive

safecomm_mac_3des_encrypt_block()/_decrypt_block() added to mac.h/mac.c for Subset-114 §4.2.4 KMAC encryption. No dynamic memory, fixed-width types, arguments NULL-checked before use (SAFECOMM_STATUS_INVALID_PARAM), no new tables/permutation logic — both functions call this module's own already-verified des_ecb()/des3_algo3() static primitives, not a new DES engine. safecomm_mac_ctx_t.ksmac (a plain public field) is reused directly with a caller-supplied key (e.g. KTRANS1 or the Subset-114 predefined key) for CBC-MAC purposes elsewhere — no library change needed there. cppcheck --enable=warning,performance,portability clean; MISRA addon still not run (no licensed rule text). Verified against the official Subset-114 §6.5.1.8 predefined-key worked example, round-tripped through both directions (tests/test_mac_kat.c) — a real conformance check, not a self-consistency one, same posture as the existing Subset-037-2 CBC-MAC vector. ctest 9/9. No new deviations.

Update 3 — 2026-09-21 — SaF supervision timer, wrap-safe sequence window; DES/3DES known-answer test

Manual review of safecomm_saf_set_time(), safecomm_saf_supervise() and the sequence-window change in saf/saf.c: no dynamic memory, fixed-width types, unsigned wrap-around arithmetic is intended and explicit (Rule 12.4 is not triggered: no constant expression wraps), single point of failure paths return a status. cppcheck --enable=warning,performance,portability clean. The cppcheck MISRA addon was not run (no rule text available). No new deviations.

Update 2 — 2026-09-09 — vital / non-vital split + file config (ADR-002)

  • Skeleton restructured from one library into four CMake targets on the vital / non-vital boundary: safecomm::safety (vital SIL 4), safecomm::cfm (vital context), safecomm::ale (non-vital), safecomm::config (non-vital). The vital target links no non-vital code.
  • New module config/ — a key = value file loader — is fully implemented and covered by tests/test_config.c (fixture written + parsed + accessors + error paths). Fixed storage (SAFECOMM_CONFIG_MAX_*), no dynamic allocation, bounded fgets loop, over-long line → BUFFER_TOO_SMALL. Uses strtoul / strcasecmp (needs -std=gnu99; CMAKE_C_EXTENSIONS ON) — a documented, bounded deviation from strict ISO C99, acceptable for a non-vital parser; the vital targets do not use it.
  • cfm/, ale/ headers + arg-validating stubs added.
  • Build still -Werror clean under -Wall -Wextra -Wpedantic -Wconversion -Wshadow for the vital and non-vital targets alike; ctest 3/3.
  • No deviations recorded for the vital targets.

Update 1 — 2026-09-09 — project skeleton

  • Project created: shared SaF sub-layer + 3DES MAC + transport abstraction, with Subset-037 and Subset-098 profiles on top. All protocol entry points return SAFECOMM_STATUS_NOT_IMPLEMENTED; argument validation and the SaF object lifecycle are real.
  • Build is -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Werror clean (C99). No compiler-visible MISRA issues in the skeleton.
  • No deviations recorded.

Deviations

None.

Rules to watch as implementation proceeds

Rule Where it will bite Plan
17.1 (no <stdarg.h>) logging helpers use Platform_RTE's structured logging, never printf-style in lib code
21.x (no <string.h> misuse) MAC / frame buffers bounded copies only; caller-supplied sizes checked first
Dir 4.12 (no dynamic memory) connection objects caller-allocated safecomm_saf_conn_t, fixed SAFECOMM_SAF_MAX_PDU
10.x (essential type) 3DES bit math explicit uint8_t/uint32_t, no plain char arithmetic
12.x (evaluation order) MAC constant-time compare accumulate into one uint8_t diff, single branch at the end