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

Functions

bool optiga_manager_init (callback_handler_t callback, void *context)
 Bring up the OPTIGA stack (idempotent); task context only — false if the chip did not answer.
optiga_util_t * optiga_manager_acquire (void)
 The shared optiga_util instance; NULL until optiga_manager_init() has run.
void optiga_manager_release (void)
 Release the acquired instance — exactly one per non-NULL acquire, on every exit.
bool optiga_manager_lock (void)
 Take the manager mutex; false when never initialised — the real "is the manager up?" test.
void optiga_manager_unlock (void)
 One unlock per successful lock, every early exit included; release a touch hold first.
bool optiga_chip_enter (void)
 Open a chip session (re-entrant per task); false is fatal for this call — and NOT an init check.
void optiga_chip_exit (void)
 One exit per successful enter; never call it after a failed enter.

Detailed Description

Seven functions — ownership of the single OPTIGA instance. The chip is one device behind one I2C bus, shared by the MQTT/TLS path, the HSM provisioning screen and the MicroPython optiga module; everything that touches it goes through here. Three of the seven are aliases of one another in the archive — optiga_manager_release(), optiga_manager_unlock() and optiga_chip_exit() all decrement the same re-entrant depth counter — which is why the pairing rules on each entry are strict.

Variant
mtb-mpy and mtb-only

Function Documentation

◆ optiga_manager_init()

bool optiga_manager_init ( callback_handler_t callback,
void * context )

Bring up the OPTIGA stack (idempotent); task context only — false if the chip did not answer.

Bring up the OPTIGA stack. Returns false if the chip did not answer.

Contract
Brings up the OPTIGA stack; false if the chip did not answer. Task context only — from main() before vTaskStartScheduler() it reaches xTimerCreate() inside a critical section with no scheduler (ipc_hsm_handler.c:1357-1364). Idempotent (returns true if already initialised) and internally serialised. The caller supplies optiga_util_callback — a consumer-provided extern (What the consumer must provide). optiga_trust_open_application() is a separate step: init alone does not open the application, and the shipped prov_open_held() does both under one touch hold. Skipping init made every TLS CertificateVerify fail (mqtt_mtls_setup.c:184-201) — the mTLS setup now calls it first and releases its touch hold on the failure branch.
Variant
mtb-mpy and mtb-only
static bool prov_open_held(void)
{
bool ok;
optiga_manager_touch_hold_reason("Opening the secure element");
return ok;
}
/* ...context: inside mqtt_mtls_setup() ... */
printf("[mTLS] optiga_manager_init failed — signing would be impossible\n");
return false;
}

◆ optiga_manager_acquire()

optiga_util_t * optiga_manager_acquire ( void )

The shared optiga_util instance; NULL until optiga_manager_init() has run.

The shared optiga_util instance, or NULL before init.

Contract
The shared optiga_util instance. Returns NULL until optiga_manager_init() has run (ipc_hsm_handler.c:1442-1445). On NULL, do not call optiga_manager_release() — the implementation has already exited the gate (tesaiot_optiga_manager.c:266-269). On non-NULL, exactly one release() per exit path, errors included. The OPTIGA host library is asynchronous: set optiga_lib_status = OPTIGA_LIB_BUSY before the call and poll it afterwards. Every caller is template-side (optiga_trust_helpers.c ×14, tesaiot_pu_ingest.c ×4); acquire itself wraps optiga_chip_enter().
Variant
mtb-mpy and mtb-only
/* ...context: inside the certificate read helper ... */
// Acquire OPTIGA instance (thread-safe)
optiga_util_t *me_util = optiga_manager_acquire();
if (!me_util) {
printf("%s ERROR: OPTIGA instance not available\n", LABEL_SUBSCRIBER);
vPortFree(cert_der);
return CY_RSLT_TYPE_ERROR;
}
// Perform async read
optiga_lib_status = OPTIGA_LIB_BUSY;
optiga_lib_status_t status = optiga_util_read_data(me_util, oid, 0, cert_der, &cert_len);
if (OPTIGA_LIB_SUCCESS != status) {
printf("%s ERROR: OPTIGA read failed (0x%04X)\n", LABEL_SUBSCRIBER, status);
vPortFree(cert_der);
return CY_RSLT_TYPE_ERROR;
}
// Wait for read completion (max 2 seconds)
TickType_t start = xTaskGetTickCount();
TickType_t timeout = pdMS_TO_TICKS(2000);
while (optiga_lib_status == OPTIGA_LIB_BUSY && (xTaskGetTickCount() - start) < timeout) {
vTaskDelay(pdMS_TO_TICKS(100));
}
if (optiga_lib_status != OPTIGA_LIB_SUCCESS) {
printf("%s ERROR: OPTIGA read timeout/failed (0x%04X)\n", LABEL_SUBSCRIBER, optiga_lib_status);
vPortFree(cert_der);
return CY_RSLT_TYPE_ERROR;
}

◆ optiga_manager_release()

void optiga_manager_release ( void )

Release the acquired instance — exactly one per non-NULL acquire, on every exit.

Release the instance taken with optiga_manager_acquire().

Contract
Releases the instance taken with optiga_manager_acquire(). Exactly one per non-NULL acquire, on every exit including errors — the lifted function below has three exits (tesaiot_pu_ingest.c:242, :256, :261) and each releases. It is an alias for optiga_chip_exit() and decrements the same re-entrant depth counter, so an extra release unbalances a caller higher up the stack.
Variant
mtb-mpy and mtb-only
/* ...context: inside the certificate read helper ... */
// Acquire OPTIGA instance (thread-safe)
optiga_util_t *me_util = optiga_manager_acquire();
if (!me_util) {
printf("%s ERROR: OPTIGA instance not available\n", LABEL_SUBSCRIBER);
vPortFree(cert_der);
return CY_RSLT_TYPE_ERROR;
}
// Perform async read
optiga_lib_status = OPTIGA_LIB_BUSY;
optiga_lib_status_t status = optiga_util_read_data(me_util, oid, 0, cert_der, &cert_len);
if (OPTIGA_LIB_SUCCESS != status) {
printf("%s ERROR: OPTIGA read failed (0x%04X)\n", LABEL_SUBSCRIBER, status);
vPortFree(cert_der);
return CY_RSLT_TYPE_ERROR;
}
// Wait for read completion (max 2 seconds)
TickType_t start = xTaskGetTickCount();
TickType_t timeout = pdMS_TO_TICKS(2000);
while (optiga_lib_status == OPTIGA_LIB_BUSY && (xTaskGetTickCount() - start) < timeout) {
vTaskDelay(pdMS_TO_TICKS(100));
}
if (optiga_lib_status != OPTIGA_LIB_SUCCESS) {
printf("%s ERROR: OPTIGA read timeout/failed (0x%04X)\n", LABEL_SUBSCRIBER, optiga_lib_status);
vPortFree(cert_der);
return CY_RSLT_TYPE_ERROR;
}

◆ optiga_manager_lock()

bool optiga_manager_lock ( void )

Take the manager mutex; false when never initialised — the real "is the manager up?" test.

Take and release the manager mutex. Task context only.

Contract
Takes the manager mutex; task context only. Returns false when the manager was never initialised (tesaiot_optiga_manager.c:342-348) — this, not optiga_chip_enter(), is the correct "is the manager up?" test. Order inside a transaction: lock → touch_hold → work → touch_release → unlock. Never open the OPTIGA application while holding the lock — optiga_trust_helpers.c:4628-4636 shows the required order, optiga_trust_open_application() first, optiga_manager_lock() second. On a false return, return an error; do not proceed and do not unlock.
Variant
mtb-mpy and mtb-only
/* ...context: inside trustm_ecdsa_sign() ... */
/* Lock OPTIGA mutex for thread-safe access */
printf("optiga_manager_lock failed\n");
return OPTIGA_LIB_BUSY;
}
/* Keep CM55 touch off SCB5 for the whole transaction — the secure element
* and the touch controller share the bus, and the TLS handshake signs after
* the mTLS setup has already resumed touch polling. */
/* ...context: inside trustm_ecdsa_sign(), the single exit path ... */

◆ optiga_manager_unlock()

void optiga_manager_unlock ( void )

One unlock per successful lock, every early exit included; release a touch hold first.

Contract
One unlock per successful lock, including every early exit (the !crypt branch in the textbook below). When a touch hold was also taken, release the hold before unlocking (optiga_trust_helpers.c:1721-1722). Alias for optiga_chip_exit(). The compiled exemplar is the release/unlock pair shown under optiga_manager_lock(); the clearest lock/unlock shape in the tree is quoted next — shipped reference, not compiled by proj_cm33_ns (tesaiot_crypto.c is in no SOURCES list; lift it as idiom only).
Variant
mtb-mpy and mtb-only
/* shipped reference, not compiled by proj_cm33_ns */
/* ...context: inside the TRNG random_generate helper ... */
if (!optiga_manager_is_initialized()) {
return TESAIOT_ERROR_NOT_INITIALIZED;
}
return TESAIOT_ERROR_TIMEOUT;
}
volatile optiga_lib_status_t optiga_status = OPTIGA_LIB_BUSY;
optiga_crypt_t *crypt = optiga_manager_create_crypt(crypto_callback,
(void *)&optiga_status);
if (!crypt) {
return TESAIOT_ERROR_OPTIGA;
}
optiga_lib_status_t result = optiga_crypt_random(crypt,
OPTIGA_RNG_TYPE_TRNG,
buffer,
length);
int rc = TESAIOT_ERROR_OPTIGA;
if (result == OPTIGA_LIB_SUCCESS) {
rc = crypto_wait_for_completion(&optiga_status);
}
optiga_crypt_destroy(crypt);

◆ optiga_chip_enter()

bool optiga_chip_enter ( void )

Open a chip session (re-entrant per task); false is fatal for this call — and NOT an init check.

Open and close a chip session around a burst of operations.

Contract
Opens a chip session around a burst of operations. Re-entrant per FreeRTOS task — nesting is free, so a callee that also enters does not deadlock on its caller. A false return means another task holds the chip; that is fatal for this call — return an error, never proceed. The touch hold is taken inside the gate and released before optiga_chip_exit(). NOT an init check: it deliberately returns true when the manager was never initialised (tesaiot_optiga_manager.c:157-169); use optiga_manager_lock() for that. Getting this backwards is the documented cause of several ungated-access defects. The two enrolment journeys never call it directly — they reach it through lock/unlock and acquire/release, which wrap it (tesaiot_optiga_manager.c:340-365).
Variant
mtb-mpy and mtb-only
int optiga_verify_cert_key_pair(uint16_t cert_oid, uint16_t key_oid)
{
int rc;
/* Two tasks call this: the MQTT subscriber after installing a certificate,
* and the provisioning task when its wait ends. They share cert_pem - a 2 KB
* static - and the library's single global status. The gate is re-entrant, so
* the certificate read and the signature inside still take it, without
* deadlocking on this one. */
return -5; /* the chip is busy elsewhere; a verdict now would be a guess */
}
optiga_manager_touch_hold_reason("Checking certificate against its key");
rc = verify_cert_key_pair_locked(cert_oid, key_oid);
return rc;
}

◆ optiga_chip_exit()

void optiga_chip_exit ( void )

One exit per successful enter; never call it after a failed enter.

Contract
One exit per successful enter; never call it after a failed enter — the deferred-close pattern below returns early at the failed-enter branch without exiting, and defers the close to the next balanced one ("closing under another task's transaction is worse than deferring the close"). Ownership is checked per task in the implementation.
Variant
mtb-mpy and mtb-only
{
/* Closing under another task's transaction is worse than deferring the
* close: the reference stays, and the next balanced close will do it. */
optiga_lib_print_message("close deferred: the chip is busy elsewhere",
OPTIGA_UTIL_SERVICE, OPTIGA_UTIL_SERVICE_COLOR);
return;
}
optiga_trust_close_application_gated();
}