libmicrohttpd

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

test_https_session_info.c (11087B)


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