ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_rsip_key_injection.c
Go to the documentation of this file.
1
23
25
26#include <stdint.h>
27
28#include "ra8_attributes.h"
29#include "ra8_check.h"
30#include "ra8_err.h"
31#include "ra8_log.h"
32#include "ra8_secure.h"
33
41static const char* s_tag = "RSIP_KI";
42
43/*
44 * Fail-closed stub-crypto gate (issue #180). The key-wrap and MAC below use a
45 * NON-cryptographic xorshift mixer (see the @warning in the file banner), so
46 * the wrapping is not cryptographically meaningful. It is only safe under an
47 * off-target build or an explicitly-declared insecure dev/eval image. A real
48 * production/HIL image (neither flag set) compiles the #else branch, where
49 * every entry point hard-errors so keys are never wrapped or validated with the
50 * stub. scripts/checks/check_stub_crypto_guarded.py enforces the guard.
51 */
52#if defined(RA8_INSECURE_STUB_CRYPTO) || defined(RA8_OFF_TARGET)
53
55typedef enum : uint16_t {
56 k_aes_192_key_bytes = 24U,
61 k_ecc_256_pub_bytes = 64U,
62 k_ecc_384_priv_bytes = 48U,
63 k_ecc_384_pub_bytes = 96U,
64 k_ecc_521_priv_bytes = 66U,
65 k_ecc_521_pub_bytes = 132U,
66} rsip_ki_size_t;
67
79typedef enum : uint64_t {
80 k_ra8_rsip_ki_seed = 0x9E3779B97F4A7C15ULL,
81 k_ra8_rsip_ki_mul = 0x2545F4914F6CDD1DULL,
82 k_ra8_rsip_ki_xor_a = 12ULL,
83 k_ra8_rsip_ki_xor_b = 25ULL,
84 k_ra8_rsip_ki_xor_c = 27ULL,
85 k_ra8_rsip_ki_byte_mask = 0xFFULL,
86} ra8_rsip_ki_internal_t;
87
94typedef enum : uint32_t {
95 k_ra8_rsip_ki_off_type = 0U,
96 k_ra8_rsip_ki_off_mgmt_info = 4U,
97 k_ra8_rsip_ki_off_payload = 20U,
98} ra8_rsip_ki_layout_t;
99
106typedef enum : uint32_t {
107 k_ra8_rsip_ki_byte_bits = 8U,
108 k_ra8_rsip_ki_word_byte0 = 0U,
109 k_ra8_rsip_ki_word_byte1 = 1U,
110 k_ra8_rsip_ki_word_byte2 = 2U,
111 k_ra8_rsip_ki_word_byte3 = 3U,
112 k_ra8_rsip_ki_shift_8 = 8U,
113 k_ra8_rsip_ki_shift_16 = 16U,
114 k_ra8_rsip_ki_shift_24 = 24U,
115 k_ra8_rsip_ki_byte_low = 0xFFU,
116 k_ra8_rsip_ki_rsa_e_bytes = 4U,
117} ra8_rsip_ki_const_t;
118
140static uint64_t ki_xorshift(uint64_t state)
141{
142 uint64_t x = state;
143 x ^= x >> k_ra8_rsip_ki_xor_a;
144 x ^= x << k_ra8_rsip_ki_xor_b;
145 x ^= x >> k_ra8_rsip_ki_xor_c;
146 return x * k_ra8_rsip_ki_mul;
147}
148
168static uint64_t ki_mix_byte(uint64_t state, uint8_t b)
169{
170 return ki_xorshift(state ^ (uint64_t)b);
171}
172
192static void ki_compute_mac(const uint8_t* buf, uint32_t len, uint8_t* mac_out)
193{
194 uint64_t state = k_ra8_rsip_ki_seed;
195 for (uint32_t i = 0U; i < len; ++i) {
196 state = ki_mix_byte(state, buf[i]);
197 }
198 for (uint32_t i = 0U; i < (uint32_t)k_ra8_rsip_wrapped_mac_bytes; ++i) {
199 state = ki_xorshift(state);
200 mac_out[i] = (uint8_t)(state & k_ra8_rsip_ki_byte_mask);
201 }
202}
203
221static void ki_write_type(uint8_t* buf, uint32_t tag)
222{
223 buf[k_ra8_rsip_ki_word_byte0] = (uint8_t)((tag >> 0U) & (uint32_t)k_ra8_rsip_ki_byte_low);
224 buf[k_ra8_rsip_ki_word_byte1] =
225 (uint8_t)((tag >> (uint32_t)k_ra8_rsip_ki_shift_8) & (uint32_t)k_ra8_rsip_ki_byte_low);
226 buf[k_ra8_rsip_ki_word_byte2] =
227 (uint8_t)((tag >> (uint32_t)k_ra8_rsip_ki_shift_16) & (uint32_t)k_ra8_rsip_ki_byte_low);
228 buf[k_ra8_rsip_ki_word_byte3] =
229 (uint8_t)((tag >> (uint32_t)k_ra8_rsip_ki_shift_24) & (uint32_t)k_ra8_rsip_ki_byte_low);
230}
231
250static uint32_t ki_read_type(const uint8_t* buf)
251{
252 uint32_t v = 0U;
253 v |= (uint32_t)buf[k_ra8_rsip_ki_word_byte0] << 0U;
254 v |= (uint32_t)buf[k_ra8_rsip_ki_word_byte1] << (uint32_t)k_ra8_rsip_ki_shift_8;
255 v |= (uint32_t)buf[k_ra8_rsip_ki_word_byte2] << (uint32_t)k_ra8_rsip_ki_shift_16;
256 v |= (uint32_t)buf[k_ra8_rsip_ki_word_byte3] << (uint32_t)k_ra8_rsip_ki_shift_24;
257 return v;
258}
259
278static void ki_fill_mgmt_info(uint8_t* mgmt, const uint8_t* raw, uint32_t len)
279{
280 uint64_t state = k_ra8_rsip_ki_seed ^ (uint64_t)len;
281 for (uint32_t i = 0U; i < len; ++i) {
282 state = ki_mix_byte(state, raw[i]);
283 }
284 for (uint32_t i = 0U; i < (uint32_t)k_ra8_rsip_wrapped_mgmt_info_bytes; ++i) {
285 state = ki_xorshift(state);
286 mgmt[i] = (uint8_t)(state & k_ra8_rsip_ki_byte_mask);
287 }
288}
289
308static bool ki_aes_bytes(ra8_rsip_aes_key_bits_t key_bits, uint32_t* out)
309{
310 bool ok = true;
311 switch (key_bits) {
313 *out = 16U;
314 break;
316 *out = k_aes_192_key_bytes;
317 break;
319 *out = 32U;
320 break;
321 default:
322 ok = false;
323 break;
324 }
325 return ok;
326}
327
346static bool ki_rsa_bytes(ra8_rsip_rsa_size_t size, uint32_t* out)
347{
348 bool ok = true;
349 switch (size) {
352 break;
355 break;
358 break;
361 break;
362 default:
363 ok = false;
364 break;
365 }
366 return ok;
367}
368
388static bool ki_ecc_bytes(ra8_rsip_curve_t curve, uint32_t* priv, uint32_t* pub)
389{
390 bool ok = true;
391 switch (curve) {
395 *priv = 32U;
396 *pub = k_ecc_256_pub_bytes;
397 break;
400 *priv = k_ecc_384_priv_bytes;
401 *pub = k_ecc_384_pub_bytes;
402 break;
405 *priv = k_ecc_521_priv_bytes;
406 *pub = k_ecc_521_pub_bytes;
407 break;
409 *priv = 32U;
410 *pub = 32U;
411 break;
412 default:
413 ok = false;
414 break;
415 }
416 return ok;
417}
418
438static void ki_pack(uint8_t* dst, uint32_t type, const uint8_t* payload, uint32_t payload_len)
439{
440 /* Zero the entire blob so unused slack is deterministic. */
441 for (uint32_t i = 0U; i < (uint32_t)k_ra8_rsip_wrapped_max_total; ++i) {
442 dst[i] = 0U;
443 }
444 ki_write_type(dst + (uint32_t)k_ra8_rsip_ki_off_type, type);
445 ki_fill_mgmt_info(dst + (uint32_t)k_ra8_rsip_ki_off_mgmt_info, payload, payload_len);
446 for (uint32_t i = 0U; i < payload_len; ++i) {
447 dst[(uint32_t)k_ra8_rsip_ki_off_payload + i] = payload[i];
448 }
449 const uint32_t mac_off =
451 ki_compute_mac(dst, mac_off, dst + mac_off);
452}
453
454ra8_err_t ra8_rsip_key_inject_aes(uint8_t* installed_key_buf,
455 const uint8_t* raw_key,
457{
458 RA8_CHECK_NULL_PTR(installed_key_buf, s_tag, "inject_aes: installed_key_buf");
459 RA8_CHECK_NULL_PTR(raw_key, s_tag, "inject_aes: raw_key");
460
461 uint32_t key_len = 0U;
462 if (!ki_aes_bytes(key_bits, &key_len)) {
464 }
465 ki_pack(installed_key_buf, (uint32_t)k_ra8_rsip_wrapped_type_aes, raw_key, key_len);
466 return k_ra8_ok;
467}
468
469ra8_err_t ra8_rsip_key_inject_rsa(uint8_t* installed_key_buf,
470 const uint8_t* raw_modulus,
471 const uint8_t* raw_exponent,
473{
474 RA8_CHECK_NULL_PTR(installed_key_buf, s_tag, "inject_rsa: installed_key_buf");
475 RA8_CHECK_NULL_PTR(raw_modulus, s_tag, "inject_rsa: raw_modulus");
476 RA8_CHECK_NULL_PTR(raw_exponent, s_tag, "inject_rsa: raw_exponent");
477
478 uint32_t mod_bytes = 0U;
479 if (!ki_rsa_bytes(size, &mod_bytes)) {
481 }
482
483 /* Layout: modulus first, then 4-byte exponent. */
484 uint8_t payload[k_ra8_rsip_wrapped_max_payload] = {};
485 const uint32_t exp_bytes = (uint32_t)k_ra8_rsip_ki_rsa_e_bytes;
486 if ((mod_bytes + exp_bytes) > (uint32_t)k_ra8_rsip_wrapped_max_payload) {
488 }
489 for (uint32_t i = 0U; i < mod_bytes; ++i) {
490 payload[i] = raw_modulus[i];
491 }
492 for (uint32_t i = 0U; i < exp_bytes; ++i) {
493 payload[mod_bytes + i] = raw_exponent[i];
494 }
495 /* Public blob if the wrapper holds a 4-byte e; the stub uses the
496 * public type tag for both because there is no engine to enforce
497 * the discrimination here -- the protected layer accepts either. */
498 ki_pack(installed_key_buf,
500 payload,
501 mod_bytes + exp_bytes);
502 return k_ra8_ok;
503}
504
505ra8_err_t ra8_rsip_key_inject_ecc(uint8_t* installed_key_buf,
506 ra8_rsip_curve_t curve,
507 const uint8_t* raw_priv_or_pub,
508 bool is_private)
509{
510 RA8_CHECK_NULL_PTR(installed_key_buf, s_tag, "inject_ecc: installed_key_buf");
511 RA8_CHECK_NULL_PTR(raw_priv_or_pub, s_tag, "inject_ecc: raw_priv_or_pub");
512
513 uint32_t priv = 0U;
514 uint32_t pub = 0U;
515 if (!ki_ecc_bytes(curve, &priv, &pub)) {
517 }
518 const uint32_t len = is_private ? priv : pub;
519 const uint32_t tag = is_private ? (uint32_t)k_ra8_rsip_wrapped_type_ecc_priv
521 ki_pack(installed_key_buf, tag, raw_priv_or_pub, len);
522 return k_ra8_ok;
523}
524
525ra8_err_t ra8_rsip_key_validate(const uint8_t* installed_key_buf,
526 ra8_rsip_wrapped_key_type_t expected_type)
527{
528 RA8_CHECK_NULL_PTR(installed_key_buf, s_tag, "key_validate: installed_key_buf");
529
530 const uint32_t tag = ki_read_type(installed_key_buf);
531 if (tag != (uint32_t)expected_type) {
533 }
534 uint8_t mac[k_ra8_rsip_wrapped_mac_bytes] = {};
535 const uint32_t mac_off =
537 ki_compute_mac(installed_key_buf, mac_off, mac);
538 /* Constant-time MAC compare: an early-out byte loop would leak, through its
539 * timing, how many leading MAC bytes an attacker's forged wrapped key got
540 * right -- a byte-at-a-time forgery oracle (T5-12). */
541 const bool match =
542 ra8_ct_equal(&installed_key_buf[mac_off], mac, (size_t)k_ra8_rsip_wrapped_mac_bytes);
543 return match ? k_ra8_ok : k_ra8_err_hw_error;
544}
545
546#else /* production build: neither RA8_INSECURE_STUB_CRYPTO nor RA8_OFF_TARGET */
547
548/*
549 * Fail-closed production variant. Without a real RSIP/SCE key-injection backend
550 * the xorshift key-wrap above must never be used, so every entry point returns
551 * a hard error (never k_ra8_ok). A production image that forgot to provide the
552 * real backend therefore cannot wrap or validate keys with the insecure stub.
553 */
554
555ra8_err_t ra8_rsip_key_inject_aes(uint8_t* installed_key_buf,
556 const uint8_t* raw_key,
558{
559 RA8_CHECK_NULL_PTR(installed_key_buf, s_tag, "inject_aes: installed_key_buf");
560 RA8_CHECK_NULL_PTR(raw_key, s_tag, "inject_aes: raw_key");
561 (void)key_bits;
563}
564
565ra8_err_t ra8_rsip_key_inject_rsa(uint8_t* installed_key_buf,
566 const uint8_t* raw_modulus,
567 const uint8_t* raw_exponent,
569{
570 RA8_CHECK_NULL_PTR(installed_key_buf, s_tag, "inject_rsa: installed_key_buf");
571 RA8_CHECK_NULL_PTR(raw_modulus, s_tag, "inject_rsa: raw_modulus");
572 RA8_CHECK_NULL_PTR(raw_exponent, s_tag, "inject_rsa: raw_exponent");
573 (void)size;
575}
576
577ra8_err_t ra8_rsip_key_inject_ecc(uint8_t* installed_key_buf,
578 ra8_rsip_curve_t curve,
579 const uint8_t* raw_priv_or_pub,
580 bool is_private)
581{
582 RA8_CHECK_NULL_PTR(installed_key_buf, s_tag, "inject_ecc: installed_key_buf");
583 RA8_CHECK_NULL_PTR(raw_priv_or_pub, s_tag, "inject_ecc: raw_priv_or_pub");
584 (void)curve;
585 (void)is_private;
587}
588
589ra8_err_t ra8_rsip_key_validate(const uint8_t* installed_key_buf,
590 ra8_rsip_wrapped_key_type_t expected_type)
591{
592 RA8_CHECK_NULL_PTR(installed_key_buf, s_tag, "key_validate: installed_key_buf");
593 (void)expected_type;
595}
596
597#endif /* RA8_INSECURE_STUB_CRYPTO || RA8_OFF_TARGET */
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#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_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ 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_hw_error
Generic hardware fault detected (error flag set, fault interrupt).
Definition ra8_err.h:310
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Lightweight Logging Interface for ra8-firmware.
ra8_err_t ra8_rsip_key_inject_rsa(uint8_t *installed_key_buf, const uint8_t *raw_modulus, const uint8_t *raw_exponent, ra8_rsip_rsa_size_t size)
Wrap a raw RSA key (modulus + exponent) into the installed-key format.
ra8_err_t ra8_rsip_key_validate(const uint8_t *installed_key_buf, ra8_rsip_wrapped_key_type_t expected_type)
Validate that a wrapped-key blob has the expected structure and a matching trailing MAC.
ra8_err_t ra8_rsip_key_inject_aes(uint8_t *installed_key_buf, const uint8_t *raw_key, ra8_rsip_aes_key_bits_t key_bits)
Wrap a raw AES key into the RSIP installed-key format.
ra8_err_t ra8_rsip_key_inject_ecc(uint8_t *installed_key_buf, ra8_rsip_curve_t curve, const uint8_t *raw_priv_or_pub, bool is_private)
Wrap a raw ECC scalar (private or public) into the installed-key format.
RSIP key-injection HAL – wrap raw key material into theRSIP installed-key blob format.
ra8_rsip_wrapped_key_type_t
Type tag stored in the leading 4 bytes of a wrapped blob.
@ k_ra8_rsip_wrapped_type_ecc_pub
ECC public blob.
@ k_ra8_rsip_wrapped_type_rsa_pub
RSA public blob.
@ k_ra8_rsip_wrapped_type_ecc_priv
ECC private blob.
@ k_ra8_rsip_wrapped_type_aes
AES key blob.
@ k_ra8_rsip_wrapped_max_payload
Largest key payload (RSA-4096).
@ k_ra8_rsip_wrapped_max_total
Largest wrapped blob in bytes.
@ k_ra8_rsip_wrapped_mac_bytes
Trailing integrity MAC.
@ k_ra8_rsip_wrapped_mgmt_info_bytes
Key-injection envelope.
ra8_rsip_aes_key_bits_t
AES key-width selector accepted by ra8_rsip_key_inject_aes.
@ k_ra8_rsip_aes_key_bits_256
AES-256.
@ k_ra8_rsip_aes_key_bits_128
AES-128.
@ k_ra8_rsip_aes_key_bits_192
AES-192.
@ k_rsa_3072_mod_bytes
RSA 3072 mod bytes.
@ k_rsa_4096_mod_bytes
RSA 4096 mod bytes.
@ k_rsa_2048_mod_bytes
RSA 2048 mod bytes.
@ k_rsa_1024_mod_bytes
RSA 1024 mod bytes.
ra8_rsip_curve_t
ECC curve selector (HUM Ch 52.1 Table 52.1 "ECC" p 3302).
@ k_ra8_rsip_curve_secp384r1
NIST P-384.
@ k_ra8_rsip_curve_brain384r1
Brainpool P-384r1.
@ k_ra8_rsip_curve_secp521r1
NIST P-521.
@ k_ra8_rsip_curve_brain512r1
Brainpool P-512r1.
@ k_ra8_rsip_curve_brain256r1
Brainpool P-256r1.
@ k_ra8_rsip_curve_ed25519
Ed25519.
@ k_ra8_rsip_curve_secp256r1
NIST P-256.
@ k_ra8_rsip_curve_secp256k1
secp256k1.
ra8_rsip_rsa_size_t
RSA key-size selector (HUM Ch 52.1 Table 52.1 "RSA" p 3302).
@ k_ra8_rsip_rsa_4096
4096-bit RSA.
@ k_ra8_rsip_rsa_1024
1024-bit RSA.
@ k_ra8_rsip_rsa_3072
3072-bit RSA.
@ k_ra8_rsip_rsa_2048
2048-bit RSA.
Secure-comparison primitives for the crypto / secure-boot paths.
bool ra8_ct_equal(const void *a, const void *b, size_t len)
Constant-time equality of two byte buffers.
Definition ra8_secure.c:20