协议通信

[English]

概述

协议通信 (protocomm) 组件用于管理安全会话并为多种传输提供框架。应用程序还可以直接使用 protocomm 层来增加特定扩展,用于配网或非配网使用场景。

以下功能可用于配网:

  • 应用程序层面的通信安全

    • protocomm_security0 (无安全功能)

    • protocomm_security1 (Curve25519 密钥交换 + AES-CTR 加密/解密)

    • protocomm_security2 (基于 SRP6a 的密钥交换 + AES-GCM 加密/解密)

  • 所有权验证 (Proof-of-possession)(仅 protocomm_security1 支持该功能)

  • 盐值和验证器 (Salt and Verifier)(仅 protocomm_security2 支持该功能)

在 protocomm 内部,protobuf(协议缓冲区)用于建立安全会话。用户可以自行选择(即使在不使用 Protobuf 的情况下)实现安全性,也可以在没有任何安全层的情况下使用协议。

Protocomm 为以下各种传输提供框架:

  • 控制台:使用该传输方案时,设备端会自动调用处理程序。相关代码片段,请参见下文传输示例。

请注意,对于 protocomm_security1protocomm_security2,客户端仍需要执行双向握手来建立会话。

启用 protocomm 安全版本

关于启用/禁用相应的安全版本,请参阅 protocomm 组件的项目配置菜单。相应配置选项如下:

备注

启用多个安全版本后可以动态控制安全版本,但也会增加固件大小。

API 参考

Header File

  • components/protocomm/include/common/protocomm.h

  • This header file can be included with:

    #include "protocomm.h"
    
  • This header file is a part of the API provided by the protocomm component. To declare that your component depends on protocomm, add the following to your CMakeLists.txt:

    REQUIRES protocomm
    

    or

    PRIV_REQUIRES protocomm
    

Functions

protocomm_t *protocomm_new(void)

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.

返回

  • 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().

参数

pc -- [in] 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.

备注

  • 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.

参数
  • pc -- [in] Pointer to the protocomm instance

  • ep_name -- [in] Endpoint identifier(name) string

  • h -- [in] Endpoint handler function

  • priv_data -- [in] Pointer to private data to be passed as a parameter to the handler function on call. Pass NULL if not needed.

返回

  • 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

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.

备注

  • This function internally calls the registered remove_endpoint() function which is a member of the protocomm_t instance structure.

参数
  • pc -- [in] Pointer to the protocomm instance

  • ep_name -- [in] Endpoint identifier(name) string

返回

  • 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_open_session(protocomm_t *pc, uint32_t session_id)

Allocates internal resources for new transport session.

备注

  • An endpoint must be bound to a valid protocomm instance, created using protocomm_new().

参数
  • pc -- [in] Pointer to the protocomm instance

  • session_id -- [in] Unique ID for a communication session

返回

  • ESP_OK : Request handled successfully

  • ESP_ERR_NO_MEM : Error allocating internal resource

  • ESP_ERR_INVALID_ARG : Null instance/name arguments

esp_err_t protocomm_close_session(protocomm_t *pc, uint32_t session_id)

Frees internal resources used by a transport session.

备注

  • An endpoint must be bound to a valid protocomm instance, created using protocomm_new().

参数
  • pc -- [in] Pointer to the protocomm instance

  • session_id -- [in] Unique ID for a communication session

返回

  • ESP_OK : Request handled successfully

  • ESP_ERR_INVALID_ARG : Null instance/name arguments

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.

备注

  • An endpoint must be bound to a valid protocomm instance, created using protocomm_new().

  • Resulting output buffer must be deallocated by the caller.

参数
  • pc -- [in] Pointer to the protocomm instance

  • ep_name -- [in] Endpoint identifier(name) string

  • session_id -- [in] Unique ID for a communication session

  • inbuf -- [in] Input buffer contains input request data which is to be processed by the registered handler

  • inlen -- [in] Length of the input buffer

  • outbuf -- [out] Pointer to internally allocated output buffer, where the resulting response data output from the registered handler is to be stored

  • outlen -- [out] Buffer length of the allocated output buffer

返回

  • 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

esp_err_t protocomm_set_security(protocomm_t *pc, const char *ep_name, const protocomm_security_t *sec, const void *sec_params)

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.

备注

  • 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. Choices protocomm_security0 and protocomm_security1 and protocomm_security2 are readily available.

参数
  • pc -- [in] Pointer to the protocomm instance

  • ep_name -- [in] Endpoint identifier(name) string

  • sec -- [in] Pointer to endpoint security instance

  • sec_params -- [in] Pointer to security params (NULL if not needed) The pointer should contain the security params struct of appropriate security version. For protocomm security version 1 and 2 sec_params should contain pointer to struct of type protocomm_security1_params_t and protocmm_security2_params_t respectively. The contents of this pointer must be valid till the security session has been running and is not closed.

返回

  • 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

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.

参数
  • pc -- [in] Pointer to the protocomm instance

  • ep_name -- [in] Endpoint identifier(name) string

返回

  • 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_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.

备注

  • An endpoint must be bound to a valid protocomm instance, created using protocomm_new().

参数
  • pc -- [in] Pointer to the protocomm instance

  • ep_name -- [in] Endpoint identifier(name) string

  • version -- [in] Version identifier(name) string

返回

  • 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

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.

参数
  • pc -- [in] Pointer to the protocomm instance

  • ep_name -- [in] Endpoint identifier(name) string

返回

  • ESP_OK : Success

  • ESP_ERR_NOT_FOUND : Endpoint with specified name doesn't exist

  • ESP_ERR_INVALID_ARG : Null instance/name arguments

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.

备注

Structure of the protocomm object is kept private

Header File

  • components/protocomm/include/security/protocomm_security.h

  • This header file can be included with:

    #include "protocomm_security.h"
    
  • This header file is a part of the API provided by the protocomm component. To declare that your component depends on protocomm, add the following to your CMakeLists.txt:

    REQUIRES protocomm
    

    or

    PRIV_REQUIRES protocomm
    

Structures

struct protocomm_security1_params

Protocomm Security 1 parameters: Proof Of Possession.

Public Members

const uint8_t *data

Pointer to buffer containing the proof of possession data

uint16_t len

Length (in bytes) of the proof of possession data

struct protocomm_security2_params

Protocomm Security 2 parameters: Salt and Verifier.

Public Members

const char *salt

Pointer to the buffer containing the salt

uint16_t salt_len

Length (in bytes) of the salt

const char *verifier

Pointer to the buffer containing the verifier

uint16_t verifier_len

Length (in bytes) of the verifier

struct protocomm_security

Protocomm security object structure.

The member functions are used for implementing secure protocomm sessions.

备注

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 (*init)(protocomm_security_handle_t *handle)

Function for initializing/allocating security infrastructure

esp_err_t (*cleanup)(protocomm_security_handle_t handle)

Function for deallocating security infrastructure

esp_err_t (*new_transport_session)(protocomm_security_handle_t handle, uint32_t session_id)

Starts new secure transport session with specified ID

esp_err_t (*close_transport_session)(protocomm_security_handle_t handle, uint32_t session_id)

Closes a secure transport session with specified ID

esp_err_t (*security_req_handler)(protocomm_security_handle_t handle, const void *sec_params, 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

esp_err_t (*encrypt)(protocomm_security_handle_t handle, uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen)

Function which implements the encryption algorithm

esp_err_t (*decrypt)(protocomm_security_handle_t handle, uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen)

Function which implements the decryption algorithm

Type Definitions

typedef struct protocomm_security1_params protocomm_security1_params_t

Protocomm Security 1 parameters: Proof Of Possession.

typedef protocomm_security1_params_t protocomm_security_pop_t
typedef struct protocomm_security2_params protocomm_security2_params_t

Protocomm Security 2 parameters: Salt and Verifier.

typedef void *protocomm_security_handle_t
typedef struct protocomm_security protocomm_security_t

Protocomm security object structure.

The member functions are used for implementing secure protocomm sessions.

备注

This structure should not have any dynamic members to allow re-entrancy

Enumerations

enum protocomm_security_session_event_t

Events generated by the protocomm security layer.

These events are generated while establishing secured session.

Values:

enumerator PROTOCOMM_SECURITY_SESSION_SETUP_OK

Secured session established successfully

enumerator PROTOCOMM_SECURITY_SESSION_INVALID_SECURITY_PARAMS

Received invalid (NULL) security parameters (username / client public-key)

enumerator PROTOCOMM_SECURITY_SESSION_CREDENTIALS_MISMATCH

Received incorrect credentials (username / PoP)

Header File

  • components/protocomm/include/security/protocomm_security0.h

  • This header file can be included with:

    #include "protocomm_security0.h"
    
  • This header file is a part of the API provided by the protocomm component. To declare that your component depends on protocomm, add the following to your CMakeLists.txt:

    REQUIRES protocomm
    

    or

    PRIV_REQUIRES protocomm
    

Header File

  • components/protocomm/include/security/protocomm_security1.h

  • This header file can be included with:

    #include "protocomm_security1.h"
    
  • This header file is a part of the API provided by the protocomm component. To declare that your component depends on protocomm, add the following to your CMakeLists.txt:

    REQUIRES protocomm
    

    or

    PRIV_REQUIRES protocomm
    

Header File

  • components/protocomm/include/security/protocomm_security2.h

  • This header file can be included with:

    #include "protocomm_security2.h"
    
  • This header file is a part of the API provided by the protocomm component. To declare that your component depends on protocomm, add the following to your CMakeLists.txt:

    REQUIRES protocomm
    

    or

    PRIV_REQUIRES protocomm
    

Header File

  • components/protocomm/include/crypto/srp6a/esp_srp.h

  • This header file can be included with:

    #include "esp_srp.h"
    
  • This header file is a part of the API provided by the protocomm component. To declare that your component depends on protocomm, add the following to your CMakeLists.txt:

    REQUIRES protocomm
    

    or

    PRIV_REQUIRES protocomm
    

Functions

esp_srp_handle_t *esp_srp_init(esp_ng_type_t ng)

Initialize srp context for given NG type.

备注

the handle gets freed with esp_srp_free

参数

ng -- NG type given by esp_ng_type_t

返回

esp_srp_handle_t* srp handle

void esp_srp_free(esp_srp_handle_t *hd)

free esp_srp_context

参数

hd -- handle to be free

esp_err_t esp_srp_srv_pubkey(esp_srp_handle_t *hd, const char *username, int username_len, const char *pass, int pass_len, int salt_len, char **bytes_B, int *len_B, char **bytes_salt)

Returns B (pub key) and salt. [Step2.b].

备注

*bytes_B MUST NOT BE FREED BY THE CALLER

备注

*bytes_salt MUST NOT BE FREE BY THE CALLER

参数
  • hd -- esp_srp handle

  • username -- Username not expected NULL terminated

  • username_len -- Username length

  • pass -- Password not expected to be NULL terminated

  • pass_len -- Pasword length

  • salt_len -- Salt length

  • bytes_B -- Public Key returned

  • len_B -- Length of the public key

  • bytes_salt -- Salt bytes generated

返回

esp_err_t ESP_OK on success, appropriate error otherwise

esp_err_t esp_srp_gen_salt_verifier(const char *username, int username_len, const char *pass, int pass_len, char **bytes_salt, int salt_len, char **verifier, int *verifier_len)

Generate salt-verifier pair, given username, password and salt length.

备注

if API has returned ESP_OK, salt and verifier generated need to be freed by caller

备注

Usually, username and password are not saved on the device. Rather salt and verifier are generated outside the device and are embedded. this covenience API can be used to generate salt and verifier on the fly for development use case. OR for devices which intentionally want to generate different password each time and can send it to the client securely. e.g., a device has a display and it shows the pin

参数
  • username -- [in] username

  • username_len -- [in] length of the username

  • pass -- [in] password

  • pass_len -- [in] length of the password

  • bytes_salt -- [out] generated salt on successful generation, or NULL

  • salt_len -- [in] salt length

  • verifier -- [out] generated verifier on successful generation, or NULL

  • verifier_len -- [out] length of the generated verifier

返回

esp_err_t ESP_OK on success, appropriate error otherwise

esp_err_t esp_srp_set_salt_verifier(esp_srp_handle_t *hd, const char *salt, int salt_len, const char *verifier, int verifier_len)

Set the Salt and Verifier pre-generated for a given password. This should be used only if the actual password is not available. The public key can then be generated using esp_srp_srv_pubkey_from_salt_verifier() and not esp_srp_srv_pubkey()

参数
  • hd -- esp_srp_handle

  • salt -- pre-generated salt bytes

  • salt_len -- length of the salt bytes

  • verifier -- pre-generated verifier

  • verifier_len -- length of the verifier bytes

返回

esp_err_t ESP_OK on success, appropriate error otherwise

esp_err_t esp_srp_srv_pubkey_from_salt_verifier(esp_srp_handle_t *hd, char **bytes_B, int *len_B)

Returns B (pub key)[Step2.b] when the salt and verifier are set using esp_srp_set_salt_verifier()

备注

*bytes_B MUST NOT BE FREED BY THE CALLER

参数
  • hd -- esp_srp handle

  • bytes_B -- Key returned to the called

  • len_B -- Length of the key returned

返回

esp_err_t ESP_OK on success, appropriate error otherwise

esp_err_t esp_srp_get_session_key(esp_srp_handle_t *hd, char *bytes_A, int len_A, char **bytes_key, uint16_t *len_key)

Get session key in *bytes_key given by len in *len_key. [Step2.c].

This calculated session key is used for further communication given the proofs are exchanged/authenticated with esp_srp_exchange_proofs

备注

*bytes_key MUST NOT BE FREED BY THE CALLER

参数
  • hd -- esp_srp handle

  • bytes_A -- Private Key

  • len_A -- Private Key length

  • bytes_key -- Key returned to the caller

  • len_key -- length of the key in *bytes_key

返回

esp_err_t ESP_OK on success, appropriate error otherwise

esp_err_t esp_srp_exchange_proofs(esp_srp_handle_t *hd, char *username, uint16_t username_len, char *bytes_user_proof, char *bytes_host_proof)

Complete the authentication. If this step fails, the session_key exchanged should not be used.

This is the final authentication step in SRP algorithm [Step4.1, Step4.b, Step4.c]

参数
  • hd -- esp_srp handle

  • username -- Username not expected NULL terminated

  • username_len -- Username length

  • bytes_user_proof -- param in

  • bytes_host_proof -- parameter out (should be SHA512_DIGEST_LENGTH) bytes in size

返回

esp_err_t ESP_OK if user's proof is ok and subsequently bytes_host_proof is populated with our own proof.

Type Definitions

typedef struct esp_srp_handle esp_srp_handle_t

esp_srp handle as the result of esp_srp_init

The handle is returned by esp_srp_init on successful init. It is then passed for subsequent API calls as an argument. esp_srp_free can be used to clean up the handle. After esp_srp_free the handle becomes invalid.

Enumerations

enum esp_ng_type_t

Large prime+generator to be used for the algorithm.

Values:

enumerator ESP_NG_3072

Header File

  • components/protocomm/include/transports/protocomm_httpd.h

  • This header file can be included with:

    #include "protocomm_httpd.h"
    
  • This header file is a part of the API provided by the protocomm component. To declare that your component depends on protocomm, add the following to your CMakeLists.txt:

    REQUIRES protocomm
    

    or

    PRIV_REQUIRES protocomm
    

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.

备注

This is a singleton. ie. Protocomm can have multiple instances, but only one instance can be bound to an HTTP transport layer.

参数
  • pc -- [in] Protocomm instance pointer obtained from protocomm_new()

  • config -- [in] Pointer to config structure for initializing HTTP server

返回

  • 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

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.

参数

pc -- [in] Same protocomm instance that was passed to protocomm_httpd_start()

返回

  • ESP_OK : Success

  • ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance pointer

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

Structures

struct protocomm_http_server_config_t

Config parameters for protocomm HTTP server.

Public Members

uint16_t port

Port on which the HTTP server will listen

size_t stack_size

Stack size of server task, adjusted depending upon stack usage of endpoint handler

unsigned task_priority

Priority of server task

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

Macros

PROTOCOMM_HTTPD_DEFAULT_CONFIG()