ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_ota_parse.c
Go to the documentation of this file.
1
30
31#include <stddef.h>
32#include <stdint.h>
33#include <string.h>
34
35#include "ra8_attributes.h"
36#include "ra8_check.h"
37#include "ra8_err.h"
38#include "ra8_ota.h"
39#include "ra8_ota_internal.h"
40
42static const char* const s_tag = "ra8_ota";
43
58
76bool priv_ota_char_in_range(char c, char lo, char hi)
77{
78 return (c >= lo) && (c <= hi);
79}
80
98bool priv_ota_download_state_invalid(uint32_t state_idle_val,
99 uint32_t state_downloading_val,
100 uint32_t state)
101{
102 return (state != state_idle_val) && (state != state_downloading_val);
103}
104
105/* =============================================================================
106 * Configuration validation
107 * ============================================================================= */
108
134{
135 RA8_CHECK_NULL_PTR(cfg->net.open, s_tag, "net.open");
136 RA8_CHECK_NULL_PTR(cfg->net.read, s_tag, "net.read");
137 RA8_CHECK_NULL_PTR(cfg->net.close, s_tag, "net.close");
138 return k_ra8_ok;
139}
140
165{
166 RA8_CHECK_NULL_PTR(cfg->crypto.sha256_init, s_tag, "crypto.sha256_init");
167 RA8_CHECK_NULL_PTR(cfg->crypto.sha256_update, s_tag, "crypto.sha256_update");
168 RA8_CHECK_NULL_PTR(cfg->crypto.sha256_final, s_tag, "crypto.sha256_final");
169 RA8_CHECK_NULL_PTR(cfg->crypto.ecdsa_verify, s_tag, "crypto.ecdsa_verify");
170 return k_ra8_ok;
171}
172
198{
199 RA8_CHECK_NULL_PTR(cfg->flash.erase, s_tag, "flash.erase");
200 RA8_CHECK_NULL_PTR(cfg->flash.program, s_tag, "flash.program");
201 RA8_CHECK_NULL_PTR(cfg->flash.set_startup, s_tag, "flash.set_startup");
202 RA8_CHECK_NULL_PTR(cfg->flash.readback, s_tag, "flash.readback");
203 if (cfg->flash.bank_size_bytes == 0U) {
205 }
208 }
209 return k_ra8_ok;
210}
211
213{
214 RA8_CHECK_NULL_PTR(cfg, s_tag, "cfg");
216 if (e != k_ra8_ok) {
217 return e;
218 }
220 if (e != k_ra8_ok) {
221 return e;
222 }
224 if (e != k_ra8_ok) {
225 return e;
226 }
227 if (cfg->manifest_url[0] == '\0') {
229 }
230 return k_ra8_ok;
231}
232
233/* =============================================================================
234 * JSON / hex scanning helpers
235 * ============================================================================= */
236
266static ra8_err_t internal_json_str(const char* json, const char* key, char* dst, uint32_t cap)
267{
268 const char* p = strstr(json, key);
269 if (p == nullptr) {
271 }
272 p = strchr(p + strlen(key), '"');
273 if (p == nullptr) {
275 }
276 ++p;
277 const char* q = strchr(p, '"');
278 if (q == nullptr) {
280 }
281 const uint32_t n = (uint32_t)(q - p);
282 if (n + 1U > cap) {
284 }
285 (void)memcpy(dst, p, n);
286 dst[n] = '\0';
287 return k_ra8_ok;
288}
289
316ra8_err_t priv_ota_json_u32(const char* json, const char* key, uint32_t* out_v)
317{
318 const char* p = strstr(json, key);
319 if (p == nullptr) {
321 }
322 p += strlen(key);
323 /* Skip past quote/colon/whitespace. */
324 for (uint32_t guard = 0U; guard < (uint32_t)k_ra8_ota_json_skip_max; ++guard) {
325 if (*p == ':' || *p == ' ' || *p == '"') {
326 ++p;
327 } else {
328 break;
329 }
330 }
331 uint32_t v = 0U;
332 uint32_t i = 0U;
333 for (; i < (uint32_t)k_ra8_ota_u32_decimal_digits; ++i) {
334 const char c = p[i];
335 if ((c < '0') || (c > '9')) {
336 break;
337 }
338 v = (v * (uint32_t)k_ra8_ota_u32_decimal_base) + (uint32_t)(c - '0');
339 }
340 if (i == 0U) {
342 }
343 *out_v = v;
344 return k_ra8_ok;
345}
346
369static uint8_t internal_hex_nibble(char c)
370{
371 if ((c >= '0') && (c <= '9')) {
372 return (uint8_t)(c - '0');
373 }
374 if ((c >= 'a') && (c <= 'f')) {
375 return (uint8_t)((uint8_t)k_ra8_ota_hex_alpha_offset + (c - 'a'));
376 }
377 if (priv_ota_char_in_range(c, 'A', 'F')) {
378 return (uint8_t)((uint8_t)k_ra8_ota_hex_alpha_offset + (c - 'A'));
379 }
380 return (uint8_t)k_ra8_ota_hex_invalid_nibble;
381}
382
407static uint32_t internal_hex_decode(const char* in, uint8_t* out, uint32_t out_cap)
408{
409 const uint32_t in_len = (uint32_t)strlen(in);
410 if ((in_len % (uint32_t)k_ra8_ota_hex_chars_per_byte) != 0U) {
411 return 0U;
412 }
413 const uint32_t bytes = in_len / (uint32_t)k_ra8_ota_hex_chars_per_byte;
414 if (bytes > out_cap) {
415 return 0U;
416 }
417 for (uint32_t i = 0U; i < bytes; ++i) {
418 const size_t base_idx = (size_t)i * (size_t)k_ra8_ota_hex_chars_per_byte;
419 const uint8_t hi = internal_hex_nibble(in[base_idx]);
420 const uint8_t lo = internal_hex_nibble(in[base_idx + 1U]);
421 if ((hi == (uint8_t)k_ra8_ota_hex_invalid_nibble) ||
422 (lo == (uint8_t)k_ra8_ota_hex_invalid_nibble)) {
423 return 0U;
424 }
425 out[i] = (uint8_t)((hi << (uint8_t)k_ra8_ota_hex_nibble_shift) | lo);
426 }
427 return bytes;
428}
429
430/* =============================================================================
431 * Manifest decode
432 * ============================================================================= */
433
458{
459 char hex[k_ra8_ota_hex_buf_bytes];
460 ra8_err_t e = internal_json_str(json, "\"sha256\"", hex, sizeof hex);
461 if (e != k_ra8_ok) {
462 return e;
463 }
464 const uint32_t n_d = internal_hex_decode(hex, out->image_sha256, k_ra8_ota_sha256_bytes);
465 if (n_d != k_ra8_ota_sha256_bytes) {
467 }
468
469 e = internal_json_str(json, "\"signature\"", hex, sizeof hex);
470 if (e != k_ra8_ok) {
471 return e;
472 }
473 const uint32_t n_s = internal_hex_decode(hex, out->signature, k_ra8_ota_signature_max_bytes);
474 if (n_s == 0U) {
476 }
477 out->signature_len = (uint16_t)n_s;
478 return k_ra8_ok;
479}
480
507{
508 (void)memset(out, 0, sizeof *out);
509 ra8_err_t e = internal_json_str(json, "\"version\"", out->version, k_ra8_ota_version_str_bytes);
510 if (e != k_ra8_ok) {
511 return e;
512 }
513 e = internal_json_str(json, "\"url\"", out->image_url, k_ra8_ota_url_max_bytes);
514 if (e != k_ra8_ok) {
515 return e;
516 }
517 e = priv_ota_json_u32(json, "\"size\"", &out->image_size_bytes);
518 if (e != k_ra8_ok) {
519 return e;
520 }
521 if (out->image_size_bytes == 0U) {
523 }
526 }
527 return internal_manifest_decode_crypto(json, out);
528}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
size_t strlen(const char *s)
Calculate string length.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
char * strstr(const char *haystack, const char *needle)
Locate substring in string.
char * strchr(const char *s, int c)
Locate first occurrence of character in string.
Phase-5 OTA firmware-update orchestration for the RA8D2.
@ k_ra8_ota_url_max_bytes
NUL-terminated URL upper bound.
Definition ra8_ota.h:77
@ k_ra8_ota_sha256_bytes
SHA-256 digest length.
Definition ra8_ota.h:75
@ k_ra8_ota_version_str_bytes
NUL-terminated version string.
Definition ra8_ota.h:78
@ k_ra8_ota_max_image_bytes
512 KiB upper bound per bank.
Definition ra8_ota.h:79
@ k_ra8_ota_signature_max_bytes
ECDSA-P256 ASN.1 sig upper bound.
Definition ra8_ota.h:76
Test-access surface for ra8_ota internal helpers (MC/DC).
ra8_ota_internal_const_t
Internal numeric constants used by JSON / hex helpers.
@ k_ra8_ota_hex_chars_per_byte
Two hex chars per encoded byte.
@ k_ra8_ota_hex_nibble_shift
Shift for high nibble in a byte.
@ k_ra8_ota_hex_invalid_nibble
Sentinel for invalid hex nibble.
@ k_ra8_ota_u32_decimal_base
Base for decimal parsing.
@ k_ra8_ota_hex_alpha_offset
Offset added for 'a'..'f'/'A'..'F'.
@ k_ra8_ota_json_skip_max
Max JSON whitespace/quote skip.
@ k_ra8_ota_hex_buf_bytes
Capacity of stack hex buffer.
@ k_ra8_ota_u32_decimal_digits
Max decimal digits in a uint32.
static uint8_t internal_hex_nibble(char c)
Decode a single hex nibble.
bool priv_ota_char_in_range(char c, char lo, char hi)
Pure char-in-range predicate – see header for full contract.
static ra8_err_t internal_validate_cfg_flash(const ra8_ota_cfg_t *cfg)
Validate the flash function-pointer block of cfg.
static ra8_err_t internal_validate_cfg_crypto(const ra8_ota_cfg_t *cfg)
Validate the crypto function-pointer block of cfg.
ra8_err_t priv_ota_manifest_decode(const char *json, ra8_ota_manifest_t *out)
Decode every field of a JSON manifest into an ra8_ota_manifest_t.
static ra8_err_t internal_validate_cfg_net(const ra8_ota_cfg_t *cfg)
Validate the network function-pointer block of cfg.
ra8_err_t priv_ota_validate_cfg(const ra8_ota_cfg_t *cfg)
Validate the entire OTA configuration descriptor.
static ra8_err_t internal_manifest_decode_crypto(const char *json, ra8_ota_manifest_t *out)
Pull the sha256 + signature hex blobs out of a JSON manifest.
ra8_err_t priv_ota_json_u32(const char *json, const char *key, uint32_t *out_v)
Parse a decimal "key": NNN field out of a JSON-ish buffer.
bool priv_ota_download_state_invalid(uint32_t state_idle_val, uint32_t state_downloading_val, uint32_t state)
Pure download-state-invalid predicate – see header for full contract.
static uint32_t internal_hex_decode(const char *in, uint8_t *out, uint32_t out_cap)
Decode a hex string into bytes.
static ra8_err_t internal_json_str(const char *json, const char *key, char *dst, uint32_t cap)
Locate "key" inside a JSON-ish buffer and copy its string value (assumes minimal, well-formed manifes...
Initialisation descriptor for ra8_ota_init.
Definition ra8_ota.h:258
ra8_ota_crypto_iface_t crypto
Crypto interface (must be fully populated).
Definition ra8_ota.h:272
char manifest_url[k_ra8_ota_url_max_bytes]
HTTPS URL of the manifest JSON.
Definition ra8_ota.h:260
ra8_ota_flash_iface_t flash
Flash backend (must be fully populated).
Definition ra8_ota.h:275
ra8_ota_net_iface_t net
Network HTTPS interface (must be fully populated).
Definition ra8_ota.h:269
ra8_err_t(* ecdsa_verify)(void *ctx, uint32_t pubkey_handle, const uint8_t digest[k_ra8_ota_sha256_bytes], const uint8_t *sig, uint32_t sig_len)
Verify sig is a valid ECDSA signature over digest using the public key referenced by pubkey_handle.
Definition ra8_ota.h:207
ra8_err_t(* sha256_final)(void *ctx, uint8_t out[k_ra8_ota_sha256_bytes])
Finalise and write the 32-byte digest to out.
Definition ra8_ota.h:201
ra8_err_t(* sha256_update)(void *ctx, const uint8_t *data, uint32_t len)
Feed bytes to the running SHA-256 hash.
Definition ra8_ota.h:199
ra8_err_t(* sha256_init)(void *ctx)
Begin a SHA-256 streaming hash.
Definition ra8_ota.h:197
ra8_err_t(* program)(void *ctx, uint32_t addr, const uint8_t *src, uint32_t len)
Program len bytes at addr (must be 32-byte aligned).
Definition ra8_ota.h:232
ra8_err_t(* set_startup)(void *ctx, uint8_t which_bank, bool persistent)
Pick the bank to boot from at the next reset.
Definition ra8_ota.h:234
uint32_t bank_size_bytes
Size of one bank in bytes.
Definition ra8_ota.h:241
ra8_err_t(* erase)(void *ctx, uint32_t addr, uint32_t len)
Erase len bytes starting at addr in the inactive bank.
Definition ra8_ota.h:230
ra8_err_t(* readback)(void *ctx, uint32_t addr, uint8_t *dst, uint32_t len)
Read back len bytes (used by verification re-hash).
Definition ra8_ota.h:236
Decoded representation of the server manifest.
Definition ra8_ota.h:115
uint8_t image_sha256[k_ra8_ota_sha256_bytes]
Expected digest.
Definition ra8_ota.h:119
uint16_t signature_len
Bytes used in signature.
Definition ra8_ota.h:121
char image_url[k_ra8_ota_url_max_bytes]
HTTPS URL of the image blob.
Definition ra8_ota.h:117
uint8_t signature[k_ra8_ota_signature_max_bytes]
ECDSA signature over digest.
Definition ra8_ota.h:120
uint32_t image_size_bytes
Image size on the wire.
Definition ra8_ota.h:118
char version[k_ra8_ota_version_str_bytes]
Firmware version string.
Definition ra8_ota.h:116
ra8_err_t(* close)(void *ctx)
Tear the streaming GET down.
Definition ra8_ota.h:179
ra8_err_t(* open)(void *ctx, const char *url, uint32_t *out_content_len)
Begin a streaming GET against url.
Definition ra8_ota.h:168
ra8_err_t(* read)(void *ctx, uint8_t *dst, uint32_t cap, uint32_t *out_len)
Read up to cap bytes from the open session.
Definition ra8_ota.h:174