diff --git a/samples/net/sockets/coap_server/CMakeLists.txt b/samples/net/sockets/coap_server/CMakeLists.txt index 5b9a0beeb19..8941035a7c5 100644 --- a/samples/net/sockets/coap_server/CMakeLists.txt +++ b/samples/net/sockets/coap_server/CMakeLists.txt @@ -4,6 +4,19 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(coap_server) +if(CONFIG_NET_SOCKETS_ENABLE_DTLS AND + CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND + (CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h")) + add_custom_target(development_psk + COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------" + COMMAND ${CMAKE_COMMAND} -E echo "--- WARNING: Using dummy PSK! Only suitable for ---" + COMMAND ${CMAKE_COMMAND} -E echo "--- development. Set NET_SAMPLE_PSK_HEADER_FILE to use ---" + COMMAND ${CMAKE_COMMAND} -E echo "--- own pre-shared key. ---" + COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------" + ) + add_dependencies(app development_psk) +endif() + FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/ip) @@ -18,3 +31,19 @@ zephyr_iterable_section( SUBALIGN ${CONFIG_LINKER_ITERABLE_SUBALIGN}) include(${ZEPHYR_BASE}/samples/net/common/common.cmake) + +set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/) + +foreach(inc_file + ca.der + server.der + server_privkey.der + coaps-server-cert.der + coaps-server-key.der +) + generate_inc_file_for_target( + app + src/certs/${inc_file} + ${gen_dir}/${inc_file}.inc + ) +endforeach() diff --git a/samples/net/sockets/coap_server/Kconfig b/samples/net/sockets/coap_server/Kconfig new file mode 100644 index 00000000000..6cef67ac154 --- /dev/null +++ b/samples/net/sockets/coap_server/Kconfig @@ -0,0 +1,36 @@ +# Copyright (c) 2023, Emna Rekik +# Copyright (c) 2025, Basalte bv +# SPDX-License-Identifier: Apache-2.0 + +# Config options for CoAP server sample application + +mainmenu "CoAP server sample application" + +config NET_SAMPLE_COAPS_SERVICE + bool "Enable CoAP secure service" + depends on NET_SOCKETS_ENABLE_DTLS || TLS_CREDENTIALS + +config NET_SAMPLE_COAP_SERVER_SERVICE_PORT + int "Port number for CoAP service" + default 5684 if NET_SAMPLE_COAPS_SERVICE + default 5683 + +if NET_SAMPLE_COAPS_SERVICE + +config NET_SAMPLE_PSK_HEADER_FILE + string "Header file containing PSK" + default "dummy_psk.h" + depends on MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + help + Name of a header file containing a pre-shared key. + +config NET_SAMPLE_CERTS_WITH_SC + bool "Signed Certificates" + depends on NET_SOCKETS_SOCKOPT_TLS + help + Enable this flag, if you are interested to run this + application with certificates. + +endif + +source "Kconfig.zephyr" diff --git a/samples/net/sockets/coap_server/README.rst b/samples/net/sockets/coap_server/README.rst index 64bb1a687dc..ac6e1b15cb2 100644 --- a/samples/net/sockets/coap_server/README.rst +++ b/samples/net/sockets/coap_server/README.rst @@ -17,8 +17,9 @@ service's name. A linker file is required, see ``sections-ram.ld`` for an exampl This demo assumes that the platform of choice has networking support, some adjustments to the configuration may be needed. -The sample will listen for requests in the CoAP UDP port (5683) in the -site-local IPv6 multicast address reserved for CoAP nodes. +The sample will listen for requests on the default CoAP UDP port +(5683 or 5684 for secure CoAP) in the site-local IPv6 multicast address reserved +for CoAP nodes. The sample exports the following resources: @@ -37,6 +38,16 @@ against coap-server. Building And Running ******************** +Build the CoAP server sample application like this: + +.. zephyr-app-commands:: + :zephyr-app: samples/net/sockets/coap_server + :board: + :goals: build + :compact: + +Use :zephyr_file:`overlay-dtls.conf ` +to build the sample with CoAP secure resources instead. This project has no output in case of success, the correct functionality can be verified by using some external tool such as tcpdump diff --git a/samples/net/sockets/coap_server/overlay-dtls.conf b/samples/net/sockets/coap_server/overlay-dtls.conf new file mode 100644 index 00000000000..d0a85bad132 --- /dev/null +++ b/samples/net/sockets/coap_server/overlay-dtls.conf @@ -0,0 +1,18 @@ +CONFIG_NET_SAMPLE_COAPS_SERVICE=y + +# Secure Socket +CONFIG_NET_SOCKETS_SOCKOPT_TLS=y +CONFIG_NET_SOCKETS_ENABLE_DTLS=y +CONFIG_NET_SOCKETS_TLS_MAX_CLIENT_SESSION_COUNT=6 +CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=6 +CONFIG_NET_SOCKETS_DTLS_TIMEOUT=30000 + +# TLS configuration +CONFIG_MBEDTLS_DEBUG=y +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_MBEDTLS_ENABLE_HEAP=y +CONFIG_MBEDTLS_HEAP_SIZE=60000 +CONFIG_MBEDTLS_SSL_DTLS_CONNECTION_ID=y +CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=2048 +CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED=y diff --git a/samples/net/sockets/coap_server/prj.conf b/samples/net/sockets/coap_server/prj.conf index 9fdbcb99c20..ce12e0d895a 100644 --- a/samples/net/sockets/coap_server/prj.conf +++ b/samples/net/sockets/coap_server/prj.conf @@ -6,7 +6,7 @@ CONFIG_NET_UDP=y # Socket CONFIG_NET_SOCKETS=y CONFIG_POSIX_API=y -CONFIG_ZVFS_POLL_MAX=4 +CONFIG_ZVFS_POLL_MAX=10 # CoAP CONFIG_COAP=y @@ -48,3 +48,6 @@ CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5 CONFIG_NET_IPV4=n CONFIG_NET_CONFIG_NEED_IPV4=n CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" + +# Enable v4-mapped-on-v6 +CONFIG_NET_IPV4_MAPPING_TO_IPV6=y diff --git a/samples/net/sockets/coap_server/sample.yaml b/samples/net/sockets/coap_server/sample.yaml index d1efb969706..2be258caa50 100644 --- a/samples/net/sockets/coap_server/sample.yaml +++ b/samples/net/sockets/coap_server/sample.yaml @@ -12,6 +12,16 @@ tests: platform_allow: - native_sim - qemu_x86 + sample.net.sockets.coaps_server: + harness: net + extra_args: EXTRA_CONF_FILE="overlay-dtls.conf" + tags: + - net + - socket + - tls + platform_allow: + - native_sim + - qemu_x86 sample.net.sockets.coap_server.wifi.nrf70dk: extra_args: - SNIPPET=wifi-ipv4 diff --git a/samples/net/sockets/coap_server/src/certificate.h b/samples/net/sockets/coap_server/src/certificate.h new file mode 100644 index 00000000000..7488d4afc5e --- /dev/null +++ b/samples/net/sockets/coap_server/src/certificate.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __CERTIFICATE_H__ +#define __CERTIFICATE_H__ + +#define SERVER_CERTIFICATE_TAG 1 +#define PSK_TAG 2 + +#if !defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC) +static const unsigned char server_certificate[] = { +#include "coaps-server-cert.der.inc" +}; + +/* This is the private key in pkcs#8 format. */ +static const unsigned char private_key[] = { +#include "coaps-server-key.der.inc" +}; + +#else + +static const unsigned char ca_certificate[] = { +#include "ca.der.inc" +}; + +static const unsigned char server_certificate[] = { +#include "server.der.inc" +}; + +/* This is the private key in pkcs#8 format. */ +static const unsigned char private_key[] = { +#include "server_privkey.der.inc" +}; +#endif + +#if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) +#include CONFIG_NET_SAMPLE_PSK_HEADER_FILE +#endif + +#endif /* __CERTIFICATE_H__ */ diff --git a/samples/net/sockets/coap_server/src/certs/ca.der b/samples/net/sockets/coap_server/src/certs/ca.der new file mode 100644 index 00000000000..b1d3e097cad Binary files /dev/null and b/samples/net/sockets/coap_server/src/certs/ca.der differ diff --git a/samples/net/sockets/coap_server/src/certs/coaps-server-cert.der b/samples/net/sockets/coap_server/src/certs/coaps-server-cert.der new file mode 100644 index 00000000000..bfcb335e31c Binary files /dev/null and b/samples/net/sockets/coap_server/src/certs/coaps-server-cert.der differ diff --git a/samples/net/sockets/coap_server/src/certs/coaps-server-key.der b/samples/net/sockets/coap_server/src/certs/coaps-server-key.der new file mode 100644 index 00000000000..5a4d67372ea Binary files /dev/null and b/samples/net/sockets/coap_server/src/certs/coaps-server-key.der differ diff --git a/samples/net/sockets/coap_server/src/certs/server.der b/samples/net/sockets/coap_server/src/certs/server.der new file mode 100644 index 00000000000..2b664a4bdb2 Binary files /dev/null and b/samples/net/sockets/coap_server/src/certs/server.der differ diff --git a/samples/net/sockets/coap_server/src/certs/server_privkey.der b/samples/net/sockets/coap_server/src/certs/server_privkey.der new file mode 100644 index 00000000000..2269293fe79 Binary files /dev/null and b/samples/net/sockets/coap_server/src/certs/server_privkey.der differ diff --git a/samples/net/sockets/coap_server/src/dummy_psk.h b/samples/net/sockets/coap_server/src/dummy_psk.h new file mode 100644 index 00000000000..e67107266fd --- /dev/null +++ b/samples/net/sockets/coap_server/src/dummy_psk.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DUMMY_PSK_H__ +#define __DUMMY_PSK_H__ + +static const unsigned char psk[] = {0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, +0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; +static const char psk_id[] = "PSK_identity"; + +#endif /* __DUMMY_PSK_H__ */ diff --git a/samples/net/sockets/coap_server/src/main.c b/samples/net/sockets/coap_server/src/main.c index 19890c1f3d3..64db9d128cd 100644 --- a/samples/net/sockets/coap_server/src/main.c +++ b/samples/net/sockets/coap_server/src/main.c @@ -8,18 +8,98 @@ LOG_MODULE_REGISTER(net_coap_service_sample, LOG_LEVEL_DBG); #include -#include + +#include "net_sample_common.h" #ifdef CONFIG_NET_IPV6 +#include + #include "net_private.h" #include "ipv6.h" #endif -#include "net_sample_common.h" +static uint16_t coap_port = CONFIG_NET_SAMPLE_COAP_SERVER_SERVICE_PORT; -static const uint16_t coap_port = 5683; +#ifndef CONFIG_NET_SAMPLE_COAPS_SERVICE -#ifdef CONFIG_NET_IPV6 +COAP_SERVICE_DEFINE(coap_server, NULL, &coap_port, COAP_SERVICE_AUTOSTART); + +#else /* CONFIG_NET_SAMPLE_COAPS_SERVICE */ + +#include "certificate.h" + +static const sec_tag_t sec_tag_list_verify_none[] = { + SERVER_CERTIFICATE_TAG, +#if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + PSK_TAG, +#endif +}; + +COAPS_SERVICE_DEFINE(coap_server, NULL, &coap_port, 0, + sec_tag_list_verify_none, sizeof(sec_tag_list_verify_none)); + +#endif /* CONFIG_NET_SAMPLE_COAPS_SERVICE */ + +static int setup_dtls(void) +{ +#if defined(CONFIG_NET_SAMPLE_COAPS_SERVICE) +#if defined(CONFIG_NET_SOCKETS_ENABLE_DTLS) + int err; + +#if defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC) + err = tls_credential_add(SERVER_CERTIFICATE_TAG, + TLS_CREDENTIAL_CA_CERTIFICATE, + ca_certificate, + sizeof(ca_certificate)); + if (err < 0) { + LOG_ERR("Failed to register CA certificate: %d", err); + return err; + } +#endif /* defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC) */ + + err = tls_credential_add(SERVER_CERTIFICATE_TAG, + TLS_CREDENTIAL_SERVER_CERTIFICATE, + server_certificate, + sizeof(server_certificate)); + if (err < 0) { + LOG_ERR("Failed to register public certificate: %d", err); + return err; + } + + err = tls_credential_add(SERVER_CERTIFICATE_TAG, + TLS_CREDENTIAL_PRIVATE_KEY, + private_key, sizeof(private_key)); + if (err < 0) { + LOG_ERR("Failed to register private key: %d", err); + return err; + } + +#if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + err = tls_credential_add(PSK_TAG, + TLS_CREDENTIAL_PSK, + psk, + sizeof(psk)); + if (err < 0) { + LOG_ERR("Failed to register PSK: %d", err); + return err; + } + + err = tls_credential_add(PSK_TAG, + TLS_CREDENTIAL_PSK_ID, + psk_id, + sizeof(psk_id) - 1); + if (err < 0) { + LOG_ERR("Failed to register PSK ID: %d", err); + return err; + } + +#endif /* defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) */ +#endif /* defined(CONFIG_NET_SOCKETS_ENABLE_DTLS) */ +#endif /* defined(CONFIG_NET_SAMPLE_COAPS_SERVICE) */ + return 0; +} + +#if !defined(CONFIG_NET_SAMPLE_COAPS_SERVICE) && defined(CONFIG_NET_IPV6) #define ALL_NODES_LOCAL_COAP_MCAST \ { { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfd } } } @@ -27,13 +107,13 @@ static const uint16_t coap_port = 5683; #define MY_IP6ADDR \ { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } } -static int join_coap_multicast_group(void) +static int join_coap_multicast_group(uint16_t port) { static struct in6_addr my_addr = MY_IP6ADDR; - static struct sockaddr_in6 mcast_addr = { + struct sockaddr_in6 mcast_addr = { .sin6_family = AF_INET6, .sin6_addr = ALL_NODES_LOCAL_COAP_MCAST, - .sin6_port = htons(coap_port) }; + .sin6_port = htons(port) }; struct net_if_addr *ifaddr; struct net_if *iface; int ret; @@ -71,22 +151,36 @@ static int join_coap_multicast_group(void) return 0; } +#endif /* CONFIG_NET_IPV6 */ + int main(void) { + int ret; + wait_for_network(); - return join_coap_multicast_group(); -} + ret = setup_dtls(); + if (ret < 0) { + LOG_ERR("Failed to setup DTLS (%d)", ret); + return ret; + } -#else /* CONFIG_NET_IPV6 */ +#if !defined(CONFIG_NET_SAMPLE_COAPS_SERVICE) && defined(CONFIG_NET_IPV6) + ret = join_coap_multicast_group(coap_port); + if (ret < 0) { + LOG_ERR("Failed to join CoAP all-nodes multicast (%d)", ret); + return ret; + } +#endif -int main(void) -{ - wait_for_network(); +#ifdef CONFIG_NET_SAMPLE_COAPS_SERVICE + /* CoAP secure server has to be started manually after DTLS setup */ + ret = coap_service_start(&coap_server); + if (ret < 0) { + LOG_ERR("Failed to start CoAP secure server (%d)", ret); + return ret; + } +#endif - return 0; + return ret; } - -#endif /* CONFIG_NET_IPV6 */ - -COAP_SERVICE_DEFINE(coap_server, NULL, &coap_port, COAP_SERVICE_AUTOSTART);