SDK for TESAIoT Dev Kit
API reference & tutorials (ModusToolbox)
Loading...
Searching...
No Matches

Functions

void bento_devmode_init (void)
 Idempotent; seeds the 32-byte RAM secret. Every public devmode entry self-calls it.
void bento_devmode_nonce_issue (uint8_t nonce_out[BENTO_DEVMODE_NONCE_LEN])
 Fill a fresh 16-byte nonce, overwriting any pending one; starts the TTL clock.
bool bento_devmode_unlock (const char *hmac_hex, size_t hmac_hex_len)
 Verify the HMAC against the pending nonce; consumes the nonce on any call (one-shot).
void bento_devmode_lock (void)
 Clear the unlocked flag.
bool bento_devmode_is_unlocked (void)
 Whether privileged verbs (bento.exec) are permitted right now.
size_t bento_devmode_secret_hex (char *out, size_t out_sz)
 The secret as 64 hex chars + NUL, or 0 if the buffer is too small; never log it to UART.
void bento_devmode_emit_provision (void)
 Emit the provision event once per boot on the CONNECTED transition; a failed send retries.
size_t bento_devmode_secret_fp_hex (char *out, size_t out_sz)
 First 4 bytes of SHA-256(secret) as 8 hex chars + NUL — safe to log.

Detailed Description

Eight functions: the developer-mode unlock, bento_devmode_*. Compiled only with ENABLE_PAGE_BENTO_BUDDY=1 (default 0, proj_cm33_ns/Makefile:64, :305); rebuild after make getlibs — Flag gate (read first).

Declarations: bento_devmode.h. The implementation is archived in libbento_secure.a. The shared secret is RAM-only and regenerated every boot (OPTIGA slot 0xE120 persistence is deferred) — the desktop must re-provision after every reboot. Nonce TTL is BENTO_DEVMODE_NONCE_TTL_MS (60000); there is one in-flight challenge.

What this challenge/response does and does not protect.** Provisioning works by sending the secret in plaintext to the first peer that connects (Devmode, bento_devmode_emit_provision) over a TX characteristic that carries no GATTDB_PERM_AUTH_* bit, and the secret comes from an xorshift32 with under 32 bits of entropy. The HMAC step itself is sound; the net effect is a gate that keeps out a peer connecting second and no one else — a deterrent, not an enforcement boundary.

Variant
mtb-mpy and mtb-only

Function Documentation

◆ bento_devmode_init()

void bento_devmode_init ( void )

Idempotent; seeds the 32-byte RAM secret. Every public devmode entry self-calls it.

Contract
Idempotent (guarded by an internal secret-ready flag). No external caller is required — every public devmode entry point self-calls it (bento_devmode_nonce_issue(), bento_devmode_secret_hex(), bento_devmode_secret_fp_hex(), bento_devmode_emit_provision()). No locking. Seeds a PRNG and fills the 32-byte secret. Template call sites: 0 (archived: 4).

Quality of the secret.** The PRNG is xorshift32, seeded from the FreeRTOS tick, a stack address and one constant — under 32 bits of entropy, and not cryptographically strong. The OPTIGA RNG is not used. Moving to a chip-supplied seed is open work.

Variant
mtb-mpy and mtb-only

◆ bento_devmode_nonce_issue()

void bento_devmode_nonce_issue ( uint8_t nonce_out[BENTO_DEVMODE_NONCE_LEN])

Fill a fresh 16-byte nonce, overwriting any pending one; starts the TTL clock.

Contract
Fills a fresh 16-byte nonce, overwriting any pending one, and starts the TTL clock. Self-inits. Template call sites: 0; called only inside the archive (from the bento.devmode.nonce verb handler).
Variant
mtb-mpy and mtb-only

◆ bento_devmode_unlock()

bool bento_devmode_unlock ( const char * hmac_hex,
size_t hmac_hex_len )

Verify the HMAC against the pending nonce; consumes the nonce on any call (one-shot).

Contract
Verifies an HMAC-SHA256 hex string against the pending nonce and the secret; true on match and unexpired TTL, which sets the unlocked flag. Consumes the nonce on any call (one-shot, replay protection). Template call sites: 0; called only inside the archive (from the bento.devmode.unlock verb handler, which passes the hex string straight from the JSON token, not NUL-terminated).
Variant
mtb-mpy and mtb-only

◆ bento_devmode_lock()

void bento_devmode_lock ( void )

Clear the unlocked flag.

Contract
Clears the unlocked flag. Template call sites: 0; called only inside the archive (from the bento.devmode.lock verb handler).
Variant
mtb-mpy and mtb-only

◆ bento_devmode_is_unlocked()

bool bento_devmode_is_unlocked ( void )

Whether privileged verbs (bento.exec) are permitted right now.

Contract
Whether privileged verbs (bento.exec) are permitted right now. Template call sites: 0; called only inside the archive (from the bento.exec verb handler, as its gate check, and from the status JSON builder).
Variant
mtb-mpy and mtb-only

◆ bento_devmode_secret_hex()

size_t bento_devmode_secret_hex ( char * out,
size_t out_sz )

The secret as 64 hex chars + NUL, or 0 if the buffer is too small; never log it to UART.

Contract
Writes the secret as 64 hex chars + NUL; returns the length written or 0 if the buffer is too small — check for 0. The caller must not log this to UART. Template call sites: 0; called inside the archive by bento_devmode_emit_provision().
Variant
mtb-mpy and mtb-only

◆ bento_devmode_emit_provision()

void bento_devmode_emit_provision ( void )

Emit the provision event once per boot on the CONNECTED transition; a failed send retries.

Contract
Emits {"evt":"bento.devmode.provision","secret":"<64 hex>"} over NUS once per boot (static already-sent flag; a failed send leaves it unset so the next CONNECTED transition retries). Wired into the CONNECTED transition in the ble_nus module's implementation, paired with bento_fw_emit_boot_complete(). Without this emit every bento.devmode.unlock answers not_permitted. Template call sites: 0; called only inside the archive (from the link-state callback, on that CONNECTED transition).

State the security consequence exactly.** This function sends the secret in plaintext to the first peer that connects after boot, and the TX characteristic carries no GATTDB_PERM_AUTH_* bit (see GATT data), so an unpaired peer receives it. The HMAC-SHA256 step itself is sound, but possession of the key is not restricted to an authorised desktop. The gate keeps out a peer that connects second and no one else — a deterrent, not an enforcement boundary.

Variant
mtb-mpy and mtb-only

◆ bento_devmode_secret_fp_hex()

size_t bento_devmode_secret_fp_hex ( char * out,
size_t out_sz )

First 4 bytes of SHA-256(secret) as 8 hex chars + NUL — safe to log.

Contract
First 4 bytes of SHA-256(secret) as 8 hex chars + NUL — safe to log; lets desktop and firmware confirm they hold the same secret without leaking it. Returns length written, 0 if the buffer is too small. Template call sites: 0 (archived: 3 — once in bento_devmode_emit_provision(), twice in the bento.devmode.unlock verb handler).
Variant
mtb-mpy and mtb-only