1COAP_ENCRYPTION(3) libcoap Manual COAP_ENCRYPTION(3)
2
3
4
6 coap_encryption, coap_dtls_cpsk_t, coap_dtls_spsk_t, coap_dtls_pki_t -
7 Work with CoAP TLS/DTLS
8
10 #include <coap3/coap.h>
11
12 struct coap_dtls_cpsk_t;
13
14 struct coap_dtls_spsk_t;
15
16 struct coap_dtls_pki_t;
17
18 For specific (D)TLS library support, link with -lcoap-3-notls,
19 -lcoap-3-gnutls, -lcoap-3-openssl, -lcoap-3-mbedtls or
20 -lcoap-3-tinydtls. Otherwise, link with -lcoap-3 to get the default
21 (D)TLS library support.
22
24 This man page focuses on setting up CoAP to use encryption.
25
26 When the libcoap library was built, it will have been compiled using a
27 specific underlying TLS implementation type (e.g. OpenSSL, GnuTLS, Mbed
28 TLS, TinyDTLS or noTLS). When the libcoap library is linked into an
29 application, it is possible that the application needs to dynamically
30 determine whether DTLS or TLS is supported, what type of TLS
31 implementation libcoap was compiled with, as well as detect what is the
32 version of the currently loaded TLS library.
33
34 NOTE: If OpenSSL is being used, then the minimum supported OpenSSL
35 library version is 1.1.0.
36
37 NOTE: If GnuTLS is being used, then the minimum GnuTLS library version
38 is 3.3.0.
39
40 NOTE: If Mbed TLS is being used, then the minimum Mbed TLS library
41 version is 2.7.10.
42
43 NOTE: If GnuTLS is going to interoperate with TinyDTLS, then a minimum
44 revision of GnuTLS 3.5.5 which supports CCM algorithms is required by
45 TinyDTLS as TinyDTLS currently only supports CCM.
46
47 NOTE: For Raw Public Key support, GnuTLS library version must be 3.6.6
48 or later. TinyDTLS only supports TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
49 curve secp256r1 and hash SHA-256. There currently is no OpenSSL or Mbed
50 TLS RPK support (respective library limitations).
51
52 Network traffic can be un-encrypted or encrypted with libcoap if there
53 is an underlying TLS library.
54
55 If TLS is going to be used for encrypting the network traffic, then the
56 TLS information for Pre-Shared Keys (PSK), Public Key Infrastructure
57 (PKI) or Raw Public Key (RPK) needs to be configured before any network
58 traffic starts to flow. For Servers, this has to be done before the
59 Endpoint is created, for Clients, this is done during the Client
60 Session set up.
61
62 For Servers, all the encryption information is held internally by the
63 TLS Context level and the CoAP Context level as the Server is listening
64 for new incoming traffic based on the Endpoint definition. The TLS and
65 CoAP session will not get built until the new traffic starts, which is
66 done by the libcoap library, with the session having a reference count
67 of 1.
68
69 For Clients, all the encryption information will be held internally by
70 the TLS Context and/or TLS Session level and internally by the CoAP
71 Session level.
72
73 In principle the set-up sequence for CoAP Servers looks like
74
75 coap_new_context()
76 coap_context_set_pki_root_cas() - if the root CAs need to be updated and PKI
77 coap_context_set_pki() and/or coap_context_set_psk2() - if encryption is required
78 coap_new_endpoint()
79
80 Multiple endpoints can be set up per Context, each listening for a new
81 traffic flow with different TCP/UDP protocols, TLS protocols, port
82 numbers etc. When a new traffic flow is started, then the CoAP library
83 will create and start a new server session.
84
85 In principle the set-up sequence for CoAP Clients looks like
86
87 coap_new_context()
88 coap_context_set_pki_root_cas() - if the root CAs need to be updated and PKI
89 coap_new_client_session(), coap_new_client_session_pki() or coap_new_client_session_psk2()
90
91 Multiple client sessions are supported per Context.
92
93 Due to the nature of TLS, there are Callbacks that are invoked as the
94 TLS session negotiates encryption algorithms, encryption keys etc.
95 Where possible, the CoAP layer handles all this automatically based on
96 different configuration options passed in by the
97 coap_context_set_pki(), coap_new_client_session_pki(),
98 coap_context_set_psk2() and coap_new_client_session_psk2() functions.
99
101 For Client PSK setup, the required information needs to be provided in
102 the setup calls with optional application callbacks defined to update
103 the Identity and PSK. Initially, the Client has to provide an Identity
104 and a Pre-Shared Key.
105
106 Libcoap will put the Identity and Pre-Shared Key as appropriate into
107 the TLS environment.
108
109 SECTION: PSK Client: coap_dtls_cpsk_t
110
111 typedef struct coap_dtls_cpsk_t {
112 uint8_t version; /** Set to COAP_DTLS_CPSK_SETUP_VERSION
113 to support the version of the struct */
114
115 /* Options to enable different TLS functionality in libcoap */
116 uint8_t reserved[7]; /* Reserved - must be set to 0 for
117 future compatibility */
118
119 /** Identity Hint check callback function.
120 * If not NULL, is called when the Identity Hint (TLS1.2 or earlier) is
121 * provided by the server.
122 * The appropriate Identity and Pre-Shared Key to use can then be returned.
123 */
124 coap_dtls_ih_callback_t validate_ih_call_back;
125 void *ih_call_back_arg; /* Passed in to the Identity Hint callback
126 function */
127
128 char* client_sni; /* If not NULL, SNI to use in client TLS setup.
129 Owned by the client app and must remain valid
130 during the call to coap_new_client_session_pki().
131 Note: Not supported by TinyDTLS. */
132
133 coap_dtls_cpsk_info_t psk_info; /* Client PSK definition */
134 } coap_dtls_cpsk_t;
135
136 More detailed explanation of the coap_dtls_cpsk_t structure follows.
137
138 WARNING: For all the parameter definitions that are pointers to other
139 locations, these locations must remain valid during the lifetime of all
140 the underlying TLS sessions that are, or will get created based on this
141 PSK definition.
142
143 SECTION: PSK Client: coap_dtls_cpsk_t: Version
144
145 #define COAP_DTLS_CPSK_SETUP_VERSION 1 /**< Latest CPSK setup version */
146
147 version is set to COAP_DTLS_CPSK_SETUP_VERSION. This will then allow
148 support for different versions of the coap_dtls_cpsk_t structure in the
149 future.
150
151 SECTION: PSK Client: coap_dtls_cpsk_t: Reserved
152
153 reserved All must be set to 0. Future functionality updates will make
154 use of these reserved definitions.
155
156 SECTION: PSK Client: coap_dtls_cpsk_t: Identity Hint Callback
157
158 /**
159 * Identity Hint Validation callback that can be set up by
160 * coap_new_client_session_psk2().
161 * Invoked when libcoap has done the validation checks at the TLS level,
162 * but the application needs to check that the Identity Hint is allowed, and
163 * needs to use the appropriate PSK information for the (D)TLS session.
164 * Note: Identity Hint is not supported in (D)TLS1.3.
165 *
166 * @param hint The server provided Identity Hint
167 * @param coap_session The CoAP session associated with the Identity Hint
168 * @param arg The same as was passed into coap_new_client_session_psk2()
169 * in setup_data->ih_call_back_arg
170 *
171 * @return New coap_dtls_cpsk_info_t object or @c NULL on error.
172 */
173 typedef const coap_dtls_cpsk_info_t *(*coap_dtls_ih_callback_t)(
174 coap_str_const_t *hint,
175 coap_session_t *coap_session,
176 void *arg);
177
178 validate_ih_call_back points to an application provided Identity Hint
179 callback function or NULL. The application can make use of this
180 Identity Hint information to decide what Identity and Pre-Shared Key
181 should be used for this session. The Callback returns the new
182 coap_dtls_cpsk_info_t on success, or NULL if the Identity Hint is
183 unacceptable.
184
185 NOTE: The Server may not provide a hint, or a zero length hint to
186 indicate there is no hint. In this case the initially provided Identity
187 and Pre-Shared Key should be used.
188
189 ih_call_back_arg points to a user defined set of data that will get
190 passed in to the validate_ih_call_back() function’s arg parameter and
191 can be used by that function. An example would be a set of Identity
192 Hints that map into new Identity / Pre-Shared Key to use.
193
194 SECTION: PSK Client: coap_dtls_cpsk_t: Subject Name Indicator (SNI)
195 Definition
196
197 client_sni points to the SNI name that will be added in as a TLS
198 extension, if not NULL. This typically is the DNS name of the server
199 that the client is trying to contact. The server is then able to
200 decide, based on the name in the SNI extension, whether, for example, a
201 different Hint and/or Pre-Shared Key is to be used.
202
203 Note: Not supported by TinyDTLS.
204
205 SECTION: PSK Client: coap_dtls_cpsk_t: PSK Client Definitions
206
207 typedef struct coap_dtls_cpsk_info_t {
208 coap_bin_const_t identity; /* The Identity */
209 coap_bin_const_t key; /* The Pre-Shared Key */
210 } coap_dtls_cpsk_info_t;
211
212 identity defines the Identity to use.
213
214 key defines the Pre-Shared Key to use
215
217 For PSK setup, the required information needs to be provided in the
218 setup calls with optional application Callbacks defined to update the
219 Identity Hint and Pre-SHared Key. Initially, the Server has to provided
220 with an (optional) Identity Hint and a (required) Pre-Shared Key.
221
222 Libcoap will put the Hint and Pre-Shared Key as appropriate into the
223 TLS environment.
224
225 SECTION: PSK Server: coap_dtls_spsk_t
226
227 typedef struct coap_dtls_spsk_t {
228 uint8_t version; /** Set to COAP_DTLS_SPSK_SETUP_VERSION
229 to support the version of the struct */
230
231 /* Options to enable different TLS functionality in libcoap */
232 uint8_t reserved[7]; /* Reserved - must be set to 0 for
233 future compatibility */
234
235 /** Identity check callback function.
236 * If not @p NULL, is called when the Identity is provided by the client.
237 * The appropriate Pre-Shared Key to use can then be returned.
238 */
239 coap_dtls_id_callback_t validate_id_call_back;
240 void *id_call_back_arg; /* Passed in to the Identity callback function */
241
242 /** SNI check callback function.
243 * If not @p NULL, called if the SNI is not previously seen and exexuted
244 * prior to sending an Identity Hint back to the client so that the
245 * appropriate PSK information can be used based on the requesting SNI.
246 */
247 coap_dtls_psk_sni_callback_t validate_sni_call_back;
248 void *sni_call_back_arg; /* Passed in to the SNI callback function */
249
250 coap_dtls_spsk_info_t psk_info; /* Server PSK definition */
251 } coap_dtls_spsk_t;
252
253 More detailed explanation of the coap_dtls_spsk_t structure follows.
254
255 WARNING: For all the parameter definitions that are pointers to other
256 locations, these locations must remain valid during the lifetime of all
257 the underlying TLS sessions that are, or will get created based on this
258 PSK definition.
259
260 SECTION: PSK Server: coap_dtls_spsk_t: Version
261
262 #define COAP_DTLS_SPSK_SETUP_VERSION 1 /**< Latest SPSK setup version */
263
264 version is set to COAP_DTLS_SPSK_SETUP_VERSION. This will then allow
265 support for different versions of the coap_dtls_spsk_t structure in the
266 future.
267
268 SECTION: PSK Server: coap_dtls_spsk_t: Reserved
269
270 reserved All must be set to 0. Future functionality updates will make
271 use of these reserved definitions.
272
273 SECTION: PSK Server: coap_dtls_spsk_t: Identity Validation Callback
274
275 /**
276 * Identity Validation callback that can be set up by
277 * coap_context_set_psk2().
278 * Invoked when libcoap has done the validation checks at the TLS level,
279 * but the application needs to check that the Identity is allowed, and
280 * needs to use the appropriate Pre-Shared Key for the (D)TLS session.
281 *
282 * @param identity The client provided Identity (should be NULL terminated)
283 * @param coap_session The CoAP session associated with the Identity Hint
284 * @param arg The same as was passed into coap_context_set_psk2()
285 * in setup_data->id_call_back_arg
286 *
287 * @return New coap_bin_const_t Pre-Shared Key object or @c NULL on error.
288 */
289 typedef const coap_bin_const_t *(*coap_dtls_id_callback_t)(
290 coap_bin_const_t *identity,
291 coap_session_t *coap_session,
292 void *arg);
293
294 WARNING: If both validate_id_call_back and validate_sni_call_back are
295 defined, validate_id_call_back() is invoked after
296 validate_sni_call_back(), and so if the Pre-Shared Key is changed in
297 validate_sni_call_back(), validate_id_call_back() needs to be sure that
298 the appropriate Pre-Shared Key is provided.
299
300 validate_id_call_back points to an application provided Identity
301 callback function or NULL. The application can make use of this
302 Identity information to decide what PSK should be used for this
303 session. The Callback returns the new coap_bin_const_t Pre-Shared Key
304 on success, or NULL if the Identity is unacceptable.
305
306 NOTE: The Client may be using a binary Identity that contains an
307 embedded zero. However OpenSSL and GnuTLS do not currently support
308 this.
309
310 id_call_back_arg points to a user defined set of data that will get
311 passed in to the validate_id_call_back() function and can be used by
312 that function. An example would be a set of Identities that map into
313 new Pre-Shared Keys to use.
314
315 SECTION: PSK Server: coap_dtls_spsk_t: Subject Name Identifier (SNI)
316 Callback
317
318 /**
319 * PSK SNI callback that can be set up by coap_context_set_psk2().
320 * Invoked when libcoap has done the validation checks at the TLS level,
321 * but the application needs to check that the SNI is allowed, and needs
322 * to use the appropriate PSK information for the (D)TLS session.
323 *
324 * @param sni The client provided SNI
325 * @param coap_session The CoAP session associated with the SNI
326 * @param arg The same as was passed into coap_new_client_session_psk2()
327 * in setup_data->sni_call_back_arg
328 *
329 * @return New coap_dtls_spsk_info_t object or @c NULL on error.
330 */
331 typedef const coap_dtls_spsk_info_t *(*coap_dtls_psk_sni_callback_t)(
332 const char *sni,
333 coap_session_t *coap_session,
334 void *arg);
335
336 validate_sni_call_back points to an application provided SNI callback
337 checking function or NULL. The application can make use of this SNI
338 information to decide whether the SNI is valid, and hence what new Hint
339 and Pre-Shared Key to use. Thus it is possible for the coap server to
340 host multiple domains with different Hints and PSKs allocated to each
341 SNI domain. The Callback returns a coap_dtls_spsk_info_t pointer to the
342 Hint and Pre-Shared Key to use for this SNI, or NULL if the connection
343 is to get rejected. Libcoap remembers the association between a
344 specific SNI and Hint Pre-Shared Key set and will only invoke this
345 callback if the SNI is unknown.
346
347 Note: Not supported by TinyDTLS.
348
349 sni_call_back_arg points to a user defined set of data that will get
350 passed in to the validate_sni_call_back() function and can be used by
351 that function. An example would be a set of SNIs that are allowed with
352 their matching Hint + Pre-Shared Key sets.
353
354 SECTION: PSK Server: coap_dtls_spsk_t: PSK Information Definitions
355
356 typedef struct coap_dtls_spsk_info_t {
357 coap_bin_const_t hint; /* The identity hint to use */
358 coap_bin_const_t key; /* The Pre-Shared Key to use */
359 } coap_dtls_spsk_info_t;
360
361 identity defines the Identity Hint to use.
362
363 key defines the Pre-Shared Key to use
364
366 For PKI or RPK setup, if the libcoap PKI/RPK configuration options do
367 not handle a specific requirement as defined by the available options,
368 then an application defined Callback can called to do the additional
369 specific checks.
370
371 The information passed to this Application Callback will be the TLS
372 session (as well the configuration information), but the structures
373 containing this information will be different as they will be based on
374 the underlying TLS library type. coap_get_tls_library_version() is
375 provided to help here.
376
377 Libcoap will add in the defined Certificate (or Public Key), Private
378 Key and CA Certificate into the TLS environment. The CA Certificate is
379 also added in to the list of valid CAs for Certificate checking.
380
381 The internal Callbacks (and optionally the Application Callback) will
382 then check the required information as defined in the coap_dtls_pki_t
383 described below.
384
385 SECTION: PKI/RPK: coap_dtls_pki_t
386
387 typedef struct coap_dtls_pki_t {
388 uint8_t version; /* COAP_DTLS_PKI_SETUP_VERSION */
389
390 /* Options to enable different TLS functionality in libcoap */
391 uint8_t verify_peer_cert; /* 1 if peer cert is to be verified */
392 uint8_t check_common_ca; /* 1 if peer cert is to be signed by
393 * the same CA as the local cert */
394 uint8_t allow_self_signed; /* 1 if self-signed certs are allowed */
395 uint8_t allow_self_signed; /* 1 if self-signed certs are allowed.
396 * Ignored if check_common_ca set */
397 uint8_t allow_expired_certs; /* 1 if expired certs are allowed */
398 uint8_t cert_chain_validation; /* 1 if to check cert_chain_verify_depth */
399 uint8_t cert_chain_verify_depth; /* recommended depth is 3 */
400 uint8_t check_cert_revocation; /* 1 if revocation checks wanted */
401 uint8_t allow_no_crl; /* 1 ignore if CRL not there */
402 uint8_t allow_expired_crl; /* 1 if expired crl is allowed */
403 uint8_t allow_bad_md_hash; /* 1 if unsupported MD hashes are allowed */
404 uint8_t allow_short_rsa_length; /* 1 if small RSA keysizes are allowed */
405 uint8_t is_rpk_not_cert; /* 1 is RPK instead of Public Certificate.
406 * If set, PKI key format type cannot be
407 * COAP_PKI_KEY_PEM */
408 uint8_t reserved[3]; /* Reserved - must be set to 0 for
409 future compatibility */
410
411 /** CN check callback function
412 * If not NULL, is called when the TLS connection has passed the configured
413 * TLS options above for the application to verify if the CN is valid.
414 */
415 coap_dtls_cn_callback_t validate_cn_call_back;
416 void *cn_call_back_arg; /* Passed in to the CN callback function */
417
418 /** SNI check callback function
419 * If not NULL, called if the SNI is not previously seen and prior to sending
420 * a certificate set back to the client so that the appropriate certificate
421 * set can be used based on the requesting SNI.
422 */
423 coap_dtls_sni_callback_t validate_sni_call_back;
424 void *sni_call_back_arg; /* Passed in to the SNI callback function */
425
426 /** Additional Security callback handler that is invoked when libcoap has
427 * done the standard, defined validation checks at the TLS level,
428 * If not NULL, called from within the TLS Client Hello connection
429 * setup.
430 */
431 coap_dtls_security_setup_t additional_tls_setup_call_back;
432
433 char* client_sni; /* If not NULL, SNI to use in client TLS setup.
434 Owned by the client app and must remain valid
435 during the call to coap_new_client_session_pki() */
436
437 coap_dtls_key_t pki_key; /* PKI key definition */
438 } coap_dtls_pki_t;
439
440 More detailed explanation of the coap_dtls_pki_t structure follows.
441
442 WARNING: For all the parameter definitions that are pointers to other
443 locations, these locations must remain valid during the lifetime of all
444 the underlying TLS sessions that are, or will get created based on this
445 PKI/RPK definition.
446
447 The first parameter in each subsection enables/disables the
448 functionality, the remaining parameter(s) control what happens when the
449 functionality is enabled.
450
451 SECTION: PKI/RPK: coap_dtls_pki_t: Version
452
453 #define COAP_DTLS_PKI_SETUP_VERSION 1
454
455 version is set to COAP_DTLS_PKI_SETUP_VERSION. This will then allow
456 support for different versions of the coap_dtls_pki_t structure in the
457 future.
458
459 SECTION: PKI/RPK: coap_dtls_pki_t: Peer Certificate Checking
460
461 verify_peer_cert Set to 1 to check that the peer’s certificate is valid
462 if provided, else 0. If not set, check_common_ca, allow_self_signed,
463 allow_expired_certs, cert_chain_validation, cert_chain_verify_depth,
464 check_cert_revocation, allow_no_crl, allow_expired_crl,
465 allow_bad_md_hash and allow_short_rsa_length settings are all ignored.
466
467 check_common_ca Set to 1 to check that the CA that signed the peer’s
468 certificate is the same CA that signed the local certificate else 0. If
469 set to 1 and verify_peer_cert is set to 1, then for the server, a list
470 of valid CAs are sent to client. For the client, the logic will check
471 that both the client and server certificates are signed by the same CA.
472
473 allow_self_signed Set to 1 to allow the peer (or any certificate in the
474 certificate chain) to be a self-signed certificate, else 0. If
475 check_common_ca is set, then a self-signed certificate will not be
476 allowed.
477
478 allow_expired_certs Set to 1 to allow certificates that have either
479 expired, or are not yet valid to be allowed, else 0.
480
481 SECTION: PKI/RPK: coap_dtls_pki_t: Certificate Chain Validation
482
483 cert_chain_validation Set to 1 to check that the certificate chain is
484 valid, else 0.
485
486 cert_chain_verify_depth Set to the chain depth that is to be checked.
487 This is the number of intermediate CAs in the chain. If set to 0, then
488 there can be no intermediate CA in the chain.
489
490 SECTION: PKI/RPK: coap_dtls_pki_t: Certificate Revocation
491
492 check_cert_revocation Set to 1 to check whether any certificate in the
493 chain has been revoked, else 0.
494
495 allow_no_crl Set to 1 to not check any certificate that does not have a
496 CRL, else 0.
497
498 allow_expired_crl Set to 1 to allow an certificate that has an expired
499 CRL definition to be valid, else 0.
500
501 SECTION: PKI/RPK: coap_dtls_pki_t: Other
502
503 allow_bad_md_hash Set to 1 if unsupported MD hashes are allowed, else
504 0.
505
506 allow_short_rsa_length Set to 1 if small RSA keysizes are allowed, else
507 0.
508
509 is_rpk_not_cert Set to 1 if the Certificate is actually a Raw Public
510 Key. If set, PKI key format type cannot be COAP_PKI_KEY_PEM. If set,
511 check_common_ca, allow_self_signed, allow_expired_certs,
512 cert_chain_validation, cert_chain_verify_depth, check_cert_revocation,
513 allow_no_crl, allow_expired_crl, allow_bad_md_hash and
514 allow_short_rsa_length settings are all ignored.
515
516 SECTION: PKI/RPK: coap_dtls_pki_t: Reserved
517
518 reserved All must be set to 0. Future functionality updates will make
519 use of these reserved definitions.
520
521 SECTION: PKI/RPK: coap_dtls_pki_t: Common Name (CN) Callback
522
523 #define COAP_DTLS_RPK_CERT_CN "RPK"
524
525 /**
526 * CN Validation callback that can be set up by coap_context_set_pki().
527 * Invoked when libcoap has done the validation checks at the TLS level,
528 * but the application needs to check that the CN is allowed.
529 * CN is the SubjectAltName in the cert, if not present, then the leftmost
530 * Common Name (CN) component of the subject name.
531 * NOTE: If using RPK, then the Public Key does not contain a CN, but the
532 * content of COAP_DTLS_RPK_CERT_CN is presented for the @p cn parameter.
533 *
534 * @param cn The determined CN from the certificate
535 * @param asn1_public_cert The ASN.1 encoded (DER) X.509 certificate
536 * @param asn1_length The ASN.1 length
537 * @param session The coap session associated with the certificate update
538 * @param depth Depth in cert chain. If 0, then client cert, else a CA
539 * @param validated TLS can find no issues if 1
540 * @param arg The same as was passed into coap_context_set_pki()
541 * in setup_data->cn_call_back_arg
542 *
543 * @return 1 if accepted, else 0 if to be rejected
544 */
545 typedef int (*coap_dtls_cn_callback_t)(const char *cn,
546 const uint8_t *asn1_public_cert,
547 size_t asn1_length,
548 coap_session_t *session,
549 unsigned int depth,
550 int validated,
551 void *arg);
552
553 validate_cn_call_back points to an application provided CN callback
554 checking function or NULL. The application can make use of this CN
555 information to decide, for example, that the CN is valid coming from a
556 particular peer. The Callback returns 1 on success, 0 if the TLS
557 connection is to be aborted.
558
559 cn_call_back_arg points to a user defined set of data that will get
560 passed in to the validate_cn_call_back() function and can be used by
561 that function. An example would be a set of CNs that are allowed.
562
563 SECTION: PKI/RPK: coap_dtls_pki_t: Subject Name Identifier (SNI)
564 Callback
565
566 typedef struct coap_dtls_key_t {
567 coap_pki_key_t key_type; /* key format type */
568 union {
569 coap_pki_key_pem_t pem; /* for PEM file keys */
570 coap_pki_key_pem_buf_t pem_buf; /* for PEM memory keys */
571 coap_pki_key_asn1_t asn1; /* for ASN.1 (DER) memory keys */
572 coap_pki_key_pkcs11_t pkcs11; /* for PKCS11 keys */
573 } key;
574 } coap_dtls_key_t;
575
576 /**
577 * SNI Validation callback that can be set up by coap_context_set_pki().
578 * Invoked if the SNI is not previously seen and prior to sending a certificate
579 * set back to the client so that the appropriate certificate set can be used
580 * based on the requesting SNI.
581 *
582 * @param sni The requested SNI
583 * @param arg The same as was passed into coap_context_set_pki()
584 * in setup_data->sni_call_back_arg
585 *
586 * @return new set of certificates to use, or NULL if SNI is to be rejected.
587 */
588 typedef coap_dtls_key_t *(*coap_dtls_sni_callback_t)(const char *sni,
589 void* arg);
590
591 validate_sni_call_back points to an application provided SNI callback
592 checking function or NULL. The application can make use of this SNI
593 information to decide whether the SNI is valid, and what set of
594 certificates to give to the client. Thus it is possible for the coap
595 server to host multiple domains with different certificates allocated
596 to each domain. The Callback returns a pointer to the certificates to
597 use for this SNI, or NULL if the connection it to get rejected. libcoap
598 remembers the association between the SNI and Certificate set and will
599 only invoke this callback if the SNI is unknown.
600
601 sni_call_back_arg points to a user defined set of data that will get
602 passed in to the validate_sni_call_back() function and can be used by
603 that function. An example would be a set of SNIs that are allowed with
604 their matching certificate sets.
605
606 SECTION: PKI/RPK: coap_dtls_pki_t: Application Additional Setup
607 Callback
608
609 /**
610 * Additional Security setup handler that can be set up by
611 * coap_context_set_pki().
612 * Invoked when libcoap has done the validation checks at the TLS level,
613 * but the application needs to do some additional checks/changes/updates.
614 *
615 * @param session The security session definition - e.g. SSL * for OpenSSL.
616 * This will be dependent on the underlying TLS library
617 * - see coap_get_tls_library_version()
618 * @param setup_data A structure containing setup data originally passed into
619 * coap_context_set_pki() or coap_new_client_session_pki().
620 * @return 1 if successful, else 0
621 */
622 typedef int (*coap_dtls_security_setup_t)(void *context, void* session,
623 coap_dtls_pki_t *setup_data);
624
625 additional_tls_setup_call_back points to an application provided
626 callback function that will do additional checking/changes/updates
627 after libcoap has done all of the configured TLS setup checking, or
628 NULL to do no additional checking.
629
630 SECTION: PKI/RPK: coap_dtls_pki_t: Subject Name Indicator (SNI)
631 Definition
632
633 client_sni points to the SNI name that will be added in as a TLS
634 extension, or set NULL. This typically is the DNS name of the server
635 that the client is trying to contact. This is only used by a client
636 application and the server is then able to decide, based on the name in
637 the SNI extension, whether, for example, a different certificate should
638 be provided.
639
640 SECTION: PKI/RPK: coap_dtls_pki_t: Key Type Definition
641
642 typedef enum coap_pki_key_t {
643 COAP_PKI_KEY_PEM, /* The PKI key type is PEM file */
644 COAP_PKI_KEY_ASN1, /* The PKI key type is ASN.1 (DER) buffer */
645 COAP_PKI_KEY_PEM_BUF, /* The PKI key type is PEM buffer */
646 COAP_PKI_KEY_PKCS11, /* The PKI key type is PKCS11 (DER) */
647 } coap_pki_key_t;
648
649 key_type defines the format that the certificates / keys are provided
650 in. This can be COAP_PKI_KEY_PEM, COAP_PKI_KEY_PEM_BUF,
651 COAP_PKI_KEY_ASN1 or COAP_PKI_KEY_PKCS11.
652
653 SECTION: PKI: coap_dtls_pki_t: PEM Key Definitions
654
655 typedef struct coap_pki_key_pem_t {
656 const char *ca_file; /* File location of Common CA in PEM format */
657 const char *public_cert; /* File location of Public Cert */
658 const char *private_key; /* File location of Private Key in PEM format */
659 } coap_pki_key_pem_t;
660
661 key.pem.ca_file points to the CA File location on disk which will be in
662 PEM format, or NULL. This file should only contain one CA (that has
663 signed the public certificate) as this is passed from the server to the
664 client when requesting the client’s certificate. This certificate is
665 also added into the valid root CAs list if not already present.
666
667 key.pem.public_cert points to the public certificate location on disk
668 which will be in PEM format.
669
670 key.pem.private_key points to the private key location on disk which
671 will be in PEM format. This file cannot be password protected.
672
673 SECTION: PKI/RPK: coap_dtls_pki_t: PEM Memory Key Definitions
674
675 typedef struct coap_pki_key_pem_buf_t {
676 const uint8_t *ca_cert; /* PEM buffer Common CA Cert */
677 const uint8_t *public_cert; /* PEM buffer Public Cert, or Public Key if RPK */
678 const uint8_t *private_key; /* PEM buffer Private Key */
679 If RPK and 'EC PRIVATE KEY' this can be used
680 for both the public_cert and private_key */
681 size_t ca_cert_len; /* PEM buffer CA Cert length */
682 size_t public_cert_len; /* PEM buffer Public Cert length */
683 size_t private_key_len; /* PEM buffer Private Key length */
684 } coap_pki_key_pem_buf_t;
685
686 key.pem_buf.ca_cert points to the CA location in memory which will be
687 in PEM format, or NULL. This file should only contain one CA (that has
688 signed the public certificate) as this is passed from the server to the
689 client when requesting the client’s certificate. This certificate is
690 also added into the valid root CAs list if not already present.
691
692 key.pem_buf.ca_cert_len is the length of the CA.
693
694 key.pem_buf.public_cert points to the public certificate (or public key
695 if RPK) location in memory which will be in PEM format.
696
697 key.pem_buf.public_cert_len is the length of the public certificate.
698
699 key.pem_buf.private_key points to the private key location in memory
700 which will be in PEM format. This data cannot be password protected. If
701 RPK and EC PRIVATE KEY this can be used for both the public_cert and
702 private_key.
703
704 key.pem_buf.private_key is the length of the private key.
705
706 • Note:* The PEM buffer Certs and Key should be be NULL terminated
707 strings for performance reasons (to save a potential buffer copy)
708 and the length include this NULL terminator. It is not a
709 requirement to have the NULL terminator though and the length must
710 then reflect the actual data size.
711
712 SECTION: PKI/RPK: coap_dtls_pki_t: ASN1 Key Definitions
713
714 typedef struct coap_pki_key_asn1_t {
715 const uint8_t *ca_cert; /* ASN1 Common CA Certificate */
716 const uint8_t *public_cert; /* ASN1 (DER) Public Cert, or Public Key if RPK */
717 const uint8_t *private_key; /* ASN1 Private Key */
718 int ca_cert_len; /* ASN1 CA Certificate length */
719 int public_cert_len; /* ASN1 Public Certificate length */
720 int private_key_len; /* ASN1 Private Key length */
721 coap_asn1_privatekey_type_t private_key_type; /* Private Key Type
722 COAP_ASN1_PKEY_* */
723 } coap_pki_key_asn1_t;
724
725 typedef enum coap_asn1_privatekey_type_t {
726 COAP_ASN1_PKEY_NONE,
727 COAP_ASN1_PKEY_RSA,
728 COAP_ASN1_PKEY_RSA2,
729 COAP_ASN1_PKEY_DSA,
730 COAP_ASN1_PKEY_DSA1,
731 COAP_ASN1_PKEY_DSA2,
732 COAP_ASN1_PKEY_DSA3,
733 COAP_ASN1_PKEY_DSA4,
734 COAP_ASN1_PKEY_DH,
735 COAP_ASN1_PKEY_DHX,
736 COAP_ASN1_PKEY_EC,
737 COAP_ASN1_PKEY_HMAC,
738 COAP_ASN1_PKEY_CMAC,
739 COAP_ASN1_PKEY_TLS1_PRF,
740 COAP_ASN1_PKEY_HKDF
741 } coap_asn1_privatekey_type_t;
742
743 key.asn1.ca_cert points to a DER encoded ASN.1 definition of the CA
744 Certificate, or NULL. This certificate is passed from the server to the
745 client when requesting the client’s certificate. This certificate is
746 also added into the valid root CAs list if not already present.
747
748 key.asn1.public_cert points to a DER encoded ASN.1 definition of the
749 public certificate (or public key if RPK).
750
751 key.asn1.private_key points to DER encoded ASN.1 definition of the
752 private key.
753
754 key.asn1.ca_cert_len is the length of the DER encoded ASN.1 definition
755 of the CA Certificate.
756
757 key.asn1.public_cert_len is the length of the DER encoded ASN.1
758 definition of the public certificate.
759
760 key.asn1.private_key_len is the length of the DER encoded ASN.1
761 definition of the private key.
762
763 key.asn1.private_key_type is the encoding type of the DER encoded ASN.1
764 definition of the private key. This will be one of the COAP_ASN1_PKEY_*
765 definitions.
766
767 SECTION: PKI: coap_dtls_pki_t: PKCS11 Key Definitions
768
769 typedef struct coap_pki_key_pkcs11_t {
770 const char *ca; /* pkcs11: URI for Common CA Certificate */
771 const char *public_cert; /* pkcs11: URI for Public Cert */
772 const char *private_key; /* pkcs11: URI for Private Key */
773 const char *pin; /* pin to access PKCS11. If NULL, then
774 pin-value= parameter must be set in
775 pkcs11: URI as a query. */
776 } coap_pki_key_pkcs11_t;
777
778 key.pkcs11.ca is a pkcs11: URI for the CA certificate or NULL. This is
779 for the CA (that has signed the public certificate) as this is passed
780 from the server to the client when requesting the client’s certificate.
781 This certificate is also added into the valid root CAs list if not
782 already present. An example URI is
783 pkcs11:pkcs11:token=My%20Token;id=%aa%bb%cc%dd which is for token My
784 Token and (hex) id of aabbccdd.
785
786 key.pkcs11.public_cert is a pkcs11: URI for the Public Certificate
787 which was signed by key.pkcs11.ca or NULL.
788
789 key.pkcs11.private_key is a pkcs11: URI for the Private Key for the
790 public certificate defined by key.pkcs11.public_cert or NULL.
791
792 key.pkcs11.user_pin is the user pin used to unlock the token or NULL.
793 If NULL, the pin can be defined on the other pkcs11: URI entries by
794 using pin-value=XXX as a query - e.g.
795 pkcs11:pkcs11:token=My%20Token;id=%aa%bb%cc%dd?pin-value=XXX where XXX
796 is the user pin.
797
799 CoAP Server DTLS PKI Setup
800
801 #include <coap3/coap.h>
802
803 typedef struct valid_cns_t {
804 int count;
805 char **cn_list;
806 } valid_cns_t;
807
808 /**
809 * CN Validation callback that can be set up by coap_context_set_pki().
810 * Invoked when libcoap has done the validation checks at the TLS level,
811 * but the application needs to check that the CN is allowed.
812 * CN is the SubjectAltName in the cert, if not present, then the leftmost
813 * Common Name (CN) component of the subject name.
814 * NOTE: If using RPK, then the Public Key does not contain a CN, but "RPK"
815 * is presented for the cn parameter.
816 *
817 * @param cn The determined CN from the certificate
818 * @param asn1_public_cert The ASN.1 encoded (DER) X.509 certificate
819 * @param asn1_length The ASN.1 length
820 * @param session The coap session associated with the certificate update
821 * @param depth Depth in cert chain. If 0, then client cert, else a CA
822 * @param validated TLS can find no issues if 1
823 * @param arg The same as was passed into coap_context_set_pki()
824 * in setup_data->cn_call_back_arg
825 *
826 * @return 1 if accepted, else 0 if to be rejected
827 */
828 static int
829 verify_cn_callback(const char *cn,
830 const uint8_t *asn1_public_cert,
831 size_t asn1_length,
832 coap_session_t *c_session,
833 unsigned depth,
834 int validated,
835 void *arg
836 ) {
837 valid_cns_t *valid_cn_list = (valid_cns_t*)arg;
838 int i;
839 /* Remove (void) definition if variable is used */
840 (void)asn1_public_cert;
841 (void)asn1_length;
842 (void)c_session;
843 (void)depth;
844 (void)validated;
845
846 /* Check that the CN is valid */
847 for (i = 0; i < valid_cn_list->count; i++) {
848 if (!strcasecmp(cn, valid_cn_list->cn_list[i])) {
849 return 1;
850 }
851 }
852 return 0;
853 }
854
855 typedef struct sni_def_t {
856 char* sni;
857 coap_dtls_key_t key;
858 } sni_def_t;
859
860 typedef struct valid_snis_t {
861 int count;
862 sni_def_t *sni_list;
863 } valid_snis_t;
864
865 /**
866 * SNI Validation callback that is set up by coap_context_set_pki().
867 * Invoked if the SNI is not previously seen and prior to sending a certificate
868 * set back to the client so that the appropriate certificate set can be used
869 * based on the requesting SNI.
870 *
871 * @param sni The requested SNI
872 * @param arg The same as was passed into coap_context_set_pki()
873 * in setup_data->sni_call_back_arg
874 *
875 * @return new set of certificates to use, or NULL if SNI is to be rejected.
876 */
877 static coap_dtls_key_t *
878 verify_pki_sni_callback(const char *sni,
879 void *arg
880 ) {
881 valid_snis_t *valid_sni_list = (valid_snis_t *)arg;
882 int i;
883
884 /* Check that the SNI is valid */
885 for (i = 0; i < valid_sni_list->count; i++) {
886 if (!strcasecmp(sni, valid_sni_list->sni_list[i].sni)) {
887 return &valid_sni_list->sni_list[i].key;
888 }
889 }
890 return NULL;
891 }
892
893 /*
894 * Set up PKI encryption information
895 */
896 static coap_context_t *
897 setup_server_context_pki (const char *public_cert_file,
898 const char *private_key_file,
899 const char *ca_file,
900 valid_cns_t *valid_cn_list,
901 valid_snis_t *valid_sni_list
902 ) {
903 coap_endpoint_t *endpoint;
904 coap_address_t listen_addr;
905 coap_dtls_pki_t dtls_pki;
906 coap_context_t *context;
907
908 /* See coap_tls_library(3) */
909 if (!coap_dtls_is_supported())
910 return NULL;
911
912 /* See coap_context(3) */
913 context = coap_new_context(NULL);
914 if (!context)
915 return NULL;
916 /* See coap_block(3) */
917 coap_context_set_block_mode(context,
918 COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
919
920
921 memset (&dtls_pki, 0, sizeof (dtls_pki));
922
923 dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION;
924 dtls_pki.verify_peer_cert = 1;
925 dtls_pki.check_common_ca = 1;
926 dtls_pki.allow_self_signed = 1;
927 dtls_pki.allow_expired_certs = 1;
928 dtls_pki.cert_chain_validation = 1;
929 dtls_pki.cert_chain_verify_depth = 1;
930 dtls_pki.check_cert_revocation = 1;
931 dtls_pki.allow_no_crl = 1;
932 dtls_pki.allow_expired_crl = 1;
933 dtls_pki.allow_bad_md_hash = 0;
934 dtls_pki.allow_short_rsa_length = 0;
935 dtls_pki.is_rpk_not_cert = 0; /* Set to 1 if RPK */
936 dtls_pki.validate_cn_call_back = verify_cn_callback;
937 dtls_pki.cn_call_back_arg = valid_cn_list;
938 dtls_pki.validate_sni_call_back = verify_pki_sni_callback;
939 dtls_pki.sni_call_back_arg = valid_sni_list;
940 dtls_pki.additional_tls_setup_call_back = NULL;
941 dtls_pki.client_sni = NULL;
942 dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM;
943 dtls_pki.pki_key.key.pem.ca_file = ca_file;
944 dtls_pki.pki_key.key.pem.public_cert = public_cert_file;
945 dtls_pki.pki_key.key.pem.private_key = private_key_file;
946
947 /* See coap_context(3) */
948 if (coap_context_set_pki(context, &dtls_pki)) {
949 coap_free_context(context);
950 return NULL;
951 }
952
953 coap_address_init(&listen_addr);
954 listen_addr.addr.sa.sa_family = AF_INET;
955 listen_addr.addr.sin.sin_port = htons (5684);
956
957 /* See coap_context(3) */
958 endpoint = coap_new_endpoint(context, &listen_addr, COAP_PROTO_DTLS);
959 if (!endpoint) {
960 coap_free_context(context);
961 return NULL;
962 }
963
964 /* Initialize resources - See coap_resource(3) init_resources() example */
965
966 return context;
967 }
968
969 CoAP Server DTLS PSK Setup
970
971 #include <coap3/coap.h>
972
973 typedef struct id_def_t {
974 char *hint_match;
975 coap_bin_const_t id;
976 coap_bin_const_t key;
977 } id_def_t;
978
979 typedef struct valid_ids_t {
980 size_t count;
981 id_def_t *id_list;
982 } valid_ids_t;
983
984 /*
985 * PSK Identity Pre-Shared Key selection Callback function
986 */
987 static const coap_bin_const_t *
988 verify_id_callback(coap_bin_const_t *identity,
989 coap_session_t *c_session,
990 void *arg
991 ) {
992 valid_ids_t *valid_id_list = (valid_ids_t*)arg;
993 const coap_bin_const_t *s_psk_hint = coap_session_get_psk_hint(c_session);
994 size_t i;
995
996 /* Check that the Identity is valid */
997 for (i = 0; i < valid_id_list->count; i++) {
998 if (s_psk_hint &&
999 strcmp((const char *)s_psk_hint->s,
1000 valid_id_list->id_list[i].hint_match)) {
1001 continue;
1002 }
1003 if (coap_binary_equal(identity, &valid_id_list->id_list[i].id)) {
1004 return &valid_id_list->id_list[i].key;
1005 }
1006 }
1007 return NULL;
1008 }
1009
1010 typedef struct sni_psk_def_t {
1011 char* sni;
1012 coap_dtls_spsk_info_t psk_info;
1013 } sni_psk_def_t;
1014
1015 typedef struct valid_psk_snis_t {
1016 int count;
1017 sni_psk_def_t *sni_list;
1018 } valid_psk_snis_t;
1019
1020 /*
1021 * PSK Subject Name Identifier (SNI) callback verifier
1022 */
1023 static const coap_dtls_spsk_info_t *
1024 verify_psk_sni_callback(const char *sni,
1025 coap_session_t *c_session,
1026 void *arg
1027 ) {
1028 valid_psk_snis_t *valid_sni_list = (valid_psk_snis_t *)arg;
1029 int i;
1030 /* Remove (void) definition if variable is used */
1031 (void)c_session;
1032
1033 /* Check that the SNI is valid */
1034 for (i = 0; i < valid_sni_list->count; i++) {
1035 if (!strcasecmp(sni, valid_sni_list->sni_list[i].sni)) {
1036 return &valid_sni_list->sni_list[i].psk_info;
1037 }
1038 }
1039 return NULL;
1040 }
1041
1042 static coap_context_t *
1043 setup_server_context_psk (const char *hint,
1044 const uint8_t *key,
1045 unsigned int key_len,
1046 valid_ids_t *valid_id_list,
1047 valid_psk_snis_t *valid_sni_list
1048 ) {
1049 coap_endpoint_t *endpoint;
1050 coap_address_t listen_addr;
1051 coap_context_t *context;
1052 coap_dtls_spsk_t dtls_psk;
1053
1054 /* See coap_tls_library(3) */
1055 if (!coap_dtls_is_supported())
1056 return NULL;
1057
1058 context = coap_new_context(NULL);
1059 if (!context)
1060 return NULL;
1061 /* See coap_block(3) */
1062 coap_context_set_block_mode(context,
1063 COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
1064
1065
1066 memset (&dtls_psk, 0, sizeof (dtls_psk));
1067
1068 /* see coap_encryption(3) */
1069 dtls_psk.version = COAP_DTLS_SPSK_SETUP_VERSION;
1070 dtls_psk.validate_id_call_back = verify_id_callback;
1071 dtls_psk.id_call_back_arg = valid_id_list;
1072 dtls_psk.validate_sni_call_back = verify_psk_sni_callback;
1073 dtls_psk.sni_call_back_arg = valid_sni_list;
1074 dtls_psk.psk_info.hint.s = (const uint8_t*)hint;
1075 dtls_psk.psk_info.hint.length = hint ? strlen(hint) : 0;
1076 dtls_psk.psk_info.key.s = key;
1077 dtls_psk.psk_info.key.length = key_len;
1078
1079 if (coap_context_set_psk2(context, &dtls_psk)) {
1080 coap_free_context(context);
1081 return NULL;
1082 }
1083
1084 coap_address_init(&listen_addr);
1085 listen_addr.addr.sa.sa_family = AF_INET;
1086 listen_addr.addr.sin.sin_port = htons (5684);
1087
1088 endpoint = coap_new_endpoint(context, &listen_addr, COAP_PROTO_DTLS);
1089 if (!endpoint) {
1090 coap_free_context(context);
1091 return NULL;
1092 }
1093
1094 /* Initialize resources - See coap_resource(3) init_resources() example */
1095
1096 return context;
1097 }
1098
1099 CoAP Client DTLS PSK Setup
1100
1101 #include <coap3/coap.h>
1102
1103 #include <stdio.h>
1104
1105 #ifndef min
1106 #define min(a,b) ((a) < (b) ? (a) : (b))
1107 #endif
1108
1109 static const coap_dtls_cpsk_info_t *
1110 verify_ih_callback(coap_str_const_t *hint,
1111 coap_session_t *c_session,
1112 void *arg
1113 ) {
1114 coap_dtls_cpsk_info_t *psk_info = (coap_dtls_cpsk_info_t *)arg;
1115 /* Remove (void) definition if variable is used */
1116 (void)c_session;
1117
1118 coap_log(LOG_INFO, "Identity Hint '%.*s' provided\n", (int)hint->length, hint->s);
1119
1120 /* Just use the defined information for now as passed in by arg */
1121 return psk_info;
1122 }
1123
1124 static coap_dtls_cpsk_t dtls_psk;
1125 static char client_sni[256];
1126
1127 static coap_session_t *
1128 setup_client_session_psk (const char *uri,
1129 struct in_addr ip_address,
1130 const uint8_t *identity,
1131 unsigned int identity_len,
1132 const uint8_t *key,
1133 unsigned int key_len
1134 ) {
1135 coap_session_t *session;
1136 coap_address_t server;
1137 /* See coap_context(3) */
1138 coap_context_t *context = coap_new_context(NULL);
1139
1140 if (!context)
1141 return NULL;
1142 /* See coap_block(3) */
1143 coap_context_set_block_mode(context,
1144 COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
1145
1146
1147 coap_address_init(&server);
1148 server.addr.sa.sa_family = AF_INET;
1149 server.addr.sin.sin_addr = ip_address;
1150 server.addr.sin.sin_port = htons (5684);
1151
1152 /* See coap_encryption(3) */
1153 memset (&dtls_psk, 0, sizeof(dtls_psk));
1154 dtls_psk.version = COAP_DTLS_CPSK_SETUP_VERSION;
1155 dtls_psk.validate_ih_call_back = verify_ih_callback;
1156 dtls_psk.ih_call_back_arg = &dtls_psk.psk_info;
1157 if (uri)
1158 memcpy(client_sni, uri, min(strlen(uri), sizeof(client_sni)-1));
1159 else
1160 memcpy(client_sni, "localhost", 9);
1161 dtls_psk.client_sni = client_sni;
1162 dtls_psk.psk_info.identity.s = identity;
1163 dtls_psk.psk_info.identity.length = identity_len;
1164 dtls_psk.psk_info.key.s = key;
1165 dtls_psk.psk_info.key.length = key_len;
1166 session = coap_new_client_session_psk2(context, NULL, &server,
1167 COAP_PROTO_DTLS, &dtls_psk);
1168 if (!session) {
1169 coap_free_context(context);
1170 return NULL;
1171 }
1172 /* The context is in session->context */
1173 return session;
1174 }
1175
1177 coap_block(3), coap_context(3), coap_resource(3), coap_session(3) and
1178 coap_tls_library(3).
1179
1181 See "RFC7252: The Constrained Application Protocol (CoAP)" for further
1182 information.
1183
1185 Please report bugs on the mailing list for libcoap:
1186 libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at
1187 https://github.com/obgm/libcoap/issues
1188
1190 The libcoap project <libcoap-developers@lists.sourceforge.net>
1191
1192
1193
1194coap_encryption 4.3.0 01/20/2022 COAP_ENCRYPTION(3)