RTE RBC 2oo2 Reference Application 0.1.0 build 0006685
SIL 4 2oo2 Dual-Site Fault-Tolerant ERTMS Radio Block Centre Reference Architecture
Loading...
Searching...
No Matches
ab_gp_km114_client.c
Go to the documentation of this file.
1
6#include "ab_gp_saf_train.h"
7
8#include <stdbool.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13#include "rte/oal/log/rte_log.h"
14#include "km114/km114.h"
15
17
19
21/* Known limitation (documented, not accidental): held in-process only, not persisted across a
22 * restart. If ADD_AUTHENTICATION_KEY is relayed in a separate KMC drop after this process
23 * restarted since its own INSTALL_TRANSPORT_KEY, it is dropped (logged) rather than silently
24 * misapplied - the off-line KMC operator re-sends INSTALL_TRANSPORT_KEY in that case, the same
25 * operational recovery Subset-114 itself assumes for a lost/corrupted transfer. */
26static bool s_have_ktrans = false;
27static uint8_t s_ktrans1[KM114_MAC_KEY_LEN];
28static uint8_t s_ktrans2[KM114_MAC_KEY_LEN];
29
30/* A/B cross-check (step 3 of the consumption design): each side's own most recently installed KMAC, and whatever
31 * the sibling last sent, kept independently since the two installs and the sibling's frame can arrive in any order -
32 * see ab_gp_km114_client_on_peer_digest()'s own doc. Never logged, only compared. */
33static bool s_have_own = false;
34static uint32_t s_own_snum = 0U;
35static uint8_t s_own_kmac[KM114_MAC_KEY_LEN];
36static bool s_have_peer = false;
37static uint32_t s_peer_snum = 0U;
38static uint8_t s_peer_kmac[KM114_MAC_KEY_LEN];
39
41static void handle_install_transport_key(const uint8_t *bytes, size_t len, const char *role_tag,
43static void handle_add_authentication_key(const uint8_t *bytes, size_t len, const char *role_tag,
45static void install_kmac(const uint8_t kmac[KM114_MAC_KEY_LEN], uint32_t snum, const char *role_tag,
47static int km114_cross_check(const char *role_tag, rte_example_site_t site);
48
50void ab_gp_km114_client_on_message(const uint8_t *bytes, size_t len, const char *role_tag,
52{
53 km114_header_t hdr;
54
55 if ((bytes == NULL) || (km114_decode_header(bytes, len, &hdr) != KM114_STATUS_OK))
56 {
57 rte_log_write_event(RTE_LOG_LEVEL_WARNING, site_config_name(site), 0U, role_tag, "-", "KM114_CLIENT",
58 "malformed message header", NULL);
59 return;
60 }
61
62 switch (hdr.message_type)
63 {
64 case KM114_MSG_INSTALL_TRANSPORT_KEY:
65 handle_install_transport_key(bytes, len, role_tag, site);
66 break;
67 case KM114_MSG_ADD_AUTHENTICATION_KEY:
68 handle_add_authentication_key(bytes, len, role_tag, site, handle);
69 break;
70 default:
71 {
72 char info[32];
73
74 (void)snprintf(info, sizeof(info), "type=0x%02X", (unsigned int)hdr.message_type);
75 rte_log_write_event(RTE_LOG_LEVEL_INFO, site_config_name(site), 0U, role_tag, "-", "KM114_CLIENT",
76 "message received, not acted on", info);
77 break;
78 }
79 }
80}
81
82int ab_gp_km114_client_on_peer_digest(const uint8_t *payload, size_t size, const char *role_tag,
84{
85 if ((payload == NULL) || (size < (4U + (size_t)KM114_MAC_KEY_LEN)))
86 {
87 return 0;
88 }
89 s_peer_snum = ((uint32_t)payload[0] << 24) | ((uint32_t)payload[1] << 16) |
90 ((uint32_t)payload[2] << 8) | (uint32_t)payload[3];
91 (void)memcpy(s_peer_kmac, &payload[4], (size_t)KM114_MAC_KEY_LEN);
92 s_have_peer = true;
93 return km114_cross_check(role_tag, site);
94}
95
96/****Local functions ****/
97
98static void handle_install_transport_key(const uint8_t *bytes, size_t len, const char *role_tag,
100{
101 km114_header_t hdr;
102 km114_install_transport_key_t body;
103
104 if (km114_parse_install_transport_key(bytes, len, &hdr, &body) != KM114_STATUS_OK)
105 {
106 rte_log_write_event(RTE_LOG_LEVEL_WARNING, site_config_name(site), 0U, role_tag, "-", "KM114_CLIENT",
107 "INSTALL_TRANSPORT_KEY MAC/parse failed", NULL);
108 return;
109 }
110 (void)memcpy(s_ktrans1, body.ktrans1, KM114_MAC_KEY_LEN);
111 (void)memcpy(s_ktrans2, body.ktrans2, KM114_MAC_KEY_LEN);
112 s_have_ktrans = true;
113
114 {
115 char info[32];
116
117 (void)snprintf(info, sizeof(info), "snum=%u", (unsigned int)body.new_kt_snum);
118 rte_log_write_event(RTE_LOG_LEVEL_INFO, site_config_name(site), 0U, role_tag, "-", "KM114_CLIENT",
119 "KTRANS1/KTRANS2 installed", info);
120 }
121}
122
126static void install_train_link_keys(const km114_kstruct_t *ks, const uint8_t kmac[KM114_MAC_KEY_LEN],
127 const char *role_tag, rte_example_site_t site)
128{
129 uint16_t i;
130 uint16_t installed = 0U;
131 char info[48];
132
133 for (i = 0U; (i < ks->peer_num) && (i < (uint16_t)KM114_MAX_PEERS); i++)
134 {
135 if (ab_gp_saf_keys_install(ks->peers[i].id & 0xFFFFFFU, kmac))
136 {
137 installed++;
138 }
139 }
140 (void)snprintf(info, sizeof(info), "snum=%u peers=%u installed=%u", (unsigned int)ks->snum,
141 (unsigned int)ks->peer_num, (unsigned int)installed);
142 rte_log_write_event((installed == ks->peer_num) ? RTE_LOG_LEVEL_INFO : RTE_LOG_LEVEL_WARNING,
143 site_config_name(site), 0U, role_tag, "-", "KM114_CLIENT",
144 "KMAC installed for the train-link safe connection", info);
145}
146
147static void handle_add_authentication_key(const uint8_t *bytes, size_t len, const char *role_tag,
149{
150 km114_header_t hdr;
151 km114_kstruct_t ks;
152 uint8_t kmac[KM114_MAC_KEY_LEN];
153
154 if (!s_have_ktrans)
155 {
156 rte_log_write_event(RTE_LOG_LEVEL_WARNING, site_config_name(site), 0U, role_tag, "-", "KM114_CLIENT",
157 "ADD_AUTHENTICATION_KEY dropped - no KTRANS held", NULL);
158 return;
159 }
160 if (km114_parse_add_authentication_key(bytes, len, s_ktrans1, &hdr, &ks) != KM114_STATUS_OK)
161 {
162 rte_log_write_event(RTE_LOG_LEVEL_WARNING, site_config_name(site), 0U, role_tag, "-", "KM114_CLIENT",
163 "ADD_AUTHENTICATION_KEY MAC/parse failed", NULL);
164 return;
165 }
166 km114_decrypt_kmac(s_ktrans2, ks.enc_kmac, kmac);
167 install_kmac(kmac, ks.snum, role_tag, site, handle);
168 install_train_link_keys(&ks, kmac, role_tag, site);
169 (void)memset(kmac, 0, sizeof(kmac));
170}
171
176static void send_km114_digest(ab_gp_channel_handle_t handle, uint32_t snum, const uint8_t kmac[KM114_MAC_KEY_LEN])
177{
178 uint8_t frame[PEER_WIRE_FRAME_SIZE] = { 0 };
179
180 if (handle == NULL)
181 {
182 return; /* no live channel (e.g. a unit test calling install_kmac() directly) - nothing to cross-check */
183 }
185 frame[1] = (uint8_t)(snum >> 24);
186 frame[2] = (uint8_t)(snum >> 16);
187 frame[3] = (uint8_t)(snum >> 8);
188 frame[4] = (uint8_t)snum;
189 (void)memcpy(&frame[5], kmac, (size_t)KM114_MAC_KEY_LEN);
190 (void)ab_gp_channel_send_peer(handle, frame, sizeof(frame));
191}
192
198static int km114_cross_check(const char *role_tag, rte_example_site_t site)
199{
200 char info[16];
201 int result;
202
204 {
205 return 0;
206 }
207 (void)snprintf(info, sizeof(info), "snum=%u", (unsigned int)s_own_snum);
208 if (memcmp(s_own_kmac, s_peer_kmac, (size_t)KM114_MAC_KEY_LEN) == 0)
209 {
210 rte_log_write_event(RTE_LOG_LEVEL_INFO, site_config_name(site), 0U, role_tag, "-", "KM114_CLIENT",
211 "KMAC cross-check with A/B sibling: MATCH", info);
212 result = 1;
213 }
214 else
215 {
216 rte_log_write_event(RTE_LOG_LEVEL_WARNING, site_config_name(site), 0U, role_tag, "-", "KM114_CLIENT",
217 "KMAC cross-check with A/B sibling: MISMATCH", info);
218 result = -1;
219 }
220 return result;
221}
222
223static void install_kmac(const uint8_t kmac[KM114_MAC_KEY_LEN], uint32_t snum, const char *role_tag,
225{
226 const char *out_path = getenv("RTE_KM114_KMAC_OUT_FILE");
227 char info[48];
228
229 /* Cross-check regardless of whether this side even installs the key to a file below - it is about whether A and
230 * B independently decoded the SAME key, not about what either side then does with it. */
231 s_own_snum = snum;
232 (void)memcpy(s_own_kmac, kmac, (size_t)KM114_MAC_KEY_LEN);
233 s_have_own = true;
234 send_km114_digest(handle, snum, kmac);
235 km114_cross_check(role_tag, site);
236
237 (void)snprintf(info, sizeof(info), "snum=%u", (unsigned int)snum);
238
239 if ((out_path == NULL) || (out_path[0] == '\0'))
240 {
241 /* Not configured - the decoded key is discarded. Logged at INFO, not WARNING: this is
242 * a valid, common state (a process not participating in key installation, e.g. a test
243 * run) not a fault. */
244 rte_log_write_event(RTE_LOG_LEVEL_INFO, site_config_name(site), 0U, role_tag, "-", "KM114_CLIENT",
245 "KMAC decoded, RTE_KM114_KMAC_OUT_FILE unset - not installed", info);
246 return;
247 }
248
249 {
250 FILE *fp = fopen(out_path, "w");
251 size_t i;
252
253 if (fp == NULL)
254 {
255 rte_log_write_event(RTE_LOG_LEVEL_ERROR, site_config_name(site), 0U, role_tag, "-", "KM114_CLIENT",
256 "KMAC decoded, keys.kmac_file open failed", info);
257 return;
258 }
259 for (i = 0U; i < (size_t)KM114_MAC_KEY_LEN; i++)
260 {
261 (void)fprintf(fp, "%02x", (unsigned int)kmac[i]);
262 }
263 (void)fprintf(fp, "\n");
264 (void)fclose(fp);
265 }
266 /* Never log the key itself - only that installation happened and its serial number. */
267 rte_log_write_event(RTE_LOG_LEVEL_INFO, site_config_name(site), 0U, role_tag, "-", "KM114_CLIENT",
268 "KMAC installed", info);
269}
rte_status_t ab_gp_channel_send_peer(ab_gp_channel_handle_t handle, const uint8_t *bytes, size_t size)
Sends a frame over the A<->B peer channel.
struct ab_gp_channel_context_s * ab_gp_channel_handle_t
Opaque handle over this component's own static per-process context.
#define PEER_WIRE_FRAME_SIZE
#define PEER_MSG_KIND_KM114_DIGEST
static bool s_have_peer
static uint8_t s_own_kmac[KM114_MAC_KEY_LEN]
static uint32_t s_own_snum
static uint8_t s_peer_kmac[KM114_MAC_KEY_LEN]
static int km114_cross_check(const char *role_tag, rte_example_site_t site)
static void handle_install_transport_key(const uint8_t *bytes, size_t len, const char *role_tag, rte_example_site_t site)
static void install_train_link_keys(const km114_kstruct_t *ks, const uint8_t kmac[KM114_MAC_KEY_LEN], const char *role_tag, rte_example_site_t site)
static void install_kmac(const uint8_t kmac[KM114_MAC_KEY_LEN], uint32_t snum, const char *role_tag, rte_example_site_t site, ab_gp_channel_handle_t handle)
static uint8_t s_ktrans1[KM114_MAC_KEY_LEN]
void ab_gp_km114_client_on_message(const uint8_t *bytes, size_t len, const char *role_tag, rte_example_site_t site, ab_gp_channel_handle_t handle)
Processes one complete, reassembled Subset-114 message.
static bool s_have_own
static uint32_t s_peer_snum
static void send_km114_digest(ab_gp_channel_handle_t handle, uint32_t snum, const uint8_t kmac[KM114_MAC_KEY_LEN])
static bool s_have_ktrans
int ab_gp_km114_client_on_peer_digest(const uint8_t *payload, size_t size, const char *role_tag, rte_example_site_t site)
Consumes a PEER_MSG_KIND_KM114_DIGEST frame from the A/B sibling (called from pre_execute....
static void handle_add_authentication_key(const uint8_t *bytes, size_t len, const char *role_tag, rte_example_site_t site, ab_gp_channel_handle_t handle)
static uint8_t s_ktrans2[KM114_MAC_KEY_LEN]
A/B-side Subset-114 KMC message decoder - step 2 of Platform_Protocol_KM114's "Consumption design" (s...
bool ab_gp_saf_keys_install(uint32_t peer_etcs_id, const uint8_t kmac[SAFECOMM_MAC_KEY_LEN])
Installs (or replaces) the KMAC for one train ETCS identity.
Train link safe communication (Subset-037 SaF) terminated inside A and B - REQ-SC-001,...
const char * site_config_name(rte_example_site_t site)
Definition site_config.c:52
rte_example_site_t
Definition site_config.h:20