tls_open_funcs.c (55736B)
1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ 2 /* 3 This file is part of GNU libmicrohttpd. 4 Copyright (C) 2024-2025 Evgeny Grin (Karlson2k) 5 6 GNU libmicrohttpd is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 GNU libmicrohttpd is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 Alternatively, you can redistribute GNU libmicrohttpd and/or 17 modify it under the terms of the GNU General Public License as 18 published by the Free Software Foundation; either version 2 of 19 the License, or (at your option) any later version, together 20 with the eCos exception, as follows: 21 22 As a special exception, if other files instantiate templates or 23 use macros or inline functions from this file, or you compile this 24 file and link it with other works to produce a work based on this 25 file, this file does not by itself cause the resulting work to be 26 covered by the GNU General Public License. However the source code 27 for this file must still be made available in accordance with 28 section (3) of the GNU General Public License v2. 29 30 This exception does not invalidate any other reasons why a work 31 based on this file might be covered by the GNU General Public 32 License. 33 34 You should have received copies of the GNU Lesser General Public 35 License and the GNU General Public License along with this library; 36 if not, see <https://www.gnu.org/licenses/>. 37 */ 38 39 /** 40 * @file src/mhd2/tls_open_funcs.c 41 * @brief The implementation of OpenSSL wrapper functions 42 * @author Karlson2k (Evgeny Grin) 43 */ 44 45 #include "mhd_sys_options.h" 46 47 #include "sys_bool_type.h" 48 #include "sys_base_types.h" 49 50 #include "compat_calloc.h" 51 #include "sys_malloc.h" 52 #include <string.h> 53 54 #ifdef mhd_USE_TLS_DEBUG_MESSAGES 55 # include <stdio.h> /* For TLS debug printing */ 56 #endif 57 58 #include "mhd_assert.h" 59 #include "mhd_unreachable.h" 60 #include "mhd_assume.h" 61 62 #include "mhd_str.h" 63 #include "mhd_conn_socket.h" 64 65 #include "mhd_tls_internal.h" 66 67 #include "tls_open_tls_lib.h" 68 69 #include "mhd_tls_ver_stct.h" 70 71 #include "tls_open_daemon_data.h" 72 #include "tls_open_conn_data.h" 73 #include "tls_open_funcs.h" 74 75 #include "daemon_options.h" 76 77 #include "daemon_logger.h" 78 79 #include "microhttpd2_portability.h" 80 #include "mhd_public_api.h" 81 82 #if defined(HAVE_WUSED_BUT_MARKED_UNUSED) && defined(MHD_WARN_IGNORE_STYLE_GCC) 83 # define mhd_NOWARN_USED_UNUSED \ 84 MHD_WARN_PUSH_ MHD_WARN_IGNORE_ ("-Wused-but-marked-unused") 85 # define mhd_RESTORE_WARN_USED_UNUSED MHD_WARN_POP_ 86 #else 87 # define mhd_NOWARN_USED_UNUSED /* empty */ 88 # define mhd_RESTORE_WARN_USED_UNUSED /* empty */ 89 #endif 90 91 #ifdef mhd_USE_TLS_DEBUG_MESSAGES 92 93 static MHD_FN_PAR_NONNULL_ (1) int 94 mhd_tls_open_dbg_print_errs (const char *msg, 95 size_t msg_len, 96 void *cls) 97 { 98 int ret; 99 int print_size = (int) msg_len; 100 101 (void) cls; /* Not used */ 102 103 if ((print_size < 0) || 104 (msg_len != (unsigned int) print_size)) 105 print_size = (int) ((~((unsigned int) 0u)) >> 1); 106 107 ret = fprintf (stderr, 108 "## OpenSSL error: %.*s\n", 109 print_size, msg); 110 (void) fflush (stderr); 111 return ret; 112 } 113 114 115 # define mhd_DBG_PRINT_TLS_ERRS() \ 116 ERR_print_errors_cb (&mhd_tls_open_dbg_print_errs, NULL) 117 118 # define mhd_DBG_PRINT_TLS_INFO_MSG(message) \ 119 do { (void) fprintf (stderr, "## OpenSSL info: %s\n", (message)); \ 120 (void) fflush (stderr);} while (0) 121 # define mhd_DBG_PRINT_TLS_INFO_PARAM1(message,param) \ 122 do { (void) fprintf (stderr, "## OpenSSL info: " message "\n", (param)); \ 123 (void) fflush (stderr);} while (0) 124 #else 125 # define mhd_DBG_PRINT_TLS_ERRS() ERR_clear_error () 126 # define mhd_DBG_PRINT_TLS_INFO_MSG(message) ((void) 0) 127 # define mhd_DBG_PRINT_TLS_INFO_PARAM1(message,param) ((void) 0) 128 #endif 129 130 /* ** Global initialisation / de-initialisation ** */ 131 132 static bool openssl_lib_inited = false; 133 134 MHD_INTERNAL void 135 mhd_tls_open_global_init_once (void) 136 { 137 const unsigned long ver_num = OpenSSL_version_num (); 138 /* Make sure that used shared OpenSSL library has least the same version as 139 MHD was configured for. Fail if the version is earlier. */ 140 openssl_lib_inited = ((0x900000UL < ver_num) /* Versions before 3.0 */ 141 && (OPENSSL_VERSION_NUMBER <= ver_num)); 142 143 /* The call of OPENSSL_init_ssl() typically not needed, but it won't hurt 144 if library was initialised automatically. 145 In some exotic situations automatic initialisation could fail, and 146 this call would make sure that the library is initialised before used. */ 147 openssl_lib_inited = openssl_lib_inited 148 && (0 < OPENSSL_init_ssl (0, NULL)); 149 } 150 151 152 MHD_INTERNAL MHD_FN_PURE_ bool 153 mhd_tls_open_is_inited_fine (void) 154 { 155 return openssl_lib_inited; 156 } 157 158 159 /* ** Daemon initialisation / de-initialisation ** */ 160 161 /** 162 * Check application-provided daemon TLS settings 163 * @param d the daemon handle 164 * @param sk_edge_trigg the sockets polling uses edge-triggering 165 * @param s the application-provided settings 166 * @return #MHD_SC_OK on success, 167 * error code otherwise 168 */ 169 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 170 check_app_tls_settings (struct MHD_Daemon *restrict d, 171 bool sk_edge_trigg, 172 struct DaemonOptions *restrict s) 173 { 174 mhd_assert (MHD_TLS_BACKEND_NONE != s->tls); 175 mhd_assert ((MHD_TLS_BACKEND_OPENSSL == s->tls) || \ 176 (MHD_TLS_BACKEND_ANY == s->tls)); 177 if (NULL == s->tls_cert_key.v_mem_cert) 178 { 179 mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \ 180 "No valid TLS certificate is provided"); 181 return MHD_SC_TLS_CONF_BAD_CERT; 182 } 183 mhd_assert (NULL != s->tls_cert_key.v_mem_key); 184 185 if (sk_edge_trigg) 186 { 187 mhd_LOG_MSG (d, MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS, \ 188 "Edge-triggered sockets polling cannot be used " 189 "with OpenSSL backend"); 190 return MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS; 191 } 192 193 return MHD_SC_OK; 194 } 195 196 197 /* Helper to prevent password prompts in terminal */ 198 static int 199 null_passwd_cb (char *buf, 200 int size, 201 int rwflag, 202 void *cls) 203 { 204 (void) buf; (void) size; (void) rwflag; (void) cls; /* Unused */ 205 mhd_DBG_PRINT_TLS_INFO_MSG ("The NULL passphrase callback is called\n"); 206 return 0; 207 } 208 209 210 /** 211 * Create new empty OpenSSL library context 212 * @param d the daemon handle 213 * @param d_tls the daemon TLS settings 214 * @return 'true' on success, 215 * 'false' otherwise 216 */ 217 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ bool 218 create_lib_ctx (struct MHD_Daemon *restrict d, 219 struct mhd_TlsOpenDaemonData *restrict d_tls) 220 { 221 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY 222 (void) d; /* Used for logging only */ 223 #endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */ 224 mhd_assert (NULL == d_tls->libctx); 225 226 d_tls->libctx = OSSL_LIB_CTX_new (); 227 228 if (NULL == d_tls->libctx) 229 { 230 mhd_DBG_PRINT_TLS_ERRS (); 231 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 232 "Failed to create TLS library context"); 233 return false; 234 } 235 return true; 236 } 237 238 239 /** 240 * Reset OpenSSL library context. 241 * 242 * This function must not be called if library context is being used. 243 * @param d the daemon handle 244 * @param d_tls the daemon TLS settings 245 * @return 'true' on success, 246 * 'false' otherwise 247 */ 248 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ bool 249 reset_lib_ctx (struct MHD_Daemon *restrict d, 250 struct mhd_TlsOpenDaemonData *restrict d_tls) 251 { 252 mhd_assert (NULL != d_tls->libctx); 253 254 OSSL_LIB_CTX_free (d_tls->libctx); 255 d_tls->libctx = NULL; 256 257 return create_lib_ctx (d, 258 d_tls); 259 } 260 261 262 /** 263 * Get non-default pathname for OpenSSL configuration file 264 * @param s the application-provided settings 265 * @param[out] conf_pathname set to the pathname on success 266 * @return #MHD_SC_OK on success, 267 * error code otherwise 268 */ 269 static MHD_FN_PAR_NONNULL_ALL_ 270 MHD_FN_PAR_OUT_ (2) MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 271 daemon_get_conf_file (struct DaemonOptions *restrict s, 272 char **restrict conf_pathname) 273 { 274 size_t name_len; 275 bool has_path; 276 277 mhd_assert (NULL != s->tls_openssl_def_file.v_pathname); 278 279 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY 280 (void) d; /* Used only for logging */ 281 #endif 282 283 /* Handle custom pathname */ 284 285 name_len = strlen (s->tls_openssl_def_file.v_pathname); 286 has_path = (NULL != memchr (s->tls_openssl_def_file.v_pathname, 287 '/', 288 name_len)); 289 #ifdef _WIN32 290 has_path = has_path || (NULL != memchr (s->tls_openssl_def_file, 291 '\\', 292 name_len)); 293 #endif /* _WIN32 */ 294 295 if ((! has_path) && (0u != name_len)) 296 { 297 const char *def_path; 298 size_t def_path_len; 299 300 def_path = X509_get_default_cert_area (); 301 if (NULL == def_path) 302 { 303 mhd_DBG_PRINT_TLS_ERRS (); 304 mhd_DBG_PRINT_TLS_INFO_MSG ("X509_get_default_cert_area() returned NULL"); 305 return MHD_SC_TLS_DAEMON_INIT_FAILED; /* Unrealistic */ 306 } 307 308 def_path_len = strlen (def_path); 309 310 *conf_pathname = 311 (char *) OPENSSL_malloc (def_path_len + 1u + name_len + 1u); 312 if (NULL == *conf_pathname) 313 return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; 314 315 memcpy (*conf_pathname, 316 def_path, 317 def_path_len); 318 (*conf_pathname)[def_path_len] = '/'; 319 memcpy ((*conf_pathname) + def_path_len + 1u, 320 s->tls_openssl_def_file.v_pathname, 321 name_len + 1u); 322 323 return MHD_SC_OK; 324 } 325 326 *conf_pathname = (char *) OPENSSL_malloc (name_len + 1u); 327 if (NULL == *conf_pathname) 328 return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; 329 330 memcpy (*conf_pathname, 331 s->tls_openssl_def_file.v_pathname, 332 name_len + 1u); 333 334 return MHD_SC_OK; 335 } 336 337 338 #ifdef mhd_TLS_OPEN_HAS_CONF_DIAG 339 # define mhd_LIBCTX_FORBIDS_FALLBACKS(d_tls) \ 340 (0 != OSSL_LIB_CTX_get_conf_diagnostics (d_tls->libctx)) 341 #else 342 # define mhd_LIBCTX_FORBIDS_FALLBACKS(d_tls) ((void) (d_tls), ! ! 0) 343 #endif /* ! mhd_TLS_OPEN_HAS_CONF_DIAG */ 344 345 346 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) 347 MHD_FN_PAR_NONNULL_ (4) bool 348 daemon_load_conf_from_cfg (struct MHD_Daemon *restrict d, 349 const char *restrict filename, 350 const char *restrict app_name, 351 CONF *restrict cfg, 352 unsigned long load_flags, 353 bool log_missing_app_name) 354 { 355 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY 356 (void) d; /* Used for logging only */ 357 # ifndef mhd_USE_TLS_DEBUG_MESSAGES 358 (void) filename; /* Used for logs only */ 359 # endif /* mhd_USE_TLS_DEBUG_MESSAGES */ 360 #endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */ 361 362 if (NULL != app_name) 363 { 364 if (NULL == NCONF_get_string (cfg, 365 NULL, 366 app_name)) 367 { 368 if (log_missing_app_name) 369 mhd_LOG_PRINT (d, 370 MHD_SC_TLS_LIB_CONF_WARNING, 371 mhd_LOG_FMT ("TLS library configuration '%s' " 372 "was not found in file '%s'"), 373 app_name, 374 filename); 375 else 376 mhd_DBG_PRINT_TLS_INFO_PARAM1 ("TLS library configuration '%s' " 377 "was not found in the configuration " 378 "file", 379 app_name); 380 return false; 381 } 382 mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Trying to load configuration section " 383 "pointed by '%s'", 384 app_name); 385 } 386 else 387 mhd_DBG_PRINT_TLS_INFO_MSG ("Trying to load configuration section " 388 "pointed by default OpenSSL configuration"); 389 390 if (1 != CONF_modules_load (cfg, 391 app_name, 392 load_flags)) 393 { 394 mhd_DBG_PRINT_TLS_ERRS (); 395 396 mhd_LOG_PRINT (d, 397 MHD_SC_TLS_LIB_CONF_WARNING, 398 mhd_LOG_FMT ("Error loading TLS library " 399 "configuration '%s' " 400 "from file '%s'"), 401 app_name, 402 filename); 403 404 return false; 405 } 406 407 mhd_DBG_PRINT_TLS_INFO_MSG ("Successfully loaded OpenSSL configuration " 408 "from the configuration file"); 409 410 return true; 411 } 412 413 414 static MHD_FN_PAR_NONNULL_ALL_ 415 MHD_FN_PAR_INOUT_ (2) MHD_FN_PAR_INOUT_ (4) bool 416 cfg_reset_and_reload (struct MHD_Daemon *restrict d, 417 struct mhd_TlsOpenDaemonData *restrict d_tls, 418 const char *restrict filename, 419 CONF **restrict cfg_ptr) 420 { 421 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY 422 (void) d; /* Used for logging only */ 423 #endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */ 424 mhd_assert (NULL != *cfg_ptr); 425 426 mhd_DBG_PRINT_TLS_INFO_MSG ("Resetting library CTX, CONF and reloading " 427 "configuration file"); 428 429 /* Destroy old cfg, which is connected to the library CTX */ 430 NCONF_free (*cfg_ptr); 431 *cfg_ptr = NULL; 432 433 /* Reset OpenSSL library CTX, which may have partially applied configuration */ 434 if (! reset_lib_ctx (d, 435 d_tls)) 436 return false; 437 438 /* Create a new cfg connected to the new CTX */ 439 *cfg_ptr = NCONF_new_ex (d_tls->libctx, 440 NULL); 441 if (NULL == *cfg_ptr) 442 { 443 mhd_DBG_PRINT_TLS_ERRS (); 444 445 mhd_DBG_PRINT_TLS_INFO_MSG ("Failed to create a new OpenSSL CONF"); 446 return false; 447 } 448 449 if (0 >= NCONF_load (*cfg_ptr, 450 filename, 451 NULL)) 452 { 453 mhd_DBG_PRINT_TLS_ERRS (); 454 455 mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Failed to reload configuration file '%s'", 456 filename); 457 return false; 458 } 459 460 return true; 461 } 462 463 464 static inline MHD_FN_PAR_NONNULL_ALL_ bool 465 is_conf_file_fallback_allowed ( 466 const struct mhd_TlsOpenDaemonData *restrict d_tls, 467 const struct DaemonOptions *restrict s) 468 { 469 mhd_assert (NULL != d_tls->libctx); 470 471 if (! s->tls_openssl_def_file.v_disable_fallback) 472 return false; 473 if (mhd_LIBCTX_FORBIDS_FALLBACKS (d_tls)) 474 return false; 475 return true; 476 } 477 478 479 static inline MHD_FN_PAR_NONNULL_ALL_ bool 480 is_conf_fallback_allowed (const struct mhd_TlsOpenDaemonData *restrict d_tls, 481 const struct DaemonOptions *restrict s) 482 { 483 if (! s->tls_app_name.v_disable_fallback) 484 return false; 485 486 return is_conf_file_fallback_allowed (d_tls, 487 s); 488 } 489 490 491 /** 492 * Load OpenSSL configuration from OpenSSL configuration file 493 * @param d the daemon handle 494 * @param d_tls the daemon TLS settings 495 * @param s the application-provided settings 496 * @param use_custom_conf_pathname choose application-provided pathname or 497 * TLS backend default pathname 498 * @return #MHD_SC_OK on success, 499 * #MHD_SC_TLS_LIB_CONF_WARNING if configuration was not loaded due to 500 * non-fatal error, 501 * error code otherwise 502 */ 503 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3) 504 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 505 daemon_load_lib_conf (struct MHD_Daemon *restrict d, 506 struct mhd_TlsOpenDaemonData *restrict d_tls, 507 struct DaemonOptions *restrict s, 508 bool use_custom_conf_pathname) 509 { 510 char *conf_pathname; 511 CONF *conf; 512 enum MHD_StatusCode ret; 513 514 if (! use_custom_conf_pathname) 515 { 516 /* Use default pathname */ 517 conf_pathname = CONF_get1_default_config_file (); 518 519 if (NULL == conf_pathname) 520 { 521 mhd_DBG_PRINT_TLS_ERRS (); 522 523 ret = is_conf_fallback_allowed (d_tls, 524 s) 525 ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED; 526 527 mhd_LOG_MSG (d, ret, \ 528 "Failed to get default configuration file pathname"); 529 } 530 else 531 ret = MHD_SC_OK; 532 } 533 else 534 ret = daemon_get_conf_file (s, 535 &conf_pathname); 536 537 if (MHD_SC_OK != ret) 538 { 539 mhd_DBG_PRINT_TLS_INFO_MSG ("Failed to get configuration file pathname"); 540 return ret; 541 } 542 543 mhd_ASSUME (NULL != conf_pathname); 544 mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Trying '%s' as OpenSSL configuration file", 545 conf_pathname); 546 547 if ('\0' == conf_pathname[0]) 548 { 549 OPENSSL_free (conf_pathname); /* A short-cut */ 550 551 if (NULL == s->tls_app_name.v_app_name) 552 return MHD_SC_OK; /* No special "application name" profile is needed */ 553 554 if (! s->tls_app_name.v_disable_fallback) 555 return MHD_SC_OK; /* Initialisation allowed with default values */ 556 557 /* Load of special "application name" profile is required */ 558 559 if (! use_custom_conf_pathname) 560 return MHD_SC_TLS_DAEMON_INIT_FAILED; /* No fallback pathname */ 561 562 mhd_assert (NULL != s->tls_openssl_def_file.v_pathname); 563 564 if (s->tls_openssl_def_file.v_disable_fallback) 565 return MHD_SC_TLS_DAEMON_INIT_FAILED; /* Fallback pathname is disallowed */ 566 567 /* Try to use fallback pathname to load special "application name" profile */ 568 return MHD_SC_TLS_LIB_CONF_WARNING; 569 } 570 571 conf = NCONF_new_ex (d_tls->libctx, 572 NULL); 573 if (NULL == conf) 574 { 575 mhd_DBG_PRINT_TLS_ERRS (); 576 577 ret = is_conf_fallback_allowed (d_tls, 578 s) 579 ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED; 580 mhd_LOG_MSG (d, ret, \ 581 "Failed to create OpenSSL empty configuration object"); 582 } 583 584 if (MHD_SC_OK == ret) 585 { 586 long err_line_num; 587 mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Trying to load configuration file '%s'", 588 conf_pathname); 589 590 if (0 >= NCONF_load (conf, 591 conf_pathname, 592 &err_line_num)) 593 { 594 mhd_DBG_PRINT_TLS_ERRS (); 595 596 if (use_custom_conf_pathname) 597 ret = is_conf_file_fallback_allowed (d_tls, 598 s) 599 ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED; 600 else 601 ret = is_conf_fallback_allowed (d_tls, 602 s) 603 ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED; 604 605 mhd_LOG_PRINT (d, 606 ret, 607 mhd_LOG_FMT ("Error loading TLS library configuration " 608 "file '%s' at line %ld"), 609 conf_pathname, 610 err_line_num); 611 } 612 613 if (MHD_SC_OK == ret) 614 { 615 bool conf_loaded; 616 unsigned long flags; 617 618 flags = 0u; 619 if (! s->tls_app_name.v_disable_fallback) 620 flags |= CONF_MFLAGS_IGNORE_ERRORS; 621 622 conf_loaded = false; 623 624 if (NULL != s->tls_app_name.v_app_name) 625 { 626 char app_name_lc[128]; 627 const size_t app_name_len = strlen (s->tls_app_name.v_app_name); 628 629 /* Checked at the parameter processing */ 630 mhd_ASSUME ((128u) > app_name_len); 631 632 mhd_str_to_lowercase_bin_n (app_name_len + 1u, /* '+1' for zero termination */ 633 s->tls_app_name.v_app_name, 634 app_name_lc); 635 636 mhd_ASSUME ('\0' == app_name_lc[app_name_len]); 637 638 conf_loaded = 639 daemon_load_conf_from_cfg (d, 640 conf_pathname, 641 app_name_lc, 642 conf, 643 flags, 644 s->tls_app_name.v_disable_fallback || 645 mhd_LIBCTX_FORBIDS_FALLBACKS (d_tls)); 646 647 if (! conf_loaded) 648 { 649 if (s->tls_app_name.v_disable_fallback || 650 mhd_LIBCTX_FORBIDS_FALLBACKS (d_tls)) 651 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 652 else if (! cfg_reset_and_reload (d, 653 d_tls, 654 conf_pathname, 655 &conf)) 656 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 657 } 658 } 659 660 if (! conf_loaded && 661 (MHD_SC_OK == ret)) 662 { 663 664 mhd_assert ((NULL == s->tls_app_name.v_app_name) || 665 ! s->tls_app_name.v_disable_fallback); 666 667 conf_loaded = 668 daemon_load_conf_from_cfg (d, 669 conf_pathname, 670 "libmicrohttpd", 671 conf, 672 flags, 673 false); 674 if ((! conf_loaded) && 675 (! cfg_reset_and_reload (d, 676 d_tls, 677 conf_pathname, 678 &conf))) 679 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 680 } 681 682 if (! conf_loaded && 683 (MHD_SC_OK == ret)) 684 { 685 686 mhd_assert ((NULL == s->tls_app_name.v_app_name) || 687 ! s->tls_app_name.v_disable_fallback); 688 689 conf_loaded = 690 daemon_load_conf_from_cfg (d, 691 conf_pathname, 692 NULL, 693 conf, 694 flags, 695 true); 696 } 697 698 if (! conf_loaded) 699 ret = MHD_SC_TLS_LIB_CONF_WARNING; 700 } 701 702 NCONF_free (conf); /* Explicitly safe with NULL */ 703 } 704 705 OPENSSL_free (conf_pathname); 706 707 return ret; 708 } 709 710 711 /** 712 * Initialise OpenSSL library context 713 * @param d the daemon handle 714 * @param d_tls the daemon TLS settings 715 * @param s the application-provided settings 716 * @return #MHD_SC_OK on success, 717 * error code otherwise 718 */ 719 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 720 daemon_init_lib_ctx (struct MHD_Daemon *restrict d, 721 struct mhd_TlsOpenDaemonData *restrict d_tls, 722 struct DaemonOptions *restrict s) 723 { 724 enum MHD_StatusCode ret; 725 726 #ifndef HAVE_NULL_PTR_ALL_ZEROS 727 d_tls->libctx = NULL; 728 #endif /* HAVE_NULL_PTR_ALL_ZEROS */ 729 730 if (! create_lib_ctx (d, d_tls)) 731 return MHD_SC_TLS_DAEMON_INIT_FAILED; 732 733 if (NULL != s->tls_openssl_def_file.v_pathname) 734 { 735 ret = daemon_load_lib_conf (d, 736 d_tls, 737 s, 738 true); 739 740 if (MHD_SC_OK == ret) 741 return MHD_SC_OK; 742 743 if (MHD_SC_TLS_LIB_CONF_WARNING == ret) 744 ret = s->tls_openssl_def_file.v_disable_fallback 745 ? MHD_SC_TLS_DAEMON_INIT_FAILED : MHD_SC_OK; 746 } 747 else 748 ret = MHD_SC_OK; 749 750 mhd_assert (MHD_SC_TLS_LIB_CONF_WARNING != ret); 751 752 if (MHD_SC_OK == ret) 753 { 754 mhd_assert ((NULL == s->tls_openssl_def_file.v_pathname) || 755 ! s->tls_openssl_def_file.v_disable_fallback); 756 757 ret = daemon_load_lib_conf (d, 758 d_tls, 759 s, 760 false); 761 762 if (MHD_SC_OK == ret) 763 return MHD_SC_OK; 764 765 if (MHD_SC_TLS_LIB_CONF_WARNING == ret) 766 { 767 if ((! s->tls_app_name.v_disable_fallback) && 768 (! s->tls_openssl_def_file.v_disable_fallback)) 769 return MHD_SC_OK; /* Load without configuration file */ 770 771 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 772 } 773 } 774 775 mhd_assert (MHD_SC_TLS_LIB_CONF_WARNING != ret); 776 777 OSSL_LIB_CTX_free (d_tls->libctx); /* Explicitly safe with NULL */ 778 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 779 "Failed to initialise TLS library context"); 780 return MHD_SC_TLS_DAEMON_INIT_FAILED; 781 } 782 783 784 /** 785 * De-initialise OpenSSL library context 786 * @param d_tls the daemon TLS settings 787 */ 788 static MHD_FN_PAR_NONNULL_ALL_ void 789 daemon_deinit_lib_ctx (struct mhd_TlsOpenDaemonData *restrict d_tls) 790 { 791 mhd_assert (NULL != d_tls->libctx); 792 OSSL_LIB_CTX_free (d_tls->libctx); 793 } 794 795 796 #define mhd_ALPN_CODE_HTTP1_0 \ 797 'h', 't', 't', 'p', '/', '1', '.', '0' /* Registered value for HTTP/1.0 */ 798 #define mhd_ALPN_CODE_HTTP1_1 \ 799 'h', 't', 't', 'p', '/', '1', '.', '1' /* Registered value for HTTP/1.1 */ 800 #ifdef MHD_SUPPORT_HTTP2 801 #define mhd_ALPN_CODE_HTTP2 \ 802 'h', '2' /* Registered value for HTTP/2 over TLS */ 803 #endif /* MHD_SUPPORT_HTTP2 */ 804 #if 0 /* Disabled code */ 805 #define mhd_ALPN_CODE_HTTP3 \ 806 'h', '3' /* Registered value for HTTP/3 */ 807 #endif /* Disabled code */ 808 809 810 #ifdef MHD_SUPPORT_HTTP2 811 static const unsigned char alpn_list_http2_1x[] = { 812 mhd_ALPN_H2_LEN, mhd_ALPN_CODE_HTTP2 813 , 814 mhd_ALPN_H1_1_LEN, mhd_ALPN_CODE_HTTP1_1 815 , 816 mhd_ALPN_H1_0_LEN, mhd_ALPN_CODE_HTTP1_0 817 }; 818 static const unsigned char alpn_list_http2_only[] = { 819 mhd_ALPN_H2_LEN, mhd_ALPN_CODE_HTTP2 820 }; 821 #endif /* MHD_SUPPORT_HTTP2 */ 822 static const unsigned char alpn_list_http1x_only[] = { 823 mhd_ALPN_H1_1_LEN, mhd_ALPN_CODE_HTTP1_1 824 , 825 mhd_ALPN_H1_0_LEN, mhd_ALPN_CODE_HTTP1_0 826 }; 827 828 #ifndef OPENSSL_NO_NEXTPROTONEG 829 /** 830 * Provide the list of supported protocols for NPN extension 831 * @param sess the TLS session (ignored) 832 * @param[out] out the pointer to get the location of the data 833 * @param[out] outlen the size of the data provided 834 * @param cls the closure (ignored) 835 * @return always SSL_TLSEXT_ERR_OK 836 */ 837 static int 838 get_npn_list (SSL *sess, 839 const unsigned char **out, 840 unsigned int *outlen, 841 void *cls) 842 { 843 struct mhd_TlsOpenDaemonData *const d_tls = 844 (struct mhd_TlsOpenDaemonData *) cls; 845 (void) sess; /* Unused */ 846 *out = d_tls->alpn_prots; 847 *outlen = d_tls->alpn_prots_size; 848 return SSL_TLSEXT_ERR_OK; 849 } 850 851 852 #endif /* ! OPENSSL_NO_NEXTPROTONEG */ 853 854 /** 855 * Select protocol from the provided list for ALPN extension 856 * @param sess the TLS session (ignored) 857 * @param[out] out the pointer to get the location of selected protocol value 858 * @param[out] outlen the size of the selected protocol value 859 * @param in the list of protocols values provided by the client 860 * @param inlen the size of the list of protocols values provided by the client 861 * @param cls the closure (ignored) 862 * @return SSL_TLSEXT_ERR_OK if matching protocol found and selected, 863 * SSL_TLSEXT_ERR_ALERT_FATAL otherwise 864 */ 865 static int 866 select_alpn_prot (SSL *sess, 867 const unsigned char **out, 868 unsigned char *outlen, 869 const unsigned char *in, 870 unsigned int inlen, 871 void *cls) 872 { 873 struct mhd_TlsOpenDaemonData *const d_tls = 874 (struct mhd_TlsOpenDaemonData *) cls; 875 (void) sess; /* Unused */ 876 if (OPENSSL_NPN_NEGOTIATED == 877 SSL_select_next_proto ((unsigned char **) mhd_DROP_CONST (out), 878 outlen, 879 in, 880 inlen, 881 d_tls->alpn_prots, 882 d_tls->alpn_prots_size)) 883 return SSL_TLSEXT_ERR_OK; /* Success */ 884 885 return SSL_TLSEXT_ERR_ALERT_FATAL; /* Failure */ 886 } 887 888 889 /** 890 * Initialise TLS server context 891 * @param d the daemon handle 892 * @param d_tls the daemon TLS settings 893 * @param s the application-provided settings 894 * @return #MHD_SC_OK on success, 895 * error code otherwise 896 */ 897 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 898 daemon_init_ctx (struct MHD_Daemon *restrict d, 899 struct mhd_TlsOpenDaemonData *restrict d_tls, 900 struct DaemonOptions *restrict s) 901 { 902 uint64_t ctx_opts; 903 904 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY 905 (void) d; /* Mute compiler warning */ 906 #endif 907 (void) s; // TODO: support configuration options 908 909 mhd_assert (NULL != d_tls->libctx); 910 911 ERR_clear_error (); 912 913 d_tls->ctx = SSL_CTX_new_ex (d_tls->libctx, 914 NULL, 915 TLS_server_method ()); 916 if (NULL == d_tls->ctx) 917 { 918 mhd_DBG_PRINT_TLS_ERRS (); 919 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 920 "Failed to initialise TLS server context"); 921 return MHD_SC_TLS_DAEMON_INIT_FAILED; 922 } 923 924 /* Enable some safe and useful workarounds */ 925 ctx_opts = SSL_OP_SAFARI_ECDHE_ECDSA_BUG | SSL_OP_TLSEXT_PADDING; 926 927 // TODO: add configuration option 928 // ctx_opts |= SSL_OP_CIPHER_SERVER_PREFERENCE; 929 930 #ifndef OPENSSL_NO_KTLS 931 /* Enable kernel TLS */ // TODO: add configuration option 932 ctx_opts |= SSL_OP_ENABLE_KTLS; 933 # ifdef SSL_OP_ENABLE_KTLS_TX_ZEROCOPY_SENDFILE 934 ctx_opts |= SSL_OP_ENABLE_KTLS_TX_ZEROCOPY_SENDFILE; 935 # endif 936 #endif 937 938 /* HTTP defines strict framing for the client-side data, 939 no risk of attack on server on unexpected connection interruption */ 940 /* ctx_opts |= SSL_OP_IGNORE_UNEXPECTED_EOF; */ // TODO: recheck 941 942 /* There is no reason to use re-negotiation with HTTP */ 943 ctx_opts |= SSL_OP_NO_RENEGOTIATION; 944 945 /* Do not use session resumption for now */ 946 ctx_opts |= SSL_OP_NO_TICKET; 947 948 (void) SSL_CTX_set_options (d_tls->ctx, 949 ctx_opts); 950 951 /* Prevent interactive password prompts */ 952 SSL_CTX_set_default_passwd_cb (d_tls->ctx, 953 &null_passwd_cb); 954 955 // TODO: make the setting configurable 956 /* SSL_CTX_set_security_level (d_tls->ctx, 0); */ 957 958 /* recv()- and send()-related options */ 959 (void) SSL_CTX_set_mode (d_tls->ctx, 960 SSL_MODE_ENABLE_PARTIAL_WRITE 961 | SSL_MODE_AUTO_RETRY); 962 (void) SSL_CTX_clear_mode (d_tls->ctx, 963 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 964 | SSL_MODE_ASYNC); 965 966 SSL_CTX_set_read_ahead (d_tls->ctx, 967 ! 0); 968 969 /* ALPN and NPN */ 970 // TODO: use daemon option to disable ALPN 971 // TODO: use daemon option to select protocols for ALPN 972 #ifdef MHD_SUPPORT_HTTP2 973 if (1 /* enabled both HTTP/2 and HTTP/1.x */) 974 { 975 d_tls->alpn_prots = alpn_list_http2_1x; 976 d_tls->alpn_prots_size = sizeof(alpn_list_http2_1x); 977 } 978 else if (0 /* HTTP/2 only */) 979 { 980 d_tls->alpn_prots = alpn_list_http2_only; 981 d_tls->alpn_prots_size = sizeof(alpn_list_http2_only); 982 } 983 else 984 #endif /* MHD_SUPPORT_HTTP2 */ 985 if (1 /* HTTP/1.x only */) 986 { 987 d_tls->alpn_prots = alpn_list_http1x_only; 988 d_tls->alpn_prots_size = sizeof(alpn_list_http1x_only); 989 } 990 else 991 { 992 mhd_UNREACHABLE (); 993 } 994 SSL_CTX_set_alpn_select_cb (d_tls->ctx, 995 &select_alpn_prot, 996 d_tls); 997 #ifndef OPENSSL_NO_NEXTPROTONEG 998 SSL_CTX_set_next_protos_advertised_cb (d_tls->ctx, 999 &get_npn_list, 1000 d_tls); 1001 #endif /* ! OPENSSL_NO_NEXTPROTONEG */ 1002 1003 return MHD_SC_OK; 1004 } 1005 1006 1007 /** 1008 * De-initialise TLS server context 1009 * @param d_tls the daemon TLS settings 1010 */ 1011 static MHD_FN_PAR_NONNULL_ALL_ void 1012 daemon_deinit_ctx (struct mhd_TlsOpenDaemonData *restrict d_tls) 1013 { 1014 mhd_assert (NULL != d_tls->ctx); 1015 SSL_CTX_free (d_tls->ctx); 1016 } 1017 1018 1019 /** 1020 * Load the certificates chain from the OpenSSL BIO 1021 * @param d the daemon handle 1022 * @param d_tls the daemon TLS settings 1023 * @param bio the certificates chain data opened in OpenSSL BIO 1024 * @return #MHD_SC_OK on success, 1025 * error code otherwise 1026 */ 1027 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 1028 daemon_load_certs_chain_obio (struct MHD_Daemon *restrict d, 1029 struct mhd_TlsOpenDaemonData *restrict d_tls, 1030 BIO *restrict bio) 1031 { 1032 enum MHD_StatusCode ret; 1033 X509 *cert; 1034 1035 ret = MHD_SC_OK; 1036 1037 /* The certificate object must be pre-allocated to associate it with 1038 * the lib context */ 1039 cert = X509_new_ex (d_tls->libctx, 1040 NULL); 1041 if (NULL == cert) 1042 { 1043 mhd_DBG_PRINT_TLS_ERRS (); 1044 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1045 "Failed to create new certificate object"); 1046 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1047 } 1048 1049 if (NULL == PEM_read_bio_X509_AUX (bio, 1050 &cert, 1051 &null_passwd_cb, 1052 NULL)) 1053 { 1054 mhd_DBG_PRINT_TLS_ERRS (); 1055 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1056 "Failed to process the certificate"); 1057 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 1058 } 1059 else 1060 { 1061 if (0 >= SSL_CTX_use_certificate (d_tls->ctx, 1062 cert)) 1063 { 1064 mhd_DBG_PRINT_TLS_ERRS (); 1065 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1066 "Failed to set the certificate"); 1067 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 1068 } 1069 else 1070 { 1071 if (0 != ERR_peek_error ()) 1072 mhd_DBG_PRINT_TLS_ERRS (); 1073 } 1074 } 1075 /* Free certificate: if it was successfully read, it has been "copied" to CTX */ 1076 X509_free (cert); 1077 if (MHD_SC_OK != ret) 1078 return ret; 1079 1080 do 1081 { 1082 X509 *inter_ca; /* Certifying certificate */ 1083 inter_ca = X509_new_ex (d_tls->libctx, 1084 NULL); 1085 if (NULL == inter_ca) 1086 { 1087 mhd_DBG_PRINT_TLS_ERRS (); 1088 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1089 "Failed to create new chain certificate object"); 1090 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1091 } 1092 if (NULL == PEM_read_bio_X509 (bio, 1093 &inter_ca, 1094 &null_passwd_cb, 1095 NULL)) 1096 { 1097 unsigned long err; 1098 err = ERR_peek_last_error (); 1099 1100 mhd_NOWARN_USED_UNUSED 1101 1102 if ((ERR_LIB_PEM == ERR_GET_LIB (err)) && 1103 (PEM_R_NO_START_LINE == ERR_GET_REASON (err))) 1104 { 1105 /* End of data */ 1106 ERR_clear_error (); 1107 X509_free (inter_ca); /* Empty, not needed */ 1108 1109 mhd_assert (MHD_SC_OK == ret); 1110 return MHD_SC_OK; /* Success exit point */ 1111 } 1112 1113 mhd_RESTORE_WARN_USED_UNUSED 1114 1115 mhd_DBG_PRINT_TLS_ERRS (); 1116 1117 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1118 "Failed to load next object in the certificates " \ 1119 "chain"); 1120 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 1121 } 1122 else 1123 { 1124 if (SSL_CTX_add0_chain_cert (d_tls->ctx, 1125 inter_ca)) 1126 { 1127 /* Success, do not free the certificate as 1128 * function '_add0_' was used to add it. */ 1129 /* Read the next certificate in the chain. */ 1130 continue; 1131 } 1132 1133 mhd_DBG_PRINT_TLS_ERRS (); 1134 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1135 "Failed to add the new certificate object " 1136 "to the chain"); 1137 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 1138 } 1139 1140 X509_free (inter_ca); /* Failed, the object is not needed */ 1141 mhd_assert (MHD_SC_OK != ret); 1142 } while (MHD_SC_OK == ret); 1143 mhd_assert (MHD_SC_OK != ret); 1144 return ret; 1145 } 1146 1147 1148 /** 1149 * Load the certificates chain based on application-provided settings 1150 * @param d the daemon handle 1151 * @param d_tls the daemon TLS settings 1152 * @param s the application-provided settings 1153 * @return #MHD_SC_OK on success, 1154 * error code otherwise 1155 */ 1156 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 1157 daemon_load_certs_chain (struct MHD_Daemon *restrict d, 1158 struct mhd_TlsOpenDaemonData *restrict d_tls, 1159 struct DaemonOptions *restrict s) 1160 { 1161 enum MHD_StatusCode ret; 1162 BIO *m_bio; 1163 1164 mhd_assert (NULL != d_tls->libctx); 1165 mhd_assert (NULL != d_tls->ctx); 1166 1167 ERR_clear_error (); 1168 1169 m_bio = BIO_new_mem_buf (s->tls_cert_key.v_mem_cert, 1170 -1); 1171 if (NULL == m_bio) 1172 { 1173 mhd_DBG_PRINT_TLS_ERRS (); 1174 return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; 1175 } 1176 ret = daemon_load_certs_chain_obio (d, 1177 d_tls, 1178 m_bio); 1179 BIO_free (m_bio); 1180 return ret; 1181 } 1182 1183 1184 /** 1185 * Initialise TLS certificate 1186 * The function loads the certificate chain and the private key. 1187 * @param d the daemon handle 1188 * @param d_tls the daemon TLS settings 1189 * @param s the application-provided settings 1190 * @return #MHD_SC_OK on success, 1191 * error code otherwise 1192 */ 1193 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 1194 daemon_init_cert (struct MHD_Daemon *restrict d, 1195 struct mhd_TlsOpenDaemonData *restrict d_tls, 1196 struct DaemonOptions *restrict s) 1197 { 1198 enum MHD_StatusCode ret; 1199 BIO *m_bio; 1200 EVP_PKEY *pr_key; 1201 int res_i; 1202 long res_l; 1203 1204 mhd_assert (NULL != d_tls->libctx); 1205 mhd_assert (NULL != d_tls->ctx); 1206 1207 ERR_clear_error (); 1208 1209 ret = daemon_load_certs_chain (d, 1210 d_tls, 1211 s); 1212 if (MHD_SC_OK != ret) 1213 return ret; 1214 1215 /* Check and cache the certificates chain. 1216 This also prevents automatic chain re-building for each session. */ 1217 res_l = 1218 SSL_CTX_build_cert_chain ( 1219 d_tls->ctx, 1220 SSL_BUILD_CHAIN_FLAG_CHECK /* Use only certificates in the chain */ 1221 | SSL_BUILD_CHAIN_FLAG_UNTRUSTED /* Intermediate CA certs does not need to be trusted */ 1222 | SSL_BUILD_CHAIN_FLAG_NO_ROOT /* The root CA should not be added to the chain */ 1223 | SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR /* Allow the root CA to be not trusted */ 1224 ); 1225 if (0 >= res_l) 1226 { 1227 mhd_DBG_PRINT_TLS_ERRS (); 1228 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1229 "Failed rebuild certificate chain"); 1230 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1231 } 1232 if (2 == res_l) 1233 mhd_DBG_PRINT_TLS_ERRS (); 1234 1235 m_bio = BIO_new_mem_buf (s->tls_cert_key.v_mem_key, 1236 -1); 1237 if (NULL == m_bio) 1238 { 1239 mhd_DBG_PRINT_TLS_ERRS (); 1240 return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; 1241 } 1242 pr_key = 1243 PEM_read_bio_PrivateKey_ex (m_bio, 1244 NULL, 1245 NULL == s->tls_cert_key.v_mem_pass ? 1246 &null_passwd_cb : NULL, 1247 mhd_DROP_CONST (s->tls_cert_key.v_mem_pass), 1248 d_tls->libctx, 1249 NULL); 1250 BIO_free (m_bio); 1251 if (NULL == pr_key) 1252 { 1253 mhd_DBG_PRINT_TLS_ERRS (); 1254 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1255 "Failed to read the private key"); 1256 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1257 } 1258 1259 res_i = SSL_CTX_use_PrivateKey (d_tls->ctx, 1260 pr_key); 1261 EVP_PKEY_free (pr_key); /* The key has been "copied" or failed */ 1262 if (1 != res_i) 1263 { 1264 mhd_DBG_PRINT_TLS_ERRS (); 1265 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1266 "Failed to set the private key"); 1267 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1268 } 1269 /* This actually RE-checks the key. 1270 The key should be already checked automatically when it was set after 1271 setting the certificate. */ 1272 if (1 != SSL_CTX_check_private_key (d_tls->ctx)) 1273 { 1274 mhd_DBG_PRINT_TLS_ERRS (); 1275 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1276 "The private key does not match the certificate"); 1277 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1278 } 1279 1280 return MHD_SC_OK; 1281 } 1282 1283 1284 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ 1285 MHD_FN_PAR_OUT_ (4) mhd_StatusCodeInt 1286 mhd_tls_open_daemon_init (struct MHD_Daemon *restrict d, 1287 bool sk_edge_trigg, 1288 struct DaemonOptions *restrict s, 1289 struct mhd_TlsOpenDaemonData **restrict p_d_tls) 1290 { 1291 mhd_StatusCodeInt res; 1292 struct mhd_TlsOpenDaemonData *restrict d_tls; 1293 1294 /* Successful initialisation must be checked earlier */ 1295 mhd_assert (openssl_lib_inited); 1296 1297 res = check_app_tls_settings (d, sk_edge_trigg, s); 1298 if (MHD_SC_OK != res) 1299 return res; 1300 1301 d_tls = (struct mhd_TlsOpenDaemonData *) 1302 mhd_calloc (1, sizeof (struct mhd_TlsOpenDaemonData)); 1303 *p_d_tls = d_tls; 1304 if (NULL == d_tls) 1305 return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; 1306 1307 res = daemon_init_lib_ctx (d, 1308 d_tls, 1309 s); 1310 if (MHD_SC_OK == res) 1311 { 1312 res = daemon_init_ctx (d, 1313 d_tls, 1314 s); 1315 if (MHD_SC_OK == res) 1316 { 1317 res = daemon_init_cert (d, 1318 d_tls, 1319 s); 1320 if (MHD_SC_OK == res) 1321 return MHD_SC_OK; /* Success exit point */ 1322 1323 /* Below is a clean-up code path */ 1324 daemon_deinit_ctx (d_tls); 1325 } 1326 daemon_deinit_lib_ctx (d_tls); 1327 } 1328 free (d_tls); 1329 *p_d_tls = NULL; 1330 mhd_assert (MHD_SC_OK != res); 1331 return res; /* Failure exit point */ 1332 } 1333 1334 1335 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 1336 MHD_FN_PAR_INOUT_ (1) void 1337 mhd_tls_open_daemon_deinit (struct mhd_TlsOpenDaemonData *restrict d_tls) 1338 { 1339 mhd_assert (NULL != d_tls); 1340 daemon_deinit_ctx (d_tls); 1341 daemon_deinit_lib_ctx (d_tls); 1342 free (d_tls); 1343 } 1344 1345 1346 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 1347 MHD_FN_PAR_INOUT_ (1) void 1348 mhd_tls_open_thread_cleanup (struct mhd_TlsOpenDaemonData *restrict d_tls) 1349 { 1350 OPENSSL_thread_stop_ex (d_tls->libctx); 1351 } 1352 1353 1354 /* ** Connection initialisation / de-initialisation ** */ 1355 1356 MHD_INTERNAL size_t 1357 mhd_tls_open_conn_get_tls_size_v (void) 1358 { 1359 return sizeof (struct mhd_TlsOpenConnData); 1360 } 1361 1362 1363 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ 1364 MHD_FN_PAR_OUT_ (3) bool 1365 mhd_tls_open_conn_init (const struct mhd_TlsOpenDaemonData *restrict d_tls, 1366 const struct mhd_ConnSocket *sk, 1367 struct mhd_TlsOpenConnData *restrict c_tls) 1368 { 1369 int fd; 1370 1371 ERR_clear_error (); 1372 1373 fd = (int) sk->fd; 1374 if (sk->fd != (MHD_Socket) fd) 1375 return false; /* OpenSSL docs clam that it should not be possible */ 1376 1377 c_tls->sess = SSL_new (d_tls->ctx); 1378 1379 if (NULL == c_tls->sess) 1380 { 1381 mhd_DBG_PRINT_TLS_ERRS (); 1382 return false; 1383 } 1384 1385 if (0 < SSL_set_fd (c_tls->sess, fd)) 1386 { 1387 SSL_set_accept_state (c_tls->sess); /* Force server mode */ 1388 1389 #ifndef NDEBUG 1390 c_tls->dbg.is_inited = true; 1391 #endif 1392 return true; /* Success exit point */ 1393 } 1394 1395 SSL_free (c_tls->sess); 1396 c_tls->sess = NULL; 1397 return false; 1398 } 1399 1400 1401 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 1402 mhd_tls_open_conn_deinit (struct mhd_TlsOpenConnData *restrict c_tls) 1403 { 1404 mhd_assert (NULL != c_tls->sess); 1405 mhd_assert (c_tls->dbg.is_inited); 1406 SSL_free (c_tls->sess); 1407 } 1408 1409 1410 /* ** TLS connection establishing ** */ 1411 1412 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ 1413 enum mhd_TlsProcedureResult 1414 mhd_tls_open_conn_handshake (struct mhd_TlsOpenConnData *restrict c_tls) 1415 { 1416 int res; 1417 1418 mhd_assert (c_tls->dbg.is_inited); 1419 mhd_assert (! c_tls->dbg.is_tls_handshake_completed); 1420 mhd_assert (! c_tls->shut_tls_wr_sent); 1421 mhd_assert (! c_tls->shut_tls_wr_received); 1422 mhd_assert (! c_tls->dbg.is_failed); 1423 1424 ERR_clear_error (); 1425 1426 res = SSL_do_handshake (c_tls->sess); 1427 1428 if (1 == res) 1429 { 1430 #ifndef NDEBUG 1431 c_tls->dbg.is_tls_handshake_completed = true; 1432 #endif /* ! NDEBUG */ 1433 return mhd_TLS_PROCED_SUCCESS; /* Success exit point */ 1434 } 1435 1436 switch (SSL_get_error (c_tls->sess, res)) 1437 { 1438 case SSL_ERROR_WANT_READ: 1439 /* OpenSSL does not distinguish between "interrupted" and "try again" codes. 1440 Based on OpenSSL result it is unclear whether the "recv-ready" flag 1441 should be reset or not. 1442 If edge-triggered sockets polling is used and the flag is cleared, but 1443 it should not (because the process has been "interrupted") then already 1444 pending data could be never processed. 1445 If the flag is not cleared, but it should be cleared (because all 1446 received data has been processed) then it would create busy-waiting loop 1447 with edge-triggered sockets polling. 1448 Temporal solution: disallow edge-triggered sockets polling with OpenSSL 1449 backend and use clear of "ready" flag. */ 1450 // TODO: replace "BIO" with custom version and track returned errors. 1451 return mhd_TLS_PROCED_SEND_MORE_NEEDED; 1452 case SSL_ERROR_WANT_WRITE: 1453 /* OpenSSL does not distinguish between "interrupted" and "try again" codes. 1454 Based on OpenSSL result it is unclear whether the "send-ready" flag 1455 should be reset or not. 1456 If edge-triggered sockets polling is used and the flag is cleared, but 1457 it should not (because the process has been "interrupted") then already 1458 pending data could be never sent. 1459 If the flag is not cleared, but it should be cleared (because all 1460 received data has been processed) then it would create busy-waiting loop 1461 with edge-triggered sockets polling. 1462 Temporal solution: disallow edge-triggered sockets polling with OpenSSL 1463 backend and use clear of "ready" flag. */ 1464 // TODO: replace "BIO" with custom version and track returned errors. 1465 return mhd_TLS_PROCED_RECV_MORE_NEEDED; 1466 case SSL_ERROR_NONE: 1467 mhd_assert (0 && "This should not be possible"); 1468 mhd_UNREACHABLE (); 1469 break; 1470 default: /* Handled with all other errors below */ 1471 break; 1472 } 1473 mhd_DBG_PRINT_TLS_ERRS (); 1474 #ifndef NDEBUG 1475 c_tls->dbg.is_failed = true; 1476 #endif /* ! NDEBUG */ 1477 return mhd_TLS_PROCED_FAILED; 1478 } 1479 1480 1481 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ 1482 enum mhd_TlsProcedureResult 1483 mhd_tls_open_conn_shutdown (struct mhd_TlsOpenConnData *restrict c_tls) 1484 { 1485 int res; 1486 1487 mhd_assert (c_tls->dbg.is_inited); 1488 mhd_assert (c_tls->dbg.is_tls_handshake_completed); 1489 mhd_assert (! c_tls->dbg.is_failed); 1490 1491 ERR_clear_error (); 1492 1493 res = SSL_shutdown (c_tls->sess); 1494 1495 if (1 == res) 1496 { 1497 c_tls->shut_tls_wr_sent = true; 1498 c_tls->shut_tls_wr_received = true; 1499 return mhd_TLS_PROCED_SUCCESS; /* Success exit point */ 1500 } 1501 1502 /* The OpenSSL documentation contradicts itself: there are two mutually 1503 exclusive statements on a single page. 1504 * https://docs.openssl.org/master/man3/SSL_shutdown/#shutdown-lifecycle 1505 indicates that for nonblocking socket ZERO could be returned when 1506 "close_notify" is GOING to be sent, but NOT sent yet. 1507 It also suggests to CALL SSL_get_error(3) when ZERO is returned. 1508 * https://docs.openssl.org/master/man3/SSL_shutdown/#return-values 1509 indicates ZERO is returned ONLY when "close_notify" HAS BEEN sent. 1510 It also suggests to NOT CALL SSL_get_error(3) when ZERO is returned. 1511 */ 1512 switch (SSL_get_error (c_tls->sess, res)) 1513 { 1514 case SSL_ERROR_WANT_READ: 1515 /* OpenSSL does not distinguish between "interrupted" and "try again" codes. 1516 Based on OpenSSL result it is unclear whether the "recv-ready" flag 1517 should be reset or not. 1518 If edge-triggered sockets polling is used and the flag is cleared, but 1519 it should not (because the process has been "interrupted") then already 1520 pending data could be never processed. 1521 If the flag is not cleared, but it should be cleared (because all 1522 received data has been processed) then it would create busy-waiting loop 1523 with edge-triggered sockets polling. 1524 Temporal solution: disallow edge-triggered sockets polling with OpenSSL 1525 backend and use clear of "ready" flag. */ 1526 // TODO: replace "BIO" with custom version and track returned errors. 1527 return mhd_TLS_PROCED_SEND_MORE_NEEDED; 1528 case SSL_ERROR_WANT_WRITE: 1529 c_tls->shut_tls_wr_sent = true; 1530 /* OpenSSL does not distinguish between "interrupted" and "try again" codes. 1531 Based on OpenSSL result it is unclear whether the "send-ready" flag 1532 should be reset or not. 1533 If edge-triggered sockets polling is used and the flag is cleared, but 1534 it should not (because the process has been "interrupted") then already 1535 pending data could be never sent. 1536 If the flag is not cleared, but it should be cleared (because all 1537 received data has been processed) then it would create busy-waiting loop 1538 with edge-triggered sockets polling. 1539 Temporal solution: disallow edge-triggered sockets polling with OpenSSL 1540 backend and use clear of "ready" flag. */ 1541 // TODO: replace "BIO" with custom version and track returned errors. 1542 return mhd_TLS_PROCED_RECV_MORE_NEEDED; 1543 case SSL_ERROR_NONE: 1544 mhd_assert (res != 0 && "Should not be possible"); 1545 c_tls->shut_tls_wr_sent = true; 1546 return mhd_TLS_PROCED_RECV_INTERRUPTED; 1547 default: /* Handled with all other errors below */ 1548 break; 1549 } 1550 mhd_DBG_PRINT_TLS_ERRS (); 1551 #ifndef NDEBUG 1552 c_tls->dbg.is_failed = true; 1553 #endif /* ! NDEBUG */ 1554 return mhd_TLS_PROCED_FAILED; 1555 } 1556 1557 1558 /* ** Data receiving and sending ** */ 1559 1560 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 1561 MHD_FN_PAR_OUT_SIZE_ (3,2) 1562 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError 1563 mhd_tls_open_conn_recv (struct mhd_TlsOpenConnData *restrict c_tls, 1564 size_t buf_size, 1565 char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)], 1566 size_t *restrict received) 1567 { 1568 int res; 1569 1570 mhd_assert (c_tls->dbg.is_inited); 1571 mhd_assert (c_tls->dbg.is_tls_handshake_completed); 1572 mhd_assert (! c_tls->shut_tls_wr_sent); 1573 mhd_assert (! c_tls->dbg.is_failed); 1574 1575 ERR_clear_error (); 1576 1577 res = SSL_read_ex (c_tls->sess, 1578 buf, 1579 buf_size, 1580 received); 1581 if (1 == res) 1582 { 1583 mhd_assert (0 != *received); 1584 return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */ 1585 } 1586 1587 mhd_assert (0 == res); 1588 *received = 0; 1589 switch (SSL_get_error (c_tls->sess, res)) 1590 { 1591 case SSL_ERROR_ZERO_RETURN: /* Not an error */ 1592 c_tls->shut_tls_wr_received = true; 1593 return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */ 1594 case SSL_ERROR_WANT_READ: 1595 /* OpenSSL does not distinguish between "interrupted" and "try again" codes. 1596 Based on OpenSSL result it is unclear whether the "recv-ready" flag 1597 should be reset or not. 1598 If edge-triggered sockets polling is used and the flag is cleared, but 1599 it should not (because the process has been "interrupted") then already 1600 pending data could be never processed. 1601 If the flag is not cleared, but it should be cleared (because all 1602 received data has been processed) then it would create busy-waiting loop 1603 with edge-triggered sockets polling. 1604 Temporal solution: disallow edge-triggered sockets polling with OpenSSL 1605 backend and use clear of "ready" flag. */ 1606 // TODO: replace "BIO" with custom version and track returned errors. 1607 return mhd_SOCKET_ERR_AGAIN; 1608 case SSL_ERROR_NONE: 1609 mhd_assert (0 && "Should not be possible"); 1610 break; 1611 case SSL_ERROR_WANT_WRITE: 1612 mhd_assert (0 && "Should not be possible as re-handshakes are disallowed"); 1613 break; 1614 case SSL_ERROR_SYSCALL: 1615 mhd_DBG_PRINT_TLS_ERRS (); 1616 #ifndef NDEBUG 1617 c_tls->dbg.is_failed = true; 1618 #endif /* ! NDEBUG */ 1619 return mhd_SOCKET_ERR_CONN_BROKEN; 1620 case SSL_ERROR_SSL: 1621 default: 1622 break; 1623 } 1624 /* Treat all other kinds of errors as hard errors */ 1625 mhd_DBG_PRINT_TLS_ERRS (); 1626 #ifndef NDEBUG 1627 c_tls->dbg.is_failed = true; 1628 #endif /* ! NDEBUG */ 1629 return mhd_SOCKET_ERR_TLS; 1630 } 1631 1632 1633 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 1634 mhd_tls_open_conn_has_data_in (struct mhd_TlsOpenConnData *restrict c_tls) 1635 { 1636 return 0 != SSL_pending (c_tls->sess); 1637 } 1638 1639 1640 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 1641 MHD_FN_PAR_IN_SIZE_ (3,2) 1642 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError 1643 mhd_tls_open_conn_send4 (struct mhd_TlsOpenConnData *restrict c_tls, 1644 size_t buf_size, 1645 const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)], 1646 size_t *restrict sent) 1647 { 1648 int res; 1649 1650 mhd_assert (c_tls->dbg.is_inited); 1651 mhd_assert (c_tls->dbg.is_tls_handshake_completed); 1652 mhd_assert (! c_tls->shut_tls_wr_sent); 1653 mhd_assert (! c_tls->dbg.is_failed); 1654 1655 ERR_clear_error (); 1656 1657 res = SSL_write_ex (c_tls->sess, 1658 buf, 1659 buf_size, 1660 sent); 1661 if (1 == res) 1662 { 1663 mhd_assert (0 != *sent); 1664 return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */ 1665 } 1666 1667 mhd_assert (0 == res); 1668 *sent = 0; 1669 switch (SSL_get_error (c_tls->sess, res)) 1670 { 1671 case SSL_ERROR_WANT_WRITE: 1672 /* OpenSSL does not distinguish between "interrupted" and "try again" codes. 1673 Based on OpenSSL result it is unclear whether the "send-ready" flag 1674 should be reset or not. 1675 If edge-triggered sockets polling is used and the flag is cleared, but 1676 it should not (because the process has been "interrupted") then already 1677 pending data could be never sent. 1678 If the flag is not cleared, but it should be cleared (because all 1679 received data has been processed) then it would create busy-waiting loop 1680 with edge-triggered sockets polling. 1681 Temporal solution: disallow edge-triggered sockets polling with OpenSSL 1682 backend and use clear of "ready" flag. */ 1683 // TODO: replace "BIO" with custom version and track returned errors. 1684 return mhd_SOCKET_ERR_AGAIN; 1685 case SSL_ERROR_NONE: 1686 mhd_assert (0 && "Should not be possible"); 1687 break; 1688 case SSL_ERROR_WANT_READ: 1689 mhd_assert (0 && "Should not be possible as re-handshakes are disallowed"); 1690 break; 1691 case SSL_ERROR_ZERO_RETURN: 1692 c_tls->shut_tls_wr_received = true; 1693 return mhd_SOCKET_ERR_AGAIN; 1694 case SSL_ERROR_SYSCALL: 1695 mhd_DBG_PRINT_TLS_ERRS (); 1696 #ifndef NDEBUG 1697 c_tls->dbg.is_failed = true; 1698 #endif /* ! NDEBUG */ 1699 return mhd_SOCKET_ERR_CONN_BROKEN; 1700 case SSL_ERROR_SSL: 1701 default: 1702 break; 1703 } 1704 /* Treat all other kinds of errors as hard errors */ 1705 mhd_DBG_PRINT_TLS_ERRS (); 1706 #ifndef NDEBUG 1707 c_tls->dbg.is_failed = true; 1708 #endif /* ! NDEBUG */ 1709 return mhd_SOCKET_ERR_TLS; 1710 } 1711 1712 1713 /* ** TLS connection information ** */ 1714 1715 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 1716 MHD_FN_PAR_OUT_ (2) void 1717 mhd_tls_open_conn_get_tls_sess ( 1718 struct mhd_TlsOpenConnData *restrict c_tls, 1719 union MHD_ConnInfoDynamicTlsSess *restrict tls_sess_out) 1720 { 1721 tls_sess_out->v_openssl_session = c_tls->sess; 1722 } 1723 1724 1725 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 1726 MHD_FN_PAR_OUT_ (2) bool 1727 mhd_tls_open_conn_get_tls_ver (struct mhd_TlsOpenConnData *restrict c_tls, 1728 struct mhd_StctTlsVersion *restrict tls_ver_out) 1729 { 1730 int openssl_tls_ver; 1731 1732 mhd_assert (c_tls->dbg.is_tls_handshake_completed); 1733 1734 openssl_tls_ver = SSL_version (c_tls->sess); 1735 switch (openssl_tls_ver) 1736 { 1737 case TLS1_VERSION: 1738 tls_ver_out->tls_ver = MHD_TLS_VERSION_1_0; 1739 break; 1740 case TLS1_1_VERSION: 1741 tls_ver_out->tls_ver = MHD_TLS_VERSION_1_1; 1742 break; 1743 case TLS1_2_VERSION: 1744 tls_ver_out->tls_ver = MHD_TLS_VERSION_1_2; 1745 break; 1746 case TLS1_3_VERSION: 1747 tls_ver_out->tls_ver = MHD_TLS_VERSION_1_3; 1748 break; 1749 case SSL3_VERSION: 1750 default: 1751 tls_ver_out->tls_ver = MHD_TLS_VERSION_UNKNOWN; 1752 break; 1753 } 1754 1755 return true; 1756 } 1757 1758 1759 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ enum mhd_TlsAlpnProt 1760 mhd_tls_open_conn_get_alpn_prot (struct mhd_TlsOpenConnData *restrict c_tls) 1761 { 1762 const unsigned char *sel_prot; 1763 unsigned int sel_prot_len; 1764 1765 SSL_get0_alpn_selected (c_tls->sess, 1766 &sel_prot, 1767 &sel_prot_len); 1768 1769 #ifndef OPENSSL_NO_NEXTPROTONEG 1770 if ((NULL == sel_prot) || 1771 (0 == sel_prot_len)) 1772 { 1773 SSL_get0_next_proto_negotiated (c_tls->sess, 1774 &sel_prot, 1775 &sel_prot_len); 1776 } 1777 #endif /* ! OPENSSL_NO_NEXTPROTONEG */ 1778 1779 mhd_assert (sel_prot_len == (size_t) sel_prot_len); 1780 1781 return mhd_tls_alpn_decode_n ((size_t) sel_prot_len, 1782 sel_prot); 1783 }