test_acme_alpn.c (45521B)
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) 2026 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/tests/acme/test_acme_alpn.c 41 * @brief Test for the ACME TLS-ALPN-01 challenge support 42 * @author Karlson2k (Evgeny Grin) 43 * 44 * The test starts the daemon with two ACME challenge certificates and 45 * connects to it with a simple GnuTLS client. For each tested combination of 46 * the SNI and the offered ALPN protocols the test checks which certificate has 47 * been served and which application protocol has been negotiated. 48 */ 49 50 #include "mhd_sys_options.h" 51 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <errno.h> 56 57 #include "sys_bool_type.h" 58 59 #include "sys_sockets_headers.h" 60 #include "sys_sockets_types.h" 61 #include "sys_ip_headers.h" 62 #include "mhd_sockets_macros.h" 63 #include <fcntl.h> 64 65 #include <gnutls/gnutls.h> 66 #include <gnutls/x509.h> 67 68 #include "microhttpd2.h" 69 70 #include "acme_test_certs.h" 71 72 73 /* The ACME TLS-ALPN-01 challenge requires ALPN, which is supported by 74 GnuTLS 3.2.0 and later. The test client uses the same library. */ 75 #if GNUTLS_VERSION_NUMBER >= 0x030200 76 77 # ifndef mhd_SSTR_LEN 78 /** 79 * Determine the length of the static string at compile time 80 */ 81 # define mhd_SSTR_LEN(sstr) (sizeof(sstr) / sizeof(char) - 1) 82 # endif /* ! mhd_SSTR_LEN */ 83 84 85 # if defined(MHD_SOCKETS_KIND_POSIX) 86 # if defined(ENETUNREACH) 87 # define mhdt_SCKT_HARD_ERR ENETUNREACH 88 # elif defined(ENOTCONN) 89 # define mhdt_SCKT_HARD_ERR ENOTCONN 90 # elif defined(ECONNRESET) 91 # define mhdt_SCKT_HARD_ERR ECONNRESET 92 # elif defined(EPIPE) 93 # define mhdt_SCKT_HARD_ERR EPIPE 94 # elif defined(EBADF) 95 # define mhdt_SCKT_HARD_ERR EBADF 96 # else 97 # define mhdt_SCKT_HARD_ERR 99 /* Fallback, never used in practice */ 98 # endif 99 # else /* MHD_SOCKETS_KIND_WINSOCK */ 100 # define mhdt_SCKT_HARD_ERR WSAENETRESET 101 # endif 102 103 104 MHD_NORETURN_ static void 105 _externalErrorExit_func (const char *errDesc, 106 const char *funcName, 107 int lineNum) 108 { 109 int last_errno = errno; 110 111 fflush (stdout); 112 if ((NULL != errDesc) && (0 != errDesc[0])) 113 fprintf (stderr, "!!! %s", errDesc); 114 else 115 fprintf (stderr, "!!! System or external library call failed"); 116 if ((NULL != funcName) && (0 != funcName[0])) 117 fprintf (stderr, " in %s", funcName); 118 if (0 < lineNum) 119 fprintf (stderr, " at line %d", lineNum); 120 121 fprintf (stderr, ".\nLast errno value: %d (%s)\n", last_errno, 122 strerror (last_errno)); 123 # ifdef MHD_SOCKETS_KIND_WINSOCK 124 fprintf (stderr, "WSAGetLastError() value: %d\n", (int)WSAGetLastError ()); 125 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 126 fflush (stderr); 127 exit (99); 128 } 129 130 131 MHD_NORETURN_ static void 132 _mhdErrorExit_func (const char *errDesc, 133 const char *funcName, 134 int lineNum) 135 { 136 int last_errno = errno; 137 138 fflush (stdout); 139 if ((NULL != errDesc) && (0 != errDesc[0])) 140 fprintf (stderr, "!!! %s", errDesc); 141 else 142 fprintf (stderr, "!!! MHD unexpected error"); 143 if ((NULL != funcName) && (0 != funcName[0])) 144 fprintf (stderr, " in %s", funcName); 145 if (0 < lineNum) 146 fprintf (stderr, " at line %d", lineNum); 147 148 fprintf (stderr, ".\nLast errno value: %d (%s)\n", last_errno, 149 strerror (last_errno)); 150 fflush (stderr); 151 exit (8); 152 } 153 154 155 static void 156 _testErrorLog_func (const char *errDesc, 157 const char *funcName, 158 int lineNum) 159 { 160 int last_errno = errno; 161 162 fflush (stdout); 163 if ((NULL != errDesc) && (0 != errDesc[0])) 164 fprintf (stderr, "!!! %s", errDesc); 165 else 166 fprintf (stderr, "!!! System or external library call resulted in error"); 167 if ((NULL != funcName) && (0 != funcName[0])) 168 fprintf (stderr, " in %s", funcName); 169 if (0 < lineNum) 170 fprintf (stderr, " at line %d", lineNum); 171 172 fprintf (stderr, ".\nLast errno value: %d (%s)\n", last_errno, 173 strerror (last_errno)); 174 # ifdef MHD_SOCKETS_KIND_WINSOCK 175 fprintf (stderr, "WSAGetLastError() value: %d\n", (int)WSAGetLastError ()); 176 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 177 fflush (stderr); 178 } 179 180 181 # ifdef MHD_HAVE_MHD_FUNC_ 182 # define externalErrorExitDesc(errDesc) \ 183 _externalErrorExit_func (errDesc, MHD_FUNC_, __LINE__) 184 # define mhdErrorExitDesc(errDesc) \ 185 _mhdErrorExit_func (errDesc, MHD_FUNC_, __LINE__) 186 # define testErrorLogDesc(errDesc) \ 187 _testErrorLog_func (errDesc, MHD_FUNC_, __LINE__) 188 # else /* ! MHD_HAVE_MHD_FUNC_ */ 189 # define externalErrorExitDesc(errDesc) \ 190 _externalErrorExit_func (errDesc, NULL, __LINE__) 191 # define mhdErrorExitDesc(errDesc) \ 192 _mhdErrorExit_func (errDesc, NULL, __LINE__) 193 # define testErrorLogDesc(errDesc) \ 194 _testErrorLog_func (errDesc, NULL, __LINE__) 195 # endif /* ! MHD_HAVE_MHD_FUNC_ */ 196 197 198 /* Could be increased to facilitate debugging */ 199 static int test_timeout = 5; 200 201 202 /** 203 * The string with the length known at compile time 204 */ 205 struct TestStr 206 { 207 /** 208 * The pointer to the string, NULL if the string is not used 209 */ 210 const char *str; 211 /** 212 * The length of the @a str, not including the terminating null character 213 */ 214 size_t len; 215 }; 216 217 /** 218 * Static initialiser for #TestStr from the static string 219 */ 220 # define TSTR(s) { (s), mhd_SSTR_LEN (s) } 221 222 /** 223 * Static initialiser for the unused #TestStr 224 */ 225 # define TSTR_NONE { NULL, 0 } 226 227 228 /** 229 * The ALPN protocol name for the ACME TLS-ALPN-01 challenge 230 */ 231 # define ALPN_ACME "acme-tls/1" 232 233 /** 234 * The ALPN protocol name for HTTP/1.1 235 */ 236 # define ALPN_HTTP_1_1 "http/1.1" 237 238 /** 239 * The domain without any ACME challenge certificate 240 */ 241 # define DOMAIN_NO_ACME "acme-test3.example" 242 243 /** 244 * The first ACME domain spelled in the different letters case 245 */ 246 # define DOMAIN_A_MIXED_CASE "ACME-Test1.Example" 247 248 /** 249 * The domain used only for the calls that must be rejected 250 */ 251 # define DOMAIN_BAD_CERT "bad-cert.example" 252 253 /** 254 * The data that looks like a certificate, but is not one 255 */ 256 # define BAD_CERT_PEM \ 257 "-----BEGIN CERTIFICATE-----\n" \ 258 "this is not a certificate\n" \ 259 "-----END CERTIFICATE-----\n" 260 261 /** 262 * The maximum number of the ALPN protocols offered by the test client 263 */ 264 # define MAX_ALPN_PROTS 2 265 266 267 /** 268 * The certificate expected from the daemon 269 */ 270 enum ExpectedCert 271 { 272 /** 273 * The certificate served for all non-ACME connections 274 */ 275 CERT_SERVER = 0 276 , 277 /** 278 * The ACME challenge certificate for #mhdt_ACME_CHLNG_A_DOMAIN 279 */ 280 CERT_CHLNG_A 281 , 282 /** 283 * The ACME challenge certificate for #mhdt_ACME_CHLNG_B_DOMAIN 284 */ 285 CERT_CHLNG_B 286 }; 287 288 /** 289 * Set to 'true' if the daemon has received any request. 290 * 291 * The test client never sends a request, so this must not happen. 292 */ 293 static volatile bool unexpected_request; 294 295 296 /** 297 * The certificates in PEM format, indexed by #ExpectedCert 298 */ 299 static const struct TestStr certs_pem[] = { 300 TSTR (mhdt_ACME_SRV_CERT_PEM), 301 TSTR (mhdt_ACME_CHLNG_A_CERT_PEM), 302 TSTR (mhdt_ACME_CHLNG_B_CERT_PEM) 303 }; 304 305 /** 306 * The names of the certificates for the log, indexed by #ExpectedCert 307 */ 308 static const char *const certs_name[] = { 309 "the server certificate", 310 "the challenge certificate \"A\"", 311 "the challenge certificate \"B\"" 312 }; 313 314 315 /** 316 * The parameters and the expected results for a single connection 317 */ 318 struct TestCase 319 { 320 /** 321 * The name of the test case 322 */ 323 const char *label; 324 /** 325 * The domain name sent as SNI, unused string to send no SNI 326 */ 327 struct TestStr sni; 328 /** 329 * The ALPN protocols offered by the client, terminated by the unused string 330 */ 331 struct TestStr alpn[MAX_ALPN_PROTS + 1]; 332 /** 333 * The protocol expected to be negotiated, unused string if none must be 334 * selected 335 */ 336 struct TestStr expect_alpn; 337 /** 338 * The certificate expected to be served 339 */ 340 enum ExpectedCert expect_cert; 341 }; 342 343 344 /** 345 * The test cases performed for every TLS backend 346 */ 347 static const struct TestCase test_cases[] = { 348 { 349 "the ACME challenge for the first domain", 350 TSTR (mhdt_ACME_CHLNG_A_DOMAIN), 351 { TSTR (ALPN_ACME), TSTR_NONE, TSTR_NONE }, 352 TSTR (ALPN_ACME), 353 CERT_CHLNG_A 354 }, 355 { 356 "the ACME challenge for the second domain", 357 TSTR (mhdt_ACME_CHLNG_B_DOMAIN), 358 { TSTR (ALPN_ACME), TSTR_NONE, TSTR_NONE }, 359 TSTR (ALPN_ACME), 360 CERT_CHLNG_B 361 }, 362 { 363 "the ACME domain in the different letters case", 364 TSTR (DOMAIN_A_MIXED_CASE), 365 { TSTR (ALPN_ACME), TSTR_NONE, TSTR_NONE }, 366 TSTR (ALPN_ACME), 367 CERT_CHLNG_A 368 }, 369 { 370 "the ACME protocol together with the HTTP protocol", 371 TSTR (mhdt_ACME_CHLNG_A_DOMAIN), 372 { TSTR (ALPN_ACME), TSTR (ALPN_HTTP_1_1), TSTR_NONE }, 373 TSTR (ALPN_HTTP_1_1), 374 CERT_SERVER 375 }, 376 { 377 "the ACME protocol for the domain without the challenge", 378 TSTR (DOMAIN_NO_ACME), 379 { TSTR (ALPN_ACME), TSTR_NONE, TSTR_NONE }, 380 TSTR_NONE, 381 CERT_SERVER 382 }, 383 { 384 "the ACME protocol without the domain name", 385 TSTR_NONE, 386 { TSTR (ALPN_ACME), TSTR_NONE, TSTR_NONE }, 387 TSTR_NONE, 388 CERT_SERVER 389 }, 390 { 391 "the HTTP protocol for the ACME domain", 392 TSTR (mhdt_ACME_CHLNG_A_DOMAIN), 393 { TSTR (ALPN_HTTP_1_1), TSTR_NONE, TSTR_NONE }, 394 TSTR (ALPN_HTTP_1_1), 395 CERT_SERVER 396 }, 397 { 398 "the ACME domain without the ALPN extension", 399 TSTR (mhdt_ACME_CHLNG_A_DOMAIN), 400 { TSTR_NONE, TSTR_NONE, TSTR_NONE }, 401 TSTR_NONE, 402 CERT_SERVER 403 }, 404 { 405 "the HTTP protocol offered before the ACME protocol", 406 TSTR (mhdt_ACME_CHLNG_A_DOMAIN), 407 { TSTR (ALPN_HTTP_1_1), TSTR (ALPN_ACME), TSTR_NONE }, 408 TSTR (ALPN_HTTP_1_1), 409 CERT_SERVER 410 }, 411 { 412 "the ACME protocol offered twice", 413 TSTR (mhdt_ACME_CHLNG_A_DOMAIN), 414 { TSTR (ALPN_ACME), TSTR (ALPN_ACME), TSTR_NONE }, 415 TSTR_NONE, 416 CERT_SERVER 417 } 418 }; 419 420 /** 421 * The test case performed after the removal of the challenge certificate 422 * for the first domain 423 */ 424 static const struct TestCase removed_case = { 425 "the certificate removed by the differently spelled domain is not served", 426 TSTR (mhdt_ACME_CHLNG_A_DOMAIN), 427 { TSTR (ALPN_ACME), TSTR_NONE, TSTR_NONE }, 428 TSTR_NONE, 429 CERT_SERVER 430 }; 431 432 /** 433 * The check for the fallback certificate: the domain without a certificate 434 * of its own is served with the certificate registered for any domain 435 */ 436 static const struct TestCase fallback_case = { 437 "the fallback certificate is served for the unknown domain", 438 TSTR (DOMAIN_NO_ACME), 439 { TSTR (ALPN_ACME), TSTR_NONE, TSTR_NONE }, 440 TSTR (ALPN_ACME), 441 CERT_CHLNG_A 442 }; 443 444 /** 445 * The check that the fallback certificate is not used without the SNI 446 */ 447 static const struct TestCase fallback_no_sni_case = { 448 "the fallback certificate is not served without the domain name", 449 TSTR_NONE, 450 { TSTR (ALPN_ACME), TSTR_NONE, TSTR_NONE }, 451 TSTR_NONE, 452 CERT_SERVER 453 }; 454 455 /** 456 * The check that the certificate of the domain takes precedence over 457 * the fallback certificate 458 */ 459 static const struct TestCase fallback_specific_case = { 460 "the domain certificate takes precedence over the fallback certificate", 461 TSTR (mhdt_ACME_CHLNG_B_DOMAIN), 462 { TSTR (ALPN_ACME), TSTR_NONE, TSTR_NONE }, 463 TSTR (ALPN_ACME), 464 CERT_CHLNG_B 465 }; 466 467 /** 468 * The check performed after the challenge certificate for the first domain 469 * has been replaced by another certificate 470 */ 471 static const struct TestCase replaced_case = { 472 "the replaced challenge certificate is served", 473 TSTR (mhdt_ACME_CHLNG_A_DOMAIN), 474 { TSTR (ALPN_ACME), TSTR_NONE, TSTR_NONE }, 475 TSTR (ALPN_ACME), 476 CERT_CHLNG_B 477 }; 478 479 /** 480 * The check performed after the removal of all the challenge certificates 481 * by the single call. The second domain is used: its certificate has never 482 * been removed individually. 483 */ 484 static const struct TestCase cleared_case = { 485 "no challenge certificate is served after the removal of all of them", 486 TSTR (mhdt_ACME_CHLNG_B_DOMAIN), 487 { TSTR (ALPN_ACME), TSTR_NONE, TSTR_NONE }, 488 TSTR_NONE, 489 CERT_SERVER 490 }; 491 492 493 /** 494 * Set the socket to the non-blocking mode 495 * @param fd the socket to set the mode for 496 */ 497 static void 498 make_nonblocking (MHD_Socket fd) 499 { 500 # if defined(MHD_SOCKETS_KIND_POSIX) 501 int flags; 502 503 flags = fcntl (fd, F_GETFL); 504 if (-1 == flags) 505 externalErrorExitDesc ("fcntl() failed"); 506 if (O_NONBLOCK != (flags & O_NONBLOCK)) 507 if (-1 == fcntl (fd, F_SETFL, flags | O_NONBLOCK)) 508 externalErrorExitDesc ("fcntl() failed"); 509 # elif defined(MHD_SOCKETS_KIND_WINSOCK) 510 unsigned long flags = 1; 511 512 if (0 != ioctlsocket (fd, (int)FIONBIO, &flags)) 513 externalErrorExitDesc ("ioctlsocket() failed"); 514 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 515 } 516 517 518 /** 519 * Disable Nagle's algorithm on the socket, the failure is not fatal 520 * @param fd the socket to set the option for 521 */ 522 static void 523 make_nodelay (MHD_Socket fd) 524 { 525 # ifdef TCP_NODELAY 526 const mhd_SCKT_OPT_BOOL on_val = 1; 527 528 if (0 == setsockopt (fd, 529 IPPROTO_TCP, 530 TCP_NODELAY, 531 (const void *)&on_val, 532 sizeof (on_val))) 533 return; /* Success exit point */ 534 535 # ifndef MHD_SOCKETS_KIND_WINSOCK 536 fprintf (stderr, "Failed to enable TCP_NODELAY on socket (ignored). " 537 "errno: %d (%s)\n", (int)errno, strerror (errno)); 538 # else /* MHD_SOCKETS_KIND_WINSOCK */ 539 fprintf (stderr, "Failed to enable TCP_NODELAY on socket (ignored). " 540 "WSAGetLastError() value: %d\n", (int)WSAGetLastError ()); 541 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 542 fflush (stderr); 543 # else /* ! TCP_NODELAY */ 544 (void)fd; /* Unused */ 545 # endif /* ! TCP_NODELAY */ 546 } 547 548 549 /** 550 * The client socket with the TLS session on it 551 */ 552 struct wr_socket 553 { 554 /** 555 * The socket 556 */ 557 MHD_Socket fd; 558 /** 559 * 'true' if the socket is in the non-blocking mode 560 */ 561 bool is_nonblocking; 562 /** 563 * The TLS credentials, without any trusted CA 564 */ 565 gnutls_certificate_credentials_t tls_crd; 566 /** 567 * The TLS session 568 */ 569 gnutls_session_t tls_s; 570 /** 571 * 'true' if the TLS handshake has been completed 572 */ 573 bool tls_connected; 574 }; 575 576 577 /** 578 * Create the socket with the TLS session, without connecting it. 579 * 580 * The server certificate is not verified: the daemon uses self-signed 581 * certificates. 582 * 583 * @return the created socket, 584 * NULL on failure 585 */ 586 static struct wr_socket * 587 wr_create_tls_sckt (void) 588 { 589 struct wr_socket *s; 590 591 s = (struct wr_socket *)malloc (sizeof(struct wr_socket)); 592 if (NULL == s) 593 { 594 testErrorLogDesc ("malloc() failed"); 595 return NULL; 596 } 597 s->is_nonblocking = false; 598 s->tls_connected = false; 599 s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 600 if (MHD_INVALID_SOCKET != s->fd) 601 { 602 make_nodelay (s->fd); 603 if (GNUTLS_E_SUCCESS == gnutls_init (&(s->tls_s), GNUTLS_CLIENT)) 604 { 605 if (GNUTLS_E_SUCCESS == gnutls_set_default_priority (s->tls_s)) 606 { 607 if (GNUTLS_E_SUCCESS == 608 gnutls_certificate_allocate_credentials (&(s->tls_crd))) 609 { 610 if (GNUTLS_E_SUCCESS == 611 gnutls_credentials_set (s->tls_s, 612 GNUTLS_CRD_CERTIFICATE, 613 s->tls_crd)) 614 { 615 # ifndef _WIN64 616 gnutls_transport_set_int (s->tls_s, (int)(s->fd)); 617 # else /* Win x64 */ 618 /* The socket does not fit into "int" */ 619 gnutls_transport_set_ptr (s->tls_s, 620 (gnutls_transport_ptr_t) \ 621 (intptr_t)(s->fd)); 622 # endif /* Win x64 */ 623 return s; /* Success exit point */ 624 } 625 else 626 testErrorLogDesc ("gnutls_credentials_set() failed"); 627 628 /* Below is a clean-up path */ 629 gnutls_certificate_free_credentials (s->tls_crd); 630 } 631 else 632 testErrorLogDesc ("gnutls_certificate_allocate_credentials() failed"); 633 } 634 else 635 testErrorLogDesc ("gnutls_set_default_priority() failed"); 636 gnutls_deinit (s->tls_s); 637 } 638 else 639 testErrorLogDesc ("gnutls_init() failed"); 640 (void)mhd_socket_close (s->fd); 641 } 642 else 643 testErrorLogDesc ("socket() failed"); 644 free (s); 645 return NULL; /* Failure exit point */ 646 } 647 648 649 /** 650 * Close the socket and release the TLS session 651 * @param s the socket to close 652 */ 653 static void 654 wr_close (struct wr_socket *s) 655 { 656 (void)mhd_socket_close (s->fd); 657 gnutls_deinit (s->tls_s); 658 gnutls_certificate_free_credentials (s->tls_crd); 659 free (s); 660 } 661 662 663 /** 664 * Set the socket to the non-blocking mode if it is not set already 665 * @param s the socket to set the mode for 666 */ 667 static void 668 wr_make_nonblocking (struct wr_socket *s) 669 { 670 if (!s->is_nonblocking) 671 make_nonblocking (s->fd); 672 s->is_nonblocking = true; 673 } 674 675 676 /** 677 * The direction to wait for 678 */ 679 enum wr_wait_for_type 680 { 681 WR_WAIT_FOR_RECV = 0 682 , 683 WR_WAIT_FOR_SEND = 1 684 }; 685 686 687 /** 688 * Wait for the socket to become ready for the specified operation. 689 * 690 * @param s the socket to wait for 691 * @param timeout_ms the maximum wait time in milliseconds, 692 * no limit if negative value is used 693 * @param wait_for the direction to wait for 694 * @return 'true' if the socket is ready, 695 * 'false' on timeout or error 696 */ 697 static bool 698 wr_wait_socket_ready_noabort_ (struct wr_socket *s, 699 int timeout_ms, 700 enum wr_wait_for_type wait_for) 701 { 702 fd_set fds; 703 int sel_res; 704 struct timeval tmo; 705 struct timeval *tmo_ptr; 706 707 # ifndef MHD_SOCKETS_KIND_WINSOCK 708 if (FD_SETSIZE <= s->fd) 709 externalErrorExitDesc ("Too large FD value"); 710 # endif /* ! MHD_SOCKETS_KIND_WINSOCK */ 711 FD_ZERO (&fds); 712 FD_SET (s->fd, &fds); 713 if (0 <= timeout_ms) 714 { 715 # if !defined(_WIN32) || defined(__CYGWIN__) 716 tmo.tv_sec = (time_t)(timeout_ms / 1000); 717 # else /* Native W32 */ 718 tmo.tv_sec = (long)(timeout_ms / 1000); 719 # endif /* Native W32 */ 720 tmo.tv_usec = ((long)(timeout_ms % 1000)) * 1000; 721 tmo_ptr = &tmo; 722 } 723 else 724 tmo_ptr = NULL; /* No timeout */ 725 726 do 727 { 728 if (WR_WAIT_FOR_RECV == wait_for) 729 sel_res = select (1 + (int)s->fd, &fds, NULL, NULL, tmo_ptr); 730 else 731 sel_res = select (1 + (int)s->fd, NULL, &fds, NULL, tmo_ptr); 732 } while ((0 > sel_res) && mhd_SCKT_ERR_IS_EINTR (mhd_SCKT_GET_LERR ())); 733 734 if (1 == sel_res) 735 return true; 736 737 if (0 == sel_res) 738 fprintf (stderr, "Timeout"); 739 else 740 { 741 # ifndef MHD_SOCKETS_KIND_WINSOCK 742 fprintf (stderr, "Error %d (%s)", (int)errno, strerror (errno)); 743 # else /* MHD_SOCKETS_KIND_WINSOCK */ 744 fprintf (stderr, "Error (WSAGetLastError code: %d)", 745 (int)WSAGetLastError ()); 746 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 747 } 748 fprintf (stderr, " waiting for socket to be available for %s.\n", 749 (WR_WAIT_FOR_RECV == wait_for) ? "receiving" : "sending"); 750 return false; 751 } 752 753 754 /** 755 * Wait for the socket to become ready, abort the test on failure 756 * @param s the socket to wait for 757 * @param timeout_ms the maximum wait time in milliseconds 758 * @param wait_for the direction to wait for 759 */ 760 static void 761 wr_wait_socket_ready_ (struct wr_socket *s, 762 int timeout_ms, 763 enum wr_wait_for_type wait_for) 764 { 765 if (wr_wait_socket_ready_noabort_ (s, timeout_ms, wait_for)) 766 return; 767 768 if (WR_WAIT_FOR_RECV == wait_for) 769 mhdErrorExitDesc ("The daemon did not send the data in time"); 770 else 771 mhdErrorExitDesc ("The daemon did not accept the data in time"); 772 } 773 774 775 /** 776 * Connect the socket to the specified address. 777 * 778 * @param s the socket to connect 779 * @param addr the address to connect to 780 * @param length the size of the structure pointed by @a addr 781 * @param timeout_ms the maximum wait time in milliseconds 782 * @return 'true' on success, 783 * 'false' otherwise 784 */ 785 static bool 786 wr_connect_tmo (struct wr_socket *s, 787 const struct sockaddr *addr, 788 unsigned int length, 789 int timeout_ms) 790 { 791 if (0 != connect (s->fd, addr, (socklen_t)length)) 792 { 793 int err; 794 bool connect_completed = false; 795 796 err = mhd_SCKT_GET_LERR (); 797 # if defined(MHD_SOCKETS_KIND_POSIX) 798 while ((!connect_completed) && (EINTR == err)) 799 { 800 connect_completed = (0 == connect (s->fd, addr, (socklen_t)length)); 801 if (!connect_completed) 802 { 803 err = errno; 804 if (EALREADY == err) 805 err = EINPROGRESS; 806 else if (EISCONN == err) 807 connect_completed = true; 808 } 809 } 810 # endif /* MHD_SOCKETS_KIND_POSIX */ 811 /* No modern system uses EAGAIN here, except W32 */ 812 if ((!connect_completed) 813 && (mhd_SCKT_ERR_IS_INPROGRESS (err) 814 || mhd_SCKT_ERR_IS_EAGAIN (err))) 815 connect_completed = 816 wr_wait_socket_ready_noabort_ (s, timeout_ms, WR_WAIT_FOR_SEND); 817 if (!connect_completed) 818 { 819 testErrorLogDesc ("connect() failed"); 820 return false; 821 } 822 } 823 return true; 824 } 825 826 827 /** 828 * Connect the socket to the daemon on the loopback interface 829 * @param s the socket to connect 830 * @param port the port of the daemon 831 * @return 'true' on success, 832 * 'false' otherwise 833 */ 834 static bool 835 wr_connect_to_daemon (struct wr_socket *s, 836 uint16_t port) 837 { 838 struct sockaddr_in sa; 839 840 memset (&sa, 0, sizeof(sa)); 841 sa.sin_family = AF_INET; 842 sa.sin_port = htons (port); 843 if (1 != inet_pton (AF_INET, 844 "127.0.0.1", 845 &(sa.sin_addr))) 846 { 847 testErrorLogDesc ("inet_pton() failed"); 848 return false; 849 } 850 return wr_connect_tmo (s, 851 (const struct sockaddr *)&sa, 852 (unsigned int)sizeof(sa), 853 test_timeout * 1000); 854 } 855 856 857 /** 858 * The result of the TLS handshake performed by the test client 859 */ 860 enum HandshakeResult 861 { 862 /** 863 * The handshake has been completed 864 */ 865 HSK_COMPLETED = 0 866 , 867 /** 868 * The daemon aborted the handshake as no offered ALPN protocol matched 869 */ 870 HSK_NO_ALPN_ALERT 871 , 872 /** 873 * The handshake failed 874 */ 875 HSK_FAILED 876 }; 877 878 879 /** 880 * Perform the TLS handshake. 881 * 882 * Unlike the same function in the "upgrade" test, the rejection by the 883 * "no_application_protocol" alert is reported separately: it is the expected 884 * result for some of the test cases. 885 * 886 * @param s the socket to perform the handshake on 887 * @param timeout_ms the maximum wait time in milliseconds 888 * @return the result of the handshake 889 */ 890 static enum HandshakeResult 891 wr_handshake_tmo_ (struct wr_socket *s, 892 int timeout_ms) 893 { 894 int res; 895 896 res = gnutls_handshake (s->tls_s); 897 while ((GNUTLS_E_AGAIN == res) || (GNUTLS_E_INTERRUPTED == res)) 898 { 899 wr_wait_socket_ready_ (s, timeout_ms, 900 gnutls_record_get_direction (s->tls_s) ? 901 WR_WAIT_FOR_SEND : WR_WAIT_FOR_RECV); 902 res = gnutls_handshake (s->tls_s); 903 } 904 if (GNUTLS_E_SUCCESS == res) 905 { 906 s->tls_connected = true; 907 return HSK_COMPLETED; 908 } 909 if ((GNUTLS_E_FATAL_ALERT_RECEIVED == res) 910 && (GNUTLS_A_NO_APPLICATION_PROTOCOL == gnutls_alert_get (s->tls_s))) 911 return HSK_NO_ALPN_ALERT; 912 913 fprintf (stderr, "The error returned by gnutls_handshake() is " 914 "'%s' ", gnutls_strerror (res)); 915 fprintf (stderr, "(%s)\n", gnutls_strerror_name (res)); 916 testErrorLogDesc ("gnutls_handshake() failed with hard error"); 917 mhd_SCKT_SET_LERR (mhdt_SCKT_HARD_ERR); /* hard error */ 918 return HSK_FAILED; 919 } 920 921 922 /** 923 * Perform the TLS handshake with the default timeout 924 * @param s the socket to perform the handshake on 925 * @return the result of the handshake 926 */ 927 static enum HandshakeResult 928 wr_handshake (struct wr_socket *s) 929 { 930 return wr_handshake_tmo_ (s, test_timeout * 1000); 931 } 932 933 934 /** 935 * Send the TLS "close notify" alert, the failure is not fatal. 936 * 937 * The daemon should not be left with the abruptly terminated connection. 938 * 939 * @param s the socket to close the session on 940 * @param timeout_ms the maximum wait time in milliseconds 941 */ 942 static void 943 wr_close_notify_tmo_ (struct wr_socket *s, 944 int timeout_ms) 945 { 946 int res; 947 948 if (!s->tls_connected) 949 return; 950 951 res = gnutls_bye (s->tls_s, GNUTLS_SHUT_WR); 952 while ((GNUTLS_E_AGAIN == res) || (GNUTLS_E_INTERRUPTED == res)) 953 { 954 if (!wr_wait_socket_ready_noabort_ (s, timeout_ms, 955 gnutls_record_get_direction (s->tls_s) ? 956 WR_WAIT_FOR_SEND : WR_WAIT_FOR_RECV)) 957 return; 958 res = gnutls_bye (s->tls_s, GNUTLS_SHUT_WR); 959 } 960 } 961 962 963 /** 964 * Set the SNI and the ALPN protocols requested by the test case. 965 * 966 * @param s the socket to set the extensions for 967 * @param tc the test case being performed 968 * @return 'true' on success, 969 * 'false' otherwise 970 */ 971 static bool 972 client_set_extensions (struct wr_socket *s, 973 const struct TestCase *tc) 974 { 975 gnutls_datum_t prots[MAX_ALPN_PROTS]; 976 unsigned int num_prots; 977 978 if (NULL != tc->sni.str) 979 { 980 if (GNUTLS_E_SUCCESS != 981 gnutls_server_name_set (s->tls_s, 982 GNUTLS_NAME_DNS, 983 tc->sni.str, 984 tc->sni.len)) 985 { 986 testErrorLogDesc ("gnutls_server_name_set() failed"); 987 return false; 988 } 989 } 990 for (num_prots = 0; NULL != tc->alpn[num_prots].str; ++num_prots) 991 { 992 prots[num_prots].data = 993 (unsigned char *)mhd_DROP_CONST (tc->alpn[num_prots].str); 994 prots[num_prots].size = (unsigned int)tc->alpn[num_prots].len; 995 } 996 if (0 == num_prots) 997 return true; /* Send no ALPN extension at all */ 998 999 if (GNUTLS_E_SUCCESS != 1000 gnutls_alpn_set_protocols (s->tls_s, 1001 prots, 1002 num_prots, 1003 0)) 1004 { 1005 testErrorLogDesc ("gnutls_alpn_set_protocols() failed"); 1006 return false; 1007 } 1008 return true; 1009 } 1010 1011 1012 /** 1013 * Check that the daemon has served the expected certificate. 1014 * 1015 * The certificates are compared in the DER form: the challenge certificate 1016 * "B" repeats the subject of the server certificate, so the names alone 1017 * cannot tell them apart. 1018 * 1019 * @param sess the completed session 1020 * @param tc the test case being performed 1021 * @return 'true' if the expected certificate has been served, 1022 * 'false' otherwise 1023 */ 1024 static bool 1025 check_served_cert (gnutls_session_t sess, 1026 const struct TestCase *tc) 1027 { 1028 const gnutls_datum_t *peers; 1029 unsigned int num_peers; 1030 gnutls_x509_crt_t crt; 1031 gnutls_datum_t pem; 1032 gnutls_datum_t der; 1033 bool res; 1034 1035 peers = gnutls_certificate_get_peers (sess, 1036 &num_peers); 1037 if ((NULL == peers) || (0 == num_peers)) 1038 { 1039 fprintf (stderr, 1040 "The daemon has not sent any certificate.\n"); 1041 return false; 1042 } 1043 if (GNUTLS_E_SUCCESS != gnutls_x509_crt_init (&crt)) 1044 { 1045 fprintf (stderr, 1046 "gnutls_x509_crt_init() failed.\n"); 1047 return false; 1048 } 1049 pem.data = 1050 (unsigned char *)mhd_DROP_CONST (certs_pem[tc->expect_cert].str); 1051 pem.size = (unsigned int)certs_pem[tc->expect_cert].len; 1052 res = false; 1053 if (GNUTLS_E_SUCCESS == gnutls_x509_crt_import (crt, 1054 &pem, 1055 GNUTLS_X509_FMT_PEM)) 1056 { 1057 if (GNUTLS_E_SUCCESS == gnutls_x509_crt_export2 (crt, 1058 GNUTLS_X509_FMT_DER, 1059 &der)) 1060 { 1061 res = ((der.size == peers[0].size) 1062 && (0 == memcmp (der.data, 1063 peers[0].data, 1064 (size_t)der.size))); 1065 gnutls_free (der.data); 1066 } 1067 else 1068 fprintf (stderr, 1069 "gnutls_x509_crt_export2() failed.\n"); 1070 } 1071 else 1072 fprintf (stderr, 1073 "gnutls_x509_crt_import() failed.\n"); 1074 gnutls_x509_crt_deinit (crt); 1075 if (!res) 1076 fprintf (stderr, 1077 "The daemon has not served %s.\n", 1078 certs_name[tc->expect_cert]); 1079 return res; 1080 } 1081 1082 1083 /** 1084 * Check that the expected application protocol has been negotiated. 1085 * 1086 * @param sess the completed session 1087 * @param tc the test case being performed 1088 * @return 'true' if the result matches the expectation, 1089 * 'false' otherwise 1090 */ 1091 static bool 1092 check_selected_alpn (gnutls_session_t sess, 1093 const struct TestCase *tc) 1094 { 1095 gnutls_datum_t alpn; 1096 1097 if (GNUTLS_E_SUCCESS != gnutls_alpn_get_selected_protocol (sess, 1098 &alpn)) 1099 { 1100 if (NULL == tc->expect_alpn.str) 1101 return true; 1102 fprintf (stderr, 1103 "No application protocol has been negotiated, \"%s\" expected.\n", 1104 tc->expect_alpn.str); 1105 return false; 1106 } 1107 if ((NULL != tc->expect_alpn.str) 1108 && (tc->expect_alpn.len == (size_t)alpn.size) 1109 && (0 == memcmp (tc->expect_alpn.str, 1110 alpn.data, 1111 (size_t)alpn.size))) 1112 return true; 1113 1114 fprintf (stderr, 1115 "The negotiated application protocol is \"%.*s\", %s expected.\n", 1116 (int)alpn.size, 1117 (const char *)alpn.data, 1118 (NULL != tc->expect_alpn.str) ? tc->expect_alpn.str : "none"); 1119 return false; 1120 } 1121 1122 1123 /** 1124 * Perform a single test case. 1125 * 1126 * @param port the port of the daemon 1127 * @param tc the test case to perform 1128 * @return 'true' if the results are as expected, 1129 * 'false' otherwise 1130 */ 1131 static bool 1132 run_test_case (uint16_t port, 1133 const struct TestCase *tc) 1134 { 1135 struct wr_socket *s; 1136 bool res; 1137 1138 s = wr_create_tls_sckt (); 1139 if (NULL == s) 1140 return false; 1141 1142 if (client_set_extensions (s, 1143 tc)) 1144 { 1145 wr_make_nonblocking (s); 1146 if (wr_connect_to_daemon (s, 1147 port)) 1148 { 1149 switch (wr_handshake (s)) 1150 { 1151 case HSK_COMPLETED: 1152 res = check_selected_alpn (s->tls_s, 1153 tc); 1154 if (!check_served_cert (s->tls_s, 1155 tc)) 1156 res = false; 1157 break; 1158 case HSK_NO_ALPN_ALERT: 1159 /* The daemon supports none of the offered protocols and aborts the 1160 handshake, as required by RFC 7301, section 3.2. The certificate 1161 cannot be checked, the test case is passed if no protocol was 1162 expected to be negotiated. */ 1163 res = (NULL == tc->expect_alpn.str); 1164 if (!res) 1165 fprintf (stderr, 1166 "The daemon rejected the offered application protocols.\n"); 1167 break; 1168 case HSK_FAILED: 1169 default: 1170 res = false; 1171 break; 1172 } 1173 wr_close_notify_tmo_ (s, 1174 test_timeout * 1000); 1175 } 1176 else 1177 res = false; 1178 } 1179 else 1180 res = false; 1181 wr_close (s); 1182 return res; 1183 } 1184 1185 1186 /** 1187 * Check the status code returned by the rejected call 1188 * 1189 * @param sc the returned status code 1190 * @param expected the expected status code 1191 * @param descr the description of the checked call 1192 * @return 'true' if the code is the expected one, 1193 * 'false' otherwise 1194 */ 1195 static bool 1196 check_status (enum MHD_StatusCode sc, 1197 enum MHD_StatusCode expected, 1198 const char *descr) 1199 { 1200 if (expected == sc) 1201 return true; 1202 1203 fprintf (stderr, 1204 "The status code for %s is %u, %u expected.\n", 1205 descr, 1206 (unsigned int)sc, 1207 (unsigned int)expected); 1208 return false; 1209 } 1210 1211 1212 /** 1213 * The daemon request callback. 1214 * 1215 * The test client never sends any request, the callback is required by 1216 * #MHD_daemon_create(). 1217 */ 1218 static const struct MHD_Action * 1219 server_req_cb (void *cls, 1220 struct MHD_Request *MHD_RESTRICT request, 1221 const struct MHD_String *MHD_RESTRICT path, 1222 enum MHD_HTTP_Method method, 1223 uint_fast64_t upload_size) 1224 { 1225 (void)cls; /* Unused */ 1226 (void)path; /* Unused */ 1227 (void)method; /* Unused */ 1228 (void)upload_size; /* Unused */ 1229 1230 unexpected_request = true; 1231 fprintf (stderr, 1232 "Unexpected request received.\n"); 1233 return MHD_action_from_response ( 1234 request, 1235 MHD_response_from_empty (MHD_HTTP_STATUS_NO_CONTENT)); 1236 } 1237 1238 1239 /** 1240 * Configure the started daemon and add the ACME challenge certificates. 1241 * 1242 * Everything set here is owned by the daemon, so nothing has to be released 1243 * by this function on failure. 1244 * 1245 * @param d the created daemon 1246 * @param be the TLS backend to use 1247 * @param[out] p_port the port bound by the daemon, set on success only 1248 * @return 0 on success, 1249 * 77 if the ACME ALPN challenge is not supported, 1250 * 1 on failure 1251 */ 1252 static int 1253 daemon_setup (struct MHD_Daemon *d, 1254 enum MHD_TlsBackend be, 1255 uint16_t *p_port) 1256 { 1257 union MHD_DaemonInfoFixedData info; 1258 enum MHD_StatusCode sc; 1259 1260 if (MHD_SC_OK != 1261 MHD_DAEMON_SET_OPTIONS ( 1262 d, 1263 MHD_D_OPTION_WM_WORKER_THREADS (1), 1264 MHD_D_OPTION_DEFAULT_TIMEOUT_MILSEC (2000), 1265 MHD_D_OPTION_BIND_PORT (MHD_AF_AUTO, 1266 0), 1267 MHD_D_OPTION_TLS (be), 1268 /* The certificate parameter is not declared "const" */ 1269 MHD_D_OPTION_TLS_CERT_KEY ((char *)mhd_DROP_CONST ( 1270 mhdt_ACME_SRV_CERT_PEM), 1271 mhdt_ACME_SRV_KEY_PEM, 1272 NULL))) 1273 { 1274 fprintf (stderr, 1275 "Failed to configure the daemon.\n"); 1276 return 1; 1277 } 1278 1279 sc = MHD_daemon_acme_alpn_cert_add (d, 1280 mhdt_ACME_CHLNG_A_DOMAIN, 1281 mhdt_ACME_CHLNG_A_CERT_PEM, 1282 mhdt_ACME_CHLNG_A_KEY_PEM, 1283 NULL); 1284 if (!check_status (sc, 1285 MHD_SC_TOO_EARLY, 1286 "adding the certificate before the daemon start")) 1287 return 1; 1288 1289 sc = MHD_daemon_acme_alpn_cert_del (d, 1290 mhdt_ACME_CHLNG_A_DOMAIN); 1291 if (!check_status (sc, 1292 MHD_SC_TOO_EARLY, 1293 "removing the certificate before the daemon start")) 1294 return 1; 1295 1296 sc = MHD_daemon_start (d); 1297 if (MHD_SC_OK != sc) 1298 { 1299 fprintf (stderr, 1300 "Failed to start the daemon: %u\n", 1301 (unsigned int)sc); 1302 return 1; 1303 } 1304 1305 sc = MHD_daemon_acme_alpn_cert_add (d, 1306 mhdt_ACME_CHLNG_A_DOMAIN, 1307 mhdt_ACME_CHLNG_A_CERT_PEM, 1308 mhdt_ACME_CHLNG_A_KEY_PEM, 1309 NULL); 1310 if (MHD_SC_TLS_BACKEND_OPERATION_UNSUPPORTED == sc) 1311 { 1312 fprintf (stderr, 1313 "The ACME ALPN challenge is not supported, skipping.\n"); 1314 return 77; 1315 } 1316 if (MHD_SC_OK == sc) 1317 sc = MHD_daemon_acme_alpn_cert_add (d, 1318 mhdt_ACME_CHLNG_B_DOMAIN, 1319 mhdt_ACME_CHLNG_B_CERT_PEM, 1320 mhdt_ACME_CHLNG_B_KEY_PEM, 1321 NULL); 1322 if (MHD_SC_OK != sc) 1323 { 1324 fprintf (stderr, 1325 "MHD_daemon_acme_alpn_cert_add() failed: %u\n", 1326 (unsigned int)sc); 1327 return 1; 1328 } 1329 1330 if (MHD_SC_OK != 1331 MHD_daemon_get_info_fixed (d, 1332 MHD_DAEMON_INFO_FIXED_BIND_PORT, 1333 &info)) 1334 { 1335 fprintf (stderr, 1336 "Failed to get the port of the daemon.\n"); 1337 return 1; 1338 } 1339 *p_port = info.v_bind_port_uint16; 1340 return 0; 1341 } 1342 1343 1344 /** 1345 * Create and start the daemon with the ACME challenge certificates. 1346 * 1347 * @param be the TLS backend to use 1348 * @param[out] p_d the started daemon, set on success only 1349 * @param[out] p_port the port bound by the daemon, set on success only 1350 * @return 0 on success, 1351 * 77 if the ACME ALPN challenge is not supported, 1352 * 1 on failure 1353 */ 1354 static int 1355 start_daemon (enum MHD_TlsBackend be, 1356 struct MHD_Daemon **p_d, 1357 uint16_t *p_port) 1358 { 1359 struct MHD_Daemon *d; 1360 int res; 1361 1362 *p_d = NULL; 1363 d = MHD_daemon_create (&server_req_cb, 1364 NULL); 1365 if (NULL == d) 1366 { 1367 fprintf (stderr, 1368 "MHD_daemon_create() failed.\n"); 1369 return 1; 1370 } 1371 1372 res = daemon_setup (d, 1373 be, 1374 p_port); 1375 if (0 == res) 1376 { 1377 *p_d = d; 1378 return 0; /* Success exit point */ 1379 } 1380 1381 /* Below is a clean-up path */ 1382 MHD_daemon_destroy (d); 1383 return res; /* Failure exit point */ 1384 } 1385 1386 1387 /** 1388 * Check that the certificate management functions reject the wrong use. 1389 * 1390 * @param d the started daemon 1391 * @return 'true' if all the calls are rejected as expected, 1392 * 'false' otherwise 1393 */ 1394 static bool 1395 check_cert_api_misuse (struct MHD_Daemon *d) 1396 { 1397 enum MHD_StatusCode sc; 1398 bool res; 1399 1400 res = true; 1401 1402 sc = MHD_daemon_acme_alpn_cert_add (d, 1403 "", 1404 mhdt_ACME_CHLNG_A_CERT_PEM, 1405 mhdt_ACME_CHLNG_A_KEY_PEM, 1406 NULL); 1407 if (!check_status (sc, 1408 MHD_SC_PARAM_EMPTY, 1409 "adding the certificate for the empty domain")) 1410 res = false; 1411 1412 sc = MHD_daemon_acme_alpn_cert_del (d, 1413 ""); 1414 if (!check_status (sc, 1415 MHD_SC_PARAM_EMPTY, 1416 "removing the certificate of the empty domain")) 1417 res = false; 1418 1419 sc = MHD_daemon_acme_alpn_cert_del (d, 1420 DOMAIN_NO_ACME); 1421 if (!check_status (sc, 1422 MHD_SC_ITEM_NOT_FOUND, 1423 "removing the certificate of the unknown domain")) 1424 res = false; 1425 1426 sc = MHD_daemon_acme_alpn_cert_add (d, 1427 DOMAIN_BAD_CERT, 1428 "", 1429 mhdt_ACME_CHLNG_A_KEY_PEM, 1430 NULL); 1431 if (!check_status (sc, 1432 MHD_SC_TLS_CONF_BAD_CERT, 1433 "adding the empty certificate")) 1434 res = false; 1435 1436 sc = MHD_daemon_acme_alpn_cert_add (d, 1437 DOMAIN_BAD_CERT, 1438 BAD_CERT_PEM, 1439 mhdt_ACME_CHLNG_A_KEY_PEM, 1440 NULL); 1441 if (!check_status (sc, 1442 MHD_SC_TLS_CONF_BAD_CERT, 1443 "adding the malformed certificate")) 1444 res = false; 1445 1446 sc = MHD_daemon_acme_alpn_cert_add (d, 1447 DOMAIN_BAD_CERT, 1448 mhdt_ACME_CHLNG_A_CERT_PEM, 1449 mhdt_ACME_CHLNG_B_KEY_PEM, 1450 NULL); 1451 if (!check_status (sc, 1452 MHD_SC_TLS_CONF_BAD_CERT, 1453 "adding the certificate with the key of another one")) 1454 res = false; 1455 1456 return res; 1457 } 1458 1459 1460 /** 1461 * Perform a single test case and report the failure 1462 * 1463 * @param port the port of the daemon 1464 * @param tc the test case to perform 1465 * @return 'true' if the results are as expected, 1466 * 'false' otherwise 1467 */ 1468 static bool 1469 run_case (uint16_t port, 1470 const struct TestCase *tc) 1471 { 1472 fprintf (stderr, 1473 "Checking %s.\n", 1474 tc->label); 1475 if (run_test_case (port, 1476 tc)) 1477 return true; 1478 1479 fprintf (stderr, 1480 "FAILED: %s\n", 1481 tc->label); 1482 return false; 1483 } 1484 1485 1486 /** 1487 * Perform all the test cases with the specified TLS backend. 1488 * 1489 * @param be the TLS backend to use 1490 * @param be_name the name of the backend for the log 1491 * @return 0 on success, 1492 * 77 if the ACME ALPN challenge is not supported, 1493 * 1 if any test case failed 1494 */ 1495 static int 1496 run_backend (enum MHD_TlsBackend be, 1497 const char *be_name) 1498 { 1499 struct MHD_Daemon *d; 1500 uint16_t port; 1501 unsigned int i; 1502 int res; 1503 1504 fprintf (stderr, 1505 "Testing with the TLS backend \"%s\".\n", 1506 be_name); 1507 res = start_daemon (be, 1508 &d, 1509 &port); 1510 if (0 != res) 1511 return res; 1512 1513 if (!check_cert_api_misuse (d)) 1514 res = 1; 1515 1516 for (i = 0; i < (sizeof(test_cases) / sizeof(test_cases[0])); ++i) 1517 { 1518 if (!run_case (port, 1519 test_cases + i)) 1520 res = 1; 1521 } 1522 1523 /* The certificate for the first domain is removed, the domain name is 1524 spelled in the different letters case */ 1525 if (MHD_SC_OK != 1526 MHD_daemon_acme_alpn_cert_del (d, 1527 DOMAIN_A_MIXED_CASE)) 1528 { 1529 fprintf (stderr, 1530 "MHD_daemon_acme_alpn_cert_del() failed.\n"); 1531 res = 1; 1532 } 1533 else if (!run_case (port, 1534 &removed_case)) 1535 res = 1; 1536 1537 /* The same certificate is registered for any domain */ 1538 if (MHD_SC_OK != 1539 MHD_daemon_acme_alpn_cert_add (d, 1540 NULL, 1541 mhdt_ACME_CHLNG_A_CERT_PEM, 1542 mhdt_ACME_CHLNG_A_KEY_PEM, 1543 NULL)) 1544 { 1545 fprintf (stderr, 1546 "Failed to add the fallback certificate.\n"); 1547 res = 1; 1548 } 1549 else 1550 { 1551 if (!run_case (port, 1552 &fallback_case)) 1553 res = 1; 1554 if (!run_case (port, 1555 &fallback_no_sni_case)) 1556 res = 1; 1557 if (!run_case (port, 1558 &fallback_specific_case)) 1559 res = 1; 1560 } 1561 1562 /* The certificate of the first domain is set to another certificate */ 1563 if (MHD_SC_OK != 1564 MHD_daemon_acme_alpn_cert_add (d, 1565 mhdt_ACME_CHLNG_A_DOMAIN, 1566 mhdt_ACME_CHLNG_B_CERT_PEM, 1567 mhdt_ACME_CHLNG_B_KEY_PEM, 1568 NULL)) 1569 { 1570 fprintf (stderr, 1571 "Failed to replace the challenge certificate.\n"); 1572 res = 1; 1573 } 1574 else if (!run_case (port, 1575 &replaced_case)) 1576 res = 1; 1577 1578 /* All the challenge certificates are removed by the single call */ 1579 if (MHD_SC_OK != 1580 MHD_daemon_acme_alpn_cert_del (d, 1581 NULL)) 1582 { 1583 fprintf (stderr, 1584 "Failed to remove all the challenge certificates.\n"); 1585 res = 1; 1586 } 1587 else if (!run_case (port, 1588 &cleared_case)) 1589 res = 1; 1590 1591 /* Unlike the removal by the domain name, the removal of all the 1592 certificates is not an error when nothing is left to remove */ 1593 if (MHD_SC_OK != 1594 MHD_daemon_acme_alpn_cert_del (d, 1595 NULL)) 1596 { 1597 fprintf (stderr, 1598 "The repeated removal of all the certificates failed.\n"); 1599 res = 1; 1600 } 1601 1602 MHD_daemon_destroy (d); 1603 1604 if (unexpected_request) 1605 { 1606 fprintf (stderr, 1607 "FAILED: the daemon has received a request.\n"); 1608 unexpected_request = false; 1609 res = 1; 1610 } 1611 return res; 1612 } 1613 1614 1615 int 1616 main (int argc, 1617 char *argv[]) 1618 { 1619 bool tested_one_or_more; 1620 bool failed; 1621 int res; 1622 1623 (void)argc; /* Unused */ 1624 (void)argv; /* Unused */ 1625 1626 if (GNUTLS_E_SUCCESS != gnutls_global_init ()) 1627 { 1628 fprintf (stderr, 1629 "gnutls_global_init() failed.\n"); 1630 return 99; 1631 } 1632 tested_one_or_more = false; 1633 failed = false; 1634 1635 res = run_backend (MHD_TLS_BACKEND_GNUTLS, 1636 "GnuTLS"); 1637 if (77 != res) 1638 { 1639 tested_one_or_more = true; 1640 if (0 != res) 1641 failed = true; 1642 } 1643 # ifdef MHD_SUPPORT_OPENSSL 1644 res = run_backend (MHD_TLS_BACKEND_OPENSSL, 1645 "OpenSSL"); 1646 if (77 != res) 1647 { 1648 tested_one_or_more = true; 1649 if (0 != res) 1650 failed = true; 1651 } 1652 # endif /* MHD_SUPPORT_OPENSSL */ 1653 1654 gnutls_global_deinit (); 1655 1656 if (!tested_one_or_more) 1657 return 77; 1658 1659 return failed ? 1 : 0; 1660 } 1661 1662 1663 #else /* GnuTLS before 3.2.0 */ 1664 1665 int 1666 main (void) 1667 { 1668 fprintf (stderr, 1669 "GnuTLS has no ALPN support, skipping.\n"); 1670 return 77; 1671 } 1672 1673 1674 #endif /* GnuTLS before 3.2.0 */