libcoap  4.2.0
coap_dtls.c
Go to the documentation of this file.
1 /*
2  * coap_dtls.c -- Datagram Transport Layer Support for libcoap
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 #include "address.h"
12 #include "coap_debug.h"
13 #include "mem.h"
14 #include "coap_dtls.h"
15 #include "coap_keystore.h"
16 #include "utlist.h"
17 
18 #ifdef __GNUC__
19 #define UNUSED __attribute__((unused))
20 #else /* __GNUC__ */
21 #define UNUSED
22 #endif /* __GNUC__ */
23 
24 
25 #ifdef HAVE_LIBTINYDTLS
26 #include <tinydtls.h>
27 #include <dtls.h>
28 
29 /* Data item in the DTLS send queue. */
30 struct queue_t {
31  struct queue_t *next;
32  coap_tid_t id;
33  size_t data_length;
34  unsigned char data[];
35 };
36 
37 /* This structure takes a tinydtls peer object to represent a session
38  * with a remote peer. Note that session_t objects in tinydtls are
39  * less useful to pass around because in the end, you will always need
40  * to find the corresponding dtls_peer_t object. dtls_session must be
41  * * the first component in this structure. */
42 typedef struct coap_dtls_session_t {
43  session_t dtls_session;
44  struct coap_dtls_session_t *next;
45  struct queue_t *sendqueue;
47 
48 /* This structure encapsulates the dtls_context_t object from tinydtls
49  * which must always be the first component. */
50 typedef struct coap_dtls_context_t {
51  dtls_context_t *dtls_context;
52  coap_dtls_session_t *sessions;
54 
55 int
57  return 1;
58 }
59 
60 static int
62  const unsigned char *data, size_t data_length) {
63  struct queue_t *item;
64 #define ITEM_SIZE (sizeof(struct queue_t) + data_length)
65 
66  /* Only add if we do not already have that item. */
67  LL_SEARCH_SCALAR(session->sendqueue, item, id, id);
68  if (!item) { /* Not found, add new item */
69  if ((item = (struct queue_t *)coap_malloc(ITEM_SIZE)) != NULL) {
70  debug("*** add %p to sendqueue of session %p\n", item, session);
71  item->id = id;
72  item->data_length = data_length;
73  memcpy(item->data, data, data_length);
74  LL_APPEND(session->sendqueue, item);
75  }
76  }
77 
78  return item != NULL;
79 }
80 
81 static int
82 flush_data(struct coap_dtls_context_t *context,
83  struct coap_dtls_session_t *session) {
84  struct queue_t *item, *tmp;
85  int ok = 0;
86  int res;
87 
88  LL_FOREACH_SAFE(session->sendqueue, item, tmp) {
89  res = dtls_write(context->dtls_context, &session->dtls_session,
90  (uint8_t *)item->data, item->data_length);
91 
92  if (res <= 0) {
93  debug("data not written\n");
94  return ok;
95  } else {
96  if ((size_t)res < item->data_length) {
97  debug("data truncated by dtls_write()\n");
98  } else {
99  ok = 1;
100  }
101  LL_DELETE(session->sendqueue, item);
102  coap_free(item);
103  }
104  }
105 
106  return ok;
107 }
108 
109 static int
110 dtls_send_to_peer(struct dtls_context_t *dtls_context,
111  session_t *session, uint8 *data, size_t len) {
112  coap_context_t *coap_context = dtls_get_app_data(dtls_context);
113  coap_endpoint_t *local_interface;
114 
115  assert(coap_context);
116 
117  LL_SEARCH_SCALAR(coap_context->endpoint, local_interface,
118  handle.fd, session->ifindex);
119 
120  if (!local_interface) {
121  coap_log(LOG_WARNING, "dtls_send_to_peer: cannot find local interface\n");
122  return -3;
123  }
124 
125  return coap_network_send(coap_context, local_interface,
126  (coap_address_t *)session, data, len);
127 }
128 
129 static int
130 dtls_application_data(struct dtls_context_t *dtls_context,
131  session_t *session, uint8 *data, size_t len) {
132  coap_context_t *coap_context;
133  coap_endpoint_t *local_interface;
134 
135  coap_context = (coap_context_t *)dtls_get_app_data(dtls_context);
136  assert(coap_context && coap_context->dtls_context);
137 
138  LL_SEARCH_SCALAR(coap_context->endpoint, local_interface,
139  handle.fd, session->ifindex);
140 
141  if (!local_interface) {
142  debug("dropped message that was received on invalid interface\n");
143  return -1;
144  }
145 
146  return coap_handle_message(coap_context, local_interface,
147  (coap_address_t *)session,
148  (unsigned char *)data, len);
149 }
150 
151 static int
152 dtls_event(struct dtls_context_t *dtls_context,
153  session_t *dtls_session,
154  dtls_alert_level_t level,
155  unsigned short code) {
156  coap_context_t *coap_context;
157  coap_dtls_session_t *session;
158  int event = (level == DTLS_ALERT_LEVEL_FATAL) ? COAP_EVENT_DTLS_ERROR : -1;
159 
160  coap_context = (coap_context_t *)dtls_get_app_data(dtls_context);
161  assert(coap_context && coap_context->dtls_context);
162 
163  LL_FOREACH(coap_context->dtls_context->sessions, session) {
164  if ((session->dtls_session.ifindex == dtls_session->ifindex) &&
166  (coap_address_t *)dtls_session)) {
167  break;
168  }
169  }
170 
171  if (!session) {
172  coap_log(LOG_CRIT, "cannot handle event: session not found\n");
173  return -1;
174  }
175 
176  /* Stop all transactions that are affected from a fatal error
177  * condition. */
178  if (level == DTLS_ALERT_LEVEL_FATAL) {
179  struct queue_t *item;
180  LL_FOREACH(session->sendqueue, item) {
181  coap_queue_t *node = NULL;
182  coap_remove_from_queue(&coap_context->sendqueue, item->id, &node);
183  coap_delete_node(node);
184  }
185  }
186 
187  /* handle DTLS events */
188  switch (code) {
189  case DTLS_ALERT_CLOSE_NOTIFY: {
190  event = COAP_EVENT_DTLS_CLOSED;
191  break;
192  }
193  case DTLS_EVENT_CONNECTED: {
194  flush_data(coap_context->dtls_context, session);
196  break;
197  }
198  case DTLS_EVENT_RENEGOTIATE: {
200  break;
201  }
202  default:
203  ;
204  }
205 
206  if (event != -1) {
207  coap_handle_event(coap_context, event, session);
208  }
209 
210  if (level == DTLS_ALERT_LEVEL_FATAL) {
211  coap_dtls_free_session(coap_context->dtls_context, session);
212  }
213 
214  return 0;
215 }
216 
217 /* This function is the "key store" for tinyDTLS. It is called to
218  * retrieve a key for the given identity within this particular
219  * session. */
220 static int
221 get_psk_info(struct dtls_context_t *dtls_context,
222  const session_t *session,
223  dtls_credentials_type_t type,
224  const unsigned char *id, size_t id_len,
225  unsigned char *result, size_t result_length) {
226  coap_context_t *coap_context = dtls_get_app_data(dtls_context);
227  coap_keystore_item_t *psk;
228  ssize_t length;
229  int fatal_error = DTLS_ALERT_INTERNAL_ERROR;
230 
231  if(!coap_context || !coap_context->keystore) {
232  goto error;
233  }
234 
235  switch (type) {
236  case DTLS_PSK_IDENTITY:
237  if (id_len) {
238  coap_log(LOG_DEBUG, "got psk_identity_hint: '%.*s'\n", id_len, id);
239  }
240 
241  psk = coap_keystore_find_psk(coap_context->keystore, id, id_len,
242  NULL, 0, (coap_address_t *)session);
243  if (!psk) {
244  coap_log(LOG_WARNING, "no PSK identity for given realm\n");
245  fatal_error = DTLS_ALERT_CLOSE_NOTIFY;
246  goto error;
247  }
248 
249  length = coap_psk_set_identity(psk, result, result_length);
250  if (length < 0) {
251  coap_log(LOG_WARNING, "cannot set psk_identity -- buffer too small\n");
252  goto error;
253  }
254 
255  return length;
256  case DTLS_PSK_KEY:
257  psk = coap_keystore_find_psk(coap_context->keystore, NULL, 0,
258  id, id_len, (coap_address_t *)session);
259  if (!psk) {
260  coap_log(LOG_WARNING, "PSK for unknown id requested, exiting\n");
261  fatal_error = DTLS_ALERT_HANDSHAKE_FAILURE;
262  goto error;
263  }
264 
265  length = coap_psk_set_key(psk, result, result_length);
266  if (length < 0) {
267  coap_log(LOG_WARNING, "cannot set psk -- buffer too small\n");
268  goto error;
269  }
270 
271  return length;
272  case DTLS_PSK_HINT:
273  /* There is no point in sending a psk_identity_hint hence it is
274  * set to zero length. */
275  return 0;
276  default:
277  coap_log(LOG_WARNING, "unsupported request type: %d\n", type);
278  }
279 
280  error:
281  return dtls_alert_fatal_create(fatal_error);
282 }
283 
284 static dtls_handler_t cb = {
285  .write = dtls_send_to_peer,
286  .read = dtls_application_data,
287  .event = dtls_event,
288  .get_psk_info = get_psk_info,
289 #ifdef WITH_ECC
290  .get_ecdsa_key = NULL,
291  .verify_ecdsa_key = NULL
292 #endif
293 };
294 
295 struct coap_dtls_context_t *
296 coap_dtls_new_context(struct coap_context_t *coap_context) {
297  struct coap_dtls_context_t *context;
298 #define CONTEXT_SIZE (sizeof(struct coap_dtls_context_t))
299 
300  context = (struct coap_dtls_context_t *)coap_malloc(CONTEXT_SIZE);
301  if (context) {
302  memset(context, 0, CONTEXT_SIZE);
303 
304  context->dtls_context = dtls_new_context(coap_context);
305  if (!context->dtls_context) {
306  goto error;
307  }
308 
309  dtls_set_handler(context->dtls_context, &cb);
310  }
311 
312  return context;
313  error:
314 
315  coap_dtls_free_context(context);
316  return NULL;
317 }
318 
319 void
320 coap_dtls_free_context(struct coap_dtls_context_t *dtls_context) {
321  while(dtls_context->sessions) {
322  coap_dtls_free_session(dtls_context, dtls_context->sessions);
323  }
324  dtls_free_context(dtls_context->dtls_context);
325  coap_free(dtls_context);
326 }
327 
328 /* Convenience macro to copy IPv6 addresses without garbage. */
329 #define COAP_COPY_ADDRESS(DST,SRC) do { \
330  (DST)->size = (SRC)->size; \
331  if ((SRC)->addr.sa.sa_family == AF_INET6) { \
332  (DST)->addr.sin6.sin6_family = (SRC)->addr.sin6.sin6_family; \
333  (DST)->addr.sin6.sin6_addr = (SRC)->addr.sin6.sin6_addr; \
334  (DST)->addr.sin6.sin6_port = (SRC)->addr.sin6.sin6_port; \
335  } else { \
336  (DST)->addr.st = (SRC)->addr.st; \
337  } \
338  } while (0);
339 
340 struct coap_dtls_session_t *
343  const coap_address_t *remote) {
344  struct coap_dtls_session_t *session;
345  const size_t need = sizeof(struct coap_dtls_session_t);
346 
347  session = coap_malloc_type(COAP_DTLS_SESSION, need);
348 
349  if (session) {
350  /* create tinydtls session object from remote address and local
351  * endpoint handle */
352  memset(session, 0, need);
353  dtls_session_init(&session->dtls_session);
354  COAP_COPY_ADDRESS(&session->dtls_session, remote);
355  session->dtls_session.ifindex = local_interface->handle.fd;
356 
357  LL_PREPEND(dtls_context->sessions, session);
358  debug("*** new session %p\n", session);
359  }
360 
361  return session;
362 }
363 
364 void
366  coap_dtls_session_t *session) {
367  if (session) {
368  struct queue_t *item, *tmp;
369 
370  LL_DELETE(dtls_context->sessions, session);
371  LL_FOREACH_SAFE(session->sendqueue, item, tmp) {
372  coap_free(item);
373  }
374  debug("*** removed session %p\n", session);
375  coap_free_type(COAP_DTLS_SESSION, session);
376  }
377 }
378 
379 static coap_dtls_session_t *
381  const coap_endpoint_t *local_interface,
382  const coap_address_t *dst) {
383  struct coap_dtls_session_t *session;
384 
385  LL_FOREACH(dtls_context->sessions, session) {
386  if ((session->dtls_session.ifindex == local_interface->handle.fd) &&
387  coap_address_equals((coap_address_t *)&session->dtls_session, dst)) {
388  return session;
389  }
390  }
391  return session;
392 }
393 
394 struct coap_dtls_session_t *
395 coap_dtls_get_session(struct coap_context_t *coap_context,
396  const coap_endpoint_t *local_interface,
397  const coap_address_t *dst) {
398  dtls_peer_t *peer;
399  coap_dtls_session_t *session;
400 
401  assert(coap_context && coap_context->dtls_context);
402 
403  /* reuse existing session if available, otherwise create new session */
404  session = coap_dtls_find_session(coap_context->dtls_context,
405  local_interface, dst);
406 
407  if (!session &&
408  ((session = coap_dtls_new_session(coap_context->dtls_context,
409  local_interface, dst)) == NULL)) {
410  coap_log(LOG_WARNING, "cannot create session object\n");
411  return NULL;
412  }
413 
414  peer = dtls_get_peer(coap_context->dtls_context->dtls_context,
415  &session->dtls_session);
416 
417  if (!peer) {
418  /* The peer connection does not yet exist. */
419  /* dtls_connect() returns a value greater than zero if a new
420  * connection attempt is made, 0 for session reuse. */
421  if (dtls_connect(coap_context->dtls_context->dtls_context,
422  &session->dtls_session) >= 0) {
423 
424  peer = dtls_get_peer(coap_context->dtls_context->dtls_context,
425  &session->dtls_session);
426  }
427  }
428 
429  if (!peer) {
430  /* delete existing session because the peer object has been invalidated */
431  coap_dtls_free_session(coap_context->dtls_context, session);
432  session = NULL;
433  }
434 
435  return session;
436 }
437 
438 int
439 coap_dtls_send(struct coap_context_t *coap_context,
440  struct coap_dtls_session_t *session,
441  const coap_pdu_t *pdu) {
442  int res = -2;
443 
444  assert(coap_context && coap_context->dtls_context);
445  coap_log(LOG_DEBUG, "call dtls_write\n");
446 
447  res = dtls_write(coap_context->dtls_context->dtls_context,
448  &session->dtls_session,
449  (uint8 *)pdu->hdr, pdu->length);
450 
451  if (res < 0) {
452  coap_log(LOG_WARNING, "coap_dtls_send: cannot send PDU\n");
453  } else if (res == 0) {
454  coap_tid_t id;
455  coap_transaction_id((coap_address_t *)&session->dtls_session, pdu, &id);
456 
457  if (!push_data_item(session, id, (uint8 *)pdu->hdr, pdu->length)) {
458  coap_log(LOG_DEBUG, "cannot store %u bytes for deferred transmission\n",
459  pdu->length);
460  res = -2;
461  }
462  }
463 
464  return res;
465 }
466 
467 int
468 coap_dtls_handle_message(struct coap_context_t *coap_context,
469  const coap_endpoint_t *local_interface,
470  const coap_address_t *dst,
471  const unsigned char *data, size_t data_len) {
472  coap_dtls_session_t *session;
473  int new_session = 0;
474 
475  session = coap_dtls_find_session(coap_context->dtls_context,
476  local_interface, dst);
477 
478  if (!session) {
479  if ((session = coap_dtls_new_session(coap_context->dtls_context,
480  local_interface, dst)) != NULL) {
481  new_session = 1;
482  }
483  }
484 
485  if (!session) {
486  coap_log(LOG_WARNING, "cannot allocate session, drop packet\n");
487  return -1;
488  }
489 
490  int res =
491  dtls_handle_message(coap_context->dtls_context->dtls_context,
492  &session->dtls_session, (uint8 *)data, data_len);
493 
494  if ((res < 0) && new_session) {
495  coap_dtls_free_session(coap_context->dtls_context, session);
496  }
497 
498  return -1;
499 }
500 
501 #elif defined(HAVE_GNUTLS)
502 #include <gnutls/gnutls.h>
503 #include <gnutls/dtls.h>
504 
505 #include "coap_debug.h"
506 
507 /* Data item in the DTLS send queue. */
508 struct queue_t {
509  struct queue_t *next;
510  coap_tid_t id;
511  size_t data_length;
512  unsigned char data[];
513 };
514 
515 typedef struct transport_t {
516  coap_context_t *coap_context;
517  const coap_endpoint_t *local_interface;
518  const coap_address_t *dst;
519 } transport_t;
520 
521 typedef struct coap_dtls_session_t {
522  gnutls_session_t dtls_session;
523  unsigned int flags;
524  coap_context_t *coap_context;
525  coap_endpoint_t local_interface;
526  coap_address_t dst;
527  struct coap_dtls_session_t *next;
528  struct queue_t *sendqueue;
530 
531 /* This structure encapsulates the dtls_context_t object from tinydtls
532  * which must always be the first component. */
533 typedef struct coap_dtls_context_t {
534  coap_context_t *coap_context;
535  gnutls_datum_t cookie_key;
536  coap_dtls_session_t *sessions;
538 
539 int
541  /* Check for GnuTLS version 3.3.0 or higher to ensure that
542  * initialization and finalization is done during library
543  * load/unload. */
544  return gnutls_check_version("3.3.0") != NULL;
545 }
546 
547 static int
548 get_psk(gnutls_session_t session __attribute__((unused)),
549  const char *identity,
550  gnutls_datum_t *key) {
551 #define PSK_IDENTITY "Client_identity"
552 #define PSK_IDENTITY_LENGTH (sizeof(PSK_IDENTITY) - 1)
553 #define PSK "secretPSK"
554 #define PSK_LENGTH (sizeof(PSK) - 1)
555 
556  if ((strlen(identity) == PSK_IDENTITY_LENGTH) &&
557  (memcmp(identity, PSK_IDENTITY, PSK_IDENTITY_LENGTH) == 0)) {
558  key->data = gnutls_malloc(PSK_LENGTH);
559 
560  if (key->data != NULL) {
561  key->size = PSK_LENGTH;
562  memcpy(key->data, PSK, PSK_LENGTH);
563  return 0;
564  }
565  }
566 
567  return -1;
568 }
569 
570 struct coap_dtls_session_t *
572  const coap_endpoint_t *local_interface,
573  const coap_address_t *remote) {
574  struct coap_dtls_session_t *session;
575  const size_t need = sizeof(struct coap_dtls_session_t);
576 
577  session = coap_malloc_type(COAP_DTLS_SESSION, need);
578 
579  if (session) {
580  /* create tinydtls session object from remote address and local
581  * endpoint handle */
582  memset(session, 0, need);
583  /* dtls_session_init(&session->dtls_session); */
584  /* COAP_COPY_ADDRESS(&session->dtls_session, remote); */
585  session->coap_context = dtls_context->coap_context;
586  session->local_interface = *local_interface;
587  session->dst = *remote;
588 
589  LL_PREPEND(dtls_context->sessions, session);
590  debug("*** new session %p\n", session);
591  }
592 
593  return session;
594 }
595 
596 void
598  coap_dtls_session_t *session) {
599  if (session) {
600  struct queue_t *item, *tmp;
601  void *credentials;
602 
603  LL_DELETE(dtls_context->sessions, session);
604  LL_FOREACH_SAFE(session->sendqueue, item, tmp) {
605  coap_free(item);
606  }
607  if (gnutls_credentials_get(session->dtls_session, GNUTLS_CRD_PSK,
608  &credentials)
609  == GNUTLS_E_SUCCESS) {
610  if (session->flags & GNUTLS_SERVER) {
611  gnutls_psk_free_server_credentials(
612  (gnutls_psk_server_credentials_t)credentials);
613  } else {
614  gnutls_psk_free_client_credentials(
615  (gnutls_psk_client_credentials_t)credentials);
616  }
617  }
618  gnutls_deinit(session->dtls_session);
619  debug("*** removed session %p\n", session);
620  coap_free_type(COAP_DTLS_SESSION, session);
621  }
622 }
623 
624 static int
625 push_data_item(struct coap_dtls_session_t *session, coap_tid_t id,
626  const unsigned char *data, size_t data_length) {
627  struct queue_t *item;
628 #define ITEM_SIZE (sizeof(struct queue_t) + data_length)
629 
630  /* Only add if we do not already have that item. */
631  LL_SEARCH_SCALAR(session->sendqueue, item, id, id);
632  if (!item) { /* Not found, add new item */
633  if ((item = (struct queue_t *)coap_malloc(ITEM_SIZE)) != NULL) {
634  debug("*** add %p to sendqueue of session %p\n", item, session);
635  item->id = id;
636  item->data_length = data_length;
637  memcpy(item->data, data, data_length);
638  LL_APPEND(session->sendqueue, item);
639  }
640  }
641 
642  return item != NULL;
643 }
644 
645 int
646 coap_dtls_send(struct coap_context_t *coap_context,
647  struct coap_dtls_session_t *session,
648  const coap_pdu_t *pdu) {
649  int res = -2;
650 
651  assert(coap_context && coap_context->dtls_context);
652  coap_log(LOG_DEBUG, "call dtls_write\n");
653 
654  /* FIXME: send to DTLS peer */
655 #if 0
656  res = dtls_write(coap_context->dtls_context->dtls_context,
657  &session->dtls_session,
658  (uint8 *)pdu->hdr, pdu->length);
659 #endif
660  if (res < 0) {
661  coap_log(LOG_WARNING, "coap_dtls_send: cannot send PDU\n");
662  } else if (res == 0) {
663  coap_tid_t id;
664  coap_transaction_id((coap_address_t *)&session->dtls_session, pdu, &id);
665 
666  if (!push_data_item(session, id, (uint8_t *)pdu->hdr, pdu->length)) {
667  coap_log(LOG_DEBUG, "cannot store %u bytes for deferred transmission\n",
668  pdu->length);
669  res = -2;
670  }
671  }
672 
673  return res;
674 }
675 
676 static inline void
677 show_log(int level, const char *msg) {
678  coap_log(level, msg);
679 }
680 
681 struct coap_dtls_context_t *
682 coap_dtls_new_context(struct coap_context_t *coap_context) {
683  struct coap_dtls_context_t *context;
684 #define CONTEXT_SIZE (sizeof(struct coap_dtls_context_t))
685 
686  context = (struct coap_dtls_context_t *)coap_malloc(CONTEXT_SIZE);
687  if (context) {
688  memset(context, 0, CONTEXT_SIZE);
689  context->coap_context = coap_context;
690 
691  gnutls_global_set_log_level(coap_get_log_level());
692  gnutls_global_set_log_function(show_log);
693 
694  gnutls_key_generate(&context->cookie_key, GNUTLS_COOKIE_KEY_SIZE);
695  }
696 
697  return context;
698 }
699 
700 void
701 coap_dtls_free_context(struct coap_dtls_context_t *dtls_context) {
702  while(dtls_context->sessions) {
703  coap_dtls_free_session(dtls_context, dtls_context->sessions);
704  }
705  coap_free(dtls_context);
706 }
707 
708 static ssize_t
709 push_cookie(gnutls_transport_ptr_t tp, const void *buf, size_t len) {
710  transport_t *trans = (transport_t *)tp;
711 
712  return coap_network_send(trans->coap_context, trans->local_interface,
713  trans->dst, (unsigned char *)buf, len);
714 }
715 
716 static ssize_t
717 push_func(gnutls_transport_ptr_t tp, const void *buf, size_t len) {
718  coap_dtls_session_t *session = (coap_dtls_session_t *)tp;
719 
720  return coap_network_send(session->coap_context,
721  &session->local_interface,
722  &session->dst,
723  (unsigned char *)buf,
724  len);
725 }
726 
727 static coap_dtls_session_t *
729  const coap_endpoint_t *local_interface,
730  const coap_address_t *dst) {
731  struct coap_dtls_session_t *session;
732 
733  LL_FOREACH(dtls_context->sessions, session) {
734  if ((session->local_interface.handle.fd == local_interface->handle.fd) &&
735  coap_address_equals((coap_address_t *)&session->dst, dst)) {
736  return session;
737  }
738  }
739  return session;
740 }
741 
742 struct coap_dtls_session_t *
743 coap_dtls_get_session(struct coap_context_t *coap_context,
744  const coap_endpoint_t *local_interface,
745  const coap_address_t *dst) {
746  coap_dtls_session_t *session;
747 
748  assert(coap_context && coap_context->dtls_context);
749 
750  /* reuse existing session if available, otherwise create new session */
751  session = coap_dtls_find_session(coap_context->dtls_context,
752  local_interface, dst);
753 
754  if (!session &&
755  ((session = coap_dtls_new_session(coap_context->dtls_context,
756  local_interface, dst)) == NULL)) {
757  coap_log(LOG_WARNING, "cannot create session object\n");
758  return NULL;
759  }
760 
761  /* FIXME: check if we have a client connection, otherwise initiate it */
762 #if 0
763  peer = dtls_get_peer(coap_context->dtls_context->dtls_context,
764  &session->dtls_session);
765 
766  if (!peer) {
767  /* The peer connection does not yet exist. */
768  /* dtls_connect() returns a value greater than zero if a new
769  * connection attempt is made, 0 for session reuse. */
770  if (dtls_connect(coap_context->dtls_context->dtls_context,
771  &session->dtls_session) >= 0) {
772 
773  peer = dtls_get_peer(coap_context->dtls_context->dtls_context,
774  &session->dtls_session);
775  }
776  }
777 
778  if (!peer) {
779  /* delete existing session because the peer object has been invalidated */
780  coap_dtls_free_session(coap_context->dtls_context, session);
781  session = NULL;
782  }
783 #endif
784  return session;
785 }
786 
787 int
788 coap_dtls_handle_message(struct coap_context_t *coap_context,
789  const coap_endpoint_t *local_interface,
790  const coap_address_t *dst,
791  const unsigned char *data, size_t data_len) {
792  coap_dtls_session_t *session;
793  int new_session = 0;
794  int result;
795 
796  session = coap_dtls_find_session(coap_context->dtls_context,
797  local_interface, dst);
798 
799  if (!session) {
800  gnutls_dtls_prestate_st prestate;
801 
802  memset(&prestate, 0, sizeof(prestate));
803  result = gnutls_dtls_cookie_verify(&coap_context->dtls_context->cookie_key,
804  (void *)&dst->addr,
805  dst->size,
806  (void *)data, data_len, &prestate);
807  if (result < 0) {
808  transport_t trans = { coap_context, local_interface, dst };
809  gnutls_dtls_cookie_send(&coap_context->dtls_context->cookie_key,
810  (void *)&dst->addr, dst->size, &prestate,
811  (gnutls_transport_ptr_t)&trans, push_cookie);
812 
813  return 0;
814  } else {
815  if ((session = coap_dtls_new_session(coap_context->dtls_context,
816  local_interface, dst)) != NULL) {
817  const char *error = NULL;
818  gnutls_psk_server_credentials_t cred;
819 
820  new_session = 1;
821 
822 #define TRY(stmt, dbgmsg) \
823  do { \
824  result = (stmt); \
825  if (result != GNUTLS_E_SUCCESS) { \
826  debug(dbgmsg); \
827  return result; \
828  } \
829  } while (0);
830 
831  session->flags = GNUTLS_SERVER;
832  TRY(gnutls_init(&session->dtls_session,
833  GNUTLS_SERVER | GNUTLS_DATAGRAM /*| GNUTLS_NONBLOCK*/),
834  "cannot init GnuTLS session\n");
835 
836  TRY(gnutls_psk_allocate_server_credentials(&cred),
837  "cannot create credentials\n");
838 
839  gnutls_psk_set_server_credentials_function(cred, get_psk);
840 
841  TRY(gnutls_credentials_set(session->dtls_session, GNUTLS_CRD_PSK, cred),
842  "cannot set credentials");
843 
844  TRY(gnutls_priority_set_direct(session->dtls_session,
845  "NONE:+VERS-DTLS1.2:+PSK:+AES-128-CCM:+SHA256:+COMP-NULL",
846  &error),
847  "cannot set cipher suite\n");
848 
849  gnutls_dtls_prestate_set(session->dtls_session, &prestate);
850  gnutls_transport_set_int(session->dtls_session, local_interface->handle.fd);
851  /* gnutls_transport_set_ptr(session->dtls_session, session); */
852  /* gnutls_transport_set_push_function(session->dtls_session, push_func); */
853  /* gnutls_transport_set_pull_function(session, pull_func); */
854  /* gnutls_transport_set_pull_timeout_function(session, pull_timeout_func); */
855 
856  /* test */
857  do {
858  result = gnutls_handshake(session->dtls_session);
859  } while (result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN);
860 
861  if (result < 0) {
862  coap_log(LOG_ALERT, "Error in handshake(): %s\n",
863  gnutls_strerror(result));
864  return result;
865  }
866 
867  debug("Handshake was completed\n");
868  }
869  }
870  }
871 
872  if (!session) {
873  coap_log(LOG_WARNING, "cannot allocate session, drop packet\n");
874  return -1;
875  }
876 
877  /* int res = */
878  /* dtls_handle_message(coap_context->dtls_context->dtls_context, */
879  /* &session->dtls_session, (uint8 *)data, data_len); */
880 
881  if ((result < 0) && new_session) {
882  coap_dtls_free_session(coap_context->dtls_context, session);
883  }
884 
885  return -1;
886 }
887 
888 #else /* HAVE_GNUTLS */
889 
890 int
892  return 0;
893 }
894 
895 struct coap_dtls_context_t *
897  return NULL;
898 }
899 
900 void
902 }
903 
904 struct coap_dtls_session_t *
906  const coap_endpoint_t *local_interface UNUSED,
907  const coap_address_t *dst UNUSED) {
908  return NULL;
909 }
910 
911 int
912 coap_dtls_send(struct coap_context_t *coap_context UNUSED,
913  struct coap_dtls_session_t *session UNUSED,
914  const unsigned char *data UNUSED, size_t data_len UNUSED) {
915  return -1;
916 }
917 
918 struct coap_dtls_session_t *
920  const coap_address_t *remote UNUSED) {
921  return NULL;
922 }
923 
924 void
926 
927 int
929  const coap_endpoint_t *local_interface UNUSED,
930  const coap_address_t *dst UNUSED,
931  const unsigned char *data UNUSED,
932  size_t data_len UNUSED) {
933  return -1;
934 }
935 
936 #endif /* HAVE_LIBTINYDTLS */
937 
938 #undef UNUSED
size_t data_length
#define LL_FOREACH(head, el)
Definition: utlist.h:413
coap_queue_t * sendqueue
Definition: net.h:165
coap_endpoint_t * endpoint
the endpoints used for listening
Definition: net.h:166
multi-purpose address abstraction
Definition: address.h:62
#define COAP_EVENT_DTLS_RENEGOTIATE
Definition: coap_event.h:35
int coap_tid_t
coap_tid_t is used to store CoAP transaction id, i.e.
Definition: pdu.h:238
#define LL_PREPEND(head, add)
Definition: utlist.h:314
static int push_data_item(struct coap_dtls_session_t *session, coap_tid_t id, const unsigned char *data, size_t data_length)
int coap_dtls_is_supported(void)
Check whether DTLS is available.
Definition: coap_dtls.c:891
struct queue_t * next
struct coap_dtls_session_t * sessions
Debug.
Definition: coap_debug.h:49
ssize_t coap_network_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen)
Definition: coap_io.c:758
void coap_dtls_free_session(coap_dtls_session_t *session UNUSED)
Definition: coap_dtls.c:925
Abstraction of virtual endpoint that can be attached to coap_context_t.
Definition: coap_session.h:301
struct coap_dtls_context_t coap_dtls_context_t
int coap_dtls_handle_message(struct coap_context_t *coap_context UNUSED, const coap_endpoint_t *local_interface UNUSED, const coap_address_t *dst UNUSED, const unsigned char *data UNUSED, size_t data_len UNUSED)
Definition: coap_dtls.c:928
#define COAP_COPY_ADDRESS(DST, SRC)
COAP_STATIC_INLINE void * coap_malloc(size_t size)
Wrapper function to coap_malloc_type() for backwards compatibility.
Definition: mem.h:75
struct coap_dtls_session_t * coap_dtls_get_session(struct coap_context_t *coap_context UNUSED, const coap_endpoint_t *local_interface UNUSED, const coap_address_t *dst UNUSED)
Definition: coap_dtls.c:905
struct coap_dtls_session_t * coap_dtls_new_session(const coap_endpoint_t *local_interface UNUSED, const coap_address_t *remote UNUSED)
Definition: coap_dtls.c:919
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
Definition: pdu.h:287
Warning.
Definition: coap_debug.h:46
#define assert(...)
Definition: mem.c:18
coap_endpoint_t * local_interface
Representation of network addresses.
#define UNUSED
Definition: coap_dtls.c:21
#define COAP_EVENT_DTLS_CLOSED
(D)TLS events for COAP_PROTO_DTLS and COAP_PROTO_TLS
Definition: coap_event.h:33
#define LL_APPEND(head, add)
Definition: utlist.h:338
COAP_STATIC_INLINE void coap_free(void *object)
Wrapper function to coap_free_type() for backwards compatibility.
Definition: mem.h:82
void * dtls_context
Definition: net.h:207
static struct coap_dtls_session_t * coap_dtls_find_session(coap_dtls_context_t *dtls_context, const coap_endpoint_t *local_interface, const coap_address_t *dst)
int coap_remove_from_queue(coap_queue_t **queue, coap_session_t *session, coap_tid_t id, coap_queue_t **node)
This function removes the element with given id from the list given list.
Definition: net.c:1397
#define COAP_EVENT_DTLS_ERROR
Definition: coap_event.h:36
#define COAP_EVENT_DTLS_CONNECTED
Definition: coap_event.h:34
int coap_address_equals(const coap_address_t *a, const coap_address_t *b)
Compares given address objects a and b.
Definition: address.c:36
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:2310
static ssize_t dtls_send_to_peer(gnutls_transport_ptr_t context, const void *send_buffer, size_t send_buffer_length)
void coap_dtls_free_context(struct coap_dtls_context_t *dtls_context)
Definition: coap_dtls.c:901
#define LL_FOREACH_SAFE(head, el, tmp)
Definition: utlist.h:419
struct coap_dtls_context_t * coap_dtls_new_context(struct coap_context_t *coap_context UNUSED)
Definition: coap_dtls.c:896
struct queue_t * sendqueue
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.
#define LL_DELETE(head, del)
Definition: utlist.h:385
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition: coap_debug.c:71
int coap_dtls_send(struct coap_context_t *coap_context UNUSED, struct coap_dtls_session_t *session UNUSED, const unsigned char *data UNUSED, size_t data_len UNUSED)
Definition: coap_dtls.c:912
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:122
union coap_address_t::@0 addr
#define ITEM_SIZE
unsigned char data[]
#define LL_SEARCH_SCALAR(head, out, field, val)
Definition: utlist.h:425
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 CONTEXT_SIZE
Critical.
Definition: coap_debug.h:44
gnutls_session_t dtls_session
coap_tid_t id
Queue entry.
Definition: net.h:39
Alert.
Definition: coap_debug.h:43
The CoAP stack&#39;s global state is stored in a coap_context_t object.
Definition: net.h:148
int coap_delete_node(coap_queue_t *node)
Destroys specified node.
Definition: net.c:225