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