Skip to content

Add DTLS example #615

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions pico_w/wifi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
83 changes: 83 additions & 0 deletions pico_w/wifi/dtls/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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})
63 changes: 63 additions & 0 deletions pico_w/wifi/dtls/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# 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, 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 host.
```
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 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.

## 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.
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 host.
```
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 host.
```
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 linux host and Pico W with the correct value of DTLS_SERVER or else the handshake will fail.
1 change: 1 addition & 0 deletions pico_w/wifi/dtls/certs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*/
59 changes: 59 additions & 0 deletions pico_w/wifi/dtls/certs/makecerts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/bash
set -e

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
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
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 -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 -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 -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 -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 -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
echo "\"" >> $SERVER_NAME/dtls_server.inc
Loading