ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_rsip_protected.c
Go to the documentation of this file.
1
20
21#include "ra8_rsip_protected.h"
22
23#include <stdint.h>
24
25#include "ra8_attributes.h"
26#include "ra8_check.h"
27#include "ra8_err.h"
28#include "ra8_log.h"
29#include "ra8_rsip.h"
31#include "ra8_rsip_regs.h"
32#include "ra8_stack_budget.h"
33
41static const char* s_tag = "RSIP_P";
42
53
60
72typedef enum : uint32_t {
75
91
107
116
124static bool s_p_aes_iv_set;
125
134
143static bool s_p_aes_active;
144
162RA8_INTERNAL static void internal_p_scrub(uint8_t* buf, uint32_t n)
163{
164 for (uint32_t i = 0U; i < n; ++i) {
165 buf[i] = 0U;
166 }
167}
168
189RA8_INTERNAL static ra8_err_t internal_p_aes_install(const uint8_t* raw_key,
192{
193 switch (key_bits) {
195 return ra8_rsip_aes128_install_plain(raw_key, out);
197 return ra8_rsip_aes192_install_plain(raw_key, out);
199 return ra8_rsip_aes256_install_plain(raw_key, out);
200 default:
202 }
203}
204
205ra8_err_t ra8_rsip_protected_aes_init(const uint8_t* wrapped_key,
208 const uint8_t* iv)
209{
210 RA8_STACK_BUDGET(k_unwrap_key_stack_bytes); /* unwrapped-key scratch; scrubbed on unwind */
211 RA8_CHECK_NULL_PTR(wrapped_key, s_tag, "p_aes_init: wrapped_key");
212
214 if (rc != k_ra8_ok) {
215 return rc;
216 }
217
218 uint8_t raw_key[k_ra8_rsip_p_aes_max_bytes] = {};
219 const uint32_t n_bytes = (uint32_t)key_bits / (uint32_t)k_ra8_rsip_p_bits_per_byte;
220 if (n_bytes > (uint32_t)k_ra8_rsip_p_aes_max_bytes) {
222 }
223 for (uint32_t i = 0U; i < n_bytes; ++i) {
224 raw_key[i] = wrapped_key[(uint32_t)k_ra8_rsip_p_off_payload + i];
225 }
226
227 ra8_rsip_key_handle_t handle = {};
228 rc = internal_p_aes_install(raw_key, key_bits, &handle);
229 internal_p_scrub(raw_key, n_bytes);
230 if (rc != k_ra8_ok) {
231 return rc;
232 }
233
234 s_p_aes_handle = handle;
235 s_p_aes_mode = mode;
236 s_p_aes_iv_set = (iv != nullptr);
237 if (s_p_aes_iv_set) {
238 for (uint32_t i = 0U; i < (uint32_t)k_ra8_rsip_p_iv_bytes; ++i) {
239 s_p_aes_iv[i] = iv[i];
240 }
241 } else {
243 }
244 s_p_aes_active = true;
245 return k_ra8_ok;
246}
247
249ra8_rsip_protected_aes_encrypt(const uint8_t* plaintext, uint8_t* ciphertext, uint32_t len)
250{
251 if (!s_p_aes_active) {
253 }
254 RA8_CHECK_NULL_PTR(plaintext, s_tag, "p_aes_encrypt: plaintext");
255 RA8_CHECK_NULL_PTR(ciphertext, s_tag, "p_aes_encrypt: ciphertext");
259 s_p_aes_iv_set ? s_p_aes_iv : nullptr,
260 plaintext,
261 ciphertext,
262 len);
263}
264
266ra8_rsip_protected_aes_decrypt(const uint8_t* ciphertext, uint8_t* plaintext, uint32_t len)
267{
268 if (!s_p_aes_active) {
270 }
271 RA8_CHECK_NULL_PTR(ciphertext, s_tag, "p_aes_decrypt: ciphertext");
272 RA8_CHECK_NULL_PTR(plaintext, s_tag, "p_aes_decrypt: plaintext");
276 s_p_aes_iv_set ? s_p_aes_iv : nullptr,
277 ciphertext,
278 plaintext,
279 len);
280}
281
283{
284 if (!s_p_aes_active) {
286 }
287 uint8_t* h = (uint8_t*)&s_p_aes_handle;
288 internal_p_scrub(h, (uint32_t)sizeof(s_p_aes_handle));
290 s_p_aes_iv_set = false;
291 s_p_aes_active = false;
292 return k_ra8_ok;
293}
294
319static ra8_err_t internal_rsa_mod_bytes(ra8_rsip_rsa_size_t size, uint32_t* out_bytes)
320{
321 switch (size) {
323 *out_bytes = k_rsa_1024_mod_bytes;
324 return k_ra8_ok;
326 *out_bytes = k_rsa_2048_mod_bytes;
327 return k_ra8_ok;
329 *out_bytes = k_rsa_3072_mod_bytes;
330 return k_ra8_ok;
332 *out_bytes = k_rsa_4096_mod_bytes;
333 return k_ra8_ok;
334 default:
336 }
337}
338
378
401static ra8_err_t internal_rsa_validate_wrapped(const uint8_t* wrapped_priv)
402{
404 if (rc == k_ra8_ok) {
405 return k_ra8_ok;
406 }
408}
409
438static ra8_err_t internal_rsa_install_priv(const uint8_t* wrapped_priv,
440 uint32_t mod_bytes,
441 ra8_rsip_key_handle_t* out_handle)
442{
443 uint8_t modulus[k_ra8_rsip_wrapped_max_payload] = {};
444 for (uint32_t i = 0U; i < mod_bytes; ++i) {
445 modulus[i] = wrapped_priv[(uint32_t)k_ra8_rsip_p_off_payload + i];
446 }
447 /* Use the OEM install path for RSA private keys: the wrapped layout
448 * fed in here is already the engine-acceptable blob plus a 16-byte
449 * IV that the stub validates trivially. */
450 uint8_t install_iv[k_ra8_rsip_p_iv_bytes] = {};
451 const ra8_rsip_oem_cmd_t install_cmd = internal_rsa_install_cmd(size);
452 const ra8_err_t rc =
453 ra8_rsip_oem_install(install_cmd, install_iv, modulus, mod_bytes, out_handle);
454 internal_p_scrub(modulus, mod_bytes);
455 return rc;
456}
457
458ra8_err_t ra8_rsip_protected_rsa_decrypt(const uint8_t* wrapped_priv,
460 const uint8_t* ciphertext,
461 uint32_t ciphertext_len,
462 uint8_t* plaintext_out,
463 uint32_t plaintext_cap)
464{
465 RA8_STACK_BUDGET(k_rsa4096_priv_stack_bytes); /* RSA-4096 modulus scratch; scrubbed on unwind */
466 RA8_CHECK_NULL_PTR(wrapped_priv, s_tag, "p_rsa_decrypt: wrapped_priv");
467 RA8_CHECK_NULL_PTR(ciphertext, s_tag, "p_rsa_decrypt: ciphertext");
468 RA8_CHECK_NULL_PTR(plaintext_out, s_tag, "p_rsa_decrypt: plaintext_out");
469
470 ra8_err_t rc = internal_rsa_validate_wrapped(wrapped_priv);
471 if (rc != k_ra8_ok) {
472 return rc;
473 }
474
475 uint32_t mod_bytes = 0U;
476 rc = internal_rsa_mod_bytes(size, &mod_bytes);
477 if (rc != k_ra8_ok) {
478 return rc;
479 }
480 if (plaintext_cap < mod_bytes) {
482 }
483 if (ciphertext_len > mod_bytes) {
485 }
486
487 ra8_rsip_key_handle_t handle = {};
488 rc = internal_rsa_install_priv(wrapped_priv, size, mod_bytes, &handle);
489 if (rc != k_ra8_ok) {
490 return rc;
491 }
492
493 /* RSA "private decrypt" maps onto ra8_rsip_rsa_sign in the stub --
494 * both drive the engine's modular-exponentiation path. */
495 return ra8_rsip_rsa_sign(&handle, size, ciphertext, ciphertext_len, plaintext_out);
496}
497
524static ra8_err_t
525internal_ecc_priv_params(ra8_rsip_curve_t curve, uint32_t* out_alg, uint32_t* out_priv_bytes)
526{
527 switch (curve) {
529 *out_alg = (uint32_t)k_ra8_rsip_oem_cmd_ecc_secp256r1_priv;
530 *out_priv_bytes = (uint32_t)k_ecc_secp256_priv_bytes;
531 return k_ra8_ok;
533 *out_alg = (uint32_t)k_ra8_rsip_oem_cmd_ecc_secp384r1_priv;
534 *out_priv_bytes = (uint32_t)k_ecc_secp384r1_priv_bytes;
535 return k_ra8_ok;
537 *out_alg = (uint32_t)k_ra8_rsip_oem_cmd_ecc_secp521r1_priv;
538 *out_priv_bytes = (uint32_t)k_ecc_secp521r1_priv_bytes;
539 return k_ra8_ok;
541 *out_alg = (uint32_t)k_ra8_rsip_oem_cmd_ecc_secp256k1_priv;
542 *out_priv_bytes = (uint32_t)k_ecc_secp256_priv_bytes;
543 return k_ra8_ok;
544 default:
546 }
547}
548
549ra8_err_t ra8_rsip_protected_ecdsa_sign(const uint8_t* wrapped_priv,
550 ra8_rsip_curve_t curve,
551 const uint8_t* hash,
552 uint32_t hash_len,
553 uint8_t* sig_out)
554{
555 RA8_STACK_BUDGET(k_ecc_priv_stack_bytes); /* ECC private scalar scratch; scrubbed on unwind */
556 RA8_CHECK_NULL_PTR(wrapped_priv, s_tag, "p_ecdsa_sign: wrapped_priv");
557 RA8_CHECK_NULL_PTR(hash, s_tag, "p_ecdsa_sign: hash");
558 RA8_CHECK_NULL_PTR(sig_out, s_tag, "p_ecdsa_sign: sig_out");
559
561 if (rc != k_ra8_ok) {
562 return rc;
563 }
564
565 /* Build a minimal ECC private handle for the engine. The stub's
566 * ``ra8_rsip_ecdsa_sign`` routes through ``internal_asym_run`` which
567 * just needs a non-NULL handle whose ``alg`` carries an ECC opcode;
568 * the wrapped body holds the private scalar bytes copied from the
569 * payload. */
570 ra8_rsip_key_handle_t handle = {};
571 uint32_t priv_bytes = 0U;
572 rc = internal_ecc_priv_params(curve, &handle.alg, &priv_bytes);
573 if (rc != k_ra8_ok) {
574 return rc;
575 }
576 handle.body_words = priv_bytes / sizeof(uint32_t);
577
578 /* Copy the private scalar into the handle body word-aligned. */
579 for (uint32_t i = 0U; i < priv_bytes; ++i) {
580 ((uint8_t*)handle.body)[i] = wrapped_priv[(uint32_t)k_ra8_rsip_p_off_payload + i];
581 }
582
583 rc = ra8_rsip_ecdsa_sign(&handle, curve, hash, hash_len, sig_out);
584 internal_p_scrub((uint8_t*)handle.body, priv_bytes);
585 return rc;
586}
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_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
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.
Renesas Secure IP (RSIP-E50D) HAL driver – public API.
RSIP key-injection HAL – wrap raw key material into theRSIP installed-key blob format.
@ k_ra8_rsip_wrapped_type_rsa_pub
RSA public blob.
@ k_ra8_rsip_wrapped_type_rsa_priv
RSA private blob.
@ k_ra8_rsip_wrapped_type_ecc_priv
ECC private blob.
@ k_ra8_rsip_wrapped_type_aes
AES key blob.
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.
@ k_ra8_rsip_wrapped_max_payload
Largest key payload (RSA-4096).
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.
ra8_err_t ra8_rsip_oem_install(ra8_rsip_oem_cmd_t cmd, const uint8_t *iv, const uint8_t *oem_blob, uint32_t blob_len, ra8_rsip_key_handle_t *out)
Install an OEM-encrypted key blob into the wrapped vault.
ra8_err_t ra8_rsip_aes256_install_plain(const uint8_t *key, ra8_rsip_key_handle_t *out)
Wrap a 32-byte AES-256 key (see ra8_rsip_aes128_install_plain).
ra8_err_t ra8_rsip_aes_cipher(const ra8_rsip_key_handle_t *key, ra8_rsip_aes_mode_t mode, ra8_rsip_aes_dir_t dir, const uint8_t *iv, const uint8_t *in, uint8_t *out, uint32_t len)
Encrypt or decrypt a buffer with AES in a non-AEAD mode.
ra8_err_t ra8_rsip_aes128_install_plain(const uint8_t *key, ra8_rsip_key_handle_t *out)
Wrap a 16-byte AES-128 key for use by the engine.
ra8_err_t ra8_rsip_aes192_install_plain(const uint8_t *key, ra8_rsip_key_handle_t *out)
Wrap a 24-byte AES-192 key (see ra8_rsip_aes128_install_plain).
ra8_err_t ra8_rsip_ecdsa_sign(const ra8_rsip_key_handle_t *key, ra8_rsip_curve_t curve, const uint8_t *digest, uint32_t digest_len, uint8_t *signature)
ECDSA sign a digest with a wrapped private key.
ra8_err_t ra8_rsip_rsa_sign(const ra8_rsip_key_handle_t *key, ra8_rsip_rsa_size_t size, const uint8_t *digest, uint32_t digest_len, uint8_t *signature)
RSA sign a digest with a wrapped private key.
static ra8_rsip_aes_mode_t s_p_aes_mode
Latched block-cipher mode for the protected-AES path.
ra8_err_t ra8_rsip_protected_ecdsa_sign(const uint8_t *wrapped_priv, ra8_rsip_curve_t curve, const uint8_t *hash, uint32_t hash_len, uint8_t *sig_out)
ECDSA sign using a wrapped private key.
ra8_err_t ra8_rsip_protected_aes_encrypt(const uint8_t *plaintext, uint8_t *ciphertext, uint32_t len)
Encrypt with the latched protected AES context.
static ra8_err_t internal_rsa_install_priv(const uint8_t *wrapped_priv, ra8_rsip_rsa_size_t size, uint32_t mod_bytes, ra8_rsip_key_handle_t *out_handle)
Recover the modulus from a wrapped blob and OEM-install it.
ra8_err_t ra8_rsip_protected_aes_init(const uint8_t *wrapped_key, ra8_rsip_aes_key_bits_t key_bits, ra8_rsip_aes_mode_t mode, const uint8_t *iv)
Initialise an AES context using a wrapped key blob.
rsip_prot_size_t
RSA modulus / ECC private-scalar byte counts.
@ k_rsa_3072_mod_bytes
RSA 3072 mod bytes.
@ k_rsa_4096_mod_bytes
RSA 4096 mod bytes.
@ k_ecc_secp384r1_priv_bytes
ECC secp384r1 priv bytes.
@ k_rsa_2048_mod_bytes
RSA 2048 mod bytes.
@ k_ecc_secp256_priv_bytes
ECC secp256 priv bytes.
@ k_ecc_secp521r1_priv_bytes
ECC secp521r1 priv bytes.
@ k_rsa_1024_mod_bytes
RSA 1024 mod bytes.
static ra8_rsip_key_handle_t s_p_aes_handle
Latched AES handle for the protected-AES path.
ra8_rsip_p_layout_t
Local copy of the wrapped-key blob layout.
@ k_ra8_rsip_p_off_payload
Payload offset inside a wrapped blob.
static ra8_err_t internal_p_aes_install(const uint8_t *raw_key, ra8_rsip_aes_key_bits_t key_bits, ra8_rsip_key_handle_t *out)
Drive the right ra8_rsip_aes*_install_plain for the width.
static bool s_p_aes_active
Whether ra8_rsip_protected_aes_init has run since the last finish.
ra8_err_t ra8_rsip_protected_aes_decrypt(const uint8_t *ciphertext, uint8_t *plaintext, uint32_t len)
Decrypt with the latched protected AES context.
static ra8_err_t internal_ecc_priv_params(ra8_rsip_curve_t curve, uint32_t *out_alg, uint32_t *out_priv_bytes)
Map an ra8_rsip_curve_t to its OEM opcode and scalar size.
static bool s_p_aes_iv_set
Whether s_p_aes_iv was populated by the caller.
static uint8_t s_p_aes_iv[k_ra8_rsip_p_iv_bytes]
Latched IV used by the protected-AES path.
static void internal_p_scrub(uint8_t *buf, uint32_t n)
Bytewise scrub of a buffer.
static ra8_rsip_oem_cmd_t internal_rsa_install_cmd(ra8_rsip_rsa_size_t size)
Resolve the OEM install opcode for an RSA private key size.
static ra8_err_t internal_rsa_validate_wrapped(const uint8_t *wrapped_priv)
Accept a wrapped RSA blob tagged with either RSA type tag.
ra8_err_t ra8_rsip_protected_rsa_decrypt(const uint8_t *wrapped_priv, ra8_rsip_rsa_size_t size, const uint8_t *ciphertext, uint32_t ciphertext_len, uint8_t *plaintext_out, uint32_t plaintext_cap)
RSA-private decrypt using a wrapped private key.
rsip_prot_stack_t
Measured worst-case stack frames (bytes), scrubbed on unwind.
@ k_unwrap_key_stack_bytes
Unwrap key stack bytes.
@ k_ecc_priv_stack_bytes
ECC priv stack bytes.
@ k_rsa4096_priv_stack_bytes
Rsa4096 priv stack bytes.
static ra8_err_t internal_rsa_mod_bytes(ra8_rsip_rsa_size_t size, uint32_t *out_bytes)
Map an ra8_rsip_rsa_size_t to its modulus byte count.
ra8_rsip_p_const_t
Sizing constants used by the protected layer.
@ k_ra8_rsip_p_iv_bytes
AES IV length.
@ k_ra8_rsip_p_aes128_bytes
AES-128 raw-key bytes.
@ k_ra8_rsip_p_rsa_e_bytes
RSA exponent bytes (stub).
@ k_ra8_rsip_p_bits_per_byte
Width of a byte.
@ k_ra8_rsip_p_aes256_bytes
AES-256 raw-key bytes.
@ k_ra8_rsip_p_aes192_bytes
AES-192 raw-key bytes.
@ k_ra8_rsip_p_aes_max_bytes
AES-256 key length.
ra8_err_t ra8_rsip_protected_aes_finish(void)
Finalise the protected AES context.
RSIP protected-key HAL – crypto operations driven by wrappedkey blobs (the RSIP engine never sees the...
Renesas Secure IP (RSIP-E50D) register layout for the RA8D2.
@ k_ra8_rsip_dir_decrypt
Ciphertext -> Plaintext.
@ k_ra8_rsip_dir_encrypt
Plaintext -> Ciphertext.
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_secp521r1
NIST P-521.
@ k_ra8_rsip_curve_secp256r1
NIST P-256.
@ k_ra8_rsip_curve_secp256k1
secp256k1.
ra8_rsip_oem_cmd_t
OEM-key install opcode written to OEM_CTRL.
@ k_ra8_rsip_oem_cmd_rsa3072_priv
RSA-3072 private.
@ k_ra8_rsip_oem_cmd_ecc_secp521r1_priv
ECC NIST P-521 private.
@ k_ra8_rsip_oem_cmd_rsa4096_priv
RSA-4096 private.
@ k_ra8_rsip_oem_cmd_ecc_secp256r1_priv
ECC NIST P-256 private.
@ k_ra8_rsip_oem_cmd_ecc_secp256k1_priv
ECC secp256k1 private.
@ k_ra8_rsip_oem_cmd_ecc_secp384r1_priv
ECC NIST P-384 private.
@ k_ra8_rsip_oem_cmd_rsa2048_priv
RSA-2048 private.
@ k_ra8_rsip_oem_cmd_invalid
Sentinel / unused.
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.
ra8_rsip_aes_mode_t
Block-cipher mode selector for the AES engine.
Greppable stack-frame deviation marker.
#define RA8_STACK_BUDGET(bytes)
Marker macro recording an approved stack-frame deviation.
Opaque wrapped-key handle.
uint32_t body_words
Number of body words (1..261).
uint32_t body[k_ra8_rsip_handle_words_rsa4096_priv]
Wrapped body.
uint32_t alg
OEM-cmd algorithm selector.