diff --git a/.github/workflows/check-labels.yml b/.github/workflows/check-labels.yml index 37d9dcd3ee26e..027e7e3e80adb 100644 --- a/.github/workflows/check-labels.yml +++ b/.github/workflows/check-labels.yml @@ -1,7 +1,7 @@ name: check-labels on: pull_request: - types: [opened, reopened, labeled, unlabeled] + types: [opened, reopened, labeled, unlabeled, synchronize] pull_request_review: types: [submitted, dismissed] jobs: diff --git a/cpu/avr8_common/avr_libc_extra/include/errno.h b/cpu/avr8_common/avr_libc_extra/include/errno.h index 0277ad9073629..231d1a3f44faa 100644 --- a/cpu/avr8_common/avr_libc_extra/include/errno.h +++ b/cpu/avr8_common/avr_libc_extra/include/errno.h @@ -148,6 +148,9 @@ extern int errno; #define ETXTBSY (79) /**< Text file busy. */ #define EWOULDBLOCK (80) /**< Operation would block (may be the same value as [EAGAIN]). */ #define EXDEV (81) /**< Cross-device link. */ +#define EHOSTDOWN (82) /**< Host is down. */ +#define EPFNOSUPPORT (83) /**< Protocol family not supported. */ +#define ETOOMANYREFS (84) /**< Too many references: cannot splice. */ /** @} */ /** @} */ diff --git a/dist/tools/suit/suit-manifest-generator/suit_tool/get_pubkey.py b/dist/tools/suit/suit-manifest-generator/suit_tool/get_pubkey.py index b9f075bb0b38f..7289e375035bb 100644 --- a/dist/tools/suit/suit-manifest-generator/suit_tool/get_pubkey.py +++ b/dist/tools/suit/suit-manifest-generator/suit_tool/get_pubkey.py @@ -49,11 +49,11 @@ def to_header(pk): if isinstance(pk, ed25519.Ed25519PrivateKey): public_bytes = pk.public_key().public_bytes(ks.Encoding.Raw, ks.PublicFormat.Raw) - public_c_def = ['const uint8_t public_key[] = {'] + textwrap.wrap( + public_c_def = ['{'] + textwrap.wrap( ', '.join(['{:0=#4x}'.format(x) for x in public_bytes]), 76 ) - return str.encode('\n '.join(public_c_def) + '\n};\n') + return str.encode('\n '.join(public_c_def) + '\n},\n') OutputFormaters = { diff --git a/examples/filesystem/Makefile.ci b/examples/filesystem/Makefile.ci index d5368f025e748..eb1520a8a0fa3 100644 --- a/examples/filesystem/Makefile.ci +++ b/examples/filesystem/Makefile.ci @@ -5,8 +5,8 @@ BOARD_INSUFFICIENT_MEMORY := \ arduino-uno \ atmega328p \ atmega328p-xplained-mini \ - nucleo-f031k6 \ nucleo-l011k4 \ samd10-xmini \ stm32f030f4-demo \ + waspmote-pro \ # diff --git a/examples/lua_REPL/Makefile.ci b/examples/lua_REPL/Makefile.ci index a616a7b44e83d..e39c182eb9065 100644 --- a/examples/lua_REPL/Makefile.ci +++ b/examples/lua_REPL/Makefile.ci @@ -10,9 +10,9 @@ BOARD_INSUFFICIENT_MEMORY := \ bastwan \ blackpill-stm32f103c8 \ blackpill-stm32f103cb \ + bluepill-stm32f030c8 \ bluepill-stm32f103c8 \ bluepill-stm32f103cb \ - bluepill-stm32f030c8 \ calliope-mini \ cc1350-launchpad \ cc2538dk \ @@ -22,9 +22,6 @@ BOARD_INSUFFICIENT_MEMORY := \ e104-bt5011a-tb \ e180-zg120b-tb \ ek-lm4f120xl \ - esp8266-esp-12x \ - esp8266-olimex-mod \ - esp8266-sparkfun-thing \ feather-m0 \ feather-m0-lora \ feather-m0-wifi \ @@ -96,7 +93,6 @@ BOARD_INSUFFICIENT_MEMORY := \ spark-core \ stk3200 \ stk3600 \ - stm32f030f4-demo \ stm32f0discovery \ stm32f3discovery \ stm32f7508-dk \ diff --git a/makefiles/suit.base.inc.mk b/makefiles/suit.base.inc.mk index 8272c387b7395..633d859fe332a 100644 --- a/makefiles/suit.base.inc.mk +++ b/makefiles/suit.base.inc.mk @@ -18,13 +18,11 @@ else SUIT_KEY_DIR ?= $(XDG_DATA_HOME)/RIOT/keys endif -# Enable user to encrypt private key with a password -ifneq (,$(SUIT_SEC_PASSWORD)) - SUIT_TOOL_ARGS += -p $(SUIT_SEC_PASSWORD) -endif - SUIT_SEC ?= $(SUIT_KEY_DIR)/$(SUIT_KEY).pem +# Multiple keys can be specified with "key0:pw0 key1:pw1 …" (pw may be empty) +SUIT_SECS ?= $(SUIT_SEC):$(SUIT_SEC_PASSWORD) + SUIT_PUB_HDR = $(BINDIR)/riotbuild/public_key.h SUIT_PUB_HDR_DIR = $(dir $(SUIT_PUB_HDR)) CFLAGS += -I$(SUIT_PUB_HDR_DIR) @@ -40,7 +38,21 @@ $(SUIT_SEC): | $(CLEAN) # key's mtime is too far back). $(SUIT_PUB_HDR): $(SUIT_SEC) FORCE | $(CLEAN) $(Q)mkdir -p $(SUIT_PUB_HDR_DIR) - $(Q)$(SUIT_TOOL) pubkey $(SUIT_TOOL_ARGS) -f header -k $(SUIT_SEC) \ - | '$(LAZYSPONGE)' $(LAZYSPONGE_FLAGS) '$@' + $(Q)( \ + echo "const uint8_t public_key[][32] = {"; \ + for i in $(SUIT_SECS); do \ + key=$${i%:*}; \ + pw=$${i#*:}; \ + if [ "$$key" = "$$pw" ]; then \ + unset pw; \ + fi; \ + if [ -z "$$pw" ]; then \ + $(SUIT_TOOL) pubkey -f header -k $$key; \ + else \ + $(SUIT_TOOL) pubkey -f header -k $$key -p $$pw; \ + fi \ + done; \ + echo "};" \ + ) | '$(LAZYSPONGE)' $(LAZYSPONGE_FLAGS) '$@' suit/genkey: $(SUIT_SEC) diff --git a/pkg/tinydtls/contrib/sock_dtls.c b/pkg/tinydtls/contrib/sock_dtls.c index 003d8609ff4ff..124a0a07bdec5 100644 --- a/pkg/tinydtls/contrib/sock_dtls.c +++ b/pkg/tinydtls/contrib/sock_dtls.c @@ -814,6 +814,71 @@ ssize_t sock_dtls_recv_aux(sock_dtls_t *sock, sock_dtls_session_t *remote, } } +ssize_t sock_dtls_recv_buf_aux(sock_dtls_t *sock, sock_dtls_session_t *remote, + void **data, void **buf_ctx, uint32_t timeout, + sock_dtls_aux_rx_t *aux) +{ + assert(sock); + assert(data); + assert(buf_ctx); + assert(remote); + + sock_udp_ep_t ep; + + /* 2nd call to the function (with ctx set) will free the data */ + if (*buf_ctx) { + int res = sock_udp_recv_buf_aux(sock->udp_sock, data, buf_ctx, + timeout, &ep, (sock_udp_aux_rx_t *)aux); + assert(res == 0); + return res; + } + + /* loop breaks when timeout or application data read */ + while (1) { + ssize_t res; + uint32_t start_recv = ztimer_now(ZTIMER_USEC); + msg_t msg; + + if (sock->buffer.data != NULL) { + *data = sock->buffer.data; + sock->buffer.data = NULL; + _copy_session(sock, remote); + + return sock->buffer.datalen; + } + else if (mbox_try_get(&sock->mbox, &msg) && + msg.type == DTLS_EVENT_CONNECTED) { + return _complete_handshake(sock, remote, msg.content.ptr); + } + /* Crude way to somewhat test that `sock_dtls_aux_rx_t` and + * `sock_udp_aux_rx_t` remain compatible: */ + static_assert(sizeof(sock_dtls_aux_rx_t) == sizeof(sock_udp_aux_rx_t), + "sock_dtls_aux_rx_t became incompatible with " + "sock_udp_aux_rx_t"); + res = sock_udp_recv_buf_aux(sock->udp_sock, data, buf_ctx, + timeout, &ep, (sock_udp_aux_rx_t *)aux); + if (res == 0) { + continue; + } + if (res < 0) { + DEBUG("sock_dtls: error receiving UDP packet: %d\n", (int)res); + return res; + } + + _ep_to_session(&ep, &remote->dtls_session); + res = dtls_handle_message(sock->dtls_ctx, &remote->dtls_session, + *data, res); + + if ((timeout != SOCK_NO_TIMEOUT) && (timeout != 0)) { + timeout = _update_timeout(start_recv, timeout); + } + if (timeout == 0) { + DEBUG("sock_dtls: timed out while decrypting message\n"); + return -ETIMEDOUT; + } + } +} + void sock_dtls_close(sock_dtls_t *sock) { dtls_free_context(sock->dtls_ctx); diff --git a/sys/Makefile.dep b/sys/Makefile.dep index 4ae9d6ae4efac..1233470594192 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -713,6 +713,11 @@ ifneq (,$(filter luid,$(USEMODULE))) FEATURES_OPTIONAL += periph_cpuid endif +ifneq (,$(filter nanocoap_dtls,$(USEMODULE))) + USEMODULE += sock_dtls + USEPKG += tinydtls +endif + ifneq (,$(filter nanocoap_sock,$(USEMODULE))) USEMODULE += sock_udp USEMODULE += sock_util diff --git a/sys/include/net/coap.h b/sys/include/net/coap.h index 1480ea543dd14..d14a0bfe072bf 100644 --- a/sys/include/net/coap.h +++ b/sys/include/net/coap.h @@ -31,6 +31,11 @@ extern "C" { */ #define COAP_PORT (5683) +/** + * @brief Default CoAP DTLS port + */ +#define COAPS_PORT (5684) + #define COAP_V1 (1) /**< Identifier for CoAP version 1 (RFC 7252) */ /** diff --git a/sys/include/net/nanocoap_sock.h b/sys/include/net/nanocoap_sock.h index 27439a2db116a..c8dc01f6bd6a2 100644 --- a/sys/include/net/nanocoap_sock.h +++ b/sys/include/net/nanocoap_sock.h @@ -135,16 +135,58 @@ #include "net/nanocoap.h" #include "net/sock/udp.h" #include "net/sock/util.h" +#if IS_USED(MODULE_NANOCOAP_DTLS) +#include "net/credman.h" +#include "net/sock/dtls.h" +#endif #ifdef __cplusplus extern "C" { #endif /** - * @brief nanocoap socket type - * + * @brief Timeout for CoAP over DTLS queries in milliseconds */ -typedef sock_udp_t nanocoap_sock_t; +#ifndef CONFIG_NANOCOAP_SOCK_DTLS_TIMEOUT_MS +#define CONFIG_NANOCOAP_SOCK_DTLS_TIMEOUT_MS (1000U) +#endif + +/** + * @brief Number of CoAP over DTLS handshake retries + */ +#ifndef CONFIG_NANOCOAP_SOCK_DTLS_RETRIES +#define CONFIG_NANOCOAP_SOCK_DTLS_RETRIES (2) +#endif + +/** + * @brief Credman tag used for NanoCoAP + * Tag together with the credential type (PSK) needs to be unique + */ +#ifndef CONFIG_NANOCOAP_SOCK_DTLS_TAG +#define CONFIG_NANOCOAP_SOCK_DTLS_TAG (0xc0ab) +#endif + +/** + * @brief NanoCoAP socket types + */ +typedef enum { + COAP_SOCKET_TYPE_UDP, /**< transport is plain UDP */ + COAP_SOCKET_TYPE_DTLS, /**< transport is DTLS */ +} nanocoap_socket_type_t; + +/** + * @brief NanoCoAP socket struct + */ +typedef struct { + sock_udp_t udp; /**< UDP socket */ +#if IS_USED(MODULE_NANOCOAP_DTLS) || defined(DOXYGEN) + sock_dtls_t dtls; /**< DTLS socket */ + sock_dtls_session_t dtls_session; /**< Session object for the stored socket. + Used for exchanging a session between + functions. */ + nanocoap_socket_type_t type; /**< Socket type (UDP, DTLS) */ +#endif +} nanocoap_sock_t; /** * @brief Blockwise request helper struct @@ -185,9 +227,30 @@ static inline int nanocoap_sock_connect(nanocoap_sock_t *sock, const sock_udp_ep_t *local, const sock_udp_ep_t *remote) { - return sock_udp_create(sock, local, remote, 0); +#if IS_USED(MODULE_NANOCOAP_DTLS) + sock->type = COAP_SOCKET_TYPE_UDP; +#endif + + return sock_udp_create(&sock->udp, local, remote, 0); } +#if IS_USED(MODULE_NANOCOAP_DTLS) || DOXYGEN +/** + * @brief Create a DTLS secured CoAP client socket + * + * @param[out] sock CoAP UDP socket + * @param[in] local Local UDP endpoint, may be NULL + * @param[in] remote remote UDP endpoint + * @param[in] tag Tag of the PSK credential to use + * Has to be added with @ref credman_add + * + * @returns 0 on success + * @returns <0 on error + */ +int nanocoap_sock_dtls_connect(nanocoap_sock_t *sock, sock_udp_ep_t *local, + const sock_udp_ep_t *remote, credman_tag_t tag); +#endif + /** * @brief Create a CoAP client socket by URL * @@ -206,7 +269,13 @@ int nanocoap_sock_url_connect(const char *url, nanocoap_sock_t *sock); */ static inline void nanocoap_sock_close(nanocoap_sock_t *sock) { - sock_udp_close(sock); +#if IS_USED(MODULE_NANOCOAP_DTLS) + if (sock->type == COAP_SOCKET_TYPE_DTLS) { + sock_dtls_session_destroy(&sock->dtls, &sock->dtls_session); + sock_dtls_close(&sock->dtls); + } +#endif + sock_udp_close(&sock->udp); } /** @@ -441,7 +510,7 @@ ssize_t nanocoap_sock_request(nanocoap_sock_t *sock, coap_pkt_t *pkt, size_t len * @returns length of response on success * @returns <0 on error */ -ssize_t nanocoap_sock_request_cb(sock_udp_t *sock, coap_pkt_t *pkt, +ssize_t nanocoap_sock_request_cb(nanocoap_sock_t *sock, coap_pkt_t *pkt, coap_request_cb_t cb, void *arg); /** diff --git a/sys/include/ztimer.h b/sys/include/ztimer.h index 3ee7356463022..30b9428532548 100644 --- a/sys/include/ztimer.h +++ b/sys/include/ztimer.h @@ -776,6 +776,19 @@ void ztimer_set_wakeup(ztimer_clock_t *clock, ztimer_t *timer, uint32_t offset, void ztimer_set_timeout_flag(ztimer_clock_t *clock, ztimer_t *timer, uint32_t timeout); +/** + * @brief Unlock mutex after @p timeout + * + * This function will unlock the given mutex after the timeout has passed. + * + * @param[in] clock ztimer clock to operate on + * @param[in] timer timer struct to use + * @param[in] timeout timeout in ztimer_clock's ticks + * @param[in] mutex mutex to unlock after timeout + */ +void ztimer_mutex_unlock(ztimer_clock_t *clock, ztimer_t *timer, + uint32_t timeout, mutex_t *mutex); + /** * @brief Try to lock the given mutex, but give up after @p timeout * diff --git a/sys/net/application_layer/nanocoap/sock.c b/sys/net/application_layer/nanocoap/sock.c index a9ad2b9910b33..72e176b47e971 100644 --- a/sys/net/application_layer/nanocoap/sock.c +++ b/sys/net/application_layer/nanocoap/sock.c @@ -26,9 +26,11 @@ #include #include "atomic_utils.h" +#include "net/credman.h" #include "net/nanocoap_sock.h" #include "net/sock/util.h" #include "net/sock/udp.h" +#include "net/iana/portrange.h" #include "random.h" #include "sys/uio.h" #include "timex.h" @@ -37,6 +39,17 @@ #define ENABLE_DEBUG 0 #include "debug.h" +/** + * @brief Size of the buffer used for the DTLS handshake + * + * This size was found suitable for DTLS using a simple PSK in mode AES_128_CCM_8. + * DTLS places no restriction on its handshake package size therefore this might need change, + * if mode or key-size change especially if certificates instead of PSK are used. + */ +#ifndef CONFIG_NANOCOAP_DTLS_HANDSHAKE_BUF_SIZE +#define CONFIG_NANOCOAP_DTLS_HANDSHAKE_BUF_SIZE (160) +#endif + enum { STATE_REQUEST_SEND, /**< request was just sent or will be sent again */ STATE_RESPONSE_RCVD, /**< response received but might be invalid */ @@ -56,6 +69,93 @@ static uint16_t _get_id(void) return atomic_fetch_add_u16(&id, 1); } +#if IS_USED(MODULE_NANOCOAP_DTLS) +int nanocoap_sock_dtls_connect(nanocoap_sock_t *sock, sock_udp_ep_t *local, + const sock_udp_ep_t *remote, credman_tag_t tag) +{ + int res; + uint32_t timeout_ms = CONFIG_NANOCOAP_SOCK_DTLS_TIMEOUT_MS; + uint8_t retries = CONFIG_NANOCOAP_SOCK_DTLS_RETRIES; + + bool auto_port = local->port == 0; + do { + if (auto_port) { + /* choose random ephemeral port, since DTLS requires a local port */ + local->port = random_uint32_range(IANA_DYNAMIC_PORTRANGE_MIN, + IANA_DYNAMIC_PORTRANGE_MAX); + } + /* connect UDP socket */ + res = nanocoap_sock_connect(sock, local, remote); + } while (auto_port && (res == -EADDRINUSE)); + + if (res < 0) { + return res; + } + + /* create DTLS socket on to of UDP socket */ + res = sock_dtls_create(&sock->dtls, &sock->udp, tag, + SOCK_DTLS_1_2, SOCK_DTLS_CLIENT); + if (res < 0) { + DEBUG("Unable to create DTLS sock: %s\n", strerror(-res)); + nanocoap_sock_close(sock); + return res; + } + sock->type = COAP_SOCKET_TYPE_DTLS; + + while (1) { + uint8_t buf[CONFIG_NANOCOAP_DTLS_HANDSHAKE_BUF_SIZE]; + mutex_t lock = MUTEX_INIT_LOCKED; + ztimer_t timeout; + + /* unlock lock after timeout */ + ztimer_mutex_unlock(ZTIMER_MSEC, &timeout, timeout_ms, &lock); + + /* create DTLS session */ + res = sock_dtls_session_init(&sock->dtls, remote, &sock->dtls_session); + if (res >= 0) { + /* handle handshake */ + res = sock_dtls_recv(&sock->dtls, &sock->dtls_session, buf, + sizeof(buf), timeout_ms * US_PER_MS); + if (res == -SOCK_DTLS_HANDSHAKE) { + DEBUG("DTLS handshake successful\n"); + ztimer_remove(ZTIMER_MSEC, &timeout); + return 0; + } + DEBUG("Unable to establish DTLS handshake: %s\n", strerror(-res)); + + } else { + DEBUG("Unable to initialize DTLS session: %s\n", strerror(-res)); + } + + sock_dtls_session_destroy(&sock->dtls, &sock->dtls_session); + + if (retries--) { + /* wait for timeout to expire */ + mutex_lock(&lock); + } else { + ztimer_remove(ZTIMER_MSEC, &timeout); + break; + } + + /* see https://datatracker.ietf.org/doc/html/rfc6347#section-4.2.4.1 */ + timeout_ms *= 2U; + } + + nanocoap_sock_close(sock); + return res; +} +#else +int nanocoap_sock_dtls_connect(nanocoap_sock_t *sock, const sock_udp_ep_t *local, + const sock_udp_ep_t *remote, credman_tag_t tag) +{ + (void)sock; + (void)local; + (void)remote; + (void)tag; + return -ENOTSUP; +} +#endif + static int _get_error(const coap_pkt_t *pkt) { switch (coap_get_code_class(pkt)) { @@ -68,15 +168,61 @@ static int _get_error(const coap_pkt_t *pkt) } } +static inline nanocoap_socket_type_t _get_type(nanocoap_sock_t *sock) +{ +#if IS_USED(MODULE_NANOCOAP_DTLS) + return sock->type; +#else + (void)sock; + return COAP_SOCKET_TYPE_UDP; +#endif +} + +static int _sock_sendv(nanocoap_sock_t *sock, const iolist_t *snips) +{ + switch (_get_type(sock)) { + case COAP_SOCKET_TYPE_UDP: + return sock_udp_sendv(&sock->udp, snips, NULL); +#if IS_USED(MODULE_NANOCOAP_DTLS) + case COAP_SOCKET_TYPE_DTLS: + return sock_dtls_sendv(&sock->dtls, &sock->dtls_session, snips, + CONFIG_NANOCOAP_SOCK_DTLS_TIMEOUT_MS); +#endif + default: + assert(0); + return -EINVAL; + } +} + +static int _sock_recv_buf(nanocoap_sock_t *sock, void **data, void **ctx, uint32_t timeout) +{ + switch (_get_type(sock)) { + case COAP_SOCKET_TYPE_UDP: + return sock_udp_recv_buf(&sock->udp, data, ctx, timeout, NULL); +#if IS_USED(MODULE_NANOCOAP_DTLS) + case COAP_SOCKET_TYPE_DTLS: + return sock_dtls_recv_buf(&sock->dtls, &sock->dtls_session, data, ctx, timeout); +#endif + default: + assert(0); + return -EINVAL; + } +} + static int _send_ack(nanocoap_sock_t *sock, coap_pkt_t *pkt) { coap_hdr_t ack; unsigned tkl = coap_get_token_len(pkt); + const iolist_t snip = { + .iol_base = &ack, + .iol_len = sizeof(ack), + }; + coap_build_hdr(&ack, COAP_TYPE_ACK, coap_get_token(pkt), tkl, COAP_CODE_EMPTY, ntohs(pkt->hdr->id)); - return sock_udp_send(sock, &ack, sizeof(ack), NULL); + return _sock_sendv(sock, &snip); } static bool _id_or_token_missmatch(const coap_pkt_t *pkt, unsigned id, @@ -149,7 +295,7 @@ ssize_t nanocoap_sock_request_cb(nanocoap_sock_t *sock, coap_pkt_t *pkt, DEBUG("nanocoap: send %u bytes (%u tries left)\n", (unsigned)iolist_size(&head), tries_left); - res = sock_udp_sendv(sock, &head, NULL); + res = _sock_sendv(sock, &head); if (res <= 0) { DEBUG("nanocoap: error sending coap request, %d\n", (int)res); return res; @@ -170,7 +316,7 @@ ssize_t nanocoap_sock_request_cb(nanocoap_sock_t *sock, coap_pkt_t *pkt, _deadline_left_us(deadline)); } const void *old_ctx = ctx; - tmp = sock_udp_recv_buf(sock, &payload, &ctx, _deadline_left_us(deadline), NULL); + tmp = _sock_recv_buf(sock, &payload, &ctx, _deadline_left_us(deadline)); /* sock_udp_recv_buf() is supposed to return multiple packet fragments * when called multiple times with the same context. * In practise, this is not implemented and it will always return a pointer @@ -271,7 +417,7 @@ static int _request_cb(void *arg, coap_pkt_t *pkt) return pkt_len; } -ssize_t nanocoap_sock_request(sock_udp_t *sock, coap_pkt_t *pkt, size_t len) +ssize_t nanocoap_sock_request(nanocoap_sock_t *sock, coap_pkt_t *pkt, size_t len) { struct iovec buf = { .iov_base = pkt->hdr, @@ -611,7 +757,14 @@ int nanocoap_sock_url_connect(const char *url, nanocoap_sock_t *sock) char hostport[CONFIG_SOCK_HOSTPORT_MAXLEN]; sock_udp_ep_t remote; - if (strncmp(url, "coap://", 7)) { + bool is_coaps = false; + + if (IS_USED(MODULE_NANOCOAP_DTLS) && !strncmp(url, "coaps://", 8)) { + DEBUG("nanocoap: CoAPS URL detected\n"); + is_coaps = true; + } + + if (!is_coaps && strncmp(url, "coap://", 7)) { DEBUG("nanocoap: URL doesn't start with \"coap://\"\n"); return -EINVAL; } @@ -627,10 +780,26 @@ int nanocoap_sock_url_connect(const char *url, nanocoap_sock_t *sock) } if (!remote.port) { - remote.port = COAP_PORT; + remote.port = is_coaps ? COAPS_PORT : COAP_PORT; } - return nanocoap_sock_connect(sock, NULL, &remote); + if (is_coaps) { + + /* tinydtls wants the interface to match */ + if (!remote.netif && + ipv6_addr_is_link_local((ipv6_addr_t *)remote.addr.ipv6)) { + netif_t *iface = netif_iter(NULL); + if (iface == NULL) { + return -ENODEV; + } + remote.netif = netif_get_id(iface); + } + + sock_udp_ep_t local = SOCK_IPV6_EP_ANY; + return nanocoap_sock_dtls_connect(sock, &local, &remote, CONFIG_NANOCOAP_SOCK_DTLS_TAG); + } else { + return nanocoap_sock_connect(sock, NULL, &remote); + } } int nanocoap_get_blockwise_url(const char *url, @@ -693,13 +862,13 @@ int nanocoap_server(sock_udp_ep_t *local, uint8_t *buf, size_t bufsize) local->port = COAP_PORT; } - ssize_t res = sock_udp_create(&sock, local, NULL, 0); + ssize_t res = sock_udp_create(&sock.udp, local, NULL, 0); if (res != 0) { return -1; } while (1) { - res = sock_udp_recv(&sock, buf, bufsize, -1, &remote); + res = sock_udp_recv(&sock.udp, buf, bufsize, -1, &remote); if (res < 0) { DEBUG("error receiving UDP packet %d\n", (int)res); } @@ -710,7 +879,7 @@ int nanocoap_server(sock_udp_ep_t *local, uint8_t *buf, size_t bufsize) continue; } if ((res = coap_handle_req(&pkt, buf, bufsize, &ctx)) > 0) { - sock_udp_send(&sock, buf, res, &remote); + sock_udp_send(&sock.udp, buf, res, &remote); } else { DEBUG("error handling request %d\n", (int)res); diff --git a/sys/suit/handlers_command_seq.c b/sys/suit/handlers_command_seq.c index c18e674e95c33..f8b63ea292870 100644 --- a/sys/suit/handlers_command_seq.c +++ b/sys/suit/handlers_command_seq.c @@ -438,7 +438,8 @@ static int _dtv_fetch(suit_manifest_t *manifest, int key, if (0) {} #ifdef MODULE_SUIT_TRANSPORT_COAP - else if (strncmp(manifest->urlbuf, "coap://", 7) == 0) { + else if ((strncmp(manifest->urlbuf, "coap://", 7) == 0) || + (IS_USED(MODULE_NANOCOAP_DTLS) && strncmp(manifest->urlbuf, "coaps://", 8) == 0)) { res = nanocoap_get_blockwise_url(manifest->urlbuf, CONFIG_SUIT_COAP_BLOCKSIZE, _storage_helper, manifest); diff --git a/sys/suit/handlers_envelope.c b/sys/suit/handlers_envelope.c index 4a1df3087d6e0..e63131c86605b 100644 --- a/sys/suit/handlers_envelope.c +++ b/sys/suit/handlers_envelope.c @@ -32,17 +32,18 @@ #include "suit/handlers.h" #include "suit.h" -static int _auth_handler(suit_manifest_t *manifest, int key, - nanocbor_value_t *it) +static int _verify_with_key(suit_manifest_t *manifest, const nanocbor_value_t *it, + const void *key) { - (void)key; cose_sign_dec_t verify; const uint8_t *cose_buf; const uint8_t *auth_container; size_t auth_container_len; size_t cose_len = 0; + nanocbor_value_t tmp = *it; + /* It is a list of cose signatures */ - if (nanocbor_get_bstr(it, &auth_container, &auth_container_len) < 0) { + if (nanocbor_get_bstr(&tmp, &auth_container, &auth_container_len) < 0) { LOG_INFO("Unable to get auth container\n"); return SUIT_ERR_INVALID_MANIFEST; } @@ -51,7 +52,7 @@ static int _auth_handler(suit_manifest_t *manifest, int key, cose_key_t pkey; cose_key_init(&pkey); cose_key_set_keys(&pkey, COSE_EC_CURVE_ED25519, COSE_ALGO_EDDSA, - (uint8_t *)public_key, NULL, NULL); + (void *)key, NULL, NULL); nanocbor_value_t _cont, arr; nanocbor_decoder_init(&_cont, auth_container, auth_container_len); @@ -96,6 +97,7 @@ static int _auth_handler(suit_manifest_t *manifest, int key, } else { LOG_INFO("Unable to validate signature: %d\n", verification); + res = SUIT_ERR_SIGNATURE; } } } @@ -103,6 +105,23 @@ static int _auth_handler(suit_manifest_t *manifest, int key, return res; } +static int _auth_handler(suit_manifest_t *manifest, int key, + nanocbor_value_t *it) +{ + (void)key; + + int res = 0; + + for (unsigned i = 0; i < ARRAY_SIZE(public_key); ++i) { + res = _verify_with_key(manifest, it, public_key[i]); + if (res != SUIT_ERR_SIGNATURE) { + break; + } + } + + return res; +} + static int _manifest_handler(suit_manifest_t *manifest, int key, nanocbor_value_t *it) { diff --git a/sys/suit/transport/worker.c b/sys/suit/transport/worker.c index 1a32bc350c76e..a54022fb287c5 100644 --- a/sys/suit/transport/worker.c +++ b/sys/suit/transport/worker.c @@ -87,7 +87,8 @@ int suit_handle_url(const char *url) if (0) {} #ifdef MODULE_SUIT_TRANSPORT_COAP - else if (strncmp(url, "coap://", 7) == 0) { + else if ((strncmp(url, "coap://", 7) == 0) || + (IS_USED(MODULE_NANOCOAP_DTLS) && strncmp(url, "coaps://", 8) == 0)) { size = nanocoap_get_blockwise_url_to_buf(url, CONFIG_SUIT_COAP_BLOCKSIZE, _manifest_buf, diff --git a/sys/tiny_strerror/tiny_strerror.c b/sys/tiny_strerror/tiny_strerror.c index ad129d935b25d..e85caa4b92846 100644 --- a/sys/tiny_strerror/tiny_strerror.c +++ b/sys/tiny_strerror/tiny_strerror.c @@ -44,10 +44,13 @@ static const char *lookup[] = { [EDEADLK] = "-EDEADLK", [EDESTADDRREQ] = "-EDESTADDRREQ", [EDOM] = "-EDOM", + [EDQUOT] = "-EDQUOT", [EEXIST] = "-EEXIST", [EFAULT] = "-EFAULT", [EFBIG] = "-EFBIG", + [EHOSTDOWN] = "-EHOSTDOWN", [EHOSTUNREACH] = "-EHOSTUNREACH", + [EIDRM] = "-EIDRM", [EILSEQ] = "-EILSEQ", [EINPROGRESS] = "-EINPROGRESS", [EINTR] = "-EINTR", @@ -59,37 +62,51 @@ static const char *lookup[] = { [EMFILE] = "-EMFILE", [EMLINK] = "-EMLINK", [EMSGSIZE] = "-EMSGSIZE", + [EMULTIHOP] = "-EMULTIHOP", [ENAMETOOLONG] = "-ENAMETOOLONG", [ENETDOWN] = "-ENETDOWN", [ENETRESET] = "-ENETRESET", [ENETUNREACH] = "-ENETUNREACH", [ENFILE] = "-ENFILE", [ENOBUFS] = "-ENOBUFS", + [ENODATA] = "-ENODATA", [ENODEV] = "-ENODEV", [ENOENT] = "-ENOENT", [ENOEXEC] = "-ENOEXEC", [ENOLCK] = "-ENOLCK", + [ENOLINK] = "-ENOLILNK", [ENOMEM] = "-ENOMEM", [ENOMSG] = "-ENOMSG", [ENOPROTOOPT] = "-ENOPROTOOPT", [ENOSPC] = "-ENOSPC", + [ENOSR] = "-ENOSR", + [ENOSTR] = "-ENOSTR", [ENOSYS] = "-ENOSYS", [ENOTCONN] = "-ENOTCONN", [ENOTDIR] = "-ENOTDIR", [ENOTEMPTY] = "-ENOTEMPTY", + [ENOTRECOVERABLE] = "-ENOTRECOVERABLE", [ENOTSOCK] = "-ENOTSOCK", [ENOTSUP] = "-ENOTSUP", [ENOTTY] = "-ENOTTY", [ENXIO] = "-ENXIO", + [EOVERFLOW] = "-EOVERFLOW", + [EOWNERDEAD ] = "-EOWNERDEAD ", [EPERM] = "-EPERM", + [EPFNOSUPPORT] = "-EPFNOSUPPORT", [EPIPE] = "-EPIPE", [EPROTONOSUPPORT] = "-EPROTONOSUPPORT", [EPROTOTYPE] = "-EPROTOTYPE", + [EPROTO] = "-EPROTO", [ERANGE] = "-ERANGE", [EROFS] = "-EROFS", [ESPIPE] = "-ESPIPE", [ESRCH] = "-ESRCH", + [ESTALE] = "-ESTALE", [ETIMEDOUT] = "-ETIMEDOUT", + [ETIME] = "-ETIME", + [ETOOMANYREFS] = "-ETOOMANYREFS", + [ETXTBSY] = "-ETXTBSY", [EXDEV] = "-EXDEV", /* EAGAIN and EWOULDBLOCK have the exact same meaning and consequently may * have the same numeric value */ diff --git a/sys/ztimer/util.c b/sys/ztimer/util.c index c01f8802fa139..277f4854be3c5 100644 --- a/sys/ztimer/util.c +++ b/sys/ztimer/util.c @@ -144,6 +144,18 @@ void ztimer_set_timeout_flag(ztimer_clock_t *clock, ztimer_t *t, } #endif +void ztimer_mutex_unlock(ztimer_clock_t *clock, ztimer_t *timer, uint32_t offset, + mutex_t *mutex) +{ + unsigned state = irq_disable(); + + timer->callback = _callback_unlock_mutex; + timer->arg = (void *)mutex; + + irq_restore(state); + ztimer_set(clock, timer, offset); +} + static void _callback_wakeup(void *arg) { thread_wakeup((kernel_pid_t)((intptr_t)arg)); diff --git a/tests/driver_at86rf2xx/Makefile.ci b/tests/driver_at86rf2xx/Makefile.ci index fa21afb84b054..c9ac296b6cac1 100644 --- a/tests/driver_at86rf2xx/Makefile.ci +++ b/tests/driver_at86rf2xx/Makefile.ci @@ -3,8 +3,8 @@ BOARD_INSUFFICIENT_MEMORY := \ arduino-leonardo \ arduino-nano \ arduino-uno \ - atmega328p-xplained-mini \ atmega328p \ + atmega328p-xplained-mini \ nucleo-l011k4 \ samd10-xmini \ stm32f030f4-demo \ diff --git a/tests/driver_hsc/Makefile.ci b/tests/driver_hsc/Makefile.ci index 69c36480c64d0..1152ca53bcbb8 100644 --- a/tests/driver_hsc/Makefile.ci +++ b/tests/driver_hsc/Makefile.ci @@ -1,8 +1,8 @@ BOARD_INSUFFICIENT_MEMORY := \ arduino-duemilanove \ + arduino-leonardo \ arduino-nano \ arduino-uno \ atmega328p \ atmega328p-xplained-mini \ - nucleo-l011k4 \ # diff --git a/tests/gnrc_sock_tcp/Makefile.ci b/tests/gnrc_sock_tcp/Makefile.ci index e782ac24de7a6..d6c69d5cda1f5 100644 --- a/tests/gnrc_sock_tcp/Makefile.ci +++ b/tests/gnrc_sock_tcp/Makefile.ci @@ -7,7 +7,6 @@ BOARD_INSUFFICIENT_MEMORY := \ atmega1284p \ atmega328p \ atmega328p-xplained-mini \ - atxmega-a1u-xpro \ atxmega-a3bu-xplained \ bluepill-stm32f030c8 \ derfmega128 \ @@ -15,6 +14,7 @@ BOARD_INSUFFICIENT_MEMORY := \ hifive1b \ i-nucleo-lrwan1 \ im880b \ + m1284p \ mega-xplained \ microduino-corerf \ msb-430 \ diff --git a/tests/nanocoap_cli/Makefile b/tests/nanocoap_cli/Makefile index 79f5173546475..c11c6cefc7d96 100644 --- a/tests/nanocoap_cli/Makefile +++ b/tests/nanocoap_cli/Makefile @@ -22,22 +22,27 @@ LOW_MEMORY_BOARDS := \ blackpill-stm32f103c8 \ bluepill-stm32f103c8 \ derfmega128 \ + im880b \ nucleo-f302r8 \ saml10-xpro \ saml11-xpro \ + spark-core \ stm32f7508-dk \ stm32mp157c-dk2 \ # -# Don't enable VFS functions on small boards +# Don't enable VFS, DTLS functions on small boards ifeq (,$(filter $(BOARD),$(LOW_MEMORY_BOARDS))) + USEMODULE += nanocoap_dtls + USEMODULE += prng_sha256prng + USEMODULE += nanocoap_vfs USEMODULE += vfs_default # USEMODULE += vfs_auto_format USEMODULE += shell_cmds_default - # VFS operations require more stack on the main thread - CFLAGS += -DTHREAD_STACKSIZE_MAIN=THREAD_STACKSIZE_LARGE + # DTLS and VFS operations require more stack on the main thread + CFLAGS += -DTHREAD_STACKSIZE_MAIN=\(3*THREAD_STACKSIZE_DEFAULT\) # always enable auto-format for native ifeq ($(BOARD),native) diff --git a/tests/nanocoap_cli/Makefile.ci b/tests/nanocoap_cli/Makefile.ci index 6551c562c6a81..2fdcab0c9f387 100644 --- a/tests/nanocoap_cli/Makefile.ci +++ b/tests/nanocoap_cli/Makefile.ci @@ -8,6 +8,7 @@ BOARD_INSUFFICIENT_MEMORY := \ atmega328p-xplained-mini \ bluepill-stm32f030c8 \ i-nucleo-lrwan1 \ + m1284p \ mega-xplained \ microduino-corerf \ msb-430 \ @@ -29,8 +30,6 @@ BOARD_INSUFFICIENT_MEMORY := \ stm32l0538-disco \ telosb \ waspmote-pro \ - wsn430-v1_3b \ - wsn430-v1_4 \ z1 \ zigduino \ # diff --git a/tests/nanocoap_cli/main.c b/tests/nanocoap_cli/main.c index 1d73012339407..a6572017b3120 100644 --- a/tests/nanocoap_cli/main.c +++ b/tests/nanocoap_cli/main.c @@ -21,6 +21,7 @@ #include #include "msg.h" +#include "net/nanocoap_sock.h" #include "net/gnrc/netif.h" #include "net/ipv6/addr.h" #include "shell.h" @@ -28,6 +29,25 @@ #define MAIN_QUEUE_SIZE (4) static msg_t _main_msg_queue[MAIN_QUEUE_SIZE]; +#if IS_USED(MODULE_NANOCOAP_DTLS) +#include "net/credman.h" +#include "net/dsm.h" +#include "tinydtls_keys.h" + +static const uint8_t psk_id_0[] = PSK_DEFAULT_IDENTITY; +static const uint8_t psk_key_0[] = PSK_DEFAULT_KEY; +static const credman_credential_t credential = { + .type = CREDMAN_TYPE_PSK, + .tag = CONFIG_NANOCOAP_SOCK_DTLS_TAG, + .params = { + .psk = { + .key = { .s = psk_key_0, .len = sizeof(psk_key_0) - 1, }, + .id = { .s = psk_id_0, .len = sizeof(psk_id_0) - 1, }, + } + }, +}; +#endif + extern int nanotest_client_cmd(int argc, char **argv); extern int nanotest_client_url_cmd(int argc, char **argv); extern int nanotest_server_cmd(int argc, char **argv); @@ -121,6 +141,14 @@ int main(void) msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE); puts("nanocoap test app"); +#if IS_USED(MODULE_NANOCOAP_DTLS) + int res = credman_add(&credential); + if (res < 0 && res != CREDMAN_EXIST) { + printf("nanocoap: cannot add credential to system: %d\n", res); + return res; + } +#endif + /* start shell */ puts("All up, running the shell now"); char line_buf[SHELL_DEFAULT_BUFSIZE]; diff --git a/tests/nanocoap_cli/tinydtls_keys.h b/tests/nanocoap_cli/tinydtls_keys.h new file mode 100644 index 0000000000000..6d1d2bcdad310 --- /dev/null +++ b/tests/nanocoap_cli/tinydtls_keys.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 Inria + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup examples + * @{ + * + * @file + * @brief PSK and RPK keys for the dtls-sock example. + * + * @author Raul Fuentes + * + * @} + */ + +#ifndef TINYDTLS_KEYS_H +#define TINYDTLS_KEYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Default keys examples for tinyDTLS (for RIOT, Linux and Contiki) + */ +#define PSK_DEFAULT_IDENTITY "Client_identity" +#define PSK_DEFAULT_KEY "secretPSK" +#define PSK_OPTIONS "i:k:" +#define PSK_ID_MAXLEN 32 +#define PSK_MAXLEN 32 + +#ifdef __cplusplus +} +#endif + +#endif /* TINYDTLS_KEYS_H */