blob: ec3ff492ed894e443ff5e3e4026c298ac18669b2 [file] [log] [blame]
roman163f1662024-04-04 09:26:42 +02001#define _GNU_SOURCE
2
3#include <poll.h>
4#include <stdint.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <unistd.h>
9
10#include <curl/curl.h>
11
12#include "compat.h"
13#include "config.h"
14#include "log_p.h"
15#include "session.h"
16#include "session_p.h"
17#include "session_wrapper.h"
18
19#include <openssl/bio.h>
20#include <openssl/err.h>
21#include <openssl/evp.h>
22#include <openssl/ssl.h>
23#include <openssl/x509.h>
24#include <openssl/x509v3.h>
25
26void *
27nc_tls_session_new_wrap(void *tls_cfg)
28{
29 SSL *session;
30
31 session = SSL_new(tls_cfg);
32 if (!session) {
33 ERR(NULL, "Setting up TLS context failed (%s).", ERR_reason_error_string(ERR_get_error()));
34 return NULL;
35 }
36
37 return session;
38}
39
40void
41nc_tls_session_destroy_wrap(void *tls_session)
42{
43 SSL_free(tls_session);
44}
45
46void *
47nc_server_tls_config_new_wrap()
48{
49 SSL_CTX *tls_cfg;
50
51 tls_cfg = SSL_CTX_new(TLS_server_method());
52 NC_CHECK_ERRMEM_RET(!tls_cfg, NULL)
53
54 return tls_cfg;
55}
56
57void *
58nc_client_tls_config_new_wrap()
59{
60 SSL_CTX *tls_cfg;
61
62 tls_cfg = SSL_CTX_new(TLS_client_method());
63 NC_CHECK_ERRMEM_RET(!tls_cfg, NULL)
64
65 return tls_cfg;
66}
67
68void
69nc_tls_config_destroy_wrap(void *tls_cfg)
70{
71 SSL_CTX_free(tls_cfg);
72}
73
74void *
75nc_tls_cert_new_wrap()
76{
77 X509 *cert;
78
79 cert = X509_new();
80 NC_CHECK_ERRMEM_RET(!cert, NULL)
81
82 return cert;
83}
84
85void
86nc_tls_cert_destroy_wrap(void *cert)
87{
88 X509_free(cert);
89}
90
91void *
92nc_tls_privkey_new_wrap()
93{
94 EVP_PKEY *pkey;
95
96 pkey = EVP_PKEY_new();
97 NC_CHECK_ERRMEM_RET(!pkey, NULL);
98
99 return pkey;
100}
101
102void
103nc_tls_privkey_destroy_wrap(void *pkey)
104{
105 EVP_PKEY_free(pkey);
106}
107
108void *
109nc_tls_cert_store_new_wrap()
110{
111 X509_STORE *store;
112
113 store = X509_STORE_new();
114 NC_CHECK_ERRMEM_RET(!store, NULL);
115
116 return store;
117}
118
119void
120nc_tls_cert_store_destroy_wrap(void *cert_store)
121{
122 X509_STORE_free(cert_store);
123}
124
125void *
126nc_tls_crl_store_new_wrap()
127{
128 return NULL;
129}
130
131void
132nc_tls_crl_store_destroy_wrap(void *crl)
133{
134 (void) crl;
135 return;
136}
137
138void
139nc_tls_set_authmode_wrap(void *tls_cfg)
140{
141 SSL_CTX_set_mode(tls_cfg, SSL_MODE_AUTO_RETRY);
142}
143
144int
145nc_server_tls_set_config_defaults_wrap(void *tls_cfg)
146{
147 return 0;
148}
149
150void *
151nc_tls_pem_to_cert_wrap(const char *cert_data)
152{
153 BIO *bio;
154 X509 *cert;
155
156 bio = BIO_new_mem_buf(cert_data, strlen(cert_data));
157 if (!bio) {
158 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
159 return NULL;
160 }
161
162 cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
163 if (!cert) {
164 ERR(NULL, "Parsing certificate data failed (%s).", ERR_reason_error_string(ERR_get_error()));
165 }
166 BIO_free(bio);
167 return cert;
168}
169
170int
171nc_tls_pem_to_cert_add_to_store_wrap(const char *cert_data, void *cert_store)
172{
173 int rc;
174 X509 *cert;
175
176 cert = nc_tls_pem_to_cert_wrap(cert_data);
177 if (!cert) {
178 return 1;
179 }
180
181 rc = X509_STORE_add_cert(cert_store, cert);
182 X509_free(cert);
183 if (!rc) {
184 ERR(NULL, "Adding certificate to store failed (%s).", ERR_reason_error_string(ERR_get_error()));
185 return 1;
186 }
187 return 0;
188}
189
190void *
191nc_tls_pem_to_privkey_wrap(const char *privkey_data)
192{
193 BIO *bio;
194 EVP_PKEY *pkey;
195
196 bio = BIO_new_mem_buf(privkey_data, strlen(privkey_data));
197 if (!bio) {
198 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
199 return NULL;
200 }
201
202 pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
203 if (!pkey) {
204 ERR(NULL, "Parsing certificate data failed (%s).", ERR_reason_error_string(ERR_get_error()));
205 }
206 BIO_free(bio);
207 return pkey;
208}
209
210int
211nc_tls_load_cert_private_key_wrap(void *tls_cfg, void *cert, void *pkey)
212{
213 int rc;
214
215 rc = SSL_CTX_use_certificate(tls_cfg, cert);
216 if (rc) {
217 ERR(NULL, "Loading the server certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
218 return 1;
219 }
220
221 rc = SSL_CTX_use_PrivateKey(tls_cfg, pkey);
222 if (rc) {
223 ERR(NULL, "Loading the server private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
224 return 1;
225 }
226
227 return 0;
228}
229
230int
231nc_server_tls_crl_path(const char *crl_path, void *cert_store, void *crl_store)
232{
233 int ret = 0;
234 X509_CRL *crl = NULL;
235 FILE *f;
236
237 (void) crl_store;
238
239 f = fopen(crl_path, "r");
240 if (!f) {
241 ERR(NULL, "Unable to open CRL file \"%s\".", crl_path);
242 return 1;
243 }
244
245 /* try PEM first */
246 crl = PEM_read_X509_CRL(f, NULL, NULL, NULL);
247 if (crl) {
248 /* success */
249 goto ok;
250 }
251
252 /* PEM failed, try DER */
253 rewind(f);
254 crl = d2i_X509_CRL_fp(f, NULL);
255 if (!crl) {
256 ERR(NULL, "Reading CRL from file \"%s\" failed.", crl_path);
257 ret = 1;
258 goto cleanup;
259 }
260
261ok:
262 ret = X509_STORE_add_crl(cert_store, crl);
263 if (!ret) {
264 ERR(NULL, "Error adding CRL to store (%s).", ERR_reason_error_string(ERR_get_error()));
265 ret = 1;
266 goto cleanup;
267 }
268 /* ok */
269 ret = 0;
270
271cleanup:
272 fclose(f);
273 X509_CRL_free(crl);
274 return ret;
275}
276
277int
278nc_server_tls_add_crl_to_store_wrap(const unsigned char *crl_data, size_t size, void *cert_store, void *crl_store)
279{
280 int ret = 0;
281 X509_CRL *crl = NULL;
282 BIO *bio = NULL;
283
284 (void) crl_store;
285
286 bio = BIO_new_mem_buf(crl_data, size);
287 if (!bio) {
288 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
289 ret = 1;
290 goto cleanup;
291 }
292
293 /* try DER first */
294 crl = d2i_X509_CRL_bio(bio, NULL);
295 if (crl) {
296 /* it was DER */
297 goto ok;
298 }
299
300 /* DER failed, try PEM next */
301 crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
302 if (!crl) {
303 ERR(NULL, "Parsing downloaded CRL failed (%s).", ERR_reason_error_string(ERR_get_error()));
304 ret = 1;
305 goto cleanup;
306 }
307
308ok:
309 /* we obtained the CRL, now add it to the CRL store */
310 ret = X509_STORE_add_crl(cert_store, crl);
311 if (!ret) {
312 ERR(NULL, "Error adding CRL to store (%s).", ERR_reason_error_string(ERR_get_error()));
313 ret = 1;
314 goto cleanup;
315 }
316 /* ok */
317 ret = 0;
318
319cleanup:
320 X509_CRL_free(crl);
321 BIO_free(bio);
322 return ret;
323}
324
325void
326nc_server_tls_set_certs_wrap(void *tls_cfg, void *cert_store, void *crl_store)
327{
328 (void) crl_store;
329
330 X509_STORE_set_flags(cert_store, X509_V_FLAG_CRL_CHECK);
331 SSL_CTX_set_cert_store(tls_cfg, cert_store);
332}
333
334int
335nc_server_tls_set_tls_versions_wrap(void *tls_cfg, unsigned int tls_versions)
336{
337 int rc = 1;
338
339 /* first set the minimum version */
340 if (tls_versions & NC_TLS_VERSION_10) {
341 rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_VERSION);
342 } else if (tls_versions & NC_TLS_VERSION_11) {
343 rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_1_VERSION);
344 } else if (tls_versions & NC_TLS_VERSION_12) {
345 rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_2_VERSION);
346 } else if (tls_versions & NC_TLS_VERSION_13) {
347 rc = SSL_CTX_set_min_proto_version(tls_cfg, TLS1_3_VERSION);
348 }
349 if (!rc) {
350 ERR(NULL, "Setting TLS min version failed (%s).", ERR_reason_error_string(ERR_get_error()));
351 return 1;
352 }
353
354 /* then set the maximum version */
355 if (tls_versions & NC_TLS_VERSION_13) {
356 rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_3_VERSION);
357 } else if (tls_versions & NC_TLS_VERSION_12) {
358 rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_2_VERSION);
359 } else if (tls_versions & NC_TLS_VERSION_11) {
360 rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_1_VERSION);
361 } else if (tls_versions & NC_TLS_VERSION_10) {
362 rc = SSL_CTX_set_max_proto_version(tls_cfg, TLS1_VERSION);
363 }
364 if (!rc) {
365 ERR(NULL, "Setting TLS max version failed (%s).", ERR_reason_error_string(ERR_get_error()));
366 return 1;
367 }
368
369 return 0;
370}
371
372static int
373nc_server_tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
374{
375 int ret = 0, depth, err;
376 struct nc_tls_verify_cb_data *data;
377 SSL *ssl;
378 X509 *cert;
379
380 /* retrieve callback data stored in the SSL struct */
381 ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
382 data = SSL_get_ex_data(ssl, 0);
383
384 /* get current cert and its depth */
385 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
386 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
387
388 if (preverify_ok) {
389 /* in-built verification was successful */
390 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
391 } else {
392 /* in-built verification failed, but the client still may be authenticated if:
393 * 1) the peer cert matches any configured end-entity cert
394 * 2) the peer cert has a valid chain of trust to any configured certificate authority cert
395 * otherwise just continue until we reach the peer cert (depth = 0)
396 */
397 err = X509_STORE_CTX_get_error(x509_ctx);
398 if ((depth == 0) && (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)) {
399 /* not trusted self-signed peer certificate, case 1) */
400 ret = nc_server_tls_verify_cert(cert, depth, 1, data);
401 } else if ((err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) || (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)) {
402 /* full chain of trust is invalid, but it may be valid partially, case 2) */
403 ret = nc_server_tls_verify_cert(cert, depth, 0, data);
404 } else {
405 VRB(NULL, "Cert verify: fail (%s).", X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
406 ret = 1;
407 }
408 }
409
410 if (ret == -1) {
411 /* fatal error */
412 return 0;
413 } else if (!ret) {
414 /* success */
415 return 1;
416 } else {
417 if (depth > 0) {
418 /* chain verify failed */
419 return 1;
420 } else {
421 /* peer cert did not match */
422 return 0;
423 }
424 }
425}
426
427void
428nc_server_tls_set_verify_cb_wrap(void *tls_session, struct nc_tls_verify_cb_data *cb_data)
429{
430 SSL_set_ex_data(tls_session, 0, cb_data);
431 SSL_set_verify(tls_session, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_server_tls_verify_cb);
432}
433
434char *
435nc_server_tls_get_subject_wrap(void *cert)
436{
437 return X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
438}
439
440char *
441nc_server_tls_get_issuer_wrap(void *cert)
442{
443 return X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
444}
445
446int
447nc_server_tls_get_username_from_cert_wrap(void *cert, NC_TLS_CTN_MAPTYPE map_type, char **username)
448{
449 STACK_OF(GENERAL_NAME) * san_names;
450 GENERAL_NAME *san_name;
451 ASN1_OCTET_STRING *ip;
452 int i, san_count;
453 char *subject, *common_name;
454 X509 *peer_cert = cert;
455
456 *username = NULL;
457
458 if (map_type == NC_TLS_CTN_COMMON_NAME) {
459 subject = nc_server_tls_get_subject_wrap(peer_cert);
460 NC_CHECK_ERRMEM_RET(!subject, -1);
461 common_name = strstr(subject, "CN=");
462 if (!common_name) {
463 WRN(NULL, "Certificate does not include the commonName field.");
464 free(subject);
465 return 1;
466 }
467 common_name += 3;
468 if (strchr(common_name, '/')) {
469 *strchr(common_name, '/') = '\0';
470 }
471 *username = strdup(common_name);
472 free(subject);
473 NC_CHECK_ERRMEM_RET(!*username, -1);
474 } else {
475 /* retrieve subjectAltName's rfc822Name (email), dNSName and iPAddress values */
476 san_names = X509_get_ext_d2i(peer_cert, NID_subject_alt_name, NULL, NULL);
477 if (!san_names) {
478 WRN(NULL, "Certificate has no SANs or failed to retrieve them.");
479 return 1;
480 }
481
482 san_count = sk_GENERAL_NAME_num(san_names);
483 for (i = 0; i < san_count; ++i) {
484 san_name = sk_GENERAL_NAME_value(san_names, i);
485
486 /* rfc822Name (email) */
487 if (((map_type == NC_TLS_CTN_SAN_ANY) || (map_type == NC_TLS_CTN_SAN_RFC822_NAME)) &&
488 (san_name->type == GEN_EMAIL)) {
489 *username = strdup((char *)ASN1_STRING_get0_data(san_name->d.rfc822Name));
490 NC_CHECK_ERRMEM_RET(!*username, -1);
491 break;
492 }
493
494 /* dNSName */
495 if (((map_type == NC_TLS_CTN_SAN_ANY) || (map_type == NC_TLS_CTN_SAN_DNS_NAME)) &&
496 (san_name->type == GEN_DNS)) {
497 *username = strdup((char *)ASN1_STRING_get0_data(san_name->d.dNSName));
498 NC_CHECK_ERRMEM_RET(!*username, -1);
499 break;
500 }
501
502 /* iPAddress */
503 if (((map_type == NC_TLS_CTN_SAN_ANY) || (map_type == NC_TLS_CTN_SAN_IP_ADDRESS)) &&
504 (san_name->type == GEN_IPADD)) {
505 ip = san_name->d.iPAddress;
506 if (ip->length == 4) {
507 if (asprintf(username, "%d.%d.%d.%d", ip->data[0], ip->data[1], ip->data[2], ip->data[3]) == -1) {
508 ERRMEM;
509 sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
510 return -1;
511 }
512 break;
513 } else if (ip->length == 16) {
514 if (asprintf(username, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
515 ip->data[0], ip->data[1], ip->data[2], ip->data[3], ip->data[4], ip->data[5],
516 ip->data[6], ip->data[7], ip->data[8], ip->data[9], ip->data[10], ip->data[11],
517 ip->data[12], ip->data[13], ip->data[14], ip->data[15]) == -1) {
518 ERRMEM;
519 sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
520 return -1;
521 }
522 break;
523 } else {
524 WRN(NULL, "SAN IP address in an unknown format (length is %d).", ip->length);
525 }
526 }
527 }
528 sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free); // TODO
529
530 if (i == san_count) {
531 switch (map_type) {
532 case NC_TLS_CTN_SAN_RFC822_NAME:
533 WRN(NULL, "Certificate does not include the SAN rfc822Name field.");
534 break;
535 case NC_TLS_CTN_SAN_DNS_NAME:
536 WRN(NULL, "Certificate does not include the SAN dNSName field.");
537 break;
538 case NC_TLS_CTN_SAN_IP_ADDRESS:
539 WRN(NULL, "Certificate does not include the SAN iPAddress field.");
540 break;
541 case NC_TLS_CTN_SAN_ANY:
542 WRN(NULL, "Certificate does not include any relevant SAN fields.");
543 break;
544 default:
545 break;
546 }
547 return 1;
548 }
549 }
550
551 return 0;
552}
553
554int
555nc_server_tls_certs_match_wrap(void *cert1, void *cert2)
556{
557 return !X509_cmp(cert1, cert2);
558}
559
560int
561nc_server_tls_md5_wrap(void *cert, unsigned char *buf)
562{
563 int rc;
564
565 rc = X509_digest(cert, EVP_md5(), buf, NULL);
566 if (rc) {
567 ERR(NULL, "Calculating MD-5 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
568 return 1;
569 }
570
571 return 0;
572}
573
574int
575nc_server_tls_sha1_wrap(void *cert, unsigned char *buf)
576{
577 int rc;
578
579 rc = X509_digest(cert, EVP_sha1(), buf, NULL);
580 if (rc) {
581 ERR(NULL, "Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
582 return 1;
583 }
584
585 return 0;
586}
587
588int
589nc_server_tls_sha224_wrap(void *cert, unsigned char *buf)
590{
591 int rc;
592
593 rc = X509_digest(cert, EVP_sha224(), buf, NULL);
594 if (rc) {
595 ERR(NULL, "Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
596 return 1;
597 }
598
599 return 0;
600}
601
602int
603nc_server_tls_sha256_wrap(void *cert, unsigned char *buf)
604{
605 int rc;
606
607 rc = X509_digest(cert, EVP_sha256(), buf, NULL);
608 if (rc) {
609 ERR(NULL, "Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
610 return 1;
611 }
612
613 return 0;
614}
615
616int
617nc_server_tls_sha384_wrap(void *cert, unsigned char *buf)
618{
619 int rc;
620
621 rc = X509_digest(cert, EVP_sha384(), buf, NULL);
622 if (rc) {
623 ERR(NULL, "Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
624 return 1;
625 }
626
627 return 0;
628}
629
630int
631nc_server_tls_sha512_wrap(void *cert, unsigned char *buf)
632{
633 int rc;
634
635 rc = X509_digest(cert, EVP_sha512(), buf, NULL);
636 if (rc) {
637 ERR(NULL, "Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
638 return 1;
639 }
640
641 return 0;
642}
643
644void
645nc_server_tls_set_fd_wrap(void *tls_session, int sock, struct nc_tls_ctx *UNUSED(tls_ctx))
646{
647 SSL_set_fd(tls_session, sock);
648}
649
650int
651nc_server_tls_handshake_step_wrap(void *tls_session)
652{
653 int ret = 0;
654
655 ret = SSL_accept(tls_session);
656 if (ret == 1) {
657 return 1;
658 } else if (ret == -1) {
659 if ((SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_READ) || (SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_WRITE)) {
660 return 0;
661 }
662 }
663
664 return -1;
665}
666
667int
668nc_client_tls_handshake_step_wrap(void *tls_session)
669{
670 int ret = 0;
671
672 ret = SSL_connect(tls_session);
673 if (ret == 1) {
674 return 1;
675 } else if (ret == -1) {
676 if ((SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_READ) || (SSL_get_error(tls_session, ret) == SSL_ERROR_WANT_WRITE)) {
677 return 0;
678 }
679 }
680
681 return -1;
682}
683
684void
685nc_tls_ctx_destroy_wrap(struct nc_tls_ctx *UNUSED(tls_ctx))
686{
687 return;
688}
689
690int
691nc_client_tls_load_cert_key_wrap(const char *cert_path, const char *key_path, void **cert, void **pkey)
692{
693 BIO *bio;
694 X509 *cert_tmp;
695 EVP_PKEY *pkey_tmp;
696
697 bio = BIO_new_file(cert_path, "r");
698 if (!bio) {
699 ERR(NULL, "Opening the client certificate file \"%s\" failed.", cert_path);
700 return 1;
701 }
702
703 cert_tmp = PEM_read_bio_X509(bio, NULL, NULL, NULL);
704 BIO_free(bio);
705 if (!cert_tmp) {
706 ERR(NULL, "Parsing the client certificate file \"%s\" failed.", cert_path);
707 return 1;
708 }
709
710 bio = BIO_new_file(key_path, "r");
711 if (!bio) {
712 ERR(NULL, "Opening the client private key file \"%s\" failed.", key_path);
713 X509_free(cert_tmp);
714 return 1;
715 }
716
717 pkey_tmp = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
718 BIO_free(bio);
719 if (!pkey_tmp) {
720 ERR(NULL, "Parsing the client private key file \"%s\" failed.", key_path);
721 X509_free(cert_tmp);
722 return 1;
723 }
724
725 *cert = cert_tmp;
726 *pkey = pkey_tmp;
727
728 return 0;
729}
730
731int
732nc_client_tls_load_trusted_certs_wrap(void *cert_store, const char *file_path, const char *dir_path)
733{
734 if (!X509_STORE_load_locations(cert_store, file_path, dir_path)) {
735 ERR(NULL, "Loading CA certs from file \"%s\" or directory \"%s\" failed (%s).", file_path, dir_path, ERR_reason_error_string(ERR_get_error()));
736 return 1;
737 }
738
739 return 0;
740}
741
742int
743nc_client_tls_load_crl_wrap(void *cert_store, void *UNUSED(crl_store), const char *file_path, const char *dir_path)
744{
745 if (!X509_STORE_load_locations(cert_store, file_path, dir_path)) {
746 ERR(NULL, "Loading CRLs from file \"%s\" or directory \"%s\" failed (%s).", file_path, dir_path, ERR_reason_error_string(ERR_get_error()));
747 return 1;
748 }
749
750 return 0;
751}
752
753int
754nc_client_tls_set_hostname_wrap(void *tls_session, const char *hostname)
755{
756 int ret = 0;
757 X509_VERIFY_PARAM *vpm = NULL;
758
759 vpm = X509_VERIFY_PARAM_new();
760 NC_CHECK_ERRMEM_RET(!vpm, 1);
761
762 if (!X509_VERIFY_PARAM_set1_host(vpm, hostname, 0)) {
763 ERR(NULL, "Failed to set expected hostname (%s).", ERR_reason_error_string(ERR_get_error()));
764 ret = 1;
765 goto cleanup;
766 }
767 if (!SSL_CTX_set1_param(tls_session, vpm)) {
768 ERR(NULL, "Failed to set verify param (%s).", ERR_reason_error_string(ERR_get_error()));
769 ret = 1;
770 goto cleanup;
771 }
772
773cleanup:
774 X509_VERIFY_PARAM_free(vpm);
775 return ret;
776}
777
778uint32_t
779nc_tls_get_verify_result_wrap(void *tls_session)
780{
781 return SSL_get_verify_result(tls_session);
782}
783
784const char *
785nc_tls_verify_error_string_wrap(uint32_t err_code)
786{
787 return X509_verify_cert_error_string(err_code);
788}
789
790void
791nc_tls_print_error_string_wrap(int connect_ret, const char *peername, void *tls_session)
792{
793 switch (SSL_get_error(tls_session, connect_ret)) {
794 case SSL_ERROR_SYSCALL:
795 ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, errno ? strerror(errno) : "unexpected EOF");
796 break;
797 case SSL_ERROR_SSL:
798 ERR(NULL, "TLS connection to \"%s\" failed (%s).", peername, ERR_reason_error_string(ERR_get_error()));
799 break;
800 default:
801 ERR(NULL, "TLS connection to \"%s\" failed.", peername);
802 break;
803 }
804}
805
806void
807nc_server_tls_print_accept_error_wrap(int accept_ret, void *tls_session)
808{
809 switch (SSL_get_error(tls_session, accept_ret)) {
810 case SSL_ERROR_SYSCALL:
811 ERR(NULL, "TLS accept failed (%s).", strerror(errno));
812 break;
813 case SSL_ERROR_SSL:
814 ERR(NULL, "TLS accept failed (%s).", ERR_reason_error_string(ERR_get_error()));
815 break;
816 default:
817 ERR(NULL, "TLS accept failed.");
818 break;
819 }
820}
821
822int
823nc_der_to_pubkey_wrap(const unsigned char *der, long len)
824{
825 int ret;
826 EVP_PKEY *pkey;
827
828 pkey = d2i_PUBKEY(NULL, &der, len);
829 if (pkey) {
830 /* success */
831 ret = 0;
832 } else {
833 /* fail */
834 ret = 1;
835 }
836
837 EVP_PKEY_free(pkey);
838 return ret;
839}
840
841int
842nc_base64_decode_wrap(const char *base64, char **bin)
843{
844 BIO *bio, *bio64 = NULL;
845 size_t used = 0, size = 0, r = 0;
846 void *tmp = NULL;
847 int nl_count, i, remainder, ret = 0;
848 char *b64;
849
850 /* insert new lines into the base64 string, so BIO_read works correctly */
851 nl_count = strlen(base64) / 64;
852 remainder = strlen(base64) - 64 * nl_count;
853 b64 = calloc(strlen(base64) + nl_count + 1, 1);
854 NC_CHECK_ERRMEM_RET(!b64, -1);
855
856 for (i = 0; i < nl_count; i++) {
857 /* copy 64 bytes and add a NL */
858 strncpy(b64 + i * 65, base64 + i * 64, 64);
859 b64[i * 65 + 64] = '\n';
860 }
861
862 /* copy the rest */
863 strncpy(b64 + i * 65, base64 + i * 64, remainder);
864
865 bio64 = BIO_new(BIO_f_base64());
866 if (!bio64) {
867 ERR(NULL, "Error creating a bio (%s).", ERR_reason_error_string(ERR_get_error()));
868 ret = -1;
869 goto cleanup;
870 }
871
872 bio = BIO_new_mem_buf(b64, strlen(b64));
873 if (!bio) {
874 ERR(NULL, "Error creating a bio (%s).", ERR_reason_error_string(ERR_get_error()));
875 ret = -1;
876 goto cleanup;
877 }
878
879 BIO_push(bio64, bio);
880
881 /* store the decoded base64 in bin */
882 *bin = NULL;
883 do {
884 size += 64;
885
886 tmp = realloc(*bin, size);
887 if (!tmp) {
888 ERRMEM;
889 free(*bin);
890 *bin = NULL;
891 ret = -1;
892 goto cleanup;
893 }
894 *bin = tmp;
895
896 r = BIO_read(bio64, *bin + used, 64);
897 used += r;
898 } while (r == 64);
899
900 ret = size;
901
902cleanup:
903 free(b64);
904 BIO_free_all(bio64);
905 return ret;
906}
907
908int
909nc_base64_encode_wrap(const unsigned char *bin, size_t len, char **base64)
910{
911 BIO *bio = NULL, *b64 = NULL;
912 BUF_MEM *bptr;
913 int ret = 0;
914
915 bio = BIO_new(BIO_s_mem());
916 if (!bio) {
917 ERR(NULL, "Error creating a bio (%s).", ERR_reason_error_string(ERR_get_error()));
918 ret = -1;
919 goto cleanup;
920 }
921
922 b64 = BIO_new(BIO_f_base64());
923 if (!b64) {
924 ERR(NULL, "Error creating a bio (%s).", ERR_reason_error_string(ERR_get_error()));
925 ret = -1;
926 goto cleanup;
927 }
928
929 bio = BIO_push(b64, bio);
930 BIO_write(bio, bin, len);
931 if (BIO_flush(bio) != 1) {
932 ERR(NULL, "Error flushing the bio (%s).", ERR_reason_error_string(ERR_get_error()));
933 ret = -1;
934 goto cleanup;
935 }
936
937 BIO_get_mem_ptr(bio, &bptr);
938 *base64 = strndup(bptr->data, bptr->length);
939 NC_CHECK_ERRMEM_GOTO(!*base64, ret = -1, cleanup);
940
941cleanup:
942 BIO_free_all(bio);
943 return ret;
944}
945
946static char *
947nc_ssl_error_get_reasons(void)
948{
949 unsigned int e;
950 int reason_size, reason_len;
951 char *reasons = NULL;
952
953 reason_size = 1;
954 reason_len = 0;
955 while ((e = ERR_get_error())) {
956 if (reason_len) {
957 /* add "; " */
958 reason_size += 2;
959 reasons = nc_realloc(reasons, reason_size);
960 NC_CHECK_ERRMEM_RET(!reasons, NULL);
961 reason_len += sprintf(reasons + reason_len, "; ");
962 }
963 reason_size += strlen(ERR_reason_error_string(e));
964 reasons = nc_realloc(reasons, reason_size);
965 NC_CHECK_ERRMEM_RET(!reasons, NULL);
966 reason_len += sprintf(reasons + reason_len, "%s", ERR_reason_error_string(e));
967 }
968
969 return reasons;
970}
971
972int
973nc_tls_read_wrap(struct nc_session *session, unsigned char *buf, size_t size)
974{
975 int rc, err;
976 char *reasons;
977 SSL *tls_session = session->ti.tls.session;
978
979 ERR_clear_error();
980 rc = SSL_read(tls_session, buf, size);
981 if (rc <= 0) {
982 err = SSL_get_error(tls_session, rc);
983 switch (err) {
984 case SSL_ERROR_WANT_READ:
985 case SSL_ERROR_WANT_WRITE:
986 rc = 0;
987 break;
988 case SSL_ERROR_ZERO_RETURN:
989 ERR(session, "Communication socket unexpectedly closed (OpenSSL).");
990 session->status = NC_STATUS_INVALID;
991 session->term_reason = NC_SESSION_TERM_DROPPED;
992 rc = -1;
993 break;
994 case SSL_ERROR_SYSCALL:
995 ERR(session, "TLS socket error (%s).", errno ? strerror(errno) : "unexpected EOF");
996 session->status = NC_STATUS_INVALID;
997 session->term_reason = NC_SESSION_TERM_OTHER;
998 rc = -1;
999 break;
1000 case SSL_ERROR_SSL:
1001 reasons = nc_ssl_error_get_reasons();
1002 ERR(session, "TLS communication error (%s).", reasons);
1003 free(reasons);
1004 session->status = NC_STATUS_INVALID;
1005 session->term_reason = NC_SESSION_TERM_OTHER;
1006 rc = -1;
1007 break;
1008 default:
1009 ERR(session, "Unknown TLS error occurred (err code %d).", err);
1010 session->status = NC_STATUS_INVALID;
1011 session->term_reason = NC_SESSION_TERM_OTHER;
1012 rc = -1;
1013 break;
1014 }
1015 }
1016
1017 return rc;
1018}
1019
1020int
1021nc_tls_write_wrap(struct nc_session *session, const unsigned char *buf, size_t size)
1022{
1023 int rc, err;
1024 char *reasons;
1025 SSL *tls_session = session->ti.tls.session;
1026
1027 ERR_clear_error();
1028 rc = SSL_write(tls_session, buf, size);
1029 if (rc < 1) {
1030 err = SSL_get_error(tls_session, rc);
1031 switch (err) {
1032 case SSL_ERROR_WANT_WRITE:
1033 case SSL_ERROR_WANT_READ:
1034 rc = 0;
1035 break;
1036 case SSL_ERROR_ZERO_RETURN:
1037 ERR(session, "TLS connection was properly closed.");
1038 rc = -1;
1039 break;
1040 case SSL_ERROR_SYSCALL:
1041 ERR(session, "TLS socket error (%s).", errno ? strerror(errno) : "unexpected EOF");
1042 rc = -1;
1043 break;
1044 case SSL_ERROR_SSL:
1045 reasons = nc_ssl_error_get_reasons();
1046 ERR(session, "TLS communication error (%s).", reasons);
1047 free(reasons);
1048 rc = -1;
1049 break;
1050 default:
1051 ERR(session, "Unknown TLS error occurred (err code %d).", err);
1052 rc = -1;
1053 break;
1054 }
1055 }
1056
1057 return rc;
1058}
1059
1060int
1061nc_tls_have_pending_wrap(void *tls_session)
1062{
1063 return SSL_pending(tls_session);
1064}
1065
1066int
1067nc_tls_get_fd_wrap(const struct nc_session *session)
1068{
1069 return SSL_get_fd(session->ti.tls.session);
1070}
1071
1072void
1073nc_tls_close_notify_wrap(void *tls_session)
1074{
1075 SSL_shutdown(tls_session);
1076}
1077
1078void *
1079nc_tls_import_key_file_wrap(const char *key_path, FILE *file)
1080{
1081 EVP_PKEY *pkey;
1082
1083 pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
1084 if (!pkey) {
1085 ERR(NULL, "Parsing the private key file \"%s\" failed (%s).", key_path, ERR_reason_error_string(ERR_get_error()));
1086 }
1087
1088 return pkey;
1089}
1090
1091void *
1092nc_tls_import_cert_file_wrap(const char *cert_path)
1093{
1094 X509 *cert;
1095 FILE *file;
1096
1097 file = fopen(cert_path, "r");
1098 if (!file) {
1099 ERR(NULL, "Opening the certificate file \"%s\" failed.", cert_path);
1100 return NULL;
1101 }
1102
1103 cert = PEM_read_X509(file, NULL, NULL, NULL);
1104 fclose(file);
1105 if (!cert) {
1106 ERR(NULL, "Parsing the certificate file \"%s\" failed (%s).", cert_path, ERR_reason_error_string(ERR_get_error()));
1107 }
1108 return cert;
1109}
1110
1111char *
1112nc_tls_export_key_wrap(void *pkey)
1113{
1114 BIO *bio = NULL;
1115 char *pem = NULL;
1116
1117 bio = BIO_new(BIO_s_mem());
1118 if (!bio) {
1119 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1120 goto cleanup;
1121 }
1122
1123 if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) {
1124 ERR(NULL, "Exporting the private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1125 goto cleanup;
1126 }
1127
1128 pem = malloc(BIO_number_written(bio) + 1);
1129 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1130
1131 BIO_read(bio, pem, BIO_number_written(bio));
1132 pem[BIO_number_written(bio)] = '\0';
1133
1134cleanup:
1135 BIO_free(bio);
1136 return pem;
1137}
1138
1139char *
1140nc_tls_export_cert_wrap(void *cert)
1141{
1142 int rc, cert_len;
1143 BIO *bio = NULL;
1144 char *pem = NULL;
1145
1146 bio = BIO_new(BIO_s_mem());
1147 if (!bio) {
1148 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1149 goto cleanup;
1150 }
1151
1152 rc = PEM_write_bio_X509(bio, cert);
1153 if (!rc) {
1154 ERR(NULL, "Exporting the certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
1155 goto cleanup;
1156 }
1157
1158 cert_len = BIO_pending(bio);
1159 if (cert_len <= 0) {
1160 ERR(NULL, "Getting the certificate length failed (%s).", ERR_reason_error_string(ERR_get_error()));
1161 goto cleanup;
1162 }
1163
1164 pem = malloc(cert_len + 1);
1165 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1166
1167 /* read the cert from bio */
1168 rc = BIO_read(bio, pem, cert_len);
1169 if (rc <= 0) {
1170 ERR(NULL, "Reading the certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
1171 free(pem);
1172 pem = NULL;
1173 goto cleanup;
1174 }
1175
1176 pem[cert_len] = '\0';
1177
1178cleanup:
1179 BIO_free(bio);
1180 return pem;
1181}
1182
1183char *
1184nc_tls_export_pubkey_wrap(void *pkey)
1185{
1186 BIO *bio = NULL;
1187 char *pem = NULL;
1188
1189 bio = BIO_new(BIO_s_mem());
1190 if (!bio) {
1191 ERR(NULL, "Creating new bio failed (%s).", ERR_reason_error_string(ERR_get_error()));
1192 goto cleanup;
1193 }
1194
1195 if (!PEM_write_bio_PUBKEY(bio, pkey)) {
1196 ERR(NULL, "Exporting the public key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1197 goto cleanup;
1198 }
1199
1200 pem = malloc(BIO_number_written(bio) + 1);
1201 NC_CHECK_ERRMEM_GOTO(!pem, , cleanup);
1202
1203 BIO_read(bio, pem, BIO_number_written(bio));
1204 pem[BIO_number_written(bio)] = '\0';
1205
1206cleanup:
1207 BIO_free(bio);
1208 return pem;
1209}
1210
1211int
1212nc_tls_export_key_der_wrap(void *pkey, unsigned char **der, size_t *size)
1213{
1214 *der = NULL;
1215
1216 *size = i2d_PrivateKey(pkey, der);
1217 if (*size < 0) {
1218 ERR(NULL, "Exporting the private key to DER format failed (%s).", ERR_reason_error_string(ERR_get_error()));
1219 return 1;
1220 }
1221
1222 return 0;
1223}
1224
1225int
1226nc_tls_privkey_is_rsa_wrap(void *pkey)
1227{
1228 return EVP_PKEY_is_a(pkey, "RSA");
1229}
1230
1231int
1232nc_tls_get_rsa_pubkey_params_wrap(void *pkey, void **e, void **n)
1233{
1234 BIGNUM *exp, *mod;
1235
1236 if (!EVP_PKEY_get_bn_param(pkey, "e", &exp)) {
1237 ERR(NULL, "Getting the RSA public exponent failed (%s).", ERR_reason_error_string(ERR_get_error()));
1238 return 1;
1239 }
1240
1241 if (!EVP_PKEY_get_bn_param(pkey, "n", &mod)) {
1242 ERR(NULL, "Getting the RSA modulus failed (%s).", ERR_reason_error_string(ERR_get_error()));
1243 BN_free(exp);
1244 return 1;
1245 }
1246
1247 *e = exp;
1248 *n = mod;
1249 return 0;
1250}
1251
1252int
1253nc_tls_privkey_is_ec_wrap(void *pkey)
1254{
1255 return EVP_PKEY_is_a(pkey, "EC");
1256}
1257
1258char *
1259nc_tls_get_ec_group_wrap(void *pkey)
1260{
1261 size_t ec_group_len = 0;
1262 char *ec_group = NULL;
1263
1264 if (!EVP_PKEY_get_utf8_string_param(pkey, "group", NULL, 0, &ec_group_len)) {
1265 ERR(NULL, "Getting EC group length failed (%s).", ERR_reason_error_string(ERR_get_error()));
1266 return NULL;
1267 }
1268
1269 /* alloc mem for group + 1 for \0 */
1270 ec_group = malloc(ec_group_len + 1);
1271 NC_CHECK_ERRMEM_RET(!ec_group, NULL);
1272
1273 /* get the group */
1274 if (!EVP_PKEY_get_utf8_string_param(pkey, "group", ec_group, ec_group_len + 1, NULL)) {
1275 ERR(NULL, "Getting EC group failed (%s).", ERR_reason_error_string(ERR_get_error()));
1276 free(ec_group);
1277 return NULL;
1278 }
1279
1280 return ec_group;
1281}
1282
1283int
1284nc_tls_get_ec_pubkey_param_wrap(void *pkey, unsigned char **bin, int *bin_len)
1285{
1286 int ret = 0;
1287 BIGNUM *p;
1288
1289 if (!EVP_PKEY_get_bn_param(pkey, "p", &p)) {
1290 ERR(NULL, "Getting public key point from the EC private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
1291 ret = 1;
1292 goto cleanup;
1293 }
1294
1295 /* prepare buffer for converting p to binary */
1296 *bin = malloc(BN_num_bytes(p));
1297 NC_CHECK_ERRMEM_GOTO(!*bin, ret = 1, cleanup);
1298
1299 /* convert to binary */
1300 *bin_len = BN_bn2bin(p, *bin);
1301
1302cleanup:
1303 BN_free(p);
1304 return ret;
1305}
1306
1307int
1308nc_tls_get_bn_num_bytes_wrap(void *bn)
1309{
1310 return BN_num_bytes(bn);
1311}
1312
1313void
1314nc_tls_bn_bn2bin_wrap(void *bn, unsigned char *bin)
1315{
1316 BN_bn2bin(bn, bin);
1317}
1318
1319void *
1320nc_tls_import_pubkey_file_wrap(const char *pubkey_path)
1321{
1322 FILE *f;
1323 EVP_PKEY *pk = NULL;
1324
1325 f = fopen(pubkey_path, "r");
1326 if (!f) {
1327 ERR(NULL, "Unable to open file \"%s\".", pubkey_path);
1328 return NULL;
1329 }
1330
1331 /* read the pubkey from file */
1332 pk = PEM_read_PUBKEY(f, NULL, NULL, NULL);
1333 fclose(f);
1334 if (!pk) {
1335 ERR(NULL, "Reading public key from file \"%s\" failed (%s).", pubkey_path, ERR_reason_error_string(ERR_get_error()));
1336 return NULL;
1337 }
1338
1339 return pk;
1340}
roman275c3fb2024-04-05 12:29:11 +02001341
1342int
1343nc_server_tls_get_crl_distpoint_uris_wrap(void *cert_store, char ***uris, int *uri_count)
1344{
1345 int ret = 0, i, j, k, gtype;
1346 CURL *handle = NULL;
1347 struct nc_curl_data downloaded = {0};
1348
1349 STACK_OF(X509_OBJECT) * objs;
1350 X509_OBJECT *obj;
1351 X509 *cert;
1352
1353 STACK_OF(DIST_POINT) * dist_points;
1354 DIST_POINT *dist_point;
1355 GENERAL_NAMES *general_names;
1356 GENERAL_NAME *general_name;
1357 ASN1_STRING *asn_string_uri;
1358 const char *crl_distpoint_uri;
1359 void *tmp;
1360
1361 NC_CHECK_ARG_RET(NULL, cert_store, uris, uri_count, 1);
1362
1363 *uris = NULL;
1364 *uri_count = 0;
1365
1366 /* treat all entries in the cert_store as X509_OBJECTs */
1367 objs = X509_STORE_get0_objects(cert_store);
1368 if (!objs) {
1369 ERR(NULL, "Getting certificates from store failed (%s).", ERR_reason_error_string(ERR_get_error()));
1370 ret = -1;
1371 goto cleanup;
1372 }
1373
1374 /* iterate over all the CAs */
1375 for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
1376 obj = sk_X509_OBJECT_value(objs, i);
1377 cert = X509_OBJECT_get0_X509(obj);
1378 if (!cert) {
1379 /* the object on this index was not a certificate */
1380 continue;
1381 }
1382
1383 /* get all the distribution points for this CA */
1384 dist_points = X509_get_ext_d2i(cert, NID_crl_distribution_points, NULL, NULL);
1385
1386 /* iterate over all the dist points (there can be multiple for a single cert) */
1387 for (j = 0; j < sk_DIST_POINT_num(dist_points); j++) {
1388 dist_point = sk_DIST_POINT_value(dist_points, j);
1389 if (!dist_point) {
1390 continue;
1391 }
1392 general_names = dist_point->distpoint->name.fullname;
1393
1394 /* iterate over all the GeneralesNames in the distribution point */
1395 for (k = 0; k < sk_GENERAL_NAME_num(general_names); k++) {
1396 general_name = sk_GENERAL_NAME_value(general_names, k);
1397 asn_string_uri = GENERAL_NAME_get0_value(general_name, &gtype);
1398
1399 /* check if the general name is a URI and has a valid length */
1400 if ((gtype != GEN_URI) || (ASN1_STRING_length(asn_string_uri) <= 6)) {
1401 continue;
1402 }
1403
1404 /* found an URI */
1405 tmp = realloc(*uris, (*uri_count + 1) * sizeof **uris);
1406 NC_CHECK_ERRMEM_GOTO(!tmp, ret = 1, cleanup);
1407 *uris = tmp;
1408
1409 *uris[*uri_count] = strdup((const char *) ASN1_STRING_get0_data(asn_string_uri));
1410 NC_CHECK_ERRMEM_GOTO(!*uris[*uri_count], ret = 1, cleanup);
1411 ++(*uri_count);
1412 }
1413 }
1414 }
1415
1416cleanup:
1417 return ret;
1418}