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")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably ought to add -DDTLS_SERVER=something to https://github.com/raspberrypi/pico-examples/blob/develop/.github/workflows/cmake.yml#L56 so that the CI will at least check that these examples compile correctly?

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
These examples demonstrate how to use dtls via mbedtls on a Pico W device.
These examples demonstrate how to use DTLS via Mbed TLS 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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
./makecerts.sh
```
The examples should now build.

# Running the dtls examples
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Running the dtls examples
# 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## Using openssl
## 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The `host/server.sh` and `host/client.sh` scripts demonstrate how to use DTLS with openssl, although you will have to echo text manually.
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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
For example, run dtls_echo_client on a Pico W device and the `server.sh` on a linux host.
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The scripts use the keys in certs/myserver
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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
Or run `dtls_echo_server` on a Pico W device and `client.sh` on a Linux host. The hostname 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## Using mbedtls
## Using Mbed TLS


The host folder contains C versions of the examples that can be compiled natively for the host. They are modified versions of mbedtls examples.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The host folder contains C versions of the examples that can be compiled natively for the host. They are modified versions of mbedtls examples.
The `host` folder contains C versions of the examples that can be compiled natively for the host. They are modified versions of Mbed TLS 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
If you are building the server or client on a Linux host, the Mbed TLS 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
For example, run dtls_echo_client on a Pico W device and the dtls_host_echo_server on a linux host.
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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Or run dtls_echo_server on a Pico W device and dtls_host_echo_client on a linux host.
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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
Remember to build the client and server for the Linux host and Pico W with the correct value of `DTLS_SERVER` or else the SSL 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#!/usr/bin/bash
#!/bin/bash

/bin/bash is the usual Bash shebang line. On my Ubuntu Linux laptop /usr/bin/bash doesn't even exist!

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
echo Run \"rm -fr $SERVER_NAME\" to regenerate these keys
echo Run \"rm -rf $SERVER_NAME\" to regenerate these keys

(no functional difference, this is just convention)

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
Comment on lines +37 to +59
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes it a bit easier to see what makecerts.sh is actually doing 🙂

Suggested change
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
function append_file_define {
DEFINE=$1
INFILE=$2
OUTFILE=$3
echo -n \#define $DEFINE \" >> $OUTFILE
awk '{printf "%s\\n\\\n", $0}' $INFILE >> $OUTFILE
echo -e "\"\n" >> $OUTFILE
}
append_file_define DTLS_ROOT_CERT $SERVER_NAME/ca.crt $SERVER_NAME/dtls_client.inc
append_file_define DTLS_KEY $SERVER_NAME/client.key $SERVER_NAME/dtls_client.inc
append_file_define DTLS_CERT $SERVER_NAME/client.crt $SERVER_NAME/dtls_client.inc
append_file_define DTLS_ROOT_CERT $SERVER_NAME/ca.crt $SERVER_NAME/dtls_server.inc
append_file_define DTLS_KEY $SERVER_NAME/server.key $SERVER_NAME/dtls_server.inc
append_file_define DTLS_CERT $SERVER_NAME/server.crt $SERVER_NAME/dtls_server.inc

Loading