Skip to content

Commit 5cd7cb0

Browse files
committed
feat(tls_cxx): Add support for DTLS
1 parent a637bfc commit 5cd7cb0

File tree

6 files changed

+348
-4
lines changed

6 files changed

+348
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# For more information about build system see
2+
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
3+
# The following five lines of boilerplate have to be in your project's
4+
# CMakeLists in this exact order for cmake to work correctly
5+
cmake_minimum_required(VERSION 3.16)
6+
7+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
8+
if("${IDF_TARGET}" STREQUAL "linux")
9+
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")
10+
endif()
11+
project(udp_mutual)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
idf_component_register(SRCS "udp_mutual.cpp"
2+
INCLUDE_DIRS ".")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
dependencies:
2+
idf: ">=5.0"
3+
espressif/mbedtls_cxx:
4+
version: "*"
5+
override_path: "../../.."
6+
protocol_examples_common:
7+
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Unlicense OR CC0-1.0
5+
*/
6+
#include <sys/socket.h>
7+
#include <netdb.h>
8+
#include <unistd.h>
9+
#include "esp_log.h"
10+
#include "mbedtls_wrap.hpp"
11+
12+
static auto const *TAG = "simple_udp_example";
13+
14+
const unsigned char servercert[] = "-----BEGIN CERTIFICATE-----\n"
15+
"MIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL\n"
16+
"BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx\n"
17+
"MDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ\n"
18+
"UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n"
19+
"ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T\n"
20+
"sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k\n"
21+
"qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd\n"
22+
"GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4\n"
23+
"sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb\n"
24+
"jAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/\n"
25+
"ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud\n"
26+
"EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3\n"
27+
"emBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY\n"
28+
"W1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx\n"
29+
"bkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN\n"
30+
"ZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl\n"
31+
"hb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo=\n"
32+
"-----END CERTIFICATE-----";
33+
const unsigned char prvtkey[] = "-----BEGIN PRIVATE KEY-----\n"
34+
"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH\n"
35+
"JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw\n"
36+
"h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT\n"
37+
"aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al\n"
38+
"3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg\n"
39+
"0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB\n"
40+
"vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui\n"
41+
"f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9\n"
42+
"Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y\n"
43+
"JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX\n"
44+
"49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc\n"
45+
"+3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6\n"
46+
"pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D\n"
47+
"0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG\n"
48+
"YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV\n"
49+
"MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL\n"
50+
"CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin\n"
51+
"7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1\n"
52+
"noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8\n"
53+
"4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g\n"
54+
"Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/\n"
55+
"nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3\n"
56+
"q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2\n"
57+
"lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB\n"
58+
"jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr\n"
59+
"v/t+MeGJP/0Zw8v/X2CFll96\n"
60+
"-----END PRIVATE KEY-----";
61+
62+
63+
class SecureLink: public Tls {
64+
public:
65+
explicit SecureLink() : Tls(), addr("localhost", 3333, AF_INET, SOCK_DGRAM) {}
66+
~SecureLink() override
67+
{
68+
if (sock >= 0) {
69+
::close(sock);
70+
}
71+
}
72+
int send(const unsigned char *buf, size_t len) override
73+
{
74+
return sendto(sock, buf, len, 0, addr, ai_size);
75+
}
76+
int recv(unsigned char *buf, size_t len) override
77+
{
78+
socklen_t socklen = sizeof(sockaddr);
79+
return recvfrom(sock, buf, len, 0, addr, &socklen);
80+
}
81+
int recv_tout(unsigned char *buf, size_t len, int timeout) override
82+
{
83+
struct timeval tv {
84+
timeout / 1000, (timeout % 1000 ) * 1000
85+
};
86+
fd_set read_fds;
87+
FD_ZERO( &read_fds );
88+
FD_SET( sock, &read_fds );
89+
90+
int ret = select(sock + 1, &read_fds, nullptr, nullptr, timeout == 0 ? nullptr : &tv);
91+
if (ret == 0) {
92+
return MBEDTLS_ERR_SSL_TIMEOUT;
93+
}
94+
if (ret < 0) {
95+
if (errno == EINTR) {
96+
return MBEDTLS_ERR_SSL_WANT_READ;
97+
}
98+
return ret;
99+
}
100+
return recv(buf, len);
101+
}
102+
bool open(bool server_not_client)
103+
{
104+
if (!addr) {
105+
ESP_LOGE(TAG, "Failed to resolve endpoint");
106+
return false;
107+
}
108+
sock = addr.get_sock();
109+
if (sock < 0) {
110+
ESP_LOGE(TAG, "Failed to create socket");
111+
return false;
112+
}
113+
if (server_not_client) {
114+
int err = bind(sock, addr, ai_size);
115+
if (err < 0) {
116+
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
117+
return false;
118+
}
119+
}
120+
if (!init(is_server{server_not_client}, do_verify{false})) {
121+
return false;
122+
}
123+
124+
return handshake() == 0;
125+
}
126+
127+
private:
128+
int sock{-1};
129+
/**
130+
* RAII wrapper of the address_info
131+
*/
132+
struct addr_info {
133+
struct addrinfo *ai = nullptr;
134+
explicit addr_info(const char *host, int port, int family, int type)
135+
{
136+
struct addrinfo hints {};
137+
hints.ai_family = family;
138+
hints.ai_socktype = type;
139+
if (getaddrinfo(host, nullptr, &hints, &ai) < 0) {
140+
freeaddrinfo(ai);
141+
ai = nullptr;
142+
}
143+
auto *p = (struct sockaddr_in *)ai->ai_addr;
144+
p->sin_port = htons(port);
145+
}
146+
~addr_info()
147+
{
148+
freeaddrinfo(ai);
149+
}
150+
explicit operator bool() const
151+
{
152+
return ai != nullptr;
153+
}
154+
operator sockaddr *() const
155+
{
156+
auto *p = (struct sockaddr_in *)ai->ai_addr;
157+
return (struct sockaddr *)p;
158+
}
159+
160+
int get_sock() const
161+
{
162+
return socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
163+
}
164+
} addr;
165+
const int ai_size{sizeof(struct sockaddr_in)};
166+
};
167+
168+
static void tls_client()
169+
{
170+
const unsigned char message[] = "Hello\n";
171+
unsigned char reply[128];
172+
SecureLink client;
173+
if (!client.open(false)) {
174+
ESP_LOGE(TAG, "Failed to CONNECT! %d", errno);
175+
return;
176+
}
177+
ESP_LOGI(TAG, "client opened...");
178+
if (client.write(message, sizeof(message)) < 0) {
179+
ESP_LOGE(TAG, "Failed to write!");
180+
return;
181+
}
182+
int len = client.read(reply, sizeof(reply));
183+
if (len < 0) {
184+
ESP_LOGE(TAG, "Failed to read!");
185+
return;
186+
}
187+
ESP_LOGI(TAG, "Successfully received: %.*s", len, reply);
188+
}
189+
190+
static void tls_server()
191+
{
192+
unsigned char message[128];
193+
SecureLink server;
194+
const_buf cert{servercert, sizeof(servercert)};
195+
const_buf key{prvtkey, sizeof(prvtkey)};
196+
if (!server.set_own_cert(cert, key)) {
197+
ESP_LOGE(TAG, "Failed to set own cert");
198+
return;
199+
}
200+
ESP_LOGI(TAG, "openning...");
201+
if (!server.open(true)) {
202+
ESP_LOGE(TAG, "Failed to OPEN! %d", errno);
203+
return;
204+
}
205+
int len = server.read(message, sizeof(message));
206+
if (len < 0) {
207+
ESP_LOGE(TAG, "Failed to read!");
208+
return;
209+
}
210+
ESP_LOGI(TAG, "Received from client: %.*s", len, message);
211+
if (server.write(message, len) < 0) {
212+
ESP_LOGE(TAG, "Failed to write!");
213+
return;
214+
}
215+
ESP_LOGI(TAG, "Written back");
216+
}
217+
218+
219+
#if CONFIG_IDF_TARGET_LINUX
220+
/**
221+
* Linux target: We're already connected, just run the client
222+
*/
223+
#include <thread>
224+
int main()
225+
{
226+
std::thread t2(tls_server);
227+
usleep(1000);
228+
std::thread t1(tls_client);
229+
t1.join();
230+
t2.join();
231+
return 0;
232+
}
233+
#else
234+
/**
235+
* ESP32 chipsets: Need to initialize system components
236+
* and connect to network
237+
*/
238+
239+
#include "nvs_flash.h"
240+
#include "esp_event.h"
241+
#include "protocol_examples_common.h"
242+
#include "esp_netif.h"
243+
244+
extern "C" void app_main()
245+
{
246+
ESP_ERROR_CHECK(nvs_flash_init());
247+
ESP_ERROR_CHECK(esp_netif_init());
248+
ESP_ERROR_CHECK(esp_event_loop_create_default());
249+
ESP_ERROR_CHECK(example_connect());
250+
251+
tls_client();
252+
}
253+
#endif

components/mbedtls_cxx/include/mbedtls_wrap.hpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66
#pragma once
77

88
#include <utility>
99
#include <memory>
10+
#include <mbedtls/timing.h>
11+
#include <mbedtls/ssl_cookie.h>
1012
#include "mbedtls/ssl.h"
1113
#include "mbedtls/entropy.h"
1214
#include "mbedtls/ctr_drbg.h"
@@ -23,6 +25,7 @@ class Tls {
2325
Tls();
2426
virtual ~Tls();
2527
bool init(is_server server, do_verify verify);
28+
bool init_dtls();
2629
bool deinit();
2730
int handshake();
2831
int write(const unsigned char *buf, size_t len);
@@ -32,6 +35,7 @@ class Tls {
3235
bool set_hostname(const char *name);
3336
virtual int send(const unsigned char *buf, size_t len) = 0;
3437
virtual int recv(unsigned char *buf, size_t len) = 0;
38+
virtual int recv_tout(unsigned char *buf, size_t len, int timeout) = 0;
3539
size_t get_available_bytes();
3640

3741
protected:
@@ -42,7 +46,10 @@ class Tls {
4246
mbedtls_ssl_config conf_{};
4347
mbedtls_ctr_drbg_context ctr_drbg_{};
4448
mbedtls_entropy_context entropy_{};
49+
mbedtls_timing_delay_context timer_{};
50+
mbedtls_ssl_cookie_ctx cookie_{};
4551
virtual void delay() {}
52+
bool is_server_{false};
4653

4754
bool set_session();
4855
bool get_session();
@@ -53,6 +60,7 @@ class Tls {
5360
static void print_error(const char *function, int error_code);
5461
static int bio_write(void *ctx, const unsigned char *buf, size_t len);
5562
static int bio_read(void *ctx, unsigned char *buf, size_t len);
63+
static int bio_read_tout(void *ctx, unsigned char *buf, size_t len, uint32_t timeout);
5664
int mbedtls_pk_parse_key( mbedtls_pk_context *ctx,
5765
const unsigned char *key, size_t keylen,
5866
const unsigned char *pwd, size_t pwdlen);

0 commit comments

Comments
 (0)