FreeRTOS / iot-reference-esp32

MIT License
75 stars 45 forks source link

[Feature Request] Using Provisioning example, Storing Cert and PVT Key in storage NVS partition pcks11 module. How to retrieve so as to use demo_tasks. #108

Open wreyford opened 1 month ago

wreyford commented 1 month ago

I have managed to provision a device using fleet provisioning Amazon Web Services IoT MQTT (Fleet Provisioning With CSR) Example I'm using ESP-IDF 5.2 ESP32S3-F16-R8

I have for now stored the certificate and private key (obtained during fleet provisioning) in the nvs storage partition: storage,data,nvs,,0x4000,,

The example disconnects, then reconnects, so all is fine.

Now I'm trying to implement MQTT for publish of data to the IoT Hub, using the main/demo_tasks/temp_sub_pub_and_led_control_demo

the network context differs from the one used in fleet provisioning.

struct NetworkContext
{
    MbedtlsPkcs11Context_t * pParams;
};

I wish to use the more refined approach used in the temp_sub_pub_and_led_control_demo for our MQTT telemetry (publish) framework.

To set up the NetworkContext, it uses:

/* Static function definitions ************************************************/

static BaseType_t prvInitializeNetworkContext( void )
{
    /* This is returned by this function. */
    BaseType_t xRet = pdPASS;

    /* This is used to store the error return of ESP-IDF functions. */
    esp_err_t xEspErrRet;

    /* Verify that the MQTT endpoint and thing name have been configured by the
     * user. */
    if( strlen( CONFIG_GRI_MQTT_ENDPOINT ) == 0 )
    {
        ESP_LOGE( TAG, "Empty endpoint for MQTT broker. Set endpoint by "
                       "running idf.py menuconfig, then Golden Reference Integration -> "
                       "Endpoint for MQTT Broker to use." );
        xRet = pdFAIL;
    }

    if( strlen( CONFIG_GRI_THING_NAME ) == 0 )
    {
        ESP_LOGE( TAG, "Empty thingname for MQTT broker. Set thing name by "
                       "running idf.py menuconfig, then Golden Reference Integration -> "
                       "Thing name." );
        xRet = pdFAIL;
    }

    /* Initialize network context. */

    xNetworkContext.pcHostname = CONFIG_GRI_MQTT_ENDPOINT;
    xNetworkContext.xPort = CONFIG_GRI_MQTT_PORT;

    /* Get the device certificate from esp_secure_crt_mgr and put into network
     * context. */
    xEspErrRet = esp_secure_cert_get_device_cert( &xNetworkContext.pcClientCert,
                                                  &xNetworkContext.pcClientCertSize );

    if( xEspErrRet == ESP_OK )
    {
        #if CONFIG_GRI_OUTPUT_CERTS_KEYS
            ESP_LOGI( TAG, "\nDevice Cert: \nLength: %" PRIu32 "\n%s",
                      xNetworkContext.pcClientCertSize,
                      xNetworkContext.pcClientCert );
        #endif /* CONFIG_GRI_OUTPUT_CERTS_KEYS */
    }
    else
    {
        ESP_LOGE( TAG, "Error in getting device certificate. Error: %s",
                  esp_err_to_name( xEspErrRet ) );

        xRet = pdFAIL;
    }

    /* Putting the Root CA certificate into the network context. */
    xNetworkContext.pcServerRootCA = root_cert_auth_start;
    xNetworkContext.pcServerRootCASize = root_cert_auth_end - root_cert_auth_start;

    if( xEspErrRet == ESP_OK )
    {
        #if CONFIG_GRI_OUTPUT_CERTS_KEYS
            ESP_LOGI( TAG, "\nCA Cert: \nLength: %" PRIu32 "\n%s",
                      xNetworkContext.pcServerRootCASize,
                      xNetworkContext.pcServerRootCA );
        #endif /* CONFIG_GRI_OUTPUT_CERTS_KEYS */
    }
    else
    {
        ESP_LOGE( TAG, "Error in getting CA certificate. Error: %s",
                  esp_err_to_name( xEspErrRet ) );

        xRet = pdFAIL;
    }

    #if CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL

        /* If the digital signature peripheral is being used, get the digital
         * signature peripheral context from esp_secure_crt_mgr and put into
         * network context. */

        xNetworkContext.ds_data = esp_secure_cert_get_ds_ctx();

        if( xNetworkContext.ds_data == NULL )
        {
            ESP_LOGE( TAG, "Error in getting digital signature peripheral data." );
            xRet = pdFAIL;
        }
    #else /* if CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL */
        xEspErrRet = esp_secure_cert_get_priv_key( &xNetworkContext.pcClientKey,
                                                   &xNetworkContext.pcClientKeySize );

        if( xEspErrRet == ESP_OK )
        {
            #if CONFIG_GRI_OUTPUT_CERTS_KEYS
                ESP_LOGI( TAG, "\nPrivate Key: \nLength: %" PRIu32 "\n%s",
                          xNetworkContext.pcClientKeySize,
                          xNetworkContext.pcClientKey );
            #endif /* CONFIG_GRI_OUTPUT_CERTS_KEYS */
        }
        else
        {
            ESP_LOGE( TAG, "Error in getting private key. Error: %s",
                      esp_err_to_name( xEspErrRet ) );

            xRet = pdFAIL;
        }
    #endif /* CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL */

    xNetworkContext.pxTls = NULL;
    xNetworkContext.xTlsContextSemaphore = xSemaphoreCreateMutex();

    if( xNetworkContext.xTlsContextSemaphore == NULL )
    {
        ESP_LOGE( TAG, "Not enough memory to create TLS semaphore for global "
                       "network context." );

        xRet = pdFAIL;
    }

    return xRet;
}

The examples use the certificate and private key stored in esp_secure_cert_manager partition, (thus a different approach to storing in storage nvs partition as keypair values written by pcks11 module in the fleet provisioning example).: esp_secure_cert, 0x3F, , 0xD000, 0x2000, encrypted

I need to retrieve the client certificate from the pcks11 module, also the private key using their respective labels, and then I need to populate xNetworkContext with them, as in this example:

xEspErrRet = esp_secure_cert_get_device_cert( &xNetworkContext.pcClientCert,
                                                  &xNetworkContext.pcClientCertSize );

How can I read the certificate into xNetworkContext.pcClientCert from the nvs partition using pkcs11 module? I'm trying to get this to work, so we can migrate our application to AWS. I'm building out the framework as I go.

As an alternative later see below.

(I have a ATECC608B TRUST CUSTOM chip on the same custom PCB. It is not utilized at this moment. I could possibly write the Private Key and Client key obtained during fleet provisioning to the trust custom chip at runtime, and then use it for the examples, but have no idea how to do that. )

cookpate commented 1 month ago

I haven't worked with the secure element on ESP32, but the functions referenced in this issue appear to be implemented by https://github.com/espressif/esp_secure_cert_mgr Perhaps check documentation there, first.

Otherwise, additional Espressif documentation for ESP-IDF 5.2 can be found here: https://docs.espressif.com/projects/esp-idf/en/v5.2.2/esp32s3/api-reference

aggarg commented 2 weeks ago

@wreyford, were you able to try out @cookpate's suggestion?