ssl_send_certificate_error(): Cast ssl_send_data() return code to void
[privoxy.git] / ssl_common.c
1 /*********************************************************************
2  *
3  * File        :  $Source: /cvsroot/ijbswa/current/ssl_common.c,v $
4  *
5  * Purpose     :  File with TLS/SSL extension. Contains methods for
6  *                creating, using and closing TLS/SSL connections that do
7  *                not depend on particular TLS/SSL library.
8  *
9  * Copyright   :  Written by and Copyright (c) 2017 Vaclav Svec. FIT CVUT.
10  *                Copyright (C) 2018-2020 by Fabian Keil <fk@fabiankeil.de>
11  *
12  *                This program is free software; you can redistribute it
13  *                and/or modify it under the terms of the GNU General
14  *                Public License as published by the Free Software
15  *                Foundation; either version 2 of the License, or (at
16  *                your option) any later version.
17  *
18  *                This program is distributed in the hope that it will
19  *                be useful, but WITHOUT ANY WARRANTY; without even the
20  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
21  *                PARTICULAR PURPOSE.  See the GNU General Public
22  *                License for more details.
23  *
24  *                The GNU General Public License should be included with
25  *                this file.  If not, you can view it at
26  *                http://www.gnu.org/copyleft/gpl.html
27  *                or write to the Free Software Foundation, Inc., 59
28  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29  *
30  *********************************************************************/
31 #include <string.h>
32
33 #include <ctype.h>
34 #include "config.h"
35 #include "project.h"
36 #include "miscutil.h"
37 #include "errlog.h"
38 #include "ssl.h"
39 #include "ssl_common.h"
40
41 /*
42  * Macros for ssl_common.c
43  */
44 #define CERT_SERIAL_NUM_LENGTH           4                 /* Bytes of hash to be used for creating serial number of certificate. Min=2 and max=16 */
45
46 /*********************************************************************
47  *
48  * Function    :  client_use_ssl
49  *
50  * Description :  Tests if client in current client state structure
51  *                should use SSL connection or standard connection.
52  *
53  * Parameters  :
54  *          1  :  csp = Current client state (buffers, headers, etc...)
55  *
56  * Returns     :  If client should use TLS/SSL connection, 1 is returned.
57  *                Otherwise 0 is returned.
58  *
59  *********************************************************************/
60 extern int client_use_ssl(const struct client_state *csp)
61 {
62    return csp->http->client_ssl;
63 }
64
65
66 /*********************************************************************
67  *
68  * Function    :  server_use_ssl
69  *
70  * Description :  Tests if server in current client state structure
71  *                should use SSL connection or standard connection.
72  *
73  * Parameters  :
74  *          1  :  csp = Current client state (buffers, headers, etc...)
75  *
76  * Returns     :  If server should use TLS/SSL connection, 1 is returned.
77  *                Otherwise 0 is returned.
78  *
79  *********************************************************************/
80 extern int server_use_ssl(const struct client_state *csp)
81 {
82    return csp->http->server_ssl;
83 }
84
85
86 /*********************************************************************
87  *
88  * Function    :  ssl_send_data_delayed
89  *
90  * Description :  Sends the contents of buf (for n bytes) to given SSL
91  *                connection, optionally delaying the operation.
92  *
93  * Parameters  :
94  *          1  :  ssl_attr = SSL context to send data to
95  *          2  :  buf = Pointer to data to be sent
96  *          3  :  len = Length of data to be sent to the SSL context
97  *          4  :  delay = Delay in milliseconds.
98  *
99  * Returns     :  0 on success (entire buffer sent).
100  *                nonzero on error.
101  *
102  *********************************************************************/
103 extern int ssl_send_data_delayed(struct ssl_attr* ssl_attr,
104                                  const unsigned char *buf, size_t len,
105                                  unsigned int delay)
106 {
107    size_t i = 0;
108
109    if (delay == 0)
110    {
111       if (ssl_send_data(ssl_attr, buf, len) < 0)
112       {
113          return -1;
114       }
115       else
116       {
117          return 0;
118       }
119    }
120
121    while (i < len)
122    {
123       size_t write_length;
124       enum { MAX_WRITE_LENGTH = 10 };
125
126       if ((i + MAX_WRITE_LENGTH) > len)
127       {
128          write_length = len - i;
129       }
130       else
131       {
132          write_length = MAX_WRITE_LENGTH;
133       }
134
135       privoxy_millisleep(delay);
136
137       if (ssl_send_data(ssl_attr, buf + i, write_length) < 0)
138       {
139          return -1;
140       }
141       i += write_length;
142    }
143
144    return 0;
145
146 }
147
148
149 /*********************************************************************
150  *
151  * Function    :  ssl_flush_socket
152  *
153  * Description :  Send any pending "buffered" content with given
154  *                SSL connection. Alternative to function flush_socket.
155  *
156  * Parameters  :
157  *          1  :  ssl_attr = SSL context to send buffer to
158  *          2  :  iob = The I/O buffer to flush, usually csp->iob.
159  *
160  * Returns     :  On success, the number of bytes send are returned (zero
161  *                indicates nothing was sent).  On error, -1 is returned.
162  *
163  *********************************************************************/
164 extern long ssl_flush_socket(struct ssl_attr *ssl_attr, struct iob *iob)
165 {
166    /* Computing length of buffer part to send */
167    long len = iob->eod - iob->cur;
168
169    if (len <= 0)
170    {
171       return(0);
172    }
173
174    /* Sending data to given SSl context */
175    if (ssl_send_data(ssl_attr, (const unsigned char *)iob->cur, (size_t)len) < 0)
176    {
177       return -1;
178    }
179    iob->eod = iob->cur = iob->buf;
180    return(len);
181 }
182
183
184 /*********************************************************************
185  *
186  * Function    :  close_client_and_server_ssl_connections
187  *
188  * Description :  Checks if client or server should use secured
189  *                connection over SSL and if so, closes all of them.
190  *
191  * Parameters  :
192  *          1  :  csp = Current client state (buffers, headers, etc...)
193  *
194  * Returns     :  N/A
195  *
196  *********************************************************************/
197 extern void close_client_and_server_ssl_connections(struct client_state *csp)
198 {
199    if (client_use_ssl(csp) == 1)
200    {
201       close_client_ssl_connection(csp);
202    }
203    if (server_use_ssl(csp) == 1)
204    {
205       close_server_ssl_connection(csp);
206    }
207 }
208
209
210 /*********************************************************************
211  *
212  * Function    :  tunnel_established_successfully
213  *
214  * Description :  Check if parent proxy server response contains
215  *                information about successfully created connection with
216  *                destination server. (HTTP/... 2xx ...)
217  *
218  * Parameters  :
219  *          1  :  server_response = Buffer with parent proxy server response
220  *          2  :  response_len = Length of server_response
221  *
222  * Returns     :  1 => Connection created successfully
223  *                0 => Connection wasn't created successfully
224  *
225  *********************************************************************/
226 extern int tunnel_established_successfully(const char *server_response,
227    unsigned int response_len)
228 {
229    unsigned int pos = 0;
230
231    if (server_response == NULL)
232    {
233       return 0;
234    }
235
236    /* Tests if "HTTP/" string is at the begin of received response */
237    if (strncmp(server_response, "HTTP/", 5) != 0)
238    {
239       return 0;
240    }
241
242    for (pos = 0; pos < response_len; pos++)
243    {
244       if (server_response[pos] == ' ')
245       {
246          break;
247       }
248    }
249
250    /*
251     * response_len -3 because of buffer end, response structure and 200 code.
252     * There must be at least 3 chars after space.
253     * End of buffer: ... 2xx'\0'
254     *             pos = |
255     */
256    if (pos >= (response_len - 3))
257    {
258       return 0;
259    }
260
261    /* Test HTTP status code */
262    if (server_response[pos + 1] != '2')
263    {
264       return 0;
265    }
266
267    return 1;
268 }
269
270
271 /*********************************************************************
272  *
273  * Function    :  free_certificate_chain
274  *
275  * Description :  Frees certificates linked list. This linked list is
276  *                used to save information about certificates in
277  *                trusted chain.
278  *
279  * Parameters  :
280  *          1  :  csp = Current client state (buffers, headers, etc...)
281  *
282  * Returns     :  N/A
283  *
284  *********************************************************************/
285 extern void free_certificate_chain(struct client_state *csp)
286 {
287    struct certs_chain *cert = csp->server_certs_chain.next;
288
289    /* Cleaning buffers */
290    memset(csp->server_certs_chain.info_buf, 0,
291       sizeof(csp->server_certs_chain.info_buf));
292    memset(csp->server_certs_chain.file_buf, 0,
293       sizeof(csp->server_certs_chain.file_buf));
294    csp->server_certs_chain.next = NULL;
295
296    /* Freeing memory in whole linked list */
297    while (cert != NULL)
298    {
299       struct certs_chain *cert_for_free = cert;
300       cert = cert->next;
301       freez(cert_for_free);
302    }
303 }
304
305
306 /*********************************************************************
307  *
308  * Function    :  ssl_send_certificate_error
309  *
310  * Description :  Sends info about invalid server certificate to client.
311  *                Sent message is including all trusted chain certificates,
312  *                that can be downloaded in web browser.
313  *
314  * Parameters  :
315  *          1  :  csp = Current client state (buffers, headers, etc...)
316  *
317  * Returns     :  N/A
318  *
319  *********************************************************************/
320 extern void ssl_send_certificate_error(struct client_state *csp)
321 {
322    struct ssl_attr *ssl_attr = &csp->ssl_client_attr;
323    size_t message_len = 0;
324    int ret = 0;
325    struct certs_chain *cert = NULL;
326    const size_t head_length = 63;
327
328    /* Header of message with certificate information */
329    const char message_begin[] =
330       "HTTP/1.1 200 OK\r\n"
331       "Content-Type: text/html\r\n"
332       "Connection: close\r\n\r\n"
333       "<!DOCTYPE html>\n"
334       "<html><head><title>Server certificate verification failed</title></head>\n"
335       "<body><h1>Server certificate verification failed</h1>\n"
336       "<p><a href=\"https://" CGI_SITE_2_HOST "/\">Privoxy</a> was unable "
337       "to securely connect to the destination server.</p>"
338       "<p>Reason: ";
339    const char message_end[] = "</body></html>\r\n\r\n";
340    char reason[INVALID_CERT_INFO_BUF_SIZE];
341    memset(reason, 0, sizeof(reason));
342
343    /* Get verification message from verification return code */
344    ssl_crt_verify_info(reason, sizeof(reason), csp);
345
346    /*
347     * Computing total length of message with all certificates inside
348     */
349    message_len = strlen(message_begin) + strlen(message_end)
350                  + strlen(reason) + strlen("</p>") + 1;
351
352    cert = &(csp->server_certs_chain);
353    while (cert->next != NULL)
354    {
355       size_t base64_len = 4 * ((strlen(cert->file_buf) + 2) / 3) + 1;
356
357       message_len += strlen(cert->info_buf) + strlen("<pre></pre>\n")
358                      +  base64_len + strlen("<a href=\"data:application"
359                         "/x-x509-ca-cert;base64,\">Download certificate</a>");
360       cert = cert->next;
361    }
362
363    /*
364     * Joining all blocks in one long message
365     */
366    char message[message_len];
367    memset(message, 0, message_len);
368
369    strlcpy(message, message_begin, message_len);
370    strlcat(message, reason       , message_len);
371    strlcat(message, "</p>"       , message_len);
372
373    cert = &(csp->server_certs_chain);
374    while (cert->next != NULL)
375    {
376       size_t olen = 0;
377       size_t base64_len = 4 * ((strlen(cert->file_buf) + 2) / 3) + 1; /* +1 for terminating null*/
378       char base64_buf[base64_len];
379       memset(base64_buf, 0, base64_len);
380
381       /* Encoding certificate into base64 code */
382       ret = ssl_base64_encode((unsigned char*)base64_buf,
383                base64_len, &olen, (const unsigned char*)cert->file_buf,
384                strlen(cert->file_buf));
385       if (ret != 0)
386       {
387          log_error(LOG_LEVEL_ERROR,
388             "Encoding to base64 failed, buffer is to small");
389       }
390
391       strlcat(message, "<pre>",        message_len);
392       strlcat(message, cert->info_buf, message_len);
393       strlcat(message, "</pre>\n",     message_len);
394
395       if (ret == 0)
396       {
397          strlcat(message, "<a href=\"data:application/x-x509-ca-cert;base64,",
398             message_len);
399          strlcat(message, base64_buf, message_len);
400          strlcat(message, "\">Download certificate</a>", message_len);
401       }
402
403       cert = cert->next;
404    }
405    strlcat(message, message_end, message_len);
406
407    /*
408     * Sending final message to client
409     */
410    (void)ssl_send_data(ssl_attr, (const unsigned char *)message, strlen(message));
411
412    free_certificate_chain(csp);
413
414    log_error(LOG_LEVEL_CRUNCH, "Certificate error: %s: https://%s%s",
415       reason, csp->http->hostport, csp->http->path);
416    log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s https://%s%s %s\" 200 %lu",
417       csp->ip_addr_str, csp->http->gpc, csp->http->hostport, csp->http->path,
418       csp->http->version, message_len-head_length);
419
420 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
421    csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
422    csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED;
423 #endif
424 }
425
426
427 /*********************************************************************
428  *
429  * Function    :  file_exists
430  *
431  * Description :  Tests if file exists and is readable.
432  *
433  * Parameters  :
434  *          1  :  path = Path to tested file.
435  *
436  * Returns     :  1 => File exists and is readable.
437  *                0 => File doesn't exist or is not readable.
438  *
439  *********************************************************************/
440 extern int file_exists(const char *path)
441 {
442    FILE *f;
443    if ((f = fopen(path, "r")) != NULL)
444    {
445       fclose(f);
446       return 1;
447    }
448
449    return 0;
450 }
451
452
453 /*********************************************************************
454  *
455  * Function    :  make_certs_path
456  *
457  * Description : Creates path to file from three pieces. This function
458  *               takes parameters and puts them in one new mallocated
459  *               char * in correct order. Returned variable must be freed
460  *               by caller. This function is mainly used for creating
461  *               paths of certificates and keys files.
462  *
463  * Parameters  :
464  *          1  :  conf_dir  = Name/path of directory where is the file.
465  *                            '.' can be used for current directory.
466  *          2  :  file_name = Name of file in conf_dir without suffix.
467  *          3  :  suffix    = Suffix of given file_name.
468  *
469  * Returns     :  path => Path was built up successfully
470  *                NULL => Path can't be built up
471  *
472  *********************************************************************/
473 extern char *make_certs_path(const char *conf_dir, const char *file_name,
474    const char *suffix)
475 {
476    /* Test if all given parameters are valid */
477    if (conf_dir == NULL || *conf_dir == '\0' || file_name == NULL ||
478       *file_name == '\0' || suffix == NULL || *suffix == '\0')
479    {
480       log_error(LOG_LEVEL_ERROR,
481          "make_certs_path failed: bad input parameters");
482       return NULL;
483    }
484
485    char *path = NULL;
486    size_t path_size = strlen(conf_dir)
487       + strlen(file_name) + strlen(suffix) + 2;
488
489    /* Setting delimiter and editing path length */
490 #if defined(_WIN32)
491    char delim[] = "\\";
492    path_size += 1;
493 #else /* ifndef _WIN32 */
494    char delim[] = "/";
495 #endif /* ifndef _WIN32 */
496
497    /*
498     * Building up path from many parts
499     */
500 #if defined(unix)
501    if (*conf_dir != '/' && basedir && *basedir)
502    {
503       /*
504        * Replacing conf_dir with basedir. This new variable contains
505        * absolute path to cwd.
506        */
507       path_size += strlen(basedir) + 2;
508       path = zalloc_or_die(path_size);
509
510       strlcpy(path, basedir,   path_size);
511       strlcat(path, delim,     path_size);
512       strlcat(path, conf_dir,  path_size);
513       strlcat(path, delim,     path_size);
514       strlcat(path, file_name, path_size);
515       strlcat(path, suffix,    path_size);
516    }
517    else
518 #endif /* defined unix */
519    {
520       path = zalloc_or_die(path_size);
521
522       strlcpy(path, conf_dir,  path_size);
523       strlcat(path, delim,     path_size);
524       strlcat(path, file_name, path_size);
525       strlcat(path, suffix,    path_size);
526    }
527
528    return path;
529 }
530
531
532 /*********************************************************************
533  *
534  * Function    :  get_certificate_serial
535  *
536  * Description :  Computes serial number for new certificate from host
537  *                name hash. This hash must be already saved in csp
538  *                structure.
539  *
540  * Parameters  :
541  *          1  :  csp = Current client state (buffers, headers, etc...)
542  *
543  * Returns     :  Serial number for new certificate
544  *
545  *********************************************************************/
546 extern unsigned long get_certificate_serial(struct client_state *csp)
547 {
548    unsigned long exp    = 1;
549    unsigned long serial = 0;
550
551    int i = CERT_SERIAL_NUM_LENGTH;
552
553    for (; i >= 0; i--)
554    {
555       serial += exp * (unsigned)csp->http->hash_of_host[i];
556       exp *= 256;
557    }
558    return serial;
559 }
560
561
562 /*********************************************************************
563  *
564  * Function    :  generate_certificate_valid_date
565  *
566  * Description :  Turns a time_t into the format expected by mbedTLS.
567  *
568  * Parameters  :
569  *          1  :  time_spec = The timestamp to convert
570  *          2  :  buffer = The buffer to write the date to
571  *          3  :  buffer_size = The size of the buffer
572  *          4  :  fmt = format
573  *
574  * Returns     :   0 => The conversion worked
575  *                 1 => The conversion failed
576  *
577  *********************************************************************/
578 static int generate_certificate_valid_date(time_t time_spec, char *buffer,
579                                            size_t buffer_size, const char *fmt)
580 {
581    struct tm valid_date;
582    struct tm *timeptr;
583    size_t ret;
584
585    timeptr = privoxy_gmtime_r(&time_spec, &valid_date);
586    if (NULL == timeptr)
587    {
588       return 1;
589    }
590
591    ret = strftime(buffer, buffer_size, fmt, timeptr);
592    if (ret <= 0)
593    {
594       return 1;
595    }
596
597    return 0;
598
599 }
600
601
602 /*********************************************************************
603  *
604  * Function    :  get_certificate_valid_from_date
605  *
606  * Description :  Generates a "valid from" date in the format
607  *                expected by mbedTLS.
608  *
609  * Parameters  :
610  *          1  :  buffer = The buffer to write the date to
611  *          2  :  buffer_size = The size of the buffer
612  *          3  :  fmt = format
613  *
614  * Returns     :   0 => The generation worked
615  *                 1 => The generation failed
616  *
617  *********************************************************************/
618 extern int get_certificate_valid_from_date(char *buffer, size_t buffer_size, const char *fmt)
619 {
620    time_t time_spec;
621
622    time_spec = time(NULL);
623    /* 1 month in the past */
624    time_spec -= 30 * 24 * 60 * 60;
625
626    return generate_certificate_valid_date(time_spec, buffer, buffer_size, fmt);
627
628 }
629
630
631 /*********************************************************************
632  *
633  * Function    :  get_certificate_valid_to_date
634  *
635  * Description :  Generates a "valid to" date in the format
636  *                expected by mbedTLS.
637  *
638  * Parameters  :
639  *          1  :  buffer = The buffer to write the date to
640  *          2  :  buffer_size = The size of the buffer
641  *          3  :  fmt = format
642  *
643  * Returns     :   0 => The generation worked
644  *                 1 => The generation failed
645  *
646  *********************************************************************/
647 extern int get_certificate_valid_to_date(char *buffer, size_t buffer_size, const char *fmt)
648 {
649    time_t time_spec;
650
651    time_spec = time(NULL);
652    /* Three months in the future */
653    time_spec += 90 * 24 * 60 * 60;
654
655    return generate_certificate_valid_date(time_spec, buffer, buffer_size, fmt);
656
657 }
658
659
660 /*********************************************************************
661  *
662  * Function    :  host_is_ip_address
663  *
664  * Description :  Checks whether or not a host is specified by
665  *                IP address. Does not actually validate the
666  *                address.
667  *
668  * Parameters  :
669  *          1  :  host = The host name to check
670  *
671  * Returns     :   1 => Yes
672  *                 0 => No
673  *
674  *********************************************************************/
675 extern int host_is_ip_address(const char *host)
676 {
677    const char *p;
678
679    if (NULL != strstr(host, ":"))
680    {
681       /* Assume an IPv6 address. */
682       return 1;
683    }
684
685    for (p = host; *p; p++)
686    {
687       if ((*p != '.') && !privoxy_isdigit(*p))
688       {
689          /* Not a dot or digit so it can't be an IPv4 address. */
690          return 0;
691       }
692    }
693
694    /*
695     * Host only consists of dots and digits so
696     * assume that is an IPv4 address.
697     */
698    return 1;
699
700 }