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