diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9261d60d5fd..75ff8309660 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -62,7 +62,7 @@ repos: hooks: - id: commit message scopes name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common" - entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples)\)\:)' + entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples|tls_cxx)\)\:)' language: pygrep args: [--multiline] stages: [commit-msg] diff --git a/components/mbedtls_cxx/examples/tls_client/CMakeLists.txt b/components/mbedtls_cxx/examples/tls_client/CMakeLists.txt new file mode 100644 index 00000000000..ac83b5d1b2d --- /dev/null +++ b/components/mbedtls_cxx/examples/tls_client/CMakeLists.txt @@ -0,0 +1,11 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +if("${IDF_TARGET}" STREQUAL "linux") + list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/") +endif() +project(tls_client) diff --git a/components/mbedtls_cxx/examples/tls_client/main/CMakeLists.txt b/components/mbedtls_cxx/examples/tls_client/main/CMakeLists.txt new file mode 100644 index 00000000000..f89b6a82d62 --- /dev/null +++ b/components/mbedtls_cxx/examples/tls_client/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "tls_client.cpp" + INCLUDE_DIRS ".") diff --git a/components/mbedtls_cxx/examples/tls_client/main/idf_component.yml b/components/mbedtls_cxx/examples/tls_client/main/idf_component.yml new file mode 100644 index 00000000000..8bd6aa2845d --- /dev/null +++ b/components/mbedtls_cxx/examples/tls_client/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + idf: ">=5.0" + espressif/mbedtls_cxx: + version: "*" + override_path: "../../.." + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/components/mbedtls_cxx/examples/tls_client/main/tls_client.cpp b/components/mbedtls_cxx/examples/tls_client/main/tls_client.cpp new file mode 100644 index 00000000000..15e97f2b450 --- /dev/null +++ b/components/mbedtls_cxx/examples/tls_client/main/tls_client.cpp @@ -0,0 +1,144 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include +#include "esp_log.h" +#include "mbedtls_wrap.hpp" + +static auto const *TAG = "simple_tls_client"; + +class TlsSocketClient: public Tls { +public: + explicit TlsSocketClient() : Tls() {} + ~TlsSocketClient() override + { + if (sock >= 0) { + ::close(sock); + } + } + int send(const unsigned char *buf, size_t len) override + { + return ::send(sock, buf, len, 0); + } + int recv(unsigned char *buf, size_t len) override + { + return ::recv(sock, buf, len, 0); + } + bool connect(const char *host, int port) + { + addr_info addr(host, AF_INET, SOCK_STREAM); + if (!addr) { + ESP_LOGE(TAG, "Failed to resolve host"); + return false; + } + sock = addr.get_sock(); + if (sock < 0) { + ESP_LOGE(TAG, "Failed to create socket"); + return false; + } + + if (::connect(sock, addr.get_addr(port), sizeof(struct sockaddr)) < 0) { + ESP_LOGE(TAG, "Failed to connect %d", errno); + return false; + } + + if (!init(is_server{false}, do_verify{false})) { + return false; + } + return handshake() == 0; + } + +private: + int sock{-1}; + /** + * RAII wrapper of the address_info + */ + struct addr_info { + struct addrinfo *ai { + nullptr + }; + ~addr_info() + { + freeaddrinfo(ai); + } + explicit addr_info(const char *host, int family, int type) + { + struct addrinfo hints {}; + hints.ai_family = family; + hints.ai_socktype = type; + if (getaddrinfo(host, nullptr, &hints, &ai) < 0) { + freeaddrinfo(ai); + ai = nullptr; + } + } + explicit operator bool() const + { + return ai != nullptr; + } + struct sockaddr *get_addr(uint16_t port) const { + auto *p = (struct sockaddr_in *)ai->ai_addr; + p->sin_port = htons(port); + return (struct sockaddr *)p; + } + int get_sock() const + { + return socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + } + }; +}; + +static void tls_client() +{ + const unsigned char message[] = "Hello\n"; + unsigned char reply[128]; + TlsSocketClient client; + if (!client.connect("tcpbin.com", 4243)) { + ESP_LOGE(TAG, "Failed to connect! %d", errno); + return; + } + if (client.write(message, sizeof(message)) < 0) { + ESP_LOGE(TAG, "Failed to write!"); + return; + } + int len = client.read(reply, sizeof(reply)); + if (len < 0) { + ESP_LOGE(TAG, "Failed to read!"); + return; + } + ESP_LOGI(TAG, "Successfully received: %.*s", len, reply); +} + +#if CONFIG_IDF_TARGET_LINUX +/** + * Linux target: We're already connected, just run the client + */ +int main() +{ + tls_client(); + return 0; +} +#else +/** + * ESP32 chipsets: Need to initialize system components + * and connect to network + */ + +#include "nvs_flash.h" +#include "esp_event.h" +#include "protocol_examples_common.h" +#include "esp_netif.h" + +extern "C" void app_main() +{ + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(example_connect()); + + tls_client(); +} +#endif diff --git a/components/esp_modem/examples/modem_tcp_client/components/extra_tcp_transports/include/mbedtls_wrap.hpp b/components/mbedtls_cxx/include/mbedtls_wrap.hpp similarity index 94% rename from components/esp_modem/examples/modem_tcp_client/components/extra_tcp_transports/include/mbedtls_wrap.hpp rename to components/mbedtls_cxx/include/mbedtls_wrap.hpp index 5dc1df71ab4..25898716879 100644 --- a/components/esp_modem/examples/modem_tcp_client/components/extra_tcp_transports/include/mbedtls_wrap.hpp +++ b/components/mbedtls_cxx/include/mbedtls_wrap.hpp @@ -7,13 +7,13 @@ #include #include -#include #include "mbedtls/ssl.h" #include "mbedtls/entropy.h" #include "mbedtls/ctr_drbg.h" #include "mbedtls/error.h" -using const_buf = std::span; +using const_buf = std::pair; +using buf = std::pair; class Tls { public: diff --git a/components/esp_modem/examples/modem_tcp_client/components/extra_tcp_transports/mbedtls_wrap.cpp b/components/mbedtls_cxx/mbedtls_wrap.cpp similarity index 95% rename from components/esp_modem/examples/modem_tcp_client/components/extra_tcp_transports/mbedtls_wrap.cpp rename to components/mbedtls_cxx/mbedtls_wrap.cpp index eda6045fec9..ca1ed0da361 100644 --- a/components/esp_modem/examples/modem_tcp_client/components/extra_tcp_transports/mbedtls_wrap.cpp +++ b/components/mbedtls_cxx/mbedtls_wrap.cpp @@ -93,12 +93,12 @@ int Tls::read(unsigned char *buf, size_t len) bool Tls::set_own_cert(const_buf crt, const_buf key) { - int ret = mbedtls_x509_crt_parse(&public_cert_, crt.data(), crt.size()); + 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.data(), key.size(), nullptr, 0); + 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; @@ -108,7 +108,7 @@ bool Tls::set_own_cert(const_buf crt, const_buf key) bool Tls::set_ca_cert(const_buf crt) { - int ret = mbedtls_x509_crt_parse(&ca_cert_, crt.data(), crt.size()); + int ret = mbedtls_x509_crt_parse(&ca_cert_, crt.first, crt.second); if (ret < 0) { print_error("mbedtls_x509_crt_parse", ret); return false;