libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

test_https_session_info.c (11254B)


      1 /*
      2  This file is part of libmicrohttpd
      3  Copyright (C) 2007, 2016 Christian Grothoff
      4  Copyright (C) 2016-2021 Evgeny Grin (Karlson2k)
      5 
      6  libmicrohttpd is free software; you can redistribute it and/or modify
      7  it under the terms of the GNU General Public License as published
      8  by the Free Software Foundation; either version 2, or (at your
      9  option) any later version.
     10 
     11  libmicrohttpd is distributed in the hope that it will be useful, but
     12  WITHOUT ANY WARRANTY; without even the implied warranty of
     13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  General Public License for more details.
     15 
     16  You should have received a copy of the GNU General Public License
     17  along with libmicrohttpd; see the file COPYING.  If not, write to the
     18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19  Boston, MA 02110-1301, USA.
     20  */
     21 
     22 /**
     23  * @file test_https_session_info.c
     24  * @brief  Testcase for libmicrohttpd HTTPS connection querying operations
     25  * @author Sagie Amir
     26  * @author Karlson2k (Evgeny Grin)
     27  */
     28 
     29 #include "platform.h"
     30 #include "microhttpd.h"
     31 #include <curl/curl.h>
     32 #ifdef MHD_HTTPS_REQUIRE_GCRYPT
     33 #include <gcrypt.h>
     34 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */
     35 #include "tls_test_common.h"
     36 #include "tls_test_keys.h"
     37 
     38 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this
     39    test into a marked, classifiable test error (TESTING.md, P5). */
     40 #include "mhd_panic_tripwire.h"
     41 
     42 
     43 static int test_append_prio;
     44 
     45 /*
     46  * HTTP access handler call back
     47  * used to query negotiated security parameters
     48  */
     49 static enum MHD_Result
     50 query_info_ahc (void *cls, struct MHD_Connection *connection,
     51                 const char *url, const char *method,
     52                 const char *version, const char *upload_data,
     53                 size_t *upload_data_size, void **req_cls)
     54 {
     55   struct MHD_Response *response;
     56   enum MHD_Result ret;
     57   const union MHD_ConnectionInfo *conn_info;
     58   enum know_gnutls_tls_id *used_tls_ver;
     59   (void) url; (void) method; (void) version;   /* Unused. Silent compiler warning. */
     60   (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */
     61   used_tls_ver = (enum know_gnutls_tls_id *) cls;
     62 
     63   if (NULL == *req_cls)
     64   {
     65     *req_cls = (void *) &query_info_ahc;
     66     return MHD_YES;
     67   }
     68 
     69   conn_info = MHD_get_connection_info (connection,
     70                                        MHD_CONNECTION_INFO_PROTOCOL);
     71   if (NULL == conn_info)
     72   {
     73     fflush (stderr);
     74     fflush (stdout);
     75     fprintf (stderr, "MHD_get_connection_info() failed.\n");
     76     fflush (stderr);
     77     return MHD_NO;
     78   }
     79   if (0 == (unsigned int) conn_info->protocol)
     80   {
     81     fflush (stderr);
     82     fflush (stdout);
     83     fprintf (stderr, "MHD_get_connection_info()->protocol has "
     84              "wrong zero value.\n");
     85     fflush (stderr);
     86     return MHD_NO;
     87   }
     88   *used_tls_ver = (enum know_gnutls_tls_id) conn_info->protocol;
     89 
     90   response = MHD_create_response_from_buffer_static (strlen (EMPTY_PAGE),
     91                                                      EMPTY_PAGE);
     92   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
     93   MHD_destroy_response (response);
     94   return ret;
     95 }
     96 
     97 
     98 /**
     99  * negotiate a secure connection with server & query negotiated security parameters
    100  */
    101 static unsigned int
    102 test_query_session (enum know_gnutls_tls_id tls_ver, uint16_t *pport)
    103 {
    104   CURL *c;
    105   struct CBC cbc;
    106   CURLcode errornum;
    107   char url[256];
    108   enum know_gnutls_tls_id found_tls_ver;
    109   struct MHD_Daemon *d;
    110 
    111   if (NULL == (cbc.buf = malloc (sizeof (char) * 255)))
    112     return 99;
    113   cbc.size = 255;
    114   cbc.pos = 0;
    115 
    116   /* setup test */
    117   found_tls_ver = KNOWN_BAD;
    118   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
    119                         | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS
    120                         | MHD_USE_ERROR_LOG, *pport,
    121                         NULL, NULL,
    122                         &query_info_ahc, &found_tls_ver,
    123                         test_append_prio ?
    124                         MHD_OPTION_HTTPS_PRIORITIES_APPEND :
    125                         MHD_OPTION_HTTPS_PRIORITIES,
    126                         test_append_prio ?
    127                         priorities_append_map[tls_ver] :
    128                         priorities_map[tls_ver],
    129                         MHD_OPTION_HTTPS_MEM_KEY, srv_self_signed_key_pem,
    130                         MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem,
    131                         MHD_OPTION_END);
    132 
    133   if (d == NULL)
    134   {
    135     free (cbc.buf);
    136     fprintf (stderr, "MHD_start_daemon() with %s failed.\n",
    137              tls_names[tls_ver]);
    138     fflush (stderr);
    139     return 77;
    140   }
    141   if (0 == *pport)
    142   {
    143     const union MHD_DaemonInfo *dinfo;
    144     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    145     if ((NULL == dinfo) || (0 == dinfo->port) )
    146     {
    147       MHD_stop_daemon (d);
    148       free (cbc.buf);
    149       fprintf (stderr, "MHD_get_daemon_info() failed.\n");
    150       fflush (stderr);
    151       return 10;
    152     }
    153     *pport = dinfo->port; /* Use the same port for rest of the checks */
    154   }
    155 
    156   gen_test_uri (url,
    157                 sizeof (url),
    158                 *pport);
    159   c = curl_easy_init ();
    160   fflush (stderr);
    161   if (NULL == c)
    162   {
    163     fprintf (stderr, "curl_easy_init() failed.\n");
    164     fflush (stderr);
    165     MHD_stop_daemon (d);
    166     free (cbc.buf);
    167     return 99;
    168   }
    169 #ifdef _DEBUG
    170   curl_easy_setopt (c, CURLOPT_VERBOSE, 1L);
    171 #endif
    172 
    173   if ((CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_URL, url))) ||
    174       (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_HTTP_VERSION,
    175                                                  CURL_HTTP_VERSION_1_1))) ||
    176       (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L))) ||
    177       (CURLE_OK !=
    178        (errornum = curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L))) ||
    179       (CURLE_OK !=
    180        (errornum = curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer))) ||
    181       (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_WRITEDATA,
    182                                                  &cbc))) ||
    183       /* TLS options */
    184       /* currently skip any peer authentication */
    185       (CURLE_OK !=
    186        (errornum = curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L))) ||
    187       (CURLE_OK !=
    188        (errornum = curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L))) ||
    189       (CURLE_OK !=
    190        (errornum = curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L))) ||
    191       (CURLE_OK != (errornum = curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L))))
    192   {
    193     curl_easy_cleanup (c);
    194     free (cbc.buf);
    195     MHD_stop_daemon (d);
    196     fflush (stderr);
    197     fflush (stdout);
    198     fprintf (stderr, "Error setting libcurl option: %s.\n",
    199              curl_easy_strerror (errornum));
    200     fflush (stderr);
    201     return 99;
    202   }
    203 
    204   if (CURLE_OK != (errornum = curl_easy_perform (c)))
    205   {
    206     unsigned int ret;
    207     curl_easy_cleanup (c);
    208     free (cbc.buf);
    209     MHD_stop_daemon (d);
    210 
    211     fflush (stderr);
    212     fflush (stdout);
    213     if ((CURLE_SSL_CONNECT_ERROR == errornum) ||
    214         (CURLE_SSL_CIPHER == errornum))
    215     {
    216       ret = 77;
    217       fprintf (stderr, "libcurl request failed due to TLS error: '%s'\n",
    218                curl_easy_strerror (errornum));
    219 
    220     }
    221     else
    222     {
    223       ret = 1;
    224       fprintf (stderr, "curl_easy_perform failed: '%s'\n",
    225                curl_easy_strerror (errornum));
    226     }
    227     fflush (stderr);
    228 
    229     return ret;
    230   }
    231 
    232   curl_easy_cleanup (c);
    233   free (cbc.buf);
    234   MHD_stop_daemon (d);
    235 
    236   if (tls_ver != found_tls_ver)
    237   {
    238     fflush (stderr);
    239     fflush (stdout);
    240     fprintf (stderr, "MHD_get_connection_info (conn, "
    241              "MHD_CONNECTION_INFO_PROTOCOL) returned unexpected "
    242              "protocol version.\n"
    243              "\tReturned: %s (%u)\tExpected: %s (%u)\n",
    244              ((unsigned int) found_tls_ver) > KNOWN_TLS_MAX ?
    245              "[wrong value]" : tls_names[found_tls_ver],
    246              (unsigned int) found_tls_ver,
    247              tls_names[tls_ver], (unsigned int) tls_ver);
    248     fflush (stderr);
    249     return 2;
    250   }
    251   return 0;
    252 }
    253 
    254 
    255 static unsigned int
    256 test_all_supported_versions (void)
    257 {
    258   enum know_gnutls_tls_id ver_for_test; /**< TLS version used for test */
    259   const gnutls_protocol_t *vers_list;    /**< The list of GnuTLS supported TLS versions */
    260   uint16_t port;
    261   unsigned int num_success; /**< Number of tests succeeded */
    262   unsigned int num_failed;  /**< Number of tests failed */
    263 
    264   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    265     port = 0;     /* Use system automatic assignment */
    266   else
    267     port = 3060;  /* Use predefined port, may break parallel testing of another MHD build */
    268 
    269   vers_list = gnutls_protocol_list ();
    270   if (NULL == vers_list)
    271   {
    272     fprintf (stderr, "Error getting GnuTLS supported TLS versions");
    273     return 99;
    274   }
    275   num_success = 0;
    276   num_failed = 0;
    277 
    278   for (ver_for_test = KNOWN_TLS_MIN; KNOWN_TLS_MAX >= ver_for_test;
    279        ++ver_for_test)
    280   {
    281     const gnutls_protocol_t *ver_ptr;      /**< The pointer to the position on the @a vers_list */
    282     unsigned int res;
    283     for (ver_ptr = vers_list; 0 != *ver_ptr; ++ver_ptr)
    284     {
    285       if (ver_for_test == (enum know_gnutls_tls_id) *ver_ptr)
    286         break;
    287     }
    288     if (0 == *ver_ptr)
    289     {
    290       printf ("%s is not supported by GnuTLS, skipping.\n\n",
    291               tls_names[ver_for_test]);
    292       fflush (stdout);
    293       continue;
    294     }
    295     printf ("Starting check for %s...\n",
    296             tls_names[ver_for_test]);
    297     fflush (stdout);
    298     res = test_query_session (ver_for_test, &port);
    299     fflush (stderr);
    300     fflush (stdout);
    301     if (99 == res)
    302     {
    303       fprintf (stderr, "Hard error. Test stopped.\n");
    304       fflush (stderr);
    305       return 99;
    306     }
    307     else if (77 == res)
    308     {
    309       printf ("%s does not work with libcurl client and GnuTLS "
    310               "server combination, skipping.\n",
    311               tls_names[ver_for_test]);
    312       fflush (stdout);
    313     }
    314     else if (0 != res)
    315     {
    316       fprintf (stderr, "Check failed for %s.\n",
    317                tls_names[ver_for_test]);
    318       fflush (stderr);
    319       num_failed++;
    320     }
    321     else
    322     {
    323       printf ("Check succeeded for %s.\n",
    324               tls_names[ver_for_test]);
    325       fflush (stdout);
    326       num_success++;
    327     }
    328     printf ("\n");
    329     fflush (stdout);
    330   }
    331 
    332   if (0 == num_failed)
    333   {
    334     if (0 == num_success)
    335     {
    336       fprintf (stderr, "No supported TLS version was found.\n");
    337       fflush (stderr);
    338       return 77;
    339     }
    340     return 0;
    341   }
    342   return num_failed;
    343 }
    344 
    345 
    346 int
    347 main (int argc, char *const *argv)
    348 {
    349   unsigned int errorCount = 0;
    350   const char *ssl_version;
    351   (void) argc;   /* Unused. Silent compiler warning. */
    352 
    353 #ifdef MHD_HTTPS_REQUIRE_GCRYPT
    354   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
    355 #ifdef GCRYCTL_INITIALIZATION_FINISHED
    356   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
    357 #endif
    358 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */
    359   test_append_prio = has_in_name (argv[0], "_append");
    360   if (! testsuite_curl_global_init ())
    361     return 99;
    362 
    363   ssl_version = curl_version_info (CURLVERSION_NOW)->ssl_version;
    364   if (NULL == ssl_version)
    365   {
    366     fprintf (stderr, "Curl does not support SSL.  Cannot run the test.\n");
    367     curl_global_cleanup ();
    368     return 77;
    369   }
    370   errorCount = test_all_supported_versions ();
    371   fflush (stderr);
    372   fflush (stdout);
    373   curl_global_cleanup ();
    374   if (77 == errorCount)
    375     return 77;
    376   else if (99 == errorCount)
    377     return 99;
    378   print_test_result (errorCount, argv[0]);
    379   return errorCount != 0 ? 1 : 0;
    380 }