blob: b4d0652149fd60574b368ba1578cacb839fe36b4 [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_server_tls_add_crl_to_store_wrap(const unsigned char *crl_data, size_t size, void *crl_store)
roman163f1662024-04-04 09:26:42 +0200202{
203 int ret = 0;
204 X509_CRL *crl = NULL;
205 BIO *bio = NULL;
206
roman163f1662024-04-04 09:26:42 +0200207 bio = BIO_new_mem_buf(crl_data, size);
208 if (!bio) {
209 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
210 ret = 1;
211 goto cleanup;
212 }
213
214 /* try DER first */
215 crl = d2i_X509_CRL_bio(bio, NULL);
216 if (crl) {
217 /* it was DER */
218 goto ok;
219 }
220
221 /* DER failed, try PEM next */
222 crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
223 if (!crl) {
224 ERR(NULL, "Parsing downloaded CRL failed (%s).", ERR_reason_error_string(ERR_get_error()));
225 ret = 1;
226 goto cleanup;
227 }
228
229ok:
230 /* we obtained the CRL, now add it to the CRL store */
roman7ef57992024-04-23 15:08:45 +0200231 ret = X509_STORE_add_crl(crl_store, crl);
roman163f1662024-04-04 09:26:42 +0200232 if (!ret) {
233 ERR(NULL, "Error adding CRL to store (%s).", ERR_reason_error_string(ERR_get_error()));
234 ret = 1;
235 goto cleanup;
236 }
237 /* ok */
238 ret = 0;
239
240cleanup:
241 X509_CRL_free(crl);
242 BIO_free(bio);
243 return ret;
244}
245
roman163f1662024-04-04 09:26:42 +0200246int
247nc_server_tls_set_tls_versions_wrap(void *tls_cfg, unsigned int tls_versions)
248{
249 int rc = 1;
250
251 /* first set the minimum version */
252 if (tls_versions & NC_TLS_VERSION_10) {
253 rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_VERSION);
254 } else if (tls_versions & NC_TLS_VERSION_11) {
255 rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_1_VERSION);
256 } else if (tls_versions & NC_TLS_VERSION_12) {
257 rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_2_VERSION);
258 } else if (tls_versions & NC_TLS_VERSION_13) {
259 rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_3_VERSION);
260 }
261 if (!rc) {
262 ERR(NULL, "Setting TLS min version failed (%s).", ERR_reason_error_string(ERR_get_error()));
263 return 1;
264 }
265
266 /* then set the maximum version */
267 if (tls_versions & NC_TLS_VERSION_13) {
268 rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_3_VERSION);
269 } else if (tls_versions & NC_TLS_VERSION_12) {
270 rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_2_VERSION);
271 } else if (tls_versions & NC_TLS_VERSION_11) {
272 rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_1_VERSION);
273 } else if (tls_versions & NC_TLS_VERSION_10) {
274 rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_VERSION);
275 }
276 if (!rc) {
277 ERR(NULL, "Setting TLS max version failed (%s).", ERR_reason_error_string(ERR_get_error()));
278 return 1;
279 }
280
281 return 0;
282}
283
romane20f3542024-05-14 11:00:54 +0200284/**
285 * @brief Verify a certificate.
286 *
287 * @param[in] preverify_ok The result of the in-built verification.
288 * @param[in] x509_ctx Verification context.
289 * @return 1 on success, 0 on error.
290 */
roman163f1662024-04-04 09:26:42 +0200291static int
292nc_server_tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
293{
294 int ret = 0, depth, err;
295 struct nc_tls_verify_cb_data *data;
296 SSL *ssl;
roman7ef57992024-04-23 15:08:45 +0200297 SSL_CTX *ctx;
roman163f1662024-04-04 09:26:42 +0200298 X509 *cert;
299
roman7ffd2fc2024-05-13 13:48:34 +0200300 /* retrieve callback data stored inside the SSL_CTX struct */
roman163f1662024-04-04 09:26:42 +0200301 ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
roman7ffd2fc2024-05-13 13:48:34 +0200302 if (!ssl) {
303 ERRINT;
304 return 0;
305 }
roman7ef57992024-04-23 15:08:45 +0200306 ctx = SSL_get_SSL_CTX(ssl);
roman7ffd2fc2024-05-13 13:48:34 +0200307 if (!ctx) {
308 ERRINT;
309 return 0;
310 }
roman7ef57992024-04-23 15:08:45 +0200311 data = SSL_CTX_get_ex_data(ctx, 0);
roman163f1662024-04-04 09:26:42 +0200312
313 /* get current cert and its depth */
314 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
315 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
316
317 if (preverify_ok) {
318 /* in-built verification was successful */
roman7ffd2fc2024-05-13 13:48:34 +0200319 ret = nc_server_tls_verify_cert(cert, depth, 1, data);
roman163f1662024-04-04 09:26:42 +0200320 } else {
321 /* in-built verification failed, but the client still may be authenticated if:
322 * 1) the peer cert matches any configured end-entity cert
323 * 2) the peer cert has a valid chain of trust to any configured certificate authority cert
324 * otherwise just continue until we reach the peer cert (depth = 0)
325 */
326 err = X509_STORE_CTX_get_error(x509_ctx);
roman7ffd2fc2024-05-13 13:48:34 +0200327 if ((depth == 0) && ((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) || (err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))) {
328 /* not trusted (possibly self-signed) peer certificate, case 1) */
329 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
roman163f1662024-04-04 09:26:42 +0200330 } else if ((err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) || (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)) {
331 /* full chain of trust is invalid, but it may be valid partially, case 2) */
332 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
roman7ef57992024-04-23 15:08:45 +0200333 } else if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) {
334 /* self-signed certificate in the chain, check if peer cert complies with 1) in order to continue,
335 * if yes, this callback will be called again with the same cert, but with preverify_ok = 1
336 */
337 cert = X509_STORE_CTX_get0_cert(x509_ctx);
338 ret = nc_server_tls_verify_peer_cert(cert, data->opts);
339 if (ret) {
340 VRB(NULL, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
341 ret = -1;
roman7ef57992024-04-23 15:08:45 +0200342 }
roman163f1662024-04-04 09:26:42 +0200343 } else {
344 VRB(NULL, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
345 ret = 1;
346 }
347 }
348
349 if (ret == -1) {
350 /* fatal error */
351 return 0;
352 } else if (!ret) {
353 /* success */
roman396f4732024-05-14 09:09:30 +0200354 if ((depth == 0) && (!data->session->opts.server.client_cert)) {
355 /* copy the client cert */
356 data->session->opts.server.client_cert = X509_dup(cert);
357 NC_CHECK_ERRMEM_RET(!data->session->opts.server.client_cert, 0);
358 }
roman163f1662024-04-04 09:26:42 +0200359 return 1;
360 } else {
361 if (depth > 0) {
362 /* chain verify failed */
363 return 1;
364 } else {
365 /* peer cert did not match */
366 return 0;
367 }
368 }
369}
370
371void
roman7ef57992024-04-23 15:08:45 +0200372nc_server_tls_set_verify_wrap(void *tls_cfg, struct nc_tls_verify_cb_data *cb_data)
roman163f1662024-04-04 09:26:42 +0200373{
roman7ef57992024-04-23 15:08:45 +0200374 /* set verify cb and its data */
375 SSL_CTX_set_ex_data(tls_cfg, 0, cb_data);
376 SSL_CTX_set_verify(tls_cfg, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_server_tls_verify_cb);
377}
378
379void
380nc_client_tls_set_verify_wrap(void *tls_cfg)
381{
382 SSL_CTX_set_verify(tls_cfg, SSL_VERIFY_PEER, NULL);
roman163f1662024-04-04 09:26:42 +0200383}
384
385char *
386nc_server_tls_get_subject_wrap(void *cert)
387{
388 return X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
389}
390
391char *
392nc_server_tls_get_issuer_wrap(void *cert)
393{
394 return X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
395}
396
roman7ef57992024-04-23 15:08:45 +0200397void *
398nc_tls_get_sans_wrap(void *cert)
roman163f1662024-04-04 09:26:42 +0200399{
roman7ef57992024-04-23 15:08:45 +0200400 return X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
401}
402
403void
404nc_tls_sans_destroy_wrap(void *sans)
405{
406 sk_GENERAL_NAME_pop_free(sans, GENERAL_NAME_free);
407}
408
409int
410nc_tls_get_num_sans_wrap(void *sans)
411{
412 return sk_GENERAL_NAME_num(sans);
413}
414
415int
416nc_tls_get_san_value_type_wrap(void *sans, int idx, char **san_value, NC_TLS_CTN_MAPTYPE *san_type)
417{
418 int ret = 0;
419 GENERAL_NAME *san;
roman163f1662024-04-04 09:26:42 +0200420 ASN1_OCTET_STRING *ip;
roman163f1662024-04-04 09:26:42 +0200421
roman7ef57992024-04-23 15:08:45 +0200422 *san_value = NULL;
423 *san_type = NC_TLS_CTN_UNKNOWN;
roman163f1662024-04-04 09:26:42 +0200424
roman7ef57992024-04-23 15:08:45 +0200425 /* find the san */
426 san = sk_GENERAL_NAME_value(sans, idx);
427 if (!san) {
428 return -1;
roman163f1662024-04-04 09:26:42 +0200429 }
430
roman7ef57992024-04-23 15:08:45 +0200431 /* get its type and value */
432 switch (san->type) {
433 case GEN_EMAIL:
434 *san_type = NC_TLS_CTN_SAN_RFC822_NAME;
435 *san_value = strdup((char *)ASN1_STRING_get0_data(san->d.rfc822Name));
436 NC_CHECK_ERRMEM_RET(!*san_value, -1);
437 break;
438 case GEN_DNS:
439 *san_type = NC_TLS_CTN_SAN_DNS_NAME;
440 *san_value = strdup((char *)ASN1_STRING_get0_data(san->d.dNSName));
441 NC_CHECK_ERRMEM_RET(!*san_value, -1);
442 break;
443 case GEN_IPADD:
444 *san_type = NC_TLS_CTN_SAN_IP_ADDRESS;
445 ip = san->d.iPAddress;
446 if (ip->length == 4) {
447 if (asprintf(san_value, "%d.%d.%d.%d", ip->data[0], ip->data[1], ip->data[2], ip->data[3]) == -1) {
448 ERRMEM;
449 *san_value = NULL;
450 ret = -1;
451 }
452 } else if (ip->length == 16) {
453 if (asprintf(san_value, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
454 ip->data[0], ip->data[1], ip->data[2], ip->data[3], ip->data[4], ip->data[5],
455 ip->data[6], ip->data[7], ip->data[8], ip->data[9], ip->data[10], ip->data[11],
456 ip->data[12], ip->data[13], ip->data[14], ip->data[15]) == -1) {
457 ERRMEM;
458 *san_value = NULL;
459 ret = -1;
460 }
461 } else {
462 WRN(NULL, "SAN IP address in an unknown format (length is %d).", ip->length);
463 ret = 1;
464 }
465 break;
466 default:
467 /* we dont care about other types */
468 *san_type = NC_TLS_CTN_UNKNOWN;
469 ret = 1;
470 break;
471 }
472
473 return ret;
roman163f1662024-04-04 09:26:42 +0200474}
475
476int
477nc_server_tls_certs_match_wrap(void *cert1, void *cert2)
478{
479 return !X509_cmp(cert1, cert2);
480}
481
482int
483nc_server_tls_md5_wrap(void *cert, unsigned char *buf)
484{
485 int rc;
486
487 rc = X509_digest(cert, EVP_md5(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200488 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200489 ERR(NULL, "Calculating MD-5 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
490 return 1;
491 }
492
493 return 0;
494}
495
496int
497nc_server_tls_sha1_wrap(void *cert, unsigned char *buf)
498{
499 int rc;
500
501 rc = X509_digest(cert, EVP_sha1(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200502 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200503 ERR(NULL, "Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
504 return 1;
505 }
506
507 return 0;
508}
509
510int
511nc_server_tls_sha224_wrap(void *cert, unsigned char *buf)
512{
513 int rc;
514
515 rc = X509_digest(cert, EVP_sha224(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200516 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200517 ERR(NULL, "Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
518 return 1;
519 }
520
521 return 0;
522}
523
524int
525nc_server_tls_sha256_wrap(void *cert, unsigned char *buf)
526{
527 int rc;
528
529 rc = X509_digest(cert, EVP_sha256(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200530 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200531 ERR(NULL, "Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
532 return 1;
533 }
534
535 return 0;
536}
537
538int
539nc_server_tls_sha384_wrap(void *cert, unsigned char *buf)
540{
541 int rc;
542
543 rc = X509_digest(cert, EVP_sha384(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200544 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200545 ERR(NULL, "Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
546 return 1;
547 }
548
549 return 0;
550}
551
552int
553nc_server_tls_sha512_wrap(void *cert, unsigned char *buf)
554{
555 int rc;
556
557 rc = X509_digest(cert, EVP_sha512(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200558 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200559 ERR(NULL, "Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
560 return 1;
561 }
562
563 return 0;
564}
565
566void
567nc_server_tls_set_fd_wrap(void *tls_session, int sock, struct nc_tls_ctx *UNUSED(tls_ctx))
568{
569 SSL_set_fd(tls_session, sock);
570}
571
572int
573nc_server_tls_handshake_step_wrap(void *tls_session)
574{
575 int ret = 0;
576
577 ret = SSL_accept(tls_session);
578 if (ret == 1) {
579 return 1;
580 } else if (ret == -1) {
581 if ((SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_READ) || (SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_WRITE)) {
582 return 0;
583 }
584 }
585
586 return -1;
587}
588
589int
roman7ef57992024-04-23 15:08:45 +0200590nc_client_tls_handshake_step_wrap(void *tls_session, int UNUSED(sock))
roman163f1662024-04-04 09:26:42 +0200591{
592 int ret = 0;
593
594 ret = SSL_connect(tls_session);
595 if (ret == 1) {
596 return 1;
597 } else if (ret == -1) {
598 if ((SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_READ) || (SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_WRITE)) {
599 return 0;
600 }
601 }
602
603 return -1;
604}
605
606void
607nc_tls_ctx_destroy_wrap(struct nc_tls_ctx *UNUSED(tls_ctx))
608{
609 return;
610}
611
612int
613nc_client_tls_load_cert_key_wrap(const char *cert_path, const char *key_path, void **cert, void **pkey)
614{
615 BIO *bio;
616 X509 *cert_tmp;
617 EVP_PKEY *pkey_tmp;
618
roman7ef57992024-04-23 15:08:45 +0200619 NC_CHECK_ARG_RET(NULL, cert_path, key_path, cert, pkey, 1);
620
roman163f1662024-04-04 09:26:42 +0200621 bio = BIO_new_file(cert_path, "r");
622 if (!bio) {
623 ERR(NULL, "Opening the client certificate file \"%s\" failed.", cert_path);
624 return 1;
625 }
626
627 cert_tmp = PEM_read_bio_X509(bio, NULL, NULL, NULL);
628 BIO_free(bio);
629 if (!cert_tmp) {
630 ERR(NULL, "Parsing the client certificate file \"%s\" failed.", cert_path);
631 return 1;
632 }
633
634 bio = BIO_new_file(key_path, "r");
635 if (!bio) {
636 ERR(NULL, "Opening the client private key file \"%s\" failed.", key_path);
637 X509_free(cert_tmp);
638 return 1;
639 }
640
641 pkey_tmp = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
642 BIO_free(bio);
643 if (!pkey_tmp) {
644 ERR(NULL, "Parsing the client private key file \"%s\" failed.", key_path);
645 X509_free(cert_tmp);
646 return 1;
647 }
648
649 *cert = cert_tmp;
650 *pkey = pkey_tmp;
651
652 return 0;
653}
654
655int
656nc_client_tls_load_trusted_certs_wrap(void *cert_store, const char *file_path, const char *dir_path)
657{
658 if (!X509_STORE_load_locations(cert_store, file_path, dir_path)) {
roman7ffd2fc2024-05-13 13:48:34 +0200659 ERR(NULL, "Loading CA certs from file \"%s\" or directory \"%s\" failed (%s).",
660 file_path, dir_path, ERR_reason_error_string(ERR_get_error()));
roman163f1662024-04-04 09:26:42 +0200661 return 1;
662 }
663
664 return 0;
665}
666
667int
roman163f1662024-04-04 09:26:42 +0200668nc_client_tls_set_hostname_wrap(void *tls_session, const char *hostname)
669{
670 int ret = 0;
671 X509_VERIFY_PARAM *vpm = NULL;
672
673 vpm = X509_VERIFY_PARAM_new();
674 NC_CHECK_ERRMEM_RET(!vpm, 1);
675
676 if (!X509_VERIFY_PARAM_set1_host(vpm, hostname, 0)) {
677 ERR(NULL, "Failed to set expected hostname (%s).", ERR_reason_error_string(ERR_get_error()));
678 ret = 1;
679 goto cleanup;
680 }
roman7ef57992024-04-23 15:08:45 +0200681 if (!SSL_set1_param(tls_session, vpm)) {
roman163f1662024-04-04 09:26:42 +0200682 ERR(NULL, "Failed to set verify param (%s).", ERR_reason_error_string(ERR_get_error()));
683 ret = 1;
684 goto cleanup;
685 }
686
687cleanup:
688 X509_VERIFY_PARAM_free(vpm);
689 return ret;
690}
691
roman7ef57992024-04-23 15:08:45 +0200692int
693nc_tls_init_ctx_wrap(int UNUSED(sock), void *cert, void *pkey, void *cert_store, void *crl_store, struct nc_tls_ctx *tls_ctx)
694{
695 tls_ctx->cert = cert;
696 tls_ctx->pkey = pkey;
697 tls_ctx->cert_store = cert_store;
698 tls_ctx->crl_store = crl_store;
699 return 0;
700}
701
romane20f3542024-05-14 11:00:54 +0200702/**
703 * @brief Move CRLs from one store to another.
704 *
705 * @param[in] src Source store.
706 * @param[in] dst Destination store.
707 * @return 0 on success, 1 on error.
708 */
roman7ef57992024-04-23 15:08:45 +0200709static int
710nc_tls_move_crls_to_store(const X509_STORE *src, X509_STORE *dst)
711{
712 int i, nobjs = 0;
713
714 STACK_OF(X509_OBJECT) * objs;
715 X509_OBJECT *obj;
716 X509_CRL *crl;
717
718 objs = X509_STORE_get0_objects(src);
719 nobjs = sk_X509_OBJECT_num(objs);
720 for (i = 0; i < nobjs; i++) {
721 obj = sk_X509_OBJECT_value(objs, i);
722 crl = X509_OBJECT_get0_X509_CRL(obj);
723 if (!crl) {
724 /* not a CRL */
725 continue;
726 }
727 if (!X509_STORE_add_crl(dst, crl)) {
728 ERR(NULL, "Adding CRL to the store failed (%s).", ERR_reason_error_string(ERR_get_error()));
729 return 1;
730 }
731 }
732
733 return 0;
734}
735
736int
roman7ffd2fc2024-05-13 13:48:34 +0200737nc_tls_setup_config_from_ctx_wrap(struct nc_tls_ctx *tls_ctx, int side, void *tls_cfg)
roman7ef57992024-04-23 15:08:45 +0200738{
739 if (SSL_CTX_use_certificate(tls_cfg, tls_ctx->cert) != 1) {
roman15fbc592024-07-02 16:01:23 +0200740 ERR(NULL, "Setting up TLS certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
roman7ef57992024-04-23 15:08:45 +0200741 return 1;
742 }
743
744 if (SSL_CTX_use_PrivateKey(tls_cfg, tls_ctx->pkey) != 1) {
roman15fbc592024-07-02 16:01:23 +0200745 ERR(NULL, "Setting up TLS private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
roman7ef57992024-04-23 15:08:45 +0200746 return 1;
747 }
748
roman7ffd2fc2024-05-13 13:48:34 +0200749 /* disable server-side automatic chain building */
750 if (side == NC_SERVER) {
751 SSL_CTX_set_mode(tls_cfg, SSL_MODE_NO_AUTO_CHAIN);
752 }
roman7ef57992024-04-23 15:08:45 +0200753
754 if (tls_ctx->crl_store) {
755 /* move CRLs from crl_store to cert_store, because SSL_CTX can only have one store */
756 if (nc_tls_move_crls_to_store(tls_ctx->crl_store, tls_ctx->cert_store)) {
757 return 1;
758 }
759
760 /* enable CRL checks */
761 X509_STORE_set_flags(tls_ctx->cert_store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
762 }
763
764 SSL_CTX_set_cert_store(tls_cfg, tls_ctx->cert_store);
765
766 X509_free(tls_ctx->cert);
767 tls_ctx->cert = NULL;
768 EVP_PKEY_free(tls_ctx->pkey);
769 tls_ctx->pkey = NULL;
770 X509_STORE_free(tls_ctx->crl_store);
771 tls_ctx->crl_store = NULL;
772
773 return 0;
774}
775
roman163f1662024-04-04 09:26:42 +0200776uint32_t
777nc_tls_get_verify_result_wrap(void *tls_session)
778{
779 return SSL_get_verify_result(tls_session);
780}
781
roman7ef57992024-04-23 15:08:45 +0200782char *
roman163f1662024-04-04 09:26:42 +0200783nc_tls_verify_error_string_wrap(uint32_t err_code)
784{
roman7ef57992024-04-23 15:08:45 +0200785 return strdup(X509_verify_cert_error_string(err_code));
roman163f1662024-04-04 09:26:42 +0200786}
787
788void
roman7ef57992024-04-23 15:08:45 +0200789nc_client_tls_print_connect_err_wrap(int connect_ret, const char *peername, void *tls_session)
roman163f1662024-04-04 09:26:42 +0200790{
791 switch (SSL_get_error(tls_session, connect_ret)) {
792 case SSL_ERROR_SYSCALL:
793 ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, errno ? strerror(errno) : "unexpected EOF");
794 break;
795 case SSL_ERROR_SSL:
796 ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, ERR_reason_error_string(ERR_get_error()));
797 break;
798 default:
799 ERR(NULL, "TLS connection to \"%s\" failed.", peername);
800 break;
801 }
802}
803
804void
roman7ef57992024-04-23 15:08:45 +0200805nc_server_tls_print_accept_err_wrap(int accept_ret, void *tls_session)
roman163f1662024-04-04 09:26:42 +0200806{
807 switch (SSL_get_error(tls_session, accept_ret)) {
808 case SSL_ERROR_SYSCALL:
809 ERR(NULL, "TLS accept failed (%s).", strerror(errno));
810 break;
811 case SSL_ERROR_SSL:
812 ERR(NULL, "TLS accept failed (%s).", ERR_reason_error_string(ERR_get_error()));
813 break;
814 default:
815 ERR(NULL, "TLS accept failed.");
816 break;
817 }
818}
819
820int
roman7ef57992024-04-23 15:08:45 +0200821nc_tls_is_der_subpubkey_wrap(unsigned char *der, long len)
roman163f1662024-04-04 09:26:42 +0200822{
823 int ret;
824 EVP_PKEY *pkey;
825
roman7ef57992024-04-23 15:08:45 +0200826 pkey = d2i_PUBKEY(NULL, (const unsigned char **)&der, len);
roman163f1662024-04-04 09:26:42 +0200827 if (pkey) {
828 /* success */
roman7ef57992024-04-23 15:08:45 +0200829 ret = 1;
roman163f1662024-04-04 09:26:42 +0200830 } else {
831 /* fail */
roman7ef57992024-04-23 15:08:45 +0200832 ret = 0;
roman163f1662024-04-04 09:26:42 +0200833 }
834
835 EVP_PKEY_free(pkey);
836 return ret;
837}
838
839int
roman7ef57992024-04-23 15:08:45 +0200840nc_base64_decode_wrap(const char *base64, unsigned char **bin)
roman163f1662024-04-04 09:26:42 +0200841{
roman7ef57992024-04-23 15:08:45 +0200842 int ret;
roman163f1662024-04-04 09:26:42 +0200843
roman7ef57992024-04-23 15:08:45 +0200844 *bin = malloc((strlen(base64) / 4) * 3);
845 NC_CHECK_ERRMEM_RET(!*bin, -1);
roman163f1662024-04-04 09:26:42 +0200846
roman7ef57992024-04-23 15:08:45 +0200847 ret = EVP_DecodeBlock(*bin, (const unsigned char *)base64, strlen(base64));
848 if (ret == -1) {
849 ERR(NULL, "Base64 decoding failed (%s).", ERR_reason_error_string(ERR_get_error()));
850 free(*bin);
851 *bin = NULL;
roman163f1662024-04-04 09:26:42 +0200852 }
roman163f1662024-04-04 09:26:42 +0200853 return ret;
854}
855
856int
857nc_base64_encode_wrap(const unsigned char *bin, size_t len, char **base64)
858{
roman7ef57992024-04-23 15:08:45 +0200859 int ret, size;
roman163f1662024-04-04 09:26:42 +0200860
roman7ef57992024-04-23 15:08:45 +0200861 /* calculate the size, for every 3B of in 4B of out, + padding if not divisible + null terminator */
862 if (len % 3) {
863 size = (len / 3) * 4 + 4 + 1;
864 } else {
865 size = (len / 3) * 4 + 1;
roman163f1662024-04-04 09:26:42 +0200866 }
867
roman7ef57992024-04-23 15:08:45 +0200868 *base64 = malloc(size);
869 NC_CHECK_ERRMEM_RET(!*base64, -1);
870
871 ret = EVP_EncodeBlock((unsigned char *)*base64, bin, len);
872 if (ret == -1) {
873 ERR(NULL, "Base64 encoding failed (%s).", ERR_reason_error_string(ERR_get_error()));
874 free(*base64);
875 *base64 = NULL;
876 return -1;
roman163f1662024-04-04 09:26:42 +0200877 }
878
roman7ef57992024-04-23 15:08:45 +0200879 return 0;
roman163f1662024-04-04 09:26:42 +0200880}
881
romane20f3542024-05-14 11:00:54 +0200882/**
883 * @brief Get all OpenSSL error reasons.
884 *
885 * @return String with all OpenSSL error reasons or NULL.
886 */
roman163f1662024-04-04 09:26:42 +0200887static char *
roman7ef57992024-04-23 15:08:45 +0200888nc_tls_get_err_reasons(void)
roman163f1662024-04-04 09:26:42 +0200889{
890 unsigned int e;
891 int reason_size, reason_len;
892 char *reasons = NULL;
893
894 reason_size = 1;
895 reason_len = 0;
896 while ((e = ERR_get_error())) {
897 if (reason_len) {
898 /* add "; " */
899 reason_size += 2;
900 reasons = nc_realloc(reasons, reason_size);
901 NC_CHECK_ERRMEM_RET(!reasons, NULL);
902 reason_len += sprintf(reasons + reason_len, "; ");
903 }
904 reason_size += strlen(ERR_reason_error_string(e));
905 reasons = nc_realloc(reasons, reason_size);
906 NC_CHECK_ERRMEM_RET(!reasons, NULL);
907 reason_len += sprintf(reasons + reason_len, "%s", ERR_reason_error_string(e));
908 }
909
910 return reasons;
911}
912
913int
914nc_tls_read_wrap(struct nc_session *session, unsigned char *buf, size_t size)
915{
916 int rc, err;
917 char *reasons;
918 SSL *tls_session = session->ti.tls.session;
919
920 ERR_clear_error();
921 rc = SSL_read(tls_session, buf, size);
922 if (rc <= 0) {
923 err = SSL_get_error(tls_session, rc);
924 switch (err) {
925 case SSL_ERROR_WANT_READ:
926 case SSL_ERROR_WANT_WRITE:
927 rc = 0;
928 break;
929 case SSL_ERROR_ZERO_RETURN:
930 ERR(session, "Communication socket unexpectedly closed (OpenSSL).");
931 session->status = NC_STATUS_INVALID;
932 session->term_reason = NC_SESSION_TERM_DROPPED;
933 rc = -1;
934 break;
935 case SSL_ERROR_SYSCALL:
936 ERR(session, "TLS socket error (%s).", errno ? strerror(errno) : "unexpected EOF");
937 session->status = NC_STATUS_INVALID;
938 session->term_reason = NC_SESSION_TERM_OTHER;
939 rc = -1;
940 break;
941 case SSL_ERROR_SSL:
roman7ef57992024-04-23 15:08:45 +0200942 reasons = nc_tls_get_err_reasons();
roman163f1662024-04-04 09:26:42 +0200943 ERR(session, "TLS communication error (%s).", reasons);
944 free(reasons);
945 session->status = NC_STATUS_INVALID;
946 session->term_reason = NC_SESSION_TERM_OTHER;
947 rc = -1;
948 break;
949 default:
950 ERR(session, "Unknown TLS error occurred (err code %d).", err);
951 session->status = NC_STATUS_INVALID;
952 session->term_reason = NC_SESSION_TERM_OTHER;
953 rc = -1;
954 break;
955 }
956 }
957
958 return rc;
959}
960
961int
962nc_tls_write_wrap(struct nc_session *session, const unsigned char *buf, size_t size)
963{
964 int rc, err;
965 char *reasons;
966 SSL *tls_session = session->ti.tls.session;
967
968 ERR_clear_error();
969 rc = SSL_write(tls_session, buf, size);
970 if (rc < 1) {
971 err = SSL_get_error(tls_session, rc);
972 switch (err) {
973 case SSL_ERROR_WANT_WRITE:
974 case SSL_ERROR_WANT_READ:
975 rc = 0;
976 break;
977 case SSL_ERROR_ZERO_RETURN:
978 ERR(session, "TLS connection was properly closed.");
979 rc = -1;
980 break;
981 case SSL_ERROR_SYSCALL:
982 ERR(session, "TLS socket error (%s).", errno ? strerror(errno) : "unexpected EOF");
983 rc = -1;
984 break;
985 case SSL_ERROR_SSL:
roman7ef57992024-04-23 15:08:45 +0200986 reasons = nc_tls_get_err_reasons();
roman163f1662024-04-04 09:26:42 +0200987 ERR(session, "TLS communication error (%s).", reasons);
988 free(reasons);
989 rc = -1;
990 break;
991 default:
992 ERR(session, "Unknown TLS error occurred (err code %d).", err);
993 rc = -1;
994 break;
995 }
996 }
997
998 return rc;
999}
1000
1001int
roman7ef57992024-04-23 15:08:45 +02001002nc_tls_get_num_pending_bytes_wrap(void *tls_session)
roman163f1662024-04-04 09:26:42 +02001003{
1004 return SSL_pending(tls_session);
1005}
1006
1007int
1008nc_tls_get_fd_wrap(const struct nc_session *session)
1009{
roman7ef57992024-04-23 15:08:45 +02001010 return session->ti.tls.session ? SSL_get_fd(session->ti.tls.session) : -1;
roman163f1662024-04-04 09:26:42 +02001011}
1012
1013void
1014nc_tls_close_notify_wrap(void *tls_session)
1015{
1016 SSL_shutdown(tls_session);
1017}
1018
1019void *
roman7ef57992024-04-23 15:08:45 +02001020nc_tls_import_privkey_file_wrap(const char *key_path)
roman163f1662024-04-04 09:26:42 +02001021{
1022 EVP_PKEY *pkey;
roman7ef57992024-04-23 15:08:45 +02001023 FILE *file;
1024
1025 file = fopen(key_path, "r");
1026 if (!file) {
1027 ERR(NULL, "Opening the private key file \"%s\" failed.", key_path);
1028 return NULL;
1029 }
roman163f1662024-04-04 09:26:42 +02001030
1031 pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
roman7ef57992024-04-23 15:08:45 +02001032 fclose(file);
roman163f1662024-04-04 09:26:42 +02001033 if (!pkey) {
1034 ERR(NULL, "Parsing the private key file \"%s\" failed (%s).", key_path, ERR_reason_error_string(ERR_get_error()));
1035 }
1036
1037 return pkey;
1038}
1039
1040void *
1041nc_tls_import_cert_file_wrap(const char *cert_path)
1042{
1043 X509 *cert;
1044 FILE *file;
1045
1046 file = fopen(cert_path, "r");
1047 if (!file) {
1048 ERR(NULL, "Opening the certificate file \"%s\" failed.", cert_path);
1049 return NULL;
1050 }
1051
1052 cert = PEM_read_X509(file, NULL, NULL, NULL);
1053 fclose(file);
1054 if (!cert) {
1055 ERR(NULL, "Parsing the certificate file \"%s\" failed (%s).", cert_path, ERR_reason_error_string(ERR_get_error()));
1056 }
1057 return cert;
1058}
1059
1060char *
roman7ef57992024-04-23 15:08:45 +02001061nc_tls_export_privkey_pem_wrap(void *pkey)
roman163f1662024-04-04 09:26:42 +02001062{
1063 BIO *bio = NULL;
1064 char *pem = NULL;
1065
1066 bio = BIO_new(BIO_s_mem());
1067 if (!bio) {
1068 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1069 goto cleanup;
1070 }
1071
1072 if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) {
1073 ERR(NULL, "Exporting the private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1074 goto cleanup;
1075 }
1076
1077 pem = malloc(BIO_number_written(bio) + 1);
1078 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1079
1080 BIO_read(bio, pem, BIO_number_written(bio));
1081 pem[BIO_number_written(bio)] = '\0';
1082
1083cleanup:
1084 BIO_free(bio);
1085 return pem;
1086}
1087
1088char *
roman7ef57992024-04-23 15:08:45 +02001089nc_tls_export_cert_pem_wrap(void *cert)
roman163f1662024-04-04 09:26:42 +02001090{
roman163f1662024-04-04 09:26:42 +02001091 BIO *bio = NULL;
1092 char *pem = NULL;
1093
1094 bio = BIO_new(BIO_s_mem());
1095 if (!bio) {
1096 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1097 goto cleanup;
1098 }
1099
roman7ef57992024-04-23 15:08:45 +02001100 if (!PEM_write_bio_X509(bio, cert)) {
roman163f1662024-04-04 09:26:42 +02001101 ERR(NULL, "Exporting the certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
1102 goto cleanup;
1103 }
1104
roman7ef57992024-04-23 15:08:45 +02001105 pem = malloc(BIO_number_written(bio) + 1);
roman163f1662024-04-04 09:26:42 +02001106 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1107
roman7ef57992024-04-23 15:08:45 +02001108 BIO_read(bio, pem, BIO_number_written(bio));
1109 pem[BIO_number_written(bio)] = '\0';
roman163f1662024-04-04 09:26:42 +02001110
1111cleanup:
1112 BIO_free(bio);
1113 return pem;
1114}
1115
1116char *
roman7ef57992024-04-23 15:08:45 +02001117nc_tls_export_pubkey_pem_wrap(void *pkey)
roman163f1662024-04-04 09:26:42 +02001118{
1119 BIO *bio = NULL;
1120 char *pem = NULL;
1121
1122 bio = BIO_new(BIO_s_mem());
1123 if (!bio) {
1124 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1125 goto cleanup;
1126 }
1127
1128 if (!PEM_write_bio_PUBKEY(bio, pkey)) {
1129 ERR(NULL, "Exporting the public key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1130 goto cleanup;
1131 }
1132
1133 pem = malloc(BIO_number_written(bio) + 1);
1134 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1135
1136 BIO_read(bio, pem, BIO_number_written(bio));
1137 pem[BIO_number_written(bio)] = '\0';
1138
1139cleanup:
1140 BIO_free(bio);
1141 return pem;
1142}
1143
1144int
roman163f1662024-04-04 09:26:42 +02001145nc_tls_privkey_is_rsa_wrap(void *pkey)
1146{
1147 return EVP_PKEY_is_a(pkey, "RSA");
1148}
1149
1150int
1151nc_tls_get_rsa_pubkey_params_wrap(void *pkey, void **e, void **n)
1152{
roman7ef57992024-04-23 15:08:45 +02001153 BIGNUM *exp = NULL, *mod = NULL;
roman163f1662024-04-04 09:26:42 +02001154
1155 if (!EVP_PKEY_get_bn_param(pkey, "e", &exp)) {
1156 ERR(NULL, "Getting the RSA public exponent failed (%s).", ERR_reason_error_string(ERR_get_error()));
1157 return 1;
1158 }
1159
1160 if (!EVP_PKEY_get_bn_param(pkey, "n", &mod)) {
1161 ERR(NULL, "Getting the RSA modulus failed (%s).", ERR_reason_error_string(ERR_get_error()));
1162 BN_free(exp);
1163 return 1;
1164 }
1165
1166 *e = exp;
1167 *n = mod;
1168 return 0;
1169}
1170
roman7ef57992024-04-23 15:08:45 +02001171void
1172nc_tls_destroy_mpi_wrap(void *mpi)
1173{
1174 BN_free(mpi);
1175}
1176
roman163f1662024-04-04 09:26:42 +02001177int
1178nc_tls_privkey_is_ec_wrap(void *pkey)
1179{
1180 return EVP_PKEY_is_a(pkey, "EC");
1181}
1182
1183char *
1184nc_tls_get_ec_group_wrap(void *pkey)
1185{
1186 size_t ec_group_len = 0;
1187 char *ec_group = NULL;
1188
1189 if (!EVP_PKEY_get_utf8_string_param(pkey, "group", NULL, 0, &ec_group_len)) {
1190 ERR(NULL, "Getting EC group length failed (%s).", ERR_reason_error_string(ERR_get_error()));
1191 return NULL;
1192 }
1193
1194 /* alloc mem for group + 1 for \0 */
1195 ec_group = malloc(ec_group_len + 1);
1196 NC_CHECK_ERRMEM_RET(!ec_group, NULL);
1197
1198 /* get the group */
1199 if (!EVP_PKEY_get_utf8_string_param(pkey, "group", ec_group, ec_group_len + 1, NULL)) {
1200 ERR(NULL, "Getting EC group failed (%s).", ERR_reason_error_string(ERR_get_error()));
1201 free(ec_group);
1202 return NULL;
1203 }
1204
1205 return ec_group;
1206}
1207
1208int
roman7ef57992024-04-23 15:08:45 +02001209nc_tls_get_ec_pubkey_params_wrap(void *pkey, void **q, void **UNUSED(q_grp))
roman163f1662024-04-04 09:26:42 +02001210{
roman7ef57992024-04-23 15:08:45 +02001211 BIGNUM *p = NULL;
roman163f1662024-04-04 09:26:42 +02001212
1213 if (!EVP_PKEY_get_bn_param(pkey, "p", &p)) {
1214 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 +02001215 return 1;
roman163f1662024-04-04 09:26:42 +02001216 }
1217
roman7ef57992024-04-23 15:08:45 +02001218 *q = p;
roman163f1662024-04-04 09:26:42 +02001219
roman7ef57992024-04-23 15:08:45 +02001220 return 0;
roman163f1662024-04-04 09:26:42 +02001221}
1222
1223int
roman7ef57992024-04-23 15:08:45 +02001224nc_tls_ec_point_to_bin_wrap(void *q, void *UNUSED(q_grp), unsigned char **bin, int *bin_len)
roman163f1662024-04-04 09:26:42 +02001225{
roman7ef57992024-04-23 15:08:45 +02001226 /* prepare buffer for converting p to binary */
1227 *bin = malloc(BN_num_bytes(q));
1228 NC_CHECK_ERRMEM_RET(!*bin, 1);
1229
1230 /* convert to binary */
1231 *bin_len = BN_bn2bin(q, *bin);
1232 return 0;
roman163f1662024-04-04 09:26:42 +02001233}
1234
1235void
roman7ef57992024-04-23 15:08:45 +02001236nc_tls_ec_point_destroy_wrap(void *p)
roman163f1662024-04-04 09:26:42 +02001237{
roman7ef57992024-04-23 15:08:45 +02001238 BN_free(p);
1239}
1240
1241void
1242nc_tls_ec_group_destroy_wrap(void *UNUSED(grp))
1243{
1244 return;
1245}
1246
1247int
1248nc_tls_mpi2bin_wrap(void *mpi, unsigned char **bin, int *bin_len)
1249{
1250 /* prepare buffer for converting mpi to binary */
1251 *bin = malloc(BN_num_bytes(mpi));
1252 NC_CHECK_ERRMEM_RET(!*bin, 1);
1253
1254 /* convert to binary */
1255 *bin_len = BN_bn2bin(mpi, *bin);
1256 return 0;
roman163f1662024-04-04 09:26:42 +02001257}
1258
1259void *
1260nc_tls_import_pubkey_file_wrap(const char *pubkey_path)
1261{
1262 FILE *f;
1263 EVP_PKEY *pk = NULL;
1264
1265 f = fopen(pubkey_path, "r");
1266 if (!f) {
1267 ERR(NULL, "Unable to open file \"%s\".", pubkey_path);
1268 return NULL;
1269 }
1270
1271 /* read the pubkey from file */
1272 pk = PEM_read_PUBKEY(f, NULL, NULL, NULL);
1273 fclose(f);
1274 if (!pk) {
1275 ERR(NULL, "Reading public key from file \"%s\" failed (%s).", pubkey_path, ERR_reason_error_string(ERR_get_error()));
1276 return NULL;
1277 }
1278
1279 return pk;
1280}
roman275c3fb2024-04-05 12:29:11 +02001281
1282int
roman15fbc592024-07-02 16:01:23 +02001283nc_server_tls_get_crl_distpoint_uris_wrap(void *leaf_cert, void *cert_store, char ***uris, int *uri_count)
roman275c3fb2024-04-05 12:29:11 +02001284{
1285 int ret = 0, i, j, k, gtype;
roman275c3fb2024-04-05 12:29:11 +02001286
1287 STACK_OF(X509_OBJECT) * objs;
1288 X509_OBJECT *obj;
1289 X509 *cert;
1290
1291 STACK_OF(DIST_POINT) * dist_points;
1292 DIST_POINT *dist_point;
1293 GENERAL_NAMES *general_names;
1294 GENERAL_NAME *general_name;
1295 ASN1_STRING *asn_string_uri;
roman275c3fb2024-04-05 12:29:11 +02001296 void *tmp;
1297
1298 NC_CHECK_ARG_RET(NULL, cert_store, uris, uri_count, 1);
1299
roman275c3fb2024-04-05 12:29:11 +02001300 /* treat all entries in the cert_store as X509_OBJECTs */
1301 objs = X509_STORE_get0_objects(cert_store);
1302 if (!objs) {
1303 ERR(NULL, "Getting certificates from store failed (%s).", ERR_reason_error_string(ERR_get_error()));
1304 ret = -1;
1305 goto cleanup;
1306 }
1307
1308 /* iterate over all the CAs */
roman15fbc592024-07-02 16:01:23 +02001309 for (i = -1; i < sk_X509_OBJECT_num(objs); i++) {
1310 if (i == -1) {
1311 cert = leaf_cert;
1312 } else {
1313 obj = sk_X509_OBJECT_value(objs, i);
1314 cert = X509_OBJECT_get0_X509(obj);
1315 }
1316
roman275c3fb2024-04-05 12:29:11 +02001317 if (!cert) {
1318 /* the object on this index was not a certificate */
1319 continue;
1320 }
1321
1322 /* get all the distribution points for this CA */
1323 dist_points = X509_get_ext_d2i(cert, NID_crl_distribution_points, NULL, NULL);
1324
1325 /* iterate over all the dist points (there can be multiple for a single cert) */
1326 for (j = 0; j < sk_DIST_POINT_num(dist_points); j++) {
1327 dist_point = sk_DIST_POINT_value(dist_points, j);
1328 if (!dist_point) {
1329 continue;
1330 }
1331 general_names = dist_point->distpoint->name.fullname;
1332
1333 /* iterate over all the GeneralesNames in the distribution point */
1334 for (k = 0; k < sk_GENERAL_NAME_num(general_names); k++) {
1335 general_name = sk_GENERAL_NAME_value(general_names, k);
1336 asn_string_uri = GENERAL_NAME_get0_value(general_name, &gtype);
1337
1338 /* check if the general name is a URI and has a valid length */
1339 if ((gtype != GEN_URI) || (ASN1_STRING_length(asn_string_uri) <= 6)) {
1340 continue;
1341 }
1342
1343 /* found an URI */
1344 tmp = realloc(*uris, (*uri_count + 1) * sizeof **uris);
1345 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
1346 *uris = tmp;
1347
roman15fbc592024-07-02 16:01:23 +02001348 (*uris)[*uri_count] = strdup((const char *) ASN1_STRING_get0_data(asn_string_uri));
1349 NC_CHECK_ERRMEM_GOTO(!(*uris)[*uri_count], ret = 1, cleanup);
roman275c3fb2024-04-05 12:29:11 +02001350 ++(*uri_count);
1351 }
1352 }
1353 }
1354
1355cleanup:
1356 return ret;
1357}
roman7ef57992024-04-23 15:08:45 +02001358
1359int
1360nc_tls_process_cipher_suite_wrap(const char *cipher, char **out)
1361{
1362 int i;
1363
1364 *out = malloc(strlen(cipher) + 1);
1365 NC_CHECK_ERRMEM_RET(!*out, 1);
1366
1367 /* convert to uppercase */
1368 for (i = 0; cipher[i]; i++) {
1369 if (cipher[i] == '-') {
1370 /* OpenSSL requires _ instead of - in cipher names */
1371 (*out)[i] = '_';
1372 } else {
1373 (*out)[i] = toupper(cipher[i]);
1374 }
1375 }
1376
1377 (*out)[i] = '\0';
1378 return 0;
1379}
1380
1381int
1382nc_tls_append_cipher_suite_wrap(struct nc_server_tls_opts *opts, const char *cipher_suite)
1383{
1384 if (!opts->ciphers) {
1385 /* first entry */
1386 opts->ciphers = strdup(cipher_suite);
1387 NC_CHECK_ERRMEM_RET(!opts->ciphers, 1);
1388 } else {
1389 /* + 1 because of : between entries */
1390 opts->ciphers = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(cipher_suite) + 1 + 1);
1391 NC_CHECK_ERRMEM_RET(!opts->ciphers, 1);
1392 strcat(opts->ciphers, ":");
1393 strcat(opts->ciphers, cipher_suite);
1394 }
1395
1396 return 0;
1397}
1398
1399void
1400nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, void *cipher_suites)
1401{
1402 /* set for TLS1.2 and lower */
1403 SSL_CTX_set_cipher_list(tls_cfg, cipher_suites);
1404 /* set for TLS1.3 */
1405 SSL_CTX_set_ciphersuites(tls_cfg, cipher_suites);
1406}