• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// -*- mode:doc; -*-
2// vim: set syntax=asciidoc,tw=0:
3
4coap_endpoint_server(3)
5=======================
6:doctype: manpage
7:man source:   coap_endpoint_server
8:man version:  @PACKAGE_VERSION@
9:man manual:   libcoap Manual
10
11NAME
12----
13coap_endpoint_server,
14coap_context_set_pki,
15coap_context_set_pki_root_cas,
16coap_context_set_psk2,
17coap_new_endpoint,
18coap_free_endpoint,
19coap_endpoint_set_default_mtu,
20coap_join_mcast_group_intf
21- Work with CoAP server endpoints
22
23SYNOPSIS
24--------
25*#include <coap@LIBCOAP_API_VERSION@/coap.h>*
26
27*int coap_context_set_pki(coap_context_t *_context_,
28const coap_dtls_pki_t *_setup_data_);*
29
30*int coap_context_set_pki_root_cas(coap_context_t *_context_,
31const char *_ca_file_, const char *_ca_dir_);*
32
33*int coap_context_set_psk2(coap_context_t *_context_,
34coap_dtls_spsk_t *setup_data);*
35
36*coap_endpoint_t *coap_new_endpoint(coap_context_t *_context_,
37const coap_address_t *_listen_addr_, coap_proto_t _proto_);*
38
39*void coap_free_endpoint(coap_endpoint_t *_endpoint_);*
40
41*void coap_endpoint_set_default_mtu(coap_endpoint_t *_endpoint_,
42unsigned _mtu_);*
43
44*int coap_join_mcast_group_intf(coap_context_t *_context_,
45const char *_groupname_, const char *_ifname_);*
46
47For specific (D)TLS library support, link with
48*-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*,
49*-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls*
50or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*.   Otherwise, link with
51*-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support.
52
53DESCRIPTION
54-----------
55This man page focuses on the setting up of a CoAP server endpoint. For a CoAP
56client endpoint, see *coap_endpoint_client*(3).
57
58The CoAP stack's global state is stored in a coap_context_t Context object.
59Resources, Endpoints and Sessions are associated with this context object.
60There can be more than one coap_context_t object per application, it is up to
61the application to manage each one accordingly.
62
63A CoAP Session maintains the state of an ongoing connection between a Client
64and Server which is stored in a coap_session_t Session object. A CoAP session
65is tracked by local port, CoAP protocol, remote IP address and remote port.
66
67The Session network traffic can be encrypted or un-encrypted if there is an
68underlying TLS library.
69
70If TLS is going to be used for encrypting the network traffic, then the TLS
71information for Pre-Shared Keys (PSK) or Public Key Infrastructure (PKI) needs
72to be configured before any network traffic starts to flow. For Servers, this
73has to be done before the Endpoint is created, for Clients, this is done
74during the Client Session set up.
75
76For Servers, all the encryption information is held internally by the TLS
77Context level and the CoAP Context level as the Server is listening for new
78incoming traffic based on the Endpoint definition.  The TLS and CoAP session
79will not get built until the new traffic starts, which is done by the libcoap
80library.
81
82In principle the set-up sequence for CoAP Servers looks like
83----
84coap_new_context()
85coap_context_set_pki_root_cas() - if the root CAs need to be updated and PKI
86coap_context_set_pki() and/or coap_context_set_psk2() - if encryption is required
87coap_new_endpoint()
88----
89
90Multiple endpoints can be set up per Context, each listening for a new traffic
91flow with different TCP/UDP protocols, TLS protocols, port numbers etc. When a
92new traffic flow is started, then the CoAP library will create and start a new
93server session.
94
95The *coap_context_set_pki*() function, for a specific _context_, is used to
96configure the TLS context using the _setup_data_ variables as defined in the
97coap_dtls_pki_t structure  - see *coap_encryption*(3).
98
99The *coap_context_set_pki_root_cas*() function is used to define a set of
100root CAs to be used instead of the default set of root CAs provided as a part
101of the TLS library.  _ca_file_ points to a PEM encoded file containing the
102list of CAs.  _ca_file can be NULL.  _ca_dir_ points to a directory
103containing a set of PEM encoded files containing rootCAs.  _ca_dir_ can be
104NULL. One or both of _ca_file_ and _ca_dir_ must be set. +
105*NOTE:* Some TLS libraries send the full list of CAs added by this function
106during the (D)TLS session setup handshakes. To stop this, either provide a
107single CA using the _ca_file_ definition in _pki_key_ in _setup_data_ variable
108when calling *coap_context_set_pki*(), or set _check_common_ca to 0 in
109_setup_data_ variable. See *coap_encryption*(3).
110
111The *coap_context_set_psk2*() function is used to configure the TLS context
112using the _setup_data_ variables as defined in the
113coap_dtls_spsk_t structure  - see *coap_encryption*(3).
114This function can only be used for servers as _setup_data_ provides
115a _hint_, not an _identity_.
116
117The *coap_new_endpoint*() function creates a new endpoint for _context_ that
118is listening for new traffic on the IP address and port number defined by
119_listen_addr_. If the port number is 0, then the default CoAP port is used.
120Different CoAP protocols can be defined for _proto_ - the current supported
121list is:
122
123[source, c]
124----
125COAP_PROTO_UDP
126COAP_PROTO_DTLS
127COAP_PROTO_TCP
128COAP_PROTO_TLS
129----
130
131*coap_tcp_is_supported*(), *coap_dtls_is_supported*() and
132*coap_tls_is_supported*() can be used for checking whether the underlying
133TCP or (D)TLS protocol support is available.  See *coap_tls_library(3)* for
134further information.
135
136When traffic starts to come in from a client, a server CoAP Session is created
137associated with this endpoint. This CoAP Session is created with a reference
138count of 0. This means that if the server session is not used for 5 minutes,
139then it will get completely freed off.  See coap_session_reference(3) and
140coap_session_release(3) for further information.
141
142The *coap_free_endpoint*() function must be used to free off the _endpoint_.
143It clears out all the sessions associated with this endpoint.
144
145The *coap_endpoint_set_default_mtu*() function is used to set the MTU size
146(the maximum message size) of the data in a packet, excluding any IP or
147TCP/UDP overhead to _mtu_ for the _endpoint_.  A sensible default is 1280.
148
149The *coap_join_mcast_group_intf*() function is used to join the currently
150defined endpoints that are UDP, associated with _context_, to the defined
151multicast group _groupname_.  If _ifname_ is not NULL, then the multicast group
152is associated with this interface, otherwise the underlying O/S will choose the
153first appropriate interface. When the endpoint is freed off, the associated
154multicast group will be removed. The registered multicast addresses for CoAP
155are 224.0.1.187, ff0x::fd (Variable-Scope) - i.e. ff02::fd (Link-Local) and
156ff05::fd (Site-Local).
157
158RETURN VALUES
159-------------
160*coap_context_set_pki*(), *coap_context_set_pki_root_cas*() and
161*coap_context_set_psk2*() functions return 1 on success, 0 on failure.
162
163*coap_new_endpoint*() function returns a newly created endpoint or
164NULL if there is a creation failure.
165
166*coap_join_mcast_group_intf*() returns 0 on success, -1 on failure.
167
168EXAMPLES
169--------
170*CoAP Server Non-Encrypted Setup*
171
172[source, c]
173----
174#include <coap@LIBCOAP_API_VERSION@/coap.h>
175
176static coap_context_t *
177setup_server_context (void) {
178  coap_endpoint_t *endpoint;
179  coap_address_t listen_addr;
180  coap_context_t *context = coap_new_context(NULL);
181
182  if (!context)
183    return NULL;
184  /* See coap_block(3) */
185  coap_context_set_block_mode(context,
186                              COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
187
188
189  coap_address_init(&listen_addr);
190  listen_addr.addr.sa.sa_family = AF_INET;
191  listen_addr.addr.sin.sin_port = htons (5683);
192
193  endpoint = coap_new_endpoint(context, &listen_addr, COAP_PROTO_UDP);
194  if (!endpoint) {
195    coap_free_context(context);
196    return NULL;
197  }
198
199  /* Initialize resources - See coap_resource(3) init_resources() example */
200
201  return context;
202}
203----
204
205*CoAP Server DTLS PKI Setup*
206[source, c]
207----
208#include <coap@LIBCOAP_API_VERSION@/coap.h>
209
210typedef struct valid_cns_t {
211  size_t count;
212  char **cn_list;
213} valid_cns_t;
214
215/*
216 * Common Name (CN) Callback verifier
217 */
218static int
219verify_cn_callback(const char *cn,
220                   const uint8_t *asn1_public_cert,
221                   size_t asn1_length,
222                   coap_session_t *c_session,
223                   unsigned depth,
224                   int validated,
225                   void *arg
226) {
227  valid_cns_t *valid_cn_list = (valid_cns_t*)arg;
228  size_t i;
229  /* Remove (void) definition if variable is used */
230  (void)asn1_public_cert;
231  (void)asn1_length;
232  (void)c_session;
233  (void)depth;
234  (void)validated;
235
236  /* Check that the CN is valid */
237  for (i = 0; i < valid_cn_list->count; i++) {
238    if (!strcasecmp(cn, valid_cn_list->cn_list[i])) {
239      return 1;
240    }
241  }
242  return 0;
243}
244
245typedef struct sni_def_t {
246  char* sni;
247  coap_dtls_key_t key;
248} sni_def_t;
249
250typedef struct valid_snis_t {
251  size_t count;
252  sni_def_t *sni_list;
253} valid_snis_t;
254
255/*
256 * Subject Name Identifier (SNI) callback verifier
257 */
258static coap_dtls_key_t *
259verify_pki_sni_callback(const char *sni,
260                        void *arg
261) {
262  valid_snis_t *valid_sni_list = (valid_snis_t *)arg;
263  size_t i;
264
265  /* Check that the SNI is valid */
266  for (i = 0; i < valid_sni_list->count; i++) {
267    if (!strcasecmp(sni, valid_sni_list->sni_list[i].sni)) {
268      return &valid_sni_list->sni_list[i].key;
269    }
270  }
271  return NULL;
272}
273
274/*
275 * Set up PKI encryption information
276 */
277static coap_context_t *
278setup_server_context_pki (const char *public_cert_file,
279                          const char *private_key_file,
280                          const char *ca_file,
281                          valid_cns_t *valid_cn_list,
282                          valid_snis_t *valid_sni_list
283) {
284  coap_endpoint_t *endpoint;
285  coap_address_t listen_addr;
286  coap_dtls_pki_t dtls_pki;
287  coap_context_t *context;
288
289  /* See coap_tls_library(3) */
290  if (!coap_dtls_is_supported())
291    return NULL;
292
293  context = coap_new_context(NULL);
294  if (!context)
295    return NULL;
296  /* See coap_block(3) */
297  coap_context_set_block_mode(context,
298                              COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
299
300
301  memset (&dtls_pki, 0, sizeof (dtls_pki));
302
303  /* see coap_encryption(3) */
304  dtls_pki.version                 = COAP_DTLS_PKI_SETUP_VERSION;
305  dtls_pki.verify_peer_cert        = 1;
306  dtls_pki.check_common_ca         = 1;
307  dtls_pki.allow_self_signed       = 1;
308  dtls_pki.allow_expired_certs     = 1;
309  dtls_pki.cert_chain_validation   = 1;
310  dtls_pki.cert_chain_verify_depth = 1;
311  dtls_pki.check_cert_revocation   = 1;
312  dtls_pki.allow_no_crl            = 1;
313  dtls_pki.allow_expired_crl       = 1;
314  dtls_pki.allow_bad_md_hash       = 0;
315  dtls_pki.allow_short_rsa_length  = 0;
316  dtls_pki.is_rpk_not_cert         = 0; /* Set to 1 if RPK */
317  dtls_pki.validate_cn_call_back   = verify_cn_callback;
318  dtls_pki.cn_call_back_arg        = valid_cn_list;
319  dtls_pki.validate_sni_call_back  = verify_pki_sni_callback;
320  dtls_pki.sni_call_back_arg       = valid_sni_list;
321  dtls_pki.additional_tls_setup_call_back = NULL;
322  dtls_pki.client_sni              = NULL;
323  dtls_pki.pki_key.key_type        = COAP_PKI_KEY_PEM;
324  dtls_pki.pki_key.key.pem.ca_file = ca_file;
325  dtls_pki.pki_key.key.pem.public_cert = public_cert_file;
326  dtls_pki.pki_key.key.pem.private_key = private_key_file;
327
328  if (coap_context_set_pki(context, &dtls_pki)) {
329    coap_free_context(context);
330    return NULL;
331  }
332
333  coap_address_init(&listen_addr);
334  listen_addr.addr.sa.sa_family = AF_INET;
335  listen_addr.addr.sin.sin_port = htons (5684);
336
337  endpoint = coap_new_endpoint(context, &listen_addr, COAP_PROTO_DTLS);
338  if (!endpoint) {
339    coap_free_context(context);
340    return NULL;
341  }
342
343  /* Initialize resources - See coap_resource(3) init_resources() example */
344
345  return context;
346}
347----
348
349*CoAP Server DTLS PSK Setup*
350[source, c]
351----
352#include <coap@LIBCOAP_API_VERSION@/coap.h>
353
354typedef struct id_def_t {
355  char* id;
356  coap_bin_const_t key;
357} id_def_t;
358
359typedef struct valid_ids_t {
360  int count;
361  id_def_t *id_list;
362} valid_ids_t;
363
364/*
365 * PSK Identity Pre-Shared Key selection Callback function
366 */
367static const coap_bin_const_t *
368verify_id_callback(coap_bin_const_t *identity,
369                   coap_session_t *c_session,
370                   void *arg
371) {
372  valid_ids_t *valid_id_list = (valid_ids_t*)arg;
373  int i;
374  /* Remove (void) definition if variable is used */
375  (void)c_session;
376
377  /* Check that the Identity is valid */
378  for (i = 0; i < valid_id_list->count; i++) {
379    if (!strcasecmp((const char*)identity->s, valid_id_list->id_list[i].id)) {
380      return &valid_id_list->id_list[i].key;
381    }
382  }
383  return NULL;
384}
385
386typedef struct sni_psk_def_t {
387  char* sni;
388  coap_dtls_spsk_info_t psk_info;
389} sni_psk_def_t;
390
391typedef struct valid_psk_snis_t {
392  int count;
393  sni_psk_def_t *sni_list;
394} valid_psk_snis_t;
395
396/*
397 * PSK Subject Name Identifier (SNI) callback verifier
398 */
399static const coap_dtls_spsk_info_t *
400verify_psk_sni_callback(const char *sni,
401                        coap_session_t *c_session,
402                        void *arg
403) {
404  valid_psk_snis_t *valid_sni_list = (valid_psk_snis_t *)arg;
405  int i;
406  /* Remove (void) definition if variable is used */
407  (void)c_session;
408
409  /* Check that the SNI is valid */
410  for (i = 0; i < valid_sni_list->count; i++) {
411    if (!strcasecmp(sni, valid_sni_list->sni_list[i].sni)) {
412      return &valid_sni_list->sni_list[i].psk_info;
413    }
414  }
415  return NULL;
416}
417
418static coap_context_t *
419setup_server_context_psk (const char *hint,
420                          const uint8_t *key,
421                          unsigned int key_len,
422                          valid_ids_t *valid_id_list,
423                          valid_psk_snis_t *valid_sni_list
424) {
425  coap_endpoint_t *endpoint;
426  coap_address_t listen_addr;
427  coap_context_t *context;
428  coap_dtls_spsk_t dtls_psk;
429
430  /* See coap_tls_library(3) */
431  if (!coap_dtls_is_supported())
432    return NULL;
433
434  context = coap_new_context(NULL);
435  if (!context)
436    return NULL;
437  /* See coap_block(3) */
438  coap_context_set_block_mode(context,
439                              COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
440
441
442  memset (&dtls_psk, 0, sizeof (dtls_psk));
443
444  /* see coap_encryption(3) */
445  dtls_psk.version                 = COAP_DTLS_SPSK_SETUP_VERSION;
446  dtls_psk.validate_id_call_back   = verify_id_callback;
447  dtls_psk.id_call_back_arg        = valid_id_list;
448  dtls_psk.validate_sni_call_back  = verify_psk_sni_callback;
449  dtls_psk.sni_call_back_arg       = valid_sni_list;
450  dtls_psk.psk_info.hint.s         = (const uint8_t*)hint;
451  dtls_psk.psk_info.hint.length    = hint ? strlen(hint) : 0;
452  dtls_psk.psk_info.key.s          = key;
453  dtls_psk.psk_info.key.length     = key_len;
454
455  if (coap_context_set_psk2(context, &dtls_psk)) {
456    coap_free_context(context);
457    return NULL;
458  }
459
460  coap_address_init(&listen_addr);
461  listen_addr.addr.sa.sa_family = AF_INET;
462  listen_addr.addr.sin.sin_port = htons (5684);
463
464  endpoint = coap_new_endpoint(context, &listen_addr, COAP_PROTO_DTLS);
465  if (!endpoint) {
466    coap_free_context(context);
467    return NULL;
468  }
469
470  /* Initialize resources - See coap_resource(3) init_resources() example */
471
472  return context;
473}
474----
475
476*CoAP Client DTLS PSK Setup*
477[source, c]
478----
479#include <coap@LIBCOAP_API_VERSION@/coap.h>
480
481#include <stdio.h>
482
483#ifndef min
484#define min(a,b) ((a) < (b) ? (a) : (b))
485#endif
486
487static const coap_dtls_cpsk_info_t *
488verify_ih_callback(coap_str_const_t *hint,
489                   coap_session_t *c_session,
490                   void *arg
491) {
492  coap_dtls_cpsk_info_t *psk_info = (coap_dtls_cpsk_info_t *)arg;
493  char lhint[COAP_DTLS_HINT_LENGTH];
494  /* Remove (void) definition if variable is used */
495  (void)c_session;
496
497  snprintf(lhint, sizeof(lhint), "%.*s", (int)hint->length, hint->s);
498  coap_log(LOG_INFO, "Identity Hint '%s' provided\n", lhint);
499
500  /* Just use the defined information for now as passed in by arg */
501  return psk_info;
502}
503
504static coap_dtls_cpsk_t dtls_psk;
505static char client_sni[256];
506
507static coap_session_t *
508setup_client_session_psk (const char *uri,
509                          struct in_addr ip_address,
510                          const uint8_t *identity,
511                          unsigned int identity_len,
512                          const uint8_t *key,
513                          unsigned int key_len
514) {
515  coap_session_t *session;
516  coap_address_t server;
517  coap_context_t *context = coap_new_context(NULL);
518
519  if (!context)
520    return NULL;
521  /* See coap_block(3) */
522  coap_context_set_block_mode(context,
523                              COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
524
525
526  coap_address_init(&server);
527  server.addr.sa.sa_family = AF_INET;
528  server.addr.sin.sin_addr = ip_address;
529  server.addr.sin.sin_port = htons (5684);
530
531  /* See coap_encryption(3) */
532  memset (&dtls_psk, 0, sizeof(dtls_psk));
533  dtls_psk.version = COAP_DTLS_CPSK_SETUP_VERSION;
534  dtls_psk.validate_ih_call_back = verify_ih_callback;
535  dtls_psk.ih_call_back_arg = &dtls_psk.psk_info;
536  if (uri)
537    memcpy(client_sni, uri, min(strlen(uri), sizeof(client_sni)-1));
538  else
539    memcpy(client_sni, "localhost", 9);
540  dtls_psk.client_sni = client_sni;
541  dtls_psk.psk_info.identity.s = identity;
542  dtls_psk.psk_info.identity.length = identity_len;
543  dtls_psk.psk_info.key.s = key;
544  dtls_psk.psk_info.key.length = key_len;
545  session = coap_new_client_session_psk2(context, NULL, &server,
546                                        COAP_PROTO_DTLS, &dtls_psk);
547  if (!session) {
548    coap_free_context(context);
549    return NULL;
550  }
551  /* The context is in session->context */
552  return session;
553}
554
555----
556
557SEE ALSO
558--------
559*coap_block*(3), *coap_context*(3), *coap_encryption*(3),
560*coap_endpoint_client*()3), *coap_resource*(3), *coap_session*(3) and
561*coap_tls_library*(3)
562
563FURTHER INFORMATION
564-------------------
565See "RFC7252: The Constrained Application Protocol (CoAP)" for further
566information.
567
568BUGS
569----
570Please report bugs on the mailing list for libcoap:
571libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at
572https://github.com/obgm/libcoap/issues
573
574AUTHORS
575-------
576The libcoap project <libcoap-developers@lists.sourceforge.net>
577