ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_tls.c
Go to the documentation of this file.
1
26
27#include "ra8_tls.h"
28
29#include <stddef.h>
30#include <stdint.h>
31#include <string.h>
32
33#include "ra8_attributes.h"
34#include "ra8_check.h"
35#include "ra8_err.h"
36#include "ra8_log.h"
37
39typedef enum : uint8_t {
42
43#ifndef RA8_OFF_TARGET
44#include "mbedtls/error.h"
45#include "mbedtls/ssl.h"
46#include "mbedtls/x509_crt.h"
47#include "psa/crypto.h"
48#endif
49
50#ifdef RA8_OFF_TARGET
52static const char* const s_ra8_tls_fake_cipher = "off-target-loopback";
53#endif
54
55/* =============================================================================
56 * Logging tag
57 * =============================================================================
58 */
59
61static const char* const s_ra8_tls_tag = "ra8_tls";
62
63/* =============================================================================
64 * Pool slot definition
65 * =============================================================================
66 */
67
79 /* Field order places the aligned cfg block first so the host
80 * (RA8_OFF_TARGET) slot -- cfg, in_use, handshake_done -- carries no
81 * excess padding (clang-analyzer-optin.performance.Padding). */
83 bool in_use;
84#ifndef RA8_OFF_TARGET
85 mbedtls_ssl_context ssl;
86 mbedtls_ssl_config config;
87 mbedtls_x509_crt ca;
88#else
89 bool handshake_done;
90#endif
91};
92
95
97static bool s_initialized;
98
99/* =============================================================================
100 * Internal helpers
101 * =============================================================================
102 */
103
124static bool internal_handle_valid(const struct ra8_tls_session_handle* session)
125{
126 if (session == nullptr) {
127 return false;
128 }
129 const struct ra8_tls_session_handle* base = &s_session_pool[0];
131 if ((session < base) || (session >= end)) {
132 return false;
133 }
134 return session->in_use;
135}
136
144{
145 for (uint8_t i = 0U; i < (uint8_t)k_ra8_tls_max_sessions; ++i) {
146 if (!s_session_pool[i].in_use) {
147 return &s_session_pool[i];
148 }
149 }
150 return nullptr;
151}
152
168static void internal_pool_reset(void)
169{
170 for (uint8_t i = 0U; i < (uint8_t)k_ra8_tls_max_sessions; ++i) {
171 struct ra8_tls_session_handle* slot = &s_session_pool[i];
172#ifndef RA8_OFF_TARGET
173 if (slot->in_use) {
174 mbedtls_ssl_free(&slot->ssl);
175 mbedtls_ssl_config_free(&slot->config);
176 mbedtls_x509_crt_free(&slot->ca);
177 }
178#endif
179 (void)memset(slot, 0, sizeof(*slot));
180 }
181}
182
206static void internal_copy_cstr(char* dst, const char* src, size_t cap)
207{
208 const size_t last = cap - 1U;
209 size_t i = 0U;
210 while ((i < last) && (src[i] != '\0')) {
211 dst[i] = src[i];
212 ++i;
213 }
214 dst[i] = '\0';
215}
216
217/* =============================================================================
218 * Public API
219 * =============================================================================
220 */
221
223{
224 if (s_initialized) {
225 ra8_log_warn(s_ra8_tls_tag, "global_init called twice");
226 return k_ra8_err_exists;
227 }
228
230
231#ifndef RA8_OFF_TARGET
232 /* Mbed TLS 4.x sources randomness from the PSA crypto layer
233 * (``psa_generate_random``) rather than a facade-owned CTR_DRBG. Bring
234 * PSA online here; the actual entropy is pulled lazily on the first
235 * random draw through the application-supplied
236 * ``mbedtls_psa_external_get_random`` hook (RSIP TRNG on hardware). */
237 const psa_status_t psa_rc = psa_crypto_init();
238 if (psa_rc != PSA_SUCCESS) {
239 ra8_log_error(s_ra8_tls_tag, "psa_crypto_init failed");
240 return k_ra8_err_hw_error;
241 }
242#endif
243
244 s_initialized = true;
245 ra8_log_info(s_ra8_tls_tag, "global_init ok");
246 return k_ra8_ok;
247}
248
250{
251 if (!s_initialized) {
253 }
254
256 s_initialized = false;
257 return k_ra8_ok;
258}
259
289{
290 if (out_session == nullptr) {
292 }
293 *out_session = nullptr;
294
295 if (!s_initialized) {
297 }
298 if (cfg == nullptr) {
300 }
301 if ((cfg->bio_send == nullptr) || (cfg->bio_recv == nullptr)) {
303 }
304 return k_ra8_ok;
305}
306
307#ifndef RA8_OFF_TARGET
334{
335 int authmode = MBEDTLS_SSL_VERIFY_REQUIRED;
336 switch (cfg->verify_mode) {
338 authmode = MBEDTLS_SSL_VERIFY_NONE;
339 break;
341 authmode = MBEDTLS_SSL_VERIFY_OPTIONAL;
342 break;
345 default:
346 authmode = MBEDTLS_SSL_VERIFY_REQUIRED;
347 break;
348 }
349 mbedtls_ssl_conf_authmode(&slot->config, authmode);
350
351 mbedtls_x509_crt_init(&slot->ca);
352 if ((cfg->ca_pem != nullptr) && (cfg->ca_pem_len > 0U)) {
353 const int ca_rc =
354 mbedtls_x509_crt_parse(&slot->ca, (const unsigned char*)cfg->ca_pem, cfg->ca_pem_len);
355 if (ca_rc == 0) {
356 mbedtls_ssl_conf_ca_chain(&slot->config, &slot->ca, nullptr);
357 }
358 }
359}
360
390{
391 mbedtls_ssl_init(&slot->ssl);
392 mbedtls_ssl_config_init(&slot->config);
393
394 const int defaults_rc = mbedtls_ssl_config_defaults(&slot->config,
395 MBEDTLS_SSL_IS_CLIENT,
396 MBEDTLS_SSL_TRANSPORT_STREAM,
397 MBEDTLS_SSL_PRESET_DEFAULT);
398 if (defaults_rc != 0) {
399 mbedtls_ssl_free(&slot->ssl);
400 mbedtls_ssl_config_free(&slot->config);
401 (void)memset(slot, 0, sizeof(*slot));
403 }
404 /* No ``mbedtls_ssl_conf_rng`` on Mbed TLS 4.x: the SSL layer draws random
405 * bytes from PSA crypto, seeded through the app's external-RNG hook. */
407
408 const int setup_rc = mbedtls_ssl_setup(&slot->ssl, &slot->config);
409 if (setup_rc != 0) {
410 mbedtls_ssl_free(&slot->ssl);
411 mbedtls_ssl_config_free(&slot->config);
412 mbedtls_x509_crt_free(&slot->ca);
413 (void)memset(slot, 0, sizeof(*slot));
415 }
416
417 if (cfg->server_name != nullptr) {
418 (void)mbedtls_ssl_set_hostname(&slot->ssl, cfg->server_name);
419 }
420 /* Mbed TLS BIO send/recv signatures take ``unsigned char`` buffers; our
421 * facade-public typedefs use ``uint8_t`` so the cast below is layout-safe
422 * (the two types are identical on every supported target). */
423 mbedtls_ssl_set_bio(&slot->ssl,
424 slot->cfg.bio_ctx,
425 (mbedtls_ssl_send_t*)cfg->bio_send,
426 (mbedtls_ssl_recv_t*)cfg->bio_recv,
427 nullptr);
428 return k_ra8_ok;
429}
430#endif
431
433{
434 const ra8_err_t arg_rc = internal_session_validate_args(out_session, cfg);
435 if (arg_rc != k_ra8_ok) {
436 return arg_rc;
437 }
438
440 if (slot == nullptr) {
441 ra8_log_warn(s_ra8_tls_tag, "session pool exhausted");
442 return k_ra8_err_no_mem;
443 }
444
445 slot->in_use = true;
446 slot->cfg = *cfg;
447
448#ifndef RA8_OFF_TARGET
449 const ra8_err_t setup_rc = internal_session_mbedtls_setup(slot, cfg);
450 if (setup_rc != k_ra8_ok) {
451 return setup_rc;
452 }
453#else
454 slot->handshake_done = false;
455#endif
456
457 *out_session = slot;
458 return k_ra8_ok;
459}
460
462{
463 if (!s_initialized) {
465 }
466 if (!internal_handle_valid(session)) {
468 }
469
470#ifndef RA8_OFF_TARGET
471 mbedtls_ssl_free(&session->ssl);
472 mbedtls_ssl_config_free(&session->config);
473 mbedtls_x509_crt_free(&session->ca);
474#endif
475 (void)memset(session, 0, sizeof(*session));
476 return k_ra8_ok;
477}
478
480{
481 if (!s_initialized) {
483 }
484 if (!internal_handle_valid(session)) {
486 }
487
488#ifndef RA8_OFF_TARGET
489 const int rc = mbedtls_ssl_handshake(&session->ssl);
490 if (rc == 0) {
491 return k_ra8_ok;
492 }
493 if ((rc == MBEDTLS_ERR_SSL_WANT_READ) || (rc == MBEDTLS_ERR_SSL_WANT_WRITE)) {
495 }
496 ra8_log_error(s_ra8_tls_tag, "handshake failed");
498#else
499 /* Off-target path: drive a single round-trip through the BIO callbacks
500 * so the loopback test exercises the function-pointer plumbing without
501 * a real TLS handshake. */
502 uint8_t fake_byte = k_tls_content_handshake;
503 const int send_rc = session->cfg.bio_send(session->cfg.bio_ctx, &fake_byte, 1U);
504 if (send_rc < 0) {
506 }
507 uint8_t recv_byte = 0U;
508 const int recv_rc = session->cfg.bio_recv(session->cfg.bio_ctx, &recv_byte, 1U);
509 if (recv_rc < 0) {
511 }
512 session->handshake_done = true;
513 return k_ra8_ok;
514#endif
515}
516
517ra8_err_t ra8_tls_send(ra8_tls_session_t session, const uint8_t* buf, size_t len, size_t* out_sent)
518{
519 if (out_sent == nullptr) {
521 }
522 *out_sent = 0U;
523
524 if (!s_initialized) {
526 }
527 if (!internal_handle_valid(session)) {
529 }
530 if ((buf == nullptr) && (len > 0U)) {
532 }
533 if (len == 0U) {
534 return k_ra8_ok;
535 }
536
537#ifndef RA8_OFF_TARGET
538 const int rc = mbedtls_ssl_write(&session->ssl, buf, len);
539 if (rc >= 0) {
540 *out_sent = (size_t)rc;
541 return k_ra8_ok;
542 }
543 if ((rc == MBEDTLS_ERR_SSL_WANT_READ) || (rc == MBEDTLS_ERR_SSL_WANT_WRITE)) {
545 }
547#else
548 const int rc = session->cfg.bio_send(session->cfg.bio_ctx, buf, len);
549 if (rc < 0) {
551 }
552 *out_sent = (size_t)rc;
553 return k_ra8_ok;
554#endif
555}
556
557ra8_err_t ra8_tls_recv(ra8_tls_session_t session, uint8_t* buf, size_t len, size_t* out_received)
558{
559 if (out_received == nullptr) {
561 }
562 *out_received = 0U;
563
564 if (!s_initialized) {
566 }
567 if (!internal_handle_valid(session)) {
569 }
570 if ((buf == nullptr) && (len > 0U)) {
572 }
573 if (len == 0U) {
574 return k_ra8_ok;
575 }
576
577#ifndef RA8_OFF_TARGET
578 const int rc = mbedtls_ssl_read(&session->ssl, buf, len);
579 if (rc >= 0) {
580 *out_received = (size_t)rc;
581 return k_ra8_ok;
582 }
583 if ((rc == MBEDTLS_ERR_SSL_WANT_READ) || (rc == MBEDTLS_ERR_SSL_WANT_WRITE)) {
585 }
586 if (rc == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
587 return k_ra8_ok;
588 }
590#else
591 const int rc = session->cfg.bio_recv(session->cfg.bio_ctx, buf, len);
592 if (rc < 0) {
594 }
595 *out_received = (size_t)rc;
596 return k_ra8_ok;
597#endif
598}
599
601 uint16_t* out_id,
602 char* out_name,
603 size_t name_cap)
604{
605 if ((out_id == nullptr) || (out_name == nullptr) || (name_cap == 0U)) {
607 }
608 *out_id = 0U;
609 out_name[0] = '\0';
610
611 if (!s_initialized) {
613 }
614 if (!internal_handle_valid(session)) {
616 }
617
618#ifndef RA8_OFF_TARGET
619 const char* name = mbedtls_ssl_get_ciphersuite(&session->ssl);
620 if (name != nullptr) {
621 *out_id = (uint16_t)mbedtls_ssl_get_ciphersuite_id_from_ssl(&session->ssl);
622 internal_copy_cstr(out_name, name, name_cap);
623 }
624 return k_ra8_ok;
625#else
626 internal_copy_cstr(out_name, s_ra8_tls_fake_cipher, name_cap);
627 return k_ra8_ok;
628#endif
629}
630
632{
633 if (out_flags == nullptr) {
635 }
636 *out_flags = 0U;
637
638 if (!s_initialized) {
640 }
641 if (!internal_handle_valid(session)) {
643 }
644
645#ifndef RA8_OFF_TARGET
646 *out_flags = mbedtls_ssl_get_verify_result(&session->ssl);
647#endif
648 return k_ra8_ok;
649}
650
651ra8_err_t ra8_tls_mss_clamp(uint16_t mtu, uint16_t* out_mss)
652{
653 if (out_mss == nullptr) {
655 }
656 *out_mss = 0U;
657
658 const uint16_t overhead =
659 (uint16_t)((uint16_t)k_ra8_tls_ipv4_hdr_bytes + (uint16_t)k_ra8_tls_tcp_hdr_bytes);
660 if ((mtu <= overhead) || ((mtu - overhead) < (int)k_ra8_tls_mss_min)) {
662 }
663 *out_mss = (uint16_t)(mtu - overhead);
664 return k_ra8_ok;
665}
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.
static bool s_initialized
True once display_init has succeeded.
Error Code Definitions for ra8-firmware.
@ k_ra8_err_hw_init_failed
Hardware peripheral failed to initialise.
Definition ra8_err.h:290
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_err_would_block
Non-blocking operation would have blocked.
Definition ra8_err.h:210
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_exists
Item already exists – cannot create again.
Definition ra8_err.h:216
@ k_ra8_err_not_initialized
Module not initialized – _init() not yet called successfully.
Definition ra8_err.h:235
@ 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
@ k_ra8_err_comm_error
Generic communication error (use a more specific code when possible).
Definition ra8_err.h:399
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.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_warn(tag, message)
RA8 log warn.
Definition ra8_log.h:347
#define ra8_log_info(tag, message)
RA8 log info.
Definition ra8_log.h:364
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
ra8_err_t ra8_tls_get_verify_result(ra8_tls_session_t session, uint32_t *out_flags)
Report the peer-certificate verification result for a session.
Definition ra8_tls.c:631
static ra8_err_t internal_session_validate_args(ra8_tls_session_t *out_session, const ra8_tls_session_cfg_t *cfg)
Validate ra8_tls_session_open inputs before slot acquisition.
Definition ra8_tls.c:287
static struct ra8_tls_session_handle s_session_pool[k_ra8_tls_max_sessions]
Per-session state pool sized at compile time.
Definition ra8_tls.c:94
static void internal_pool_reset(void)
Reset every pool slot to a known-clean state.
Definition ra8_tls.c:168
static struct ra8_tls_session_handle * internal_pool_acquire(void)
Locate the first free slot in the pool.
Definition ra8_tls.c:143
ra8_err_t ra8_tls_send(ra8_tls_session_t session, const uint8_t *buf, size_t len, size_t *out_sent)
Encrypt and send application data.
Definition ra8_tls.c:517
ra8_err_t ra8_tls_recv(ra8_tls_session_t session, uint8_t *buf, size_t len, size_t *out_received)
Decrypt and receive application data.
Definition ra8_tls.c:557
static ra8_err_t internal_session_mbedtls_setup(struct ra8_tls_session_handle *slot, const ra8_tls_session_cfg_t *cfg)
Run the Mbed TLS init/config/setup sequence for a fresh slot.
Definition ra8_tls.c:388
ra8_err_t ra8_tls_session_open(ra8_tls_session_t *out_session, const ra8_tls_session_cfg_t *cfg)
Allocate a TLS session from the static pool.
Definition ra8_tls.c:432
static const char *const s_ra8_tls_tag
Logging tag prefix used by every ra8_tls log line.
Definition ra8_tls.c:61
ra8_err_t ra8_tls_session_close(ra8_tls_session_t session)
Release a TLS session back to the pool.
Definition ra8_tls.c:461
static bool internal_handle_valid(const struct ra8_tls_session_handle *session)
Validate that a typed handle points into the static pool.
Definition ra8_tls.c:124
ra8_err_t ra8_tls_handshake(ra8_tls_session_t session)
Iterative TLS handshake driver.
Definition ra8_tls.c:479
static void internal_apply_verify_cfg(struct ra8_tls_session_handle *slot, const ra8_tls_session_cfg_t *cfg)
Apply the caller's verify-mode and optional trust anchor to a slot.
Definition ra8_tls.c:332
static void internal_copy_cstr(char *dst, const char *src, size_t cap)
Bounded, always-NUL-terminating C-string copy.
Definition ra8_tls.c:206
ra8_err_t ra8_tls_get_cipher_suite(ra8_tls_session_t session, uint16_t *out_id, char *out_name, size_t name_cap)
Report the negotiated cipher suite for a session.
Definition ra8_tls.c:600
ra8_err_t ra8_tls_mss_clamp(uint16_t mtu, uint16_t *out_mss)
Compute the TCP MSS that keeps a segment inside one MTU frame.
Definition ra8_tls.c:651
ra8_err_t ra8_tls_global_deinit(void)
Symmetric tear-down for ra8_tls_global_init.
Definition ra8_tls.c:249
ra8_err_t ra8_tls_global_init(void)
One-shot facade initialisation.
Definition ra8_tls.c:222
tls_content_type_t
TLS record content type: Handshake (22).
Definition ra8_tls.c:39
@ k_tls_content_handshake
TLS content handshake.
Definition ra8_tls.c:40
Tiny TLS facade over the vendored Mbed TLS 4.x stack.
struct ra8_tls_session_handle * ra8_tls_session_t
Opaque TLS session handle (typed pointer into the static pool).
Definition ra8_tls.h:277
@ k_ra8_tls_max_sessions
Maximum simultaneous TLS sessions handed out by the pool.
Definition ra8_tls.h:107
@ k_ra8_tls_verify_default
Facade default – same as required.
Definition ra8_tls.h:155
@ k_ra8_tls_verify_required
Verify and abort the handshake on fail.
Definition ra8_tls.h:158
@ k_ra8_tls_verify_none
Do not verify the peer certificate.
Definition ra8_tls.h:156
@ k_ra8_tls_verify_optional
Verify but do not abort on failure.
Definition ra8_tls.h:157
@ k_ra8_tls_tcp_hdr_bytes
TCP header with no options.
Definition ra8_tls.h:136
@ k_ra8_tls_mss_min
Smallest MSS worth clamping to.
Definition ra8_tls.h:138
@ k_ra8_tls_ipv4_hdr_bytes
IPv4 header with no options.
Definition ra8_tls.h:135
Per-session configuration handed to ra8_tls_session_open.
Forward declaration of the pool slot type.
Definition ra8_tls.c:78
mbedtls_ssl_config config
Mbed TLS SSL configuration block.
Definition ra8_tls.c:86
mbedtls_ssl_context ssl
Mbed TLS SSL context.
Definition ra8_tls.c:85
mbedtls_x509_crt ca
Parsed trust anchor (if cfg.ca_pem).
Definition ra8_tls.c:87
bool in_use
Slot allocated.
Definition ra8_tls.c:83
ra8_tls_session_cfg_t cfg
Cached caller configuration.
Definition ra8_tls.c:82