337 lines
8.9 KiB
C
337 lines
8.9 KiB
C
|
|
/* This is needed for apple */
|
|
#define __APPLE_USE_RFC_3542
|
|
|
|
#include "printf.h"
|
|
#include <assert.h>
|
|
//#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
|
|
#include <lwip/sockets.h>
|
|
#include <lwip/netdb.h>
|
|
#include "lwip.h"
|
|
|
|
#include "tinydtls.h"
|
|
#include "dtls.h"
|
|
#include "dtls_debug.h"
|
|
|
|
#define DEFAULT_PORT 20220
|
|
|
|
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
|
|
};
|
|
|
|
/* SIGINT handler: set quit to 1 for graceful termination */
|
|
static void
|
|
handle_sigint(int signum)
|
|
{
|
|
// dsrv_stop(dsrv_get_context());
|
|
}
|
|
|
|
#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 */
|
|
|
|
#define DTLS_SERVER_CMD_CLOSE "server:close"
|
|
#define DTLS_SERVER_CMD_RENEGOTIATE "server:renegotiate"
|
|
|
|
static int dtls_event_cb(struct dtls_context_t *ctx, session_t *session,
|
|
dtls_alert_level_t level, unsigned short code)
|
|
{
|
|
printf("dtls_event_cb->%d,%d\n", level, code);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
read_from_peer(struct dtls_context_t *ctx,
|
|
session_t *session, uint8 *data, size_t len)
|
|
{
|
|
size_t i;
|
|
|
|
printf("read_from_peer->%s\n", data);
|
|
|
|
if (len >= strlen(DTLS_SERVER_CMD_CLOSE) &&
|
|
!memcmp(data, DTLS_SERVER_CMD_CLOSE, strlen(DTLS_SERVER_CMD_CLOSE))) {
|
|
printf("server: closing connection\n");
|
|
dtls_close(ctx, session);
|
|
return len;
|
|
} else if (len >= strlen(DTLS_SERVER_CMD_RENEGOTIATE) &&
|
|
!memcmp(data, DTLS_SERVER_CMD_RENEGOTIATE, strlen(DTLS_SERVER_CMD_RENEGOTIATE))) {
|
|
printf("server: renegotiate connection\n");
|
|
dtls_renegotiate(ctx, session);
|
|
return len;
|
|
}
|
|
|
|
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)
|
|
{
|
|
|
|
int fd = *(int *)dtls_get_app_data(ctx);
|
|
return sendto(fd, data, len, MSG_DONTWAIT,
|
|
&session->addr.sa, session->size);
|
|
}
|
|
|
|
static int
|
|
dtls_handle_read(struct dtls_context_t *ctx)
|
|
{
|
|
int *fd;
|
|
session_t session;
|
|
static uint8 buf[DTLS_MAX_BUF];
|
|
int len;
|
|
|
|
fd = dtls_get_app_data(ctx);
|
|
|
|
assert(fd);
|
|
|
|
memset(&session, 0, sizeof(session_t));
|
|
session.size = sizeof(session.addr);
|
|
len = recvfrom(*fd, buf, sizeof(buf), 0,
|
|
&session.addr.sa, &session.size);
|
|
|
|
if (len < 0) {
|
|
printf("recvfrom");
|
|
return -1;
|
|
} else {
|
|
dtls_debug("got %d bytes from port %d\n", len,
|
|
ntohs(session.addr.sin.sin_port));
|
|
if (sizeof(buf) < len) {
|
|
dtls_warn("packet was truncated (%d bytes lost)\n", len - sizeof(buf));
|
|
}
|
|
}
|
|
|
|
return dtls_handle_message(ctx, &session, buf, len);
|
|
}
|
|
|
|
static void
|
|
usage(const char *program, const char *version)
|
|
{
|
|
const char *p;
|
|
|
|
p = strrchr(program, '/');
|
|
if (p) {
|
|
program = ++p;
|
|
}
|
|
|
|
printf("%s v%s -- DTLS server implementation\n"
|
|
"(c) 2011-2014 Olaf Bergmann <bergmann@tzi.org>\n\n"
|
|
"usage: %s [-A address] [-p port] [-v num]\n"
|
|
"\t-A address\t\tlisten on specified address (default is ::)\n"
|
|
"\t-p port\t\tlisten on specified port (default is %d)\n"
|
|
"\t-v num\t\tverbosity level (default: 3)\n",
|
|
program, version, program, DEFAULT_PORT);
|
|
}
|
|
|
|
static dtls_handler_t cb = {
|
|
.net_write = send_to_peer,
|
|
.net_read = read_from_peer,
|
|
.event = dtls_event_cb,
|
|
#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 */
|
|
};
|
|
|
|
int dtls_server_test(void)
|
|
{
|
|
dtls_context_t *the_context = NULL;
|
|
log_t log_level = DTLS_LOG_WARN;//DTLS_LOG_DEBUG;
|
|
fd_set rfds, wfds;
|
|
struct timeval timeout;
|
|
int fd, result;
|
|
int on = 1;
|
|
char ip[16];
|
|
struct sockaddr_in listen_addr;
|
|
|
|
memset(&listen_addr, 0, sizeof(struct sockaddr_in));
|
|
|
|
/* fill extra field for 4.4BSD-based systems (see RFC 3493, section 3.4) */
|
|
#if defined(SIN6_LEN) || defined(HAVE_SOCKADDR_IN6_SIN6_LEN)
|
|
listen_addr.sin6_len = sizeof(struct sockaddr_in6);
|
|
#endif
|
|
Get_IPAddress(0, ip);
|
|
listen_addr.sin_family = AF_INET;
|
|
listen_addr.sin_port = htons(DEFAULT_PORT);
|
|
listen_addr.sin_addr.s_addr = inet_addr(ip);//htonl(INADDR_ANY);
|
|
|
|
|
|
dtls_set_log_level(log_level);
|
|
|
|
/* init socket and set it to non-blocking */
|
|
fd = socket(listen_addr.sin_family, SOCK_DGRAM, 0);
|
|
|
|
if (fd < 0) {
|
|
dtls_alert("socket: %s\n", strerror(errno));
|
|
return 0;
|
|
}
|
|
|
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
|
|
dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
|
|
}
|
|
#if 0
|
|
flags = fcntl(fd, F_GETFL, 0);
|
|
if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
|
dtls_alert("fcntl: %s\n", strerror(errno));
|
|
goto error;
|
|
}
|
|
#endif
|
|
on = 1;
|
|
|
|
#if LWIP_IPV6
|
|
#ifdef IPV6_RECVPKTINFO
|
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) {
|
|
#else /* IPV6_RECVPKTINFO */
|
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) {
|
|
#endif /* IPV6_RECVPKTINFO */
|
|
dtls_alert("setsockopt IPV6_PKTINFO: %s\n", strerror(errno));
|
|
}
|
|
#endif
|
|
|
|
if (bind(fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) {
|
|
dtls_alert("bind: %s\n", strerror(errno));
|
|
goto error;
|
|
}
|
|
|
|
dtls_init();
|
|
|
|
the_context = dtls_new_context(&fd);
|
|
|
|
dtls_set_handler(the_context, &cb);
|
|
|
|
while (1) {
|
|
FD_ZERO(&rfds);
|
|
FD_ZERO(&wfds);
|
|
|
|
FD_SET(fd, &rfds);
|
|
/* FD_SET(fd, &wfds); */
|
|
|
|
timeout.tv_sec = 5;
|
|
timeout.tv_usec = 0;
|
|
|
|
result = select(fd + 1, &rfds, &wfds, 0, &timeout);
|
|
|
|
if (result < 0) { /* error */
|
|
if (errno != EINTR) {
|
|
printf("select");
|
|
}
|
|
} else if (result == 0) { /* timeout */
|
|
} else { /* ok */
|
|
if (FD_ISSET(fd, &wfds))
|
|
;
|
|
else if (FD_ISSET(fd, &rfds)) {
|
|
dtls_handle_read(the_context);
|
|
}
|
|
}
|
|
}
|
|
|
|
error:
|
|
dtls_free_context(the_context);
|
|
return (0);
|
|
}
|