"Fossies" - the Fresh Open Source Software Archive

Member "HTTPing-2.9/mssl.c" (29 Oct 2022, 9210 Bytes) of package /linux/www/HTTPing-2.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mssl.c" see the Fossies "Dox" file reference documentation.

    1 /* Released under AGPL v3 with exception for the OpenSSL library. See license.txt */
    2 #include <errno.h>
    3 #include <libintl.h>
    4 #include <string.h>
    5 #include <unistd.h>
    6 #include <sys/types.h>
    7 #include <sys/socket.h>
    8 #include <sys/types.h>
    9 #include <sys/time.h>
   10 #include <sys/socket.h>
   11 #include <openssl/bio.h>
   12 #include <openssl/conf.h>
   13 #include <openssl/engine.h>
   14 #include <openssl/err.h>
   15 #include <openssl/evp.h>
   16 #include <openssl/md5.h>
   17 #include <openssl/ssl.h>
   18 #include <openssl/x509.h>
   19 
   20 #include "error.h"
   21 #include "gen.h"
   22 #include "mssl.h"
   23 #include "tcp.h"
   24 #include "io.h"
   25 #include "http.h"
   26 #include "utils.h"
   27 #include "main.h"
   28 
   29 BIO *bio_err = NULL;
   30 
   31 void shutdown_ssl(void)
   32 {
   33     BIO_free(bio_err);
   34 
   35     ERR_free_strings();
   36 
   37     ERR_remove_state(0);
   38     ENGINE_cleanup();
   39     CONF_modules_free();
   40     EVP_cleanup();
   41     CRYPTO_cleanup_all_ex_data();
   42 }
   43 
   44 int close_ssl_connection(SSL *const ssl_h)
   45 {
   46     int rc = SSL_shutdown(ssl_h);
   47 
   48     if (!rc)
   49         rc = SSL_shutdown(ssl_h);
   50 
   51 /*
   52 ignoring failures: the socket will be closed
   53 anyway later on so any openssl failures won't
   54 do any harm
   55     if (rc == -1)
   56     {
   57         fprintf(stderr, "SSL_shutdown failed: %s\n", strerror(errno));
   58         return -1;
   59     }
   60 */
   61 
   62     return 0;
   63 }
   64 
   65 int READ_SSL(SSL *const ssl_h, char *whereto, int len, const double timeout)
   66 {
   67     const int cnt = len;
   68     const int fd = SSL_get_rfd(ssl_h);
   69     double end = get_ts() + timeout;
   70 
   71     while(len > 0 && !got_sigquit)
   72     {
   73         int rc = -1;
   74         fd_set rfds, wfds;
   75         struct timeval tv;
   76         double now = get_ts(), left = end - now;
   77 
   78         if (left <= 0.0)
   79         {
   80             set_error(gettext("Time-out on SSL connection"));
   81             return -1;
   82         }
   83 
   84         FD_ZERO(&rfds);
   85         FD_SET(fd, &rfds);
   86         FD_ZERO(&wfds); /* yes, see openssl */
   87         FD_SET(fd, &wfds);
   88 
   89         tv.tv_sec = left;
   90         tv.tv_usec = (left - tv.tv_sec) * 1000000;
   91 
   92         rc = select(fd + 1, &rfds, &wfds, NULL, &tv);
   93 
   94         if (rc == -1)
   95         {
   96             if (errno != EINTR && errno != EAGAIN)
   97                 set_error(gettext("READ_SSL: io-error: %s"), strerror(errno));
   98 
   99             return -1;
  100         }
  101 
  102         if (rc == 0)
  103         {
  104             set_error(gettext("Time-out on SSL connection (READ)"));
  105             return -1;
  106         }
  107 
  108         rc = SSL_read(ssl_h, whereto, len);
  109         if (rc == -1)
  110         {
  111             if (errno != EINTR && errno != EAGAIN)
  112                 set_error(gettext("READ_SSL: io-error: %s"), strerror(errno));
  113 
  114             return -1;
  115         }
  116 
  117         if (rc == 0)
  118             return 0;
  119 
  120         whereto += rc;
  121         len -= rc;
  122     }
  123 
  124     return cnt;
  125 }
  126 
  127 int WRITE_SSL(SSL *const ssl_h, const char *wherefrom, int len, const double timeout)
  128 {
  129     const int cnt = len;
  130     const int fd = SSL_get_wfd(ssl_h);
  131     double end = get_ts() + timeout;
  132 
  133     while(len > 0 && !got_sigquit)
  134     {
  135         int rc = -1;
  136         fd_set rfds, wfds;
  137         struct timeval tv;
  138         double now = get_ts(), left = end - now;
  139 
  140         if (left <= 0.0)
  141         {
  142             set_error(gettext("Time-out on SSL connection"));
  143             return -1;
  144         }
  145 
  146         FD_ZERO(&rfds); /* yes, that's correct */
  147         FD_SET(fd, &rfds);
  148         FD_ZERO(&wfds);
  149         FD_SET(fd, &wfds);
  150 
  151         tv.tv_sec = left;
  152         tv.tv_usec = (left - tv.tv_sec) * 1000000;
  153 
  154         rc = select(fd + 1, &rfds, &wfds, NULL, &tv);
  155 
  156         if (rc == -1)
  157         {
  158             if (errno != EINTR && errno != EAGAIN)
  159                 set_error(gettext("WRITE_SSL: io-error: %s"), strerror(errno));
  160 
  161             return -1;
  162         }
  163 
  164         if (rc == 0)
  165         {
  166             set_error(gettext("Time-out on SSL connection (write)"));
  167             return -1;
  168         }
  169 
  170         rc = SSL_write(ssl_h, wherefrom, len);
  171         if (rc == -1)
  172         {
  173             if (errno != EINTR && errno != EAGAIN)
  174                 set_error(gettext("WRITE_SSL: io-error: %s"), strerror(errno));
  175             return -1;
  176         }
  177 
  178         if (rc == 0)
  179             return 0;
  180 
  181         wherefrom += rc;
  182         len -= rc;
  183     }
  184 
  185     return cnt;
  186 }
  187 
  188 int connect_ssl(const int fd, SSL_CTX *const client_ctx, SSL **const ssl_h, BIO **const s_bio, const double timeout, double *const ssl_handshake, char *const hostname)
  189 {
  190     double dstart = get_ts();
  191     double end = get_ts() + timeout;
  192 
  193     struct timeval tv;
  194     tv.tv_sec  = (long)(timeout / 1000.0);
  195     tv.tv_usec = (long)(timeout * 1000.0) % 1000000;
  196 
  197     *ssl_handshake = -1.0;
  198 
  199     if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv) == -1)
  200     {
  201         set_error(gettext("problem setting receive timeout (%s)"), strerror(errno));
  202         return -1;
  203     }
  204 
  205     if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv) == -1)
  206     {
  207         set_error(gettext("problem setting transmit timeout (%s)"), strerror(errno));
  208         return -1;
  209     }
  210 
  211     *ssl_h = SSL_new(client_ctx);
  212     SSL_set_tlsext_host_name(*ssl_h, hostname);
  213 
  214     X509_VERIFY_PARAM *param = SSL_get0_param(*ssl_h);
  215     X509_VERIFY_PARAM_set1_host(param, hostname, 0);
  216 
  217     *s_bio = BIO_new_socket(fd, BIO_NOCLOSE);
  218     SSL_set_bio(*ssl_h, *s_bio, *s_bio);
  219 
  220     if (set_fd_nonblocking(fd) == -1)
  221         return RC_INVAL;
  222 
  223     do
  224     {
  225         int rc = SSL_connect(*ssl_h);
  226 
  227         if (rc <= 0)
  228         {
  229             int err = SSL_get_error(*ssl_h, rc);
  230 
  231             if (err == SSL_ERROR_WANT_CONNECT || err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
  232             {
  233                 struct timeval tv;
  234                 fd_set fds;
  235                 double left = end - get_ts();
  236 
  237                 if (left <= 0)
  238                 {
  239                     set_error(gettext("Time-out during SSL handshake"));
  240                     return -1;
  241                 }
  242 
  243                 tv.tv_sec = left;
  244                 tv.tv_usec = (left - tv.tv_sec) * 1000000;
  245 
  246                 FD_ZERO(&fds);
  247                 FD_SET(fd, &fds);
  248 
  249                 if (err == SSL_ERROR_WANT_READ)
  250                     rc = select(fd + 1, &fds, NULL, NULL, &tv);
  251                 else
  252                     rc = select(fd + 1, NULL, &fds, NULL, &tv);
  253             }
  254             else
  255             {
  256                 set_error(gettext("SSL handshake error: %s"), ERR_reason_error_string(ERR_get_error()));
  257                 return -1;
  258             }
  259         }
  260     }
  261     while (!SSL_is_init_finished(*ssl_h) && !got_sigquit);
  262 
  263     X509 *cert = SSL_get_peer_certificate(*ssl_h);
  264     if (cert)
  265         X509_free(cert);
  266     else
  267         set_error(gettext("SSL no peer certificate"));
  268 
  269     long v = SSL_get_verify_result(*ssl_h);
  270     if (v != X509_V_OK)
  271         set_error(gettext("SSL certificate validation failed: %s"), X509_verify_cert_error_string(v));
  272 
  273     if (got_sigquit)
  274         return -1;
  275 
  276     *ssl_handshake = get_ts() - dstart;
  277 
  278     if (set_fd_blocking(fd) == -1)
  279         return -1;
  280 
  281     return 0;
  282 }
  283 
  284 SSL_CTX * initialize_ctx(const char ask_compression, const char *ca_path)
  285 {
  286     const SSL_METHOD *meth = NULL;
  287     SSL_CTX *ctx = NULL;
  288 
  289     if (!bio_err)
  290     {
  291         SSL_library_init();
  292         SSL_load_error_strings();
  293         ERR_load_crypto_strings();
  294 
  295         /* error write context */
  296         bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
  297     }
  298 
  299     /* create context */
  300     meth = SSLv23_method();
  301     ctx = SSL_CTX_new(meth);
  302 
  303     if (ca_path == NULL)
  304 #if defined(__NetBSD__)
  305         ca_path = "/etc/openssl/certs";
  306 #else
  307         ca_path = "/etc/ssl/certs";
  308 #endif
  309 
  310     SSL_CTX_load_verify_locations(ctx, NULL, ca_path);
  311 
  312 #ifdef SSL_OP_NO_COMPRESSION
  313     if (!ask_compression)
  314         SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
  315 #endif
  316 
  317     return ctx;
  318 }
  319 
  320 char * get_fingerprint(SSL *const ssl_h)
  321 {
  322     char *string = NULL;
  323 
  324     unsigned char fp_digest[EVP_MAX_MD_SIZE];
  325     X509 *x509_data = SSL_get_peer_certificate(ssl_h);
  326 
  327     if (x509_data)
  328     {
  329         unsigned int fp_digest_size = sizeof fp_digest;
  330 
  331         memset(fp_digest, 0x00, fp_digest_size);
  332 
  333         if (X509_digest(x509_data, EVP_md5(), fp_digest, &fp_digest_size))
  334         {
  335             string = (char *)malloc(MD5_DIGEST_LENGTH * 3 + 1);
  336             if (string)
  337             {
  338                 int loop, pos =0;
  339 
  340                 for(loop=0; loop<MD5_DIGEST_LENGTH; loop++)
  341                 {
  342                     if (loop)
  343                         pos += sprintf(&string[pos], ":%02x", fp_digest[loop]);
  344                     else
  345                         pos = sprintf(&string[pos], "%02x", fp_digest[loop]);
  346                 }
  347             }
  348         }
  349 
  350         X509_free(x509_data);
  351     }
  352 
  353     return string;
  354 }
  355 
  356 int connect_ssl_proxy(const int fd, struct addrinfo *const ai, const double timeout, const char *const proxy_user, const char *const proxy_password, const char *const hostname, const int portnr, char *const tfo)
  357 {
  358     int rc = -1;
  359     char request_headers[4096] = { 0 };
  360     int request_headers_len = -1;
  361     char rh_sent = 0;
  362     char *response_headers = NULL, *code = NULL, *term = NULL;
  363 
  364     request_headers_len = snprintf(request_headers, sizeof request_headers, "CONNECT %s:%d HTTP/1.1\r\nUser-Agent: HTTPing v" VERSION \
  365             "\r\nProxy-Connection: keep-alive\r\nConnection: keep-alive\r\nHost: %s\r\n", hostname, portnr, hostname);
  366 
  367     if (proxy_user)
  368     {
  369         char ppa_string[256] = { 0 };
  370         char b64_ppa_string[512] = { 0 };
  371 
  372         sprintf(ppa_string, "%s:%s", proxy_user, proxy_password);
  373         enc_b64(ppa_string, strlen(ppa_string), b64_ppa_string);
  374         request_headers_len += snprintf(&request_headers[request_headers_len], sizeof request_headers - request_headers_len, "Proxy-Authorization: Basic %s\r\n", b64_ppa_string);
  375     }
  376 
  377     request_headers_len += snprintf(&request_headers[request_headers_len], sizeof request_headers - request_headers_len, "\r\n");
  378 
  379     if ((rc = connect_to(fd, ai, timeout, tfo, request_headers, request_headers_len, &rh_sent)) == -1)
  380         return rc;
  381 
  382     if (!rh_sent)
  383     {
  384         if ((rc = mywrite(fd, request_headers, request_headers_len, timeout)) < RC_OK)
  385         {
  386             set_error(gettext("Problem sending request to proxy"));
  387             return rc;
  388         }
  389     }
  390 
  391     rc = dumb_get_HTTP_headers(fd, &response_headers, timeout);
  392     if (rc != RC_OK)
  393     {
  394         free(response_headers);
  395         set_error(gettext("Problem retrieving proxy response"));
  396         return rc;
  397     }
  398 
  399     term = strchr(response_headers, '\r');
  400     if (!term)
  401         term = strchr(response_headers, '\n');
  402     if (term)
  403         *term = 0x00;
  404 
  405     code = strchr(response_headers, ' ');
  406     if (!code)
  407     {
  408         free(response_headers);
  409         set_error(gettext("Invalid proxy response headers"));
  410         return RC_INVAL;
  411     }
  412 
  413     if (atoi(code + 1) != 200)
  414     {
  415         free(response_headers);
  416         set_error(gettext("Proxy indicated error: %s"), code + 1);
  417         return RC_INVAL;
  418     }
  419 
  420     free(response_headers);
  421 
  422     return RC_OK;
  423 }