-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(modem): Support custom transport in AT TCP client example
- Loading branch information
1 parent
42fe608
commit ae629ed
Showing
17 changed files
with
602 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
...onents/esp_modem/examples/modem_tcp_client/components/extra_tcp_transports/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
idf_component_register(SRCS mbedtls_wrap.cpp | ||
tls_transport.cpp | ||
INCLUDE_DIRS include | ||
REQUIRES tcp_transport) |
9 changes: 9 additions & 0 deletions
9
...s/esp_modem/examples/modem_tcp_client/components/extra_tcp_transports/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Custom transports | ||
|
||
This component is a placeholder of custom transports. It contains mbedTLS cxx wrapper which could be used to create a custom TLS layer on any kind of IO function. | ||
|
||
# List of Transports | ||
|
||
## TLS Transport | ||
|
||
TLS layer on top of any custom transport. Very similar to `ssl_transport` (standard IDF transport), but this is customizable and could work on any kind of transport, not only the BSD socket based tcp transport (like `ssl_transport`). |
46 changes: 46 additions & 0 deletions
46
..._modem/examples/modem_tcp_client/components/extra_tcp_transports/include/mbedtls_wrap.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
#pragma once | ||
|
||
#include <utility> | ||
#include "mbedtls/ssl.h" | ||
#include "mbedtls/entropy.h" | ||
#include "mbedtls/ctr_drbg.h" | ||
#include "mbedtls/error.h" | ||
|
||
using const_buf = std::pair<const unsigned char *, std::size_t>; | ||
using buf = std::pair<unsigned char *, std::size_t>; | ||
|
||
class Tls { | ||
public: | ||
Tls(); | ||
bool init(bool is_server, bool verify); | ||
int handshake(); | ||
int write(const unsigned char *buf, size_t len); | ||
int read(unsigned char *buf, size_t len); | ||
bool set_own_cert(const_buf crt, const_buf key); | ||
bool set_ca_cert(const_buf crt); | ||
virtual int send(const unsigned char *buf, size_t len) = 0; | ||
virtual int recv(unsigned char *buf, size_t len) = 0; | ||
size_t get_available_bytes(); | ||
|
||
private: | ||
mbedtls_ssl_context ssl_{}; | ||
mbedtls_x509_crt public_cert_{}; | ||
mbedtls_pk_context pk_key_{}; | ||
mbedtls_x509_crt ca_cert_{}; | ||
mbedtls_ssl_config conf_{}; | ||
mbedtls_ctr_drbg_context ctr_drbg_{}; | ||
mbedtls_entropy_context entropy_{}; | ||
|
||
static void print_error(const char *function, int error_code); | ||
static int bio_write(void *ctx, const unsigned char *buf, size_t len); | ||
static int bio_read(void *ctx, unsigned char *buf, size_t len); | ||
int mbedtls_pk_parse_key( mbedtls_pk_context *ctx, | ||
const unsigned char *key, size_t keylen, | ||
const unsigned char *pwd, size_t pwdlen); | ||
|
||
}; |
16 changes: 16 additions & 0 deletions
16
...examples/modem_tcp_client/components/extra_tcp_transports/include/tcp_transport_mbedtls.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
#pragma once | ||
|
||
#include "esp_transport.h" | ||
|
||
/** | ||
* @brief Initializes TLS transport based on mbetls wrapper | ||
* | ||
* @param parent Transport on top of which we run TLS layer | ||
* @return Transport handle on success | ||
*/ | ||
esp_transport_handle_t esp_transport_tls_init(esp_transport_handle_t parent); |
129 changes: 129 additions & 0 deletions
129
...ents/esp_modem/examples/modem_tcp_client/components/extra_tcp_transports/mbedtls_wrap.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
#include "mbedtls/ctr_drbg.h" | ||
#include "mbedtls/ssl.h" | ||
#include "mbedtls_wrap.hpp" | ||
|
||
bool Tls::init(bool is_server, bool verify) | ||
{ | ||
const char pers[] = "mbedtls_wrapper"; | ||
mbedtls_entropy_init(&entropy_); | ||
mbedtls_ctr_drbg_seed(&ctr_drbg_, mbedtls_entropy_func, &entropy_, (const unsigned char *)pers, sizeof(pers)); | ||
int ret = mbedtls_ssl_config_defaults(&conf_, is_server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); | ||
if (ret) { | ||
print_error("mbedtls_ssl_config_defaults", ret); | ||
return false; | ||
} | ||
mbedtls_ssl_conf_rng(&conf_, mbedtls_ctr_drbg_random, &ctr_drbg_); | ||
mbedtls_ssl_conf_authmode(&conf_, verify ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE); | ||
ret = mbedtls_ssl_conf_own_cert(&conf_, &public_cert_, &pk_key_); | ||
if (ret) { | ||
print_error("mbedtls_ssl_conf_own_cert", ret); | ||
return false; | ||
} | ||
if (verify) { | ||
mbedtls_ssl_conf_ca_chain(&conf_, &ca_cert_, nullptr); | ||
} | ||
ret = mbedtls_ssl_setup(&ssl_, &conf_); | ||
if (ret) { | ||
print_error("mbedtls_ssl_setup", ret); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
void Tls::print_error(const char *function, int error_code) | ||
{ | ||
static char error_buf[100]; | ||
mbedtls_strerror(error_code, error_buf, sizeof(error_buf)); | ||
|
||
printf("%s() returned -0x%04X\n", function, -error_code); | ||
printf("-0x%04X: %s\n", -error_code, error_buf); | ||
} | ||
#include "freertos/FreeRTOS.h" | ||
#include "freertos/task.h" | ||
#include "esp_log.h" | ||
int Tls::handshake() | ||
{ | ||
ESP_LOGI("TLS", "handshake"); | ||
int ret = 0; | ||
mbedtls_ssl_set_bio(&ssl_, this, bio_write, bio_read, nullptr); | ||
|
||
while ( ( ret = mbedtls_ssl_handshake( &ssl_ ) ) != 0 ) { | ||
if ( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { | ||
print_error( "mbedtls_ssl_handshake returned", ret ); | ||
return -1; | ||
} | ||
vTaskDelay(pdMS_TO_TICKS(500)); | ||
} | ||
ESP_LOGI("TLS", "handshake done with %d", ret); | ||
return ret; | ||
} | ||
|
||
int Tls::bio_write(void *ctx, const unsigned char *buf, size_t len) | ||
{ | ||
auto s = static_cast<Tls *>(ctx); | ||
return s->send(buf, len); | ||
} | ||
|
||
int Tls::bio_read(void *ctx, unsigned char *buf, size_t len) | ||
{ | ||
auto s = static_cast<Tls *>(ctx); | ||
return s->recv(buf, len); | ||
} | ||
|
||
int Tls::write(const unsigned char *buf, size_t len) | ||
{ | ||
return mbedtls_ssl_write( &ssl_, buf, len ); | ||
} | ||
|
||
int Tls::read(unsigned char *buf, size_t len) | ||
{ | ||
return mbedtls_ssl_read( &ssl_, buf, len ); | ||
} | ||
|
||
bool Tls::set_own_cert(const_buf crt, const_buf key) | ||
{ | ||
int ret = mbedtls_x509_crt_parse(&public_cert_, crt.first, crt.second); | ||
if (ret < 0) { | ||
print_error("mbedtls_x509_crt_parse", ret); | ||
return false; | ||
} | ||
ret = mbedtls_pk_parse_key(&pk_key_, key.first, key.second, nullptr, 0); | ||
if (ret < 0) { | ||
print_error("mbedtls_pk_parse_keyfile", ret); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
bool Tls::set_ca_cert(const_buf crt) | ||
{ | ||
int ret = mbedtls_x509_crt_parse(&ca_cert_, crt.first, crt.second); | ||
if (ret < 0) { | ||
print_error("mbedtls_x509_crt_parse", ret); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
Tls::Tls() | ||
{ | ||
mbedtls_x509_crt_init(&public_cert_); | ||
mbedtls_pk_init(&pk_key_); | ||
mbedtls_x509_crt_init(&ca_cert_); | ||
} | ||
|
||
int Tls::mbedtls_pk_parse_key(mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen) | ||
{ | ||
|
||
return ::mbedtls_pk_parse_key(ctx, key, keylen, pwd, pwdlen, nullptr, nullptr); | ||
} | ||
|
||
size_t Tls::get_available_bytes() | ||
{ | ||
return ::mbedtls_ssl_get_bytes_avail(&ssl_); | ||
} |
132 changes: 132 additions & 0 deletions
132
...nts/esp_modem/examples/modem_tcp_client/components/extra_tcp_transports/tls_transport.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
#include "esp_log.h" | ||
#include "esp_transport.h" | ||
#include "mbedtls_wrap.hpp" | ||
|
||
static const char *TAG = "tls_transport"; | ||
|
||
class TlsTransport: public Tls { | ||
public: | ||
explicit TlsTransport(esp_transport_handle_t parent) : Tls(), transport_(parent) {} | ||
int send(const unsigned char *buf, size_t len) override; | ||
int recv(unsigned char *buf, size_t len) override; | ||
static bool set_func(esp_transport_handle_t tls_transport); | ||
|
||
private: | ||
esp_transport_handle_t transport_{}; | ||
int connect(const char *host, int port, int timeout_ms); | ||
|
||
struct priv { | ||
static int connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms); | ||
static int read(esp_transport_handle_t t, char *buffer, int len, int timeout_ms); | ||
static int write(esp_transport_handle_t t, const char *buffer, int len, int timeout_ms); | ||
static int close(esp_transport_handle_t t); | ||
static int poll_read(esp_transport_handle_t t, int timeout_ms); | ||
static int poll_write(esp_transport_handle_t t, int timeout_ms); | ||
static int destroy(esp_transport_handle_t t); | ||
}; | ||
}; | ||
|
||
esp_transport_handle_t esp_transport_tls_init(esp_transport_handle_t parent) | ||
{ | ||
esp_transport_handle_t ssl = esp_transport_init(); | ||
auto *tls = new TlsTransport(parent); | ||
esp_transport_set_context_data(ssl, tls); | ||
TlsTransport::set_func(ssl); | ||
return ssl; | ||
} | ||
|
||
int TlsTransport::send(const unsigned char *buf, size_t len) | ||
{ | ||
return esp_transport_write(transport_, reinterpret_cast<const char *>(buf), len, 0); | ||
} | ||
|
||
int TlsTransport::recv(unsigned char *buf, size_t len) | ||
{ | ||
int ret = esp_transport_read(transport_, reinterpret_cast<char *>(buf), len, 0); | ||
|
||
if (ret == ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT) { | ||
return MBEDTLS_ERR_SSL_WANT_READ; | ||
} | ||
return ret == ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN ? 0 : ret; | ||
} | ||
|
||
bool TlsTransport::set_func(esp_transport_handle_t tls_transport) | ||
{ | ||
return esp_transport_set_func(tls_transport, TlsTransport::priv::connect, TlsTransport::priv::read, TlsTransport::priv::write, TlsTransport::priv::close, TlsTransport::priv::poll_read, TlsTransport::priv::poll_write, TlsTransport::priv::destroy) == ESP_OK; | ||
} | ||
|
||
int TlsTransport::connect(const char *host, int port, int timeout_ms) | ||
{ | ||
return esp_transport_connect(transport_, host, port, timeout_ms); | ||
} | ||
|
||
int TlsTransport::priv::connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms) | ||
{ | ||
ESP_LOGI("tag", "SSL connect!"); | ||
auto tls = static_cast<TlsTransport *>(esp_transport_get_context_data(t)); | ||
tls->init(false, false); | ||
|
||
ESP_LOGI("tag", "TCP connect!"); | ||
auto ret = tls->connect(host, port, timeout_ms); | ||
if (ret < 0) { | ||
ESP_LOGI("tag", "TCP connect fail!"); | ||
return ret; | ||
} | ||
return tls->handshake(); | ||
} | ||
|
||
int TlsTransport::priv::read(esp_transport_handle_t t, char *buffer, int len, int timeout_ms) | ||
{ | ||
auto tls = static_cast<TlsTransport *>(esp_transport_get_context_data(t)); | ||
if (tls->get_available_bytes() <= 0) { | ||
int poll = esp_transport_poll_read(t, timeout_ms); | ||
if (poll == -1) { | ||
return ERR_TCP_TRANSPORT_CONNECTION_FAILED; | ||
} | ||
if (poll == 0) { | ||
return ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT; | ||
} | ||
} | ||
return tls->read(reinterpret_cast<unsigned char *>(buffer), len); | ||
} | ||
|
||
int TlsTransport::priv::write(esp_transport_handle_t t, const char *buffer, int len, int timeout_ms) | ||
{ | ||
int poll; | ||
if ((poll = esp_transport_poll_write(t, timeout_ms)) <= 0) { | ||
ESP_LOGW(TAG, "Poll timeout or error timeout_ms=%d", timeout_ms); | ||
return poll; | ||
} | ||
|
||
auto tls = static_cast<TlsTransport *>(esp_transport_get_context_data(t)); | ||
return tls->write(reinterpret_cast<const unsigned char *>(buffer), len); | ||
} | ||
|
||
int TlsTransport::priv::close(esp_transport_handle_t t) | ||
{ | ||
auto tls = static_cast<TlsTransport *>(esp_transport_get_context_data(t)); | ||
return esp_transport_close(tls->transport_); | ||
} | ||
|
||
int TlsTransport::priv::poll_read(esp_transport_handle_t t, int timeout_ms) | ||
{ | ||
auto tls = static_cast<TlsTransport *>(esp_transport_get_context_data(t)); | ||
return esp_transport_poll_read(tls->transport_, timeout_ms); | ||
} | ||
|
||
int TlsTransport::priv::poll_write(esp_transport_handle_t t, int timeout_ms) | ||
{ | ||
auto tls = static_cast<TlsTransport *>(esp_transport_get_context_data(t)); | ||
return esp_transport_poll_write(tls->transport_, timeout_ms); | ||
} | ||
|
||
int TlsTransport::priv::destroy(esp_transport_handle_t t) | ||
{ | ||
auto tls = static_cast<TlsTransport *>(esp_transport_get_context_data(t)); | ||
return esp_transport_destroy(tls->transport_); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
components/esp_modem/examples/modem_tcp_client/main/Kconfig.projbuild
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.