blob: 3fd88980d9937eac0b2ed6f6c7f7c727c7b1834c [file] [log] [blame]
romane60ef992024-05-13 12:53:02 +02001/**
2 * @file session_openssl.c
3 * @author Roman Janota <janota@cesnet.cz>
4 * @brief libnetconf2 - wrapped OpenSSL function calls for TLS/asymmetric cryptography support
5 *
6 * This file is a wrapper for OpenSSL function calls. The implementation is done
7 * in such a way that the original libnetconf2 code is not dependent on OpenSSL.
8 * This file is included in the build process only if OpenSSL 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
roman163f1662024-04-04 09:26:42 +020020#define _GNU_SOURCE
21
roman7ef57992024-04-23 15:08:45 +020022#include <ctype.h>
roman163f1662024-04-04 09:26:42 +020023#include <poll.h>
24#include <stdint.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29
30#include <curl/curl.h>
31
32#include "compat.h"
33#include "config.h"
34#include "log_p.h"
35#include "session.h"
36#include "session_p.h"
37#include "session_wrapper.h"
38
39#include <openssl/bio.h>
40#include <openssl/err.h>
41#include <openssl/evp.h>
42#include <openssl/ssl.h>
43#include <openssl/x509.h>
44#include <openssl/x509v3.h>
45
46void *
47nc_tls_session_new_wrap(void *tls_cfg)
48{
49 SSL *session;
50
51 session = SSL_new(tls_cfg);
52 if (!session) {
roman7ef57992024-04-23 15:08:45 +020053 ERR(NULL, "Setting up TLS session failed (%s).", ERR_reason_error_string(ERR_get_error()));
roman163f1662024-04-04 09:26:42 +020054 return NULL;
55 }
56
57 return session;
58}
59
60void
61nc_tls_session_destroy_wrap(void *tls_session)
62{
63 SSL_free(tls_session);
64}
65
66void *
roman7ef57992024-04-23 15:08:45 +020067nc_tls_config_new_wrap(int side)
roman163f1662024-04-04 09:26:42 +020068{
69 SSL_CTX *tls_cfg;
70
roman7ef57992024-04-23 15:08:45 +020071 if ((side != NC_SERVER) && (side != NC_CLIENT)) {
72 ERRINT;
73 return NULL;
74 }
roman163f1662024-04-04 09:26:42 +020075
roman7ef57992024-04-23 15:08:45 +020076 if (side == NC_SERVER) {
77 tls_cfg = SSL_CTX_new(TLS_server_method());
78 } else {
79 tls_cfg = SSL_CTX_new(TLS_client_method());
80 }
roman163f1662024-04-04 09:26:42 +020081 NC_CHECK_ERRMEM_RET(!tls_cfg, NULL)
82
83 return tls_cfg;
84}
85
86void
87nc_tls_config_destroy_wrap(void *tls_cfg)
88{
89 SSL_CTX_free(tls_cfg);
90}
91
92void *
romanb87aa452024-05-13 12:58:00 +020093nc_tls_cert_new_wrap(void)
roman163f1662024-04-04 09:26:42 +020094{
95 X509 *cert;
96
97 cert = X509_new();
98 NC_CHECK_ERRMEM_RET(!cert, NULL)
99
100 return cert;
101}
102
103void
104nc_tls_cert_destroy_wrap(void *cert)
105{
106 X509_free(cert);
107}
108
roman163f1662024-04-04 09:26:42 +0200109void
110nc_tls_privkey_destroy_wrap(void *pkey)
111{
112 EVP_PKEY_free(pkey);
113}
114
115void *
romanb87aa452024-05-13 12:58:00 +0200116nc_tls_cert_store_new_wrap(void)
roman163f1662024-04-04 09:26:42 +0200117{
118 X509_STORE *store;
119
120 store = X509_STORE_new();
121 NC_CHECK_ERRMEM_RET(!store, NULL);
122
123 return store;
124}
125
126void
127nc_tls_cert_store_destroy_wrap(void *cert_store)
128{
129 X509_STORE_free(cert_store);
130}
131
132void *
romanb87aa452024-05-13 12:58:00 +0200133nc_tls_crl_store_new_wrap(void)
roman163f1662024-04-04 09:26:42 +0200134{
roman7ef57992024-04-23 15:08:45 +0200135 return nc_tls_cert_store_new_wrap();
roman163f1662024-04-04 09:26:42 +0200136}
137
138void
roman7ef57992024-04-23 15:08:45 +0200139nc_tls_crl_store_destroy_wrap(void *crl_store)
roman163f1662024-04-04 09:26:42 +0200140{
roman7ef57992024-04-23 15:08:45 +0200141 X509_STORE_free(crl_store);
roman163f1662024-04-04 09:26:42 +0200142}
143
144void *
145nc_tls_pem_to_cert_wrap(const char *cert_data)
146{
147 BIO *bio;
148 X509 *cert;
149
150 bio = BIO_new_mem_buf(cert_data, strlen(cert_data));
151 if (!bio) {
152 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
153 return NULL;
154 }
155
156 cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
157 if (!cert) {
158 ERR(NULL, "Parsing certificate data failed (%s).", ERR_reason_error_string(ERR_get_error()));
159 }
160 BIO_free(bio);
161 return cert;
162}
163
164int
roman7ef57992024-04-23 15:08:45 +0200165nc_tls_add_cert_to_store_wrap(void *cert, void *cert_store)
roman163f1662024-04-04 09:26:42 +0200166{
167 int rc;
roman163f1662024-04-04 09:26:42 +0200168
roman7ef57992024-04-23 15:08:45 +0200169 /* on success increases ref count to cert, so free it */
roman163f1662024-04-04 09:26:42 +0200170 rc = X509_STORE_add_cert(cert_store, cert);
roman163f1662024-04-04 09:26:42 +0200171 if (!rc) {
172 ERR(NULL, "Adding certificate to store failed (%s).", ERR_reason_error_string(ERR_get_error()));
173 return 1;
174 }
roman7ef57992024-04-23 15:08:45 +0200175
176 X509_free(cert);
roman163f1662024-04-04 09:26:42 +0200177 return 0;
178}
179
180void *
181nc_tls_pem_to_privkey_wrap(const char *privkey_data)
182{
183 BIO *bio;
184 EVP_PKEY *pkey;
185
186 bio = BIO_new_mem_buf(privkey_data, strlen(privkey_data));
187 if (!bio) {
188 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
189 return NULL;
190 }
191
192 pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
193 if (!pkey) {
194 ERR(NULL, "Parsing certificate data failed (%s).", ERR_reason_error_string(ERR_get_error()));
195 }
196 BIO_free(bio);
197 return pkey;
198}
199
200int
roman7ef57992024-04-23 15:08:45 +0200201nc_tls_import_crl_path_wrap(const char *path, void *crl_store)
roman163f1662024-04-04 09:26:42 +0200202{
roman7ef57992024-04-23 15:08:45 +0200203 int ret = 0, rc;
roman163f1662024-04-04 09:26:42 +0200204 X509_CRL *crl = NULL;
205 FILE *f;
206
roman7ef57992024-04-23 15:08:45 +0200207 f = fopen(path, "r");
roman163f1662024-04-04 09:26:42 +0200208 if (!f) {
roman7ef57992024-04-23 15:08:45 +0200209 ERR(NULL, "Unable to open CRL file \"%s\".", path);
roman163f1662024-04-04 09:26:42 +0200210 return 1;
211 }
212
213 /* try PEM first */
214 crl = PEM_read_X509_CRL(f, NULL, NULL, NULL);
215 if (crl) {
216 /* success */
217 goto ok;
218 }
219
220 /* PEM failed, try DER */
221 rewind(f);
222 crl = d2i_X509_CRL_fp(f, NULL);
223 if (!crl) {
roman7ef57992024-04-23 15:08:45 +0200224 ERR(NULL, "Reading CRL from file \"%s\" failed.", path);
roman163f1662024-04-04 09:26:42 +0200225 ret = 1;
226 goto cleanup;
227 }
228
229ok:
roman7ef57992024-04-23 15:08:45 +0200230 rc = X509_STORE_add_crl(crl_store, crl);
231 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200232 ERR(NULL, "Error adding CRL to store (%s).", ERR_reason_error_string(ERR_get_error()));
233 ret = 1;
234 goto cleanup;
235 }
roman163f1662024-04-04 09:26:42 +0200236
237cleanup:
238 fclose(f);
239 X509_CRL_free(crl);
240 return ret;
241}
242
243int
roman7ef57992024-04-23 15:08:45 +0200244nc_server_tls_add_crl_to_store_wrap(const unsigned char *crl_data, size_t size, void *crl_store)
roman163f1662024-04-04 09:26:42 +0200245{
246 int ret = 0;
247 X509_CRL *crl = NULL;
248 BIO *bio = NULL;
249
roman163f1662024-04-04 09:26:42 +0200250 bio = BIO_new_mem_buf(crl_data, size);
251 if (!bio) {
252 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
253 ret = 1;
254 goto cleanup;
255 }
256
257 /* try DER first */
258 crl = d2i_X509_CRL_bio(bio, NULL);
259 if (crl) {
260 /* it was DER */
261 goto ok;
262 }
263
264 /* DER failed, try PEM next */
265 crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
266 if (!crl) {
267 ERR(NULL, "Parsing downloaded CRL failed (%s).", ERR_reason_error_string(ERR_get_error()));
268 ret = 1;
269 goto cleanup;
270 }
271
272ok:
273 /* we obtained the CRL, now add it to the CRL store */
roman7ef57992024-04-23 15:08:45 +0200274 ret = X509_STORE_add_crl(crl_store, crl);
roman163f1662024-04-04 09:26:42 +0200275 if (!ret) {
276 ERR(NULL, "Error adding CRL to store (%s).", ERR_reason_error_string(ERR_get_error()));
277 ret = 1;
278 goto cleanup;
279 }
280 /* ok */
281 ret = 0;
282
283cleanup:
284 X509_CRL_free(crl);
285 BIO_free(bio);
286 return ret;
287}
288
roman163f1662024-04-04 09:26:42 +0200289int
290nc_server_tls_set_tls_versions_wrap(void *tls_cfg, unsigned int tls_versions)
291{
292 int rc = 1;
293
294 /* first set the minimum version */
295 if (tls_versions & NC_TLS_VERSION_10) {
296 rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_VERSION);
297 } else if (tls_versions & NC_TLS_VERSION_11) {
298 rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_1_VERSION);
299 } else if (tls_versions & NC_TLS_VERSION_12) {
300 rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_2_VERSION);
301 } else if (tls_versions & NC_TLS_VERSION_13) {
302 rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_3_VERSION);
303 }
304 if (!rc) {
305 ERR(NULL, "Setting TLS min version failed (%s).", ERR_reason_error_string(ERR_get_error()));
306 return 1;
307 }
308
309 /* then set the maximum version */
310 if (tls_versions & NC_TLS_VERSION_13) {
311 rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_3_VERSION);
312 } else if (tls_versions & NC_TLS_VERSION_12) {
313 rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_2_VERSION);
314 } else if (tls_versions & NC_TLS_VERSION_11) {
315 rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_1_VERSION);
316 } else if (tls_versions & NC_TLS_VERSION_10) {
317 rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_VERSION);
318 }
319 if (!rc) {
320 ERR(NULL, "Setting TLS max version failed (%s).", ERR_reason_error_string(ERR_get_error()));
321 return 1;
322 }
323
324 return 0;
325}
326
romane20f3542024-05-14 11:00:54 +0200327/**
328 * @brief Verify a certificate.
329 *
330 * @param[in] preverify_ok The result of the in-built verification.
331 * @param[in] x509_ctx Verification context.
332 * @return 1 on success, 0 on error.
333 */
roman163f1662024-04-04 09:26:42 +0200334static int
335nc_server_tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
336{
337 int ret = 0, depth, err;
338 struct nc_tls_verify_cb_data *data;
339 SSL *ssl;
roman7ef57992024-04-23 15:08:45 +0200340 SSL_CTX *ctx;
roman163f1662024-04-04 09:26:42 +0200341 X509 *cert;
342
roman7ffd2fc2024-05-13 13:48:34 +0200343 /* retrieve callback data stored inside the SSL_CTX struct */
roman163f1662024-04-04 09:26:42 +0200344 ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
roman7ffd2fc2024-05-13 13:48:34 +0200345 if (!ssl) {
346 ERRINT;
347 return 0;
348 }
roman7ef57992024-04-23 15:08:45 +0200349 ctx = SSL_get_SSL_CTX(ssl);
roman7ffd2fc2024-05-13 13:48:34 +0200350 if (!ctx) {
351 ERRINT;
352 return 0;
353 }
roman7ef57992024-04-23 15:08:45 +0200354 data = SSL_CTX_get_ex_data(ctx, 0);
roman163f1662024-04-04 09:26:42 +0200355
356 /* get current cert and its depth */
357 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
358 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
359
360 if (preverify_ok) {
361 /* in-built verification was successful */
roman7ffd2fc2024-05-13 13:48:34 +0200362 ret = nc_server_tls_verify_cert(cert, depth, 1, data);
roman163f1662024-04-04 09:26:42 +0200363 } else {
364 /* in-built verification failed, but the client still may be authenticated if:
365 * 1) the peer cert matches any configured end-entity cert
366 * 2) the peer cert has a valid chain of trust to any configured certificate authority cert
367 * otherwise just continue until we reach the peer cert (depth = 0)
368 */
369 err = X509_STORE_CTX_get_error(x509_ctx);
roman7ffd2fc2024-05-13 13:48:34 +0200370 if ((depth == 0) && ((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) || (err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))) {
371 /* not trusted (possibly self-signed) peer certificate, case 1) */
372 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
roman163f1662024-04-04 09:26:42 +0200373 } else if ((err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) || (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)) {
374 /* full chain of trust is invalid, but it may be valid partially, case 2) */
375 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
roman7ef57992024-04-23 15:08:45 +0200376 } else if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) {
377 /* self-signed certificate in the chain, check if peer cert complies with 1) in order to continue,
378 * if yes, this callback will be called again with the same cert, but with preverify_ok = 1
379 */
380 cert = X509_STORE_CTX_get0_cert(x509_ctx);
381 ret = nc_server_tls_verify_peer_cert(cert, data->opts);
382 if (ret) {
383 VRB(NULL, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
384 ret = -1;
roman7ef57992024-04-23 15:08:45 +0200385 }
roman163f1662024-04-04 09:26:42 +0200386 } else {
387 VRB(NULL, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
388 ret = 1;
389 }
390 }
391
392 if (ret == -1) {
393 /* fatal error */
394 return 0;
395 } else if (!ret) {
396 /* success */
roman396f4732024-05-14 09:09:30 +0200397 if ((depth == 0) && (!data->session->opts.server.client_cert)) {
398 /* copy the client cert */
399 data->session->opts.server.client_cert = X509_dup(cert);
400 NC_CHECK_ERRMEM_RET(!data->session->opts.server.client_cert, 0);
401 }
roman163f1662024-04-04 09:26:42 +0200402 return 1;
403 } else {
404 if (depth > 0) {
405 /* chain verify failed */
406 return 1;
407 } else {
408 /* peer cert did not match */
409 return 0;
410 }
411 }
412}
413
414void
roman7ef57992024-04-23 15:08:45 +0200415nc_server_tls_set_verify_wrap(void *tls_cfg, struct nc_tls_verify_cb_data *cb_data)
roman163f1662024-04-04 09:26:42 +0200416{
roman7ef57992024-04-23 15:08:45 +0200417 /* set verify cb and its data */
418 SSL_CTX_set_ex_data(tls_cfg, 0, cb_data);
419 SSL_CTX_set_verify(tls_cfg, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_server_tls_verify_cb);
420}
421
422void
423nc_client_tls_set_verify_wrap(void *tls_cfg)
424{
425 SSL_CTX_set_verify(tls_cfg, SSL_VERIFY_PEER, NULL);
roman163f1662024-04-04 09:26:42 +0200426}
427
428char *
429nc_server_tls_get_subject_wrap(void *cert)
430{
431 return X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
432}
433
434char *
435nc_server_tls_get_issuer_wrap(void *cert)
436{
437 return X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
438}
439
roman7ef57992024-04-23 15:08:45 +0200440void *
441nc_tls_get_sans_wrap(void *cert)
roman163f1662024-04-04 09:26:42 +0200442{
roman7ef57992024-04-23 15:08:45 +0200443 return X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
444}
445
446void
447nc_tls_sans_destroy_wrap(void *sans)
448{
449 sk_GENERAL_NAME_pop_free(sans, GENERAL_NAME_free);
450}
451
452int
453nc_tls_get_num_sans_wrap(void *sans)
454{
455 return sk_GENERAL_NAME_num(sans);
456}
457
458int
459nc_tls_get_san_value_type_wrap(void *sans, int idx, char **san_value, NC_TLS_CTN_MAPTYPE *san_type)
460{
461 int ret = 0;
462 GENERAL_NAME *san;
roman163f1662024-04-04 09:26:42 +0200463 ASN1_OCTET_STRING *ip;
roman163f1662024-04-04 09:26:42 +0200464
roman7ef57992024-04-23 15:08:45 +0200465 *san_value = NULL;
466 *san_type = NC_TLS_CTN_UNKNOWN;
roman163f1662024-04-04 09:26:42 +0200467
roman7ef57992024-04-23 15:08:45 +0200468 /* find the san */
469 san = sk_GENERAL_NAME_value(sans, idx);
470 if (!san) {
471 return -1;
roman163f1662024-04-04 09:26:42 +0200472 }
473
roman7ef57992024-04-23 15:08:45 +0200474 /* get its type and value */
475 switch (san->type) {
476 case GEN_EMAIL:
477 *san_type = NC_TLS_CTN_SAN_RFC822_NAME;
478 *san_value = strdup((char *)ASN1_STRING_get0_data(san->d.rfc822Name));
479 NC_CHECK_ERRMEM_RET(!*san_value, -1);
480 break;
481 case GEN_DNS:
482 *san_type = NC_TLS_CTN_SAN_DNS_NAME;
483 *san_value = strdup((char *)ASN1_STRING_get0_data(san->d.dNSName));
484 NC_CHECK_ERRMEM_RET(!*san_value, -1);
485 break;
486 case GEN_IPADD:
487 *san_type = NC_TLS_CTN_SAN_IP_ADDRESS;
488 ip = san->d.iPAddress;
489 if (ip->length == 4) {
490 if (asprintf(san_value, "%d.%d.%d.%d", ip->data[0], ip->data[1], ip->data[2], ip->data[3]) == -1) {
491 ERRMEM;
492 *san_value = NULL;
493 ret = -1;
494 }
495 } else if (ip->length == 16) {
496 if (asprintf(san_value, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
497 ip->data[0], ip->data[1], ip->data[2], ip->data[3], ip->data[4], ip->data[5],
498 ip->data[6], ip->data[7], ip->data[8], ip->data[9], ip->data[10], ip->data[11],
499 ip->data[12], ip->data[13], ip->data[14], ip->data[15]) == -1) {
500 ERRMEM;
501 *san_value = NULL;
502 ret = -1;
503 }
504 } else {
505 WRN(NULL, "SAN IP address in an unknown format (length is %d).", ip->length);
506 ret = 1;
507 }
508 break;
509 default:
510 /* we dont care about other types */
511 *san_type = NC_TLS_CTN_UNKNOWN;
512 ret = 1;
513 break;
514 }
515
516 return ret;
roman163f1662024-04-04 09:26:42 +0200517}
518
519int
520nc_server_tls_certs_match_wrap(void *cert1, void *cert2)
521{
522 return !X509_cmp(cert1, cert2);
523}
524
525int
526nc_server_tls_md5_wrap(void *cert, unsigned char *buf)
527{
528 int rc;
529
530 rc = X509_digest(cert, EVP_md5(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200531 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200532 ERR(NULL, "Calculating MD-5 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
533 return 1;
534 }
535
536 return 0;
537}
538
539int
540nc_server_tls_sha1_wrap(void *cert, unsigned char *buf)
541{
542 int rc;
543
544 rc = X509_digest(cert, EVP_sha1(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200545 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200546 ERR(NULL, "Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
547 return 1;
548 }
549
550 return 0;
551}
552
553int
554nc_server_tls_sha224_wrap(void *cert, unsigned char *buf)
555{
556 int rc;
557
558 rc = X509_digest(cert, EVP_sha224(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200559 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200560 ERR(NULL, "Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
561 return 1;
562 }
563
564 return 0;
565}
566
567int
568nc_server_tls_sha256_wrap(void *cert, unsigned char *buf)
569{
570 int rc;
571
572 rc = X509_digest(cert, EVP_sha256(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200573 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200574 ERR(NULL, "Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
575 return 1;
576 }
577
578 return 0;
579}
580
581int
582nc_server_tls_sha384_wrap(void *cert, unsigned char *buf)
583{
584 int rc;
585
586 rc = X509_digest(cert, EVP_sha384(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200587 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200588 ERR(NULL, "Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
589 return 1;
590 }
591
592 return 0;
593}
594
595int
596nc_server_tls_sha512_wrap(void *cert, unsigned char *buf)
597{
598 int rc;
599
600 rc = X509_digest(cert, EVP_sha512(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200601 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200602 ERR(NULL, "Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
603 return 1;
604 }
605
606 return 0;
607}
608
609void
610nc_server_tls_set_fd_wrap(void *tls_session, int sock, struct nc_tls_ctx *UNUSED(tls_ctx))
611{
612 SSL_set_fd(tls_session, sock);
613}
614
615int
616nc_server_tls_handshake_step_wrap(void *tls_session)
617{
618 int ret = 0;
619
620 ret = SSL_accept(tls_session);
621 if (ret == 1) {
622 return 1;
623 } else if (ret == -1) {
624 if ((SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_READ) || (SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_WRITE)) {
625 return 0;
626 }
627 }
628
629 return -1;
630}
631
632int
roman7ef57992024-04-23 15:08:45 +0200633nc_client_tls_handshake_step_wrap(void *tls_session, int UNUSED(sock))
roman163f1662024-04-04 09:26:42 +0200634{
635 int ret = 0;
636
637 ret = SSL_connect(tls_session);
638 if (ret == 1) {
639 return 1;
640 } else if (ret == -1) {
641 if ((SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_READ) || (SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_WRITE)) {
642 return 0;
643 }
644 }
645
646 return -1;
647}
648
649void
650nc_tls_ctx_destroy_wrap(struct nc_tls_ctx *UNUSED(tls_ctx))
651{
652 return;
653}
654
655int
656nc_client_tls_load_cert_key_wrap(const char *cert_path, const char *key_path, void **cert, void **pkey)
657{
658 BIO *bio;
659 X509 *cert_tmp;
660 EVP_PKEY *pkey_tmp;
661
roman7ef57992024-04-23 15:08:45 +0200662 NC_CHECK_ARG_RET(NULL, cert_path, key_path, cert, pkey, 1);
663
roman163f1662024-04-04 09:26:42 +0200664 bio = BIO_new_file(cert_path, "r");
665 if (!bio) {
666 ERR(NULL, "Opening the client certificate file \"%s\" failed.", cert_path);
667 return 1;
668 }
669
670 cert_tmp = PEM_read_bio_X509(bio, NULL, NULL, NULL);
671 BIO_free(bio);
672 if (!cert_tmp) {
673 ERR(NULL, "Parsing the client certificate file \"%s\" failed.", cert_path);
674 return 1;
675 }
676
677 bio = BIO_new_file(key_path, "r");
678 if (!bio) {
679 ERR(NULL, "Opening the client private key file \"%s\" failed.", key_path);
680 X509_free(cert_tmp);
681 return 1;
682 }
683
684 pkey_tmp = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
685 BIO_free(bio);
686 if (!pkey_tmp) {
687 ERR(NULL, "Parsing the client private key file \"%s\" failed.", key_path);
688 X509_free(cert_tmp);
689 return 1;
690 }
691
692 *cert = cert_tmp;
693 *pkey = pkey_tmp;
694
695 return 0;
696}
697
698int
699nc_client_tls_load_trusted_certs_wrap(void *cert_store, const char *file_path, const char *dir_path)
700{
701 if (!X509_STORE_load_locations(cert_store, file_path, dir_path)) {
roman7ffd2fc2024-05-13 13:48:34 +0200702 ERR(NULL, "Loading CA certs from file \"%s\" or directory \"%s\" failed (%s).",
703 file_path, dir_path, ERR_reason_error_string(ERR_get_error()));
roman163f1662024-04-04 09:26:42 +0200704 return 1;
705 }
706
707 return 0;
708}
709
710int
roman7ef57992024-04-23 15:08:45 +0200711nc_client_tls_load_crl_wrap(void *crl_store, const char *file_path, const char *dir_path)
roman163f1662024-04-04 09:26:42 +0200712{
roman7ef57992024-04-23 15:08:45 +0200713 if (!X509_STORE_load_locations(crl_store, file_path, dir_path)) {
roman7ffd2fc2024-05-13 13:48:34 +0200714 ERR(NULL, "Loading CRLs from file \"%s\" or directory \"%s\" failed (%s).",
715 file_path, dir_path, ERR_reason_error_string(ERR_get_error()));
roman163f1662024-04-04 09:26:42 +0200716 return 1;
717 }
718
719 return 0;
720}
721
722int
723nc_client_tls_set_hostname_wrap(void *tls_session, const char *hostname)
724{
725 int ret = 0;
726 X509_VERIFY_PARAM *vpm = NULL;
727
728 vpm = X509_VERIFY_PARAM_new();
729 NC_CHECK_ERRMEM_RET(!vpm, 1);
730
731 if (!X509_VERIFY_PARAM_set1_host(vpm, hostname, 0)) {
732 ERR(NULL, "Failed to set expected hostname (%s).", ERR_reason_error_string(ERR_get_error()));
733 ret = 1;
734 goto cleanup;
735 }
roman7ef57992024-04-23 15:08:45 +0200736 if (!SSL_set1_param(tls_session, vpm)) {
roman163f1662024-04-04 09:26:42 +0200737 ERR(NULL, "Failed to set verify param (%s).", ERR_reason_error_string(ERR_get_error()));
738 ret = 1;
739 goto cleanup;
740 }
741
742cleanup:
743 X509_VERIFY_PARAM_free(vpm);
744 return ret;
745}
746
roman7ef57992024-04-23 15:08:45 +0200747int
748nc_tls_init_ctx_wrap(int UNUSED(sock), void *cert, void *pkey, void *cert_store, void *crl_store, struct nc_tls_ctx *tls_ctx)
749{
750 tls_ctx->cert = cert;
751 tls_ctx->pkey = pkey;
752 tls_ctx->cert_store = cert_store;
753 tls_ctx->crl_store = crl_store;
754 return 0;
755}
756
romane20f3542024-05-14 11:00:54 +0200757/**
758 * @brief Move CRLs from one store to another.
759 *
760 * @param[in] src Source store.
761 * @param[in] dst Destination store.
762 * @return 0 on success, 1 on error.
763 */
roman7ef57992024-04-23 15:08:45 +0200764static int
765nc_tls_move_crls_to_store(const X509_STORE *src, X509_STORE *dst)
766{
767 int i, nobjs = 0;
768
769 STACK_OF(X509_OBJECT) * objs;
770 X509_OBJECT *obj;
771 X509_CRL *crl;
772
773 objs = X509_STORE_get0_objects(src);
774 nobjs = sk_X509_OBJECT_num(objs);
775 for (i = 0; i < nobjs; i++) {
776 obj = sk_X509_OBJECT_value(objs, i);
777 crl = X509_OBJECT_get0_X509_CRL(obj);
778 if (!crl) {
779 /* not a CRL */
780 continue;
781 }
782 if (!X509_STORE_add_crl(dst, crl)) {
783 ERR(NULL, "Adding CRL to the store failed (%s).", ERR_reason_error_string(ERR_get_error()));
784 return 1;
785 }
786 }
787
788 return 0;
789}
790
791int
roman7ffd2fc2024-05-13 13:48:34 +0200792nc_tls_setup_config_from_ctx_wrap(struct nc_tls_ctx *tls_ctx, int side, void *tls_cfg)
roman7ef57992024-04-23 15:08:45 +0200793{
794 if (SSL_CTX_use_certificate(tls_cfg, tls_ctx->cert) != 1) {
795 return 1;
796 }
797
798 if (SSL_CTX_use_PrivateKey(tls_cfg, tls_ctx->pkey) != 1) {
799 return 1;
800 }
801
roman7ffd2fc2024-05-13 13:48:34 +0200802 /* disable server-side automatic chain building */
803 if (side == NC_SERVER) {
804 SSL_CTX_set_mode(tls_cfg, SSL_MODE_NO_AUTO_CHAIN);
805 }
roman7ef57992024-04-23 15:08:45 +0200806
807 if (tls_ctx->crl_store) {
808 /* move CRLs from crl_store to cert_store, because SSL_CTX can only have one store */
809 if (nc_tls_move_crls_to_store(tls_ctx->crl_store, tls_ctx->cert_store)) {
810 return 1;
811 }
812
813 /* enable CRL checks */
814 X509_STORE_set_flags(tls_ctx->cert_store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
815 }
816
817 SSL_CTX_set_cert_store(tls_cfg, tls_ctx->cert_store);
818
819 X509_free(tls_ctx->cert);
820 tls_ctx->cert = NULL;
821 EVP_PKEY_free(tls_ctx->pkey);
822 tls_ctx->pkey = NULL;
823 X509_STORE_free(tls_ctx->crl_store);
824 tls_ctx->crl_store = NULL;
825
826 return 0;
827}
828
roman163f1662024-04-04 09:26:42 +0200829uint32_t
830nc_tls_get_verify_result_wrap(void *tls_session)
831{
832 return SSL_get_verify_result(tls_session);
833}
834
roman7ef57992024-04-23 15:08:45 +0200835char *
roman163f1662024-04-04 09:26:42 +0200836nc_tls_verify_error_string_wrap(uint32_t err_code)
837{
roman7ef57992024-04-23 15:08:45 +0200838 return strdup(X509_verify_cert_error_string(err_code));
roman163f1662024-04-04 09:26:42 +0200839}
840
841void
roman7ef57992024-04-23 15:08:45 +0200842nc_client_tls_print_connect_err_wrap(int connect_ret, const char *peername, void *tls_session)
roman163f1662024-04-04 09:26:42 +0200843{
844 switch (SSL_get_error(tls_session, connect_ret)) {
845 case SSL_ERROR_SYSCALL:
846 ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, errno ? strerror(errno) : "unexpected EOF");
847 break;
848 case SSL_ERROR_SSL:
849 ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, ERR_reason_error_string(ERR_get_error()));
850 break;
851 default:
852 ERR(NULL, "TLS connection to \"%s\" failed.", peername);
853 break;
854 }
855}
856
857void
roman7ef57992024-04-23 15:08:45 +0200858nc_server_tls_print_accept_err_wrap(int accept_ret, void *tls_session)
roman163f1662024-04-04 09:26:42 +0200859{
860 switch (SSL_get_error(tls_session, accept_ret)) {
861 case SSL_ERROR_SYSCALL:
862 ERR(NULL, "TLS accept failed (%s).", strerror(errno));
863 break;
864 case SSL_ERROR_SSL:
865 ERR(NULL, "TLS accept failed (%s).", ERR_reason_error_string(ERR_get_error()));
866 break;
867 default:
868 ERR(NULL, "TLS accept failed.");
869 break;
870 }
871}
872
873int
roman7ef57992024-04-23 15:08:45 +0200874nc_tls_is_der_subpubkey_wrap(unsigned char *der, long len)
roman163f1662024-04-04 09:26:42 +0200875{
876 int ret;
877 EVP_PKEY *pkey;
878
roman7ef57992024-04-23 15:08:45 +0200879 pkey = d2i_PUBKEY(NULL, (const unsigned char **)&der, len);
roman163f1662024-04-04 09:26:42 +0200880 if (pkey) {
881 /* success */
roman7ef57992024-04-23 15:08:45 +0200882 ret = 1;
roman163f1662024-04-04 09:26:42 +0200883 } else {
884 /* fail */
roman7ef57992024-04-23 15:08:45 +0200885 ret = 0;
roman163f1662024-04-04 09:26:42 +0200886 }
887
888 EVP_PKEY_free(pkey);
889 return ret;
890}
891
892int
roman7ef57992024-04-23 15:08:45 +0200893nc_base64_decode_wrap(const char *base64, unsigned char **bin)
roman163f1662024-04-04 09:26:42 +0200894{
roman7ef57992024-04-23 15:08:45 +0200895 int ret;
roman163f1662024-04-04 09:26:42 +0200896
roman7ef57992024-04-23 15:08:45 +0200897 *bin = malloc((strlen(base64) / 4) * 3);
898 NC_CHECK_ERRMEM_RET(!*bin, -1);
roman163f1662024-04-04 09:26:42 +0200899
roman7ef57992024-04-23 15:08:45 +0200900 ret = EVP_DecodeBlock(*bin, (const unsigned char *)base64, strlen(base64));
901 if (ret == -1) {
902 ERR(NULL, "Base64 decoding failed (%s).", ERR_reason_error_string(ERR_get_error()));
903 free(*bin);
904 *bin = NULL;
roman163f1662024-04-04 09:26:42 +0200905 }
roman163f1662024-04-04 09:26:42 +0200906 return ret;
907}
908
909int
910nc_base64_encode_wrap(const unsigned char *bin, size_t len, char **base64)
911{
roman7ef57992024-04-23 15:08:45 +0200912 int ret, size;
roman163f1662024-04-04 09:26:42 +0200913
roman7ef57992024-04-23 15:08:45 +0200914 /* calculate the size, for every 3B of in 4B of out, + padding if not divisible + null terminator */
915 if (len % 3) {
916 size = (len / 3) * 4 + 4 + 1;
917 } else {
918 size = (len / 3) * 4 + 1;
roman163f1662024-04-04 09:26:42 +0200919 }
920
roman7ef57992024-04-23 15:08:45 +0200921 *base64 = malloc(size);
922 NC_CHECK_ERRMEM_RET(!*base64, -1);
923
924 ret = EVP_EncodeBlock((unsigned char *)*base64, bin, len);
925 if (ret == -1) {
926 ERR(NULL, "Base64 encoding failed (%s).", ERR_reason_error_string(ERR_get_error()));
927 free(*base64);
928 *base64 = NULL;
929 return -1;
roman163f1662024-04-04 09:26:42 +0200930 }
931
roman7ef57992024-04-23 15:08:45 +0200932 return 0;
roman163f1662024-04-04 09:26:42 +0200933}
934
romane20f3542024-05-14 11:00:54 +0200935/**
936 * @brief Get all OpenSSL error reasons.
937 *
938 * @return String with all OpenSSL error reasons or NULL.
939 */
roman163f1662024-04-04 09:26:42 +0200940static char *
roman7ef57992024-04-23 15:08:45 +0200941nc_tls_get_err_reasons(void)
roman163f1662024-04-04 09:26:42 +0200942{
943 unsigned int e;
944 int reason_size, reason_len;
945 char *reasons = NULL;
946
947 reason_size = 1;
948 reason_len = 0;
949 while ((e = ERR_get_error())) {
950 if (reason_len) {
951 /* add "; " */
952 reason_size += 2;
953 reasons = nc_realloc(reasons, reason_size);
954 NC_CHECK_ERRMEM_RET(!reasons, NULL);
955 reason_len += sprintf(reasons + reason_len, "; ");
956 }
957 reason_size += strlen(ERR_reason_error_string(e));
958 reasons = nc_realloc(reasons, reason_size);
959 NC_CHECK_ERRMEM_RET(!reasons, NULL);
960 reason_len += sprintf(reasons + reason_len, "%s", ERR_reason_error_string(e));
961 }
962
963 return reasons;
964}
965
966int
967nc_tls_read_wrap(struct nc_session *session, unsigned char *buf, size_t size)
968{
969 int rc, err;
970 char *reasons;
971 SSL *tls_session = session->ti.tls.session;
972
973 ERR_clear_error();
974 rc = SSL_read(tls_session, buf, size);
975 if (rc <= 0) {
976 err = SSL_get_error(tls_session, rc);
977 switch (err) {
978 case SSL_ERROR_WANT_READ:
979 case SSL_ERROR_WANT_WRITE:
980 rc = 0;
981 break;
982 case SSL_ERROR_ZERO_RETURN:
983 ERR(session, "Communication socket unexpectedly closed (OpenSSL).");
984 session->status = NC_STATUS_INVALID;
985 session->term_reason = NC_SESSION_TERM_DROPPED;
986 rc = -1;
987 break;
988 case SSL_ERROR_SYSCALL:
989 ERR(session, "TLS socket error (%s).", errno ? strerror(errno) : "unexpected EOF");
990 session->status = NC_STATUS_INVALID;
991 session->term_reason = NC_SESSION_TERM_OTHER;
992 rc = -1;
993 break;
994 case SSL_ERROR_SSL:
roman7ef57992024-04-23 15:08:45 +0200995 reasons = nc_tls_get_err_reasons();
roman163f1662024-04-04 09:26:42 +0200996 ERR(session, "TLS communication error (%s).", reasons);
997 free(reasons);
998 session->status = NC_STATUS_INVALID;
999 session->term_reason = NC_SESSION_TERM_OTHER;
1000 rc = -1;
1001 break;
1002 default:
1003 ERR(session, "Unknown TLS error occurred (err code %d).", err);
1004 session->status = NC_STATUS_INVALID;
1005 session->term_reason = NC_SESSION_TERM_OTHER;
1006 rc = -1;
1007 break;
1008 }
1009 }
1010
1011 return rc;
1012}
1013
1014int
1015nc_tls_write_wrap(struct nc_session *session, const unsigned char *buf, size_t size)
1016{
1017 int rc, err;
1018 char *reasons;
1019 SSL *tls_session = session->ti.tls.session;
1020
1021 ERR_clear_error();
1022 rc = SSL_write(tls_session, buf, size);
1023 if (rc < 1) {
1024 err = SSL_get_error(tls_session, rc);
1025 switch (err) {
1026 case SSL_ERROR_WANT_WRITE:
1027 case SSL_ERROR_WANT_READ:
1028 rc = 0;
1029 break;
1030 case SSL_ERROR_ZERO_RETURN:
1031 ERR(session, "TLS connection was properly closed.");
1032 rc = -1;
1033 break;
1034 case SSL_ERROR_SYSCALL:
1035 ERR(session, "TLS socket error (%s).", errno ? strerror(errno) : "unexpected EOF");
1036 rc = -1;
1037 break;
1038 case SSL_ERROR_SSL:
roman7ef57992024-04-23 15:08:45 +02001039 reasons = nc_tls_get_err_reasons();
roman163f1662024-04-04 09:26:42 +02001040 ERR(session, "TLS communication error (%s).", reasons);
1041 free(reasons);
1042 rc = -1;
1043 break;
1044 default:
1045 ERR(session, "Unknown TLS error occurred (err code %d).", err);
1046 rc = -1;
1047 break;
1048 }
1049 }
1050
1051 return rc;
1052}
1053
1054int
roman7ef57992024-04-23 15:08:45 +02001055nc_tls_get_num_pending_bytes_wrap(void *tls_session)
roman163f1662024-04-04 09:26:42 +02001056{
1057 return SSL_pending(tls_session);
1058}
1059
1060int
1061nc_tls_get_fd_wrap(const struct nc_session *session)
1062{
roman7ef57992024-04-23 15:08:45 +02001063 return session->ti.tls.session ? SSL_get_fd(session->ti.tls.session) : -1;
roman163f1662024-04-04 09:26:42 +02001064}
1065
1066void
1067nc_tls_close_notify_wrap(void *tls_session)
1068{
1069 SSL_shutdown(tls_session);
1070}
1071
1072void *
roman7ef57992024-04-23 15:08:45 +02001073nc_tls_import_privkey_file_wrap(const char *key_path)
roman163f1662024-04-04 09:26:42 +02001074{
1075 EVP_PKEY *pkey;
roman7ef57992024-04-23 15:08:45 +02001076 FILE *file;
1077
1078 file = fopen(key_path, "r");
1079 if (!file) {
1080 ERR(NULL, "Opening the private key file \"%s\" failed.", key_path);
1081 return NULL;
1082 }
roman163f1662024-04-04 09:26:42 +02001083
1084 pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
roman7ef57992024-04-23 15:08:45 +02001085 fclose(file);
roman163f1662024-04-04 09:26:42 +02001086 if (!pkey) {
1087 ERR(NULL, "Parsing the private key file \"%s\" failed (%s).", key_path, ERR_reason_error_string(ERR_get_error()));
1088 }
1089
1090 return pkey;
1091}
1092
1093void *
1094nc_tls_import_cert_file_wrap(const char *cert_path)
1095{
1096 X509 *cert;
1097 FILE *file;
1098
1099 file = fopen(cert_path, "r");
1100 if (!file) {
1101 ERR(NULL, "Opening the certificate file \"%s\" failed.", cert_path);
1102 return NULL;
1103 }
1104
1105 cert = PEM_read_X509(file, NULL, NULL, NULL);
1106 fclose(file);
1107 if (!cert) {
1108 ERR(NULL, "Parsing the certificate file \"%s\" failed (%s).", cert_path, ERR_reason_error_string(ERR_get_error()));
1109 }
1110 return cert;
1111}
1112
1113char *
roman7ef57992024-04-23 15:08:45 +02001114nc_tls_export_privkey_pem_wrap(void *pkey)
roman163f1662024-04-04 09:26:42 +02001115{
1116 BIO *bio = NULL;
1117 char *pem = NULL;
1118
1119 bio = BIO_new(BIO_s_mem());
1120 if (!bio) {
1121 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1122 goto cleanup;
1123 }
1124
1125 if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) {
1126 ERR(NULL, "Exporting the private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1127 goto cleanup;
1128 }
1129
1130 pem = malloc(BIO_number_written(bio) + 1);
1131 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1132
1133 BIO_read(bio, pem, BIO_number_written(bio));
1134 pem[BIO_number_written(bio)] = '\0';
1135
1136cleanup:
1137 BIO_free(bio);
1138 return pem;
1139}
1140
1141char *
roman7ef57992024-04-23 15:08:45 +02001142nc_tls_export_cert_pem_wrap(void *cert)
roman163f1662024-04-04 09:26:42 +02001143{
roman163f1662024-04-04 09:26:42 +02001144 BIO *bio = NULL;
1145 char *pem = NULL;
1146
1147 bio = BIO_new(BIO_s_mem());
1148 if (!bio) {
1149 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1150 goto cleanup;
1151 }
1152
roman7ef57992024-04-23 15:08:45 +02001153 if (!PEM_write_bio_X509(bio, cert)) {
roman163f1662024-04-04 09:26:42 +02001154 ERR(NULL, "Exporting the certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
1155 goto cleanup;
1156 }
1157
roman7ef57992024-04-23 15:08:45 +02001158 pem = malloc(BIO_number_written(bio) + 1);
roman163f1662024-04-04 09:26:42 +02001159 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1160
roman7ef57992024-04-23 15:08:45 +02001161 BIO_read(bio, pem, BIO_number_written(bio));
1162 pem[BIO_number_written(bio)] = '\0';
roman163f1662024-04-04 09:26:42 +02001163
1164cleanup:
1165 BIO_free(bio);
1166 return pem;
1167}
1168
1169char *
roman7ef57992024-04-23 15:08:45 +02001170nc_tls_export_pubkey_pem_wrap(void *pkey)
roman163f1662024-04-04 09:26:42 +02001171{
1172 BIO *bio = NULL;
1173 char *pem = NULL;
1174
1175 bio = BIO_new(BIO_s_mem());
1176 if (!bio) {
1177 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1178 goto cleanup;
1179 }
1180
1181 if (!PEM_write_bio_PUBKEY(bio, pkey)) {
1182 ERR(NULL, "Exporting the public key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1183 goto cleanup;
1184 }
1185
1186 pem = malloc(BIO_number_written(bio) + 1);
1187 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1188
1189 BIO_read(bio, pem, BIO_number_written(bio));
1190 pem[BIO_number_written(bio)] = '\0';
1191
1192cleanup:
1193 BIO_free(bio);
1194 return pem;
1195}
1196
1197int
roman163f1662024-04-04 09:26:42 +02001198nc_tls_privkey_is_rsa_wrap(void *pkey)
1199{
1200 return EVP_PKEY_is_a(pkey, "RSA");
1201}
1202
1203int
1204nc_tls_get_rsa_pubkey_params_wrap(void *pkey, void **e, void **n)
1205{
roman7ef57992024-04-23 15:08:45 +02001206 BIGNUM *exp = NULL, *mod = NULL;
roman163f1662024-04-04 09:26:42 +02001207
1208 if (!EVP_PKEY_get_bn_param(pkey, "e", &exp)) {
1209 ERR(NULL, "Getting the RSA public exponent failed (%s).", ERR_reason_error_string(ERR_get_error()));
1210 return 1;
1211 }
1212
1213 if (!EVP_PKEY_get_bn_param(pkey, "n", &mod)) {
1214 ERR(NULL, "Getting the RSA modulus failed (%s).", ERR_reason_error_string(ERR_get_error()));
1215 BN_free(exp);
1216 return 1;
1217 }
1218
1219 *e = exp;
1220 *n = mod;
1221 return 0;
1222}
1223
roman7ef57992024-04-23 15:08:45 +02001224void
1225nc_tls_destroy_mpi_wrap(void *mpi)
1226{
1227 BN_free(mpi);
1228}
1229
roman163f1662024-04-04 09:26:42 +02001230int
1231nc_tls_privkey_is_ec_wrap(void *pkey)
1232{
1233 return EVP_PKEY_is_a(pkey, "EC");
1234}
1235
1236char *
1237nc_tls_get_ec_group_wrap(void *pkey)
1238{
1239 size_t ec_group_len = 0;
1240 char *ec_group = NULL;
1241
1242 if (!EVP_PKEY_get_utf8_string_param(pkey, "group", NULL, 0, &ec_group_len)) {
1243 ERR(NULL, "Getting EC group length failed (%s).", ERR_reason_error_string(ERR_get_error()));
1244 return NULL;
1245 }
1246
1247 /* alloc mem for group + 1 for \0 */
1248 ec_group = malloc(ec_group_len + 1);
1249 NC_CHECK_ERRMEM_RET(!ec_group, NULL);
1250
1251 /* get the group */
1252 if (!EVP_PKEY_get_utf8_string_param(pkey, "group", ec_group, ec_group_len + 1, NULL)) {
1253 ERR(NULL, "Getting EC group failed (%s).", ERR_reason_error_string(ERR_get_error()));
1254 free(ec_group);
1255 return NULL;
1256 }
1257
1258 return ec_group;
1259}
1260
1261int
roman7ef57992024-04-23 15:08:45 +02001262nc_tls_get_ec_pubkey_params_wrap(void *pkey, void **q, void **UNUSED(q_grp))
roman163f1662024-04-04 09:26:42 +02001263{
roman7ef57992024-04-23 15:08:45 +02001264 BIGNUM *p = NULL;
roman163f1662024-04-04 09:26:42 +02001265
1266 if (!EVP_PKEY_get_bn_param(pkey, "p", &p)) {
1267 ERR(NULL, "Getting public key point from the EC private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
roman7ef57992024-04-23 15:08:45 +02001268 return 1;
roman163f1662024-04-04 09:26:42 +02001269 }
1270
roman7ef57992024-04-23 15:08:45 +02001271 *q = p;
roman163f1662024-04-04 09:26:42 +02001272
roman7ef57992024-04-23 15:08:45 +02001273 return 0;
roman163f1662024-04-04 09:26:42 +02001274}
1275
1276int
roman7ef57992024-04-23 15:08:45 +02001277nc_tls_ec_point_to_bin_wrap(void *q, void *UNUSED(q_grp), unsigned char **bin, int *bin_len)
roman163f1662024-04-04 09:26:42 +02001278{
roman7ef57992024-04-23 15:08:45 +02001279 /* prepare buffer for converting p to binary */
1280 *bin = malloc(BN_num_bytes(q));
1281 NC_CHECK_ERRMEM_RET(!*bin, 1);
1282
1283 /* convert to binary */
1284 *bin_len = BN_bn2bin(q, *bin);
1285 return 0;
roman163f1662024-04-04 09:26:42 +02001286}
1287
1288void
roman7ef57992024-04-23 15:08:45 +02001289nc_tls_ec_point_destroy_wrap(void *p)
roman163f1662024-04-04 09:26:42 +02001290{
roman7ef57992024-04-23 15:08:45 +02001291 BN_free(p);
1292}
1293
1294void
1295nc_tls_ec_group_destroy_wrap(void *UNUSED(grp))
1296{
1297 return;
1298}
1299
1300int
1301nc_tls_mpi2bin_wrap(void *mpi, unsigned char **bin, int *bin_len)
1302{
1303 /* prepare buffer for converting mpi to binary */
1304 *bin = malloc(BN_num_bytes(mpi));
1305 NC_CHECK_ERRMEM_RET(!*bin, 1);
1306
1307 /* convert to binary */
1308 *bin_len = BN_bn2bin(mpi, *bin);
1309 return 0;
roman163f1662024-04-04 09:26:42 +02001310}
1311
1312void *
1313nc_tls_import_pubkey_file_wrap(const char *pubkey_path)
1314{
1315 FILE *f;
1316 EVP_PKEY *pk = NULL;
1317
1318 f = fopen(pubkey_path, "r");
1319 if (!f) {
1320 ERR(NULL, "Unable to open file \"%s\".", pubkey_path);
1321 return NULL;
1322 }
1323
1324 /* read the pubkey from file */
1325 pk = PEM_read_PUBKEY(f, NULL, NULL, NULL);
1326 fclose(f);
1327 if (!pk) {
1328 ERR(NULL, "Reading public key from file \"%s\" failed (%s).", pubkey_path, ERR_reason_error_string(ERR_get_error()));
1329 return NULL;
1330 }
1331
1332 return pk;
1333}
roman275c3fb2024-04-05 12:29:11 +02001334
1335int
1336nc_server_tls_get_crl_distpoint_uris_wrap(void *cert_store, char ***uris, int *uri_count)
1337{
1338 int ret = 0, i, j, k, gtype;
roman275c3fb2024-04-05 12:29:11 +02001339
1340 STACK_OF(X509_OBJECT) * objs;
1341 X509_OBJECT *obj;
1342 X509 *cert;
1343
1344 STACK_OF(DIST_POINT) * dist_points;
1345 DIST_POINT *dist_point;
1346 GENERAL_NAMES *general_names;
1347 GENERAL_NAME *general_name;
1348 ASN1_STRING *asn_string_uri;
roman275c3fb2024-04-05 12:29:11 +02001349 void *tmp;
1350
1351 NC_CHECK_ARG_RET(NULL, cert_store, uris, uri_count, 1);
1352
1353 *uris = NULL;
1354 *uri_count = 0;
1355
1356 /* treat all entries in the cert_store as X509_OBJECTs */
1357 objs = X509_STORE_get0_objects(cert_store);
1358 if (!objs) {
1359 ERR(NULL, "Getting certificates from store failed (%s).", ERR_reason_error_string(ERR_get_error()));
1360 ret = -1;
1361 goto cleanup;
1362 }
1363
1364 /* iterate over all the CAs */
1365 for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
1366 obj = sk_X509_OBJECT_value(objs, i);
1367 cert = X509_OBJECT_get0_X509(obj);
1368 if (!cert) {
1369 /* the object on this index was not a certificate */
1370 continue;
1371 }
1372
1373 /* get all the distribution points for this CA */
1374 dist_points = X509_get_ext_d2i(cert, NID_crl_distribution_points, NULL, NULL);
1375
1376 /* iterate over all the dist points (there can be multiple for a single cert) */
1377 for (j = 0; j < sk_DIST_POINT_num(dist_points); j++) {
1378 dist_point = sk_DIST_POINT_value(dist_points, j);
1379 if (!dist_point) {
1380 continue;
1381 }
1382 general_names = dist_point->distpoint->name.fullname;
1383
1384 /* iterate over all the GeneralesNames in the distribution point */
1385 for (k = 0; k < sk_GENERAL_NAME_num(general_names); k++) {
1386 general_name = sk_GENERAL_NAME_value(general_names, k);
1387 asn_string_uri = GENERAL_NAME_get0_value(general_name, &gtype);
1388
1389 /* check if the general name is a URI and has a valid length */
1390 if ((gtype != GEN_URI) || (ASN1_STRING_length(asn_string_uri) <= 6)) {
1391 continue;
1392 }
1393
1394 /* found an URI */
1395 tmp = realloc(*uris, (*uri_count + 1) * sizeof **uris);
1396 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
1397 *uris = tmp;
1398
1399 *uris[*uri_count] = strdup((const char *) ASN1_STRING_get0_data(asn_string_uri));
1400 NC_CHECK_ERRMEM_GOTO(!*uris[*uri_count], ret = 1, cleanup);
1401 ++(*uri_count);
1402 }
1403 }
1404 }
1405
1406cleanup:
1407 return ret;
1408}
roman7ef57992024-04-23 15:08:45 +02001409
1410int
1411nc_tls_process_cipher_suite_wrap(const char *cipher, char **out)
1412{
1413 int i;
1414
1415 *out = malloc(strlen(cipher) + 1);
1416 NC_CHECK_ERRMEM_RET(!*out, 1);
1417
1418 /* convert to uppercase */
1419 for (i = 0; cipher[i]; i++) {
1420 if (cipher[i] == '-') {
1421 /* OpenSSL requires _ instead of - in cipher names */
1422 (*out)[i] = '_';
1423 } else {
1424 (*out)[i] = toupper(cipher[i]);
1425 }
1426 }
1427
1428 (*out)[i] = '\0';
1429 return 0;
1430}
1431
1432int
1433nc_tls_append_cipher_suite_wrap(struct nc_server_tls_opts *opts, const char *cipher_suite)
1434{
1435 if (!opts->ciphers) {
1436 /* first entry */
1437 opts->ciphers = strdup(cipher_suite);
1438 NC_CHECK_ERRMEM_RET(!opts->ciphers, 1);
1439 } else {
1440 /* + 1 because of : between entries */
1441 opts->ciphers = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(cipher_suite) + 1 + 1);
1442 NC_CHECK_ERRMEM_RET(!opts->ciphers, 1);
1443 strcat(opts->ciphers, ":");
1444 strcat(opts->ciphers, cipher_suite);
1445 }
1446
1447 return 0;
1448}
1449
1450void
1451nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, void *cipher_suites)
1452{
1453 /* set for TLS1.2 and lower */
1454 SSL_CTX_set_cipher_list(tls_cfg, cipher_suites);
1455 /* set for TLS1.3 */
1456 SSL_CTX_set_ciphersuites(tls_cfg, cipher_suites);
1457}