From d8c310dd8b0de7bfaaf5e2648305588ba3d409d2 Mon Sep 17 00:00:00 2001
From: Peter Harper <peter.harper@raspberrypi.com>
Date: Tue, 18 Feb 2025 19:19:52 +0000
Subject: [PATCH 1/2] Add DTLS example

The server listens for the client to connect and send it a string.
It then sends the same text back to the client.
---
 README.md                                     |   1 +
 pico_w/wifi/CMakeLists.txt                    |   1 +
 pico_w/wifi/dtls/CMakeLists.txt               |  83 +++
 pico_w/wifi/dtls/README.md                    |  65 +++
 pico_w/wifi/dtls/certs/.gitignore             |   1 +
 pico_w/wifi/dtls/certs/makecerts.sh           |  57 +++
 pico_w/wifi/dtls/dtls_common.c                | 374 ++++++++++++++
 pico_w/wifi/dtls/dtls_common.h                |  79 +++
 pico_w/wifi/dtls/dtls_echo_client.c           | 241 +++++++++
 pico_w/wifi/dtls/dtls_echo_server.c           | 156 ++++++
 pico_w/wifi/dtls/host/CMakeLists.txt          |  62 +++
 pico_w/wifi/dtls/host/client.sh               |  16 +
 pico_w/wifi/dtls/host/dtls_host_echo_client.c | 410 +++++++++++++++
 pico_w/wifi/dtls/host/dtls_host_echo_server.c | 471 ++++++++++++++++++
 pico_w/wifi/dtls/host/server.sh               |  14 +
 pico_w/wifi/dtls/lwipopts.h                   |  12 +
 pico_w/wifi/dtls/mbedtls_config.h             |  11 +
 17 files changed, 2054 insertions(+)
 create mode 100644 pico_w/wifi/dtls/CMakeLists.txt
 create mode 100644 pico_w/wifi/dtls/README.md
 create mode 100644 pico_w/wifi/dtls/certs/.gitignore
 create mode 100755 pico_w/wifi/dtls/certs/makecerts.sh
 create mode 100644 pico_w/wifi/dtls/dtls_common.c
 create mode 100644 pico_w/wifi/dtls/dtls_common.h
 create mode 100644 pico_w/wifi/dtls/dtls_echo_client.c
 create mode 100755 pico_w/wifi/dtls/dtls_echo_server.c
 create mode 100644 pico_w/wifi/dtls/host/CMakeLists.txt
 create mode 100755 pico_w/wifi/dtls/host/client.sh
 create mode 100755 pico_w/wifi/dtls/host/dtls_host_echo_client.c
 create mode 100755 pico_w/wifi/dtls/host/dtls_host_echo_server.c
 create mode 100755 pico_w/wifi/dtls/host/server.sh
 create mode 100644 pico_w/wifi/dtls/lwipopts.h
 create mode 100644 pico_w/wifi/dtls/mbedtls_config.h

diff --git a/README.md b/README.md
index 5a436a348..00579a7c3 100644
--- a/README.md
+++ b/README.md
@@ -196,6 +196,7 @@ App|Description
 [picow_http_client](pico_w/wifi/http_client) | Demonstrates how to make http and https requests
 [picow_http_client_verify](pico_w/wifi/http_client) | Demonstrates how to make a https request with server authentication
 [picow_mqtt_client](pico_w/wifi/mqtt) | Demonstrates how to implement a MQTT client application
+[picow_dtls](pico_w/wifi/dtls) | Demonstrates how to implement a simple DTLS client and server
 
 #### FreeRTOS examples
 
diff --git a/pico_w/wifi/CMakeLists.txt b/pico_w/wifi/CMakeLists.txt
index 31797084b..45e5f7d18 100644
--- a/pico_w/wifi/CMakeLists.txt
+++ b/pico_w/wifi/CMakeLists.txt
@@ -19,6 +19,7 @@ else()
     add_subdirectory_exclude_platforms(udp_beacon)
     add_subdirectory_exclude_platforms(http_client)
     add_subdirectory_exclude_platforms(mqtt)
+    add_subdirectory_exclude_platforms(dtls)
 
     if (NOT PICO_MBEDTLS_PATH)
         message("Skipping tls examples as PICO_MBEDTLS_PATH is not defined")
diff --git a/pico_w/wifi/dtls/CMakeLists.txt b/pico_w/wifi/dtls/CMakeLists.txt
new file mode 100644
index 000000000..939bd25cc
--- /dev/null
+++ b/pico_w/wifi/dtls/CMakeLists.txt
@@ -0,0 +1,83 @@
+# Pick DTLS server from environment
+if (DEFINED ENV{DTLS_SERVER} AND (NOT DTLS_SERVER))
+    set(DTLS_SERVER $ENV{DTLS_SERVER})
+    message("Using DTLS_SERVER from environment ('${DTLS_SERVER}')")
+endif()
+if (NOT DTLS_SERVER)
+    message("Skipping DTLS example as DTLS_SERVER is not defined")
+    return()
+endif()
+set(DTLS_SERVER "${DTLS_SERVER}" CACHE INTERNAL "DTLS server for examples")
+if (NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/certs/${DTLS_SERVER}")
+    message("Generate DTLS certs by running ${CMAKE_CURRENT_LIST_DIR}/certs/makecerts.sh")
+    return()
+endif()
+
+set(RANDOM_DATA_LEN 32)
+string(RANDOM LENGTH ${RANDOM_DATA_LEN} RANDOM_DATA)
+
+pico_add_library(pico_dtls)
+target_include_directories(pico_dtls_headers INTERFACE
+    ${CMAKE_CURRENT_LIST_DIR}
+    )
+target_sources(pico_dtls INTERFACE
+    ${CMAKE_CURRENT_LIST_DIR}/dtls_common.c
+    )
+pico_mirrored_target_link_libraries(pico_dtls INTERFACE
+    pico_lwip_mbedtls
+    pico_mbedtls
+    )
+target_compile_definitions(pico_dtls INTERFACE
+    CUSTOM_MBEDTLS_ENTROPY_PTR=\"${RANDOM_DATA}\"
+    CUSTOM_MBEDTLS_ENTROPY_LEN=${RANDOM_DATA_LEN}
+    )
+
+set(TARGET_NAME dtls_echo_server)
+
+add_executable(${TARGET_NAME}
+    dtls_echo_server.c
+    )
+target_include_directories(${TARGET_NAME} PRIVATE
+    ${CMAKE_CURRENT_LIST_DIR}
+    ${CMAKE_CURRENT_LIST_DIR}/..
+    )
+target_link_libraries(${TARGET_NAME} PRIVATE
+    pico_cyw43_arch_lwip_threadsafe_background
+    pico_lwip_nosys
+    pico_stdlib
+    pico_dtls
+    )
+target_compile_definitions(${TARGET_NAME} PRIVATE
+    DTLS_CERT_INC=\"certs/${DTLS_SERVER}/dtls_server.inc\"
+    )
+target_compile_definitions(${TARGET_NAME} PRIVATE
+    CYW43_HOST_NAME=\"pico_dtls_example\"
+    WIFI_SSID=\"${WIFI_SSID}\"
+    WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
+    )
+pico_add_extra_outputs(${TARGET_NAME})
+
+set(TARGET_NAME dtls_echo_client)
+
+add_executable(${TARGET_NAME}
+    dtls_echo_client.c
+    )
+target_include_directories(${TARGET_NAME} PRIVATE
+    ${CMAKE_CURRENT_LIST_DIR}
+    ${CMAKE_CURRENT_LIST_DIR}/..
+    )
+target_link_libraries(${TARGET_NAME} PRIVATE
+    pico_cyw43_arch_lwip_threadsafe_background
+    pico_lwip_nosys
+    pico_stdlib
+    pico_dtls
+    )
+target_compile_definitions(${TARGET_NAME} PRIVATE
+    DTLS_SERVER=\"${DTLS_SERVER}\"
+    DTLS_CERT_INC=\"certs/${DTLS_SERVER}/dtls_client.inc\"
+    )
+target_compile_definitions(${TARGET_NAME} PRIVATE
+    WIFI_SSID=\"${WIFI_SSID}\"
+    WIFI_PASSWORD=\"${WIFI_PASSWORD}\"
+    )
+pico_add_extra_outputs(${TARGET_NAME})
diff --git a/pico_w/wifi/dtls/README.md b/pico_w/wifi/dtls/README.md
new file mode 100644
index 000000000..3607b297e
--- /dev/null
+++ b/pico_w/wifi/dtls/README.md
@@ -0,0 +1,65 @@
+# Setup
+
+These examples demonstrate how to use dtls via mbedtls on a Pico W device.
+You need to define DTLS_SERVER and run the makecerts.sh script to generate the certificates and keys needed for the server and client.
+```
+export DTLS_SERVER=myserver
+cd dtls/certs
+./makecerts.sh
+```
+The examples should now build.
+
+# Running the dtls examples
+
+The client connects to a server and sends it a few lines of text which it expects to be sent back.
+
+You can build and run the client and server examples on two Pico W devices. To make testing easier to test with just one Pico W device, you can run the server or client on a Linux host.
+The client.sh and server.sh scripts show how to run the client or server with openssl. The host folder contains source code for a version of the client and server using mbedtls.
+
+## Using openssl
+
+The host/server.sh and host/client/sh scripts demonstrate how to use DTLS with openssl, although you will have to echo text manually.
+For example, run dtls_echo_client on a Pico W device and the server.sh on a linux PC.
+```
+export DTLS_SERVER=myserver
+cd host
+./server.sh
+```
+The scripts use the keys in certs/myserver
+
+Or run dtls_echo_server on a Pico W device and client.sh on a linux PC. The host name for the server on Pico W is set to `pico_dtls_example`"`. Make sure you build the code for the Pico W and run the client with the right DTLS_SERVER name (and matching keys in the client and server) or else the SSL handshake will fail.
+```
+export DTLS_SERVER=pico_dtls_example
+ping pico_dtls_example # make sure you can reach it!
+cd host
+./client.sh
+```
+The scripts use the keys in certs/pico_dtls_example. Type a sentence into the client.sh console and the server should send it back as a reply.
+
+## Using mbedtls
+
+The host folder contains C versions of the examples that can be compiled natively for the host. They are modified versions of mbedtls examples.
+You can build these on a rpi linux device to act as the server or client. The mbedtls library in PICO_SDK_PATH will be used to build the host code.
+
+For example, run dtls_echo_client on a Pico W device and the dtls_host_echo_server on a linux PC.
+```
+export DTLS_SERVER=myserver
+cd host
+mkdir build
+cd build
+cmake ..
+make -j8
+./dtls_host_echo_server
+
+```
+Or run dtls_echo_server on a Pico W device and dtls_host_echo_client on a linux PC.
+```
+export DTLS_SERVER=pico_dtls_example
+cd host
+mkdir build
+cd build
+cmake ..
+make -j8
+./dtls_host_echo_client
+```
+Remember to build the client and server for the host and Pico W with the correct value of DTLS_SERVER or else the handshake will fail.
\ No newline at end of file
diff --git a/pico_w/wifi/dtls/certs/.gitignore b/pico_w/wifi/dtls/certs/.gitignore
new file mode 100644
index 000000000..355164c12
--- /dev/null
+++ b/pico_w/wifi/dtls/certs/.gitignore
@@ -0,0 +1 @@
+*/
diff --git a/pico_w/wifi/dtls/certs/makecerts.sh b/pico_w/wifi/dtls/certs/makecerts.sh
new file mode 100755
index 000000000..efdbe7ad9
--- /dev/null
+++ b/pico_w/wifi/dtls/certs/makecerts.sh
@@ -0,0 +1,57 @@
+#!/usr/bin/bash
+
+if [ "${PWD##*/}" != "certs" ]; then
+    echo Run this in the certs folder
+    exit 1
+fi
+if [ -z "$DTLS_SERVER" ]; then
+    echo Define DTLS_SERVER
+    exit 1
+fi
+SERVER_NAME=$DTLS_SERVER
+
+if [ -d "$SERVER_NAME" ]; then
+    echo Run \"rm -fr $SERVER_NAME\" to regenerate these keys
+    exit 1
+fi
+mkdir $SERVER_NAME
+echo Generating keys in $PWD/$SERVER_NAME
+
+openssl genrsa -out $SERVER_NAME/ca.key 2048
+openssl req -new -x509 -days 99999 -key $SERVER_NAME/ca.key -out $SERVER_NAME/ca.crt -subj "/C=UK/ST=Cambridgeshire/L=Cambridge/O=Raspberry Pi Ltd/OU=Software/CN=rpiroot"
+
+openssl genrsa -out $SERVER_NAME/server.key 2048
+openssl req -new -out $SERVER_NAME/server.csr -key $SERVER_NAME/server.key -subj "/C=UK/ST=Cambridgeshire/L=Cambridge/O=Raspberry Pi Ltd/OU=Software/CN=$SERVER_NAME"
+openssl x509 -req -in $SERVER_NAME/server.csr -CA $SERVER_NAME/ca.crt -CAkey $SERVER_NAME/ca.key -CAcreateserial -out $SERVER_NAME/server.crt -days 9999
+
+openssl genrsa -out $SERVER_NAME/client.key 2048
+openssl req -new -out $SERVER_NAME/client.csr -key $SERVER_NAME/client.key -subj "/C=UK/ST=Cambridgeshire/L=Cambridge/O=Raspberry Pi Ltd/OU=Software/CN=$SERVER_NAME"
+openssl x509 -req -in $SERVER_NAME/client.csr -CA $SERVER_NAME/ca.crt -CAkey $SERVER_NAME/ca.key -CAcreateserial -out $SERVER_NAME/client.crt -days 999
+
+echo -n \#define DTLS_ROOT_CERT \" > $SERVER_NAME/dtls_client.inc
+cat $SERVER_NAME/ca.crt | awk '{printf "%s\\n\\\n", $0}' >> $SERVER_NAME/dtls_client.inc
+echo "\"" >> $SERVER_NAME/dtls_client.inc
+echo >> $SERVER_NAME/dtls_client.inc
+
+echo -n \#define DTLS_KEY \" >> $SERVER_NAME/dtls_client.inc
+cat $SERVER_NAME/client.key | awk '{printf "%s\\n\\\n", $0}' >> $SERVER_NAME/dtls_client.inc
+echo "\"" >> $SERVER_NAME/dtls_client.inc
+echo >> $SERVER_NAME/dtls_client.inc
+
+echo -n \#define DTLS_CERT \" >> $SERVER_NAME/dtls_client.inc
+cat $SERVER_NAME/client.crt | awk '{printf "%s\\n\\\n", $0}' >> $SERVER_NAME/dtls_client.inc
+echo "\"" >> $SERVER_NAME/dtls_client.inc
+
+echo -n \#define DTLS_ROOT_CERT \" > $SERVER_NAME/dtls_server.inc
+cat $SERVER_NAME/ca.crt | awk '{printf "%s\\n\\\n", $0}' >> $SERVER_NAME/dtls_server.inc
+echo "\"" >> $SERVER_NAME/dtls_server.inc
+echo >> $SERVER_NAME/dtls_server.inc
+
+echo -n \#define DTLS_KEY \" >> $SERVER_NAME/dtls_server.inc
+cat $SERVER_NAME/server.key | awk '{printf "%s\\n\\\n", $0}' >> $SERVER_NAME/dtls_server.inc
+echo "\"" >> $SERVER_NAME/dtls_server.inc
+echo >> $SERVER_NAME/dtls_server.inc
+
+echo -n \#define DTLS_CERT \" >> $SERVER_NAME/dtls_server.inc
+cat $SERVER_NAME/server.crt | awk '{printf "%s\\n\\\n", $0}' >> $SERVER_NAME/dtls_server.inc
+echo "\"" >> $SERVER_NAME/dtls_server.inc
diff --git a/pico_w/wifi/dtls/dtls_common.c b/pico_w/wifi/dtls/dtls_common.c
new file mode 100644
index 000000000..438036dd5
--- /dev/null
+++ b/pico_w/wifi/dtls/dtls_common.c
@@ -0,0 +1,374 @@
+#include <string.h>
+#include "dtls_common.h"
+
+#ifndef DTLS_CERT_INC
+#error Need to define DTLS_CERT_INC
+#endif
+#include DTLS_CERT_INC
+
+static const uint8_t dtls_root_cert[] = DTLS_ROOT_CERT;
+static const uint8_t dtls_key[] = DTLS_KEY;
+static const uint8_t dtls_cert[] = DTLS_CERT;
+
+#include "mbedtls/net_sockets.h"
+
+// If the timeout is zero the dtls connection will not timeout
+// If the timeout is set then the dtls connection will be dropped if no data is received within this time
+// Having a timeout is useful as there's no way for the client/server to know if the other end disappears
+// Having a timeout implies you need some sort of keep alive from the client to the server?
+#ifndef DTLS_READ_TIMEOUT_MS
+#define DTLS_READ_TIMEOUT_MS 30000
+#endif
+
+// 0 No debug
+// 1 Error
+// 2 State change
+// 3 Informational
+// 4 Verbose
+#ifndef MBEDTLS_DEBUG_LEVEL
+#define MBEDTLS_DEBUG_LEVEL 1
+#endif
+
+static void dtls_timer_callback(__unused async_context_t *context, async_at_time_worker_t *worker) {
+    DTLS_DEBUG("pico_mbedtls_timing_worker_callback\n");
+    dtls_processing((dtls_session_t*)worker->user_data, true);
+}
+
+static void dtls_timer_set_delay(void *data, uint32_t int_ms, uint32_t fin_ms)
+{
+    pico_mbedtls_timer_context_t *ctx = (pico_mbedtls_timer_context_t*)data;
+    if (fin_ms == 0) {
+        async_context_remove_at_time_worker(ctx->async_context, &ctx->worker);
+        ctx->fin_time = nil_time;
+        DTLS_DEBUGV("dtls_timer_set_delay cancelled\n");
+        return;
+    }
+    // The async worker will get called
+    DTLS_DEBUGV("dtls_timer_set_delay fin_ms=%u\n", fin_ms);
+    async_context_add_at_time_worker_in_ms(ctx->async_context, &ctx->worker, fin_ms);
+    ctx->fin_time = make_timeout_time_ms(fin_ms);
+    ctx->int_time = make_timeout_time_ms(int_ms);
+}
+
+static int dtls_timer_get_delay(void *data)
+{
+    pico_mbedtls_timer_context_t *ctx = (pico_mbedtls_timer_context_t*)data;
+    if (is_nil_time(ctx->fin_time)) {
+        return -1 ;
+    }
+    if (time_reached(ctx->fin_time)) {
+        DTLS_DEBUG("dtls_timer_get_delay FIN\n");
+        return 2;
+    }
+    if (time_reached(ctx->int_time)) {
+        DTLS_DEBUG("dtls_timer_get_delay INT\n");
+        return 1;
+    }
+    return 0;
+}
+
+static void init_dtls_timer_context(pico_mbedtls_timer_context_t *timer_ctx, async_context_t *async_context, dtls_session_t *session) {
+    timer_ctx->async_context = async_context;
+    timer_ctx->worker.do_work = dtls_timer_callback;
+    timer_ctx->worker.user_data = session;
+    timer_ctx->fin_time = nil_time;
+    mbedtls_ssl_set_timer_cb(&session->ssl, timer_ctx, dtls_timer_set_delay, dtls_timer_get_delay);
+}
+
+static void ssl_debug(void *ctx, int level, const char *file, int line, const char *str)
+{
+    (void)ctx;
+    (void)level;
+    DTLS_DEBUG("%s:%04d: %s", file, line, str);
+}
+
+static int bio_send(void *arg, const unsigned char *dataptr, size_t size)
+{
+    DTLS_DEBUG("bio_send %d\n", size);
+    dtls_session_t *session = (dtls_session_t*)arg;
+    assert(session && session->udp_pcb);
+    assert(session->port != 0 && !ip_addr_isany_val(session->addr));
+    assert(session->active);
+
+    int written = 0;
+    size_t size_left = size;
+
+    while (size_left) {
+        u16_t write_len = (u16_t)LWIP_MIN(size_left, 0xFFFF);
+        struct pbuf* p = pbuf_alloc(PBUF_TRANSPORT, write_len, PBUF_RAM);
+        if (!p) {
+            DTLS_ERROR("pbuf alloc failed\n");
+            break;
+        }
+        memcpy(p->payload, dataptr, write_len);
+        int err = udp_sendto(session->udp_pcb, p, &session->addr, session->port);
+        DTLS_DEBUG("udp_sendto %d\n", err);
+        pbuf_free(p);
+        assert(err == ERR_OK);
+        if (err == ERR_OK) {
+            written += write_len;
+            size_left -= write_len;
+            dataptr += write_len;
+        } else if (err == ERR_MEM) {
+            break;
+        } else {
+            return MBEDTLS_ERR_NET_SEND_FAILED;
+        }
+    }
+    return written;
+}
+
+static int bio_recv(void *arg, unsigned char *buf, size_t len)
+{
+    dtls_session_t *session = (dtls_session_t*)arg;
+    assert(session && session->udp_pcb);
+
+    struct pbuf *p = session->rx;
+    if (!p || (p->len == 0 && !p->next)) {
+        if (p) {
+          pbuf_free(p);
+        }
+        session->rx = NULL;
+        return MBEDTLS_ERR_SSL_WANT_READ;
+    }
+
+    uint16_t copy_len = (u16_t)LWIP_MIN(len, p->tot_len);
+    DTLS_DEBUG("bio_recv %d/%d\n", copy_len, len);
+    uint16_t ret = pbuf_copy_partial(p, buf, copy_len, 0);
+    p = pbuf_free_header(p, ret);
+    if (p && p->len == 0) {
+        session->rx = p->next;
+        p->next = NULL;
+        pbuf_free(p);
+    }
+    session->rx = p;
+    return ret;
+}
+
+int dtls_base_init(dtls_base_t *base)
+{
+    int ret = ERR_OK;
+#if defined(MBEDTLS_DEBUG_C)
+    mbedtls_debug_set_threshold(MBEDTLS_DEBUG_LEVEL);
+#endif
+    mbedtls_ssl_config_init(&base->conf);
+    mbedtls_ctr_drbg_init(&base->ctr_drbg);
+    mbedtls_ssl_conf_rng(&base->conf, mbedtls_ctr_drbg_random, &base->ctr_drbg);
+    mbedtls_ssl_conf_dbg(&base->conf, ssl_debug, NULL);
+    mbedtls_ssl_conf_read_timeout(&base->conf, DTLS_READ_TIMEOUT_MS);
+    mbedtls_entropy_init(&base->entropy);
+    if ((ret = mbedtls_ctr_drbg_seed(&base->ctr_drbg, mbedtls_entropy_func, &base->entropy, (const unsigned char *)CUSTOM_MBEDTLS_ENTROPY_PTR, CUSTOM_MBEDTLS_ENTROPY_LEN)) != 0) {
+        DTLS_ERROR("Failed to seed rnd %d", ret);
+        return ret;
+    }
+    mbedtls_x509_crt_init(&base->cert);
+    ret = mbedtls_x509_crt_parse(&base->cert, dtls_cert, sizeof(dtls_cert));
+    if (ret != 0) {
+        DTLS_ERROR("Failed to parse client cert %d", ret);
+        return ret;
+    }
+    ret = mbedtls_x509_crt_parse(&base->cert, dtls_root_cert, sizeof(dtls_root_cert));
+    if (ret != 0) {
+        DTLS_ERROR("Failed to parse ca cert %d", ret);
+        return ret;
+    }
+    mbedtls_ssl_conf_ca_chain(&base->conf, base->cert.next, NULL);
+    mbedtls_pk_init(&base->pkey);
+    ret = mbedtls_pk_parse_key(&base->pkey, dtls_key, sizeof(dtls_key), NULL, 0);
+    if (ret != 0) {
+        DTLS_ERROR("Failed to parse key");
+        return ret;
+    }
+    if ((ret = mbedtls_ssl_conf_own_cert(&base->conf, &base->cert, &base->pkey)) != 0) {
+        DTLS_ERROR("failed to load own cert %d", ret);
+        return ret;
+    }
+    mbedtls_ssl_conf_authmode(&base->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+#ifdef DTLS_SERVER
+    if ((ret = mbedtls_ssl_config_defaults(&base->conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+        DTLS_ERROR("ssl client config failed %d", ret);
+        return ret;
+    }
+#else
+    if ((ret = mbedtls_ssl_config_defaults(&base->conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+        DTLS_ERROR("ssl server config failed %d", ret);
+        return ret;
+    }
+    mbedtls_ssl_cookie_init(&base->cookie_ctx);
+    if ((ret = mbedtls_ssl_cookie_setup(&base->cookie_ctx, mbedtls_ctr_drbg_random, &base->ctr_drbg)) != 0) {
+        DTLS_ERROR("cookie setup failed %d", ret);
+        return ret;
+    }
+    mbedtls_ssl_conf_dtls_cookies(&base->conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &base->cookie_ctx);
+#endif
+    return ret;
+}
+
+void dtls_base_deinit(dtls_base_t *base)
+{
+    mbedtls_x509_crt_free(&base->cert);
+    mbedtls_pk_free(&base->pkey);
+#ifndef DTLS_SERVER
+    mbedtls_ssl_cookie_free(&base->cookie_ctx);
+#endif
+    mbedtls_ssl_config_free(&base->conf);
+    mbedtls_ctr_drbg_free(&base->ctr_drbg);
+    mbedtls_entropy_free(&base->entropy);
+}
+
+int dtls_session_init(dtls_session_t *session, dtls_base_t *base, async_context_t *context, const char *hostname)
+{
+    int ret;
+    mbedtls_ssl_init(&session->ssl);
+    if ((ret = mbedtls_ssl_setup(&session->ssl, &base->conf)) != 0) {
+        DTLS_ERROR("ssl setup failed %d", ret);
+        return ret;
+    }
+    mbedtls_ssl_set_bio(&session->ssl, session, bio_send, bio_recv, NULL);
+    init_dtls_timer_context(&base->timer_ctx, context, session);
+    if (hostname) {
+        if ((ret = mbedtls_ssl_set_hostname(&session->ssl, hostname)) != 0) { // server hostname
+            DTLS_ERROR("Failed to set host name %d", ret);
+            return ret;
+        }
+    }
+    return ret;
+}
+
+void dtls_session_deinit(dtls_session_t *session)
+{
+    mbedtls_ssl_free(&session->ssl);
+}
+
+// receive tls data
+static int recv_data(dtls_session_t *session)
+{
+    DTLS_DEBUG("recv_data\n");
+    int ret;
+    do {
+        struct pbuf *buf = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL);
+        if (buf == NULL) {
+            DTLS_ERROR("pbuf_alloc failed\n");
+            assert(0); // todo
+            return ERR_OK;
+        }
+        ret = mbedtls_ssl_read(&session->ssl, (unsigned char *)buf->payload, PBUF_POOL_BUFSIZE);
+        if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+            pbuf_free(buf);
+            return ERR_OK;
+        }
+        if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { // the other end is closing the connection
+            DTLS_INFO("Peer closed the connection\n");
+            pbuf_free(buf);
+            return dtls_session_close(session);
+        }
+        if (ret < 0) {
+            DTLS_ERROR("mbedtls_ssl_read error -0x%X\n", -ret);
+            pbuf_free(buf);
+            return dtls_session_close(session);
+        }
+        if (ret > 0) {
+            assert(ret <= PBUF_POOL_BUFSIZE);
+            pbuf_realloc(buf, (u16_t)ret);
+            if (session->handle_data_rx_cb) {
+                int err = session->handle_data_rx_cb(session, buf);
+                if (err != ERR_OK) {
+                    if (err == ERR_ABRT) {
+                      return ERR_ABRT;
+                    }
+                    return ERR_OK;
+                }
+            } else {
+                pbuf_free(buf);
+            }
+        } else {
+            pbuf_free(buf);
+        }
+    } while (ret > 0 && session->active);
+    return ERR_OK;
+}
+
+int dtls_processing(dtls_session_t *session, bool timeout)
+{
+    DTLS_DEBUG("dtls_processing timeout=%d\n", timeout);
+    int ret;
+    if (session->close_queued) {
+        dtls_session_close(session);
+    }
+    if (!session->handshake_done) {
+        ret = mbedtls_ssl_handshake(&session->ssl);
+        if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+            // handshake not done, wait for more recv calls
+            return ERR_OK;
+        }
+        if (ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) {
+            // Handshake ok, client should reconnect with correct cookie
+            return dtls_session_close(session);
+        }
+        if (ret != 0) {
+            DTLS_ERROR("mbedtls_ssl_handshake failed: -0x%X\n", -ret);
+            dtls_session_close(session);
+            return ret;
+        }
+        if (session->handle_handshake_done_cb) {
+            session->handle_handshake_done_cb(session); // todo: handle error?
+        }
+        session->handshake_done = true;
+    }
+    if (session->rx == NULL && !timeout) {
+        DTLS_DEBUG("No data\n");
+        return ERR_OK;
+    }
+    return recv_data(session);
+}
+
+int dtls_session_close(dtls_session_t *session) {
+    // send notification
+    int ret = mbedtls_ssl_close_notify(&session->ssl);
+    DTLS_DEBUG("close_notify %d\n", ret);
+    if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+        session->close_queued = true;
+        return ret;
+    }
+    if (session->handle_session_closed_cb) {
+        session->handle_session_closed_cb(session);
+    }
+    mbedtls_ssl_session_reset(&session->ssl);
+    session->close_queued = false;
+    session->handshake_done = false;
+    if (session->rx) {
+        pbuf_free(session->rx);
+        session->rx = NULL;
+    }
+    // clear client details
+    session->port = 0;
+    ip_addr_set_zero(&session->addr);
+    return ERR_OK;
+}
+
+int dtls_write(dtls_session_t *session, const uint8_t *data, size_t data_len) {
+    int ret = mbedtls_ssl_write(&session->ssl, data, data_len);
+    assert(ret > 0);
+    if (ret < 0) {
+        DTLS_ERROR("mbedtls_ssl_write failed %d", ret);
+    }
+    return ret;
+}
+
+int dtls_set_client(dtls_session_t *session, const ip_addr_t *addr, u16_t port) {
+    ip_addr_copy(session->addr, *addr);
+    session->port = port;
+
+    char client_ip[48];
+    size_t client_ip_len;
+    ipaddr_ntoa_r(addr, client_ip, sizeof(client_ip));
+    client_ip_len = strlen(client_ip);
+    client_ip_len += snprintf(client_ip + client_ip_len, sizeof(client_ip) - client_ip_len, ":%u", port);
+
+    // For HelloVerifyRequest cookies
+    int ret = mbedtls_ssl_set_client_transport_id(&session->ssl, (unsigned char *)client_ip, client_ip_len);
+    if (ret == ERR_OK) {
+        DTLS_DEBUG("New client %s\n", client_ip);
+    }
+    return ret;
+}
\ No newline at end of file
diff --git a/pico_w/wifi/dtls/dtls_common.h b/pico_w/wifi/dtls/dtls_common.h
new file mode 100644
index 000000000..1e40b1fc5
--- /dev/null
+++ b/pico_w/wifi/dtls/dtls_common.h
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2023 Raspberry Pi Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _DTLS_COMMON_H_
+#define _DTLS_COMMON_H_
+
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/ssl_cookie.h"
+#include "mbedtls/debug.h"
+
+#include "lwip/udp.h"
+#include "pico/async_context.h"
+#include "pico/time.h"
+
+#ifndef DTLS_PRINT
+#define DTLS_PRINT printf
+#endif
+#define DTLS_DEBUGV(...)
+#ifdef NDEBUG
+#define DTLS_DEBUG(...)
+#define DTLS_INFO(...)
+#else
+#define DTLS_DEBUG DTLS_PRINT
+#define DTLS_INFO DTLS_PRINT
+#endif
+#define DTLS_ERROR DTLS_PRINT
+
+typedef struct pico_mbedtls_timer_context_t_ {
+    async_context_t *async_context;
+    async_at_time_worker_t worker;
+    absolute_time_t fin_time;
+    absolute_time_t int_time;
+} pico_mbedtls_timer_context_t;
+
+typedef struct dtls_base_t_ {
+    mbedtls_ssl_config conf;
+    mbedtls_ctr_drbg_context ctr_drbg;
+    mbedtls_entropy_context entropy;
+    pico_mbedtls_timer_context_t timer_ctx;
+    mbedtls_x509_crt cert;
+#ifndef DTLS_SERVER
+    mbedtls_ssl_cookie_ctx cookie_ctx;
+#endif
+    mbedtls_pk_context pkey;
+} dtls_base_t;
+
+typedef struct dtls_session_t_ {
+    mbedtls_ssl_context ssl;
+    struct udp_pcb *udp_pcb;
+    struct pbuf *rx;
+    ip_addr_t addr;
+    u16_t port;
+    bool close_queued;
+    bool handshake_done;
+    bool active;
+    void *user_data;
+    // callbacks to the user
+    int (*handle_data_rx_cb)(struct dtls_session_t_*, struct pbuf*);
+    int (*handle_handshake_done_cb)(struct dtls_session_t_*);
+    void (*handle_session_closed_cb)(struct dtls_session_t_*);
+} dtls_session_t;
+
+
+int dtls_base_init(dtls_base_t *base);
+void dtls_base_deinit(dtls_base_t *base);
+
+int dtls_session_init(dtls_session_t *session, dtls_base_t *base, async_context_t *context, const char *hostname);
+int dtls_set_client(dtls_session_t *session, const ip_addr_t *addr, u16_t port);
+int dtls_write(dtls_session_t *session, const uint8_t *data, size_t data_len);
+int dtls_processing(dtls_session_t *session, bool timeout);
+int dtls_session_close(dtls_session_t *session);
+void dtls_session_deinit(dtls_session_t *session);
+
+#endif
diff --git a/pico_w/wifi/dtls/dtls_echo_client.c b/pico_w/wifi/dtls/dtls_echo_client.c
new file mode 100644
index 000000000..781a758d2
--- /dev/null
+++ b/pico_w/wifi/dtls/dtls_echo_client.c
@@ -0,0 +1,241 @@
+#include <stdio.h>
+#include <string.h>
+#include "pico/stdlib.h"
+
+#include "pico/cyw43_arch.h"
+#include "pico/lwip_nosys.h"
+#include "lwip/netif.h"
+#include "lwip/udp.h"
+#include "lwip/dns.h"
+
+#include "dtls_common.h"
+
+typedef struct client_state_t_ {
+    dtls_base_t base;
+    dtls_session_t session;
+    bool complete;
+    int test_string_id;
+    int expected_len;
+} client_state_t;
+
+static const char *test_data[] = {
+    "if you can see this, it worked!",
+    "This is the second request",
+    "The quick brown fox jumped over the lazy dog",
+};
+static bool test_passed = false;
+
+#ifndef DTLS_SERVER_PORT
+#define DTLS_SERVER_PORT 4433
+#endif
+#ifndef DTLS_SERVER
+#error Need to define DTLS_SERVER
+#endif
+
+// Forward declarations
+static int client_data_rx(dtls_session_t *session, struct pbuf *p);
+static int client_handshake_done(dtls_session_t *session);
+static void client_session_closed(dtls_session_t *session);
+
+// Callback to receive data
+static void client_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
+{
+    client_state_t *state = (client_state_t*)arg;
+    assert(state && pcb && state->session.udp_pcb == pcb);
+    if (p == NULL) {
+        return;
+    }
+    if (state->session.port == 0 || ip_addr_isany_val(state->session.addr)) {
+        return;
+    }
+
+    assert(port == state->session.port);
+    assert(ip_addr_cmp(addr, &state->session.addr));
+
+    if (state->session.rx == NULL) {
+        state->session.rx = p;
+    } else {
+        assert(p->tot_len + (int)p->len <= 0xFFFF);
+        pbuf_cat(state->session.rx, p);
+    }
+
+    DTLS_DEBUG("client_udp_recv_cb %d\n", p->tot_len);
+    dtls_processing(&state->session, false);
+}
+
+static int start_client(client_state_t *state, const ip_addr_t *addr, int port)
+{
+    assert(ip_addr_isany_val(state->session.addr) && !state->session.active);
+    // initialise the session
+    ip_addr_copy(state->session.addr, *addr);
+    state->session.port = port;
+    state->session.active = true;
+    state->session.user_data = state;
+    state->session.udp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
+
+    // set the callbacks
+    state->session.handle_data_rx_cb = client_data_rx;
+    state->session.handle_handshake_done_cb = client_handshake_done;
+    state->session.handle_session_closed_cb = client_session_closed;
+
+    if (!state->session.udp_pcb) {
+        DTLS_ERROR("Failed to allocate udp pcb");
+        return ERR_MEM;
+    }
+    int ret = udp_connect(state->session.udp_pcb, addr, port);
+    if (ret != ERR_OK) {
+        DTLS_ERROR("udp_connect failed %d", ret);
+        return ret;
+    }
+    // set receive callback
+    udp_recv(state->session.udp_pcb, client_udp_recv_cb, state);
+    // start handshake
+    ret = dtls_processing(&state->session, false);
+    if (ret != ERR_OK) {
+        DTLS_ERROR("dtls_processing failed %d", ret);
+        return ret;
+    }
+    return ERR_OK;
+}
+
+// Call back with a DNS result
+static void server_address_found(const char *hostname, const ip_addr_t *addr, void *arg) {
+    client_state_t *state = (client_state_t*)arg;
+    if (addr) {
+        DTLS_DEBUG("server address %s\n", ipaddr_ntoa(addr));
+        if (start_client(state, addr, DTLS_SERVER_PORT) != 0) {
+            panic("Client request failed");
+        }
+    } else {
+        panic("dns request failed"); // todo: retry?
+    }
+}
+
+// Send a string to the server
+static int send_request(dtls_session_t *session, const char *string) {
+    // send some data to the server
+    DTLS_DEBUG("CLIENT OUT: %s\n", string);
+    int ret = dtls_write(session, (uint8_t*)string, strlen(string));
+    if (ret < 0) {
+        return ret;
+    }
+    assert(ret == strlen(string));
+    DTLS_DEBUG("client sent: %d bytes\n", ret);
+    client_state_t *state = (client_state_t*)session->user_data;
+    state->expected_len = ret;
+    return ERR_OK;
+}
+
+// Handle received data
+static int client_data_rx(dtls_session_t *session, struct pbuf *p)
+{
+    client_state_t *state = (client_state_t*)session->user_data;
+    assert(state->expected_len > 0);
+    uint16_t tot_len = p->tot_len;
+    // print data received
+    int offset = 0;
+    while(offset < tot_len) {
+        char data_in[32];
+        uint16_t req_len = LWIP_MIN(tot_len - offset, sizeof(data_in));
+        assert(req_len > 0);
+        uint16_t data_in_len = pbuf_copy_partial(p, data_in, sizeof(data_in), offset);
+        assert(data_in_len > 0);
+        DTLS_DEBUG("CLIENT IN: (got %d need %d) %.*s\n", data_in_len, state->expected_len, data_in_len, data_in);
+        // check the echo is correct
+        const uint16_t string_len = (uint16_t)strlen(test_data[state->test_string_id]);
+        if (strncmp(test_data[state->test_string_id] + string_len - state->expected_len, data_in, LWIP_MIN(state->expected_len, data_in_len)) != 0) {
+            DTLS_ERROR("Echo mismatch want \"%s\" got \"%s\"\n", test_data[state->test_string_id] + string_len - state->expected_len, data_in);
+            assert(false);
+        }
+        offset += data_in_len;
+        state->expected_len -= data_in_len;
+    }
+    pbuf_free(p);
+    if (state->expected_len <= 0) {
+        // Send the next request or close the session
+        client_state_t *state = (client_state_t*)session->user_data;
+        if (++state->test_string_id < count_of(test_data)) {
+            return send_request(session, test_data[state->test_string_id]);
+        } else {
+            test_passed = true;
+            return dtls_session_close(session);
+        }
+    }
+    return ERR_OK;
+}
+
+// Called when handshake has completed
+static int client_handshake_done(dtls_session_t *session)
+{
+    client_state_t *state = (client_state_t*)session->user_data;
+    return send_request(session, test_data[state->test_string_id]);
+}
+
+// Called when session is actually ready to close
+static void client_session_closed(dtls_session_t *session)
+{
+    client_state_t *state = (client_state_t*)session->user_data;
+    state->complete = true;
+    session->active = false;
+    // Get rid of udp pcb
+    if (session->udp_pcb) {
+        udp_remove(session->udp_pcb);
+        session->udp_pcb = NULL;
+    }
+}
+
+int main() {
+    stdio_init_all();
+
+    // Create a context
+    if (cyw43_arch_init()) {
+        printf("failed to initialise\n");
+        return 1;
+    }
+    cyw43_arch_enable_sta_mode();
+    if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
+        printf("failed to connect\n");
+        return 1;
+    }
+    DTLS_INFO("Client ip address %s\n", ipaddr_ntoa(&(netif_list->ip_addr)));
+
+    client_state_t state;
+    memset(&state, 0, sizeof(state));
+
+    int ret = dtls_base_init(&state.base);
+    if (ret != ERR_OK) {
+        panic("Failed to initialise dtls");
+    }
+    ret = dtls_session_init(&state.session, &state.base, cyw43_arch_async_context(), DTLS_SERVER);
+    if (ret != ERR_OK) {
+        panic("Failed to initialise dtls session");
+    }
+
+    cyw43_arch_lwip_begin();
+    ip_addr_t addr;
+    ret = dns_gethostbyname(DTLS_SERVER, &addr, server_address_found, &state);
+    cyw43_arch_lwip_end();
+    if (ret == ERR_OK) {
+        cyw43_arch_lwip_begin();
+        ret = start_client(&state, &addr, DTLS_SERVER_PORT);
+        cyw43_arch_lwip_end();
+        if (ret != 0) {
+            panic("client request failed %d", ret);
+        }
+    } else if (ret != ERR_INPROGRESS) {
+        panic("dns request failed");
+    }
+
+    while(!state.complete) {
+        cyw43_arch_poll();
+        cyw43_arch_wait_for_work_until(make_timeout_time_ms(1000));
+    }
+    lwip_nosys_deinit(cyw43_arch_async_context());
+    cyw43_arch_deinit();
+
+    dtls_session_deinit(&state.session);
+    dtls_base_deinit(&state.base);
+
+    DTLS_INFO("All done. Test %s\n", test_passed ? "passed" : "failed");
+    sleep_ms(100);
+}
diff --git a/pico_w/wifi/dtls/dtls_echo_server.c b/pico_w/wifi/dtls/dtls_echo_server.c
new file mode 100755
index 000000000..ec5f367fc
--- /dev/null
+++ b/pico_w/wifi/dtls/dtls_echo_server.c
@@ -0,0 +1,156 @@
+/**
+ * Copyright (c) 2023 Raspberry Pi Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "pico/stdlib.h"
+
+#include "pico/cyw43_arch.h"
+#include "pico/lwip_nosys.h"
+#include "lwip/netif.h"
+
+#include "dtls_common.h"
+
+typedef struct server_state_t_ {
+    dtls_base_t base;
+    dtls_session_t session;
+    bool complete;
+} server_state_t;
+
+#define LISTEN_PORT 4433
+
+static int server_result(server_state_t *state, int status) {
+    if (status == 0) {
+        DTLS_DEBUG("test success\n");
+    } else {
+        DTLS_DEBUG("test failed %d\n", status);
+    }
+    state->complete = true;
+    return dtls_session_close(&state->session);
+}
+
+static int server_data_rx(dtls_session_t *session, struct pbuf *p)
+{
+    int ret = ERR_OK;
+    uint16_t tot_len = p->tot_len;
+    // Print data received
+    int offset = 0;
+    while(offset < tot_len) {
+        char data_in[32];
+        uint16_t req_len = LWIP_MIN(tot_len - offset, sizeof(data_in));
+        assert(req_len > 0);
+        (void)req_len;
+        uint16_t data_in_len = pbuf_copy_partial(p, data_in, sizeof(data_in), offset);
+        assert(data_in_len > 0);
+        DTLS_DEBUG("SERVER IN: %.*s\n", data_in_len, data_in);
+        offset += data_in_len;
+    }
+    // echo it back as a reply
+    offset = 0;
+    while(offset < tot_len) {
+        char data_out[32];
+        uint16_t resp_len = LWIP_MIN(tot_len - offset, sizeof(data_out));
+        assert(resp_len > 0);
+        (void)resp_len;
+        uint16_t data_out_len = pbuf_copy_partial(p, data_out, sizeof(data_out), offset);
+        assert(data_out_len > 0);
+        DTLS_DEBUG("SERVER OUT: %.*s\n", data_out_len, data_out);
+        int ret = dtls_write(session, (uint8_t*)data_out, data_out_len);
+        if (ret < 0) {
+            break;
+        }
+        DTLS_DEBUG("server sent: %d bytes\n", ret);
+        offset += data_out_len;
+    }
+    pbuf_free(p);
+    return ret;
+}
+
+// Callback to receive data
+static void server_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
+{
+    server_state_t *state = (server_state_t*)arg;
+    assert(state && pcb && state->session.udp_pcb == pcb);
+    if (p == NULL) {
+        return;
+    }
+    // Ignore?
+    if (((state->session.port != 0) && (port != state->session.port)) ||
+            (!ip_addr_isany_val(state->session.addr) && !ip_addr_eq(&state->session.addr, addr))) {
+        pbuf_free(p);
+        return;
+    }
+    // New client connected?
+    if (state->session.port == 0 && ip_addr_isany_val(state->session.addr)) {
+        int ret = dtls_set_client(&state->session, addr, port);
+        if (ret != ERR_OK) {
+            DTLS_ERROR("failed to set client details %d", ret);
+            pbuf_free(p);
+            return;
+        }
+    }
+    if (state->session.rx == NULL) {
+        state->session.rx = p;
+    } else {
+        assert(p->tot_len + (int)p->len <= 0xFFFF);
+        pbuf_cat(state->session.rx, p);
+    }
+    DTLS_DEBUG("server_udp_recv_cb %d\n", p->tot_len);
+    dtls_processing(&state->session, false);
+}
+
+int main() {
+    stdio_init_all();
+
+    // Create a context
+    if (cyw43_arch_init()) {
+        printf("failed to initialise\n");
+        return 1;
+    }
+    cyw43_arch_enable_sta_mode();
+    if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
+        printf("failed to connect\n");
+        return 1;
+    }
+
+    server_state_t state;
+    memset(&state, 0, sizeof(state));
+
+    int ret = dtls_base_init(&state.base);
+    if (ret != ERR_OK) {
+        panic("Failed to initialise dtls");
+    }
+    ret = dtls_session_init(&state.session, &state.base, cyw43_arch_async_context(), NULL);
+    if (ret != ERR_OK) {
+        panic("Failed to initialise dtls session");
+    }
+
+    DTLS_INFO("Waiting for remote connection on %s:%d\n", ipaddr_ntoa(&(netif_list->ip_addr)), LISTEN_PORT);
+    state.session.udp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
+    if (!state.session.udp_pcb) {
+        panic("Failed to allocate pcb");
+    }
+    ret = udp_bind(state.session.udp_pcb, &(netif_list->ip_addr), LISTEN_PORT);
+    if (ret != ERR_OK) {
+        panic("bind failed");
+    }
+    udp_recv(state.session.udp_pcb, server_udp_recv_cb, &state);
+    state.session.handle_data_rx_cb = server_data_rx;
+    state.session.active = true;
+
+    while(!state.complete) {
+        cyw43_arch_poll();
+        cyw43_arch_wait_for_work_until(make_timeout_time_ms(1000));
+    }
+    lwip_nosys_deinit(cyw43_arch_async_context());
+    cyw43_arch_deinit();
+
+    dtls_base_deinit(&state.base);
+    dtls_session_deinit(&state.session);
+
+    DTLS_INFO("All done\n");
+    sleep_ms(100);
+}
diff --git a/pico_w/wifi/dtls/host/CMakeLists.txt b/pico_w/wifi/dtls/host/CMakeLists.txt
new file mode 100644
index 000000000..dcfca7e5e
--- /dev/null
+++ b/pico_w/wifi/dtls/host/CMakeLists.txt
@@ -0,0 +1,62 @@
+cmake_minimum_required(VERSION 3.12)
+project(pico_mbedtls_host_test C)
+
+option(ENABLE_TESTING "Build mbed TLS tests." OFF)
+option(ENABLE_PROGRAMS "Build mbed TLS programs." OFF)
+
+# Pick DTLS server from environment
+if (DEFINED ENV{DTLS_SERVER} AND (NOT DTLS_SERVER))
+    set(DTLS_SERVER $ENV{DTLS_SERVER})
+    message("Using DTLS_SERVER from environment ('${DTLS_SERVER}')")
+endif()
+if (NOT DTLS_SERVER)
+    message("Skipping DTLS example as DTLS_SERVER is not defined")
+    return()
+endif()
+set(DTLS_SERVER "${DTLS_SERVER}" CACHE INTERNAL "DTLS server for examples")
+if (NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/../certs/${DTLS_SERVER}")
+    message("Generate DTLS certs by running certs/makecerts.sh")
+    return()
+endif()
+
+if (DEFINED ENV{MBEDTLS_DIR} AND NOT MBEDTLS_DIR)
+	set(MBEDTLS_DIR $ENV{MBEDTLS_DIR})
+endif()
+if (NOT MBEDTLS_DIR)
+	if (DEFINED ENV{PICO_SDK_PATH} AND NOT PICO_SDK_PATH)
+		set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
+	endif()
+	if (PICO_SDK_PATH)
+		set(MBEDTLS_DIR ${PICO_SDK_PATH}/lib/mbedtls)
+	else()
+		message(FATAL_ERROR "Need to set MBEDTLS_DIR to mbedtls source location")
+	endif()
+endif()
+add_subdirectory(${MBEDTLS_DIR} mbedtls)
+
+add_executable(dtls_host_echo_client
+	dtls_host_echo_client.c
+	)
+target_link_libraries(dtls_host_echo_client PRIVATE
+	mbedtls
+	)
+target_include_directories(dtls_host_echo_client PRIVATE
+    ${CMAKE_CURRENT_LIST_DIR}/..
+    )
+target_compile_definitions(dtls_host_echo_client PRIVATE
+    DTLS_SERVER=\"${DTLS_SERVER}\"
+    DTLS_CERT_INC=\"certs/${DTLS_SERVER}/dtls_client.inc\"
+    )
+
+add_executable(dtls_host_echo_server
+	dtls_host_echo_server.c
+	)
+target_link_libraries(dtls_host_echo_server PRIVATE
+	mbedtls
+	)
+target_include_directories(dtls_host_echo_server PRIVATE
+    ${CMAKE_CURRENT_LIST_DIR}/..
+    )
+target_compile_definitions(dtls_host_echo_server PRIVATE
+    DTLS_CERT_INC=\"certs/${DTLS_SERVER}/dtls_server.inc\"
+    )
diff --git a/pico_w/wifi/dtls/host/client.sh b/pico_w/wifi/dtls/host/client.sh
new file mode 100755
index 000000000..a1eaea720
--- /dev/null
+++ b/pico_w/wifi/dtls/host/client.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/bash
+
+SERVER_PORT=4433
+SERVER_ADDR=${DTLS_SERVER:-$1}
+if [ -z "$SERVER_ADDR" ]; then
+    echo Pass dtls server address as a parameter or set DTLS_SERVER
+    exit 1
+fi
+CERT_FOLDER=../certs/$SERVER_ADDR
+if [ ! -e $CERT_FOLDER/client.crt ]; then
+	echo Cannot find client certificate
+	exit 2
+fi
+echo Connecting to $SERVER_ADDR
+echo Enter some text to send. Enter \"Q\" to exit
+openssl s_client -dtls -cert $CERT_FOLDER/client.crt -key $CERT_FOLDER/client.key -verifyCAfile $CERT_FOLDER/ca.crt -timeout -connect $SERVER_ADDR:${SERVER_PORT}
diff --git a/pico_w/wifi/dtls/host/dtls_host_echo_client.c b/pico_w/wifi/dtls/host/dtls_host_echo_client.c
new file mode 100755
index 000000000..16652bfd3
--- /dev/null
+++ b/pico_w/wifi/dtls/host/dtls_host_echo_client.c
@@ -0,0 +1,410 @@
+/*
+ *  Simple DTLS client demonstration program
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  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.
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_printf     printf
+#define mbedtls_fprintf    fprintf
+#define mbedtls_exit            exit
+#define MBEDTLS_EXIT_SUCCESS    EXIT_SUCCESS
+#define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE
+#endif
+
+#if !defined(MBEDTLS_SSL_CLI_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) ||    \
+    !defined(MBEDTLS_NET_C)  || !defined(MBEDTLS_TIMING_C) ||             \
+    !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) ||        \
+    !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_RSA_C) ||      \
+    !defined(MBEDTLS_CERTS_C) || !defined(MBEDTLS_PEM_PARSE_C)
+int main( void )
+{
+    mbedtls_printf( "MBEDTLS_SSL_CLI_C and/or MBEDTLS_SSL_PROTO_DTLS and/or "
+            "MBEDTLS_NET_C and/or MBEDTLS_TIMING_C and/or "
+            "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C and/or "
+            "MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_RSA_C and/or "
+            "MBEDTLS_CERTS_C and/or MBEDTLS_PEM_PARSE_C not defined.\n" );
+    mbedtls_exit( 0 );
+}
+#else
+
+#include <string.h>
+
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/error.h"
+#include "mbedtls/certs.h"
+#include "mbedtls/timing.h"
+
+#ifndef DTLS_CERT_INC
+#error Need to define DTLS_CERT_INC
+#endif
+#include DTLS_CERT_INC
+
+static const uint8_t dtls_root_cert[] = DTLS_ROOT_CERT;
+static const uint8_t dtls_key[] = DTLS_KEY;
+static const uint8_t dtls_cert[] = DTLS_CERT;
+
+/* Uncomment out the following line to default to IPv4 and disable IPv6 */
+//#define FORCE_IPV4
+
+#define SERVER_PORT "4433"
+
+#define MESSAGE  "The quick brown fox jumped over the lazy dog"
+
+#define READ_TIMEOUT_MS 1000
+#define MAX_RETRY       5
+
+#define DEBUG_LEVEL 0
+
+
+static void my_debug( void *ctx, int level,
+                      const char *file, int line,
+                      const char *str )
+{
+    ((void) level);
+
+    mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );
+    fflush(  (FILE *) ctx  );
+}
+
+int main( int argc, char *argv[] )
+{
+    int ret, len;
+    mbedtls_net_context server_fd;
+    uint32_t flags;
+    unsigned char buf[1024];
+    const char *pers = "dtls_client";
+    int retry_left = MAX_RETRY;
+    const char *server_addr = DTLS_SERVER;
+
+    if (argc >= 2) {
+        server_addr = argv[1];
+    }
+
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg;
+    mbedtls_ssl_context ssl;
+    mbedtls_ssl_config conf;
+    mbedtls_x509_crt clicert;
+    mbedtls_pk_context pkey;
+    mbedtls_timing_delay_context timer;
+
+    ((void) argc);
+    ((void) argv);
+
+#if defined(MBEDTLS_DEBUG_C)
+    mbedtls_debug_set_threshold( DEBUG_LEVEL );
+#endif
+
+    /*
+     * 0. Initialize the RNG and the session data
+     */
+    mbedtls_net_init( &server_fd );
+    mbedtls_ssl_init( &ssl );
+    mbedtls_ssl_config_init( &conf );
+    mbedtls_x509_crt_init( &clicert );
+    mbedtls_pk_init( &pkey );
+    mbedtls_ctr_drbg_init( &ctr_drbg );
+
+    mbedtls_printf( "\n  . Seeding the random number generator..." );
+    fflush( stdout );
+
+    mbedtls_entropy_init( &entropy );
+    if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
+                               (const unsigned char *) pers,
+                               strlen( pers ) ) ) != 0 )
+    {
+        mbedtls_printf( " failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", ret );
+        goto exit;
+    }
+
+    mbedtls_printf( " ok\n" );
+
+    /*
+     * 0. Load the certificates and private RSA key
+     */
+    printf( "\n  . Loading the client cert. and key..." );
+    fflush( stdout );
+
+    /*
+     * This demonstration program uses embedded test certificates.
+     * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the
+     * client and CA certificates, as well as mbedtls_pk_parse_keyfile().
+     */
+    ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) dtls_cert, sizeof(dtls_cert));
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  mbedtls_x509_crt_parse returned %d\n\n", ret );
+        goto exit;
+    }
+
+    ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) dtls_root_cert, sizeof(dtls_root_cert));
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  mbedtls_x509_crt_parse returned %d\n\n", ret );
+        goto exit;
+    }
+
+    ret =  mbedtls_pk_parse_key( &pkey, (const unsigned char *) dtls_key, sizeof(dtls_key), NULL, 0 );
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  mbedtls_pk_parse_key returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 1. Start the connection
+     */
+    mbedtls_printf( "  . Connecting to udp/%s/%s...", DTLS_SERVER, SERVER_PORT );
+    fflush( stdout );
+
+    if( ( ret = mbedtls_net_connect( &server_fd, server_addr,
+                                         SERVER_PORT, MBEDTLS_NET_PROTO_UDP ) ) != 0 )
+    {
+        mbedtls_printf( " failed\n  ! mbedtls_net_connect returned %d\n\n", ret );
+        goto exit;
+    }
+
+    mbedtls_printf( " ok\n" );
+
+    /*
+     * 2. Setup stuff
+     */
+    mbedtls_printf( "  . Setting up the DTLS structure..." );
+    fflush( stdout );
+
+    if( ( ret = mbedtls_ssl_config_defaults( &conf,
+                   MBEDTLS_SSL_IS_CLIENT,
+                   MBEDTLS_SSL_TRANSPORT_DATAGRAM,
+                   MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
+    {
+        mbedtls_printf( " failed\n  ! mbedtls_ssl_config_defaults returned %d\n\n", ret );
+        goto exit;
+    }
+
+    /* OPTIONAL is usually a bad choice for security, but makes interop easier
+     * in this simplified example, in which the ca chain is hardcoded.
+     * Production code should set a proper ca chain and use REQUIRED. */
+    mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_REQUIRED );
+    mbedtls_ssl_conf_ca_chain( &conf, clicert.next, NULL );
+    if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &clicert, &pkey ) ) != 0 )
+    {
+        printf( " failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
+        goto exit;
+    }
+    mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+    mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+    mbedtls_ssl_conf_read_timeout( &conf, READ_TIMEOUT_MS );
+
+    if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
+    {
+        mbedtls_printf( " failed\n  ! mbedtls_ssl_setup returned %d\n\n", ret );
+        goto exit;
+    }
+
+    if( ( ret = mbedtls_ssl_set_hostname( &ssl, DTLS_SERVER ) ) != 0 )
+    {
+        mbedtls_printf( " failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret );
+        goto exit;
+    }
+
+    mbedtls_ssl_set_bio( &ssl, &server_fd,
+                         mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout );
+
+    mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay,
+                                            mbedtls_timing_get_delay );
+
+    mbedtls_printf( " ok\n" );
+
+    /*
+     * 4. Handshake
+     */
+    mbedtls_printf( "  . Performing the DTLS handshake..." );
+    fflush( stdout );
+
+    do ret = mbedtls_ssl_handshake( &ssl );
+    while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
+           ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+
+    if( ret != 0 )
+    {
+        mbedtls_printf( " failed\n  ! mbedtls_ssl_handshake returned -0x%x\n\n", (unsigned int) -ret );
+        goto exit;
+    }
+
+    mbedtls_printf( " ok\n" );
+
+    /*
+     * 5. Verify the server certificate
+     */
+    mbedtls_printf( "  . Verifying peer X.509 certificate..." );
+
+    /* In real life, we would have used MBEDTLS_SSL_VERIFY_REQUIRED so that the
+     * handshake would not succeed if the peer's cert is bad.  Even if we used
+     * MBEDTLS_SSL_VERIFY_OPTIONAL, we would bail out here if ret != 0 */
+    if( ( flags = mbedtls_ssl_get_verify_result( &ssl ) ) != 0 )
+    {
+        char vrfy_buf[512];
+
+        mbedtls_printf( " failed\n" );
+
+        mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), "  ! ", flags );
+
+        mbedtls_printf( "%s\n", vrfy_buf );
+    }
+    else
+        mbedtls_printf( " ok\n" );
+
+    /*
+     * 6. Write the echo request
+     */
+send_request:
+    mbedtls_printf( "  > Write to server:" );
+    fflush( stdout );
+
+    len = sizeof( MESSAGE ) - 1;
+
+    do ret = mbedtls_ssl_write( &ssl, (unsigned char *) MESSAGE, len );
+    while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
+           ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+
+    if( ret < 0 )
+    {
+        mbedtls_printf( " failed\n  ! mbedtls_ssl_write returned %d\n\n", ret );
+        goto exit;
+    }
+
+    len = ret;
+    mbedtls_printf( " %d bytes written\n\n%s\n\n", len, MESSAGE );
+
+    /*
+     * 7. Read the echo response
+     */
+    mbedtls_printf( "  < Read from server:" );
+    fflush( stdout );
+
+    memset( buf, 0, sizeof( buf ) );
+    size_t read_so_far = 0;
+
+    while(read_so_far < sizeof(MESSAGE) - 1)
+    {
+        len = sizeof( buf ) - 1 - read_so_far;
+        do ret = mbedtls_ssl_read( &ssl, buf + read_so_far, len );
+        while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
+               ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+
+        if( ret <= 0 )
+        {
+            switch( ret )
+            {
+                case MBEDTLS_ERR_SSL_TIMEOUT:
+                    mbedtls_printf( " timeout\n\n" );
+                    if( retry_left-- > 0 )
+                        goto send_request;
+                    goto exit;
+
+                case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+                    mbedtls_printf( " connection was closed gracefully\n" );
+                    ret = 0;
+                    goto close_notify;
+
+                default:
+                    mbedtls_printf( " mbedtls_ssl_read returned -0x%x\n\n", (unsigned int) -ret );
+                    goto exit;
+            }
+        }
+
+        len = ret;
+        mbedtls_printf( " %d bytes read\n\n%s\n\n", len, buf + read_so_far);
+        read_so_far += len;
+    }
+
+    /*
+     * print result
+     */
+    if (strcmp(buf, MESSAGE) == 0) {
+        mbedtls_printf( "TEST SUCCESS" );
+    } else {
+        mbedtls_printf( "TEST FAIL %s", buf );
+    }
+
+    /*
+     * 8. Done, cleanly close the connection
+     */
+close_notify:
+    mbedtls_printf( "  . Closing the connection..." );
+
+    /* No error checking, the connection might be closed already */
+    do ret = mbedtls_ssl_close_notify( &ssl );
+    while( ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+    ret = 0;
+
+    mbedtls_printf( " done\n" );
+
+    /*
+     * 9. Final clean-ups and exit
+     */
+exit:
+
+#ifdef MBEDTLS_ERROR_C
+    if( ret != 0 )
+    {
+        char error_buf[100];
+        mbedtls_strerror( ret, error_buf, 100 );
+        mbedtls_printf( "Last error was: %d - %s\n\n", ret, error_buf );
+    }
+#endif
+
+    mbedtls_net_free( &server_fd );
+
+    mbedtls_x509_crt_free( &clicert );
+    mbedtls_pk_free( &pkey );
+    mbedtls_ssl_free( &ssl );
+    mbedtls_ssl_config_free( &conf );
+    mbedtls_ctr_drbg_free( &ctr_drbg );
+    mbedtls_entropy_free( &entropy );
+
+#if defined(_WIN32)
+    mbedtls_printf( "  + Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    /* Shell can not handle large exit numbers -> 1 for errors */
+    if( ret < 0 )
+        ret = 1;
+
+    mbedtls_exit( ret );
+}
+#endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_PROTO_DTLS && MBEDTLS_NET_C &&
+          MBEDTLD_TIMING_C && MBEDTLS_ENTROPY_C && MBEDTLS_CTR_DRBG_C &&
+          MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_RSA_C && MBEDTLS_CERTS_C &&
+          MBEDTLS_PEM_PARSE_C */
diff --git a/pico_w/wifi/dtls/host/dtls_host_echo_server.c b/pico_w/wifi/dtls/host/dtls_host_echo_server.c
new file mode 100755
index 000000000..e9328ecbc
--- /dev/null
+++ b/pico_w/wifi/dtls/host/dtls_host_echo_server.c
@@ -0,0 +1,471 @@
+/*
+ *  Simple DTLS server demonstration program
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  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.
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_printf     printf
+#define mbedtls_fprintf    fprintf
+#define mbedtls_time_t     time_t
+#define mbedtls_exit            exit
+#define MBEDTLS_EXIT_SUCCESS    EXIT_SUCCESS
+#define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE
+#endif
+
+/* Uncomment out the following line to default to IPv4 and disable IPv6 */
+//#define FORCE_IPV4
+
+#ifdef FORCE_IPV4
+#define BIND_IP     "0.0.0.0"     /* Forces IPv4 */
+#else
+#define BIND_IP     "::"
+#endif
+
+#if !defined(MBEDTLS_SSL_SRV_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) ||    \
+    !defined(MBEDTLS_SSL_COOKIE_C) || !defined(MBEDTLS_NET_C) ||          \
+    !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) ||        \
+    !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_RSA_C) ||      \
+    !defined(MBEDTLS_CERTS_C) || !defined(MBEDTLS_PEM_PARSE_C) ||         \
+    !defined(MBEDTLS_TIMING_C)
+
+int main( void )
+{
+    printf( "MBEDTLS_SSL_SRV_C and/or MBEDTLS_SSL_PROTO_DTLS and/or "
+            "MBEDTLS_SSL_COOKIE_C and/or MBEDTLS_NET_C and/or "
+            "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C and/or "
+            "MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_RSA_C and/or "
+            "MBEDTLS_CERTS_C and/or MBEDTLS_PEM_PARSE_C and/or "
+            "MBEDTLS_TIMING_C not defined.\n" );
+    mbedtls_exit( 0 );
+}
+#else
+
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/certs.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/ssl_cookie.h"
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/error.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/timing.h"
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+#include "mbedtls/ssl_cache.h"
+#endif
+
+#ifndef DTLS_CERT_INC
+#error Need to define DTLS_CERT_INC
+#endif
+#include DTLS_CERT_INC
+
+static const uint8_t dtls_root_cert[] = DTLS_ROOT_CERT;
+static const uint8_t dtls_key[] = DTLS_KEY;
+static const uint8_t dtls_cert[] = DTLS_CERT;
+
+#define READ_TIMEOUT_MS 10000   /* 10 seconds */
+#define DEBUG_LEVEL 0
+
+static void my_debug( void *ctx, int level,
+                      const char *file, int line,
+                      const char *str )
+{
+    ((void) level);
+
+    mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );
+    fflush(  (FILE *) ctx  );
+}
+
+int main( void )
+{
+    int ret, len;
+    mbedtls_net_context listen_fd, client_fd;
+    unsigned char buf[1024];
+    const char *pers = "dtls_server";
+    unsigned char client_ip[16] = { 0 };
+    size_t cliip_len;
+    mbedtls_ssl_cookie_ctx cookie_ctx;
+
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg;
+    mbedtls_ssl_context ssl;
+    mbedtls_ssl_config conf;
+    mbedtls_x509_crt srvcert;
+    mbedtls_pk_context pkey;
+    mbedtls_timing_delay_context timer;
+#if defined(MBEDTLS_SSL_CACHE_C)
+    mbedtls_ssl_cache_context cache;
+#endif
+
+    mbedtls_net_init( &listen_fd );
+    mbedtls_net_init( &client_fd );
+    mbedtls_ssl_init( &ssl );
+    mbedtls_ssl_config_init( &conf );
+    mbedtls_ssl_cookie_init( &cookie_ctx );
+#if defined(MBEDTLS_SSL_CACHE_C)
+    mbedtls_ssl_cache_init( &cache );
+#endif
+    mbedtls_x509_crt_init( &srvcert );
+    mbedtls_pk_init( &pkey );
+    mbedtls_entropy_init( &entropy );
+    mbedtls_ctr_drbg_init( &ctr_drbg );
+
+#if defined(MBEDTLS_DEBUG_C)
+    mbedtls_debug_set_threshold( DEBUG_LEVEL );
+#endif
+
+    /*
+     * 1. Load the certificates and private RSA key
+     */
+    printf( "\n  . Loading the server cert. and key..." );
+    fflush( stdout );
+
+    /*
+     * This demonstration program uses embedded test certificates.
+     * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the
+     * server and CA certificates, as well as mbedtls_pk_parse_keyfile().
+     */
+    ret = mbedtls_x509_crt_parse( &srvcert, (const unsigned char *) dtls_cert, sizeof(dtls_cert));
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  mbedtls_x509_crt_parse returned %d\n\n", ret );
+        goto exit;
+    }
+
+    ret = mbedtls_x509_crt_parse( &srvcert, (const unsigned char *) dtls_root_cert, sizeof(dtls_root_cert));
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  mbedtls_x509_crt_parse returned %d\n\n", ret );
+        goto exit;
+    }
+
+    ret =  mbedtls_pk_parse_key( &pkey, (const unsigned char *) dtls_key, sizeof(dtls_key), NULL, 0 );
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  mbedtls_pk_parse_key returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 2. Setup the "listening" UDP socket
+     */
+    printf( "  . Bind on udp/*/4433 ..." );
+    fflush( stdout );
+
+    if( ( ret = mbedtls_net_bind( &listen_fd, BIND_IP, "4433", MBEDTLS_NET_PROTO_UDP ) ) != 0 )
+    {
+        printf( " failed\n  ! mbedtls_net_bind returned %d\n\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 3. Seed the RNG
+     */
+    printf( "  . Seeding the random number generator..." );
+    fflush( stdout );
+
+    if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
+                               (const unsigned char *) pers,
+                               strlen( pers ) ) ) != 0 )
+    {
+        printf( " failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 4. Setup stuff
+     */
+    printf( "  . Setting up the DTLS data..." );
+    fflush( stdout );
+
+    if( ( ret = mbedtls_ssl_config_defaults( &conf,
+                    MBEDTLS_SSL_IS_SERVER,
+                    MBEDTLS_SSL_TRANSPORT_DATAGRAM,
+                    MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
+    {
+        mbedtls_printf( " failed\n  ! mbedtls_ssl_config_defaults returned %d\n\n", ret );
+        goto exit;
+    }
+
+    mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+    mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+    mbedtls_ssl_conf_read_timeout( &conf, READ_TIMEOUT_MS );
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+    mbedtls_ssl_conf_session_cache( &conf, &cache,
+                                   mbedtls_ssl_cache_get,
+                                   mbedtls_ssl_cache_set );
+#endif
+
+    mbedtls_ssl_conf_ca_chain( &conf, srvcert.next, NULL );
+   if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 )
+    {
+        printf( " failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
+        goto exit;
+    }
+
+    if( ( ret = mbedtls_ssl_cookie_setup( &cookie_ctx,
+                                  mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 )
+    {
+        printf( " failed\n  ! mbedtls_ssl_cookie_setup returned %d\n\n", ret );
+        goto exit;
+    }
+
+    mbedtls_ssl_conf_dtls_cookies( &conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check,
+                               &cookie_ctx );
+
+    if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
+    {
+        printf( " failed\n  ! mbedtls_ssl_setup returned %d\n\n", ret );
+        goto exit;
+    }
+
+    mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay,
+                                            mbedtls_timing_get_delay );
+
+    printf( " ok\n" );
+
+reset:
+#ifdef MBEDTLS_ERROR_C
+    if( ret != 0 )
+    {
+        char error_buf[100];
+        mbedtls_strerror( ret, error_buf, 100 );
+        printf("Last error was: %d - %s\n\n", ret, error_buf );
+    }
+#endif
+
+    mbedtls_net_free( &client_fd );
+
+    mbedtls_ssl_session_reset( &ssl );
+
+    /*
+     * 3. Wait until a client connects
+     */
+    printf( "  . Waiting for a remote connection ..." );
+    fflush( stdout );
+
+    if( ( ret = mbedtls_net_accept( &listen_fd, &client_fd,
+                    client_ip, sizeof( client_ip ), &cliip_len ) ) != 0 )
+    {
+        printf( " failed\n  ! mbedtls_net_accept returned %d\n\n", ret );
+        goto exit;
+    }
+
+    /* For HelloVerifyRequest cookies */
+    if( ( ret = mbedtls_ssl_set_client_transport_id( &ssl,
+                    client_ip, cliip_len ) ) != 0 )
+    {
+        printf( " failed\n  ! "
+                "mbedtls_ssl_set_client_transport_id() returned -0x%x\n\n", (unsigned int) -ret );
+        goto exit;
+    }
+
+    mbedtls_ssl_set_bio( &ssl, &client_fd,
+                         mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout );
+
+    printf( " ok\n" );
+
+    /*
+     * 5. Handshake
+     */
+    printf( "  . Performing the DTLS handshake..." );
+    fflush( stdout );
+
+    do ret = mbedtls_ssl_handshake( &ssl );
+    while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
+           ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+
+    if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED )
+    {
+        printf( " hello verification requested\n" );
+        ret = 0;
+        goto reset;
+    }
+    else if( ret != 0 )
+    {
+        printf( " failed\n  ! mbedtls_ssl_handshake returned -0x%x\n\n", (unsigned int) -ret );
+        goto reset;
+    }
+
+    printf( " ok\n" );
+
+read_echo:
+    /*
+     * 6. Read the echo Request
+     */
+    printf( "  < Read from client:" );
+    fflush( stdout );
+
+    len = sizeof( buf ) - 1;
+    memset( buf, 0, sizeof( buf ) );
+
+    do ret = mbedtls_ssl_read( &ssl, buf, len );
+    while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
+           ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+
+    if( ret <= 0 )
+    {
+        switch( ret )
+        {
+            case MBEDTLS_ERR_SSL_TIMEOUT:
+                printf( " timeout\n\n" );
+                goto reset;
+
+            case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+                printf( " connection was closed gracefully\n" );
+                ret = 0;
+                goto close_notify;
+
+            default:
+                printf( " mbedtls_ssl_read returned -0x%x\n\n", (unsigned int) -ret );
+                goto reset;
+        }
+    }
+
+    len = ret;
+    printf( " %d bytes read\n\n%s\n\n", len, buf );
+
+    /*
+     * 7. Echo back
+     */
+    printf( "  > Write to client:" );
+    fflush( stdout );
+
+    do ret = mbedtls_ssl_write( &ssl, buf, len );
+    while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
+           ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+
+    if( ret < 0 )
+    {
+        printf( " failed\n  ! mbedtls_ssl_write returned %d\n\n", ret );
+        goto exit;
+    }
+
+    len = ret;
+    printf( " %d bytes written\n\n%s\n\n", len, buf );
+    goto read_echo;
+
+    // Wait for the client to close the connection
+    while(1) {
+	do ret = mbedtls_ssl_read( &ssl, buf, len );
+	while( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+
+	if( ret <= 0 )
+	{
+		switch( ret )
+		{
+		case MBEDTLS_ERR_SSL_TIMEOUT:
+			printf( " timeout\n\n" );
+			goto reset;
+
+		case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+			printf( " connection was closed gracefully\n" );
+			ret = 0;
+			goto close_notify;
+			break;
+
+		default:
+			printf( " mbedtls_ssl_read returned -0x%x\n\n", (unsigned int) -ret );
+			goto reset;
+		}
+	}
+    }
+
+    /*
+     * 8. Done, cleanly close the connection
+     */
+close_notify:
+    printf( "  . Closing the connection..." );
+
+    /* No error checking, the connection might be closed already */
+    do ret = mbedtls_ssl_close_notify( &ssl );
+    while( ret == MBEDTLS_ERR_SSL_WANT_WRITE );
+    ret = 0;
+
+    printf( " done\n" );
+
+    goto reset;
+
+    /*
+     * Final clean-ups and exit
+     */
+exit:
+
+#ifdef MBEDTLS_ERROR_C
+    if( ret != 0 )
+    {
+        char error_buf[100];
+        mbedtls_strerror( ret, error_buf, 100 );
+        printf( "Last error was: %d - %s\n\n", ret, error_buf );
+    }
+#endif
+
+    mbedtls_net_free( &client_fd );
+    mbedtls_net_free( &listen_fd );
+
+    mbedtls_x509_crt_free( &srvcert );
+    mbedtls_pk_free( &pkey );
+    mbedtls_ssl_free( &ssl );
+    mbedtls_ssl_config_free( &conf );
+    mbedtls_ssl_cookie_free( &cookie_ctx );
+#if defined(MBEDTLS_SSL_CACHE_C)
+    mbedtls_ssl_cache_free( &cache );
+#endif
+    mbedtls_ctr_drbg_free( &ctr_drbg );
+    mbedtls_entropy_free( &entropy );
+
+#if defined(_WIN32)
+    printf( "  Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    /* Shell can not handle large exit numbers -> 1 for errors */
+    if( ret < 0 )
+        ret = 1;
+
+    mbedtls_exit( ret );
+}
+#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_PROTO_DTLS &&
+          MBEDTLS_SSL_COOKIE_C && MBEDTLS_NET_C && MBEDTLS_ENTROPY_C &&
+          MBEDTLS_CTR_DRBG_C && MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_RSA_C
+          && MBEDTLS_CERTS_C && MBEDTLS_PEM_PARSE_C && MBEDTLS_TIMING_C */
diff --git a/pico_w/wifi/dtls/host/server.sh b/pico_w/wifi/dtls/host/server.sh
new file mode 100755
index 000000000..853fe55f1
--- /dev/null
+++ b/pico_w/wifi/dtls/host/server.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/bash
+
+SERVER_ADDR=${DTLS_SERVER:-$1}
+if [ -z "$SERVER_ADDR" ]; then
+    echo Pass dtls server address as a parameter or set DTLS_SERVER
+    exit 1
+fi
+CERT_FOLDER=../certs/$SERVER_ADDR
+if [ ! -e $CERT_FOLDER/server.crt ]; then
+	echo Cannot find server certificate
+	exit 2
+fi
+echo Waiting for client to connect. Manually echo text received
+openssl s_server -dtls -cert $CERT_FOLDER/server.crt -key $CERT_FOLDER/server.key -verifyCAfile $CERT_FOLDER/ca.crt -timeout
diff --git a/pico_w/wifi/dtls/lwipopts.h b/pico_w/wifi/dtls/lwipopts.h
new file mode 100644
index 000000000..4a5a2ef50
--- /dev/null
+++ b/pico_w/wifi/dtls/lwipopts.h
@@ -0,0 +1,12 @@
+#ifndef _LWIPOPTS_H
+#define _LWIPOPTS_H
+
+#define MEM_SIZE 8000
+
+#include "lwipopts_examples_common.h"
+
+#define LWIP_DEBUG 1
+#define ALTCP_MBEDTLS_DEBUG  LWIP_DBG_ON
+
+#endif
+
diff --git a/pico_w/wifi/dtls/mbedtls_config.h b/pico_w/wifi/dtls/mbedtls_config.h
new file mode 100644
index 000000000..1ec01f6ab
--- /dev/null
+++ b/pico_w/wifi/dtls/mbedtls_config.h
@@ -0,0 +1,11 @@
+#ifndef MBEDTLS_CONFIG_TLS_CLIENT_H
+#define MBEDTLS_CONFIG_TLS_CLIENT_H
+
+#include "mbedtls_config_examples_common.h"
+
+// Needed for dtls
+#define MBEDTLS_SSL_PROTO_DTLS
+#define MBEDTLS_SSL_COOKIE_C
+#define MBEDTLS_SSL_DTLS_HELLO_VERIFY
+
+#endif
\ No newline at end of file

From 92b54c5195f0e2bc9c6175c6ce119914476c6d32 Mon Sep 17 00:00:00 2001
From: Peter Harper <peter.harper@raspberrypi.com>
Date: Thu, 10 Apr 2025 12:36:07 +0100
Subject: [PATCH 2/2] Fix review comments

---
 pico_w/wifi/dtls/README.md          | 22 ++++++++++------------
 pico_w/wifi/dtls/certs/makecerts.sh | 20 +++++++++++---------
 pico_w/wifi/dtls/dtls_common.c      |  6 +++++-
 3 files changed, 26 insertions(+), 22 deletions(-)

diff --git a/pico_w/wifi/dtls/README.md b/pico_w/wifi/dtls/README.md
index 3607b297e..9bf2f069d 100644
--- a/pico_w/wifi/dtls/README.md
+++ b/pico_w/wifi/dtls/README.md
@@ -1,7 +1,7 @@
 # Setup
 
 These examples demonstrate how to use dtls via mbedtls on a Pico W device.
-You need to define DTLS_SERVER and run the makecerts.sh script to generate the certificates and keys needed for the server and client.
+You need to define DTLS_SERVER and run the `makecerts.sh` script to generate the certificates and keys needed for the server and client.
 ```
 export DTLS_SERVER=myserver
 cd dtls/certs
@@ -12,14 +12,12 @@ The examples should now build.
 # Running the dtls examples
 
 The client connects to a server and sends it a few lines of text which it expects to be sent back.
-
-You can build and run the client and server examples on two Pico W devices. To make testing easier to test with just one Pico W device, you can run the server or client on a Linux host.
-The client.sh and server.sh scripts show how to run the client or server with openssl. The host folder contains source code for a version of the client and server using mbedtls.
+You can build and run the client and server examples on two Pico W devices, or to test with just one Pico W device, you can run the server or client on a Linux host.
 
 ## Using openssl
 
-The host/server.sh and host/client/sh scripts demonstrate how to use DTLS with openssl, although you will have to echo text manually.
-For example, run dtls_echo_client on a Pico W device and the server.sh on a linux PC.
+The `host/server.sh` and `host/client.sh` scripts demonstrate how to use DTLS with openssl, although you will have to echo text manually.
+For example, run dtls_echo_client on a Pico W device and the `server.sh` on a linux host.
 ```
 export DTLS_SERVER=myserver
 cd host
@@ -27,21 +25,21 @@ cd host
 ```
 The scripts use the keys in certs/myserver
 
-Or run dtls_echo_server on a Pico W device and client.sh on a linux PC. The host name for the server on Pico W is set to `pico_dtls_example`"`. Make sure you build the code for the Pico W and run the client with the right DTLS_SERVER name (and matching keys in the client and server) or else the SSL handshake will fail.
+Or run dtls_echo_server on a Pico W device and `client.sh` on a linux host. The host name for the server on Pico W is set to `pico_dtls_example`. Make sure you build the code for the Pico W and run the client with the right DTLS_SERVER name (and matching keys in the client and server) or else the SSL handshake will fail.
 ```
 export DTLS_SERVER=pico_dtls_example
 ping pico_dtls_example # make sure you can reach it!
 cd host
 ./client.sh
 ```
-The scripts use the keys in certs/pico_dtls_example. Type a sentence into the client.sh console and the server should send it back as a reply.
+The scripts use the keys in certs/pico_dtls_example. Type a sentence into the `client.sh` console and the server should send it back as a reply.
 
 ## Using mbedtls
 
 The host folder contains C versions of the examples that can be compiled natively for the host. They are modified versions of mbedtls examples.
-You can build these on a rpi linux device to act as the server or client. The mbedtls library in PICO_SDK_PATH will be used to build the host code.
+If you are building the server or client on a linux host, the mbedtls library in PICO_SDK_PATH will be used to build the code.
 
-For example, run dtls_echo_client on a Pico W device and the dtls_host_echo_server on a linux PC.
+For example, run dtls_echo_client on a Pico W device and the dtls_host_echo_server on a linux host.
 ```
 export DTLS_SERVER=myserver
 cd host
@@ -52,7 +50,7 @@ make -j8
 ./dtls_host_echo_server
 
 ```
-Or run dtls_echo_server on a Pico W device and dtls_host_echo_client on a linux PC.
+Or run dtls_echo_server on a Pico W device and dtls_host_echo_client on a linux host.
 ```
 export DTLS_SERVER=pico_dtls_example
 cd host
@@ -62,4 +60,4 @@ cmake ..
 make -j8
 ./dtls_host_echo_client
 ```
-Remember to build the client and server for the host and Pico W with the correct value of DTLS_SERVER or else the handshake will fail.
\ No newline at end of file
+Remember to build the client and server for the linux host and Pico W with the correct value of DTLS_SERVER or else the handshake will fail.
\ No newline at end of file
diff --git a/pico_w/wifi/dtls/certs/makecerts.sh b/pico_w/wifi/dtls/certs/makecerts.sh
index efdbe7ad9..c68ec7566 100755
--- a/pico_w/wifi/dtls/certs/makecerts.sh
+++ b/pico_w/wifi/dtls/certs/makecerts.sh
@@ -1,4 +1,5 @@
 #!/usr/bin/bash
+set -e
 
 if [ "${PWD##*/}" != "certs" ]; then
     echo Run this in the certs folder
@@ -8,6 +9,11 @@ if [ -z "$DTLS_SERVER" ]; then
     echo Define DTLS_SERVER
     exit 1
 fi
+if ! command -v openssl 2>&1 >/dev/null; then
+    echo openssl could not be found
+    exit 1
+fi
+
 SERVER_NAME=$DTLS_SERVER
 
 if [ -d "$SERVER_NAME" ]; then
@@ -30,27 +36,23 @@ openssl x509 -req -in $SERVER_NAME/client.csr -CA $SERVER_NAME/ca.crt -CAkey $SE
 
 echo -n \#define DTLS_ROOT_CERT \" > $SERVER_NAME/dtls_client.inc
 cat $SERVER_NAME/ca.crt | awk '{printf "%s\\n\\\n", $0}' >> $SERVER_NAME/dtls_client.inc
-echo "\"" >> $SERVER_NAME/dtls_client.inc
-echo >> $SERVER_NAME/dtls_client.inc
+echo -e "\"\n" >> $SERVER_NAME/dtls_client.inc
 
 echo -n \#define DTLS_KEY \" >> $SERVER_NAME/dtls_client.inc
 cat $SERVER_NAME/client.key | awk '{printf "%s\\n\\\n", $0}' >> $SERVER_NAME/dtls_client.inc
-echo "\"" >> $SERVER_NAME/dtls_client.inc
-echo >> $SERVER_NAME/dtls_client.inc
+echo -e "\"\n" >> $SERVER_NAME/dtls_client.inc
 
 echo -n \#define DTLS_CERT \" >> $SERVER_NAME/dtls_client.inc
 cat $SERVER_NAME/client.crt | awk '{printf "%s\\n\\\n", $0}' >> $SERVER_NAME/dtls_client.inc
-echo "\"" >> $SERVER_NAME/dtls_client.inc
+echo -e "\"\n" >> $SERVER_NAME/dtls_client.inc
 
 echo -n \#define DTLS_ROOT_CERT \" > $SERVER_NAME/dtls_server.inc
 cat $SERVER_NAME/ca.crt | awk '{printf "%s\\n\\\n", $0}' >> $SERVER_NAME/dtls_server.inc
-echo "\"" >> $SERVER_NAME/dtls_server.inc
-echo >> $SERVER_NAME/dtls_server.inc
+echo -e "\"\n" >> $SERVER_NAME/dtls_server.inc
 
 echo -n \#define DTLS_KEY \" >> $SERVER_NAME/dtls_server.inc
 cat $SERVER_NAME/server.key | awk '{printf "%s\\n\\\n", $0}' >> $SERVER_NAME/dtls_server.inc
-echo "\"" >> $SERVER_NAME/dtls_server.inc
-echo >> $SERVER_NAME/dtls_server.inc
+echo -e "\"\n" >> $SERVER_NAME/dtls_server.inc
 
 echo -n \#define DTLS_CERT \" >> $SERVER_NAME/dtls_server.inc
 cat $SERVER_NAME/server.crt | awk '{printf "%s\\n\\\n", $0}' >> $SERVER_NAME/dtls_server.inc
diff --git a/pico_w/wifi/dtls/dtls_common.c b/pico_w/wifi/dtls/dtls_common.c
index 438036dd5..cebdd81b1 100644
--- a/pico_w/wifi/dtls/dtls_common.c
+++ b/pico_w/wifi/dtls/dtls_common.c
@@ -30,7 +30,7 @@ static const uint8_t dtls_cert[] = DTLS_CERT;
 #endif
 
 static void dtls_timer_callback(__unused async_context_t *context, async_at_time_worker_t *worker) {
-    DTLS_DEBUG("pico_mbedtls_timing_worker_callback\n");
+    DTLS_DEBUG("dtls_timer_callback\n");
     dtls_processing((dtls_session_t*)worker->user_data, true);
 }
 
@@ -174,7 +174,11 @@ int dtls_base_init(dtls_base_t *base)
     }
     mbedtls_ssl_conf_ca_chain(&base->conf, base->cert.next, NULL);
     mbedtls_pk_init(&base->pkey);
+#if MBEDTLS_VERSION_MAJOR < 3
     ret = mbedtls_pk_parse_key(&base->pkey, dtls_key, sizeof(dtls_key), NULL, 0);
+#else
+    ret = mbedtls_pk_parse_key(&base->pkey, dtls_key, sizeof(dtls_key), NULL, 0, NULL, NULL);
+#endif
     if (ret != 0) {
         DTLS_ERROR("Failed to parse key");
         return ret;