X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=ssl.c;h=0bb549bff7652bf5fc47753b9d3aa1488a644740;hp=649b301d0e890d1d24dd79ed15c6b0a486315b43;hb=b40487eec42668166a0dd9feb10626a03faea635;hpb=5740519e561441eb4addaf571ffbf2e3da74c997 diff --git a/ssl.c b/ssl.c index 649b301d..0bb549bf 100644 --- a/ssl.c +++ b/ssl.c @@ -41,6 +41,8 @@ #include "mbedtls/pem.h" #include "mbedtls/base64.h" #include "mbedtls/error.h" +#include "mbedtls/oid.h" +#include "mbedtls/asn1write.h" #include "config.h" #include "project.h" @@ -48,6 +50,7 @@ #include "errlog.h" #include "jcc.h" #include "ssl.h" +#include "encode.h" /* @@ -160,7 +163,10 @@ extern int server_use_ssl(const struct client_state *csp) * * Function : is_ssl_pending * - * Description : Tests if there are some waiting data on ssl connection + * Description : Tests if there are some waiting data on ssl connection. + * Only considers data that has actually been received + * locally and ignores data that is still on the fly + * or has not yet been sent by the remote end. * * Parameters : * 1 : ssl = SSL context to test @@ -646,7 +652,7 @@ static void free_client_ssl_structures(struct client_state *csp) { /* * We can't use function mbedtls_net_free, because this function - * inter alia close TCP connection on setted fd. Instead of this + * inter alia close TCP connection on set fd. Instead of this * function, we change fd to -1, which is the same what does * rest of mbedtls_net_free function. */ @@ -826,6 +832,7 @@ extern int create_server_ssl_connection(struct client_state *csp) { log_error(LOG_LEVEL_ERROR, "mbedtls_ssl_handshake with server failed: %s", err_buf); + free_certificate_chain(csp); ret = -1; } goto exit; @@ -905,7 +912,7 @@ static void free_server_ssl_structures(struct client_state *csp) { /* * We can't use function mbedtls_net_free, because this function - * inter alia close TCP connection on setted fd. Instead of this + * inter alia close TCP connection on set fd. Instead of this * function, we change fd to -1, which is the same what does * rest of mbedtls_net_free function. */ @@ -1344,6 +1351,112 @@ static int get_certificate_valid_to_date(char *buffer, size_t buffer_size) } +/********************************************************************* + * + * Function : set_subject_alternative_name + * + * Description : Sets the Subject Alternative Name extension to a cert + * + * Parameters : + * 1 : cert = The certificate to modify + * 2 : hostname = The hostname to add + * + * Returns : <0 => Error while creating certificate. + * 0 => It worked + * + *********************************************************************/ +static int set_subject_alternative_name(mbedtls_x509write_cert *cert, const char *hostname) +{ + char err_buf[ERROR_BUF_SIZE]; + int ret; + char *subject_alternative_name; + size_t subject_alternative_name_len; +#define MBEDTLS_SUBJECT_ALTERNATIVE_NAME_MAX_LEN 255 + unsigned char san_buf[MBEDTLS_SUBJECT_ALTERNATIVE_NAME_MAX_LEN + 1]; + unsigned char *c; + int len; + + subject_alternative_name_len = strlen(hostname) + 1; + subject_alternative_name = zalloc_or_die(subject_alternative_name_len); + + strlcpy(subject_alternative_name, hostname, subject_alternative_name_len); + + memset(san_buf, 0, sizeof(san_buf)); + + c = san_buf + sizeof(san_buf); + len = 0; + + ret = mbedtls_asn1_write_raw_buffer(&c, san_buf, + (const unsigned char *)subject_alternative_name, + strlen(subject_alternative_name)); + if (ret < 0) + { + mbedtls_strerror(ret, err_buf, sizeof(err_buf)); + log_error(LOG_LEVEL_ERROR, + "mbedtls_asn1_write_raw_buffer() failed: %s", err_buf); + goto exit; + } + len += ret; + + ret = mbedtls_asn1_write_len(&c, san_buf, strlen(subject_alternative_name)); + if (ret < 0) + { + mbedtls_strerror(ret, err_buf, sizeof(err_buf)); + log_error(LOG_LEVEL_ERROR, + "mbedtls_asn1_write_len() failed: %s", err_buf); + goto exit; + } + len += ret; + + ret = mbedtls_asn1_write_tag(&c, san_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2); + if (ret < 0) + { + mbedtls_strerror(ret, err_buf, sizeof(err_buf)); + log_error(LOG_LEVEL_ERROR, + "mbedtls_asn1_write_tag() failed: %s", err_buf); + goto exit; + } + len += ret; + + ret = mbedtls_asn1_write_len(&c, san_buf, (size_t)len); + if (ret < 0) + { + mbedtls_strerror(ret, err_buf, sizeof(err_buf)); + log_error(LOG_LEVEL_ERROR, + "mbedtls_asn1_write_len() failed: %s", err_buf); + goto exit; + } + len += ret; + + ret = mbedtls_asn1_write_tag(&c, san_buf, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); + if (ret < 0) + { + mbedtls_strerror(ret, err_buf, sizeof(err_buf)); + log_error(LOG_LEVEL_ERROR, + "mbedtls_asn1_write_tag() failed: %s", err_buf); + goto exit; + } + len += ret; + + ret = mbedtls_x509write_crt_set_extension(cert, + MBEDTLS_OID_SUBJECT_ALT_NAME, + MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME), + 0, san_buf + sizeof(san_buf) - len, (size_t)len); + if (ret < 0) + { + mbedtls_strerror(ret, err_buf, sizeof(err_buf)); + log_error(LOG_LEVEL_ERROR, + "mbedtls_x509write_crt_set_extension() failed: %s", err_buf); + } + +exit: + freez(subject_alternative_name); + + return ret; + +} + /********************************************************************* * * Function : generate_webpage_certificate @@ -1719,6 +1832,13 @@ static int generate_webpage_certificate(struct client_state *csp) } #endif /* MBEDTLS_SHA1_C */ + if (set_subject_alternative_name(&cert, csp->http->host)) + { + /* Errors are already logged by set_subject_alternative_name() */ + ret = -1; + goto exit; + } + /* * Writing certificate into file */ @@ -1877,7 +1997,7 @@ extern void ssl_send_certificate_error(struct client_state *csp) int ret = 0; struct certs_chain *cert = NULL; - /* Header of message with certificate informations */ + /* Header of message with certificate information */ const char message_begin[] = "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\n" @@ -1902,7 +2022,7 @@ extern void ssl_send_certificate_error(struct client_state *csp) { size_t base64_len = 4 * ((strlen(cert->file_buf) + 2) / 3) + 1; - message_len += strlen(cert->text_buf) + strlen("
\n")
+      message_len += strlen(cert->info_buf) + strlen("
\n")
                      +  base64_len + strlen("Download certificate");
       cert = cert->next;
@@ -1937,7 +2057,7 @@ extern void ssl_send_certificate_error(struct client_state *csp)
       }
 
       strlcat(message, "
",        message_len);
-      strlcat(message, cert->text_buf, message_len);
+      strlcat(message, cert->info_buf, message_len);
       strlcat(message, "
\n", message_len); if (ret == 0) @@ -1967,10 +2087,10 @@ extern void ssl_send_certificate_error(struct client_state *csp) * Function : ssl_verify_callback * * Description : This is a callback function for certificate verification. - * It's called for all certificates in server certificate - * trusted chain and it's preparing information about this - * certificates. Prepared informations can be used to inform - * user about invalid certificates. + * It's called once for each certificate in the server's + * certificate trusted chain and prepares information about + * the certificate. The information can be used to inform + * the user about invalid certificates. * * Parameters : * 1 : csp_void = Current client state (buffers, headers, etc...) @@ -2002,7 +2122,7 @@ static int ssl_verify_callback(void *csp_void, mbedtls_x509_crt *crt, */ last->next = malloc_or_die(sizeof(struct certs_chain)); last->next->next = NULL; - memset(last->next->text_buf, 0, sizeof(last->next->text_buf)); + memset(last->next->info_buf, 0, sizeof(last->next->info_buf)); memset(last->next->file_buf, 0, sizeof(last->next->file_buf)); /* @@ -2012,14 +2132,27 @@ static int ssl_verify_callback(void *csp_void, mbedtls_x509_crt *crt, crt->raw.p, crt->raw.len, (unsigned char *)last->file_buf, sizeof(last->file_buf)-1, &olen)) != 0) { + char err_buf[ERROR_BUF_SIZE]; + + mbedtls_strerror(ret, err_buf, sizeof(err_buf)); + log_error(LOG_LEVEL_ERROR, "mbedtls_pem_write_buffer() failed: %s", + err_buf); + return(ret); } /* * Saving certificate information into buffer */ - mbedtls_x509_crt_info(last->text_buf, sizeof(last->text_buf) - 1, - CERT_INFO_PREFIX, crt); + { + char buf[CERT_INFO_BUF_SIZE]; + char *encoded_text; + + mbedtls_x509_crt_info(buf, sizeof(buf), CERT_INFO_PREFIX, crt); + encoded_text = html_encode(buf); + strlcpy(last->info_buf, encoded_text, sizeof(last->info_buf)); + freez(encoded_text); + } return 0; } @@ -2030,7 +2163,7 @@ static int ssl_verify_callback(void *csp_void, mbedtls_x509_crt *crt, * Function : free_certificate_chain * * Description : Frees certificates linked list. This linked list is - * used to save informations about certificates in + * used to save information about certificates in * trusted chain. * * Parameters : @@ -2044,21 +2177,18 @@ static void free_certificate_chain(struct client_state *csp) struct certs_chain *cert = csp->server_certs_chain.next; /* Cleaning buffers */ - memset(csp->server_certs_chain.text_buf, 0, - sizeof(csp->server_certs_chain.text_buf)); + memset(csp->server_certs_chain.info_buf, 0, + sizeof(csp->server_certs_chain.info_buf)); memset(csp->server_certs_chain.file_buf, 0, sizeof(csp->server_certs_chain.file_buf)); csp->server_certs_chain.next = NULL; /* Freeing memory in whole linked list */ - if (cert != NULL) + while (cert != NULL) { - do - { - struct certs_chain *cert_for_free = cert; - cert = cert->next; - freez(cert_for_free); - } while (cert != NULL); + struct certs_chain *cert_for_free = cert; + cert = cert->next; + freez(cert_for_free); } } @@ -2136,7 +2266,7 @@ static int host_to_hash(struct client_state *csp) * Function : tunnel_established_successfully * * Description : Check if parent proxy server response contains - * informations about successfully created connection with + * information about successfully created connection with * destination server. (HTTP/... 2xx ...) * * Parameters :