diff --git a/components/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c b/components/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c index 380da2edb5..9fe47212bc 100644 --- a/components/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c +++ b/components/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,9 +33,131 @@ #include "esp_err.h" #include "esp_blufi.h" #include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "soc/soc_caps.h" #if (BLUFI_INCLUDED == TRUE) +#if !SOC_MPI_SUPPORTED +#define BLUFI_RX_QUEUE_LEN 8 +#define BLUFI_RX_TASK_STACK_SIZE 4096 +#define BLUFI_RX_TASK_PRIO (tskIDLE_PRIORITY + 1) + +typedef struct { + uint8_t *data; + uint16_t len; +} blufi_rx_item_t; + +static QueueHandle_t s_blufi_rx_queue; +static TaskHandle_t s_blufi_rx_task_hdl; + +static void blufi_rx_task(void *arg) +{ + blufi_rx_item_t item; + + while (xQueueReceive(s_blufi_rx_queue, &item, portMAX_DELAY) == pdTRUE) { + if (item.data == NULL) { + break; + } + + btc_blufi_recv_handler(item.data, item.len); + free(item.data); + } + + s_blufi_rx_task_hdl = NULL; + vTaskDelete(NULL); +} + +static int blufi_rx_worker_start(void) +{ + if (s_blufi_rx_queue != NULL && s_blufi_rx_task_hdl != NULL) { + return 0; + } + + if (s_blufi_rx_queue != NULL && s_blufi_rx_task_hdl == NULL) { + blufi_rx_item_t item; + while (xQueueReceive(s_blufi_rx_queue, &item, 0) == pdTRUE) { + free(item.data); + } + vQueueDelete(s_blufi_rx_queue); + s_blufi_rx_queue = NULL; + } + + s_blufi_rx_queue = xQueueCreate(BLUFI_RX_QUEUE_LEN, sizeof(blufi_rx_item_t)); + if (s_blufi_rx_queue == NULL) { + BTC_TRACE_ERROR("failed to create BLUFI RX queue"); + return -1; + } + + BaseType_t ret = xTaskCreate(blufi_rx_task, "blufi_rx", BLUFI_RX_TASK_STACK_SIZE, + NULL, BLUFI_RX_TASK_PRIO, &s_blufi_rx_task_hdl); + if (ret != pdPASS) { + BTC_TRACE_ERROR("failed to create BLUFI RX task"); + vQueueDelete(s_blufi_rx_queue); + s_blufi_rx_queue = NULL; + return -1; + } + + return 0; +} + +static void blufi_rx_worker_stop(void) +{ + if (s_blufi_rx_queue == NULL) { + return; + } + + blufi_rx_item_t stop = { .data = NULL, .len = 0 }; + if (xQueueSend(s_blufi_rx_queue, &stop, 0) != pdTRUE) { + blufi_rx_item_t item; + while (xQueueReceive(s_blufi_rx_queue, &item, 0) == pdTRUE) { + free(item.data); + } + (void)xQueueSend(s_blufi_rx_queue, &stop, 0); + } + + while (s_blufi_rx_task_hdl != NULL) { + vTaskDelay(pdMS_TO_TICKS(10)); + } + + blufi_rx_item_t item; + while (xQueueReceive(s_blufi_rx_queue, &item, 0) == pdTRUE) { + free(item.data); + } + + vQueueDelete(s_blufi_rx_queue); + s_blufi_rx_queue = NULL; +} + +static bool blufi_rx_enqueue(const uint8_t *data, uint16_t len) +{ + if (len == 0) { + return false; + } + + if (s_blufi_rx_queue == NULL) { + if (blufi_rx_worker_start() != 0) { + return false; + } + } + + uint8_t *copy = malloc(len); + if (copy == NULL) { + return false; + } + memcpy(copy, data, len); + + blufi_rx_item_t item = { .data = copy, .len = len }; + if (xQueueSend(s_blufi_rx_queue, &item, 0) != pdTRUE) { + free(copy); + return false; + } + return true; +} +#endif /* !SOC_MPI_SUPPORTED */ + static uint8_t server_if; static uint16_t conn_id; static uint8_t blufi_service_uuid128[32] = { @@ -241,7 +363,6 @@ void blufi_create_service(void) uint8_t esp_blufi_init(void) { - /* register the BLUFI profile to the BTA_GATTS module*/ BTA_GATTS_AppRegister(&blufi_app_uuid, blufi_profile_cb); return GATT_SUCCESS; @@ -363,8 +484,15 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) } if (p_data->req_data.p_data->write_req.handle == blufi_env.handle_char_p2e) { +#if !SOC_MPI_SUPPORTED + if (!blufi_rx_enqueue(&p_data->req_data.p_data->write_req.value[0], + p_data->req_data.p_data->write_req.len)) { + BLUFI_TRACE_ERROR("failed to enqueue BLUFI RX data"); + } +#else btc_blufi_recv_handler(&p_data->req_data.p_data->write_req.value[0], p_data->req_data.p_data->write_req.len); +#endif } break; } @@ -375,7 +503,13 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) GATT_SUCCESS, NULL); if (blufi_env.prepare_buf && p_data->req_data.p_data->exec_write == GATT_PREP_WRITE_EXEC) { +#if !SOC_MPI_SUPPORTED + if (!blufi_rx_enqueue(blufi_env.prepare_buf, blufi_env.prepare_len)) { + BLUFI_TRACE_ERROR("failed to enqueue BLUFI RX exec data"); + } +#else btc_blufi_recv_handler(blufi_env.prepare_buf, blufi_env.prepare_len); +#endif } if (blufi_env.prepare_buf) { @@ -523,6 +657,9 @@ void esp_blufi_send_notify(void *arg) void esp_blufi_deinit(void) { +#if !SOC_MPI_SUPPORTED + blufi_rx_worker_stop(); +#endif BTA_GATTS_StopService(blufi_env.handle_srvc); BTA_GATTS_DeleteService(blufi_env.handle_srvc); /* register the BLUFI profile to the BTA_GATTS module*/ diff --git a/components/bt/common/btc/profile/esp/blufi/nimble_host/esp_blufi.c b/components/bt/common/btc/profile/esp/blufi/nimble_host/esp_blufi.c index 4813e55308..83f27f82e2 100644 --- a/components/bt/common/btc/profile/esp/blufi/nimble_host/esp_blufi.c +++ b/components/bt/common/btc/profile/esp/blufi/nimble_host/esp_blufi.c @@ -18,6 +18,9 @@ #include "esp_blufi.h" #include "osi/allocator.h" #include "console/console.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" /*nimBLE Host*/ #include "nimble/nimble_port.h" @@ -29,6 +32,7 @@ #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" +#include "soc/soc_caps.h" #if (BLUFI_INCLUDED == TRUE) @@ -37,6 +41,104 @@ static uint8_t own_addr_type; struct gatt_value gatt_values[SERVER_MAX_VALUES]; const static char *TAG = "BLUFI_EXAMPLE"; +#if !SOC_MPI_SUPPORTED +#define BLUFI_RX_QUEUE_LEN 8 +#define BLUFI_RX_TASK_STACK_SIZE 8192 +#define BLUFI_RX_TASK_PRIO (tskIDLE_PRIORITY + 1) + +typedef struct { + uint8_t *data; + uint16_t len; +} blufi_rx_item_t; + +static QueueHandle_t s_blufi_rx_queue; +static TaskHandle_t s_blufi_rx_task_hdl; + +static void blufi_rx_task(void *arg) +{ + blufi_rx_item_t item; + + while (xQueueReceive(s_blufi_rx_queue, &item, portMAX_DELAY) == pdTRUE) { + if (item.data == NULL) { + break; + } + + btc_blufi_recv_handler(item.data, item.len); + free(item.data); + } + + s_blufi_rx_task_hdl = NULL; + vTaskDelete(NULL); +} + +static int blufi_rx_worker_start(void) +{ + if (s_blufi_rx_queue != NULL && s_blufi_rx_task_hdl != NULL) { + return 0; + } + + if (s_blufi_rx_queue != NULL && s_blufi_rx_task_hdl == NULL) { + /* Recover from partial state: stale queue left after worker exit. */ + blufi_rx_item_t item; + while (xQueueReceive(s_blufi_rx_queue, &item, 0) == pdTRUE) { + free(item.data); + } + vQueueDelete(s_blufi_rx_queue); + s_blufi_rx_queue = NULL; + } + + s_blufi_rx_queue = xQueueCreate(BLUFI_RX_QUEUE_LEN, sizeof(blufi_rx_item_t)); + if (s_blufi_rx_queue == NULL) { + ESP_LOGE(TAG, "failed to create BLUFI RX queue"); + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + BaseType_t ret = xTaskCreate(blufi_rx_task, "blufi_rx", BLUFI_RX_TASK_STACK_SIZE, + NULL, BLUFI_RX_TASK_PRIO, &s_blufi_rx_task_hdl); + if (ret != pdPASS) { + ESP_LOGE(TAG, "failed to create BLUFI RX task"); + vQueueDelete(s_blufi_rx_queue); + s_blufi_rx_queue = NULL; + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + return 0; +} + +static void blufi_rx_worker_stop(void) +{ + if (s_blufi_rx_queue == NULL) { + return; + } + + blufi_rx_item_t stop = { + .data = NULL, + .len = 0, + }; + if (xQueueSend(s_blufi_rx_queue, &stop, 0) != pdTRUE) { + /* Queue is full; free pending packets and resend stop marker. */ + blufi_rx_item_t item; + while (xQueueReceive(s_blufi_rx_queue, &item, 0) == pdTRUE) { + free(item.data); + } + (void)xQueueSend(s_blufi_rx_queue, &stop, 0); + } + + while (s_blufi_rx_task_hdl != NULL) { + vTaskDelay(pdMS_TO_TICKS(10)); + } + + /* Drain and free any queued packets before deleting the queue. */ + blufi_rx_item_t item; + while (xQueueReceive(s_blufi_rx_queue, &item, 0) == pdTRUE) { + free(item.data); + } + + vQueueDelete(s_blufi_rx_queue); + s_blufi_rx_queue = NULL; +} +#endif /* !SOC_MPI_SUPPORTED */ + enum { GATT_VALUE_TYPE_CHR, GATT_VALUE_TYPE_DSC, @@ -142,13 +244,30 @@ static size_t write_value(uint16_t conn_handle, uint16_t attr_handle, return BLE_ATT_ERR_UNLIKELY; } - btc_blufi_recv_handler(flat_buf, pkt_len); - if (value->buf != NULL) { os_mbuf_free_chain(value->buf); value->buf = NULL; } +#if !SOC_MPI_SUPPORTED + if (s_blufi_rx_queue == NULL) { + free(flat_buf); + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + if (pkt_len > 0) { + blufi_rx_item_t item = { + .data = flat_buf, + .len = pkt_len, + }; + if (xQueueSend(s_blufi_rx_queue, &item, 0) != pdTRUE) { + free(flat_buf); + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + } else { + free(flat_buf); + } +#else /* SOC_MPI_SUPPORTED */ value->buf = os_msys_get(0, 0); if (value->buf == NULL) { free(flat_buf); @@ -164,7 +283,9 @@ static size_t write_value(uint16_t conn_handle, uint16_t attr_handle, } } + btc_blufi_recv_handler(flat_buf, pkt_len); free(flat_buf); +#endif return 0; } @@ -278,16 +399,30 @@ static void deinit_gatt_values(void) int esp_blufi_gatt_svr_init(void) { int rc; + +#if !SOC_MPI_SUPPORTED + rc = blufi_rx_worker_start(); + if (rc != 0) { + return rc; + } +#endif + ble_svc_gap_init(); ble_svc_gatt_init(); rc = ble_gatts_count_cfg(gatt_svr_svcs); if (rc != 0) { +#if !SOC_MPI_SUPPORTED + blufi_rx_worker_stop(); +#endif return rc; } rc = ble_gatts_add_svcs(gatt_svr_svcs); if (rc != 0) { +#if !SOC_MPI_SUPPORTED + blufi_rx_worker_stop(); +#endif return rc; } @@ -297,6 +432,10 @@ int esp_blufi_gatt_svr_init(void) int esp_blufi_gatt_svr_deinit(void) { +#if !SOC_MPI_SUPPORTED + blufi_rx_worker_stop(); +#endif + deinit_gatt_values(); ble_gatts_free_svcs(); diff --git a/examples/bluetooth/blufi/main/blufi_example.h b/examples/bluetooth/blufi/main/blufi_example.h index 9efb28be29..b8214faa96 100644 --- a/examples/bluetooth/blufi/main/blufi_example.h +++ b/examples/bluetooth/blufi/main/blufi_example.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -7,6 +7,8 @@ #pragma once +#include "soc/soc_caps.h" + #define BLUFI_EXAMPLE_TAG "BLUFI_EXAMPLE" #define BLUFI_INFO(fmt, ...) ESP_LOGI(BLUFI_EXAMPLE_TAG, fmt, ##__VA_ARGS__) #define BLUFI_ERROR(fmt, ...) ESP_LOGE(BLUFI_EXAMPLE_TAG, fmt, ##__VA_ARGS__) @@ -18,6 +20,11 @@ uint16_t blufi_crc_checksum(uint8_t iv8, uint8_t *data, int len); int blufi_security_init(void); void blufi_security_deinit(void); +#if !SOC_MPI_SUPPORTED +void blufi_dh_pregen_start(void); +void blufi_dh_pregen_start_with_cb(void (*done_cb)(void)); +void blufi_dh_pregen_wait(void); +#endif int esp_blufi_gap_register_callback(void); esp_err_t esp_blufi_host_init(void); esp_err_t esp_blufi_host_and_cb_init(esp_blufi_callbacks_t *callbacks); diff --git a/examples/bluetooth/blufi/main/blufi_example_main.c b/examples/bluetooth/blufi/main/blufi_example_main.c index e88aec78d4..2867bbf79d 100644 --- a/examples/bluetooth/blufi/main/blufi_example_main.c +++ b/examples/bluetooth/blufi/main/blufi_example_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -312,8 +312,9 @@ static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_para switch (event) { case ESP_BLUFI_EVENT_INIT_FINISH: BLUFI_INFO("BLUFI init finish\n"); - +#if SOC_MPI_SUPPORTED esp_blufi_adv_start(); +#endif break; case ESP_BLUFI_EVENT_DEINIT_FINISH: BLUFI_INFO("BLUFI deinit finish\n"); @@ -336,7 +337,11 @@ static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_para BLUFI_INFO("BLUFI ble disconnect\n"); ble_is_connected = false; blufi_security_deinit(); +#if !SOC_MPI_SUPPORTED + blufi_dh_pregen_start_with_cb(esp_blufi_adv_start); +#else esp_blufi_adv_start(); +#endif break; case ESP_BLUFI_EVENT_SET_WIFI_OPMODE: BLUFI_INFO("BLUFI Set WIFI opmode %d\n", param->wifi_mode.op_mode); @@ -531,5 +536,11 @@ void app_main(void) return; } +#if !SOC_MPI_SUPPORTED + blufi_dh_pregen_start(); + blufi_dh_pregen_wait(); + esp_blufi_adv_start(); +#endif + BLUFI_INFO("BLUFI VERSION %04x\n", esp_blufi_get_version()); } diff --git a/examples/bluetooth/blufi/main/blufi_security.c b/examples/bluetooth/blufi/main/blufi_security.c index 8c44daa190..7f2e04fb3f 100644 --- a/examples/bluetooth/blufi/main/blufi_security.c +++ b/examples/bluetooth/blufi/main/blufi_security.c @@ -10,10 +10,12 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" +#include "freertos/semphr.h" #include "esp_system.h" #include "esp_wifi.h" #include "esp_event.h" #include "esp_log.h" +#include "esp_task_wdt.h" #include "nvs_flash.h" #include "esp_random.h" #if CONFIG_BT_CONTROLLER_ENABLED || !CONFIG_BT_NIMBLE_ENABLED @@ -25,6 +27,7 @@ #include "psa/crypto.h" #include "esp_crc.h" +#include "soc/soc_caps.h" /* The SEC_TYPE_xxx is for self-defined packet data type in the procedure of "BLUFI negotiate key" @@ -43,6 +46,13 @@ #define BLUFI_ENC_DOMAIN_STR "blufi_enc" #define BLUFI_DEC_DOMAIN_STR "blufi_dec" +#if !SOC_MPI_SUPPORTED +#define BLUFI_DH_PREGEN_STACK_SIZE 4096 +#define BLUFI_DH_PREGEN_PRIO (tskIDLE_PRIORITY + 1) +#define BLUFI_DH_PREGEN_WAIT_MS 30000 +#define BLUFI_DH_HEAVY_CRYPTO_WDT_MS 30000 +#endif + struct blufi_security { #define DH_PARAM_LEN_MAX 1024 #define DH_SELF_PUB_KEY_LEN 384 /* Support 3072-bit DH key (3072/8 = 384 bytes) */ @@ -109,6 +119,135 @@ static void blufi_cleanup_negotiation(bool abort_enc, bool abort_dec) blufi_cleanup_dh_param(); } +#if !SOC_MPI_SUPPORTED +/* + * DH keypair pre-generation: overlap the expensive G^X mod P computation + * with BLE advertising so only key agreement remains on the critical path + * when the phone sends its DH parameters. + */ +static psa_key_id_t s_pregen_private_key; +static uint8_t s_pregen_public_key[DH_SELF_PUB_KEY_LEN]; +static size_t s_pregen_public_key_len; +static SemaphoreHandle_t s_pregen_done; +static bool s_pregen_ok; +static TaskHandle_t s_pregen_task_hdl; +static void (*s_pregen_complete_cb)(void); + +static void blufi_wdt_set_timeout(uint32_t timeout_ms) +{ + esp_task_wdt_config_t cfg = { + .timeout_ms = timeout_ms, + .idle_core_mask = (1 << portNUM_PROCESSORS) - 1, + .trigger_panic = true, + }; + esp_task_wdt_reconfigure(&cfg); +} + +static void blufi_dh_pregen_task(void *arg) +{ + (void)arg; + + blufi_wdt_set_timeout(BLUFI_DH_HEAVY_CRYPTO_WDT_MS); + + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_set_key_type(&attr, PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919)); + psa_set_key_bits(&attr, 3072); + psa_set_key_algorithm(&attr, PSA_ALG_FFDH); + psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DERIVE); + + psa_status_t status = psa_generate_key(&attr, &s_pregen_private_key); + if (status == PSA_SUCCESS) { + status = psa_export_public_key(s_pregen_private_key, + s_pregen_public_key, DH_SELF_PUB_KEY_LEN, + &s_pregen_public_key_len); + } + psa_reset_key_attributes(&attr); + + s_pregen_ok = (status == PSA_SUCCESS); + if (!s_pregen_ok && s_pregen_private_key != 0) { + psa_destroy_key(s_pregen_private_key); + s_pregen_private_key = 0; + } + + BLUFI_INFO("DH keypair pre-generation %s", s_pregen_ok ? "done" : "FAILED"); + + blufi_wdt_set_timeout(CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000); + + xSemaphoreGive(s_pregen_done); + + if (s_pregen_complete_cb) { + void (*cb)(void) = s_pregen_complete_cb; + s_pregen_complete_cb = NULL; + cb(); + } + + vTaskSuspend(NULL); +} + +static void blufi_dh_pregen_start_impl(void (*done_cb)(void)) +{ + if (s_pregen_done != NULL) { + return; + } + + s_pregen_private_key = 0; + s_pregen_public_key_len = 0; + s_pregen_ok = false; + s_pregen_task_hdl = NULL; + s_pregen_complete_cb = done_cb; + s_pregen_done = xSemaphoreCreateBinary(); + if (s_pregen_done == NULL) { + BLUFI_ERROR("Failed to create pre-gen semaphore"); + return; + } + + if (xTaskCreate(blufi_dh_pregen_task, "blufi_pregen", + BLUFI_DH_PREGEN_STACK_SIZE, NULL, + BLUFI_DH_PREGEN_PRIO, &s_pregen_task_hdl) != pdPASS) { + BLUFI_ERROR("Failed to create pre-gen task"); + vSemaphoreDelete(s_pregen_done); + s_pregen_done = NULL; + } +} + +void blufi_dh_pregen_start(void) +{ + blufi_dh_pregen_start_impl(NULL); +} + +void blufi_dh_pregen_start_with_cb(void (*done_cb)(void)) +{ + blufi_dh_pregen_start_impl(done_cb); +} + +void blufi_dh_pregen_wait(void) +{ + if (s_pregen_done == NULL) { + return; + } + xSemaphoreTake(s_pregen_done, portMAX_DELAY); + xSemaphoreGive(s_pregen_done); +} + +static void blufi_dh_pregen_cleanup(void) +{ + if (s_pregen_done != NULL) { + xSemaphoreTake(s_pregen_done, portMAX_DELAY); + vSemaphoreDelete(s_pregen_done); + s_pregen_done = NULL; + } + if (s_pregen_task_hdl != NULL) { + vTaskDelete(s_pregen_task_hdl); + s_pregen_task_hdl = NULL; + } + if (s_pregen_private_key != 0) { + psa_destroy_key(s_pregen_private_key); + s_pregen_private_key = 0; + } + s_pregen_ok = false; +} +#endif /* !SOC_MPI_SUPPORTED */ + void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free) { if (data == NULL || len < 3) { @@ -234,39 +373,114 @@ void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_da return; } - psa_key_type_t key_type = PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919); psa_algorithm_t alg = PSA_ALG_FFDH; - psa_key_attributes_t attributes = psa_key_attributes_init(); - psa_set_key_type(&attributes, key_type); - psa_set_key_bits(&attributes, key_bits); - psa_set_key_algorithm(&attributes, alg); - psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); - psa_key_id_t private_key = 0; - psa_status_t status = psa_generate_key(&attributes, &private_key); - if (status != PSA_SUCCESS) { - BLUFI_ERROR("%s psa_generate_key failed %d\n", __func__, status); - btc_blufi_report_error(ESP_BLUFI_DH_MALLOC_ERROR); - blufi_cleanup_dh_param(); - return; - } - - psa_reset_key_attributes(&attributes); size_t public_key_len = 0; - status = psa_export_public_key(private_key, blufi_sec->self_public_key, DH_SELF_PUB_KEY_LEN, &public_key_len); - if (status != PSA_SUCCESS) { - BLUFI_ERROR("%s psa_export_public_key failed %d\n", __func__, status); - psa_destroy_key(private_key); - btc_blufi_report_error(ESP_BLUFI_DH_MALLOC_ERROR); - blufi_cleanup_dh_param(); - return; + psa_status_t status; + +#if !SOC_MPI_SUPPORTED + /* On SoCs without hardware MPI, 3072-bit modular exponentiation takes + * ~12s in software. Use the pre-generated keypair, free all possible + * heap before key agreement, and widen the task WDT window. */ + bool used_pregen = false; + + if (s_pregen_done != NULL && + xSemaphoreTake(s_pregen_done, pdMS_TO_TICKS(BLUFI_DH_PREGEN_WAIT_MS)) == pdTRUE) { + xSemaphoreGive(s_pregen_done); + if (s_pregen_ok && s_pregen_private_key != 0) { + private_key = s_pregen_private_key; + s_pregen_private_key = 0; + memcpy(blufi_sec->self_public_key, s_pregen_public_key, s_pregen_public_key_len); + public_key_len = s_pregen_public_key_len; + used_pregen = true; + BLUFI_INFO("Using pre-generated DH keypair"); + } } - status = psa_raw_key_agreement(alg, private_key, param, pub_len, blufi_sec->share_key, SHARE_KEY_LEN, &blufi_sec->share_len); + if (!used_pregen) { + BLUFI_INFO("Pre-gen unavailable, generating DH keypair inline"); + blufi_wdt_set_timeout(BLUFI_DH_HEAVY_CRYPTO_WDT_MS); + + psa_key_attributes_t keygen_attr = psa_key_attributes_init(); + psa_set_key_type(&keygen_attr, PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919)); + psa_set_key_bits(&keygen_attr, key_bits); + psa_set_key_algorithm(&keygen_attr, alg); + psa_set_key_usage_flags(&keygen_attr, PSA_KEY_USAGE_DERIVE); + + status = psa_generate_key(&keygen_attr, &private_key); + if (status != PSA_SUCCESS) { + BLUFI_ERROR("%s psa_generate_key failed %d\n", __func__, status); + blufi_wdt_set_timeout(CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000); + btc_blufi_report_error(ESP_BLUFI_DH_MALLOC_ERROR); + blufi_cleanup_dh_param(); + return; + } + psa_reset_key_attributes(&keygen_attr); + + status = psa_export_public_key(private_key, blufi_sec->self_public_key, + DH_SELF_PUB_KEY_LEN, &public_key_len); + if (status != PSA_SUCCESS) { + BLUFI_ERROR("%s psa_export_public_key failed %d\n", __func__, status); + blufi_wdt_set_timeout(CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000); + psa_destroy_key(private_key); + btc_blufi_report_error(ESP_BLUFI_DH_MALLOC_ERROR); + blufi_cleanup_dh_param(); + return; + } + } + + uint8_t peer_pub[DH_SELF_PUB_KEY_LEN]; + memcpy(peer_pub, param, pub_len); + blufi_cleanup_dh_param(); + + if (s_pregen_task_hdl != NULL) { + vTaskDelete(s_pregen_task_hdl); + s_pregen_task_hdl = NULL; + } + + blufi_wdt_set_timeout(BLUFI_DH_HEAVY_CRYPTO_WDT_MS); + status = psa_raw_key_agreement(alg, private_key, peer_pub, pub_len, + blufi_sec->share_key, SHARE_KEY_LEN, + &blufi_sec->share_len); psa_destroy_key(private_key); + blufi_wdt_set_timeout(CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000); +#else /* SOC_MPI_SUPPORTED */ + { + psa_key_attributes_t keygen_attr = psa_key_attributes_init(); + psa_set_key_type(&keygen_attr, PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919)); + psa_set_key_bits(&keygen_attr, key_bits); + psa_set_key_algorithm(&keygen_attr, alg); + psa_set_key_usage_flags(&keygen_attr, PSA_KEY_USAGE_DERIVE); + + status = psa_generate_key(&keygen_attr, &private_key); + if (status != PSA_SUCCESS) { + BLUFI_ERROR("%s psa_generate_key failed %d\n", __func__, status); + btc_blufi_report_error(ESP_BLUFI_DH_MALLOC_ERROR); + blufi_cleanup_dh_param(); + return; + } + psa_reset_key_attributes(&keygen_attr); + + status = psa_export_public_key(private_key, blufi_sec->self_public_key, + DH_SELF_PUB_KEY_LEN, &public_key_len); + if (status != PSA_SUCCESS) { + BLUFI_ERROR("%s psa_export_public_key failed %d\n", __func__, status); + psa_destroy_key(private_key); + btc_blufi_report_error(ESP_BLUFI_DH_MALLOC_ERROR); + blufi_cleanup_dh_param(); + return; + } + } + + status = psa_raw_key_agreement(alg, private_key, param, pub_len, + blufi_sec->share_key, SHARE_KEY_LEN, + &blufi_sec->share_len); + psa_destroy_key(private_key); + blufi_cleanup_dh_param(); +#endif /* !SOC_MPI_SUPPORTED */ + if (status != PSA_SUCCESS) { BLUFI_ERROR("%s psa_raw_key_agreement failed %d\n", __func__, status); - blufi_cleanup_dh_param(); btc_blufi_report_error(ESP_BLUFI_DH_PARAM_ERROR); return; } @@ -292,7 +506,7 @@ void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_da blufi_cleanup_aes_session(true, true); /* Import AES key for CTR mode */ - attributes = psa_key_attributes_init(); + psa_key_attributes_t attributes = psa_key_attributes_init(); psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); psa_set_key_bits(&attributes, PSK_LEN * 8); psa_set_key_algorithm(&attributes, PSA_ALG_CTR); @@ -386,7 +600,6 @@ void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_da *output_data = &blufi_sec->self_public_key[0]; *output_len = public_key_len; *need_free = false; - } break; case SEC_TYPE_DH_P: @@ -512,6 +725,10 @@ esp_err_t blufi_security_init(void) blufi_sec->enc_operation = psa_cipher_operation_init(); blufi_sec->dec_operation = psa_cipher_operation_init(); +#if !SOC_MPI_SUPPORTED + blufi_dh_pregen_start(); +#endif + return 0; } @@ -521,6 +738,10 @@ void blufi_security_deinit(void) return; } +#if !SOC_MPI_SUPPORTED + blufi_dh_pregen_cleanup(); +#endif + /* Clean up all resources */ blufi_cleanup_negotiation(true, true); diff --git a/examples/bluetooth/blufi/sdkconfig.defaults.esp32c2 b/examples/bluetooth/blufi/sdkconfig.defaults.esp32c2 index 9e6420f770..50c9e67317 100644 --- a/examples/bluetooth/blufi/sdkconfig.defaults.esp32c2 +++ b/examples/bluetooth/blufi/sdkconfig.defaults.esp32c2 @@ -8,6 +8,9 @@ CONFIG_BT_NIMBLE_BLUFI_ENABLE=y # CONFIG_BT_BLE_SMP_ENABLE is not set # CONFIG_BT_BLE_50_FEATURES_SUPPORTED is not set CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y +CONFIG_BT_LE_50_FEATURE_SUPPORT=n +CONFIG_BT_LE_MSYS_2_BLOCK_COUNT=12 +CONFIG_BT_LE_HCI_EVT_BUF_SIZE=70 # The config items for NIMBLE HOST CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_ROLE_CENTRAL=n