libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

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 */