Protocol Communication¶
Overview¶
Protocol Communication (protocomm) component manages secure sessions and provides framework for multiple transports. The application can also use protocomm layer directly to have application specific extensions for the provisioning (or non-provisioning) use cases.
- Following features are available for provisioning :
- Communication security at application level -
- protocomm_security0 (no security)
- protocomm_security1 (curve25519 key exchange + AES-CTR encryption)
- Proof-of-possession (support with protocomm_security1 only)
Protocomm internally uses protobuf (protocol buffers) for secure session establishment. Though users can implement their own security (even without using protobuf). One can even use protocomm without any security layer.
Protocomm provides framework for various transports - WiFi (SoftAP+HTTPD), BLE, console - in which case the handler invocation is automatically taken care of on the device side (see Transport Examples below for code snippets).
Note that the client still needs to establish session (only for protocomm_security1) by performing the two way handshake. See Unified Provisioning for more details about the secure handshake logic.
Transport Example (SoftAP + HTTP) with Security 1¶
For complete example see provisioning/softap_prov
/* Endpoint handler to be registered with protocomm. * This simply echoes back the received data. */ esp_err_t echo_req_handler (uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen, void *priv_data) { /* Session ID may be used for persistence */ printf("Session ID : %d", session_id); /* Echo back the received data */ *outlen = inlen; /* Output data length updated */ *outbuf = malloc(inlen); /* This will be deallocated outside */ memcpy(*outbuf, inbuf, inlen); /* Private data that was passed at the time of endpoint creation */ uint32_t *priv = (uint32_t *) priv_data; if (priv) { printf("Private data : %d", *priv); } return ESP_OK; } /* Example function for launching a protocomm instance over HTTP */ protocomm_t *start_pc(const char *pop_string) { protocomm_t *pc = protocomm_new(); /* Config for protocomm_httpd_start() */ 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); /* Create Proof of Possession object from pop_string. It must be valid * throughout the scope of protocomm endpoint. This need not be static, * ie. could be dynamically allocated and freed at the time of endpoint * removal */ const static protocomm_security_pop_t pop_obj = { .data = (const uint8_t *) strdup(pop_string), .len = strlen(pop_string) }; /* Set security for communication at application level. Just like for * request handlers, setting security creates an endpoint and registers * the handler provided by protocomm_security1. One can similarly use * protocomm_security0. Only one type of security can be set for a * protocomm instance at a time. */ protocomm_set_security(pc, "security_endpoint", &protocomm_security1, &pop_obj); /* Private data passed to the endpoint must be valid throughout the scope * of protocomm endpoint. This need not be static, ie. could be dynamically * allocated and freed at the time of endpoint removal */ static uint32_t priv_data = 1234; /* Add a new endpoint for the protocomm instance, identified by a unique name * and register a handler function along with private data to be passed at the * time of handler execution. Multiple endpoints can be added as long as they * are identified by unique names */ protocomm_add_endpoint(pc, "echo_req_endpoint", echo_req_handler, (void *) &priv_data); return pc; } /* Example function for stopping a protocomm instance */ void stop_pc(protocomm_t *pc) { /* Remove endpoint identified by it's unique name */ protocomm_remove_endpoint(pc, "echo_req_endpoint"); /* Remove security endpoint identified by it's name */ protocomm_unset_security(pc, "security_endpoint"); /* Stop HTTP server */ protocomm_httpd_stop(pc); /* Delete (deallocate) the protocomm instance */ protocomm_delete(pc); }
Transport Example (BLE) with Security 0¶
For complete example see provisioning/ble_prov
/* Example function for launching a secure protocomm instance over BLE */ protocomm_t *start_pc() { protocomm_t *pc = protocomm_new(); /* Endpoint UUIDs */ protocomm_ble_name_uuid_t nu_lookup_table[] = { {"security_endpoint", 0xFF51}, {"echo_req_endpoint", 0xFF52} }; /* Config for protocomm_ble_start() */ protocomm_ble_config_t config = { .service_uuid = { /* LSB <--------------------------------------- * ---------------------------------------> MSB */ 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, }, .nu_lookup_count = sizeof(nu_lookup_table)/sizeof(nu_lookup_table[0]), .nu_lookup = nu_lookup_table }; /* Start protocomm layer on top of BLE */ protocomm_ble_start(pc, &config); /* For protocomm_security0, Proof of Possession is not used, and can be kept NULL */ protocomm_set_security(pc, "security_endpoint", &protocomm_security0, NULL); protocomm_add_endpoint(pc, "echo_req_endpoint", echo_req_handler, NULL); return pc; } /* Example function for stopping a protocomm instance */ void stop_pc(protocomm_t *pc) { protocomm_remove_endpoint(pc, "echo_req_endpoint"); protocomm_unset_security(pc, "security_endpoint"); /* Stop BLE protocomm service */ protocomm_ble_stop(pc); protocomm_delete(pc); }
API Reference¶
Header File¶
Functions¶
-
protocomm_t *
protocomm_new
()¶ Create a new protocomm instance.
This API will return a new dynamically allocated protocomm instance with all elements of the protocomm_t structure initialized to NULL.
- Return
- protocomm_t* : On success
- NULL : No memory for allocating new instance
-
void
protocomm_delete
(protocomm_t *pc)¶ Delete a protocomm instance.
This API will deallocate a protocomm instance that was created using
protocomm_new()
.- Parameters
pc
: Pointer to the protocomm instance to be deleted
-
esp_err_t
protocomm_add_endpoint
(protocomm_t *pc, const char *ep_name, protocomm_req_handler_t h, void *priv_data)¶ Add endpoint request handler for a protocomm instance.
This API will bind an endpoint handler function to the specified endpoint name, along with any private data that needs to be pass to the handler at the time of call.
- Note
- An endpoint must be bound to a valid protocomm instance, created using
protocomm_new()
. - This function internally calls the registered
add_endpoint()
function of the selected transport which is a member of the protocomm_t instance structure.
- An endpoint must be bound to a valid protocomm instance, created using
- Return
- 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
- Parameters
pc
: Pointer to the protocomm instanceep_name
: Endpoint identifier(name) stringh
: Endpoint handler functionpriv_data
: Pointer to private data to be passed as a parameter to the handler function on call. Pass NULL if not needed.
-
esp_err_t
protocomm_remove_endpoint
(protocomm_t *pc, const char *ep_name)¶ Remove endpoint request handler for a protocomm instance.
This API will remove a registered endpoint handler identified by an endpoint name.
- Note
- This function internally calls the registered
remove_endpoint()
function which is a member of the protocomm_t instance structure.
- This function internally calls the registered
- Return
- ESP_OK : Success
- ESP_ERR_NOT_FOUND : Endpoint with specified name doesn’t exist
- ESP_ERR_INVALID_ARG : Null instance/name arguments
- Parameters
pc
: Pointer to the protocomm instanceep_name
: Endpoint identifier(name) string
-
esp_err_t
protocomm_req_handle
(protocomm_t *pc, const char *ep_name, uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen)¶ Calls the registered handler of an endpoint session 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 caller.
- An endpoint must be bound to a valid protocomm instance, created using
- Return
- 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
- ESP_ERR_INVALID_ARG : Null instance/name arguments
- Parameters
pc
: Pointer to the protocomm instanceep_name
: Endpoint identifier(name) stringsession_id
: Unique ID for a communication sessioninbuf
: Input buffer contains input request data which is to be processed by the registered handlerinlen
: Length of the input bufferoutbuf
: Pointer to internally allocated output buffer, where the resulting response data output from the registered handler is to be storedoutlen
: Buffer length of the allocated output buffer
-
esp_err_t
protocomm_set_security
(protocomm_t *pc, const char *ep_name, const protocomm_security_t *sec, const protocomm_security_pop_t *pop)¶ Add endpoint security for a protocomm instance.
This API will bind a security session establisher to the specified endpoint name, along with any proof of possession that may be required for authenticating a session client.
- Note
- An endpoint must be bound to a valid protocomm instance, created using
protocomm_new()
. - The choice of security can be any
protocomm_security_t
instance. Choicesprotocomm_security0
andprotocomm_security1
are readily available.
- An endpoint must be bound to a valid protocomm instance, created using
- Return
- 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
- ESP_ERR_INVALID_ARG : Null instance/name/handler arguments
- Parameters
pc
: Pointer to the protocomm instanceep_name
: Endpoint identifier(name) stringsec
: Pointer to endpoint security instancepop
: Pointer to proof of possession for authenticating a client
-
esp_err_t
protocomm_unset_security
(protocomm_t *pc, const char *ep_name)¶ Remove endpoint security for a protocomm instance.
This API will remove a registered security endpoint identified by an endpoint name.
- Return
- ESP_OK : Success
- ESP_ERR_NOT_FOUND : Endpoint with specified name doesn’t exist
- ESP_ERR_INVALID_ARG : Null instance/name arguments
- Parameters
pc
: Pointer to the protocomm instanceep_name
: Endpoint identifier(name) string
-
esp_err_t
protocomm_set_version
(protocomm_t *pc, const char *ep_name, const char *version)¶ Set endpoint for version verification.
This API can be used for setting an application specific protocol version which can be verified by clients through the endpoint.
- Note
- An endpoint must be bound to a valid protocomm instance, created using
protocomm_new()
.
- An endpoint must be bound to a valid protocomm instance, created using
- Return
- 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
- ESP_ERR_INVALID_ARG : Null instance/name/handler arguments
- Parameters
pc
: Pointer to the protocomm instanceep_name
: Endpoint identifier(name) stringversion
: Version identifier(name) string
-
esp_err_t
protocomm_unset_version
(protocomm_t *pc, const char *ep_name)¶ Remove version verification endpoint from a protocomm instance.
This API will remove a registered version endpoint identified by an endpoint name.
- Return
- ESP_OK : Success
- ESP_ERR_NOT_FOUND : Endpoint with specified name doesn’t exist
- ESP_ERR_INVALID_ARG : Null instance/name arguments
- Parameters
pc
: Pointer to the protocomm instanceep_name
: Endpoint identifier(name) string
Type Definitions¶
-
typedef esp_err_t (*
protocomm_req_handler_t
)(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen, void *priv_data)¶ Function prototype for protocomm endpoint handler.
-
typedef struct protocomm
protocomm_t
¶ This structure corresponds to a unique instance of protocomm returned when the API
protocomm_new()
is called. The remaining Protocomm APIs require this object as the first parameter.- Note
- Structure of the protocomm object is kept private
Header File¶
Structures¶
-
struct
protocomm_security_pop
¶ Proof Of Possession for authenticating a secure session.
-
struct
protocomm_security
¶ Protocomm security object structure.
The member functions are used for implementing secure protocomm sessions.
- Note
- This structure should not have any dynamic members to allow re-entrancy
Public Members
-
int
ver
¶ Unique version number of security implementation
-
esp_err_t (*
new_transport_session
)(uint32_t session_id)¶ Starts new secure transport session with specified ID
-
esp_err_t (*
close_transport_session
)(uint32_t session_id)¶ Closes a secure transport session with specified ID
-
esp_err_t (*
security_req_handler
)(const protocomm_security_pop_t *pop, uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen, void *priv_data)¶ Handler function for authenticating connection request and establishing secure session
Type Definitions¶
-
typedef struct protocomm_security_pop
protocomm_security_pop_t
¶ Proof Of Possession for authenticating a secure session.
-
typedef struct protocomm_security
protocomm_security_t
¶ Protocomm security object structure.
The member functions are used for implementing secure protocomm sessions.
- Note
- This structure should not have any dynamic members to allow re-entrancy
Header File¶
Functions¶
-
esp_err_t
protocomm_httpd_start
(protocomm_t *pc, const protocomm_httpd_config_t *config)¶ Start HTTPD protocomm transport.
This API internally creates a framework to allow endpoint registration and security configuration for the protocomm.
- Note
- This is a singleton. ie. Protocomm can have multiple instances, but only one instance can be bound to an HTTP transport layer.
- Return
- 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
- ESP_ERR_NO_MEM : Memory allocation for server resource failed
- ESP_ERR_HTTPD_* : HTTP server error on start
- Parameters
pc
: Protocomm instance pointer obtained from protocomm_new()config
: Pointer to config structure for initializing HTTP server
-
esp_err_t
protocomm_httpd_stop
(protocomm_t *pc)¶ Stop HTTPD protocomm transport.
This API cleans up the HTTPD transport protocomm and frees all the handlers registered with the protocomm.
- Return
- ESP_OK : Success
- ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance pointer
- Parameters
pc
: Same protocomm instance that was passed to protocomm_httpd_start()
Unions¶
-
union
protocomm_httpd_config_data_t
¶ - #include <protocomm_httpd.h>
Protocomm HTTPD Configuration Data
Public Members
-
void *
handle
¶ HTTP Server Handle, if ext_handle_provided is set to true
-
protocomm_http_server_config_t
config
¶ HTTP Server Configuration, if a server is not already active
-
void *
Structures¶
-
struct
protocomm_http_server_config_t
¶ Config parameters for protocomm HTTP server.
-
struct
protocomm_httpd_config_t
¶ Config parameters for protocomm HTTP server.
Public Members
-
bool
ext_handle_provided
¶ 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.
-
protocomm_httpd_config_data_t
data
¶ Protocomm HTTPD Configuration Data
-
bool
Header File¶
Functions¶
-
esp_err_t
protocomm_ble_start
(protocomm_t *pc, const protocomm_ble_config_t *config)¶ Start Bluetooth Low Energy based transport layer for provisioning.
Initialize and start required BLE service for provisioning. This includes the initialization for characteristics/service for BLE.
- Return
- 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
- ESP_ERR_INVALID_ARG : Null arguments
- Parameters
pc
: Protocomm instance pointer obtained from protocomm_new()config
: Pointer to config structure for initializing BLE
-
esp_err_t
protocomm_ble_stop
(protocomm_t *pc)¶ Stop Bluetooth Low Energy based transport layer for provisioning.
Stops service/task responsible for BLE based interactions for provisioning
- Note
- You might want to optionally reclaim memory from Bluetooth. Refer to the documentation of
esp_bt_mem_release
in that case. - Return
- ESP_OK : Success
- ESP_FAIL : Simple BLE stop error
- ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance
- Parameters
pc
: Same protocomm instance that was passed to protocomm_ble_start()
Structures¶
-
struct
name_uuid
¶ This structure maps handler required by protocomm layer to UUIDs which are used to uniquely identify BLE characteristics from a smartphone or a similar client device.
-
struct
protocomm_ble_config_t
¶ Config parameters for protocomm BLE service.
Public Members
-
char
device_name
[MAX_BLE_DEVNAME_LEN
]¶ BLE device name being broadcast at the time of provisioning
-
uint8_t
service_uuid
[ESP_UUID_LEN_128
]¶ 128 bit UUID of the provisioning service
-
ssize_t
nu_lookup_count
¶ Number of entries in the Name-UUID lookup table
-
protocomm_ble_name_uuid_t *
nu_lookup
¶ Pointer to the Name-UUID lookup table
-
char