libcoap  4.2.0rc2
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) {
115  "dropped message that was received on invalid interface\n");
116  return -1;
117  }
118 
119  return coap_handle_dgram(coap_context, coap_session, data, len);
120 }
121 
122 static int coap_event_dtls = 0;
123 
124 static int
125 dtls_event(struct dtls_context_t *dtls_context,
126  session_t *dtls_session,
127  dtls_alert_level_t level,
128  uint16_t code) {
129  (void)dtls_context;
130  (void)dtls_session;
131 
132  if (level == DTLS_ALERT_LEVEL_FATAL)
133  coap_event_dtls = COAP_EVENT_DTLS_ERROR;
134 
135  /* handle DTLS events */
136  switch (code) {
137  case DTLS_ALERT_CLOSE_NOTIFY:
138  {
139  coap_event_dtls = COAP_EVENT_DTLS_CLOSED;
140  break;
141  }
142  case DTLS_EVENT_CONNECTED:
143  {
144  coap_event_dtls = COAP_EVENT_DTLS_CONNECTED;
145  break;
146  }
147  case DTLS_EVENT_RENEGOTIATE:
148  {
149  coap_event_dtls = COAP_EVENT_DTLS_RENEGOTIATE;
150  break;
151  }
152  default:
153  ;
154  }
155 
156  return 0;
157 }
158 
159 /* This function is the "key store" for tinyDTLS. It is called to
160  * retrieve a key for the given identity within this particular
161  * session. */
162 static int
163 get_psk_info(struct dtls_context_t *dtls_context,
164  const session_t *dtls_session,
165  dtls_credentials_type_t type,
166  const uint8_t *id, size_t id_len,
167  unsigned char *result, size_t result_length) {
168  coap_context_t *coap_context;
169  coap_session_t *coap_session;
170  int fatal_error = DTLS_ALERT_INTERNAL_ERROR;
171  size_t identity_length;
172  static int client = 0;
173  static uint8_t psk[128];
174  static size_t psk_len = 0;
175  coap_address_t remote_addr;
176 
177 
178  if (type == DTLS_PSK_KEY && client) {
179  if (psk_len > result_length) {
180  coap_log(LOG_WARNING, "cannot set psk -- buffer too small\n");
181  goto error;
182  }
183  memcpy(result, psk, psk_len);
184  client = 0;
185  return (int)psk_len;
186  }
187 
188  client = 0;
189  coap_context = (coap_context_t *)dtls_get_app_data(dtls_context);
190  get_session_addr(dtls_session, &remote_addr);
191  coap_session = coap_session_get_by_peer(coap_context, &remote_addr, dtls_session->ifindex);
192  if (!coap_session) {
193  coap_log(LOG_DEBUG, "cannot get PSK, session not found\n");
194  goto error;
195  }
196 
197  switch (type) {
198  case DTLS_PSK_IDENTITY:
199 
200  if (id_len)
201  coap_log(LOG_DEBUG, "got psk_identity_hint: '%.*s'\n", (int)id_len, id);
202 
203  if (!coap_context || !coap_context->get_client_psk)
204  goto error;
205 
206  identity_length = 0;
207  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));
208  if (!psk_len) {
209  coap_log(LOG_WARNING, "no PSK identity for given realm\n");
210  fatal_error = DTLS_ALERT_CLOSE_NOTIFY;
211  goto error;
212  }
213  client = 1;
214  return (int)identity_length;
215 
216  case DTLS_PSK_KEY:
217  if (coap_context->get_server_psk)
218  return (int)coap_context->get_server_psk(coap_session, (const uint8_t*)id, id_len, (uint8_t*)result, result_length);
219  return 0;
220  break;
221 
222  case DTLS_PSK_HINT:
223  client = 0;
224  if (coap_context->get_server_hint)
225  return (int)coap_context->get_server_hint(coap_session, (uint8_t *)result, result_length);
226  return 0;
227 
228  default:
229  coap_log(LOG_WARNING, "unsupported request type: %d\n", type);
230  }
231 
232 error:
233  client = 0;
234  return dtls_alert_fatal_create(fatal_error);
235 }
236 
237 static dtls_handler_t cb = {
238  .write = dtls_send_to_peer,
239  .read = dtls_application_data,
240  .event = dtls_event,
241  .get_psk_info = get_psk_info,
242 #ifdef WITH_ECC
243  .get_ecdsa_key = NULL,
244  .verify_ecdsa_key = NULL
245 #endif
246 };
247 
248 void *
249 coap_dtls_new_context(struct coap_context_t *coap_context) {
250  struct dtls_context_t *dtls_context = dtls_new_context(coap_context);
251  if (!dtls_context)
252  goto error;
253  dtls_set_handler(dtls_context, &cb);
254  return dtls_context;
255 error:
256  coap_dtls_free_context(dtls_context);
257  return NULL;
258 }
259 
260 void
261 coap_dtls_free_context(void *handle) {
262  if (handle) {
263  struct dtls_context_t *dtls_context = (struct dtls_context_t *)handle;
264  dtls_free_context(dtls_context);
265  }
266 }
267 
268 static session_t *
269 coap_dtls_new_session(coap_session_t *session) {
270  session_t *dtls_session = coap_malloc_type(COAP_DTLS_SESSION, sizeof(session_t));
271 
272  if (dtls_session) {
273  /* create tinydtls session object from remote address and local
274  * endpoint handle */
275  dtls_session_init(dtls_session);
276  put_session_addr(&session->remote_addr, dtls_session);
277  dtls_session->ifindex = session->ifindex;
278  coap_log(LOG_DEBUG, "***new session %p\n", (void *)dtls_session);
279  }
280 
281  return dtls_session;
282 }
283 
285  return coap_dtls_new_session(session);
286 }
287 
289  dtls_peer_t *peer;
290  session_t *dtls_session = coap_dtls_new_session(session);
291  if (!dtls_session)
292  return NULL;
293  peer =
294  dtls_get_peer((struct dtls_context_t *)session->context->dtls_context,
295  dtls_session);
296 
297  if (!peer) {
298  /* The peer connection does not yet exist. */
299  /* dtls_connect() returns a value greater than zero if a new
300  * connection attempt is made, 0 for session reuse. */
301  if (dtls_connect((struct dtls_context_t *)session->context->dtls_context,
302  dtls_session) >= 0) {
303  peer =
304  dtls_get_peer((struct dtls_context_t *)session->context->dtls_context,
305  dtls_session);
306  }
307  }
308 
309  if (!peer) {
310  /* delete existing session because the peer object has been invalidated */
311  coap_free_type(COAP_DTLS_SESSION, dtls_session);
312  dtls_session = NULL;
313  }
314 
315  return dtls_session;
316 }
317 
318 void
320  (void)session;
321 }
322 
323 void
324 coap_dtls_free_session(coap_session_t *coap_session) {
325  struct dtls_context_t *ctx = (struct dtls_context_t *)coap_session->context->dtls_context;
326  if (coap_session->tls) {
327  dtls_peer_t *peer = dtls_get_peer(ctx, (session_t *)coap_session->tls);
328  if ( peer )
329  dtls_reset_peer(ctx, peer);
330  else
331  dtls_close(ctx, (session_t *)coap_session->tls);
332  coap_log(LOG_DEBUG, "***removed session %p\n", coap_session->tls);
333  coap_free_type(COAP_DTLS_SESSION, coap_session->tls);
334  coap_session->tls = NULL;
335  }
336 }
337 
338 int
340  const uint8_t *data,
341  size_t data_len
342 ) {
343  int res;
344 
345  coap_log(LOG_DEBUG, "call dtls_write\n");
346 
347  coap_event_dtls = -1;
348  res = dtls_write((struct dtls_context_t *)session->context->dtls_context,
349  (session_t *)session->tls, (uint8 *)data, data_len);
350 
351  if (res < 0)
352  coap_log(LOG_WARNING, "coap_dtls_send: cannot send PDU\n");
353 
354  if (coap_event_dtls >= 0) {
355  coap_handle_event(session->context, coap_event_dtls, session);
356  if (coap_event_dtls == COAP_EVENT_DTLS_CONNECTED)
357  coap_session_connected(session);
358  else if (coap_event_dtls == DTLS_ALERT_CLOSE_NOTIFY || coap_event_dtls == COAP_EVENT_DTLS_ERROR)
360  }
361 
362  return res;
363 }
364 
366  return 1;
367 }
368 
369 coap_tick_t coap_dtls_get_context_timeout(void *dtls_context) {
370  clock_time_t next = 0;
371  dtls_check_retransmit((struct dtls_context_t *)dtls_context, &next);
372  if (next > 0)
373  return ((coap_tick_t)(next - dtls_tick_0)) * COAP_TICKS_PER_SECOND / DTLS_TICKS_PER_SECOND + coap_tick_0;
374  return 0;
375 }
376 
378  (void)session;
379  return 0;
380 }
381 
383  (void)session;
384  return;
385 }
386 
387 int
389  const uint8_t *data,
390  size_t data_len
391 ) {
392  session_t *dtls_session = (session_t *)session->tls;
393  int err;
394 
395  coap_event_dtls = -1;
396  err = dtls_handle_message(
397  (struct dtls_context_t *)session->context->dtls_context,
398  dtls_session, (uint8 *)data, (int)data_len);
399 
400  if (err){
401  coap_event_dtls = COAP_EVENT_DTLS_ERROR;
402  }
403 
404  if (coap_event_dtls >= 0) {
405  coap_handle_event(session->context, coap_event_dtls, session);
406  if (coap_event_dtls == COAP_EVENT_DTLS_CONNECTED)
407  coap_session_connected(session);
408  else if (coap_event_dtls == DTLS_ALERT_CLOSE_NOTIFY || coap_event_dtls == COAP_EVENT_DTLS_ERROR)
410  }
411 
412  return err;
413 }
414 
415 int
417  const uint8_t *data,
418  size_t data_len
419 ) {
420  session_t dtls_session;
421  struct dtls_context_t *dtls_context =
422  (struct dtls_context_t *)session->context->dtls_context;
423 
424  dtls_session_init(&dtls_session);
425  put_session_addr(&session->remote_addr, &dtls_session);
426  dtls_session.ifindex = session->ifindex;
427  int res = dtls_handle_message(dtls_context, &dtls_session,
428  (uint8 *)data, (int)data_len);
429  if (res >= 0) {
430  if (dtls_get_peer(dtls_context, &dtls_session))
431  res = 1;
432  else
433  res = 0;
434  }
435  return res;
436 }
437 
438 unsigned int coap_dtls_get_overhead(coap_session_t *session) {
439  (void)session;
440  return 13 + 8 + 8;
441 }
442 
443 #ifdef __GNUC__
444 #define UNUSED __attribute__((unused))
445 #else /* __GNUC__ */
446 #define UNUSED
447 #endif /* __GNUC__ */
448 
449 int coap_tls_is_supported(void) {
450  return 0;
451 }
452 
455  static coap_tls_version_t version;
456  version.version = DTLS_VERSION;
458  return &version;
459 }
460 
461 int
463  coap_dtls_pki_t* setup_data UNUSED,
464  int server UNUSED
465 ) {
466  return 0;
467 }
468 
469 int
471  const char *ca_file UNUSED,
472  const char *ca_path UNUSED
473 ) {
474  return 0;
475 }
476 
477 int
479  const char *hint UNUSED,
480  int server UNUSED
481 ) {
482  return 1;
483 }
484 
485 int
487 {
488  return 1;
489 }
490 
491 void *coap_tls_new_client_session(coap_session_t *session UNUSED, int *connected UNUSED) {
492  return NULL;
493 }
494 
495 void *coap_tls_new_server_session(coap_session_t *session UNUSED, int *connected UNUSED) {
496  return NULL;
497 }
498 
499 void coap_tls_free_session(coap_session_t *coap_session UNUSED) {
500 }
501 
502 ssize_t coap_tls_write(coap_session_t *session UNUSED,
503  const uint8_t *data UNUSED,
504  size_t data_len UNUSED
505 ) {
506  return -1;
507 }
508 
509 ssize_t coap_tls_read(coap_session_t *session UNUSED,
510  uint8_t *data UNUSED,
511  size_t data_len UNUSED
512 ) {
513  return -1;
514 }
515 
516 #undef UNUSED
517 
518 #else /* !HAVE_LIBTINYDTLS */
519 
520 #ifdef __clang__
521 /* Make compilers happy that do not like empty modules. As this function is
522  * never used, we ignore -Wunused-function at the end of compiling this file
523  */
524 #pragma GCC diagnostic ignored "-Wunused-function"
525 #endif
526 static inline void dummy(void) {
527 }
528 
529 #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:889
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:1369
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:2310
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:323
The structure used for defining the PKI setup data to be used.
Definition: coap_dtls.h:190
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:380
#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