blob: 3891dc7becade73e4d32b0ffe62ded9ab47dad91 [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
327static int
328nc_server_tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
329{
330 int ret = 0, depth, err;
331 struct nc_tls_verify_cb_data *data;
332 SSL *ssl;
roman7ef57992024-04-23 15:08:45 +0200333 SSL_CTX *ctx;
roman163f1662024-04-04 09:26:42 +0200334 X509 *cert;
335
roman7ffd2fc2024-05-13 13:48:34 +0200336 /* retrieve callback data stored inside the SSL_CTX struct */
roman163f1662024-04-04 09:26:42 +0200337 ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
roman7ffd2fc2024-05-13 13:48:34 +0200338 if (!ssl) {
339 ERRINT;
340 return 0;
341 }
roman7ef57992024-04-23 15:08:45 +0200342 ctx = SSL_get_SSL_CTX(ssl);
roman7ffd2fc2024-05-13 13:48:34 +0200343 if (!ctx) {
344 ERRINT;
345 return 0;
346 }
roman7ef57992024-04-23 15:08:45 +0200347 data = SSL_CTX_get_ex_data(ctx, 0);
roman163f1662024-04-04 09:26:42 +0200348
349 /* get current cert and its depth */
350 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
351 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
352
353 if (preverify_ok) {
354 /* in-built verification was successful */
roman7ffd2fc2024-05-13 13:48:34 +0200355 ret = nc_server_tls_verify_cert(cert, depth, 1, data);
roman163f1662024-04-04 09:26:42 +0200356 } else {
357 /* in-built verification failed, but the client still may be authenticated if:
358 * 1) the peer cert matches any configured end-entity cert
359 * 2) the peer cert has a valid chain of trust to any configured certificate authority cert
360 * otherwise just continue until we reach the peer cert (depth = 0)
361 */
362 err = X509_STORE_CTX_get_error(x509_ctx);
roman7ffd2fc2024-05-13 13:48:34 +0200363 if ((depth == 0) && ((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) || (err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))) {
364 /* not trusted (possibly self-signed) peer certificate, case 1) */
365 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
roman163f1662024-04-04 09:26:42 +0200366 } else if ((err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) || (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)) {
367 /* full chain of trust is invalid, but it may be valid partially, case 2) */
368 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
roman7ef57992024-04-23 15:08:45 +0200369 } else if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) {
370 /* self-signed certificate in the chain, check if peer cert complies with 1) in order to continue,
371 * if yes, this callback will be called again with the same cert, but with preverify_ok = 1
372 */
373 cert = X509_STORE_CTX_get0_cert(x509_ctx);
374 ret = nc_server_tls_verify_peer_cert(cert, data->opts);
375 if (ret) {
376 VRB(NULL, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
377 ret = -1;
roman7ef57992024-04-23 15:08:45 +0200378 }
roman163f1662024-04-04 09:26:42 +0200379 } else {
380 VRB(NULL, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
381 ret = 1;
382 }
383 }
384
385 if (ret == -1) {
386 /* fatal error */
387 return 0;
388 } else if (!ret) {
389 /* success */
390 return 1;
391 } else {
392 if (depth > 0) {
393 /* chain verify failed */
394 return 1;
395 } else {
396 /* peer cert did not match */
397 return 0;
398 }
399 }
400}
401
402void
roman7ef57992024-04-23 15:08:45 +0200403nc_server_tls_set_verify_wrap(void *tls_cfg, struct nc_tls_verify_cb_data *cb_data)
roman163f1662024-04-04 09:26:42 +0200404{
roman7ef57992024-04-23 15:08:45 +0200405 /* set verify cb and its data */
406 SSL_CTX_set_ex_data(tls_cfg, 0, cb_data);
407 SSL_CTX_set_verify(tls_cfg, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_server_tls_verify_cb);
408}
409
410void
411nc_client_tls_set_verify_wrap(void *tls_cfg)
412{
413 SSL_CTX_set_verify(tls_cfg, SSL_VERIFY_PEER, NULL);
roman163f1662024-04-04 09:26:42 +0200414}
415
416char *
417nc_server_tls_get_subject_wrap(void *cert)
418{
419 return X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
420}
421
422char *
423nc_server_tls_get_issuer_wrap(void *cert)
424{
425 return X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
426}
427
roman7ef57992024-04-23 15:08:45 +0200428void *
429nc_tls_get_sans_wrap(void *cert)
roman163f1662024-04-04 09:26:42 +0200430{
roman7ef57992024-04-23 15:08:45 +0200431 return X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
432}
433
434void
435nc_tls_sans_destroy_wrap(void *sans)
436{
437 sk_GENERAL_NAME_pop_free(sans, GENERAL_NAME_free);
438}
439
440int
441nc_tls_get_num_sans_wrap(void *sans)
442{
443 return sk_GENERAL_NAME_num(sans);
444}
445
446int
447nc_tls_get_san_value_type_wrap(void *sans, int idx, char **san_value, NC_TLS_CTN_MAPTYPE *san_type)
448{
449 int ret = 0;
450 GENERAL_NAME *san;
roman163f1662024-04-04 09:26:42 +0200451 ASN1_OCTET_STRING *ip;
roman163f1662024-04-04 09:26:42 +0200452
roman7ef57992024-04-23 15:08:45 +0200453 *san_value = NULL;
454 *san_type = NC_TLS_CTN_UNKNOWN;
roman163f1662024-04-04 09:26:42 +0200455
roman7ef57992024-04-23 15:08:45 +0200456 /* find the san */
457 san = sk_GENERAL_NAME_value(sans, idx);
458 if (!san) {
459 return -1;
roman163f1662024-04-04 09:26:42 +0200460 }
461
roman7ef57992024-04-23 15:08:45 +0200462 /* get its type and value */
463 switch (san->type) {
464 case GEN_EMAIL:
465 *san_type = NC_TLS_CTN_SAN_RFC822_NAME;
466 *san_value = strdup((char *)ASN1_STRING_get0_data(san->d.rfc822Name));
467 NC_CHECK_ERRMEM_RET(!*san_value, -1);
468 break;
469 case GEN_DNS:
470 *san_type = NC_TLS_CTN_SAN_DNS_NAME;
471 *san_value = strdup((char *)ASN1_STRING_get0_data(san->d.dNSName));
472 NC_CHECK_ERRMEM_RET(!*san_value, -1);
473 break;
474 case GEN_IPADD:
475 *san_type = NC_TLS_CTN_SAN_IP_ADDRESS;
476 ip = san->d.iPAddress;
477 if (ip->length == 4) {
478 if (asprintf(san_value, "%d.%d.%d.%d", ip->data[0], ip->data[1], ip->data[2], ip->data[3]) == -1) {
479 ERRMEM;
480 *san_value = NULL;
481 ret = -1;
482 }
483 } else if (ip->length == 16) {
484 if (asprintf(san_value, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
485 ip->data[0], ip->data[1], ip->data[2], ip->data[3], ip->data[4], ip->data[5],
486 ip->data[6], ip->data[7], ip->data[8], ip->data[9], ip->data[10], ip->data[11],
487 ip->data[12], ip->data[13], ip->data[14], ip->data[15]) == -1) {
488 ERRMEM;
489 *san_value = NULL;
490 ret = -1;
491 }
492 } else {
493 WRN(NULL, "SAN IP address in an unknown format (length is %d).", ip->length);
494 ret = 1;
495 }
496 break;
497 default:
498 /* we dont care about other types */
499 *san_type = NC_TLS_CTN_UNKNOWN;
500 ret = 1;
501 break;
502 }
503
504 return ret;
roman163f1662024-04-04 09:26:42 +0200505}
506
507int
508nc_server_tls_certs_match_wrap(void *cert1, void *cert2)
509{
510 return !X509_cmp(cert1, cert2);
511}
512
513int
514nc_server_tls_md5_wrap(void *cert, unsigned char *buf)
515{
516 int rc;
517
518 rc = X509_digest(cert, EVP_md5(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200519 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200520 ERR(NULL, "Calculating MD-5 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
521 return 1;
522 }
523
524 return 0;
525}
526
527int
528nc_server_tls_sha1_wrap(void *cert, unsigned char *buf)
529{
530 int rc;
531
532 rc = X509_digest(cert, EVP_sha1(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200533 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200534 ERR(NULL, "Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
535 return 1;
536 }
537
538 return 0;
539}
540
541int
542nc_server_tls_sha224_wrap(void *cert, unsigned char *buf)
543{
544 int rc;
545
546 rc = X509_digest(cert, EVP_sha224(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200547 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200548 ERR(NULL, "Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
549 return 1;
550 }
551
552 return 0;
553}
554
555int
556nc_server_tls_sha256_wrap(void *cert, unsigned char *buf)
557{
558 int rc;
559
560 rc = X509_digest(cert, EVP_sha256(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200561 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200562 ERR(NULL, "Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
563 return 1;
564 }
565
566 return 0;
567}
568
569int
570nc_server_tls_sha384_wrap(void *cert, unsigned char *buf)
571{
572 int rc;
573
574 rc = X509_digest(cert, EVP_sha384(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200575 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200576 ERR(NULL, "Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
577 return 1;
578 }
579
580 return 0;
581}
582
583int
584nc_server_tls_sha512_wrap(void *cert, unsigned char *buf)
585{
586 int rc;
587
588 rc = X509_digest(cert, EVP_sha512(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200589 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200590 ERR(NULL, "Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
591 return 1;
592 }
593
594 return 0;
595}
596
597void
598nc_server_tls_set_fd_wrap(void *tls_session, int sock, struct nc_tls_ctx *UNUSED(tls_ctx))
599{
600 SSL_set_fd(tls_session, sock);
601}
602
603int
604nc_server_tls_handshake_step_wrap(void *tls_session)
605{
606 int ret = 0;
607
608 ret = SSL_accept(tls_session);
609 if (ret == 1) {
610 return 1;
611 } else if (ret == -1) {
612 if ((SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_READ) || (SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_WRITE)) {
613 return 0;
614 }
615 }
616
617 return -1;
618}
619
620int
roman7ef57992024-04-23 15:08:45 +0200621nc_client_tls_handshake_step_wrap(void *tls_session, int UNUSED(sock))
roman163f1662024-04-04 09:26:42 +0200622{
623 int ret = 0;
624
625 ret = SSL_connect(tls_session);
626 if (ret == 1) {
627 return 1;
628 } else if (ret == -1) {
629 if ((SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_READ) || (SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_WRITE)) {
630 return 0;
631 }
632 }
633
634 return -1;
635}
636
637void
638nc_tls_ctx_destroy_wrap(struct nc_tls_ctx *UNUSED(tls_ctx))
639{
640 return;
641}
642
643int
644nc_client_tls_load_cert_key_wrap(const char *cert_path, const char *key_path, void **cert, void **pkey)
645{
646 BIO *bio;
647 X509 *cert_tmp;
648 EVP_PKEY *pkey_tmp;
649
roman7ef57992024-04-23 15:08:45 +0200650 NC_CHECK_ARG_RET(NULL, cert_path, key_path, cert, pkey, 1);
651
roman163f1662024-04-04 09:26:42 +0200652 bio = BIO_new_file(cert_path, "r");
653 if (!bio) {
654 ERR(NULL, "Opening the client certificate file \"%s\" failed.", cert_path);
655 return 1;
656 }
657
658 cert_tmp = PEM_read_bio_X509(bio, NULL, NULL, NULL);
659 BIO_free(bio);
660 if (!cert_tmp) {
661 ERR(NULL, "Parsing the client certificate file \"%s\" failed.", cert_path);
662 return 1;
663 }
664
665 bio = BIO_new_file(key_path, "r");
666 if (!bio) {
667 ERR(NULL, "Opening the client private key file \"%s\" failed.", key_path);
668 X509_free(cert_tmp);
669 return 1;
670 }
671
672 pkey_tmp = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
673 BIO_free(bio);
674 if (!pkey_tmp) {
675 ERR(NULL, "Parsing the client private key file \"%s\" failed.", key_path);
676 X509_free(cert_tmp);
677 return 1;
678 }
679
680 *cert = cert_tmp;
681 *pkey = pkey_tmp;
682
683 return 0;
684}
685
686int
687nc_client_tls_load_trusted_certs_wrap(void *cert_store, const char *file_path, const char *dir_path)
688{
689 if (!X509_STORE_load_locations(cert_store, file_path, dir_path)) {
roman7ffd2fc2024-05-13 13:48:34 +0200690 ERR(NULL, "Loading CA certs from file \"%s\" or directory \"%s\" failed (%s).",
691 file_path, dir_path, ERR_reason_error_string(ERR_get_error()));
roman163f1662024-04-04 09:26:42 +0200692 return 1;
693 }
694
695 return 0;
696}
697
698int
roman7ef57992024-04-23 15:08:45 +0200699nc_client_tls_load_crl_wrap(void *crl_store, const char *file_path, const char *dir_path)
roman163f1662024-04-04 09:26:42 +0200700{
roman7ef57992024-04-23 15:08:45 +0200701 if (!X509_STORE_load_locations(crl_store, file_path, dir_path)) {
roman7ffd2fc2024-05-13 13:48:34 +0200702 ERR(NULL, "Loading CRLs 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
711nc_client_tls_set_hostname_wrap(void *tls_session, const char *hostname)
712{
713 int ret = 0;
714 X509_VERIFY_PARAM *vpm = NULL;
715
716 vpm = X509_VERIFY_PARAM_new();
717 NC_CHECK_ERRMEM_RET(!vpm, 1);
718
719 if (!X509_VERIFY_PARAM_set1_host(vpm, hostname, 0)) {
720 ERR(NULL, "Failed to set expected hostname (%s).", ERR_reason_error_string(ERR_get_error()));
721 ret = 1;
722 goto cleanup;
723 }
roman7ef57992024-04-23 15:08:45 +0200724 if (!SSL_set1_param(tls_session, vpm)) {
roman163f1662024-04-04 09:26:42 +0200725 ERR(NULL, "Failed to set verify param (%s).", ERR_reason_error_string(ERR_get_error()));
726 ret = 1;
727 goto cleanup;
728 }
729
730cleanup:
731 X509_VERIFY_PARAM_free(vpm);
732 return ret;
733}
734
roman7ef57992024-04-23 15:08:45 +0200735int
736nc_tls_init_ctx_wrap(int UNUSED(sock), void *cert, void *pkey, void *cert_store, void *crl_store, struct nc_tls_ctx *tls_ctx)
737{
738 tls_ctx->cert = cert;
739 tls_ctx->pkey = pkey;
740 tls_ctx->cert_store = cert_store;
741 tls_ctx->crl_store = crl_store;
742 return 0;
743}
744
745static int
746nc_tls_move_crls_to_store(const X509_STORE *src, X509_STORE *dst)
747{
748 int i, nobjs = 0;
749
750 STACK_OF(X509_OBJECT) * objs;
751 X509_OBJECT *obj;
752 X509_CRL *crl;
753
754 objs = X509_STORE_get0_objects(src);
755 nobjs = sk_X509_OBJECT_num(objs);
756 for (i = 0; i < nobjs; i++) {
757 obj = sk_X509_OBJECT_value(objs, i);
758 crl = X509_OBJECT_get0_X509_CRL(obj);
759 if (!crl) {
760 /* not a CRL */
761 continue;
762 }
763 if (!X509_STORE_add_crl(dst, crl)) {
764 ERR(NULL, "Adding CRL to the store failed (%s).", ERR_reason_error_string(ERR_get_error()));
765 return 1;
766 }
767 }
768
769 return 0;
770}
771
772int
roman7ffd2fc2024-05-13 13:48:34 +0200773nc_tls_setup_config_from_ctx_wrap(struct nc_tls_ctx *tls_ctx, int side, void *tls_cfg)
roman7ef57992024-04-23 15:08:45 +0200774{
775 if (SSL_CTX_use_certificate(tls_cfg, tls_ctx->cert) != 1) {
776 return 1;
777 }
778
779 if (SSL_CTX_use_PrivateKey(tls_cfg, tls_ctx->pkey) != 1) {
780 return 1;
781 }
782
roman7ffd2fc2024-05-13 13:48:34 +0200783 /* disable server-side automatic chain building */
784 if (side == NC_SERVER) {
785 SSL_CTX_set_mode(tls_cfg, SSL_MODE_NO_AUTO_CHAIN);
786 }
roman7ef57992024-04-23 15:08:45 +0200787
788 if (tls_ctx->crl_store) {
789 /* move CRLs from crl_store to cert_store, because SSL_CTX can only have one store */
790 if (nc_tls_move_crls_to_store(tls_ctx->crl_store, tls_ctx->cert_store)) {
791 return 1;
792 }
793
794 /* enable CRL checks */
795 X509_STORE_set_flags(tls_ctx->cert_store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
796 }
797
798 SSL_CTX_set_cert_store(tls_cfg, tls_ctx->cert_store);
799
800 X509_free(tls_ctx->cert);
801 tls_ctx->cert = NULL;
802 EVP_PKEY_free(tls_ctx->pkey);
803 tls_ctx->pkey = NULL;
804 X509_STORE_free(tls_ctx->crl_store);
805 tls_ctx->crl_store = NULL;
806
807 return 0;
808}
809
roman163f1662024-04-04 09:26:42 +0200810uint32_t
811nc_tls_get_verify_result_wrap(void *tls_session)
812{
813 return SSL_get_verify_result(tls_session);
814}
815
roman7ef57992024-04-23 15:08:45 +0200816char *
roman163f1662024-04-04 09:26:42 +0200817nc_tls_verify_error_string_wrap(uint32_t err_code)
818{
roman7ef57992024-04-23 15:08:45 +0200819 return strdup(X509_verify_cert_error_string(err_code));
roman163f1662024-04-04 09:26:42 +0200820}
821
822void
roman7ef57992024-04-23 15:08:45 +0200823nc_client_tls_print_connect_err_wrap(int connect_ret, const char *peername, void *tls_session)
roman163f1662024-04-04 09:26:42 +0200824{
825 switch (SSL_get_error(tls_session, connect_ret)) {
826 case SSL_ERROR_SYSCALL:
827 ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, errno ? strerror(errno) : "unexpected EOF");
828 break;
829 case SSL_ERROR_SSL:
830 ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, ERR_reason_error_string(ERR_get_error()));
831 break;
832 default:
833 ERR(NULL, "TLS connection to \"%s\" failed.", peername);
834 break;
835 }
836}
837
838void
roman7ef57992024-04-23 15:08:45 +0200839nc_server_tls_print_accept_err_wrap(int accept_ret, void *tls_session)
roman163f1662024-04-04 09:26:42 +0200840{
841 switch (SSL_get_error(tls_session, accept_ret)) {
842 case SSL_ERROR_SYSCALL:
843 ERR(NULL, "TLS accept failed (%s).", strerror(errno));
844 break;
845 case SSL_ERROR_SSL:
846 ERR(NULL, "TLS accept failed (%s).", ERR_reason_error_string(ERR_get_error()));
847 break;
848 default:
849 ERR(NULL, "TLS accept failed.");
850 break;
851 }
852}
853
854int
roman7ef57992024-04-23 15:08:45 +0200855nc_tls_is_der_subpubkey_wrap(unsigned char *der, long len)
roman163f1662024-04-04 09:26:42 +0200856{
857 int ret;
858 EVP_PKEY *pkey;
859
roman7ef57992024-04-23 15:08:45 +0200860 pkey = d2i_PUBKEY(NULL, (const unsigned char **)&der, len);
roman163f1662024-04-04 09:26:42 +0200861 if (pkey) {
862 /* success */
roman7ef57992024-04-23 15:08:45 +0200863 ret = 1;
roman163f1662024-04-04 09:26:42 +0200864 } else {
865 /* fail */
roman7ef57992024-04-23 15:08:45 +0200866 ret = 0;
roman163f1662024-04-04 09:26:42 +0200867 }
868
869 EVP_PKEY_free(pkey);
870 return ret;
871}
872
873int
roman7ef57992024-04-23 15:08:45 +0200874nc_base64_decode_wrap(const char *base64, unsigned char **bin)
roman163f1662024-04-04 09:26:42 +0200875{
roman7ef57992024-04-23 15:08:45 +0200876 int ret;
roman163f1662024-04-04 09:26:42 +0200877
roman7ef57992024-04-23 15:08:45 +0200878 *bin = malloc((strlen(base64) / 4) * 3);
879 NC_CHECK_ERRMEM_RET(!*bin, -1);
roman163f1662024-04-04 09:26:42 +0200880
roman7ef57992024-04-23 15:08:45 +0200881 ret = EVP_DecodeBlock(*bin, (const unsigned char *)base64, strlen(base64));
882 if (ret == -1) {
883 ERR(NULL, "Base64 decoding failed (%s).", ERR_reason_error_string(ERR_get_error()));
884 free(*bin);
885 *bin = NULL;
roman163f1662024-04-04 09:26:42 +0200886 }
roman163f1662024-04-04 09:26:42 +0200887 return ret;
888}
889
890int
891nc_base64_encode_wrap(const unsigned char *bin, size_t len, char **base64)
892{
roman7ef57992024-04-23 15:08:45 +0200893 int ret, size;
roman163f1662024-04-04 09:26:42 +0200894
roman7ef57992024-04-23 15:08:45 +0200895 /* calculate the size, for every 3B of in 4B of out, + padding if not divisible + null terminator */
896 if (len % 3) {
897 size = (len / 3) * 4 + 4 + 1;
898 } else {
899 size = (len / 3) * 4 + 1;
roman163f1662024-04-04 09:26:42 +0200900 }
901
roman7ef57992024-04-23 15:08:45 +0200902 *base64 = malloc(size);
903 NC_CHECK_ERRMEM_RET(!*base64, -1);
904
905 ret = EVP_EncodeBlock((unsigned char *)*base64, bin, len);
906 if (ret == -1) {
907 ERR(NULL, "Base64 encoding failed (%s).", ERR_reason_error_string(ERR_get_error()));
908 free(*base64);
909 *base64 = NULL;
910 return -1;
roman163f1662024-04-04 09:26:42 +0200911 }
912
roman7ef57992024-04-23 15:08:45 +0200913 return 0;
roman163f1662024-04-04 09:26:42 +0200914}
915
916static char *
roman7ef57992024-04-23 15:08:45 +0200917nc_tls_get_err_reasons(void)
roman163f1662024-04-04 09:26:42 +0200918{
919 unsigned int e;
920 int reason_size, reason_len;
921 char *reasons = NULL;
922
923 reason_size = 1;
924 reason_len = 0;
925 while ((e = ERR_get_error())) {
926 if (reason_len) {
927 /* add "; " */
928 reason_size += 2;
929 reasons = nc_realloc(reasons, reason_size);
930 NC_CHECK_ERRMEM_RET(!reasons, NULL);
931 reason_len += sprintf(reasons + reason_len, "; ");
932 }
933 reason_size += strlen(ERR_reason_error_string(e));
934 reasons = nc_realloc(reasons, reason_size);
935 NC_CHECK_ERRMEM_RET(!reasons, NULL);
936 reason_len += sprintf(reasons + reason_len, "%s", ERR_reason_error_string(e));
937 }
938
939 return reasons;
940}
941
942int
943nc_tls_read_wrap(struct nc_session *session, unsigned char *buf, size_t size)
944{
945 int rc, err;
946 char *reasons;
947 SSL *tls_session = session->ti.tls.session;
948
949 ERR_clear_error();
950 rc = SSL_read(tls_session, buf, size);
951 if (rc <= 0) {
952 err = SSL_get_error(tls_session, rc);
953 switch (err) {
954 case SSL_ERROR_WANT_READ:
955 case SSL_ERROR_WANT_WRITE:
956 rc = 0;
957 break;
958 case SSL_ERROR_ZERO_RETURN:
959 ERR(session, "Communication socket unexpectedly closed (OpenSSL).");
960 session->status = NC_STATUS_INVALID;
961 session->term_reason = NC_SESSION_TERM_DROPPED;
962 rc = -1;
963 break;
964 case SSL_ERROR_SYSCALL:
965 ERR(session, "TLS socket error (%s).", errno ? strerror(errno) : "unexpected EOF");
966 session->status = NC_STATUS_INVALID;
967 session->term_reason = NC_SESSION_TERM_OTHER;
968 rc = -1;
969 break;
970 case SSL_ERROR_SSL:
roman7ef57992024-04-23 15:08:45 +0200971 reasons = nc_tls_get_err_reasons();
roman163f1662024-04-04 09:26:42 +0200972 ERR(session, "TLS communication error (%s).", reasons);
973 free(reasons);
974 session->status = NC_STATUS_INVALID;
975 session->term_reason = NC_SESSION_TERM_OTHER;
976 rc = -1;
977 break;
978 default:
979 ERR(session, "Unknown TLS error occurred (err code %d).", err);
980 session->status = NC_STATUS_INVALID;
981 session->term_reason = NC_SESSION_TERM_OTHER;
982 rc = -1;
983 break;
984 }
985 }
986
987 return rc;
988}
989
990int
991nc_tls_write_wrap(struct nc_session *session, const unsigned char *buf, size_t size)
992{
993 int rc, err;
994 char *reasons;
995 SSL *tls_session = session->ti.tls.session;
996
997 ERR_clear_error();
998 rc = SSL_write(tls_session, buf, size);
999 if (rc < 1) {
1000 err = SSL_get_error(tls_session, rc);
1001 switch (err) {
1002 case SSL_ERROR_WANT_WRITE:
1003 case SSL_ERROR_WANT_READ:
1004 rc = 0;
1005 break;
1006 case SSL_ERROR_ZERO_RETURN:
1007 ERR(session, "TLS connection was properly closed.");
1008 rc = -1;
1009 break;
1010 case SSL_ERROR_SYSCALL:
1011 ERR(session, "TLS socket error (%s).", errno ? strerror(errno) : "unexpected EOF");
1012 rc = -1;
1013 break;
1014 case SSL_ERROR_SSL:
roman7ef57992024-04-23 15:08:45 +02001015 reasons = nc_tls_get_err_reasons();
roman163f1662024-04-04 09:26:42 +02001016 ERR(session, "TLS communication error (%s).", reasons);
1017 free(reasons);
1018 rc = -1;
1019 break;
1020 default:
1021 ERR(session, "Unknown TLS error occurred (err code %d).", err);
1022 rc = -1;
1023 break;
1024 }
1025 }
1026
1027 return rc;
1028}
1029
1030int
roman7ef57992024-04-23 15:08:45 +02001031nc_tls_get_num_pending_bytes_wrap(void *tls_session)
roman163f1662024-04-04 09:26:42 +02001032{
1033 return SSL_pending(tls_session);
1034}
1035
1036int
1037nc_tls_get_fd_wrap(const struct nc_session *session)
1038{
roman7ef57992024-04-23 15:08:45 +02001039 return session->ti.tls.session ? SSL_get_fd(session->ti.tls.session) : -1;
roman163f1662024-04-04 09:26:42 +02001040}
1041
1042void
1043nc_tls_close_notify_wrap(void *tls_session)
1044{
1045 SSL_shutdown(tls_session);
1046}
1047
1048void *
roman7ef57992024-04-23 15:08:45 +02001049nc_tls_import_privkey_file_wrap(const char *key_path)
roman163f1662024-04-04 09:26:42 +02001050{
1051 EVP_PKEY *pkey;
roman7ef57992024-04-23 15:08:45 +02001052 FILE *file;
1053
1054 file = fopen(key_path, "r");
1055 if (!file) {
1056 ERR(NULL, "Opening the private key file \"%s\" failed.", key_path);
1057 return NULL;
1058 }
roman163f1662024-04-04 09:26:42 +02001059
1060 pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
roman7ef57992024-04-23 15:08:45 +02001061 fclose(file);
roman163f1662024-04-04 09:26:42 +02001062 if (!pkey) {
1063 ERR(NULL, "Parsing the private key file \"%s\" failed (%s).", key_path, ERR_reason_error_string(ERR_get_error()));
1064 }
1065
1066 return pkey;
1067}
1068
1069void *
1070nc_tls_import_cert_file_wrap(const char *cert_path)
1071{
1072 X509 *cert;
1073 FILE *file;
1074
1075 file = fopen(cert_path, "r");
1076 if (!file) {
1077 ERR(NULL, "Opening the certificate file \"%s\" failed.", cert_path);
1078 return NULL;
1079 }
1080
1081 cert = PEM_read_X509(file, NULL, NULL, NULL);
1082 fclose(file);
1083 if (!cert) {
1084 ERR(NULL, "Parsing the certificate file \"%s\" failed (%s).", cert_path, ERR_reason_error_string(ERR_get_error()));
1085 }
1086 return cert;
1087}
1088
1089char *
roman7ef57992024-04-23 15:08:45 +02001090nc_tls_export_privkey_pem_wrap(void *pkey)
roman163f1662024-04-04 09:26:42 +02001091{
1092 BIO *bio = NULL;
1093 char *pem = NULL;
1094
1095 bio = BIO_new(BIO_s_mem());
1096 if (!bio) {
1097 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1098 goto cleanup;
1099 }
1100
1101 if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) {
1102 ERR(NULL, "Exporting the private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1103 goto cleanup;
1104 }
1105
1106 pem = malloc(BIO_number_written(bio) + 1);
1107 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1108
1109 BIO_read(bio, pem, BIO_number_written(bio));
1110 pem[BIO_number_written(bio)] = '\0';
1111
1112cleanup:
1113 BIO_free(bio);
1114 return pem;
1115}
1116
1117char *
roman7ef57992024-04-23 15:08:45 +02001118nc_tls_export_cert_pem_wrap(void *cert)
roman163f1662024-04-04 09:26:42 +02001119{
roman163f1662024-04-04 09:26:42 +02001120 BIO *bio = NULL;
1121 char *pem = NULL;
1122
1123 bio = BIO_new(BIO_s_mem());
1124 if (!bio) {
1125 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1126 goto cleanup;
1127 }
1128
roman7ef57992024-04-23 15:08:45 +02001129 if (!PEM_write_bio_X509(bio, cert)) {
roman163f1662024-04-04 09:26:42 +02001130 ERR(NULL, "Exporting the certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
1131 goto cleanup;
1132 }
1133
roman7ef57992024-04-23 15:08:45 +02001134 pem = malloc(BIO_number_written(bio) + 1);
roman163f1662024-04-04 09:26:42 +02001135 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1136
roman7ef57992024-04-23 15:08:45 +02001137 BIO_read(bio, pem, BIO_number_written(bio));
1138 pem[BIO_number_written(bio)] = '\0';
roman163f1662024-04-04 09:26:42 +02001139
1140cleanup:
1141 BIO_free(bio);
1142 return pem;
1143}
1144
1145char *
roman7ef57992024-04-23 15:08:45 +02001146nc_tls_export_pubkey_pem_wrap(void *pkey)
roman163f1662024-04-04 09:26:42 +02001147{
1148 BIO *bio = NULL;
1149 char *pem = NULL;
1150
1151 bio = BIO_new(BIO_s_mem());
1152 if (!bio) {
1153 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1154 goto cleanup;
1155 }
1156
1157 if (!PEM_write_bio_PUBKEY(bio, pkey)) {
1158 ERR(NULL, "Exporting the public key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1159 goto cleanup;
1160 }
1161
1162 pem = malloc(BIO_number_written(bio) + 1);
1163 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1164
1165 BIO_read(bio, pem, BIO_number_written(bio));
1166 pem[BIO_number_written(bio)] = '\0';
1167
1168cleanup:
1169 BIO_free(bio);
1170 return pem;
1171}
1172
1173int
roman163f1662024-04-04 09:26:42 +02001174nc_tls_privkey_is_rsa_wrap(void *pkey)
1175{
1176 return EVP_PKEY_is_a(pkey, "RSA");
1177}
1178
1179int
1180nc_tls_get_rsa_pubkey_params_wrap(void *pkey, void **e, void **n)
1181{
roman7ef57992024-04-23 15:08:45 +02001182 BIGNUM *exp = NULL, *mod = NULL;
roman163f1662024-04-04 09:26:42 +02001183
1184 if (!EVP_PKEY_get_bn_param(pkey, "e", &exp)) {
1185 ERR(NULL, "Getting the RSA public exponent failed (%s).", ERR_reason_error_string(ERR_get_error()));
1186 return 1;
1187 }
1188
1189 if (!EVP_PKEY_get_bn_param(pkey, "n", &mod)) {
1190 ERR(NULL, "Getting the RSA modulus failed (%s).", ERR_reason_error_string(ERR_get_error()));
1191 BN_free(exp);
1192 return 1;
1193 }
1194
1195 *e = exp;
1196 *n = mod;
1197 return 0;
1198}
1199
roman7ef57992024-04-23 15:08:45 +02001200void
1201nc_tls_destroy_mpi_wrap(void *mpi)
1202{
1203 BN_free(mpi);
1204}
1205
roman163f1662024-04-04 09:26:42 +02001206int
1207nc_tls_privkey_is_ec_wrap(void *pkey)
1208{
1209 return EVP_PKEY_is_a(pkey, "EC");
1210}
1211
1212char *
1213nc_tls_get_ec_group_wrap(void *pkey)
1214{
1215 size_t ec_group_len = 0;
1216 char *ec_group = NULL;
1217
1218 if (!EVP_PKEY_get_utf8_string_param(pkey, "group", NULL, 0, &ec_group_len)) {
1219 ERR(NULL, "Getting EC group length failed (%s).", ERR_reason_error_string(ERR_get_error()));
1220 return NULL;
1221 }
1222
1223 /* alloc mem for group + 1 for \0 */
1224 ec_group = malloc(ec_group_len + 1);
1225 NC_CHECK_ERRMEM_RET(!ec_group, NULL);
1226
1227 /* get the group */
1228 if (!EVP_PKEY_get_utf8_string_param(pkey, "group", ec_group, ec_group_len + 1, NULL)) {
1229 ERR(NULL, "Getting EC group failed (%s).", ERR_reason_error_string(ERR_get_error()));
1230 free(ec_group);
1231 return NULL;
1232 }
1233
1234 return ec_group;
1235}
1236
1237int
roman7ef57992024-04-23 15:08:45 +02001238nc_tls_get_ec_pubkey_params_wrap(void *pkey, void **q, void **UNUSED(q_grp))
roman163f1662024-04-04 09:26:42 +02001239{
roman7ef57992024-04-23 15:08:45 +02001240 BIGNUM *p = NULL;
roman163f1662024-04-04 09:26:42 +02001241
1242 if (!EVP_PKEY_get_bn_param(pkey, "p", &p)) {
1243 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 +02001244 return 1;
roman163f1662024-04-04 09:26:42 +02001245 }
1246
roman7ef57992024-04-23 15:08:45 +02001247 *q = p;
roman163f1662024-04-04 09:26:42 +02001248
roman7ef57992024-04-23 15:08:45 +02001249 return 0;
roman163f1662024-04-04 09:26:42 +02001250}
1251
1252int
roman7ef57992024-04-23 15:08:45 +02001253nc_tls_ec_point_to_bin_wrap(void *q, void *UNUSED(q_grp), unsigned char **bin, int *bin_len)
roman163f1662024-04-04 09:26:42 +02001254{
roman7ef57992024-04-23 15:08:45 +02001255 /* prepare buffer for converting p to binary */
1256 *bin = malloc(BN_num_bytes(q));
1257 NC_CHECK_ERRMEM_RET(!*bin, 1);
1258
1259 /* convert to binary */
1260 *bin_len = BN_bn2bin(q, *bin);
1261 return 0;
roman163f1662024-04-04 09:26:42 +02001262}
1263
1264void
roman7ef57992024-04-23 15:08:45 +02001265nc_tls_ec_point_destroy_wrap(void *p)
roman163f1662024-04-04 09:26:42 +02001266{
roman7ef57992024-04-23 15:08:45 +02001267 BN_free(p);
1268}
1269
1270void
1271nc_tls_ec_group_destroy_wrap(void *UNUSED(grp))
1272{
1273 return;
1274}
1275
1276int
1277nc_tls_mpi2bin_wrap(void *mpi, unsigned char **bin, int *bin_len)
1278{
1279 /* prepare buffer for converting mpi to binary */
1280 *bin = malloc(BN_num_bytes(mpi));
1281 NC_CHECK_ERRMEM_RET(!*bin, 1);
1282
1283 /* convert to binary */
1284 *bin_len = BN_bn2bin(mpi, *bin);
1285 return 0;
roman163f1662024-04-04 09:26:42 +02001286}
1287
1288void *
1289nc_tls_import_pubkey_file_wrap(const char *pubkey_path)
1290{
1291 FILE *f;
1292 EVP_PKEY *pk = NULL;
1293
1294 f = fopen(pubkey_path, "r");
1295 if (!f) {
1296 ERR(NULL, "Unable to open file \"%s\".", pubkey_path);
1297 return NULL;
1298 }
1299
1300 /* read the pubkey from file */
1301 pk = PEM_read_PUBKEY(f, NULL, NULL, NULL);
1302 fclose(f);
1303 if (!pk) {
1304 ERR(NULL, "Reading public key from file \"%s\" failed (%s).", pubkey_path, ERR_reason_error_string(ERR_get_error()));
1305 return NULL;
1306 }
1307
1308 return pk;
1309}
roman275c3fb2024-04-05 12:29:11 +02001310
1311int
1312nc_server_tls_get_crl_distpoint_uris_wrap(void *cert_store, char ***uris, int *uri_count)
1313{
1314 int ret = 0, i, j, k, gtype;
roman275c3fb2024-04-05 12:29:11 +02001315
1316 STACK_OF(X509_OBJECT) * objs;
1317 X509_OBJECT *obj;
1318 X509 *cert;
1319
1320 STACK_OF(DIST_POINT) * dist_points;
1321 DIST_POINT *dist_point;
1322 GENERAL_NAMES *general_names;
1323 GENERAL_NAME *general_name;
1324 ASN1_STRING *asn_string_uri;
roman275c3fb2024-04-05 12:29:11 +02001325 void *tmp;
1326
1327 NC_CHECK_ARG_RET(NULL, cert_store, uris, uri_count, 1);
1328
1329 *uris = NULL;
1330 *uri_count = 0;
1331
1332 /* treat all entries in the cert_store as X509_OBJECTs */
1333 objs = X509_STORE_get0_objects(cert_store);
1334 if (!objs) {
1335 ERR(NULL, "Getting certificates from store failed (%s).", ERR_reason_error_string(ERR_get_error()));
1336 ret = -1;
1337 goto cleanup;
1338 }
1339
1340 /* iterate over all the CAs */
1341 for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
1342 obj = sk_X509_OBJECT_value(objs, i);
1343 cert = X509_OBJECT_get0_X509(obj);
1344 if (!cert) {
1345 /* the object on this index was not a certificate */
1346 continue;
1347 }
1348
1349 /* get all the distribution points for this CA */
1350 dist_points = X509_get_ext_d2i(cert, NID_crl_distribution_points, NULL, NULL);
1351
1352 /* iterate over all the dist points (there can be multiple for a single cert) */
1353 for (j = 0; j < sk_DIST_POINT_num(dist_points); j++) {
1354 dist_point = sk_DIST_POINT_value(dist_points, j);
1355 if (!dist_point) {
1356 continue;
1357 }
1358 general_names = dist_point->distpoint->name.fullname;
1359
1360 /* iterate over all the GeneralesNames in the distribution point */
1361 for (k = 0; k < sk_GENERAL_NAME_num(general_names); k++) {
1362 general_name = sk_GENERAL_NAME_value(general_names, k);
1363 asn_string_uri = GENERAL_NAME_get0_value(general_name, &gtype);
1364
1365 /* check if the general name is a URI and has a valid length */
1366 if ((gtype != GEN_URI) || (ASN1_STRING_length(asn_string_uri) <= 6)) {
1367 continue;
1368 }
1369
1370 /* found an URI */
1371 tmp = realloc(*uris, (*uri_count + 1) * sizeof **uris);
1372 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
1373 *uris = tmp;
1374
1375 *uris[*uri_count] = strdup((const char *) ASN1_STRING_get0_data(asn_string_uri));
1376 NC_CHECK_ERRMEM_GOTO(!*uris[*uri_count], ret = 1, cleanup);
1377 ++(*uri_count);
1378 }
1379 }
1380 }
1381
1382cleanup:
1383 return ret;
1384}
roman7ef57992024-04-23 15:08:45 +02001385
1386int
1387nc_tls_process_cipher_suite_wrap(const char *cipher, char **out)
1388{
1389 int i;
1390
1391 *out = malloc(strlen(cipher) + 1);
1392 NC_CHECK_ERRMEM_RET(!*out, 1);
1393
1394 /* convert to uppercase */
1395 for (i = 0; cipher[i]; i++) {
1396 if (cipher[i] == '-') {
1397 /* OpenSSL requires _ instead of - in cipher names */
1398 (*out)[i] = '_';
1399 } else {
1400 (*out)[i] = toupper(cipher[i]);
1401 }
1402 }
1403
1404 (*out)[i] = '\0';
1405 return 0;
1406}
1407
1408int
1409nc_tls_append_cipher_suite_wrap(struct nc_server_tls_opts *opts, const char *cipher_suite)
1410{
1411 if (!opts->ciphers) {
1412 /* first entry */
1413 opts->ciphers = strdup(cipher_suite);
1414 NC_CHECK_ERRMEM_RET(!opts->ciphers, 1);
1415 } else {
1416 /* + 1 because of : between entries */
1417 opts->ciphers = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(cipher_suite) + 1 + 1);
1418 NC_CHECK_ERRMEM_RET(!opts->ciphers, 1);
1419 strcat(opts->ciphers, ":");
1420 strcat(opts->ciphers, cipher_suite);
1421 }
1422
1423 return 0;
1424}
1425
1426void
1427nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, void *cipher_suites)
1428{
1429 /* set for TLS1.2 and lower */
1430 SSL_CTX_set_cipher_list(tls_cfg, cipher_suites);
1431 /* set for TLS1.3 */
1432 SSL_CTX_set_ciphersuites(tls_cfg, cipher_suites);
1433}