diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/IO/IO.c | 10 | ||||
-rw-r--r-- | src/IO/Makefile.am | 4 | ||||
-rw-r--r-- | src/IO/http.c | 217 | ||||
-rw-r--r-- | src/IO/ssl.h | 47 | ||||
-rw-r--r-- | src/IO/tls.c (renamed from src/IO/ssl.c) | 431 | ||||
-rw-r--r-- | src/IO/tls.h | 47 | ||||
-rw-r--r-- | src/cache.c | 16 | ||||
-rw-r--r-- | src/dialog.cc | 20 | ||||
-rw-r--r-- | src/dillo.cc | 6 | ||||
-rw-r--r-- | src/html.cc | 2 | ||||
-rw-r--r-- | src/url.c | 25 | ||||
-rw-r--r-- | src/url.h | 10 |
12 files changed, 478 insertions, 357 deletions
diff --git a/src/IO/IO.c b/src/IO/IO.c index e5c5fc79..0cdb9499 100644 --- a/src/IO/IO.c +++ b/src/IO/IO.c @@ -21,7 +21,7 @@ #include "../klist.h" #include "IO.h" #include "iowatch.hh" -#include "ssl.h" +#include "tls.h" /* * Symbolic defines for shutdown() function @@ -163,7 +163,7 @@ static bool_t IO_read(IOData_t *io) ssize_t St; bool_t ret = FALSE; int io_key = io->Key; - void *conn = a_Ssl_connection(io->FD); + void *conn = a_Tls_connection(io->FD); _MSG(" IO_read\n"); @@ -172,7 +172,7 @@ static bool_t IO_read(IOData_t *io) io->Status = 0; while (1) { - St = conn ? a_Ssl_read(conn, Buf, IOBufLen) + St = conn ? a_Tls_read(conn, Buf, IOBufLen) : read(io->FD, Buf, IOBufLen); if (St > 0) { dStr_append_l(io->Buf, Buf, St); @@ -217,13 +217,13 @@ static bool_t IO_write(IOData_t *io) { ssize_t St; bool_t ret = FALSE; - void *conn = a_Ssl_connection(io->FD); + void *conn = a_Tls_connection(io->FD); _MSG(" IO_write\n"); io->Status = 0; while (1) { - St = conn ? a_Ssl_write(conn, io->Buf->str, io->Buf->len) + St = conn ? a_Tls_write(conn, io->Buf->str, io->Buf->len) : write(io->FD, io->Buf->str, io->Buf->len); if (St < 0) { /* Error */ diff --git a/src/IO/Makefile.am b/src/IO/Makefile.am index ff600521..d8fed40a 100644 --- a/src/IO/Makefile.am +++ b/src/IO/Makefile.am @@ -15,8 +15,8 @@ libDiof_a_SOURCES = \ about.c \ Url.h \ http.c \ - ssl.h \ - ssl.c \ + tls.h \ + tls.c \ dpi.c \ IO.c \ iowatch.cc \ diff --git a/src/IO/http.c b/src/IO/http.c index e5c459ee..379d51c1 100644 --- a/src/IO/http.c +++ b/src/IO/http.c @@ -27,7 +27,7 @@ #include <arpa/inet.h> /* for inet_ntop */ #include "IO.h" -#include "ssl.h" +#include "tls.h" #include "Url.h" #include "../msg.h" #include "../klist.h" @@ -52,18 +52,18 @@ D_STMT_START { \ static const int HTTP_SOCKET_USE_PROXY = 0x1; static const int HTTP_SOCKET_QUEUED = 0x2; static const int HTTP_SOCKET_TO_BE_FREED = 0x4; -static const int HTTP_SOCKET_SSL = 0x8; +static const int HTTP_SOCKET_TLS = 0x8; /* 'web' is just a reference (no need to deallocate it here). */ typedef struct { int SockFD; - uint_t connect_port; uint_t flags; DilloWeb *web; /* reference to client's web structure */ DilloUrl *url; Dlist *addr_list; /* Holds the DNS answer */ ChainLink *Info; /* Used for CCC asynchronous operations */ - char *connected_to; /* Used for per-host connection limit */ + char *connected_to; /* Used for per-server connection limit */ + uint_t connect_port; Dstr *https_proxy_reply; } SocketData_t; @@ -72,19 +72,23 @@ typedef struct { */ typedef struct { char *host; + uint_t port; + bool_t https; + int active_conns; + int running_the_queue; Dlist *queue; -} HostConnection_t; +} Server_t; typedef struct { int fd; int skey; } FdMapEntry_t; -static void Http_socket_enqueue(HostConnection_t *hc, SocketData_t* sock); -static HostConnection_t *Http_host_connection_get(const char *host); -static void Http_host_connection_remove(HostConnection_t *hc); -static void Http_connect_socket(ChainLink *Info, HostConnection_t *hc); +static void Http_socket_enqueue(Server_t *srv, SocketData_t* sock); +static Server_t *Http_server_get(const char *host, uint_t port, bool_t https); +static void Http_server_remove(Server_t *srv); +static void Http_connect_socket(ChainLink *Info); static char *Http_get_connect_str(const DilloUrl *url); static void Http_send_query(SocketData_t *S); static void Http_socket_free(int SKey); @@ -97,7 +101,7 @@ static Klist_t *ValidSocks = NULL; /* Active sockets list. It holds pointers to static DilloUrl *HTTP_Proxy = NULL; static char *HTTP_Proxy_Auth_base64 = NULL; static char *HTTP_Language_hdr = NULL; -static Dlist *host_connections; +static Dlist *servers; /* TODO: If fd_map will stick around in its present form (FDs and SocketData_t) * then consider whether having both this and ValidSocks is necessary. @@ -127,7 +131,7 @@ int a_Http_init(void) HTTP_Proxy_Auth_base64 = a_Misc_encode_base64(prefs.http_proxyuser); */ - host_connections = dList_new(5); + servers = dList_new(5); fd_map = dList_new(20); return 0; @@ -211,12 +215,14 @@ void a_Http_connect_done(int fd, bool_t success) if (fme && (sd = a_Klist_get_data(ValidSocks, fme->skey))) { ChainLink *info = sd->Info; + bool_t valid_web = a_Web_valid(sd->web); - if (success) { + if (success && valid_web) { a_Chain_bfcb(OpSend, info, &sd->SockFD, "FD"); Http_send_query(sd); } else { - MSG_BW(sd->web, 1, "Could not establish connection."); + if (valid_web) + MSG_BW(sd->web, 1, "Could not establish connection."); MSG("fd %d is done and failed\n", sd->SockFD); dClose(fd); Http_socket_free(VOIDP2INT(info->LocalKey)); /* free sd */ @@ -228,48 +234,56 @@ void a_Http_connect_done(int fd, bool_t success) } } -static void Http_socket_activate(HostConnection_t *hc, SocketData_t *sd) +static void Http_socket_activate(Server_t *srv, SocketData_t *sd) { - dList_remove(hc->queue, sd); + dList_remove(srv->queue, sd); sd->flags &= ~HTTP_SOCKET_QUEUED; - hc->active_conns++; - sd->connected_to = hc->host; + srv->active_conns++; + sd->connected_to = srv->host; } -static void Http_connect_queued_sockets(HostConnection_t *hc) +static void Http_connect_queued_sockets(Server_t *srv) { SocketData_t *sd; int i; + srv->running_the_queue++; + for (i = 0; - i < dList_length(hc->queue) && hc->active_conns < prefs.http_max_conns; + (i < dList_length(srv->queue) && + srv->active_conns < prefs.http_max_conns); i++) { - sd = dList_nth_data(hc->queue, i); + sd = dList_nth_data(srv->queue, i); - if (!(sd->flags & HTTP_SOCKET_TO_BE_FREED)) { - int connect_ready = SSL_CONNECT_READY; + if (sd->flags & HTTP_SOCKET_TO_BE_FREED) { + dList_remove(srv->queue, sd); + dFree(sd); + i--; + } else { + int connect_ready = TLS_CONNECT_READY; - if (sd->flags & HTTP_SOCKET_SSL) - connect_ready = a_Ssl_connect_ready(sd->url); + if (sd->flags & HTTP_SOCKET_TLS) + connect_ready = a_Tls_connect_ready(sd->url); - if (connect_ready == SSL_CONNECT_NEVER || !a_Web_valid(sd->web)) { + if (connect_ready == TLS_CONNECT_NEVER || !a_Web_valid(sd->web)) { int SKey = VOIDP2INT(sd->Info->LocalKey); Http_socket_free(SKey); - } else if (connect_ready == SSL_CONNECT_READY) { + } else if (connect_ready == TLS_CONNECT_READY) { i--; - Http_socket_activate(hc, sd); - Http_connect_socket(sd->Info, hc); + Http_socket_activate(srv, sd); + Http_connect_socket(sd->Info); } } - if (sd->flags & HTTP_SOCKET_TO_BE_FREED) { - dList_remove(hc->queue, sd); - dFree(sd); - i--; - } } - _MSG("Queue %s len %d\n", hc->host, dList_length(hc->queue)); + _MSG("Queue http%s://%s:%u len %d\n", srv->https ? "s" : "", srv->host, + srv->port, dList_length(srv->queue)); + + if (--srv->running_the_queue == 0) { + if (srv->active_conns == 0) + Http_server_remove(srv); + } } /* @@ -290,15 +304,14 @@ static void Http_socket_free(int SKey) } else { if (S->SockFD != -1) Http_fd_map_remove_entry(S->SockFD); - a_Ssl_reset_server_state(S->url); + a_Tls_reset_server_state(S->url); if (S->connected_to) { - a_Ssl_close_by_fd(S->SockFD); + a_Tls_close_by_fd(S->SockFD); - HostConnection_t *hc = Http_host_connection_get(S->connected_to); - hc->active_conns--; - Http_connect_queued_sockets(hc); - if (hc->active_conns == 0) - Http_host_connection_remove(hc); + Server_t *srv = Http_server_get(S->connected_to, S->connect_port, + (S->flags & HTTP_SOCKET_TLS)); + srv->active_conns--; + Http_connect_queued_sockets(srv); } a_Url_free(S->url); dFree(S); @@ -478,9 +491,9 @@ static void Http_send_query(SocketData_t *S) /* * Prepare an HTTPS connection. If necessary, tunnel it through a proxy. - * Then perform the SSL handshake. + * Then perform the TLS handshake. */ -static void Http_connect_ssl(ChainLink *info) +static void Http_connect_tls(ChainLink *info) { int SKey = VOIDP2INT(info->LocalKey); SocketData_t *S = a_Klist_get_data(ValidSocks, SKey); @@ -496,7 +509,7 @@ static void Http_connect_ssl(ChainLink *info) dFree(dbuf); dFree(connect_str); } else { - a_Ssl_handshake(S->SockFD, S->url); + a_Tls_handshake(S->SockFD, S->url); } } @@ -504,7 +517,7 @@ static void Http_connect_ssl(ChainLink *info) * This function is called after the DNS succeeds in solving a hostname. * Task: Finish socket setup and start connecting the socket. */ -static void Http_connect_socket(ChainLink *Info, HostConnection_t *hc) +static void Http_connect_socket(ChainLink *Info) { int i, status; SocketData_t *S; @@ -542,7 +555,7 @@ static void Http_connect_socket(ChainLink *Info, HostConnection_t *hc) sin->sin_port = htons(S->connect_port); memcpy(&sin->sin_addr, dh->data, (size_t)dh->alen); if (a_Web_valid(S->web) && (S->web->flags & WEB_RootUrl)) - MSG("Connecting to %s:%d\n", inet_ntoa(sin->sin_addr), + MSG("Connecting to %s:%u\n", inet_ntoa(sin->sin_addr), S->connect_port); break; } @@ -557,7 +570,7 @@ static void Http_connect_socket(ChainLink *Info, HostConnection_t *hc) memcpy(&sin6->sin6_addr, dh->data, dh->alen); inet_ntop(dh->af, dh->data, buf, sizeof(buf)); if (a_Web_valid(S->web) && (S->web->flags & WEB_RootUrl)) - MSG("Connecting to %s:%d\n", buf, S->connect_port); + MSG("Connecting to %s:%u\n", buf, S->connect_port); break; } #endif @@ -567,8 +580,8 @@ static void Http_connect_socket(ChainLink *Info, HostConnection_t *hc) if (status == -1 && errno != EINPROGRESS) { MSG("Http_connect_socket ERROR: %s\n", dStrerror(errno)); a_Http_connect_done(S->SockFD, FALSE); - } else if (S->flags & HTTP_SOCKET_SSL) { - Http_connect_ssl(Info); + } else if (S->flags & HTTP_SOCKET_TLS) { + Http_connect_tls(Info); } else { a_Http_connect_done(S->SockFD, TRUE); } @@ -658,7 +671,7 @@ static void Http_dns_cb(int Status, Dlist *addr_list, void *data) int SKey = VOIDP2INT(data); bool_t clean_up = TRUE; SocketData_t *S; - HostConnection_t *hc; + Server_t *srv; S = a_Klist_get_data(ValidSocks, SKey); if (S) { @@ -670,9 +683,10 @@ static void Http_dns_cb(int Status, Dlist *addr_list, void *data) /* Successful DNS answer; save the IP */ S->addr_list = addr_list; clean_up = FALSE; - hc = Http_host_connection_get(host); - Http_socket_enqueue(hc, S); - Http_connect_queued_sockets(hc); + srv = Http_server_get(host, S->connect_port, + (S->flags & HTTP_SOCKET_TLS)); + Http_socket_enqueue(srv, S); + Http_connect_queued_sockets(srv); } else { /* DNS wasn't able to resolve the hostname */ MSG_BW(S->web, 0, "ERROR: DNS can't resolve %s", host); @@ -718,7 +732,7 @@ static int Http_get(ChainLink *Info, void *Data1) S->connect_port = URL_PORT(url); S->url = a_Url_dup(S->web->url); if (!dStrAsciiCasecmp(URL_SCHEME(S->url), "https")) - S->flags |= HTTP_SOCKET_SSL; + S->flags |= HTTP_SOCKET_TLS; /* Let the user know what we'll do */ MSG_BW(S->web, 1, "DNS resolving %s", hostname); @@ -734,16 +748,18 @@ static int Http_get(ChainLink *Info, void *Data1) /* * Can the old socket's fd be reused for the new socket? * - * NOTE: old and new must come from the same HostConnection_t. + * NOTE: old and new must come from the same Server_t. * This is not built to accept arbitrary sockets. */ static bool_t Http_socket_reuse_compatible(SocketData_t *old, SocketData_t *new) { + /* + * If we are using TLS through a proxy, we need to ensure that old and new + * are going through to the same host:port. + */ if (a_Web_valid(new->web) && - old->connect_port == new->connect_port && - ((old->flags & HTTP_SOCKET_SSL) == (new->flags & HTTP_SOCKET_SSL)) && - ((old->flags & HTTP_SOCKET_SSL) == 0 || + ((old->flags & HTTP_SOCKET_TLS) == 0 || (old->flags & HTTP_SOCKET_USE_PROXY) == 0 || ((URL_PORT(old->url) == URL_PORT(new->url)) && !dStrAsciiCasecmp(URL_HOST(old->url), URL_HOST(new->url))))) @@ -760,11 +776,13 @@ static void Http_socket_reuse(int SKey) SocketData_t *new_sd, *old_sd = a_Klist_get_data(ValidSocks, SKey); if (old_sd) { - HostConnection_t *hc = Http_host_connection_get(old_sd->connected_to); - int i, n = dList_length(hc->queue); + Server_t *srv = Http_server_get(old_sd->connected_to, + old_sd->connect_port, + (old_sd->flags & HTTP_SOCKET_TLS)); + int i, n = dList_length(srv->queue); for (i = 0; i < n; i++) { - new_sd = dList_nth_data(hc->queue, i); + new_sd = dList_nth_data(srv->queue, i); if (!(new_sd->flags & HTTP_SOCKET_TO_BE_FREED) && Http_socket_reuse_compatible(old_sd, new_sd)) { @@ -773,11 +791,11 @@ static void Http_socket_reuse(int SKey) new_sd->SockFD = old_sd->SockFD; old_sd->connected_to = NULL; - hc->active_conns--; + srv->active_conns--; Http_socket_free(SKey); MSG("Reusing fd %d for %s\n", new_sd->SockFD,URL_STR(new_sd->url)); - Http_socket_activate(hc, new_sd); + Http_socket_activate(srv, new_sd); Http_fd_map_add_entry(new_sd); a_Http_connect_done(new_sd->SockFD, success); return; @@ -863,7 +881,7 @@ void a_Http_ccc(int Op, int Branch, int Dir, ChainLink *Info, sd->https_proxy_reply->str); dStr_free(sd->https_proxy_reply, 1); sd->https_proxy_reply = NULL; - a_Ssl_handshake(sd->SockFD, sd->url); + a_Tls_handshake(sd->SockFD, sd->url); } else { MSG_BW(sd->web, 1, "Can't connect through proxy to %s", URL_HOST(sd->url)); @@ -935,68 +953,77 @@ void a_Http_ccc(int Op, int Branch, int Dir, ChainLink *Info, * Add socket data to the queue. Pages/stylesheets/etc. have higher priority * than images. */ -static void Http_socket_enqueue(HostConnection_t *hc, SocketData_t* sock) +static void Http_socket_enqueue(Server_t *srv, SocketData_t* sock) { sock->flags |= HTTP_SOCKET_QUEUED; if ((sock->web->flags & WEB_Image) == 0) { - int i, n = dList_length(hc->queue); + int i, n = dList_length(srv->queue); for (i = 0; i < n; i++) { - SocketData_t *curr = dList_nth_data(hc->queue, i); + SocketData_t *curr = dList_nth_data(srv->queue, i); if (a_Web_valid(curr->web) && (curr->web->flags & WEB_Image)) { - dList_insert_pos(hc->queue, sock, i); + dList_insert_pos(srv->queue, sock, i); return; } } } - dList_append(hc->queue, sock); + dList_append(srv->queue, sock); } -static HostConnection_t *Http_host_connection_get(const char *host) +static Server_t *Http_server_get(const char *host, uint_t port, bool_t https) { int i; - HostConnection_t *hc; + Server_t *srv; - for (i = 0; i < dList_length(host_connections); i++) { - hc = (HostConnection_t*) dList_nth_data(host_connections, i); + for (i = 0; i < dList_length(servers); i++) { + srv = (Server_t*) dList_nth_data(servers, i); - if (dStrAsciiCasecmp(host, hc->host) == 0) - return hc; + if (port == srv->port && https == srv->https && + !dStrAsciiCasecmp(host, srv->host)) + return srv; } - hc = dNew0(HostConnection_t, 1); - hc->queue = dList_new(10); - hc->host = dStrdup(host); - dList_append(host_connections, hc); + srv = dNew0(Server_t, 1); + srv->queue = dList_new(10); + srv->running_the_queue = 0; + srv->host = dStrdup(host); + srv->port = port; + srv->https = https; + dList_append(servers, srv); - return hc; + return srv; } -static void Http_host_connection_remove(HostConnection_t *hc) +static void Http_server_remove(Server_t *srv) { - assert(dList_length(hc->queue) == 0); - dList_free(hc->queue); - dList_remove_fast(host_connections, hc); - dFree(hc->host); - dFree(hc); + SocketData_t *sd; + + while ((sd = dList_nth_data(srv->queue, 0))) { + dList_remove_fast(srv->queue, sd); + dFree(sd); + } + dList_free(srv->queue); + dList_remove_fast(servers, srv); + dFree(srv->host); + dFree(srv); } -static void Http_host_connection_remove_all() +static void Http_servers_remove_all() { - HostConnection_t *hc; + Server_t *srv; SocketData_t *sd; - while (dList_length(host_connections) > 0) { - hc = (HostConnection_t*) dList_nth_data(host_connections, 0); - while ((sd = dList_nth_data(hc->queue, 0))) { - dList_remove(hc->queue, sd); + while (dList_length(servers) > 0) { + srv = (Server_t*) dList_nth_data(servers, 0); + while ((sd = dList_nth_data(srv->queue, 0))) { + dList_remove(srv->queue, sd); dFree(sd); } - Http_host_connection_remove(hc); + Http_server_remove(srv); } - dList_free(host_connections); + dList_free(servers); } static void Http_fd_map_remove_all() @@ -1017,7 +1044,7 @@ static void Http_fd_map_remove_all() */ void a_Http_freeall(void) { - Http_host_connection_remove_all(); + Http_servers_remove_all(); Http_fd_map_remove_all(); a_Klist_free(&ValidSocks); a_Url_free(HTTP_Proxy); diff --git a/src/IO/ssl.h b/src/IO/ssl.h deleted file mode 100644 index f55479b2..00000000 --- a/src/IO/ssl.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef __SSL_H__ -#define __SSL_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "../url.h" - -#define SSL_CONNECT_NEVER -1 -#define SSL_CONNECT_NOT_YET 0 -#define SSL_CONNECT_READY 1 - -void a_Ssl_init(); - - -#ifdef ENABLE_SSL -int a_Ssl_connect_ready(const DilloUrl *url); -void a_Ssl_reset_server_state(const DilloUrl *url); - -/* Use to initiate a SSL connection. */ -void a_Ssl_handshake(int fd, const DilloUrl *url); - -void *a_Ssl_connection(int fd); - -void a_Ssl_freeall(); - -void a_Ssl_close_by_fd(int fd); -int a_Ssl_read(void *conn, void *buf, size_t len); -int a_Ssl_write(void *conn, void *buf, size_t len); -#else - -#define a_Ssl_connect_ready(url) SSL_CONNECT_NEVER -#define a_Ssl_reset_server_state(url) ; -#define a_Ssl_handshake(fd, url) ; -#define a_Ssl_connection(fd) NULL -#define a_Ssl_freeall() ; -#define a_Ssl_close_by_fd(fd) ; -#define a_Ssl_read(conn, buf, len) 0 -#define a_Ssl_write(conn, buf, len) 0 -#endif -#ifdef __cplusplus -} -#endif - -#endif /* __SSL_H__ */ - diff --git a/src/IO/ssl.c b/src/IO/tls.c index 856d94b5..f0f33215 100644 --- a/src/IO/ssl.c +++ b/src/IO/tls.c @@ -1,5 +1,5 @@ /* - * File: ssl.c + * File: tls.c * * Copyright 2004 Garrett Kajmowicz <gkajmowi@tbaytel.net> * (for some bits derived from the https dpi, e.g., certificate handling) @@ -33,9 +33,9 @@ #ifndef ENABLE_SSL -void a_Ssl_init() +void a_Tls_init() { - MSG("SSL: Disabled at compilation time.\n"); + MSG("TLS: Disabled at compilation time.\n"); } #else @@ -52,7 +52,7 @@ void a_Ssl_init() #include "../dialog.hh" #include "../klist.h" #include "iowatch.hh" -#include "ssl.h" +#include "tls.h" #include "Url.h" #include <openssl/ssl.h> @@ -78,7 +78,7 @@ typedef struct { } FdMapEntry_t; /* - * Data type for SSL connection information + * Data type for TLS connection information */ typedef struct { int fd; @@ -87,22 +87,22 @@ typedef struct { bool_t connecting; } Conn_t; -/* List of active SSL connections */ +/* List of active TLS connections */ static Klist_t *conn_list = NULL; /* - * If ssl_context is still NULL, this corresponds to SSL being disabled. + * If ssl_context is still NULL, this corresponds to TLS being disabled. */ static SSL_CTX *ssl_context; static Dlist *servers; static Dlist *fd_map; -static void Ssl_connect_cb(int fd, void *vssl); +static void Tls_connect_cb(int fd, void *vconnkey); /* * Compare by FD. */ -static int Ssl_fd_map_cmp(const void *v1, const void *v2) +static int Tls_fd_map_cmp(const void *v1, const void *v2) { int fd = VOIDP2INT(v2); const FdMapEntry_t *e = v1; @@ -110,14 +110,14 @@ static int Ssl_fd_map_cmp(const void *v1, const void *v2) return (fd != e->fd); } -static void Ssl_fd_map_add_entry(int fd, int connkey) +static void Tls_fd_map_add_entry(int fd, int connkey) { FdMapEntry_t *e = dNew0(FdMapEntry_t, 1); e->fd = fd; e->connkey = connkey; - if (dList_find_custom(fd_map, INT2VOIDP(e->fd), Ssl_fd_map_cmp)) { - MSG_ERR("SSL FD ENTRY ALREADY FOUND FOR %d\n", e->fd); + if (dList_find_custom(fd_map, INT2VOIDP(e->fd), Tls_fd_map_cmp)) { + MSG_ERR("TLS FD ENTRY ALREADY FOUND FOR %d\n", e->fd); assert(0); } @@ -128,30 +128,30 @@ static void Ssl_fd_map_add_entry(int fd, int connkey) /* * Remove and free entry from fd_map. */ -static void Ssl_fd_map_remove_entry(int fd) +static void Tls_fd_map_remove_entry(int fd) { - void *data = dList_find_custom(fd_map, INT2VOIDP(fd), Ssl_fd_map_cmp); + void *data = dList_find_custom(fd_map, INT2VOIDP(fd), Tls_fd_map_cmp); //MSG("REMOVE ENTRY %d\n", fd); if (data) { dList_remove_fast(fd_map, data); dFree(data); } else { - MSG("SSL FD ENTRY NOT FOUND FOR %d\n", fd); + MSG("TLS FD ENTRY NOT FOUND FOR %d\n", fd); } } /* - * Return SSL connection information for a given file - * descriptor, or NULL if no SSL connection was found. + * Return TLS connection information for a given file + * descriptor, or NULL if no TLS connection was found. */ -void *a_Ssl_connection(int fd) +void *a_Tls_connection(int fd) { Conn_t *conn; if (fd_map) { FdMapEntry_t *fme = dList_find_custom(fd_map, INT2VOIDP(fd), - Ssl_fd_map_cmp); + Tls_fd_map_cmp); if (fme && (conn = a_Klist_get_data(conn_list, fme->connkey))) return conn; @@ -160,9 +160,9 @@ void *a_Ssl_connection(int fd) } /* - * Add a new SSL connection information node. + * Add a new TLS connection information node. */ -static int Ssl_conn_new(int fd, const DilloUrl *url, SSL *ssl) +static int Tls_conn_new(int fd, const DilloUrl *url, SSL *ssl) { int key; @@ -174,19 +174,22 @@ static int Ssl_conn_new(int fd, const DilloUrl *url, SSL *ssl) key = a_Klist_insert(&conn_list, conn); - Ssl_fd_map_add_entry(fd, key); + Tls_fd_map_add_entry(fd, key); return key; } /* - * Let's monitor for ssl alerts. + * Let's monitor for TLS alerts. */ -static void Ssl_info_cb(const SSL *ssl, int where, int ret) +static void Tls_info_cb(const SSL *ssl, int where, int ret) { if (where & SSL_CB_ALERT) { - MSG("SSL ALERT on %s: %s\n", (where & SSL_CB_READ) ? "read" : "write", - SSL_alert_desc_string_long(ret)); + const char *str = SSL_alert_desc_string_long(ret); + + if (strcmp(str, "close notify")) + MSG("TLS ALERT on %s: %s\n", (where & SSL_CB_READ) ? "read" : "write", + str); } } @@ -197,7 +200,7 @@ static void Ssl_info_cb(const SSL *ssl, int where, int ret) * abysmal openssl documentation, this was worked out from reading discussion * on the web and then reading openssl source to see what it normally does. */ -static void Ssl_load_certificates() +static void Tls_load_certificates() { /* curl-7.37.1 says that the following bundle locations are used on "Debian * systems", "Redhat and Mandriva", "old(er) Redhat", "FreeBSD", and @@ -207,7 +210,7 @@ static void Ssl_load_certificates() */ uint_t u; char *userpath; - static const char *ca_files[] = { + static const char *const ca_files[] = { "/etc/ssl/certs/ca-certificates.crt", "/etc/pki/tls/certs/ca-bundle.crt", "/usr/share/ssl/certs/ca-bundle.crt", @@ -216,7 +219,7 @@ static void Ssl_load_certificates() CA_CERTS_FILE }; - static const char *ca_paths[] = { + static const char *const ca_paths[] = { "/etc/ssl/certs/", CA_CERTS_DIR }; @@ -247,7 +250,7 @@ static void Ssl_load_certificates() /* * Initialize the OpenSSL library. */ -void a_Ssl_init(void) +void a_Tls_init(void) { SSL_library_init(); SSL_load_error_strings(); @@ -266,7 +269,7 @@ void a_Ssl_init(void) return; } - SSL_CTX_set_info_callback(ssl_context, Ssl_info_cb); + SSL_CTX_set_info_callback(ssl_context, Tls_info_cb); /* Don't want: eNULL, which has no encryption; aNULL, which has no * authentication; LOW, which as of 2014 use 64 or 56-bit encryption; @@ -285,7 +288,7 @@ void a_Ssl_init(void) /* This lets us deal with self-signed certificates */ SSL_CTX_set_verify(ssl_context, SSL_VERIFY_NONE, NULL); - Ssl_load_certificates(); + Tls_load_certificates(); fd_map = dList_new(20); servers = dList_new(8); @@ -295,7 +298,7 @@ void a_Ssl_init(void) * Save certificate with a hashed filename. * Return: 0 on success, 1 on failure. */ -static int Ssl_save_certificate_home(X509 * cert) +static int Tls_save_certificate_home(X509 * cert) { char buf[4096]; @@ -338,16 +341,30 @@ static int Ssl_save_certificate_home(X509 * cert) } /* - * Test whether a URL corresponds to a server. + * Ordered comparison of servers. */ -static int Ssl_servers_cmp(const void *v1, const void *v2) +static int Tls_servers_cmp(const void *v1, const void *v2) { - Server_t *s = (Server_t *)v1; + const Server_t *s1 = (const Server_t *)v1, *s2 = (const Server_t *)v2; + int cmp = dStrAsciiCasecmp(s1->hostname, s2->hostname); + + if (!cmp) + cmp = s1->port - s2->port; + return cmp; +} +/* + * Ordered comparison of server with URL. + */ +static int Tls_servers_by_url_cmp(const void *v1, const void *v2) +{ + const Server_t *s = (const Server_t *)v1; const DilloUrl *url = (const DilloUrl *)v2; - const char *host = URL_HOST(url); - int port = URL_PORT(url); - return (dStrAsciiCasecmp(s->hostname, host) || (port != s->port)); + int cmp = dStrAsciiCasecmp(s->hostname, URL_HOST(url)); + + if (!cmp) + cmp = s->port - URL_PORT(url); + return cmp; } /* @@ -355,41 +372,31 @@ static int Ssl_servers_cmp(const void *v1, const void *v2) * Once we have the certificate, know whether we like it -- and whether the * user accepts it -- HTTP can run through queued sockets as normal. * - * Return: 1 means yes, 0 means not yet, -1 means never. - * TODO: Something clearer or different. + * Return: TLS_CONNECT_READY or TLS_CONNECT_NOT_YET or TLS_CONNECT_NEVER. */ -int a_Ssl_connect_ready(const DilloUrl *url) +int a_Tls_connect_ready(const DilloUrl *url) { Server_t *s; - int i, len; - const char *host = URL_HOST(url); - const int port = URL_PORT(url); - int ret = SSL_CONNECT_READY; + int ret = TLS_CONNECT_READY; - dReturn_val_if_fail(ssl_context, SSL_CONNECT_NEVER); + dReturn_val_if_fail(ssl_context, TLS_CONNECT_NEVER); - len = dList_length(servers); + if ((s = dList_find_sorted(servers, url, Tls_servers_by_url_cmp))) { + if (s->cert_status == CERT_STATUS_RECEIVING) + ret = TLS_CONNECT_NOT_YET; + else if (s->cert_status == CERT_STATUS_BAD) + ret = TLS_CONNECT_NEVER; - for (i = 0; i < len; i++) { - s = dList_nth_data(servers, i); - - if (!dStrAsciiCasecmp(s->hostname, host) && (port == s->port)) { - if (s->cert_status == CERT_STATUS_RECEIVING) - ret = SSL_CONNECT_NOT_YET; - else if (s->cert_status == CERT_STATUS_BAD) - ret = SSL_CONNECT_NEVER; + if (s->cert_status == CERT_STATUS_NONE) + s->cert_status = CERT_STATUS_RECEIVING; + } else { + s = dNew(Server_t, 1); - if (s->cert_status == CERT_STATUS_NONE) - s->cert_status = CERT_STATUS_RECEIVING; - return ret; - } + s->hostname = dStrdup(URL_HOST(url)); + s->port = URL_PORT(url); + s->cert_status = CERT_STATUS_RECEIVING; + dList_insert_sorted(servers, s, Tls_servers_cmp); } - s = dNew(Server_t, 1); - - s->port = port; - s->hostname = dStrdup(host); - s->cert_status = CERT_STATUS_RECEIVING; - dList_append(servers, s); return ret; } @@ -397,9 +404,9 @@ int a_Ssl_connect_ready(const DilloUrl *url) * Did we find problems with the certificate, and did the user proceed to * reject the connection? */ -static int Ssl_user_said_no(const DilloUrl *url) +static int Tls_user_said_no(const DilloUrl *url) { - Server_t *s = dList_find_custom(servers, url, Ssl_servers_cmp); + Server_t *s = dList_find_sorted(servers, url, Tls_servers_by_url_cmp); if (!s) return FALSE; @@ -407,20 +414,6 @@ static int Ssl_user_said_no(const DilloUrl *url) return s->cert_status == CERT_STATUS_BAD; } -/* - * Did we find problems with the certificate, and did the user proceed to - * accept the connection anyway? - */ -static int Ssl_user_said_yes(const DilloUrl *url) -{ - Server_t *s = dList_find_custom(servers, url, Ssl_servers_cmp); - - if (!s) - return FALSE; - - return s->cert_status == CERT_STATUS_USER_ACCEPTED; -} - /******************** BEGINNING OF STUFF DERIVED FROM wget-1.16.3 */ #define ASTERISK_EXCLUDES_DOT /* mandated by rfc2818 */ @@ -466,13 +459,18 @@ static bool_t pattern_match (const char *pattern, const char *string) return *n == '\0'; } -static bool_t Ssl_check_cert_hostname(X509 *cert, const DilloUrl *url, +/* + * Check that the certificate corresponds to the site it's presented for. + * + * Return TRUE if the hostname matched or the user indicated acceptance. + * FALSE on failure. + */ +static bool_t Tls_check_cert_hostname(X509 *cert, const char *host, int *choice) { - dReturn_val_if_fail(cert && url, -1); + dReturn_val_if_fail(cert && host, FALSE); char *msg; - const char *host = URL_HOST(url); GENERAL_NAMES *subjectAltNames; bool_t success = TRUE, alt_name_checked = FALSE;; char common_name[256]; @@ -493,6 +491,10 @@ static bool_t Ssl_check_cert_hostname(X509 *cert, const DilloUrl *url, { /* Test subject alternative names */ + Dstr *err = dStr_new(""); + dStr_sprintf(err, "Hostname %s does not match any of certificate's " + "Subject Alternative Names: ", host); + /* Do we want to check for dNSNAmes or ipAddresses (see RFC 2818)? * Signal it by host_in_octet_string. */ ASN1_OCTET_STRING *host_in_octet_string = a2i_IPADDRESS (host); @@ -516,6 +518,7 @@ static bool_t Ssl_check_cert_hostname(X509 *cert, const DilloUrl *url, if (!ASN1_STRING_cmp (host_in_octet_string, name->d.iPAddress)) break; + dStr_sprintfa(err, "%s ", name->d.iPAddress); } } else if (name->type == GEN_DNS) @@ -537,6 +540,7 @@ static bool_t Ssl_check_cert_hostname(X509 *cert, const DilloUrl *url, OPENSSL_free (name_in_utf8); break; } + dStr_sprintfa(err, "%s ", name_in_utf8); OPENSSL_free (name_in_utf8); } } @@ -549,11 +553,8 @@ static bool_t Ssl_check_cert_hostname(X509 *cert, const DilloUrl *url, if (alt_name_checked == TRUE && i >= numaltnames) { success = FALSE; - msg = dStrconcat("No certificate subject alternative name matches" - " requested host name \n", host, NULL); - *choice = a_Dialog_choice("Dillo SSL security warning", - msg, "Continue", "Cancel", NULL); - dFree(msg); + *choice = a_Dialog_choice("Dillo TLS security warning", + err->str, "Continue", "Cancel", NULL); switch (*choice){ case 1: @@ -565,6 +566,7 @@ static bool_t Ssl_check_cert_hostname(X509 *cert, const DilloUrl *url, break; } } + dStr_free(err, 1); } if (alt_name_checked == FALSE) @@ -580,7 +582,7 @@ static bool_t Ssl_check_cert_hostname(X509 *cert, const DilloUrl *url, success = FALSE; msg = dStrconcat("Certificate common name ", common_name, " doesn't match requested host name ", host, NULL); - *choice = a_Dialog_choice("Dillo SSL security warning", + *choice = a_Dialog_choice("Dillo TLS security warning", msg, "Continue", "Cancel", NULL); dFree(msg); @@ -626,7 +628,7 @@ static bool_t Ssl_check_cert_hostname(X509 *cert, const DilloUrl *url, "character). This may be an indication that the " "host is not who it claims to be -- that is, not " "the real ", host, NULL); - *choice = a_Dialog_choice("Dillo SSL security warning", + *choice = a_Dialog_choice("Dillo TLS security warning", msg, "Continue", "Cancel", NULL); dFree(msg); @@ -648,18 +650,58 @@ static bool_t Ssl_check_cert_hostname(X509 *cert, const DilloUrl *url, /******************** END OF STUFF DERIVED FROM wget-1.16.3 */ /* + * Get the certificate at the end of the chain, or NULL on failure. + * + * Rumor has it that the stack can be NULL if a connection has been reused + * and that the stack can then be reconstructed if necessary, but it doesn't + * sound like a case we'll encounter. + */ +static X509 *Tls_get_end_of_chain(SSL *ssl) +{ + STACK_OF(X509) *sk = SSL_get_peer_cert_chain(ssl); + + return sk ? sk_X509_value(sk, sk_X509_num(sk) - 1) : NULL; +} + +static void Tls_get_issuer_name(X509 *cert, char *buf, uint_t buflen) +{ + if (cert) { + X509_NAME_oneline(X509_get_issuer_name(cert), buf, buflen); + } else { + strncpy(buf, "(unknown)", buflen); + buf[buflen-1] = '\0'; + } +} + +static void Tls_get_expiration_str(X509 *cert, char *buf, uint_t buflen) +{ + ASN1_TIME *exp_date = X509_get_notAfter(cert); + BIO *b = BIO_new(BIO_s_mem()); + int rc = ASN1_TIME_print(b, exp_date); + + if (rc > 0) { + rc = BIO_gets(b, buf, buflen); + } + if (rc <= 0) { + strncpy(buf, "(unknown)", buflen); + buf[buflen-1] = '\0'; + } + BIO_free(b); +} + +/* * Examine the certificate, and, if problems are detected, ask the user what * to do. * Return: -1 if connection should be canceled, or 0 if it should continue. */ -static int Ssl_examine_certificate(SSL *ssl, const DilloUrl *url) +static int Tls_examine_certificate(SSL *ssl, Server_t *srv,const char *host) { X509 *remote_cert; long st; - char buf[4096], *cn, *msg; + const uint_t buflen = 4096; + char buf[buflen], *cn, *msg; int choice = -1, ret = -1; - char *title = dStrconcat("Dillo SSL security warning: ",URL_HOST(url),NULL); - Server_t *srv = dList_find_custom(servers, url, Ssl_servers_cmp); + char *title = dStrconcat("Dillo TLS security warning: ", host, NULL); remote_cert = SSL_get_peer_certificate(ssl); if (remote_cert == NULL){ @@ -674,7 +716,7 @@ static int Ssl_examine_certificate(SSL *ssl, const DilloUrl *url) ret = 0; } - } else if (Ssl_check_cert_hostname(remote_cert, url, &choice)) { + } else if (Tls_check_cert_hostname(remote_cert, host, &choice)) { /* Figure out if (and why) the remote system can't be trusted */ st = SSL_get_verify_result(ssl); switch (st) { @@ -713,7 +755,7 @@ static int Ssl_examine_certificate(SSL *ssl, const DilloUrl *url) /* Save certificate to a file here and recheck the chain */ /* Potential security problems because we are writing * to the filesystem */ - Ssl_save_certificate_home(remote_cert); + Tls_save_certificate_home(remote_cert); ret = 1; break; default: @@ -761,14 +803,15 @@ static int Ssl_examine_certificate(SSL *ssl, const DilloUrl *url) break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_CRL_HAS_EXPIRED: - choice = a_Dialog_choice(title, - "The remote certificate has expired. The certificate " - "wasn't designed to last this long. You should avoid " - "this site.", - "Continue", "Cancel", NULL); + Tls_get_expiration_str(remote_cert, buf, buflen); + msg = dStrconcat("The remote certificate expired on: ", buf, + ". This site can no longer be trusted.", NULL); + + choice = a_Dialog_choice(title, msg, "Continue", "Cancel", NULL); if (choice == 1) { ret = 0; } + dFree(msg); break; case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: @@ -812,23 +855,24 @@ static int Ssl_examine_certificate(SSL *ssl, const DilloUrl *url) } break; case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: - choice = a_Dialog_choice(title, - "Self signed certificate in certificate chain. The certificate " - "chain could be built up using the untrusted certificates but the " - "root could not be found locally.", - "Continue", "Cancel", NULL); + Tls_get_issuer_name(Tls_get_end_of_chain(ssl), buf, buflen); + msg = dStrconcat("Certificate chain led to a self-signed certificate " + "instead of a trusted root. Name: ", buf , NULL); + choice = a_Dialog_choice(title, msg, "Continue", "Cancel", NULL); if (choice == 1) { ret = 0; } + dFree(msg); break; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: - choice = a_Dialog_choice(title, - "Unable to get local issuer certificate. The issuer certificate " - "of an untrusted certificate cannot be found.", - "Continue", "Cancel", NULL); + Tls_get_issuer_name(Tls_get_end_of_chain(ssl), buf, buflen); + msg = dStrconcat("The issuer certificate of an untrusted certificate " + "cannot be found. Issuer: ", buf, NULL); + choice = a_Dialog_choice(title, msg, "Continue", "Cancel", NULL); if (choice == 1) { ret = 0; } + dFree(msg); break; default: /* Need to add more options later */ snprintf(buf, 80, @@ -859,10 +903,10 @@ static int Ssl_examine_certificate(SSL *ssl, const DilloUrl *url) * If the connection was closed before we got the certificate, we need to * reset state so that we'll try again. */ -void a_Ssl_reset_server_state(const DilloUrl *url) +void a_Tls_reset_server_state(const DilloUrl *url) { if (servers) { - Server_t *s = dList_find_custom(servers, url, Ssl_servers_cmp); + Server_t *s = dList_find_sorted(servers, url, Tls_servers_by_url_cmp); if (s && s->cert_status == CERT_STATUS_RECEIVING) s->cert_status = CERT_STATUS_NONE; @@ -870,14 +914,14 @@ void a_Ssl_reset_server_state(const DilloUrl *url) } /* - * Close an open SSL connection. + * Close an open TLS connection. */ -static void Ssl_close_by_key(int connkey) +static void Tls_close_by_key(int connkey) { Conn_t *c; if ((c = a_Klist_get_data(conn_list, connkey))) { - a_Ssl_reset_server_state(c->url); + a_Tls_reset_server_state(c->url); if (c->connecting) { a_IOwatch_remove_fd(c->fd, -1); dClose(c->fd); @@ -886,24 +930,100 @@ static void Ssl_close_by_key(int connkey) SSL_free(c->ssl); a_Url_free(c->url); - Ssl_fd_map_remove_entry(c->fd); + Tls_fd_map_remove_entry(c->fd); a_Klist_remove(conn_list, connkey); dFree(c); } } +static void Tls_print_cert_chain(SSL *ssl) +{ + STACK_OF(X509) *sk = SSL_get_peer_cert_chain(ssl); + + if (sk) { + const uint_t buflen = 4096; + char buf[buflen]; + int rc, i, n = sk_X509_num(sk); + X509 *cert = NULL; + EVP_PKEY *public_key; + int key_type, key_bits; + const char *type_str; + BIO *b; + + for (i = 0; i < n; i++) { + cert = sk_X509_value(sk, i); + public_key = X509_get_pubkey(cert); + + /* We are trying to find a way to get the hash function used + * with a certificate. This way, which is not very pleasant, puts + * a string such as "sha256WithRSAEncryption" in our buffer and we + * then trim off the "With..." part. + */ + b = BIO_new(BIO_s_mem()); + rc = i2a_ASN1_OBJECT(b, cert->sig_alg->algorithm); + + if (rc > 0) { + rc = BIO_gets(b, buf, buflen); + } + if (rc <= 0) { + strcpy(buf, "(unknown)"); + buf[buflen-1] = '\0'; + } else { + char *s = strstr(buf, "With"); + + if (s) { + *s = '\0'; + if (!strcmp(buf, "sha1")) { + MSG_WARN("In 2015, browsers have begun to deprecate SHA1 " + "certificates.\n"); + } else if (!strncmp(buf, "md", 2)) { + MSG_ERR("Browsers stopped accepting MD5 certificates around " + "2012.\n"); + } + } + } + BIO_free(b); + MSG("%s ", buf); + + + key_type = EVP_PKEY_type(public_key->type); + type_str = key_type == EVP_PKEY_RSA ? "RSA" : + key_type == EVP_PKEY_DSA ? "DSA" : + key_type == EVP_PKEY_DH ? "DH" : + key_type == EVP_PKEY_EC ? "EC" : "???"; + key_bits = EVP_PKEY_bits(public_key); + X509_NAME_oneline(X509_get_subject_name(cert), buf, buflen); + buf[buflen-1] = '\0'; + MSG("%d-bit %s: %s\n", key_bits, type_str, buf); + EVP_PKEY_free(public_key); + + if (key_type == EVP_PKEY_RSA && key_bits <= 1024) { + /* TODO: Gather warnings into one popup. */ + MSG_WARN("In 2014/5, browsers have been deprecating 1024-bit RSA " + "keys.\n"); + } + } + + if (cert) { + X509_NAME_oneline(X509_get_issuer_name(cert), buf, buflen); + buf[buflen-1] = '\0'; + MSG("root: %s\n", buf); + } + } +} + /* * Connect, set a callback if it's still not completed. If completed, check * the certificate and report back to http. */ -static void Ssl_connect(int fd, int connkey) +static void Tls_connect(int fd, int connkey) { int ret; bool_t ongoing = FALSE, failed = TRUE; Conn_t *conn; if (!(conn = a_Klist_get_data(conn_list, connkey))) { - MSG("Ssl_connect: conn for fd %d not valid\n", fd); + MSG("Tls_connect: conn for fd %d not valid\n", fd); return; } @@ -917,10 +1037,10 @@ static void Ssl_connect(int fd, int connkey) err1_ret == SSL_ERROR_WANT_WRITE) { int want = err1_ret == SSL_ERROR_WANT_READ ? DIO_READ : DIO_WRITE; - _MSG("iowatching fd %d for ssl -- want %s\n", fd, + _MSG("iowatching fd %d for tls -- want %s\n", fd, err1_ret == SSL_ERROR_WANT_READ ? "read" : "write"); a_IOwatch_remove_fd(fd, -1); - a_IOwatch_add_fd(fd, want, Ssl_connect_cb, INT2VOIDP(connkey)); + a_IOwatch_add_fd(fd, want, Tls_connect_cb, INT2VOIDP(connkey)); ongoing = TRUE; failed = FALSE; } else if (err1_ret == SSL_ERROR_SYSCALL || err1_ret == SSL_ERROR_SSL) { @@ -934,14 +1054,14 @@ static void Ssl_connect(int fd, int connkey) } else { /* nothing in the error queue */ if (ret == 0) { - MSG("SSL connect error: \"an EOF was observed that violates " + MSG("TLS connect error: \"an EOF was observed that violates " "the protocol\"\n"); /* * I presume we took too long on our side and the server grew * impatient. */ } else if (ret == -1) { - MSG("SSL connect error: %s\n", dStrerror(errno)); + MSG("TLS connect error: %s\n", dStrerror(errno)); /* If the following can happen, I'll add code to handle it, but * I don't want to add code blindly if it isn't getting used @@ -956,9 +1076,24 @@ static void Ssl_connect(int fd, int connkey) MSG("SSL_get_error() returned %d on a connect.\n", err1_ret); } } else { - if (Ssl_user_said_yes(conn->url) || - (Ssl_examine_certificate(conn->ssl, conn->url) != -1)) + Server_t *srv = dList_find_sorted(servers, conn->url, + Tls_servers_by_url_cmp); + + if (srv->cert_status == CERT_STATUS_RECEIVING) { + /* Making first connection with the server. Show some information. */ + SSL *ssl = conn->ssl; + const char *version = SSL_get_version(ssl); + const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); + + MSG("%s: %s, cipher %s\n", URL_AUTHORITY(conn->url), version, + SSL_CIPHER_get_name(cipher)); + Tls_print_cert_chain(ssl); + } + + if (srv->cert_status == CERT_STATUS_USER_ACCEPTED || + (Tls_examine_certificate(conn->ssl, srv, URL_HOST(conn->url))!=-1)) { failed = FALSE; + } } /* @@ -970,7 +1105,7 @@ static void Ssl_connect(int fd, int connkey) if (a_Klist_get_data(conn_list, connkey)) { conn->connecting = FALSE; if (failed) { - Ssl_close_by_key(connkey); + Tls_close_by_key(connkey); } a_IOwatch_remove_fd(fd, DIO_READ|DIO_WRITE); a_Http_connect_done(fd, failed ? FALSE : TRUE); @@ -980,15 +1115,15 @@ static void Ssl_connect(int fd, int connkey) } } -static void Ssl_connect_cb(int fd, void *vconnkey) +static void Tls_connect_cb(int fd, void *vconnkey) { - Ssl_connect(fd, VOIDP2INT(vconnkey)); + Tls_connect(fd, VOIDP2INT(vconnkey)); } /* - * Perform the SSL handshake on an open socket. + * Perform the TLS handshake on an open socket. */ -void a_Ssl_handshake(int fd, const DilloUrl *url) +void a_Tls_handshake(int fd, const DilloUrl *url) { SSL *ssl; bool_t success = TRUE; @@ -997,7 +1132,7 @@ void a_Ssl_handshake(int fd, const DilloUrl *url) if (!ssl_context) success = FALSE; - if (success && Ssl_user_said_no(url)) { + if (success && Tls_user_said_no(url)) { success = FALSE; } @@ -1011,7 +1146,7 @@ void a_Ssl_handshake(int fd, const DilloUrl *url) success = FALSE; } - /* assign SSL connection to this file descriptor */ + /* assign TLS connection to this file descriptor */ if (success && !SSL_set_fd(ssl, fd)) { unsigned long err_ret = ERR_get_error(); do { @@ -1021,7 +1156,7 @@ void a_Ssl_handshake(int fd, const DilloUrl *url) } if (success) - connkey = Ssl_conn_new(fd, url, ssl); + connkey = Tls_conn_new(fd, url, ssl); #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME /* Server Name Indication. From the openssl changelog, it looks like this @@ -1032,42 +1167,42 @@ void a_Ssl_handshake(int fd, const DilloUrl *url) #endif if (!success) { - a_Ssl_reset_server_state(url); + a_Tls_reset_server_state(url); a_Http_connect_done(fd, success); } else { - Ssl_connect(fd, connkey); + Tls_connect(fd, connkey); } } /* - * Read data from an open SSL connection. + * Read data from an open TLS connection. */ -int a_Ssl_read(void *conn, void *buf, size_t len) +int a_Tls_read(void *conn, void *buf, size_t len) { Conn_t *c = (Conn_t*)conn; return SSL_read(c->ssl, buf, len); } /* - * Write data to an open SSL connection. + * Write data to an open TLS connection. */ -int a_Ssl_write(void *conn, void *buf, size_t len) +int a_Tls_write(void *conn, void *buf, size_t len) { Conn_t *c = (Conn_t*)conn; return SSL_write(c->ssl, buf, len); } -void a_Ssl_close_by_fd(int fd) +void a_Tls_close_by_fd(int fd) { FdMapEntry_t *fme = dList_find_custom(fd_map, INT2VOIDP(fd), - Ssl_fd_map_cmp); + Tls_fd_map_cmp); if (fme) { - Ssl_close_by_key(fme->connkey); + Tls_close_by_key(fme->connkey); } } -static void Ssl_servers_freeall() +static void Tls_servers_freeall() { if (servers) { Server_t *s; @@ -1082,7 +1217,7 @@ static void Ssl_servers_freeall() } } -static void Ssl_fd_map_remove_all() +static void Tls_fd_map_remove_all() { if (fd_map) { FdMapEntry_t *fme; @@ -1099,12 +1234,12 @@ static void Ssl_fd_map_remove_all() /* * Clean up the OpenSSL library */ -void a_Ssl_freeall(void) +void a_Tls_freeall(void) { if (ssl_context) SSL_CTX_free(ssl_context); - Ssl_fd_map_remove_all(); - Ssl_servers_freeall(); + Tls_fd_map_remove_all(); + Tls_servers_freeall(); } #endif /* ENABLE_SSL */ diff --git a/src/IO/tls.h b/src/IO/tls.h new file mode 100644 index 00000000..e3892cb2 --- /dev/null +++ b/src/IO/tls.h @@ -0,0 +1,47 @@ +#ifndef __TLS_H__ +#define __TLS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../url.h" + +#define TLS_CONNECT_NEVER -1 +#define TLS_CONNECT_NOT_YET 0 +#define TLS_CONNECT_READY 1 + +void a_Tls_init(); + + +#ifdef ENABLE_SSL +int a_Tls_connect_ready(const DilloUrl *url); +void a_Tls_reset_server_state(const DilloUrl *url); + +/* Use to initiate a TLS connection. */ +void a_Tls_handshake(int fd, const DilloUrl *url); + +void *a_Tls_connection(int fd); + +void a_Tls_freeall(); + +void a_Tls_close_by_fd(int fd); +int a_Tls_read(void *conn, void *buf, size_t len); +int a_Tls_write(void *conn, void *buf, size_t len); +#else + +#define a_Tls_connect_ready(url) TLS_CONNECT_NEVER +#define a_Tls_reset_server_state(url) ; +#define a_Tls_handshake(fd, url) ; +#define a_Tls_connection(fd) NULL +#define a_Tls_freeall() ; +#define a_Tls_close_by_fd(fd) ; +#define a_Tls_read(conn, buf, len) 0 +#define a_Tls_write(conn, buf, len) 0 +#endif +#ifdef __cplusplus +} +#endif + +#endif /* __TLS_H__ */ + diff --git a/src/cache.c b/src/cache.c index 2cc8c0aa..d8f1a123 100644 --- a/src/cache.c +++ b/src/cache.c @@ -756,6 +756,7 @@ static void Cache_parse_header(CacheEntry_t *entry) if (!web->requester || a_Url_same_organization(entry->Url, web->requester)) { + /* If cookies are third party, don't even consider them. */ char *server_date = Cache_parse_field(header, "Date"); a_Cookies_set(Cookies, entry->Url, server_date); @@ -764,10 +765,6 @@ static void Cache_parse_header(CacheEntry_t *entry) } } } - if (i >= dList_length(ClientQueue)) { - MSG("Cache: cookies not accepted from '%s'\n", URL_STR(entry->Url)); - } - for (i = 0; (data = dList_nth_data(Cookies, i)); ++i) dFree(data); dList_free(Cookies); @@ -857,17 +854,6 @@ static void Cache_finish_msg(CacheEntry_t *entry) MSG("Expected size: %d, Transfer size: %d\n", entry->ExpectedSize, entry->TransferSize); } - if (!entry->TransferSize && !(entry->Flags & CA_Redirect) && - (entry->Flags & WEB_RootUrl)) { - char *eol = strchr(entry->Header->str, '\n'); - if (eol) { - char *status_line = dStrndup(entry->Header->str, - eol - entry->Header->str); - MSG_HTTP("Body of %s was empty. Server sent status: %s\n", - URL_STR_(entry->Url), status_line); - dFree(status_line); - } - } entry->Flags |= CA_GotData; entry->Flags &= ~CA_Stopped; /* it may catch up! */ if (entry->TransferDecoder) { diff --git a/src/dialog.cc b/src/dialog.cc index 10988c98..03949a1c 100644 --- a/src/dialog.cc +++ b/src/dialog.cc @@ -325,6 +325,7 @@ static void choice_cb(Fl_Widget *button, void *number) { choice_answer = VOIDP2INT(number); _MSG("choice_cb: %d\n", choice_answer); + button->window()->hide(); } @@ -358,16 +359,15 @@ int a_Dialog_choice(const char *title, const char *msg, ...) Fl_Window *window = new Fl_Window(ww, wh, title); window->set_modal(); window->begin(); - Fl_Group *ib = new Fl_Group(0, 0, window->w(), window->h()); - ib->begin(); - window->resizable(ib); - if (msg != NULL){ - Fl_Box *box = new Fl_Box(0, 0, ww, wh - bh, msg); - box->labelfont(FL_HELVETICA); - box->labelsize(14); - box->align(FL_ALIGN_WRAP); - } + Fl_Text_Buffer *buf = new Fl_Text_Buffer(); + buf->text(msg); + Fl_Text_Display *td = new Fl_Text_Display(0, 0, ww, wh - bh); + td->buffer(buf); + td->textsize((int) rint(14.0 * prefs.font_factor)); + td->wrap_mode(Fl_Text_Display::WRAP_AT_BOUNDS, 0); + + window->resizable(td); int xpos = gap; va_start(ap, msg); @@ -386,6 +386,8 @@ int a_Dialog_choice(const char *title, const char *msg, ...) while (window->shown()) Fl::wait(); _MSG("Dialog_choice answer = %d\n", answer); + td->buffer(NULL); + delete buf; delete window; return choice_answer; diff --git a/src/dillo.cc b/src/dillo.cc index 847c9d63..17747c59 100644 --- a/src/dillo.cc +++ b/src/dillo.cc @@ -45,7 +45,7 @@ #include "dns.h" #include "web.hh" -#include "IO/ssl.h" +#include "IO/tls.h" #include "IO/Url.h" #include "IO/mime.h" #include "capi.h" @@ -477,7 +477,7 @@ int main(int argc, char **argv) a_Dns_init(); a_Web_init(); a_Http_init(); - a_Ssl_init(); + a_Tls_init(); a_Mime_init(); a_Capi_init(); a_Dicache_init(); @@ -599,7 +599,7 @@ int main(int argc, char **argv) a_Cache_freeall(); a_Dicache_freeall(); a_Http_freeall(); - a_Ssl_freeall(); + a_Tls_freeall(); a_Dns_freeall(); a_History_freeall(); a_Prefs_freeall(); diff --git a/src/html.cc b/src/html.cc index 3e4f27a8..a92771d3 100644 --- a/src/html.cc +++ b/src/html.cc @@ -2514,8 +2514,6 @@ static void if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "href"))) { url = a_Html_url_new(html, attrbuf, NULL, 0); dReturn_if_fail ( url != NULL ); - if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "alt"))) - a_Url_set_alt(url, attrbuf); link = Html_set_new_link(html, &url); } @@ -204,7 +204,6 @@ void a_Url_free(DilloUrl *url) dFree((char *)url->hostname); dFree((char *)url->buffer); dStr_free(url->data, 1); - dFree((char *)url->alt); dFree(url); } } @@ -213,7 +212,6 @@ void a_Url_free(DilloUrl *url) * Resolve the URL as RFC3986 suggests. */ static Dstr *Url_resolve_relative(const char *RelStr, - DilloUrl *BaseUrlPar, const char *BaseStr) { char *p, *s, *e; @@ -224,9 +222,7 @@ static Dstr *Url_resolve_relative(const char *RelStr, /* parse relative URL */ RelUrl = Url_object_new(RelStr); - if (BaseUrlPar) { - BaseUrl = BaseUrlPar; - } else if (RelUrl->scheme == NULL) { + if (RelUrl->scheme == NULL) { /* only required when there's no <scheme> in RelStr */ BaseUrl = Url_object_new(BaseStr); } @@ -336,8 +332,7 @@ static Dstr *Url_resolve_relative(const char *RelStr, done: dStr_free(Path, TRUE); a_Url_free(RelUrl); - if (BaseUrl != BaseUrlPar) - a_Url_free(BaseUrl); + a_Url_free(BaseUrl); return SolvedUrl; } @@ -356,7 +351,6 @@ done: * port = 8080 * flags = URL_Get * data = Dstr * ("") - * alt = NULL * ismap_url_len = 0 * } * @@ -406,7 +400,7 @@ DilloUrl* a_Url_new(const char *url_str, const char *base_url) } /* Resolve the URL */ - SolvedUrl = Url_resolve_relative(urlstr, NULL, base_url); + SolvedUrl = Url_resolve_relative(urlstr, base_url); _MSG("SolvedUrl = %s\n", SolvedUrl->str); /* Fill url data */ @@ -435,7 +429,6 @@ DilloUrl* a_Url_dup(const DilloUrl *ori) url->url_string = dStr_new(URL_STR(ori)); url->port = ori->port; url->flags = ori->flags; - url->alt = dStrdup(ori->alt); url->ismap_url_len = ori->ismap_url_len; url->illegal_chars = ori->illegal_chars; url->illegal_chars_spc = ori->illegal_chars_spc; @@ -495,17 +488,6 @@ void a_Url_set_data(DilloUrl *u, Dstr **data) } /* - * Set DilloUrl alt (alternate text to the URL. Used by image maps) - */ -void a_Url_set_alt(DilloUrl *u, const char *alt) -{ - if (u) { - dFree((char *)u->alt); - u->alt = dStrdup(alt); - } -} - -/* * Set DilloUrl ismap coordinates * (this is optimized for not hogging the CPU) */ @@ -516,7 +498,6 @@ void a_Url_set_ismap_coords(DilloUrl *u, char *coord_str) if (!u->ismap_url_len) { /* Save base-url length (without coords) */ u->ismap_url_len = URL_STR_(u) ? u->url_string->len : 0; - a_Url_set_flags(u, URL_FLAGS(u) | URL_Ismap); } if (u->url_string) { dStr_truncate(u->url_string, u->ismap_url_len); @@ -22,12 +22,8 @@ */ #define URL_Get (1 << 0) #define URL_Post (1 << 1) -#define URL_ISindex (1 << 2) -#define URL_Ismap (1 << 3) -#define URL_RealmAccess (1 << 4) #define URL_E2EQuery (1 << 5) -#define URL_ReloadImages (1 << 6) #define URL_ReloadPage (1 << 7) #define URL_ReloadFromCache (1 << 8) @@ -47,7 +43,6 @@ #define URL_QUERY_(u) (u)->query #define URL_FRAGMENT_(u) (u)->fragment #define URL_HOST_(u) a_Url_hostname(u) -#define URL_ALT_(u) (u)->alt #define URL_STR_(u) a_Url_str(u) /* this returns a Dstr* */ #define URL_DATA_(u) (u)->data @@ -69,9 +64,8 @@ #define URL_QUERY(u) NPTR2STR(URL_QUERY_(u)) #define URL_FRAGMENT(u) NPTR2STR(URL_FRAGMENT_(u)) #define URL_HOST(u) NPTR2STR(URL_HOST_(u)) -#define URL_DATA(u) URL_DATA_(u) -#define URL_ALT(u) NPTR2STR(URL_ALT_(u)) #define URL_STR(u) NPTR2STR(URL_STR_(u)) +#define URL_DATA(u) URL_DATA_(u) #define URL_PORT(u) URL_PORT_(u) #define URL_FLAGS(u) URL_FLAGS_(u) #define URL_ILLEGAL_CHARS(u) URL_ILLEGAL_CHARS_(u) @@ -94,7 +88,6 @@ typedef struct { int port; int flags; Dstr *data; /* POST */ - const char *alt; /* "alt" text (used by image maps) */ int ismap_url_len; /* Used by server side image maps */ int illegal_chars; /* number of illegal chars */ int illegal_chars_spc; /* number of illegal space chars */ @@ -109,7 +102,6 @@ DilloUrl* a_Url_dup(const DilloUrl *u); int a_Url_cmp(const DilloUrl *A, const DilloUrl *B); void a_Url_set_flags(DilloUrl *u, int flags); void a_Url_set_data(DilloUrl *u, Dstr **data); -void a_Url_set_alt(DilloUrl *u, const char *alt); void a_Url_set_ismap_coords(DilloUrl *u, char *coord_str); char *a_Url_decode_hex_str(const char *str); char *a_Url_encode_hex_str(const char *str); |