Reading certificates from SPIFFS and connecting to AWS IoT

KaranRaj
Posts: 16
Joined: Wed Jan 16, 2019 5:43 am

Reading certificates from SPIFFS and connecting to AWS IoT

Postby KaranRaj » Mon Sep 21, 2020 2:38 pm

Hi All!

I need to store the thing's AWS certificates and key in the SPIFFS in order to survive OTA updates. The certificates are then read from the SPIFFS and connection to AWS IoT needs to be initialized using them. However, mbedtls_ssl_handshake fails with the below error:

Code: Select all

E (2884467) aws_iot: failed! mbedtls_ssl_handshake returned -0x2700
E (2884467) aws_iot:     Unable to verify the server's certificate. 
E (2884477) AWS_CONTROL: Error(-4) connecting to a1k8en70rrdegy-ats.iot.us-east-1.amazonaws.com:8883
I think what I'm doing wrong is the way I'm passing these certificates to the IoT_Client_Init_Params struct. Here's my snippet:

Code: Select all

    char aws_root_ca_pem_start[2048] = "0";
    char certificate_pem_crt_start[2048] = "0";
    char private_pem_key_start[2048] = "0";
    
    int init_spiffs(void)
    {
    esp_vfs_spiffs_conf_t conf = {
        .base_path = "/spiffs",
        .partition_label = NULL,
        .max_files = 5,
        .format_if_mount_failed = false};

    esp_err_t ret = esp_vfs_spiffs_register(&conf);

    if (ret != ESP_OK)
    {
        if (ret == ESP_FAIL)
        {
            ESP_LOGE(TAG, "Failed to mount or format filesystem");
        }
        else if (ret == ESP_ERR_NOT_FOUND)
        {
            ESP_LOGE(TAG, "Failed to find SPIFFS partition");
        }
        else
        {
            ESP_LOGE(TAG, "Failed to initialize SPIFFS (%d)", ret);
        }
        return -1;
    }

    vTaskDelay(1000 / portTICK_RATE_MS);



    return 0;
    }

    void read_file_to_string(char *fname, char buf[2048])
    {
        printf("  file: \"%s\"\n", fname);

        int res;
        FILE *fd = fopen(fname, "rb");
        if (fd == NULL)
        {
            ESP_LOGE(TAG, "Error !!!");
            printf("  Error opening file (%d) %s\n", errno, strerror(errno));
            free(buf);
            printf("\n");
            return;
        }
        res = 999;
        res = fread(buf, 1, 2047, fd);
        if (res <= 0)
        {
            ESP_LOGE(TAG, "Error !!!");
            printf("  Error reading from file\n");
        }
        else
        {
            ESP_LOGI(TAG,"  %d bytes read \n", res);
            buf[res] = '\0';
            // printf("%s\n]\n", buf);
        }
        // free(buf);

        res = fclose(fd);
        if (res)
        {
            ESP_LOGE(TAG, "Error !!!");
            printf("  Error closing file\n");
        }
        printf("\n");
    }
    
    void aws_iot_task(void *param)
    {
    
    IoT_Error_t rc = FAILURE;

    AWS_IoT_Client client;
    IoT_Client_Init_Params mqttInitParams = iotClientInitParamsDefault;
    IoT_Client_Connect_Params connectParams = iotClientConnectParamsDefault;

    IoT_Publish_Message_Params paramsQOS0;

    ESP_LOGI(TAG, "AWS IoT SDK Version %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);

    mqttInitParams.enableAutoReconnect = false; // We enable this later below
    mqttInitParams.pHostURL = HostAddress;
    mqttInitParams.port = port;

    mqttInitParams.pRootCALocation = (const char *)aws_root_ca_pem_start;
    mqttInitParams.pDeviceCertLocation = (const char *)certificate_pem_crt_start;
    mqttInitParams.pDevicePrivateKeyLocation = (const char *)private_pem_key_start;

    mqttInitParams.mqttCommandTimeout_ms = 20000;
    mqttInitParams.tlsHandshakeTimeout_ms = 5000;
    mqttInitParams.isSSLHostnameVerify = true;
    mqttInitParams.disconnectHandler = disconnect_callback_handler;
    mqttInitParams.disconnectHandlerData = NULL;

    rc = aws_iot_mqtt_init(&client, &mqttInitParams);
    if(SUCCESS != rc) {
        ESP_LOGE(TAG, "aws_iot_mqtt_init returned error : %d ", rc);
        abort();
    }

    /* Wait for WiFI to show as connected */
    xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);

    connectParams.keepAliveIntervalInSec = 10;
    connectParams.isCleanSession = true;
    connectParams.MQTTVersion = MQTT_3_1_1;
    /* Client ID is set in the menuconfig of the example */
    connectParams.pClientID = device_id;
    connectParams.clientIDLen = (uint16_t) strlen(device_id);
    connectParams.isWillMsgPresent = false;

    ESP_LOGI(TAG, "Connecting to AWS...");
    do {
        ESP_LOGW(TAG, "Reattempting ************************************** Connecting to AWS...");
        rc = aws_iot_mqtt_connect(&client, &connectParams);
        if(SUCCESS != rc) {
            ESP_LOGE(TAG, "Error(%d) connecting to %s:%d", rc, mqttInitParams.pHostURL, mqttInitParams.port);
            vTaskDelay(1000 / portTICK_RATE_MS);
        }
    } while(SUCCESS != rc);
    
    rc = aws_iot_mqtt_autoreconnect_set_status(&client, true);
    if(SUCCESS != rc) {
        ESP_LOGE(TAG, "Unable to set Auto Reconnect to true - %d", rc);
        abort();
    }
    char sub_topic[] = "esp32/device";
    ESP_LOGW(TAG, "Subscribing to %s", sub_topic);
    rc = aws_iot_mqtt_subscribe(&client, SUBTOPIC, SUBTOPIC_LEN, QOS0, iot_subscribe_callback_handler, NULL);
    if(SUCCESS != rc) {
        ESP_LOGE(TAG, "Error subscribing : %d ", rc);
        abort();
    }
    
    int spiffs_ok = init_spiffs();
    if (spiffs_ok == 0)
    {
        // read aws certificates into memory
        read_file_to_string("/spiffs/certificate.pem.crt", certificate_pem_crt_start);
        ESP_LOGI(TAG, "PEM CERT: \n %s", certificate_pem_crt_start);
        read_file_to_string("/spiffs/private.pem.key", private_pem_key_start);
        ESP_LOGI(TAG, "PEM KEY: \n %s", private_pem_key_start);
        read_file_to_string("/spiffs/aws-root-ca.pem", aws_root_ca_pem_start);
        ESP_LOGI(TAG, "ROOT CERT: \n %s", aws_root_ca_pem_start);
        xTaskCreate(&aws_iot_task, "aws_iot_task", LARGER_STACK, NULL, LOW_PRIORITY, aws_iot_task_handle);
    }
I know that reading the certificates are not a problem because they are printing fine, as according to the code above.

When I use the same certificates with the https://github.com/espressif/esp-aws-io ... be_publish, it works fine. But the example, embeds the certificates onto the binary, and that destroys my OTA use-case.

Thanks for reading. Any help is appreciated!

Regards,
Karan

ESP_Mahavir
Posts: 188
Joined: Wed Jan 24, 2018 6:51 am

Re: Reading certificates from SPIFFS and connecting to AWS IoT

Postby ESP_Mahavir » Tue Sep 22, 2020 6:56 am

Hi Karan,

Did you try passing certificates path directly as shown at https://github.com/espressif/esp-aws-io ... ple.c#L185? Please note that this example supports SDcard storage but changing to SPIFFS should be fairly straight forward. Internally mbedTLS port layer will take care of retrieving certificate from filesystem or buffer, refer: https://github.com/espressif/esp-aws-io ... #L157-L166

Mahavir

KaranRaj
Posts: 16
Joined: Wed Jan 16, 2019 5:43 am

Re: Reading certificates from SPIFFS and connecting to AWS IoT

Postby KaranRaj » Fri Sep 25, 2020 11:28 am

Hi Mahavir,

I tried passing the path directly, and that worked!

Thanks!

Regards,
Karan

Who is online

Users browsing this forum: Abisha, tomy983 and 288 guests