/src/libcoap/src/coap_dtls.c
Line | Count | Source |
1 | | /* |
2 | | * coap_dtls.c -- (D)TLS functions for libcoap |
3 | | * |
4 | | * Copyright (C) 2023-2026 Olaf Bergmann <bergmann@tzi.org> |
5 | | * Copyright (C) 2023-2026 Jon Shallow <supjps-libcoap@jpshallow.com> |
6 | | * |
7 | | * SPDX-License-Identifier: BSD-2-Clause |
8 | | * |
9 | | * This file is part of the CoAP library libcoap. Please see README for terms |
10 | | * of use. |
11 | | */ |
12 | | |
13 | | /** |
14 | | * @file coap_dtls.c |
15 | | * @brief CoAP (D)TLS handling functions |
16 | | */ |
17 | | |
18 | | #include "coap3/coap_libcoap_build.h" |
19 | | |
20 | | #ifdef _WIN32 |
21 | | #define strcasecmp _stricmp |
22 | | #define strncasecmp _strnicmp |
23 | | #endif |
24 | | |
25 | | void |
26 | 0 | coap_dtls_map_key_type_to_define(const coap_dtls_pki_t *setup_data, coap_dtls_key_t *key) { |
27 | 0 | *key = setup_data->pki_key; |
28 | |
|
29 | 0 | switch (key->key_type) { |
30 | 0 | case COAP_PKI_KEY_PEM: |
31 | 0 | key->key_type = COAP_PKI_KEY_DEFINE; |
32 | 0 | key->key.define.ca.s_byte = setup_data->pki_key.key.pem.ca_file; |
33 | 0 | key->key.define.public_cert.s_byte = setup_data->pki_key.key.pem.public_cert; |
34 | 0 | key->key.define.private_key.s_byte = setup_data->pki_key.key.pem.private_key; |
35 | |
|
36 | 0 | key->key.define.public_cert_def = COAP_PKI_KEY_DEF_PEM; |
37 | 0 | key->key.define.private_key_def = COAP_PKI_KEY_DEF_PEM; |
38 | 0 | key->key.define.ca_def = COAP_PKI_KEY_DEF_PEM; |
39 | 0 | break; |
40 | 0 | case COAP_PKI_KEY_ASN1: |
41 | 0 | key->key_type = COAP_PKI_KEY_DEFINE; |
42 | 0 | key->key.define.ca.u_byte = setup_data->pki_key.key.asn1.ca_cert; |
43 | 0 | key->key.define.public_cert.u_byte = setup_data->pki_key.key.asn1.public_cert; |
44 | 0 | key->key.define.private_key.u_byte = setup_data->pki_key.key.asn1.private_key; |
45 | |
|
46 | 0 | key->key.define.ca_len = setup_data->pki_key.key.asn1.ca_cert_len; |
47 | 0 | key->key.define.public_cert_len = setup_data->pki_key.key.asn1.public_cert_len; |
48 | 0 | key->key.define.private_key_len = setup_data->pki_key.key.asn1.private_key_len; |
49 | |
|
50 | 0 | key->key.define.private_key_type = setup_data->pki_key.key.asn1.private_key_type; |
51 | |
|
52 | 0 | key->key.define.public_cert_def = COAP_PKI_KEY_DEF_DER_BUF; |
53 | 0 | key->key.define.private_key_def = COAP_PKI_KEY_DEF_DER_BUF; |
54 | 0 | key->key.define.ca_def = COAP_PKI_KEY_DEF_DER_BUF; |
55 | 0 | break; |
56 | 0 | case COAP_PKI_KEY_PEM_BUF: |
57 | 0 | key->key_type = COAP_PKI_KEY_DEFINE; |
58 | 0 | key->key.define.ca.u_byte = setup_data->pki_key.key.pem_buf.ca_cert; |
59 | 0 | key->key.define.public_cert.u_byte = setup_data->pki_key.key.pem_buf.public_cert; |
60 | 0 | key->key.define.private_key.u_byte = setup_data->pki_key.key.pem_buf.private_key; |
61 | |
|
62 | 0 | key->key.define.ca_len = setup_data->pki_key.key.pem_buf.ca_cert_len; |
63 | 0 | key->key.define.public_cert_len = setup_data->pki_key.key.pem_buf.public_cert_len; |
64 | 0 | key->key.define.private_key_len = setup_data->pki_key.key.pem_buf.private_key_len; |
65 | |
|
66 | 0 | if (setup_data->is_rpk_not_cert) { |
67 | 0 | key->key.define.public_cert_def = COAP_PKI_KEY_DEF_RPK_BUF; |
68 | 0 | key->key.define.private_key_def = COAP_PKI_KEY_DEF_RPK_BUF; |
69 | 0 | key->key.define.ca_def = COAP_PKI_KEY_DEF_RPK_BUF; |
70 | 0 | } else { |
71 | 0 | key->key.define.public_cert_def = COAP_PKI_KEY_DEF_PEM_BUF; |
72 | 0 | key->key.define.private_key_def = COAP_PKI_KEY_DEF_PEM_BUF; |
73 | 0 | key->key.define.ca_def = COAP_PKI_KEY_DEF_PEM_BUF; |
74 | 0 | } |
75 | 0 | break; |
76 | 0 | case COAP_PKI_KEY_PKCS11: |
77 | 0 | key->key_type = COAP_PKI_KEY_DEFINE; |
78 | 0 | key->key.define.ca.s_byte = setup_data->pki_key.key.pkcs11.ca; |
79 | 0 | key->key.define.public_cert.s_byte = setup_data->pki_key.key.pkcs11.public_cert; |
80 | 0 | key->key.define.private_key.s_byte = setup_data->pki_key.key.pkcs11.private_key; |
81 | |
|
82 | 0 | key->key.define.user_pin = setup_data->pki_key.key.pkcs11.user_pin; |
83 | |
|
84 | 0 | if (strncasecmp(key->key.pkcs11.ca, "pkcs11:", 7) == 0) { |
85 | 0 | if (setup_data->is_rpk_not_cert) { |
86 | 0 | key->key.define.ca_def = COAP_PKI_KEY_DEF_PKCS11_RPK; |
87 | 0 | } else { |
88 | 0 | key->key.define.ca_def = COAP_PKI_KEY_DEF_PKCS11; |
89 | 0 | } |
90 | 0 | } else { |
91 | 0 | if (setup_data->is_rpk_not_cert) { |
92 | 0 | key->key.define.ca_def = COAP_PKI_KEY_DEF_RPK_BUF; |
93 | 0 | } else { |
94 | 0 | key->key.define.ca_def = COAP_PKI_KEY_DEF_DER; |
95 | 0 | } |
96 | 0 | } |
97 | 0 | if (strncasecmp(key->key.pkcs11.public_cert, "pkcs11:", 7) == 0) { |
98 | 0 | if (setup_data->is_rpk_not_cert) { |
99 | 0 | key->key.define.public_cert_def = COAP_PKI_KEY_DEF_PKCS11_RPK; |
100 | 0 | } else { |
101 | 0 | key->key.define.public_cert_def = COAP_PKI_KEY_DEF_PKCS11; |
102 | 0 | } |
103 | 0 | } else { |
104 | 0 | if (setup_data->is_rpk_not_cert) { |
105 | 0 | key->key.define.public_cert_def = COAP_PKI_KEY_DEF_RPK_BUF; |
106 | 0 | } else { |
107 | 0 | key->key.define.public_cert_def = COAP_PKI_KEY_DEF_DER; |
108 | 0 | } |
109 | 0 | } |
110 | 0 | if (strncasecmp(key->key.pkcs11.private_key, "pkcs11:", 7) == 0) { |
111 | 0 | if (setup_data->is_rpk_not_cert) { |
112 | 0 | key->key.define.private_key_def = COAP_PKI_KEY_DEF_PKCS11_RPK; |
113 | 0 | } else { |
114 | 0 | key->key.define.private_key_def = COAP_PKI_KEY_DEF_PKCS11; |
115 | 0 | } |
116 | 0 | } else { |
117 | 0 | if (setup_data->is_rpk_not_cert) { |
118 | 0 | key->key.define.private_key_def = COAP_PKI_KEY_DEF_RPK_BUF; |
119 | 0 | } else { |
120 | 0 | key->key.define.private_key_def = COAP_PKI_KEY_DEF_DER; |
121 | 0 | } |
122 | 0 | } |
123 | 0 | break; |
124 | 0 | case COAP_PKI_KEY_DEFINE: |
125 | | /* Already configured */ |
126 | 0 | break; |
127 | 0 | default: |
128 | 0 | break; |
129 | 0 | } |
130 | 0 | } |
131 | | |
132 | | #if (COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_ERR) |
133 | | static const char * |
134 | 0 | coap_dtls_get_define_type(coap_pki_define_t def, coap_const_char_ptr_t name) { |
135 | 0 | switch (def) { |
136 | 0 | case COAP_PKI_KEY_DEF_PEM: |
137 | 0 | return name.s_byte; |
138 | 0 | case COAP_PKI_KEY_DEF_PEM_BUF: |
139 | 0 | return "PEM_BUF"; |
140 | 0 | case COAP_PKI_KEY_DEF_RPK_BUF: |
141 | 0 | return "RPK_BUF"; |
142 | 0 | case COAP_PKI_KEY_DEF_DER: |
143 | 0 | return name.s_byte; |
144 | 0 | case COAP_PKI_KEY_DEF_DER_BUF: |
145 | 0 | return "DER_BUF"; |
146 | 0 | case COAP_PKI_KEY_DEF_PKCS11: |
147 | 0 | return name.s_byte; |
148 | 0 | case COAP_PKI_KEY_DEF_PKCS11_RPK: |
149 | 0 | return name.s_byte; |
150 | 0 | case COAP_PKI_KEY_DEF_ENGINE: |
151 | 0 | return name.s_byte; |
152 | 0 | default: |
153 | 0 | return "???"; |
154 | 0 | } |
155 | 0 | } |
156 | | #endif /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_ERR */ |
157 | | |
158 | | int |
159 | | coap_dtls_define_issue(coap_define_issue_key_t type, coap_define_issue_fail_t fail, |
160 | 0 | coap_dtls_key_t *key, const coap_dtls_role_t role, int ret) { |
161 | 0 | #if (COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_ERR) |
162 | 0 | coap_pki_key_define_t define = key->key.define; |
163 | 0 | switch (type) { |
164 | 0 | case COAP_DEFINE_KEY_CA: |
165 | 0 | switch (fail) { |
166 | 0 | case COAP_DEFINE_FAIL_BAD: |
167 | 0 | coap_log_warn("*** setup_pki: (D)TLS: %s: %s CA configure failure\n", |
168 | 0 | coap_dtls_get_define_type(define.ca_def, define.ca), |
169 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
170 | 0 | break; |
171 | 0 | case COAP_DEFINE_FAIL_NOT_SUPPORTED: |
172 | 0 | coap_log_err("*** setup_pki: (D)TLS: %s: %s CA type not supported\n", |
173 | 0 | coap_dtls_get_define_type(define.ca_def, define.ca), |
174 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
175 | 0 | break; |
176 | 0 | case COAP_DEFINE_FAIL_NONE: |
177 | 0 | coap_log_err("*** setup_pki: (D)TLS: %s: %s CA not defined\n", |
178 | 0 | coap_dtls_get_define_type(define.ca_def, define.ca), |
179 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
180 | 0 | break; |
181 | 0 | default: |
182 | 0 | break; |
183 | 0 | } |
184 | 0 | break; |
185 | 0 | case COAP_DEFINE_KEY_ROOT_CA: |
186 | 0 | switch (fail) { |
187 | 0 | case COAP_DEFINE_FAIL_BAD: |
188 | 0 | coap_log_warn("*** setup_pki: (D)TLS: %s: %s Root CA configure failure\n", |
189 | 0 | coap_dtls_get_define_type(define.ca_def, define.ca), |
190 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
191 | 0 | break; |
192 | 0 | case COAP_DEFINE_FAIL_NOT_SUPPORTED: |
193 | 0 | coap_log_err("*** setup_pki: (D)TLS: %s: %s Root CA type not supported\n", |
194 | 0 | coap_dtls_get_define_type(define.ca_def, define.ca), |
195 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
196 | 0 | break; |
197 | 0 | case COAP_DEFINE_FAIL_NONE: |
198 | 0 | coap_log_err("*** setup_pki: (D)TLS: %s: %s Root CA not defined\n", |
199 | 0 | coap_dtls_get_define_type(define.ca_def, define.ca), |
200 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
201 | 0 | break; |
202 | 0 | default: |
203 | 0 | break; |
204 | 0 | } |
205 | 0 | break; |
206 | 0 | case COAP_DEFINE_KEY_PUBLIC: |
207 | 0 | switch (fail) { |
208 | 0 | case COAP_DEFINE_FAIL_BAD: |
209 | 0 | coap_log_warn("*** setup_pki: (D)TLS: %s: %s Certificate configure failure\n", |
210 | 0 | coap_dtls_get_define_type(define.public_cert_def, define.public_cert), |
211 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
212 | 0 | break; |
213 | 0 | case COAP_DEFINE_FAIL_NOT_SUPPORTED: |
214 | 0 | coap_log_err("*** setup_pki: (D)TLS: %s: %s Certificate type not supported\n", |
215 | 0 | coap_dtls_get_define_type(define.public_cert_def, define.public_cert), |
216 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
217 | 0 | break; |
218 | 0 | case COAP_DEFINE_FAIL_NONE: |
219 | 0 | coap_log_err("*** setup_pki: (D)TLS: %s: %s Certificate not defined\n", |
220 | 0 | coap_dtls_get_define_type(define.public_cert_def, define.public_cert), |
221 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
222 | 0 | break; |
223 | 0 | default: |
224 | 0 | break; |
225 | 0 | } |
226 | 0 | break; |
227 | 0 | case COAP_DEFINE_KEY_PRIVATE: |
228 | 0 | switch (fail) { |
229 | 0 | case COAP_DEFINE_FAIL_BAD: |
230 | 0 | coap_log_warn("*** setup_pki: (D)TLS: %s: %s Private Key configure failure\n", |
231 | 0 | coap_dtls_get_define_type(define.private_key_def, define.private_key), |
232 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
233 | 0 | break; |
234 | 0 | case COAP_DEFINE_FAIL_NOT_SUPPORTED: |
235 | 0 | coap_log_err("*** setup_pki: (D)TLS: %s: %s Private Key type not supported\n", |
236 | 0 | coap_dtls_get_define_type(define.private_key_def, define.private_key), |
237 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
238 | 0 | break; |
239 | 0 | case COAP_DEFINE_FAIL_NONE: |
240 | 0 | coap_log_err("*** setup_pki: (D)TLS: %s: %s Private Key not defined\n", |
241 | 0 | coap_dtls_get_define_type(define.private_key_def, define.private_key), |
242 | 0 | role == COAP_DTLS_ROLE_SERVER ? "Server" : "Client"); |
243 | 0 | break; |
244 | 0 | default: |
245 | 0 | break; |
246 | 0 | } |
247 | 0 | default: |
248 | 0 | break; |
249 | 0 | } |
250 | | #else /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_ERR */ |
251 | | (void)type; |
252 | | (void)fail; |
253 | | (void)key; |
254 | | (void)role; |
255 | | #endif /* COAP_MAX_LOGGING_LEVEL < _COAP_LOG_ERR */ |
256 | 0 | return ret; |
257 | 0 | } |
258 | | |
259 | | void |
260 | 0 | coap_dtls_establish(coap_session_t *session) { |
261 | 0 | session->state = COAP_SESSION_STATE_HANDSHAKE; |
262 | 0 | #if COAP_CLIENT_SUPPORT |
263 | 0 | if (session->type == COAP_SESSION_TYPE_CLIENT || session->client_initiated) |
264 | 0 | session->tls = coap_dtls_new_client_session(session); |
265 | 0 | else |
266 | 0 | #endif /* COAP_CLIENT_SUPPORT */ |
267 | 0 | #if COAP_SERVER_SUPPORT |
268 | 0 | session->tls = coap_dtls_new_server_session(session); |
269 | 0 | #endif /* COAP_SERVER_SUPPORT */ |
270 | |
|
271 | 0 | if (!session->tls) { |
272 | 0 | coap_session_disconnected_lkd(session, COAP_NACK_TLS_LAYER_FAILED); |
273 | 0 | return; |
274 | 0 | } |
275 | 0 | coap_ticks(&session->last_rx_tx); |
276 | 0 | } |
277 | | |
278 | | void |
279 | 0 | coap_dtls_close(coap_session_t *session) { |
280 | 0 | if (session->tls) { |
281 | 0 | coap_dtls_free_session(session); |
282 | 0 | session->tls = NULL; |
283 | 0 | } |
284 | 0 | session->sock.lfunc[COAP_LAYER_TLS].l_close(session); |
285 | 0 | } |
286 | | |
287 | | int |
288 | 0 | coap_pki_name_match_sni(const char *name_entry, size_t name_length, const char *sni_match) { |
289 | 0 | if (!sni_match) |
290 | 0 | return 1; |
291 | | |
292 | 0 | if (name_length >= 2 && name_entry[0] == '*' && name_entry[1] == '.') { |
293 | | /* Check for wildcard match */ |
294 | 0 | const char *cp = strchr(sni_match, '.'); |
295 | |
|
296 | 0 | if (!cp || strlen(cp) != name_length -1 || memcmp(&name_entry[1], cp, name_length -1)) { |
297 | | /* Not an wildcard match */ |
298 | 0 | return 0; |
299 | 0 | } |
300 | 0 | } else { |
301 | 0 | if (strlen(sni_match) != name_length || memcmp(name_entry, sni_match, name_length)) { |
302 | | /* Not an absolute match */ |
303 | 0 | return 0; |
304 | 0 | } |
305 | 0 | } |
306 | 0 | return 1; |
307 | 0 | } |
308 | | |
309 | | #if !COAP_DISABLE_TCP |
310 | | void |
311 | 0 | coap_tls_establish(coap_session_t *session) { |
312 | 0 | session->state = COAP_SESSION_STATE_HANDSHAKE; |
313 | 0 | #if COAP_CLIENT_SUPPORT |
314 | 0 | if (session->type == COAP_SESSION_TYPE_CLIENT || session->client_initiated) |
315 | 0 | session->tls = coap_tls_new_client_session(session); |
316 | 0 | else |
317 | 0 | #endif /* COAP_CLIENT_SUPPORT */ |
318 | 0 | #if COAP_SERVER_SUPPORT |
319 | 0 | session->tls = coap_tls_new_server_session(session); |
320 | 0 | #endif /* COAP_SERVER_SUPPORT */ |
321 | |
|
322 | 0 | if (!session->tls) { |
323 | 0 | coap_session_disconnected_lkd(session, COAP_NACK_TLS_LAYER_FAILED); |
324 | 0 | return; |
325 | 0 | } |
326 | 0 | coap_ticks(&session->last_rx_tx); |
327 | 0 | } |
328 | | |
329 | | void |
330 | 0 | coap_tls_close(coap_session_t *session) { |
331 | 0 | if (session->tls) { |
332 | 0 | coap_tls_free_session(session); |
333 | | session->tls = NULL; |
334 | 0 | } |
335 | 0 | session->sock.lfunc[COAP_LAYER_TLS].l_close(session); |
336 | 0 | } |
337 | | #endif /* !COAP_DISABLE_TCP */ |