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_takeover_key.c
Go to the documentation of this file.
1
6
7#include <stdio.h>
8#include <string.h>
9
10#include "safecomm/mac/mac.h"
11
12static uint8_t s_key[SAFECOMM_MAC_KEY_LEN];
13static bool s_key_loaded = false;
14
15static int hex_nibble(char c)
16{
17 if ((c >= '0') && (c <= '9'))
18 {
19 return c - '0';
20 }
21 if ((c >= 'a') && (c <= 'f'))
22 {
23 return (c - 'a') + 10;
24 }
25 if ((c >= 'A') && (c <= 'F'))
26 {
27 return (c - 'A') + 10;
28 }
29 return -1;
30}
31
32/* Exactly 2 * len hex characters from hex into out; false on any non-hex character. */
33static bool decode_hex(const char *hex, uint8_t *out, size_t len)
34{
35 size_t i;
36
37 for (i = 0U; i < len; i++)
38 {
39 int hi = hex_nibble(hex[2U * i]);
40 int lo = hex_nibble(hex[(2U * i) + 1U]);
41
42 if ((hi < 0) || (lo < 0))
43 {
44 return false;
45 }
46 out[i] = (uint8_t)((hi << 4) | lo);
47 }
48 return true;
49}
50
51/* Strips a `#` comment and surrounding whitespace in place; returns the remaining text (may be empty). */
52static char *trim_line(char *line)
53{
54 char *hash = strchr(line, '#');
55 char *p = line;
56 size_t n;
57
58 if (hash != NULL)
59 {
60 *hash = '\0';
61 }
62 while ((*p == ' ') || (*p == '\t'))
63 {
64 p++;
65 }
66 n = strlen(p);
67 while ((n > 0U) && ((p[n - 1U] == ' ') || (p[n - 1U] == '\t') || (p[n - 1U] == '\r') || (p[n - 1U] == '\n')))
68 {
69 p[n - 1U] = '\0';
70 n--;
71 }
72 return p;
73}
74
75bool ab_gp_takeover_key_load_file(const char *path)
76{
77 FILE *fp;
78 char line[160];
79 uint8_t key[SAFECOMM_MAC_KEY_LEN];
80 uint32_t keys = 0U;
81 bool ok = true;
82
83 s_key_loaded = false;
84 (void)memset(s_key, 0, sizeof(s_key));
85 if (path == NULL)
86 {
87 return false;
88 }
89 fp = fopen(path, "r");
90 if (fp == NULL)
91 {
92 return false;
93 }
94 while (ok && (fgets(line, (int)sizeof(line), fp) != NULL))
95 {
96 char *p = trim_line(line);
97
98 if (*p == '\0')
99 {
100 continue;
101 }
102 keys++;
103 ok = (keys == 1U) && (strlen(p) == (2U * SAFECOMM_MAC_KEY_LEN)) && decode_hex(p, key, sizeof(key));
104 }
105 (void)fclose(fp);
106 (void)memset(line, 0, sizeof(line));
107 if (ok && (keys == 1U))
108 {
109 (void)memcpy(s_key, key, sizeof(s_key));
110 s_key_loaded = true;
111 }
112 (void)memset(key, 0, sizeof(key));
113 return s_key_loaded;
114}
115
117{
118 return s_key_loaded;
119}
120
121bool ab_gp_takeover_verify_mac(void *user, const uint8_t *msg, size_t msg_len,
122 const uint8_t mac[RTE_SITE_ROLE_TOKEN_MAC_LEN])
123{
124 safecomm_mac_ctx_t mac_ctx;
125 bool match;
126
127 (void)user;
128 if ((!s_key_loaded) || (msg == NULL) || (mac == NULL))
129 {
130 return false;
131 }
132 (void)memcpy(mac_ctx.ksmac, s_key, sizeof(mac_ctx.ksmac));
133 mac_ctx.alg = SAFECOMM_MAC_ALG_3DES_SS037;
134 match = (safecomm_mac_verify(&mac_ctx, msg, msg_len, mac) == SAFECOMM_STATUS_OK);
135 (void)memset(&mac_ctx, 0, sizeof(mac_ctx));
136 return match;
137}
138
139bool ab_gp_takeover_token_from_payload(const char *payload, uint8_t out[RTE_SITE_ROLE_TOKEN_LEN])
140{
141 const size_t prefix_len = sizeof(AB_GP_TAKEOVER_TOKEN_PREFIX) - 1U;
142
143 if ((payload == NULL) || (out == NULL) || (strncmp(payload, AB_GP_TAKEOVER_TOKEN_PREFIX, prefix_len) != 0) ||
144 (strlen(&payload[prefix_len]) != (2U * (size_t)RTE_SITE_ROLE_TOKEN_LEN)))
145 {
146 return false;
147 }
148 return decode_hex(&payload[prefix_len], out, (size_t)RTE_SITE_ROLE_TOKEN_LEN);
149}
150
151bool ab_gp_takeover_token_build(uint8_t site_id, uint8_t channel_id, uint32_t challenge, uint32_t seq,
152 uint8_t out[RTE_SITE_ROLE_TOKEN_LEN])
153{
154 safecomm_mac_ctx_t mac_ctx;
155 bool ok;
156
157 if ((!s_key_loaded) || (out == NULL))
158 {
159 return false;
160 }
161 (void)memset(out, 0, RTE_SITE_ROLE_TOKEN_LEN);
162 out[0] = (uint8_t)RTE_SITE_ROLE_TOKEN_VERSION;
163 out[1] = site_id;
164 out[2] = channel_id;
165 out[4] = (uint8_t)(challenge & 0xFFU);
166 out[5] = (uint8_t)((challenge >> 8U) & 0xFFU);
167 out[6] = (uint8_t)((challenge >> 16U) & 0xFFU);
168 out[7] = (uint8_t)((challenge >> 24U) & 0xFFU);
169 out[8] = (uint8_t)(seq & 0xFFU);
170 out[9] = (uint8_t)((seq >> 8U) & 0xFFU);
171 out[10] = (uint8_t)((seq >> 16U) & 0xFFU);
172 out[11] = (uint8_t)((seq >> 24U) & 0xFFU);
173 (void)memcpy(mac_ctx.ksmac, s_key, sizeof(mac_ctx.ksmac));
174 mac_ctx.alg = SAFECOMM_MAC_ALG_3DES_SS037;
175 ok = (safecomm_mac_compute(&mac_ctx, out, (size_t)RTE_SITE_ROLE_TOKEN_MSG_LEN, &out[RTE_SITE_ROLE_TOKEN_MSG_LEN]) ==
176 SAFECOMM_STATUS_OK);
177 (void)memset(&mac_ctx, 0, sizeof(mac_ctx));
178 return ok;
179}
180
181bool ab_gp_takeover_token_to_payload(const uint8_t token[RTE_SITE_ROLE_TOKEN_LEN], char *out, size_t out_size)
182{
183 static const char digits[] = "0123456789abcdef";
184 const size_t prefix_len = sizeof(AB_GP_TAKEOVER_TOKEN_PREFIX) - 1U;
185 size_t i;
186
187 if ((token == NULL) || (out == NULL) || (out_size < (prefix_len + (2U * (size_t)RTE_SITE_ROLE_TOKEN_LEN) + 1U)))
188 {
189 return false;
190 }
191 (void)memcpy(out, AB_GP_TAKEOVER_TOKEN_PREFIX, prefix_len);
192 for (i = 0U; i < (size_t)RTE_SITE_ROLE_TOKEN_LEN; i++)
193 {
194 out[prefix_len + (2U * i)] = digits[(token[i] >> 4U) & 0x0FU];
195 out[prefix_len + (2U * i) + 1U] = digits[token[i] & 0x0FU];
196 }
197 out[prefix_len + (2U * (size_t)RTE_SITE_ROLE_TOKEN_LEN)] = '\0';
198 return true;
199}
static int hex_nibble(char c)
bool ab_gp_takeover_token_from_payload(const char *payload, uint8_t out[RTE_SITE_ROLE_TOKEN_LEN])
Decodes a util payload token=<48 hex> into a token.
static uint8_t s_key[SAFECOMM_MAC_KEY_LEN]
bool ab_gp_takeover_token_to_payload(const uint8_t token[RTE_SITE_ROLE_TOKEN_LEN], char *out, size_t out_size)
Encodes a token as the util payload token=<48 hex> (NUL-terminated).
static char * trim_line(char *line)
static bool s_key_loaded
bool ab_gp_takeover_key_loaded(void)
bool ab_gp_takeover_verify_mac(void *user, const uint8_t *msg, size_t msg_len, const uint8_t mac[RTE_SITE_ROLE_TOKEN_MAC_LEN])
rte_site_role verify_mac callback: true only when a key is loaded and the Subset-037 MAC over msg mat...
bool ab_gp_takeover_token_build(uint8_t site_id, uint8_t channel_id, uint32_t challenge, uint32_t seq, uint8_t out[RTE_SITE_ROLE_TOKEN_LEN])
Builds a token for one channel: the message (version, site id, channel id, challenge,...
static bool decode_hex(const char *hex, uint8_t *out, size_t len)
bool ab_gp_takeover_key_load_file(const char *path)
Loads the key file (one key, 48 hex characters) into this process's key slot.
The site's takeover key and the token codec for the dispatcher takeover confirmation (ADR-040 step 4b...
#define AB_GP_TAKEOVER_TOKEN_PREFIX