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