Skip to content

Fleet Provisioning certificate secure storage in nvs ( Encryption ) #244

@Lenin-Weinkling

Description

@Lenin-Weinkling

Checklist

  • Checked the issue tracker for similar issues to ensure this is not a duplicate.
  • Described the feature in detail and justified the reason for the request.
  • Provided specific use cases and examples.

Feature description

Hi,

I am currently using the fleet provisioning with csr example in my esp-idf 5.4.1 in for esp32s3 ad storing the claim certificates using CONFIG_SECURE_FLASH_ENC_ENABLED=y in EFUSE BLOCK = 0 .

I would like to know how is the provision certificates are stored and is it secured for production ready code if not can you help me in achieving it.

The below code is used for retrieving the certificate after provisioning for my ota , please let me know is it fine

BaseType_t prvInitializeNetworkContext(void) {
if (!is_device_provisioned) return pdFAIL;

BaseType_t xRet = pdPASS;
esp_err_t xEspErrRet;

ESP_LOGI(TAG, "Initializing network context...");

if (strlen(AWS_IOT_ENDPOINT) == 0) {
    ESP_LOGE(TAG, "Empty endpoint for MQTT broker. Set endpoint in menuconfig.");
    return pdFAIL;
}
if (strlen(provisionedThingName) == 0) {
    ESP_LOGE(TAG, "Empty thingname for MQTT broker. Set thing name in menuconfig.");
    return pdFAIL;
}

xNetworkContext.pcHostname = AWS_IOT_ENDPOINT;
xNetworkContext.xPort = AWS_MQTT_PORT;

// Initialize NVS partition "storage"
xEspErrRet = nvs_flash_init_partition("storage");
if (xEspErrRet != ESP_OK) {
    ESP_LOGE(TAG, "Failed to initialize NVS partition 'storage': %s", esp_err_to_name(xEspErrRet));
    if (xEspErrRet == ESP_ERR_NVS_NO_FREE_PAGES || xEspErrRet == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_LOGI(TAG, "Erasing 'storage' partition and retrying...");
        ESP_ERROR_CHECK(nvs_flash_erase_partition("storage"));
        xEspErrRet = nvs_flash_init_partition("storage");
        if (xEspErrRet != ESP_OK) {
            ESP_LOGE(TAG, "Retry failed: %s", esp_err_to_name(xEspErrRet));
            return pdFAIL;
        }
    } else {
        return pdFAIL;
    }
}

nvs_handle_t nvs_handle;
xEspErrRet = nvs_open_from_partition("storage", "creds", NVS_READONLY, &nvs_handle);
if (xEspErrRet != ESP_OK) {
    ESP_LOGE(TAG, "Failed to open NVS 'creds' namespace: %s", esp_err_to_name(xEspErrRet));
    return pdFAIL;
}

// Read device certificate from NVS
size_t cert_size = 0;
xEspErrRet = nvs_get_blob(nvs_handle, "P11_Cert", NULL, &cert_size);
if (xEspErrRet != ESP_OK || cert_size == 0) {
    ESP_LOGE(TAG, "P11_Cert not found or invalid: %s, size: %zu", esp_err_to_name(xEspErrRet), cert_size);
    nvs_close(nvs_handle);
    return pdFAIL;
}

xNetworkContext.pcClientCert = (char *)malloc(cert_size);
if (!xNetworkContext.pcClientCert) {
    ESP_LOGE(TAG, "Failed to allocate memory for P11_Cert");
    nvs_close(nvs_handle);
    return pdFAIL;
}

xEspErrRet = nvs_get_blob(nvs_handle, "P11_Cert", (void *)xNetworkContext.pcClientCert, &cert_size);
if (xEspErrRet != ESP_OK) {
    ESP_LOGE(TAG, "Failed to read P11_Cert: %s", esp_err_to_name(xEspErrRet));
    free((void *)xNetworkContext.pcClientCert);
    nvs_close(nvs_handle);
    return pdFAIL;
}
xNetworkContext.pcClientCertSize = cert_size;

// Set Root CA certificate from embedded binary
xNetworkContext.pcServerRootCA = root_cert_auth_start;
xNetworkContext.pcServerRootCASize = root_cert_auth_end - root_cert_auth_start;

// Read device private key from NVS
size_t key_size = 0;
xEspErrRet = nvs_get_blob(nvs_handle, "P11_Key", NULL, &key_size);
if (xEspErrRet != ESP_OK || key_size == 0) {
    ESP_LOGE(TAG, "P11_Key not found or invalid: %s, size: %zu", esp_err_to_name(xEspErrRet), key_size);
    free((void *)xNetworkContext.pcClientCert);
    nvs_close(nvs_handle);
    return pdFAIL;
}

xNetworkContext.pcClientKey = (char *)malloc(key_size);
if (!xNetworkContext.pcClientKey) {
    ESP_LOGE(TAG, "Failed to allocate memory for P11_Key");
    free((void *)xNetworkContext.pcClientCert);
    nvs_close(nvs_handle);
    return pdFAIL;
}

xEspErrRet = nvs_get_blob(nvs_handle, "P11_Key", (void *)xNetworkContext.pcClientKey, &key_size);
if (xEspErrRet != ESP_OK) {
    ESP_LOGE(TAG, "Failed to read P11_Key: %s", esp_err_to_name(xEspErrRet));
    free((void *)xNetworkContext.pcClientCert);
    free((void *)xNetworkContext.pcClientKey);
    nvs_close(nvs_handle);
    return pdFAIL;
}
xNetworkContext.pcClientKeySize = key_size;

// Initialize TLS semaphore
xNetworkContext.xTlsContextSemaphore = xSemaphoreCreateMutex();
if (!xNetworkContext.xTlsContextSemaphore) {
    ESP_LOGE(TAG, "Not enough memory to create TLS semaphore.");
    free((void *)xNetworkContext.pcClientCert);
    free((void *)xNetworkContext.pcClientKey);
    nvs_close(nvs_handle);
    return pdFAIL;
}

nvs_close(nvs_handle);
ESP_LOGI(TAG, "Network context initialized successfully");
return xRet;

}

Use cases

For OTA and Fleet Provisioning

Alternatives

No response

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions