blob: d67bca9e2e2b5de64eee38e3f72f41eff248106e [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);
roman7251b0d2024-07-04 13:25:02 +0200312 if (!data) {
313 ERRINT;
314 return 0;
315 }
316
317 /* get the cert chain once */
318 if (!data->chain) {
319 data->chain = X509_STORE_CTX_get0_chain(x509_ctx);
320 if (!data->chain) {
321 ERRINT;
322 return 0;
323 }
324 }
roman163f1662024-04-04 09:26:42 +0200325
326 /* get current cert and its depth */
327 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
328 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
329
330 if (preverify_ok) {
331 /* in-built verification was successful */
roman7ffd2fc2024-05-13 13:48:34 +0200332 ret = nc_server_tls_verify_cert(cert, depth, 1, data);
roman163f1662024-04-04 09:26:42 +0200333 } else {
334 /* in-built verification failed, but the client still may be authenticated if:
335 * 1) the peer cert matches any configured end-entity cert
336 * 2) the peer cert has a valid chain of trust to any configured certificate authority cert
337 * otherwise just continue until we reach the peer cert (depth = 0)
338 */
339 err = X509_STORE_CTX_get_error(x509_ctx);
roman7ffd2fc2024-05-13 13:48:34 +0200340 if ((depth == 0) && ((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) || (err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))) {
341 /* not trusted (possibly self-signed) peer certificate, case 1) */
342 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
roman163f1662024-04-04 09:26:42 +0200343 } else if ((err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) || (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)) {
344 /* full chain of trust is invalid, but it may be valid partially, case 2) */
345 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
roman7ef57992024-04-23 15:08:45 +0200346 } else if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) {
347 /* self-signed certificate in the chain, check if peer cert complies with 1) in order to continue,
348 * if yes, this callback will be called again with the same cert, but with preverify_ok = 1
349 */
350 cert = X509_STORE_CTX_get0_cert(x509_ctx);
351 ret = nc_server_tls_verify_peer_cert(cert, data->opts);
352 if (ret) {
353 VRB(NULL, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
354 ret = -1;
roman7ef57992024-04-23 15:08:45 +0200355 }
roman163f1662024-04-04 09:26:42 +0200356 } else {
357 VRB(NULL, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
358 ret = 1;
359 }
360 }
361
362 if (ret == -1) {
363 /* fatal error */
364 return 0;
365 } else if (!ret) {
366 /* success */
roman396f4732024-05-14 09:09:30 +0200367 if ((depth == 0) && (!data->session->opts.server.client_cert)) {
368 /* copy the client cert */
369 data->session->opts.server.client_cert = X509_dup(cert);
370 NC_CHECK_ERRMEM_RET(!data->session->opts.server.client_cert, 0);
371 }
roman163f1662024-04-04 09:26:42 +0200372 return 1;
373 } else {
374 if (depth > 0) {
375 /* chain verify failed */
376 return 1;
377 } else {
378 /* peer cert did not match */
379 return 0;
380 }
381 }
382}
383
384void
roman7ef57992024-04-23 15:08:45 +0200385nc_server_tls_set_verify_wrap(void *tls_cfg, struct nc_tls_verify_cb_data *cb_data)
roman163f1662024-04-04 09:26:42 +0200386{
roman7ef57992024-04-23 15:08:45 +0200387 /* set verify cb and its data */
388 SSL_CTX_set_ex_data(tls_cfg, 0, cb_data);
389 SSL_CTX_set_verify(tls_cfg, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_server_tls_verify_cb);
390}
391
392void
393nc_client_tls_set_verify_wrap(void *tls_cfg)
394{
395 SSL_CTX_set_verify(tls_cfg, SSL_VERIFY_PEER, NULL);
roman163f1662024-04-04 09:26:42 +0200396}
397
398char *
399nc_server_tls_get_subject_wrap(void *cert)
400{
401 return X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
402}
403
404char *
405nc_server_tls_get_issuer_wrap(void *cert)
406{
407 return X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
408}
409
roman7ef57992024-04-23 15:08:45 +0200410void *
411nc_tls_get_sans_wrap(void *cert)
roman163f1662024-04-04 09:26:42 +0200412{
roman7ef57992024-04-23 15:08:45 +0200413 return X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
414}
415
416void
417nc_tls_sans_destroy_wrap(void *sans)
418{
419 sk_GENERAL_NAME_pop_free(sans, GENERAL_NAME_free);
420}
421
422int
423nc_tls_get_num_sans_wrap(void *sans)
424{
425 return sk_GENERAL_NAME_num(sans);
426}
427
428int
429nc_tls_get_san_value_type_wrap(void *sans, int idx, char **san_value, NC_TLS_CTN_MAPTYPE *san_type)
430{
431 int ret = 0;
432 GENERAL_NAME *san;
roman163f1662024-04-04 09:26:42 +0200433 ASN1_OCTET_STRING *ip;
roman163f1662024-04-04 09:26:42 +0200434
roman7ef57992024-04-23 15:08:45 +0200435 *san_value = NULL;
436 *san_type = NC_TLS_CTN_UNKNOWN;
roman163f1662024-04-04 09:26:42 +0200437
roman7ef57992024-04-23 15:08:45 +0200438 /* find the san */
439 san = sk_GENERAL_NAME_value(sans, idx);
440 if (!san) {
441 return -1;
roman163f1662024-04-04 09:26:42 +0200442 }
443
roman7ef57992024-04-23 15:08:45 +0200444 /* get its type and value */
445 switch (san->type) {
446 case GEN_EMAIL:
447 *san_type = NC_TLS_CTN_SAN_RFC822_NAME;
448 *san_value = strdup((char *)ASN1_STRING_get0_data(san->d.rfc822Name));
449 NC_CHECK_ERRMEM_RET(!*san_value, -1);
450 break;
451 case GEN_DNS:
452 *san_type = NC_TLS_CTN_SAN_DNS_NAME;
453 *san_value = strdup((char *)ASN1_STRING_get0_data(san->d.dNSName));
454 NC_CHECK_ERRMEM_RET(!*san_value, -1);
455 break;
456 case GEN_IPADD:
457 *san_type = NC_TLS_CTN_SAN_IP_ADDRESS;
458 ip = san->d.iPAddress;
459 if (ip->length == 4) {
460 if (asprintf(san_value, "%d.%d.%d.%d", ip->data[0], ip->data[1], ip->data[2], ip->data[3]) == -1) {
461 ERRMEM;
462 *san_value = NULL;
463 ret = -1;
464 }
465 } else if (ip->length == 16) {
466 if (asprintf(san_value, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
467 ip->data[0], ip->data[1], ip->data[2], ip->data[3], ip->data[4], ip->data[5],
468 ip->data[6], ip->data[7], ip->data[8], ip->data[9], ip->data[10], ip->data[11],
469 ip->data[12], ip->data[13], ip->data[14], ip->data[15]) == -1) {
470 ERRMEM;
471 *san_value = NULL;
472 ret = -1;
473 }
474 } else {
475 WRN(NULL, "SAN IP address in an unknown format (length is %d).", ip->length);
476 ret = 1;
477 }
478 break;
479 default:
480 /* we dont care about other types */
481 *san_type = NC_TLS_CTN_UNKNOWN;
482 ret = 1;
483 break;
484 }
485
486 return ret;
roman163f1662024-04-04 09:26:42 +0200487}
488
489int
roman7251b0d2024-07-04 13:25:02 +0200490nc_tls_get_num_certs_wrap(void *chain)
491{
492 return sk_X509_num(chain);
493}
494
495void
496nc_tls_get_cert_wrap(void *chain, int idx, void **cert)
497{
498 *cert = sk_X509_value(chain, idx);
499}
500
501int
roman163f1662024-04-04 09:26:42 +0200502nc_server_tls_certs_match_wrap(void *cert1, void *cert2)
503{
504 return !X509_cmp(cert1, cert2);
505}
506
507int
508nc_server_tls_md5_wrap(void *cert, unsigned char *buf)
509{
510 int rc;
511
512 rc = X509_digest(cert, EVP_md5(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200513 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200514 ERR(NULL, "Calculating MD-5 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
515 return 1;
516 }
517
518 return 0;
519}
520
521int
522nc_server_tls_sha1_wrap(void *cert, unsigned char *buf)
523{
524 int rc;
525
526 rc = X509_digest(cert, EVP_sha1(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200527 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200528 ERR(NULL, "Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
529 return 1;
530 }
531
532 return 0;
533}
534
535int
536nc_server_tls_sha224_wrap(void *cert, unsigned char *buf)
537{
538 int rc;
539
540 rc = X509_digest(cert, EVP_sha224(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200541 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200542 ERR(NULL, "Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
543 return 1;
544 }
545
546 return 0;
547}
548
549int
550nc_server_tls_sha256_wrap(void *cert, unsigned char *buf)
551{
552 int rc;
553
554 rc = X509_digest(cert, EVP_sha256(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200555 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200556 ERR(NULL, "Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
557 return 1;
558 }
559
560 return 0;
561}
562
563int
564nc_server_tls_sha384_wrap(void *cert, unsigned char *buf)
565{
566 int rc;
567
568 rc = X509_digest(cert, EVP_sha384(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200569 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200570 ERR(NULL, "Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
571 return 1;
572 }
573
574 return 0;
575}
576
577int
578nc_server_tls_sha512_wrap(void *cert, unsigned char *buf)
579{
580 int rc;
581
582 rc = X509_digest(cert, EVP_sha512(), buf, NULL);
roman7ef57992024-04-23 15:08:45 +0200583 if (!rc) {
roman163f1662024-04-04 09:26:42 +0200584 ERR(NULL, "Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
585 return 1;
586 }
587
588 return 0;
589}
590
591void
592nc_server_tls_set_fd_wrap(void *tls_session, int sock, struct nc_tls_ctx *UNUSED(tls_ctx))
593{
594 SSL_set_fd(tls_session, sock);
595}
596
597int
598nc_server_tls_handshake_step_wrap(void *tls_session)
599{
600 int ret = 0;
601
602 ret = SSL_accept(tls_session);
603 if (ret == 1) {
604 return 1;
605 } else if (ret == -1) {
606 if ((SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_READ) || (SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_WRITE)) {
607 return 0;
608 }
609 }
610
611 return -1;
612}
613
614int
roman7ef57992024-04-23 15:08:45 +0200615nc_client_tls_handshake_step_wrap(void *tls_session, int UNUSED(sock))
roman163f1662024-04-04 09:26:42 +0200616{
617 int ret = 0;
618
619 ret = SSL_connect(tls_session);
620 if (ret == 1) {
621 return 1;
622 } else if (ret == -1) {
623 if ((SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_READ) || (SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_WRITE)) {
624 return 0;
625 }
626 }
627
628 return -1;
629}
630
631void
632nc_tls_ctx_destroy_wrap(struct nc_tls_ctx *UNUSED(tls_ctx))
633{
634 return;
635}
636
637int
638nc_client_tls_load_cert_key_wrap(const char *cert_path, const char *key_path, void **cert, void **pkey)
639{
640 BIO *bio;
641 X509 *cert_tmp;
642 EVP_PKEY *pkey_tmp;
643
roman7ef57992024-04-23 15:08:45 +0200644 NC_CHECK_ARG_RET(NULL, cert_path, key_path, cert, pkey, 1);
645
roman163f1662024-04-04 09:26:42 +0200646 bio = BIO_new_file(cert_path, "r");
647 if (!bio) {
648 ERR(NULL, "Opening the client certificate file \"%s\" failed.", cert_path);
649 return 1;
650 }
651
652 cert_tmp = PEM_read_bio_X509(bio, NULL, NULL, NULL);
653 BIO_free(bio);
654 if (!cert_tmp) {
655 ERR(NULL, "Parsing the client certificate file \"%s\" failed.", cert_path);
656 return 1;
657 }
658
659 bio = BIO_new_file(key_path, "r");
660 if (!bio) {
661 ERR(NULL, "Opening the client private key file \"%s\" failed.", key_path);
662 X509_free(cert_tmp);
663 return 1;
664 }
665
666 pkey_tmp = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
667 BIO_free(bio);
668 if (!pkey_tmp) {
669 ERR(NULL, "Parsing the client private key file \"%s\" failed.", key_path);
670 X509_free(cert_tmp);
671 return 1;
672 }
673
674 *cert = cert_tmp;
675 *pkey = pkey_tmp;
676
677 return 0;
678}
679
680int
681nc_client_tls_load_trusted_certs_wrap(void *cert_store, const char *file_path, const char *dir_path)
682{
683 if (!X509_STORE_load_locations(cert_store, file_path, dir_path)) {
roman7ffd2fc2024-05-13 13:48:34 +0200684 ERR(NULL, "Loading CA certs from file \"%s\" or directory \"%s\" failed (%s).",
685 file_path, dir_path, ERR_reason_error_string(ERR_get_error()));
roman163f1662024-04-04 09:26:42 +0200686 return 1;
687 }
688
689 return 0;
690}
691
692int
roman163f1662024-04-04 09:26:42 +0200693nc_client_tls_set_hostname_wrap(void *tls_session, const char *hostname)
694{
695 int ret = 0;
696 X509_VERIFY_PARAM *vpm = NULL;
697
698 vpm = X509_VERIFY_PARAM_new();
699 NC_CHECK_ERRMEM_RET(!vpm, 1);
700
701 if (!X509_VERIFY_PARAM_set1_host(vpm, hostname, 0)) {
702 ERR(NULL, "Failed to set expected hostname (%s).", ERR_reason_error_string(ERR_get_error()));
703 ret = 1;
704 goto cleanup;
705 }
roman7ef57992024-04-23 15:08:45 +0200706 if (!SSL_set1_param(tls_session, vpm)) {
roman163f1662024-04-04 09:26:42 +0200707 ERR(NULL, "Failed to set verify param (%s).", ERR_reason_error_string(ERR_get_error()));
708 ret = 1;
709 goto cleanup;
710 }
711
712cleanup:
713 X509_VERIFY_PARAM_free(vpm);
714 return ret;
715}
716
roman7ef57992024-04-23 15:08:45 +0200717int
718nc_tls_init_ctx_wrap(int UNUSED(sock), void *cert, void *pkey, void *cert_store, void *crl_store, struct nc_tls_ctx *tls_ctx)
719{
720 tls_ctx->cert = cert;
721 tls_ctx->pkey = pkey;
722 tls_ctx->cert_store = cert_store;
723 tls_ctx->crl_store = crl_store;
724 return 0;
725}
726
romane20f3542024-05-14 11:00:54 +0200727/**
728 * @brief Move CRLs from one store to another.
729 *
730 * @param[in] src Source store.
731 * @param[in] dst Destination store.
732 * @return 0 on success, 1 on error.
733 */
roman7ef57992024-04-23 15:08:45 +0200734static int
735nc_tls_move_crls_to_store(const X509_STORE *src, X509_STORE *dst)
736{
737 int i, nobjs = 0;
738
739 STACK_OF(X509_OBJECT) * objs;
740 X509_OBJECT *obj;
741 X509_CRL *crl;
742
743 objs = X509_STORE_get0_objects(src);
744 nobjs = sk_X509_OBJECT_num(objs);
745 for (i = 0; i < nobjs; i++) {
746 obj = sk_X509_OBJECT_value(objs, i);
747 crl = X509_OBJECT_get0_X509_CRL(obj);
748 if (!crl) {
749 /* not a CRL */
750 continue;
751 }
752 if (!X509_STORE_add_crl(dst, crl)) {
753 ERR(NULL, "Adding CRL to the store failed (%s).", ERR_reason_error_string(ERR_get_error()));
754 return 1;
755 }
756 }
757
758 return 0;
759}
760
761int
roman7ffd2fc2024-05-13 13:48:34 +0200762nc_tls_setup_config_from_ctx_wrap(struct nc_tls_ctx *tls_ctx, int side, void *tls_cfg)
roman7ef57992024-04-23 15:08:45 +0200763{
764 if (SSL_CTX_use_certificate(tls_cfg, tls_ctx->cert) != 1) {
roman15fbc592024-07-02 16:01:23 +0200765 ERR(NULL, "Setting up TLS certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
roman7ef57992024-04-23 15:08:45 +0200766 return 1;
767 }
768
769 if (SSL_CTX_use_PrivateKey(tls_cfg, tls_ctx->pkey) != 1) {
roman15fbc592024-07-02 16:01:23 +0200770 ERR(NULL, "Setting up TLS private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
roman7ef57992024-04-23 15:08:45 +0200771 return 1;
772 }
773
roman7ffd2fc2024-05-13 13:48:34 +0200774 /* disable server-side automatic chain building */
775 if (side == NC_SERVER) {
776 SSL_CTX_set_mode(tls_cfg, SSL_MODE_NO_AUTO_CHAIN);
777 }
roman7ef57992024-04-23 15:08:45 +0200778
779 if (tls_ctx->crl_store) {
780 /* move CRLs from crl_store to cert_store, because SSL_CTX can only have one store */
781 if (nc_tls_move_crls_to_store(tls_ctx->crl_store, tls_ctx->cert_store)) {
782 return 1;
783 }
784
785 /* enable CRL checks */
786 X509_STORE_set_flags(tls_ctx->cert_store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
787 }
788
789 SSL_CTX_set_cert_store(tls_cfg, tls_ctx->cert_store);
790
791 X509_free(tls_ctx->cert);
792 tls_ctx->cert = NULL;
793 EVP_PKEY_free(tls_ctx->pkey);
794 tls_ctx->pkey = NULL;
795 X509_STORE_free(tls_ctx->crl_store);
796 tls_ctx->crl_store = NULL;
797
798 return 0;
799}
800
roman163f1662024-04-04 09:26:42 +0200801uint32_t
802nc_tls_get_verify_result_wrap(void *tls_session)
803{
804 return SSL_get_verify_result(tls_session);
805}
806
roman7ef57992024-04-23 15:08:45 +0200807char *
roman163f1662024-04-04 09:26:42 +0200808nc_tls_verify_error_string_wrap(uint32_t err_code)
809{
roman7ef57992024-04-23 15:08:45 +0200810 return strdup(X509_verify_cert_error_string(err_code));
roman163f1662024-04-04 09:26:42 +0200811}
812
813void
roman7ef57992024-04-23 15:08:45 +0200814nc_client_tls_print_connect_err_wrap(int connect_ret, const char *peername, void *tls_session)
roman163f1662024-04-04 09:26:42 +0200815{
816 switch (SSL_get_error(tls_session, connect_ret)) {
817 case SSL_ERROR_SYSCALL:
818 ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, errno ? strerror(errno) : "unexpected EOF");
819 break;
820 case SSL_ERROR_SSL:
821 ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, ERR_reason_error_string(ERR_get_error()));
822 break;
823 default:
824 ERR(NULL, "TLS connection to \"%s\" failed.", peername);
825 break;
826 }
827}
828
829void
roman7ef57992024-04-23 15:08:45 +0200830nc_server_tls_print_accept_err_wrap(int accept_ret, void *tls_session)
roman163f1662024-04-04 09:26:42 +0200831{
832 switch (SSL_get_error(tls_session, accept_ret)) {
833 case SSL_ERROR_SYSCALL:
834 ERR(NULL, "TLS accept failed (%s).", strerror(errno));
835 break;
836 case SSL_ERROR_SSL:
837 ERR(NULL, "TLS accept failed (%s).", ERR_reason_error_string(ERR_get_error()));
838 break;
839 default:
840 ERR(NULL, "TLS accept failed.");
841 break;
842 }
843}
844
845int
roman7ef57992024-04-23 15:08:45 +0200846nc_tls_is_der_subpubkey_wrap(unsigned char *der, long len)
roman163f1662024-04-04 09:26:42 +0200847{
848 int ret;
849 EVP_PKEY *pkey;
850
roman7ef57992024-04-23 15:08:45 +0200851 pkey = d2i_PUBKEY(NULL, (const unsigned char **)&der, len);
roman163f1662024-04-04 09:26:42 +0200852 if (pkey) {
853 /* success */
roman7ef57992024-04-23 15:08:45 +0200854 ret = 1;
roman163f1662024-04-04 09:26:42 +0200855 } else {
856 /* fail */
roman7ef57992024-04-23 15:08:45 +0200857 ret = 0;
roman163f1662024-04-04 09:26:42 +0200858 }
859
860 EVP_PKEY_free(pkey);
861 return ret;
862}
863
864int
roman7ef57992024-04-23 15:08:45 +0200865nc_base64_decode_wrap(const char *base64, unsigned char **bin)
roman163f1662024-04-04 09:26:42 +0200866{
roman7ef57992024-04-23 15:08:45 +0200867 int ret;
roman163f1662024-04-04 09:26:42 +0200868
roman7ef57992024-04-23 15:08:45 +0200869 *bin = malloc((strlen(base64) / 4) * 3);
870 NC_CHECK_ERRMEM_RET(!*bin, -1);
roman163f1662024-04-04 09:26:42 +0200871
roman7ef57992024-04-23 15:08:45 +0200872 ret = EVP_DecodeBlock(*bin, (const unsigned char *)base64, strlen(base64));
873 if (ret == -1) {
874 ERR(NULL, "Base64 decoding failed (%s).", ERR_reason_error_string(ERR_get_error()));
875 free(*bin);
876 *bin = NULL;
roman163f1662024-04-04 09:26:42 +0200877 }
roman163f1662024-04-04 09:26:42 +0200878 return ret;
879}
880
881int
882nc_base64_encode_wrap(const unsigned char *bin, size_t len, char **base64)
883{
roman7ef57992024-04-23 15:08:45 +0200884 int ret, size;
roman163f1662024-04-04 09:26:42 +0200885
roman7ef57992024-04-23 15:08:45 +0200886 /* calculate the size, for every 3B of in 4B of out, + padding if not divisible + null terminator */
887 if (len % 3) {
888 size = (len / 3) * 4 + 4 + 1;
889 } else {
890 size = (len / 3) * 4 + 1;
roman163f1662024-04-04 09:26:42 +0200891 }
892
roman7ef57992024-04-23 15:08:45 +0200893 *base64 = malloc(size);
894 NC_CHECK_ERRMEM_RET(!*base64, -1);
895
896 ret = EVP_EncodeBlock((unsigned char *)*base64, bin, len);
897 if (ret == -1) {
898 ERR(NULL, "Base64 encoding failed (%s).", ERR_reason_error_string(ERR_get_error()));
899 free(*base64);
900 *base64 = NULL;
901 return -1;
roman163f1662024-04-04 09:26:42 +0200902 }
903
roman7ef57992024-04-23 15:08:45 +0200904 return 0;
roman163f1662024-04-04 09:26:42 +0200905}
906
romane20f3542024-05-14 11:00:54 +0200907/**
908 * @brief Get all OpenSSL error reasons.
909 *
910 * @return String with all OpenSSL error reasons or NULL.
911 */
roman163f1662024-04-04 09:26:42 +0200912static char *
roman7ef57992024-04-23 15:08:45 +0200913nc_tls_get_err_reasons(void)
roman163f1662024-04-04 09:26:42 +0200914{
915 unsigned int e;
916 int reason_size, reason_len;
917 char *reasons = NULL;
918
919 reason_size = 1;
920 reason_len = 0;
921 while ((e = ERR_get_error())) {
922 if (reason_len) {
923 /* add "; " */
924 reason_size += 2;
925 reasons = nc_realloc(reasons, reason_size);
926 NC_CHECK_ERRMEM_RET(!reasons, NULL);
927 reason_len += sprintf(reasons + reason_len, "; ");
928 }
929 reason_size += strlen(ERR_reason_error_string(e));
930 reasons = nc_realloc(reasons, reason_size);
931 NC_CHECK_ERRMEM_RET(!reasons, NULL);
932 reason_len += sprintf(reasons + reason_len, "%s", ERR_reason_error_string(e));
933 }
934
935 return reasons;
936}
937
938int
939nc_tls_read_wrap(struct nc_session *session, unsigned char *buf, size_t size)
940{
941 int rc, err;
942 char *reasons;
943 SSL *tls_session = session->ti.tls.session;
944
945 ERR_clear_error();
946 rc = SSL_read(tls_session, buf, size);
947 if (rc <= 0) {
948 err = SSL_get_error(tls_session, rc);
949 switch (err) {
950 case SSL_ERROR_WANT_READ:
951 case SSL_ERROR_WANT_WRITE:
952 rc = 0;
953 break;
954 case SSL_ERROR_ZERO_RETURN:
955 ERR(session, "Communication socket unexpectedly closed (OpenSSL).");
956 session->status = NC_STATUS_INVALID;
957 session->term_reason = NC_SESSION_TERM_DROPPED;
958 rc = -1;
959 break;
960 case SSL_ERROR_SYSCALL:
961 ERR(session, "TLS socket error (%s).", errno ? strerror(errno) : "unexpected EOF");
962 session->status = NC_STATUS_INVALID;
963 session->term_reason = NC_SESSION_TERM_OTHER;
964 rc = -1;
965 break;
966 case SSL_ERROR_SSL:
roman7ef57992024-04-23 15:08:45 +0200967 reasons = nc_tls_get_err_reasons();
roman163f1662024-04-04 09:26:42 +0200968 ERR(session, "TLS communication error (%s).", reasons);
969 free(reasons);
970 session->status = NC_STATUS_INVALID;
971 session->term_reason = NC_SESSION_TERM_OTHER;
972 rc = -1;
973 break;
974 default:
975 ERR(session, "Unknown TLS error occurred (err code %d).", err);
976 session->status = NC_STATUS_INVALID;
977 session->term_reason = NC_SESSION_TERM_OTHER;
978 rc = -1;
979 break;
980 }
981 }
982
983 return rc;
984}
985
986int
987nc_tls_write_wrap(struct nc_session *session, const unsigned char *buf, size_t size)
988{
989 int rc, err;
990 char *reasons;
991 SSL *tls_session = session->ti.tls.session;
992
993 ERR_clear_error();
994 rc = SSL_write(tls_session, buf, size);
995 if (rc < 1) {
996 err = SSL_get_error(tls_session, rc);
997 switch (err) {
998 case SSL_ERROR_WANT_WRITE:
999 case SSL_ERROR_WANT_READ:
1000 rc = 0;
1001 break;
1002 case SSL_ERROR_ZERO_RETURN:
1003 ERR(session, "TLS connection was properly closed.");
1004 rc = -1;
1005 break;
1006 case SSL_ERROR_SYSCALL:
1007 ERR(session, "TLS socket error (%s).", errno ? strerror(errno) : "unexpected EOF");
1008 rc = -1;
1009 break;
1010 case SSL_ERROR_SSL:
roman7ef57992024-04-23 15:08:45 +02001011 reasons = nc_tls_get_err_reasons();
roman163f1662024-04-04 09:26:42 +02001012 ERR(session, "TLS communication error (%s).", reasons);
1013 free(reasons);
1014 rc = -1;
1015 break;
1016 default:
1017 ERR(session, "Unknown TLS error occurred (err code %d).", err);
1018 rc = -1;
1019 break;
1020 }
1021 }
1022
1023 return rc;
1024}
1025
1026int
roman7ef57992024-04-23 15:08:45 +02001027nc_tls_get_num_pending_bytes_wrap(void *tls_session)
roman163f1662024-04-04 09:26:42 +02001028{
1029 return SSL_pending(tls_session);
1030}
1031
1032int
1033nc_tls_get_fd_wrap(const struct nc_session *session)
1034{
roman7ef57992024-04-23 15:08:45 +02001035 return session->ti.tls.session ? SSL_get_fd(session->ti.tls.session) : -1;
roman163f1662024-04-04 09:26:42 +02001036}
1037
1038void
1039nc_tls_close_notify_wrap(void *tls_session)
1040{
1041 SSL_shutdown(tls_session);
1042}
1043
1044void *
roman7ef57992024-04-23 15:08:45 +02001045nc_tls_import_privkey_file_wrap(const char *key_path)
roman163f1662024-04-04 09:26:42 +02001046{
1047 EVP_PKEY *pkey;
roman7ef57992024-04-23 15:08:45 +02001048 FILE *file;
1049
1050 file = fopen(key_path, "r");
1051 if (!file) {
1052 ERR(NULL, "Opening the private key file \"%s\" failed.", key_path);
1053 return NULL;
1054 }
roman163f1662024-04-04 09:26:42 +02001055
1056 pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
roman7ef57992024-04-23 15:08:45 +02001057 fclose(file);
roman163f1662024-04-04 09:26:42 +02001058 if (!pkey) {
1059 ERR(NULL, "Parsing the private key file \"%s\" failed (%s).", key_path, ERR_reason_error_string(ERR_get_error()));
1060 }
1061
1062 return pkey;
1063}
1064
1065void *
1066nc_tls_import_cert_file_wrap(const char *cert_path)
1067{
1068 X509 *cert;
1069 FILE *file;
1070
1071 file = fopen(cert_path, "r");
1072 if (!file) {
1073 ERR(NULL, "Opening the certificate file \"%s\" failed.", cert_path);
1074 return NULL;
1075 }
1076
1077 cert = PEM_read_X509(file, NULL, NULL, NULL);
1078 fclose(file);
1079 if (!cert) {
1080 ERR(NULL, "Parsing the certificate file \"%s\" failed (%s).", cert_path, ERR_reason_error_string(ERR_get_error()));
1081 }
1082 return cert;
1083}
1084
1085char *
roman7ef57992024-04-23 15:08:45 +02001086nc_tls_export_privkey_pem_wrap(void *pkey)
roman163f1662024-04-04 09:26:42 +02001087{
1088 BIO *bio = NULL;
1089 char *pem = NULL;
1090
1091 bio = BIO_new(BIO_s_mem());
1092 if (!bio) {
1093 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1094 goto cleanup;
1095 }
1096
1097 if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) {
1098 ERR(NULL, "Exporting the private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1099 goto cleanup;
1100 }
1101
1102 pem = malloc(BIO_number_written(bio) + 1);
1103 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1104
1105 BIO_read(bio, pem, BIO_number_written(bio));
1106 pem[BIO_number_written(bio)] = '\0';
1107
1108cleanup:
1109 BIO_free(bio);
1110 return pem;
1111}
1112
1113char *
roman7ef57992024-04-23 15:08:45 +02001114nc_tls_export_cert_pem_wrap(void *cert)
roman163f1662024-04-04 09:26:42 +02001115{
roman163f1662024-04-04 09:26:42 +02001116 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
roman7ef57992024-04-23 15:08:45 +02001125 if (!PEM_write_bio_X509(bio, cert)) {
roman163f1662024-04-04 09:26:42 +02001126 ERR(NULL, "Exporting the certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
1127 goto cleanup;
1128 }
1129
roman7ef57992024-04-23 15:08:45 +02001130 pem = malloc(BIO_number_written(bio) + 1);
roman163f1662024-04-04 09:26:42 +02001131 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1132
roman7ef57992024-04-23 15:08:45 +02001133 BIO_read(bio, pem, BIO_number_written(bio));
1134 pem[BIO_number_written(bio)] = '\0';
roman163f1662024-04-04 09:26:42 +02001135
1136cleanup:
1137 BIO_free(bio);
1138 return pem;
1139}
1140
1141char *
roman7ef57992024-04-23 15:08:45 +02001142nc_tls_export_pubkey_pem_wrap(void *pkey)
roman163f1662024-04-04 09:26:42 +02001143{
1144 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
1153 if (!PEM_write_bio_PUBKEY(bio, pkey)) {
1154 ERR(NULL, "Exporting the public key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1155 goto cleanup;
1156 }
1157
1158 pem = malloc(BIO_number_written(bio) + 1);
1159 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1160
1161 BIO_read(bio, pem, BIO_number_written(bio));
1162 pem[BIO_number_written(bio)] = '\0';
1163
1164cleanup:
1165 BIO_free(bio);
1166 return pem;
1167}
1168
1169int
roman163f1662024-04-04 09:26:42 +02001170nc_tls_privkey_is_rsa_wrap(void *pkey)
1171{
1172 return EVP_PKEY_is_a(pkey, "RSA");
1173}
1174
1175int
1176nc_tls_get_rsa_pubkey_params_wrap(void *pkey, void **e, void **n)
1177{
roman7ef57992024-04-23 15:08:45 +02001178 BIGNUM *exp = NULL, *mod = NULL;
roman163f1662024-04-04 09:26:42 +02001179
1180 if (!EVP_PKEY_get_bn_param(pkey, "e", &exp)) {
1181 ERR(NULL, "Getting the RSA public exponent failed (%s).", ERR_reason_error_string(ERR_get_error()));
1182 return 1;
1183 }
1184
1185 if (!EVP_PKEY_get_bn_param(pkey, "n", &mod)) {
1186 ERR(NULL, "Getting the RSA modulus failed (%s).", ERR_reason_error_string(ERR_get_error()));
1187 BN_free(exp);
1188 return 1;
1189 }
1190
1191 *e = exp;
1192 *n = mod;
1193 return 0;
1194}
1195
roman7ef57992024-04-23 15:08:45 +02001196void
1197nc_tls_destroy_mpi_wrap(void *mpi)
1198{
1199 BN_free(mpi);
1200}
1201
roman163f1662024-04-04 09:26:42 +02001202int
1203nc_tls_privkey_is_ec_wrap(void *pkey)
1204{
1205 return EVP_PKEY_is_a(pkey, "EC");
1206}
1207
1208char *
1209nc_tls_get_ec_group_wrap(void *pkey)
1210{
1211 size_t ec_group_len = 0;
1212 char *ec_group = NULL;
1213
1214 if (!EVP_PKEY_get_utf8_string_param(pkey, "group", NULL, 0, &ec_group_len)) {
1215 ERR(NULL, "Getting EC group length failed (%s).", ERR_reason_error_string(ERR_get_error()));
1216 return NULL;
1217 }
1218
1219 /* alloc mem for group + 1 for \0 */
1220 ec_group = malloc(ec_group_len + 1);
1221 NC_CHECK_ERRMEM_RET(!ec_group, NULL);
1222
1223 /* get the group */
1224 if (!EVP_PKEY_get_utf8_string_param(pkey, "group", ec_group, ec_group_len + 1, NULL)) {
1225 ERR(NULL, "Getting EC group failed (%s).", ERR_reason_error_string(ERR_get_error()));
1226 free(ec_group);
1227 return NULL;
1228 }
1229
1230 return ec_group;
1231}
1232
1233int
roman7ef57992024-04-23 15:08:45 +02001234nc_tls_get_ec_pubkey_params_wrap(void *pkey, void **q, void **UNUSED(q_grp))
roman163f1662024-04-04 09:26:42 +02001235{
roman7ef57992024-04-23 15:08:45 +02001236 BIGNUM *p = NULL;
roman163f1662024-04-04 09:26:42 +02001237
1238 if (!EVP_PKEY_get_bn_param(pkey, "p", &p)) {
1239 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 +02001240 return 1;
roman163f1662024-04-04 09:26:42 +02001241 }
1242
roman7ef57992024-04-23 15:08:45 +02001243 *q = p;
roman163f1662024-04-04 09:26:42 +02001244
roman7ef57992024-04-23 15:08:45 +02001245 return 0;
roman163f1662024-04-04 09:26:42 +02001246}
1247
1248int
roman7ef57992024-04-23 15:08:45 +02001249nc_tls_ec_point_to_bin_wrap(void *q, void *UNUSED(q_grp), unsigned char **bin, int *bin_len)
roman163f1662024-04-04 09:26:42 +02001250{
roman7ef57992024-04-23 15:08:45 +02001251 /* prepare buffer for converting p to binary */
1252 *bin = malloc(BN_num_bytes(q));
1253 NC_CHECK_ERRMEM_RET(!*bin, 1);
1254
1255 /* convert to binary */
1256 *bin_len = BN_bn2bin(q, *bin);
1257 return 0;
roman163f1662024-04-04 09:26:42 +02001258}
1259
1260void
roman7ef57992024-04-23 15:08:45 +02001261nc_tls_ec_point_destroy_wrap(void *p)
roman163f1662024-04-04 09:26:42 +02001262{
roman7ef57992024-04-23 15:08:45 +02001263 BN_free(p);
1264}
1265
1266void
1267nc_tls_ec_group_destroy_wrap(void *UNUSED(grp))
1268{
1269 return;
1270}
1271
1272int
1273nc_tls_mpi2bin_wrap(void *mpi, unsigned char **bin, int *bin_len)
1274{
1275 /* prepare buffer for converting mpi to binary */
1276 *bin = malloc(BN_num_bytes(mpi));
1277 NC_CHECK_ERRMEM_RET(!*bin, 1);
1278
1279 /* convert to binary */
1280 *bin_len = BN_bn2bin(mpi, *bin);
1281 return 0;
roman163f1662024-04-04 09:26:42 +02001282}
1283
1284void *
1285nc_tls_import_pubkey_file_wrap(const char *pubkey_path)
1286{
1287 FILE *f;
1288 EVP_PKEY *pk = NULL;
1289
1290 f = fopen(pubkey_path, "r");
1291 if (!f) {
1292 ERR(NULL, "Unable to open file \"%s\".", pubkey_path);
1293 return NULL;
1294 }
1295
1296 /* read the pubkey from file */
1297 pk = PEM_read_PUBKEY(f, NULL, NULL, NULL);
1298 fclose(f);
1299 if (!pk) {
1300 ERR(NULL, "Reading public key from file \"%s\" failed (%s).", pubkey_path, ERR_reason_error_string(ERR_get_error()));
1301 return NULL;
1302 }
1303
1304 return pk;
1305}
roman275c3fb2024-04-05 12:29:11 +02001306
1307int
roman15fbc592024-07-02 16:01:23 +02001308nc_server_tls_get_crl_distpoint_uris_wrap(void *leaf_cert, void *cert_store, char ***uris, int *uri_count)
roman275c3fb2024-04-05 12:29:11 +02001309{
1310 int ret = 0, i, j, k, gtype;
roman275c3fb2024-04-05 12:29:11 +02001311
1312 STACK_OF(X509_OBJECT) * objs;
1313 X509_OBJECT *obj;
1314 X509 *cert;
1315
1316 STACK_OF(DIST_POINT) * dist_points;
1317 DIST_POINT *dist_point;
1318 GENERAL_NAMES *general_names;
1319 GENERAL_NAME *general_name;
1320 ASN1_STRING *asn_string_uri;
roman275c3fb2024-04-05 12:29:11 +02001321 void *tmp;
1322
roman50e3e562024-07-03 15:01:35 +02001323 *uris = NULL;
1324 *uri_count = 0;
1325
roman275c3fb2024-04-05 12:29:11 +02001326 NC_CHECK_ARG_RET(NULL, cert_store, uris, uri_count, 1);
1327
roman275c3fb2024-04-05 12:29:11 +02001328 /* treat all entries in the cert_store as X509_OBJECTs */
1329 objs = X509_STORE_get0_objects(cert_store);
1330 if (!objs) {
1331 ERR(NULL, "Getting certificates from store failed (%s).", ERR_reason_error_string(ERR_get_error()));
1332 ret = -1;
1333 goto cleanup;
1334 }
1335
1336 /* iterate over all the CAs */
roman15fbc592024-07-02 16:01:23 +02001337 for (i = -1; i < sk_X509_OBJECT_num(objs); i++) {
1338 if (i == -1) {
1339 cert = leaf_cert;
1340 } else {
1341 obj = sk_X509_OBJECT_value(objs, i);
1342 cert = X509_OBJECT_get0_X509(obj);
1343 }
1344
roman275c3fb2024-04-05 12:29:11 +02001345 if (!cert) {
1346 /* the object on this index was not a certificate */
1347 continue;
1348 }
1349
1350 /* get all the distribution points for this CA */
1351 dist_points = X509_get_ext_d2i(cert, NID_crl_distribution_points, NULL, NULL);
1352
1353 /* iterate over all the dist points (there can be multiple for a single cert) */
1354 for (j = 0; j < sk_DIST_POINT_num(dist_points); j++) {
1355 dist_point = sk_DIST_POINT_value(dist_points, j);
1356 if (!dist_point) {
1357 continue;
1358 }
1359 general_names = dist_point->distpoint->name.fullname;
1360
1361 /* iterate over all the GeneralesNames in the distribution point */
1362 for (k = 0; k < sk_GENERAL_NAME_num(general_names); k++) {
1363 general_name = sk_GENERAL_NAME_value(general_names, k);
1364 asn_string_uri = GENERAL_NAME_get0_value(general_name, &gtype);
1365
1366 /* check if the general name is a URI and has a valid length */
1367 if ((gtype != GEN_URI) || (ASN1_STRING_length(asn_string_uri) <= 6)) {
1368 continue;
1369 }
1370
1371 /* found an URI */
1372 tmp = realloc(*uris, (*uri_count + 1) * sizeof **uris);
1373 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
1374 *uris = tmp;
1375
roman15fbc592024-07-02 16:01:23 +02001376 (*uris)[*uri_count] = strdup((const char *) ASN1_STRING_get0_data(asn_string_uri));
1377 NC_CHECK_ERRMEM_GOTO(!(*uris)[*uri_count], ret = 1, cleanup);
roman275c3fb2024-04-05 12:29:11 +02001378 ++(*uri_count);
1379 }
1380 }
1381 }
1382
1383cleanup:
1384 return ret;
1385}
roman7ef57992024-04-23 15:08:45 +02001386
1387int
1388nc_tls_process_cipher_suite_wrap(const char *cipher, char **out)
1389{
1390 int i;
1391
1392 *out = malloc(strlen(cipher) + 1);
1393 NC_CHECK_ERRMEM_RET(!*out, 1);
1394
1395 /* convert to uppercase */
1396 for (i = 0; cipher[i]; i++) {
1397 if (cipher[i] == '-') {
1398 /* OpenSSL requires _ instead of - in cipher names */
1399 (*out)[i] = '_';
1400 } else {
1401 (*out)[i] = toupper(cipher[i]);
1402 }
1403 }
1404
1405 (*out)[i] = '\0';
1406 return 0;
1407}
1408
1409int
1410nc_tls_append_cipher_suite_wrap(struct nc_server_tls_opts *opts, const char *cipher_suite)
1411{
1412 if (!opts->ciphers) {
1413 /* first entry */
1414 opts->ciphers = strdup(cipher_suite);
1415 NC_CHECK_ERRMEM_RET(!opts->ciphers, 1);
1416 } else {
1417 /* + 1 because of : between entries */
1418 opts->ciphers = nc_realloc(opts->ciphers, strlen(opts->ciphers) + strlen(cipher_suite) + 1 + 1);
1419 NC_CHECK_ERRMEM_RET(!opts->ciphers, 1);
1420 strcat(opts->ciphers, ":");
1421 strcat(opts->ciphers, cipher_suite);
1422 }
1423
1424 return 0;
1425}
1426
1427void
1428nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, void *cipher_suites)
1429{
1430 /* set for TLS1.2 and lower */
1431 SSL_CTX_set_cipher_list(tls_cfg, cipher_suites);
1432 /* set for TLS1.3 */
1433 SSL_CTX_set_ciphersuites(tls_cfg, cipher_suites);
1434}