mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
ESP_TLS: Restructuring esp_tls
1)Segregating mbedtls API into seperate file and cleaned esp_tls.c 2)Added support for wolfssl for CMake and make 3)Added support for debug_wolfssl (with menuconfig option) 4)Added info on wolfssl in ESP-TLS docs
This commit is contained in:
parent
758db1e008
commit
f7eaa5f946
@ -1,5 +1,21 @@
|
||||
idf_component_register(SRCS "esp_tls.c"
|
||||
set(srcs esp_tls.c)
|
||||
if(CONFIG_ESP_TLS_USING_MBEDTLS)
|
||||
list(APPEND srcs
|
||||
"esp_tls_mbedtls.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_ESP_TLS_USING_WOLFSSL)
|
||||
list(APPEND srcs
|
||||
"esp_tls_wolfssl.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_INCLUDE_DIRS "private_include"
|
||||
REQUIRES mbedtls
|
||||
PRIV_REQUIRES lwip nghttp)
|
||||
|
||||
if(CONFIG_ESP_TLS_USING_WOLFSSL)
|
||||
idf_component_get_property(wolfssl esp-wolfssl COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC ${wolfssl})
|
||||
endif()
|
||||
|
@ -1,12 +1,28 @@
|
||||
menu "ESP-TLS"
|
||||
choice ESP_TLS_LIBRARY_CHOOSE
|
||||
prompt "Choose SSL/TLS library for ESP-TLS (See help for more Info)"
|
||||
default ESP_TLS_USING_MBEDTLS
|
||||
help
|
||||
The ESP-TLS APIs support multiple backend TLS libraries. Currently mbedTLS and WolfSSL are
|
||||
supported. Different TLS libraries may support different features and have different resource
|
||||
usage. Consult the ESP-TLS documentation in ESP-IDF Programming guide for more details.
|
||||
config ESP_TLS_USING_MBEDTLS
|
||||
bool "mbedTLS"
|
||||
config ESP_TLS_USING_WOLFSSL
|
||||
depends on TLS_STACK_WOLFSSL
|
||||
bool "wolfSSL (License info in wolfSSL directory README)"
|
||||
endchoice
|
||||
|
||||
config ESP_TLS_SERVER
|
||||
bool "Enable ESP-TLS Server"
|
||||
depends on ESP_TLS_USING_MBEDTLS
|
||||
default n
|
||||
help
|
||||
Enable support for creating server side SSL/TLS session
|
||||
Enable support for creating server side SSL/TLS session, uses the mbedtls crypto library
|
||||
|
||||
config ESP_TLS_PSK_VERIFICATION
|
||||
bool "Enable PSK verification"
|
||||
depends on ESP_TLS_USING_MBEDTLS
|
||||
select MBEDTLS_PSK_MODES
|
||||
select MBEDTLS_KEY_EXCHANGE_PSK
|
||||
select MBEDTLS_KEY_EXCHANGE_DHE_PSK
|
||||
@ -14,7 +30,22 @@ menu "ESP-TLS"
|
||||
select MBEDTLS_KEY_EXCHANGE_RSA_PSK
|
||||
default n
|
||||
help
|
||||
Enable support for pre shared key ciphers
|
||||
Enable support for pre shared key ciphers, uses the mbedtls crypto library
|
||||
|
||||
config ESP_WOLFSSL_SMALL_CERT_VERIFY
|
||||
bool "Enable SMALL_CERT_VERIFY"
|
||||
depends on ESP_TLS_USING_WOLFSSL
|
||||
default y
|
||||
help
|
||||
Enables server verification with Intermediate CA cert, does not authenticate full chain
|
||||
of trust upto the root CA cert (After Enabling this option client only needs to have Intermediate
|
||||
CA certificate of the server to authenticate server, root CA cert is not necessary).
|
||||
|
||||
config ESP_DEBUG_WOLFSSL
|
||||
bool "Enable debug logs for wolfSSL"
|
||||
depends on ESP_TLS_USING_WOLFSSL
|
||||
default n
|
||||
help
|
||||
Enable detailed debug prints for wolfSSL SSL library.
|
||||
|
||||
endmenu
|
||||
|
||||
|
@ -1,3 +1,16 @@
|
||||
|
||||
COMPONENT_SRCDIRS := .
|
||||
COMPONENT_OBJS := esp_tls.o
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := . private_include
|
||||
|
||||
|
||||
ifneq ($(CONFIG_ESP_TLS_USING_MBEDTLS), )
|
||||
COMPONENT_OBJS += esp_tls_mbedtls.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_ESP_TLS_USING_WOLFSSL), )
|
||||
COMPONENT_OBJS += esp_tls_wolfssl.o
|
||||
endif
|
||||
|
||||
CFLAGS += -DWOLFSSL_USER_SETTINGS
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -24,9 +24,13 @@
|
||||
#include "esp_tls.h"
|
||||
#include "esp_tls_error_capture_internal.h"
|
||||
#include <errno.h>
|
||||
|
||||
static const char *TAG = "esp-tls";
|
||||
static mbedtls_x509_crt *global_cacert = NULL;
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
#include "esp_tls_mbedtls.h"
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL
|
||||
#include "esp_tls_wolfssl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <esp_log.h>
|
||||
@ -35,16 +39,86 @@ static mbedtls_x509_crt *global_cacert = NULL;
|
||||
#define ESP_LOGE(TAG, ...) printf(__VA_ARGS__);
|
||||
#endif
|
||||
|
||||
typedef struct esp_tls_pki_t {
|
||||
mbedtls_x509_crt *public_cert;
|
||||
mbedtls_pk_context *pk_key;
|
||||
const unsigned char *publiccert_pem_buf;
|
||||
unsigned int publiccert_pem_bytes;
|
||||
const unsigned char *privkey_pem_buf;
|
||||
unsigned int privkey_pem_bytes;
|
||||
const unsigned char *privkey_password;
|
||||
unsigned int privkey_password_len;
|
||||
} esp_tls_pki_t;
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
#define _esp_create_ssl_handle esp_create_mbedtls_handle
|
||||
#define _esp_tls_handshake esp_mbedtls_handshake
|
||||
#define _esp_tls_read esp_mbedtls_read
|
||||
#define _esp_tls_write esp_mbedtls_write
|
||||
#define _esp_tls_conn_delete esp_mbedtls_conn_delete
|
||||
#ifdef CONFIG_ESP_TLS_SERVER
|
||||
#define _esp_tls_server_session_create esp_mbedtls_server_session_create
|
||||
#define _esp_tls_server_session_delete esp_mbedtls_server_session_delete
|
||||
#endif /* CONFIG_ESP_TLS_SERVER */
|
||||
#define _esp_tls_get_bytes_avail esp_mbedtls_get_bytes_avail
|
||||
#define _esp_tls_init_global_ca_store esp_mbedtls_init_global_ca_store
|
||||
#define _esp_tls_set_global_ca_store esp_mbedtls_set_global_ca_store /*!< Callback function for setting global CA store data for TLS/SSL */
|
||||
#define _esp_tls_get_global_ca_store esp_mbedtls_get_global_ca_store
|
||||
#define _esp_tls_free_global_ca_store esp_mbedtls_free_global_ca_store /*!< Callback function for freeing global ca store for TLS/SSL */
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL /* CONFIG_ESP_TLS_USING_MBEDTLS */
|
||||
#define _esp_create_ssl_handle esp_create_wolfssl_handle
|
||||
#define _esp_tls_handshake esp_wolfssl_handshake
|
||||
#define _esp_tls_read esp_wolfssl_read
|
||||
#define _esp_tls_write esp_wolfssl_write
|
||||
#define _esp_tls_conn_delete esp_wolfssl_conn_delete
|
||||
#define _esp_tls_get_bytes_avail esp_wolfssl_get_bytes_avail
|
||||
#define _esp_tls_init_global_ca_store esp_wolfssl_init_global_ca_store
|
||||
#define _esp_tls_set_global_ca_store esp_wolfssl_set_global_ca_store /*!< Callback function for setting global CA store data for TLS/SSL */
|
||||
#define _esp_tls_free_global_ca_store esp_wolfssl_free_global_ca_store /*!< Callback function for freeing global ca store for TLS/SSL */
|
||||
#else /* ESP_TLS_USING_WOLFSSL */
|
||||
#error "No TLS stack configured"
|
||||
#endif
|
||||
|
||||
static esp_err_t create_ssl_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls)
|
||||
{
|
||||
return _esp_create_ssl_handle(hostname, hostlen, cfg, tls);
|
||||
}
|
||||
|
||||
static esp_err_t esp_tls_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg)
|
||||
{
|
||||
return _esp_tls_handshake(tls, cfg);
|
||||
}
|
||||
|
||||
static ssize_t tcp_read(esp_tls_t *tls, char *data, size_t datalen)
|
||||
{
|
||||
return recv(tls->sockfd, data, datalen, 0);
|
||||
}
|
||||
|
||||
static ssize_t tcp_write(esp_tls_t *tls, const char *data, size_t datalen)
|
||||
{
|
||||
return send(tls->sockfd, data, datalen, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close the TLS connection and free any allocated resources.
|
||||
*/
|
||||
void esp_tls_conn_delete(esp_tls_t *tls)
|
||||
{
|
||||
if (tls != NULL) {
|
||||
_esp_tls_conn_delete(tls);
|
||||
if (tls->sockfd >= 0) {
|
||||
close(tls->sockfd);
|
||||
}
|
||||
free(tls->error_handle);
|
||||
free(tls);
|
||||
}
|
||||
}
|
||||
|
||||
esp_tls_t *esp_tls_init(void)
|
||||
{
|
||||
esp_tls_t *tls = (esp_tls_t *)calloc(1, sizeof(esp_tls_t));
|
||||
if (!tls) {
|
||||
return NULL;
|
||||
}
|
||||
tls->error_handle = calloc(1, sizeof(esp_tls_last_error_t));
|
||||
if (!tls->error_handle) {
|
||||
free(tls);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
tls->server_fd.fd = tls->sockfd = -1;
|
||||
#endif
|
||||
return tls;
|
||||
}
|
||||
|
||||
static esp_err_t resolve_host_name(const char *host, size_t hostlen, struct addrinfo **address_info)
|
||||
{
|
||||
@ -68,26 +142,6 @@ static esp_err_t resolve_host_name(const char *host, size_t hostlen, struct addr
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static ssize_t tcp_read(esp_tls_t *tls, char *data, size_t datalen)
|
||||
{
|
||||
return recv(tls->sockfd, data, datalen, 0);
|
||||
}
|
||||
|
||||
static ssize_t tls_read(esp_tls_t *tls, char *data, size_t datalen)
|
||||
{
|
||||
ssize_t ret = mbedtls_ssl_read(&tls->ssl, (unsigned char *)data, datalen);
|
||||
if (ret < 0) {
|
||||
if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
|
||||
return 0;
|
||||
}
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
ESP_LOGE(TAG, "read error :%d:", ret);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ms_to_timeval(int timeout_ms, struct timeval *tv)
|
||||
{
|
||||
tv->tv_sec = timeout_ms / 1000;
|
||||
@ -159,426 +213,6 @@ err_freeaddr:
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t esp_tls_init_global_ca_store(void)
|
||||
{
|
||||
if (global_cacert == NULL) {
|
||||
global_cacert = (mbedtls_x509_crt *)calloc(1, sizeof(mbedtls_x509_crt));
|
||||
if (global_cacert == NULL) {
|
||||
ESP_LOGE(TAG, "global_cacert not allocated");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
mbedtls_x509_crt_init(global_cacert);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_tls_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes)
|
||||
{
|
||||
int ret;
|
||||
if (cacert_pem_buf == NULL) {
|
||||
ESP_LOGE(TAG, "cacert_pem_buf is null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (global_cacert == NULL) {
|
||||
ret = esp_tls_init_global_ca_store();
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = mbedtls_x509_crt_parse(global_cacert, cacert_pem_buf, cacert_pem_bytes);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x", -ret);
|
||||
mbedtls_x509_crt_free(global_cacert);
|
||||
global_cacert = NULL;
|
||||
return ESP_FAIL;
|
||||
} else if (ret > 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_x509_crt_parse was partly successful. No. of failed certificates: %d", ret);
|
||||
return ESP_ERR_MBEDTLS_CERT_PARTLY_OK;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
mbedtls_x509_crt *esp_tls_get_global_ca_store(void)
|
||||
{
|
||||
return global_cacert;
|
||||
}
|
||||
|
||||
void esp_tls_free_global_ca_store(void)
|
||||
{
|
||||
if (global_cacert) {
|
||||
mbedtls_x509_crt_free(global_cacert);
|
||||
global_cacert = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void verify_certificate(esp_tls_t *tls)
|
||||
{
|
||||
int flags;
|
||||
char buf[100];
|
||||
if ((flags = mbedtls_ssl_get_verify_result(&tls->ssl)) != 0) {
|
||||
ESP_LOGI(TAG, "Failed to verify peer certificate!");
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS_CERT_FLAGS, flags);
|
||||
bzero(buf, sizeof(buf));
|
||||
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
|
||||
ESP_LOGI(TAG, "verification info: %s", buf);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Certificate verified.");
|
||||
}
|
||||
}
|
||||
|
||||
static void mbedtls_cleanup(esp_tls_t *tls)
|
||||
{
|
||||
if (!tls) {
|
||||
return;
|
||||
}
|
||||
if (tls->cacert_ptr != global_cacert) {
|
||||
mbedtls_x509_crt_free(tls->cacert_ptr);
|
||||
}
|
||||
tls->cacert_ptr = NULL;
|
||||
#ifdef CONFIG_ESP_TLS_SERVER
|
||||
mbedtls_x509_crt_free(&tls->servercert);
|
||||
mbedtls_pk_free(&tls->serverkey);
|
||||
#endif
|
||||
mbedtls_x509_crt_free(&tls->cacert);
|
||||
mbedtls_x509_crt_free(&tls->clientcert);
|
||||
mbedtls_pk_free(&tls->clientkey);
|
||||
mbedtls_entropy_free(&tls->entropy);
|
||||
mbedtls_ssl_config_free(&tls->conf);
|
||||
mbedtls_ctr_drbg_free(&tls->ctr_drbg);
|
||||
mbedtls_ssl_free(&tls->ssl);
|
||||
}
|
||||
|
||||
static esp_err_t set_global_ca_store(esp_tls_t *tls)
|
||||
{
|
||||
assert(tls);
|
||||
if (global_cacert == NULL) {
|
||||
ESP_LOGE(TAG, "global_cacert is NULL");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
tls->cacert_ptr = global_cacert;
|
||||
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_ca_cert(esp_tls_t *tls, const unsigned char *cacert, size_t cacert_len)
|
||||
{
|
||||
assert(tls);
|
||||
tls->cacert_ptr = &tls->cacert;
|
||||
mbedtls_x509_crt_init(tls->cacert_ptr);
|
||||
int ret = mbedtls_x509_crt_parse(tls->cacert_ptr, cacert, cacert_len);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED;
|
||||
}
|
||||
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_pki_context(esp_tls_t *tls, const esp_tls_pki_t *pki)
|
||||
{
|
||||
assert(tls);
|
||||
assert(pki);
|
||||
int ret;
|
||||
|
||||
if (pki->publiccert_pem_buf != NULL &&
|
||||
pki->privkey_pem_buf != NULL &&
|
||||
pki->public_cert != NULL &&
|
||||
pki->pk_key != NULL) {
|
||||
|
||||
mbedtls_x509_crt_init(pki->public_cert);
|
||||
mbedtls_pk_init(pki->pk_key);
|
||||
|
||||
ret = mbedtls_x509_crt_parse(pki->public_cert, pki->publiccert_pem_buf, pki->publiccert_pem_bytes);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED;
|
||||
}
|
||||
|
||||
ret = mbedtls_pk_parse_key(pki->pk_key, pki->privkey_pem_buf, pki->privkey_pem_bytes,
|
||||
NULL, 0);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_pk_parse_keyfile returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED;
|
||||
}
|
||||
|
||||
ret = mbedtls_ssl_conf_own_cert(&tls->conf, pki->public_cert, pki->pk_key);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_conf_own_cert returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED;
|
||||
}
|
||||
} else {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_SERVER
|
||||
static esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(tls != NULL);
|
||||
int ret;
|
||||
esp_err_t esp_ret;
|
||||
if ((ret = mbedtls_ssl_config_defaults(&tls->conf,
|
||||
MBEDTLS_SSL_IS_SERVER,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_SSL_ALPN
|
||||
if (cfg->alpn_protos) {
|
||||
mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cfg->cacert_buf != NULL) {
|
||||
esp_ret = set_ca_cert(tls, cfg->cacert_buf, cfg->cacert_bytes);
|
||||
if (esp_ret != ESP_OK) {
|
||||
return esp_ret;
|
||||
}
|
||||
} else {
|
||||
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||
}
|
||||
|
||||
if (cfg->servercert_buf != NULL && cfg->serverkey_buf != NULL) {
|
||||
esp_tls_pki_t pki = {
|
||||
.public_cert = &tls->servercert,
|
||||
.pk_key = &tls->serverkey,
|
||||
.publiccert_pem_buf = cfg->servercert_buf,
|
||||
.publiccert_pem_bytes = cfg->servercert_bytes,
|
||||
.privkey_pem_buf = cfg->serverkey_buf,
|
||||
.privkey_pem_bytes = cfg->serverkey_bytes,
|
||||
.privkey_password = cfg->serverkey_password,
|
||||
.privkey_password_len = cfg->serverkey_password_len,
|
||||
};
|
||||
esp_ret = set_pki_context(tls, &pki);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set server pki context");
|
||||
return esp_ret;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Missing server certificate and/or key");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif /* ! CONFIG_ESP_TLS_SERVER */
|
||||
|
||||
static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t *cfg, esp_tls_t *tls)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(tls != NULL);
|
||||
int ret;
|
||||
if (!cfg->skip_common_name) {
|
||||
char *use_host = NULL;
|
||||
if (cfg->common_name != NULL) {
|
||||
use_host = strndup(cfg->common_name, strlen(cfg->common_name));
|
||||
} else {
|
||||
use_host = strndup(hostname, hostlen);
|
||||
}
|
||||
|
||||
if (use_host == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
/* Hostname set here should match CN in server certificate */
|
||||
if ((ret = mbedtls_ssl_set_hostname(&tls->ssl, use_host)) != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
free(use_host);
|
||||
return ESP_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED;
|
||||
}
|
||||
free(use_host);
|
||||
}
|
||||
|
||||
if ((ret = mbedtls_ssl_config_defaults(&tls->conf,
|
||||
MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_SSL_ALPN
|
||||
if (cfg->alpn_protos) {
|
||||
if ((ret =mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos) != 0)) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_conf_alpn_protocols returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (cfg->use_global_ca_store == true) {
|
||||
esp_err_t esp_ret = set_global_ca_store(tls);
|
||||
if (esp_ret != ESP_OK) {
|
||||
return esp_ret;
|
||||
}
|
||||
} else if (cfg->cacert_buf != NULL) {
|
||||
esp_err_t esp_ret = set_ca_cert(tls, cfg->cacert_buf, cfg->cacert_bytes);
|
||||
if (esp_ret != ESP_OK) {
|
||||
return esp_ret;
|
||||
}
|
||||
mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
|
||||
} else if (cfg->psk_hint_key) {
|
||||
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
|
||||
//
|
||||
// PSK encryption mode is configured only if no certificate supplied and psk pointer not null
|
||||
ESP_LOGD(TAG, "ssl psk authentication");
|
||||
ret = mbedtls_ssl_conf_psk(&tls->conf, cfg->psk_hint_key->key, cfg->psk_hint_key->key_size,
|
||||
(const unsigned char *)cfg->psk_hint_key->hint, strlen(cfg->psk_hint_key->hint));
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_conf_psk returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED;
|
||||
}
|
||||
#else
|
||||
ESP_LOGE(TAG, "psk_hint_key configured but not enabled in menuconfig: Please enable ESP_TLS_PSK_VERIFICATION option");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
#endif
|
||||
} else {
|
||||
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||
}
|
||||
|
||||
if (cfg->clientcert_buf != NULL && cfg->clientkey_buf != NULL) {
|
||||
esp_tls_pki_t pki = {
|
||||
.public_cert = &tls->clientcert,
|
||||
.pk_key = &tls->clientkey,
|
||||
.publiccert_pem_buf = cfg->clientcert_buf,
|
||||
.publiccert_pem_bytes = cfg->clientcert_bytes,
|
||||
.privkey_pem_buf = cfg->clientkey_buf,
|
||||
.privkey_pem_bytes = cfg->clientkey_bytes,
|
||||
.privkey_password = cfg->clientkey_password,
|
||||
.privkey_password_len = cfg->clientkey_password_len,
|
||||
};
|
||||
esp_err_t esp_ret = set_pki_context(tls, &pki);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set client pki context");
|
||||
return esp_ret;
|
||||
}
|
||||
} else if (cfg->clientcert_buf != NULL || cfg->clientkey_buf != NULL) {
|
||||
ESP_LOGE(TAG, "You have to provide both clientcert_buf and clientkey_buf for mutual authentication");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t create_ssl_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(tls != NULL);
|
||||
int ret;
|
||||
esp_err_t esp_ret;
|
||||
tls->server_fd.fd = tls->sockfd;
|
||||
mbedtls_ssl_init(&tls->ssl);
|
||||
mbedtls_ctr_drbg_init(&tls->ctr_drbg);
|
||||
mbedtls_ssl_config_init(&tls->conf);
|
||||
mbedtls_entropy_init(&tls->entropy);
|
||||
|
||||
if (tls->role == ESP_TLS_CLIENT) {
|
||||
esp_ret = set_client_config(hostname, hostlen, (esp_tls_cfg_t *)cfg, tls);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set client configurations");
|
||||
goto exit;
|
||||
}
|
||||
#ifdef CONFIG_ESP_TLS_SERVER
|
||||
} else if (tls->role == ESP_TLS_SERVER) {
|
||||
esp_ret = set_server_config((esp_tls_cfg_server_t *) cfg, tls);
|
||||
if (esp_ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to set server configurations");
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((ret = mbedtls_ctr_drbg_seed(&tls->ctr_drbg,
|
||||
mbedtls_entropy_func, &tls->entropy, NULL, 0)) != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
esp_ret = ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_rng(&tls->conf, mbedtls_ctr_drbg_random, &tls->ctr_drbg);
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_DEBUG
|
||||
mbedtls_esp_enable_debug_log(&tls->conf, CONFIG_MBEDTLS_DEBUG_LEVEL);
|
||||
#endif
|
||||
|
||||
if ((ret = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
esp_ret = ESP_ERR_MBEDTLS_SSL_SETUP_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
mbedtls_ssl_set_bio(&tls->ssl, &tls->server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
|
||||
return ESP_OK;
|
||||
exit:
|
||||
mbedtls_cleanup(tls);
|
||||
return esp_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close the TLS connection and free any allocated resources.
|
||||
*/
|
||||
void esp_tls_conn_delete(esp_tls_t *tls)
|
||||
{
|
||||
if (tls != NULL) {
|
||||
mbedtls_cleanup(tls);
|
||||
if (tls->is_tls) {
|
||||
mbedtls_net_free(&tls->server_fd);
|
||||
} else if (tls->sockfd >= 0) {
|
||||
close(tls->sockfd);
|
||||
}
|
||||
free(tls->error_handle);
|
||||
free(tls);
|
||||
}
|
||||
};
|
||||
|
||||
static ssize_t tcp_write(esp_tls_t *tls, const char *data, size_t datalen)
|
||||
{
|
||||
return send(tls->sockfd, data, datalen, 0);
|
||||
}
|
||||
|
||||
static ssize_t tls_write(esp_tls_t *tls, const char *data, size_t datalen)
|
||||
{
|
||||
size_t written = 0;
|
||||
size_t write_len = datalen;
|
||||
while (written < datalen) {
|
||||
if (write_len > MBEDTLS_SSL_OUT_CONTENT_LEN) {
|
||||
write_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
|
||||
}
|
||||
if (datalen > MBEDTLS_SSL_OUT_CONTENT_LEN) {
|
||||
ESP_LOGD(TAG, "Fragmenting data of excessive size :%d, offset: %d, size %d", datalen, written, write_len);
|
||||
}
|
||||
ssize_t ret = mbedtls_ssl_write(&tls->ssl, (unsigned char*) data + written, write_len);
|
||||
if (ret <= 0) {
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != 0) {
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_MBEDTLS_SSL_WRITE_FAILED);
|
||||
ESP_LOGE(TAG, "write error :%d:", ret);
|
||||
return ret;
|
||||
} else {
|
||||
// Exitting the tls-write process as less than desired datalen are writable
|
||||
ESP_LOGD(TAG, "mbedtls_ssl_write() returned %d, already written %d, exitting...", ret, written);
|
||||
return written;
|
||||
}
|
||||
}
|
||||
written += ret;
|
||||
write_len = datalen - written;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls)
|
||||
{
|
||||
if (!tls) {
|
||||
@ -586,101 +220,82 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c
|
||||
return -1;
|
||||
}
|
||||
esp_err_t esp_ret;
|
||||
int ret;
|
||||
|
||||
/* These states are used to keep a tab on connection progress in case of non-blocking connect,
|
||||
and in case of blocking connect these cases will get executed one after the other */
|
||||
switch (tls->conn_state) {
|
||||
case ESP_TLS_INIT:
|
||||
tls->sockfd = -1;
|
||||
if (cfg != NULL) {
|
||||
mbedtls_net_init(&tls->server_fd);
|
||||
tls->is_tls = true;
|
||||
}
|
||||
if ((esp_ret = esp_tcp_connect(hostname, hostlen, port, &tls->sockfd, tls, cfg)) != ESP_OK) {
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, esp_ret);
|
||||
return -1;
|
||||
}
|
||||
if (!cfg) {
|
||||
tls->read = tcp_read;
|
||||
tls->write = tcp_write;
|
||||
ESP_LOGD(TAG, "non-tls connection established");
|
||||
return 1;
|
||||
}
|
||||
if (cfg->non_block) {
|
||||
FD_ZERO(&tls->rset);
|
||||
FD_SET(tls->sockfd, &tls->rset);
|
||||
tls->wset = tls->rset;
|
||||
}
|
||||
tls->conn_state = ESP_TLS_CONNECTING;
|
||||
/* falls through */
|
||||
case ESP_TLS_CONNECTING:
|
||||
if (cfg->non_block) {
|
||||
ESP_LOGD(TAG, "connecting...");
|
||||
struct timeval tv;
|
||||
ms_to_timeval(cfg->timeout_ms, &tv);
|
||||
case ESP_TLS_INIT:
|
||||
tls->sockfd = -1;
|
||||
if (cfg != NULL) {
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
mbedtls_net_init(&tls->server_fd);
|
||||
#endif
|
||||
tls->is_tls = true;
|
||||
}
|
||||
if ((esp_ret = esp_tcp_connect(hostname, hostlen, port, &tls->sockfd, tls, cfg)) != ESP_OK) {
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, esp_ret);
|
||||
return -1;
|
||||
}
|
||||
if (!cfg) {
|
||||
tls->read = tcp_read;
|
||||
tls->write = tcp_write;
|
||||
ESP_LOGD(TAG, "non-tls connection established");
|
||||
return 1;
|
||||
}
|
||||
if (cfg->non_block) {
|
||||
FD_ZERO(&tls->rset);
|
||||
FD_SET(tls->sockfd, &tls->rset);
|
||||
tls->wset = tls->rset;
|
||||
}
|
||||
tls->conn_state = ESP_TLS_CONNECTING;
|
||||
/* falls through */
|
||||
case ESP_TLS_CONNECTING:
|
||||
if (cfg->non_block) {
|
||||
ESP_LOGD(TAG, "connecting...");
|
||||
struct timeval tv;
|
||||
ms_to_timeval(cfg->timeout_ms, &tv);
|
||||
|
||||
/* In case of non-blocking I/O, we use the select() API to check whether
|
||||
connection has been estbalished or not*/
|
||||
if (select(tls->sockfd + 1, &tls->rset, &tls->wset, NULL,
|
||||
cfg->timeout_ms ? &tv : NULL) == 0) {
|
||||
ESP_LOGD(TAG, "select() timed out");
|
||||
return 0;
|
||||
}
|
||||
if (FD_ISSET(tls->sockfd, &tls->rset) || FD_ISSET(tls->sockfd, &tls->wset)) {
|
||||
int error;
|
||||
unsigned int len = sizeof(error);
|
||||
/* pending error check */
|
||||
if (getsockopt(tls->sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
|
||||
ESP_LOGD(TAG, "Non blocking connect failed");
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_SYSTEM, errno);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED);
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* In case of non-blocking I/O, we use the select() API to check whether
|
||||
connection has been estbalished or not*/
|
||||
if (select(tls->sockfd + 1, &tls->rset, &tls->wset, NULL,
|
||||
cfg->timeout_ms ? &tv : NULL) == 0) {
|
||||
ESP_LOGD(TAG, "select() timed out");
|
||||
return 0;
|
||||
}
|
||||
/* By now, the connection has been established */
|
||||
esp_ret = create_ssl_handle(hostname, hostlen, cfg, tls);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "create_ssl_handle failed");
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, esp_ret);
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return -1;
|
||||
}
|
||||
tls->read = tls_read;
|
||||
tls->write = tls_write;
|
||||
tls->conn_state = ESP_TLS_HANDSHAKE;
|
||||
/* falls through */
|
||||
case ESP_TLS_HANDSHAKE:
|
||||
ESP_LOGD(TAG, "handshake in progress...");
|
||||
ret = mbedtls_ssl_handshake(&tls->ssl);
|
||||
if (ret == 0) {
|
||||
tls->conn_state = ESP_TLS_DONE;
|
||||
return 1;
|
||||
} else {
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED);
|
||||
if (cfg->cacert_buf != NULL || cfg->use_global_ca_store == true) {
|
||||
/* This is to check whether handshake failed due to invalid certificate*/
|
||||
verify_certificate(tls);
|
||||
}
|
||||
if (FD_ISSET(tls->sockfd, &tls->rset) || FD_ISSET(tls->sockfd, &tls->wset)) {
|
||||
int error;
|
||||
unsigned int len = sizeof(error);
|
||||
/* pending error check */
|
||||
if (getsockopt(tls->sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
|
||||
ESP_LOGD(TAG, "Non blocking connect failed");
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_SYSTEM, errno);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED);
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return -1;
|
||||
}
|
||||
/* Irrespective of blocking or non-blocking I/O, we return on getting MBEDTLS_ERR_SSL_WANT_READ
|
||||
or MBEDTLS_ERR_SSL_WANT_WRITE during handshake */
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case ESP_TLS_FAIL:
|
||||
ESP_LOGE(TAG, "failed to open a new connection");;
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "invalid esp-tls state");
|
||||
break;
|
||||
}
|
||||
/* By now, the connection has been established */
|
||||
esp_ret = create_ssl_handle(hostname, hostlen, cfg, tls);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "create_ssl_handle failed");
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, esp_ret);
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return -1;
|
||||
}
|
||||
tls->read = _esp_tls_read;
|
||||
tls->write = _esp_tls_write;
|
||||
tls->conn_state = ESP_TLS_HANDSHAKE;
|
||||
/* falls through */
|
||||
case ESP_TLS_HANDSHAKE:
|
||||
ESP_LOGD(TAG, "handshake in progress...");
|
||||
return esp_tls_handshake(tls, cfg);
|
||||
break;
|
||||
case ESP_TLS_FAIL:
|
||||
ESP_LOGE(TAG, "failed to open a new connection");;
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "invalid esp-tls state");
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -728,7 +343,7 @@ int esp_tls_conn_new_sync(const char *hostname, int hostlen, int port, const esp
|
||||
/*
|
||||
* @brief Create a new TLS/SSL non-blocking connection
|
||||
*/
|
||||
int esp_tls_conn_new_async(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg , esp_tls_t *tls)
|
||||
int esp_tls_conn_new_async(const char *hostname, int hostlen, int port, const esp_tls_cfg_t *cfg, esp_tls_t *tls)
|
||||
{
|
||||
return esp_tls_low_level_conn(hostname, hostlen, port, cfg, tls);
|
||||
}
|
||||
@ -757,24 +372,17 @@ esp_tls_t *esp_tls_conn_http_new(const char *url, const esp_tls_cfg_t *cfg)
|
||||
http_parser_url_init(&u);
|
||||
http_parser_parse_url(url, strlen(url), 0, &u);
|
||||
esp_tls_t *tls = esp_tls_init();
|
||||
if (!tls) return NULL;
|
||||
if (!tls) {
|
||||
return NULL;
|
||||
}
|
||||
/* Connect to host */
|
||||
if (esp_tls_conn_new_sync(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len,
|
||||
get_port(url, &u), cfg, tls) == 1) {
|
||||
get_port(url, &u), cfg, tls) == 1) {
|
||||
return tls;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t esp_tls_get_bytes_avail(esp_tls_t *tls)
|
||||
{
|
||||
if (!tls) {
|
||||
ESP_LOGE(TAG, "empty arg passed to esp_tls_get_bytes_avail()");
|
||||
return -1;
|
||||
}
|
||||
return mbedtls_ssl_get_bytes_avail(&tls->ssl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a new non-blocking TLS/SSL connection with a given "HTTP" url
|
||||
*/
|
||||
@ -787,78 +395,66 @@ int esp_tls_conn_http_new_async(const char *url, const esp_tls_cfg_t *cfg, esp_t
|
||||
|
||||
/* Connect to host */
|
||||
return esp_tls_conn_new_async(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len,
|
||||
get_port(url, &u), cfg, tls);
|
||||
get_port(url, &u), cfg, tls);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
|
||||
mbedtls_x509_crt *esp_tls_get_global_ca_store(void)
|
||||
{
|
||||
return _esp_tls_get_global_ca_store();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_SERVER
|
||||
/**
|
||||
* @brief Create TLS/SSL server session
|
||||
* @brief Create a server side TLS/SSL connection
|
||||
*/
|
||||
int esp_tls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls)
|
||||
{
|
||||
if (tls == NULL || cfg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
tls->role = ESP_TLS_SERVER;
|
||||
tls->sockfd = sockfd;
|
||||
esp_err_t esp_ret = create_ssl_handle(NULL, 0, cfg, tls);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "create_ssl_handle failed");
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, esp_ret);
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return -1;
|
||||
}
|
||||
tls->read = tls_read;
|
||||
tls->write = tls_write;
|
||||
int ret;
|
||||
while ((ret = mbedtls_ssl_handshake(&tls->ssl)) != 0) {
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_handshake returned %d", ret);
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return _esp_tls_server_session_create(cfg, sockfd, tls);
|
||||
}
|
||||
/**
|
||||
* @brief Close the server side TLS/SSL connection and free any allocated resources.
|
||||
*/
|
||||
void esp_tls_server_session_delete(esp_tls_t *tls)
|
||||
{
|
||||
if (tls != NULL) {
|
||||
mbedtls_cleanup(tls);
|
||||
free(tls);
|
||||
}
|
||||
};
|
||||
#endif /* ! CONFIG_ESP_TLS_SERVER */
|
||||
return _esp_tls_server_session_delete(tls);
|
||||
}
|
||||
#endif /* CONFIG_ESP_TLS_SERVER */
|
||||
#endif /* CONFIG_ESP_TLS_USING_MBEDTLS */
|
||||
|
||||
esp_tls_t *esp_tls_init(void)
|
||||
ssize_t esp_tls_get_bytes_avail(esp_tls_t *tls)
|
||||
{
|
||||
esp_tls_t *tls = (esp_tls_t *)calloc(1, sizeof(esp_tls_t));
|
||||
if (!tls) {
|
||||
return NULL;
|
||||
}
|
||||
tls->error_handle = calloc(1, sizeof(esp_tls_last_error_t));
|
||||
if (!tls->error_handle) {
|
||||
free(tls);
|
||||
return NULL;
|
||||
}
|
||||
tls->server_fd.fd = tls->sockfd = -1;
|
||||
return tls;
|
||||
return _esp_tls_get_bytes_avail(tls);
|
||||
}
|
||||
|
||||
esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *mbedtls_code, int *mbedtls_flags)
|
||||
esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *esp_tls_code, int *esp_tls_flags)
|
||||
{
|
||||
if (!h) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
esp_err_t last_err = h->last_error;
|
||||
if (mbedtls_code) {
|
||||
*mbedtls_code = h->mbedtls_error_code;
|
||||
if (esp_tls_code) {
|
||||
*esp_tls_code = h->esp_tls_error_code;
|
||||
}
|
||||
if (mbedtls_flags) {
|
||||
*mbedtls_flags = h->mbedtls_flags;
|
||||
if (esp_tls_flags) {
|
||||
*esp_tls_flags = h->esp_tls_flags;
|
||||
}
|
||||
memset(h, 0, sizeof(esp_tls_last_error_t));
|
||||
return last_err;
|
||||
}
|
||||
|
||||
esp_err_t esp_tls_init_global_ca_store(void)
|
||||
{
|
||||
return _esp_tls_init_global_ca_store();
|
||||
}
|
||||
|
||||
esp_err_t esp_tls_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes)
|
||||
{
|
||||
return _esp_tls_set_global_ca_store(cacert_pem_buf, cacert_pem_bytes);
|
||||
}
|
||||
|
||||
void esp_tls_free_global_ca_store(void)
|
||||
{
|
||||
return _esp_tls_free_global_ca_store();
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/net_sockets.h"
|
||||
#include "mbedtls/esp_debug.h"
|
||||
@ -27,6 +27,10 @@
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/certs.h"
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL
|
||||
#include "wolfssl/wolfcrypt/settings.h"
|
||||
#include "wolfssl/ssl.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -58,8 +62,8 @@ typedef struct esp_tls_last_error* esp_tls_error_handle_t;
|
||||
*/
|
||||
typedef struct esp_tls_last_error {
|
||||
esp_err_t last_error; /*!< error code (based on ESP_ERR_ESP_TLS_BASE) of the last occurred error */
|
||||
int mbedtls_error_code; /*!< mbedtls error code from last mbedtls failed api */
|
||||
int mbedtls_flags; /*!< last certification verification flags */
|
||||
int esp_tls_error_code; /*!< esp_tls error code from last esp_tls failed api */
|
||||
int esp_tls_flags; /*!< last certification verification flags */
|
||||
} esp_tls_last_error_t;
|
||||
|
||||
/**
|
||||
@ -236,6 +240,7 @@ typedef struct esp_tls_cfg_server {
|
||||
* @brief ESP-TLS Connection Handle
|
||||
*/
|
||||
typedef struct esp_tls {
|
||||
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
mbedtls_ssl_context ssl; /*!< TLS/SSL context */
|
||||
|
||||
mbedtls_entropy_context entropy; /*!< mbedTLS entropy context structure */
|
||||
@ -263,6 +268,10 @@ typedef struct esp_tls {
|
||||
|
||||
mbedtls_pk_context serverkey; /*!< Container for the private key of the server
|
||||
certificate */
|
||||
#endif
|
||||
#elif CONFIG_ESP_TLS_USING_WOLFSSL
|
||||
void *priv_ctx;
|
||||
void *priv_ssl;
|
||||
#endif
|
||||
int sockfd; /*!< Underlying socket file descriptor. */
|
||||
|
||||
@ -491,20 +500,6 @@ esp_err_t esp_tls_init_global_ca_store(void);
|
||||
*/
|
||||
esp_err_t esp_tls_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes);
|
||||
|
||||
/**
|
||||
* @brief Get the pointer to the global CA store currently being used.
|
||||
*
|
||||
* The application must first call esp_tls_set_global_ca_store(). Then the same
|
||||
* CA store could be used by the application for APIs other than esp_tls.
|
||||
*
|
||||
* @note Modifying the pointer might cause a failure in verifying the certificates.
|
||||
*
|
||||
* @return
|
||||
* - Pointer to the global CA store currently being used if successful.
|
||||
* - NULL if there is no global CA store set.
|
||||
*/
|
||||
mbedtls_x509_crt *esp_tls_get_global_ca_store(void);
|
||||
|
||||
/**
|
||||
* @brief Free the global CA store currently being used.
|
||||
*
|
||||
@ -518,17 +513,32 @@ void esp_tls_free_global_ca_store(void);
|
||||
* The error information is cleared internally upon return
|
||||
*
|
||||
* @param[in] h esp-tls error handle.
|
||||
* @param[out] mbedtls_code last error code returned from mbedtls api (set to zero if none)
|
||||
* This pointer could be NULL if caller does not care about mbedtls_code
|
||||
* @param[out] mbedtls_flags last certification verification flags (set to zero if none)
|
||||
* This pointer could be NULL if caller does not care about mbedtls_flags
|
||||
* @param[out] esp_tls_code last error code returned from mbedtls api (set to zero if none)
|
||||
* This pointer could be NULL if caller does not care about esp_tls_code
|
||||
* @param[out] esp_tls_flags last certification verification flags (set to zero if none)
|
||||
* This pointer could be NULL if caller does not care about esp_tls_code
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_STATE if invalid parameters
|
||||
* - ESP_OK (0) if no error occurred
|
||||
* - specific error code (based on ESP_ERR_ESP_TLS_BASE) otherwise
|
||||
*/
|
||||
esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *mbedtls_code, int *mbedtls_flags);
|
||||
esp_err_t esp_tls_get_and_clear_last_error(esp_tls_error_handle_t h, int *esp_tls_code, int *esp_tls_flags);
|
||||
|
||||
#if CONFIG_ESP_TLS_USING_MBEDTLS
|
||||
/**
|
||||
* @brief Get the pointer to the global CA store currently being used.
|
||||
*
|
||||
* The application must first call esp_tls_set_global_ca_store(). Then the same
|
||||
* CA store could be used by the application for APIs other than esp_tls.
|
||||
*
|
||||
* @note Modifying the pointer might cause a failure in verifying the certificates.
|
||||
*
|
||||
* @return
|
||||
* - Pointer to the global CA store currently being used if successful.
|
||||
* - NULL if there is no global CA store set.
|
||||
*/
|
||||
mbedtls_x509_crt *esp_tls_get_global_ca_store(void);
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_SERVER
|
||||
/**
|
||||
@ -557,6 +567,7 @@ int esp_tls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls
|
||||
*/
|
||||
void esp_tls_server_session_delete(esp_tls_t *tls);
|
||||
#endif /* ! CONFIG_ESP_TLS_SERVER */
|
||||
#endif /* CONFIG_ESP_TLS_USING_MBEDTLS */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
547
components/esp-tls/esp_tls_mbedtls.c
Normal file
547
components/esp-tls/esp_tls_mbedtls.c
Normal file
@ -0,0 +1,547 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <http_parser.h>
|
||||
#include "esp_tls_mbedtls.h"
|
||||
#include "esp_tls_error_capture_internal.h"
|
||||
#include <errno.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "esp-tls-mbedtls";
|
||||
static mbedtls_x509_crt *global_cacert = NULL;
|
||||
|
||||
typedef struct esp_tls_pki_t {
|
||||
mbedtls_x509_crt *public_cert;
|
||||
mbedtls_pk_context *pk_key;
|
||||
const unsigned char *publiccert_pem_buf;
|
||||
unsigned int publiccert_pem_bytes;
|
||||
const unsigned char *privkey_pem_buf;
|
||||
unsigned int privkey_pem_bytes;
|
||||
const unsigned char *privkey_password;
|
||||
unsigned int privkey_password_len;
|
||||
} esp_tls_pki_t;
|
||||
|
||||
esp_err_t esp_create_mbedtls_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(tls != NULL);
|
||||
int ret;
|
||||
esp_err_t esp_ret = ESP_FAIL;
|
||||
tls->server_fd.fd = tls->sockfd;
|
||||
mbedtls_ssl_init(&tls->ssl);
|
||||
mbedtls_ctr_drbg_init(&tls->ctr_drbg);
|
||||
mbedtls_ssl_config_init(&tls->conf);
|
||||
mbedtls_entropy_init(&tls->entropy);
|
||||
|
||||
if (tls->role == ESP_TLS_CLIENT) {
|
||||
esp_ret = set_client_config(hostname, hostlen, (esp_tls_cfg_t *)cfg, tls);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set client configurations");
|
||||
goto exit;
|
||||
}
|
||||
} else if (tls->role == ESP_TLS_SERVER) {
|
||||
#ifdef CONFIG_ESP_TLS_SERVER
|
||||
esp_ret = set_server_config((esp_tls_cfg_server_t *) cfg, tls);
|
||||
if (esp_ret != 0) {
|
||||
ESP_LOGE(TAG, "Failed to set server configurations");
|
||||
goto exit;
|
||||
}
|
||||
#else
|
||||
ESP_LOGE(TAG, "ESP_TLS_SERVER Not enabled in Kconfig");
|
||||
goto exit;
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((ret = mbedtls_ctr_drbg_seed(&tls->ctr_drbg,
|
||||
mbedtls_entropy_func, &tls->entropy, NULL, 0)) != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
esp_ret = ESP_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_rng(&tls->conf, mbedtls_ctr_drbg_random, &tls->ctr_drbg);
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_DEBUG
|
||||
mbedtls_esp_enable_debug_log(&tls->conf, CONFIG_MBEDTLS_DEBUG_LEVEL);
|
||||
#endif
|
||||
|
||||
if ((ret = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
esp_ret = ESP_ERR_MBEDTLS_SSL_SETUP_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
mbedtls_ssl_set_bio(&tls->ssl, &tls->server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
exit:
|
||||
esp_mbedtls_cleanup(tls);
|
||||
return esp_ret;
|
||||
|
||||
}
|
||||
|
||||
int esp_mbedtls_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
ret = mbedtls_ssl_handshake(&tls->ssl);
|
||||
if (ret == 0) {
|
||||
tls->conn_state = ESP_TLS_DONE;
|
||||
return 1;
|
||||
} else {
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED);
|
||||
if (cfg->cacert_buf != NULL || cfg->use_global_ca_store == true) {
|
||||
/* This is to check whether handshake failed due to invalid certificate*/
|
||||
esp_mbedtls_verify_certificate(tls);
|
||||
}
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return -1;
|
||||
}
|
||||
/* Irrespective of blocking or non-blocking I/O, we return on getting MBEDTLS_ERR_SSL_WANT_READ
|
||||
or MBEDTLS_ERR_SSL_WANT_WRITE during handshake */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t esp_mbedtls_read(esp_tls_t *tls, char *data, size_t datalen)
|
||||
{
|
||||
|
||||
ssize_t ret = mbedtls_ssl_read(&tls->ssl, (unsigned char *)data, datalen);
|
||||
if (ret < 0) {
|
||||
if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
|
||||
return 0;
|
||||
}
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
ESP_LOGE(TAG, "read error :%d:", ret);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t esp_mbedtls_write(esp_tls_t *tls, const char *data, size_t datalen)
|
||||
{
|
||||
size_t written = 0;
|
||||
size_t write_len = datalen;
|
||||
while (written < datalen) {
|
||||
if (write_len > MBEDTLS_SSL_OUT_CONTENT_LEN) {
|
||||
write_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
|
||||
}
|
||||
if (datalen > MBEDTLS_SSL_OUT_CONTENT_LEN) {
|
||||
ESP_LOGD(TAG, "Fragmenting data of excessive size :%d, offset: %d, size %d", datalen, written, write_len);
|
||||
}
|
||||
ssize_t ret = mbedtls_ssl_write(&tls->ssl, (unsigned char*) data + written, write_len);
|
||||
if (ret <= 0) {
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != 0) {
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, ESP_ERR_MBEDTLS_SSL_WRITE_FAILED);
|
||||
ESP_LOGE(TAG, "write error :%d:", ret);
|
||||
return ret;
|
||||
} else {
|
||||
// Exitting the tls-write process as less than desired datalen are writable
|
||||
ESP_LOGD(TAG, "mbedtls_ssl_write() returned %d, already written %d, exitting...", ret, written);
|
||||
return written;
|
||||
}
|
||||
}
|
||||
written += ret;
|
||||
write_len = datalen - written;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
void esp_mbedtls_conn_delete(esp_tls_t *tls)
|
||||
{
|
||||
if (tls != NULL) {
|
||||
esp_mbedtls_cleanup(tls);
|
||||
if (tls->is_tls) {
|
||||
mbedtls_net_free(&tls->server_fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void esp_mbedtls_verify_certificate(esp_tls_t *tls)
|
||||
{
|
||||
int flags;
|
||||
char buf[100];
|
||||
if ((flags = mbedtls_ssl_get_verify_result(&tls->ssl)) != 0) {
|
||||
ESP_LOGI(TAG, "Failed to verify peer certificate!");
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS_CERT_FLAGS, flags);
|
||||
bzero(buf, sizeof(buf));
|
||||
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
|
||||
ESP_LOGI(TAG, "verification info: %s", buf);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Certificate verified.");
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t esp_mbedtls_get_bytes_avail(esp_tls_t *tls)
|
||||
{
|
||||
if (!tls) {
|
||||
ESP_LOGE(TAG, "empty arg passed to esp_tls_get_bytes_avail()");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return mbedtls_ssl_get_bytes_avail(&tls->ssl);
|
||||
}
|
||||
|
||||
void esp_mbedtls_cleanup(esp_tls_t *tls)
|
||||
{
|
||||
if (!tls) {
|
||||
return;
|
||||
}
|
||||
if (tls->cacert_ptr != global_cacert) {
|
||||
mbedtls_x509_crt_free(tls->cacert_ptr);
|
||||
}
|
||||
tls->cacert_ptr = NULL;
|
||||
#ifdef CONFIG_ESP_TLS_SERVER
|
||||
mbedtls_x509_crt_free(&tls->servercert);
|
||||
mbedtls_pk_free(&tls->serverkey);
|
||||
#endif
|
||||
mbedtls_x509_crt_free(&tls->cacert);
|
||||
mbedtls_x509_crt_free(&tls->clientcert);
|
||||
mbedtls_pk_free(&tls->clientkey);
|
||||
mbedtls_entropy_free(&tls->entropy);
|
||||
mbedtls_ssl_config_free(&tls->conf);
|
||||
mbedtls_ctr_drbg_free(&tls->ctr_drbg);
|
||||
mbedtls_ssl_free(&tls->ssl);
|
||||
}
|
||||
|
||||
static esp_err_t set_ca_cert(esp_tls_t *tls, const unsigned char *cacert, size_t cacert_len)
|
||||
{
|
||||
assert(tls);
|
||||
tls->cacert_ptr = &tls->cacert;
|
||||
mbedtls_x509_crt_init(tls->cacert_ptr);
|
||||
int ret = mbedtls_x509_crt_parse(tls->cacert_ptr, cacert, cacert_len);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED;
|
||||
}
|
||||
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_pki_context(esp_tls_t *tls, const esp_tls_pki_t *pki)
|
||||
{
|
||||
assert(tls);
|
||||
assert(pki);
|
||||
int ret;
|
||||
|
||||
if (pki->publiccert_pem_buf != NULL &&
|
||||
pki->privkey_pem_buf != NULL &&
|
||||
pki->public_cert != NULL &&
|
||||
pki->pk_key != NULL) {
|
||||
|
||||
mbedtls_x509_crt_init(pki->public_cert);
|
||||
mbedtls_pk_init(pki->pk_key);
|
||||
|
||||
ret = mbedtls_x509_crt_parse(pki->public_cert, pki->publiccert_pem_buf, pki->publiccert_pem_bytes);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED;
|
||||
}
|
||||
|
||||
ret = mbedtls_pk_parse_key(pki->pk_key, pki->privkey_pem_buf, pki->privkey_pem_bytes,
|
||||
NULL, 0);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_pk_parse_keyfile returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED;
|
||||
}
|
||||
|
||||
ret = mbedtls_ssl_conf_own_cert(&tls->conf, pki->public_cert, pki->pk_key);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_conf_own_cert returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED;
|
||||
}
|
||||
} else {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_global_ca_store(esp_tls_t *tls)
|
||||
{
|
||||
assert(tls);
|
||||
if (global_cacert == NULL) {
|
||||
ESP_LOGE(TAG, "global_cacert is NULL");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
tls->cacert_ptr = global_cacert;
|
||||
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_SERVER
|
||||
esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(tls != NULL);
|
||||
int ret;
|
||||
esp_err_t esp_ret;
|
||||
if ((ret = mbedtls_ssl_config_defaults(&tls->conf,
|
||||
MBEDTLS_SSL_IS_SERVER,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_SSL_ALPN
|
||||
if (cfg->alpn_protos) {
|
||||
mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cfg->cacert_buf != NULL) {
|
||||
esp_ret = set_ca_cert(tls, cfg->cacert_buf, cfg->cacert_bytes);
|
||||
if (esp_ret != ESP_OK) {
|
||||
return esp_ret;
|
||||
}
|
||||
} else {
|
||||
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||
}
|
||||
|
||||
if (cfg->servercert_buf != NULL && cfg->serverkey_buf != NULL) {
|
||||
esp_tls_pki_t pki = {
|
||||
.public_cert = &tls->servercert,
|
||||
.pk_key = &tls->serverkey,
|
||||
.publiccert_pem_buf = cfg->servercert_buf,
|
||||
.publiccert_pem_bytes = cfg->servercert_bytes,
|
||||
.privkey_pem_buf = cfg->serverkey_buf,
|
||||
.privkey_pem_bytes = cfg->serverkey_bytes,
|
||||
.privkey_password = cfg->serverkey_password,
|
||||
.privkey_password_len = cfg->serverkey_password_len,
|
||||
};
|
||||
esp_ret = set_pki_context(tls, &pki);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set server pki context");
|
||||
return esp_ret;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Missing server certificate and/or key");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif /* ! CONFIG_ESP_TLS_SERVER */
|
||||
|
||||
esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t *cfg, esp_tls_t *tls)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(tls != NULL);
|
||||
int ret;
|
||||
if (!cfg->skip_common_name) {
|
||||
char *use_host = NULL;
|
||||
if (cfg->common_name != NULL) {
|
||||
use_host = strndup(cfg->common_name, strlen(cfg->common_name));
|
||||
} else {
|
||||
use_host = strndup(hostname, hostlen);
|
||||
}
|
||||
|
||||
if (use_host == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
/* Hostname set here should match CN in server certificate */
|
||||
if ((ret = mbedtls_ssl_set_hostname(&tls->ssl, use_host)) != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
free(use_host);
|
||||
return ESP_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED;
|
||||
}
|
||||
free(use_host);
|
||||
}
|
||||
|
||||
if ((ret = mbedtls_ssl_config_defaults(&tls->conf,
|
||||
MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_SSL_ALPN
|
||||
if (cfg->alpn_protos) {
|
||||
if ((ret = mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos) != 0)) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_conf_alpn_protocols returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (cfg->use_global_ca_store == true) {
|
||||
esp_err_t esp_ret = set_global_ca_store(tls);
|
||||
if (esp_ret != ESP_OK) {
|
||||
return esp_ret;
|
||||
}
|
||||
} else if (cfg->cacert_buf != NULL) {
|
||||
esp_err_t esp_ret = set_ca_cert(tls, cfg->cacert_buf, cfg->cacert_bytes);
|
||||
if (esp_ret != ESP_OK) {
|
||||
return esp_ret;
|
||||
}
|
||||
mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
|
||||
} else if (cfg->psk_hint_key) {
|
||||
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
|
||||
//
|
||||
// PSK encryption mode is configured only if no certificate supplied and psk pointer not null
|
||||
ESP_LOGD(TAG, "ssl psk authentication");
|
||||
ret = mbedtls_ssl_conf_psk(&tls->conf, cfg->psk_hint_key->key, cfg->psk_hint_key->key_size,
|
||||
(const unsigned char *)cfg->psk_hint_key->hint, strlen(cfg->psk_hint_key->hint));
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_conf_psk returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED;
|
||||
}
|
||||
#else
|
||||
ESP_LOGE(TAG, "psk_hint_key configured but not enabled in menuconfig: Please enable ESP_TLS_PSK_VERIFICATION option");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
#endif
|
||||
} else {
|
||||
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||
}
|
||||
|
||||
if (cfg->clientcert_buf != NULL && cfg->clientkey_buf != NULL) {
|
||||
esp_tls_pki_t pki = {
|
||||
.public_cert = &tls->clientcert,
|
||||
.pk_key = &tls->clientkey,
|
||||
.publiccert_pem_buf = cfg->clientcert_buf,
|
||||
.publiccert_pem_bytes = cfg->clientcert_bytes,
|
||||
.privkey_pem_buf = cfg->clientkey_buf,
|
||||
.privkey_pem_bytes = cfg->clientkey_bytes,
|
||||
.privkey_password = cfg->clientkey_password,
|
||||
.privkey_password_len = cfg->clientkey_password_len,
|
||||
};
|
||||
esp_err_t esp_ret = set_pki_context(tls, &pki);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set client pki context");
|
||||
return esp_ret;
|
||||
}
|
||||
} else if (cfg->clientcert_buf != NULL || cfg->clientkey_buf != NULL) {
|
||||
ESP_LOGE(TAG, "You have to provide both clientcert_buf and clientkey_buf for mutual authentication");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_SERVER
|
||||
/**
|
||||
* @brief Create TLS/SSL server session
|
||||
*/
|
||||
int esp_mbedtls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls)
|
||||
{
|
||||
if (tls == NULL || cfg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
tls->role = ESP_TLS_SERVER;
|
||||
tls->sockfd = sockfd;
|
||||
esp_err_t esp_ret = esp_create_mbedtls_handle(NULL, 0, cfg, tls);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "create_ssl_handle failed");
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_ESP, esp_ret);
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return -1;
|
||||
}
|
||||
tls->read = esp_mbedtls_read;
|
||||
tls->write = esp_mbedtls_write;
|
||||
int ret;
|
||||
while ((ret = mbedtls_ssl_handshake(&tls->ssl)) != 0) {
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_handshake returned %d", ret);
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @brief Close the server side TLS/SSL connection and free any allocated resources.
|
||||
*/
|
||||
void esp_mbedtls_server_session_delete(esp_tls_t *tls)
|
||||
{
|
||||
if (tls != NULL) {
|
||||
esp_mbedtls_cleanup(tls);
|
||||
free(tls);
|
||||
}
|
||||
};
|
||||
#endif /* ! CONFIG_ESP_TLS_SERVER */
|
||||
|
||||
esp_err_t esp_mbedtls_init_global_ca_store(void)
|
||||
{
|
||||
if (global_cacert == NULL) {
|
||||
global_cacert = (mbedtls_x509_crt *)calloc(1, sizeof(mbedtls_x509_crt));
|
||||
if (global_cacert == NULL) {
|
||||
ESP_LOGE(TAG, "global_cacert not allocated");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
mbedtls_x509_crt_init(global_cacert);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_mbedtls_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes)
|
||||
{
|
||||
if (cacert_pem_buf == NULL) {
|
||||
ESP_LOGE(TAG, "cacert_pem_buf is null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
int ret;
|
||||
if (global_cacert == NULL) {
|
||||
ret = esp_mbedtls_init_global_ca_store();
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = mbedtls_x509_crt_parse(global_cacert, cacert_pem_buf, cacert_pem_bytes);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x", -ret);
|
||||
mbedtls_x509_crt_free(global_cacert);
|
||||
global_cacert = NULL;
|
||||
return ESP_FAIL;
|
||||
} else if (ret > 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_x509_crt_parse was partly successful. No. of failed certificates: %d", ret);
|
||||
return ESP_ERR_MBEDTLS_CERT_PARTLY_OK;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
mbedtls_x509_crt *esp_mbedtls_get_global_ca_store(void)
|
||||
{
|
||||
return global_cacert;
|
||||
}
|
||||
|
||||
void esp_mbedtls_free_global_ca_store(void)
|
||||
{
|
||||
if (global_cacert) {
|
||||
mbedtls_x509_crt_free(global_cacert);
|
||||
global_cacert = NULL;
|
||||
}
|
||||
}
|
244
components/esp-tls/esp_tls_wolfssl.c
Normal file
244
components/esp-tls/esp_tls_wolfssl.c
Normal file
@ -0,0 +1,244 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <http_parser.h>
|
||||
#include "esp_tls_wolfssl.h"
|
||||
#include "esp_tls_error_capture_internal.h"
|
||||
#include <errno.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
static unsigned char *global_cacert = NULL;
|
||||
static unsigned int global_cacert_pem_bytes = 0;
|
||||
static const char *TAG = "esp-tls-wolfssl";
|
||||
|
||||
int esp_create_wolfssl_handle(const char *hostname, size_t hostlen, const void *cfg1, esp_tls_t *tls)
|
||||
{
|
||||
#ifdef CONFIG_ESP_DEBUG_WOLFSSL
|
||||
wolfSSL_Debugging_ON();
|
||||
#endif
|
||||
const esp_tls_cfg_t *cfg = cfg1;
|
||||
assert(cfg != NULL);
|
||||
assert(tls != NULL);
|
||||
|
||||
int ret;
|
||||
ret = wolfSSL_Init();
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Init wolfSSL failed: %d", ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_WOLFSSL, -ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
tls->priv_ctx = (void *)wolfSSL_CTX_new(wolfTLSv1_2_client_method());
|
||||
if (!tls->priv_ctx) {
|
||||
ESP_LOGE(TAG, "Set wolfSSL ctx failed");
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_WOLFSSL, -ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ALPN
|
||||
if (cfg->alpn_protos) {
|
||||
char **alpn_list = (char **)cfg->alpn_protos;
|
||||
for (; *alpn_list != NULL; alpn_list ++) {
|
||||
if (wolfSSL_UseALPN( (WOLFSSL *)tls->priv_ssl, *alpn_list, strlen(*alpn_list), WOLFSSL_ALPN_FAILED_ON_MISMATCH) != WOLFSSL_SUCCESS) {
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_WOLFSSL, -ret);
|
||||
ESP_LOGE(TAG, "Use wolfSSL ALPN failed");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( cfg->use_global_ca_store == true) {
|
||||
wolfSSL_CTX_load_verify_buffer( (WOLFSSL_CTX *)tls->priv_ctx, global_cacert, global_cacert_pem_bytes, WOLFSSL_FILETYPE_PEM);
|
||||
wolfSSL_CTX_set_verify( (WOLFSSL_CTX *)tls->priv_ctx, SSL_VERIFY_PEER, NULL);
|
||||
} else if (cfg->cacert_pem_buf != NULL) {
|
||||
wolfSSL_CTX_load_verify_buffer( (WOLFSSL_CTX *)tls->priv_ctx, cfg->cacert_pem_buf, cfg->cacert_pem_bytes, WOLFSSL_FILETYPE_PEM);
|
||||
wolfSSL_CTX_set_verify( (WOLFSSL_CTX *)tls->priv_ctx, SSL_VERIFY_PEER, NULL);
|
||||
} else if (cfg->psk_hint_key) {
|
||||
ESP_LOGE(TAG,"psk_hint_key not supported in wolfssl");
|
||||
goto exit;
|
||||
} else {
|
||||
wolfSSL_CTX_set_verify( (WOLFSSL_CTX *)tls->priv_ctx, SSL_VERIFY_NONE, NULL);
|
||||
}
|
||||
|
||||
if (cfg->clientcert_pem_buf != NULL && cfg->clientkey_pem_buf != NULL) {
|
||||
wolfSSL_CTX_use_certificate_buffer( (WOLFSSL_CTX *)tls->priv_ctx, cfg->clientcert_pem_buf, cfg->clientcert_pem_bytes, WOLFSSL_FILETYPE_PEM);
|
||||
wolfSSL_CTX_use_PrivateKey_buffer( (WOLFSSL_CTX *)tls->priv_ctx, cfg->clientkey_pem_buf, cfg->clientkey_pem_bytes, WOLFSSL_FILETYPE_PEM);
|
||||
} else if (cfg->clientcert_pem_buf != NULL || cfg->clientkey_pem_buf != NULL) {
|
||||
ESP_LOGE(TAG, "You have to provide both clientcert_pem_buf and clientkey_pem_buf for mutual authentication\n\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
tls->priv_ssl =(void *)wolfSSL_new( (WOLFSSL_CTX *)tls->priv_ctx);
|
||||
if (!tls->priv_ssl) {
|
||||
ESP_LOGE(TAG, "Create wolfSSL failed");
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_WOLFSSL, -ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SNI
|
||||
/* Hostname set here should match CN in server certificate */
|
||||
char *use_host = strndup(hostname, hostlen);
|
||||
if (!use_host) {
|
||||
goto exit;
|
||||
}
|
||||
wolfSSL_set_tlsext_host_name( (WOLFSSL *)tls->priv_ssl, use_host);
|
||||
free(use_host);
|
||||
#endif
|
||||
|
||||
wolfSSL_set_fd((WOLFSSL *)tls->priv_ssl, tls->sockfd);
|
||||
return 0;
|
||||
exit:
|
||||
esp_wolfssl_cleanup(tls);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int esp_wolfssl_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
ret = wolfSSL_connect( (WOLFSSL *)tls->priv_ssl);
|
||||
if (ret == WOLFSSL_SUCCESS) {
|
||||
tls->conn_state = ESP_TLS_DONE;
|
||||
return 1;
|
||||
} else {
|
||||
int err = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
if (err != WOLFSSL_ERROR_WANT_READ && err != WOLFSSL_ERROR_WANT_WRITE) {
|
||||
ESP_LOGE(TAG, "wolfSSL_connect returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_WOLFSSL, -ret);
|
||||
|
||||
if (cfg->cacert_pem_buf != NULL || cfg->use_global_ca_store == true) {
|
||||
/* This is to check whether handshake failed due to invalid certificate*/
|
||||
esp_wolfssl_verify_certificate(tls);
|
||||
}
|
||||
tls->conn_state = ESP_TLS_FAIL;
|
||||
return -1;
|
||||
}
|
||||
/* Irrespective of blocking or non-blocking I/O, we return on getting wolfSSL_want_read
|
||||
or wolfSSL_want_write during handshake */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t esp_wolfssl_read(esp_tls_t *tls, char *data, size_t datalen)
|
||||
{
|
||||
ssize_t ret = wolfSSL_read( (WOLFSSL *)tls->priv_ssl, (unsigned char *)data, datalen);
|
||||
if (ret < 0) {
|
||||
ret = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
/* peer sent close notify */
|
||||
if (ret == WOLFSSL_ERROR_ZERO_RETURN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret != WOLFSSL_ERROR_WANT_READ && ret != WOLFSSL_ERROR_WANT_WRITE) {
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_WOLFSSL, -ret);
|
||||
ESP_LOGE(TAG, "read error :%d:", ret);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t esp_wolfssl_write(esp_tls_t *tls, const char *data, size_t datalen)
|
||||
{
|
||||
ssize_t ret = wolfSSL_write( (WOLFSSL *)tls->priv_ssl, (unsigned char *) data, datalen);
|
||||
if (ret < 0) {
|
||||
ret = wolfSSL_get_error( (WOLFSSL *)tls->priv_ssl, ret);
|
||||
if (ret != WOLFSSL_ERROR_WANT_READ && ret != WOLFSSL_ERROR_WANT_WRITE) {
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_WOLFSSL, -ret);
|
||||
ESP_LOGE(TAG, "write error :%d:", ret);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void esp_wolfssl_verify_certificate(esp_tls_t *tls)
|
||||
{
|
||||
int flags;
|
||||
if ((flags = wolfSSL_get_verify_result( (WOLFSSL *)tls->priv_ssl)) != WOLFSSL_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Failed to verify peer certificate %d!", flags);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_WOLFSSL_CERT_FLAGS, flags);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Certificate verified.");
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t esp_wolfssl_get_bytes_avail(esp_tls_t *tls)
|
||||
{
|
||||
if (!tls) {
|
||||
ESP_LOGE(TAG, "empty arg passed to esp_tls_get_bytes_avail()");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return wolfSSL_pending( (WOLFSSL *)tls->priv_ssl);
|
||||
}
|
||||
|
||||
void esp_wolfssl_conn_delete(esp_tls_t *tls)
|
||||
{
|
||||
if (tls != NULL) {
|
||||
esp_wolfssl_cleanup(tls);
|
||||
}
|
||||
}
|
||||
|
||||
void esp_wolfssl_cleanup(esp_tls_t *tls)
|
||||
{
|
||||
if (!tls) {
|
||||
return;
|
||||
}
|
||||
wolfSSL_shutdown( (WOLFSSL *)tls->priv_ssl);
|
||||
wolfSSL_free( (WOLFSSL *)tls->priv_ssl);
|
||||
wolfSSL_CTX_free( (WOLFSSL_CTX *)tls->priv_ctx);
|
||||
wolfSSL_Cleanup();
|
||||
}
|
||||
|
||||
esp_err_t esp_wolfssl_init_global_ca_store(void)
|
||||
{
|
||||
/* This function is just to provide consistancy between function calls of esp_tls.h and wolfssl */
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_wolfssl_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes)
|
||||
{
|
||||
if (cacert_pem_buf == NULL) {
|
||||
ESP_LOGE(TAG, "cacert_pem_buf is null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (global_cacert != NULL) {
|
||||
esp_wolfssl_free_global_ca_store();
|
||||
}
|
||||
|
||||
global_cacert = (unsigned char *)strndup((const char *)cacert_pem_buf, cacert_pem_bytes);
|
||||
if (!global_cacert) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
global_cacert_pem_bytes = cacert_pem_bytes;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_wolfssl_free_global_ca_store(void)
|
||||
{
|
||||
if (global_cacert) {
|
||||
free(global_cacert);
|
||||
global_cacert = NULL;
|
||||
global_cacert_pem_bytes = 0;
|
||||
}
|
||||
}
|
@ -33,11 +33,13 @@ typedef enum {
|
||||
ERR_TYPE_MBEDTLS,
|
||||
ERR_TYPE_MBEDTLS_CERT_FLAGS,
|
||||
ERR_TYPE_ESP,
|
||||
ERR_TYPE_WOLFSSL,
|
||||
ERR_TYPE_WOLFSSL_CERT_FLAGS,
|
||||
} err_type_t;
|
||||
|
||||
/**
|
||||
* Error tracker logging macro, this implementation saves latest errors of
|
||||
* ERR_TYPE_ESP, ERR_TYPE_MBEDTLS and ERR_TYPE_MBEDTLS_CERT_FLAGS types
|
||||
* ERR_TYPE_ESP, ERR_TYPE_ESP_TLS and ERR_TYPE_ESP_TLS_CERT_FLAGS types
|
||||
*/
|
||||
#define ESP_INT_EVENT_TRACKER_CAPTURE(h, type, code) esp_int_event_tracker_capture(h, type, code)
|
||||
|
||||
@ -47,13 +49,19 @@ static inline void esp_int_event_tracker_capture(esp_tls_error_handle_t h, uint3
|
||||
if (type == ERR_TYPE_ESP) {
|
||||
h->last_error = code;
|
||||
} else if (type == ERR_TYPE_MBEDTLS) {
|
||||
h->mbedtls_error_code = code;
|
||||
h->esp_tls_error_code = code;
|
||||
} else if (type == ERR_TYPE_MBEDTLS_CERT_FLAGS) {
|
||||
h->mbedtls_flags = code;
|
||||
h->esp_tls_flags = code;
|
||||
} else if (type == ERR_TYPE_WOLFSSL) {
|
||||
h->esp_tls_error_code = code;
|
||||
} else if (type == ERR_TYPE_WOLFSSL_CERT_FLAGS) {
|
||||
h->esp_tls_flags = code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
104
components/esp-tls/private_include/esp_tls_mbedtls.h
Normal file
104
components/esp-tls/private_include/esp_tls_mbedtls.h
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include "esp_tls.h"
|
||||
|
||||
/**
|
||||
* Internal Callback API for mbedtls_ssl_read
|
||||
*/
|
||||
ssize_t esp_mbedtls_read(esp_tls_t *tls, char *data, size_t datalen);
|
||||
|
||||
/**
|
||||
* Internal callback API for mbedtls_ssl_write
|
||||
*/
|
||||
ssize_t esp_mbedtls_write(esp_tls_t *tls, const char *data, size_t datalen);
|
||||
|
||||
/**
|
||||
* Internal Callback for mbedtls_handshake
|
||||
*/
|
||||
int esp_mbedtls_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg);
|
||||
|
||||
/**
|
||||
* Internal Callback for mbedtls_cleanup , frees up all the memory used by mbedtls
|
||||
*/
|
||||
void esp_mbedtls_cleanup(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for Certificate verification for mbedtls
|
||||
*/
|
||||
void esp_mbedtls_verify_certificate(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for deleting the mbedtls connection
|
||||
*/
|
||||
void esp_mbedtls_conn_delete(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for mbedtls_get_bytes_avail
|
||||
*/
|
||||
ssize_t esp_mbedtls_get_bytes_avail(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for creating ssl handle for mbedtls
|
||||
*/
|
||||
esp_err_t esp_create_mbedtls_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls);
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_SERVER
|
||||
/**
|
||||
* Internal Callback for set_server_config
|
||||
*
|
||||
* /note :- can only be used with mbedtls ssl library
|
||||
*/
|
||||
esp_err_t set_server_config(esp_tls_cfg_server_t *cfg, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for mbedtls_server_session_create
|
||||
*
|
||||
* /note :- The function can only be used with mbedtls ssl library
|
||||
*/
|
||||
int esp_mbedtls_server_session_create(esp_tls_cfg_server_t *cfg, int sockfd, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for mbedtls_server_session_delete
|
||||
*
|
||||
* /note :- The function can only be used with mbedtls ssl library
|
||||
*/
|
||||
void esp_mbedtls_server_session_delete(esp_tls_t *tls);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Internal Callback for set_client_config_function
|
||||
*/
|
||||
esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t *cfg, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for mbedtls_init_global_ca_store
|
||||
*/
|
||||
esp_err_t esp_mbedtls_init_global_ca_store(void);
|
||||
|
||||
/**
|
||||
* Callback function for setting global CA store data for TLS/SSL using mbedtls
|
||||
*/
|
||||
esp_err_t esp_mbedtls_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes);
|
||||
|
||||
/**
|
||||
* Internal Callback for esp_tls_global_ca_store
|
||||
*/
|
||||
mbedtls_x509_crt *esp_mbedtls_get_global_ca_store(void);
|
||||
|
||||
/**
|
||||
* Callback function for freeing global ca store for TLS/SSL using mbedtls
|
||||
*/
|
||||
void esp_mbedtls_free_global_ca_store(void);
|
72
components/esp-tls/private_include/esp_tls_wolfssl.h
Normal file
72
components/esp-tls/private_include/esp_tls_wolfssl.h
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include "esp_tls.h"
|
||||
|
||||
/**
|
||||
* Internal Callback for creating ssl handle for wolfssl
|
||||
*/
|
||||
int esp_create_wolfssl_handle(const char *hostname, size_t hostlen, const void *cfg, esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for wolfssl_handshake
|
||||
*/
|
||||
int esp_wolfssl_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg);
|
||||
|
||||
/**
|
||||
* Internal Callback API for wolfssl_ssl_read
|
||||
*/
|
||||
ssize_t esp_wolfssl_read(esp_tls_t *tls, char *data, size_t datalen);
|
||||
|
||||
/**
|
||||
* Internal callback API for wolfssl_ssl_write
|
||||
*/
|
||||
ssize_t esp_wolfssl_write(esp_tls_t *tls, const char *data, size_t datalen);
|
||||
|
||||
/**
|
||||
* Internal Callback for wolfssl_cleanup , frees up all the memory used by wolfssl
|
||||
*/
|
||||
void esp_wolfssl_cleanup(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for Certificate verification for wolfssl
|
||||
*/
|
||||
void esp_wolfssl_verify_certificate(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for deleting the wolfssl connection
|
||||
*/
|
||||
void esp_wolfssl_conn_delete(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Internal Callback for wolfssl_get_bytes_avail
|
||||
*/
|
||||
ssize_t esp_wolfssl_get_bytes_avail(esp_tls_t *tls);
|
||||
|
||||
/**
|
||||
* Callback function for setting global CA store data for TLS/SSL using wolfssl
|
||||
*/
|
||||
esp_err_t esp_wolfssl_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes);
|
||||
|
||||
/**
|
||||
* Callback function for freeing global ca store for TLS/SSL using wolfssl
|
||||
*/
|
||||
void esp_wolfssl_free_global_ca_store(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* Callback function for Initializing the global ca store for TLS?SSL using wolfssl
|
||||
*/
|
||||
esp_err_t esp_wolfssl_init_global_ca_store(void);
|
@ -6,10 +6,13 @@ Overview
|
||||
|
||||
The ESP-TLS component provides a simplified API interface for accessing the commonly used TLS functionality.
|
||||
It supports common scenarios like CA certification validation, SNI, ALPN negotiation, non-blocking connection among others.
|
||||
All the configuration can be specified in the esp_tls_cfg_t data structure. Once done, TLS communication can be conducted using the following APIs:
|
||||
* esp_tls_conn_new(): for opening a new TLS connection
|
||||
* esp_tls_conn_read/write(): for reading/writing from the connection
|
||||
* esp_tls_conn_delete(): for freeing up the connection
|
||||
All the configuration can be specified in the ``esp_tls_cfg_t`` data structure. Once done, TLS communication can be conducted using the following APIs:
|
||||
|
||||
* :cpp:func:`esp_tls_conn_new`: for opening a new TLS connection.
|
||||
* :cpp:func:`esp_tls_conn_read`: for reading from the connection.
|
||||
* :cpp:func:`esp_tls_conn_write`: for writing into the connection.
|
||||
* :cpp:func:`esp_tls_conn_delete`: for freeing up the connection.
|
||||
|
||||
Any application layer protocol like HTTP1, HTTP2 etc can be executed on top of this layer.
|
||||
|
||||
Application Example
|
||||
@ -17,8 +20,75 @@ Application Example
|
||||
|
||||
Simple HTTPS example that uses ESP-TLS to establish a secure socket connection: :example:`protocols/https_request`.
|
||||
|
||||
Tree structure for ESP-TLS component
|
||||
-------------------------------------
|
||||
.. highlight:: none
|
||||
|
||||
::
|
||||
|
||||
├── esp_tls.c
|
||||
├── esp_tls.h
|
||||
├── esp_tls_mbedtls.c
|
||||
├── esp_tls_wolfssl.c
|
||||
└── private_include
|
||||
├── esp_tls_mbedtls.h
|
||||
└── esp_tls_wolfssl.h
|
||||
|
||||
The ESP-TLS component has a file :component_file:`esp-tls/esp_tls.h` which contain the public API headers for the component. Internally ESP-TLS component uses one
|
||||
of the two SSL/TLS Libraries between mbedtls and wolfssl for its operation. API specific to mbedtls are present in :component_file:`esp-tls/private_include/esp_tls_mbedtls.h` and API
|
||||
specific to wolfssl are present in :component_file:`esp-tls/private_include/esp_tls_wolfssl.h`.
|
||||
|
||||
Underlying SSL/TLS Library Options
|
||||
----------------------------------
|
||||
The ESP-TLS component has an option to use mbedtls or wolfssl as their underlying SSL/TLS library. By default only mbedtls is available and is
|
||||
used, wolfssl SSL/TLS library is available publicly at https://github.com/espressif/esp-wolfssl. The repository provides wolfssl component in binary format, it
|
||||
also provides few examples which are useful for understanding the API. Please refer the repository README.md for
|
||||
information on licensing and other options. Please see below option for using wolfssl in your project.
|
||||
|
||||
.. note:: `As the library options are internal to ESP-TLS, switching the libries will not change ESP-TLS specific code for a project.`
|
||||
|
||||
How to use wolfssl with ESP-IDF
|
||||
-------------------------------
|
||||
There are two ways to use wolfssl in your project
|
||||
|
||||
1) Directly add wolfssl as a component in your project with following three commands.::
|
||||
|
||||
(First change directory (cd) to your project directory)
|
||||
mkdir components
|
||||
cd components
|
||||
git clone https://github.com/espressif/esp-wolfssl.git
|
||||
|
||||
2) Add wolfssl as an extra component in your project.
|
||||
|
||||
* Download wolfssl with::
|
||||
|
||||
git clone https://github.com/espressif/esp-wolfssl.git
|
||||
|
||||
* Include esp-wolfssl in ESP-IDF with setting EXTRA_COMPONENT_DIRS in CMakeLists.txt/Makefile of your project as done in `wolfssl/examples <https://github.com/espressif/esp-wolfssl/tree/master/examples>`_. For reference see Optional Project variables in :doc:`build-system.</api-guides/build-system>`
|
||||
|
||||
After above steps, you will have option to choose wolfssl as underlying SSL/TLS library in configuration menu of your project as follows::
|
||||
|
||||
idf.py/make menuconfig -> ESP-TLS -> choose SSL/TLS Library -> mbedtls/wolfssl
|
||||
|
||||
Comparison between mbedtls and wolfssl
|
||||
--------------------------------------
|
||||
The following table shows a typical comparison between wolfssl and mbedtls when :example:`protocols/https_request` example `(which has server authentication)` was run with both
|
||||
SSL/TLS libraries and with all respective configurations set to default.
|
||||
`(mbedtls IN_CONTENT length and OUT_CONTENT length were set to 16384 bytes and 4096 bytes respectively)`
|
||||
|
||||
+---------------------+------------+-----------+
|
||||
| Property | Wolfssl | Mbedtls |
|
||||
+=====================+============+===========+
|
||||
| Total Heap Consumed | ~19 Kb | ~37 Kb |
|
||||
+---------------------+------------+-----------+
|
||||
| Task Stack Used | ~2.2 Kb | ~3.6 Kb |
|
||||
+---------------------+------------+-----------+
|
||||
| Bin size | ~858 Kb | ~736 Kb |
|
||||
+---------------------+------------+-----------+
|
||||
|
||||
.. note:: `These values are subject to change with change in configuration options and version of respective libraries`.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_tls.inc
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user