blob: b8287b8c4e28121f8437112e3a60582ffcb2f52a [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 <errno.h>
24#include <poll.h>
romanb00f4322024-04-04 09:26:18 +020025#include <stdint.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30
31#include <curl/curl.h>
32
33#include "compat.h"
34#include "config.h"
35#include "log_p.h"
36#include "session.h"
37#include "session_p.h"
38#include "session_wrapper.h"
39
romanb00f4322024-04-04 09:26:18 +020040#include <mbedtls/base64.h>
roman008cfe72024-04-05 12:36:18 +020041#include <mbedtls/bignum.h>
42#include <mbedtls/ctr_drbg.h>
roman008cfe72024-04-05 12:36:18 +020043#include <mbedtls/entropy.h>
44#include <mbedtls/error.h>
45#include <mbedtls/net_sockets.h>
46#include <mbedtls/oid.h>
47#include <mbedtls/pem.h>
48#include <mbedtls/ssl.h>
49#include <mbedtls/x509.h>
50#include <mbedtls/x509_crl.h>
51#include <mbedtls/x509_crt.h>
romanb00f4322024-04-04 09:26:18 +020052
romane20f3542024-05-14 11:00:54 +020053/**
54 * @brief Converts mbedTLS error codes to a string.
55 *
56 * Some mbedTLS functions may return 'high' and some 'low' level errors, try to handle both cases this way.
57 *
58 * @param[in] err MbedTLS error code.
59 * @return Error string.
60 */
romanc1124572024-04-23 15:08:06 +020061static const char *
62nc_get_mbedtls_str_err(int err)
63{
64 const char *err_str;
65
66 err_str = mbedtls_high_level_strerr(err);
67 if (err_str) {
68 return err_str;
69 }
70
71 err_str = mbedtls_low_level_strerr(err);
72 if (err_str) {
73 return err_str;
74 }
75
76 return "unknown error";
77}
78
79/**
80 * @brief Converts DN to a string.
81 *
82 * @param[in] dn Internal DN representation.
83 * @return DN string on success, NULL of fail.
84 */
85static char *
86nc_server_tls_dn2str(const mbedtls_x509_name *dn)
87{
88 char *str;
89 size_t len = 64;
90 int r;
91
92 str = malloc(len);
93 NC_CHECK_ERRMEM_RET(!str, NULL);
94
95 while ((r = mbedtls_x509_dn_gets(str, len, dn)) == MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) {
96 len <<= 1;
97 str = nc_realloc(str, len);
98 NC_CHECK_ERRMEM_RET(!str, NULL);
99 }
100 if (r < 1) {
101 free(str);
102 ERR(NULL, "Failed to convert DN to string (%s).", nc_get_mbedtls_str_err(r));
103 return NULL;
104 }
105
106 return str;
107}
108
romane20f3542024-05-14 11:00:54 +0200109/**
110 * @brief Create a new random number generator context.
111 *
112 * @param[out] ctr_drbg Random bit generator context.
113 * @param[out] entropy Entropy context.
114 * @return 0 on success, 1 on failure.
115 */
romanc1124572024-04-23 15:08:06 +0200116static int
117nc_tls_rng_new(mbedtls_ctr_drbg_context **ctr_drbg, mbedtls_entropy_context **entropy)
118{
119 int rc;
120
121 *ctr_drbg = NULL;
122 *entropy = NULL;
123
124 *entropy = malloc(sizeof **entropy);
125 NC_CHECK_ERRMEM_GOTO(!*entropy, , fail);
126 *ctr_drbg = malloc(sizeof **ctr_drbg);
127 NC_CHECK_ERRMEM_GOTO(!*ctr_drbg, , fail);
128
129 mbedtls_entropy_init(*entropy);
130 mbedtls_ctr_drbg_init(*ctr_drbg);
131
132 rc = mbedtls_ctr_drbg_seed(*ctr_drbg, mbedtls_entropy_func, *entropy, NULL, 0);
133 if (rc) {
134 ERR(NULL, "Seeding ctr_drbg failed (%s).", nc_get_mbedtls_str_err(rc));
135 goto fail;
136 }
137
138 return 0;
139
140fail:
141 mbedtls_ctr_drbg_free(*ctr_drbg);
142 free(*ctr_drbg);
143 if (*entropy) {
144 mbedtls_entropy_free(*entropy);
145 free(*entropy);
146 }
147 *ctr_drbg = NULL;
148 *entropy = NULL;
149 return 1;
150}
151
romane20f3542024-05-14 11:00:54 +0200152/**
153 * @brief Destroy the random number generator context.
154 *
155 * @param[in] ctr_drbg Random bit generator context.
156 * @param[in] entropy Entropy context.
157 */
romanc1124572024-04-23 15:08:06 +0200158static void
159nc_tls_rng_destroy(mbedtls_ctr_drbg_context *ctr_drbg, mbedtls_entropy_context *entropy)
160{
161 mbedtls_ctr_drbg_free(ctr_drbg);
162 free(ctr_drbg);
163 if (entropy) {
164 mbedtls_entropy_free(entropy);
165 free(entropy);
166 }
167}
168
romane20f3542024-05-14 11:00:54 +0200169/**
170 * @brief Get a string representation of the verification error.
171 *
172 * @param[in] err Verification error code.
173 * @return String representation of the error. Caller is responsible for freeing it.
174 */
romanc1124572024-04-23 15:08:06 +0200175static char *
176nc_tls_get_verify_err_str(int err)
177{
178 int ret;
179 char *err_buf = NULL;
180
181 err_buf = malloc(256);
182 NC_CHECK_ERRMEM_RET(!err_buf, NULL);
183
184 ret = mbedtls_x509_crt_verify_info(err_buf, 256, "", err);
185 if (ret < 0) {
186 free(err_buf);
187 return NULL;
188 }
189
190 /* strip the NL */
191 err_buf[ret - 1] = '\0';
192
193 return err_buf;
194}
romanb00f4322024-04-04 09:26:18 +0200195
196void *
197nc_tls_session_new_wrap(void *tls_cfg)
198{
199 int rc;
200 mbedtls_ssl_context *session;
201
202 session = malloc(sizeof *session);
203 NC_CHECK_ERRMEM_RET(!session, NULL);
204
205 mbedtls_ssl_init(session);
206
207 rc = mbedtls_ssl_setup(session, tls_cfg);
208 if (rc) {
romanc1124572024-04-23 15:08:06 +0200209 ERR(NULL, "Setting up TLS session failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200210 mbedtls_ssl_free(session);
211 free(session);
212 return NULL;
213 }
214
215 return session;
216}
217
218void
219nc_tls_session_destroy_wrap(void *tls_session)
220{
221 mbedtls_ssl_free(tls_session);
222 free(tls_session);
223}
224
225void *
romanc1124572024-04-23 15:08:06 +0200226nc_tls_config_new_wrap(int UNUSED(side))
romanb00f4322024-04-04 09:26:18 +0200227{
228 mbedtls_ssl_config *tls_cfg;
229
230 tls_cfg = malloc(sizeof *tls_cfg);
231 NC_CHECK_ERRMEM_RET(!tls_cfg, NULL);
232
233 mbedtls_ssl_config_init(tls_cfg);
234 return tls_cfg;
235}
236
237void
238nc_tls_config_destroy_wrap(void *tls_cfg)
239{
240 if (!tls_cfg) {
241 return;
242 }
243
244 mbedtls_ssl_config_free(tls_cfg);
245 free(tls_cfg);
246}
247
248void *
romanb87aa452024-05-13 12:58:00 +0200249nc_tls_cert_new_wrap(void)
romanb00f4322024-04-04 09:26:18 +0200250{
251 mbedtls_x509_crt *cert;
252
253 cert = malloc(sizeof *cert);
254 NC_CHECK_ERRMEM_RET(!cert, NULL);
255
256 mbedtls_x509_crt_init(cert);
257 return cert;
258}
259
260void
261nc_tls_cert_destroy_wrap(void *cert)
262{
263 mbedtls_x509_crt_free(cert);
264 free(cert);
265}
266
romane20f3542024-05-14 11:00:54 +0200267/**
268 * @brief Create a new private key context.
269 *
270 * @return New private key context or NULL.
271 */
romanc1124572024-04-23 15:08:06 +0200272static void *
273nc_tls_pkey_new_wrap(void)
romanb00f4322024-04-04 09:26:18 +0200274{
275 mbedtls_pk_context *pkey;
276
277 pkey = malloc(sizeof *pkey);
278 NC_CHECK_ERRMEM_RET(!pkey, NULL);
279
280 mbedtls_pk_init(pkey);
281 return pkey;
282}
283
284void
285nc_tls_privkey_destroy_wrap(void *pkey)
286{
287 mbedtls_pk_free(pkey);
288 free(pkey);
289}
290
291void *
romanb87aa452024-05-13 12:58:00 +0200292nc_tls_cert_store_new_wrap(void)
romanb00f4322024-04-04 09:26:18 +0200293{
romanc1124572024-04-23 15:08:06 +0200294 /* certificate is the same as a certificate store in MbedTLS */
romanb00f4322024-04-04 09:26:18 +0200295 return nc_tls_cert_new_wrap();
296}
297
298void
299nc_tls_cert_store_destroy_wrap(void *cert_store)
300{
romanc1124572024-04-23 15:08:06 +0200301 /* certificate is the same as a certificate store in MbedTLS */
romanb00f4322024-04-04 09:26:18 +0200302 nc_tls_cert_destroy_wrap(cert_store);
303}
304
305void *
romanb87aa452024-05-13 12:58:00 +0200306nc_tls_crl_store_new_wrap(void)
romanb00f4322024-04-04 09:26:18 +0200307{
308 mbedtls_x509_crl *crl;
309
310 crl = malloc(sizeof *crl);
311 NC_CHECK_ERRMEM_RET(!crl, NULL);
312
313 mbedtls_x509_crl_init(crl);
314 return crl;
315}
316
317void
romanc1124572024-04-23 15:08:06 +0200318nc_tls_crl_store_destroy_wrap(void *crl_store)
romanb00f4322024-04-04 09:26:18 +0200319{
romanc1124572024-04-23 15:08:06 +0200320 mbedtls_x509_crl_free(crl_store);
321 free(crl_store);
romanb00f4322024-04-04 09:26:18 +0200322}
323
324void *
325nc_tls_pem_to_cert_wrap(const char *cert_data)
326{
327 int rc;
328 mbedtls_x509_crt *cert;
329
330 cert = nc_tls_cert_new_wrap();
331 if (!cert) {
332 return NULL;
333 }
334
335 rc = mbedtls_x509_crt_parse(cert, (const unsigned char *)cert_data, strlen(cert_data) + 1);
336 if (rc) {
romanc1124572024-04-23 15:08:06 +0200337 ERR(NULL, "Parsing certificate data failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200338 nc_tls_cert_destroy_wrap(cert);
339 return NULL;
340 }
341
342 return cert;
343}
344
345int
romanc1124572024-04-23 15:08:06 +0200346nc_tls_add_cert_to_store_wrap(void *cert, void *cert_store)
romanb00f4322024-04-04 09:26:18 +0200347{
romanc1124572024-04-23 15:08:06 +0200348 mbedtls_x509_crt *iter;
romanb00f4322024-04-04 09:26:18 +0200349
romanc1124572024-04-23 15:08:06 +0200350 /* store is a linked list */
351 iter = cert_store;
352 while (iter->next) {
353 iter = iter->next;
romanb00f4322024-04-04 09:26:18 +0200354 }
romanc1124572024-04-23 15:08:06 +0200355 iter->next = cert;
romanb00f4322024-04-04 09:26:18 +0200356
357 return 0;
358}
359
360void *
361nc_tls_pem_to_privkey_wrap(const char *privkey_data)
362{
romand971fa22024-04-25 15:08:13 +0200363 int rc = 0;
romanc1124572024-04-23 15:08:06 +0200364 mbedtls_pk_context *pkey = NULL;
365 mbedtls_ctr_drbg_context *ctr_drbg = NULL;
366 mbedtls_entropy_context *entropy = NULL;
romanb00f4322024-04-04 09:26:18 +0200367
romand971fa22024-04-25 15:08:13 +0200368 rc = nc_tls_rng_new(&ctr_drbg, &entropy);
369 if (rc) {
romanc1124572024-04-23 15:08:06 +0200370 goto cleanup;
romanb00f4322024-04-04 09:26:18 +0200371 }
372
romanc1124572024-04-23 15:08:06 +0200373 pkey = nc_tls_pkey_new_wrap();
romanb00f4322024-04-04 09:26:18 +0200374 if (!pkey) {
romand971fa22024-04-25 15:08:13 +0200375 rc = 1;
romanc1124572024-04-23 15:08:06 +0200376 goto cleanup;
romanb00f4322024-04-04 09:26:18 +0200377 }
378
379 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 +0200380 if (rc) {
romanc1124572024-04-23 15:08:06 +0200381 ERR(NULL, "Parsing private key data failed (%s).", nc_get_mbedtls_str_err(rc));
romanc1124572024-04-23 15:08:06 +0200382 goto cleanup;
romanb00f4322024-04-04 09:26:18 +0200383 }
romanc1124572024-04-23 15:08:06 +0200384
385cleanup:
romand971fa22024-04-25 15:08:13 +0200386 if (rc) {
romanc1124572024-04-23 15:08:06 +0200387 nc_tls_privkey_destroy_wrap(pkey);
romand971fa22024-04-25 15:08:13 +0200388 pkey = NULL;
romanc1124572024-04-23 15:08:06 +0200389 }
390 nc_tls_rng_destroy(ctr_drbg, entropy);
romanb00f4322024-04-04 09:26:18 +0200391 return pkey;
392}
393
394int
romanc1124572024-04-23 15:08:06 +0200395nc_server_tls_add_crl_to_store_wrap(const unsigned char *crl_data, size_t size, void *crl_store)
romanb00f4322024-04-04 09:26:18 +0200396{
397 int rc;
398
romanb00f4322024-04-04 09:26:18 +0200399 /* try DER first */
400 rc = mbedtls_x509_crl_parse_der(crl_store, crl_data, size);
401 if (!rc) {
402 /* success, it was DER */
403 return 0;
404 }
405
406 /* DER failed, try PEM */
romanc1124572024-04-23 15:08:06 +0200407 rc = mbedtls_x509_crl_parse(crl_store, crl_data, size + 1);
romanb00f4322024-04-04 09:26:18 +0200408 if (!rc) {
409 /* success, it was PEM */
410 return 0;
411 }
412
413 /* failed to parse it */
414 ERR(NULL, "Reading downloaded CRL failed.");
415 return 1;
416}
417
romanb00f4322024-04-04 09:26:18 +0200418int
419nc_server_tls_set_tls_versions_wrap(void *tls_cfg, unsigned int tls_versions)
420{
421 if ((tls_versions & NC_TLS_VERSION_10) || ((tls_versions & NC_TLS_VERSION_11))) {
422 /* skip TLS versions 1.0 and 1.1 */
423 WRN(NULL, "mbedTLS does not support TLS1.0 and TLS1.1");
424 }
425
426 /* first set the minimum version */
427 if (tls_versions & NC_TLS_VERSION_12) {
428 mbedtls_ssl_conf_min_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_2);
429 } else if (tls_versions & NC_TLS_VERSION_13) {
430 mbedtls_ssl_conf_min_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_3);
431 }
432
433 /* then set the maximum version */
434 if (tls_versions & NC_TLS_VERSION_13) {
435 mbedtls_ssl_conf_max_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_3);
436 } else if (tls_versions & NC_TLS_VERSION_12) {
437 mbedtls_ssl_conf_max_tls_version(tls_cfg, MBEDTLS_SSL_VERSION_TLS1_2);
438 }
439
440 return 0;
441}
442
romane20f3542024-05-14 11:00:54 +0200443/**
444 * @brief Duplicates a certificate.
445 *
446 * @param[in] cert Certificate to duplicate.
447 * @return Duplicated certificate or NULL.
448 */
roman396f4732024-05-14 09:09:30 +0200449static mbedtls_x509_crt *
450nc_tls_cert_dup(const mbedtls_x509_crt *cert)
451{
452 mbedtls_x509_crt *new_cert;
453
454 new_cert = nc_tls_cert_new_wrap();
455 if (!new_cert) {
456 return NULL;
457 }
458
459 if (mbedtls_x509_crt_parse_der(new_cert, cert->raw.p, cert->raw.len)) {
460 free(new_cert);
461 return NULL;
462 }
463
464 return new_cert;
465}
466
romane20f3542024-05-14 11:00:54 +0200467/**
roman7251b0d2024-07-04 13:25:02 +0200468 * @brief Duplicate a certificate and append it to a chain.
469 *
470 * @param[in] cert Certificate to duplicate and append.
471 * @param[in,out] chain Chain to append the certificate to.
472 * @return 0 on success, -1 on error.
473 */
474static int
475nc_server_tls_append_cert_to_chain(mbedtls_x509_crt *cert, mbedtls_x509_crt **chain)
476{
477 mbedtls_x509_crt *iter, *copy;
478
479 copy = nc_tls_cert_dup(cert);
480 if (!copy) {
481 return -1;
482 }
483
484 if (!*chain) {
485 /* first in the list */
486 *chain = copy;
487 } else {
488 /* find the last cert */
489 iter = *chain;
490 while (iter->next) {
491 iter = iter->next;
492 }
493 iter->next = copy;
494 }
495
496 return 0;
497}
498
499/**
romane20f3542024-05-14 11:00:54 +0200500 * @brief Verify a certificate.
501 *
502 * @param[in] cb_data Callback data (session, opts, data for CTN).
503 * @param[in] cert Certificate to verify.
504 * @param[in] depth Certificate depth in the chain.
505 * @param[in,out] flags Verification flags. Used to propagate errors.
506 * @return 0 on success (verification result is based on the value of flags), non-zero on fatal-error.
507 */
romanb00f4322024-04-04 09:26:18 +0200508static int
509nc_server_tls_verify_cb(void *cb_data, mbedtls_x509_crt *cert, int depth, uint32_t *flags)
510{
511 int ret = 0;
512 struct nc_tls_verify_cb_data *data = cb_data;
romanc1124572024-04-23 15:08:06 +0200513 char *err;
romanb00f4322024-04-04 09:26:18 +0200514
roman7251b0d2024-07-04 13:25:02 +0200515 /* append to the chain we're building */
516 ret = nc_server_tls_append_cert_to_chain(cert, (mbedtls_x509_crt **)&data->chain);
517 if (ret) {
518 nc_tls_cert_destroy_wrap(data->chain);
519 return MBEDTLS_ERR_X509_ALLOC_FAILED;
520 }
521
romanb00f4322024-04-04 09:26:18 +0200522 if (!*flags) {
523 /* in-built verification was successful */
roman7ffd2fc2024-05-13 13:48:34 +0200524 ret = nc_server_tls_verify_cert(cert, depth, 1, data);
romanb00f4322024-04-04 09:26:18 +0200525 } else {
romanc1124572024-04-23 15:08:06 +0200526 /* in-built verification failed, but the client still may be authenticated if:
527 * 1) the peer cert matches any configured end-entity cert
528 * 2) the peer cert has a valid chain of trust to any configured certificate authority cert
529 * otherwise just continue until we reach the peer cert (depth = 0)
romanb00f4322024-04-04 09:26:18 +0200530 */
531 if ((depth == 0) && (*flags == MBEDTLS_X509_BADCERT_NOT_TRUSTED)) {
romanc1124572024-04-23 15:08:06 +0200532 /* not trusted self-signed peer certificate, case 1) */
roman7ffd2fc2024-05-13 13:48:34 +0200533 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
romanb00f4322024-04-04 09:26:18 +0200534 if (!ret) {
535 *flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED;
536 }
romanc1124572024-04-23 15:08:06 +0200537 } else if (*flags == MBEDTLS_X509_BADCERT_MISSING) {
538 /* full chain of trust is invalid, but it may be valid partially, case 2) */
roman7ffd2fc2024-05-13 13:48:34 +0200539 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
romanc1124572024-04-23 15:08:06 +0200540 if (!ret) {
541 *flags &= ~MBEDTLS_X509_BADCERT_MISSING;
romanb00f4322024-04-04 09:26:18 +0200542 }
romanc1124572024-04-23 15:08:06 +0200543 } else {
544 err = nc_tls_get_verify_err_str(*flags);
545 ERR(data->session, "Cert verify: fail (%s).", err);
546 free(err);
romanb00f4322024-04-04 09:26:18 +0200547 ret = 1;
548 }
549 }
550
roman7251b0d2024-07-04 13:25:02 +0200551 if ((ret == -1) || (depth == 0)) {
552 /* free the chain */
553 nc_tls_cert_destroy_wrap(data->chain);
554 }
555
romanb00f4322024-04-04 09:26:18 +0200556 if (ret == -1) {
557 /* fatal error */
558 return MBEDTLS_ERR_X509_ALLOC_FAILED;
559 } else if (!ret) {
560 /* success */
roman396f4732024-05-14 09:09:30 +0200561 if ((depth == 0) && (!data->session->opts.server.client_cert)) {
562 /* copy the client cert */
563 data->session->opts.server.client_cert = nc_tls_cert_dup(cert);
564 if (!data->session->opts.server.client_cert) {
565 return MBEDTLS_ERR_X509_ALLOC_FAILED;
566 }
567 }
romanb00f4322024-04-04 09:26:18 +0200568 return 0;
569 } else {
570 if (depth > 0) {
571 /* chain verify failed, but peer cert can still match */
572 return 0;
573 } else {
romanc1124572024-04-23 15:08:06 +0200574 /* failed to verify peer cert, but return 0 so that we can propagate the error via the flags */
575 if (!*flags) {
576 *flags |= MBEDTLS_X509_BADCERT_OTHER;
577 }
578 return 0;
romanb00f4322024-04-04 09:26:18 +0200579 }
580 }
581}
582
583void
romanc1124572024-04-23 15:08:06 +0200584nc_server_tls_set_verify_wrap(void *tls_cfg, struct nc_tls_verify_cb_data *cb_data)
romanb00f4322024-04-04 09:26:18 +0200585{
romanc1124572024-04-23 15:08:06 +0200586 mbedtls_ssl_conf_authmode(tls_cfg, MBEDTLS_SSL_VERIFY_REQUIRED);
587 mbedtls_ssl_conf_verify(tls_cfg, nc_server_tls_verify_cb, cb_data);
romanb00f4322024-04-04 09:26:18 +0200588}
589
romanc1124572024-04-23 15:08:06 +0200590void
591nc_client_tls_set_verify_wrap(void *tls_cfg)
romanb00f4322024-04-04 09:26:18 +0200592{
romanc1124572024-04-23 15:08:06 +0200593 mbedtls_ssl_conf_authmode(tls_cfg, MBEDTLS_SSL_VERIFY_REQUIRED);
romanb00f4322024-04-04 09:26:18 +0200594}
595
596char *
597nc_server_tls_get_subject_wrap(void *cert)
598{
599 return nc_server_tls_dn2str(&(((mbedtls_x509_crt *)cert)->subject));
600}
601
602char *
603nc_server_tls_get_issuer_wrap(void *cert)
604{
605 return nc_server_tls_dn2str(&(((mbedtls_x509_crt *)cert)->issuer));
606}
607
romanc1124572024-04-23 15:08:06 +0200608void *
609nc_tls_get_sans_wrap(void *cert)
romanb00f4322024-04-04 09:26:18 +0200610{
romanc1124572024-04-23 15:08:06 +0200611 return &(((mbedtls_x509_crt *)cert)->subject_alt_names);
612}
romanb00f4322024-04-04 09:26:18 +0200613
romanc1124572024-04-23 15:08:06 +0200614void
615nc_tls_sans_destroy_wrap(void *UNUSED(sans))
616{
617 return;
618}
romanb00f4322024-04-04 09:26:18 +0200619
romanc1124572024-04-23 15:08:06 +0200620int
621nc_tls_get_num_sans_wrap(void *sans)
622{
623 mbedtls_x509_sequence *iter;
624 int n = 0;
romanb00f4322024-04-04 09:26:18 +0200625
romanc1124572024-04-23 15:08:06 +0200626 /* sans are a linked list */
627 iter = sans;
628 while (iter) {
629 ++n;
630 iter = iter->next;
romanb00f4322024-04-04 09:26:18 +0200631 }
632
romanc1124572024-04-23 15:08:06 +0200633 return n;
634}
635
636int
637nc_tls_get_san_value_type_wrap(void *sans, int idx, char **san_value, NC_TLS_CTN_MAPTYPE *san_type)
638{
639 int i, rc, ret = 0;
640 mbedtls_x509_sequence *iter;
641 mbedtls_x509_subject_alternative_name san = {0};
642 const mbedtls_x509_buf *ip;
643
644 *san_value = NULL;
645 *san_type = NC_TLS_CTN_UNKNOWN;
646
647 /* find the SAN */
648 iter = sans;
649 for (i = 0; i < idx; i++) {
650 iter = iter->next;
651 }
652
653 /* parse it */
654 rc = mbedtls_x509_parse_subject_alt_name(&iter->buf, &san);
655 if (rc && (rc != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE)) {
656 return -1;
657 }
658
659 /* get its type and value */
660 switch (san.type) {
661 case MBEDTLS_X509_SAN_DNS_NAME:
662 *san_type = NC_TLS_CTN_SAN_DNS_NAME;
663 *san_value = strndup((const char *)san.san.unstructured_name.p, san.san.unstructured_name.len);
664 NC_CHECK_ERRMEM_GOTO(!*san_value, ret = -1, cleanup);
665 break;
666 case MBEDTLS_X509_SAN_RFC822_NAME:
667 *san_type = NC_TLS_CTN_SAN_RFC822_NAME;
668 *san_value = strndup((const char *)san.san.unstructured_name.p, san.san.unstructured_name.len);
669 NC_CHECK_ERRMEM_GOTO(!*san_value, ret = -1, cleanup);
670 break;
671 case MBEDTLS_X509_SAN_IP_ADDRESS:
672 *san_type = NC_TLS_CTN_SAN_IP_ADDRESS;
673 ip = &san.san.unstructured_name;
674 if (ip->len == 4) {
675 rc = asprintf(san_value, "%d.%d.%d.%d", ip->p[0], ip->p[1], ip->p[2], ip->p[3]) == -1;
676 NC_CHECK_ERRMEM_GOTO(rc == -1, ret = -1, cleanup);
677 } else if (ip->len == 16) {
678 rc = asprintf(san_value, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
679 ip->p[0], ip->p[1], ip->p[2], ip->p[3], ip->p[4], ip->p[5],
680 ip->p[6], ip->p[7], ip->p[8], ip->p[9], ip->p[10], ip->p[11],
681 ip->p[12], ip->p[13], ip->p[14], ip->p[15]);
682 NC_CHECK_ERRMEM_GOTO(rc == -1, ret = -1, cleanup);
683 } else {
684 WRN(NULL, "SAN IP address in an unknown format (length is %d).", ip->len);
685 ret = 1;
686 }
687 break;
688 default:
689 /* we dont care about other types */
690 *san_type = NC_TLS_CTN_UNKNOWN;
691 ret = 1;
692 break;
693 }
694
695cleanup:
696 mbedtls_x509_free_subject_alt_name(&san);
697 return ret;
romanb00f4322024-04-04 09:26:18 +0200698}
699
700int
roman7251b0d2024-07-04 13:25:02 +0200701nc_tls_get_num_certs_wrap(void *chain)
702{
703 mbedtls_x509_crt *iter;
704 int n = 0;
705
706 /* chain is a linked list */
707 iter = chain;
708 while (iter) {
709 ++n;
710 iter = iter->next;
711 }
712
713 return n;
714}
715
716void
717nc_tls_get_cert_wrap(void *chain, int idx, void **cert)
718{
719 int i;
720 mbedtls_x509_crt *iter;
721
722 iter = chain;
723 for (i = 0; i < idx; i++) {
724 iter = iter->next;
725 }
726
727 *cert = iter;
728}
729
730int
romanb00f4322024-04-04 09:26:18 +0200731nc_server_tls_certs_match_wrap(void *cert1, void *cert2)
732{
733 mbedtls_x509_crt *c1 = cert1;
734 mbedtls_x509_crt *c2 = cert2;
735
736 if (!c1 || !c2) {
737 return 0;
738 }
739
740 /* compare raw DER encoded data */
741 if (!c1->raw.p || !c2->raw.p || (c1->raw.len != c2->raw.len) ||
742 memcmp(c1->raw.p, c2->raw.p, c1->raw.len)) {
743 return 0;
744 }
745
746 return 1;
747}
748
749int
750nc_server_tls_md5_wrap(void *cert, unsigned char *buf)
751{
752 int rc;
753 mbedtls_x509_crt *c = cert;
754
755 rc = mbedtls_md5(c->raw.p, c->raw.len, buf);
756 if (rc) {
romanc1124572024-04-23 15:08:06 +0200757 ERR(NULL, "Calculating MD5 digest failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200758 return 1;
759 }
760
761 return 0;
762}
763
764int
765nc_server_tls_sha1_wrap(void *cert, unsigned char *buf)
766{
767 int rc;
768 mbedtls_x509_crt *c = cert;
769
770 rc = mbedtls_sha1(c->raw.p, c->raw.len, buf);
771 if (rc) {
romanc1124572024-04-23 15:08:06 +0200772 ERR(NULL, "Calculating SHA-1 digest failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200773 return 1;
774 }
775
776 return 0;
777}
778
779int
780nc_server_tls_sha224_wrap(void *cert, unsigned char *buf)
781{
782 int rc;
783 mbedtls_x509_crt *c = cert;
784
785 rc = mbedtls_sha256(c->raw.p, c->raw.len, buf, 1);
786 if (rc) {
romanc1124572024-04-23 15:08:06 +0200787 ERR(NULL, "Calculating SHA-224 digest failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200788 return 1;
789 }
790
791 return 0;
792}
793
794int
795nc_server_tls_sha256_wrap(void *cert, unsigned char *buf)
796{
797 int rc;
798 mbedtls_x509_crt *c = cert;
799
800 rc = mbedtls_sha256(c->raw.p, c->raw.len, buf, 0);
801 if (rc) {
romanc1124572024-04-23 15:08:06 +0200802 ERR(NULL, "Calculating SHA-256 digest failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200803 return 1;
804 }
805
806 return 0;
807}
808
809int
810nc_server_tls_sha384_wrap(void *cert, unsigned char *buf)
811{
812 int rc;
813 mbedtls_x509_crt *c = cert;
814
815 rc = mbedtls_sha512(c->raw.p, c->raw.len, buf, 1);
816 if (rc) {
romanc1124572024-04-23 15:08:06 +0200817 ERR(NULL, "Calculating SHA-384 digest failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200818 return 1;
819 }
820
821 return 0;
822}
823
824int
825nc_server_tls_sha512_wrap(void *cert, unsigned char *buf)
826{
827 int rc;
828 mbedtls_x509_crt *c = cert;
829
830 rc = mbedtls_sha512(c->raw.p, c->raw.len, buf, 0);
831 if (rc) {
romanc1124572024-04-23 15:08:06 +0200832 ERR(NULL, "Calculating SHA-512 digest failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200833 return 1;
834 }
835
836 return 0;
837}
838
romane20f3542024-05-14 11:00:54 +0200839/**
840 * @brief Callback for sending data.
841 *
842 * @param[in] ctx Socket.
843 * @param[in] buf Data to send.
844 * @param[in] len Length of the data.
845 * @return Number of bytes sent or negative value on error.
846 */
romanc1124572024-04-23 15:08:06 +0200847static int
848nc_server_tls_send(void *ctx, const unsigned char *buf, size_t len)
849{
850 int sock, ret;
851
852 NC_CHECK_ARG_RET(NULL, ctx, MBEDTLS_ERR_NET_INVALID_CONTEXT);
853
854 sock = *(int *)ctx;
855
856 ret = send(sock, buf, len, MSG_NOSIGNAL);
857 if (ret < 0) {
858 if ((errno == EWOULDBLOCK) || (errno = EAGAIN) || (errno == EINTR)) {
859 return MBEDTLS_ERR_SSL_WANT_WRITE;
860 } else if ((errno == EPIPE) || (errno == ECONNRESET)) {
861 return MBEDTLS_ERR_NET_CONN_RESET;
862 } else {
863 return MBEDTLS_ERR_NET_SEND_FAILED;
864 }
865 }
866
867 return ret;
868}
869
romane20f3542024-05-14 11:00:54 +0200870/**
871 * @brief Callback for receiving data.
872 *
873 * @param[in] ctx Socket.
874 * @param[out] buf Buffer to store the received data.
875 * @param[in] len Length of the buffer.
876 * @return Number of bytes received or negative value on error.
877 */
romanc1124572024-04-23 15:08:06 +0200878static int
879nc_server_tls_recv(void *ctx, unsigned char *buf, size_t len)
880{
881 int sock, ret;
882
883 NC_CHECK_ARG_RET(NULL, ctx, MBEDTLS_ERR_NET_INVALID_CONTEXT);
884
885 sock = *(int *)ctx;
886
887 ret = recv(sock, buf, len, 0);
888 if (ret < 0) {
889 if ((errno == EWOULDBLOCK) || (errno = EAGAIN) || (errno == EINTR)) {
890 return MBEDTLS_ERR_SSL_WANT_READ;
891 } else if ((errno == EPIPE) || (errno == ECONNRESET)) {
892 return MBEDTLS_ERR_NET_CONN_RESET;
893 } else {
894 return MBEDTLS_ERR_NET_RECV_FAILED;
895 }
896 }
897
898 return ret;
899}
900
romanb00f4322024-04-04 09:26:18 +0200901void
902nc_server_tls_set_fd_wrap(void *tls_session, int UNUSED(sock), struct nc_tls_ctx *tls_ctx)
903{
romanc1124572024-04-23 15:08:06 +0200904 /* mbedtls sets a pointer to the sock, which is stored in tls_ctx */
905 mbedtls_ssl_set_bio(tls_session, tls_ctx->sock, nc_server_tls_send, nc_server_tls_recv, NULL);
romanb00f4322024-04-04 09:26:18 +0200906}
907
908int
909nc_server_tls_handshake_step_wrap(void *tls_session)
910{
911 int rc = 0;
912
913 rc = mbedtls_ssl_handshake(tls_session);
914 if (!rc) {
915 return 1;
roman008cfe72024-04-05 12:36:18 +0200916 } else if ((rc == MBEDTLS_ERR_SSL_WANT_READ) || (rc == MBEDTLS_ERR_SSL_WANT_WRITE)) {
romanb00f4322024-04-04 09:26:18 +0200917 return 0;
918 } else {
romanc1124572024-04-23 15:08:06 +0200919 return rc;
romanb00f4322024-04-04 09:26:18 +0200920 }
921}
922
923int
romanc1124572024-04-23 15:08:06 +0200924nc_client_tls_handshake_step_wrap(void *tls_session, int sock)
romanb00f4322024-04-04 09:26:18 +0200925{
romanc1124572024-04-23 15:08:06 +0200926 int rc = 0;
927 struct pollfd pfd = {sock, 0, 0};
romanb00f4322024-04-04 09:26:18 +0200928
romanc1124572024-04-23 15:08:06 +0200929 rc = mbedtls_ssl_handshake(tls_session);
930 if (!rc) {
romanb00f4322024-04-04 09:26:18 +0200931 return 1;
romanc1124572024-04-23 15:08:06 +0200932 } else if ((rc == MBEDTLS_ERR_SSL_WANT_READ) || (rc == MBEDTLS_ERR_SSL_WANT_WRITE)) {
933 /* check for EPIPE */
934 if (poll(&pfd, 1, 0) < 0) {
935 return -1;
936 } else {
937 if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
938 return -1;
939 } else {
940 return 0;
941 }
942 }
943 } else {
944 return rc;
romanb00f4322024-04-04 09:26:18 +0200945 }
romanb00f4322024-04-04 09:26:18 +0200946}
947
948void
949nc_tls_ctx_destroy_wrap(struct nc_tls_ctx *tls_ctx)
950{
romanc1124572024-04-23 15:08:06 +0200951 nc_tls_rng_destroy(tls_ctx->ctr_drbg, tls_ctx->entropy);
romanb00f4322024-04-04 09:26:18 +0200952 nc_tls_cert_destroy_wrap(tls_ctx->cert);
953 nc_tls_privkey_destroy_wrap(tls_ctx->pkey);
954 nc_tls_cert_store_destroy_wrap(tls_ctx->cert_store);
955 nc_tls_crl_store_destroy_wrap(tls_ctx->crl_store);
956 free(tls_ctx->sock);
957}
958
romanc1124572024-04-23 15:08:06 +0200959void *
960nc_tls_import_privkey_file_wrap(const char *privkey_path)
romanb00f4322024-04-04 09:26:18 +0200961{
962 int rc;
963 mbedtls_pk_context *pkey;
964 mbedtls_ctr_drbg_context *ctr_drbg;
965 mbedtls_entropy_context *entropy;
966
967 if (nc_tls_rng_new(&ctr_drbg, &entropy)) {
968 return NULL;
969 }
970
romanc1124572024-04-23 15:08:06 +0200971 pkey = nc_tls_pkey_new_wrap();
romanb00f4322024-04-04 09:26:18 +0200972 if (!pkey) {
973 nc_tls_rng_destroy(ctr_drbg, entropy);
974 return NULL;
975 }
976
977 rc = mbedtls_pk_parse_keyfile(pkey, privkey_path, NULL, mbedtls_ctr_drbg_random, ctr_drbg);
978 nc_tls_rng_destroy(ctr_drbg, entropy);
979 if (rc) {
romanc1124572024-04-23 15:08:06 +0200980 ERR(NULL, "Parsing private key from file \"%s\" failed (%s).", privkey_path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +0200981 nc_tls_privkey_destroy_wrap(pkey);
982 return NULL;
983 }
984 return pkey;
985}
986
romanb00f4322024-04-04 09:26:18 +0200987int
988nc_client_tls_load_cert_key_wrap(const char *cert_path, const char *key_path, void **cert, void **pkey)
989{
990 int ret = 0;
991 mbedtls_x509_crt *c;
992 mbedtls_pk_context *pk;
romanc1124572024-04-23 15:08:06 +0200993
994 NC_CHECK_ARG_RET(NULL, cert_path, key_path, cert, pkey, 1);
romanb00f4322024-04-04 09:26:18 +0200995
996 c = nc_tls_cert_new_wrap();
997 if (!c) {
998 return 1;
999 }
1000
1001 ret = mbedtls_x509_crt_parse_file(c, cert_path);
1002 if (ret) {
romanc1124572024-04-23 15:08:06 +02001003 ERR(NULL, "Parsing certificate from file \"%s\" failed (%s).", cert_path, nc_get_mbedtls_str_err(ret));
romanb00f4322024-04-04 09:26:18 +02001004 goto cleanup;
1005 }
1006
romanc1124572024-04-23 15:08:06 +02001007 pk = nc_tls_import_privkey_file_wrap(key_path);
1008 if (!pk) {
1009 ret = 1;
1010 goto cleanup;
romanb00f4322024-04-04 09:26:18 +02001011 }
1012
1013 *cert = c;
roman18ad7352024-05-13 12:58:52 +02001014 c = NULL;
romanb00f4322024-04-04 09:26:18 +02001015 *pkey = pk;
1016
1017cleanup:
roman18ad7352024-05-13 12:58:52 +02001018 nc_tls_cert_destroy_wrap(c);
romanb00f4322024-04-04 09:26:18 +02001019 return ret;
1020}
1021
1022int
1023nc_client_tls_load_trusted_certs_wrap(void *cert_store, const char *file_path, const char *dir_path)
1024{
1025 int rc;
1026
1027 if (file_path && ((rc = mbedtls_x509_crt_parse_file(cert_store, file_path)) < 0)) {
romanc1124572024-04-23 15:08:06 +02001028 ERR(NULL, "Loading CA certificate from file \"%s\" failed (%s).", file_path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001029 return 1;
1030 }
1031
1032 if (dir_path && ((rc = mbedtls_x509_crt_parse_path(cert_store, dir_path)) < 0)) {
romanc1124572024-04-23 15:08:06 +02001033 ERR(NULL, "Loading CA certificate from directory \"%s\" failed (%s).", dir_path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001034 return 1;
1035 }
1036
1037 return 0;
1038}
1039
1040int
romanb00f4322024-04-04 09:26:18 +02001041nc_client_tls_set_hostname_wrap(void *tls_session, const char *hostname)
1042{
1043 int rc;
1044
1045 rc = mbedtls_ssl_set_hostname(tls_session, hostname);
1046 if (rc) {
romanc1124572024-04-23 15:08:06 +02001047 ERR(NULL, "Setting hostname failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001048 return 1;
1049 }
1050
1051 return 0;
1052}
1053
1054int
romanc1124572024-04-23 15:08:06 +02001055nc_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 +02001056{
1057 /* setup rng */
1058 if (nc_tls_rng_new(&tls_ctx->ctr_drbg, &tls_ctx->entropy)) {
1059 return 1;
1060 }
1061
1062 /* fill the context */
1063 tls_ctx->sock = malloc(sizeof *tls_ctx->sock);
1064 NC_CHECK_ERRMEM_RET(!tls_ctx->sock, 1);
1065 *tls_ctx->sock = sock;
romanc1124572024-04-23 15:08:06 +02001066 tls_ctx->cert = cert;
1067 tls_ctx->pkey = pkey;
romanb00f4322024-04-04 09:26:18 +02001068 tls_ctx->cert_store = cert_store;
1069 tls_ctx->crl_store = crl_store;
1070 return 0;
1071}
1072
1073int
romanc1124572024-04-23 15:08:06 +02001074nc_tls_setup_config_from_ctx_wrap(struct nc_tls_ctx *tls_ctx, int side, void *tls_cfg)
romanb00f4322024-04-04 09:26:18 +02001075{
romanc1124572024-04-23 15:08:06 +02001076 int rc;
romanb00f4322024-04-04 09:26:18 +02001077
romanc1124572024-04-23 15:08:06 +02001078 /* set default config data */
1079 if (side == NC_SERVER) {
1080 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 +02001081 } else {
romanc1124572024-04-23 15:08:06 +02001082 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 +02001083 }
romanc1124572024-04-23 15:08:06 +02001084 if (rc) {
1085 ERR(NULL, "Setting default TLS config failed (%s).", nc_get_mbedtls_str_err(rc));
1086 return 1;
1087 }
1088
1089 /* set config's rng */
1090 mbedtls_ssl_conf_rng(tls_cfg, mbedtls_ctr_drbg_random, tls_ctx->ctr_drbg);
1091 /* set config's cert and key */
1092 mbedtls_ssl_conf_own_cert(tls_cfg, tls_ctx->cert, tls_ctx->pkey);
1093 /* set config's CA and CRL cert store */
1094 mbedtls_ssl_conf_ca_chain(tls_cfg, tls_ctx->cert_store, tls_ctx->crl_store);
1095 return 0;
romanb00f4322024-04-04 09:26:18 +02001096}
1097
1098uint32_t
1099nc_tls_get_verify_result_wrap(void *tls_session)
1100{
1101 return mbedtls_ssl_get_verify_result(tls_session);
1102}
1103
romanc1124572024-04-23 15:08:06 +02001104char *
romanb00f4322024-04-04 09:26:18 +02001105nc_tls_verify_error_string_wrap(uint32_t err_code)
1106{
romanc1124572024-04-23 15:08:06 +02001107 return nc_tls_get_verify_err_str(err_code);
romanb00f4322024-04-04 09:26:18 +02001108}
1109
1110void
romanc1124572024-04-23 15:08:06 +02001111nc_client_tls_print_connect_err_wrap(int connect_ret, const char *peername, void *UNUSED(tls_session))
romanb00f4322024-04-04 09:26:18 +02001112{
romanc1124572024-04-23 15:08:06 +02001113 const char *err = nc_get_mbedtls_str_err(connect_ret);
romanb00f4322024-04-04 09:26:18 +02001114
romanc1124572024-04-23 15:08:06 +02001115 if (err) {
1116 ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, err);
romanb00f4322024-04-04 09:26:18 +02001117 } else {
romanc1124572024-04-23 15:08:06 +02001118 ERR(NULL, "TLS connection to \"%s\" failed.", peername);
1119 }
1120}
1121
1122void
1123nc_server_tls_print_accept_err_wrap(int accept_ret, void *UNUSED(tls_session))
1124{
1125 const char *err = nc_get_mbedtls_str_err(accept_ret);
1126
1127 if (err) {
1128 ERR(NULL, "TLS accept failed (%s).", err);
1129 } else {
1130 ERR(NULL, "TLS accept failed.");
romanb00f4322024-04-04 09:26:18 +02001131 }
1132}
1133
1134int
romanc1124572024-04-23 15:08:06 +02001135nc_tls_is_der_subpubkey_wrap(unsigned char *der, long len)
1136{
1137 int ret;
1138 mbedtls_pk_context *pkey;
1139
1140 pkey = nc_tls_pkey_new_wrap();
1141 if (!pkey) {
1142 return -1;
1143 }
1144
1145 ret = mbedtls_pk_parse_subpubkey(&der, der + len, pkey);
1146 nc_tls_privkey_destroy_wrap(pkey);
romane20f3542024-05-14 11:00:54 +02001147
1148 return !ret;
romanc1124572024-04-23 15:08:06 +02001149}
1150
1151int
1152nc_base64_decode_wrap(const char *base64, unsigned char **bin)
romanb00f4322024-04-04 09:26:18 +02001153{
1154 size_t size;
romanc1124572024-04-23 15:08:06 +02001155 int rc;
romanb00f4322024-04-04 09:26:18 +02001156
romanc1124572024-04-23 15:08:06 +02001157 /* get the size of the decoded data */
1158 rc = mbedtls_base64_decode(NULL, 0, &size, (const unsigned char *)base64, strlen(base64));
1159 if (rc != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
1160 ERR(NULL, "Base64 decoding failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001161 return -1;
1162 }
1163
1164 *bin = malloc(size);
1165 NC_CHECK_ERRMEM_RET(!*bin, -1);
1166
romanc1124572024-04-23 15:08:06 +02001167 /* decode */
1168 rc = mbedtls_base64_decode(*bin, size, &size, (const unsigned char *)base64, strlen(base64));
1169 if (rc) {
1170 ERR(NULL, "Base64 decoding failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001171 free(*bin);
1172 *bin = NULL;
1173 return -1;
1174 }
1175
1176 return size;
1177}
1178
1179int
1180nc_base64_encode_wrap(const unsigned char *bin, size_t len, char **base64)
1181{
1182 size_t size;
romanc1124572024-04-23 15:08:06 +02001183 int rc;
romanb00f4322024-04-04 09:26:18 +02001184
romanc1124572024-04-23 15:08:06 +02001185 rc = mbedtls_base64_encode(NULL, 0, &size, bin, len);
1186 if (rc != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
1187 ERR(NULL, "Base64 encoding failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001188 return -1;
1189 }
1190
1191 *base64 = malloc(size);
1192 NC_CHECK_ERRMEM_RET(!*base64, -1);
1193
romanc1124572024-04-23 15:08:06 +02001194 rc = mbedtls_base64_encode((unsigned char *)*base64, size, &size, bin, len);
1195 if (rc) {
1196 ERR(NULL, "Base64 encoding failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001197 free(*base64);
1198 *base64 = NULL;
1199 return -1;
1200 }
1201
1202 return 0;
1203}
1204
1205int
1206nc_tls_read_wrap(struct nc_session *session, unsigned char *buf, size_t size)
1207{
1208 int rc;
1209 mbedtls_ssl_context *tls_session = session->ti.tls.session;
1210
1211 rc = mbedtls_ssl_read(tls_session, buf, size);
1212 if (rc <= 0) {
1213 switch (rc) {
1214 case MBEDTLS_ERR_SSL_WANT_READ:
1215 case MBEDTLS_ERR_SSL_WANT_WRITE:
1216 rc = 0;
1217 break;
1218 case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
1219 ERR(session, "Communication socket unexpectedly closed (MbedTLS).");
1220 session->status = NC_STATUS_INVALID;
1221 session->term_reason = NC_SESSION_TERM_DROPPED;
1222 rc = -1;
1223 break;
1224 default:
romanc1124572024-04-23 15:08:06 +02001225 ERR(session, "TLS communication error occurred (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001226 session->status = NC_STATUS_INVALID;
1227 session->term_reason = NC_SESSION_TERM_OTHER;
1228 rc = -1;
1229 break;
1230 }
1231 }
1232
1233 return rc;
1234}
1235
1236int
1237nc_tls_write_wrap(struct nc_session *session, const unsigned char *buf, size_t size)
1238{
1239 int rc = 0;
1240 mbedtls_ssl_context *tls_session = session->ti.tls.session;
1241
1242 rc = mbedtls_ssl_write(tls_session, buf, size);
1243 if (rc < 0) {
1244 switch (rc) {
1245 case MBEDTLS_ERR_SSL_WANT_READ:
1246 case MBEDTLS_ERR_SSL_WANT_WRITE:
1247 rc = 0;
1248 break;
1249 case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
1250 ERR(session, "TLS connection was properly closed.");
1251 rc = -1;
1252 break;
1253 default:
romanc1124572024-04-23 15:08:06 +02001254 ERR(session, "TLS communication error occurred (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001255 rc = -1;
1256 break;
1257 }
1258 }
1259
1260 return rc;
1261}
1262
1263int
romanc1124572024-04-23 15:08:06 +02001264nc_tls_get_num_pending_bytes_wrap(void *tls_session)
romanb00f4322024-04-04 09:26:18 +02001265{
1266 return mbedtls_ssl_get_bytes_avail(tls_session);
1267}
1268
1269int
1270nc_tls_get_fd_wrap(const struct nc_session *session)
1271{
romanc1124572024-04-23 15:08:06 +02001272 return session->ti.tls.ctx.sock ? *session->ti.tls.ctx.sock : -1;
romanb00f4322024-04-04 09:26:18 +02001273}
1274
1275void
1276nc_tls_close_notify_wrap(void *tls_session)
1277{
1278 int rc;
1279
1280 while ((rc = mbedtls_ssl_close_notify(tls_session))) {
1281 if ((rc != MBEDTLS_ERR_SSL_WANT_READ) && (rc != MBEDTLS_ERR_SSL_WANT_WRITE)) {
1282 /* some error occurred */
romanc1124572024-04-23 15:08:06 +02001283 ERR(NULL, "Sending TLS close notify failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001284 return;
1285 }
1286 }
1287}
1288
1289void *
romanb00f4322024-04-04 09:26:18 +02001290nc_tls_import_cert_file_wrap(const char *cert_path)
1291{
1292 int rc;
1293 mbedtls_x509_crt *c;
1294
1295 c = nc_tls_cert_new_wrap();
1296 if (!c) {
1297 return NULL;
1298 }
1299
1300 rc = mbedtls_x509_crt_parse_file(c, cert_path);
1301 if (rc) {
romanc1124572024-04-23 15:08:06 +02001302 ERR(NULL, "Parsing certificate from file \"%s\" failed (%s).", cert_path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001303 nc_tls_cert_destroy_wrap(c);
1304 return NULL;
1305 }
1306
1307 return c;
1308}
1309
1310char *
romanc1124572024-04-23 15:08:06 +02001311nc_tls_export_privkey_pem_wrap(void *pkey)
romanb00f4322024-04-04 09:26:18 +02001312{
1313 int rc;
1314 char *pem;
1315 size_t size = 128;
romanb00f4322024-04-04 09:26:18 +02001316
1317 pem = malloc(size);
1318 NC_CHECK_ERRMEM_RET(!pem, NULL);
1319
1320 while ((rc = mbedtls_pk_write_key_pem(pkey, (unsigned char *)pem, size)) == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
1321 size <<= 1;
romanc1124572024-04-23 15:08:06 +02001322 pem = nc_realloc(pem, size);
1323 NC_CHECK_ERRMEM_RET(!pem, NULL);
romanb00f4322024-04-04 09:26:18 +02001324 }
1325 if (rc < 0) {
romanc1124572024-04-23 15:08:06 +02001326 ERR(NULL, "Exporting private key to PEM format failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001327 free(pem);
1328 return NULL;
1329 }
1330
1331 return pem;
1332}
1333
1334char *
romanc1124572024-04-23 15:08:06 +02001335nc_tls_export_cert_pem_wrap(void *cert)
romanb00f4322024-04-04 09:26:18 +02001336{
1337 char *b64 = NULL, *pem = NULL;
1338
romanc1124572024-04-23 15:08:06 +02001339 /* encode the certificate */
romanb00f4322024-04-04 09:26:18 +02001340 if (nc_base64_encode_wrap(((mbedtls_x509_crt *)cert)->raw.p, ((mbedtls_x509_crt *)cert)->raw.len, &b64)) {
1341 goto cleanup;
1342 }
1343
1344 if (asprintf(&pem, "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n", b64) == -1) {
1345 ERRMEM;
1346 pem = NULL;
1347 goto cleanup;
1348 }
1349
1350cleanup:
1351 free(b64);
1352 return pem;
1353}
1354
1355char *
romanc1124572024-04-23 15:08:06 +02001356nc_tls_export_pubkey_pem_wrap(void *pkey)
romanb00f4322024-04-04 09:26:18 +02001357{
1358 int rc;
1359 char *pem;
1360 size_t size = 128;
romanb00f4322024-04-04 09:26:18 +02001361
1362 pem = malloc(size);
1363 NC_CHECK_ERRMEM_RET(!pem, NULL);
1364
1365 while ((rc = mbedtls_pk_write_pubkey_pem(pkey, (unsigned char *)pem, size)) == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
1366 size <<= 1;
romanc1124572024-04-23 15:08:06 +02001367 pem = nc_realloc(pem, size);
1368 NC_CHECK_ERRMEM_RET(!pem, NULL);
romanb00f4322024-04-04 09:26:18 +02001369 }
1370 if (rc < 0) {
romanc1124572024-04-23 15:08:06 +02001371 ERR(NULL, "Exporting public key to PEM format failed (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001372 free(pem);
1373 return NULL;
1374 }
1375
1376 return pem;
1377}
1378
1379int
romanb00f4322024-04-04 09:26:18 +02001380nc_tls_privkey_is_rsa_wrap(void *pkey)
1381{
1382 return mbedtls_pk_get_type(pkey) == MBEDTLS_PK_RSA;
1383}
1384
1385int
1386nc_tls_get_rsa_pubkey_params_wrap(void *pkey, void **e, void **n)
1387{
1388 int rc;
1389 mbedtls_mpi *exp = NULL, *mod = NULL;
1390
1391 exp = malloc(sizeof *exp);
1392 mod = malloc(sizeof *mod);
1393 if (!exp || !mod) {
1394 ERRMEM;
1395 goto fail;
1396 }
1397 mbedtls_mpi_init(exp);
1398 mbedtls_mpi_init(mod);
1399
1400 if ((rc = mbedtls_rsa_export(mbedtls_pk_rsa(*(mbedtls_pk_context *)pkey), mod, NULL, NULL, NULL, exp))) {
romanc1124572024-04-23 15:08:06 +02001401 ERR(NULL, "Failed to export RSA public key parameters (%s).", nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001402 goto fail;
1403 }
1404
1405 *e = exp;
1406 *n = mod;
1407 return 0;
1408
1409fail:
1410 mbedtls_mpi_free(exp);
1411 mbedtls_mpi_free(mod);
1412 free(exp);
1413 free(mod);
1414 return 1;
1415}
1416
romanc1124572024-04-23 15:08:06 +02001417void
1418nc_tls_destroy_mpi_wrap(void *mpi)
1419{
1420 mbedtls_mpi_free(mpi);
1421 free(mpi);
1422}
1423
romanb00f4322024-04-04 09:26:18 +02001424int
1425nc_tls_privkey_is_ec_wrap(void *pkey)
1426{
1427 return mbedtls_pk_get_type(pkey) == MBEDTLS_PK_ECKEY;
1428}
1429
1430char *
1431nc_tls_get_ec_group_wrap(void *pkey)
1432{
1433 const mbedtls_ecp_curve_info *curve_info;
1434 mbedtls_ecp_group_id group_id;
1435 mbedtls_ecp_keypair *ec;
1436
romanc1124572024-04-23 15:08:06 +02001437 /* get the group ID from the EC key */
romanb00f4322024-04-04 09:26:18 +02001438 ec = mbedtls_pk_ec(*(mbedtls_pk_context *)pkey);
1439 group_id = ec->private_grp.id;
romanc1124572024-04-23 15:08:06 +02001440
1441 /* get the group name based on the id */
romanb00f4322024-04-04 09:26:18 +02001442 curve_info = mbedtls_ecp_curve_info_from_grp_id(group_id);
1443 return strdup(curve_info->name);
1444}
1445
1446int
romanc1124572024-04-23 15:08:06 +02001447nc_tls_get_ec_pubkey_params_wrap(void *pkey, void **q, void **q_grp)
romanb00f4322024-04-04 09:26:18 +02001448{
romanc1124572024-04-23 15:08:06 +02001449 int ret;
1450 mbedtls_ecp_group *grp = NULL;
1451 mbedtls_ecp_point *p = NULL;
1452 mbedtls_mpi *d = NULL;
romanb00f4322024-04-04 09:26:18 +02001453
romanc1124572024-04-23 15:08:06 +02001454 /* init group, mpi and point */
1455 grp = malloc(sizeof *grp);
1456 d = malloc(sizeof *d);
1457 p = malloc(sizeof *p);
1458 if (!grp || !p || !d) {
1459 ERRMEM;
1460 ret = 1;
1461 goto cleanup;
1462 }
1463 mbedtls_ecp_group_init(grp);
1464 mbedtls_mpi_init(d);
1465 mbedtls_ecp_point_init(p);
romanb00f4322024-04-04 09:26:18 +02001466
romanc1124572024-04-23 15:08:06 +02001467 /* get the group and public key */
1468 ret = mbedtls_ecp_export(mbedtls_pk_ec(*(mbedtls_pk_context *)pkey), grp, d, p);
1469 if (ret) {
1470 ERR(NULL, "Failed to export EC public key parameters (%s).", nc_get_mbedtls_str_err(ret));
1471 ret = 1;
1472 goto cleanup;
1473 }
1474
1475 *q_grp = grp;
1476 grp = NULL;
1477 *q = p;
1478 p = NULL;
1479
1480cleanup:
1481 mbedtls_ecp_group_free(grp);
1482 free(grp);
1483 mbedtls_mpi_free(d);
1484 free(d);
1485 mbedtls_ecp_point_free(p);
1486 free(p);
1487 return ret;
1488}
1489
1490int
1491nc_tls_ec_point_to_bin_wrap(void *q, void *q_grp, unsigned char **bin, int *bin_len)
1492{
1493 int rc;
1494 unsigned char *buf;
1495 size_t buf_len = 32, out_len;
1496
1497 buf = malloc(buf_len);
1498 NC_CHECK_ERRMEM_RET(!buf, 1);
1499
1500 while ((rc = (mbedtls_ecp_point_write_binary(q_grp, q, MBEDTLS_ECP_PF_COMPRESSED, &out_len, buf, buf_len)))) {
1501 if (rc != MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL) {
1502 break;
romanb00f4322024-04-04 09:26:18 +02001503 }
romanc1124572024-04-23 15:08:06 +02001504 buf_len <<= 1;
1505 buf = nc_realloc(buf, buf_len);
1506 NC_CHECK_ERRMEM_RET(!buf, 1);
romanb00f4322024-04-04 09:26:18 +02001507 }
1508 if (rc) {
romanc1124572024-04-23 15:08:06 +02001509 ERR(NULL, "Failed to write EC public key binary (%s).", nc_get_mbedtls_str_err(rc));
1510 free(buf);
romanb00f4322024-04-04 09:26:18 +02001511 return 1;
1512 }
1513
romanc1124572024-04-23 15:08:06 +02001514 *bin = buf;
romanb00f4322024-04-04 09:26:18 +02001515 *bin_len = out_len;
1516 return 0;
1517}
1518
romanc1124572024-04-23 15:08:06 +02001519void
1520nc_tls_ec_point_destroy_wrap(void *p)
romanb00f4322024-04-04 09:26:18 +02001521{
romanc1124572024-04-23 15:08:06 +02001522 mbedtls_ecp_point_free(p);
1523 free(p);
romanb00f4322024-04-04 09:26:18 +02001524}
1525
1526void
romanc1124572024-04-23 15:08:06 +02001527nc_tls_ec_group_destroy_wrap(void *grp)
romanb00f4322024-04-04 09:26:18 +02001528{
romanc1124572024-04-23 15:08:06 +02001529 mbedtls_ecp_group_free(grp);
1530 free(grp);
romanb00f4322024-04-04 09:26:18 +02001531}
1532
1533int
romanc1124572024-04-23 15:08:06 +02001534nc_tls_mpi2bin_wrap(void *mpi, unsigned char **bin, int *bin_len)
romanb00f4322024-04-04 09:26:18 +02001535{
romanc1124572024-04-23 15:08:06 +02001536 int rc;
1537 unsigned char *buf;
1538 int buf_len;
romanb00f4322024-04-04 09:26:18 +02001539
romanc1124572024-04-23 15:08:06 +02001540 buf_len = mbedtls_mpi_size(mpi);
1541 buf = malloc(buf_len);
1542 NC_CHECK_ERRMEM_RET(!buf, 1);
1543
1544 rc = mbedtls_mpi_write_binary(mpi, buf, buf_len);
1545 if (rc) {
1546 ERR(NULL, "Failed to convert MPI to binary (%s).", nc_get_mbedtls_str_err(rc));
1547 free(buf);
romanb00f4322024-04-04 09:26:18 +02001548 return 1;
1549 }
1550
romanc1124572024-04-23 15:08:06 +02001551 *bin = buf;
1552 *bin_len = buf_len;
1553 return 0;
romanb00f4322024-04-04 09:26:18 +02001554}
1555
1556void *
1557nc_tls_import_pubkey_file_wrap(const char *pubkey_path)
1558{
1559 int rc = 0;
1560 mbedtls_pk_context *pk = NULL;
1561
romanc1124572024-04-23 15:08:06 +02001562 pk = nc_tls_pkey_new_wrap();
romanb00f4322024-04-04 09:26:18 +02001563 if (!pk) {
1564 return NULL;
1565 }
1566
1567 rc = mbedtls_pk_parse_public_keyfile(pk, pubkey_path);
1568 if (rc) {
romanc1124572024-04-23 15:08:06 +02001569 ERR(NULL, "Parsing public key from file \"%s\" failed (%s).", pubkey_path, nc_get_mbedtls_str_err(rc));
romanb00f4322024-04-04 09:26:18 +02001570 nc_tls_privkey_destroy_wrap(pk);
1571 return NULL;
1572 }
1573
1574 return pk;
1575}
roman275c3fb2024-04-05 12:29:11 +02001576
roman77e327a2024-05-14 11:01:21 +02001577/**
1578 * @brief Parse the CRL distribution points X509v3 extension and obtain the URIs.
1579 *
1580 * @param[in,out] p Pointer to the DER encoded extension. When the function gets called, this should
1581 * point to the first byte in the value of CRLDistributionPoints.
1582 * @param[in] len Length of the CRLDistributionPoints ASN.1 encoded value.
1583 * @param[out] uris Array of URIs found in the extension.
1584 * @param[out] uri_count Number of URIs found in the extension.
1585 * @return 0 on success, non-zero on error.
1586 */
1587static int
1588nc_server_tls_parse_crl_dist_points(unsigned char **p, size_t len, char ***uris, int *uri_count)
1589{
1590 int ret = 0;
1591 unsigned char *end_crl_dist_points;
1592 mbedtls_x509_sequence general_names = {0};
1593 mbedtls_x509_sequence *iter = NULL;
1594 mbedtls_x509_subject_alternative_name san = {0};
1595 void *tmp;
1596
1597 /*
1598 * parsing the value of CRLDistributionPoints
1599 *
1600 * CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
1601 */
1602 end_crl_dist_points = *p + len;
1603 while (*p < end_crl_dist_points) {
1604 /*
1605 * DistributionPoint ::= SEQUENCE {
1606 * distributionPoint [0] DistributionPointName OPTIONAL,
1607 * reasons [1] ReasonFlags OPTIONAL,
1608 * cRLIssuer [2] GeneralNames OPTIONAL }
1609 */
1610 ret = mbedtls_asn1_get_tag(p, end_crl_dist_points, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
1611 if (ret) {
1612 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
1613 goto cleanup;
1614 }
1615 if (!len) {
1616 /* empty sequence */
1617 continue;
1618 }
1619
1620 /* parse distributionPoint */
1621 ret = mbedtls_asn1_get_tag(p, end_crl_dist_points, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0);
1622 if (!ret) {
1623 /*
1624 * DistributionPointName ::= CHOICE {
1625 * fullName [0] GeneralNames,
1626 * nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
1627 */
1628 ret = mbedtls_asn1_get_tag(p, end_crl_dist_points, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0);
1629 if (ret) {
1630 if ((ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) && (**p == (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1))) {
1631 /* it's nameRelativeToCRLIssuer, but we don't support it */
1632 ERR(NULL, "Failed to parse CRL distribution points extension (nameRelativeToCRLIssuer not yet supported).");
1633 goto cleanup;
1634 } else {
1635 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
1636 goto cleanup;
1637 }
1638 }
1639
1640 /* parse GeneralNames, but thankfully there is an api for this */
1641 ret = mbedtls_x509_get_subject_alt_name_ext(p, *p + len, &general_names);
1642 if (ret) {
1643 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
1644 goto cleanup;
1645 }
1646
1647 /* iterate over all the GeneralNames */
1648 iter = &general_names;
1649 while (iter) {
1650 ret = mbedtls_x509_parse_subject_alt_name(&iter->buf, &san);
1651 if (ret && (ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE)) {
1652 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
1653 goto cleanup;
1654 }
1655
1656 if (san.type == MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER) {
1657 /* found an URI */
1658 tmp = realloc(*uris, (*uri_count + 1) * sizeof **uris);
1659 if (!tmp) {
1660 ERRMEM;
1661 ret = 1;
1662 mbedtls_x509_free_subject_alt_name(&san);
1663 goto cleanup;
1664 }
1665 *uris = tmp;
1666
roman15fbc592024-07-02 16:01:23 +02001667 (*uris)[*uri_count] = strndup((const char *)san.san.unstructured_name.p, san.san.unstructured_name.len);
1668 if (!(*uris)[*uri_count]) {
roman77e327a2024-05-14 11:01:21 +02001669 ERRMEM;
1670 ret = 1;
1671 mbedtls_x509_free_subject_alt_name(&san);
1672 goto cleanup;
1673 }
1674 ++(*uri_count);
1675 }
1676
1677 mbedtls_x509_free_subject_alt_name(&san);
1678 iter = iter->next;
1679 }
1680
1681 } else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
1682 /* failed to parse it, but not because it's optional */
1683 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
1684 goto cleanup;
1685 }
1686 }
1687
1688cleanup:
1689 return ret;
1690}
1691
roman275c3fb2024-04-05 12:29:11 +02001692int
roman15fbc592024-07-02 16:01:23 +02001693nc_server_tls_get_crl_distpoint_uris_wrap(void *leaf_cert, void *cert_store, char ***uris, int *uri_count)
roman275c3fb2024-04-05 12:29:11 +02001694{
roman15fbc592024-07-02 16:01:23 +02001695 int ret = 0, is_critical = 0, cert_count, i;
roman275c3fb2024-04-05 12:29:11 +02001696 mbedtls_x509_crt *cert;
romanc6309612024-05-14 12:36:02 +02001697 unsigned char *p, *end_v3_ext, *end_ext, *end_ext_octet;
roman275c3fb2024-04-05 12:29:11 +02001698 size_t len;
1699 mbedtls_x509_buf ext_oid = {0};
roman275c3fb2024-04-05 12:29:11 +02001700
1701 NC_CHECK_ARG_RET(NULL, cert_store, uris, uri_count, 1);
1702
roman50e3e562024-07-03 15:01:35 +02001703 *uris = NULL;
1704 *uri_count = 0;
1705
roman15fbc592024-07-02 16:01:23 +02001706 /* get the number of certs in the store */
roman275c3fb2024-04-05 12:29:11 +02001707 cert = cert_store;
roman15fbc592024-07-02 16:01:23 +02001708 cert_count = 0;
roman275c3fb2024-04-05 12:29:11 +02001709 while (cert) {
roman15fbc592024-07-02 16:01:23 +02001710 ++cert_count;
1711 cert = cert->next;
1712 }
1713
1714 /* iterate over all the certs */
1715 for (i = -1; i < cert_count; i++) {
1716 if (i == -1) {
1717 cert = leaf_cert;
1718 } else if (i == 0) {
1719 cert = cert_store;
1720 } else {
1721 cert = cert->next;
1722 }
1723
roman275c3fb2024-04-05 12:29:11 +02001724 if (!cert->v3_ext.len) {
1725 /* no extensions, skip this cert */
roman275c3fb2024-04-05 12:29:11 +02001726 continue;
1727 }
1728
1729 /* go over all the extensions and try to find the CRL distribution points */
1730 p = cert->v3_ext.p;
1731 end_v3_ext = p + cert->v3_ext.len;
1732
1733 /*
1734 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
1735 */
1736 ret = mbedtls_asn1_get_tag(&p, end_v3_ext, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
1737 if (ret) {
romanc1124572024-04-23 15:08:06 +02001738 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001739 goto cleanup;
1740 }
1741
1742 while (p < end_v3_ext) {
1743 /*
1744 * Extension ::= SEQUENCE {
1745 * extnID OBJECT IDENTIFIER,
1746 * critical BOOLEAN DEFAULT FALSE,
1747 * extnValue OCTET STRING }
1748 */
1749 ret = mbedtls_asn1_get_tag(&p, end_v3_ext, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
1750 if (ret) {
romanc1124572024-04-23 15:08:06 +02001751 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001752 goto cleanup;
1753 }
1754
1755 end_ext = p + len;
1756
1757 /* parse extnID */
1758 ret = mbedtls_asn1_get_tag(&p, end_ext, &ext_oid.len, MBEDTLS_ASN1_OID);
1759 if (ret) {
romanc1124572024-04-23 15:08:06 +02001760 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001761 goto cleanup;
1762 }
1763 ext_oid.tag = MBEDTLS_ASN1_OID;
1764 ext_oid.p = p;
1765
1766 if (memcmp(ext_oid.p, MBEDTLS_OID_CRL_DISTRIBUTION_POINTS, ext_oid.len)) {
1767 /* not the extension we are looking for */
1768 p = end_ext;
1769 continue;
1770 }
1771
1772 p += ext_oid.len;
1773
1774 /* parse optional critical */
1775 ret = mbedtls_asn1_get_bool(&p, end_ext, &is_critical);
1776 if (ret && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
romanc1124572024-04-23 15:08:06 +02001777 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001778 goto cleanup;
1779 }
1780
1781 /* parse extnValue */
1782 ret = mbedtls_asn1_get_tag(&p, end_ext, &len, MBEDTLS_ASN1_OCTET_STRING);
1783 if (ret) {
romanc1124572024-04-23 15:08:06 +02001784 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001785 goto cleanup;
1786 }
1787
1788 end_ext_octet = p + len;
1789
1790 /*
1791 * parse extnValue, that is CRLDistributionPoints
1792 *
1793 * CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
1794 */
1795 ret = mbedtls_asn1_get_tag(&p, end_ext_octet, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
1796 if (ret) {
romanc1124572024-04-23 15:08:06 +02001797 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001798 goto cleanup;
1799 }
1800 if (p + len != end_ext_octet) {
1801 /* length mismatch */
romanc1124572024-04-23 15:08:06 +02001802 ERR(NULL, "Failed to parse CRL distribution points extension (%s).", nc_get_mbedtls_str_err(ret));
roman275c3fb2024-04-05 12:29:11 +02001803 goto cleanup;
1804 } else if (!len) {
1805 /* empty sequence, but size is 1..max */
1806 ERR(NULL, "Failed to parse CRL distribution points extension (empty sequence).");
1807 goto cleanup;
1808 }
1809
roman77e327a2024-05-14 11:01:21 +02001810 /* parse the distribution points and obtain the uris */
1811 ret = nc_server_tls_parse_crl_dist_points(&p, len, uris, uri_count);
1812 if (ret) {
1813 goto cleanup;
roman275c3fb2024-04-05 12:29:11 +02001814 }
1815 }
roman275c3fb2024-04-05 12:29:11 +02001816 }
1817
1818cleanup:
1819 return ret;
1820}
romanc1124572024-04-23 15:08:06 +02001821
1822int
1823nc_tls_process_cipher_suite_wrap(const char *cipher, char **out)
1824{
1825 const char *begin, *ptr;
1826
1827 /* check if it's a TLS 1.3 cipher suite */
1828 if (!strcmp(cipher, "tls-aes-256-gcm-sha384") || !strcmp(cipher, "tls-aes-128-gcm-sha256") ||
1829 !strcmp(cipher, "tls-chacha20-poly1305-sha256") || !strcmp(cipher, "tls-aes-128-ccm-sha256") ||
1830 !strcmp(cipher, "tls-aes-128-ccm-8-sha256")) {
1831 /* + 3 because mbedtls has "TLS1-3" prefix for 1.3 suites */
1832 *out = malloc(strlen(cipher) + 3 + 1);
1833 NC_CHECK_ERRMEM_RET(!*out, 1);
1834 sprintf(*out, "TLS1-3");
1835 begin = cipher + 4;
1836 } else {
1837 *out = malloc(strlen(cipher) + 1);
1838 NC_CHECK_ERRMEM_RET(!*out, 1);
1839 begin = cipher;
1840 }
1841
1842 /* convert to uppercase */
1843 for (ptr = begin; *ptr; ptr++) {
1844 (*out)[ptr - begin] = toupper(*ptr);
1845 }
1846
1847 (*out)[ptr - begin] = '\0';
1848 return 0;
1849}
1850
1851int
1852nc_tls_append_cipher_suite_wrap(struct nc_server_tls_opts *opts, const char *cipher_suite)
1853{
1854 int cipher_id;
1855
1856 cipher_id = mbedtls_ssl_get_ciphersuite_id(cipher_suite);
1857 if (!cipher_id) {
1858 return 1;
1859 }
1860
1861 /* append the cipher suite to a zero terminated array */
1862 if (!opts->ciphers) {
1863 /* first entry, account for terminating 0 */
1864 opts->ciphers = malloc(2 * sizeof *opts->ciphers);
1865 NC_CHECK_ERRMEM_RET(!opts->ciphers, 1);
1866 ((int *)opts->ciphers)[0] = cipher_id;
1867 opts->cipher_count = 1;
1868 } else {
1869 /* +2 because of terminating 0 */
1870 opts->ciphers = nc_realloc(opts->ciphers, (opts->cipher_count + 2) * sizeof *opts->ciphers);
1871 NC_CHECK_ERRMEM_RET(!opts->ciphers, 1);
1872 ((int *)opts->ciphers)[opts->cipher_count] = cipher_id;
1873 opts->cipher_count++;
1874 }
1875
1876 /* terminate the array */
1877 ((int *)opts->ciphers)[opts->cipher_count] = 0;
1878 return 0;
1879}
1880
1881void
1882nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, void *cipher_suites)
1883{
1884 mbedtls_ssl_conf_ciphersuites(tls_cfg, cipher_suites);
1885}