talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

commit fd6f84d6b30d40bcf198cdb7ad3747b0ed27be48
parent 51df50ba2a8cb6dd3af2d753ef09bbec96b56327
Author: Andrej Kacian <ticho@claws-mail.org>
Date:   Fri, 21 Dec 2018 10:21:10 +0100

Add Server Name Indication support to TLS connections, if applicable.

Adds a hidden pref "use_tls_sni".

Patch by Alex Smith.
Closes bug #4103: TLS SNI (Server Name Indication) support for IMAP, POP & SMTP

Diffstat:
MAUTHORS | 1+
Msrc/common/session.c | 3+++
Msrc/common/session.h | 1+
Msrc/common/socket.h | 1+
Msrc/common/ssl.c | 14++++++++++++++
Msrc/common/utils.c | 23+++++++++++++++++++++++
Msrc/common/utils.h | 1+
Msrc/etpan/etpan-ssl.c | 17+++++++++++++++++
Msrc/gtk/authors.h | 1+
Msrc/imap.c | 2++
Msrc/news.c | 1+
Msrc/plugins/managesieve/managesieve.c | 1+
Msrc/pop.c | 1+
Msrc/prefs_account.c | 3+++
Msrc/prefs_account.h | 1+
Msrc/send_message.c | 1+
16 files changed, 72 insertions(+), 0 deletions(-)

diff --git a/AUTHORS b/AUTHORS @@ -325,3 +325,4 @@ contributors (in addition to the above; based on Changelog) Michael Schwendt Eric S. Raymond Avinash Sonawane + Alex Smith diff --git a/src/common/session.c b/src/common/session.c @@ -69,6 +69,7 @@ void session_init(Session *session, const void *prefs_account, gboolean is_smtp) session->port = 0; #ifdef USE_GNUTLS session->ssl_type = SSL_NONE; + session->use_tls_sni = TRUE; #endif session->nonblocking = TRUE; session->state = SESSION_READY; @@ -194,6 +195,7 @@ static gint session_connect_cb(SockInfo *sock, gpointer data) #ifdef USE_GNUTLS sock->gnutls_priority = session->gnutls_priority; + sock->use_tls_sni = session->use_tls_sni; if (session->ssl_type == SSL_TUNNEL) { sock_set_nonblocking_mode(sock, FALSE); @@ -407,6 +409,7 @@ gint session_start_tls(Session *session) session->sock->ssl_cert_auto_accept = session->ssl_cert_auto_accept; session->sock->gnutls_priority = session->gnutls_priority; + session->sock->use_tls_sni = session->use_tls_sni; if (nb_mode) sock_set_nonblocking_mode(session->sock, FALSE); diff --git a/src/common/session.h b/src/common/session.h @@ -160,6 +160,7 @@ struct _Session #ifdef USE_GNUTLS SSLType ssl_type; gchar *gnutls_priority; + gboolean use_tls_sni; #endif }; diff --git a/src/common/socket.h b/src/common/socket.h @@ -84,6 +84,7 @@ struct _SockInfo const void *account; gboolean is_smtp; gboolean ssl_cert_auto_accept; + gboolean use_tls_sni; }; void refresh_resolvers (void); diff --git a/src/common/ssl.c b/src/common/ssl.c @@ -410,6 +410,20 @@ gboolean ssl_init_socket(SockInfo *sockinfo) gnutls_record_disable_padding(session); + /* If we have a host name, rather than a numerical IP address, tell + * gnutls to send it in the server name identification extension field, + * to give the server a chance to select the correct certificate in the + * virtual hosting case where multiple domain names are hosted on the + * same IP address. */ + if (sockinfo->use_tls_sni && + sockinfo->hostname != NULL && + !is_numeric_host_address(sockinfo->hostname)) { + r = gnutls_server_name_set(session, GNUTLS_NAME_DNS, + sockinfo->hostname, strlen(sockinfo->hostname)); + debug_print("Set GnuTLS session server name indication to %s, status = %d\n", + sockinfo->hostname, r); + } + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); if (claws_ssl_get_cert_file()) { diff --git a/src/common/utils.c b/src/common/utils.c @@ -1908,6 +1908,29 @@ const gchar *get_domain_name(void) #endif } +/* Tells whether the given host address string is a valid representation of a + * numerical IP (v4 or, if supported, v6) address. + */ +gboolean is_numeric_host_address(const gchar *hostaddress) +{ + struct addrinfo hints, *res; + int err; + + /* See what getaddrinfo makes of the string when told that it is a + * numeric IP address representation. */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = 0; + hints.ai_flags = AI_NUMERICHOST; + hints.ai_protocol = 0; + + err = getaddrinfo(hostaddress, NULL, &hints, &res); + if (err == 0) + freeaddrinfo(res); + + return (err == 0); +} + off_t get_file_size(const gchar *file) { #ifdef G_OS_WIN32 diff --git a/src/common/utils.h b/src/common/utils.h @@ -395,6 +395,7 @@ const gchar *get_tmp_dir (void); const gchar *get_locale_dir (void); gchar *get_tmp_file (void); const gchar *get_domain_name (void); +gboolean is_numeric_host_address (const gchar *hostaddress); const gchar *get_desktop_file(void); #ifdef G_OS_WIN32 const gchar *w32_get_themes_dir (void); diff --git a/src/etpan/etpan-ssl.c b/src/etpan/etpan-ssl.c @@ -171,6 +171,23 @@ void etpan_connect_ssl_context_cb(struct mailstream_ssl_context * ssl_context, v gnutls_x509_crt_deinit(x509); gnutls_x509_privkey_deinit(pkey); } + +#if (defined LIBETPAN_API_CURRENT && LIBETPAN_API_CURRENT >= 23) + /* If we have a host name, rather than a numerical IP address, tell + * gnutls to send it in the Server Name Identification extension field, + * to give the server a chance to select the correct certificate in the + * virtual hosting case where multiple domain names are hosted on the + * same IP address. */ + if (session->use_tls_sni && + !is_numeric_host_address(account->recv_server)) { + int r; + + r = mailstream_ssl_set_server_name(ssl_context, account->recv_server); + debug_print("Set libetpan SSL mail stream server name indication to %s, status = %d\n", + account->recv_server, r); + } +#endif /* LIBETPAN_API_CURRENT >= 23 */ + } #endif /* USE_GNUTLS */ diff --git a/src/gtk/authors.h b/src/gtk/authors.h @@ -283,6 +283,7 @@ static char *CONTRIBS_LIST[] = { "shigeri", "Jesse Skinner", "Ville Skyttä", +"Alex Smith", "Dale P. Smith", "Avinash Sonawane", "Andrea Spadaccini", diff --git a/src/imap.c b/src/imap.c @@ -1277,7 +1277,9 @@ static IMAPSession *imap_session_new(Folder * folder, session->uidplus = FALSE; session->cmd_count = 1; } + SESSION(session)->use_tls_sni = account->use_tls_sni; #endif + log_message(LOG_PROTOCOL, "IMAP connection is %s-authenticated\n", (session->authenticated) ? "pre" : "un"); diff --git a/src/news.c b/src/news.c @@ -361,6 +361,7 @@ static Session *news_session_new(Folder *folder, const PrefsAccount *account, gu nntp_init(folder); #ifdef USE_GNUTLS + SESSION(session)->use_tls_sni = account->use_tls_sni; if (ssl_type != SSL_NONE) r = nntp_threaded_connect_ssl(folder, server, port, proxy_info); else diff --git a/src/plugins/managesieve/managesieve.c b/src/plugins/managesieve/managesieve.c @@ -1058,6 +1058,7 @@ static void sieve_session_reset(SieveSession *session) session->state = SIEVE_CAPABILITIES; #ifdef USE_GNUTLS session->tls_init_done = FALSE; + SESSION(session)->use_tls_sni = account->use_tls_sni; #endif session->avail_auth_type = 0; session->auth_type = 0; diff --git a/src/pop.c b/src/pop.c @@ -538,6 +538,7 @@ Session *pop3_session_new(PrefsAccount *account) if (account->set_gnutls_priority && account->gnutls_priority && strlen(account->gnutls_priority) != 0) SESSION(session)->gnutls_priority = g_strdup(account->gnutls_priority); + SESSION(session)->use_tls_sni = account->use_tls_sni; #endif session->state = POP3_READY; diff --git a/src/prefs_account.c b/src/prefs_account.c @@ -787,6 +787,9 @@ static PrefParam ssl_param[] = { &ssl_page.use_nonblocking_ssl_checkbtn, prefs_set_data_from_toggle, prefs_set_toggle}, + {"use_tls_sni", "1", &tmp_ac_prefs.use_tls_sni, P_BOOL, + NULL, NULL, NULL}, + {"in_ssl_client_cert_file", "", &tmp_ac_prefs.in_ssl_client_cert_file, P_STRING, &ssl_page.entry_in_cert_file, prefs_set_data_from_entry, prefs_set_entry}, diff --git a/src/prefs_account.h b/src/prefs_account.h @@ -86,6 +86,7 @@ struct _PrefsAccount gboolean ssl_certs_auto_accept; gboolean use_nonblocking_ssl; + gboolean use_tls_sni; /* Receive */ gboolean use_apop_auth; diff --git a/src/send_message.c b/src/send_message.c @@ -280,6 +280,7 @@ gint send_message_smtp_full(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp, g if (ac_prefs->set_gnutls_priority && ac_prefs->gnutls_priority && strlen(ac_prefs->gnutls_priority)) session->gnutls_priority = g_strdup(ac_prefs->gnutls_priority); + session->use_tls_sni = ac_prefs->use_tls_sni; #else if (ac_prefs->ssl_smtp != SSL_NONE) { if (alertpanel_full(_("Insecure connection"),