blob: ef7aac412e3457782fcaad90b811977769d0681a [file] [log] [blame]
romane60ef992024-05-13 12:53:02 +02001/**
2 * @file session_mbedtls.c
3 * @author Roman Janota <janota@cesnet.cz>
4 * @brief libnetconf2 - wrapped MbedTLS function calls for TLS/asymmetric cryptography support
5 *
6 * This file is a wrapper for MbedTLS function calls. The implementation is done
7 * in such a way that the original libnetconf2 code is not dependent on MbedTLS.
8 * This file is included in the build process only if MbedTLS is being used.
9 *
10 * @copyright
11 * Copyright (c) 2024 CESNET, z.s.p.o.
12 *
13 * This source code is licensed under BSD 3-Clause License (the "License").
14 * You may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 * https://opensource.org/licenses/BSD-3-Clause
18 */
19
romanb00f4322024-04-04 09:26:18 +020020#define _GNU_SOURCE
21
romanc1124572024-04-23 15:08:06 +020022#include <ctype.h>
romanb00f4322024-04-04 09:26:18 +020023#include <dirent.h>
24#include <errno.h>
25#include <poll.h>
romanb00f4322024-04-04 09:26:18 +020026#include <stdint.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
roman008cfe72024-04-05 12:36:18 +020030#include <sys/stat.h>
romanb00f4322024-04-04 09:26:18 +020031#include <unistd.h>
32
33#include <curl/curl.h>
34
35#include "compat.h"
36#include "config.h"
37#include "log_p.h"
38#include "session.h"
39#include "session_p.h"
40#include "session_wrapper.h"
41
romanb00f4322024-04-04 09:26:18 +020042#include <mbedtls/base64.h>
roman008cfe72024-04-05 12:36:18 +020043#include <mbedtls/bignum.h>
44#include <mbedtls/ctr_drbg.h>
roman008cfe72024-04-05 12:36:18 +020045#include <mbedtls/entropy.h>
46#include <mbedtls/error.h>
47#include <mbedtls/net_sockets.h>
48#include <mbedtls/oid.h>
49#include <mbedtls/pem.h>
50#include <mbedtls/ssl.h>
51#include <mbedtls/x509.h>
52#include <mbedtls/x509_crl.h>
53#include <mbedtls/x509_crt.h>
romanb00f4322024-04-04 09:26:18 +020054
romane20f3542024-05-14 11:00:54 +020055/**
56 * @brief Converts mbedTLS error codes to a string.
57 *
58 * Some mbedTLS functions may return 'high' and some 'low' level errors, try to handle both cases this way.
59 *
60 * @param[in] err MbedTLS error code.
61 * @return Error string.
62 */
romanc1124572024-04-23 15:08:06 +020063static const char *
64nc_get_mbedtls_str_err(int err)
65{
66 const char *err_str;
67
68 err_str = mbedtls_high_level_strerr(err);
69 if (err_str) {
70 return err_str;
71 }
72
73 err_str = mbedtls_low_level_strerr(err);
74 if (err_str) {
75 return err_str;
76 }
77
78 return "unknown error";
79}
80
81/**
82 * @brief Converts DN to a string.
83 *
84 * @param[in] dn Internal DN representation.
85 * @return DN string on success, NULL of fail.
86 */
87static char *
88nc_server_tls_dn2str(const mbedtls_x509_name *dn)
89{
90 char *str;
91 size_t len = 64;
92 int r;
93
94 str = malloc(len);
95 NC_CHECK_ERRMEM_RET(!str, NULL);
96
97 while ((r = mbedtls_x509_dn_gets(str, len, dn)) == MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) {
98 len <<= 1;
99 str = nc_realloc(str, len);
100 NC_CHECK_ERRMEM_RET(!str, NULL);
101 }
102 if (r < 1) {
103 free(str);
104 ERR(NULL, "Failed to convert DN to string (%s).", nc_get_mbedtls_str_err(r));
105 return NULL;
106 }
107
108 return str;
109}
110
romane20f3542024-05-14 11:00:54 +0200111/**
112 * @brief Create a new random number generator context.
113 *
114 * @param[out] ctr_drbg Random bit generator context.
115 * @param[out] entropy Entropy context.
116 * @return 0 on success, 1 on failure.
117 */
romanc1124572024-04-23 15:08:06 +0200118static int
119nc_tls_rng_new(mbedtls_ctr_drbg_context **ctr_drbg, mbedtls_entropy_context **entropy)
120{
121 int rc;
122
123 *ctr_drbg = NULL;
124 *entropy = NULL;
125
126 *entropy = malloc(sizeof **entropy);
127 NC_CHECK_ERRMEM_GOTO(!*entropy, , fail);
128 *ctr_drbg = malloc(sizeof **ctr_drbg);
129 NC_CHECK_ERRMEM_GOTO(!*ctr_drbg, , fail);
130
131 mbedtls_entropy_init(*entropy);
132 mbedtls_ctr_drbg_init(*ctr_drbg);
133
134 rc = mbedtls_ctr_drbg_seed(*ctr_drbg, mbedtls_entropy_func, *entropy, NULL, 0);
135 if (rc) {
136 ERR(NULL, "Seeding ctr_drbg failed (%s).", nc_get_mbedtls_str_err(rc));
137 goto fail;
138 }
139
140 return 0;
141
142fail:
143 mbedtls_ctr_drbg_free(*ctr_drbg);
144 free(*ctr_drbg);
145 if (*entropy) {
146 mbedtls_entropy_free(*entropy);
147 free(*entropy);
148 }
149 *ctr_drbg = NULL;
150 *entropy = NULL;
151 return 1;
152}
153
romane20f3542024-05-14 11:00:54 +0200154/**
155 * @brief Destroy the random number generator context.
156 *
157 * @param[in] ctr_drbg Random bit generator context.
158 * @param[in] entropy Entropy context.
159 */
romanc1124572024-04-23 15:08:06 +0200160static void
161nc_tls_rng_destroy(mbedtls_ctr_drbg_context *ctr_drbg, mbedtls_entropy_context *entropy)
162{
163 mbedtls_ctr_drbg_free(ctr_drbg);
164 free(ctr_drbg);
165 if (entropy) {
166 mbedtls_entropy_free(entropy);
167 free(entropy);
168 }
169}
170
romane20f3542024-05-14 11:00:54 +0200171/**
172 * @brief Get a string representation of the verification error.
173 *
174 * @param[in] err Verification error code.
175 * @return String representation of the error. Caller is responsible for freeing it.
176 */
romanc1124572024-04-23 15:08:06 +0200177static char *
178nc_tls_get_verify_err_str(int err)
179{
180 int ret;
181 char *err_buf = NULL;
182
183 err_buf = malloc(256);
184 NC_CHECK_ERRMEM_RET(!err_buf, NULL);
185
186 ret = mbedtls_x509_crt_verify_info(err_buf, 256, "", err);
187 if (ret < 0) {
188 free(err_buf);
189 return NULL;
190 }
191
192 /* strip the NL */
193 err_buf[ret - 1] = '\0';
194
195 return err_buf;
196}
romanb00f4322024-04-04 09:26:18 +0200197
198void *
199nc_tls_session_new_wrap(void *tls_cfg)
200{
201 int rc;
202 mbedtls_ssl_context *session;
203
204 session = malloc(sizeof *session);
205 NC_CHECK_ERRMEM_RET(!session, NULL);
206
207 mbedtls_ssl_init(session);
208
209 rc = mbedtls_ssl_setup(session, tls_cfg);
210 if (rc) {
romanc1124572024-04-23 15:08:06 +0200211 ERR(NULL, "Setting up TLS session failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200212 mbedtls_ssl_free(session);
213 free(session);
214 return NULL;
215 }
216
217 return session;
218}
219
220void
221nc_tls_session_destroy_wrap(void *tls_session)
222{
223 mbedtls_ssl_free(tls_session);
224 free(tls_session);
225}
226
227void *
romanc1124572024-04-23 15:08:06 +0200228nc_tls_config_new_wrap(int UNUSED(side))
romanb00f4322024-04-04 09:26:18 +0200229{
230 mbedtls_ssl_config *tls_cfg;
231
232 tls_cfg = malloc(sizeof *tls_cfg);
233 NC_CHECK_ERRMEM_RET(!tls_cfg, NULL);
234
235 mbedtls_ssl_config_init(tls_cfg);
236 return tls_cfg;
237}
238
239void
240nc_tls_config_destroy_wrap(void *tls_cfg)
241{
242 if (!tls_cfg) {
243 return;
244 }
245
246 mbedtls_ssl_config_free(tls_cfg);
247 free(tls_cfg);
248}
249
250void *
romanb87aa452024-05-13 12:58:00 +0200251nc_tls_cert_new_wrap(void)
romanb00f4322024-04-04 09:26:18 +0200252{
253 mbedtls_x509_crt *cert;
254
255 cert = malloc(sizeof *cert);
256 NC_CHECK_ERRMEM_RET(!cert, NULL);
257
258 mbedtls_x509_crt_init(cert);
259 return cert;
260}
261
262void
263nc_tls_cert_destroy_wrap(void *cert)
264{
265 mbedtls_x509_crt_free(cert);
266 free(cert);
267}
268
romane20f3542024-05-14 11:00:54 +0200269/**
270 * @brief Create a new private key context.
271 *
272 * @return New private key context or NULL.
273 */
romanc1124572024-04-23 15:08:06 +0200274static void *
275nc_tls_pkey_new_wrap(void)
romanb00f4322024-04-04 09:26:18 +0200276{
277 mbedtls_pk_context *pkey;
278
279 pkey = malloc(sizeof *pkey);
280 NC_CHECK_ERRMEM_RET(!pkey, NULL);
281
282 mbedtls_pk_init(pkey);
283 return pkey;
284}
285
286void
287nc_tls_privkey_destroy_wrap(void *pkey)
288{
289 mbedtls_pk_free(pkey);
290 free(pkey);
291}
292
293void *
romanb87aa452024-05-13 12:58:00 +0200294nc_tls_cert_store_new_wrap(void)
romanb00f4322024-04-04 09:26:18 +0200295{
romanc1124572024-04-23 15:08:06 +0200296 /* certificate is the same as a certificate store in MbedTLS */
romanb00f4322024-04-04 09:26:18 +0200297 return nc_tls_cert_new_wrap();
298}
299
300void
301nc_tls_cert_store_destroy_wrap(void *cert_store)
302{
romanc1124572024-04-23 15:08:06 +0200303 /* certificate is the same as a certificate store in MbedTLS */
romanb00f4322024-04-04 09:26:18 +0200304 nc_tls_cert_destroy_wrap(cert_store);
305}
306
307void *
romanb87aa452024-05-13 12:58:00 +0200308nc_tls_crl_store_new_wrap(void)
romanb00f4322024-04-04 09:26:18 +0200309{
310 mbedtls_x509_crl *crl;
311
312 crl = malloc(sizeof *crl);
313 NC_CHECK_ERRMEM_RET(!crl, NULL);
314
315 mbedtls_x509_crl_init(crl);
316 return crl;
317}
318
319void
romanc1124572024-04-23 15:08:06 +0200320nc_tls_crl_store_destroy_wrap(void *crl_store)
romanb00f4322024-04-04 09:26:18 +0200321{
romanc1124572024-04-23 15:08:06 +0200322 mbedtls_x509_crl_free(crl_store);
323 free(crl_store);
romanb00f4322024-04-04 09:26:18 +0200324}
325
326void *
327nc_tls_pem_to_cert_wrap(const char *cert_data)
328{
329 int rc;
330 mbedtls_x509_crt *cert;
331
332 cert = nc_tls_cert_new_wrap();
333 if (!cert) {
334 return NULL;
335 }
336
337 rc = mbedtls_x509_crt_parse(cert, (const unsigned char *)cert_data, strlen(cert_data) + 1);
338 if (rc) {
romanc1124572024-04-23 15:08:06 +0200339 ERR(NULL, "Parsing certificate data failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200340 nc_tls_cert_destroy_wrap(cert);
341 return NULL;
342 }
343
344 return cert;
345}
346
347int
romanc1124572024-04-23 15:08:06 +0200348nc_tls_add_cert_to_store_wrap(void *cert, void *cert_store)
romanb00f4322024-04-04 09:26:18 +0200349{
romanc1124572024-04-23 15:08:06 +0200350 mbedtls_x509_crt *iter;
romanb00f4322024-04-04 09:26:18 +0200351
romanc1124572024-04-23 15:08:06 +0200352 /* store is a linked list */
353 iter = cert_store;
354 while (iter->next) {
355 iter = iter->next;
romanb00f4322024-04-04 09:26:18 +0200356 }
romanc1124572024-04-23 15:08:06 +0200357 iter->next = cert;
romanb00f4322024-04-04 09:26:18 +0200358
359 return 0;
360}
361
362void *
363nc_tls_pem_to_privkey_wrap(const char *privkey_data)
364{
romand971fa22024-04-25 15:08:13 +0200365 int rc = 0;
romanc1124572024-04-23 15:08:06 +0200366 mbedtls_pk_context *pkey = NULL;
367 mbedtls_ctr_drbg_context *ctr_drbg = NULL;
368 mbedtls_entropy_context *entropy = NULL;
romanb00f4322024-04-04 09:26:18 +0200369
romand971fa22024-04-25 15:08:13 +0200370 rc = nc_tls_rng_new(&ctr_drbg, &entropy);
371 if (rc) {
romanc1124572024-04-23 15:08:06 +0200372 goto cleanup;
romanb00f4322024-04-04 09:26:18 +0200373 }
374
romanc1124572024-04-23 15:08:06 +0200375 pkey = nc_tls_pkey_new_wrap();
romanb00f4322024-04-04 09:26:18 +0200376 if (!pkey) {
romand971fa22024-04-25 15:08:13 +0200377 rc = 1;
romanc1124572024-04-23 15:08:06 +0200378 goto cleanup;
romanb00f4322024-04-04 09:26:18 +0200379 }
380
381 rc = mbedtls_pk_parse_key(pkey, (const unsigned char *)privkey_data, strlen(privkey_data) + 1, NULL, 0, mbedtls_ctr_drbg_random, ctr_drbg);
romanb00f4322024-04-04 09:26:18 +0200382 if (rc) {
romanc1124572024-04-23 15:08:06 +0200383 ERR(NULL, "Parsing private key data failed (%s).", nc_get_mbedtls_str_err(rc));
romanc1124572024-04-23 15:08:06 +0200384 goto cleanup;
romanb00f4322024-04-04 09:26:18 +0200385 }
romanc1124572024-04-23 15:08:06 +0200386
387cleanup:
romand971fa22024-04-25 15:08:13 +0200388 if (rc) {
romanc1124572024-04-23 15:08:06 +0200389 nc_tls_privkey_destroy_wrap(pkey);
romand971fa22024-04-25 15:08:13 +0200390 pkey = NULL;
romanc1124572024-04-23 15:08:06 +0200391 }
392 nc_tls_rng_destroy(ctr_drbg, entropy);
romanb00f4322024-04-04 09:26:18 +0200393 return pkey;
394}
395
396int
romanc1124572024-04-23 15:08:06 +0200397nc_tls_import_crl_path_wrap(const char *path, void *crl_store)
romanb00f4322024-04-04 09:26:18 +0200398{
399 int rc;
400
romanc1124572024-04-23 15:08:06 +0200401 rc = mbedtls_x509_crl_parse_file(crl_store, path);
romanb00f4322024-04-04 09:26:18 +0200402 if (rc) {
romanc1124572024-04-23 15:08:06 +0200403 ERR(NULL, "Failed to import CRL from file \"%s\" (%s).", path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200404 return 1;
405 }
406
407 return 0;
408}
409
410int
romanc1124572024-04-23 15:08:06 +0200411nc_server_tls_add_crl_to_store_wrap(const unsigned char *crl_data, size_t size, void *crl_store)
romanb00f4322024-04-04 09:26:18 +0200412{
413 int rc;
414
romanb00f4322024-04-04 09:26:18 +0200415 /* try DER first */
416 rc = mbedtls_x509_crl_parse_der(crl_store, crl_data, size);
417 if (!rc) {
418 /* success, it was DER */
419 return 0;
420 }
421
422 /* DER failed, try PEM */
romanc1124572024-04-23 15:08:06 +0200423 rc = mbedtls_x509_crl_parse(crl_store, crl_data, size + 1);
romanb00f4322024-04-04 09:26:18 +0200424 if (!rc) {
425 /* success, it was PEM */
426 return 0;
427 }
428
429 /* failed to parse it */
430 ERR(NULL, "Reading downloaded CRL failed.");
431 return 1;
432}
433
romanb00f4322024-04-04 09:26:18 +0200434int
435nc_server_tls_set_tls_versions_wrap(void *tls_cfg, unsigned int tls_versions)
436{
437 if ((tls_versions & NC_TLS_VERSION_10) || ((tls_versions & NC_TLS_VERSION_11))) {
438 /* skip TLS versions 1.0 and 1.1 */
439 WRN(NULL, "mbedTLS does not support TLS1.0 and TLS1.1");
440 }
441
442 /* first set the minimum version */
443 if (tls_versions & NC_TLS_VERSION_12) {
444 mbedtls_ssl_conf_min_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_2);
445 } else if (tls_versions & NC_TLS_VERSION_13) {
446 mbedtls_ssl_conf_min_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_3);
447 }
448
449 /* then set the maximum version */
450 if (tls_versions & NC_TLS_VERSION_13) {
451 mbedtls_ssl_conf_max_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_3);
452 } else if (tls_versions & NC_TLS_VERSION_12) {
453 mbedtls_ssl_conf_max_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_2);
454 }
455
456 return 0;
457}
458
romane20f3542024-05-14 11:00:54 +0200459/**
460 * @brief Duplicates a certificate.
461 *
462 * @param[in] cert Certificate to duplicate.
463 * @return Duplicated certificate or NULL.
464 */
roman396f4732024-05-14 09:09:30 +0200465static mbedtls_x509_crt *
466nc_tls_cert_dup(const mbedtls_x509_crt *cert)
467{
468 mbedtls_x509_crt *new_cert;
469
470 new_cert = nc_tls_cert_new_wrap();
471 if (!new_cert) {
472 return NULL;
473 }
474
475 if (mbedtls_x509_crt_parse_der(new_cert, cert->raw.p, cert->raw.len)) {
476 free(new_cert);
477 return NULL;
478 }
479
480 return new_cert;
481}
482
romane20f3542024-05-14 11:00:54 +0200483/**
484 * @brief Verify a certificate.
485 *
486 * @param[in] cb_data Callback data (session, opts, data for CTN).
487 * @param[in] cert Certificate to verify.
488 * @param[in] depth Certificate depth in the chain.
489 * @param[in,out] flags Verification flags. Used to propagate errors.
490 * @return 0 on success (verification result is based on the value of flags), non-zero on fatal-error.
491 */
romanb00f4322024-04-04 09:26:18 +0200492static int
493nc_server_tls_verify_cb(void *cb_data, mbedtls_x509_crt *cert, int depth, uint32_t *flags)
494{
495 int ret = 0;
496 struct nc_tls_verify_cb_data *data = cb_data;
romanc1124572024-04-23 15:08:06 +0200497 char *err;
romanb00f4322024-04-04 09:26:18 +0200498
499 if (!*flags) {
500 /* in-built verification was successful */
roman7ffd2fc2024-05-13 13:48:34 +0200501 ret = nc_server_tls_verify_cert(cert, depth, 1, data);
romanb00f4322024-04-04 09:26:18 +0200502 } else {
romanc1124572024-04-23 15:08:06 +0200503 /* in-built verification failed, but the client still may be authenticated if:
504 * 1) the peer cert matches any configured end-entity cert
505 * 2) the peer cert has a valid chain of trust to any configured certificate authority cert
506 * otherwise just continue until we reach the peer cert (depth = 0)
romanb00f4322024-04-04 09:26:18 +0200507 */
508 if ((depth == 0) && (*flags == MBEDTLS_X509_BADCERT_NOT_TRUSTED)) {
romanc1124572024-04-23 15:08:06 +0200509 /* not trusted self-signed peer certificate, case 1) */
roman7ffd2fc2024-05-13 13:48:34 +0200510 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
romanb00f4322024-04-04 09:26:18 +0200511 if (!ret) {
512 *flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED;
513 }
romanc1124572024-04-23 15:08:06 +0200514 } else if (*flags == MBEDTLS_X509_BADCERT_MISSING) {
515 /* full chain of trust is invalid, but it may be valid partially, case 2) */
roman7ffd2fc2024-05-13 13:48:34 +0200516 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
romanc1124572024-04-23 15:08:06 +0200517 if (!ret) {
518 *flags &= ~MBEDTLS_X509_BADCERT_MISSING;
romanb00f4322024-04-04 09:26:18 +0200519 }
romanc1124572024-04-23 15:08:06 +0200520 } else {
521 err = nc_tls_get_verify_err_str(*flags);
522 ERR(data->session, "Cert verify: fail (%s).", err);
523 free(err);
romanb00f4322024-04-04 09:26:18 +0200524 ret = 1;
525 }
526 }
527
528 if (ret == -1) {
529 /* fatal error */
530 return MBEDTLS_ERR_X509_ALLOC_FAILED;
531 } else if (!ret) {
532 /* success */
roman396f4732024-05-14 09:09:30 +0200533 if ((depth == 0) && (!data->session->opts.server.client_cert)) {
534 /* copy the client cert */
535 data->session->opts.server.client_cert = nc_tls_cert_dup(cert);
536 if (!data->session->opts.server.client_cert) {
537 return MBEDTLS_ERR_X509_ALLOC_FAILED;
538 }
539 }
romanb00f4322024-04-04 09:26:18 +0200540 return 0;
541 } else {
542 if (depth > 0) {
543 /* chain verify failed, but peer cert can still match */
544 return 0;
545 } else {
romanc1124572024-04-23 15:08:06 +0200546 /* failed to verify peer cert, but return 0 so that we can propagate the error via the flags */
547 if (!*flags) {
548 *flags |= MBEDTLS_X509_BADCERT_OTHER;
549 }
550 return 0;
romanb00f4322024-04-04 09:26:18 +0200551 }
552 }
553}
554
555void
romanc1124572024-04-23 15:08:06 +0200556nc_server_tls_set_verify_wrap(void *tls_cfg, struct nc_tls_verify_cb_data *cb_data)
romanb00f4322024-04-04 09:26:18 +0200557{
romanc1124572024-04-23 15:08:06 +0200558 mbedtls_ssl_conf_authmode(tls_cfg, MBEDTLS_SSL_VERIFY_REQUIRED);
559 mbedtls_ssl_conf_verify(tls_cfg, nc_server_tls_verify_cb, cb_data);
romanb00f4322024-04-04 09:26:18 +0200560}
561
romanc1124572024-04-23 15:08:06 +0200562void
563nc_client_tls_set_verify_wrap(void *tls_cfg)
romanb00f4322024-04-04 09:26:18 +0200564{
romanc1124572024-04-23 15:08:06 +0200565 mbedtls_ssl_conf_authmode(tls_cfg, MBEDTLS_SSL_VERIFY_REQUIRED);
romanb00f4322024-04-04 09:26:18 +0200566}
567
568char *
569nc_server_tls_get_subject_wrap(void *cert)
570{
571 return nc_server_tls_dn2str(&(((mbedtls_x509_crt *)cert)->subject));
572}
573
574char *
575nc_server_tls_get_issuer_wrap(void *cert)
576{
577 return nc_server_tls_dn2str(&(((mbedtls_x509_crt *)cert)->issuer));
578}
579
romanc1124572024-04-23 15:08:06 +0200580void *
581nc_tls_get_sans_wrap(void *cert)
romanb00f4322024-04-04 09:26:18 +0200582{
romanc1124572024-04-23 15:08:06 +0200583 return &(((mbedtls_x509_crt *)cert)->subject_alt_names);
584}
romanb00f4322024-04-04 09:26:18 +0200585
romanc1124572024-04-23 15:08:06 +0200586void
587nc_tls_sans_destroy_wrap(void *UNUSED(sans))
588{
589 return;
590}
romanb00f4322024-04-04 09:26:18 +0200591
romanc1124572024-04-23 15:08:06 +0200592int
593nc_tls_get_num_sans_wrap(void *sans)
594{
595 mbedtls_x509_sequence *iter;
596 int n = 0;
romanb00f4322024-04-04 09:26:18 +0200597
romanc1124572024-04-23 15:08:06 +0200598 /* sans are a linked list */
599 iter = sans;
600 while (iter) {
601 ++n;
602 iter = iter->next;
romanb00f4322024-04-04 09:26:18 +0200603 }
604
romanc1124572024-04-23 15:08:06 +0200605 return n;
606}
607
608int
609nc_tls_get_san_value_type_wrap(void *sans, int idx, char **san_value, NC_TLS_CTN_MAPTYPE *san_type)
610{
611 int i, rc, ret = 0;
612 mbedtls_x509_sequence *iter;
613 mbedtls_x509_subject_alternative_name san = {0};
614 const mbedtls_x509_buf *ip;
615
616 *san_value = NULL;
617 *san_type = NC_TLS_CTN_UNKNOWN;
618
619 /* find the SAN */
620 iter = sans;
621 for (i = 0; i < idx; i++) {
622 iter = iter->next;
623 }
624
625 /* parse it */
626 rc = mbedtls_x509_parse_subject_alt_name(&iter->buf, &san);
627 if (rc && (rc != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE)) {
628 return -1;
629 }
630
631 /* get its type and value */
632 switch (san.type) {
633 case MBEDTLS_X509_SAN_DNS_NAME:
634 *san_type = NC_TLS_CTN_SAN_DNS_NAME;
635 *san_value = strndup((const char *)san.san.unstructured_name.p, san.san.unstructured_name.len);
636 NC_CHECK_ERRMEM_GOTO(!*san_value, ret = -1, cleanup);
637 break;
638 case MBEDTLS_X509_SAN_RFC822_NAME:
639 *san_type = NC_TLS_CTN_SAN_RFC822_NAME;
640 *san_value = strndup((const char *)san.san.unstructured_name.p, san.san.unstructured_name.len);
641 NC_CHECK_ERRMEM_GOTO(!*san_value, ret = -1, cleanup);
642 break;
643 case MBEDTLS_X509_SAN_IP_ADDRESS:
644 *san_type = NC_TLS_CTN_SAN_IP_ADDRESS;
645 ip = &san.san.unstructured_name;
646 if (ip->len == 4) {
647 rc = asprintf(san_value, "%d.%d.%d.%d", ip->p[0], ip->p[1], ip->p[2], ip->p[3]) == -1;
648 NC_CHECK_ERRMEM_GOTO(rc == -1, ret = -1, cleanup);
649 } else if (ip->len == 16) {
650 rc = asprintf(san_value, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
651 ip->p[0], ip->p[1], ip->p[2], ip->p[3], ip->p[4], ip->p[5],
652 ip->p[6], ip->p[7], ip->p[8], ip->p[9], ip->p[10], ip->p[11],
653 ip->p[12], ip->p[13], ip->p[14], ip->p[15]);
654 NC_CHECK_ERRMEM_GOTO(rc == -1, ret = -1, cleanup);
655 } else {
656 WRN(NULL, "SAN IP address in an unknown format (length is %d).", ip->len);
657 ret = 1;
658 }
659 break;
660 default:
661 /* we dont care about other types */
662 *san_type = NC_TLS_CTN_UNKNOWN;
663 ret = 1;
664 break;
665 }
666
667cleanup:
668 mbedtls_x509_free_subject_alt_name(&san);
669 return ret;
romanb00f4322024-04-04 09:26:18 +0200670}
671
672int
673nc_server_tls_certs_match_wrap(void *cert1, void *cert2)
674{
675 mbedtls_x509_crt *c1 = cert1;
676 mbedtls_x509_crt *c2 = cert2;
677
678 if (!c1 || !c2) {
679 return 0;
680 }
681
682 /* compare raw DER encoded data */
683 if (!c1->raw.p || !c2->raw.p || (c1->raw.len != c2->raw.len) ||
684 memcmp(c1->raw.p, c2->raw.p, c1->raw.len)) {
685 return 0;
686 }
687
688 return 1;
689}
690
691int
692nc_server_tls_md5_wrap(void *cert, unsigned char *buf)
693{
694 int rc;
695 mbedtls_x509_crt *c = cert;
696
697 rc = mbedtls_md5(c->raw.p, c->raw.len, buf);
698 if (rc) {
romanc1124572024-04-23 15:08:06 +0200699 ERR(NULL, "Calculating MD5 digest failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200700 return 1;
701 }
702
703 return 0;
704}
705
706int
707nc_server_tls_sha1_wrap(void *cert, unsigned char *buf)
708{
709 int rc;
710 mbedtls_x509_crt *c = cert;
711
712 rc = mbedtls_sha1(c->raw.p, c->raw.len, buf);
713 if (rc) {
romanc1124572024-04-23 15:08:06 +0200714 ERR(NULL, "Calculating SHA-1 digest failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200715 return 1;
716 }
717
718 return 0;
719}
720
721int
722nc_server_tls_sha224_wrap(void *cert, unsigned char *buf)
723{
724 int rc;
725 mbedtls_x509_crt *c = cert;
726
727 rc = mbedtls_sha256(c->raw.p, c->raw.len, buf, 1);
728 if (rc) {
romanc1124572024-04-23 15:08:06 +0200729 ERR(NULL, "Calculating SHA-224 digest failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200730 return 1;
731 }
732
733 return 0;
734}
735
736int
737nc_server_tls_sha256_wrap(void *cert, unsigned char *buf)
738{
739 int rc;
740 mbedtls_x509_crt *c = cert;
741
742 rc = mbedtls_sha256(c->raw.p, c->raw.len, buf, 0);
743 if (rc) {
romanc1124572024-04-23 15:08:06 +0200744 ERR(NULL, "Calculating SHA-256 digest failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200745 return 1;
746 }
747
748 return 0;
749}
750
751int
752nc_server_tls_sha384_wrap(void *cert, unsigned char *buf)
753{
754 int rc;
755 mbedtls_x509_crt *c = cert;
756
757 rc = mbedtls_sha512(c->raw.p, c->raw.len, buf, 1);
758 if (rc) {
romanc1124572024-04-23 15:08:06 +0200759 ERR(NULL, "Calculating SHA-384 digest failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200760 return 1;
761 }
762
763 return 0;
764}
765
766int
767nc_server_tls_sha512_wrap(void *cert, unsigned char *buf)
768{
769 int rc;
770 mbedtls_x509_crt *c = cert;
771
772 rc = mbedtls_sha512(c->raw.p, c->raw.len, buf, 0);
773 if (rc) {
romanc1124572024-04-23 15:08:06 +0200774 ERR(NULL, "Calculating SHA-512 digest failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200775 return 1;
776 }
777
778 return 0;
779}
780
romane20f3542024-05-14 11:00:54 +0200781/**
782 * @brief Callback for sending data.
783 *
784 * @param[in] ctx Socket.
785 * @param[in] buf Data to send.
786 * @param[in] len Length of the data.
787 * @return Number of bytes sent or negative value on error.
788 */
romanc1124572024-04-23 15:08:06 +0200789static int
790nc_server_tls_send(void *ctx, const unsigned char *buf, size_t len)
791{
792 int sock, ret;
793
794 NC_CHECK_ARG_RET(NULL, ctx, MBEDTLS_ERR_NET_INVALID_CONTEXT);
795
796 sock = *(int *)ctx;
797
798 ret = send(sock, buf, len, MSG_NOSIGNAL);
799 if (ret < 0) {
800 if ((errno == EWOULDBLOCK) || (errno = EAGAIN) || (errno == EINTR)) {
801 return MBEDTLS_ERR_SSL_WANT_WRITE;
802 } else if ((errno == EPIPE) || (errno == ECONNRESET)) {
803 return MBEDTLS_ERR_NET_CONN_RESET;
804 } else {
805 return MBEDTLS_ERR_NET_SEND_FAILED;
806 }
807 }
808
809 return ret;
810}
811
romane20f3542024-05-14 11:00:54 +0200812/**
813 * @brief Callback for receiving data.
814 *
815 * @param[in] ctx Socket.
816 * @param[out] buf Buffer to store the received data.
817 * @param[in] len Length of the buffer.
818 * @return Number of bytes received or negative value on error.
819 */
romanc1124572024-04-23 15:08:06 +0200820static int
821nc_server_tls_recv(void *ctx, unsigned char *buf, size_t len)
822{
823 int sock, ret;
824
825 NC_CHECK_ARG_RET(NULL, ctx, MBEDTLS_ERR_NET_INVALID_CONTEXT);
826
827 sock = *(int *)ctx;
828
829 ret = recv(sock, buf, len, 0);
830 if (ret < 0) {
831 if ((errno == EWOULDBLOCK) || (errno = EAGAIN) || (errno == EINTR)) {
832 return MBEDTLS_ERR_SSL_WANT_READ;
833 } else if ((errno == EPIPE) || (errno == ECONNRESET)) {
834 return MBEDTLS_ERR_NET_CONN_RESET;
835 } else {
836 return MBEDTLS_ERR_NET_RECV_FAILED;
837 }
838 }
839
840 return ret;
841}
842
romanb00f4322024-04-04 09:26:18 +0200843void
844nc_server_tls_set_fd_wrap(void *tls_session, int UNUSED(sock), struct nc_tls_ctx *tls_ctx)
845{
romanc1124572024-04-23 15:08:06 +0200846 /* mbedtls sets a pointer to the sock, which is stored in tls_ctx */
847 mbedtls_ssl_set_bio(tls_session, tls_ctx->sock, nc_server_tls_send, nc_server_tls_recv, NULL);
romanb00f4322024-04-04 09:26:18 +0200848}
849
850int
851nc_server_tls_handshake_step_wrap(void *tls_session)
852{
853 int rc = 0;
854
855 rc = mbedtls_ssl_handshake(tls_session);
856 if (!rc) {
857 return 1;
roman008cfe72024-04-05 12:36:18 +0200858 } else if ((rc == MBEDTLS_ERR_SSL_WANT_READ) || (rc == MBEDTLS_ERR_SSL_WANT_WRITE)) {
romanb00f4322024-04-04 09:26:18 +0200859 return 0;
860 } else {
romanc1124572024-04-23 15:08:06 +0200861 return rc;
romanb00f4322024-04-04 09:26:18 +0200862 }
863}
864
865int
romanc1124572024-04-23 15:08:06 +0200866nc_client_tls_handshake_step_wrap(void *tls_session, int sock)
romanb00f4322024-04-04 09:26:18 +0200867{
romanc1124572024-04-23 15:08:06 +0200868 int rc = 0;
869 struct pollfd pfd = {sock, 0, 0};
romanb00f4322024-04-04 09:26:18 +0200870
romanc1124572024-04-23 15:08:06 +0200871 rc = mbedtls_ssl_handshake(tls_session);
872 if (!rc) {
romanb00f4322024-04-04 09:26:18 +0200873 return 1;
romanc1124572024-04-23 15:08:06 +0200874 } else if ((rc == MBEDTLS_ERR_SSL_WANT_READ) || (rc == MBEDTLS_ERR_SSL_WANT_WRITE)) {
875 /* check for EPIPE */
876 if (poll(&pfd, 1, 0) < 0) {
877 return -1;
878 } else {
879 if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
880 return -1;
881 } else {
882 return 0;
883 }
884 }
885 } else {
886 return rc;
romanb00f4322024-04-04 09:26:18 +0200887 }
romanb00f4322024-04-04 09:26:18 +0200888}
889
890void
891nc_tls_ctx_destroy_wrap(struct nc_tls_ctx *tls_ctx)
892{
romanc1124572024-04-23 15:08:06 +0200893 nc_tls_rng_destroy(tls_ctx->ctr_drbg, tls_ctx->entropy);
romanb00f4322024-04-04 09:26:18 +0200894 nc_tls_cert_destroy_wrap(tls_ctx->cert);
895 nc_tls_privkey_destroy_wrap(tls_ctx->pkey);
896 nc_tls_cert_store_destroy_wrap(tls_ctx->cert_store);
897 nc_tls_crl_store_destroy_wrap(tls_ctx->crl_store);
898 free(tls_ctx->sock);
899}
900
romanc1124572024-04-23 15:08:06 +0200901void *
902nc_tls_import_privkey_file_wrap(const char *privkey_path)
romanb00f4322024-04-04 09:26:18 +0200903{
904 int rc;
905 mbedtls_pk_context *pkey;
906 mbedtls_ctr_drbg_context *ctr_drbg;
907 mbedtls_entropy_context *entropy;
908
909 if (nc_tls_rng_new(&ctr_drbg, &entropy)) {
910 return NULL;
911 }
912
romanc1124572024-04-23 15:08:06 +0200913 pkey = nc_tls_pkey_new_wrap();
romanb00f4322024-04-04 09:26:18 +0200914 if (!pkey) {
915 nc_tls_rng_destroy(ctr_drbg, entropy);
916 return NULL;
917 }
918
919 rc = mbedtls_pk_parse_keyfile(pkey, privkey_path, NULL, mbedtls_ctr_drbg_random, ctr_drbg);
920 nc_tls_rng_destroy(ctr_drbg, entropy);
921 if (rc) {
romanc1124572024-04-23 15:08:06 +0200922 ERR(NULL, "Parsing private key from file \"%s\" failed (%s).", privkey_path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200923 nc_tls_privkey_destroy_wrap(pkey);
924 return NULL;
925 }
926 return pkey;
927}
928
romanb00f4322024-04-04 09:26:18 +0200929int
930nc_client_tls_load_cert_key_wrap(const char *cert_path, const char *key_path, void **cert, void **pkey)
931{
932 int ret = 0;
933 mbedtls_x509_crt *c;
934 mbedtls_pk_context *pk;
romanc1124572024-04-23 15:08:06 +0200935
936 NC_CHECK_ARG_RET(NULL, cert_path, key_path, cert, pkey, 1);
romanb00f4322024-04-04 09:26:18 +0200937
938 c = nc_tls_cert_new_wrap();
939 if (!c) {
940 return 1;
941 }
942
943 ret = mbedtls_x509_crt_parse_file(c, cert_path);
944 if (ret) {
romanc1124572024-04-23 15:08:06 +0200945 ERR(NULL, "Parsing certificate from file \"%s\" failed (%s).", cert_path, nc_get_mbedtls_str_err(ret));
romanb00f4322024-04-04 09:26:18 +0200946 goto cleanup;
947 }
948
romanc1124572024-04-23 15:08:06 +0200949 pk = nc_tls_import_privkey_file_wrap(key_path);
950 if (!pk) {
951 ret = 1;
952 goto cleanup;
romanb00f4322024-04-04 09:26:18 +0200953 }
954
955 *cert = c;
roman18ad7352024-05-13 12:58:52 +0200956 c = NULL;
romanb00f4322024-04-04 09:26:18 +0200957 *pkey = pk;
958
959cleanup:
roman18ad7352024-05-13 12:58:52 +0200960 nc_tls_cert_destroy_wrap(c);
romanb00f4322024-04-04 09:26:18 +0200961 return ret;
962}
963
964int
965nc_client_tls_load_trusted_certs_wrap(void *cert_store, const char *file_path, const char *dir_path)
966{
967 int rc;
968
969 if (file_path && ((rc = mbedtls_x509_crt_parse_file(cert_store, file_path)) < 0)) {
romanc1124572024-04-23 15:08:06 +0200970 ERR(NULL, "Loading CA certificate from file \"%s\" failed (%s).", file_path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200971 return 1;
972 }
973
974 if (dir_path && ((rc = mbedtls_x509_crt_parse_path(cert_store, dir_path)) < 0)) {
romanc1124572024-04-23 15:08:06 +0200975 ERR(NULL, "Loading CA certificate from directory \"%s\" failed (%s).", dir_path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200976 return 1;
977 }
978
979 return 0;
980}
981
982int
romanc1124572024-04-23 15:08:06 +0200983nc_client_tls_load_crl_wrap(void *crl_store, const char *file_path, const char *dir_path)
romanb00f4322024-04-04 09:26:18 +0200984{
romanc1124572024-04-23 15:08:06 +0200985 int rc, ret = 0;
986 DIR *dir = NULL;
romanb00f4322024-04-04 09:26:18 +0200987 struct dirent *entry;
988 struct stat st = {0};
romanc1124572024-04-23 15:08:06 +0200989 char *path = NULL;
romanb00f4322024-04-04 09:26:18 +0200990
991 if (file_path && (rc = mbedtls_x509_crl_parse_file(crl_store, file_path))) {
romanc1124572024-04-23 15:08:06 +0200992 ERR(NULL, "Loading CRL from file \"%s\" failed (%s).", file_path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200993 return 1;
994 }
995
996 if (dir_path) {
997 /* parse the CRLs in the directory one by one */
998 dir = opendir(dir_path);
999 if (!dir) {
1000 ERR(NULL, "Failed to open directory \"%s\" (%s).", dir_path, strerror(errno));
romanc1124572024-04-23 15:08:06 +02001001 return 1;
romanb00f4322024-04-04 09:26:18 +02001002 }
1003
1004 while ((entry = readdir(dir))) {
1005 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
1006 /* skip current and parent directory */
1007 continue;
1008 }
1009
romanc1124572024-04-23 15:08:06 +02001010 rc = asprintf(&path, "%s/%s", dir_path, entry->d_name);
1011 NC_CHECK_ERRMEM_GOTO(rc == -1, ret = 1; path = NULL, cleanup);
romanb00f4322024-04-04 09:26:18 +02001012
1013 if (stat(path, &st) == -1) {
1014 if (errno == ENOENT) {
1015 /* broken symbolic link, ignore */
1016 free(path);
romanb6aa3532024-05-13 13:44:54 +02001017 path = NULL;
romanb00f4322024-04-04 09:26:18 +02001018 continue;
1019 } else {
1020 ERR(NULL, "Failed to get information about \"%s\" (%s).", path, strerror(errno));
romanc1124572024-04-23 15:08:06 +02001021 ret = 1;
1022 goto cleanup;
romanb00f4322024-04-04 09:26:18 +02001023 }
1024 }
1025
1026 if (!S_ISREG(st.st_mode)) {
1027 /* not a regular file, ignore */
1028 free(path);
romanb6aa3532024-05-13 13:44:54 +02001029 path = NULL;
romanb00f4322024-04-04 09:26:18 +02001030 continue;
1031 }
1032
1033 rc = mbedtls_x509_crl_parse_file(crl_store, path);
1034 if (rc) {
romanc1124572024-04-23 15:08:06 +02001035 WRN(NULL, "Loading CRL from file \"%s\" failed (%s), skipping.", path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001036 }
1037
1038 free(path);
romanc1124572024-04-23 15:08:06 +02001039 path = NULL;
romanb00f4322024-04-04 09:26:18 +02001040 }
1041 }
1042
romanc1124572024-04-23 15:08:06 +02001043cleanup:
1044 free(path);
romanb6aa3532024-05-13 13:44:54 +02001045 if (dir) {
1046 closedir(dir);
1047 }
romanc1124572024-04-23 15:08:06 +02001048 return ret;
romanb00f4322024-04-04 09:26:18 +02001049}
1050
1051int
1052nc_client_tls_set_hostname_wrap(void *tls_session, const char *hostname)
1053{
1054 int rc;
1055
1056 rc = mbedtls_ssl_set_hostname(tls_session, hostname);
1057 if (rc) {
romanc1124572024-04-23 15:08:06 +02001058 ERR(NULL, "Setting hostname failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001059 return 1;
1060 }
1061
1062 return 0;
1063}
1064
1065int
romanc1124572024-04-23 15:08:06 +02001066nc_tls_init_ctx_wrap(int sock, void *cert, void *pkey, void *cert_store, void *crl_store, struct nc_tls_ctx *tls_ctx)
romanb00f4322024-04-04 09:26:18 +02001067{
1068 /* setup rng */
1069 if (nc_tls_rng_new(&tls_ctx->ctr_drbg, &tls_ctx->entropy)) {
1070 return 1;
1071 }
1072
1073 /* fill the context */
1074 tls_ctx->sock = malloc(sizeof *tls_ctx->sock);
1075 NC_CHECK_ERRMEM_RET(!tls_ctx->sock, 1);
1076 *tls_ctx->sock = sock;
romanc1124572024-04-23 15:08:06 +02001077 tls_ctx->cert = cert;
1078 tls_ctx->pkey = pkey;
romanb00f4322024-04-04 09:26:18 +02001079 tls_ctx->cert_store = cert_store;
1080 tls_ctx->crl_store = crl_store;
1081 return 0;
1082}
1083
1084int
romanc1124572024-04-23 15:08:06 +02001085nc_tls_setup_config_from_ctx_wrap(struct nc_tls_ctx *tls_ctx, int side, void *tls_cfg)
romanb00f4322024-04-04 09:26:18 +02001086{
romanc1124572024-04-23 15:08:06 +02001087 int rc;
romanb00f4322024-04-04 09:26:18 +02001088
romanc1124572024-04-23 15:08:06 +02001089 /* set default config data */
1090 if (side == NC_SERVER) {
1091 rc = mbedtls_ssl_config_defaults(tls_cfg, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
romanb00f4322024-04-04 09:26:18 +02001092 } else {
romanc1124572024-04-23 15:08:06 +02001093 rc = mbedtls_ssl_config_defaults(tls_cfg, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
romanb00f4322024-04-04 09:26:18 +02001094 }
romanc1124572024-04-23 15:08:06 +02001095 if (rc) {
1096 ERR(NULL, "Setting default TLS config failed (%s).", nc_get_mbedtls_str_err(rc));
1097 return 1;
1098 }
1099
1100 /* set config's rng */
1101 mbedtls_ssl_conf_rng(tls_cfg, mbedtls_ctr_drbg_random, tls_ctx->ctr_drbg);
1102 /* set config's cert and key */
1103 mbedtls_ssl_conf_own_cert(tls_cfg, tls_ctx->cert, tls_ctx->pkey);
1104 /* set config's CA and CRL cert store */
1105 mbedtls_ssl_conf_ca_chain(tls_cfg, tls_ctx->cert_store, tls_ctx->crl_store);
1106 return 0;
romanb00f4322024-04-04 09:26:18 +02001107}
1108
1109uint32_t
1110nc_tls_get_verify_result_wrap(void *tls_session)
1111{
1112 return mbedtls_ssl_get_verify_result(tls_session);
1113}
1114
romanc1124572024-04-23 15:08:06 +02001115char *
romanb00f4322024-04-04 09:26:18 +02001116nc_tls_verify_error_string_wrap(uint32_t err_code)
1117{
romanc1124572024-04-23 15:08:06 +02001118 return nc_tls_get_verify_err_str(err_code);
romanb00f4322024-04-04 09:26:18 +02001119}
1120
1121void
romanc1124572024-04-23 15:08:06 +02001122nc_client_tls_print_connect_err_wrap(int connect_ret, const char *peername, void *UNUSED(tls_session))
romanb00f4322024-04-04 09:26:18 +02001123{
romanc1124572024-04-23 15:08:06 +02001124 const char *err = nc_get_mbedtls_str_err(connect_ret);
romanb00f4322024-04-04 09:26:18 +02001125
romanc1124572024-04-23 15:08:06 +02001126 if (err) {
1127 ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, err);
romanb00f4322024-04-04 09:26:18 +02001128 } else {
romanc1124572024-04-23 15:08:06 +02001129 ERR(NULL, "TLS connection to \"%s\" failed.", peername);
1130 }
1131}
1132
1133void
1134nc_server_tls_print_accept_err_wrap(int accept_ret, void *UNUSED(tls_session))
1135{
1136 const char *err = nc_get_mbedtls_str_err(accept_ret);
1137
1138 if (err) {
1139 ERR(NULL, "TLS accept failed (%s).", err);
1140 } else {
1141 ERR(NULL, "TLS accept failed.");
romanb00f4322024-04-04 09:26:18 +02001142 }
1143}
1144
1145int
romanc1124572024-04-23 15:08:06 +02001146nc_tls_is_der_subpubkey_wrap(unsigned char *der, long len)
1147{
1148 int ret;
1149 mbedtls_pk_context *pkey;
1150
1151 pkey = nc_tls_pkey_new_wrap();
1152 if (!pkey) {
1153 return -1;
1154 }
1155
1156 ret = mbedtls_pk_parse_subpubkey(&der, der + len, pkey);
1157 nc_tls_privkey_destroy_wrap(pkey);
romane20f3542024-05-14 11:00:54 +02001158
1159 return !ret;
romanc1124572024-04-23 15:08:06 +02001160}
1161
1162int
1163nc_base64_decode_wrap(const char *base64, unsigned char **bin)
romanb00f4322024-04-04 09:26:18 +02001164{
1165 size_t size;
romanc1124572024-04-23 15:08:06 +02001166 int rc;
romanb00f4322024-04-04 09:26:18 +02001167
romanc1124572024-04-23 15:08:06 +02001168 /* get the size of the decoded data */
1169 rc = mbedtls_base64_decode(NULL, 0, &size, (const unsigned char *)base64, strlen(base64));
1170 if (rc != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
1171 ERR(NULL, "Base64 decoding failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001172 return -1;
1173 }
1174
1175 *bin = malloc(size);
1176 NC_CHECK_ERRMEM_RET(!*bin, -1);
1177
romanc1124572024-04-23 15:08:06 +02001178 /* decode */
1179 rc = mbedtls_base64_decode(*bin, size, &size, (const unsigned char *)base64, strlen(base64));
1180 if (rc) {
1181 ERR(NULL, "Base64 decoding failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001182 free(*bin);
1183 *bin = NULL;
1184 return -1;
1185 }
1186
1187 return size;
1188}
1189
1190int
1191nc_base64_encode_wrap(const unsigned char *bin, size_t len, char **base64)
1192{
1193 size_t size;
romanc1124572024-04-23 15:08:06 +02001194 int rc;
romanb00f4322024-04-04 09:26:18 +02001195
romanc1124572024-04-23 15:08:06 +02001196 rc = mbedtls_base64_encode(NULL, 0, &size, bin, len);
1197 if (rc != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
1198 ERR(NULL, "Base64 encoding failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001199 return -1;
1200 }
1201
1202 *base64 = malloc(size);
1203 NC_CHECK_ERRMEM_RET(!*base64, -1);
1204
romanc1124572024-04-23 15:08:06 +02001205 rc = mbedtls_base64_encode((unsigned char *)*base64, size, &size, bin, len);
1206 if (rc) {
1207 ERR(NULL, "Base64 encoding failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001208 free(*base64);
1209 *base64 = NULL;
1210 return -1;
1211 }
1212
1213 return 0;
1214}
1215
1216int
1217nc_tls_read_wrap(struct nc_session *session, unsigned char *buf, size_t size)
1218{
1219 int rc;
1220 mbedtls_ssl_context *tls_session = session->ti.tls.session;
1221
1222 rc = mbedtls_ssl_read(tls_session, buf, size);
1223 if (rc <= 0) {
1224 switch (rc) {
1225 case MBEDTLS_ERR_SSL_WANT_READ:
1226 case MBEDTLS_ERR_SSL_WANT_WRITE:
1227 rc = 0;
1228 break;
1229 case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
1230 ERR(session, "Communication socket unexpectedly closed (MbedTLS).");
1231 session->status = NC_STATUS_INVALID;
1232 session->term_reason = NC_SESSION_TERM_DROPPED;
1233 rc = -1;
1234 break;
1235 default:
romanc1124572024-04-23 15:08:06 +02001236 ERR(session, "TLS communication error occurred (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001237 session->status = NC_STATUS_INVALID;
1238 session->term_reason = NC_SESSION_TERM_OTHER;
1239 rc = -1;
1240 break;
1241 }
1242 }
1243
1244 return rc;
1245}
1246
1247int
1248nc_tls_write_wrap(struct nc_session *session, const unsigned char *buf, size_t size)
1249{
1250 int rc = 0;
1251 mbedtls_ssl_context *tls_session = session->ti.tls.session;
1252
1253 rc = mbedtls_ssl_write(tls_session, buf, size);
1254 if (rc < 0) {
1255 switch (rc) {
1256 case MBEDTLS_ERR_SSL_WANT_READ:
1257 case MBEDTLS_ERR_SSL_WANT_WRITE:
1258 rc = 0;
1259 break;
1260 case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
1261 ERR(session, "TLS connection was properly closed.");
1262 rc = -1;
1263 break;
1264 default:
romanc1124572024-04-23 15:08:06 +02001265 ERR(session, "TLS communication error occurred (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001266 rc = -1;
1267 break;
1268 }
1269 }
1270
1271 return rc;
1272}
1273
1274int
romanc1124572024-04-23 15:08:06 +02001275nc_tls_get_num_pending_bytes_wrap(void *tls_session)
romanb00f4322024-04-04 09:26:18 +02001276{
1277 return mbedtls_ssl_get_bytes_avail(tls_session);
1278}
1279
1280int
1281nc_tls_get_fd_wrap(const struct nc_session *session)
1282{
romanc1124572024-04-23 15:08:06 +02001283 return session->ti.tls.ctx.sock ? *session->ti.tls.ctx.sock : -1;
romanb00f4322024-04-04 09:26:18 +02001284}
1285
1286void
1287nc_tls_close_notify_wrap(void *tls_session)
1288{
1289 int rc;
1290
1291 while ((rc = mbedtls_ssl_close_notify(tls_session))) {
1292 if ((rc != MBEDTLS_ERR_SSL_WANT_READ) && (rc != MBEDTLS_ERR_SSL_WANT_WRITE)) {
1293 /* some error occurred */
romanc1124572024-04-23 15:08:06 +02001294 ERR(NULL, "Sending TLS close notify failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001295 return;
1296 }
1297 }
1298}
1299
1300void *
romanb00f4322024-04-04 09:26:18 +02001301nc_tls_import_cert_file_wrap(const char *cert_path)
1302{
1303 int rc;
1304 mbedtls_x509_crt *c;
1305
1306 c = nc_tls_cert_new_wrap();
1307 if (!c) {
1308 return NULL;
1309 }
1310
1311 rc = mbedtls_x509_crt_parse_file(c, cert_path);
1312 if (rc) {
romanc1124572024-04-23 15:08:06 +02001313 ERR(NULL, "Parsing certificate from file \"%s\" failed (%s).", cert_path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001314 nc_tls_cert_destroy_wrap(c);
1315 return NULL;
1316 }
1317
1318 return c;
1319}
1320
1321char *
romanc1124572024-04-23 15:08:06 +02001322nc_tls_export_privkey_pem_wrap(void *pkey)
romanb00f4322024-04-04 09:26:18 +02001323{
1324 int rc;
1325 char *pem;
1326 size_t size = 128;
romanb00f4322024-04-04 09:26:18 +02001327
1328 pem = malloc(size);
1329 NC_CHECK_ERRMEM_RET(!pem, NULL);
1330
1331 while ((rc = mbedtls_pk_write_key_pem(pkey, (unsigned char *)pem, size)) == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
1332 size <<= 1;
romanc1124572024-04-23 15:08:06 +02001333 pem = nc_realloc(pem, size);
1334 NC_CHECK_ERRMEM_RET(!pem, NULL);
romanb00f4322024-04-04 09:26:18 +02001335 }
1336 if (rc < 0) {
romanc1124572024-04-23 15:08:06 +02001337 ERR(NULL, "Exporting private key to PEM format failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001338 free(pem);
1339 return NULL;
1340 }
1341
1342 return pem;
1343}
1344
1345char *
romanc1124572024-04-23 15:08:06 +02001346nc_tls_export_cert_pem_wrap(void *cert)
romanb00f4322024-04-04 09:26:18 +02001347{
1348 char *b64 = NULL, *pem = NULL;
1349
romanc1124572024-04-23 15:08:06 +02001350 /* encode the certificate */
romanb00f4322024-04-04 09:26:18 +02001351 if (nc_base64_encode_wrap(((mbedtls_x509_crt *)cert)->raw.p, ((mbedtls_x509_crt *)cert)->raw.len, &b64)) {
1352 goto cleanup;
1353 }
1354
1355 if (asprintf(&pem, "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n", b64) == -1) {
1356 ERRMEM;
1357 pem = NULL;
1358 goto cleanup;
1359 }
1360
1361cleanup:
1362 free(b64);
1363 return pem;
1364}
1365
1366char *
romanc1124572024-04-23 15:08:06 +02001367nc_tls_export_pubkey_pem_wrap(void *pkey)
romanb00f4322024-04-04 09:26:18 +02001368{
1369 int rc;
1370 char *pem;
1371 size_t size = 128;
romanb00f4322024-04-04 09:26:18 +02001372
1373 pem = malloc(size);
1374 NC_CHECK_ERRMEM_RET(!pem, NULL);
1375
1376 while ((rc = mbedtls_pk_write_pubkey_pem(pkey, (unsigned char *)pem, size)) == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
1377 size <<= 1;
romanc1124572024-04-23 15:08:06 +02001378 pem = nc_realloc(pem, size);
1379 NC_CHECK_ERRMEM_RET(!pem, NULL);
romanb00f4322024-04-04 09:26:18 +02001380 }
1381 if (rc < 0) {
romanc1124572024-04-23 15:08:06 +02001382 ERR(NULL, "Exporting public key to PEM format failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001383 free(pem);
1384 return NULL;
1385 }
1386
1387 return pem;
1388}
1389
1390int
romanb00f4322024-04-04 09:26:18 +02001391nc_tls_privkey_is_rsa_wrap(void *pkey)
1392{
1393 return mbedtls_pk_get_type(pkey) == MBEDTLS_PK_RSA;
1394}
1395
1396int
1397nc_tls_get_rsa_pubkey_params_wrap(void *pkey, void **e, void **n)
1398{
1399 int rc;
1400 mbedtls_mpi *exp = NULL, *mod = NULL;
1401
1402 exp = malloc(sizeof *exp);
1403 mod = malloc(sizeof *mod);
1404 if (!exp || !mod) {
1405 ERRMEM;
1406 goto fail;
1407 }
1408 mbedtls_mpi_init(exp);
1409 mbedtls_mpi_init(mod);
1410
1411 if ((rc = mbedtls_rsa_export(mbedtls_pk_rsa(*(mbedtls_pk_context *)pkey), mod, NULL, NULL, NULL, exp))) {
romanc1124572024-04-23 15:08:06 +02001412 ERR(NULL, "Failed to export RSA public key parameters (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001413 goto fail;
1414 }
1415
1416 *e = exp;
1417 *n = mod;
1418 return 0;
1419
1420fail:
1421 mbedtls_mpi_free(exp);
1422 mbedtls_mpi_free(mod);
1423 free(exp);
1424 free(mod);
1425 return 1;
1426}
1427
romanc1124572024-04-23 15:08:06 +02001428void
1429nc_tls_destroy_mpi_wrap(void *mpi)
1430{
1431 mbedtls_mpi_free(mpi);
1432 free(mpi);
1433}
1434
romanb00f4322024-04-04 09:26:18 +02001435int
1436nc_tls_privkey_is_ec_wrap(void *pkey)
1437{
1438 return mbedtls_pk_get_type(pkey) == MBEDTLS_PK_ECKEY;
1439}
1440
1441char *
1442nc_tls_get_ec_group_wrap(void *pkey)
1443{
1444 const mbedtls_ecp_curve_info *curve_info;
1445 mbedtls_ecp_group_id group_id;
1446 mbedtls_ecp_keypair *ec;
1447
romanc1124572024-04-23 15:08:06 +02001448 /* get the group ID from the EC key */
romanb00f4322024-04-04 09:26:18 +02001449 ec = mbedtls_pk_ec(*(mbedtls_pk_context *)pkey);
1450 group_id = ec->private_grp.id;
romanc1124572024-04-23 15:08:06 +02001451
1452 /* get the group name based on the id */
romanb00f4322024-04-04 09:26:18 +02001453 curve_info = mbedtls_ecp_curve_info_from_grp_id(group_id);
1454 return strdup(curve_info->name);
1455}
1456
1457int
romanc1124572024-04-23 15:08:06 +02001458nc_tls_get_ec_pubkey_params_wrap(void *pkey, void **q, void **q_grp)
romanb00f4322024-04-04 09:26:18 +02001459{
romanc1124572024-04-23 15:08:06 +02001460 int ret;
1461 mbedtls_ecp_group *grp = NULL;
1462 mbedtls_ecp_point *p = NULL;
1463 mbedtls_mpi *d = NULL;
romanb00f4322024-04-04 09:26:18 +02001464
romanc1124572024-04-23 15:08:06 +02001465 /* init group, mpi and point */
1466 grp = malloc(sizeof *grp);
1467 d = malloc(sizeof *d);
1468 p = malloc(sizeof *p);
1469 if (!grp || !p || !d) {
1470 ERRMEM;
1471 ret = 1;
1472 goto cleanup;
1473 }
1474 mbedtls_ecp_group_init(grp);
1475 mbedtls_mpi_init(d);
1476 mbedtls_ecp_point_init(p);
romanb00f4322024-04-04 09:26:18 +02001477
romanc1124572024-04-23 15:08:06 +02001478 /* get the group and public key */
1479 ret = mbedtls_ecp_export(mbedtls_pk_ec(*(mbedtls_pk_context *)pkey), grp, d, p);
1480 if (ret) {
1481 ERR(NULL, "Failed to export EC public key parameters (%s).", nc_get_mbedtls_str_err(ret));
1482 ret = 1;
1483 goto cleanup;
1484 }
1485
1486 *q_grp = grp;
1487 grp = NULL;
1488 *q = p;
1489 p = NULL;
1490
1491cleanup:
1492 mbedtls_ecp_group_free(grp);
1493 free(grp);
1494 mbedtls_mpi_free(d);
1495 free(d);
1496 mbedtls_ecp_point_free(p);
1497 free(p);
1498 return ret;
1499}
1500
1501int
1502nc_tls_ec_point_to_bin_wrap(void *q, void *q_grp, unsigned char **bin, int *bin_len)
1503{
1504 int rc;
1505 unsigned char *buf;
1506 size_t buf_len = 32, out_len;
1507
1508 buf = malloc(buf_len);
1509 NC_CHECK_ERRMEM_RET(!buf, 1);
1510
1511 while ((rc = (mbedtls_ecp_point_write_binary(q_grp, q, MBEDTLS_ECP_PF_COMPRESSED, &out_len, buf, buf_len)))) {
1512 if (rc != MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL) {
1513 break;
romanb00f4322024-04-04 09:26:18 +02001514 }
romanc1124572024-04-23 15:08:06 +02001515 buf_len <<= 1;
1516 buf = nc_realloc(buf, buf_len);
1517 NC_CHECK_ERRMEM_RET(!buf, 1);
romanb00f4322024-04-04 09:26:18 +02001518 }
1519 if (rc) {
romanc1124572024-04-23 15:08:06 +02001520 ERR(NULL, "Failed to write EC public key binary (%s).", nc_get_mbedtls_str_err(rc));
1521 free(buf);
romanb00f4322024-04-04 09:26:18 +02001522 return 1;
1523 }
1524
romanc1124572024-04-23 15:08:06 +02001525 *bin = buf;
romanb00f4322024-04-04 09:26:18 +02001526 *bin_len = out_len;
1527 return 0;
1528}
1529
romanc1124572024-04-23 15:08:06 +02001530void
1531nc_tls_ec_point_destroy_wrap(void *p)
romanb00f4322024-04-04 09:26:18 +02001532{
romanc1124572024-04-23 15:08:06 +02001533 mbedtls_ecp_point_free(p);
1534 free(p);
romanb00f4322024-04-04 09:26:18 +02001535}
1536
1537void
romanc1124572024-04-23 15:08:06 +02001538nc_tls_ec_group_destroy_wrap(void *grp)
romanb00f4322024-04-04 09:26:18 +02001539{
romanc1124572024-04-23 15:08:06 +02001540 mbedtls_ecp_group_free(grp);
1541 free(grp);
romanb00f4322024-04-04 09:26:18 +02001542}
1543
1544int
romanc1124572024-04-23 15:08:06 +02001545nc_tls_mpi2bin_wrap(void *mpi, unsigned char **bin, int *bin_len)
romanb00f4322024-04-04 09:26:18 +02001546{
romanc1124572024-04-23 15:08:06 +02001547 int rc;
1548 unsigned char *buf;
1549 int buf_len;
romanb00f4322024-04-04 09:26:18 +02001550
romanc1124572024-04-23 15:08:06 +02001551 buf_len = mbedtls_mpi_size(mpi);
1552 buf = malloc(buf_len);
1553 NC_CHECK_ERRMEM_RET(!buf, 1);
1554
1555 rc = mbedtls_mpi_write_binary(mpi, buf, buf_len);
1556 if (rc) {
1557 ERR(NULL, "Failed to convert MPI to binary (%s).", nc_get_mbedtls_str_err(rc));
1558 free(buf);
romanb00f4322024-04-04 09:26:18 +02001559 return 1;
1560 }
1561
romanc1124572024-04-23 15:08:06 +02001562 *bin = buf;
1563 *bin_len = buf_len;
1564 return 0;
romanb00f4322024-04-04 09:26:18 +02001565}
1566
1567void *
1568nc_tls_import_pubkey_file_wrap(const char *pubkey_path)
1569{
1570 int rc = 0;
1571 mbedtls_pk_context *pk = NULL;
1572
romanc1124572024-04-23 15:08:06 +02001573 pk = nc_tls_pkey_new_wrap();
romanb00f4322024-04-04 09:26:18 +02001574 if (!pk) {
1575 return NULL;
1576 }
1577
1578 rc = mbedtls_pk_parse_public_keyfile(pk, pubkey_path);
1579 if (rc) {
romanc1124572024-04-23 15:08:06 +02001580 ERR(NULL, "Parsing public key from file \"%s\" failed (%s).", pubkey_path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001581 nc_tls_privkey_destroy_wrap(pk);
1582 return NULL;
1583 }
1584
1585 return pk;
1586}
roman275c3fb2024-04-05 12:29:11 +02001587
roman77e327a2024-05-14 11:01:21 +02001588/**
1589 * @brief Parse the CRL distribution points X509v3 extension and obtain the URIs.
1590 *
1591 * @param[in,out] p Pointer to the DER encoded extension. When the function gets called, this should
1592 * point to the first byte in the value of CRLDistributionPoints.
1593 * @param[in] len Length of the CRLDistributionPoints ASN.1 encoded value.
1594 * @param[out] uris Array of URIs found in the extension.
1595 * @param[out] uri_count Number of URIs found in the extension.
1596 * @return 0 on success, non-zero on error.
1597 */
1598static int
1599nc_server_tls_parse_crl_dist_points(unsigned char **p, size_t len, char ***uris, int *uri_count)
1600{
1601 int ret = 0;
1602 unsigned char *end_crl_dist_points;
1603 mbedtls_x509_sequence general_names = {0};
1604 mbedtls_x509_sequence *iter = NULL;
1605 mbedtls_x509_subject_alternative_name san = {0};
1606 void *tmp;
1607
1608 /*
1609 * parsing the value of CRLDistributionPoints
1610 *
1611 * CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
1612 */
1613 end_crl_dist_points = *p + len;
1614 while (*p < end_crl_dist_points) {
1615 /*
1616 * DistributionPoint ::= SEQUENCE {
1617 * distributionPoint [0] DistributionPointName OPTIONAL,
1618 * reasons [1] ReasonFlags OPTIONAL,
1619 * cRLIssuer [2] GeneralNames OPTIONAL }
1620 */
1621 ret = mbedtls_asn1_get_tag(p, end_crl_dist_points, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
1622 if (ret) {
1623 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
1624 goto cleanup;
1625 }
1626 if (!len) {
1627 /* empty sequence */
1628 continue;
1629 }
1630
1631 /* parse distributionPoint */
1632 ret = mbedtls_asn1_get_tag(p, end_crl_dist_points, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0);
1633 if (!ret) {
1634 /*
1635 * DistributionPointName ::= CHOICE {
1636 * fullName [0] GeneralNames,
1637 * nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
1638 */
1639 ret = mbedtls_asn1_get_tag(p, end_crl_dist_points, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0);
1640 if (ret) {
1641 if ((ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) && (**p == (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1))) {
1642 /* it's nameRelativeToCRLIssuer, but we don't support it */
1643 ERR(NULL, "Failed to parse CRL distribution points extension (nameRelativeToCRLIssuer not yet supported).");
1644 goto cleanup;
1645 } else {
1646 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
1647 goto cleanup;
1648 }
1649 }
1650
1651 /* parse GeneralNames, but thankfully there is an api for this */
1652 ret = mbedtls_x509_get_subject_alt_name_ext(p, *p + len, &general_names);
1653 if (ret) {
1654 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
1655 goto cleanup;
1656 }
1657
1658 /* iterate over all the GeneralNames */
1659 iter = &general_names;
1660 while (iter) {
1661 ret = mbedtls_x509_parse_subject_alt_name(&iter->buf, &san);
1662 if (ret && (ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE)) {
1663 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
1664 goto cleanup;
1665 }
1666
1667 if (san.type == MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER) {
1668 /* found an URI */
1669 tmp = realloc(*uris, (*uri_count + 1) * sizeof **uris);
1670 if (!tmp) {
1671 ERRMEM;
1672 ret = 1;
1673 mbedtls_x509_free_subject_alt_name(&san);
1674 goto cleanup;
1675 }
1676 *uris = tmp;
1677
1678 *uris[*uri_count] = strndup((const char *)san.san.unstructured_name.p, san.san.unstructured_name.len);
1679 if (!*uris[*uri_count]) {
1680 ERRMEM;
1681 ret = 1;
1682 mbedtls_x509_free_subject_alt_name(&san);
1683 goto cleanup;
1684 }
1685 ++(*uri_count);
1686 }
1687
1688 mbedtls_x509_free_subject_alt_name(&san);
1689 iter = iter->next;
1690 }
1691
1692 } else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
1693 /* failed to parse it, but not because it's optional */
1694 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
1695 goto cleanup;
1696 }
1697 }
1698
1699cleanup:
1700 return ret;
1701}
1702
roman275c3fb2024-04-05 12:29:11 +02001703int
1704nc_server_tls_get_crl_distpoint_uris_wrap(void *cert_store, char ***uris, int *uri_count)
1705{
1706 int ret = 0;
1707 mbedtls_x509_crt *cert;
romanc6309612024-05-14 12:36:02 +02001708 unsigned char *p, *end_v3_ext, *end_ext, *end_ext_octet;
roman275c3fb2024-04-05 12:29:11 +02001709 size_t len;
1710 mbedtls_x509_buf ext_oid = {0};
1711 int is_critical = 0;
roman275c3fb2024-04-05 12:29:11 +02001712
1713 NC_CHECK_ARG_RET(NULL, cert_store, uris, uri_count, 1);
1714
1715 *uris = NULL;
1716 *uri_count = 0;
1717
1718 /* iterate over all the CAs */
1719 cert = cert_store;
1720 while (cert) {
1721 if (!cert->v3_ext.len) {
1722 /* no extensions, skip this cert */
1723 cert = cert->next;
1724 continue;
1725 }
1726
1727 /* go over all the extensions and try to find the CRL distribution points */
1728 p = cert->v3_ext.p;
1729 end_v3_ext = p + cert->v3_ext.len;
1730
1731 /*
1732 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
1733 */
1734 ret = mbedtls_asn1_get_tag(&p, end_v3_ext, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
1735 if (ret) {
romanc1124572024-04-23 15:08:06 +02001736 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001737 goto cleanup;
1738 }
1739
1740 while (p < end_v3_ext) {
1741 /*
1742 * Extension ::= SEQUENCE {
1743 * extnID OBJECT IDENTIFIER,
1744 * critical BOOLEAN DEFAULT FALSE,
1745 * extnValue OCTET STRING }
1746 */
1747 ret = mbedtls_asn1_get_tag(&p, end_v3_ext, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
1748 if (ret) {
romanc1124572024-04-23 15:08:06 +02001749 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001750 goto cleanup;
1751 }
1752
1753 end_ext = p + len;
1754
1755 /* parse extnID */
1756 ret = mbedtls_asn1_get_tag(&p, end_ext, &ext_oid.len, MBEDTLS_ASN1_OID);
1757 if (ret) {
romanc1124572024-04-23 15:08:06 +02001758 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001759 goto cleanup;
1760 }
1761 ext_oid.tag = MBEDTLS_ASN1_OID;
1762 ext_oid.p = p;
1763
1764 if (memcmp(ext_oid.p, MBEDTLS_OID_CRL_DISTRIBUTION_POINTS, ext_oid.len)) {
1765 /* not the extension we are looking for */
1766 p = end_ext;
1767 continue;
1768 }
1769
1770 p += ext_oid.len;
1771
1772 /* parse optional critical */
1773 ret = mbedtls_asn1_get_bool(&p, end_ext, &is_critical);
1774 if (ret && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
romanc1124572024-04-23 15:08:06 +02001775 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001776 goto cleanup;
1777 }
1778
1779 /* parse extnValue */
1780 ret = mbedtls_asn1_get_tag(&p, end_ext, &len, MBEDTLS_ASN1_OCTET_STRING);
1781 if (ret) {
romanc1124572024-04-23 15:08:06 +02001782 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001783 goto cleanup;
1784 }
1785
1786 end_ext_octet = p + len;
1787
1788 /*
1789 * parse extnValue, that is CRLDistributionPoints
1790 *
1791 * CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
1792 */
1793 ret = mbedtls_asn1_get_tag(&p, end_ext_octet, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
1794 if (ret) {
romanc1124572024-04-23 15:08:06 +02001795 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001796 goto cleanup;
1797 }
1798 if (p + len != end_ext_octet) {
1799 /* length mismatch */
romanc1124572024-04-23 15:08:06 +02001800 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001801 goto cleanup;
1802 } else if (!len) {
1803 /* empty sequence, but size is 1..max */
1804 ERR(NULL, "Failed to parse CRL distribution points extension (empty sequence).");
1805 goto cleanup;
1806 }
1807
roman77e327a2024-05-14 11:01:21 +02001808 /* parse the distribution points and obtain the uris */
1809 ret = nc_server_tls_parse_crl_dist_points(&p, len, uris, uri_count);
1810 if (ret) {
1811 goto cleanup;
roman275c3fb2024-04-05 12:29:11 +02001812 }
1813 }
1814 cert = cert->next;
1815 }
1816
1817cleanup:
1818 return ret;
1819}
romanc1124572024-04-23 15:08:06 +02001820
1821int
1822nc_tls_process_cipher_suite_wrap(const char *cipher, char **out)
1823{
1824 const char *begin, *ptr;
1825
1826 /* check if it's a TLS 1.3 cipher suite */
1827 if (!strcmp(cipher, "tls-aes-256-gcm-sha384") || !strcmp(cipher, "tls-aes-128-gcm-sha256") ||
1828 !strcmp(cipher, "tls-chacha20-poly1305-sha256") || !strcmp(cipher, "tls-aes-128-ccm-sha256") ||
1829 !strcmp(cipher, "tls-aes-128-ccm-8-sha256")) {
1830 /* + 3 because mbedtls has "TLS1-3" prefix for 1.3 suites */
1831 *out = malloc(strlen(cipher) + 3 + 1);
1832 NC_CHECK_ERRMEM_RET(!*out, 1);
1833 sprintf(*out, "TLS1-3");
1834 begin = cipher + 4;
1835 } else {
1836 *out = malloc(strlen(cipher) + 1);
1837 NC_CHECK_ERRMEM_RET(!*out, 1);
1838 begin = cipher;
1839 }
1840
1841 /* convert to uppercase */
1842 for (ptr = begin; *ptr; ptr++) {
1843 (*out)[ptr - begin] = toupper(*ptr);
1844 }
1845
1846 (*out)[ptr - begin] = '\0';
1847 return 0;
1848}
1849
1850int
1851nc_tls_append_cipher_suite_wrap(struct nc_server_tls_opts *opts, const char *cipher_suite)
1852{
1853 int cipher_id;
1854
1855 cipher_id = mbedtls_ssl_get_ciphersuite_id(cipher_suite);
1856 if (!cipher_id) {
1857 return 1;
1858 }
1859
1860 /* append the cipher suite to a zero terminated array */
1861 if (!opts->ciphers) {
1862 /* first entry, account for terminating 0 */
1863 opts->ciphers = malloc(2 * sizeof *opts->ciphers);
1864 NC_CHECK_ERRMEM_RET(!opts->ciphers, 1);
1865 ((int *)opts->ciphers)[0] = cipher_id;
1866 opts->cipher_count = 1;
1867 } else {
1868 /* +2 because of terminating 0 */
1869 opts->ciphers = nc_realloc(opts->ciphers, (opts->cipher_count + 2) * sizeof *opts->ciphers);
1870 NC_CHECK_ERRMEM_RET(!opts->ciphers, 1);
1871 ((int *)opts->ciphers)[opts->cipher_count] = cipher_id;
1872 opts->cipher_count++;
1873 }
1874
1875 /* terminate the array */
1876 ((int *)opts->ciphers)[opts->cipher_count] = 0;
1877 return 0;
1878}
1879
1880void
1881nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, void *cipher_suites)
1882{
1883 mbedtls_ssl_conf_ciphersuites(tls_cfg, cipher_suites);
1884}