Merge pull request #11943 from pokgak/sock_dtls_impl
pkg/tinydtls: add DTLS sock API implementation
This commit is contained in:
commit
6e53e28a3a
54
examples/dtls-sock/Makefile
Normal file
54
examples/dtls-sock/Makefile
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# name of your application
|
||||||
|
APPLICATION = dtls_sock
|
||||||
|
|
||||||
|
# If no BOARD is found in the environment, use this default:
|
||||||
|
BOARD ?= native
|
||||||
|
|
||||||
|
# This has to be the absolute path to the RIOT base directory:
|
||||||
|
RIOTBASE ?= $(CURDIR)/../..
|
||||||
|
|
||||||
|
# TinyDTLS only has support for 32-bit architectures ATM
|
||||||
|
FEATURES_REQUIRED += arch_32bit
|
||||||
|
|
||||||
|
# Include packages that pull up and auto-init the link layer.
|
||||||
|
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
|
||||||
|
USEMODULE += gnrc_netdev_default
|
||||||
|
USEMODULE += auto_init_gnrc_netif
|
||||||
|
# Specify the mandatory networking modules for IPv6 and UDP
|
||||||
|
USEMODULE += gnrc_ipv6_default
|
||||||
|
USEMODULE += gnrc_sock_udp
|
||||||
|
|
||||||
|
# Use tinydtls for sock_dtls
|
||||||
|
USEMODULE += tinydtls_sock_dtls
|
||||||
|
|
||||||
|
# Add also the shell, some shell commands
|
||||||
|
USEMODULE += shell
|
||||||
|
USEMODULE += shell_commands
|
||||||
|
|
||||||
|
# UDP Port to use (20220 is default for DTLS).
|
||||||
|
DTLS_PORT ?= 20220
|
||||||
|
CFLAGS += -DDTLS_DEFAULT_PORT=$(DTLS_PORT)
|
||||||
|
|
||||||
|
# NOTE: If no cipher suite is selected, DTLS_PSK is used by default.
|
||||||
|
# This adds support for TLS_PSK_WITH_AES_128_CCM_8
|
||||||
|
CFLAGS += -DDTLS_PSK
|
||||||
|
# This adds support for TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
|
||||||
|
# CFLAGS += -DDTLS_ECC
|
||||||
|
|
||||||
|
# Uncomment to enable debug logs
|
||||||
|
# CFLAGS += -DDTLS_DEBUG
|
||||||
|
# When DTLS_DEBUG is set and using tinydtls, verbosity of debug log can be set with
|
||||||
|
# Values: 0:EMERG (Default), 1:ALERT 2:CRIT 3:WARN 4:NOTICE 5:INFO 6:DEBUG
|
||||||
|
# TINYDTLS_LOG=3
|
||||||
|
|
||||||
|
# FIXME: This is a temporary patch
|
||||||
|
CFLAGS += -DTHREAD_STACKSIZE_MAIN=\(2*THREAD_STACKSIZE_LARGE\)
|
||||||
|
|
||||||
|
# Comment this out to disable code in RIOT that does safety checking
|
||||||
|
# which is not needed in a production environment but helps in the
|
||||||
|
# development process:
|
||||||
|
DEVELHELP ?= 1
|
||||||
|
# Change this to 0 show compiler invocation lines by default:
|
||||||
|
QUIET ?= 1
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.include
|
||||||
41
examples/dtls-sock/Makefile.ci
Normal file
41
examples/dtls-sock/Makefile.ci
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
BOARD_INSUFFICIENT_MEMORY := \
|
||||||
|
airfy-beacon \
|
||||||
|
b-l072z-lrwan1 \
|
||||||
|
blackpill \
|
||||||
|
blackpill-128kib \
|
||||||
|
bluepill \
|
||||||
|
bluepill-128kib \
|
||||||
|
calliope-mini \
|
||||||
|
cc1352-launchpad \
|
||||||
|
cc2650-launchpad \
|
||||||
|
cc2650stk \
|
||||||
|
hifive1 \
|
||||||
|
hifive1b \
|
||||||
|
i-nucleo-lrwan1 \
|
||||||
|
lsn50 \
|
||||||
|
maple-mini \
|
||||||
|
microbit \
|
||||||
|
nrf51dongle \
|
||||||
|
nrf6310 \
|
||||||
|
nucleo-f030r8 \
|
||||||
|
nucleo-f031k6 \
|
||||||
|
nucleo-f042k6 \
|
||||||
|
nucleo-f070rb \
|
||||||
|
nucleo-f072rb \
|
||||||
|
nucleo-f103rb \
|
||||||
|
nucleo-f302r8 \
|
||||||
|
nucleo-f303k8 \
|
||||||
|
nucleo-f334r8 \
|
||||||
|
nucleo-l031k6 \
|
||||||
|
nucleo-l053r8 \
|
||||||
|
nucleo-l073rz \
|
||||||
|
opencm904 \
|
||||||
|
saml10-xpro \
|
||||||
|
saml11-xpro \
|
||||||
|
spark-core \
|
||||||
|
stm32f0discovery \
|
||||||
|
stm32f030f4-demo \
|
||||||
|
stm32l0538-disco \
|
||||||
|
stm32mindev \
|
||||||
|
yunjia-nrf51822
|
||||||
|
#
|
||||||
42
examples/dtls-sock/README.md
Normal file
42
examples/dtls-sock/README.md
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# DTLS sock example
|
||||||
|
|
||||||
|
This example shows how to use DTLS sock `sock_dtls_t`.
|
||||||
|
|
||||||
|
## Testing using RIOT `native`
|
||||||
|
|
||||||
|
For testing, we can use two RIOT `native` RIOT instances. For that first we
|
||||||
|
need to prepare the network interfaces:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ ./../../dist/tools/tapsetup/tapsetup --create 2
|
||||||
|
```
|
||||||
|
|
||||||
|
For the server instance:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ PORT=tap0 make all term
|
||||||
|
[...]
|
||||||
|
> dtlss start
|
||||||
|
ifconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
For the client:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ PORT=tap1 make all term
|
||||||
|
[...]
|
||||||
|
> dtlsc <server ip address> "DATA to send"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debug logs
|
||||||
|
|
||||||
|
To enable debug logs uncomment `CFLAGS += -DDTLS_DEBUG` in the Makefile.
|
||||||
|
Tinydtls supports setting the log level. See Makefile for more info.
|
||||||
|
|
||||||
|
## Configs and constraints
|
||||||
|
|
||||||
|
DTLS sock acts as a wrapper for the underlying DTLS stack and as such, the
|
||||||
|
constraints that applies specifically to the stack are also applied here.
|
||||||
|
For tinydtls, please refer to [dtls-echo README][1].
|
||||||
|
|
||||||
|
[1]: https://github.com/RIOT-OS/RIOT/blob/master/examples/dtls-echo/README.md
|
||||||
163
examples/dtls-sock/dtls-client.c
Normal file
163
examples/dtls-sock/dtls-client.c
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 HAW Hamburg
|
||||||
|
*
|
||||||
|
* 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 DTLS sock client example
|
||||||
|
*
|
||||||
|
* @author Aiman Ismail <muhammadaimanbin.ismail@haw-hamburg.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "net/sock/udp.h"
|
||||||
|
#include "net/sock/dtls.h"
|
||||||
|
#include "net/ipv6/addr.h"
|
||||||
|
#include "net/credman.h"
|
||||||
|
|
||||||
|
#include "tinydtls_keys.h"
|
||||||
|
|
||||||
|
#ifndef DTLS_DEFAULT_PORT
|
||||||
|
#define DTLS_DEFAULT_PORT 20220 /* DTLS default port */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SOCK_DTLS_CLIENT_TAG (2)
|
||||||
|
|
||||||
|
#ifdef DTLS_ECC
|
||||||
|
static const ecdsa_public_key_t other_pubkeys[] = {
|
||||||
|
{ .x = ecdsa_pub_key_x, .y = ecdsa_pub_key_y },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const credman_credential_t credential = {
|
||||||
|
.type = CREDMAN_TYPE_ECDSA,
|
||||||
|
.tag = SOCK_DTLS_CLIENT_TAG,
|
||||||
|
.params = {
|
||||||
|
.ecdsa = {
|
||||||
|
.private_key = ecdsa_priv_key,
|
||||||
|
.public_key = {
|
||||||
|
.x = ecdsa_pub_key_x,
|
||||||
|
.y = ecdsa_pub_key_y,
|
||||||
|
},
|
||||||
|
.client_keys = (ecdsa_public_key_t *)other_pubkeys,
|
||||||
|
.client_keys_size = ARRAY_SIZE(other_pubkeys),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#else /* ifdef DTLS_PSK */
|
||||||
|
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 = SOCK_DTLS_CLIENT_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
|
||||||
|
|
||||||
|
static int client_send(char *addr_str, char *data, size_t datalen)
|
||||||
|
{
|
||||||
|
ssize_t res;
|
||||||
|
sock_udp_t udp_sock;
|
||||||
|
sock_dtls_t dtls_sock;
|
||||||
|
sock_dtls_session_t session;
|
||||||
|
sock_udp_ep_t remote;
|
||||||
|
sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
|
||||||
|
local.port = 12345;
|
||||||
|
remote.port = DTLS_DEFAULT_PORT;
|
||||||
|
|
||||||
|
/* get interface */
|
||||||
|
char* iface = ipv6_addr_split_iface(addr_str);
|
||||||
|
if (iface) {
|
||||||
|
int pid = atoi(iface);
|
||||||
|
if (gnrc_netif_get_by_pid(pid) == NULL) {
|
||||||
|
puts("Invalid network interface");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
remote.netif = pid;
|
||||||
|
} else if (gnrc_netif_numof() == 1) {
|
||||||
|
/* assign the single interface found in gnrc_netif_numof() */
|
||||||
|
remote.netif = gnrc_netif_iter(NULL)->pid;
|
||||||
|
} else {
|
||||||
|
/* no interface is given, or given interface is invalid */
|
||||||
|
/* FIXME This probably is not valid with multiple interfaces */
|
||||||
|
remote.netif = SOCK_ADDR_ANY_NETIF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ipv6_addr_from_str((ipv6_addr_t *)remote.addr.ipv6, addr_str)) {
|
||||||
|
puts("Error parsing destination address");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sock_udp_create(&udp_sock, &local, NULL, 0) < 0) {
|
||||||
|
puts("Error creating UDP sock");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sock_dtls_create(&dtls_sock, &udp_sock,
|
||||||
|
SOCK_DTLS_CLIENT_TAG,
|
||||||
|
SOCK_DTLS_1_2, SOCK_DTLS_CLIENT) < 0) {
|
||||||
|
puts("Error creating DTLS sock");
|
||||||
|
sock_udp_close(&udp_sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = credman_add(&credential);
|
||||||
|
if (res < 0 && res != CREDMAN_EXIST) {
|
||||||
|
/* ignore duplicate credentials */
|
||||||
|
printf("Error cannot add credential to system: %zd\n", res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = sock_dtls_session_create(&dtls_sock, &remote, &session);
|
||||||
|
if (res < 0) {
|
||||||
|
printf("Error creating session: %zd\n", res);
|
||||||
|
sock_dtls_close(&dtls_sock);
|
||||||
|
sock_udp_close(&udp_sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sock_dtls_send(&dtls_sock, &session, data, datalen) < 0) {
|
||||||
|
puts("Error sending data");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Sent DTLS message\n");
|
||||||
|
|
||||||
|
uint8_t rcv[512];
|
||||||
|
if (sock_dtls_recv(&dtls_sock, &session, rcv, sizeof(rcv), SOCK_NO_TIMEOUT) < 0) {
|
||||||
|
printf("Error receiving DTLS message\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Received DTLS message\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
puts("Terminating");
|
||||||
|
sock_dtls_session_destroy(&dtls_sock, &session);
|
||||||
|
sock_dtls_close(&dtls_sock);
|
||||||
|
sock_udp_close(&udp_sock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dtls_client_cmd(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc != 3) {
|
||||||
|
printf("usage %s <addr> <data>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return client_send(argv[1], argv[2], strlen(argv[2]));
|
||||||
|
}
|
||||||
200
examples/dtls-sock/dtls-server.c
Normal file
200
examples/dtls-sock/dtls-server.c
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 HAW Hamburg
|
||||||
|
*
|
||||||
|
* 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 DTLS sock server example
|
||||||
|
*
|
||||||
|
* @author Aiman Ismail <muhammadaimanbin.ismail@haw-hamburg.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "net/sock/udp.h"
|
||||||
|
#include "net/sock/dtls.h"
|
||||||
|
#include "net/credman.h"
|
||||||
|
#include "msg.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
|
#include "tinydtls_keys.h"
|
||||||
|
|
||||||
|
#ifndef DTLS_DEFAULT_PORT
|
||||||
|
#define DTLS_DEFAULT_PORT (20220) /* DTLS default port */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SOCK_DTLS_SERVER_TAG (10)
|
||||||
|
#define DTLS_STOP_SERVER_MSG 0x4001 /* Custom IPC type msg. */
|
||||||
|
#define READER_QUEUE_SIZE (8U)
|
||||||
|
|
||||||
|
char _dtls_server_stack[THREAD_STACKSIZE_MAIN +
|
||||||
|
THREAD_EXTRA_STACKSIZE_PRINTF];
|
||||||
|
|
||||||
|
static kernel_pid_t _dtls_server_pid = KERNEL_PID_UNDEF;
|
||||||
|
|
||||||
|
#ifdef DTLS_ECC
|
||||||
|
static const ecdsa_public_key_t other_pubkeys[] = {
|
||||||
|
{ .x = ecdsa_pub_key_x, .y = ecdsa_pub_key_y },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const credman_credential_t credential = {
|
||||||
|
.type = CREDMAN_TYPE_ECDSA,
|
||||||
|
.tag = SOCK_DTLS_SERVER_TAG,
|
||||||
|
.params = {
|
||||||
|
.ecdsa = {
|
||||||
|
.private_key = ecdsa_priv_key,
|
||||||
|
.public_key = {
|
||||||
|
.x = ecdsa_pub_key_x,
|
||||||
|
.y = ecdsa_pub_key_y,
|
||||||
|
},
|
||||||
|
.client_keys = (ecdsa_public_key_t *)other_pubkeys,
|
||||||
|
.client_keys_size = ARRAY_SIZE(other_pubkeys),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
#else /* #ifdef DTLS_PSK */
|
||||||
|
static const uint8_t psk_key_0[] = PSK_DEFAULT_KEY;
|
||||||
|
|
||||||
|
static const credman_credential_t credential = {
|
||||||
|
.type = CREDMAN_TYPE_PSK,
|
||||||
|
.tag = SOCK_DTLS_SERVER_TAG,
|
||||||
|
.params = {
|
||||||
|
.psk = {
|
||||||
|
.key = { .s = psk_key_0, .len = sizeof(psk_key_0) - 1, },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *dtls_server_wrapper(void *arg)
|
||||||
|
{
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
ssize_t res;
|
||||||
|
bool active = true;
|
||||||
|
msg_t _reader_queue[READER_QUEUE_SIZE];
|
||||||
|
msg_t msg;
|
||||||
|
uint8_t rcv[512];
|
||||||
|
|
||||||
|
/* Prepare (thread) messages reception */
|
||||||
|
msg_init_queue(_reader_queue, READER_QUEUE_SIZE);
|
||||||
|
|
||||||
|
sock_dtls_session_t session;
|
||||||
|
sock_dtls_t sock;
|
||||||
|
sock_udp_t udp_sock;
|
||||||
|
sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
|
||||||
|
local.port = DTLS_DEFAULT_PORT;
|
||||||
|
sock_udp_create(&udp_sock, &local, NULL, 0);
|
||||||
|
|
||||||
|
res = sock_dtls_create(&sock, &udp_sock, SOCK_DTLS_SERVER_TAG,
|
||||||
|
SOCK_DTLS_1_2, SOCK_DTLS_SERVER);
|
||||||
|
if (res < 0) {
|
||||||
|
puts("Error creating DTLS sock");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = credman_add(&credential);
|
||||||
|
if (res < 0 && res != CREDMAN_EXIST) {
|
||||||
|
/* ignore duplicate credentials */
|
||||||
|
printf("Error cannot add credential to system: %zd\n", res);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (active) {
|
||||||
|
msg_try_receive(&msg);
|
||||||
|
if (msg.type == DTLS_STOP_SERVER_MSG) {
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res = sock_dtls_recv(&sock, &session, rcv, sizeof(rcv),
|
||||||
|
10 * US_PER_SEC);
|
||||||
|
if (res < 0) {
|
||||||
|
if (res != -ETIMEDOUT) {
|
||||||
|
printf("Error receiving UDP over DTLS %zd", res);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printf("Received %zd bytes -- (echo!)\n", res);
|
||||||
|
res = sock_dtls_send(&sock, &session, rcv, (size_t)res);
|
||||||
|
if (res < 0) {
|
||||||
|
printf("Error resending DTLS message: %zd", res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sock_dtls_session_destroy(&sock, &session);
|
||||||
|
sock_dtls_close(&sock);
|
||||||
|
sock_udp_close(&udp_sock);
|
||||||
|
puts("Terminating");
|
||||||
|
msg_reply(&msg, &msg); /* Basic answer to the main thread */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start_server(void)
|
||||||
|
{
|
||||||
|
/* Only one instance of the server */
|
||||||
|
if (_dtls_server_pid != KERNEL_PID_UNDEF) {
|
||||||
|
puts("Error: server already running");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start the server thread */
|
||||||
|
_dtls_server_pid = thread_create(_dtls_server_stack,
|
||||||
|
sizeof(_dtls_server_stack),
|
||||||
|
THREAD_PRIORITY_MAIN - 1,
|
||||||
|
THREAD_CREATE_STACKTEST,
|
||||||
|
dtls_server_wrapper, NULL, "dtls_server");
|
||||||
|
|
||||||
|
/* Uncommon but better be sure */
|
||||||
|
if (_dtls_server_pid < 0) {
|
||||||
|
printf("ERROR: failed to create thread: %d\n", _dtls_server_pid);
|
||||||
|
_dtls_server_pid = KERNEL_PID_UNDEF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stop_server(void)
|
||||||
|
{
|
||||||
|
/* check if server is running at all */
|
||||||
|
if (_dtls_server_pid == KERNEL_PID_UNDEF) {
|
||||||
|
puts("Error: DTLS server is not running");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prepare the stop message */
|
||||||
|
msg_t m;
|
||||||
|
m.type = DTLS_STOP_SERVER_MSG;
|
||||||
|
|
||||||
|
puts("Stopping server...");
|
||||||
|
|
||||||
|
/* send the stop message to thread AND wait for (any) answer */
|
||||||
|
msg_send_receive(&m, &m, _dtls_server_pid);
|
||||||
|
|
||||||
|
_dtls_server_pid = KERNEL_PID_UNDEF;
|
||||||
|
puts("Success: DTLS server stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
int dtls_server_cmd(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("usage: %s start | stop\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (strcmp(argv[1], "start") == 0) {
|
||||||
|
start_server();
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[1], "stop") == 0) {
|
||||||
|
stop_server();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Error: invalid command. Usage: %s start | stop\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
43
examples/dtls-sock/main.c
Normal file
43
examples/dtls-sock/main.c
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 HAW Hamburg
|
||||||
|
*
|
||||||
|
* 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 Example application for DTLS sock
|
||||||
|
*
|
||||||
|
* @author Aiman Ismail <muhammadaimanbin.ismail@haw-hamburg.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
|
extern int dtls_client_cmd(int argc, char **argv);
|
||||||
|
extern int dtls_server_cmd(int argc, char **argv);
|
||||||
|
|
||||||
|
static const shell_command_t shell_commands[] = {
|
||||||
|
{ "dtlsc", "Start a DTLS client", dtls_client_cmd },
|
||||||
|
{ "dtlss", "Start and stop a DTLS server", dtls_server_cmd },
|
||||||
|
{ NULL, NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
puts("DTLS sock example application");
|
||||||
|
|
||||||
|
/* start shell */
|
||||||
|
puts("All up, running the shell now");
|
||||||
|
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||||
|
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||||
|
|
||||||
|
/* should never be reached */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
66
examples/dtls-sock/tinydtls_keys.h
Normal file
66
examples/dtls-sock/tinydtls_keys.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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 <raul.fuentes-samaniego@inria.fr>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TINYDTLS_KEYS_H
|
||||||
|
#define TINYDTLS_KEYS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default keys examples for tinyDTLS (for RIOT, Linux and Contiki)
|
||||||
|
*/
|
||||||
|
#ifdef DTLS_PSK
|
||||||
|
#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
|
||||||
|
|
||||||
|
#endif /* DTLS_PSK */
|
||||||
|
|
||||||
|
#ifdef DTLS_ECC
|
||||||
|
static const unsigned char ecdsa_priv_key[] = {
|
||||||
|
0x41, 0xC1, 0xCB, 0x6B, 0x51, 0x24, 0x7A, 0x14,
|
||||||
|
0x43, 0x21, 0x43, 0x5B, 0x7A, 0x80, 0xE7, 0x14,
|
||||||
|
0x89, 0x6A, 0x33, 0xBB, 0xAD, 0x72, 0x94, 0xCA,
|
||||||
|
0x40, 0x14, 0x55, 0xA1, 0x94, 0xA9, 0x49, 0xFA
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char ecdsa_pub_key_x[] = {
|
||||||
|
0x36, 0xDF, 0xE2, 0xC6, 0xF9, 0xF2, 0xED, 0x29,
|
||||||
|
0xDA, 0x0A, 0x9A, 0x8F, 0x62, 0x68, 0x4E, 0x91,
|
||||||
|
0x63, 0x75, 0xBA, 0x10, 0x30, 0x0C, 0x28, 0xC5,
|
||||||
|
0xE4, 0x7C, 0xFB, 0xF2, 0x5F, 0xA5, 0x8F, 0x52
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char ecdsa_pub_key_y[] = {
|
||||||
|
0x71, 0xA0, 0xD4, 0xFC, 0xDE, 0x1A, 0xB8, 0x78,
|
||||||
|
0x5A, 0x3C, 0x78, 0x69, 0x35, 0xA7, 0xCF, 0xAB,
|
||||||
|
0xE9, 0x3F, 0x98, 0x72, 0x09, 0xDA, 0xED, 0x0B,
|
||||||
|
0x4F, 0xAB, 0xC3, 0x6F, 0xC7, 0x72, 0xF8, 0x29
|
||||||
|
};
|
||||||
|
#endif /* DTLS_ECC */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* TINYDTLS_KEYS_H */
|
||||||
@ -80,6 +80,7 @@ PSEUDOMODULES += sched_cb
|
|||||||
PSEUDOMODULES += semtech_loramac_rx
|
PSEUDOMODULES += semtech_loramac_rx
|
||||||
PSEUDOMODULES += sock
|
PSEUDOMODULES += sock
|
||||||
PSEUDOMODULES += sock_async
|
PSEUDOMODULES += sock_async
|
||||||
|
PSEUDOMODULES += sock_dtls
|
||||||
PSEUDOMODULES += sock_ip
|
PSEUDOMODULES += sock_ip
|
||||||
PSEUDOMODULES += sock_tcp
|
PSEUDOMODULES += sock_tcp
|
||||||
PSEUDOMODULES += sock_udp
|
PSEUDOMODULES += sock_udp
|
||||||
|
|||||||
@ -6,6 +6,9 @@ ifeq ($(TOOLCHAIN), llvm)
|
|||||||
CFLAGS += -Wno-gnu-zero-variadic-macro-arguments -Wno-unused-function
|
CFLAGS += -Wno-gnu-zero-variadic-macro-arguments -Wno-unused-function
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
INCLUDES += -I$(RIOTBASE)/pkg/tinydtls/include
|
||||||
|
DIRS += $(RIOTBASE)/pkg/tinydtls/contrib
|
||||||
|
|
||||||
ifneq (,$(filter tinydtls,$(USEMODULE)))
|
ifneq (,$(filter tinydtls,$(USEMODULE)))
|
||||||
INCLUDES += -I$(PKG_BUILDDIR)
|
INCLUDES += -I$(PKG_BUILDDIR)
|
||||||
# Mandatory for tinyDTLS
|
# Mandatory for tinyDTLS
|
||||||
@ -27,6 +30,13 @@ ifneq (,$(filter tinydtls,$(USEMODULE)))
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Enable debug when using tinydtls_sock_dtls
|
||||||
|
ifneq (,$(filter -DDTLS_DEBUG,$(CFLAGS)))
|
||||||
|
ifeq (,$(TINYDTLS_LOG))
|
||||||
|
CFLAGS += -DTINYDTLS_DEBUG
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
# Handles the verbosity of tinyDTLS. Default: Minimum or just error messages.
|
# Handles the verbosity of tinyDTLS. Default: Minimum or just error messages.
|
||||||
ifeq (,$(filter -DTINYDTLS_DEBUG,$(CFLAGS)))
|
ifeq (,$(filter -DTINYDTLS_DEBUG,$(CFLAGS)))
|
||||||
ifeq ( , $(TINYDTLS_LOG))
|
ifeq ( , $(TINYDTLS_LOG))
|
||||||
|
|||||||
3
pkg/tinydtls/contrib/Makefile
Normal file
3
pkg/tinydtls/contrib/Makefile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
MODULE := tinydtls_sock_dtls
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.base
|
||||||
480
pkg/tinydtls/contrib/sock_dtls.c
Normal file
480
pkg/tinydtls/contrib/sock_dtls.c
Normal file
@ -0,0 +1,480 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 HAW Hamburg
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief tinydtls implementation of @ref net_sock_dtls
|
||||||
|
*
|
||||||
|
* @author Aiman Ismail <muhammadaimanbin.ismail@haw-hamburg.de>
|
||||||
|
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dtls.h"
|
||||||
|
#include "net/sock/dtls.h"
|
||||||
|
#include "net/credman.h"
|
||||||
|
|
||||||
|
#define ENABLE_DEBUG (0)
|
||||||
|
#include "debug.h"
|
||||||
|
#include "dtls_debug.h"
|
||||||
|
|
||||||
|
#define DTLS_EVENT_READ (0x01E0)
|
||||||
|
#define DTLS_EVENT_TIMEOUT (0x01E1)
|
||||||
|
|
||||||
|
#define DTLS_HANDSHAKE_BUFSIZE (256) /**< Size buffer used in handshake
|
||||||
|
to hold credentials */
|
||||||
|
/* ECC handshake takes more time */
|
||||||
|
#ifdef DTLS_ECC
|
||||||
|
#define DTLS_HANDSHAKE_TIMEOUT (30 * US_PER_SEC)
|
||||||
|
#else
|
||||||
|
#define DTLS_HANDSHAKE_TIMEOUT (1 * US_PER_SEC)
|
||||||
|
#endif /* DTLS_ECC */
|
||||||
|
|
||||||
|
static void _timeout_callback(void *arg);
|
||||||
|
|
||||||
|
#ifdef DTLS_PSK
|
||||||
|
static int _get_psk_info(struct dtls_context_t *ctx, const session_t *session,
|
||||||
|
dtls_credentials_type_t type,
|
||||||
|
const unsigned char *id, size_t id_len,
|
||||||
|
unsigned char *result, size_t result_length);
|
||||||
|
#endif /* DTLS_PSK */
|
||||||
|
|
||||||
|
#ifdef DTLS_ECC
|
||||||
|
static int _get_ecdsa_key(struct dtls_context_t *ctx, const session_t *session,
|
||||||
|
const dtls_ecdsa_key_t **result);
|
||||||
|
|
||||||
|
static int _verify_ecdsa_key(struct dtls_context_t *ctx,
|
||||||
|
const session_t *session,
|
||||||
|
const unsigned char *other_pub_x,
|
||||||
|
const unsigned char *other_pub_y,
|
||||||
|
size_t key_size);
|
||||||
|
#endif /* DTLS_ECC */
|
||||||
|
|
||||||
|
static int _write(struct dtls_context_t *ctx, session_t *session, uint8_t *buf,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
|
static int _read(struct dtls_context_t *ctx, session_t *session, uint8_t *buf,
|
||||||
|
size_t len);
|
||||||
|
static int _event(struct dtls_context_t *ctx, session_t *session,
|
||||||
|
dtls_alert_level_t level, unsigned short code);
|
||||||
|
|
||||||
|
static void _session_to_ep(const session_t *session, sock_udp_ep_t *ep);
|
||||||
|
static void _ep_to_session(const sock_udp_ep_t *ep, session_t *session);
|
||||||
|
|
||||||
|
static dtls_handler_t _dtls_handler = {
|
||||||
|
.event = _event,
|
||||||
|
.write = _write,
|
||||||
|
.read = _read,
|
||||||
|
#ifdef DTLS_PSK
|
||||||
|
.get_psk_info = _get_psk_info,
|
||||||
|
#endif /* DTLS_PSK */
|
||||||
|
#ifdef DTLS_ECC
|
||||||
|
.get_ecdsa_key = _get_ecdsa_key,
|
||||||
|
.verify_ecdsa_key = _verify_ecdsa_key,
|
||||||
|
#endif /* DTLS_ECC */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int _read(struct dtls_context_t *ctx, session_t *session, uint8_t *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
(void)session;
|
||||||
|
msg_t msg = { .type = DTLS_EVENT_READ };
|
||||||
|
sock_dtls_t *sock = dtls_get_app_data(ctx);
|
||||||
|
|
||||||
|
DEBUG("sock_dtls: decrypted message arrived\n");
|
||||||
|
if (sock->buflen < len && sock->buf) {
|
||||||
|
DEBUG("sock_dtls: not enough place on buffer for decrypted message\n");
|
||||||
|
msg.content.value = -ENOBUFS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memmove(sock->buf, buf, len);
|
||||||
|
msg.content.value = len;
|
||||||
|
}
|
||||||
|
mbox_put(&sock->mbox, &msg);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _write(struct dtls_context_t *ctx, session_t *session, uint8_t *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
sock_dtls_t *sock = (sock_dtls_t *)dtls_get_app_data(ctx);
|
||||||
|
sock_udp_ep_t remote;
|
||||||
|
|
||||||
|
_session_to_ep(session, &remote);
|
||||||
|
remote.family = AF_INET6;
|
||||||
|
|
||||||
|
ssize_t res = sock_udp_send(sock->udp_sock, buf, len, &remote);
|
||||||
|
if (res < 0) {
|
||||||
|
DEBUG("sock_dtls: failed to send DTLS record: %zd\n", res);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _event(struct dtls_context_t *ctx, session_t *session,
|
||||||
|
dtls_alert_level_t level, unsigned short code)
|
||||||
|
{
|
||||||
|
(void)level;
|
||||||
|
(void)session;
|
||||||
|
|
||||||
|
sock_dtls_t *sock = dtls_get_app_data(ctx);
|
||||||
|
msg_t msg = { .type = code };
|
||||||
|
#ifdef ENABLE_DEBUG
|
||||||
|
switch(code) {
|
||||||
|
case DTLS_EVENT_CONNECT:
|
||||||
|
DEBUG("sock_dtls: event connect\n");
|
||||||
|
break;
|
||||||
|
case DTLS_EVENT_CONNECTED:
|
||||||
|
DEBUG("sock_dtls: event connected\n");
|
||||||
|
break;
|
||||||
|
case DTLS_EVENT_RENEGOTIATE:
|
||||||
|
DEBUG("sock_dtls: event renegotiate\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif /* ENABLE_DEBUG */
|
||||||
|
mbox_put(&sock->mbox, &msg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DTLS_PSK
|
||||||
|
static int _get_psk_info(struct dtls_context_t *ctx, const session_t *session,
|
||||||
|
dtls_credentials_type_t type,
|
||||||
|
const unsigned char *desc, size_t desc_len,
|
||||||
|
unsigned char *result, size_t result_length)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
(void)desc;
|
||||||
|
(void)desc_len;
|
||||||
|
int ret;
|
||||||
|
sock_dtls_session_t _session;
|
||||||
|
sock_udp_ep_t ep;
|
||||||
|
sock_dtls_t *sock = (sock_dtls_t *)dtls_get_app_data(ctx);
|
||||||
|
|
||||||
|
_session_to_ep(session, &ep);
|
||||||
|
memcpy(&_session.ep, &ep, sizeof(sock_udp_ep_t));
|
||||||
|
memcpy(&_session.dtls_session, session, sizeof(session_t));
|
||||||
|
|
||||||
|
credman_credential_t credential;
|
||||||
|
ret = credman_get(&credential, sock->tag, CREDMAN_TYPE_PSK);
|
||||||
|
if (ret < 0) {
|
||||||
|
DEBUG("sock_dtls: no matching PSK credential found\n");
|
||||||
|
return dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *c = NULL;
|
||||||
|
size_t c_len = 0;
|
||||||
|
switch(type) {
|
||||||
|
case DTLS_PSK_HINT:
|
||||||
|
DEBUG("sock_dtls: psk hint request\n");
|
||||||
|
/* Ignored. See https://tools.ietf.org/html/rfc4279#section-5.2 */
|
||||||
|
return 0;
|
||||||
|
case DTLS_PSK_IDENTITY:
|
||||||
|
DEBUG("sock_dtls: psk id request\n");
|
||||||
|
c = credential.params.psk.id.s;
|
||||||
|
c_len = credential.params.psk.id.len;
|
||||||
|
break;
|
||||||
|
case DTLS_PSK_KEY:
|
||||||
|
DEBUG("sock_dtls: psk key request\n");
|
||||||
|
c = credential.params.psk.key.s;
|
||||||
|
c_len = credential.params.psk.key.len;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DEBUG("sock:dtls unsupported request type: %d\n", type);
|
||||||
|
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c_len > result_length) {
|
||||||
|
DEBUG("sock_dtls: not enough memory for credential type: %d\n", type);
|
||||||
|
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
if (c == NULL || c_len == 0) {
|
||||||
|
DEBUG("sock_dtls: invalid credential params for type %d\n", type);
|
||||||
|
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
memcpy(result, c, c_len);
|
||||||
|
return c_len;
|
||||||
|
}
|
||||||
|
#endif /* DTLS_PSK */
|
||||||
|
|
||||||
|
#ifdef DTLS_ECC
|
||||||
|
static int _get_ecdsa_key(struct dtls_context_t *ctx, const session_t *session,
|
||||||
|
const dtls_ecdsa_key_t **result)
|
||||||
|
{
|
||||||
|
(void)session;
|
||||||
|
int ret;
|
||||||
|
sock_dtls_t *sock = (sock_dtls_t *)dtls_get_app_data(ctx);
|
||||||
|
|
||||||
|
credman_credential_t credential;
|
||||||
|
ret = credman_get(&credential, sock->tag, CREDMAN_TYPE_ECDSA);
|
||||||
|
if (ret < 0) {
|
||||||
|
DEBUG("sock_dtls: no matching ecdsa credential found\n");
|
||||||
|
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dtls_ecdsa_key_t key;
|
||||||
|
key.curve = DTLS_ECDH_CURVE_SECP256R1;
|
||||||
|
key.priv_key = credential.params.ecdsa.private_key;
|
||||||
|
key.pub_key_x = credential.params.ecdsa.public_key.x;
|
||||||
|
key.pub_key_y = credential.params.ecdsa.public_key.y;
|
||||||
|
*result = &key;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _verify_ecdsa_key(struct dtls_context_t *ctx,
|
||||||
|
const session_t *session,
|
||||||
|
const unsigned char *other_pub_x,
|
||||||
|
const unsigned char *other_pub_y, size_t key_size)
|
||||||
|
{
|
||||||
|
(void) ctx;
|
||||||
|
(void) session;
|
||||||
|
(void) other_pub_y;
|
||||||
|
(void) other_pub_x;
|
||||||
|
(void) key_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* DTLS_ECC */
|
||||||
|
|
||||||
|
int sock_dtls_create(sock_dtls_t *sock, sock_udp_t *udp_sock,
|
||||||
|
credman_tag_t tag, unsigned version, unsigned role)
|
||||||
|
{
|
||||||
|
assert(sock);
|
||||||
|
assert(udp_sock);
|
||||||
|
|
||||||
|
if (role != SOCK_DTLS_CLIENT && role != SOCK_DTLS_SERVER) {
|
||||||
|
DEBUG("sock_dtls: invalid role\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if tinydtls compiled with wanted DTLS version */
|
||||||
|
if (version < SOCK_DTLS_1_0 || version > SOCK_DTLS_1_3) {
|
||||||
|
DEBUG("sock_dtls: invalid version\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if ((version == SOCK_DTLS_1_2) &&
|
||||||
|
(DTLS_VERSION != 0xfefd)) {
|
||||||
|
DEBUG("sock_dtls: tinydtls not compiled with support for DTLS 1.2\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (version == SOCK_DTLS_1_0 || version == SOCK_DTLS_1_3) {
|
||||||
|
DEBUG("sock_dtls: tinydtls only support DTLS 1.2\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock->udp_sock = udp_sock;
|
||||||
|
sock->role = role;
|
||||||
|
sock->tag = tag;
|
||||||
|
sock->dtls_ctx = dtls_new_context(sock);
|
||||||
|
if (!sock->dtls_ctx) {
|
||||||
|
DEBUG("sock_dtls: error getting DTLS context\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mbox_init(&sock->mbox, sock->mbox_queue, SOCK_DTLS_MBOX_SIZE);
|
||||||
|
dtls_set_handler(sock->dtls_ctx, &_dtls_handler);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sock_dtls_session_create(sock_dtls_t *sock, const sock_udp_ep_t *ep,
|
||||||
|
sock_dtls_session_t *remote)
|
||||||
|
{
|
||||||
|
uint8_t rcv_buffer[DTLS_HANDSHAKE_BUFSIZE];
|
||||||
|
msg_t msg;
|
||||||
|
ssize_t res;
|
||||||
|
|
||||||
|
assert(sock);
|
||||||
|
assert(ep);
|
||||||
|
assert(remote);
|
||||||
|
|
||||||
|
/* prepare a the remote party to connect to */
|
||||||
|
memcpy(&remote->ep, ep, sizeof(sock_udp_ep_t));
|
||||||
|
memcpy(&remote->dtls_session.addr, &ep->addr.ipv6, sizeof(ipv6_addr_t));
|
||||||
|
_ep_to_session(ep, &remote->dtls_session);
|
||||||
|
|
||||||
|
/* start a handshake */
|
||||||
|
DEBUG("sock_dtls: starting handshake\n");
|
||||||
|
res = dtls_connect(sock->dtls_ctx, &remote->dtls_session);
|
||||||
|
if (res < 0) {
|
||||||
|
DEBUG("sock_dtls: error establishing a session: %zd\n", res);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
else if (res == 0) {
|
||||||
|
DEBUG("sock_dtls: session already exist. Skip establishing session\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* receive all handshake messages or timeout if timer expires */
|
||||||
|
while (!mbox_try_get(&sock->mbox, &msg) ||
|
||||||
|
msg.type != DTLS_EVENT_CONNECTED) {
|
||||||
|
res = sock_udp_recv(sock->udp_sock, rcv_buffer, sizeof(rcv_buffer),
|
||||||
|
DTLS_HANDSHAKE_TIMEOUT, &remote->ep);
|
||||||
|
if (res <= 0) {
|
||||||
|
DEBUG("sock_dtls: error receiving handshake messages: %zd\n", res);
|
||||||
|
/* deletes peer created in dtls_connect() */
|
||||||
|
dtls_peer_t *peer = dtls_get_peer(sock->dtls_ctx,
|
||||||
|
&remote->dtls_session);
|
||||||
|
dtls_reset_peer(sock->dtls_ctx, peer);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = dtls_handle_message(sock->dtls_ctx, &remote->dtls_session,
|
||||||
|
rcv_buffer, res);
|
||||||
|
/* stop handshake if received fatal level alert */
|
||||||
|
if (res == -1) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sock_dtls_session_destroy(sock_dtls_t *sock, sock_dtls_session_t *remote)
|
||||||
|
{
|
||||||
|
dtls_close(sock->dtls_ctx, &remote->dtls_session);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t sock_dtls_send(sock_dtls_t *sock, sock_dtls_session_t *remote,
|
||||||
|
const void *data, size_t len)
|
||||||
|
{
|
||||||
|
assert(sock);
|
||||||
|
assert(remote);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
/* check if session exists, if not create session first then send */
|
||||||
|
if (!dtls_get_peer(sock->dtls_ctx, &remote->dtls_session)) {
|
||||||
|
int res;
|
||||||
|
|
||||||
|
/* no session with remote, creating new session.
|
||||||
|
* This will also create new peer for this session */
|
||||||
|
res = dtls_connect(sock->dtls_ctx, &remote->dtls_session);
|
||||||
|
if (res < 0) {
|
||||||
|
DEBUG("sock_dtls: error initiating handshake\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
else if (res > 0) {
|
||||||
|
/* handshake initiated, wait until connected or timed out */
|
||||||
|
xtimer_t timeout_timer;
|
||||||
|
timeout_timer.callback = _timeout_callback;
|
||||||
|
timeout_timer.arg = sock;
|
||||||
|
xtimer_set(&timeout_timer, DTLS_HANDSHAKE_TIMEOUT);
|
||||||
|
|
||||||
|
msg_t msg;
|
||||||
|
do {
|
||||||
|
mbox_get(&sock->mbox, &msg);
|
||||||
|
} while ((msg.type != DTLS_EVENT_CONNECTED) &&
|
||||||
|
(msg.type != DTLS_EVENT_TIMEOUT));
|
||||||
|
|
||||||
|
if (msg.type == DTLS_EVENT_TIMEOUT) {
|
||||||
|
DEBUG("sock_dtls: handshake process timed out\n");
|
||||||
|
|
||||||
|
/* deletes peer created in dtls_connect() before */
|
||||||
|
dtls_peer_t *peer = dtls_get_peer(sock->dtls_ctx, &remote->dtls_session);
|
||||||
|
dtls_reset_peer(sock->dtls_ctx, peer);
|
||||||
|
return -EHOSTUNREACH;
|
||||||
|
}
|
||||||
|
xtimer_remove(&timeout_timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dtls_write(sock->dtls_ctx, &remote->dtls_session, (uint8_t *)data,
|
||||||
|
len);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t sock_dtls_recv(sock_dtls_t *sock, sock_dtls_session_t *remote,
|
||||||
|
void *data, size_t max_len, uint32_t timeout)
|
||||||
|
{
|
||||||
|
xtimer_t timeout_timer;
|
||||||
|
|
||||||
|
assert(sock);
|
||||||
|
assert(data);
|
||||||
|
assert(remote);
|
||||||
|
|
||||||
|
if ((timeout != SOCK_NO_TIMEOUT) && (timeout != 0)) {
|
||||||
|
timeout_timer.callback = _timeout_callback;
|
||||||
|
timeout_timer.arg = sock;
|
||||||
|
xtimer_set(&timeout_timer, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save location to result buffer */
|
||||||
|
sock->buf = data;
|
||||||
|
sock->buflen = max_len;
|
||||||
|
|
||||||
|
/* loop breaks when timeout or application data read */
|
||||||
|
while(1) {
|
||||||
|
uint32_t start_recv = xtimer_now_usec();
|
||||||
|
ssize_t res = sock_udp_recv(sock->udp_sock, data, max_len, timeout,
|
||||||
|
&remote->ep);
|
||||||
|
if (res <= 0) {
|
||||||
|
DEBUG("sock_dtls: error receiving UDP packet: %zd\n", res);
|
||||||
|
xtimer_remove(&timeout_timer);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((timeout != SOCK_NO_TIMEOUT) && (timeout != 0)) {
|
||||||
|
uint32_t time_passed = (xtimer_now_usec() - start_recv);
|
||||||
|
timeout = (time_passed > timeout) ? 0: timeout - time_passed;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ep_to_session(&remote->ep, &remote->dtls_session);
|
||||||
|
res = dtls_handle_message(sock->dtls_ctx, &remote->dtls_session,
|
||||||
|
(uint8_t *)data, res);
|
||||||
|
|
||||||
|
/* reset msg type */
|
||||||
|
msg_t msg;
|
||||||
|
if (mbox_try_get(&sock->mbox, &msg)) {
|
||||||
|
switch(msg.type) {
|
||||||
|
case DTLS_EVENT_READ:
|
||||||
|
xtimer_remove(&timeout_timer);
|
||||||
|
return msg.content.value;
|
||||||
|
case DTLS_EVENT_TIMEOUT:
|
||||||
|
DEBUG("sock_dtls: timed out while decrypting message\n");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (timeout == 0) {
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void sock_dtls_close(sock_dtls_t *sock)
|
||||||
|
{
|
||||||
|
dtls_free_context(sock->dtls_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sock_dtls_init(void)
|
||||||
|
{
|
||||||
|
dtls_init();
|
||||||
|
dtls_set_log_level(TINYDTLS_LOG_LVL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ep_to_session(const sock_udp_ep_t *ep, session_t *session)
|
||||||
|
{
|
||||||
|
session->port = ep->port;
|
||||||
|
session->size = sizeof(ipv6_addr_t) + /* addr */
|
||||||
|
sizeof(unsigned short); /* port */
|
||||||
|
session->ifindex = ep->netif;
|
||||||
|
memcpy(&session->addr, &ep->addr.ipv6, sizeof(ipv6_addr_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _session_to_ep(const session_t *session, sock_udp_ep_t *ep)
|
||||||
|
{
|
||||||
|
ep->port = session->port;
|
||||||
|
ep->netif = session->ifindex;
|
||||||
|
memcpy(&ep->addr.ipv6, &session->addr, sizeof(ipv6_addr_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _timeout_callback(void *arg)
|
||||||
|
{
|
||||||
|
msg_t timeout_msg = { .type = DTLS_EVENT_TIMEOUT };
|
||||||
|
sock_dtls_t *sock = arg;
|
||||||
|
mbox_try_put(&sock->mbox, &timeout_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
66
pkg/tinydtls/include/sock_dtls_types.h
Normal file
66
pkg/tinydtls/include/sock_dtls_types.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 HAW Hamburg
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief tinydtls-specific types and functions definitions
|
||||||
|
*
|
||||||
|
* @author Aiman Ismail <muhammadaimanbin.ismail@haw-hamburg.de>
|
||||||
|
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SOCK_DTLS_TYPES_H
|
||||||
|
#define SOCK_DTLS_TYPES_H
|
||||||
|
|
||||||
|
#include "dtls.h"
|
||||||
|
#include "net/sock/udp.h"
|
||||||
|
#include "net/credman.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SOCK_DTLS_MBOX_SIZE
|
||||||
|
#define SOCK_DTLS_MBOX_SIZE (4) /**< Size of DTLS sock mailbox */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Information about DTLS sock
|
||||||
|
*/
|
||||||
|
struct sock_dtls {
|
||||||
|
dtls_context_t *dtls_ctx; /**< TinyDTLS context for sock */
|
||||||
|
sock_udp_t *udp_sock; /**< Underlying UDP sock to use */
|
||||||
|
mbox_t mbox; /**< Mailbox for internal event
|
||||||
|
handling */
|
||||||
|
msg_t mbox_queue[SOCK_DTLS_MBOX_SIZE]; /**< Queue for struct
|
||||||
|
sock_dtls::mbox */
|
||||||
|
uint8_t *buf; /**< Buffer to pass decrypted data
|
||||||
|
back to user */
|
||||||
|
size_t buflen; /**< Size of buffer */
|
||||||
|
credman_tag_t tag; /**< Credential tag of a registered
|
||||||
|
(D)TLS credential */
|
||||||
|
dtls_peer_type role; /**< DTLS role of the socket */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Information about remote client connected to the server
|
||||||
|
*/
|
||||||
|
struct sock_dtls_session {
|
||||||
|
sock_udp_ep_t ep; /**< Remote endpoint the session
|
||||||
|
is connected to */
|
||||||
|
session_t dtls_session; /**< TinyDTLS session */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SOCK_DTLS_TYPES_H */
|
||||||
|
/** @} */
|
||||||
Loading…
x
Reference in New Issue
Block a user