Merge branch 'feature/provisioning_backport_api_changes' into 'release/v3.2'

(backport v3.2)  Provisioning Framework API changes

See merge request idf/esp-idf!4249
This commit is contained in:
Angus Gratton 2019-02-19 10:47:47 +08:00
commit 332ccd0925
30 changed files with 589 additions and 263 deletions

View file

@ -17,6 +17,10 @@
#include <protocomm_security.h>
#include <esp_err.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Function prototype for protocomm endpoint handler
*/
@ -42,7 +46,7 @@ typedef struct protocomm protocomm_t;
* @brief Create a new protocomm instance
*
* This API will return a new dynamically allocated protocomm instance
* with all elements of the protocomm_t structure initialised to NULL.
* with all elements of the protocomm_t structure initialized to NULL.
*
* @return
* - protocomm_t* : On success
@ -71,7 +75,8 @@ void protocomm_delete(protocomm_t *pc);
* - An endpoint must be bound to a valid protocomm instance,
* created using `protocomm_new()`.
* - This function internally calls the registered `add_endpoint()`
* function which is a member of the protocomm_t instance structure.
* function of the selected transport which is a member of the
* protocomm_t instance structure.
*
* @param[in] pc Pointer to the protocomm instance
* @param[in] ep_name Endpoint identifier(name) string
@ -81,7 +86,7 @@ void protocomm_delete(protocomm_t *pc);
* Pass NULL if not needed.
*
* @return
* - ESP_OK : Added new endpoint succesfully
* - ESP_OK : Success
* - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists
* - ESP_ERR_NO_MEM : Error allocating endpoint resource
* - ESP_ERR_INVALID_ARG : Null instance/name/handler arguments
@ -103,7 +108,7 @@ esp_err_t protocomm_add_endpoint(protocomm_t *pc, const char *ep_name,
* @param[in] ep_name Endpoint identifier(name) string
*
* @return
* - ESP_OK : Added new endpoint succesfully
* - ESP_OK : Success
* - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist
* - ESP_ERR_INVALID_ARG : Null instance/name arguments
*/
@ -111,12 +116,12 @@ esp_err_t protocomm_remove_endpoint(protocomm_t *pc, const char *ep_name);
/**
* @brief Calls the registered handler of an endpoint session
* for processing incoming data and giving the output
* for processing incoming data and generating the response
*
* @note
* - An endpoint must be bound to a valid protocomm instance,
* created using `protocomm_new()`.
* - Resulting output buffer must be deallocated by the user.
* - Resulting output buffer must be deallocated by the caller.
*
* @param[in] pc Pointer to the protocomm instance
* @param[in] ep_name Endpoint identifier(name) string
@ -130,7 +135,7 @@ esp_err_t protocomm_remove_endpoint(protocomm_t *pc, const char *ep_name);
* @param[out] outlen Buffer length of the allocated output buffer
*
* @return
* - ESP_OK : Request handled succesfully
* - ESP_OK : Request handled successfully
* - ESP_FAIL : Internal error in execution of registered handler
* - ESP_ERR_NO_MEM : Error allocating internal resource
* - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist
@ -159,7 +164,7 @@ esp_err_t protocomm_req_handle(protocomm_t *pc, const char *ep_name, uint32_t se
* @param[in] pop Pointer to proof of possession for authenticating a client
*
* @return
* - ESP_OK : Added new security endpoint succesfully
* - ESP_OK : Success
* - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists
* - ESP_ERR_INVALID_STATE : Security endpoint already set
* - ESP_ERR_NO_MEM : Error allocating endpoint resource
@ -179,7 +184,7 @@ esp_err_t protocomm_set_security(protocomm_t *pc, const char *ep_name,
* @param[in] ep_name Endpoint identifier(name) string
*
* @return
* - ESP_OK : Added new endpoint succesfully
* - ESP_OK : Success
* - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist
* - ESP_ERR_INVALID_ARG : Null instance/name arguments
*/
@ -189,7 +194,7 @@ esp_err_t protocomm_unset_security(protocomm_t *pc, const char *ep_name);
* @brief Set endpoint for version verification
*
* This API can be used for setting an application specific protocol
* version which can be verfied by clients through the endpoint.
* version which can be verified by clients through the endpoint.
*
* @note
* - An endpoint must be bound to a valid protocomm instance,
@ -200,7 +205,7 @@ esp_err_t protocomm_unset_security(protocomm_t *pc, const char *ep_name);
* @param[in] version Version identifier(name) string
*
* @return
* - ESP_OK : Added new security endpoint succesfully
* - ESP_OK : Success
* - ESP_FAIL : Error adding endpoint / Endpoint with this name already exists
* - ESP_ERR_INVALID_STATE : Version endpoint already set
* - ESP_ERR_NO_MEM : Error allocating endpoint resource
@ -219,8 +224,12 @@ esp_err_t protocomm_set_version(protocomm_t *pc, const char *ep_name,
* @param[in] ep_name Endpoint identifier(name) string
*
* @return
* - ESP_OK : Added new endpoint succesfully
* - ESP_OK : Success
* - ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist
* - ESP_ERR_INVALID_ARG : Null instance/name arguments
*/
esp_err_t protocomm_unset_version(protocomm_t *pc, const char *ep_name);
#ifdef __cplusplus
}
#endif

View file

@ -16,6 +16,10 @@
#include <esp_err.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Proof Of Possession for authenticating a secure session
*/
@ -42,12 +46,12 @@ typedef struct protocomm_security_pop {
*/
typedef struct protocomm_security {
/**
* Unique version number of security implmentation
* Unique version number of security implementation
*/
int ver;
/**
* Function for initialising/allocating security
* Function for initializing/allocating security
* infrastructure
*/
esp_err_t (*init)();
@ -91,3 +95,7 @@ typedef struct protocomm_security {
const uint8_t *inbuf, ssize_t inlen,
uint8_t *outbuf, ssize_t *outlen);
} protocomm_security_t;
#ifdef __cplusplus
}
#endif

View file

@ -16,6 +16,10 @@
#include <protocomm_security.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Protocomm security version 0 implementation
*
@ -23,3 +27,7 @@
* security is required for the protocomm instance
*/
extern const protocomm_security_t protocomm_security0;
#ifdef __cplusplus
}
#endif

View file

@ -16,10 +16,18 @@
#include <protocomm_security.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Protocomm security version 1 implementation
*
* This is a full fledged security implmentation using
* This is a full fledged security implementation using
* Curve25519 key exchange and AES-256-CTR encryption
*/
extern const protocomm_security_t protocomm_security1;
#ifdef __cplusplus
}
#endif

View file

@ -16,6 +16,10 @@
#include <protocomm.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* BLE device name cannot be larger than this value
*/
@ -30,7 +34,7 @@ typedef struct name_uuid {
/**
* Name of the handler, which is passed to protocomm layer
*/
char *name;
const char *name;
/**
* UUID to be assigned to the BLE characteristic which is
@ -63,10 +67,10 @@ typedef struct {
* the initialization for characteristics/service for BLE.
*
* @param[in] pc Protocomm instance pointer obtained from protocomm_new()
* @param[in] config Pointer to config structure for initialising BLE
* @param[in] config Pointer to config structure for initializing BLE
*
* @return
* - ESP_OK : if successful
* - ESP_OK : Success
* - ESP_FAIL : Simple BLE start error
* - ESP_ERR_NO_MEM : Error allocating memory for internal resources
* - ESP_ERR_INVALID_STATE : Error in ble config
@ -85,8 +89,12 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con
* @param[in] pc Same protocomm instance that was passed to protocomm_ble_start()
*
* @return
* - ESP_OK : For success or appropriate error code
* - ESP_OK : Success
* - ESP_FAIL : Simple BLE stop error
* - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance
*/
esp_err_t protocomm_ble_stop(protocomm_t *pc);
#ifdef __cplusplus
}
#endif

View file

@ -16,6 +16,10 @@
#include <protocomm.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PROTOCOMM_CONSOLE_DEFAULT_CONFIG() { \
.stack_size = 4096, \
.task_priority = tskIDLE_PRIORITY + 3, \
@ -25,7 +29,7 @@
* @brief Config parameters for protocomm console
*/
typedef struct {
size_t stack_size; /*!< Stack size of console taks */
size_t stack_size; /*!< Stack size of console task */
unsigned task_priority; /*!< Priority of console task */
} protocomm_console_config_t;
@ -39,7 +43,7 @@ typedef struct {
* @param[in] config Config param structure for protocomm console
*
* @return
* - ESP_OK : Server started succefully
* - ESP_OK : Success
* - ESP_ERR_INVALID_ARG : Null arguments
* - ESP_ERR_NOT_SUPPORTED : Transport layer bound to another protocomm instance
* - ESP_ERR_INVALID_STATE : Transport layer already bound to this protocomm instance
@ -53,7 +57,11 @@ esp_err_t protocomm_console_start(protocomm_t *pc, const protocomm_console_confi
* @param[in] pc Same protocomm instance that was passed to protocomm_console_start()
*
* @return
* - ESP_OK : Server stopped succefully
* - ESP_OK : Success
* - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance pointer
*/
esp_err_t protocomm_console_stop(protocomm_t *pc);
#ifdef __cplusplus
}
#endif

View file

@ -22,11 +22,16 @@
.task_priority = tskIDLE_PRIORITY + 5, \
}
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Config parameters for protocomm HTTP server
*/
typedef struct {
uint16_t port; /*!< Port on which the http server will listen */
uint16_t port; /*!< Port on which the HTTP server will listen */
/**
* Stack size of server task, adjusted depending
@ -34,6 +39,31 @@ typedef struct {
*/
size_t stack_size;
unsigned task_priority; /*!< Priority of server task */
} protocomm_http_server_config_t; /*!< HTTP Server Configuration, if HTTP Server has not been started already */
/** Protocomm HTTPD Configuration Data
*/
typedef union {
/** HTTP Server Handle, if ext_handle_provided is set to true
*/
void *handle;
/** HTTP Server Configuration, if a server is not already active
*/
protocomm_http_server_config_t config;
} protocomm_httpd_config_data_t;
/**
* @brief Config parameters for protocomm HTTP server
*/
typedef struct {
/** Flag to indicate of an external HTTP Server Handle has been provided.
* In such as case, protocomm will use the same HTTP Server and not start
* a new one internally.
*/
bool ext_handle_provided;
/** Protocomm HTTPD Configuration Data */
protocomm_httpd_config_data_t data;
} protocomm_httpd_config_t;
/**
@ -46,10 +76,10 @@ typedef struct {
* one instance can be bound to an HTTP transport layer.
*
* @param[in] pc Protocomm instance pointer obtained from protocomm_new()
* @param[in] config Pointer to config structure for initialising HTTP server
* @param[in] config Pointer to config structure for initializing HTTP server
*
* @return
* - ESP_OK : Server started succefully
* - ESP_OK : Success
* - ESP_ERR_INVALID_ARG : Null arguments
* - ESP_ERR_NOT_SUPPORTED : Transport layer bound to another protocomm instance
* - ESP_ERR_INVALID_STATE : Transport layer already bound to this protocomm instance
@ -67,7 +97,11 @@ esp_err_t protocomm_httpd_start(protocomm_t *pc, const protocomm_httpd_config_t
* @param[in] pc Same protocomm instance that was passed to protocomm_httpd_start()
*
* @return
* - ESP_OK : Server stopped succefully
* - ESP_OK : Success
* - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance pointer
*/
esp_err_t protocomm_httpd_stop(protocomm_t *pc);
#ifdef __cplusplus
}
#endif

View file

@ -52,6 +52,19 @@ void protocomm_delete(protocomm_t *pc)
free(it);
}
/* Free memory allocated to version string */
if (pc->ver) {
free((void *)pc->ver);
}
/* Free memory allocated to security */
if (pc->sec && pc->sec->cleanup) {
pc->sec->cleanup();
}
if (pc->pop) {
free(pc->pop);
}
free(pc);
}
@ -140,11 +153,14 @@ esp_err_t protocomm_req_handle(protocomm_t *pc, const char *ep_name, uint32_t se
const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen)
{
if ((pc == NULL) || (ep_name == NULL)) {
if (!pc || !ep_name || !outbuf || !outlen) {
ESP_LOGE(TAG, "Invalid params %p %p", pc, ep_name);
return ESP_ERR_INVALID_ARG;
}
*outbuf = NULL;
*outlen = 0;
protocomm_ep_t *ep = search_endpoint(pc, ep_name);
if (!ep) {
ESP_LOGE(TAG, "No registered endpoint for %s", ep_name);
@ -166,19 +182,23 @@ esp_err_t protocomm_req_handle(protocomm_t *pc, const char *ep_name, uint32_t se
}
ssize_t dec_inbuf_len = inlen;
pc->sec->decrypt(session_id, inbuf, inlen, dec_inbuf, &dec_inbuf_len);
ret = pc->sec->decrypt(session_id, inbuf, inlen, dec_inbuf, &dec_inbuf_len);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Decryption of response failed for endpoint %s", ep_name);
free(dec_inbuf);
return ret;
}
/* Invoke the request handler */
uint8_t *plaintext_resp;
ssize_t plaintext_resp_len;
uint8_t *plaintext_resp = NULL;
ssize_t plaintext_resp_len = 0;
ret = ep->req_handler(session_id,
dec_inbuf, dec_inbuf_len,
&plaintext_resp, &plaintext_resp_len,
ep->priv_data);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Request handler for %s failed", ep_name);
*outbuf = NULL;
*outlen = 0;
free(plaintext_resp);
free(dec_inbuf);
return ret;
}
@ -189,12 +209,20 @@ esp_err_t protocomm_req_handle(protocomm_t *pc, const char *ep_name, uint32_t se
uint8_t *enc_resp = (uint8_t *) malloc(plaintext_resp_len);
if (!enc_resp) {
ESP_LOGE(TAG, "Failed to allocate decrypt buf len %d", inlen);
free(plaintext_resp);
return ESP_ERR_NO_MEM;
}
ssize_t enc_resp_len = plaintext_resp_len;
pc->sec->encrypt(session_id, plaintext_resp, plaintext_resp_len,
enc_resp, &enc_resp_len);
ret = pc->sec->encrypt(session_id, plaintext_resp, plaintext_resp_len,
enc_resp, &enc_resp_len);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Encryption of response failed for endpoint %s", ep_name);
free(enc_resp);
free(plaintext_resp);
return ret;
}
/* We no more need plaintext response */
free(plaintext_resp);
@ -257,7 +285,7 @@ esp_err_t protocomm_set_security(protocomm_t *pc, const char *ep_name,
if (sec->init) {
ret = sec->init();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Error initialising security");
ESP_LOGE(TAG, "Error initializing security");
protocomm_remove_endpoint(pc, ep_name);
return ret;
}
@ -305,40 +333,22 @@ static int protocomm_version_handler(uint32_t session_id,
uint8_t **outbuf, ssize_t *outlen,
void *priv_data)
{
const char *resp_match = "SUCCESS";
const char *resp_fail = "FAIL";
bool match = false;
char *version = strndup((const char *)inbuf, inlen);
protocomm_t *pc = (protocomm_t *) priv_data;
*outbuf = NULL;
*outlen = 0;
if ((pc->ver != NULL) && (version != NULL)) {
ESP_LOGV(TAG, "Protocol version of device : %s", pc->ver);
ESP_LOGV(TAG, "Protocol version of client : %s", version);
if (strcmp(pc->ver, version) == 0) {
match = true;
}
} else if ((pc->ver == NULL) && (version == NULL)) {
match = true;
if (!pc->ver) {
*outlen = 0;
*outbuf = NULL;
return ESP_OK;
}
free(version);
if (!match) {
ESP_LOGE(TAG, "Protocol version mismatch");
}
const char *result_msg = match ? resp_match : resp_fail;
/* Output is a non null terminated string with length specified */
*outlen = strlen(result_msg);
*outbuf = malloc(strlen(result_msg));
*outlen = strlen(pc->ver);
*outbuf = malloc(*outlen);
if (outbuf == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for version check response");
ESP_LOGE(TAG, "Failed to allocate memory for version response");
return ESP_ERR_NO_MEM;
}
memcpy(*outbuf, result_msg, *outlen);
memcpy(*outbuf, pc->ver, *outlen);
return ESP_OK;
}

View file

@ -62,7 +62,7 @@ struct protocomm {
int (*remove_endpoint)(const char *ep_name);
/* Pointer to security layer instance to be used internally for
* establising secure sessions */
* establishing secure sessions */
const protocomm_security_t *sec;
/* Pointer to proof of possession object */

View file

@ -36,6 +36,8 @@ static esp_err_t sec0_session_setup(uint32_t session_id,
S0SessionResp *s0resp = (S0SessionResp *) malloc(sizeof(S0SessionResp));
if (!out || !s0resp) {
ESP_LOGE(TAG, "Error allocating response");
free(out);
free(s0resp);
return ESP_ERR_NO_MEM;
}
sec0_payload__init(out);
@ -79,6 +81,7 @@ static esp_err_t sec0_req_handler(const protocomm_security_pop_t *pop, uint32_t
}
if (req->sec_ver != protocomm_security0.ver) {
ESP_LOGE(TAG, "Security version mismatch. Closing connection");
session_data__free_unpacked(req, NULL);
return ESP_ERR_INVALID_ARG;
}
@ -86,12 +89,12 @@ static esp_err_t sec0_req_handler(const protocomm_security_pop_t *pop, uint32_t
ret = sec0_session_setup(session_id, req, &resp, pop);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Session setup error %d", ret);
session_data__free_unpacked(req, NULL);
return ESP_FAIL;
}
session_data__free_unpacked(req, NULL);
resp.sec_ver = req->sec_ver;
session_data__free_unpacked(req, NULL);
*outlen = session_data__get_packed_size(&resp);
*outbuf = (uint8_t *) malloc(*outlen);

View file

@ -38,8 +38,9 @@ static const char* TAG = "security1";
#define PUBLIC_KEY_LEN 32
#define SZ_RANDOM 16
#define SESSION_STATE_1 1 /* Session in state 1 */
#define SESSION_STATE_SETUP 2 /* Session setup successful */
#define SESSION_STATE_CMD0 0 /* Session is not setup */
#define SESSION_STATE_CMD1 1 /* Session is not setup */
#define SESSION_STATE_DONE 2 /* Session setup successful */
typedef struct session {
/* Session data */
@ -82,22 +83,12 @@ static esp_err_t handle_session_command1(uint32_t session_id,
uint8_t check_buf[PUBLIC_KEY_LEN];
int mbed_err;
if (!cur_session) {
ESP_LOGE(TAG, "Data on session endpoint without session establishment");
if (cur_session->state != SESSION_STATE_CMD1) {
ESP_LOGE(TAG, "Invalid state of session %d (expected %d)", SESSION_STATE_CMD1, cur_session->state);
return ESP_ERR_INVALID_STATE;
}
if (session_id != cur_session->id) {
ESP_LOGE(TAG, "Invalid session");
return ESP_ERR_INVALID_STATE;
}
if (!in) {
ESP_LOGE(TAG, "Empty session data");
return ESP_ERR_INVALID_ARG;
}
/* Initialise crypto context */
/* Initialize crypto context */
mbedtls_aes_init(&cur_session->ctx_aes);
memset(cur_session->stb, 0, sizeof(cur_session->stb));
cur_session->nc_off = 0;
@ -109,6 +100,7 @@ static esp_err_t handle_session_command1(uint32_t session_id,
sizeof(cur_session->sym_key)*8);
if (mbed_err != 0) {
ESP_LOGE(TAG, "Failure at mbedtls_aes_setkey_enc with error code : -0x%x", -mbed_err);
mbedtls_aes_free(&cur_session->ctx_aes);
return ESP_FAIL;
}
@ -118,6 +110,7 @@ static esp_err_t handle_session_command1(uint32_t session_id,
in->sc1->client_verify_data.data, check_buf);
if (mbed_err != 0) {
ESP_LOGE(TAG, "Failure at mbedtls_aes_crypt_ctr with error code : -0x%x", -mbed_err);
mbedtls_aes_free(&cur_session->ctx_aes);
return ESP_FAIL;
}
@ -127,19 +120,30 @@ static esp_err_t handle_session_command1(uint32_t session_id,
if (mbedtls_ssl_safer_memcmp(check_buf, cur_session->device_pubkey,
sizeof(cur_session->device_pubkey)) != 0) {
ESP_LOGE(TAG, "Key mismatch. Close connection");
mbedtls_aes_free(&cur_session->ctx_aes);
return ESP_FAIL;
}
Sec1Payload *out = (Sec1Payload *) malloc(sizeof(Sec1Payload));
sec1_payload__init(out);
SessionResp1 *out_resp = (SessionResp1 *) malloc(sizeof(SessionResp1));
session_resp1__init(out_resp);
if (!out || !out_resp) {
ESP_LOGE(TAG, "Error allocating memory for response1");
free(out);
free(out_resp);
mbedtls_aes_free(&cur_session->ctx_aes);
return ESP_ERR_NO_MEM;
}
sec1_payload__init(out);
session_resp1__init(out_resp);
out_resp->status = STATUS__Success;
uint8_t *outbuf = (uint8_t *) malloc(PUBLIC_KEY_LEN);
if (!outbuf) {
ESP_LOGE(TAG, "Error allocating ciphertext buffer");
free(out);
free(out_resp);
mbedtls_aes_free(&cur_session->ctx_aes);
return ESP_ERR_NO_MEM;
}
@ -149,6 +153,10 @@ static esp_err_t handle_session_command1(uint32_t session_id,
cur_session->client_pubkey, outbuf);
if (mbed_err != 0) {
ESP_LOGE(TAG, "Failure at mbedtls_aes_crypt_ctr with error code : -0x%x", -mbed_err);
free(outbuf);
free(out);
free(out_resp);
mbedtls_aes_free(&cur_session->ctx_aes);
return ESP_FAIL;
}
@ -163,8 +171,8 @@ static esp_err_t handle_session_command1(uint32_t session_id,
resp->proto_case = SESSION_DATA__PROTO_SEC1;
resp->sec1 = out;
ESP_LOGD(TAG, "Session successful");
cur_session->state = SESSION_STATE_DONE;
ESP_LOGD(TAG, "Secure session established successfully");
return ESP_OK;
}
@ -172,32 +180,21 @@ static esp_err_t handle_session_command0(uint32_t session_id,
SessionData *req, SessionData *resp,
const protocomm_security_pop_t *pop)
{
ESP_LOGD(TAG, "Request to handle setup0_command");
Sec1Payload *in = (Sec1Payload *) req->sec1;
esp_err_t ret;
int mbed_err;
if (!cur_session) {
ESP_LOGE(TAG, "Data on session endpoint without session establishment");
if (cur_session->state != SESSION_STATE_CMD0) {
ESP_LOGE(TAG, "Invalid state of session %d (expected %d)", SESSION_STATE_CMD0, cur_session->state);
return ESP_ERR_INVALID_STATE;
}
if (session_id != cur_session->id) {
ESP_LOGE(TAG, "Invalid session");
return ESP_ERR_INVALID_STATE;
}
if (!in) {
ESP_LOGE(TAG, "Empty session data");
return ESP_ERR_INVALID_ARG;
}
if (in->sc0->client_pubkey.len != PUBLIC_KEY_LEN) {
ESP_LOGE(TAG, "Invalid public key length");
return ESP_ERR_INVALID_ARG;
}
cur_session->state = SESSION_STATE_1;
mbedtls_ecdh_context *ctx_server = malloc(sizeof(mbedtls_ecdh_context));
mbedtls_entropy_context *entropy = malloc(sizeof(mbedtls_entropy_context));
mbedtls_ctr_drbg_context *ctr_drbg = malloc(sizeof(mbedtls_ctr_drbg_context));
@ -315,8 +312,10 @@ static esp_err_t handle_session_command0(uint32_t session_id,
Sec1Payload *out = (Sec1Payload *) malloc(sizeof(Sec1Payload));
SessionResp0 *out_resp = (SessionResp0 *) malloc(sizeof(SessionResp0));
if (!out || !out_resp) {
ESP_LOGE(TAG, "Error allocating memory for response");
ret = ESP_FAIL;
ESP_LOGE(TAG, "Error allocating memory for response0");
ret = ESP_ERR_NO_MEM;
free(out);
free(out_resp);
goto exit_cmd0;
}
@ -338,6 +337,8 @@ static esp_err_t handle_session_command0(uint32_t session_id,
resp->proto_case = SESSION_DATA__PROTO_SEC1;
resp->sec1 = out;
cur_session->state = SESSION_STATE_CMD1;
ESP_LOGD(TAG, "Session setup phase1 done");
ret = ESP_OK;
@ -361,6 +362,21 @@ static esp_err_t sec1_session_setup(uint32_t session_id,
Sec1Payload *in = (Sec1Payload *) req->sec1;
esp_err_t ret;
if (!cur_session) {
ESP_LOGE(TAG, "Invalid session context data");
return ESP_ERR_INVALID_ARG;
}
if (session_id != cur_session->id) {
ESP_LOGE(TAG, "Invalid session ID : %d (expected %d)", session_id, cur_session->id);
return ESP_ERR_INVALID_STATE;
}
if (!in) {
ESP_LOGE(TAG, "Empty session data");
return ESP_ERR_INVALID_ARG;
}
switch (in->msg) {
case SEC1_MSG_TYPE__Session_Command0:
ret = handle_session_command0(session_id, req, resp, pop);
@ -411,30 +427,30 @@ static void sec1_session_setup_cleanup(uint32_t session_id, SessionData *resp)
return;
}
static esp_err_t sec1_init()
static esp_err_t sec1_close_session(uint32_t session_id)
{
return ESP_OK;
}
static esp_err_t sec1_cleanup()
{
if (cur_session) {
ESP_LOGD(TAG, "Closing current session with id %u", cur_session->id);
mbedtls_aes_free(&cur_session->ctx_aes);
bzero(cur_session, sizeof(session_t));
free(cur_session);
cur_session = NULL;
if (!cur_session || cur_session->id != session_id) {
ESP_LOGE(TAG, "Attempt to close invalid session");
return ESP_ERR_INVALID_ARG;
}
if (cur_session->state == SESSION_STATE_DONE) {
/* Free AES context data */
mbedtls_aes_free(&cur_session->ctx_aes);
}
bzero(cur_session, sizeof(session_t));
free(cur_session);
cur_session = NULL;
return ESP_OK;
}
static esp_err_t sec1_new_session(uint32_t session_id)
{
if (cur_session && cur_session->id != session_id) {
if (cur_session) {
/* Only one session is allowed at a time */
ESP_LOGE(TAG, "Closing old session with id %u", cur_session->id);
sec1_cleanup();
} else if (cur_session && cur_session->id == session_id) {
return ESP_OK;
sec1_close_session(cur_session->id);
}
cur_session = (session_t *) calloc(1, sizeof(session_t));
@ -447,16 +463,17 @@ static esp_err_t sec1_new_session(uint32_t session_id)
return ESP_OK;
}
static esp_err_t sec1_close_session(uint32_t session_id)
static esp_err_t sec1_init()
{
if (!cur_session || cur_session->id != session_id) {
ESP_LOGE(TAG, "Attempt to close invalid session");
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
bzero(cur_session, sizeof(session_t));
free(cur_session);
cur_session = NULL;
static esp_err_t sec1_cleanup()
{
if (cur_session) {
ESP_LOGD(TAG, "Closing current session with id %u", cur_session->id);
sec1_close_session(cur_session->id);
}
return ESP_OK;
}
@ -469,8 +486,15 @@ static esp_err_t sec1_decrypt(uint32_t session_id,
}
if (!cur_session || cur_session->id != session_id) {
ESP_LOGE(TAG, "Session with ID %d not found", session_id);
return ESP_ERR_INVALID_STATE;
}
if (cur_session->state != SESSION_STATE_DONE) {
ESP_LOGE(TAG, "Secure session not established");
return ESP_ERR_INVALID_STATE;
}
*outlen = inlen;
int ret = mbedtls_aes_crypt_ctr(&cur_session->ctx_aes, inlen, &cur_session->nc_off,
cur_session->rand, cur_session->stb, inbuf, outbuf);
@ -497,6 +521,7 @@ static esp_err_t sec1_req_handler(const protocomm_security_pop_t *pop, uint32_t
}
if (req->sec_ver != protocomm_security1.ver) {
ESP_LOGE(TAG, "Security version mismatch. Closing connection");
session_data__free_unpacked(req, NULL);
return ESP_ERR_INVALID_ARG;
}
@ -504,12 +529,12 @@ static esp_err_t sec1_req_handler(const protocomm_security_pop_t *pop, uint32_t
ret = sec1_session_setup(session_id, req, &resp, pop);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Session setup error %d", ret);
session_data__free_unpacked(req, NULL);
return ESP_FAIL;
}
session_data__free_unpacked(req, NULL);
resp.sec_ver = req->sec_ver;
session_data__free_unpacked(req, NULL);
*outlen = session_data__get_packed_size(&resp);
*outbuf = (uint8_t *) malloc(*outlen);

View file

@ -103,7 +103,7 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_
g_ble_cfg_p->exec_write_fn(event, gatts_if, param);
break;
case ESP_GATTS_MTU_EVT:
ESP_LOGV(TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu);
ESP_LOGD(TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu);
if (g_ble_cfg_p->set_mtu_fn) {
g_ble_cfg_p->set_mtu_fn(event, gatts_if, param);
}

View file

@ -55,7 +55,7 @@ typedef struct {
} simple_ble_cfg_t;
/** Initialise a simple ble connection
/** Initialize a simple ble connection
*
* This function allocates memory and returns a pointer to the
* configuration structure.

View file

@ -276,7 +276,7 @@ static void transport_simple_ble_exec_write(esp_gatts_cb_event_t event, esp_gatt
static void transport_simple_ble_disconnect(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
esp_err_t ret;
ESP_LOGV(TAG, "Inside disconnect w/ session - %d", param->disconnect.conn_id);
ESP_LOGD(TAG, "Inside disconnect w/ session - %d", param->disconnect.conn_id);
if (protoble_internal->pc_ble->sec &&
protoble_internal->pc_ble->sec->close_transport_session) {
ret = protoble_internal->pc_ble->sec->close_transport_session(param->disconnect.conn_id);
@ -290,7 +290,7 @@ static void transport_simple_ble_disconnect(esp_gatts_cb_event_t event, esp_gatt
static void transport_simple_ble_connect(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
esp_err_t ret;
ESP_LOGV(TAG, "Inside BLE connect w/ conn_id - %d", param->connect.conn_id);
ESP_LOGD(TAG, "Inside BLE connect w/ conn_id - %d", param->connect.conn_id);
if (protoble_internal->pc_ble->sec &&
protoble_internal->pc_ble->sec->new_transport_session) {
ret = protoble_internal->pc_ble->sec->new_transport_session(param->connect.conn_id);
@ -372,7 +372,7 @@ static void protocomm_ble_cleanup(void)
if (protoble_internal->g_nu_lookup) {
for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) {
if (protoble_internal->g_nu_lookup[i].name) {
free(protoble_internal->g_nu_lookup[i].name);
free((void *)protoble_internal->g_nu_lookup[i].name);
}
}
free(protoble_internal->g_nu_lookup);
@ -488,7 +488,7 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con
}
prepare_write_env.prepare_buf = NULL;
ESP_LOGV(TAG, "Waiting for client to connect ......");
ESP_LOGD(TAG, "Waiting for client to connect ......");
return ESP_OK;
}

View file

@ -76,7 +76,7 @@ static void protocomm_console_task(void *arg)
QueueHandle_t uart_queue;
uart_event_t event;
ESP_LOGV(TAG, "Initialising UART on port %d", uart_num);
ESP_LOGD(TAG, "Initializing UART on port %d", uart_num);
uart_driver_install(uart_num, 256, 0, 8, &uart_queue, 0);
/* Initialize the console */
esp_console_config_t console_config = {
@ -121,10 +121,6 @@ static void protocomm_console_task(void *arg)
}
}
if (pc_console->sec && pc_console->sec->cleanup) {
pc_console->sec->cleanup();
}
pc_console = NULL;
esp_console_deinit();

View file

@ -26,6 +26,7 @@
static const char *TAG = "protocomm_httpd";
static protocomm_t *pc_httpd; /* The global protocomm instance for HTTPD */
static bool pc_ext_httpd_handle_provided = false;
static uint32_t session_id = PROTOCOMM_NO_SESSION_ID;
#define MAX_REQ_BODY_LEN 4096
@ -41,9 +42,9 @@ static esp_err_t common_post_handler(httpd_req_t *req)
int cur_session_id = httpd_req_to_sockfd(req);
if (cur_session_id != session_id) {
/* Initialise new security session */
/* Initialize new security session */
if (session_id != PROTOCOMM_NO_SESSION_ID) {
ESP_LOGV(TAG, "Closing session with ID: %d", session_id);
ESP_LOGD(TAG, "Closing session with ID: %d", session_id);
/* Presently HTTP server doesn't support callback on socket closure so
* previous session can only be closed when new session is requested */
if (pc_httpd->sec && pc_httpd->sec->close_transport_session) {
@ -65,7 +66,7 @@ static esp_err_t common_post_handler(httpd_req_t *req)
}
}
session_id = cur_session_id;
ESP_LOGV(TAG, "New session with ID: %d", cur_session_id);
ESP_LOGD(TAG, "New session with ID: %d", cur_session_id);
}
if (req->content_len <= 0) {
@ -124,7 +125,7 @@ out:
return ret;
}
esp_err_t protocomm_httpd_add_endpoint(const char *ep_name,
static esp_err_t protocomm_httpd_add_endpoint(const char *ep_name,
protocomm_req_handler_t req_handler,
void *priv_data)
{
@ -132,7 +133,7 @@ esp_err_t protocomm_httpd_add_endpoint(const char *ep_name,
return ESP_ERR_INVALID_STATE;
}
ESP_LOGV(TAG, "Adding endpoint : %s", ep_name);
ESP_LOGD(TAG, "Adding endpoint : %s", ep_name);
/* Construct URI name by prepending '/' to ep_name */
char* ep_uri = calloc(1, strlen(ep_name) + 2);
@ -169,7 +170,7 @@ static esp_err_t protocomm_httpd_remove_endpoint(const char *ep_name)
return ESP_ERR_INVALID_STATE;
}
ESP_LOGV(TAG, "Removing endpoint : %s", ep_name);
ESP_LOGD(TAG, "Removing endpoint : %s", ep_name);
/* Construct URI name by prepending '/' to ep_name */
char* ep_uri = calloc(1, strlen(ep_name) + 2);
@ -207,28 +208,36 @@ esp_err_t protocomm_httpd_start(protocomm_t *pc, const protocomm_httpd_config_t
return ESP_ERR_NOT_SUPPORTED;
}
/* Private data will point to the HTTP server handle */
pc->priv = calloc(1, sizeof(httpd_handle_t));
if (!pc->priv) {
ESP_LOGE(TAG, "Malloc failed for HTTP server handle");
return ESP_ERR_NO_MEM;
if (config->ext_handle_provided) {
if (config->data.handle) {
pc->priv = config->data.handle;
pc_ext_httpd_handle_provided = true;
} else {
return ESP_ERR_INVALID_ARG;
}
} else {
/* Private data will point to the HTTP server handle */
pc->priv = calloc(1, sizeof(httpd_handle_t));
if (!pc->priv) {
ESP_LOGE(TAG, "Malloc failed for HTTP server handle");
return ESP_ERR_NO_MEM;
}
/* Configure the HTTP server */
httpd_config_t server_config = HTTPD_DEFAULT_CONFIG();
server_config.server_port = config->data.config.port;
server_config.stack_size = config->data.config.stack_size;
server_config.task_priority = config->data.config.task_priority;
server_config.lru_purge_enable = true;
server_config.max_open_sockets = 1;
esp_err_t err;
if ((err = httpd_start((httpd_handle_t *)pc->priv, &server_config)) != ESP_OK) {
ESP_LOGE(TAG, "Failed to start http server: %s", esp_err_to_name(err));
free(pc->priv);
return err;
}
}
/* Configure the HTTP server */
httpd_config_t server_config = HTTPD_DEFAULT_CONFIG();
server_config.server_port = config->port;
server_config.stack_size = config->stack_size;
server_config.task_priority = config->task_priority;
server_config.lru_purge_enable = true;
server_config.max_open_sockets = 1;
esp_err_t err;
if ((err = httpd_start((httpd_handle_t *)pc->priv, &server_config)) != ESP_OK) {
ESP_LOGE(TAG, "Failed to start http server: %s", esp_err_to_name(err));
free(pc->priv);
return err;
}
pc->add_endpoint = protocomm_httpd_add_endpoint;
pc->remove_endpoint = protocomm_httpd_remove_endpoint;
pc_httpd = pc;
@ -238,9 +247,13 @@ esp_err_t protocomm_httpd_start(protocomm_t *pc, const protocomm_httpd_config_t
esp_err_t protocomm_httpd_stop(protocomm_t *pc)
{
if ((pc != NULL) && (pc == pc_httpd)) {
httpd_handle_t *server_handle = (httpd_handle_t *) pc_httpd->priv;
httpd_stop(*server_handle);
free(server_handle);
if (!pc_ext_httpd_handle_provided) {
httpd_handle_t *server_handle = (httpd_handle_t *) pc_httpd->priv;
httpd_stop(*server_handle);
free(server_handle);
} else {
pc_ext_httpd_handle_provided = false;
}
pc_httpd->priv = NULL;
pc_httpd = NULL;
return ESP_OK;

View file

@ -19,6 +19,7 @@
#include <esp_log.h>
#include <esp_system.h>
#include <sys/random.h>
#include <unistd.h>
#include <unity.h>
#include <mbedtls/aes.h>
@ -36,7 +37,7 @@
#include "session.pb-c.h"
#ifdef DO_HEAP_TRACING
#ifdef CONFIG_HEAP_TRACING
#include <esp_heap_trace.h>
#define NUM_RECORDS 100
static heap_trace_record_t trace_record[NUM_RECORDS]; // This buffer must be in internal RAM
@ -492,6 +493,30 @@ abort_test_sec_endpoint:
return ESP_FAIL;
}
#define TEST_VER_STR "<some version string>"
static esp_err_t test_ver_endpoint(session_t *session)
{
ssize_t ver_data_len = 0;
uint8_t *ver_data = NULL;
esp_err_t ret = protocomm_req_handle(test_pc, "test-ver", session->id,
NULL, 0, &ver_data, &ver_data_len);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "test-ver handler failed");
return ESP_FAIL;
}
if (ver_data_len != strlen(TEST_VER_STR) || memcmp(TEST_VER_STR, ver_data, ver_data_len)) {
ESP_LOGE(TAG, "incorrect response data from test-ver");
free(ver_data);
return ESP_FAIL;
}
free(ver_data);
return ESP_OK;
}
static esp_err_t test_req_endpoint(session_t *session)
{
uint32_t session_id = session->id;
@ -514,7 +539,7 @@ static esp_err_t test_req_endpoint(session_t *session)
enc_test_data, sizeof(enc_test_data),
&enc_verify_data, &verify_data_len);
if (ret != ESP_OK) {
if (ret != ESP_OK || !verify_data_len) {
ESP_LOGE(TAG, "test-ep handler failed");
return ESP_FAIL;
}
@ -600,6 +625,11 @@ static esp_err_t start_test_service(uint8_t sec_ver, const protocomm_security_po
test_sec = &protocomm_security1;
}
if (protocomm_set_version(test_pc, "test-ver", TEST_VER_STR) != ESP_OK) {
ESP_LOGE(TAG, "Failed to set version");
return ESP_FAIL;
}
if (protocomm_add_endpoint(test_pc, "test-ep",
test_req_handler,
(void *) &test_priv_data) != ESP_OK) {
@ -611,8 +641,6 @@ static esp_err_t start_test_service(uint8_t sec_ver, const protocomm_security_po
static void stop_test_service(void)
{
protocomm_remove_endpoint(test_pc, "test-ep");
protocomm_unset_security(test_pc, "test-sec");
test_sec = NULL;
protocomm_delete(test_pc);
test_pc = NULL;
@ -913,8 +941,8 @@ static esp_err_t test_security1_weak_session (void)
}
// Sending request data to echo endpoint encrypted with zero
// public keys on both client and server side should pass
if (test_req_endpoint(session) != ESP_OK) {
// public keys on both client and server side should fail
if (test_req_endpoint(session) == ESP_OK) {
ESP_LOGE(TAG, "Error testing request endpoint");
stop_test_service();
free(session);
@ -938,6 +966,13 @@ static esp_err_t test_protocomm (session_t *session)
return ESP_FAIL;
}
// Check version endpoint
if (test_ver_endpoint(session) != ESP_OK) {
ESP_LOGE(TAG, "Error testing version endpoint");
stop_test_service();
return ESP_FAIL;
}
// Intialise protocomm session with zero public keys
if (test_new_session(session) != ESP_OK) {
ESP_LOGE(TAG, "Error creating new session");
@ -1024,33 +1059,43 @@ static esp_err_t test_security0 (void)
TEST_CASE("leak test", "[PROTOCOMM]")
{
#ifdef DO_HEAP_TRACING
#ifdef CONFIG_HEAP_TRACING
heap_trace_init_standalone(trace_record, NUM_RECORDS);
#endif
unsigned pre_start_mem = esp_get_free_heap_size();
#ifdef DO_HEAP_TRACING
heap_trace_start(HEAP_TRACE_LEAKS);
#endif
/* Run basic tests for the first time to allow for internal long
* time allocations to happen (not related to protocomm) */
test_security0();
test_security1();
usleep(1000);
#ifdef DO_HEAP_TRACING
#ifdef CONFIG_HEAP_TRACING
heap_trace_stop();
heap_trace_dump();
#endif
/* Run all tests passively. Any leaks due
* to protocomm should show up now */
unsigned pre_start_mem = esp_get_free_heap_size();
test_security0();
test_security1();
test_security1_no_encryption();
test_security1_session_overflow();
test_security1_wrong_pop();
test_security1_insecure_client();
test_security1_weak_session();
usleep(1000);
unsigned post_stop_mem = esp_get_free_heap_size();
if (pre_start_mem != post_stop_mem) {
ESP_LOGE(TAG, "Mismatch in free heap size");
ESP_LOGE(TAG, "Mismatch in free heap size : %d bytes", post_stop_mem - pre_start_mem);
}
#ifdef DO_HEAP_TRACING
TEST_ASSERT(pre_start_mem != post_stop_mem);
#endif
TEST_ASSERT(pre_start_mem == post_stop_mem);
}
TEST_CASE("security 0 basic test", "[PROTOCOMM]")

View file

@ -17,6 +17,10 @@
#include <lwip/inet.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief WiFi STA status for conveying back to the provisioning master
*/
@ -77,6 +81,15 @@ typedef struct {
uint8_t channel; /*!< Channel of the AP */
} wifi_prov_config_set_data_t;
/**
* @brief Type of context data passed to each get/set/apply handler
* function set in `wifi_prov_config_handlers` structure.
*
* This is passed as an opaque pointer, thereby allowing it be defined
* later in application code as per requirements.
*/
typedef struct wifi_prov_ctx wifi_prov_ctx_t;
/**
* @brief Internal handlers for receiving and responding to protocomm
* requests from master
@ -89,14 +102,16 @@ typedef struct wifi_prov_config_handlers {
* Handler function called when connection status
* of the slave (in WiFi station mode) is requested
*/
esp_err_t (*get_status_handler)(wifi_prov_config_get_data_t *resp_data);
esp_err_t (*get_status_handler)(wifi_prov_config_get_data_t *resp_data,
wifi_prov_ctx_t **ctx);
/**
* Handler function called when WiFi connection configuration
* (eg. AP SSID, password, etc.) of the slave (in WiFi station mode)
* is to be set to user provided values
*/
esp_err_t (*set_config_handler)(const wifi_prov_config_set_data_t *req_data);
esp_err_t (*set_config_handler)(const wifi_prov_config_set_data_t *req_data,
wifi_prov_ctx_t **ctx);
/**
* Handler function for applying the configuration that was set in
@ -105,7 +120,12 @@ typedef struct wifi_prov_config_handlers {
* updated connection status information when `get_status_handler` is
* invoked again by the master.
*/
esp_err_t (*apply_config_handler)(void);
esp_err_t (*apply_config_handler)(wifi_prov_ctx_t **ctx);
/**
* Context pointer to be passed to above handler functions upon invocation
*/
wifi_prov_ctx_t *ctx;
} wifi_prov_config_handlers_t;
/**
@ -117,4 +137,8 @@ typedef struct wifi_prov_config_handlers {
esp_err_t wifi_prov_config_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen, void *priv_data);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -72,7 +72,7 @@ static esp_err_t cmd_get_status_handler(WiFiConfigPayload *req,
resp_get_status__init(resp_payload);
wifi_prov_config_get_data_t resp_data;
if (h->get_status_handler(&resp_data) == ESP_OK) {
if (h->get_status_handler(&resp_data, &h->ctx) == ESP_OK) {
if (resp_data.wifi_state == WIFI_PROV_STA_CONNECTING) {
resp_payload->sta_state = WIFI_STATION_STATE__Connecting;
resp_payload->state_case = RESP_GET_STATUS__STATE_CONNECTED;
@ -158,7 +158,7 @@ static esp_err_t cmd_set_config_handler(WiFiConfigPayload *req,
memcpy(req_data.bssid, req->cmd_set_config->bssid.data,
req->cmd_set_config->bssid.len);
req_data.channel = req->cmd_set_config->channel;
if (h->set_config_handler(&req_data) == ESP_OK) {
if (h->set_config_handler(&req_data, &h->ctx) == ESP_OK) {
resp_payload->status = STATUS__Success;
}
@ -185,7 +185,7 @@ static esp_err_t cmd_apply_config_handler(WiFiConfigPayload *req,
resp_apply_config__init(resp_payload);
if (h->apply_config_handler() == ESP_OK) {
if (h->apply_config_handler(&h->ctx) == ESP_OK) {
resp_payload->status = STATUS__Success;
} else {
resp_payload->status = STATUS__InvalidArgument;

View file

@ -54,8 +54,13 @@ For complete example see :example:`provisioning/softap_prov`
{
protocomm_t *pc = protocomm_new();
/* Config for protocomm_httpd_start() */
protocomm_httpd_config_t pc_config = PROTOCOMM_HTTPD_DEFAULT_CONFIG();
protocomm_httpd_config_t pc_config = {
.data = {
.config = PROTOCOMM_HTTPD_DEFAULT_CONFIG()
}
};
/* Start protocomm server on top of HTTP */
protocomm_httpd_start(pc, &pc_config);

View file

@ -4,7 +4,9 @@ Wi-Fi Provisioning
Overview
--------
This component provides protocomm endpoint handler - `wifi_prov_config_data_handler` - and related protobuf framework which can be used for Wi-Fi configuration in the context of device provisioning, though it may be used in non-provisioning cases as well. The configuration consists of three commands :
This component provides protocomm endpoint handler - `wifi_prov_config_data_handler` - and related protobuf framework which can be used for Wi-Fi configuration in the context of device provisioning, though it may be used in non-provisioning cases as well.
The configuration consists of three commands :
* `get_status` - For querying the Wi-Fi connection status
* `set_config` - For setting the Wi-Fi connection credentials
* `apply_config` - For applying the credentials saved during `set_config` and (re)start the Wi-Fi station
@ -18,7 +20,7 @@ Application Example
::
esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data)
esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx)
{
/* Fill the wifi_prov_config_get_data_t structure
* with Wi-Fi station connection status information. */
@ -26,7 +28,7 @@ Application Example
return ESP_OK;
}
esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx)
{
/* Copy contents of req_data->ssid and req_data->password
* which are Wi-Fi AP credentials to which the device will connect */
@ -34,7 +36,7 @@ Application Example
return ESP_OK;
}
esp_err_t apply_config_handler(void)
esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx)
{
/* Apply the Wi-Fi STA credentials saved during set_config */
@ -47,6 +49,7 @@ Application Example
.get_status_handler = get_status_handler,
.set_config_handler = set_config_handler,
.apply_config_handler = apply_config_handler,
.ctx = NULL
};
/* Set the endpoint handler */

View file

@ -188,7 +188,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "STA Got IP");
/* Station got IP. That means configuraion is successful.
/* Station got IP. That means configuration is successful.
* Schedule timer to stop provisioning app after 30 seconds. */
g_prov->wifi_state = WIFI_PROV_STA_CONNECTED;
if (g_prov && g_prov->timer) {
@ -341,7 +341,7 @@ esp_err_t app_prov_start_ble_provisioning(int security, const protocomm_security
return ESP_ERR_NO_MEM;
}
/* Initialise app data */
/* Initialize app data */
g_prov->pop = pop;
g_prov->security = security;

View file

@ -1,4 +1,4 @@
/* BLE based Provisioning Example
/* SoftAP based Provisioning Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
@ -23,9 +23,32 @@
static const char* TAG = "app_prov_handler";
static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data)
/* Provide definition of wifi_prov_ctx_t */
struct wifi_prov_ctx {
wifi_config_t wifi_cfg;
};
static wifi_config_t *get_config(wifi_prov_ctx_t **ctx)
{
/* Initialise to zero */
return (*ctx ? &(*ctx)->wifi_cfg : NULL);
}
static wifi_config_t *new_config(wifi_prov_ctx_t **ctx)
{
free(*ctx);
(*ctx) = (wifi_prov_ctx_t *) calloc(1, sizeof(wifi_prov_ctx_t));
return get_config(ctx);
}
static void free_config(wifi_prov_ctx_t **ctx)
{
free(*ctx);
*ctx = NULL;
}
static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx)
{
/* Initialize to zero */
memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t));
if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) {
@ -60,16 +83,14 @@ static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data)
return ESP_OK;
}
static wifi_config_t *wifi_cfg;
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx)
{
wifi_config_t *wifi_cfg = get_config(ctx);
if (wifi_cfg) {
free(wifi_cfg);
wifi_cfg = NULL;
free_config(ctx);
}
wifi_cfg = (wifi_config_t *) calloc(1, sizeof(wifi_config_t));
wifi_cfg = new_config(ctx);
if (!wifi_cfg) {
ESP_LOGE(TAG, "Unable to alloc wifi config");
return ESP_FAIL;
@ -84,8 +105,9 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
return ESP_OK;
}
static esp_err_t apply_config_handler(void)
static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx)
{
wifi_config_t *wifi_cfg = get_config(ctx);
if (!wifi_cfg) {
ESP_LOGE(TAG, "WiFi config not set");
return ESP_FAIL;
@ -94,8 +116,7 @@ static esp_err_t apply_config_handler(void)
app_prov_configure_sta(wifi_cfg);
ESP_LOGI(TAG, "WiFi Credentials Applied");
free(wifi_cfg);
wifi_cfg = NULL;
free_config(ctx);
return ESP_OK;
}
@ -103,4 +124,5 @@ wifi_prov_config_handlers_t wifi_prov_handlers = {
.get_status_handler = get_status_handler,
.set_config_handler = set_config_handler,
.apply_config_handler = apply_config_handler,
.ctx = NULL
};

View file

@ -101,8 +101,8 @@ static void app_prov_stop_service(void)
protocomm_delete(g_prov->pc);
}
/* Callback to be invoked by timer */
static void _stop_prov_cb(void * arg)
/* Task spawned by timer callback */
static void stop_prov_task(void * arg)
{
ESP_LOGI(TAG, "Stopping provisioning");
app_prov_stop_service();
@ -116,6 +116,14 @@ static void _stop_prov_cb(void * arg)
free(g_prov);
g_prov = NULL;
ESP_LOGI(TAG, "Provisioning stopped");
vTaskDelete(NULL);
}
/* Callback to be invoked by timer */
static void _stop_prov_cb(void * arg)
{
xTaskCreate(&stop_prov_task, "stop_prov", 2048, NULL, tskIDLE_PRIORITY, NULL);
}
/* Event handler for starting/stopping provisioning.
@ -146,7 +154,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "STA Got IP");
/* Station got IP. That means configuraion is successful.
/* Station got IP. That means configuration is successful.
* Schedule timer to stop provisioning app after 30 seconds. */
g_prov->wifi_state = WIFI_PROV_STA_CONNECTED;
if (g_prov && g_prov->timer) {
@ -299,7 +307,7 @@ esp_err_t app_prov_start_console_provisioning(int security, const protocomm_secu
return ESP_ERR_NO_MEM;
}
/* Initialise app data */
/* Initialize app data */
g_prov->pop = pop;
g_prov->security = security;
@ -308,7 +316,7 @@ esp_err_t app_prov_start_console_provisioning(int security, const protocomm_secu
.callback = _stop_prov_cb,
.arg = NULL,
.dispatch_method = ESP_TIMER_TASK,
.name = "stop_softap_tm"
.name = "stop_console_tm"
};
esp_err_t err = esp_timer_create(&timer_conf, &g_prov->timer);
if (err != ESP_OK) {

View file

@ -23,9 +23,32 @@
static const char* TAG = "app_prov_handler";
static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data)
/* Provide definition of wifi_prov_ctx_t */
struct wifi_prov_ctx {
wifi_config_t wifi_cfg;
};
static wifi_config_t *get_config(wifi_prov_ctx_t **ctx)
{
/* Initialise to zero */
return (*ctx ? &(*ctx)->wifi_cfg : NULL);
}
static wifi_config_t *new_config(wifi_prov_ctx_t **ctx)
{
free(*ctx);
(*ctx) = (wifi_prov_ctx_t *) calloc(1, sizeof(wifi_prov_ctx_t));
return get_config(ctx);
}
static void free_config(wifi_prov_ctx_t **ctx)
{
free(*ctx);
*ctx = NULL;
}
static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx)
{
/* Initialize to zero */
memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t));
if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) {
@ -60,16 +83,14 @@ static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data)
return ESP_OK;
}
static wifi_config_t *wifi_cfg;
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx)
{
wifi_config_t *wifi_cfg = get_config(ctx);
if (wifi_cfg) {
free(wifi_cfg);
wifi_cfg = NULL;
free_config(ctx);
}
wifi_cfg = (wifi_config_t *) calloc(1, sizeof(wifi_config_t));
wifi_cfg = new_config(ctx);
if (!wifi_cfg) {
ESP_LOGE(TAG, "Unable to alloc wifi config");
return ESP_FAIL;
@ -84,8 +105,9 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
return ESP_OK;
}
static esp_err_t apply_config_handler(void)
static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx)
{
wifi_config_t *wifi_cfg = get_config(ctx);
if (!wifi_cfg) {
ESP_LOGE(TAG, "WiFi config not set");
return ESP_FAIL;
@ -94,8 +116,7 @@ static esp_err_t apply_config_handler(void)
app_prov_configure_sta(wifi_cfg);
ESP_LOGI(TAG, "WiFi Credentials Applied");
free(wifi_cfg);
wifi_cfg = NULL;
free_config(ctx);
return ESP_OK;
}
@ -103,4 +124,5 @@ wifi_prov_config_handlers_t wifi_prov_handlers = {
.get_status_handler = get_status_handler,
.set_config_handler = set_config_handler,
.apply_config_handler = apply_config_handler,
.ctx = NULL
};

View file

@ -58,7 +58,11 @@ static esp_err_t app_prov_start_service(void)
}
/* Config for protocomm_httpd_start() */
protocomm_httpd_config_t pc_config = PROTOCOMM_HTTPD_DEFAULT_CONFIG();
protocomm_httpd_config_t pc_config = {
.data = {
.config = PROTOCOMM_HTTPD_DEFAULT_CONFIG()
}
};
/* Start protocomm server on top of HTTP */
if (protocomm_httpd_start(g_prov->pc, &pc_config) != ESP_OK) {
@ -112,8 +116,8 @@ static void app_prov_stop_service(void)
protocomm_delete(g_prov->pc);
}
/* Callback to be invoked by timer */
static void _stop_softap_cb(void * arg)
/* Task spawned by timer callback */
static void stop_prov_task(void * arg)
{
ESP_LOGI(TAG, "Stopping provisioning");
app_prov_stop_service();
@ -128,6 +132,14 @@ static void _stop_softap_cb(void * arg)
free(g_prov);
g_prov = NULL;
ESP_LOGI(TAG, "Provisioning stopped");
vTaskDelete(NULL);
}
/* Callback to be invoked by timer */
static void _stop_prov_cb(void * arg)
{
xTaskCreate(&stop_prov_task, "stop_prov", 2048, NULL, tskIDLE_PRIORITY, NULL);
}
/* Event handler for starting/stopping provisioning.
@ -158,7 +170,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "STA Got IP");
/* Station got IP. That means configuraion is successful.
/* Station got IP. That means configuration is successful.
* Schedule timer to stop provisioning app after 30 seconds. */
g_prov->wifi_state = WIFI_PROV_STA_CONNECTED;
if (g_prov && g_prov->timer) {
@ -170,7 +182,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
* to reconnect and get STA connection status from the device.
* Otherwise, the AP will be turned off before the user can
* reconnect and thus the user app will see connection timed out,
* signalling a failure in provisioning. */
* signaling a failure in provisioning. */
esp_timer_start_once(g_prov->timer, 30000*1000U);
}
break;
@ -299,7 +311,7 @@ esp_err_t app_prov_configure_sta(wifi_config_t *wifi_cfg)
static esp_err_t start_wifi_ap(const char *ssid, const char *pass)
{
/* Initialise WiFi with default configuration */
/* Initialize WiFi with default configuration */
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_err_t err = esp_wifi_init(&cfg);
if (err != ESP_OK) {
@ -368,7 +380,7 @@ esp_err_t app_prov_start_softap_provisioning(const char *ssid, const char *pass,
/* Create timer object as a member of app data */
esp_timer_create_args_t timer_conf = {
.callback = _stop_softap_cb,
.callback = _stop_prov_cb,
.arg = NULL,
.dispatch_method = ESP_TIMER_TASK,
.name = "stop_softap_tm"

View file

@ -24,6 +24,29 @@
static const char* TAG = "app_prov_handler";
/* Provide definition of wifi_prov_ctx_t */
struct wifi_prov_ctx {
wifi_config_t wifi_cfg;
};
static wifi_config_t *get_config(wifi_prov_ctx_t **ctx)
{
return (*ctx ? &(*ctx)->wifi_cfg : NULL);
}
static wifi_config_t *new_config(wifi_prov_ctx_t **ctx)
{
free(*ctx);
(*ctx) = (wifi_prov_ctx_t *) calloc(1, sizeof(wifi_prov_ctx_t));
return get_config(ctx);
}
static void free_config(wifi_prov_ctx_t **ctx)
{
free(*ctx);
*ctx = NULL;
}
/****************** Handler for Custom Configuration *******************/
static esp_err_t custom_config_handler(const custom_config_t *config)
{
@ -35,9 +58,9 @@ static esp_err_t custom_config_handler(const custom_config_t *config)
custom_prov_config_handler_t custom_prov_handler = custom_config_handler;
/****************** Handlers for Wi-Fi Configuration *******************/
static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data)
static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx)
{
/* Initialise to zero */
/* Initialize to zero */
memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t));
if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) {
@ -72,16 +95,14 @@ static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data)
return ESP_OK;
}
static wifi_config_t *wifi_cfg;
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx)
{
wifi_config_t *wifi_cfg = get_config(ctx);
if (wifi_cfg) {
free(wifi_cfg);
wifi_cfg = NULL;
free_config(ctx);
}
wifi_cfg = (wifi_config_t *) calloc(1, sizeof(wifi_config_t));
wifi_cfg = new_config(ctx);
if (!wifi_cfg) {
ESP_LOGE(TAG, "Unable to alloc wifi config");
return ESP_FAIL;
@ -96,8 +117,9 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
return ESP_OK;
}
static esp_err_t apply_config_handler(void)
static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx)
{
wifi_config_t *wifi_cfg = get_config(ctx);
if (!wifi_cfg) {
ESP_LOGE(TAG, "WiFi config not set");
return ESP_FAIL;
@ -106,8 +128,7 @@ static esp_err_t apply_config_handler(void)
app_prov_configure_sta(wifi_cfg);
ESP_LOGI(TAG, "WiFi Credentials Applied");
free(wifi_cfg);
wifi_cfg = NULL;
free_config(ctx);
return ESP_OK;
}
@ -115,4 +136,5 @@ wifi_prov_config_handlers_t wifi_prov_handlers = {
.get_status_handler = get_status_handler,
.set_config_handler = set_config_handler,
.apply_config_handler = apply_config_handler,
.ctx = NULL
};

View file

@ -56,8 +56,11 @@ static esp_err_t app_prov_start_service(void)
}
/* Config for protocomm_httpd_start() */
protocomm_httpd_config_t pc_config = PROTOCOMM_HTTPD_DEFAULT_CONFIG();
protocomm_httpd_config_t pc_config = {
.data = {
.config = PROTOCOMM_HTTPD_DEFAULT_CONFIG()
}
};
/* Start protocomm server on top of HTTP */
if (protocomm_httpd_start(g_prov->pc, &pc_config) != ESP_OK) {
ESP_LOGE(TAG, "Failed to start protocomm HTTP server");
@ -99,8 +102,8 @@ static void app_prov_stop_service(void)
protocomm_delete(g_prov->pc);
}
/* Callback to be invoked by timer */
static void _stop_softap_cb(void * arg)
/* Task spawned by timer callback */
static void stop_prov_task(void * arg)
{
ESP_LOGI(TAG, "Stopping provisioning");
app_prov_stop_service();
@ -115,6 +118,14 @@ static void _stop_softap_cb(void * arg)
free(g_prov);
g_prov = NULL;
ESP_LOGI(TAG, "Provisioning stopped");
vTaskDelete(NULL);
}
/* Callback to be invoked by timer */
static void _stop_prov_cb(void * arg)
{
xTaskCreate(&stop_prov_task, "stop_prov", 2048, NULL, tskIDLE_PRIORITY, NULL);
}
/* Event handler for starting/stopping provisioning.
@ -145,7 +156,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "STA Got IP");
/* Station got IP. That means configuraion is successful.
/* Station got IP. That means configuration is successful.
* Schedule timer to stop provisioning app after 30 seconds. */
g_prov->wifi_state = WIFI_PROV_STA_CONNECTED;
if (g_prov && g_prov->timer) {
@ -157,7 +168,7 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
* to reconnect and get STA connection status from the device.
* Otherwise, the AP will be turned off before the user can
* reconnect and thus the user app will see connection timed out,
* signalling a failure in provisioning. */
* signaling a failure in provisioning. */
esp_timer_start_once(g_prov->timer, 30000*1000U);
}
break;
@ -287,7 +298,7 @@ esp_err_t app_prov_configure_sta(wifi_config_t *wifi_cfg)
static esp_err_t start_wifi_ap(const char *ssid, const char *pass)
{
/* Initialise WiFi with default configuration */
/* Initialize WiFi with default configuration */
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_err_t err = esp_wifi_init(&cfg);
if (err != ESP_OK) {
@ -350,13 +361,13 @@ esp_err_t app_prov_start_softap_provisioning(const char *ssid, const char *pass,
return ESP_ERR_NO_MEM;
}
/* Initialise app data */
/* Initialize app data */
g_prov->pop = pop;
g_prov->security = security;
/* Create timer object as a member of app data */
esp_timer_create_args_t timer_conf = {
.callback = _stop_softap_cb,
.callback = _stop_prov_cb,
.arg = NULL,
.dispatch_method = ESP_TIMER_TASK,
.name = "stop_softap_tm"

View file

@ -23,9 +23,32 @@
static const char* TAG = "app_prov_handler";
static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data)
/* Provide definition of wifi_prov_ctx_t */
struct wifi_prov_ctx {
wifi_config_t wifi_cfg;
};
static wifi_config_t *get_config(wifi_prov_ctx_t **ctx)
{
/* Initialise to zero */
return (*ctx ? &(*ctx)->wifi_cfg : NULL);
}
static wifi_config_t *new_config(wifi_prov_ctx_t **ctx)
{
free(*ctx);
(*ctx) = (wifi_prov_ctx_t *) calloc(1, sizeof(wifi_prov_ctx_t));
return get_config(ctx);
}
static void free_config(wifi_prov_ctx_t **ctx)
{
free(*ctx);
*ctx = NULL;
}
static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx)
{
/* Initialize to zero */
memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t));
if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) {
@ -60,16 +83,14 @@ static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data)
return ESP_OK;
}
static wifi_config_t *wifi_cfg;
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx)
{
wifi_config_t *wifi_cfg = get_config(ctx);
if (wifi_cfg) {
free(wifi_cfg);
wifi_cfg = NULL;
free_config(ctx);
}
wifi_cfg = (wifi_config_t *) calloc(1, sizeof(wifi_config_t));
wifi_cfg = new_config(ctx);
if (!wifi_cfg) {
ESP_LOGE(TAG, "Unable to alloc wifi config");
return ESP_FAIL;
@ -84,8 +105,9 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data)
return ESP_OK;
}
static esp_err_t apply_config_handler(void)
static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx)
{
wifi_config_t *wifi_cfg = get_config(ctx);
if (!wifi_cfg) {
ESP_LOGE(TAG, "WiFi config not set");
return ESP_FAIL;
@ -94,8 +116,7 @@ static esp_err_t apply_config_handler(void)
app_prov_configure_sta(wifi_cfg);
ESP_LOGI(TAG, "WiFi Credentials Applied");
free(wifi_cfg);
wifi_cfg = NULL;
free_config(ctx);
return ESP_OK;
}
@ -103,4 +124,5 @@ wifi_prov_config_handlers_t wifi_prov_handlers = {
.get_status_handler = get_status_handler,
.set_config_handler = set_config_handler,
.apply_config_handler = apply_config_handler,
.ctx = NULL
};

View file

@ -59,7 +59,7 @@ def get_transport(sel_transport, softap_endpoint=None, ble_devname=None):
def version_match(tp, protover):
try:
response = tp.send_data('proto-ver', protover)
if response != "SUCCESS":
if response != protover:
return False
return True
except RuntimeError as e: