fix(provisioning): fix incorrect AES-GCM IV usage in security2 scheme

Using same IV in AES-GCM across multiple invocation of
encryption/decryption operations can pose a security risk. It can help
to reveal co-relation between different plaintexts.

This commit introduces a change to use part of IV as a monotonic
counter, which must be incremented after every AES-GCM invocation
on both the client and the device side.

Concept of patch version for a security scheme has been introduced here
which can help to differentiate a protocol behavior for the provisioning
entity. The security patch version will be available in the JSON
response for `proto-ver` endpoint request with the field
`sec_patch_ver`.

Please refer to documentation for more details on the changes required
on the provisioning entity side (e.g., PhoneApps).
This commit is contained in:
Mahavir Jain
2025-03-10 10:00:00 +05:30
parent 7e8251d16b
commit af1bd1472c
7 changed files with 183 additions and 47 deletions
+23 -16
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -156,7 +156,7 @@ static struct wifi_prov_mgr_ctx *prov_ctx;
/* This executes registered app_event_callback for a particular event
*
* NOTE : By the time this fucntion returns, it is possible that
* NOTE : By the time this function returns, it is possible that
* the manager got de-initialized due to a call to wifi_prov_mgr_deinit()
* either inside the event callbacks or from another thread. Therefore
* post execution of execute_event_cb(), the validity of prov_ctx must
@@ -257,7 +257,15 @@ static cJSON* wifi_prov_get_info_json(void)
/* Version field */
cJSON_AddStringToObject(prov_info_json, "ver", prov_ctx->mgr_info.version);
/* Security field */
int sec_ver = 0;
uint8_t sec_patch_ver = 0;
protocomm_get_sec_version(prov_ctx->pc, &sec_ver, &sec_patch_ver);
assert(sec_ver == prov_ctx->security);
cJSON_AddNumberToObject(prov_info_json, "sec_ver", prov_ctx->security);
cJSON_AddNumberToObject(prov_info_json, "sec_patch_ver", sec_patch_ver);
/* Capabilities field */
cJSON_AddItemToObject(prov_info_json, "cap", prov_capabilities);
@@ -304,19 +312,6 @@ static esp_err_t wifi_prov_mgr_start_service(const char *service_name, const cha
return ret;
}
/* Set version information / capabilities of provisioning service and application */
cJSON *version_json = wifi_prov_get_info_json();
char *version_str = cJSON_Print(version_json);
ret = protocomm_set_version(prov_ctx->pc, "proto-ver", version_str);
free(version_str);
cJSON_Delete(version_json);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set version endpoint");
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ret;
}
/* Set protocomm security type for endpoint */
if (prov_ctx->security == 0) {
#ifdef CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0
@@ -353,6 +348,19 @@ static esp_err_t wifi_prov_mgr_start_service(const char *service_name, const cha
return ret;
}
/* Set version information / capabilities of provisioning service and application */
cJSON *version_json = wifi_prov_get_info_json();
char *version_str = cJSON_Print(version_json);
ret = protocomm_set_version(prov_ctx->pc, "proto-ver", version_str);
free(version_str);
cJSON_Delete(version_json);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set version endpoint");
scheme->prov_stop(prov_ctx->pc);
protocomm_delete(prov_ctx->pc);
return ret;
}
prov_ctx->wifi_prov_handlers = malloc(sizeof(wifi_prov_config_handlers_t));
ret = get_wifi_prov_handlers(prov_ctx->wifi_prov_handlers);
if (ret != ESP_OK) {
@@ -1609,7 +1617,6 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const
#endif
prov_ctx->security = security;
esp_timer_create_args_t wifi_connect_timer_conf = {
.callback = wifi_connect_timer_cb,
.arg = NULL,