zephyr/samples/net/dtls_server/src/dtls-server.c

421 lines
9.9 KiB
C

/* dtls-server.c - dtls server */
/*
* Copyright (c) 2015 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(CONFIG_STDOUT_CONSOLE)
#include <stdio.h>
#define PRINT printf
#else
#include <misc/printk.h>
#define PRINT printk
#endif
#include <zephyr.h>
#include <errno.h>
#include <net/ip_buf.h>
#include <net/net_core.h>
#include <net/net_socket.h>
#include <net/tinydtls.h>
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};
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};
/* The peer is the client in our case. Just invent a mac
* address for it because lower parts of the stack cannot set it
* in this test as we do not have any radios.
*/
//static uint8_t peer_mac[] = { 0x15, 0x0a, 0xbe, 0xef, 0xf0, 0x0d };
/* This is my mac address
*/
static uint8_t my_mac[] = { 0x0a, 0xbe, 0xef, 0x15, 0xf0, 0x0d };
#ifdef CONFIG_NETWORKING_WITH_IPV6
/* The 2001:db8::/32 is the private address space for documentation RFC 3849 */
#define MY_IPADDR { { { 0x20,0x01,0x0d,0xb8,0,0,0,0,0,0,0,0,0,0,0,0x2 } } }
#else
/* The 192.0.2.0/24 is the private address space for documentation RFC 5737 */
#define MY_IPADDR { { { 192,0,2,2 } } }
#endif
#define MY_PORT 4242
#ifdef CONFIG_NETWORKING_WITH_IPV6
static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
static struct in6_addr in6addr_my = MY_IPADDR;
#else
static const struct in_addr in4addr_any = { { { 0 } } };
static struct in_addr in4addr_my = MY_IPADDR;
#endif
static inline void init_server()
{
PRINT("%s: run dtls server\n", __func__);
net_set_mac(my_mac, sizeof(my_mac));
#ifdef CONFIG_NETWORKING_WITH_IPV4
{
uip_ipaddr_t addr;
uip_ipaddr(&addr, 192,0,2,2);
uip_sethostaddr(&addr);
}
#else
{
uip_ipaddr_t *addr;
addr = (uip_ipaddr_t *)&in6addr_my;
uip_ds6_addr_add(addr, 0, ADDR_MANUAL);
}
#endif
}
static inline void reverse(unsigned char *buf, int len)
{
int i, last = len - 1;
for (i = 0; i < len / 2; i++) {
unsigned char tmp = buf[i];
buf[i] = buf[last - i];
buf[last - i] = tmp;
}
}
/* How many tics to wait for a network packet */
#if 0
#define WAIT_TIME 1
#define WAIT_TICKS (WAIT_TIME * sys_clock_ticks_per_sec)
#else
#define WAIT_TICKS TICKS_UNLIMITED
#endif
static inline void receive_message(const char *name,
struct net_context *recv,
dtls_context_t *dtls)
{
struct net_buf *buf;
buf = net_receive(recv, WAIT_TICKS);
if (buf) {
session_t session;
dtls_session_init(&session);
uip_ipaddr_copy(&session.addr.ipaddr,
&NET_BUF_IP(buf)->srcipaddr);
session.addr.port = NET_BUF_UDP(buf)->srcport;
PRINT("Received data %p datalen %d\n",
ip_buf_appdata(buf), ip_buf_appdatalen(buf));
dtls_handle_message(dtls, &session, ip_buf_appdata(buf),
ip_buf_appdatalen(buf));
/* We never send the buffer by this function. A network buffer
* to be sent is allocated in send_to_peer() that is
* responsible for sending the data.
*/
ip_buf_unref(buf);
}
}
static inline struct net_context *get_context(void)
{
static struct net_addr any_addr;
static struct net_addr my_addr;
struct net_context *ctx;
#ifdef CONFIG_NETWORKING_WITH_IPV6
any_addr.in6_addr = in6addr_any;
any_addr.family = AF_INET6;
my_addr.in6_addr = in6addr_my;
my_addr.family = AF_INET6;
#else
any_addr.in_addr = in4addr_any;
any_addr.family = AF_INET;
my_addr.in_addr = in4addr_my;
my_addr.family = AF_INET;
#endif
ctx = net_context_get(IPPROTO_UDP,
&any_addr, 0,
&my_addr, MY_PORT);
if (!ctx) {
PRINT("%s: Cannot get network context\n", __func__);
return NULL;
}
return ctx;
}
static int read_from_peer(struct dtls_context_t *ctx,
session_t *session,
uint8 *data, size_t len)
{
PRINT("%s: read from peer %p len %d\n", __func__, data, len);
/* In this test we reverse the received bytes.
* We could also just pass the data back as is.
*/
reverse(data, len);
/* echo incoming application data */
return dtls_write(ctx, session, data, len);
}
static int send_to_peer(struct dtls_context_t *ctx,
session_t *session,
uint8 *data, size_t len)
{
struct net_context *recv =
(struct net_context *)dtls_get_app_data(ctx);
struct net_buf *buf;
int max_data_len;
uint8_t *ptr;
buf = ip_buf_get_tx(recv);
if (!buf) {
len = -ENOBUFS;
goto out;
}
max_data_len = IP_BUF_MAX_DATA - sizeof(struct uip_udp_hdr) -
sizeof(struct uip_ip_hdr);
PRINT("%s: reply to peer data %p len %d\n", __func__, data, len);
if (len > max_data_len) {
PRINT("%s: too much (%d bytes) data to send (max %d bytes)\n",
__func__, len, max_data_len);
ip_buf_unref(buf);
len = -EINVAL;
goto out;
}
/* Note that we have reversed the addresses here
* because net_reply() will reverse them again.
*/
#ifdef CONFIG_NETWORKING_WITH_IPV6
uip_ip6addr_copy(&NET_BUF_IP(buf)->destipaddr,
(uip_ip6addr_t *)&in6addr_my);
uip_ip6addr_copy(&NET_BUF_IP(buf)->srcipaddr,
(uip_ip6addr_t *)&session->addr.ipaddr);
#else
uip_ip4addr_copy(&NET_BUF_IP(buf)->destipaddr,
(uip_ip4addr_t *)&in4addr_my);
uip_ip4addr_copy(&NET_BUF_IP(buf)->srcipaddr,
(uip_ip4addr_t *)&session->addr.ipaddr);
#endif
NET_BUF_UDP(buf)->destport = uip_ntohs(MY_PORT);
NET_BUF_UDP(buf)->srcport = session->addr.port;
uip_set_udp_conn(buf) = net_context_get_udp_connection(recv);
ptr = net_buf_add(buf, len);
memcpy(ptr, data, len);
ip_buf_appdata(buf) = ptr;
ip_buf_appdatalen(buf) = len;
if (net_reply(recv, buf)) {
ip_buf_unref(buf);
}
out:
return len;
}
#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 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)
{
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 *)"default identity", 16,
(unsigned char *)"\x11\x22\x33", 3 },
{ (unsigned char *)"\0", 2,
(unsigned char *)"", 1 }
};
if (type != DTLS_PSK_KEY) {
return 0;
}
if (id) {
int 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) {
dtls_warn("buffer too small for PSK");
return dtls_alert_fatal_create(
DTLS_ALERT_INTERNAL_ERROR);
}
memcpy(result, psk[i].key, psk[i].key_length);
return psk[i].key_length;
}
}
}
return dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
}
#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 const dtls_ecdsa_key_t ecdsa_key = {
.curve = DTLS_ECDH_CURVE_SECP256R1,
.priv_key = ecdsa_priv_key,
.pub_key_x = ecdsa_pub_key_x,
.pub_key_y = ecdsa_pub_key_y
};
*result = &ecdsa_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)
{
return 0;
}
#endif /* DTLS_ECC */
static int handle_event(struct dtls_context_t *ctx, session_t *session,
dtls_alert_level_t level, unsigned short code)
{
dtls_debug("event: level %d code %d\n", level, code);
if (level > 0) {
/* alert code, quit */
} else if (level == 0) {
/* internal event */
if (code == DTLS_EVENT_CONNECTED) {
PRINT("*** Connected ***\n");
}
}
return 0;
}
static void init_dtls(struct net_context *recv, dtls_context_t **dtls)
{
static dtls_handler_t cb = {
.write = send_to_peer,
.read = read_from_peer,
.event = handle_event,
#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 */
};
PRINT("DTLS server started\n");
#ifdef CONFIG_TINYDTLS_DEBUG
dtls_set_log_level(DTLS_LOG_DEBUG);
#endif
*dtls = dtls_new_context(recv);
if (*dtls) {
dtls_set_handler(*dtls, &cb);
}
}
void startup(void)
{
static dtls_context_t *dtls;
static struct net_context *recv;
net_init();
dtls_init();
init_server();
recv = get_context();
if (!recv) {
PRINT("%s: Cannot get network context\n", __func__);
return;
}
init_dtls(recv, &dtls);
if (!dtls) {
PRINT("%s: Cannot get DTLS context\n", __func__);
return;
}
while (1) {
receive_message(__func__, recv, dtls);
}
}
#ifdef CONFIG_NANOKERNEL
#define STACKSIZE 3000
char fiberStack[STACKSIZE];
void main(void)
{
fiber_start(&fiberStack[0], STACKSIZE,
(nano_fiber_entry_t)startup, 0, 0, 7, 0);
}
#endif /* CONFIG_MICROKERNEL || CONFIG_NANOKERNEL */