tls_open_funcs.c (89064B)
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 #include "mhd_predict.h" 62 63 #include "mhd_str.h" 64 #include "mhd_str_types.h" 65 #include "mhd_conn_socket.h" 66 67 #include "mhd_tls_internal.h" 68 69 #include "tls_open_tls_lib.h" 70 71 #include "mhd_tls_ver_stct.h" 72 73 #include "tls_open_daemon_data.h" 74 #include "tls_open_conn_data.h" 75 #include "tls_open_funcs.h" 76 77 #include "daemon_options.h" 78 79 #include "daemon_logger.h" 80 81 #ifdef mhd_HAVE_OPENSSL_ACME 82 # include "mhd_tls_acme_func.h" 83 #endif /* mhd_HAVE_OPENSSL_ACME */ 84 85 #include "microhttpd2_portability.h" 86 #include "mhd_public_api.h" 87 88 #if defined(HAVE_WUSED_BUT_MARKED_UNUSED) && defined(MHD_WARN_IGNORE_STYLE_GCC) 89 # define mhd_NOWARN_USED_UNUSED \ 90 MHD_WARN_PUSH_ MHD_WARN_IGNORE_ ("-Wused-but-marked-unused") 91 # define mhd_RESTORE_WARN_USED_UNUSED MHD_WARN_POP_ 92 #else 93 # define mhd_NOWARN_USED_UNUSED /* empty */ 94 # define mhd_RESTORE_WARN_USED_UNUSED /* empty */ 95 #endif 96 97 #ifdef mhd_USE_TLS_DEBUG_MESSAGES 98 99 static MHD_FN_PAR_NONNULL_ (1) int 100 mhd_tls_open_dbg_print_errs (const char *msg, 101 size_t msg_len, 102 void *cls) 103 { 104 int ret; 105 int print_size = (int)msg_len; 106 107 (void)cls; /* Not used */ 108 109 if ((print_size < 0) 110 || (msg_len != (unsigned int)print_size)) 111 print_size = (int)((~((unsigned int)0u)) >> 1); 112 113 ret = fprintf (stderr, 114 "## OpenSSL error: %.*s\n", 115 print_size, msg); 116 (void)fflush (stderr); 117 return ret; 118 } 119 120 121 # define mhd_DBG_PRINT_TLS_ERRS() \ 122 ERR_print_errors_cb (&mhd_tls_open_dbg_print_errs, NULL) 123 124 # define mhd_DBG_PRINT_TLS_INFO_MSG(message) \ 125 do { (void) fprintf (stderr, "## OpenSSL info: %s\n", (message)); \ 126 (void) fflush (stderr);} while (0) 127 # define mhd_DBG_PRINT_TLS_INFO_PARAM1(message, param) \ 128 do { (void) fprintf (stderr, "## OpenSSL info: " message "\n", (param)); \ 129 (void) fflush (stderr);} while (0) 130 #else 131 # define mhd_DBG_PRINT_TLS_ERRS() ERR_clear_error () 132 # define mhd_DBG_PRINT_TLS_INFO_MSG(message) ((void) 0) 133 # define mhd_DBG_PRINT_TLS_INFO_PARAM1(message, param) ((void) 0) 134 #endif 135 136 /* ** Global initialisation / de-initialisation ** */ 137 138 static bool openssl_lib_inited = false; 139 140 #ifdef mhd_HAVE_OPENSSL_ACME 141 /** 142 * The index of the pointer to MHD connection TLS data in the "ex_data" storage 143 * of the TLS session. 144 * This leaves the "app_data" (index zero of the "ex_data" storage) for other 145 * possible uses. 146 */ 147 static int conn_mhd_ctls_idx = -1; 148 #endif /* mhd_HAVE_OPENSSL_ACME */ 149 150 MHD_INTERNAL void 151 mhd_tls_open_global_init_once (void) 152 { 153 const unsigned long ver_num = OpenSSL_version_num (); 154 /* Make sure that used shared OpenSSL library has least the same version as 155 MHD was configured for. Fail if the version is earlier. */ 156 openssl_lib_inited = ((0x900000UL < ver_num) /* Versions before 3.0 */ 157 && (OPENSSL_VERSION_NUMBER <= ver_num)); 158 159 /* The call of OPENSSL_init_ssl() typically not needed, but it won't hurt 160 if library was initialised automatically. 161 In some exotic situations automatic initialisation could fail, and 162 this call would make sure that the library is initialised before used. */ 163 openssl_lib_inited = openssl_lib_inited 164 && (0 < OPENSSL_init_ssl (0, NULL)); 165 166 #ifdef mhd_HAVE_OPENSSL_ACME 167 if (openssl_lib_inited) 168 { 169 conn_mhd_ctls_idx = SSL_get_ex_new_index (0, 170 NULL, 171 NULL, 172 NULL, 173 NULL); 174 openssl_lib_inited = (0 <= conn_mhd_ctls_idx); 175 } 176 #endif /* mhd_HAVE_OPENSSL_ACME */ 177 } 178 179 180 MHD_INTERNAL MHD_FN_PURE_ bool 181 mhd_tls_open_is_inited_fine (void) 182 { 183 return openssl_lib_inited; 184 } 185 186 187 /* ** Daemon initialisation / de-initialisation ** */ 188 189 /** 190 * Check application-provided daemon TLS settings 191 * @param d the daemon handle 192 * @param sk_edge_trigg the sockets polling uses edge-triggering 193 * @param s the application-provided settings 194 * @return #MHD_SC_OK on success, 195 * error code otherwise 196 */ 197 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 198 check_app_tls_settings (struct MHD_Daemon *restrict d, 199 bool sk_edge_trigg, 200 struct DaemonOptions *restrict s) 201 { 202 mhd_assert (MHD_TLS_BACKEND_NONE != s->tls); 203 mhd_assert ((MHD_TLS_BACKEND_OPENSSL == s->tls) \ 204 || (MHD_TLS_BACKEND_ANY == s->tls)); 205 if (NULL == s->tls_cert_key.v_mem_cert) 206 { 207 mhd_LOG_MSG (d, MHD_SC_TLS_CONF_BAD_CERT, \ 208 "No valid TLS certificate is provided"); 209 return MHD_SC_TLS_CONF_BAD_CERT; 210 } 211 mhd_assert (NULL != s->tls_cert_key.v_mem_key); 212 213 if (sk_edge_trigg) 214 { 215 mhd_LOG_MSG (d, MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS, \ 216 "Edge-triggered sockets polling cannot be used " 217 "with OpenSSL backend"); 218 return MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS; 219 } 220 221 #ifdef mhd_HAVE_TLS_ACME 222 if (!mhd_tls_open_is_acme_alpn_supported (s) 223 && s->acme_alpn_required) 224 { 225 mhd_LOG_MSG (d, MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS, 226 "This build of OpenSSL backend does not support " 227 "ACME ALPN challenge protocol, but daemon settings " 228 "require it"); 229 return MHD_SC_TLS_BACKEND_DAEMON_INCOMPATIBLE_SETTINGS; 230 } 231 #endif 232 233 return MHD_SC_OK; 234 } 235 236 237 /* Helper to prevent password prompts in terminal */ 238 static int 239 null_passwd_cb (char *buf, 240 int size, 241 int rwflag, 242 void *cls) 243 { 244 (void)buf; 245 (void)size; 246 (void)rwflag; 247 (void)cls; /* Unused */ 248 mhd_DBG_PRINT_TLS_INFO_MSG ("The NULL passphrase callback is called\n"); 249 return 0; 250 } 251 252 253 /** 254 * Create new empty OpenSSL library context 255 * @param d the daemon handle 256 * @param d_tls the daemon TLS settings 257 * @return 'true' on success, 258 * 'false' otherwise 259 */ 260 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ bool 261 create_lib_ctx (struct MHD_Daemon *restrict d, 262 struct mhd_TlsOpenDaemonData *restrict d_tls) 263 { 264 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY 265 (void)d; /* Used for logging only */ 266 #endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */ 267 mhd_assert (NULL == d_tls->libctx); 268 269 d_tls->libctx = OSSL_LIB_CTX_new (); 270 271 if (NULL == d_tls->libctx) 272 { 273 mhd_DBG_PRINT_TLS_ERRS (); 274 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 275 "Failed to create TLS library context"); 276 return false; 277 } 278 return true; 279 } 280 281 282 /** 283 * Reset OpenSSL library context. 284 * 285 * This function must not be called if library context is being used. 286 * @param d the daemon handle 287 * @param d_tls the daemon TLS settings 288 * @return 'true' on success, 289 * 'false' otherwise 290 */ 291 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ bool 292 reset_lib_ctx (struct MHD_Daemon *restrict d, 293 struct mhd_TlsOpenDaemonData *restrict d_tls) 294 { 295 mhd_assert (NULL != d_tls->libctx); 296 297 OSSL_LIB_CTX_free (d_tls->libctx); 298 d_tls->libctx = NULL; 299 300 return create_lib_ctx (d, 301 d_tls); 302 } 303 304 305 /** 306 * Get non-default pathname for OpenSSL configuration file 307 * @param s the application-provided settings 308 * @param[out] conf_pathname set to the pathname on success 309 * @return #MHD_SC_OK on success, 310 * error code otherwise 311 */ 312 static MHD_FN_PAR_NONNULL_ALL_ 313 MHD_FN_PAR_OUT_ (2) MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 314 daemon_get_conf_file (struct DaemonOptions *restrict s, 315 char **restrict conf_pathname) 316 { 317 size_t name_len; 318 bool has_path; 319 320 mhd_assert (NULL != s->tls_openssl_def_file.v_pathname); 321 322 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY 323 (void)d; /* Used only for logging */ 324 #endif 325 326 /* Handle custom pathname */ 327 328 name_len = strlen (s->tls_openssl_def_file.v_pathname); 329 has_path = (NULL != memchr (s->tls_openssl_def_file.v_pathname, 330 '/', 331 name_len)); 332 #ifdef _WIN32 333 has_path = has_path || (NULL != memchr (s->tls_openssl_def_file, 334 '\\', 335 name_len)); 336 #endif /* _WIN32 */ 337 338 if ((!has_path) && (0u != name_len)) 339 { 340 const char *def_path; 341 size_t def_path_len; 342 343 def_path = X509_get_default_cert_area (); 344 if (NULL == def_path) 345 { 346 mhd_DBG_PRINT_TLS_ERRS (); 347 mhd_DBG_PRINT_TLS_INFO_MSG ("X509_get_default_cert_area() returned NULL"); 348 return MHD_SC_TLS_DAEMON_INIT_FAILED; /* Unrealistic */ 349 } 350 351 def_path_len = strlen (def_path); 352 353 *conf_pathname = 354 (char *)OPENSSL_malloc (def_path_len + 1u + name_len + 1u); 355 if (NULL == *conf_pathname) 356 return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; 357 358 memcpy (*conf_pathname, 359 def_path, 360 def_path_len); 361 (*conf_pathname)[def_path_len] = '/'; 362 memcpy ((*conf_pathname) + def_path_len + 1u, 363 s->tls_openssl_def_file.v_pathname, 364 name_len + 1u); 365 366 return MHD_SC_OK; 367 } 368 369 *conf_pathname = (char *)OPENSSL_malloc (name_len + 1u); 370 if (NULL == *conf_pathname) 371 return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; 372 373 memcpy (*conf_pathname, 374 s->tls_openssl_def_file.v_pathname, 375 name_len + 1u); 376 377 return MHD_SC_OK; 378 } 379 380 381 #ifdef mhd_TLS_OPEN_HAS_CONF_DIAG 382 # define mhd_LIBCTX_FORBIDS_FALLBACKS(d_tls) \ 383 (0 != OSSL_LIB_CTX_get_conf_diagnostics (d_tls->libctx)) 384 #else 385 # define mhd_LIBCTX_FORBIDS_FALLBACKS(d_tls) ((void) (d_tls), ! ! 0) 386 #endif /* ! mhd_TLS_OPEN_HAS_CONF_DIAG */ 387 388 389 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) 390 MHD_FN_PAR_NONNULL_ (4) bool 391 daemon_load_conf_from_cfg (struct MHD_Daemon *restrict d, 392 const char *restrict filename, 393 const char *restrict app_name, 394 CONF *restrict cfg, 395 unsigned long load_flags, 396 bool log_missing_app_name) 397 { 398 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY 399 (void)d; /* Used for logging only */ 400 # ifndef mhd_USE_TLS_DEBUG_MESSAGES 401 (void)filename; /* Used for logs only */ 402 # endif /* mhd_USE_TLS_DEBUG_MESSAGES */ 403 #endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */ 404 405 if (NULL != app_name) 406 { 407 if (NULL == NCONF_get_string (cfg, 408 NULL, 409 app_name)) 410 { 411 if (log_missing_app_name) 412 mhd_LOG_PRINT (d, 413 MHD_SC_TLS_LIB_CONF_WARNING, 414 mhd_LOG_FMT ("TLS library configuration '%s' " 415 "was not found in file '%s'"), 416 app_name, 417 filename); 418 else 419 mhd_DBG_PRINT_TLS_INFO_PARAM1 ("TLS library configuration '%s' " 420 "was not found in the configuration " 421 "file", 422 app_name); 423 return false; 424 } 425 mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Trying to load configuration section " 426 "pointed by '%s'", 427 app_name); 428 } 429 else 430 mhd_DBG_PRINT_TLS_INFO_MSG ("Trying to load configuration section " 431 "pointed by default OpenSSL configuration"); 432 433 if (1 != CONF_modules_load (cfg, 434 app_name, 435 load_flags)) 436 { 437 mhd_DBG_PRINT_TLS_ERRS (); 438 439 mhd_LOG_PRINT (d, 440 MHD_SC_TLS_LIB_CONF_WARNING, 441 mhd_LOG_FMT ("Error loading TLS library " 442 "configuration '%s' " 443 "from file '%s'"), 444 app_name, 445 filename); 446 447 return false; 448 } 449 450 mhd_DBG_PRINT_TLS_INFO_MSG ("Successfully loaded OpenSSL configuration " 451 "from the configuration file"); 452 453 return true; 454 } 455 456 457 static MHD_FN_PAR_NONNULL_ALL_ 458 MHD_FN_PAR_INOUT_ (2) MHD_FN_PAR_INOUT_ (4) bool 459 cfg_reset_and_reload (struct MHD_Daemon *restrict d, 460 struct mhd_TlsOpenDaemonData *restrict d_tls, 461 const char *restrict filename, 462 CONF **restrict cfg_ptr) 463 { 464 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY 465 (void)d; /* Used for logging only */ 466 #endif /* MHD_SUPPORT_LOG_FUNCTIONALITY */ 467 mhd_assert (NULL != *cfg_ptr); 468 469 mhd_DBG_PRINT_TLS_INFO_MSG ("Resetting library CTX, CONF and reloading " 470 "configuration file"); 471 472 /* Destroy old cfg, which is connected to the library CTX */ 473 NCONF_free (*cfg_ptr); 474 *cfg_ptr = NULL; 475 476 /* Reset OpenSSL library CTX, which may have partially applied configuration */ 477 if (!reset_lib_ctx (d, 478 d_tls)) 479 return false; 480 481 /* Create a new cfg connected to the new CTX */ 482 *cfg_ptr = NCONF_new_ex (d_tls->libctx, 483 NULL); 484 if (NULL == *cfg_ptr) 485 { 486 mhd_DBG_PRINT_TLS_ERRS (); 487 488 mhd_DBG_PRINT_TLS_INFO_MSG ("Failed to create a new OpenSSL CONF"); 489 return false; 490 } 491 492 if (0 >= NCONF_load (*cfg_ptr, 493 filename, 494 NULL)) 495 { 496 mhd_DBG_PRINT_TLS_ERRS (); 497 498 mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Failed to reload configuration file '%s'", 499 filename); 500 return false; 501 } 502 503 return true; 504 } 505 506 507 static inline MHD_FN_PAR_NONNULL_ALL_ bool 508 is_conf_file_fallback_allowed ( 509 const struct mhd_TlsOpenDaemonData *restrict d_tls, 510 const struct DaemonOptions *restrict s) 511 { 512 mhd_assert (NULL != d_tls->libctx); 513 514 if (!s->tls_openssl_def_file.v_disable_fallback) 515 return false; 516 if (mhd_LIBCTX_FORBIDS_FALLBACKS (d_tls)) 517 return false; 518 return true; 519 } 520 521 522 static inline MHD_FN_PAR_NONNULL_ALL_ bool 523 is_conf_fallback_allowed (const struct mhd_TlsOpenDaemonData *restrict d_tls, 524 const struct DaemonOptions *restrict s) 525 { 526 if (!s->tls_app_name.v_disable_fallback) 527 return false; 528 529 return is_conf_file_fallback_allowed (d_tls, 530 s); 531 } 532 533 534 /** 535 * Load OpenSSL configuration from OpenSSL configuration file 536 * @param d the daemon handle 537 * @param d_tls the daemon TLS settings 538 * @param s the application-provided settings 539 * @param use_custom_conf_pathname choose application-provided pathname or 540 * TLS backend default pathname 541 * @return #MHD_SC_OK on success, 542 * #MHD_SC_TLS_LIB_CONF_WARNING if configuration was not loaded due to 543 * non-fatal error, 544 * error code otherwise 545 */ 546 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_NONNULL_ (3) 547 MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 548 daemon_load_lib_conf (struct MHD_Daemon *restrict d, 549 struct mhd_TlsOpenDaemonData *restrict d_tls, 550 struct DaemonOptions *restrict s, 551 bool use_custom_conf_pathname) 552 { 553 char *conf_pathname; 554 CONF *conf; 555 enum MHD_StatusCode ret; 556 557 if (!use_custom_conf_pathname) 558 { 559 /* Use default pathname */ 560 conf_pathname = CONF_get1_default_config_file (); 561 562 if (NULL == conf_pathname) 563 { 564 mhd_DBG_PRINT_TLS_ERRS (); 565 566 ret = is_conf_fallback_allowed (d_tls, 567 s) 568 ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED; 569 570 mhd_LOG_MSG (d, ret, \ 571 "Failed to get default configuration file pathname"); 572 } 573 else 574 ret = MHD_SC_OK; 575 } 576 else 577 ret = daemon_get_conf_file (s, 578 &conf_pathname); 579 580 if (MHD_SC_OK != ret) 581 { 582 mhd_DBG_PRINT_TLS_INFO_MSG ("Failed to get configuration file pathname"); 583 return ret; 584 } 585 586 mhd_ASSUME (NULL != conf_pathname); 587 mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Trying '%s' as OpenSSL configuration file", 588 conf_pathname); 589 590 if ('\0' == conf_pathname[0]) 591 { 592 OPENSSL_free (conf_pathname); /* A short-cut */ 593 594 if (NULL == s->tls_app_name.v_app_name) 595 return MHD_SC_OK; /* No special "application name" profile is needed */ 596 597 if (!s->tls_app_name.v_disable_fallback) 598 return MHD_SC_OK; /* Initialisation allowed with default values */ 599 600 /* Load of special "application name" profile is required */ 601 602 if (!use_custom_conf_pathname) 603 return MHD_SC_TLS_DAEMON_INIT_FAILED; /* No fallback pathname */ 604 605 mhd_assert (NULL != s->tls_openssl_def_file.v_pathname); 606 607 if (s->tls_openssl_def_file.v_disable_fallback) 608 return MHD_SC_TLS_DAEMON_INIT_FAILED; /* Fallback pathname is disallowed */ 609 610 /* Try to use fallback pathname to load special "application name" profile */ 611 return MHD_SC_TLS_LIB_CONF_WARNING; 612 } 613 614 conf = NCONF_new_ex (d_tls->libctx, 615 NULL); 616 if (NULL == conf) 617 { 618 mhd_DBG_PRINT_TLS_ERRS (); 619 620 ret = is_conf_fallback_allowed (d_tls, 621 s) 622 ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED; 623 mhd_LOG_MSG (d, ret, \ 624 "Failed to create OpenSSL empty configuration object"); 625 } 626 627 if (MHD_SC_OK == ret) 628 { 629 long err_line_num; 630 mhd_DBG_PRINT_TLS_INFO_PARAM1 ("Trying to load configuration file '%s'", 631 conf_pathname); 632 633 if (0 >= NCONF_load (conf, 634 conf_pathname, 635 &err_line_num)) 636 { 637 mhd_DBG_PRINT_TLS_ERRS (); 638 639 if (use_custom_conf_pathname) 640 ret = is_conf_file_fallback_allowed (d_tls, 641 s) 642 ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED; 643 else 644 ret = is_conf_fallback_allowed (d_tls, 645 s) 646 ? MHD_SC_TLS_LIB_CONF_WARNING : MHD_SC_TLS_DAEMON_INIT_FAILED; 647 648 mhd_LOG_PRINT (d, 649 ret, 650 mhd_LOG_FMT ("Error loading TLS library configuration " 651 "file '%s' at line %ld"), 652 conf_pathname, 653 err_line_num); 654 } 655 656 if (MHD_SC_OK == ret) 657 { 658 bool conf_loaded; 659 unsigned long flags; 660 661 flags = 0u; 662 if (!s->tls_app_name.v_disable_fallback) 663 flags |= CONF_MFLAGS_IGNORE_ERRORS; 664 665 conf_loaded = false; 666 667 if (NULL != s->tls_app_name.v_app_name) 668 { 669 char app_name_lc[128]; 670 const size_t app_name_len = strlen (s->tls_app_name.v_app_name); 671 672 /* Checked at the parameter processing */ 673 mhd_ASSUME ((128u) > app_name_len); 674 675 mhd_str_to_lowercase_bin_n (app_name_len + 1u, /* '+1' for zero termination */ 676 s->tls_app_name.v_app_name, 677 app_name_lc); 678 679 mhd_ASSUME ('\0' == app_name_lc[app_name_len]); 680 681 conf_loaded = 682 daemon_load_conf_from_cfg (d, 683 conf_pathname, 684 app_name_lc, 685 conf, 686 flags, 687 s->tls_app_name.v_disable_fallback 688 || mhd_LIBCTX_FORBIDS_FALLBACKS (d_tls)); 689 690 if (!conf_loaded) 691 { 692 if (s->tls_app_name.v_disable_fallback 693 || mhd_LIBCTX_FORBIDS_FALLBACKS (d_tls)) 694 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 695 else if (!cfg_reset_and_reload (d, 696 d_tls, 697 conf_pathname, 698 &conf)) 699 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 700 } 701 } 702 703 if (!conf_loaded 704 && (MHD_SC_OK == ret)) 705 { 706 707 mhd_assert ((NULL == s->tls_app_name.v_app_name) 708 || !s->tls_app_name.v_disable_fallback); 709 710 conf_loaded = 711 daemon_load_conf_from_cfg (d, 712 conf_pathname, 713 "libmicrohttpd", 714 conf, 715 flags, 716 false); 717 if ((!conf_loaded) 718 && (!cfg_reset_and_reload (d, 719 d_tls, 720 conf_pathname, 721 &conf))) 722 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 723 } 724 725 if (!conf_loaded 726 && (MHD_SC_OK == ret)) 727 { 728 729 mhd_assert ((NULL == s->tls_app_name.v_app_name) 730 || !s->tls_app_name.v_disable_fallback); 731 732 conf_loaded = 733 daemon_load_conf_from_cfg (d, 734 conf_pathname, 735 NULL, 736 conf, 737 flags, 738 true); 739 } 740 741 if (!conf_loaded) 742 ret = MHD_SC_TLS_LIB_CONF_WARNING; 743 } 744 745 NCONF_free (conf); /* Explicitly safe with NULL */ 746 } 747 748 OPENSSL_free (conf_pathname); 749 750 return ret; 751 } 752 753 754 /** 755 * Initialise OpenSSL library context 756 * @param d the daemon handle 757 * @param d_tls the daemon TLS settings 758 * @param s the application-provided settings 759 * @return #MHD_SC_OK on success, 760 * error code otherwise 761 */ 762 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 763 daemon_init_lib_ctx (struct MHD_Daemon *restrict d, 764 struct mhd_TlsOpenDaemonData *restrict d_tls, 765 struct DaemonOptions *restrict s) 766 { 767 enum MHD_StatusCode ret; 768 769 if (!create_lib_ctx (d, d_tls)) 770 return MHD_SC_TLS_DAEMON_INIT_FAILED; 771 772 if (NULL != s->tls_openssl_def_file.v_pathname) 773 { 774 ret = daemon_load_lib_conf (d, 775 d_tls, 776 s, 777 true); 778 779 if (MHD_SC_OK == ret) 780 return MHD_SC_OK; 781 782 if (MHD_SC_TLS_LIB_CONF_WARNING == ret) 783 ret = s->tls_openssl_def_file.v_disable_fallback 784 ? MHD_SC_TLS_DAEMON_INIT_FAILED : MHD_SC_OK; 785 } 786 else 787 ret = MHD_SC_OK; 788 789 mhd_assert (MHD_SC_TLS_LIB_CONF_WARNING != ret); 790 791 if (MHD_SC_OK == ret) 792 { 793 mhd_assert ((NULL == s->tls_openssl_def_file.v_pathname) 794 || !s->tls_openssl_def_file.v_disable_fallback); 795 796 ret = daemon_load_lib_conf (d, 797 d_tls, 798 s, 799 false); 800 801 if (MHD_SC_OK == ret) 802 return MHD_SC_OK; 803 804 if (MHD_SC_TLS_LIB_CONF_WARNING == ret) 805 { 806 if ((!s->tls_app_name.v_disable_fallback) 807 && (!s->tls_openssl_def_file.v_disable_fallback)) 808 return MHD_SC_OK; /* Load without configuration file */ 809 810 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 811 } 812 } 813 814 mhd_assert (MHD_SC_TLS_LIB_CONF_WARNING != ret); 815 816 OSSL_LIB_CTX_free (d_tls->libctx); /* Explicitly safe with NULL */ 817 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 818 "Failed to initialise TLS library context"); 819 return MHD_SC_TLS_DAEMON_INIT_FAILED; 820 } 821 822 823 /** 824 * De-initialise OpenSSL library context 825 * @param d_tls the daemon TLS settings 826 */ 827 static MHD_FN_PAR_NONNULL_ALL_ void 828 daemon_deinit_lib_ctx (struct mhd_TlsOpenDaemonData *restrict d_tls) 829 { 830 mhd_assert (NULL != d_tls->libctx); 831 OSSL_LIB_CTX_free (d_tls->libctx); 832 } 833 834 835 #define mhd_ALPN_CODE_HTTP1_0 \ 836 'h', 't', 't', 'p', '/', '1', '.', '0' /* Registered value for HTTP/1.0 */ 837 #define mhd_ALPN_CODE_HTTP1_1 \ 838 'h', 't', 't', 'p', '/', '1', '.', '1' /* Registered value for HTTP/1.1 */ 839 #ifdef MHD_SUPPORT_HTTP2 840 # define mhd_ALPN_CODE_HTTP2 \ 841 'h', '2' /* Registered value for HTTP/2 over TLS */ 842 #endif /* MHD_SUPPORT_HTTP2 */ 843 #if 0 /* Disabled code */ 844 # define mhd_ALPN_CODE_HTTP3 \ 845 'h', '3' /* Registered value for HTTP/3 */ 846 #endif /* Disabled code */ 847 #ifdef mhd_HAVE_OPENSSL_ACME 848 /* Registered value for ACME TLS-ALPN-01 challenge */ 849 # define mhd_ALPN_CODE_ACME \ 850 'a', 'c', 'm', 'e', '-', 't', 'l', 's', '/', '1' 851 #endif /* mhd_HAVE_OPENSSL_ACME */ 852 853 854 #ifdef MHD_SUPPORT_HTTP2 855 static const unsigned char alpn_list_http2_1x[] = { 856 mhd_ALPN_H2_LEN, mhd_ALPN_CODE_HTTP2 857 , 858 mhd_ALPN_H1_1_LEN, mhd_ALPN_CODE_HTTP1_1 859 , 860 mhd_ALPN_H1_0_LEN, mhd_ALPN_CODE_HTTP1_0 861 }; 862 static const unsigned char alpn_list_http2_only[] = { 863 mhd_ALPN_H2_LEN, mhd_ALPN_CODE_HTTP2 864 }; 865 #endif /* MHD_SUPPORT_HTTP2 */ 866 static const unsigned char alpn_list_http1x_only[] = { 867 mhd_ALPN_H1_1_LEN, mhd_ALPN_CODE_HTTP1_1 868 , 869 mhd_ALPN_H1_0_LEN, mhd_ALPN_CODE_HTTP1_0 870 }; 871 #ifdef mhd_HAVE_OPENSSL_ACME 872 /* RFC 8737, section 3: the ACME TLS-ALPN-01 challenge is answered with 873 the "acme-tls/1" protocol and no other protocol */ 874 static const unsigned char alpn_list_acme_only[] = { 875 mhd_ALPN_ACME_LEN, mhd_ALPN_CODE_ACME 876 }; 877 #endif /* mhd_HAVE_OPENSSL_ACME */ 878 879 #ifndef OPENSSL_NO_NEXTPROTONEG 880 /** 881 * Provide the list of supported protocols for NPN extension 882 * @param sess the TLS session (ignored) 883 * @param[out] out the pointer to get the location of the data 884 * @param[out] outlen the size of the data provided 885 * @param cls the closure (ignored) 886 * @return always SSL_TLSEXT_ERR_OK 887 */ 888 static int 889 get_npn_list (SSL *sess, 890 const unsigned char **out, 891 unsigned int *outlen, 892 void *cls) 893 { 894 struct mhd_TlsOpenDaemonData *const d_tls = 895 (struct mhd_TlsOpenDaemonData *)cls; 896 (void)sess; /* Unused */ 897 *out = d_tls->alpn_prots; 898 *outlen = d_tls->alpn_prots_size; 899 return SSL_TLSEXT_ERR_OK; 900 } 901 902 903 #endif /* ! OPENSSL_NO_NEXTPROTONEG */ 904 905 /** 906 * Select protocol from the provided list for ALPN extension 907 * @param sess the TLS session 908 * @param[out] out the pointer to get the location of selected protocol value 909 * @param[out] outlen the size of the selected protocol value 910 * @param in the list of protocols values provided by the client 911 * @param inlen the size of the list of protocols values provided by the client 912 * @param cls the closure (ignored) 913 * @return SSL_TLSEXT_ERR_OK if matching protocol found and selected, 914 * SSL_TLSEXT_ERR_ALERT_FATAL otherwise 915 */ 916 static int 917 select_alpn_prot (SSL *sess, 918 const unsigned char **out, 919 unsigned char *outlen, 920 const unsigned char *in, 921 unsigned int inlen, 922 void *cls) 923 { 924 struct mhd_TlsOpenDaemonData *const restrict d_tls = 925 (struct mhd_TlsOpenDaemonData *)cls; 926 927 #ifdef mhd_HAVE_OPENSSL_ACME 928 if (!0) 929 { 930 const struct mhd_TlsOpenConnData *const restrict c_tls = 931 (const struct mhd_TlsOpenConnData *)SSL_get_ex_data (sess, 932 conn_mhd_ctls_idx); 933 mhd_assert (NULL != c_tls); 934 935 if (c_tls->is_acme) 936 { 937 /* ALPN has been checked: ACME TLS-ALPN-01 only */ 938 mhd_assert (inlen == (unsigned int)sizeof(alpn_list_acme_only)); 939 mhd_assert (0 == memcmp (in, alpn_list_acme_only, inlen)); 940 941 *out = alpn_list_acme_only + 1; /* Skip the length byte */ 942 *outlen = (unsigned char)mhd_ALPN_ACME_LEN; 943 return SSL_TLSEXT_ERR_OK; /* Success */ 944 } 945 } 946 #else /* ! mhd_HAVE_OPENSSL_ACME */ 947 (void)sess; /* Unused */ 948 #endif /* ! mhd_HAVE_OPENSSL_ACME */ 949 950 if (OPENSSL_NPN_NEGOTIATED == 951 SSL_select_next_proto ((unsigned char **)mhd_DROP_CONST (out), 952 outlen, 953 in, 954 inlen, 955 d_tls->alpn_prots, 956 d_tls->alpn_prots_size)) 957 return SSL_TLSEXT_ERR_OK; /* Success */ 958 959 return SSL_TLSEXT_ERR_ALERT_FATAL; /* Failure */ 960 } 961 962 963 #ifdef mhd_USE_OPENSSL_CLIENT_HELLO_GET0_EXT 964 # ifndef mhd_HAVE_OPENSSL_ACME 965 # error mhd_USE_OPENSSL_CLIENT_HELLO_GET0_EXT requires mhd_HAVE_OPENSSL_ACME 966 # endif /* ! mhd_HAVE_OPENSSL_ACME */ 967 #endif /* mhd_USE_OPENSSL_CLIENT_HELLO_GET0_EXT */ 968 969 #ifdef mhd_HAVE_OPENSSL_ACME 970 971 /** 972 * The TLS session ID context for the ACME ALPN challenge connections. 973 * The value is not interpreted by the TLS library, it only has to differ from 974 * the context used for the normal connections, which is the empty default one. 975 */ 976 static const unsigned char acme_sid_ctx[] = { 'A', 'C', 'M', 'E' }; 977 978 979 /** 980 * Callback to prevent storing of the ACME ALPN challenge session 981 * @param sess the TLS session (unused) 982 * @param is_forward_secure set to non-zero if the session is forward secure 983 * (unused) 984 * @return always non-zero, the session must not be stored 985 */ 986 static int 987 acme_sess_not_resumable (SSL *sess, 988 int is_forward_secure) 989 { 990 (void)sess; /* Unused */ 991 (void)is_forward_secure; /* Unused */ 992 return !0; 993 } 994 995 996 /** 997 * Exclude the connection from the TLS sessions resumption. 998 * 999 * The ACME certificate is set for the single connection, while a resumed 1000 * handshake sends no certificate at all and the client keeps the certificate 1001 * of the original session. Therefore both directions must be blocked: 1002 * the session of this connection must not be stored, so that no normal 1003 * connection could resume it and get the ACME certificate, and this connection 1004 * must not resume any session stored for the normal connections, as it would 1005 * get the daemon certificate instead of the ACME certificate. 1006 * 1007 * The session ID context must be set before the TLS library looks up 1008 * the session requested by the client, the callback preventing the storing is 1009 * used later. 1010 * 1011 * @param sess the TLS session to exclude from the sessions resumption 1012 * @return 'true' on success, 1013 * 'false' otherwise 1014 */ 1015 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ bool 1016 mark_acme_no_resume (SSL *sess) 1017 { 1018 /* Any stored session has another session ID context, which is treated by 1019 the TLS library as a cache miss */ 1020 if (0 == SSL_set_session_id_context (sess, 1021 acme_sid_ctx, 1022 (unsigned int)sizeof(acme_sid_ctx))) 1023 return false; 1024 1025 SSL_set_not_resumable_session_callback (sess, 1026 &acme_sess_not_resumable); 1027 return true; 1028 } 1029 1030 1031 /** 1032 * Result of the application of the ACME ALPN challenge check to a connection 1033 */ 1034 enum mhd_TlsOpenConnAcmeCheckFinishResult 1035 { 1036 /** 1037 * The connection is prepared and the handshake can be continued, either as 1038 * a normal HTTPS connection or as an ACME ALPN challenge connection 1039 */ 1040 mhd_TLS_OPEN_ACME_CHECK_FINISH_OK = 0, 1041 /** 1042 * The TLS library failed to use the ACME credentials for the connection. 1043 * The handshake must be aborted, the "internal error" alert matches 1044 * the failure. 1045 */ 1046 mhd_TLS_OPEN_ACME_CHECK_FINISH_ERROR, 1047 /** 1048 * The second ClientHello message, received after TLS 1.3 HelloRetryRequest, 1049 * has been recognised differently than the first one. 1050 * The handshake must be aborted, the "illegal parameter" alert matches 1051 * the failure. 1052 */ 1053 mhd_TLS_OPEN_ACME_CHECK_FINISH_MISMATCH_HRR 1054 }; 1055 1056 1057 /** 1058 * Apply the result of the ACME ALPN challenge check to the connection. 1059 * 1060 * If the ClientHello message has been recognised as the challenge, the ACME 1061 * certificate, the private key and the certificates chain are set for 1062 * the connection and the connection is excluded from the TLS sessions 1063 * resumption. Otherwise only the state of the connection is updated, as 1064 * the ALPN protocols for a normal HTTPS connection are set for the TLS 1065 * context. 1066 * 1067 * The function must be called for every checked ClientHello message, 1068 * including the second one received after TLS 1.3 HelloRetryRequest. 1069 * 1070 * @param[in,out] c_tls the connection TLS handle 1071 * @param acme_certs the list of the ACME certificates used for the check 1072 * @param acme_cred the credentials selected by the check, 1073 * or NULL if the ClientHello message is not 1074 * an ACME ALPN challenge 1075 * @return #mhd_TLS_OPEN_ACME_CHECK_FINISH_OK if the handshake can be 1076 * continued, 1077 * other values if the handshake must be aborted 1078 * @warning If @p acme_cred is not NULL, the list of the ACME certificates is 1079 * read-locked by the check and is unlocked by this function 1080 */ 1081 static MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ (1) 1082 MHD_FN_PAR_NONNULL_ (2) enum mhd_TlsOpenConnAcmeCheckFinishResult 1083 mhd_tls_open_conn_acme_check_finish ( 1084 struct mhd_TlsOpenConnData *restrict c_tls, 1085 struct mhd_TlsCertsList *restrict acme_certs, 1086 const union mhd_TlsCredDataPtr *restrict acme_cred) 1087 { 1088 enum mhd_TlsOpenConnAcmeCheckFinishResult res; 1089 1090 mhd_assert (NULL != c_tls); 1091 1092 if (NULL == acme_cred) 1093 { 1094 /* Normal (not ACME ALPN challenge) connection */ 1095 if (c_tls->is_acme) /* Second ClientHello after TLS 1.3 HRR with another result */ 1096 { 1097 mhd_assert (c_tls->clienthello_processed); 1098 c_tls->is_acme = false; /* Reset to non-ACME connection */ 1099 return mhd_TLS_OPEN_ACME_CHECK_FINISH_MISMATCH_HRR; /* Unmatched ClientHello, abort handshake */ 1100 } 1101 1102 /* Process the connection as a normal HTTPS connection. */ 1103 c_tls->clienthello_processed = true; 1104 return mhd_TLS_OPEN_ACME_CHECK_FINISH_OK; /* Non-ACME connection exit point */ 1105 } 1106 1107 /* Assume OK unless the checks below fail */ 1108 res = mhd_TLS_OPEN_ACME_CHECK_FINISH_OK; 1109 1110 if (c_tls->clienthello_processed && !c_tls->is_acme) 1111 res = mhd_TLS_OPEN_ACME_CHECK_FINISH_MISMATCH_HRR; 1112 1113 if (mhd_TLS_OPEN_ACME_CHECK_FINISH_OK == res) 1114 { 1115 struct mhd_TlsOpenCredData *const restrict acme_open_cred = 1116 acme_cred->open; 1117 1118 mhd_assert (NULL != acme_open_cred); 1119 1120 ERR_clear_error (); 1121 /* Remove the daemon certificate: the certificate of another key type 1122 would not be replaced by the ACME certificate and could be selected 1123 by the TLS library instead of it. */ 1124 SSL_certs_clear (c_tls->sess); 1125 /* The TLS library takes its own references for the objects, therefore 1126 the ACME credentials could be removed by the application at any moment 1127 after this point */ 1128 if (!mark_acme_no_resume (c_tls->sess) 1129 || (0 >= SSL_use_certificate (c_tls->sess, 1130 acme_open_cred->cert)) 1131 || (0 >= SSL_set1_chain (c_tls->sess, 1132 acme_open_cred->chain)) 1133 || (0 >= SSL_use_PrivateKey (c_tls->sess, 1134 acme_open_cred->key))) 1135 { 1136 mhd_DBG_PRINT_TLS_ERRS (); 1137 res = mhd_TLS_OPEN_ACME_CHECK_FINISH_ERROR; 1138 } 1139 } 1140 mhd_daemon_acme_cert_r_unlock (acme_certs); 1141 1142 c_tls->clienthello_processed = true; 1143 c_tls->is_acme = (mhd_TLS_OPEN_ACME_CHECK_FINISH_OK == res); 1144 return res; 1145 } 1146 1147 1148 # ifdef mhd_USE_OPENSSL_CLIENT_HELLO_GET0_EXT 1149 1150 1151 /** 1152 * Check whether the ClientHello message is the ACME TLS-ALPN-01 challenge and 1153 * select the ACME credentials for the indicated domain. 1154 * 1155 * The extensions are taken from the ClientHello message parsed by the TLS 1156 * library. The TLS library rejects any duplicated extension before this 1157 * function is called. 1158 * 1159 * @param sess the TLS session processing the ClientHello message 1160 * @param acme_certs the list of the ACME certificates to check against 1161 * @return non-NULL if the ClientHello message is recognised as a TLS-ALPN-01 1162 * challenge and the ACME credentials are selected, 1163 * NULL otherwise 1164 * @warning If a non-NULL pointer is returned, the daemon's ACME certificate 1165 * list remains read-locked and must be unlocked with 1166 * #mhd_daemon_acme_cert_r_unlock(). 1167 */ 1168 static MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ 1169 const union mhd_TlsCredDataPtr * 1170 clnthello_check_acme (SSL *sess, 1171 struct mhd_TlsCertsList *restrict acme_certs) 1172 { 1173 struct mhd_TlsClientHelloAcmeCheckData check; 1174 bool all_checks_ok; 1175 1176 mhd_tls_acme_check_ext_init (&check, 1177 acme_certs); 1178 1179 all_checks_ok = true; 1180 1181 /* The ALPN extension is checked first as it is checked without locking 1182 the list of the ACME certificates. Any typical HTTPS ClientHello is 1183 rejected by this check alone. */ 1184 if (all_checks_ok) 1185 { 1186 static const unsigned int ext_alpn_id = 1187 TLSEXT_TYPE_application_layer_protocol_negotiation; 1188 const unsigned char *ext_alpn_data; 1189 size_t ext_alpn_size; 1190 1191 all_checks_ok = (0 != SSL_client_hello_get0_ext (sess, 1192 ext_alpn_id, 1193 &ext_alpn_data, 1194 &ext_alpn_size)); 1195 if (all_checks_ok) 1196 all_checks_ok = mhd_tls_acme_check_ext (ext_alpn_id, 1197 ext_alpn_size, 1198 ext_alpn_data, 1199 &check); 1200 } 1201 1202 if (all_checks_ok) 1203 { 1204 static const unsigned int ext_sni_id = TLSEXT_TYPE_server_name; 1205 const unsigned char *ext_sni_data; 1206 size_t ext_sni_size; 1207 1208 all_checks_ok = (0 != SSL_client_hello_get0_ext (sess, 1209 ext_sni_id, 1210 &ext_sni_data, 1211 &ext_sni_size)); 1212 if (all_checks_ok) 1213 all_checks_ok = mhd_tls_acme_check_ext (ext_sni_id, 1214 ext_sni_size, 1215 ext_sni_data, 1216 &check); 1217 } 1218 1219 /* The TLS library parsed the complete ClientHello message before calling 1220 this function, no need to make additional check for parse completeness */ 1221 return mhd_tls_acme_check_ext_finish (&check, 1222 all_checks_ok); 1223 } 1224 1225 1226 /** 1227 * The TLS library callback for checking the ClientHello message for 1228 * the ACME ALPN challenge. 1229 * 1230 * The callback is registered for the TLS context as the TLS library has no 1231 * session-specific version of this callback. 1232 * 1233 * @param sess the TLS session processing the ClientHello message 1234 * @param[out] alert the TLS alert to send if the handshake is aborted 1235 * @param cls the closure, the pointer to the daemon TLS settings 1236 * @return #SSL_CLIENT_HELLO_SUCCESS for a normal HTTPS ClientHello or after 1237 * successful ACME setup, 1238 * #SSL_CLIENT_HELLO_ERROR to abort the handshake otherwise 1239 */ 1240 static int 1241 check_clnt_hello_cb (SSL *sess, 1242 int *alert, 1243 void *cls) 1244 { 1245 struct mhd_TlsOpenDaemonData *const restrict d_tls = 1246 (struct mhd_TlsOpenDaemonData *)cls; 1247 struct mhd_TlsOpenConnData *const restrict c_tls = 1248 (struct mhd_TlsOpenConnData *)SSL_get_ex_data (sess, 1249 conn_mhd_ctls_idx); 1250 const union mhd_TlsCredDataPtr *acme_cred; /* Set to non-NULL if request is recognised ACME challenge */ 1251 enum mhd_TlsOpenConnAcmeCheckFinishResult res; 1252 1253 mhd_assert (NULL != c_tls); 1254 mhd_assert (c_tls->sess == sess); 1255 1256 acme_cred = NULL; 1257 if (mhd_daemon_has_acme_certs (d_tls->acme_certs)) 1258 acme_cred = clnthello_check_acme (sess, 1259 d_tls->acme_certs); 1260 1261 res = mhd_tls_open_conn_acme_check_finish (c_tls, 1262 d_tls->acme_certs, 1263 acme_cred); 1264 1265 switch (res) 1266 { 1267 case mhd_TLS_OPEN_ACME_CHECK_FINISH_OK: 1268 return SSL_CLIENT_HELLO_SUCCESS; /* Success exit point */ 1269 1270 case mhd_TLS_OPEN_ACME_CHECK_FINISH_ERROR: 1271 *alert = SSL_AD_INTERNAL_ERROR; 1272 break; 1273 1274 case mhd_TLS_OPEN_ACME_CHECK_FINISH_MISMATCH_HRR: 1275 *alert = SSL_AD_ILLEGAL_PARAMETER; 1276 break; 1277 1278 default: 1279 mhd_UNREACHABLE (); 1280 *alert = SSL_AD_INTERNAL_ERROR; 1281 break; 1282 } 1283 1284 return SSL_CLIENT_HELLO_ERROR; /* Failure exit point */ 1285 } 1286 1287 1288 # else /* ! mhd_USE_OPENSSL_CLIENT_HELLO_GET0_EXT */ 1289 1290 /** 1291 * Callback to abort the TLS handshake. 1292 * 1293 * The messages callback cannot report any failure, therefore this callback is 1294 * set by the messages callback when the handshake must be aborted. The TLS 1295 * library calls it after the ClientHello message has been processed and 1296 * before the response is constructed. 1297 * 1298 * @param sess the TLS session (unused) 1299 * @param cls the closure (unused) 1300 * @return always zero, the handshake is aborted with the "internal error" 1301 * alert 1302 */ 1303 static int 1304 cert_cb_always_fail (SSL *sess, 1305 void *cls) 1306 { 1307 (void)sess; /* Unused */ 1308 (void)cls; /* Unused */ 1309 return 0; 1310 } 1311 1312 1313 /** 1314 * The TLS library callback for checking the ClientHello message for 1315 * the ACME ALPN challenge. 1316 * 1317 * The callback is set for the session, but only when the daemon has any ACME 1318 * certificate. The body of the ClientHello message is parsed by MHD. 1319 * 1320 * The callback removes itself as soon as no ClientHello message can be 1321 * received on the connection any more. 1322 * 1323 * @param write_p zero if the message is received, non-zero if it is sent 1324 * @param version the TLS protocol version (unused) 1325 * @param content_type the type of the record carrying the message 1326 * @param buf the message data, including the handshake header 1327 * @param len the size of the data pointed by @a buf 1328 * @param sess the TLS session processing the message 1329 * @param cls the closure, the list of the ACME certificates 1330 */ 1331 static void 1332 check_hello_msg_acme (int write_p, 1333 int version, 1334 int content_type, 1335 const void *buf, 1336 size_t len, 1337 SSL *sess, 1338 void *cls) 1339 { 1340 struct mhd_TlsCertsList *const restrict acme_certs = 1341 (struct mhd_TlsCertsList *)cls; 1342 struct mhd_TlsOpenConnData *const restrict c_tls = 1343 (struct mhd_TlsOpenConnData *)SSL_get_ex_data (sess, 1344 conn_mhd_ctls_idx); 1345 const unsigned char *const restrict msg = (const unsigned char *)buf; 1346 const union mhd_TlsCredDataPtr *acme_cred; /* Set to non-NULL if request is recognised ACME challenge */ 1347 1348 (void)version; /* Unused */ 1349 mhd_assert (NULL != c_tls); 1350 mhd_assert (c_tls->sess == sess); 1351 1352 if ((0 != write_p) || (SSL3_RT_HANDSHAKE != content_type)) 1353 return; /* Not an incoming handshake message */ 1354 1355 /* The first byte of the handshake header is the type of the message, 1356 the body of the message follows the header */ 1357 if ((((size_t)SSL3_HM_HEADER_LENGTH) >= len) 1358 || (SSL3_MT_CLIENT_HELLO != msg[0])) 1359 { 1360 /* The client has sent another handshake message, no ClientHello can be 1361 received on this connection any more: TLS1.3 has no renegotiation and 1362 TLS1.2 renegotiation is rejected by #SSL_OP_NO_RENEGOTIATION */ 1363 SSL_set_msg_callback (sess, 1364 NULL); 1365 return; 1366 } 1367 1368 /* If this is the second ClientHello then stop the callback, 1369 the TLS library accepts no more ClientHello */ 1370 if (c_tls->clienthello_processed) 1371 SSL_set_msg_callback (sess, 1372 NULL); 1373 1374 acme_cred = 1375 mhd_tls_acme_check_clienthello_body (len - SSL3_HM_HEADER_LENGTH, 1376 msg + SSL3_HM_HEADER_LENGTH, 1377 acme_certs); 1378 1379 if (mhd_TLS_OPEN_ACME_CHECK_FINISH_OK != 1380 mhd_tls_open_conn_acme_check_finish (c_tls, 1381 acme_certs, 1382 acme_cred)) 1383 { 1384 /* This callback cannot abort the handshake, the abort is performed by 1385 the certificates callback after the ClientHello message is processed. 1386 The alert cannot be selected this way: the client always receives 1387 the "internal error" alert. The "illegal parameter" alert, used for 1388 the unmatched ClientHello when the ClientHello callback is available, 1389 is not delivered to the client. */ 1390 SSL_set_cert_cb (sess, 1391 &cert_cb_always_fail, 1392 NULL); 1393 } 1394 } 1395 1396 1397 # endif /* ! mhd_USE_OPENSSL_CLIENT_HELLO_GET0_EXT */ 1398 1399 #endif /* mhd_HAVE_OPENSSL_ACME */ 1400 1401 /** 1402 * Initialise TLS server context 1403 * @param d the daemon handle 1404 * @param d_tls the daemon TLS settings 1405 * @param s the application-provided settings 1406 * @return #MHD_SC_OK on success, 1407 * error code otherwise 1408 */ 1409 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 1410 daemon_init_ctx (struct MHD_Daemon *restrict d, 1411 struct mhd_TlsOpenDaemonData *restrict d_tls, 1412 struct DaemonOptions *restrict s) 1413 { 1414 uint64_t ctx_opts; 1415 1416 #ifndef MHD_SUPPORT_LOG_FUNCTIONALITY 1417 (void)d; /* Mute compiler warning */ 1418 #endif 1419 (void)s; // TODO: support configuration options 1420 1421 mhd_assert (NULL != d_tls->libctx); 1422 1423 ERR_clear_error (); 1424 1425 d_tls->ctx = SSL_CTX_new_ex (d_tls->libctx, 1426 NULL, 1427 TLS_server_method ()); 1428 if (NULL == d_tls->ctx) 1429 { 1430 mhd_DBG_PRINT_TLS_ERRS (); 1431 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1432 "Failed to initialise TLS server context"); 1433 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1434 } 1435 1436 /* Enable some safe and useful workarounds */ 1437 ctx_opts = SSL_OP_SAFARI_ECDHE_ECDSA_BUG | SSL_OP_TLSEXT_PADDING; 1438 1439 // TODO: add configuration option 1440 // ctx_opts |= SSL_OP_CIPHER_SERVER_PREFERENCE; 1441 1442 #ifndef OPENSSL_NO_KTLS 1443 /* Enable kernel TLS */ // TODO: add configuration option 1444 ctx_opts |= SSL_OP_ENABLE_KTLS; 1445 # ifdef SSL_OP_ENABLE_KTLS_TX_ZEROCOPY_SENDFILE 1446 ctx_opts |= SSL_OP_ENABLE_KTLS_TX_ZEROCOPY_SENDFILE; 1447 # endif 1448 #endif 1449 1450 /* HTTP defines strict framing for the client-side data, 1451 no risk of attack on server on unexpected connection interruption */ 1452 /* ctx_opts |= SSL_OP_IGNORE_UNEXPECTED_EOF; */ // TODO: recheck 1453 1454 /* There is no reason to use re-negotiation with HTTP */ 1455 ctx_opts |= SSL_OP_NO_RENEGOTIATION; 1456 1457 /* Do not use TLS 1.3 resumption for now */ 1458 ctx_opts |= SSL_OP_NO_TICKET; 1459 1460 (void)SSL_CTX_set_options (d_tls->ctx, 1461 ctx_opts); 1462 1463 /* Prevent interactive password prompts */ 1464 SSL_CTX_set_default_passwd_cb (d_tls->ctx, 1465 &null_passwd_cb); 1466 1467 // TODO: make the setting configurable 1468 /* SSL_CTX_set_security_level (d_tls->ctx, 0); */ 1469 1470 /* recv()- and send()-related options */ 1471 (void)SSL_CTX_set_mode (d_tls->ctx, 1472 SSL_MODE_ENABLE_PARTIAL_WRITE 1473 | SSL_MODE_AUTO_RETRY); 1474 (void)SSL_CTX_clear_mode (d_tls->ctx, 1475 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 1476 | SSL_MODE_ASYNC); 1477 1478 SSL_CTX_set_read_ahead (d_tls->ctx, 1479 !0); 1480 1481 /* ALPN and NPN */ 1482 // TODO: use daemon option to disable ALPN 1483 // TODO: use daemon option to select protocols for ALPN 1484 #ifdef MHD_SUPPORT_HTTP2 1485 if (1 /* enabled both HTTP/2 and HTTP/1.x */) 1486 { 1487 d_tls->alpn_prots = alpn_list_http2_1x; 1488 d_tls->alpn_prots_size = sizeof(alpn_list_http2_1x); 1489 } 1490 else if (0 /* HTTP/2 only */) 1491 { 1492 d_tls->alpn_prots = alpn_list_http2_only; 1493 d_tls->alpn_prots_size = sizeof(alpn_list_http2_only); 1494 } 1495 else 1496 #endif /* MHD_SUPPORT_HTTP2 */ 1497 if (1 /* HTTP/1.x only */) 1498 { 1499 d_tls->alpn_prots = alpn_list_http1x_only; 1500 d_tls->alpn_prots_size = sizeof(alpn_list_http1x_only); 1501 } 1502 else 1503 { 1504 mhd_UNREACHABLE (); 1505 } 1506 SSL_CTX_set_alpn_select_cb (d_tls->ctx, 1507 &select_alpn_prot, 1508 d_tls); 1509 #ifdef mhd_USE_OPENSSL_CLIENT_HELLO_GET0_EXT 1510 /* The ACME ALPN challenge is detected by the ClientHello message. 1511 The callback is set unconditionally as OpenSSL does not allow to set 1512 it on connection (session) basis. */ 1513 SSL_CTX_set_client_hello_cb (d_tls->ctx, 1514 &check_clnt_hello_cb, 1515 d_tls); 1516 #endif /* mhd_USE_OPENSSL_CLIENT_HELLO_GET0_EXT */ 1517 #ifndef OPENSSL_NO_NEXTPROTONEG 1518 SSL_CTX_set_next_protos_advertised_cb (d_tls->ctx, 1519 &get_npn_list, 1520 d_tls); 1521 #endif /* ! OPENSSL_NO_NEXTPROTONEG */ 1522 1523 return MHD_SC_OK; 1524 } 1525 1526 1527 /** 1528 * De-initialise TLS server context 1529 * @param d_tls the daemon TLS settings 1530 */ 1531 static MHD_FN_PAR_NONNULL_ALL_ void 1532 daemon_deinit_ctx (struct mhd_TlsOpenDaemonData *restrict d_tls) 1533 { 1534 mhd_assert (NULL != d_tls->ctx); 1535 SSL_CTX_free (d_tls->ctx); 1536 } 1537 1538 1539 /** 1540 * Load the certificates chain from the OpenSSL BIO 1541 * @param d the daemon handle 1542 * @param d_tls the daemon TLS settings 1543 * @param bio the certificates chain data opened in OpenSSL BIO 1544 * @return #MHD_SC_OK on success, 1545 * error code otherwise 1546 */ 1547 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 1548 daemon_load_certs_chain_obio (struct MHD_Daemon *restrict d, 1549 struct mhd_TlsOpenDaemonData *restrict d_tls, 1550 BIO *restrict bio) 1551 { 1552 enum MHD_StatusCode ret; 1553 X509 *cert; 1554 1555 ret = MHD_SC_OK; 1556 1557 /* The certificate object must be pre-allocated to associate it with 1558 * the lib context */ 1559 cert = X509_new_ex (d_tls->libctx, 1560 NULL); 1561 if (NULL == cert) 1562 { 1563 mhd_DBG_PRINT_TLS_ERRS (); 1564 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1565 "Failed to create new certificate object"); 1566 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1567 } 1568 1569 if (NULL == PEM_read_bio_X509_AUX (bio, 1570 &cert, 1571 &null_passwd_cb, 1572 NULL)) 1573 { 1574 mhd_DBG_PRINT_TLS_ERRS (); 1575 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1576 "Failed to process the certificate"); 1577 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 1578 } 1579 else 1580 { 1581 if (0 >= SSL_CTX_use_certificate (d_tls->ctx, 1582 cert)) 1583 { 1584 mhd_DBG_PRINT_TLS_ERRS (); 1585 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1586 "Failed to set the certificate"); 1587 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 1588 } 1589 else 1590 { 1591 if (0 != ERR_peek_error ()) 1592 mhd_DBG_PRINT_TLS_ERRS (); 1593 } 1594 } 1595 /* Free certificate: if it was successfully read, it has been "copied" to CTX */ 1596 X509_free (cert); 1597 if (MHD_SC_OK != ret) 1598 return ret; 1599 1600 do 1601 { 1602 X509 *inter_ca; /* Certifying certificate */ 1603 inter_ca = X509_new_ex (d_tls->libctx, 1604 NULL); 1605 if (NULL == inter_ca) 1606 { 1607 mhd_DBG_PRINT_TLS_ERRS (); 1608 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1609 "Failed to create new chain certificate object"); 1610 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1611 } 1612 if (NULL == PEM_read_bio_X509 (bio, 1613 &inter_ca, 1614 &null_passwd_cb, 1615 NULL)) 1616 { 1617 unsigned long err; 1618 err = ERR_peek_last_error (); 1619 1620 mhd_NOWARN_USED_UNUSED 1621 1622 if ((ERR_LIB_PEM == ERR_GET_LIB (err)) 1623 && (PEM_R_NO_START_LINE == ERR_GET_REASON (err))) 1624 { 1625 /* End of data */ 1626 ERR_clear_error (); 1627 X509_free (inter_ca); /* Empty, not needed */ 1628 1629 mhd_assert (MHD_SC_OK == ret); 1630 return MHD_SC_OK; /* Success exit point */ 1631 } 1632 1633 mhd_RESTORE_WARN_USED_UNUSED 1634 mhd_DBG_PRINT_TLS_ERRS (); 1635 1636 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1637 "Failed to load next object in the certificates " \ 1638 "chain"); 1639 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 1640 } 1641 else 1642 { 1643 if (SSL_CTX_add0_chain_cert (d_tls->ctx, 1644 inter_ca)) 1645 { 1646 /* Success, do not free the certificate as 1647 * function '_add0_' was used to add it. */ 1648 /* Read the next certificate in the chain. */ 1649 continue; 1650 } 1651 1652 mhd_DBG_PRINT_TLS_ERRS (); 1653 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1654 "Failed to add the new certificate object " 1655 "to the chain"); 1656 ret = MHD_SC_TLS_DAEMON_INIT_FAILED; 1657 } 1658 1659 X509_free (inter_ca); /* Failed, the object is not needed */ 1660 mhd_assert (MHD_SC_OK != ret); 1661 } while (MHD_SC_OK == ret); 1662 mhd_assert (MHD_SC_OK != ret); 1663 return ret; 1664 } 1665 1666 1667 /** 1668 * Load the certificates chain based on application-provided settings 1669 * @param d the daemon handle 1670 * @param d_tls the daemon TLS settings 1671 * @param s the application-provided settings 1672 * @return #MHD_SC_OK on success, 1673 * error code otherwise 1674 */ 1675 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 1676 daemon_load_certs_chain (struct MHD_Daemon *restrict d, 1677 struct mhd_TlsOpenDaemonData *restrict d_tls, 1678 struct DaemonOptions *restrict s) 1679 { 1680 enum MHD_StatusCode ret; 1681 BIO *m_bio; 1682 1683 mhd_assert (NULL != d_tls->libctx); 1684 mhd_assert (NULL != d_tls->ctx); 1685 1686 ERR_clear_error (); 1687 1688 m_bio = BIO_new_mem_buf (s->tls_cert_key.v_mem_cert, 1689 -1); 1690 if (NULL == m_bio) 1691 { 1692 mhd_DBG_PRINT_TLS_ERRS (); 1693 return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; 1694 } 1695 ret = daemon_load_certs_chain_obio (d, 1696 d_tls, 1697 m_bio); 1698 BIO_free (m_bio); 1699 return ret; 1700 } 1701 1702 1703 /** 1704 * Initialise TLS certificate 1705 * The function loads the certificate chain and the private key. 1706 * @param d the daemon handle 1707 * @param d_tls the daemon TLS settings 1708 * @param s the application-provided settings 1709 * @return #MHD_SC_OK on success, 1710 * error code otherwise 1711 */ 1712 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ enum MHD_StatusCode 1713 daemon_init_cert (struct MHD_Daemon *restrict d, 1714 struct mhd_TlsOpenDaemonData *restrict d_tls, 1715 struct DaemonOptions *restrict s) 1716 { 1717 enum MHD_StatusCode ret; 1718 BIO *m_bio; 1719 EVP_PKEY *pr_key; 1720 int res_i; 1721 long res_l; 1722 1723 mhd_assert (NULL != d_tls->libctx); 1724 mhd_assert (NULL != d_tls->ctx); 1725 1726 ERR_clear_error (); 1727 1728 ret = daemon_load_certs_chain (d, 1729 d_tls, 1730 s); 1731 if (MHD_SC_OK != ret) 1732 return ret; 1733 1734 /* Check and cache the certificates chain. 1735 This also prevents automatic chain re-building for each session. */ 1736 res_l = 1737 SSL_CTX_build_cert_chain ( 1738 d_tls->ctx, 1739 SSL_BUILD_CHAIN_FLAG_CHECK /* Use only certificates in the chain */ 1740 | SSL_BUILD_CHAIN_FLAG_UNTRUSTED /* Intermediate CA certs does not need to be trusted */ 1741 | SSL_BUILD_CHAIN_FLAG_NO_ROOT /* The root CA should not be added to the chain */ 1742 | SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR /* Allow the root CA to be not trusted */ 1743 ); 1744 if (0 >= res_l) 1745 { 1746 mhd_DBG_PRINT_TLS_ERRS (); 1747 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1748 "Failed rebuild certificate chain"); 1749 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1750 } 1751 if (2 == res_l) 1752 mhd_DBG_PRINT_TLS_ERRS (); 1753 1754 m_bio = BIO_new_mem_buf (s->tls_cert_key.v_mem_key, 1755 -1); 1756 if (NULL == m_bio) 1757 { 1758 mhd_DBG_PRINT_TLS_ERRS (); 1759 return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; 1760 } 1761 pr_key = 1762 PEM_read_bio_PrivateKey_ex (m_bio, 1763 NULL, 1764 NULL == s->tls_cert_key.v_mem_pass ? 1765 &null_passwd_cb : NULL, 1766 mhd_DROP_CONST (s->tls_cert_key.v_mem_pass), 1767 d_tls->libctx, 1768 NULL); 1769 BIO_free (m_bio); 1770 if (NULL == pr_key) 1771 { 1772 mhd_DBG_PRINT_TLS_ERRS (); 1773 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1774 "Failed to read the private key"); 1775 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1776 } 1777 1778 res_i = SSL_CTX_use_PrivateKey (d_tls->ctx, 1779 pr_key); 1780 EVP_PKEY_free (pr_key); /* The key has been "copied" or failed */ 1781 if (1 != res_i) 1782 { 1783 mhd_DBG_PRINT_TLS_ERRS (); 1784 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1785 "Failed to set the private key"); 1786 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1787 } 1788 /* This actually RE-checks the key. 1789 The key should be already checked automatically when it was set after 1790 setting the certificate. */ 1791 if (1 != SSL_CTX_check_private_key (d_tls->ctx)) 1792 { 1793 mhd_DBG_PRINT_TLS_ERRS (); 1794 mhd_LOG_MSG (d, MHD_SC_TLS_DAEMON_INIT_FAILED, \ 1795 "The private key does not match the certificate"); 1796 return MHD_SC_TLS_DAEMON_INIT_FAILED; 1797 } 1798 1799 return MHD_SC_OK; 1800 } 1801 1802 1803 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ 1804 MHD_FN_PAR_OUT_ (4) mhd_StatusCodeInt 1805 mhd_tls_open_daemon_init (struct MHD_Daemon *restrict d, 1806 bool sk_edge_trigg, 1807 struct DaemonOptions *restrict s, 1808 struct mhd_TlsOpenDaemonData **restrict p_d_tls) 1809 { 1810 mhd_StatusCodeInt res; 1811 struct mhd_TlsOpenDaemonData *restrict d_tls; 1812 1813 /* Successful initialisation must be checked earlier */ 1814 mhd_assert (openssl_lib_inited); 1815 1816 res = check_app_tls_settings (d, sk_edge_trigg, s); 1817 if (MHD_SC_OK != res) 1818 return res; 1819 1820 d_tls = (struct mhd_TlsOpenDaemonData *) 1821 mhd_calloc (1, sizeof (struct mhd_TlsOpenDaemonData)); 1822 *p_d_tls = d_tls; 1823 if (NULL == d_tls) 1824 return MHD_SC_DAEMON_MEM_ALLOC_FAILURE; 1825 1826 #ifndef HAVE_NULL_PTR_ALL_ZEROS 1827 d_tls->libctx = NULL; 1828 d_tls->ctx = NULL; 1829 d_tls->alpn_prots = NULL; 1830 # ifdef mhd_HAVE_OPENSSL_ACME 1831 d_tls->acme_certs = NULL; 1832 # endif /* mhd_HAVE_OPENSSL_ACME */ 1833 #endif /* ! HAVE_NULL_PTR_ALL_ZEROS */ 1834 1835 #ifdef mhd_HAVE_OPENSSL_ACME 1836 d_tls->acme_certs = mhd_daemon_get_acme_certs (d); 1837 #endif /* mhd_HAVE_OPENSSL_ACME */ 1838 1839 res = daemon_init_lib_ctx (d, 1840 d_tls, 1841 s); 1842 if (MHD_SC_OK == res) 1843 { 1844 res = daemon_init_ctx (d, 1845 d_tls, 1846 s); 1847 if (MHD_SC_OK == res) 1848 { 1849 res = daemon_init_cert (d, 1850 d_tls, 1851 s); 1852 if (MHD_SC_OK == res) 1853 return MHD_SC_OK; /* Success exit point */ 1854 1855 /* Below is a clean-up code path */ 1856 daemon_deinit_ctx (d_tls); 1857 } 1858 daemon_deinit_lib_ctx (d_tls); 1859 } 1860 free (d_tls); 1861 *p_d_tls = NULL; 1862 mhd_assert (MHD_SC_OK != res); 1863 return res; /* Failure exit point */ 1864 } 1865 1866 1867 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 1868 MHD_FN_PAR_INOUT_ (1) void 1869 mhd_tls_open_daemon_deinit (struct mhd_TlsOpenDaemonData *restrict d_tls) 1870 { 1871 mhd_assert (NULL != d_tls); 1872 daemon_deinit_ctx (d_tls); 1873 daemon_deinit_lib_ctx (d_tls); 1874 free (d_tls); 1875 } 1876 1877 1878 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 1879 MHD_FN_PAR_INOUT_ (1) void 1880 mhd_tls_open_thread_cleanup (struct mhd_TlsOpenDaemonData *restrict d_tls) 1881 { 1882 OPENSSL_thread_stop_ex (d_tls->libctx); 1883 } 1884 1885 1886 /* ** Credentials creation / destruction ** */ 1887 1888 #ifdef mhd_HAVE_OPENSSL_ACME 1889 1890 /** 1891 * Read the end-entity certificate and the chain of the signing certificates 1892 * from the provided PEM data. 1893 * @param d_tls the pointer to the daemon's TLS settings 1894 * @param[in,out] cred the credentials data with the initialised (empty) 1895 * @a chain member, the @a cert member is set on success 1896 * @param cert_len the length of the @p cert buffer 1897 * @param cert the certificates data in PEM format 1898 * @return #mhd_TLS_CRED_CREATE_OK on success, 1899 * other enum mhd_TlsCredCreateResult values on failure 1900 */ 1901 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ 1902 MHD_FN_PAR_IN_SIZE_ (4, 3) enum mhd_TlsCredCreateResult 1903 cred_read_certs (struct mhd_TlsOpenDaemonData *restrict d_tls, 1904 struct mhd_TlsOpenCredData *restrict cred, 1905 int cert_len, 1906 const char *restrict cert) 1907 { 1908 BIO *bio; 1909 enum mhd_TlsCredCreateResult res; 1910 1911 mhd_assert (NULL == cred->cert); 1912 mhd_assert (NULL != cred->chain); 1913 1914 res = mhd_TLS_CRED_CREATE_OK; 1915 bio = BIO_new_mem_buf (cert, 1916 cert_len); 1917 if (NULL == bio) 1918 { 1919 mhd_DBG_PRINT_TLS_ERRS (); 1920 res = mhd_TLS_CRED_CREATE_ALLOC_FAILED; 1921 } 1922 else 1923 { 1924 cred->cert = X509_new_ex (d_tls->libctx, 1925 NULL); 1926 if (NULL == cred->cert) 1927 { 1928 mhd_DBG_PRINT_TLS_ERRS (); 1929 res = mhd_TLS_CRED_CREATE_ALLOC_FAILED; 1930 } 1931 else 1932 { 1933 if (NULL == PEM_read_bio_X509_AUX (bio, 1934 &(cred->cert), 1935 &null_passwd_cb, 1936 NULL)) 1937 { 1938 mhd_DBG_PRINT_TLS_ERRS (); 1939 res = mhd_TLS_CRED_CREATE_BAD_CRED_DATA; 1940 } 1941 else 1942 { 1943 do 1944 { 1945 X509 *inter_ca; /* Certifying certificate */ 1946 1947 inter_ca = X509_new_ex (d_tls->libctx, 1948 NULL); 1949 if (NULL == inter_ca) 1950 { 1951 mhd_DBG_PRINT_TLS_ERRS (); 1952 res = mhd_TLS_CRED_CREATE_ALLOC_FAILED; 1953 break; 1954 } 1955 1956 if (NULL != PEM_read_bio_X509 (bio, 1957 &inter_ca, 1958 &null_passwd_cb, 1959 NULL)) 1960 { 1961 mhd_NOWARN_USED_UNUSED 1962 1963 if (0 < sk_X509_push (cred->chain, 1964 inter_ca)) 1965 { 1966 /* The certificate 'inter_ca' is owned by the chain now. 1967 Read the next certificate in the chain. */ 1968 continue; 1969 } 1970 1971 mhd_RESTORE_WARN_USED_UNUSED 1972 1973 /* The cleanup path */ 1974 res = mhd_TLS_CRED_CREATE_ALLOC_FAILED; 1975 } 1976 else 1977 { 1978 unsigned long err; 1979 err = ERR_peek_last_error (); 1980 1981 mhd_NOWARN_USED_UNUSED 1982 1983 if ((ERR_LIB_PEM == ERR_GET_LIB (err)) 1984 && (PEM_R_NO_START_LINE == ERR_GET_REASON (err))) 1985 { 1986 X509_free (inter_ca); /* Allocated but not used, not needed */ 1987 ERR_clear_error (); /* End of data, all certificates are read */ 1988 BIO_free (bio); 1989 return mhd_TLS_CRED_CREATE_OK; /* Success exit point */ 1990 } 1991 1992 /* The cleanup path */ 1993 res = mhd_TLS_CRED_CREATE_BAD_CRED_DATA; 1994 1995 mhd_RESTORE_WARN_USED_UNUSED 1996 } 1997 mhd_DBG_PRINT_TLS_ERRS (); 1998 mhd_assert (mhd_TLS_CRED_CREATE_OK != res); 1999 X509_free (inter_ca); /* Empty or unusable, not needed */ 2000 break; 2001 } while (!0); 2002 mhd_assert (mhd_TLS_CRED_CREATE_OK != res); 2003 } 2004 X509_free (cred->cert); 2005 } 2006 BIO_free (bio); 2007 } 2008 2009 mhd_assert (mhd_TLS_CRED_CREATE_OK != res); 2010 return res; 2011 } 2012 2013 2014 /** 2015 * Provide the application-supplied password for the private key. 2016 * 2017 * Unlike the OpenSSL built-in callback, this one uses the length known by MHD 2018 * instead of deriving it from the zero-termination and refuses to truncate 2019 * the password silently. 2020 * @param[out] buf the buffer to put the password to 2021 * @param size the size of the @a buf 2022 * @param rwflag not used, the password is used for decryption only 2023 * @param cls the pointer to the password string 2024 * @return the number of characters put to the @a buf, 2025 * -1 if the password does not fit the @a buf 2026 */ 2027 static int 2028 mem_passwd_cb (char *buf, 2029 int size, 2030 int rwflag, 2031 void *cls) 2032 { 2033 const struct MHD_String *const pass = (const struct MHD_String *)cls; 2034 2035 (void)rwflag; /* Unused */ 2036 2037 if ((0 > size) || (pass->len > (size_t)size)) 2038 return -1; /* The password does not fit, do not truncate it silently */ 2039 2040 memcpy (buf, 2041 pass->cstr, 2042 pass->len); 2043 return (int)pass->len; 2044 } 2045 2046 2047 /** 2048 * Read the private key from the provided PEM data and check that it matches 2049 * the certificate. 2050 * @param d_tls the pointer to the daemon's TLS settings 2051 * @param[in,out] cred the credentials data with the set @a cert member, 2052 * the @a key member is set on success 2053 * @param key_len the length of the @p key buffer 2054 * @param key the private key data in PEM format 2055 * @param pass_len the length of the @p pass buffer, must be zero if the @p pass 2056 * is NULL 2057 * @param pass the password for the private key, zero-terminated, 2058 * may be NULL 2059 * @return #mhd_TLS_CRED_CREATE_OK on success, 2060 * other enum mhd_TlsCredCreateResult values on failure 2061 */ 2062 static MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) 2063 MHD_FN_PAR_NONNULL_ (4) MHD_FN_MUST_CHECK_RESULT_ 2064 MHD_FN_PAR_IN_SIZE_ (4, 3) MHD_FN_PAR_IN_SIZE_ (6, 5) MHD_FN_PAR_CSTR_ (6) 2065 enum mhd_TlsCredCreateResult 2066 cred_read_key (struct mhd_TlsOpenDaemonData *restrict d_tls, 2067 struct mhd_TlsOpenCredData *restrict cred, 2068 int key_len, 2069 const char *restrict key, 2070 size_t pass_len, 2071 const char *restrict pass) 2072 { 2073 enum mhd_TlsCredCreateResult res; 2074 BIO *bio; 2075 EVP_PKEY *key_obj; 2076 struct MHD_String pass_str; 2077 2078 mhd_assert (NULL != cred->cert); 2079 mhd_assert (NULL == cred->key); 2080 mhd_assert ((NULL != pass) || (0 == pass_len)); 2081 2082 res = mhd_TLS_CRED_CREATE_OK; 2083 pass_str.len = pass_len; 2084 pass_str.cstr = pass; 2085 2086 bio = BIO_new_mem_buf (key, 2087 key_len); 2088 if (NULL == bio) 2089 { 2090 mhd_DBG_PRINT_TLS_ERRS (); 2091 res = mhd_TLS_CRED_CREATE_ALLOC_FAILED; 2092 } 2093 else 2094 { 2095 key_obj = 2096 PEM_read_bio_PrivateKey_ex (bio, 2097 NULL, 2098 (NULL == pass) ? &null_passwd_cb : 2099 &mem_passwd_cb, 2100 (NULL == pass) ? NULL : &pass_str, 2101 d_tls->libctx, 2102 NULL); 2103 BIO_free (bio); 2104 2105 if (NULL == key_obj) 2106 { 2107 mhd_DBG_PRINT_TLS_ERRS (); 2108 res = mhd_TLS_CRED_CREATE_BAD_CRED_DATA; 2109 } 2110 else 2111 { 2112 ERR_clear_error (); 2113 if (1 != X509_check_private_key (cred->cert, 2114 key_obj)) 2115 { 2116 mhd_DBG_PRINT_TLS_ERRS (); 2117 res = mhd_TLS_CRED_CREATE_BAD_CRED_DATA; 2118 } 2119 else 2120 { 2121 ERR_clear_error (); 2122 cred->key = key_obj; 2123 return mhd_TLS_CRED_CREATE_OK; /* Success exit point */ 2124 } 2125 EVP_PKEY_free (key_obj); 2126 } 2127 } 2128 2129 return res; /* Failure exit point */ 2130 } 2131 2132 2133 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ 2134 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (2) 2135 MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_NONNULL_ (6) 2136 MHD_FN_PAR_OUT_ (2) 2137 MHD_FN_PAR_IN_SIZE_ (4, 3) MHD_FN_PAR_IN_SIZE_ (6, 5) 2138 MHD_FN_PAR_IN_SIZE_ (8, 7) 2139 MHD_FN_PAR_CSTR_ (4) MHD_FN_PAR_CSTR_ (6) MHD_FN_PAR_CSTR_ (8) 2140 enum mhd_TlsCredCreateResult 2141 mhd_tls_open_cred_create (struct mhd_TlsOpenDaemonData *restrict d_tls, 2142 union mhd_TlsCredDataPtr *restrict pp_cred, 2143 size_t cert_len, 2144 const char *restrict cert, 2145 size_t key_len, 2146 const char *restrict key, 2147 size_t pass_len, 2148 const char *restrict pass) 2149 { 2150 struct mhd_TlsOpenCredData *cred; 2151 enum mhd_TlsCredCreateResult res; 2152 int cert_len_i; 2153 int key_len_i; 2154 2155 mhd_assert (0 != cert_len); 2156 mhd_assert (0 != key_len); 2157 mhd_assert ((NULL != pass) || (0 == pass_len)); 2158 2159 pp_cred->open = NULL; 2160 2161 cert_len_i = (int)cert_len; 2162 key_len_i = (int)key_len; 2163 if (mhd_COND_HARDLY_EVER (cert_len != (size_t)cert_len_i) 2164 || mhd_COND_HARDLY_EVER (0 > cert_len_i) 2165 || mhd_COND_HARDLY_EVER (key_len != (size_t)key_len_i) 2166 || mhd_COND_HARDLY_EVER (0 > key_len_i)) 2167 return mhd_TLS_CRED_CREATE_BAD_CRED_DATA; /* The data is too large */ 2168 2169 cred = (struct mhd_TlsOpenCredData *) 2170 mhd_calloc (1, 2171 sizeof(struct mhd_TlsOpenCredData)); 2172 if (NULL == cred) 2173 return mhd_TLS_CRED_CREATE_ALLOC_FAILED; 2174 2175 # ifndef NDEBUG 2176 # ifndef HAVE_NULL_PTR_ALL_ZEROS 2177 cred->cert = NULL; 2178 cred->key = NULL; 2179 cred->chain = NULL; 2180 # endif /* HAVE_NULL_PTR_ALL_ZEROS */ 2181 # endif /* NDEBUG */ 2182 2183 ERR_clear_error (); 2184 /* The chain is always allocated (and stays empty if no chain is provided) as 2185 the empty chain must replace the chain inherited from the daemon's context 2186 when the credentials are used for the connection. */ 2187 cred->chain = sk_X509_new_null (); 2188 if (NULL == cred->chain) 2189 { 2190 mhd_DBG_PRINT_TLS_ERRS (); 2191 res = mhd_TLS_CRED_CREATE_ALLOC_FAILED; 2192 } 2193 else 2194 { 2195 ERR_clear_error (); 2196 2197 res = cred_read_certs (d_tls, 2198 cred, 2199 cert_len_i, 2200 cert); 2201 if (mhd_TLS_CRED_CREATE_OK == res) 2202 { 2203 res = cred_read_key (d_tls, 2204 cred, 2205 key_len_i, 2206 key, 2207 pass_len, 2208 pass); 2209 if (mhd_TLS_CRED_CREATE_OK == res) 2210 { 2211 pp_cred->open = cred; 2212 return mhd_TLS_CRED_CREATE_OK; /* Success exit point */ 2213 } 2214 2215 /* Below is a clean-up code path */ 2216 X509_free (cred->cert); 2217 } 2218 mhd_NOWARN_USED_UNUSED 2219 sk_X509_pop_free (cred->chain, 2220 X509_free); 2221 2222 mhd_RESTORE_WARN_USED_UNUSED 2223 } 2224 2225 free (cred); 2226 mhd_assert (mhd_TLS_CRED_CREATE_OK != res); 2227 return res; /* Failure exit point */ 2228 } 2229 2230 2231 MHD_INTERNAL void 2232 mhd_tls_open_cred_destroy_nodmn (union mhd_TlsCredDataPtr cred) 2233 { 2234 mhd_ASSUME (NULL != cred.open); 2235 mhd_assert (NULL != cred.open->key); 2236 mhd_assert (NULL != cred.open->cert); 2237 mhd_assert (NULL != cred.open->chain); 2238 2239 /* Release in the reverse order of the creation. 2240 The objects still used by any TLS session or context are not destroyed 2241 here as OpenSSL holds its own references for them. */ 2242 EVP_PKEY_free (cred.open->key); 2243 X509_free (cred.open->cert); 2244 mhd_NOWARN_USED_UNUSED 2245 sk_X509_pop_free (cred.open->chain, 2246 &X509_free); 2247 2248 mhd_RESTORE_WARN_USED_UNUSED 2249 free (cred.open); 2250 2251 } 2252 2253 2254 #endif /* mhd_HAVE_OPENSSL_ACME */ 2255 2256 2257 /* ** Connection initialisation / de-initialisation ** */ 2258 2259 MHD_INTERNAL size_t 2260 mhd_tls_open_conn_get_tls_size_v (void) 2261 { 2262 return sizeof (struct mhd_TlsOpenConnData); 2263 } 2264 2265 2266 #ifdef mhd_HAVE_OPENSSL_ACME 2267 /** 2268 * Prepare the connection data for the detection of the ACME ALPN challenge 2269 * @param d_tls the daemon TLS settings 2270 * @param[in,out] c_tls the connection TLS handle with the initialised session 2271 * @return 'true' on success, 2272 * 'false' otherwise 2273 */ 2274 static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_MUST_CHECK_RESULT_ bool 2275 conn_init_acme_data (const struct mhd_TlsOpenDaemonData *restrict d_tls, 2276 struct mhd_TlsOpenConnData *restrict c_tls) 2277 { 2278 bool res; 2279 2280 /* c_tls is created by calloc(), all bool member must be 'false' */ 2281 mhd_assert (!c_tls->clienthello_processed); 2282 mhd_assert (!c_tls->is_acme); 2283 2284 /* The additional context for ClientHello and ALPN callbacks */ 2285 res = (0 != SSL_set_ex_data (c_tls->sess, 2286 conn_mhd_ctls_idx, 2287 c_tls)); 2288 2289 # ifdef mhd_USE_OPENSSL_CLIENT_HELLO_GET0_EXT 2290 (void)d_tls; /* Unused, the ClientHello callback is set for the context */ 2291 # else /* ! mhd_USE_OPENSSL_CLIENT_HELLO_GET0_EXT */ 2292 /* Conditionally process ClientHello message - only if any ACME certificates 2293 are present */ 2294 if (res 2295 && (mhd_daemon_has_acme_certs (d_tls->acme_certs))) 2296 { 2297 /* The unparsed ClientHello message is provided only by the messages 2298 callback */ 2299 (void)SSL_set_msg_callback_arg (c_tls->sess, /* does not actually return a value */ 2300 d_tls->acme_certs); 2301 SSL_set_msg_callback (c_tls->sess, 2302 &check_hello_msg_acme); 2303 } 2304 # endif /* ! mhd_USE_OPENSSL_CLIENT_HELLO_GET0_EXT */ 2305 return res; 2306 } 2307 2308 2309 #else /* ! mhd_HAVE_OPENSSL_ACME */ 2310 # define conn_init_acme_data(d_tls, c_tls) \ 2311 (((void) (d_tls)), ((void) (c_tls)), (! 0)) 2312 #endif /* ! mhd_HAVE_OPENSSL_ACME */ 2313 2314 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ 2315 MHD_FN_PAR_OUT_ (3) bool 2316 mhd_tls_open_conn_init (const struct mhd_TlsOpenDaemonData *restrict d_tls, 2317 const struct mhd_ConnSocket *sk, 2318 struct mhd_TlsOpenConnData *restrict c_tls) 2319 { 2320 int fd; 2321 2322 ERR_clear_error (); 2323 2324 fd = (int)sk->fd; 2325 if (sk->fd != (MHD_Socket)fd) 2326 return false; /* OpenSSL docs clam that it should not be possible */ 2327 2328 c_tls->sess = SSL_new (d_tls->ctx); 2329 2330 if (NULL == c_tls->sess) 2331 { 2332 mhd_DBG_PRINT_TLS_ERRS (); 2333 return false; 2334 } 2335 2336 if ((0 < SSL_set_fd (c_tls->sess, fd)) 2337 && conn_init_acme_data (d_tls, 2338 c_tls)) 2339 { 2340 SSL_set_accept_state (c_tls->sess); /* Force server mode */ 2341 2342 #ifndef NDEBUG 2343 c_tls->dbg.is_inited = true; 2344 #endif 2345 return true; /* Success exit point */ 2346 } 2347 2348 SSL_free (c_tls->sess); 2349 c_tls->sess = NULL; 2350 return false; 2351 } 2352 2353 2354 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 2355 mhd_tls_open_conn_deinit (struct mhd_TlsOpenConnData *restrict c_tls) 2356 { 2357 mhd_assert (NULL != c_tls->sess); 2358 mhd_assert (c_tls->dbg.is_inited); 2359 SSL_free (c_tls->sess); 2360 } 2361 2362 2363 /* ** TLS connection establishing ** */ 2364 2365 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ 2366 enum mhd_TlsProcedureResult 2367 mhd_tls_open_conn_handshake (struct mhd_TlsOpenConnData *restrict c_tls) 2368 { 2369 int res; 2370 2371 mhd_assert (c_tls->dbg.is_inited); 2372 mhd_assert (!c_tls->dbg.is_tls_handshake_completed); 2373 mhd_assert (!c_tls->shut_tls_wr_sent); 2374 mhd_assert (!c_tls->shut_tls_wr_received); 2375 mhd_assert (!c_tls->dbg.is_failed); 2376 2377 ERR_clear_error (); 2378 2379 res = SSL_do_handshake (c_tls->sess); 2380 2381 if (1 == res) 2382 { 2383 #ifndef NDEBUG 2384 c_tls->dbg.is_tls_handshake_completed = true; 2385 #endif /* ! NDEBUG */ 2386 return mhd_TLS_PROCED_SUCCESS; /* Success exit point */ 2387 } 2388 2389 switch (SSL_get_error (c_tls->sess, res)) 2390 { 2391 case SSL_ERROR_WANT_READ: 2392 /* OpenSSL does not distinguish between "interrupted" and "try again" codes. 2393 Based on OpenSSL result it is unclear whether the "recv-ready" flag 2394 should be reset or not. 2395 If edge-triggered sockets polling is used and the flag is cleared, but 2396 it should not (because the process has been "interrupted") then already 2397 pending data could be never processed. 2398 If the flag is not cleared, but it should be cleared (because all 2399 received data has been processed) then it would create busy-waiting loop 2400 with edge-triggered sockets polling. 2401 Temporal solution: disallow edge-triggered sockets polling with OpenSSL 2402 backend and use clear of "ready" flag. */ 2403 // TODO: replace "BIO" with custom version and track returned errors. 2404 return mhd_TLS_PROCED_SEND_MORE_NEEDED; 2405 case SSL_ERROR_WANT_WRITE: 2406 /* OpenSSL does not distinguish between "interrupted" and "try again" codes. 2407 Based on OpenSSL result it is unclear whether the "send-ready" flag 2408 should be reset or not. 2409 If edge-triggered sockets polling is used and the flag is cleared, but 2410 it should not (because the process has been "interrupted") then already 2411 pending data could be never sent. 2412 If the flag is not cleared, but it should be cleared (because all 2413 received data has been processed) then it would create busy-waiting loop 2414 with edge-triggered sockets polling. 2415 Temporal solution: disallow edge-triggered sockets polling with OpenSSL 2416 backend and use clear of "ready" flag. */ 2417 // TODO: replace "BIO" with custom version and track returned errors. 2418 return mhd_TLS_PROCED_RECV_MORE_NEEDED; 2419 case SSL_ERROR_NONE: 2420 mhd_assert (0 && "This should not be possible"); 2421 mhd_UNREACHABLE (); 2422 break; 2423 default: /* Handled with all other errors below */ 2424 break; 2425 } 2426 mhd_DBG_PRINT_TLS_ERRS (); 2427 #ifndef NDEBUG 2428 c_tls->dbg.is_failed = true; 2429 #endif /* ! NDEBUG */ 2430 return mhd_TLS_PROCED_FAILED; 2431 } 2432 2433 2434 MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ 2435 enum mhd_TlsProcedureResult 2436 mhd_tls_open_conn_shutdown (struct mhd_TlsOpenConnData *restrict c_tls) 2437 { 2438 int res; 2439 2440 mhd_assert (c_tls->dbg.is_inited); 2441 mhd_assert (c_tls->dbg.is_tls_handshake_completed); 2442 mhd_assert (!c_tls->dbg.is_failed); 2443 2444 ERR_clear_error (); 2445 2446 res = SSL_shutdown (c_tls->sess); 2447 2448 if (1 == res) 2449 { 2450 c_tls->shut_tls_wr_sent = true; 2451 c_tls->shut_tls_wr_received = true; 2452 return mhd_TLS_PROCED_SUCCESS; /* Success exit point */ 2453 } 2454 2455 /* The OpenSSL documentation contradicts itself: there are two mutually 2456 exclusive statements on a single page. 2457 * https://docs.openssl.org/master/man3/SSL_shutdown/#shutdown-lifecycle 2458 indicates that for nonblocking socket ZERO could be returned when 2459 "close_notify" is GOING to be sent, but NOT sent yet. 2460 It also suggests to CALL SSL_get_error(3) when ZERO is returned. 2461 * https://docs.openssl.org/master/man3/SSL_shutdown/#return-values 2462 indicates ZERO is returned ONLY when "close_notify" HAS BEEN sent. 2463 It also suggests to NOT CALL SSL_get_error(3) when ZERO is returned. 2464 */ 2465 switch (SSL_get_error (c_tls->sess, res)) 2466 { 2467 case SSL_ERROR_WANT_READ: 2468 /* OpenSSL does not distinguish between "interrupted" and "try again" codes. 2469 Based on OpenSSL result it is unclear whether the "recv-ready" flag 2470 should be reset or not. 2471 If edge-triggered sockets polling is used and the flag is cleared, but 2472 it should not (because the process has been "interrupted") then already 2473 pending data could be never processed. 2474 If the flag is not cleared, but it should be cleared (because all 2475 received data has been processed) then it would create busy-waiting loop 2476 with edge-triggered sockets polling. 2477 Temporal solution: disallow edge-triggered sockets polling with OpenSSL 2478 backend and use clear of "ready" flag. */ 2479 // TODO: replace "BIO" with custom version and track returned errors. 2480 return mhd_TLS_PROCED_SEND_MORE_NEEDED; 2481 case SSL_ERROR_WANT_WRITE: 2482 c_tls->shut_tls_wr_sent = true; 2483 /* OpenSSL does not distinguish between "interrupted" and "try again" codes. 2484 Based on OpenSSL result it is unclear whether the "send-ready" flag 2485 should be reset or not. 2486 If edge-triggered sockets polling is used and the flag is cleared, but 2487 it should not (because the process has been "interrupted") then already 2488 pending data could be never sent. 2489 If the flag is not cleared, but it should be cleared (because all 2490 received data has been processed) then it would create busy-waiting loop 2491 with edge-triggered sockets polling. 2492 Temporal solution: disallow edge-triggered sockets polling with OpenSSL 2493 backend and use clear of "ready" flag. */ 2494 // TODO: replace "BIO" with custom version and track returned errors. 2495 return mhd_TLS_PROCED_RECV_MORE_NEEDED; 2496 case SSL_ERROR_NONE: 2497 mhd_assert (res != 0 && "Should not be possible"); 2498 c_tls->shut_tls_wr_sent = true; 2499 return mhd_TLS_PROCED_RECV_INTERRUPTED; 2500 default: /* Handled with all other errors below */ 2501 break; 2502 } 2503 mhd_DBG_PRINT_TLS_ERRS (); 2504 #ifndef NDEBUG 2505 c_tls->dbg.is_failed = true; 2506 #endif /* ! NDEBUG */ 2507 return mhd_TLS_PROCED_FAILED; 2508 } 2509 2510 2511 /* ** Data receiving and sending ** */ 2512 2513 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 2514 MHD_FN_PAR_OUT_SIZE_ (3, 2) 2515 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError 2516 mhd_tls_open_conn_recv (struct mhd_TlsOpenConnData *restrict c_tls, 2517 size_t buf_size, 2518 char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)], 2519 size_t *restrict received) 2520 { 2521 int res; 2522 2523 mhd_assert (c_tls->dbg.is_inited); 2524 mhd_assert (c_tls->dbg.is_tls_handshake_completed); 2525 mhd_assert (!c_tls->shut_tls_wr_sent); 2526 mhd_assert (!c_tls->dbg.is_failed); 2527 #ifdef mhd_HAVE_OPENSSL_ACME 2528 mhd_assert (!c_tls->is_acme); /* ACME ALPN challenge connection is not used 2529 for the data exchange */ 2530 #endif /* mhd_HAVE_OPENSSL_ACME */ 2531 2532 ERR_clear_error (); 2533 2534 res = SSL_read_ex (c_tls->sess, 2535 buf, 2536 buf_size, 2537 received); 2538 if (1 == res) 2539 { 2540 mhd_assert (0 != *received); 2541 return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */ 2542 } 2543 2544 mhd_assert (0 == res); 2545 *received = 0; 2546 switch (SSL_get_error (c_tls->sess, res)) 2547 { 2548 case SSL_ERROR_ZERO_RETURN: /* Not an error */ 2549 c_tls->shut_tls_wr_received = true; 2550 return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */ 2551 case SSL_ERROR_WANT_READ: 2552 /* OpenSSL does not distinguish between "interrupted" and "try again" codes. 2553 Based on OpenSSL result it is unclear whether the "recv-ready" flag 2554 should be reset or not. 2555 If edge-triggered sockets polling is used and the flag is cleared, but 2556 it should not (because the process has been "interrupted") then already 2557 pending data could be never processed. 2558 If the flag is not cleared, but it should be cleared (because all 2559 received data has been processed) then it would create busy-waiting loop 2560 with edge-triggered sockets polling. 2561 Temporal solution: disallow edge-triggered sockets polling with OpenSSL 2562 backend and use clear of "ready" flag. */ 2563 // TODO: replace "BIO" with custom version and track returned errors. 2564 return mhd_SOCKET_ERR_AGAIN; 2565 case SSL_ERROR_NONE: 2566 mhd_assert (0 && "Should not be possible"); 2567 break; 2568 case SSL_ERROR_WANT_WRITE: 2569 mhd_assert (0 && "Should not be possible as re-handshakes are disallowed"); 2570 break; 2571 case SSL_ERROR_SYSCALL: 2572 mhd_DBG_PRINT_TLS_ERRS (); 2573 #ifndef NDEBUG 2574 c_tls->dbg.is_failed = true; 2575 #endif /* ! NDEBUG */ 2576 return mhd_SOCKET_ERR_CONN_BROKEN; 2577 case SSL_ERROR_SSL: 2578 default: 2579 break; 2580 } 2581 /* Treat all other kinds of errors as hard errors */ 2582 mhd_DBG_PRINT_TLS_ERRS (); 2583 #ifndef NDEBUG 2584 c_tls->dbg.is_failed = true; 2585 #endif /* ! NDEBUG */ 2586 return mhd_SOCKET_ERR_TLS; 2587 } 2588 2589 2590 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 2591 mhd_tls_open_conn_has_data_in (struct mhd_TlsOpenConnData *restrict c_tls) 2592 { 2593 return 0 != SSL_pending (c_tls->sess); 2594 } 2595 2596 2597 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 2598 MHD_FN_PAR_IN_SIZE_ (3, 2) 2599 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError 2600 mhd_tls_open_conn_send4 (struct mhd_TlsOpenConnData *restrict c_tls, 2601 size_t buf_size, 2602 const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)], 2603 size_t *restrict sent) 2604 { 2605 int res; 2606 2607 mhd_assert (c_tls->dbg.is_inited); 2608 mhd_assert (c_tls->dbg.is_tls_handshake_completed); 2609 mhd_assert (!c_tls->shut_tls_wr_sent); 2610 mhd_assert (!c_tls->dbg.is_failed); 2611 #ifdef mhd_HAVE_OPENSSL_ACME 2612 mhd_assert (!c_tls->is_acme); /* ACME ALPN challenge connection is not used 2613 for the data exchange */ 2614 #endif /* mhd_HAVE_OPENSSL_ACME */ 2615 2616 ERR_clear_error (); 2617 2618 res = SSL_write_ex (c_tls->sess, 2619 buf, 2620 buf_size, 2621 sent); 2622 if (1 == res) 2623 { 2624 mhd_assert (0 != *sent); 2625 return mhd_SOCKET_ERR_NO_ERROR; /* Success exit point */ 2626 } 2627 2628 mhd_assert (0 == res); 2629 *sent = 0; 2630 switch (SSL_get_error (c_tls->sess, res)) 2631 { 2632 case SSL_ERROR_WANT_WRITE: 2633 /* OpenSSL does not distinguish between "interrupted" and "try again" codes. 2634 Based on OpenSSL result it is unclear whether the "send-ready" flag 2635 should be reset or not. 2636 If edge-triggered sockets polling is used and the flag is cleared, but 2637 it should not (because the process has been "interrupted") then already 2638 pending data could be never sent. 2639 If the flag is not cleared, but it should be cleared (because all 2640 received data has been processed) then it would create busy-waiting loop 2641 with edge-triggered sockets polling. 2642 Temporal solution: disallow edge-triggered sockets polling with OpenSSL 2643 backend and use clear of "ready" flag. */ 2644 // TODO: replace "BIO" with custom version and track returned errors. 2645 return mhd_SOCKET_ERR_AGAIN; 2646 case SSL_ERROR_NONE: 2647 mhd_assert (0 && "Should not be possible"); 2648 break; 2649 case SSL_ERROR_WANT_READ: 2650 mhd_assert (0 && "Should not be possible as re-handshakes are disallowed"); 2651 break; 2652 case SSL_ERROR_ZERO_RETURN: 2653 c_tls->shut_tls_wr_received = true; 2654 return mhd_SOCKET_ERR_AGAIN; 2655 case SSL_ERROR_SYSCALL: 2656 mhd_DBG_PRINT_TLS_ERRS (); 2657 #ifndef NDEBUG 2658 c_tls->dbg.is_failed = true; 2659 #endif /* ! NDEBUG */ 2660 return mhd_SOCKET_ERR_CONN_BROKEN; 2661 case SSL_ERROR_SSL: 2662 default: 2663 break; 2664 } 2665 /* Treat all other kinds of errors as hard errors */ 2666 mhd_DBG_PRINT_TLS_ERRS (); 2667 #ifndef NDEBUG 2668 c_tls->dbg.is_failed = true; 2669 #endif /* ! NDEBUG */ 2670 return mhd_SOCKET_ERR_TLS; 2671 } 2672 2673 2674 /* ** TLS connection information ** */ 2675 2676 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 2677 MHD_FN_PAR_OUT_ (2) void 2678 mhd_tls_open_conn_get_tls_sess ( 2679 struct mhd_TlsOpenConnData *restrict c_tls, 2680 union MHD_ConnInfoDynamicTlsSess *restrict tls_sess_out) 2681 { 2682 tls_sess_out->v_openssl_session = c_tls->sess; 2683 } 2684 2685 2686 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 2687 MHD_FN_PAR_OUT_ (2) bool 2688 mhd_tls_open_conn_get_tls_ver (struct mhd_TlsOpenConnData *restrict c_tls, 2689 struct mhd_StctTlsVersion *restrict tls_ver_out) 2690 { 2691 int openssl_tls_ver; 2692 2693 mhd_assert (c_tls->dbg.is_tls_handshake_completed); 2694 2695 openssl_tls_ver = SSL_version (c_tls->sess); 2696 switch (openssl_tls_ver) 2697 { 2698 case TLS1_VERSION: 2699 tls_ver_out->tls_ver = MHD_TLS_VERSION_1_0; 2700 break; 2701 case TLS1_1_VERSION: 2702 tls_ver_out->tls_ver = MHD_TLS_VERSION_1_1; 2703 break; 2704 case TLS1_2_VERSION: 2705 tls_ver_out->tls_ver = MHD_TLS_VERSION_1_2; 2706 break; 2707 case TLS1_3_VERSION: 2708 tls_ver_out->tls_ver = MHD_TLS_VERSION_1_3; 2709 break; 2710 case SSL3_VERSION: 2711 default: 2712 tls_ver_out->tls_ver = MHD_TLS_VERSION_UNKNOWN; 2713 break; 2714 } 2715 2716 return true; 2717 } 2718 2719 2720 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ enum mhd_TlsAlpnProt 2721 mhd_tls_open_conn_get_alpn_prot (struct mhd_TlsOpenConnData *restrict c_tls) 2722 { 2723 const unsigned char *sel_prot; 2724 unsigned int sel_prot_len; 2725 #ifdef mhd_HAVE_OPENSSL_ACME 2726 mhd_assert (!c_tls->is_acme); 2727 #endif /* mhd_HAVE_OPENSSL_ACME */ 2728 2729 SSL_get0_alpn_selected (c_tls->sess, 2730 &sel_prot, 2731 &sel_prot_len); 2732 2733 #ifndef OPENSSL_NO_NEXTPROTONEG 2734 if ((NULL == sel_prot) 2735 || (0 == sel_prot_len)) 2736 { 2737 SSL_get0_next_proto_negotiated (c_tls->sess, 2738 &sel_prot, 2739 &sel_prot_len); 2740 } 2741 #endif /* ! OPENSSL_NO_NEXTPROTONEG */ 2742 2743 mhd_assert (sel_prot_len == (size_t)sel_prot_len); 2744 2745 return mhd_tls_alpn_decode_n ((size_t)sel_prot_len, 2746 sel_prot); 2747 } 2748 2749 2750 #ifdef mhd_HAVE_TLS_ACME 2751 # ifdef mhd_HAVE_OPENSSL_ACME 2752 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 2753 mhd_tls_open_conn_is_acme (struct mhd_TlsOpenConnData *restrict c_tls) 2754 { 2755 return c_tls->is_acme; 2756 } 2757 2758 2759 # endif /* mhd_HAVE_OPENSSL_ACME */ 2760 #endif /* mhd_HAVE_TLS_ACME */