libcoap  4.2.0rc1
coap_tinydtls.c
Go to the documentation of this file.
1 /*
2  * coap_tinydtls.c -- Datagram Transport Layer Support for libcoap with tinydtls
3  *
4  * Copyright (C) 2016 Olaf Bergmann <bergmann@tzi.org>
5  *
6  * This file is part of the CoAP library libcoap. Please see README for terms
7  * of use.
8  */
9 
10 #include "coap_config.h"
11 
12 #ifdef HAVE_LIBTINYDTLS
13 
14 #include "net.h"
15 #include "address.h"
16 #include "debug.h"
17 #include "mem.h"
18 
19 #include <tinydtls.h>
20 #include <dtls.h>
21 
22 static dtls_tick_t dtls_tick_0 = 0;
23 static coap_tick_t coap_tick_0 = 0;
24 
25  /* Prototypes from dtls_debug.h as including that header will conflict
26  * with coap_config.h. */
27 void dtls_set_log_level(int);
28 int dtls_get_log_level(void);
29 
30 int
32  return 1;
33 }
34 
35 void coap_dtls_startup(void) {
36  dtls_init();
37  dtls_ticks(&dtls_tick_0);
38  coap_ticks(&coap_tick_0);
39 }
40 
41 void
42 coap_dtls_set_log_level(int level) {
43  dtls_set_log_level(level);
44 }
45 
46 int
48  return dtls_get_log_level();
49 }
50 
51 static void get_session_addr(const session_t *s, coap_address_t *a) {
52 #ifdef WITH_CONTIKI
53  a->addr = s->addr;
54  a->port = s->port;
55 #else
56  if (s->addr.sa.sa_family == AF_INET6) {
57  a->size = (socklen_t)sizeof(a->addr.sin6);
58  a->addr.sin6 = s->addr.sin6;
59  } else if (s->addr.sa.sa_family == AF_INET) {
60  a->size = (socklen_t)sizeof(a->addr.sin);
61  a->addr.sin = s->addr.sin;
62  } else {
63  a->size = (socklen_t)s->size;
64  a->addr.sa = s->addr.sa;
65  }
66 #endif
67 }
68 
69 static void put_session_addr(const coap_address_t *a, session_t *s) {
70 #ifdef WITH_CONTIKI
71  s->size = (unsigned char)sizeof(s->addr);
72  s->addr = a->addr;
73  s->port = a->port;
74 #else
75  if (a->addr.sa.sa_family == AF_INET6) {
76  s->size = (socklen_t)sizeof(s->addr.sin6);
77  s->addr.sin6 = a->addr.sin6;
78  } else if (a->addr.sa.sa_family == AF_INET) {
79  s->size = (socklen_t)sizeof(s->addr.sin);
80  s->addr.sin = a->addr.sin;
81  } else {
82  s->size = (socklen_t)a->size;
83  s->addr.sa = a->addr.sa;
84  }
85 #endif
86 }
87 
88 static int
89 dtls_send_to_peer(struct dtls_context_t *dtls_context,
90  session_t *dtls_session, uint8 *data, size_t len) {
91  coap_context_t *coap_context = (coap_context_t *)dtls_get_app_data(dtls_context);
92  coap_session_t *coap_session;
93  coap_address_t remote_addr;
94 
95  get_session_addr(dtls_session, &remote_addr);
96  coap_session = coap_session_get_by_peer(coap_context, &remote_addr, dtls_session->ifindex);
97  if (!coap_session) {
98  coap_log(LOG_WARNING, "dtls_send_to_peer: cannot find local interface\n");
99  return -3;
100  }
101  return (int)coap_session_send(coap_session, data, len);
102 }
103 
104 static int
105 dtls_application_data(struct dtls_context_t *dtls_context,
106  session_t *dtls_session, uint8 *data, size_t len) {
107  coap_context_t *coap_context = (coap_context_t *)dtls_get_app_data(dtls_context);
108  coap_session_t *coap_session;
109  coap_address_t remote_addr;
110 
111  get_session_addr(dtls_session, &remote_addr);
112  coap_session = coap_session_get_by_peer(coap_context, &remote_addr, dtls_session->ifindex);
113  if (!coap_session) {
114  debug("dropped message that was received on invalid interface\n");
115  return -1;
116  }
117 
118  return coap_handle_dgram(coap_context, coap_session, data, len);
119 }
120 
121 static int coap_event_dtls = 0;
122 
123 static int
124 dtls_event(struct dtls_context_t *dtls_context,
125  session_t *dtls_session,
126  dtls_alert_level_t level,
127  uint16_t code) {
128  (void)dtls_context;
129  (void)dtls_session;
130 
131  if (level == DTLS_ALERT_LEVEL_FATAL)
132  coap_event_dtls = COAP_EVENT_DTLS_ERROR;
133 
134  /* handle DTLS events */
135  switch (code) {
136  case DTLS_ALERT_CLOSE_NOTIFY:
137  {
138  coap_event_dtls = COAP_EVENT_DTLS_CLOSED;
139  break;
140  }
141  case DTLS_EVENT_CONNECTED:
142  {
143  coap_event_dtls = COAP_EVENT_DTLS_CONNECTED;
144  break;
145  }
146  case DTLS_EVENT_RENEGOTIATE:
147  {
148  coap_event_dtls = COAP_EVENT_DTLS_RENEGOTIATE;
149  break;
150  }
151  default:
152  ;
153  }
154 
155  return 0;
156 }
157 
158 /* This function is the "key store" for tinyDTLS. It is called to
159  * retrieve a key for the given identity within this particular
160  * session. */
161 static int
162 get_psk_info(struct dtls_context_t *dtls_context,
163  const session_t *dtls_session,
164  dtls_credentials_type_t type,
165  const uint8_t *id, size_t id_len,
166  unsigned char *result, size_t result_length) {
167  coap_context_t *coap_context;
168  coap_session_t *coap_session;
169  int fatal_error = DTLS_ALERT_INTERNAL_ERROR;
170  size_t identity_length;
171  static int client = 0;
172  static uint8_t psk[128];
173  static size_t psk_len = 0;
174  coap_address_t remote_addr;
175 
176 
177  if (type == DTLS_PSK_KEY && client) {
178  if (psk_len > result_length) {
179  coap_log(LOG_WARNING, "cannot set psk -- buffer too small\n");
180  goto error;
181  }
182  memcpy(result, psk, psk_len);
183  client = 0;
184  return (int)psk_len;
185  }
186 
187  client = 0;
188  coap_context = (coap_context_t *)dtls_get_app_data(dtls_context);
189  get_session_addr(dtls_session, &remote_addr);
190  coap_session = coap_session_get_by_peer(coap_context, &remote_addr, dtls_session->ifindex);
191  if (!coap_session) {
192  debug("cannot get PSK, session not found\n");
193  goto error;
194  }
195 
196  switch (type) {
197  case DTLS_PSK_IDENTITY:
198 
199  if (id_len)
200  coap_log(LOG_DEBUG, "got psk_identity_hint: '%.*s'\n", (int)id_len, id);
201 
202  if (!coap_context || !coap_context->get_client_psk)
203  goto error;
204 
205  identity_length = 0;
206  psk_len = coap_context->get_client_psk(coap_session, (const uint8_t*)id, id_len, (uint8_t*)result, &identity_length, result_length, psk, sizeof(psk));
207  if (!psk_len) {
208  coap_log(LOG_WARNING, "no PSK identity for given realm\n");
209  fatal_error = DTLS_ALERT_CLOSE_NOTIFY;
210  goto error;
211  }
212  client = 1;
213  return (int)identity_length;
214 
215  case DTLS_PSK_KEY:
216  if (coap_context->get_server_psk)
217  return (int)coap_context->get_server_psk(coap_session, (const uint8_t*)id, id_len, (uint8_t*)result, result_length);
218  return 0;
219  break;
220 
221  case DTLS_PSK_HINT:
222  client = 0;
223  if (coap_context->get_server_hint)
224  return (int)coap_context->get_server_hint(coap_session, (uint8_t *)result, result_length);
225  return 0;
226 
227  default:
228  coap_log(LOG_WARNING, "unsupported request type: %d\n", type);
229  }
230 
231 error:
232  client = 0;
233  return dtls_alert_fatal_create(fatal_error);
234 }
235 
236 static dtls_handler_t cb = {
237  .write = dtls_send_to_peer,
238  .read = dtls_application_data,
239  .event = dtls_event,
240  .get_psk_info = get_psk_info,
241 #ifdef WITH_ECC
242  .get_ecdsa_key = NULL,
243  .verify_ecdsa_key = NULL
244 #endif
245 };
246 
247 void *
248 coap_dtls_new_context(struct coap_context_t *coap_context) {
249  struct dtls_context_t *dtls_context = dtls_new_context(coap_context);
250  if (!dtls_context)
251  goto error;
252  dtls_set_handler(dtls_context, &cb);
253  return dtls_context;
254 error:
255  coap_dtls_free_context(dtls_context);
256  return NULL;
257 }
258 
259 void
260 coap_dtls_free_context(void *handle) {
261  if (handle) {
262  struct dtls_context_t *dtls_context = (struct dtls_context_t *)handle;
263  dtls_free_context(dtls_context);
264  }
265 }
266 
267 static session_t *
268 coap_dtls_new_session(coap_session_t *session) {
269  session_t *dtls_session = coap_malloc_type(COAP_DTLS_SESSION, sizeof(session_t));
270 
271  if (dtls_session) {
272  /* create tinydtls session object from remote address and local
273  * endpoint handle */
274  dtls_session_init(dtls_session);
275  put_session_addr(&session->remote_addr, dtls_session);
276  dtls_session->ifindex = session->ifindex;
277  debug("*** new session %p\n", (void *)dtls_session);
278  }
279 
280  return dtls_session;
281 }
282 
284  return coap_dtls_new_session(session);
285 }
286 
288  dtls_peer_t *peer;
289  session_t *dtls_session = coap_dtls_new_session(session);
290  if (!dtls_session)
291  return NULL;
292  peer =
293  dtls_get_peer((struct dtls_context_t *)session->context->dtls_context,
294  dtls_session);
295 
296  if (!peer) {
297  /* The peer connection does not yet exist. */
298  /* dtls_connect() returns a value greater than zero if a new
299  * connection attempt is made, 0 for session reuse. */
300  if (dtls_connect((struct dtls_context_t *)session->context->dtls_context,
301  dtls_session) >= 0) {
302  peer =
303  dtls_get_peer((struct dtls_context_t *)session->context->dtls_context,
304  dtls_session);
305  }
306  }
307 
308  if (!peer) {
309  /* delete existing session because the peer object has been invalidated */
310  coap_free_type(COAP_DTLS_SESSION, dtls_session);
311  dtls_session = NULL;
312  }
313 
314  return dtls_session;
315 }
316 
317 void
319  (void)session;
320 }
321 
322 void
323 coap_dtls_free_session(coap_session_t *coap_session) {
324  struct dtls_context_t *ctx = (struct dtls_context_t *)coap_session->context->dtls_context;
325  if (coap_session->tls) {
326  dtls_peer_t *peer = dtls_get_peer(ctx, (session_t *)coap_session->tls);
327  if ( peer )
328  dtls_reset_peer(ctx, peer);
329  else
330  dtls_close(ctx, (session_t *)coap_session->tls);
331  debug("*** removed session %p\n", coap_session->tls);
332  coap_free_type(COAP_DTLS_SESSION, coap_session->tls);
333  coap_session->tls = NULL;
334  }
335 }
336 
337 int
339  const uint8_t *data,
340  size_t data_len
341 ) {
342  int res;
343 
344  coap_log(LOG_DEBUG, "call dtls_write\n");
345 
346  coap_event_dtls = -1;
347  res = dtls_write((struct dtls_context_t *)session->context->dtls_context,
348  (session_t *)session->tls, (uint8 *)data, data_len);
349 
350  if (res < 0)
351  coap_log(LOG_WARNING, "coap_dtls_send: cannot send PDU\n");
352 
353  if (coap_event_dtls >= 0) {
354  coap_handle_event(session->context, coap_event_dtls, session);
355  if (coap_event_dtls == COAP_EVENT_DTLS_CONNECTED)
356  coap_session_connected(session);
357  else if (coap_event_dtls == DTLS_ALERT_CLOSE_NOTIFY || coap_event_dtls == COAP_EVENT_DTLS_ERROR)
359  }
360 
361  return res;
362 }
363 
365  return 1;
366 }
367 
368 coap_tick_t coap_dtls_get_context_timeout(void *dtls_context) {
369  clock_time_t next = 0;
370  dtls_check_retransmit((struct dtls_context_t *)dtls_context, &next);
371  if (next > 0)
372  return ((coap_tick_t)(next - dtls_tick_0)) * COAP_TICKS_PER_SECOND / DTLS_TICKS_PER_SECOND + coap_tick_0;
373  return 0;
374 }
375 
377  (void)session;
378  return 0;
379 }
380 
382  (void)session;
383  return;
384 }
385 
386 int
388  const uint8_t *data,
389  size_t data_len
390 ) {
391  session_t *dtls_session = (session_t *)session->tls;
392  int err;
393 
394  coap_event_dtls = -1;
395  err = dtls_handle_message(
396  (struct dtls_context_t *)session->context->dtls_context,
397  dtls_session, (uint8 *)data, (int)data_len);
398 
399  if (err){
400  coap_event_dtls = COAP_EVENT_DTLS_ERROR;
401  }
402 
403  if (coap_event_dtls >= 0) {
404  coap_handle_event(session->context, coap_event_dtls, session);
405  if (coap_event_dtls == COAP_EVENT_DTLS_CONNECTED)
406  coap_session_connected(session);
407  else if (coap_event_dtls == DTLS_ALERT_CLOSE_NOTIFY || coap_event_dtls == COAP_EVENT_DTLS_ERROR)
409  }
410 
411  return err;
412 }
413 
414 int
416  const uint8_t *data,
417  size_t data_len
418 ) {
419  session_t dtls_session;
420  struct dtls_context_t *dtls_context =
421  (struct dtls_context_t *)session->context->dtls_context;
422 
423  dtls_session_init(&dtls_session);
424  put_session_addr(&session->remote_addr, &dtls_session);
425  dtls_session.ifindex = session->ifindex;
426  int res = dtls_handle_message(dtls_context, &dtls_session,
427  (uint8 *)data, (int)data_len);
428  if (res >= 0) {
429  if (dtls_get_peer(dtls_context, &dtls_session))
430  res = 1;
431  else
432  res = 0;
433  }
434  return res;
435 }
436 
437 unsigned int coap_dtls_get_overhead(coap_session_t *session) {
438  (void)session;
439  return 13 + 8 + 8;
440 }
441 
442 #ifdef __GNUC__
443 #define UNUSED __attribute__((unused))
444 #else /* __GNUC__ */
445 #define UNUSED
446 #endif /* __GNUC__ */
447 
448 int coap_tls_is_supported(void) {
449  return 0;
450 }
451 
454  static coap_tls_version_t version;
455  version.version = DTLS_VERSION;
457  return &version;
458 }
459 
460 int
462  coap_dtls_pki_t* setup_data UNUSED,
463  int server UNUSED
464 ) {
465  return 0;
466 }
467 
468 int
470  const char *ca_file UNUSED,
471  const char *ca_path UNUSED
472 ) {
473  return 0;
474 }
475 
476 int
478  const char *hint UNUSED,
479  int server UNUSED
480 ) {
481  return 1;
482 }
483 
484 int
486 {
487  return 1;
488 }
489 
490 void *coap_tls_new_client_session(coap_session_t *session UNUSED, int *connected UNUSED) {
491  return NULL;
492 }
493 
494 void *coap_tls_new_server_session(coap_session_t *session UNUSED, int *connected UNUSED) {
495  return NULL;
496 }
497 
498 void coap_tls_free_session(coap_session_t *coap_session UNUSED) {
499 }
500 
501 ssize_t coap_tls_write(coap_session_t *session UNUSED,
502  const uint8_t *data UNUSED,
503  size_t data_len UNUSED
504 ) {
505  return -1;
506 }
507 
508 ssize_t coap_tls_read(coap_session_t *session UNUSED,
509  uint8_t *data UNUSED,
510  size_t data_len UNUSED
511 ) {
512  return -1;
513 }
514 
515 #undef UNUSED
516 
517 #else /* !HAVE_LIBTINYDTLS */
518 
519 #ifdef __clang__
520 /* Make compilers happy that do not like empty modules. As this function is
521  * never used, we ignore -Wunused-function at the end of compiling this file
522  */
523 #pragma GCC diagnostic ignored "-Wunused-function"
524 #endif
525 static inline void dummy(void) {
526 }
527 
528 #endif /* HAVE_LIBTINYDTLS */
void coap_dtls_set_log_level(int level)
Sets the (D)TLS logging level to the specified level.
Definition: coap_notls.c:76
int coap_dtls_hello(coap_session_t *session UNUSED, const uint8_t *data UNUSED, size_t data_len UNUSED)
Definition: coap_notls.c:140
void coap_tls_free_session(coap_session_t *coap_session UNUSED)
Definition: coap_notls.c:159
struct coap_context_t * context
session&#39;s context
Definition: coap_session.h:68
struct sockaddr_in6 sin6
Definition: address.h:67
struct sockaddr_in sin
Definition: address.h:66
void * tls
security parameters
Definition: coap_session.h:69
int coap_dtls_receive(coap_session_t *session UNUSED, const uint8_t *data UNUSED, size_t data_len UNUSED)
Definition: coap_notls.c:132
multi-purpose address abstraction
Definition: address.h:62
int coap_dtls_context_check_keys_enabled(coap_context_t *ctx UNUSED)
Definition: coap_notls.c:65
#define COAP_EVENT_DTLS_RENEGOTIATE
Definition: coap_event.h:35
ssize_t coap_tls_read(coap_session_t *session UNUSED, uint8_t *data UNUSED, size_t data_len UNUSED)
Definition: coap_notls.c:169
int coap_dtls_get_log_level(void)
Get the current (D)TLS logging.
Definition: coap_notls.c:81
void * coap_dtls_new_client_session(coap_session_t *session UNUSED)
Definition: coap_notls.c:98
int coap_dtls_is_supported(void)
Check whether DTLS is available.
Definition: coap_notls.c:23
void coap_dtls_free_context(void *handle UNUSED)
Definition: coap_notls.c:91
void * coap_tls_new_server_session(coap_session_t *session UNUSED, int *connected UNUSED)
Definition: coap_notls.c:155
ssize_t coap_tls_write(coap_session_t *session UNUSED, const uint8_t *data UNUSED, size_t data_len UNUSED)
Definition: coap_notls.c:162
ssize_t coap_session_send(coap_session_t *session, const uint8_t *data, size_t datalen)
Function interface for datagram data transmission.
Definition: coap_session.c:215
coap_session_t * coap_session_get_by_peer(coap_context_t *ctx, const coap_address_t *remote_addr, int ifindex)
Definition: coap_session.c:874
Debug.
Definition: debug.h:49
uint64_t version
(D)TLS Library Version
Definition: coap_dtls.h:48
size_t(* get_client_psk)(const coap_session_t *session, const uint8_t *hint, size_t hint_len, uint8_t *identity, size_t *identity_len, size_t max_identity_len, uint8_t *psk, size_t max_psk_len)
Definition: net.h:203
void * coap_tls_new_client_session(coap_session_t *session UNUSED, int *connected UNUSED)
Definition: coap_notls.c:151
int coap_tls_is_supported(void)
Check whether TLS is available.
Definition: coap_notls.c:28
#define COAP_TICKS_PER_SECOND
Use ms resolution on POSIX systems.
Definition: coap_time.h:100
int coap_dtls_context_set_pki(coap_context_t *ctx UNUSED, coap_dtls_pki_t *setup_data UNUSED, int server UNUSED)
Definition: coap_notls.c:41
coap_tls_version_t * coap_get_tls_library_version(void)
Determine the type and version of the underlying (D)TLS library.
Definition: coap_notls.c:33
coap_address_t remote_addr
remote address and port
Definition: coap_session.h:63
int type
Library type.
Definition: coap_dtls.h:49
static void dummy(void)
Warning.
Definition: debug.h:46
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:85
int coap_dtls_context_set_psk(coap_context_t *ctx UNUSED, const char *hint UNUSED, int server UNUSED)
Definition: coap_notls.c:57
unsigned int coap_dtls_get_overhead(coap_session_t *session UNUSED)
Definition: coap_notls.c:147
#define COAP_TLS_LIBRARY_TINYDTLS
Using TinyDTLS library.
Definition: coap_dtls.h:39
Representation of network addresses.
void coap_ticks(coap_tick_t *t)
Sets t to the internal time with COAP_TICKS_PER_SECOND resolution.
The structure used for returning the underlying (D)TLS library information.
Definition: coap_dtls.h:47
#define COAP_EVENT_DTLS_CLOSED
(D)TLS events for COAP_PROTO_DTLS and COAP_PROTO_TLS
Definition: coap_event.h:33
int coap_handle_dgram(coap_context_t *ctx, coap_session_t *session, uint8_t *msg, size_t msg_len)
Parses and interprets a CoAP datagram with context ctx.
Definition: net.c:1348
void * dtls_context
Definition: net.h:207
int ifindex
interface index
Definition: coap_session.h:65
size_t(* get_server_hint)(const coap_session_t *session, uint8_t *hint, size_t max_hint_len)
Definition: net.h:205
void coap_dtls_free_session(coap_session_t *coap_session UNUSED)
Definition: coap_notls.c:102
#define COAP_EVENT_DTLS_ERROR
Definition: coap_event.h:36
#define COAP_EVENT_DTLS_CONNECTED
Definition: coap_event.h:34
int coap_handle_event(coap_context_t *context, coap_event_t event, coap_session_t *session)
Invokes the event handler of context for the given event and data.
Definition: net.c:2268
void * coap_dtls_new_server_session(coap_session_t *session UNUSED)
Definition: coap_notls.c:94
void coap_session_connected(coap_session_t *session)
Notify session that it has just connected or reconnected.
Definition: coap_session.c:318
The structure used for defining the PKI setup data to be used.
Definition: coap_dtls.h:190
#define debug(...)
Obsoleted.
Definition: debug.h:143
int coap_dtls_context_set_pki_root_cas(struct coap_context_t *ctx UNUSED, const char *ca_file UNUSED, const char *ca_path UNUSED)
Definition: coap_notls.c:49
int coap_dtls_send(coap_session_t *session UNUSED, const uint8_t *data UNUSED, size_t data_len UNUSED)
Definition: coap_notls.c:109
coap_tick_t coap_dtls_get_timeout(coap_session_t *session UNUSED)
Definition: coap_notls.c:124
size_t(* get_server_psk)(const coap_session_t *session, const uint8_t *identity, size_t identity_len, uint8_t *psk, size_t max_psk_len)
Definition: net.h:204
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
void coap_dtls_handle_timeout(coap_session_t *session UNUSED)
Definition: coap_notls.c:128
void coap_dtls_startup(void)
Initialize the underlying (D)TLS Library layer.
Definition: coap_notls.c:72
void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason)
Notify session that it has failed.
Definition: coap_session.c:374
#define coap_log(level,...)
Logging function.
Definition: debug.h:122
union coap_address_t::@0 addr
socklen_t size
size of addr
Definition: address.h:63
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
unsigned char uint8_t
Definition: uthash.h:79
#define UNUSED
Definition: coap_notls.c:19
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context UNUSED)
Definition: coap_notls.c:120
void coap_dtls_session_update_mtu(coap_session_t *session UNUSED)
Definition: coap_notls.c:105
void * coap_dtls_new_context(struct coap_context_t *coap_context UNUSED)
Definition: coap_notls.c:86
The CoAP stack&#39;s global state is stored in a coap_context_t object.
Definition: net.h:148
int coap_dtls_is_context_timeout(void)
Check if timeout is handled per CoAP session or per CoAP context.
Definition: coap_notls.c:116
struct sockaddr sa
Definition: address.h:65