From b77f44aa979bd4084543f31886ebc77c85ebab41 Mon Sep 17 00:00:00 2001 From: Piyush Shah Date: Wed, 2 Sep 2020 00:33:24 +0530 Subject: [PATCH 1/2] esp_claim: Add support for "Assisted Claiming" This is specifically for simplifying ESP32 claiming workflow, wherein the phone apps will assist the node for claiming during Wi-Fi provisioning. There would be no need of using CLI for claiming. This will work only for BLE provisioning, as internet connectivity will be required for claiming, and it may not be possible with SoftAP. --- components/esp_rainmaker/CMakeLists.txt | 6 + components/esp_rainmaker/Kconfig.projbuild | 12 +- components/esp_rainmaker/component.mk | 3 + .../esp_rainmaker/src/core/esp_rmaker_claim.c | 862 +++++++++++++----- .../esp_rainmaker/src/core/esp_rmaker_claim.h | 36 +- .../src/core/esp_rmaker_claim.pb-c.c | 398 ++++++++ .../src/core/esp_rmaker_claim.pb-c.h | 175 ++++ .../src/core/esp_rmaker_claim.proto | 41 + .../src/core/esp_rmaker_client_data.c | 4 +- .../esp_rainmaker/src/core/esp_rmaker_core.c | 89 +- .../src/core/esp_rmaker_internal.h | 1 + 11 files changed, 1372 insertions(+), 255 deletions(-) create mode 100644 components/esp_rainmaker/src/core/esp_rmaker_claim.pb-c.c create mode 100644 components/esp_rainmaker/src/core/esp_rmaker_claim.pb-c.h create mode 100644 components/esp_rainmaker/src/core/esp_rmaker_claim.proto diff --git a/components/esp_rainmaker/CMakeLists.txt b/components/esp_rainmaker/CMakeLists.txt index 6d137cd..9bc13fd 100644 --- a/components/esp_rainmaker/CMakeLists.txt +++ b/components/esp_rainmaker/CMakeLists.txt @@ -12,6 +12,12 @@ set(core_srcs "src/core/esp_rmaker_core.c" "src/core/esp_rmaker_utils.c" "src/core/esp_rmaker_user_mapping.c") + +if(CONFIG_ESP_RMAKER_ASSISTED_CLAIM) + list(APPEND core_srcs + "src/core/esp_rmaker_claim.c" + "src/core/esp_rmaker_claim.pb-c.c") +endif() if(CONFIG_ESP_RMAKER_SELF_CLAIM) list(APPEND core_srcs "src/core/esp_rmaker_claim.c") diff --git a/components/esp_rainmaker/Kconfig.projbuild b/components/esp_rainmaker/Kconfig.projbuild index 653b514..7f94c1d 100644 --- a/components/esp_rainmaker/Kconfig.projbuild +++ b/components/esp_rainmaker/Kconfig.projbuild @@ -15,9 +15,19 @@ menu "ESP RainMaker Config" help ESP RainMaker Claiming Service Base URL. + config ESP_RMAKER_ASSISTED_CLAIM + bool "Use Assisted Claiming" + depends on IDF_TARGET_ESP32 && BT_ENABLED + select MBEDTLS_HARDWARE_MPI + default y + help + Use Assisted Claiming i.e. get the MQTT credentials + from the claiming service via assistance from clients, + like the phone apps. + config ESP_RMAKER_MQTT_HOST string "ESP RainMaker MQTT Host" - depends on ESP_RMAKER_SELF_CLAIM + depends on ESP_RMAKER_SELF_CLAIM || ESP_RMAKER_ASSISTED_CLAIM default "a1p72mufdu6064-ats.iot.us-east-1.amazonaws.com" help ESP RainMaker MQTT Host name. diff --git a/components/esp_rainmaker/component.mk b/components/esp_rainmaker/component.mk index 032dc7c..6b94c98 100644 --- a/components/esp_rainmaker/component.mk +++ b/components/esp_rainmaker/component.mk @@ -2,8 +2,11 @@ COMPONENT_SRCDIRS := src/core src/mqtt src/ota src/standard_types src/console COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_PRIV_INCLUDEDIRS := src/core src/ota src/console +ifndef CONFIG_ESP_RMAKER_ASSISTED_CLAIM +COMPONENT_OBJEXCLUDE += src/core/esp_rmaker_claim.pb-c.o ifndef CONFIG_ESP_RMAKER_SELF_CLAIM COMPONENT_OBJEXCLUDE += src/core/esp_rmaker_claim.o endif +endif COMPONENT_EMBED_TXTFILES := server_certs/mqtt_server.crt server_certs/claim_service_server.crt server_certs/ota_server.crt diff --git a/components/esp_rainmaker/src/core/esp_rmaker_claim.c b/components/esp_rainmaker/src/core/esp_rmaker_claim.c index 1dd26ee..f7ecf21 100644 --- a/components/esp_rainmaker/src/core/esp_rmaker_claim.c +++ b/components/esp_rainmaker/src/core/esp_rmaker_claim.c @@ -23,51 +23,45 @@ #include "mbedtls/md.h" #include "mbedtls/sha512.h" -#include "soc/soc.h" -#include "soc/efuse_reg.h" -#include "esp_efuse.h" -#include "esp_efuse.h" -#include "esp_efuse_table.h" - #include #include #include +#include +#include #include #include #include #include #include #include -#include -#include "esp_rmaker_client_data.h" - #include #include +#include "esp_rmaker_internal.h" +#include "esp_rmaker_storage.h" +#include "esp_rmaker_client_data.h" +#include "esp_rmaker_claim.h" + static const char *TAG = "esp_claim"; +#ifdef CONFIG_ESP_RMAKER_SELF_CLAIM +#include "soc/soc.h" +#include "soc/efuse_reg.h" +#include "esp_efuse.h" +#include "esp_efuse_table.h" #define CLAIM_BASE_URL CONFIG_ESP_RMAKER_CLAIM_SERVICE_BASE_URL #define CLAIM_INIT_PATH "claim/initiate" #define CLAIM_VERIFY_PATH "claim/verify" -#define CLAIM_PK_SIZE 2048 - -#define MAX_CSR_SIZE 1024 -#define MAX_PAYLOAD_SIZE 3072 - -typedef struct { - unsigned char csr[MAX_CSR_SIZE]; - char payload[MAX_PAYLOAD_SIZE]; - mbedtls_pk_context key; -} esp_rmaker_claim_data_t; -esp_rmaker_claim_data_t *g_claim_data; -static EventGroupHandle_t self_claim_event_group; -static const int SELF_CLAIM_TASK_BIT = BIT0; - extern uint8_t claim_service_server_root_ca_pem_start[] asm("_binary_claim_service_server_crt_start"); extern uint8_t claim_service_server_root_ca_pem_end[] asm("_binary_claim_service_server_crt_end"); +#endif /* CONFIG_ESP_RMAKER_SELF_CLAIM */ +#define CLAIM_PK_SIZE 2048 + +static EventGroupHandle_t claim_event_group; +static const int CLAIM_TASK_BIT = BIT0; static void escape_new_line(esp_rmaker_claim_data_t *data) { char *str = (char *)data->csr; @@ -107,6 +101,167 @@ static void unescape_new_line(char *str) *target_str = '\0'; } +static esp_err_t esp_rmaker_claim_generate_csr(esp_rmaker_claim_data_t *claim_data, const char *common_name) +{ + if (!claim_data || !common_name) { + ESP_LOGE(TAG, "claim_data or common_name cannot be NULL."); + return ESP_ERR_INVALID_ARG; + } + const char *pers = "gen_csr"; + mbedtls_x509write_csr csr; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_context entropy; + + /* Generating CSR from the private key */ + mbedtls_x509write_csr_init(&csr); + mbedtls_x509write_csr_set_md_alg(&csr, MBEDTLS_MD_SHA256); + mbedtls_ctr_drbg_init(&ctr_drbg); + + ESP_LOGD(TAG, "Seeding the random number generator."); + mbedtls_entropy_init(&entropy); + int ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen(pers)); + if (ret != 0) { + ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%04x", -ret ); + goto exit; + } + char subject_name[50]; + snprintf(subject_name, sizeof(subject_name), "CN=%s", common_name); + ret = mbedtls_x509write_csr_set_subject_name(&csr, subject_name); + if (ret != 0) { + ESP_LOGE(TAG, "mbedtls_x509write_csr_set_subject_name returned %d", ret ); + goto exit; + } + + memset(claim_data->csr, 0, sizeof(claim_data->csr)); + mbedtls_x509write_csr_set_key(&csr, &claim_data->key); + ESP_LOGD(TAG, "Generating PEM"); + ret = mbedtls_x509write_csr_pem(&csr, claim_data->csr, sizeof(claim_data->csr), mbedtls_ctr_drbg_random, &ctr_drbg); + if (ret < 0) { + ESP_LOGE(TAG, "mbedtls_x509write_csr_pem returned -0x%04x", -ret ); + goto exit; + } + ESP_LOGD(TAG, "CSR generated."); + claim_data->state = RMAKER_CLAIM_STATE_CSR_GENERATED; +exit: + + mbedtls_x509write_csr_free(&csr); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + + return ret; +} + +static esp_err_t esp_rmaker_claim_generate_key(esp_rmaker_claim_data_t *claim_data) +{ + const char *pers = "gen_key"; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + + mbedtls_pk_free(&claim_data->key); + mbedtls_pk_init(&claim_data->key); + mbedtls_ctr_drbg_init(&ctr_drbg); + memset(claim_data->payload, 0, sizeof(claim_data->payload)); + + ESP_LOGD(TAG, "Seeding the random number generator."); + mbedtls_entropy_init(&entropy); + int ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen(pers)); + if (ret != 0) { + ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%04x", -ret ); + mbedtls_pk_free(&claim_data->key); + goto exit; + } + + ESP_LOGW(TAG, "Generating the private key. This may take time." ); + ret = mbedtls_pk_setup(&claim_data->key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); + if (ret != 0) { + ESP_LOGE(TAG, "mbedtls_pk_setup returned -0x%04x", -ret ); + mbedtls_pk_free(&claim_data->key); + goto exit; + } + + ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(claim_data->key), mbedtls_ctr_drbg_random, &ctr_drbg, CLAIM_PK_SIZE, 65537); /* here, 65537 is the RSA exponent */ + if (ret != 0) { + ESP_LOGE(TAG, "mbedtls_rsa_gen_key returned -0x%04x", -ret ); + mbedtls_pk_free(&claim_data->key); + goto exit; + } + + claim_data->state = RMAKER_CLAIM_STATE_PK_GENERATED; + ESP_LOGD(TAG, "Converting Private Key to PEM..."); + ret = mbedtls_pk_write_key_pem(&claim_data->key, (unsigned char *)claim_data->payload, sizeof(claim_data->payload)); + if (ret != 0) { + ESP_LOGE(TAG, "mbedtls_pk_write_key_pem returned -0x%04x", -ret ); + mbedtls_pk_free(&claim_data->key); + } +exit: + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + return ret; +} + +/* Parse the Claim Init response and generate Claim Verify request + * + * Claim Verify Response format: + * {"certificate":""} + */ +static esp_err_t handle_claim_verify_response(esp_rmaker_claim_data_t *claim_data) +{ + ESP_LOGD(TAG, "Claim Verify Response: %s", claim_data->payload); + jparse_ctx_t jctx; + if (json_parse_start(&jctx, claim_data->payload, strlen(claim_data->payload)) == 0) { + int required_len = 0; + if (json_obj_get_strlen(&jctx, "certificate", &required_len) == 0) { + required_len++; /* For NULL termination */ + char *certificate = calloc(1, required_len); + if (!certificate) { + json_parse_end(&jctx); + ESP_LOGE(TAG, "Failed to allocate %d bytes for certificate.", required_len); + return ESP_ERR_NO_MEM; + } + json_obj_get_string(&jctx, "certificate", certificate, required_len); + json_parse_end(&jctx); + unescape_new_line(certificate); + esp_err_t err = esp_rmaker_storage_set(ESP_RMAKER_CLIENT_CERT_NVS_KEY, certificate, strlen(certificate)); + free(certificate); + return err; + } else { + ESP_LOGE(TAG, "Claim Verify Response invalid."); + } + } + ESP_LOGE(TAG, "Failed to parse Claim Verify Response."); + return ESP_FAIL; +} + +static esp_err_t generate_claim_init_request(esp_rmaker_claim_data_t *claim_data) +{ + if (claim_data->state < RMAKER_CLAIM_STATE_PK_GENERATED) { + return ESP_ERR_INVALID_STATE; + } + uint8_t eth_mac[6]; + esp_err_t err = esp_wifi_get_mac(WIFI_IF_STA, eth_mac); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Could not fetch MAC address. Please initialise Wi-Fi first"); + return err; + } + + snprintf(claim_data->payload, sizeof(claim_data->payload), + "{\"mac_addr\":\"%02X%02X%02X%02X%02X%02X\",\"platform\":\"%s\"}", + eth_mac[0], eth_mac[1], eth_mac[2], eth_mac[3], eth_mac[4], eth_mac[5], CONFIG_IDF_TARGET); + claim_data->payload_len = strlen(claim_data->payload); + claim_data->payload_offset = 0; + return ESP_OK; +} + +void esp_rmaker_claim_data_free(esp_rmaker_claim_data_t *claim_data) +{ + if(claim_data) { + mbedtls_pk_free(&claim_data->key); + free(claim_data); + } +} + +#ifdef CONFIG_ESP_RMAKER_SELF_CLAIM + static esp_err_t read_hmac_key(uint32_t *out_hmac_key, size_t hmac_key_size) { /* ESP32-S2 HMAC Key programming scheme */ @@ -153,7 +308,7 @@ static esp_err_t hmac_challenge(const char* hmac_request, unsigned char *hmac_re * Claim Verify Request format * {"auth_id":"", "challenge_response":"<64byte-response-in-hex>, "csr":""} */ -static esp_err_t handle_claim_init_response(esp_rmaker_claim_data_t *claim_data) +static esp_err_t handle_self_claim_init_response(esp_rmaker_claim_data_t *claim_data) { ESP_LOGD(TAG, "Claim Init Response: %s", claim_data->payload); jparse_ctx_t jctx; @@ -192,39 +347,6 @@ static esp_err_t handle_claim_init_response(esp_rmaker_claim_data_t *claim_data) ESP_LOGE(TAG, "Failed to parse Claim Init Response."); return ESP_FAIL; } -/* Parse the Claim Init response and generate Claim Verify request - * - * Claim Verify Response format: - * {"certificate":""} - */ -static esp_err_t handle_claim_verify_response(esp_rmaker_claim_data_t *claim_data) -{ - ESP_LOGD(TAG, "Claim Verify Response: %s", claim_data->payload); - jparse_ctx_t jctx; - if (json_parse_start(&jctx, claim_data->payload, strlen(claim_data->payload)) == 0) { - int required_len = 0; - if (json_obj_get_strlen(&jctx, "certificate", &required_len) == 0) { - required_len++; /* For NULL termination */ - char *certificate = calloc(1, required_len); - if (!certificate) { - json_parse_end(&jctx); - ESP_LOGE(TAG, "Failed to allocate %d bytes for certificate.", required_len); - return ESP_ERR_NO_MEM; - } - json_obj_get_string(&jctx, "certificate", certificate, required_len); - json_parse_end(&jctx); - unescape_new_line(certificate); - esp_err_t err = esp_rmaker_storage_set(ESP_RMAKER_CLIENT_CERT_NVS_KEY, certificate, strlen(certificate)); - free(certificate); - return err; - } else { - ESP_LOGE(TAG, "Claim Verify Response invalid."); - } - } - ESP_LOGE(TAG, "Failed to parse Claim Verify Response."); - return ESP_FAIL; -} - static esp_err_t esp_rmaker_claim_perform_common(esp_rmaker_claim_data_t *claim_data, const char *path) { char url[100]; @@ -280,12 +402,22 @@ static esp_err_t esp_rmaker_claim_perform_common(esp_rmaker_claim_data_t *claim_ } static esp_err_t esp_rmaker_claim_perform_init(esp_rmaker_claim_data_t *claim_data) { - esp_err_t err = esp_rmaker_claim_perform_common(claim_data, CLAIM_INIT_PATH); + esp_err_t err = generate_claim_init_request(claim_data); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to generate Claim init request"); + return err; + } + + err = esp_rmaker_claim_perform_common(claim_data, CLAIM_INIT_PATH); if (err != OK) { ESP_LOGE(TAG, "Claim Init Request Failed."); return err; } - err = handle_claim_init_response(claim_data); + claim_data->state = RMAKER_CLAIM_STATE_INIT; + err = handle_self_claim_init_response(claim_data); + if (err == ESP_OK) { + claim_data->state = RMAKER_CLAIM_STATE_INIT_DONE; + } return err; } @@ -296,175 +428,390 @@ static esp_err_t esp_rmaker_claim_perform_verify(esp_rmaker_claim_data_t *claim_ ESP_LOGE(TAG, "Claim Verify Failed."); return err; } + claim_data->state = RMAKER_CLAIM_STATE_VERIFY; err = handle_claim_verify_response(claim_data); + if (err == ESP_OK) { + claim_data->state = RMAKER_CLAIM_STATE_VERIFY_DONE; + } return err; } -esp_err_t esp_rmaker_self_claim_perform(void) +esp_err_t esp_rmaker_self_claim_perform(esp_rmaker_claim_data_t *claim_data) { ESP_LOGI(TAG, "Starting the Self Claim Process. This may take time."); - if (g_claim_data == NULL) { + if (claim_data == NULL) { ESP_LOGE(TAG, "Self claiming not initialised."); return ESP_ERR_INVALID_STATE; } - esp_err_t err = esp_rmaker_claim_perform_init(g_claim_data); + esp_err_t err = esp_rmaker_claim_perform_init(claim_data); if (err != ESP_OK) { ESP_LOGE(TAG, "Claim Init Sequence Failed."); return err; } - err = esp_rmaker_claim_perform_verify(g_claim_data); + err = esp_rmaker_claim_perform_verify(claim_data); if (err == ESP_OK) { ESP_LOGI(TAG, "Self Claiming was successful. Certificate received."); - ESP_LOGW(TAG, "The first MQTT connection attempt may fail. The subsequent ones should work."); } - free(g_claim_data); - g_claim_data = NULL; + esp_rmaker_claim_data_free(claim_data); return err; } - -static esp_err_t generate_key(esp_rmaker_claim_data_t *claim_data) +#endif /* CONFIG_ESP_RMAKER_SELF_CLAIM */ +#ifdef CONFIG_ESP_RMAKER_ASSISTED_CLAIM +static EventGroupHandle_t claim_csr_event_group; +static const int CLAIM_CSR_TASK_BIT = BIT1; +static void esp_rmaker_claim_csr_task(void *args) { - const char *pers = "gen_key"; - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; - - mbedtls_pk_free(&claim_data->key); - mbedtls_pk_init(&claim_data->key); - mbedtls_ctr_drbg_init(&ctr_drbg); - memset(claim_data->payload, 0, sizeof(claim_data->payload)); - - ESP_LOGD(TAG, "Seeding the random number generator."); - mbedtls_entropy_init(&entropy); - int ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen(pers)); - if (ret != 0) { - ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%04x", -ret ); - mbedtls_pk_free(&claim_data->key); - goto exit; + esp_rmaker_claim_data_t *claim_data = (esp_rmaker_claim_data_t *)args; + esp_rmaker_claim_generate_csr(claim_data, esp_rmaker_get_node_id()); + xEventGroupSetBits(claim_csr_event_group, CLAIM_CSR_TASK_BIT); + vTaskDelete(NULL); +} +static esp_err_t _esp_rmaker_claim_generate_csr(esp_rmaker_claim_data_t *claim_data) +{ + claim_csr_event_group = xEventGroupCreate(); + if (!claim_csr_event_group) { + ESP_LOGE(TAG, "Couldn't create CSR event group."); + return ESP_ERR_NO_MEM; } - ESP_LOGD(TAG, "Generating the private key..." ); - ret = mbedtls_pk_setup(&claim_data->key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); - if (ret != 0) { - ESP_LOGE(TAG, "mbedtls_pk_setup returned -0x%04x", -ret ); - mbedtls_pk_free(&claim_data->key); - goto exit; +#define ESP_RMAKER_CLAIM_CSR_TASK_STACK_SIZE (10 * 1024) + if (xTaskCreate(&esp_rmaker_claim_csr_task, "claim_csr_task", ESP_RMAKER_CLAIM_CSR_TASK_STACK_SIZE, + claim_data, (CONFIG_ESP_RMAKER_TASK_PRIORITY + 1), NULL) != pdPASS) { + ESP_LOGE(TAG, "Couldn't create CSR generation task"); + vEventGroupDelete(claim_csr_event_group); + return ESP_ERR_NO_MEM; } - ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(claim_data->key), mbedtls_ctr_drbg_random, &ctr_drbg, CLAIM_PK_SIZE, 65537); /* here, 65537 is the RSA exponent */ - if (ret != 0) { - ESP_LOGE(TAG, "mbedtls_rsa_gen_key returned -0x%04x", -ret ); - mbedtls_pk_free(&claim_data->key); - goto exit; + /* Wait for claim init to complete */ + xEventGroupWaitBits(claim_csr_event_group, CLAIM_CSR_TASK_BIT, false, true, portMAX_DELAY); + if (claim_data->state == RMAKER_CLAIM_STATE_CSR_GENERATED) { + return ESP_OK; } + return ESP_FAIL; +} +/* Parse the Claim Init response and generate Claim Verify request + * + * Claim Init Response format: + * {"node_id":""} + * + * Claim Verify Request format + * {"csr":""} + */ +static esp_err_t handle_assisted_claim_init_response(esp_rmaker_claim_data_t *claim_data) +{ + ESP_LOGD(TAG, "Claim Init Response: %s", claim_data->payload); + jparse_ctx_t jctx; + if (json_parse_start(&jctx, claim_data->payload, strlen(claim_data->payload)) == 0) { + char node_id[64]; + int ret = json_obj_get_string(&jctx, "node_id", node_id, sizeof(node_id)); + json_parse_end(&jctx); + if (ret == 0) { + esp_rmaker_storage_set("node_id", node_id, strlen(node_id)); + esp_rmaker_change_node_id(node_id, strlen(node_id)); + /* We use _esp_rmaker_claim_generate_csr instead of esp_rmaker_claim_generate_csr() + * because the thread in whose context this function is called doesn't have + * enough stack memory to generate CSR. A new thread with larger stack is spawned + * to generate the CSR by the below function. + */ + esp_err_t err = _esp_rmaker_claim_generate_csr(claim_data); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to generate CSR."); + return err; + } + escape_new_line(claim_data); - ESP_LOGD(TAG, "Converting Private Key to PEM..."); - ret = mbedtls_pk_write_key_pem(&claim_data->key, (unsigned char *)claim_data->payload, sizeof(claim_data->payload)); - if (ret != 0) { - ESP_LOGE(TAG, "mbedtls_pk_write_key_pem returned -0x%04x", -ret ); - mbedtls_pk_free(&claim_data->key); - goto exit; + json_gen_str_t jstr; + json_gen_str_start(&jstr, claim_data->payload, sizeof(claim_data->payload), NULL, NULL); + json_gen_start_object(&jstr); + json_gen_obj_set_string(&jstr, "csr", (char *)claim_data->csr); + json_gen_end_object(&jstr); + json_gen_str_end(&jstr); + claim_data->payload_len = strlen(claim_data->payload); + claim_data->payload_offset = 0; + return ESP_OK; + } else { + ESP_LOGE(TAG, "Claim Init Response invalid."); + } } -exit: - mbedtls_ctr_drbg_free(&ctr_drbg); - mbedtls_entropy_free(&entropy); - return ret; + ESP_LOGE(TAG, "Failed to parse Claim Init Response."); + return ESP_FAIL; +} +#include +#define CLAIM_FRAGMENT_SIZE 200 +esp_err_t esp_rmaker_assisted_claim_handle_start(RmakerClaim__RMakerClaimPayload *command, + RmakerClaim__RMakerClaimPayload *response, esp_rmaker_claim_data_t *claim_data) +{ + if (claim_data->state < RMAKER_CLAIM_STATE_PK_GENERATED) { + ESP_LOGE(TAG, "PK not created. Cannot proceed with Assisted Claiming."); + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidState; + return ESP_OK; + } + if (generate_claim_init_request(claim_data) != ESP_OK) { + return ESP_OK; + } + RmakerClaim__PayloadBuf *payload_buf = response->resppayload->buf; + payload_buf->offset = 0; + payload_buf->totallen = claim_data->payload_len; + payload_buf->payload.data = (uint8_t *)claim_data->payload; + payload_buf->payload.len = claim_data->payload_len; + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__Success; + claim_data->state = RMAKER_CLAIM_STATE_INIT; + ESP_LOGI(TAG, "Assisted Claiming Started."); + return ESP_OK; } -static esp_err_t generate_csr(esp_rmaker_claim_data_t *claim_data) +/* Return ESP_OK if this is just an application layer error. The response content will + * indicate error to the client. + */ +ProtobufCBinaryData *esp_rmaker_assisted_claim_validate_data(RmakerClaim__PayloadBuf *recv_payload, + RmakerClaim__RMakerClaimPayload *response, esp_rmaker_claim_data_t *claim_data) { - const char *pers = "gen_csr"; - mbedtls_x509write_csr csr; - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_entropy_context entropy; - - /* Generating CSR from the private key */ - mbedtls_x509write_csr_init(&csr); - mbedtls_x509write_csr_set_md_alg(&csr, MBEDTLS_MD_SHA256); - mbedtls_ctr_drbg_init(&ctr_drbg); - - ESP_LOGD(TAG, "Seeding the random number generator."); - mbedtls_entropy_init(&entropy); - int ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen(pers)); - if (ret != 0) { - ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%04x", -ret ); - goto exit; + if (recv_payload == NULL) { + ESP_LOGE(TAG, "Empty response received. Cannot proceed."); + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidParam; + return NULL; } - char subject_name[20]; - snprintf(subject_name, sizeof(subject_name), "CN=%s", esp_rmaker_get_node_id()); - ret = mbedtls_x509write_csr_set_subject_name(&csr, subject_name); - if (ret != 0) { - ESP_LOGE(TAG, "mbedtls_x509write_csr_set_subject_name returned %d", ret ); - goto exit; + /* Read the command */ + ProtobufCBinaryData *recv_payload_buf = &recv_payload->payload; + if (!recv_payload_buf) { + ESP_LOGE(TAG, "No data received. Cannot proceed."); + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidParam; + return NULL; } - - memset(claim_data->csr, 0, sizeof(claim_data->csr)); - mbedtls_x509write_csr_set_key(&csr, &claim_data->key); - ESP_LOGD(TAG, "Generating PEM"); - ret = mbedtls_x509write_csr_pem(&csr, claim_data->csr, sizeof(claim_data->csr), mbedtls_ctr_drbg_random, &ctr_drbg); - if (ret < 0) { - ESP_LOGE(TAG, "mbedtls_x509write_csr_pem returned -0x%04x", -ret ); - goto exit; + if ((recv_payload_buf->len + recv_payload->offset) > recv_payload->totallen) { + ESP_LOGE(TAG, "Received data exceeds total length."); + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidParam; + return NULL; } - ESP_LOGD(TAG, "CSR generated."); -exit: - - mbedtls_x509write_csr_free(&csr); - mbedtls_pk_free(&claim_data->key); - mbedtls_ctr_drbg_free(&ctr_drbg); - mbedtls_entropy_free(&entropy); - - return ret; + if (recv_payload_buf->len >= sizeof(claim_data->payload)) { + ESP_LOGE(TAG, "Received data too long (%d bytes).", recv_payload_buf->len); + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__NoMemory; + return NULL; + } + return recv_payload_buf; } -esp_err_t __esp_rmaker_self_claim_init(void) +/* Return ESP_OK if this is just an application layer error. The response content will + * indicate error to the client. + */ +esp_err_t esp_rmaker_assisted_claim_handle_init(RmakerClaim__RMakerClaimPayload *command, + RmakerClaim__RMakerClaimPayload *response, esp_rmaker_claim_data_t *claim_data) +{ + if (claim_data->state < RMAKER_CLAIM_STATE_INIT) { + ESP_LOGE(TAG, "Claiming hasn't started. Cannot proceed with init handling."); + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidState; + return ESP_OK; + } else if (claim_data->state != RMAKER_CLAIM_STATE_INIT_DONE) { + if (command->payload_case != RMAKER_CLAIM__RMAKER_CLAIM_PAYLOAD__PAYLOAD_CMD_PAYLOAD) { + ESP_LOGE(TAG, "Invalid response received for Claim Init. Cannot proceed."); + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidParam; + return ESP_OK; + } + RmakerClaim__PayloadBuf *recv_payload = command->cmdpayload; + ProtobufCBinaryData *recv_payload_buf = esp_rmaker_assisted_claim_validate_data + (recv_payload, response, claim_data); + if (!recv_payload_buf) { + ESP_LOGE(TAG, "Failed to get Claim Init Data."); + return ESP_OK; + } + if (recv_payload_buf->len != recv_payload->totallen) { + ESP_LOGE(TAG, "Claim Init Data length not equal to total length. Cannot proceed."); + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidParam; + return ESP_OK; + } + memset(claim_data->payload, 0, sizeof(claim_data->payload)); + memcpy(claim_data->payload, recv_payload_buf->data, recv_payload_buf->len); + if (handle_assisted_claim_init_response(claim_data) != ESP_OK) { + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidParam; + ESP_LOGE(TAG, "Error handling Claim Init response."); + return ESP_OK; + } else { + claim_data->state = RMAKER_CLAIM_STATE_INIT_DONE; + } + } + RmakerClaim__PayloadBuf *payload_buf = response->resppayload->buf; + payload_buf->totallen = claim_data->payload_len; + payload_buf->offset = claim_data->payload_offset; + + payload_buf->payload.data = (uint8_t *)claim_data->payload + claim_data->payload_offset; + payload_buf->payload.len = (claim_data->payload_len - claim_data->payload_offset) > CLAIM_FRAGMENT_SIZE ? + CLAIM_FRAGMENT_SIZE : (claim_data->payload_len - claim_data->payload_offset); + + claim_data->payload_offset += payload_buf->payload.len; + + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__Success; + + if (claim_data->payload_offset == claim_data->payload_len) { + ESP_LOGD(TAG, "Finished sending Claim Verify Payload."); + claim_data->state = RMAKER_CLAIM_STATE_VERIFY; + } + return ESP_OK; +} +/* Return ESP_OK if this is just an application layer error. The response content will + * indicate error to the client. + */ +esp_err_t esp_rmaker_assisted_claim_handle_verify(RmakerClaim__RMakerClaimPayload *command, + RmakerClaim__RMakerClaimPayload *response, esp_rmaker_claim_data_t *claim_data) +{ + if (claim_data->state < RMAKER_CLAIM_STATE_VERIFY) { + ESP_LOGE(TAG, "Invalid state. Cannot proceed with verify handling."); + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidState; + return ESP_OK; + } + if (command->payload_case != RMAKER_CLAIM__RMAKER_CLAIM_PAYLOAD__PAYLOAD_CMD_PAYLOAD) { + ESP_LOGE(TAG, "Invalid response received for Claim Verify. Cannot proceed."); + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidParam; + return ESP_OK; + } + RmakerClaim__PayloadBuf *recv_payload = command->cmdpayload; + ProtobufCBinaryData *recv_payload_buf = esp_rmaker_assisted_claim_validate_data + (recv_payload, response, claim_data); + if (!recv_payload_buf) { + ESP_LOGE(TAG, "Failed to get Claim Verify Data."); + return ESP_OK; + } + /* If offset is 0, this is the start of the fragmented data. */ + if (recv_payload->offset == 0) { + memset(claim_data->payload, 0, sizeof(claim_data->payload)); + claim_data->payload_offset = 0; + claim_data->payload_len = 0; + } + claim_data->payload_offset = recv_payload->offset; + memcpy(claim_data->payload + claim_data->payload_offset, recv_payload_buf->data, recv_payload_buf->len); + claim_data->payload_len += recv_payload_buf->len; + + if ((recv_payload->offset + recv_payload_buf->len) == recv_payload->totallen) { + ESP_LOGD(TAG, "Received complete response of len = %d bytes for Claim Verify", recv_payload->totallen); + if (handle_claim_verify_response(claim_data) == ESP_OK) { + ESP_LOGI(TAG,"Assisted Claiming was Successful."); + claim_data->state = RMAKER_CLAIM_STATE_VERIFY_DONE; + if (claim_event_group) { + xEventGroupSetBits(claim_event_group, CLAIM_TASK_BIT); + } + } else { + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidParam; + return ESP_OK; + } + } + response->resppayload->status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__Success; + return ESP_OK; +} + +esp_err_t esp_rmaker_claiming_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen, void *priv_data) +{ + esp_rmaker_claim_data_t *claim_data = (esp_rmaker_claim_data_t *)priv_data; + if (!priv_data) { + ESP_LOGE(TAG, "Claim data cannot be NULL. Cannot proceed with Assisted Claiming."); + return ESP_ERR_INVALID_STATE; + } + RmakerClaim__RMakerClaimPayload *command; + command = rmaker_claim__rmaker_claim_payload__unpack(NULL, inlen, inbuf); + + if (!command) { + ESP_LOGE(TAG, "No Claim command received"); + return ESP_ERR_INVALID_ARG; + } + + /* Initialise the response objects */ + RmakerClaim__RMakerClaimPayload response; + rmaker_claim__rmaker_claim_payload__init(&response); + response.msg = command->msg + 1; + response.payload_case = RMAKER_CLAIM__RMAKER_CLAIM_PAYLOAD__PAYLOAD_RESP_PAYLOAD; + + RmakerClaim__RespPayload resppayload; + rmaker_claim__resp_payload__init(&resppayload); + resppayload.status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__Fail; + response.resppayload = &resppayload; + + RmakerClaim__PayloadBuf payload_buf; + rmaker_claim__payload_buf__init(&payload_buf); + resppayload.buf = &payload_buf; + + ESP_LOGD(TAG, "Received claim command: %d", command->msg); + + /* Handle the received command */ + switch (command->msg) { + case RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimStart: + esp_rmaker_assisted_claim_handle_start(command, &response, claim_data); + break; + case RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimInit: + esp_rmaker_assisted_claim_handle_init(command, &response, claim_data); + break; + case RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimVerify: + esp_rmaker_assisted_claim_handle_verify(command, &response, claim_data); + break; + case RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimAbort: + memset(claim_data->payload, 0, sizeof(claim_data->payload)); + claim_data->payload_len = 0; + claim_data->payload_offset = 0; + /* Go back to RMAKER_CLAIM_STATE_PK_GENERATED, so that claim can restart */ + claim_data->state = RMAKER_CLAIM_STATE_PK_GENERATED; + resppayload.status = RMAKER_CLAIM__RMAKER_CLAIM_STATUS__Success; + ESP_LOGW(TAG, "Assisted Claiming Aborted."); + break; + default: + break; + } + *outlen = rmaker_claim__rmaker_claim_payload__get_packed_size(&response); + *outbuf = (uint8_t *)malloc(*outlen); + rmaker_claim__rmaker_claim_payload__pack(&response, *outbuf); + rmaker_claim__rmaker_claim_payload__free_unpacked(command, NULL); + return ESP_OK; +} +#define CLAIM_ENDPOINT "rmaker_claim" +static void event_handler(void* arg, esp_event_base_t event_base, + int event_id, void* event_data) +{ + if (event_base == WIFI_PROV_EVENT) { + switch (event_id) { + case WIFI_PROV_INIT: { + static const char *capabilities[] = {"claim"}; + wifi_prov_mgr_set_app_info("rmaker", "1.0", capabilities, 1); + if (wifi_prov_mgr_endpoint_create(CLAIM_ENDPOINT) != ESP_OK) { + ESP_LOGE(TAG, "Failed to create claim end point."); + } + break; + } + case WIFI_PROV_START: + if (wifi_prov_mgr_endpoint_register(CLAIM_ENDPOINT, esp_rmaker_claiming_handler, arg) != ESP_OK) { + ESP_LOGE(TAG, "Failed to register claim end point."); + } + break; + default: + break; + } + } +} +#endif /* CONFIG_ESP_RMAKER_ASSISTED_CLAIM */ +esp_err_t __esp_rmaker_claim_init(esp_rmaker_claim_data_t *claim_data) { char hexstr[9]; uint32_t my_random; esp_err_t err; - ESP_LOGI(TAG, "Initialising Self Claiming. This may take time."); - /* Check if the claim data structure is already allocated. If yes, free it */ - if (g_claim_data) { - free(g_claim_data); - g_claim_data = NULL; + char *key = esp_rmaker_get_client_key(); + if (key) { + mbedtls_pk_free(&claim_data->key); + mbedtls_pk_init(&claim_data->key); + if (mbedtls_pk_parse_key(&claim_data->key, (uint8_t *)key, strlen(key) + 1, NULL, 0) == 0) { + ESP_LOGI(TAG, "Private key already exists. No need to re-initialise it."); + claim_data->state = RMAKER_CLAIM_STATE_PK_GENERATED; + } + free(key); } - /* Allocate memory for the claim data */ - g_claim_data = calloc(1, sizeof(esp_rmaker_claim_data_t)); - if (!g_claim_data) { - ESP_LOGE(TAG, "Failed to allocate %d bytes for Claim data.", sizeof(esp_rmaker_claim_data_t)); - return ESP_ERR_NO_MEM; + if (claim_data->state != RMAKER_CLAIM_STATE_PK_GENERATED) { + /* Generate the Private Key */ + err = esp_rmaker_claim_generate_key(claim_data); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to generate private key."); + return err; + } + err = esp_rmaker_storage_set(ESP_RMAKER_CLIENT_KEY_NVS_KEY, claim_data->payload, strlen((char *)claim_data->payload)); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to save private key to storage."); + return err; + } } - - /* Check if the CSR is already available. If yes, just generate the payload for claim init - * and return from here instead of re-generating the key and CSR - */ - void *csr = esp_rmaker_get_client_csr(); - if (csr) { - snprintf(g_claim_data->payload, sizeof(g_claim_data->payload), "{\"mac_addr\":\"%s\",\"platform\":\"esp32s2\"}", - esp_rmaker_get_node_id()); - strncpy((char *)g_claim_data->csr, csr, (sizeof(g_claim_data->csr) - 1)); - g_claim_data->csr[sizeof(g_claim_data->csr) - 1] = 0; - free(csr); - ESP_LOGI(TAG, "CSR already exists. No need to re-initialise Claiming."); - return ESP_OK; - } - /* Generate the Private Key */ - err = generate_key(g_claim_data); - if (err != ESP_OK) { - free(g_claim_data); - g_claim_data = NULL; - ESP_LOGE(TAG, "Failed to generate private key."); - return err; - } - /* Store the key in the storage */ - ESP_LOGD(TAG, "Storing private key to NVS..."); - err = esp_rmaker_storage_set(ESP_RMAKER_CLIENT_KEY_NVS_KEY, g_claim_data->payload, strlen((char *)g_claim_data->payload)); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to store private key to storage."); - free(g_claim_data); - g_claim_data = NULL; - } - /* Generate random hex string */ memset(hexstr, 0, sizeof(hexstr)); esp_fill_random(&my_random, sizeof(my_random)); @@ -473,74 +820,115 @@ esp_err_t __esp_rmaker_self_claim_init(void) /* Store the PoP in the storage */ err = esp_rmaker_storage_set(ESP_RMAKER_CLIENT_RANDOM_NVS_KEY, hexstr, strlen(hexstr)); if (err != ESP_OK) { - free(g_claim_data); - g_claim_data = NULL; + ESP_LOGE(TAG, "Failed to store random number to storage"); return err; } - - /* Generate CSR */ - err = generate_csr(g_claim_data); - ESP_LOGD(TAG, "CSR generated successfully."); +#ifdef CONFIG_ESP_RMAKER_SELF_CLAIM + err = esp_rmaker_claim_generate_csr(claim_data, esp_rmaker_get_node_id()); if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to generate CSR for Claiming"); - free(g_claim_data); - g_claim_data = NULL; + ESP_LOGE(TAG, "Failed to generate CSR."); return err; } - - /* New line characters from the CSR need to be removed and replaced with explicit \n for the claiming + /* New line characters from the CSR need to be removed and replaced with explicit \n for the claiming * service to parse properly. Make that change here and store the CSR in storage. */ - escape_new_line(g_claim_data); - err = esp_rmaker_storage_set(ESP_RMAKER_CLIENT_CSR_NVS_KEY, g_claim_data->csr, strlen((char *)g_claim_data->csr)); - if (err != ESP_OK) { - free(g_claim_data); - g_claim_data = NULL; - return err; - } else { - ESP_LOGI(TAG, "Self Claiming initialised successfully."); - } - snprintf(g_claim_data->payload, sizeof(g_claim_data->payload), "{\"mac_addr\":\"%s\",\"platform\":\"esp32s2\"}", - esp_rmaker_get_node_id()); + escape_new_line(claim_data); +#endif /* CONFIG_ESP_RMAKER_SELF_CLAIM */ return err; } -void esp_rmaker_self_claim_task(void *args) +void esp_rmaker_claim_task(void *args) { - esp_err_t err = __esp_rmaker_self_claim_init(); - if (args) { - *((esp_err_t *)args) = err; + if (!args) { + ESP_LOGE(TAG, "Arguments for claiming task cannot be NULL"); + return; } - xEventGroupSetBits(self_claim_event_group, SELF_CLAIM_TASK_BIT); + esp_rmaker_claim_data_t *claim_data = calloc(1, sizeof(esp_rmaker_claim_data_t)); + if (!claim_data) { + ESP_LOGE(TAG, "Failed to allocate memory for claim data."); + return; + } + if (__esp_rmaker_claim_init(claim_data) != ESP_OK) { + esp_rmaker_claim_data_free(claim_data); + } else { + *((esp_rmaker_claim_data_t **)args) = claim_data; + } + xEventGroupSetBits(claim_event_group, CLAIM_TASK_BIT); vTaskDelete(NULL); } -esp_err_t esp_rmaker_self_claim_init(void) +static esp_rmaker_claim_data_t *esp_rmaker_claim_init(void) { - self_claim_event_group = xEventGroupCreate(); - if (!self_claim_event_group) { + static bool claim_init_done; + if (claim_init_done) { + ESP_LOGE(TAG, "Claim already initialised"); + return NULL; + } + claim_event_group = xEventGroupCreate(); + if (!claim_event_group) { + ESP_LOGE(TAG, "Couldn't create event group"); + return NULL; + } + esp_rmaker_claim_data_t *claim_data = NULL; + +#define ESP_RMAKER_CLAIM_TASK_STACK_SIZE (10 * 1024) + /* Using tskIDLE_PRIORITY so that the time consuming tasks, especially + * PK generation does not trigger task WatchDog timer. + */ + if (xTaskCreate(&esp_rmaker_claim_task, "claim_task", ESP_RMAKER_CLAIM_TASK_STACK_SIZE, + &claim_data, tskIDLE_PRIORITY, NULL) != pdPASS) { + ESP_LOGE(TAG, "Couldn't create Claim task"); + vEventGroupDelete(claim_event_group); + return NULL; + } + + /* Wait for claim init to complete */ + xEventGroupWaitBits(claim_event_group, CLAIM_TASK_BIT, false, true, portMAX_DELAY); + vEventGroupDelete(claim_event_group); + claim_event_group = NULL; + return claim_data; +} + +#ifdef CONFIG_ESP_RMAKER_SELF_CLAIM +esp_rmaker_claim_data_t *esp_rmaker_self_claim_init(void) +{ + ESP_LOGI(TAG, "Initialising Self Claiming. This may take time."); + return esp_rmaker_claim_init(); +} +#endif +#ifdef CONFIG_ESP_RMAKER_ASSISTED_CLAIM +esp_err_t esp_rmaker_assisted_claim_perform(esp_rmaker_claim_data_t *claim_data) +{ + if (claim_data == NULL) { + ESP_LOGE(TAG, "Assisted claiming not initialised."); + return ESP_ERR_INVALID_STATE; + } + claim_event_group = xEventGroupCreate(); + if (!claim_event_group) { ESP_LOGE(TAG, "Couldn't create event group"); return ESP_ERR_NO_MEM; } - esp_err_t *err = (esp_err_t *)calloc(1, sizeof(esp_err_t)); - if (!err) { - ESP_LOGE(TAG, "Couldn't allocate err"); - vEventGroupDelete(self_claim_event_group); - return ESP_ERR_NO_MEM; + /* Wait for assisted claim to complete */ + ESP_LOGI(TAG, "Waiting for assisted claim to finish."); + xEventGroupWaitBits(claim_event_group, CLAIM_TASK_BIT, false, true, portMAX_DELAY); + esp_err_t err = ESP_FAIL; + if (claim_data->state == RMAKER_CLAIM_STATE_VERIFY_DONE) { + err = ESP_OK; } - -#define ESP_RMAKER_SELF_CLAIM_TASK_STACK_SIZE (10 * 1024) - if (xTaskCreate(&esp_rmaker_self_claim_task, "self_claim_task", ESP_RMAKER_SELF_CLAIM_TASK_STACK_SIZE, err, (CONFIG_ESP_RMAKER_TASK_PRIORITY + 1), NULL) != pdPASS) { - ESP_LOGE(TAG, "Couldn't create Self Claim task"); - free(err); - vEventGroupDelete(self_claim_event_group); - return ESP_ERR_NO_MEM; - } - - /* Wait for self claim to complete */ - xEventGroupWaitBits(self_claim_event_group, SELF_CLAIM_TASK_BIT, false, true, portMAX_DELAY); - esp_err_t ret = *err; - free(err); - vEventGroupDelete(self_claim_event_group); - return ret; + esp_event_handler_unregister(WIFI_PROV_EVENT, WIFI_PROV_INIT, &event_handler); + esp_event_handler_unregister(WIFI_PROV_EVENT, WIFI_PROV_START, &event_handler); + esp_rmaker_claim_data_free(claim_data); + vEventGroupDelete(claim_event_group); + return err; } +esp_rmaker_claim_data_t *esp_rmaker_assisted_claim_init(void) +{ + ESP_LOGI(TAG, "Initialising Assisted Claiming. This may take time."); + esp_rmaker_claim_data_t *claim_data = esp_rmaker_claim_init(); + if (claim_data) { + esp_event_handler_register(WIFI_PROV_EVENT, WIFI_PROV_INIT, &event_handler, claim_data); + esp_event_handler_register(WIFI_PROV_EVENT, WIFI_PROV_START, &event_handler, claim_data); + } + return claim_data; +} +#endif diff --git a/components/esp_rainmaker/src/core/esp_rmaker_claim.h b/components/esp_rainmaker/src/core/esp_rmaker_claim.h index a1472f8..c9aaf5a 100644 --- a/components/esp_rainmaker/src/core/esp_rmaker_claim.h +++ b/components/esp_rainmaker/src/core/esp_rmaker_claim.h @@ -12,6 +12,38 @@ // See the License for the specific language governing permissions and // limitations under the License. +#pragma once +#include #include -esp_err_t esp_rmaker_self_claim_init(void); -esp_err_t esp_rmaker_self_claim_perform(void); +#define MAX_CSR_SIZE 1024 +#define MAX_PAYLOAD_SIZE 3072 + +typedef enum { + RMAKER_CLAIM_STATE_PK_GENERATED = 1, + RMAKER_CLAIM_STATE_INIT, + RMAKER_CLAIM_STATE_INIT_DONE, + RMAKER_CLAIM_STATE_CSR_GENERATED, + RMAKER_CLAIM_STATE_VERIFY, + RMAKER_CLAIM_STATE_VERIFY_DONE, +} esp_rmaker_claim_state_t; + +typedef struct { + esp_rmaker_claim_state_t state; + unsigned char csr[MAX_CSR_SIZE]; + char payload[MAX_PAYLOAD_SIZE]; + size_t payload_offset; + size_t payload_len; + mbedtls_pk_context key; +} esp_rmaker_claim_data_t; + +#ifdef CONFIG_ESP_RMAKER_SELF_CLAIM +esp_rmaker_claim_data_t * esp_rmaker_self_claim_init(void); +esp_err_t esp_rmaker_self_claim_perform(esp_rmaker_claim_data_t *claim_data); +#endif +#ifdef CONFIG_ESP_RMAKER_ASSISTED_CLAIM +esp_rmaker_claim_data_t * esp_rmaker_assisted_claim_init(void); +esp_err_t esp_rmaker_assisted_claim_perform(esp_rmaker_claim_data_t *claim_data); +#endif + +void esp_rmaker_claim_data_free(esp_rmaker_claim_data_t *claim_data); + diff --git a/components/esp_rainmaker/src/core/esp_rmaker_claim.pb-c.c b/components/esp_rainmaker/src/core/esp_rmaker_claim.pb-c.c new file mode 100644 index 0000000..ea66430 --- /dev/null +++ b/components/esp_rainmaker/src/core/esp_rmaker_claim.pb-c.c @@ -0,0 +1,398 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: esp_rmaker_claim.proto */ + +/* Do not generate deprecated warnings for self */ +#ifndef PROTOBUF_C__NO_DEPRECATED +#define PROTOBUF_C__NO_DEPRECATED +#endif + +#include "esp_rmaker_claim.pb-c.h" +void rmaker_claim__payload_buf__init + (RmakerClaim__PayloadBuf *message) +{ + static const RmakerClaim__PayloadBuf init_value = RMAKER_CLAIM__PAYLOAD_BUF__INIT; + *message = init_value; +} +size_t rmaker_claim__payload_buf__get_packed_size + (const RmakerClaim__PayloadBuf *message) +{ + assert(message->base.descriptor == &rmaker_claim__payload_buf__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t rmaker_claim__payload_buf__pack + (const RmakerClaim__PayloadBuf *message, + uint8_t *out) +{ + assert(message->base.descriptor == &rmaker_claim__payload_buf__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t rmaker_claim__payload_buf__pack_to_buffer + (const RmakerClaim__PayloadBuf *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &rmaker_claim__payload_buf__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RmakerClaim__PayloadBuf * + rmaker_claim__payload_buf__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RmakerClaim__PayloadBuf *) + protobuf_c_message_unpack (&rmaker_claim__payload_buf__descriptor, + allocator, len, data); +} +void rmaker_claim__payload_buf__free_unpacked + (RmakerClaim__PayloadBuf *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &rmaker_claim__payload_buf__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void rmaker_claim__resp_payload__init + (RmakerClaim__RespPayload *message) +{ + static const RmakerClaim__RespPayload init_value = RMAKER_CLAIM__RESP_PAYLOAD__INIT; + *message = init_value; +} +size_t rmaker_claim__resp_payload__get_packed_size + (const RmakerClaim__RespPayload *message) +{ + assert(message->base.descriptor == &rmaker_claim__resp_payload__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t rmaker_claim__resp_payload__pack + (const RmakerClaim__RespPayload *message, + uint8_t *out) +{ + assert(message->base.descriptor == &rmaker_claim__resp_payload__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t rmaker_claim__resp_payload__pack_to_buffer + (const RmakerClaim__RespPayload *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &rmaker_claim__resp_payload__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RmakerClaim__RespPayload * + rmaker_claim__resp_payload__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RmakerClaim__RespPayload *) + protobuf_c_message_unpack (&rmaker_claim__resp_payload__descriptor, + allocator, len, data); +} +void rmaker_claim__resp_payload__free_unpacked + (RmakerClaim__RespPayload *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &rmaker_claim__resp_payload__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void rmaker_claim__rmaker_claim_payload__init + (RmakerClaim__RMakerClaimPayload *message) +{ + static const RmakerClaim__RMakerClaimPayload init_value = RMAKER_CLAIM__RMAKER_CLAIM_PAYLOAD__INIT; + *message = init_value; +} +size_t rmaker_claim__rmaker_claim_payload__get_packed_size + (const RmakerClaim__RMakerClaimPayload *message) +{ + assert(message->base.descriptor == &rmaker_claim__rmaker_claim_payload__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t rmaker_claim__rmaker_claim_payload__pack + (const RmakerClaim__RMakerClaimPayload *message, + uint8_t *out) +{ + assert(message->base.descriptor == &rmaker_claim__rmaker_claim_payload__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t rmaker_claim__rmaker_claim_payload__pack_to_buffer + (const RmakerClaim__RMakerClaimPayload *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &rmaker_claim__rmaker_claim_payload__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RmakerClaim__RMakerClaimPayload * + rmaker_claim__rmaker_claim_payload__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RmakerClaim__RMakerClaimPayload *) + protobuf_c_message_unpack (&rmaker_claim__rmaker_claim_payload__descriptor, + allocator, len, data); +} +void rmaker_claim__rmaker_claim_payload__free_unpacked + (RmakerClaim__RMakerClaimPayload *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &rmaker_claim__rmaker_claim_payload__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +static const ProtobufCFieldDescriptor rmaker_claim__payload_buf__field_descriptors[3] = +{ + { + "Offset", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(RmakerClaim__PayloadBuf, offset), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "Payload", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BYTES, + 0, /* quantifier_offset */ + offsetof(RmakerClaim__PayloadBuf, payload), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "TotalLen", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(RmakerClaim__PayloadBuf, totallen), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned rmaker_claim__payload_buf__field_indices_by_name[] = { + 0, /* field[0] = Offset */ + 1, /* field[1] = Payload */ + 2, /* field[2] = TotalLen */ +}; +static const ProtobufCIntRange rmaker_claim__payload_buf__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 3 } +}; +const ProtobufCMessageDescriptor rmaker_claim__payload_buf__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "rmaker_claim.PayloadBuf", + "PayloadBuf", + "RmakerClaim__PayloadBuf", + "rmaker_claim", + sizeof(RmakerClaim__PayloadBuf), + 3, + rmaker_claim__payload_buf__field_descriptors, + rmaker_claim__payload_buf__field_indices_by_name, + 1, rmaker_claim__payload_buf__number_ranges, + (ProtobufCMessageInit) rmaker_claim__payload_buf__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor rmaker_claim__resp_payload__field_descriptors[2] = +{ + { + "Status", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(RmakerClaim__RespPayload, status), + &rmaker_claim__rmaker_claim_status__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "Buf", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + 0, /* quantifier_offset */ + offsetof(RmakerClaim__RespPayload, buf), + &rmaker_claim__payload_buf__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned rmaker_claim__resp_payload__field_indices_by_name[] = { + 1, /* field[1] = Buf */ + 0, /* field[0] = Status */ +}; +static const ProtobufCIntRange rmaker_claim__resp_payload__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor rmaker_claim__resp_payload__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "rmaker_claim.RespPayload", + "RespPayload", + "RmakerClaim__RespPayload", + "rmaker_claim", + sizeof(RmakerClaim__RespPayload), + 2, + rmaker_claim__resp_payload__field_descriptors, + rmaker_claim__resp_payload__field_indices_by_name, + 1, rmaker_claim__resp_payload__number_ranges, + (ProtobufCMessageInit) rmaker_claim__resp_payload__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor rmaker_claim__rmaker_claim_payload__field_descriptors[3] = +{ + { + "msg", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(RmakerClaim__RMakerClaimPayload, msg), + &rmaker_claim__rmaker_claim_msg_type__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmdPayload", + 10, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(RmakerClaim__RMakerClaimPayload, payload_case), + offsetof(RmakerClaim__RMakerClaimPayload, cmdpayload), + &rmaker_claim__payload_buf__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "respPayload", + 11, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(RmakerClaim__RMakerClaimPayload, payload_case), + offsetof(RmakerClaim__RMakerClaimPayload, resppayload), + &rmaker_claim__resp_payload__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned rmaker_claim__rmaker_claim_payload__field_indices_by_name[] = { + 1, /* field[1] = cmdPayload */ + 0, /* field[0] = msg */ + 2, /* field[2] = respPayload */ +}; +static const ProtobufCIntRange rmaker_claim__rmaker_claim_payload__number_ranges[2 + 1] = +{ + { 1, 0 }, + { 10, 1 }, + { 0, 3 } +}; +const ProtobufCMessageDescriptor rmaker_claim__rmaker_claim_payload__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "rmaker_claim.RMakerClaimPayload", + "RMakerClaimPayload", + "RmakerClaim__RMakerClaimPayload", + "rmaker_claim", + sizeof(RmakerClaim__RMakerClaimPayload), + 3, + rmaker_claim__rmaker_claim_payload__field_descriptors, + rmaker_claim__rmaker_claim_payload__field_indices_by_name, + 2, rmaker_claim__rmaker_claim_payload__number_ranges, + (ProtobufCMessageInit) rmaker_claim__rmaker_claim_payload__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCEnumValue rmaker_claim__rmaker_claim_status__enum_values_by_number[5] = +{ + { "Success", "RMAKER_CLAIM__RMAKER_CLAIM_STATUS__Success", 0 }, + { "Fail", "RMAKER_CLAIM__RMAKER_CLAIM_STATUS__Fail", 1 }, + { "InvalidParam", "RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidParam", 2 }, + { "InvalidState", "RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidState", 3 }, + { "NoMemory", "RMAKER_CLAIM__RMAKER_CLAIM_STATUS__NoMemory", 4 }, +}; +static const ProtobufCIntRange rmaker_claim__rmaker_claim_status__value_ranges[] = { +{0, 0},{0, 5} +}; +static const ProtobufCEnumValueIndex rmaker_claim__rmaker_claim_status__enum_values_by_name[5] = +{ + { "Fail", 1 }, + { "InvalidParam", 2 }, + { "InvalidState", 3 }, + { "NoMemory", 4 }, + { "Success", 0 }, +}; +const ProtobufCEnumDescriptor rmaker_claim__rmaker_claim_status__descriptor = +{ + PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC, + "rmaker_claim.RMakerClaimStatus", + "RMakerClaimStatus", + "RmakerClaim__RMakerClaimStatus", + "rmaker_claim", + 5, + rmaker_claim__rmaker_claim_status__enum_values_by_number, + 5, + rmaker_claim__rmaker_claim_status__enum_values_by_name, + 1, + rmaker_claim__rmaker_claim_status__value_ranges, + NULL,NULL,NULL,NULL /* reserved[1234] */ +}; +static const ProtobufCEnumValue rmaker_claim__rmaker_claim_msg_type__enum_values_by_number[8] = +{ + { "TypeCmdClaimStart", "RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimStart", 0 }, + { "TypeRespClaimStart", "RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeRespClaimStart", 1 }, + { "TypeCmdClaimInit", "RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimInit", 2 }, + { "TypeRespClaimInit", "RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeRespClaimInit", 3 }, + { "TypeCmdClaimVerify", "RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimVerify", 4 }, + { "TypeRespClaimVerify", "RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeRespClaimVerify", 5 }, + { "TypeCmdClaimAbort", "RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimAbort", 6 }, + { "TypeRespClaimAbort", "RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeRespClaimAbort", 7 }, +}; +static const ProtobufCIntRange rmaker_claim__rmaker_claim_msg_type__value_ranges[] = { +{0, 0},{0, 8} +}; +static const ProtobufCEnumValueIndex rmaker_claim__rmaker_claim_msg_type__enum_values_by_name[8] = +{ + { "TypeCmdClaimAbort", 6 }, + { "TypeCmdClaimInit", 2 }, + { "TypeCmdClaimStart", 0 }, + { "TypeCmdClaimVerify", 4 }, + { "TypeRespClaimAbort", 7 }, + { "TypeRespClaimInit", 3 }, + { "TypeRespClaimStart", 1 }, + { "TypeRespClaimVerify", 5 }, +}; +const ProtobufCEnumDescriptor rmaker_claim__rmaker_claim_msg_type__descriptor = +{ + PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC, + "rmaker_claim.RMakerClaimMsgType", + "RMakerClaimMsgType", + "RmakerClaim__RMakerClaimMsgType", + "rmaker_claim", + 8, + rmaker_claim__rmaker_claim_msg_type__enum_values_by_number, + 8, + rmaker_claim__rmaker_claim_msg_type__enum_values_by_name, + 1, + rmaker_claim__rmaker_claim_msg_type__value_ranges, + NULL,NULL,NULL,NULL /* reserved[1234] */ +}; diff --git a/components/esp_rainmaker/src/core/esp_rmaker_claim.pb-c.h b/components/esp_rainmaker/src/core/esp_rmaker_claim.pb-c.h new file mode 100644 index 0000000..c6fc37e --- /dev/null +++ b/components/esp_rainmaker/src/core/esp_rmaker_claim.pb-c.h @@ -0,0 +1,175 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: esp_rmaker_claim.proto */ + +#ifndef PROTOBUF_C_esp_5frmaker_5fclaim_2eproto__INCLUDED +#define PROTOBUF_C_esp_5frmaker_5fclaim_2eproto__INCLUDED + +#include + +PROTOBUF_C__BEGIN_DECLS + +#if PROTOBUF_C_VERSION_NUMBER < 1003000 +# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. +#elif 1003003 < PROTOBUF_C_MIN_COMPILER_VERSION +# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. +#endif + + +typedef struct _RmakerClaim__PayloadBuf RmakerClaim__PayloadBuf; +typedef struct _RmakerClaim__RespPayload RmakerClaim__RespPayload; +typedef struct _RmakerClaim__RMakerClaimPayload RmakerClaim__RMakerClaimPayload; + + +/* --- enums --- */ + +typedef enum _RmakerClaim__RMakerClaimStatus { + RMAKER_CLAIM__RMAKER_CLAIM_STATUS__Success = 0, + RMAKER_CLAIM__RMAKER_CLAIM_STATUS__Fail = 1, + RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidParam = 2, + RMAKER_CLAIM__RMAKER_CLAIM_STATUS__InvalidState = 3, + RMAKER_CLAIM__RMAKER_CLAIM_STATUS__NoMemory = 4 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(RMAKER_CLAIM__RMAKER_CLAIM_STATUS) +} RmakerClaim__RMakerClaimStatus; +typedef enum _RmakerClaim__RMakerClaimMsgType { + RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimStart = 0, + RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeRespClaimStart = 1, + RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimInit = 2, + RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeRespClaimInit = 3, + RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimVerify = 4, + RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeRespClaimVerify = 5, + RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimAbort = 6, + RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeRespClaimAbort = 7 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE) +} RmakerClaim__RMakerClaimMsgType; + +/* --- messages --- */ + +struct _RmakerClaim__PayloadBuf +{ + ProtobufCMessage base; + uint32_t offset; + ProtobufCBinaryData payload; + uint32_t totallen; +}; +#define RMAKER_CLAIM__PAYLOAD_BUF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&rmaker_claim__payload_buf__descriptor) \ + , 0, {0,NULL}, 0 } + + +struct _RmakerClaim__RespPayload +{ + ProtobufCMessage base; + RmakerClaim__RMakerClaimStatus status; + RmakerClaim__PayloadBuf *buf; +}; +#define RMAKER_CLAIM__RESP_PAYLOAD__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&rmaker_claim__resp_payload__descriptor) \ + , RMAKER_CLAIM__RMAKER_CLAIM_STATUS__Success, NULL } + + +typedef enum { + RMAKER_CLAIM__RMAKER_CLAIM_PAYLOAD__PAYLOAD__NOT_SET = 0, + RMAKER_CLAIM__RMAKER_CLAIM_PAYLOAD__PAYLOAD_CMD_PAYLOAD = 10, + RMAKER_CLAIM__RMAKER_CLAIM_PAYLOAD__PAYLOAD_RESP_PAYLOAD = 11 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(RMAKER_CLAIM__RMAKER_CLAIM_PAYLOAD__PAYLOAD) +} RmakerClaim__RMakerClaimPayload__PayloadCase; + +struct _RmakerClaim__RMakerClaimPayload +{ + ProtobufCMessage base; + RmakerClaim__RMakerClaimMsgType msg; + RmakerClaim__RMakerClaimPayload__PayloadCase payload_case; + union { + RmakerClaim__PayloadBuf *cmdpayload; + RmakerClaim__RespPayload *resppayload; + }; +}; +#define RMAKER_CLAIM__RMAKER_CLAIM_PAYLOAD__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&rmaker_claim__rmaker_claim_payload__descriptor) \ + , RMAKER_CLAIM__RMAKER_CLAIM_MSG_TYPE__TypeCmdClaimStart, RMAKER_CLAIM__RMAKER_CLAIM_PAYLOAD__PAYLOAD__NOT_SET, {0} } + + +/* RmakerClaim__PayloadBuf methods */ +void rmaker_claim__payload_buf__init + (RmakerClaim__PayloadBuf *message); +size_t rmaker_claim__payload_buf__get_packed_size + (const RmakerClaim__PayloadBuf *message); +size_t rmaker_claim__payload_buf__pack + (const RmakerClaim__PayloadBuf *message, + uint8_t *out); +size_t rmaker_claim__payload_buf__pack_to_buffer + (const RmakerClaim__PayloadBuf *message, + ProtobufCBuffer *buffer); +RmakerClaim__PayloadBuf * + rmaker_claim__payload_buf__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void rmaker_claim__payload_buf__free_unpacked + (RmakerClaim__PayloadBuf *message, + ProtobufCAllocator *allocator); +/* RmakerClaim__RespPayload methods */ +void rmaker_claim__resp_payload__init + (RmakerClaim__RespPayload *message); +size_t rmaker_claim__resp_payload__get_packed_size + (const RmakerClaim__RespPayload *message); +size_t rmaker_claim__resp_payload__pack + (const RmakerClaim__RespPayload *message, + uint8_t *out); +size_t rmaker_claim__resp_payload__pack_to_buffer + (const RmakerClaim__RespPayload *message, + ProtobufCBuffer *buffer); +RmakerClaim__RespPayload * + rmaker_claim__resp_payload__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void rmaker_claim__resp_payload__free_unpacked + (RmakerClaim__RespPayload *message, + ProtobufCAllocator *allocator); +/* RmakerClaim__RMakerClaimPayload methods */ +void rmaker_claim__rmaker_claim_payload__init + (RmakerClaim__RMakerClaimPayload *message); +size_t rmaker_claim__rmaker_claim_payload__get_packed_size + (const RmakerClaim__RMakerClaimPayload *message); +size_t rmaker_claim__rmaker_claim_payload__pack + (const RmakerClaim__RMakerClaimPayload *message, + uint8_t *out); +size_t rmaker_claim__rmaker_claim_payload__pack_to_buffer + (const RmakerClaim__RMakerClaimPayload *message, + ProtobufCBuffer *buffer); +RmakerClaim__RMakerClaimPayload * + rmaker_claim__rmaker_claim_payload__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void rmaker_claim__rmaker_claim_payload__free_unpacked + (RmakerClaim__RMakerClaimPayload *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*RmakerClaim__PayloadBuf_Closure) + (const RmakerClaim__PayloadBuf *message, + void *closure_data); +typedef void (*RmakerClaim__RespPayload_Closure) + (const RmakerClaim__RespPayload *message, + void *closure_data); +typedef void (*RmakerClaim__RMakerClaimPayload_Closure) + (const RmakerClaim__RMakerClaimPayload *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCEnumDescriptor rmaker_claim__rmaker_claim_status__descriptor; +extern const ProtobufCEnumDescriptor rmaker_claim__rmaker_claim_msg_type__descriptor; +extern const ProtobufCMessageDescriptor rmaker_claim__payload_buf__descriptor; +extern const ProtobufCMessageDescriptor rmaker_claim__resp_payload__descriptor; +extern const ProtobufCMessageDescriptor rmaker_claim__rmaker_claim_payload__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_esp_5frmaker_5fclaim_2eproto__INCLUDED */ diff --git a/components/esp_rainmaker/src/core/esp_rmaker_claim.proto b/components/esp_rainmaker/src/core/esp_rmaker_claim.proto new file mode 100644 index 0000000..93c21d0 --- /dev/null +++ b/components/esp_rainmaker/src/core/esp_rmaker_claim.proto @@ -0,0 +1,41 @@ +syntax = "proto3"; + +package rmaker_claim; + +enum RMakerClaimStatus { + Success = 0; + Fail = 1; + InvalidParam = 2; + InvalidState = 3; + NoMemory = 4; +} + +message PayloadBuf { + uint32 Offset = 1; + bytes Payload = 2; + uint32 TotalLen = 3; +} + +message RespPayload { + RMakerClaimStatus Status = 1; + PayloadBuf Buf = 2; +} + +enum RMakerClaimMsgType { + TypeCmdClaimStart = 0; + TypeRespClaimStart = 1; + TypeCmdClaimInit = 2; + TypeRespClaimInit = 3; + TypeCmdClaimVerify = 4; + TypeRespClaimVerify = 5; + TypeCmdClaimAbort = 6; + TypeRespClaimAbort = 7; +} + +message RMakerClaimPayload { + RMakerClaimMsgType msg = 1; + oneof payload { + PayloadBuf cmdPayload = 10; + RespPayload respPayload = 11; + } +} diff --git a/components/esp_rainmaker/src/core/esp_rmaker_client_data.c b/components/esp_rainmaker/src/core/esp_rmaker_client_data.c index 482ed2b..f5632be 100644 --- a/components/esp_rainmaker/src/core/esp_rmaker_client_data.c +++ b/components/esp_rainmaker/src/core/esp_rmaker_client_data.c @@ -28,11 +28,11 @@ extern uint8_t mqtt_server_root_ca_pem_end[] asm("_binary_mqtt_server_crt_end"); char * esp_rmaker_get_mqtt_host() { char *host = esp_rmaker_storage_get(ESP_RMAKER_MQTT_HOST_NVS_KEY); -#ifdef CONFIG_ESP_RMAKER_SELF_CLAIM +#if defined(CONFIG_ESP_RMAKER_SELF_CLAIM) || defined(CONFIG_ESP_RMAKER_ASSISTED_CLAIM) if (!host) { return strdup(CONFIG_ESP_RMAKER_MQTT_HOST); } -#endif /* CONFIG_ESP_RMAKER_SELF_CLAIM */ +#endif /* defined(CONFIG_ESP_RMAKER_SELF_CLAIM) || defined(CONFIG_ESP_RMAKER_ASSISTED_CLAIM) */ return host; } diff --git a/components/esp_rainmaker/src/core/esp_rmaker_core.c b/components/esp_rainmaker/src/core/esp_rmaker_core.c index 1b4f828..908fe93 100644 --- a/components/esp_rainmaker/src/core/esp_rmaker_core.c +++ b/components/esp_rainmaker/src/core/esp_rmaker_core.c @@ -41,6 +41,9 @@ static const char *TAG = "esp_rmaker_core"; #define ESP_RMAKER_TASK_STACK CONFIG_ESP_RMAKER_TASK_STACK #define ESP_RMAKER_TASK_PRIORITY CONFIG_ESP_RMAKER_TASK_PRIORITY +#if defined(CONFIG_ESP_RMAKER_SELF_CLAIM) || defined(CONFIG_ESP_RMAKER_ASSISTED_CLAIM) +#define ESP_RMAKER_CLAIM_ENABLED +#endif #define ESP_RMAKER_CHECK_HANDLE(rval) \ { \ @@ -68,9 +71,10 @@ typedef struct { esp_rmaker_state_t state; bool mqtt_connected; esp_rmaker_mqtt_config_t *mqtt_config; -#ifdef CONFIG_ESP_RMAKER_SELF_CLAIM - bool self_claim; -#endif /* CONFIG_ESP_RMAKER_SELF_CLAIM */ +#ifdef ESP_RMAKER_CLAIM_ENABLED + bool need_claim; + esp_rmaker_claim_data_t *claim_data; +#endif /* ESP_RMAKER_CLAIM_ENABLED */ QueueHandle_t work_queue; } esp_rmaker_priv_data_t; @@ -79,7 +83,7 @@ static esp_rmaker_priv_data_t *esp_rmaker_priv_data; static char *esp_rmaker_populate_node_id() { char *node_id = esp_rmaker_storage_get("node_id"); -#ifdef CONFIG_ESP_RMAKER_SELF_CLAIM +#ifdef ESP_RMAKER_CLAIM_ENABLED if (!node_id) { uint8_t eth_mac[6]; esp_err_t err = esp_wifi_get_mac(WIFI_IF_STA, eth_mac); @@ -91,16 +95,42 @@ static char *esp_rmaker_populate_node_id() snprintf(node_id, ESP_CLAIM_NODE_ID_SIZE + 1, "%02X%02X%02X%02X%02X%02X", eth_mac[0], eth_mac[1], eth_mac[2], eth_mac[3], eth_mac[4], eth_mac[5]); } -#endif /* CONFIG_ESP_RMAKER_SELF_CLAIM */ +#endif /* ESP_RMAKER_CLAIM_ENABLED */ return node_id; } +esp_err_t esp_rmaker_change_node_id(char *node_id, size_t len) +{ + if(esp_rmaker_priv_data) { + char *new_node_id = strndup(node_id, len); + if (!new_node_id) { + ESP_LOGE(TAG, "Failed to allocate %d bytes for new node_id.", len); + return ESP_ERR_NO_MEM; + } + if (esp_rmaker_priv_data->node_id) { + free(esp_rmaker_priv_data->node_id); + } + esp_rmaker_priv_data->node_id = new_node_id; + _esp_rmaker_node_t *node = (_esp_rmaker_node_t *)esp_rmaker_get_node(); + node->node_id = new_node_id; + ESP_LOGI(TAG, "New Node ID ----- %s", new_node_id); + return ESP_OK; + } + return ESP_ERR_INVALID_STATE; +} + /* Event handler for catching system events */ static void esp_rmaker_event_handler(void* arg, esp_event_base_t event_base, int event_id, void* event_data) { if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { +#ifdef CONFIG_ESP_RMAKER_ASSISTED_CLAIM + if (esp_rmaker_priv_data->claim_data) { + ESP_LOGE(TAG, "Node connected to Wi-Fi without Assisted claiming. Cannot proceed to MQTT connection."); + ESP_LOGE(TAG, "Please update your phone apps and repeat Wi-Fi provisioning with BLE transport."); + } +#endif /* Signal rmaker thread to continue execution */ xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_EVENT); } @@ -114,6 +144,11 @@ static esp_err_t esp_rmaker_deinit_priv_data(esp_rmaker_priv_data_t *rmaker_priv if (rmaker_priv_data->work_queue) { vQueueDelete(rmaker_priv_data->work_queue); } +#ifdef ESP_RMAKER_CLAIM_ENABLED + if (rmaker_priv_data->claim_data) { + esp_rmaker_claim_data_free(rmaker_priv_data->claim_data); + } +#endif if (rmaker_priv_data->mqtt_config) { esp_rmaker_clean_mqtt_config(rmaker_priv_data->mqtt_config); free(rmaker_priv_data->mqtt_config); @@ -188,20 +223,26 @@ static esp_err_t esp_rmaker_init(const esp_rmaker_config_t *config) } esp_rmaker_priv_data->mqtt_config = esp_rmaker_get_mqtt_config(); if (!esp_rmaker_priv_data->mqtt_config) { +#ifdef ESP_RMAKER_CLAIM_ENABLED #ifdef CONFIG_ESP_RMAKER_SELF_CLAIM - esp_rmaker_priv_data->self_claim = true; - if (esp_rmaker_self_claim_init() != ESP_OK) { + esp_rmaker_priv_data->claim_data = esp_rmaker_self_claim_init(); +#endif +#ifdef CONFIG_ESP_RMAKER_ASSISTED_CLAIM + esp_rmaker_priv_data->claim_data = esp_rmaker_assisted_claim_init(); +#endif + if (!esp_rmaker_priv_data->claim_data) { esp_rmaker_deinit_priv_data(esp_rmaker_priv_data); esp_rmaker_priv_data = NULL; - ESP_LOGE(TAG, "Failed to initialise Self Claiming."); + ESP_LOGE(TAG, "Failed to initialise Claiming."); return ESP_FAIL; } + esp_rmaker_priv_data->need_claim = true; #else esp_rmaker_deinit_priv_data(esp_rmaker_priv_data); esp_rmaker_priv_data = NULL; ESP_LOGE(TAG, "Failed to initialise MQTT Config. Please perform \"claiming\" using RainMaker CLI."); return ESP_FAIL; -#endif /* !CONFIG_ESP_RMAKER_SELF_CLAIM */ +#endif /* !ESP_RMAKER_CLAIM_ENABLED */ } else { if (esp_rmaker_mqtt_init(esp_rmaker_priv_data->mqtt_config) != ESP_OK) { esp_rmaker_deinit_priv_data(esp_rmaker_priv_data); @@ -296,25 +337,46 @@ static void esp_rmaker_task(void *param) esp_rmaker_priv_data->state = ESP_RMAKER_STATE_STARTING; esp_err_t err; wifi_event_group = xEventGroupCreate(); - ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &esp_rmaker_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &esp_rmaker_event_handler, esp_rmaker_priv_data)); + /* Assisted claiming needs to be done before Wi-Fi connection */ +#ifdef CONFIG_ESP_RMAKER_ASSISTED_CLAIM + if (esp_rmaker_priv_data->need_claim) { + esp_rmaker_post_event(RMAKER_EVENT_CLAIM_STARTED, NULL, 0); + err = esp_rmaker_assisted_claim_perform(esp_rmaker_priv_data->claim_data); + if (err != ESP_OK) { + esp_rmaker_post_event(RMAKER_EVENT_CLAIM_FAILED, NULL, 0); + ESP_LOGE(TAG, "esp_rmaker_self_claim_perform() returned %d. Aborting", err); + vTaskDelete(NULL); + } + esp_rmaker_priv_data->claim_data = NULL; + esp_rmaker_post_event(RMAKER_EVENT_CLAIM_SUCCESSFUL, NULL, 0); + } +#endif /* Wait for Wi-Fi connection */ xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, false, true, portMAX_DELAY); + vEventGroupDelete(wifi_event_group); if (esp_rmaker_priv_data->enable_time_sync) { #ifdef CONFIG_MBEDTLS_HAVE_TIME_DATE esp_rmaker_time_wait_for_sync(portMAX_DELAY); #endif } + /* Self claiming can be done only after Wi-Fi connection */ #ifdef CONFIG_ESP_RMAKER_SELF_CLAIM - if (esp_rmaker_priv_data->self_claim) { + if (esp_rmaker_priv_data->need_claim) { esp_rmaker_post_event(RMAKER_EVENT_CLAIM_STARTED, NULL, 0); - err = esp_rmaker_self_claim_perform(); + err = esp_rmaker_self_claim_perform(esp_rmaker_priv_data->claim_data); if (err != ESP_OK) { esp_rmaker_post_event(RMAKER_EVENT_CLAIM_FAILED, NULL, 0); ESP_LOGE(TAG, "esp_rmaker_self_claim_perform() returned %d. Aborting", err); vTaskDelete(NULL); } + esp_rmaker_priv_data->claim_data = NULL; esp_rmaker_post_event(RMAKER_EVENT_CLAIM_SUCCESSFUL, NULL, 0); + } +#endif +#ifdef ESP_RMAKER_CLAIM_ENABLED + if (esp_rmaker_priv_data->need_claim) { esp_rmaker_priv_data->mqtt_config = esp_rmaker_get_mqtt_config(); if (!esp_rmaker_priv_data->mqtt_config) { ESP_LOGE(TAG, "Failed to initialise MQTT Config after claiming. Aborting"); @@ -325,8 +387,9 @@ static void esp_rmaker_task(void *param) ESP_LOGE(TAG, "esp_rmaker_mqtt_init() returned %d. Aborting", err); vTaskDelete(NULL); } + esp_rmaker_priv_data->need_claim = false; } -#endif /* CONFIG_ESP_RMAKER_SELF_CLAIM */ +#endif /* ESP_RMAKER_CLAIM_ENABLED */ err = esp_rmaker_mqtt_connect(); if (err != ESP_OK) { ESP_LOGE(TAG, "esp_rmaker_mqtt_connect() returned %d. Aborting", err); diff --git a/components/esp_rainmaker/src/core/esp_rmaker_internal.h b/components/esp_rainmaker/src/core/esp_rmaker_internal.h index ef626bf..4234d2f 100644 --- a/components/esp_rainmaker/src/core/esp_rmaker_internal.h +++ b/components/esp_rainmaker/src/core/esp_rmaker_internal.h @@ -79,6 +79,7 @@ typedef struct { } _esp_rmaker_node_t; esp_rmaker_node_t *esp_rmaker_node_create(const char *name, const char *type); +esp_err_t esp_rmaker_change_node_id(char *node_id, size_t len); esp_err_t esp_rmaker_report_value(const esp_rmaker_param_val_t *val, char *key, json_gen_str_t *jptr); esp_err_t esp_rmaker_report_data_type(esp_rmaker_val_type_t type, json_gen_str_t *jptr); esp_err_t esp_rmaker_report_node_config(void); From dc61b3429ff3aea4c64ae97a2483e175471204e5 Mon Sep 17 00:00:00 2001 From: Piyush Shah Date: Wed, 9 Sep 2020 15:31:34 +0530 Subject: [PATCH 2/2] app_wifi: Make BLE provisioning as the default for ESP32 - This will be required for the new "Assisted Claiming" feature. --- examples/common/app_wifi/Kconfig.projbuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/common/app_wifi/Kconfig.projbuild b/examples/common/app_wifi/Kconfig.projbuild index 8b66017..d62c5d2 100644 --- a/examples/common/app_wifi/Kconfig.projbuild +++ b/examples/common/app_wifi/Kconfig.projbuild @@ -8,7 +8,7 @@ menu "ESP RainMaker App Wi-Fi Provisioning" choice APP_WIFI_PROV_TRANSPORT bool "Provisioning Transport method" - default APP_WIFI_PROV_TRANSPORT_SOFTAP + default APP_WIFI_PROV_TRANSPORT_BLE help Wi-Fi provisioning component offers both, SoftAP and BLE transports. Choose any one.