1 /*********************************************************************
3 * File : $Source: /cvsroot/ijbswa/current/ssl_common.c,v $
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.
9 * Copyright : Written by and Copyright (c) 2017 Vaclav Svec. FIT CVUT.
10 * Copyright (C) 2018-2021 by Fabian Keil <fk@fabiankeil.de>
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.
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.
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.
30 *********************************************************************/
40 #include "ssl_common.h"
43 * Macros for ssl_common.c
45 #define CERT_SERIAL_NUM_LENGTH 4 /* Bytes of hash to be used for creating serial number of certificate. Min=2 and max=16 */
47 /*********************************************************************
49 * Function : client_use_ssl
51 * Description : Tests if client in current client state structure
52 * should use SSL connection or standard connection.
55 * 1 : csp = Current client state (buffers, headers, etc...)
57 * Returns : If client should use TLS/SSL connection, 1 is returned.
58 * Otherwise 0 is returned.
60 *********************************************************************/
61 extern int client_use_ssl(const struct client_state *csp)
63 return csp->http->client_ssl;
67 /*********************************************************************
69 * Function : server_use_ssl
71 * Description : Tests if server in current client state structure
72 * should use SSL connection or standard connection.
75 * 1 : csp = Current client state (buffers, headers, etc...)
77 * Returns : If server should use TLS/SSL connection, 1 is returned.
78 * Otherwise 0 is returned.
80 *********************************************************************/
81 extern int server_use_ssl(const struct client_state *csp)
83 return csp->http->server_ssl;
87 /*********************************************************************
89 * Function : ssl_send_data_delayed
91 * Description : Sends the contents of buf (for n bytes) to given SSL
92 * connection, optionally delaying the operation.
95 * 1 : ssl_attr = SSL context to send data to
96 * 2 : buf = Pointer to data to be sent
97 * 3 : len = Length of data to be sent to the SSL context
98 * 4 : delay = Delay in milliseconds.
100 * Returns : 0 on success (entire buffer sent).
103 *********************************************************************/
104 extern int ssl_send_data_delayed(struct ssl_attr* ssl_attr,
105 const unsigned char *buf, size_t len,
112 if (ssl_send_data(ssl_attr, buf, len) < 0)
125 enum { MAX_WRITE_LENGTH = 10 };
127 if ((i + MAX_WRITE_LENGTH) > len)
129 write_length = len - i;
133 write_length = MAX_WRITE_LENGTH;
136 privoxy_millisleep(delay);
138 if (ssl_send_data(ssl_attr, buf + i, write_length) < 0)
150 /*********************************************************************
152 * Function : ssl_flush_socket
154 * Description : Send any pending "buffered" content with given
155 * SSL connection. Alternative to function flush_socket.
158 * 1 : ssl_attr = SSL context to send buffer to
159 * 2 : iob = The I/O buffer to flush, usually csp->iob.
161 * Returns : On success, the number of bytes send are returned (zero
162 * indicates nothing was sent). On error, -1 is returned.
164 *********************************************************************/
165 extern long ssl_flush_socket(struct ssl_attr *ssl_attr, struct iob *iob)
167 /* Computing length of buffer part to send */
168 long len = iob->eod - iob->cur;
175 /* Sending data to given SSl context */
176 if (ssl_send_data(ssl_attr, (const unsigned char *)iob->cur, (size_t)len) < 0)
180 iob->eod = iob->cur = iob->buf;
185 /*********************************************************************
187 * Function : close_client_and_server_ssl_connections
189 * Description : Checks if client or server should use secured
190 * connection over SSL and if so, closes all of them.
193 * 1 : csp = Current client state (buffers, headers, etc...)
197 *********************************************************************/
198 extern void close_client_and_server_ssl_connections(struct client_state *csp)
200 if (client_use_ssl(csp) == 1)
202 close_client_ssl_connection(csp);
204 if (server_use_ssl(csp) == 1)
206 close_server_ssl_connection(csp);
211 /*********************************************************************
213 * Function : tunnel_established_successfully
215 * Description : Check if parent proxy server response contains
216 * information about successfully created connection with
217 * destination server. (HTTP/... 2xx ...)
220 * 1 : server_response = Buffer with parent proxy server response
221 * 2 : response_len = Length of server_response
223 * Returns : 1 => Connection created successfully
224 * 0 => Connection wasn't created successfully
226 *********************************************************************/
227 extern int tunnel_established_successfully(const char *server_response,
228 unsigned int response_len)
230 unsigned int pos = 0;
232 if (server_response == NULL)
237 /* Tests if "HTTP/" string is at the begin of received response */
238 if (strncmp(server_response, "HTTP/", 5) != 0)
243 for (pos = 0; pos < response_len; pos++)
245 if (server_response[pos] == ' ')
252 * response_len -3 because of buffer end, response structure and 200 code.
253 * There must be at least 3 chars after space.
254 * End of buffer: ... 2xx'\0'
257 if (pos >= (response_len - 3))
262 /* Test HTTP status code */
263 if (server_response[pos + 1] != '2')
272 /*********************************************************************
274 * Function : free_certificate_chain
276 * Description : Frees certificates linked list. This linked list is
277 * used to save information about certificates in
281 * 1 : csp = Current client state (buffers, headers, etc...)
285 *********************************************************************/
286 extern void free_certificate_chain(struct client_state *csp)
288 struct certs_chain *cert = csp->server_certs_chain.next;
290 /* Cleaning buffers */
291 memset(csp->server_certs_chain.info_buf, 0,
292 sizeof(csp->server_certs_chain.info_buf));
293 freez(csp->server_certs_chain.file_buf);
295 csp->server_certs_chain.next = NULL;
297 /* Freeing memory in whole linked list */
300 struct certs_chain *cert_for_free = cert;
303 /* Cleaning buffers */
304 memset(cert_for_free->info_buf, 0, sizeof(cert_for_free->info_buf));
305 freez(cert_for_free->file_buf);
307 freez(cert_for_free);
312 /*********************************************************************
314 * Function : ssl_send_certificate_error
316 * Description : Sends info about invalid server certificate to client.
317 * Sent message is including all trusted chain certificates,
318 * that can be downloaded in web browser.
321 * 1 : csp = Current client state (buffers, headers, etc...)
325 *********************************************************************/
326 extern void ssl_send_certificate_error(struct client_state *csp)
328 struct ssl_attr *ssl_attr = &csp->ssl_client_attr;
329 size_t message_len = 0;
331 struct certs_chain *cert = NULL;
332 const size_t head_length = 63;
334 /* Header of message with certificate information */
335 const char message_begin[] =
336 "HTTP/1.1 403 Certificate validation failed\r\n"
337 "Content-Type: text/html\r\n"
338 "Connection: close\r\n\r\n"
340 "<html><head><title>Server certificate verification failed</title></head>\n"
341 "<body><h1>Server certificate verification failed</h1>\n"
342 "<p><a href=\"https://" CGI_SITE_2_HOST "/\">Privoxy</a> was unable "
343 "to securely connect to the destination server.</p>"
345 const char message_end[] = "</body></html>\n";
346 char reason[INVALID_CERT_INFO_BUF_SIZE];
347 memset(reason, 0, sizeof(reason));
349 /* Get verification message from verification return code */
350 ssl_crt_verify_info(reason, sizeof(reason), csp);
353 * Computing total length of message with all certificates inside
355 message_len = strlen(message_begin) + strlen(message_end)
356 + strlen(reason) + strlen("</p>") + 1;
358 cert = &(csp->server_certs_chain);
359 while (cert->next != NULL)
363 if (cert->file_buf != NULL)
365 base64_len = 4 * ((strlen(cert->file_buf) + 2) / 3) + 1;
367 message_len += strlen(cert->info_buf) + strlen("<pre></pre>\n")
368 + base64_len + strlen("<a href=\"data:application"
369 "/x-x509-ca-cert;base64,\">Download certificate</a>");
373 log_error(LOG_LEVEL_ERROR,
374 "Incomplete certificate information for %s.",
375 csp->http->hostport);
381 * Joining all blocks in one long message
383 char message[message_len];
384 memset(message, 0, message_len);
386 strlcpy(message, message_begin, message_len);
387 strlcat(message, reason , message_len);
388 strlcat(message, "</p>" , message_len);
390 cert = &(csp->server_certs_chain);
391 while (cert->next != NULL)
393 if (cert->file_buf != NULL)
395 /* +1 for terminating null */
396 size_t base64_len = 4 * ((strlen(cert->file_buf) + 2) / 3) + 1;
398 char base64_buf[base64_len];
400 memset(base64_buf, 0, base64_len);
402 /* Encoding certificate into base64 code */
403 ret = ssl_base64_encode((unsigned char*)base64_buf,
404 base64_len, &olen, (const unsigned char*)cert->file_buf,
405 strlen(cert->file_buf));
408 log_error(LOG_LEVEL_ERROR,
409 "Encoding to base64 failed, buffer is to small");
412 strlcat(message, "<pre>", message_len);
413 strlcat(message, cert->info_buf, message_len);
414 strlcat(message, "</pre>\n", message_len);
418 strlcat(message, "<a href=\"data:application/x-x509-ca-cert;base64,",
420 strlcat(message, base64_buf, message_len);
421 strlcat(message, "\">Download certificate</a>", message_len);
427 strlcat(message, message_end, message_len);
429 if (0 == strcmpic(csp->http->gpc, "HEAD"))
432 char *header_end = strstr(message, "\r\n\r\n");
433 if (header_end != NULL)
435 header_end[3] = '\0';
440 * Sending final message to client
442 (void)ssl_send_data(ssl_attr, (const unsigned char *)message, strlen(message));
444 free_certificate_chain(csp);
446 log_error(LOG_LEVEL_CRUNCH, "Certificate error: %s: https://%s%s",
447 reason, csp->http->hostport, csp->http->path);
448 log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s https://%s%s %s\" 403 %lu",
449 csp->ip_addr_str, csp->http->gpc, csp->http->hostport, csp->http->path,
450 csp->http->version, message_len-head_length);
452 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
453 csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
454 csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED;
459 /*********************************************************************
461 * Function : file_exists
463 * Description : Tests if file exists and is readable.
466 * 1 : path = Path to tested file.
468 * Returns : 1 => File exists and is readable.
469 * 0 => File doesn't exist or is not readable.
471 *********************************************************************/
472 extern int file_exists(const char *path)
475 if ((f = fopen(path, "r")) != NULL)
485 /*********************************************************************
487 * Function : make_certs_path
489 * Description : Creates path to file from three pieces. This function
490 * takes parameters and puts them in one new mallocated
491 * char * in correct order. Returned variable must be freed
492 * by caller. This function is mainly used for creating
493 * paths of certificates and keys files.
496 * 1 : conf_dir = Name/path of directory where is the file.
497 * '.' can be used for current directory.
498 * 2 : file_name = Name of file in conf_dir without suffix.
499 * 3 : suffix = Suffix of given file_name.
501 * Returns : path => Path was built up successfully
502 * NULL => Path can't be built up
504 *********************************************************************/
505 extern char *make_certs_path(const char *conf_dir, const char *file_name,
508 /* Test if all given parameters are valid */
509 if (conf_dir == NULL || *conf_dir == '\0' || file_name == NULL ||
510 *file_name == '\0' || suffix == NULL || *suffix == '\0')
512 log_error(LOG_LEVEL_ERROR,
513 "make_certs_path failed: bad input parameters");
518 size_t path_size = strlen(conf_dir)
519 + strlen(file_name) + strlen(suffix) + 2;
521 /* Setting delimiter and editing path length */
525 #else /* ifndef _WIN32 */
527 #endif /* ifndef _WIN32 */
530 * Building up path from many parts
533 if (*conf_dir != '/' && basedir && *basedir)
536 * Replacing conf_dir with basedir. This new variable contains
537 * absolute path to cwd.
539 path_size += strlen(basedir) + 2;
540 path = zalloc_or_die(path_size);
542 strlcpy(path, basedir, path_size);
543 strlcat(path, delim, path_size);
544 strlcat(path, conf_dir, path_size);
545 strlcat(path, delim, path_size);
546 strlcat(path, file_name, path_size);
547 strlcat(path, suffix, path_size);
550 #endif /* defined unix */
552 path = zalloc_or_die(path_size);
554 strlcpy(path, conf_dir, path_size);
555 strlcat(path, delim, path_size);
556 strlcat(path, file_name, path_size);
557 strlcat(path, suffix, path_size);
564 /*********************************************************************
566 * Function : get_certificate_serial
568 * Description : Computes serial number for new certificate from host
569 * name hash. This hash must be already saved in csp
573 * 1 : csp = Current client state (buffers, headers, etc...)
575 * Returns : Serial number for new certificate
577 *********************************************************************/
578 extern unsigned long get_certificate_serial(struct client_state *csp)
580 unsigned long exp = 1;
581 unsigned long serial = 0;
583 int i = CERT_SERIAL_NUM_LENGTH;
587 serial += exp * (unsigned)csp->http->hash_of_host[i];
594 /*********************************************************************
596 * Function : generate_certificate_valid_date
598 * Description : Turns a time_t into the format expected by mbedTLS.
601 * 1 : time_spec = The timestamp to convert
602 * 2 : buffer = The buffer to write the date to
603 * 3 : buffer_size = The size of the buffer
606 * Returns : 0 => The conversion worked
607 * 1 => The conversion failed
609 *********************************************************************/
610 static int generate_certificate_valid_date(time_t time_spec, char *buffer,
611 size_t buffer_size, const char *fmt)
613 struct tm valid_date;
617 timeptr = privoxy_gmtime_r(&time_spec, &valid_date);
623 ret = strftime(buffer, buffer_size, fmt, timeptr);
634 /*********************************************************************
636 * Function : get_certificate_valid_from_date
638 * Description : Generates a "valid from" date in the format
639 * expected by mbedTLS.
642 * 1 : buffer = The buffer to write the date to
643 * 2 : buffer_size = The size of the buffer
646 * Returns : 0 => The generation worked
647 * 1 => The generation failed
649 *********************************************************************/
650 extern int get_certificate_valid_from_date(char *buffer, size_t buffer_size, const char *fmt)
654 time_spec = time(NULL);
655 /* 1 month in the past */
656 time_spec -= 30 * 24 * 60 * 60;
658 return generate_certificate_valid_date(time_spec, buffer, buffer_size, fmt);
663 /*********************************************************************
665 * Function : get_certificate_valid_to_date
667 * Description : Generates a "valid to" date in the format
668 * expected by mbedTLS.
671 * 1 : buffer = The buffer to write the date to
672 * 2 : buffer_size = The size of the buffer
675 * Returns : 0 => The generation worked
676 * 1 => The generation failed
678 *********************************************************************/
679 extern int get_certificate_valid_to_date(char *buffer, size_t buffer_size, const char *fmt)
683 time_spec = time(NULL);
684 /* Three months in the future */
685 time_spec += 90 * 24 * 60 * 60;
687 return generate_certificate_valid_date(time_spec, buffer, buffer_size, fmt);
692 /*********************************************************************
694 * Function : enforce_sane_certificate_state
696 * Description : Makes sure the certificate state is sane.
699 * 1 : certificate = Path to the potentionally existing certifcate.
700 * 2 : key = Path to the potentionally existing key.
702 * Returns : -1 => Error
703 * 0 => Certificate state is sane
705 *********************************************************************/
706 extern int enforce_sane_certificate_state(const char *certificate, const char *key)
708 const int certificate_exists = file_exists(certificate);
709 const int key_exists = file_exists(key);
711 if (!certificate_exists && key_exists)
713 log_error(LOG_LEVEL_ERROR,
714 "A website key already exists but there's no matching certificate. "
715 "Removing %s before creating a new key and certificate.", key);
718 log_error(LOG_LEVEL_ERROR, "Failed to unlink %s: %E", key);
723 if (certificate_exists && !key_exists)
725 log_error(LOG_LEVEL_ERROR,
726 "A certificate exists but there's no matching key. "
727 "Removing %s before creating a new key and certificate.", certificate);
728 if (unlink(certificate))
730 log_error(LOG_LEVEL_ERROR, "Failed to unlink %s: %E", certificate);