summaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/fetch.c8
-rw-r--r--content/fetch.h27
-rw-r--r--content/fetchers/about.c1
-rw-r--r--content/fetchers/curl.c37
-rw-r--r--content/fetchers/data.c2
-rw-r--r--content/fetchers/file.c1
-rw-r--r--content/fetchers/resource.c1
-rw-r--r--content/llcache.c53
8 files changed, 104 insertions, 26 deletions
diff --git a/content/fetch.c b/content/fetch.c
index 028fe9ee4..bfe4458cf 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -235,7 +235,8 @@ struct fetch * fetch_start(nsurl *url, nsurl *referer,
fetch_callback callback,
void *p, bool only_2xx, const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
- bool verifiable, const char *headers[])
+ bool verifiable, bool downgrade_tls,
+ const char *headers[])
{
struct fetch *fetch;
scheme_fetcher *fetcher = fetchers;
@@ -321,8 +322,9 @@ struct fetch * fetch_start(nsurl *url, nsurl *referer,
/* Got a scheme fetcher, try and set up the fetch */
fetch->fetcher_handle = fetch->ops->setup_fetch(fetch, url,
- only_2xx, post_urlenc,
- post_multipart, headers);
+ only_2xx, downgrade_tls,
+ post_urlenc, post_multipart,
+ headers);
if (fetch->fetcher_handle == NULL)
goto failed;
diff --git a/content/fetch.h b/content/fetch.h
index d7cdced1b..d23b3cd4b 100644
--- a/content/fetch.h
+++ b/content/fetch.h
@@ -43,7 +43,8 @@ typedef enum {
FETCH_REDIRECT,
FETCH_NOTMODIFIED,
FETCH_AUTH,
- FETCH_CERT_ERR
+ FETCH_CERT_ERR,
+ FETCH_SSL_ERR
} fetch_msg_type;
typedef struct fetch_msg {
@@ -103,7 +104,7 @@ struct fetch * fetch_start(nsurl *url, nsurl *referer,
fetch_callback callback,
void *p, bool only_2xx, const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
- bool verifiable,
+ bool verifiable, bool downgrade_tls,
const char *headers[]);
void fetch_abort(struct fetch *f);
void fetch_poll(void);
@@ -123,17 +124,17 @@ struct fetch_multipart_data *fetch_multipart_data_clone(
/* API for fetchers themselves */
-typedef bool (*fetcher_initialise)(lwc_string *);
-typedef bool (*fetcher_can_fetch)(const nsurl *);
-typedef void* (*fetcher_setup_fetch)(struct fetch *, nsurl *,
- bool, const char *,
- const struct fetch_multipart_data *,
- const char **);
-typedef bool (*fetcher_start_fetch)(void *);
-typedef void (*fetcher_abort_fetch)(void *);
-typedef void (*fetcher_free_fetch)(void *);
-typedef void (*fetcher_poll_fetcher)(lwc_string *);
-typedef void (*fetcher_finalise)(lwc_string *);
+typedef bool (*fetcher_initialise)(lwc_string *scheme);
+typedef bool (*fetcher_can_fetch)(const nsurl *url);
+typedef void *(*fetcher_setup_fetch)(struct fetch *parent_fetch, nsurl *url,
+ bool only_2xx, bool downgrade_tls, const char *post_urlenc,
+ const struct fetch_multipart_data *post_multipart,
+ const char **headers);
+typedef bool (*fetcher_start_fetch)(void *fetch);
+typedef void (*fetcher_abort_fetch)(void *fetch);
+typedef void (*fetcher_free_fetch)(void *fetch);
+typedef void (*fetcher_poll_fetcher)(lwc_string *scheme);
+typedef void (*fetcher_finalise)(lwc_string *scheme);
/** Register a fetcher for a scheme
*
diff --git a/content/fetchers/about.c b/content/fetchers/about.c
index 78f22df01..387e32a98 100644
--- a/content/fetchers/about.c
+++ b/content/fetchers/about.c
@@ -729,6 +729,7 @@ static void *
fetch_about_setup(struct fetch *fetchh,
nsurl *url,
bool only_2xx,
+ bool downgrade_tls,
const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers)
diff --git a/content/fetchers/curl.c b/content/fetchers/curl.c
index ff7ccbe30..668e05a46 100644
--- a/content/fetchers/curl.c
+++ b/content/fetchers/curl.c
@@ -77,6 +77,7 @@ struct curl_fetch_info {
bool abort; /**< Abort requested. */
bool stopped; /**< Download stopped on purpose. */
bool only_2xx; /**< Only HTTP 2xx responses acceptable. */
+ bool downgrade_tls; /**< Downgrade to TLS <= 1.0 */
nsurl *url; /**< URL of this fetch. */
lwc_string *host; /**< The hostname of this fetch. */
struct curl_slist *headers; /**< List of request headers. */
@@ -114,7 +115,7 @@ static bool fetch_curl_initialise(lwc_string *scheme);
static void fetch_curl_finalise(lwc_string *scheme);
static bool fetch_curl_can_fetch(const nsurl *url);
static void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url,
- bool only_2xx, const char *post_urlenc,
+ bool only_2xx, bool downgrade_tls, const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers);
static bool fetch_curl_start(void *vfetch);
@@ -348,7 +349,7 @@ bool fetch_curl_can_fetch(const nsurl *url)
*/
void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url,
- bool only_2xx, const char *post_urlenc,
+ bool only_2xx, bool downgrade_tls, const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers)
{
@@ -370,6 +371,7 @@ void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url,
fetch->abort = false;
fetch->stopped = false;
fetch->only_2xx = only_2xx;
+ fetch->downgrade_tls = downgrade_tls;
fetch->headers = NULL;
fetch->url = nsurl_ref(url);
fetch->host = nsurl_get_component(url, NSURL_HOST);
@@ -665,14 +667,28 @@ fetch_curl_set_options(struct curl_fetch_info *f)
CURLcode
fetch_curl_sslctxfun(CURL *curl_handle, void *_sslctx, void *parm)
{
+ struct curl_fetch_info *f = (struct curl_fetch_info *) parm;
SSL_CTX *sslctx = _sslctx;
+ long options = SSL_OP_ALL;
+
SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, fetch_curl_verify_callback);
SSL_CTX_set_cert_verify_callback(sslctx, fetch_curl_cert_verify_callback,
parm);
+
+ if (f->downgrade_tls) {
+#ifdef SSL_OP_NO_TLSv1_1
+ /* Disable TLS1.1, if the server can't cope with it */
+ options |= SSL_OP_NO_TLSv1_1;
+#endif
+ }
+
#ifdef SSL_OP_NO_TLSv1_2
/* Disable TLS1.2, as it causes some servers to stall. */
- SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_2);
+ options |= SSL_OP_NO_TLSv1_2;
#endif
+
+ SSL_CTX_set_options(sslctx, options);
+
return CURLE_OK;
}
@@ -851,17 +867,16 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result)
else {
finished = true;
}
- } else if (result == CURLE_WRITE_ERROR && f->stopped)
+ } else if (result == CURLE_WRITE_ERROR && f->stopped) {
/* CURLE_WRITE_ERROR occurs when fetch_curl_data
* returns 0, which we use to abort intentionally */
;
- else if (result == CURLE_SSL_PEER_CERTIFICATE ||
+ } else if (result == CURLE_SSL_PEER_CERTIFICATE ||
result == CURLE_SSL_CACERT) {
memcpy(certs, f->cert_data, sizeof(certs));
memset(f->cert_data, 0, sizeof(f->cert_data));
cert = true;
- }
- else {
+ } else {
LOG(("Unknown cURL response code %d", result));
error = true;
}
@@ -955,8 +970,12 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result)
msg.data.cert_err.num_certs = i;
fetch_send_callback(&msg, f->fetch_handle);
} else if (error) {
- msg.type = FETCH_ERROR;
- msg.data.error = fetch_error_buffer;
+ if (result != CURLE_SSL_CONNECT_ERROR) {
+ msg.type = FETCH_ERROR;
+ msg.data.error = fetch_error_buffer;
+ } else {
+ msg.type = FETCH_SSL_ERR;
+ }
fetch_send_callback(&msg, f->fetch_handle);
}
diff --git a/content/fetchers/data.c b/content/fetchers/data.c
index 3f8989e8c..77d3c9f9c 100644
--- a/content/fetchers/data.c
+++ b/content/fetchers/data.c
@@ -81,7 +81,7 @@ static bool fetch_data_can_fetch(const nsurl *url)
}
static void *fetch_data_setup(struct fetch *parent_fetch, nsurl *url,
- bool only_2xx, const char *post_urlenc,
+ bool only_2xx, bool downgrade_tls, const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers)
{
diff --git a/content/fetchers/file.c b/content/fetchers/file.c
index 4c02c0c60..b7b831d7b 100644
--- a/content/fetchers/file.c
+++ b/content/fetchers/file.c
@@ -128,6 +128,7 @@ static void *
fetch_file_setup(struct fetch *fetchh,
nsurl *url,
bool only_2xx,
+ bool downgrade_tls,
const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers)
diff --git a/content/fetchers/resource.c b/content/fetchers/resource.c
index 86d5498d5..1fc33f882 100644
--- a/content/fetchers/resource.c
+++ b/content/fetchers/resource.c
@@ -231,6 +231,7 @@ static void *
fetch_resource_setup(struct fetch *fetchh,
nsurl *url,
bool only_2xx,
+ bool downgrade_tls,
const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers)
diff --git a/content/llcache.c b/content/llcache.c
index ed5cc6eda..4bdebdbc2 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -84,6 +84,8 @@ typedef struct {
bool tried_with_auth; /**< Whether we've tried with auth */
+ bool tried_with_tls_downgrade; /**< Whether we've tried TLS <= 1.0 */
+
bool outstanding_query; /**< Waiting for a query response */
} llcache_fetch_ctx;
@@ -711,6 +713,7 @@ static nserror llcache_object_refetch(llcache_object *object)
object->fetch.flags & LLCACHE_RETRIEVE_NO_ERROR_PAGES,
urlenc, multipart,
object->fetch.flags & LLCACHE_RETRIEVE_VERIFIABLE,
+ object->fetch.tried_with_tls_downgrade,
(const char **) headers);
/* Clean up cache-control headers */
@@ -1544,6 +1547,45 @@ static nserror llcache_fetch_cert_error(llcache_object *object,
}
/**
+ * Handle a TLS connection setup failure
+ *
+ * \param object Object being fetched
+ * \return NSERROR_OK on success, appropriate error otherwise
+ */
+static nserror llcache_fetch_ssl_error(llcache_object *object)
+{
+ nserror error = NSERROR_OK;
+
+ /* Fetch has been stopped, and destroyed. Invalidate object's pointer */
+ object->fetch.fetch = NULL;
+
+ /* Invalidate cache-control data */
+ llcache_invalidate_cache_control_data(object);
+
+ if (object->fetch.tried_with_tls_downgrade == true) {
+ /* Have already tried to downgrade, so give up */
+ llcache_event event;
+
+ /* Mark object complete */
+ object->fetch.state = LLCACHE_FETCH_COMPLETE;
+
+ /* Inform client(s) that object fetch failed */
+ event.type = LLCACHE_EVENT_ERROR;
+ /** \todo More appropriate error message */
+ event.data.msg = messages_get("FetchFailed");
+
+ error = llcache_send_event_to_users(object, &event);
+ } else {
+ /* Flag that we've tried to downgrade, so that if the
+ * fetch fails again, we give up */
+ object->fetch.tried_with_tls_downgrade = true;
+ error = llcache_object_refetch(object);
+ }
+
+ return error;
+}
+
+/**
* Handler for fetch events
*
* \param msg Fetch event
@@ -1705,6 +1747,17 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
msg->data.cert_err.certs,
msg->data.cert_err.num_certs);
break;
+ case FETCH_SSL_ERR:
+ /* TLS connection setup failed */
+
+ /* Release candidate, if any */
+ if (object->candidate != NULL) {
+ object->candidate->candidate_count--;
+ object->candidate = NULL;
+ }
+
+ error = llcache_fetch_ssl_error(object);
+ break;
}
/* Deal with any errors reported by event handlers */