mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-25 06:23:53 +01:00
Merge pull request #7615 from rfuentess/dtls_upgrade
Improving TinyDTLS package and dtls-echo example
This commit is contained in:
commit
a3fc323cf5
@ -9,8 +9,8 @@ RIOTBASE ?= $(CURDIR)/../..
|
||||
|
||||
# TinyDTLS only has support for 32-bit architectures ATM
|
||||
BOARD_BLACKLIST := arduino-duemilanove arduino-mega2560 arduino-uno chronos \
|
||||
msb-430 msb-430h telosb waspmote-pro wsn430-v1_3b wsn430-v1_4 \
|
||||
z1 jiminy-mega256rfr2 mega-xplained
|
||||
jiminy-mega256rfr2 mega-xplained msb-430 msb-430h telosb \
|
||||
waspmote-pro wsn430-v1_3b wsn430-v1_4 z1
|
||||
|
||||
BOARD_INSUFFICIENT_MEMORY := airfy-beacon b-l072z-lrwan1 bluepill calliope-mini \
|
||||
cc2650-launchpad cc2650stk hifive1 maple-mini \
|
||||
@ -24,51 +24,44 @@ BOARD_INSUFFICIENT_MEMORY := airfy-beacon b-l072z-lrwan1 bluepill calliope-mini
|
||||
# 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 sUDP
|
||||
USEMODULE += gnrc_ipv6_router_default
|
||||
USEMODULE += gnrc_udp
|
||||
# Add a routing protocol
|
||||
USEMODULE += gnrc_rpl
|
||||
# This application dumps received packets to STDIO using the pktdump module
|
||||
USEMODULE += gnrc_pktdump
|
||||
# Additional networking modules that can be dropped if not needed
|
||||
USEMODULE += gnrc_icmpv6_echo
|
||||
# Specify the mandatory networking modules for IPv6 and UDP
|
||||
USEMODULE += gnrc_ipv6_default
|
||||
USEMODULE += gnrc_sock_udp
|
||||
|
||||
# Add also the shell, some shell commands
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
USEMODULE += ps
|
||||
|
||||
#TinyDTLs (crypto.c) made use of pthread
|
||||
ifneq ($(BOARD),native)
|
||||
USEMODULE += pthread
|
||||
endif
|
||||
USEPKG += tinydtls
|
||||
|
||||
# UDP Port to use (20220 is default for DTLS).
|
||||
DTLS_PORT ?= 20220
|
||||
CFLAGS += -DDTLS_DEFAULT_PORT=$(DTLS_PORT)
|
||||
|
||||
# NOTE: If not 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
|
||||
|
||||
# Define the log entry for the tinydtls package.
|
||||
# Values: 0:EMERG (Default), 1:ALERT 2:CRIT 3:WARN 4:NOTICE 5:INFO 6:DEBUG
|
||||
TINYDTLS_LOG ?= 0
|
||||
|
||||
# Enable this line for setting tinyDTLS in debug mode.
|
||||
# This overrides TINYDTLS_LOG to 6
|
||||
# CFLAGS += -DTINYDTLS_DEBUG
|
||||
|
||||
# FIXME: This is a temporary patch
|
||||
# TinyDTLS <= 0.8.6 requires around 426 bytes in RAM.
|
||||
CFLAGS += -DTHREAD_STACKSIZE_MAIN=\(3*THREAD_STACKSIZE_DEFAULT\)
|
||||
# TINYDTLS_EXTRA_BUFF can be used for increasing the server stack memory.
|
||||
# CFLAGS += -DTINYDTLS_EXTRA_BUFF=\(512\)
|
||||
|
||||
# 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
|
||||
|
||||
# NOTE: Add the package for TinyDTLS
|
||||
USEPKG += tinydtls
|
||||
|
||||
# NOTE: Those are taken from TinyDTLS. As the original Makefiles are
|
||||
# overwitten is a good idea to preserve them here.
|
||||
CFLAGS += -DDTLSv12 -DWITH_SHA256
|
||||
|
||||
# NOTE: This adds support for TLS_PSK_WITH_AES_128_CCM_8
|
||||
CFLAGS += -DDTLS_PSK
|
||||
|
||||
# NOTE: This adds support for TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
|
||||
CFLAGS += -DDTLS_ECC
|
||||
|
||||
# NOTE: If enabled TinyDTLS' log are disabled (if memory is a issue).
|
||||
# WARNING: Sometimes the log leads to Stack pointer corrupted.
|
||||
# The reason is not identified yet.
|
||||
# If said issue appears, enable this line.
|
||||
#CFLAGS += -DNDEBUG
|
||||
|
||||
# NOTE: The configuration for socket or non-socket communication in TinyDTLS.
|
||||
CFLAGS += -DWITH_RIOT_GNRC
|
||||
CFLAGS += -DDEVELHELP
|
||||
|
||||
# Change this to 0 show compiler invocation lines by default:
|
||||
QUIET ?= 1
|
||||
|
||||
@ -1,16 +1,12 @@
|
||||
# dtls_echo
|
||||
# dtls_echo example
|
||||
|
||||
This example shows you how to use TinyDTLS with the non-socket approach.
|
||||
This example shows how to use TinyDTLS with sock_udp.
|
||||
|
||||
This code is based on ../gnrc_networking and ../gnrc_tftp.
|
||||
Is a good idea to read their README.md's for any doubt of how making the
|
||||
testings.
|
||||
## SOCK vs. Socket
|
||||
|
||||
## SOCKET vs. Non-socket (GNRC)
|
||||
|
||||
This example is configured to use the GNRC instead of sockets (over GNRC).
|
||||
At the moment, the configuration must be done manually in the Makefile of
|
||||
this project.
|
||||
This example is configured to use socks instead of sockets (over GNRC).
|
||||
It's possible to use sockets, which give a more similar approach to the original
|
||||
Linux version of TinyDTLS. However, this is not tested yet.
|
||||
|
||||
## Fast configuration (Between RIOT instances):
|
||||
|
||||
@ -29,49 +25,37 @@ Do not forget to copy the IPv6 addresses!
|
||||
For the client:
|
||||
|
||||
PORT=tap0 make term
|
||||
dtlsc <IPv6's server address> "DATA TO DATA TO DATA!"
|
||||
dtlsc <IPv6's server address[%netif]> "DATA to send under encrypted channel!"
|
||||
|
||||
# Testings
|
||||
## Boards
|
||||
|
||||
Those boards that do not support the `../gnrc_networking` example are included
|
||||
in the `BOARD_INSUFFICIENT_MEMORY`, plus the board `cc2650stk`.
|
||||
Boards that do not support the `../gnrc_networking` example are included
|
||||
in the `BOARD_INSUFFICIENT_MEMORY`, plus the board `cc2650stk`.
|
||||
|
||||
There are certain boards that are having issues with `crypto.c` and
|
||||
`dtls_time.h` Which for now are in the the `BOARD_BLACKLIST`.
|
||||
The code has been tested in the FIT IOT-LAB tesbed with the remote
|
||||
`iotlab-m3` and `iotlab-a8-m3` boards and with local `samr21-xpro` boards.
|
||||
|
||||
The boards that requires `periph_conf.h` are not tested.
|
||||
## Handling the static memory allocation
|
||||
|
||||
Boards with problem type 1 (`crypto.c`):
|
||||
z1
|
||||
wsn430-v1_4
|
||||
wsn430-v1_3b
|
||||
waspmote-pro
|
||||
msb-430h
|
||||
msb-430
|
||||
chronos
|
||||
arduino-mega2560
|
||||
TinyDTLS for RIOT is using the `sys/memarray` module and therefore there
|
||||
are certain limits. Said resources are defined in
|
||||
`tinydtls/platform-specific/riot_boards.h`, but can be overwritten at
|
||||
compile time. Their default values are considered for having two DTLS
|
||||
contexts (for purpose of DTLS renegotiation).
|
||||
|
||||
Boards with problem type 2 (`dtls_time.h`):
|
||||
cc2538dk
|
||||
msbiot
|
||||
telosb
|
||||
The resources handled by memarray are:
|
||||
* `DTLS_CONTEXT_MAX` (default 2) The maximum number of DTLS context at the
|
||||
same time.
|
||||
* `DTLS_PEER_MAX` (default 1) The maximum number DTLS peers (i.e. sessions).
|
||||
* `DTLS_HANDSHAKE_MAX` (default 1) The maximum number of concurrent DTLS handshakes.
|
||||
* `DTLS_SECURITY_MAX` (the sum of the previous two) The maximum number of
|
||||
concurrently used cipher keys.
|
||||
* `DTLS_HASH_MAX` (Default: `3 * DTLS_PEER_MAX`) The maximum number of hash
|
||||
functions that can be used in parallel.
|
||||
|
||||
Boards with problem type 3 (Redifinition):
|
||||
saml21-xpro
|
||||
samr21-xpro
|
||||
arduino-uno
|
||||
arduino-duemilanove
|
||||
## Handling retransmissions
|
||||
|
||||
NOTE: Those on type 1 can be benefit of the following PR:
|
||||
https://github.com/RIOT-OS/RIOT/issues/2360
|
||||
However, there are still issues to fix.
|
||||
|
||||
NOTE: Those on type 2 can be fixed with the patch at
|
||||
https://github.com/RIOT-OS/RIOT/pull/5974
|
||||
|
||||
## FIT-LAB
|
||||
|
||||
The code has been tested in the FIT-LAB with M3 motes.
|
||||
However, erros can occurrs. Enabling the line `CFLAGS += -DNDEBUG` in
|
||||
the `Makefile` reduces the risk.
|
||||
By default, the number of transmissions of any DTLS record is settled to just
|
||||
one. This can be handled by `DTLS_DEFAULT_MAX_RETRANSMIT` (defined in
|
||||
`tinydtls/platform-specific/riot_boards.h`).
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freie Universität Berlin
|
||||
* 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
|
||||
@ -11,9 +12,9 @@
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief The cliend side of TinyDTLS (Simple echo)
|
||||
* @brief Demonstrating the client side of TinyDTLS (Simple echo)
|
||||
*
|
||||
* @author Raul A. Fuentes Samaniego <ra.fuentes.sam+RIOT@gmail.com>
|
||||
* @author Raul A. Fuentes Samaniego <raul.fuentes-samaniego@inria.fr>
|
||||
* @author Olaf Bergmann <bergmann@tzi.org>
|
||||
* @author Hauke Mehrtens <hauke@hauke-m.de>
|
||||
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
||||
@ -23,118 +24,122 @@
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "net/gnrc.h"
|
||||
#include "net/gnrc/ipv6.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
#include "net/gnrc/netif/hdr.h"
|
||||
#include "net/gnrc/udp.h"
|
||||
#include "net/gnrc/pktdump.h"
|
||||
#include "timex.h"
|
||||
#include "utlist.h"
|
||||
#include "xtimer.h"
|
||||
#include "net/sock/udp.h"
|
||||
#include "tinydtls_keys.h"
|
||||
|
||||
/* TinyDTLS */
|
||||
#include "dtls_debug.h"
|
||||
#include "dtls.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/* TinyDTLS */
|
||||
#include "tinydtls.h"
|
||||
#include "dtls_debug.h"
|
||||
#include "dtls.h"
|
||||
#include "global.h"
|
||||
#ifndef DTLS_DEFAULT_PORT
|
||||
#define DTLS_DEFAULT_PORT 20220 /* DTLS default port */
|
||||
#endif
|
||||
|
||||
#define CLIENT_PORT DTLS_DEFAULT_PORT + 1
|
||||
#define MAX_TIMES_TRY_TO_SEND 10 /* Expected to be 1 - 255 */
|
||||
|
||||
|
||||
/* TODO: Remove the UNUSED_PARAM from TinyDTLS' stack? */
|
||||
#ifdef __GNUC__
|
||||
#define UNUSED_PARAM __attribute__((unused))
|
||||
/* Delay to give time to the remote peer to do the compute (client only). */
|
||||
#ifdef DTLS_ECC
|
||||
#define DEFAULT_US_DELAY 10000000
|
||||
#else
|
||||
#define UNUSED_PARAM
|
||||
#endif /* __GNUC__ */
|
||||
#define DEFAULT_US_DELAY 100
|
||||
#endif
|
||||
|
||||
#ifdef DTLS_PSK
|
||||
static int dtls_connected = 0; /* This is handled by Tinydtls callbacks */
|
||||
|
||||
#define PSK_DEFAULT_IDENTITY "Client_identity"
|
||||
#define PSK_DEFAULT_KEY "secretPSK"
|
||||
#define PSK_OPTIONS "i:k:"
|
||||
|
||||
/* Max size for PSK lowered for embedded devices */
|
||||
#define PSK_ID_MAXLEN 32
|
||||
#define PSK_MAXLEN 32
|
||||
|
||||
#endif /* DTLS_PSK */
|
||||
|
||||
//#define DEFAULT_PORT 20220 /* DTLS default port */
|
||||
#define DEFAULT_PORT 61618 /* First valid FEBx address */
|
||||
|
||||
#define CLIENT_PORT DEFAULT_PORT + 1
|
||||
#define MAX_TIMES_TRY_TO_SEND 10
|
||||
|
||||
static dtls_context_t *dtls_context = NULL;
|
||||
static char *client_payload;
|
||||
static size_t buflen = 0;
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief This care about getting messages and continue with the DTLS flights.
|
||||
* This will handle all the packets arriving to the node.
|
||||
* Will determine if its from a new DTLS peer or a previous one.
|
||||
*/
|
||||
static void dtls_handle_read(dtls_context_t *ctx, gnrc_pktsnip_t *pkt)
|
||||
/* TinyDTLS callback for detecting the state of the DTLS channel. */
|
||||
static int _events_handler(struct dtls_context_t *ctx,
|
||||
session_t *session,
|
||||
dtls_alert_level_t level,
|
||||
unsigned short code)
|
||||
{
|
||||
(void) ctx;
|
||||
(void) session;
|
||||
(void) level;
|
||||
|
||||
if (code == DTLS_EVENT_CONNECTED) {
|
||||
dtls_connected = 1;
|
||||
DEBUG("CLIENT: DTLS Channel established!\n");
|
||||
}
|
||||
/* At least a DTLS Client Hello was prepared? */
|
||||
else if ((ENABLE_DEBUG) && (code == DTLS_EVENT_CONNECT)) {
|
||||
DEBUG("CLIENT: DTLS Channel started\n");
|
||||
}
|
||||
|
||||
/* NOTE: DTLS_EVENT_RENEGOTIATE can be handled here */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handles all the packets arriving at the node and identifies those that are
|
||||
* DTLS records. Also, it determines if said DTLS record is coming from a new
|
||||
* peer or a currently established peer.
|
||||
*
|
||||
*/
|
||||
static void dtls_handle_read(dtls_context_t *ctx)
|
||||
{
|
||||
static session_t session;
|
||||
static sock_udp_ep_t remote = SOCK_IPV6_EP_ANY;
|
||||
uint8_t packet_rcvd[DTLS_MAX_BUF];
|
||||
|
||||
/*
|
||||
* NOTE: GNRC (Non-socket) issue: we need to modify the current
|
||||
* DTLS Context for the IPv6 src (and in a future the port src).
|
||||
*/
|
||||
if (!ctx) {
|
||||
DEBUG("%s: No DTLS context\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Taken from the tftp server example */
|
||||
char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
gnrc_pktsnip_t *tmp2;
|
||||
if (!dtls_get_app_data(ctx)) {
|
||||
DEBUG("%s: No app_data stored!\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
tmp2 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
|
||||
ipv6_hdr_t *hdr = (ipv6_hdr_t *)tmp2->data;
|
||||
sock_udp_t *sock;
|
||||
sock = (sock_udp_t *)dtls_get_app_data(ctx);
|
||||
|
||||
ipv6_addr_to_str(addr_str, &hdr->src, sizeof(addr_str));
|
||||
|
||||
/*
|
||||
*TODO: More testings with TinyDTLS is neccesary, but seem this is safe.
|
||||
*/
|
||||
tmp2 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_UDP);
|
||||
udp_hdr_t *udp = (udp_hdr_t *)tmp2->data;
|
||||
if (sock_udp_get_remote(sock, &remote) == -ENOTCONN) {
|
||||
DEBUG("%s: Unable to retrieve remote!\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
session.size = sizeof(ipv6_addr_t) + sizeof(unsigned short);
|
||||
session.port = byteorder_ntohs(udp->src_port);
|
||||
ssize_t res = sock_udp_recv(sock, packet_rcvd, DTLS_MAX_BUF,
|
||||
1 * US_PER_SEC + DEFAULT_US_DELAY,
|
||||
&remote);
|
||||
|
||||
DEBUG("DBG-Client: Msg received from \n\t Addr Src: %s"
|
||||
"\n\t Current Peer: %s \n", addr_str, (char *)dtls_get_app_data(ctx));
|
||||
if (res <= 0) {
|
||||
if ((ENABLE_DEBUG) && (res != -EAGAIN) && (res != -ETIMEDOUT)) {
|
||||
DEBUG("sock_udp_recv unexepcted code error: %i\n", (int)res);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ipv6_addr_from_str(&session.addr, addr_str);
|
||||
/* session requires the remote socket (IPv6:UDP) address and netif */
|
||||
session.size = sizeof(uint8_t) * 16 + sizeof(unsigned short);
|
||||
session.port = remote.port;
|
||||
if (&remote.netif == SOCK_ADDR_ANY_NETIF) {
|
||||
session.ifindex = SOCK_ADDR_ANY_NETIF;
|
||||
}
|
||||
else {
|
||||
session.ifindex = remote.netif;
|
||||
}
|
||||
|
||||
dtls_handle_message(ctx, &session, pkt->data, (unsigned int)pkt->size);
|
||||
if (memcpy(&session.addr, &remote.addr.ipv6, 16) == NULL) {
|
||||
puts("ERROR: memcpy failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ENABLE_DEBUG) {
|
||||
DEBUG("DBG-Client: Msg received from \n\t Addr Src: [");
|
||||
ipv6_addr_print(&session.addr);
|
||||
DEBUG("]:%u\n", remote.port);
|
||||
}
|
||||
|
||||
dtls_handle_message(ctx, &session, packet_rcvd, (int)DTLS_MAX_BUF);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DTLS_PSK
|
||||
@ -143,25 +148,25 @@ static size_t psk_id_length = sizeof(PSK_DEFAULT_IDENTITY) - 1;
|
||||
static unsigned char psk_key[PSK_MAXLEN] = PSK_DEFAULT_KEY;
|
||||
static size_t psk_key_length = sizeof(PSK_DEFAULT_KEY) - 1;
|
||||
|
||||
/**
|
||||
/*
|
||||
* This function is the "key store" for tinyDTLS. It is called to
|
||||
* retrieve a key for the given identity within this particular
|
||||
* session.
|
||||
*/
|
||||
static int peer_get_psk_info(struct dtls_context_t *ctx UNUSED_PARAM,
|
||||
const session_t *session UNUSED_PARAM,
|
||||
dtls_credentials_type_t type,
|
||||
const unsigned char *id, size_t id_len,
|
||||
unsigned char *result, size_t result_length)
|
||||
static int _peer_get_psk_info_handler(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)
|
||||
{
|
||||
(void) ctx;
|
||||
(void) session;
|
||||
|
||||
switch (type) {
|
||||
case DTLS_PSK_IDENTITY:
|
||||
/* Removed due probably in the motes is useless
|
||||
if (id_len) {
|
||||
dtls_debug("got psk_identity_hint: '%.*s'\n", id_len, id);
|
||||
}
|
||||
*/
|
||||
if (id_len) {
|
||||
dtls_debug("got psk_identity_hint: '%.*s'\n", id_len, id);
|
||||
}
|
||||
|
||||
if (result_length < psk_id_length) {
|
||||
dtls_warn("cannot set psk_identity -- buffer too small\n");
|
||||
@ -190,15 +195,16 @@ static int peer_get_psk_info(struct dtls_context_t *ctx UNUSED_PARAM,
|
||||
}
|
||||
#endif /* DTLS_PSK */
|
||||
|
||||
|
||||
#ifdef DTLS_ECC
|
||||
static int peer_get_ecdsa_key(struct dtls_context_t *ctx,
|
||||
const session_t *session,
|
||||
const dtls_ecdsa_key_t **result)
|
||||
static int _peer_get_ecdsa_key_handler(struct dtls_context_t *ctx,
|
||||
const session_t *session,
|
||||
const dtls_ecdsa_key_t **result)
|
||||
{
|
||||
(void) ctx;
|
||||
(void) session;
|
||||
|
||||
/* TODO: Load the key from external source */
|
||||
|
||||
static const dtls_ecdsa_key_t ecdsa_key = {
|
||||
.curve = DTLS_ECDH_CURVE_SECP256R1,
|
||||
.priv_key = ecdsa_priv_key,
|
||||
@ -210,325 +216,278 @@ static int peer_get_ecdsa_key(struct dtls_context_t *ctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int peer_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)
|
||||
static int _peer_verify_ecdsa_key_handler(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) key_size;
|
||||
(void) other_pub_x;
|
||||
(void) other_pub_y;
|
||||
(void) other_pub_x;
|
||||
(void) key_size;
|
||||
|
||||
/* TODO: As far for tinyDTLS 0.8.2 this is not used */
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* DTLS_ECC */
|
||||
|
||||
/**
|
||||
* @brief This will try to transmit using only GNRC stack.
|
||||
* This is basically the original send function from gnrc/networking
|
||||
*/
|
||||
static int gnrc_sending(char *addr_str, char *data, size_t data_len )
|
||||
/* Reception of a DTLS Application data record. */
|
||||
static int _read_from_peer_handler(struct dtls_context_t *ctx,
|
||||
session_t *session,
|
||||
uint8 *data, size_t len)
|
||||
{
|
||||
int iface;
|
||||
ipv6_addr_t addr;
|
||||
gnrc_pktsnip_t *payload, *udp, *ip;
|
||||
(void) ctx;
|
||||
(void) session;
|
||||
|
||||
/* get interface, if available */
|
||||
iface = ipv6_addr_split_iface(addr_str);
|
||||
if ((iface < 0) && (gnrc_netif_numof() == 1)) {
|
||||
iface = gnrc_netif_iter(NULL)->pid;
|
||||
}
|
||||
/* parse destination address */
|
||||
if (ipv6_addr_from_str(&addr, addr_str) == NULL) {
|
||||
puts("Error: unable to parse destination address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allocate payload */
|
||||
payload = gnrc_pktbuf_add(NULL, data, data_len, GNRC_NETTYPE_UNDEF);
|
||||
|
||||
if (payload == NULL) {
|
||||
puts("Error: unable to copy data to packet buffer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allocate UDP header */
|
||||
udp = gnrc_udp_hdr_build(payload, (uint16_t) CLIENT_PORT, (uint16_t) DEFAULT_PORT);
|
||||
if (udp == NULL) {
|
||||
puts("Error: unable to allocate UDP header");
|
||||
gnrc_pktbuf_release(payload);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allocate IPv6 header */
|
||||
ip = gnrc_ipv6_hdr_build(udp, NULL, &addr);
|
||||
if (ip == NULL) {
|
||||
puts("Error: unable to allocate IPv6 header");
|
||||
gnrc_pktbuf_release(udp);
|
||||
return -1;
|
||||
}
|
||||
/* add netif header, if interface was given */
|
||||
if (iface > 0) {
|
||||
gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
|
||||
((gnrc_netif_hdr_t *)netif->data)->if_pid = (kernel_pid_t)iface;
|
||||
LL_PREPEND(ip, netif);
|
||||
}
|
||||
printf("Client: got DTLS Data App -- ");
|
||||
for (size_t i = 0; i < len; i++)
|
||||
printf("%c", data[i]);
|
||||
puts(" --");
|
||||
|
||||
/*
|
||||
* WARNING: Too fast and the nodes dies in middle of retransmissions.
|
||||
* This issue appears in the FIT-Lab (m3 motes).
|
||||
* In native, is not required.
|
||||
* NOTE: To answer the other peer uses dtls_write(). E.g.
|
||||
* return dtls_write(ctx, session, data, len);
|
||||
*/
|
||||
xtimer_usleep(500000);
|
||||
|
||||
/* send packet */
|
||||
if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_UDP, GNRC_NETREG_DEMUX_CTX_ALL, ip)) {
|
||||
puts("Error: unable to locate UDP thread");
|
||||
gnrc_pktbuf_release(ip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This will print the data read from the Peer.
|
||||
* THIS AT THE END of the 6 flights (DTLS App Data).
|
||||
* Is here where we know that the connection has finished.
|
||||
* TODO: The connected variable could de modified here.
|
||||
*/
|
||||
static int read_from_peer(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *data, size_t len)
|
||||
{
|
||||
/* Linux and Contiki version are exactly the same. */
|
||||
(void) session;
|
||||
(void) ctx;
|
||||
size_t i;
|
||||
printf("\n\n Echo received: ");
|
||||
for (i = 0; i < len; i++)
|
||||
printf("%c", data[i]);
|
||||
printf(" \n\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Will try to transmit the next DTLS flight for a speicifc Peer.
|
||||
* NOTE:The global buff and buflen is used for be able to transmit the
|
||||
* Payload in segmented datagrams.
|
||||
*/
|
||||
static void try_send(struct dtls_context_t *ctx, session_t *dst)
|
||||
/* Transmits the upper layer data data in one or more DTLS Data App records . */
|
||||
ssize_t try_send(struct dtls_context_t *ctx, session_t *dst, uint8 *buf, size_t len)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
int res;
|
||||
|
||||
res = dtls_write(ctx, dst, (uint8_t *)client_payload, buflen);
|
||||
res = dtls_write(ctx, dst, buf, len);
|
||||
|
||||
if (res >= 0) {
|
||||
memmove(client_payload, client_payload + res, buflen - res);
|
||||
buflen -= res;
|
||||
memmove(buf, buf + res, len - res);
|
||||
len -= res;
|
||||
return len;
|
||||
}
|
||||
else {
|
||||
DEBUG("DBG-Client: dtls_write returned error!\n" );
|
||||
else if (res < 0) {
|
||||
dtls_crit("Client: dtls_write returned error!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This SIGNAL function will prepare the next DTLS flight to send.
|
||||
*/
|
||||
static int send_to_peer(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *buf, size_t len)
|
||||
/* Handles the DTLS communication with the other peer. */
|
||||
static int _send_to_peer_handler(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *buf, size_t len)
|
||||
{
|
||||
|
||||
(void) session;
|
||||
/*
|
||||
* For this testing with GNR we are to extract the peer's addresses and
|
||||
* making the connection from zero.
|
||||
*/
|
||||
char *addr_str;
|
||||
addr_str = (char *)dtls_get_app_data(ctx);
|
||||
|
||||
assert(ctx);
|
||||
assert(dtls_get_app_data(ctx));
|
||||
|
||||
/* TODO: Confirm that indeed len size of data was sent, otherwise
|
||||
* return the correct number of bytes sent
|
||||
*/
|
||||
gnrc_sending(addr_str, (char *)buf, len);
|
||||
if (!dtls_get_app_data(ctx)) {
|
||||
return -1; /* At this point this should not happen anymore. */
|
||||
}
|
||||
|
||||
return len;
|
||||
sock_udp_t *sock;
|
||||
sock = (sock_udp_t *)dtls_get_app_data(ctx);
|
||||
|
||||
ssize_t res = sock_udp_send(sock, buf, len, NULL);
|
||||
if (res <= 0) {
|
||||
puts("ERROR: Unable to send DTLS record");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***
|
||||
* This is a custom function for preparing the SIGNAL events and
|
||||
* create a new DTLS context.
|
||||
*/
|
||||
static void init_dtls(session_t *dst, char *addr_str)
|
||||
/* DTLS variables are initialized. */
|
||||
dtls_context_t *_init_dtls(sock_udp_t *sock, sock_udp_ep_t *local,
|
||||
sock_udp_ep_t *remote, session_t *dst,
|
||||
char *addr_str)
|
||||
{
|
||||
dtls_context_t *new_context = NULL;
|
||||
|
||||
static dtls_handler_t cb = {
|
||||
.write = send_to_peer,
|
||||
.read = read_from_peer,
|
||||
.event = NULL,
|
||||
.write = _send_to_peer_handler,
|
||||
.read = _read_from_peer_handler,
|
||||
.event = _events_handler,
|
||||
#ifdef DTLS_PSK
|
||||
.get_psk_info = peer_get_psk_info,
|
||||
.get_psk_info = _peer_get_psk_info_handler,
|
||||
#endif /* DTLS_PSK */
|
||||
#ifdef DTLS_ECC
|
||||
.get_ecdsa_key = peer_get_ecdsa_key,
|
||||
.verify_ecdsa_key = peer_verify_ecdsa_key
|
||||
.get_ecdsa_key = _peer_get_ecdsa_key_handler,
|
||||
.verify_ecdsa_key = _peer_verify_ecdsa_key_handler
|
||||
#endif /* DTLS_ECC */
|
||||
};
|
||||
|
||||
#ifdef DTLS_PSK
|
||||
puts("Client support PSK");
|
||||
DEBUG("Client support PSK\n");
|
||||
#endif
|
||||
#ifdef DTLS_ECC
|
||||
puts("Client support ECC");
|
||||
DEBUG("Client support ECC\n");
|
||||
#endif
|
||||
|
||||
DEBUG("DBG-Client: Debug ON");
|
||||
/*
|
||||
* The objective of ctx->App is be able to retrieve
|
||||
* enough information for restablishing a connection.
|
||||
* This is to be used in the send_to_peer and (potentially) the
|
||||
* read_from_peer, to continue the transmision with the next
|
||||
* step of the DTLS flights.
|
||||
* TODO: Take away the DEFAULT_PORT and CLIENT_PORT.
|
||||
*/
|
||||
dst->size = sizeof(ipv6_addr_t) + sizeof(unsigned short);
|
||||
dst->port = (unsigned short) DEFAULT_PORT;
|
||||
dtls_connected = 0;
|
||||
|
||||
#ifdef TINYDTLS_LOG_LVL
|
||||
dtls_set_log_level(TINYDTLS_LOG_LVL);
|
||||
#endif
|
||||
|
||||
/* First, we prepare the UDP Sock */
|
||||
local->port = (unsigned short) CLIENT_PORT;
|
||||
remote->port = (unsigned short) DTLS_DEFAULT_PORT;
|
||||
|
||||
/* Parsing <address>[:<iface>]:Port */
|
||||
int iface = ipv6_addr_split_iface(addr_str);
|
||||
if (iface == -1) {
|
||||
if (gnrc_netif_numof() == 1) {
|
||||
/* assign the single interface found in gnrc_netif_numof() */
|
||||
dst->ifindex = (uint16_t)gnrc_netif_iter(NULL)->pid;
|
||||
remote->netif = (uint16_t)gnrc_netif_iter(NULL)->pid;
|
||||
}
|
||||
else {
|
||||
/* FIXME This probably is not valid with multiple interfaces */
|
||||
dst->ifindex = remote->netif;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (gnrc_netif_get_by_pid(iface) == NULL) {
|
||||
puts("ERROR: interface not valid");
|
||||
return new_context;
|
||||
}
|
||||
dst->ifindex = (uint16_t)gnrc_netif_iter(NULL)->pid;
|
||||
remote->netif = (uint16_t)gnrc_netif_iter(NULL)->pid;
|
||||
}
|
||||
|
||||
if (ipv6_addr_from_str((ipv6_addr_t *)remote->addr.ipv6, addr_str) == NULL) {
|
||||
puts("ERROR: unable to parse destination address");
|
||||
return new_context;
|
||||
}
|
||||
|
||||
/* Second: We prepare the DTLS Session by means of ctx->app */
|
||||
dst->size = sizeof(uint8_t) * 16 + sizeof(unsigned short);
|
||||
dst->port = remote->port;
|
||||
|
||||
/* NOTE: remote.addr.ipv6 and dst->addr are different structures. */
|
||||
if (ipv6_addr_from_str(&dst->addr, addr_str) == NULL) {
|
||||
puts("ERROR: init_dtls was unable to load the IPv6 addresses!\n");
|
||||
dtls_context = NULL;
|
||||
puts("ERROR: init_dtls was unable to load the IPv6 addresses!");
|
||||
return new_context;
|
||||
}
|
||||
|
||||
new_context = dtls_new_context(sock);
|
||||
if (new_context) {
|
||||
dtls_set_handler(new_context, &cb);
|
||||
}
|
||||
|
||||
return new_context;
|
||||
}
|
||||
|
||||
static void client_send(char *addr_str, char *data)
|
||||
{
|
||||
static session_t dst;
|
||||
dtls_context_t *dtls_context = NULL;
|
||||
|
||||
sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
|
||||
sock_udp_ep_t remote = SOCK_IPV6_EP_ANY;
|
||||
sock_udp_t sock;
|
||||
|
||||
uint8_t watch = MAX_TIMES_TRY_TO_SEND;
|
||||
ssize_t app_data_buf = 0; /* Upper layer packet to send */
|
||||
|
||||
/* NOTE: dtls_init() must be called previous to this (see main.c) */
|
||||
|
||||
dtls_context = _init_dtls(&sock, &local, &remote, &dst, addr_str);
|
||||
if (!dtls_context) {
|
||||
puts("ERROR: Client unable to load context!");
|
||||
return;
|
||||
}
|
||||
|
||||
ipv6_addr_t addr_dbg;
|
||||
ipv6_addr_from_str(&addr_dbg, addr_str);
|
||||
|
||||
/*akin to syslog: EMERG, ALERT, CRITC, NOTICE, INFO, DEBUG */
|
||||
dtls_set_log_level(DTLS_LOG_NOTICE);
|
||||
|
||||
dtls_context = dtls_new_context(addr_str);
|
||||
if (dtls_context) {
|
||||
dtls_set_handler(dtls_context, &cb);
|
||||
char *client_payload;
|
||||
if (strlen(data) > DTLS_MAX_BUF) {
|
||||
puts("ERROR: Exceeded max size of DTLS buffer.");
|
||||
return;
|
||||
}
|
||||
client_payload = data;
|
||||
app_data_buf = strlen(client_payload);
|
||||
|
||||
/* The sock must be opened with the remote already linked to it */
|
||||
if (sock_udp_create(&sock, &local, &remote, 0) != 0) {
|
||||
puts("ERROR: Unable to create UDP sock");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Starts the DTLS handshake process by sending the first DTLS Hello Client
|
||||
* record.
|
||||
*
|
||||
* NOTE: If dtls_connect() returns zero, then the DTLS channel for the
|
||||
* dtls_context is already created (never the case for this example)
|
||||
*/
|
||||
if (dtls_connect(dtls_context, &dst) < 0) {
|
||||
puts("ERROR: Client unable to start a DTLS channel!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This loop transmits all the DTLS records involved in the DTLS session.
|
||||
* Including the real (upper) data to send and to receive. There is a
|
||||
* watchdog if the remote peer stop answering.
|
||||
*
|
||||
* Max lifetime expected for a DTLS handshake is 10 sec. This is reflected
|
||||
* with the variable watch and the timeout for sock_udp_recv().
|
||||
*
|
||||
* NOTE: DTLS Sessions can handles more than one single node but by
|
||||
* default is limited to a single peer with a single context and
|
||||
* a single concurrent handshake.
|
||||
* See tinydtls/platform-specific/riot_boards.h for more info.
|
||||
* NOTE: DTLS_DEFAULT_MAX_RETRANSMIT has an impact here.
|
||||
*/
|
||||
while ((app_data_buf > 0) && (watch > 0)) {
|
||||
|
||||
/* DTLS Session must be established before sending our data */
|
||||
if (dtls_connected) {
|
||||
DEBUG("Sending (upper layer) data\n");
|
||||
app_data_buf = try_send(dtls_context, &dst,
|
||||
(uint8 *)client_payload, app_data_buf);
|
||||
|
||||
if (app_data_buf == 0) { /* Client only transmit data one time. */
|
||||
watch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if a DTLS record was received */
|
||||
/* NOTE: We expect an answer after try_send() */
|
||||
dtls_handle_read(dtls_context);
|
||||
watch--;
|
||||
} /* END while */
|
||||
|
||||
/*
|
||||
* BUG: tinyDTLS (<= 0.8.6)
|
||||
* If dtls_connect() is called but the handshake does not complete (e.g.
|
||||
* peer is offline) then a netq_t object is allocated and never freed
|
||||
* leaving a memory leak of 124 bytes.
|
||||
* This can lead to "retransmit buffer full" error.
|
||||
*
|
||||
* A temporary solution is to make the dtls_context_t global and be sure
|
||||
* to never release it. Alternatively, never let this part of the code
|
||||
* ends, in a similar approach to the server side.
|
||||
*/
|
||||
|
||||
/* Release resources (strict order!) */
|
||||
dtls_free_context(dtls_context); /* This also sends a DTLS Alert record */
|
||||
sock_udp_close(&sock);
|
||||
dtls_connected = 0;
|
||||
DEBUG("Client DTLS session finished\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the "client" part of this program.
|
||||
* Will be called each time a message is transmitted.
|
||||
*/
|
||||
static void client_send(char *addr_str, char *data, unsigned int delay)
|
||||
{
|
||||
int8_t iWatch;
|
||||
static session_t dst;
|
||||
static int connected = 0;
|
||||
msg_t msg;
|
||||
|
||||
gnrc_netreg_entry_t entry = GNRC_NETREG_ENTRY_INIT_PID(CLIENT_PORT,
|
||||
sched_active_pid);
|
||||
dtls_init();
|
||||
|
||||
if (gnrc_netreg_register(GNRC_NETTYPE_UDP, &entry)) {
|
||||
puts("Unable to register ports");
|
||||
/*FIXME: Release memory?*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen(data) > DTLS_MAX_BUF) {
|
||||
puts("Data too long ");
|
||||
return;
|
||||
}
|
||||
|
||||
init_dtls(&dst, addr_str);
|
||||
if (!dtls_context) {
|
||||
dtls_emerg("cannot create context\n");
|
||||
puts("Client unable to load context!");
|
||||
return;
|
||||
}
|
||||
|
||||
/* client_payload is global due to the SIGNAL function send_to_peer */
|
||||
client_payload = data;
|
||||
buflen = strlen(client_payload);
|
||||
iWatch = MAX_TIMES_TRY_TO_SEND;
|
||||
|
||||
/*
|
||||
* dtls_connect is the one who begin all the process.
|
||||
* However, do it too fast, and the node will attend it before having a
|
||||
* valid IPv6 or even a route to the destiny (This could be verified as the
|
||||
* sequence number of the first DTLS Hello message will be greater than
|
||||
* zero).
|
||||
*/
|
||||
//connected = dtls_connect(dtls_context, &dst) >= 0;
|
||||
|
||||
/*
|
||||
* Until all the data is not sent we remains trying to connect to the
|
||||
* server. Plus a small watchdog.
|
||||
*/
|
||||
while ((buflen > 0) && (iWatch > 0)) {
|
||||
|
||||
/*
|
||||
* NOTE: I (rfuentess) personally think this should be until this point
|
||||
* instead before (that is why the previous dtls_connect is by defualt
|
||||
* commented..
|
||||
*/
|
||||
if (!connected) {
|
||||
connected = dtls_connect(dtls_context, &dst);
|
||||
}
|
||||
else if (connected < 0) {
|
||||
puts("Client DTLS was unable to establish a channel!\n");
|
||||
/*NOTE: Not sure what to do in this scenario (if can happens)*/
|
||||
}
|
||||
else {
|
||||
/*TODO: must happens always or only when connected?*/
|
||||
try_send(dtls_context, &dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING: The delay is KEY HERE! Too fast, and we can kill the
|
||||
* DTLS state machine. Another alternative is change to
|
||||
* blocking states (making the watchdog useless)
|
||||
*
|
||||
* msg_receive(&msg);
|
||||
*/
|
||||
|
||||
xtimer_usleep(delay);
|
||||
|
||||
if (msg_try_receive(&msg) == 1) {
|
||||
dtls_handle_read(dtls_context, (gnrc_pktsnip_t *)(msg.content.ptr));
|
||||
}
|
||||
|
||||
iWatch--;
|
||||
} /*END while*/
|
||||
|
||||
dtls_free_context(dtls_context);
|
||||
/* unregister our UDP listener on this thread */
|
||||
gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &entry);
|
||||
connected = 0; /*Probably this should be removed or global */
|
||||
|
||||
/* Permanent or not permanent? */
|
||||
DEBUG("DTLS-Client: DTLS session finished\n");
|
||||
}
|
||||
|
||||
int udp_client_cmd(int argc, char **argv)
|
||||
{
|
||||
uint32_t delay = 1000000;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("usage: %s <addr> <data> [<delay in us>]\n", argv[0]);
|
||||
if (argc != 3) {
|
||||
printf("usage: %s <addr> <data> \n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
else if (argc > 3) {
|
||||
delay = atoi(argv[3]);
|
||||
}
|
||||
client_send(argv[1], argv[2], delay);
|
||||
|
||||
client_send(argv[1], argv[2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freie Universität Berlin
|
||||
* 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
|
||||
@ -11,9 +12,9 @@
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief The server side of TinyDTLS (Simple echo)
|
||||
* @brief Demonstrating the server side of TinyDTLS (Simple echo)
|
||||
*
|
||||
* @author Raul A. Fuentes Samaniego <ra.fuentes.sam+RIOT@gmail.com>
|
||||
* @author Raul A. Fuentes Samaniego <ra.fuentes.sam+RIOT@gmail.com>
|
||||
* @author Olaf Bergmann <bergmann@tzi.org>
|
||||
* @author Hauke Mehrtens <hauke@hauke-m.de>
|
||||
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
||||
@ -24,16 +25,9 @@
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "net/gnrc.h"
|
||||
#include "net/gnrc/ipv6.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
#include "net/gnrc/netif/hdr.h"
|
||||
#include "net/gnrc/udp.h"
|
||||
#include "timex.h"
|
||||
#include "utlist.h"
|
||||
#include "xtimer.h"
|
||||
#include "net/sock/udp.h"
|
||||
#include "msg.h"
|
||||
|
||||
#include "tinydtls_keys.h"
|
||||
|
||||
/* TinyDTLS */
|
||||
#include "dtls.h"
|
||||
@ -43,210 +37,167 @@
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
//#define DEFAULT_PORT 20220 /* DTLS default port */
|
||||
#define DEFAULT_PORT 61618 /* First valid FEBx address */
|
||||
#ifndef DTLS_DEFAULT_PORT
|
||||
#define DTLS_DEFAULT_PORT 20220 /* DTLS default port */
|
||||
#endif
|
||||
|
||||
/* TODO: MAke this local! */
|
||||
static dtls_context_t *dtls_context = NULL;
|
||||
#define DTLS_STOP_SERVER_MSG 0x4001 /* Custom IPC type msg. */
|
||||
|
||||
static const unsigned char ecdsa_priv_key[] = {
|
||||
0xD9, 0xE2, 0x70, 0x7A, 0x72, 0xDA, 0x6A, 0x05,
|
||||
0x04, 0x99, 0x5C, 0x86, 0xED, 0xDB, 0xE3, 0xEF,
|
||||
0xC7, 0xF1, 0xCD, 0x74, 0x83, 0x8F, 0x75, 0x70,
|
||||
0xC8, 0x07, 0x2D, 0x0A, 0x76, 0x26, 0x1B, 0xD4
|
||||
};
|
||||
/*
|
||||
* This structure will be used for storing the sock and the remote into the
|
||||
* dtls_context_t variable.
|
||||
*
|
||||
* This is because remote must not have port set to zero on sock_udp_create()
|
||||
* making impossible to recover the remote with sock_udp_get_remote()
|
||||
*
|
||||
* An alternative is to modify dtls_handle_message () to receive the remote
|
||||
* from sock_udp_recv(). Also, it's required to modify _send_to_peer_handler() for
|
||||
* parsing an auxiliary sock_udp_ep_t variable from the dls session.
|
||||
*/
|
||||
typedef struct {
|
||||
sock_udp_t *sock;
|
||||
sock_udp_ep_t *remote;
|
||||
} dtls_remote_peer_t;
|
||||
|
||||
static const unsigned char ecdsa_pub_key_x[] = {
|
||||
0xD0, 0x55, 0xEE, 0x14, 0x08, 0x4D, 0x6E, 0x06,
|
||||
0x15, 0x59, 0x9D, 0xB5, 0x83, 0x91, 0x3E, 0x4A,
|
||||
0x3E, 0x45, 0x26, 0xA2, 0x70, 0x4D, 0x61, 0xF2,
|
||||
0x7A, 0x4C, 0xCF, 0xBA, 0x97, 0x58, 0xEF, 0x9A
|
||||
};
|
||||
|
||||
static const unsigned char ecdsa_pub_key_y[] = {
|
||||
0xB4, 0x18, 0xB6, 0x4A, 0xFE, 0x80, 0x30, 0xDA,
|
||||
0x1D, 0xDC, 0xF4, 0xF4, 0x2E, 0x2F, 0x26, 0x31,
|
||||
0xD0, 0x43, 0xB1, 0xFB, 0x03, 0xE2, 0x2F, 0x4D,
|
||||
0x17, 0xDE, 0x43, 0xF9, 0xF9, 0xAD, 0xEE, 0x70
|
||||
};
|
||||
|
||||
|
||||
static gnrc_netreg_entry_t server = GNRC_NETREG_ENTRY_INIT_PID(
|
||||
GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
KERNEL_PID_UNDEF);
|
||||
static kernel_pid_t _dtls_server_pid = KERNEL_PID_UNDEF;
|
||||
|
||||
#define READER_QUEUE_SIZE (8U)
|
||||
char _server_stack[THREAD_STACKSIZE_MAIN + THREAD_EXTRA_STACKSIZE_PRINTF];
|
||||
|
||||
static kernel_pid_t _dtls_kernel_pid;
|
||||
|
||||
/**
|
||||
* @brief This care about getting messages and continue with the DTLS flights
|
||||
*/
|
||||
static void dtls_handle_read(dtls_context_t *ctx, gnrc_pktsnip_t *pkt)
|
||||
{
|
||||
|
||||
static session_t session;
|
||||
|
||||
/*
|
||||
* NOTE: GNRC (Non-socket) issue: we need to modify the current
|
||||
* DTLS Context for the IPv6 src (and in a future the port src).
|
||||
*/
|
||||
|
||||
/* Taken from the tftp server example */
|
||||
char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
gnrc_pktsnip_t *tmp2;
|
||||
|
||||
tmp2 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
|
||||
ipv6_hdr_t *hdr = (ipv6_hdr_t *)tmp2->data;
|
||||
|
||||
ipv6_addr_to_str(addr_str, &hdr->src, sizeof(addr_str));
|
||||
/* This is unique to the server (Non-socket) */
|
||||
ctx->app = addr_str;
|
||||
|
||||
/*
|
||||
* TODO: More testings with TinyDTLS is neccesary, but seem this is safe.
|
||||
*/
|
||||
tmp2 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_UDP);
|
||||
udp_hdr_t *udp = (udp_hdr_t *)tmp2->data;
|
||||
|
||||
session.size = sizeof(ipv6_addr_t) + sizeof(unsigned short);
|
||||
session.port = byteorder_ntohs(udp->src_port);
|
||||
|
||||
ipv6_addr_from_str(&session.addr, addr_str);
|
||||
|
||||
dtls_handle_message(ctx, &session, pkt->data, (unsigned int)pkt->size);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief We got the TinyDTLS App Data message and answer with the same
|
||||
*/
|
||||
static int read_from_peer(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *data, size_t len)
|
||||
{
|
||||
|
||||
|
||||
#if ENABLE_DEBUG == 1
|
||||
size_t i;
|
||||
DEBUG("\nDBG-Server: Data from Client: ---");
|
||||
for (i = 0; i < len; i++)
|
||||
DEBUG("%c", data[i]);
|
||||
DEBUG("--- \t Sending echo..\n");
|
||||
/* NOTE: Temporary patch for tinyDTLS 0.8.6 */
|
||||
#ifndef TINYDTLS_EXTRA_BUFF
|
||||
#define TINYDTLS_EXTRA_BUFF (0U)
|
||||
#endif
|
||||
/* echo incoming application data */
|
||||
dtls_write(ctx, session, data, len);
|
||||
return 0;
|
||||
|
||||
char _dtls_server_stack[THREAD_STACKSIZE_MAIN +
|
||||
THREAD_EXTRA_STACKSIZE_PRINTF +
|
||||
TINYDTLS_EXTRA_BUFF];
|
||||
|
||||
/*
|
||||
* Handles all the packets arriving at the node and identifies those that are
|
||||
* DTLS records. Also, it determines if said DTLS record is coming from a new
|
||||
* peer or a currently established peer.
|
||||
*/
|
||||
static void dtls_handle_read(dtls_context_t *ctx)
|
||||
{
|
||||
static session_t session;
|
||||
static uint8_t packet_rcvd[DTLS_MAX_BUF];
|
||||
|
||||
assert(ctx);
|
||||
assert(dtls_get_app_data(ctx));
|
||||
|
||||
if (!ctx) {
|
||||
DEBUG("No DTLS context!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dtls_get_app_data(ctx)) {
|
||||
DEBUG("No app_data stored!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dtls_remote_peer_t *remote_peer;
|
||||
remote_peer = (dtls_remote_peer_t *)dtls_get_app_data(ctx);
|
||||
|
||||
ssize_t res = sock_udp_recv(remote_peer->sock, packet_rcvd, DTLS_MAX_BUF,
|
||||
1 * US_PER_SEC, remote_peer->remote);
|
||||
|
||||
if (res <= 0) {
|
||||
if ((ENABLE_DEBUG) && (res != -EAGAIN) && (res != -ETIMEDOUT)) {
|
||||
DEBUG("sock_udp_recv unexepcted code error: %i\n", (int)res);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG("DBG-Server: Record Rcvd\n");
|
||||
|
||||
/* (DTLS) session requires the remote peer address (IPv6:Port) and netif */
|
||||
session.size = sizeof(uint8_t) * 16 + sizeof(unsigned short);
|
||||
session.port = remote_peer->remote->port;
|
||||
if (remote_peer->remote->netif == SOCK_ADDR_ANY_NETIF) {
|
||||
session.ifindex = SOCK_ADDR_ANY_NETIF;
|
||||
}
|
||||
else {
|
||||
session.ifindex = remote_peer->remote->netif;
|
||||
}
|
||||
|
||||
if (memcpy(&session.addr, &remote_peer->remote->addr.ipv6, 16) == NULL) {
|
||||
puts("ERROR: memcpy failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
dtls_handle_message(ctx, &session, packet_rcvd, (int)DTLS_MAX_BUF);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This will try to transmit using only GNRC stack (non-socket).
|
||||
*/
|
||||
static int gnrc_sending(char *addr_str, char *data, size_t data_len, unsigned short rem_port )
|
||||
/* Reception of a DTLS Application data record. */
|
||||
static int _read_from_peer_handler(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *data, size_t len)
|
||||
{
|
||||
int iface;
|
||||
ipv6_addr_t addr;
|
||||
gnrc_pktsnip_t *payload, *udp, *ip;
|
||||
size_t i;
|
||||
|
||||
/* get interface, if available */
|
||||
iface = ipv6_addr_split_iface(addr_str);
|
||||
if ((iface < 0) && (gnrc_netif_numof() == 1)) {
|
||||
iface = gnrc_netif_iter(NULL)->pid;
|
||||
}
|
||||
/* parse destination address */
|
||||
if (ipv6_addr_from_str(&addr, addr_str) == NULL) {
|
||||
puts("Error: unable to parse destination address");
|
||||
return -1;
|
||||
printf("\nServer: got DTLS Data App: --- ");
|
||||
for (i = 0; i < len; i++) {
|
||||
printf("%c", data[i]);
|
||||
}
|
||||
puts(" ---\t(echo!)");
|
||||
|
||||
payload = gnrc_pktbuf_add(NULL, data, data_len, GNRC_NETTYPE_UNDEF);
|
||||
/* echo back the application data rcvd. */
|
||||
return dtls_write(ctx, session, data, len);
|
||||
}
|
||||
|
||||
if (payload == NULL) {
|
||||
puts("Error: unable to copy data to packet buffer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allocate UDP header */
|
||||
udp = gnrc_udp_hdr_build(payload, DEFAULT_PORT, rem_port);
|
||||
if (udp == NULL) {
|
||||
puts("Error: unable to allocate UDP header");
|
||||
gnrc_pktbuf_release(payload);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allocate IPv6 header */
|
||||
ip = gnrc_ipv6_hdr_build(udp, NULL, &addr);
|
||||
if (ip == NULL) {
|
||||
puts("Error: unable to allocate IPv6 header");
|
||||
gnrc_pktbuf_release(udp);
|
||||
return -1;
|
||||
}
|
||||
/* add netif header, if interface was given */
|
||||
if (iface > 0) {
|
||||
gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
|
||||
((gnrc_netif_hdr_t *)netif->data)->if_pid = (kernel_pid_t)iface;
|
||||
LL_PREPEND(ip, netif);
|
||||
}
|
||||
/* send packet */
|
||||
|
||||
DEBUG("DBG-Server: Sending record to peer\n");
|
||||
/* Handles the DTLS communication with the other peer. */
|
||||
static int _send_to_peer_handler(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *buf, size_t len)
|
||||
{
|
||||
|
||||
/*
|
||||
* WARNING: Too fast and the nodes dies in middle of retransmissions.
|
||||
* This issue appears in the FIT-Lab (m3 motes).
|
||||
* It's possible to create a sock_udp_ep_t variable. But, it's required
|
||||
* to copy memory from the session variable to it.
|
||||
*/
|
||||
xtimer_usleep(500000);
|
||||
|
||||
/* Probably this part will be removed. **/
|
||||
if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_UDP, GNRC_NETREG_DEMUX_CTX_ALL, ip)) {
|
||||
puts("Error: unable to locate UDP thread");
|
||||
gnrc_pktbuf_release(ip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief We communicate with the other peer.
|
||||
*/
|
||||
static int send_to_peer(struct dtls_context_t *ctx,
|
||||
session_t *session, uint8 *buf, size_t len)
|
||||
{
|
||||
|
||||
(void) session;
|
||||
|
||||
/*FIXME TODO: dtls_get_app_data(ctx) should have the remote port! */
|
||||
char *addr_str;
|
||||
addr_str = (char *)dtls_get_app_data(ctx);
|
||||
assert(ctx);
|
||||
assert(dtls_get_app_data(ctx));
|
||||
|
||||
gnrc_sending(addr_str, (char *)buf, len, session->port);
|
||||
if (!dtls_get_app_data(ctx)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
dtls_remote_peer_t *remote_peer;
|
||||
remote_peer = (dtls_remote_peer_t *)dtls_get_app_data(ctx);
|
||||
|
||||
DEBUG("DBG-Server: Sending record\n");
|
||||
|
||||
return sock_udp_send(remote_peer->sock, buf, len, remote_peer->remote);
|
||||
}
|
||||
|
||||
#ifdef DTLS_PSK
|
||||
/* This function is the "key store" for tinyDTLS. It is called to
|
||||
* retrieve a key for the given identity within this particular
|
||||
* session. */
|
||||
static int peer_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)
|
||||
{
|
||||
static unsigned char psk_id[PSK_ID_MAXLEN] = PSK_DEFAULT_IDENTITY;
|
||||
static size_t psk_id_length = sizeof(PSK_DEFAULT_IDENTITY) - 1;
|
||||
static unsigned char psk_key[PSK_MAXLEN] = PSK_DEFAULT_KEY;
|
||||
static size_t psk_key_length = sizeof(PSK_DEFAULT_KEY) - 1;
|
||||
|
||||
/*
|
||||
* This function is the "key store" for tinyDTLS. It is called to retrieve a
|
||||
* key for the given identity within this particular session.
|
||||
*/
|
||||
static int _peer_get_psk_info_handler(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)
|
||||
{
|
||||
(void) ctx;
|
||||
(void) session;
|
||||
|
||||
struct keymap_t {
|
||||
unsigned char *id;
|
||||
size_t id_length;
|
||||
unsigned char *key;
|
||||
size_t key_length;
|
||||
} psk[3] = {
|
||||
{ (unsigned char *)"Client_identity", 15,
|
||||
(unsigned char *)"secretPSK", 9 },
|
||||
{ (unsigned char *)psk_id, psk_id_length,
|
||||
(unsigned char *)psk_key, psk_key_length },
|
||||
{ (unsigned char *)"default identity", 16,
|
||||
(unsigned char *)"\x11\x22\x33", 3 },
|
||||
{ (unsigned char *)"\0", 2,
|
||||
@ -258,7 +209,7 @@ static int peer_get_psk_info(struct dtls_context_t *ctx, const session_t *sessio
|
||||
}
|
||||
|
||||
if (id) {
|
||||
unsigned int i;
|
||||
uint8_t i;
|
||||
for (i = 0; i < sizeof(psk) / sizeof(struct keymap_t); i++) {
|
||||
if (id_len == psk[i].id_length && memcmp(id, psk[i].id, id_len) == 0) {
|
||||
if (result_length < psk[i].key_length) {
|
||||
@ -277,9 +228,9 @@ static int peer_get_psk_info(struct dtls_context_t *ctx, const session_t *sessio
|
||||
#endif /* DTLS_PSK */
|
||||
|
||||
#ifdef DTLS_ECC
|
||||
static int peer_get_ecdsa_key(struct dtls_context_t *ctx,
|
||||
const session_t *session,
|
||||
const dtls_ecdsa_key_t **result)
|
||||
static int _peer_get_ecdsa_key_handler(struct dtls_context_t *ctx,
|
||||
const session_t *session,
|
||||
const dtls_ecdsa_key_t **result)
|
||||
{
|
||||
(void) ctx;
|
||||
(void) session;
|
||||
@ -290,162 +241,184 @@ static int peer_get_ecdsa_key(struct dtls_context_t *ctx,
|
||||
.pub_key_y = ecdsa_pub_key_y
|
||||
};
|
||||
|
||||
/* TODO: Load the key from external source */
|
||||
|
||||
*result = &ecdsa_key;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int peer_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)
|
||||
static int _peer_verify_ecdsa_key_handler(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_x;
|
||||
(void) other_pub_y;
|
||||
(void) key_size;
|
||||
|
||||
/* TODO: As far for tinyDTLS 0.8.2 this is not used */
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* DTLS_ECC */
|
||||
|
||||
/**
|
||||
* @brief We prepare the DTLS for this node.
|
||||
*/
|
||||
static void init_dtls(void)
|
||||
/* DTLS variables and register are initialized. */
|
||||
dtls_context_t *_server_init_dtls(dtls_remote_peer_t *remote_peer)
|
||||
{
|
||||
dtls_context_t *new_context = NULL;
|
||||
|
||||
static dtls_handler_t cb = {
|
||||
.write = send_to_peer,
|
||||
.read = read_from_peer,
|
||||
.write = _send_to_peer_handler,
|
||||
.read = _read_from_peer_handler,
|
||||
.event = NULL,
|
||||
#ifdef DTLS_PSK
|
||||
.get_psk_info = peer_get_psk_info,
|
||||
.get_psk_info = _peer_get_psk_info_handler,
|
||||
#endif /* DTLS_PSK */
|
||||
#ifdef DTLS_ECC
|
||||
.get_ecdsa_key = peer_get_ecdsa_key,
|
||||
.verify_ecdsa_key = peer_verify_ecdsa_key
|
||||
.get_ecdsa_key = _peer_get_ecdsa_key_handler,
|
||||
.verify_ecdsa_key = _peer_verify_ecdsa_key_handler
|
||||
#endif /* DTLS_ECC */
|
||||
};
|
||||
|
||||
|
||||
#ifdef DTLS_PSK
|
||||
puts("Server support PSK");
|
||||
DEBUG("Server support PSK\n");
|
||||
#endif
|
||||
#ifdef DTLS_ECC
|
||||
puts("Server support ECC");
|
||||
DEBUG("Server support ECC\n");
|
||||
#endif
|
||||
|
||||
DEBUG("DBG-Server On\n");
|
||||
#ifdef TINYDTLS_LOG_LVL
|
||||
dtls_set_log_level(TINYDTLS_LOG_LVL);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The context for the server is a little different from the client.
|
||||
* The simplicity of GNRC do not mix transparently with
|
||||
* the DTLS Context. At this point, the server need a fresh context
|
||||
* however dtls_context->app must be populated with an unknown
|
||||
* IPv6 address.
|
||||
*
|
||||
* The non-valid Ipv6 address ( :: ) is discarded due the chaos.
|
||||
* For now, the first value will be the loopback.
|
||||
* The context for the server is different from the client.
|
||||
* This is because sock_udp_create() cannot work with a remote endpoint
|
||||
* with port set to 0. And even after sock_udp_recv(), sock_udp_get_remote()
|
||||
* cannot retrieve the remote.
|
||||
*/
|
||||
char *addr_str = "::1";
|
||||
new_context = dtls_new_context(remote_peer);
|
||||
|
||||
/*akin to syslog: EMERG, ALERT, CRITC, NOTICE, INFO, DEBUG */
|
||||
dtls_set_log_level(DTLS_LOG_DEBUG);
|
||||
|
||||
|
||||
dtls_context = dtls_new_context(addr_str);
|
||||
if (dtls_context) {
|
||||
dtls_set_handler(dtls_context, &cb);
|
||||
if (new_context) {
|
||||
dtls_set_handler(new_context, &cb);
|
||||
}
|
||||
else {
|
||||
puts("Server was unable to generate DTLS Context!");
|
||||
exit(-1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return new_context;
|
||||
}
|
||||
|
||||
/* NOTE: wrapper or trampoline ? (Syntax question) */
|
||||
|
||||
void *dtls_server_wrapper(void *arg)
|
||||
void *_dtls_server_wrapper(void *arg)
|
||||
{
|
||||
(void) arg; /* TODO: Remove? We don't have args at all (NULL) */
|
||||
(void) arg;
|
||||
|
||||
bool active = true;
|
||||
msg_t _reader_queue[READER_QUEUE_SIZE];
|
||||
msg_t msg;
|
||||
|
||||
/* The GNRC examples uses packet dump but we want a custom one */
|
||||
sock_udp_t udp_socket;
|
||||
sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
|
||||
sock_udp_ep_t remote = SOCK_IPV6_EP_ANY;
|
||||
|
||||
dtls_context_t *dtls_context = NULL;
|
||||
dtls_remote_peer_t remote_peer;
|
||||
|
||||
remote_peer.sock = &udp_socket;
|
||||
remote_peer.remote = &remote;
|
||||
|
||||
/* Prepare (thread) messages reception */
|
||||
msg_init_queue(_reader_queue, READER_QUEUE_SIZE);
|
||||
|
||||
init_dtls();
|
||||
/* NOTE: dtls_init() must be called previous to this (see main.c) */
|
||||
|
||||
/*
|
||||
* FIXME: After mutliple retransmissions, and canceled client's sessions
|
||||
* the server become unable to sent NDP NA messages. Still, the TinyDTLS
|
||||
* debugs seems to be fine.
|
||||
*/
|
||||
local.port = DTLS_DEFAULT_PORT;
|
||||
ssize_t res = sock_udp_create(&udp_socket, &local, NULL, 0);
|
||||
if (res == -1) {
|
||||
puts("ERROR: Unable create sock.");
|
||||
return (void *) NULL;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
dtls_context = _server_init_dtls(&remote_peer);
|
||||
|
||||
/* wait for a message */
|
||||
msg_receive(&msg);
|
||||
if (!dtls_context) {
|
||||
puts("ERROR: Server unable to load context!");
|
||||
return (void *) NULL;
|
||||
}
|
||||
|
||||
DEBUG("DBG-Server: Record Rcvd!\n");
|
||||
dtls_handle_read(dtls_context, (gnrc_pktsnip_t *)(msg.content.ptr));
|
||||
while (active) {
|
||||
|
||||
/*TODO: What happens with other clients connecting at the same time? */
|
||||
msg_try_receive(&msg); /* Check if we got an (thread) message */
|
||||
if (msg.type == DTLS_STOP_SERVER_MSG) {
|
||||
active = false;
|
||||
}
|
||||
else {
|
||||
/* Listening for any DTLS recodrd */
|
||||
dtls_handle_read(dtls_context);
|
||||
}
|
||||
}
|
||||
|
||||
} /*While */
|
||||
/* Release resources (strict order) */
|
||||
dtls_free_context(dtls_context); /* This also sends a DTLS Alert record */
|
||||
sock_udp_close(&udp_socket);
|
||||
msg_reply(&msg, &msg); /* Basic answer to the main thread */
|
||||
|
||||
dtls_free_context(dtls_context);
|
||||
return (void *) NULL;
|
||||
}
|
||||
|
||||
static void start_server(void)
|
||||
{
|
||||
uint16_t port;
|
||||
|
||||
port = (uint16_t)DEFAULT_PORT;
|
||||
|
||||
(void) _dtls_kernel_pid;
|
||||
|
||||
/* Only one instance of the server */
|
||||
if (server.target.pid != KERNEL_PID_UNDEF) {
|
||||
printf("Error: server already running\n");
|
||||
if (_dtls_server_pid != KERNEL_PID_UNDEF) {
|
||||
puts("Error: server already running");
|
||||
return;
|
||||
}
|
||||
|
||||
/*TESTING tinydtls*/
|
||||
dtls_init();
|
||||
/* The server is initialized */
|
||||
_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");
|
||||
|
||||
/* The server is initialized */
|
||||
server.target.pid = thread_create(_server_stack, sizeof(_server_stack),
|
||||
THREAD_PRIORITY_MAIN - 1,
|
||||
THREAD_CREATE_STACKTEST,
|
||||
dtls_server_wrapper, NULL, "DTLS Server");
|
||||
/* Uncommon but better be sure */
|
||||
if (_dtls_server_pid == EINVAL) {
|
||||
puts("ERROR: Thread invalid");
|
||||
_dtls_server_pid = KERNEL_PID_UNDEF;
|
||||
return;
|
||||
}
|
||||
|
||||
server.demux_ctx = (uint32_t)port;
|
||||
if (_dtls_server_pid == EOVERFLOW) {
|
||||
puts("ERROR: Thread overflow!");
|
||||
_dtls_server_pid = KERNEL_PID_UNDEF;
|
||||
return;
|
||||
}
|
||||
|
||||
if (gnrc_netreg_register(GNRC_NETTYPE_UDP, &server) == 0)
|
||||
printf("Success: started DTLS server on port %" PRIu16 "\n", port);
|
||||
else
|
||||
printf("FAILURE: The UDP port is not registered!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static void stop_server(void)
|
||||
{
|
||||
/* check if server is running at all */
|
||||
if (server.target.pid == KERNEL_PID_UNDEF) {
|
||||
printf("Error: server was not running\n");
|
||||
if (_dtls_server_pid == KERNEL_PID_UNDEF) {
|
||||
puts("Error: DTLS server is not running");
|
||||
return;
|
||||
}
|
||||
|
||||
dtls_free_context(dtls_context);
|
||||
/* prepare the stop message */
|
||||
msg_t m;
|
||||
m.type = DTLS_STOP_SERVER_MSG;
|
||||
|
||||
/* stop server */
|
||||
gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &server);
|
||||
server.target.pid = KERNEL_PID_UNDEF;
|
||||
puts("Success: stopped DTLS server");
|
||||
DEBUG("Stopping server...\n");
|
||||
|
||||
/* 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 udp_server_cmd(int argc, char **argv)
|
||||
@ -461,7 +434,7 @@ int udp_server_cmd(int argc, char **argv)
|
||||
stop_server();
|
||||
}
|
||||
else {
|
||||
puts("error: invalid command");
|
||||
printf("Error: invalid command. Usage: %s start|stop\n", argv[0]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freie Universität Berlin
|
||||
* 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
|
||||
@ -19,32 +20,27 @@
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "msg.h"
|
||||
|
||||
#include "dtls.h"
|
||||
|
||||
|
||||
/*TinyDTLS WARNING check*/
|
||||
/* TinyDTLS WARNING check */
|
||||
#ifdef WITH_RIOT_SOCKETS
|
||||
#error TinyDTLS is configured for working with Sockets. Yet, this is non-socket
|
||||
#error TinyDTLS is set to use sockets but the app is configured for socks.
|
||||
#endif
|
||||
|
||||
#define MAIN_QUEUE_SIZE (8)
|
||||
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
|
||||
|
||||
/*
|
||||
* Altough the server and client cna be in a simple file.
|
||||
* Is more friendly to divide them
|
||||
*/
|
||||
extern int udp_client_cmd(int argc, char **argv);
|
||||
extern int udp_server_cmd(int argc, char **argv);
|
||||
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "dtlsc", "Start a DTLS client", udp_client_cmd },
|
||||
{ "dtlss", "Start a DTLS server (with echo)", udp_server_cmd },
|
||||
{ "dtlss", "Start and stop a DTLS server", udp_server_cmd },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@ -55,6 +51,9 @@ int main(void)
|
||||
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
|
||||
puts("RIOT (Tiny)DTLS testing implementation");
|
||||
|
||||
/* TinyDTLS settings (Universal and called only one time by reboot) */
|
||||
dtls_init();
|
||||
|
||||
/* start shell */
|
||||
puts("All up, running the shell now");
|
||||
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||
|
||||
66
examples/dtls-echo/tinydtls_keys.h
Normal file
66
examples/dtls-echo/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-echo 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 */
|
||||
@ -1,7 +1,6 @@
|
||||
PKG_NAME=tinydtls
|
||||
PKG_URL=https://github.com/rfuentess/TinyDTLS.git
|
||||
# PKG_VERSION=RIOT-OS
|
||||
PKG_VERSION=eb6f017ab451bb6cc4428b3e449955a76aeeba19
|
||||
PKG_URL=https://git.eclipse.org/r/tinydtls/org.eclipse.tinydtls
|
||||
PKG_VERSION=84f1f4e3ca13101a5a9aedeaf08039636c4f34dd
|
||||
PKG_LICENSE=EPL-1.0,EDL-1.0
|
||||
|
||||
CFLAGS += -Wno-implicit-fallthrough
|
||||
@ -15,7 +14,6 @@ all: git-download
|
||||
@cp $(PKG_BUILDDIR)/Makefile.riot $(PKG_BUILDDIR)/Makefile
|
||||
@cp $(PKG_BUILDDIR)/aes/Makefile.riot $(PKG_BUILDDIR)/aes/Makefile
|
||||
@cp $(PKG_BUILDDIR)/ecc/Makefile.riot $(PKG_BUILDDIR)/ecc/Makefile
|
||||
@cp $(PKG_BUILDDIR)/sha2/Makefile.riot $(PKG_BUILDDIR)/sha2/Makefile
|
||||
"$(MAKE)" -C $(PKG_BUILDDIR)
|
||||
|
||||
include $(RIOTBASE)/pkg/pkg.mk
|
||||
|
||||
@ -3,7 +3,8 @@ ifneq (,$(filter tinydtls,$(USEPKG)))
|
||||
endif
|
||||
|
||||
ifneq (,$(filter tinydtls,$(USEMODULE)))
|
||||
USEMODULE += memarray
|
||||
USEMODULE += hashes
|
||||
USEMODULE += tinydtls_aes
|
||||
USEMODULE += tinydtls_ecc
|
||||
USEMODULE += tinydtls_sha2
|
||||
endif
|
||||
|
||||
@ -6,6 +6,39 @@ ifeq ($(TOOLCHAIN), llvm)
|
||||
CFLAGS += -Wno-gnu-zero-variadic-macro-arguments -Wno-unused-function
|
||||
endif
|
||||
|
||||
ifneq (,$(filter tinydtls,$(USEMODULE)))
|
||||
INCLUDES += -I$(PKG_BUILDDIR)
|
||||
# Mandatory for tinyDTLS
|
||||
CFLAGS += -DDTLSv12 -DWITH_SHA256
|
||||
|
||||
# Dependencies partially under control of the App's requirements
|
||||
|
||||
# The configuration for socket overrides Sock
|
||||
ifeq (,$(filter WITH_RIOT_SOCKETS,$(CFLAGS)))
|
||||
CFLAGS += -DWITH_RIOT_GNRC
|
||||
endif
|
||||
|
||||
# NOTE: PSK should be enabled by default BUT if the user define any other cipher
|
||||
# suite(s) it should not be enabled.
|
||||
# TODO: Create the flag DTLS_CIPHERS with keywords PSK, ECC (and future)
|
||||
ifeq (,$(filter -DDTLS_PSK,$(CFLAGS)))
|
||||
ifeq (,$(filter -DDTLS_ECC,$(CFLAGS)))
|
||||
CFLAGS += -DDTLS_PSK
|
||||
endif
|
||||
endif
|
||||
|
||||
# Handles the verbosity of tinyDTLS. Default: Minimum or just error messages.
|
||||
ifeq (,$(filter -DTINYDTLS_DEBUG,$(CFLAGS)))
|
||||
ifeq ( , $(TINYDTLS_LOG))
|
||||
CFLAGS += -DTINYDTLS_LOG_LVL=0
|
||||
else
|
||||
CFLAGS += -DTINYDTLS_LOG_LVL=$(TINYDTLS_LOG)
|
||||
endif
|
||||
else
|
||||
CFLAGS += -DTINYDTLS_LOG_LVL=6
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(filter tinydtls_aes,$(USEMODULE)))
|
||||
DIRS += $(PKG_BUILDDIR)/aes
|
||||
endif
|
||||
@ -13,7 +46,3 @@ endif
|
||||
ifneq (,$(filter tinydtls_ecc,$(USEMODULE)))
|
||||
DIRS += $(PKG_BUILDDIR)/ecc
|
||||
endif
|
||||
|
||||
ifneq (,$(filter tinydtls_sha2,$(USEMODULE)))
|
||||
DIRS += $(PKG_BUILDDIR)/sha2
|
||||
endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user