From 705d8e9cf0d109005b3441766270c0e584f7847d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 25 Apr 2018 09:43:18 +0200 Subject: dirmngr: Implement CRL fetching via https. * dirmngr/http.h (HTTP_FLAG_TRUST_CFG): New flag. * dirmngr/http.c (http_register_cfg_ca): New. (http_session_new) [HTTP_USE_GNUTLS]: Implement new trust flag. * dirmngr/certcache.c (load_certs_from_dir): Call new function. (cert_cache_deinit): Ditto. * dirmngr/http-ntbtls.c (gnupg_http_tls_verify_cb): Ditto. * dirmngr/ks-engine-http.c (ks_http_fetch): Add new args 'send_no_cache' and 'extra_http_trust_flags'. Change all callers to provide the default value. * dirmngr/crlfetch.c (crl_fetch): Rewrite to make use of ks_http_fetch. -- The old code simply did not use https for downloading of CRLS. Instead it rewrote https to http under the assumption that the CRL service was also available without encryption. Note that a CRL is self-standing and thus it does not need to have extra authenticity as provided by TLS. These days we should not use any unencrypted content and thus this patch. Be aware that cacert.org give a https CRL DP but that currently redirects to to http! This is a downgrade attack which we detect and don't allow. The outcome is that it is right now not possible to use CAcert certificates. Signed-off-by: Werner Koch --- dirmngr/ks-engine-http.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'dirmngr/ks-engine-http.c') diff --git a/dirmngr/ks-engine-http.c b/dirmngr/ks-engine-http.c index 6492dda8a..a03580373 100644 --- a/dirmngr/ks-engine-http.c +++ b/dirmngr/ks-engine-http.c @@ -62,9 +62,13 @@ ks_http_help (ctrl_t ctrl, parsed_uri_t uri) /* Get the key from URL which is expected to specify a http style - scheme. On success R_FP has an open stream to read the data. */ + * scheme. On success R_FP has an open stream to read the data. + * Despite its name this function is also used to retrieve arbitrary + * data via https or http. + */ gpg_error_t -ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp) +ks_http_fetch (ctrl_t ctrl, const char *url, int send_no_cache, + unsigned int extra_http_trust_flags, estream_t *r_fp) { gpg_error_t err; http_session_t session = NULL; @@ -82,11 +86,13 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp) is_https = uri->use_tls; once_more: - /* Note that we only use the system provided certificates with the - * fetch command. */ + /* By default we only use the system provided certificates with this + * fetch command. However, EXTRA_HTTP_FLAGS can be used to add more + * flags. */ err = http_session_new (&session, NULL, ((ctrl->http_no_crl? HTTP_FLAG_NO_CRL : 0) - | HTTP_FLAG_TRUST_SYS), + | HTTP_FLAG_TRUST_SYS + | extra_http_trust_flags), gnupg_http_tls_verify_cb, ctrl); if (err) goto leave; @@ -100,6 +106,7 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp) /* httphost */ NULL, /* fixme: AUTH */ NULL, ((opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0) + | (DBG_LOOKUP? HTTP_FLAG_LOG_RESP:0) | (dirmngr_use_tor ()? HTTP_FLAG_FORCE_TOR:0) | (opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4 : 0) | (opt.disable_ipv6? HTTP_FLAG_IGNORE_IPv6 : 0)), @@ -111,10 +118,11 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp) { fp = http_get_write_ptr (http); /* Avoid caches to get the most recent copy of the key. We set - both the Pragma and Cache-Control versions of the header, so - we're good with both HTTP 1.0 and 1.1. */ - es_fputs ("Pragma: no-cache\r\n" - "Cache-Control: no-cache\r\n", fp); + * both the Pragma and Cache-Control versions of the header, so + * we're good with both HTTP 1.0 and 1.1. */ + if (send_no_cache) + es_fputs ("Pragma: no-cache\r\n" + "Cache-Control: no-cache\r\n", fp); http_start_data (http); if (es_ferror (fp)) err = gpg_error_from_syserror (); -- cgit From 1de4462974113ac18cf98f903e97cd1127fa842f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 25 Apr 2018 12:37:34 +0200 Subject: dirmngr: Allow redirection from https to http for CRLs * dirmngr/ks-engine.h (KS_HTTP_FETCH_NOCACHE): New flag. (KS_HTTP_FETCH_TRUST_CFG): Ditto. (KS_HTTP_FETCH_NO_CRL): Ditto. (KS_HTTP_FETCH_ALLOW_DOWNGRADE): Ditto. * dirmngr/ks-engine-http.c (ks_http_fetch): Replace args send_no_cache and extra_http_trust_flags by a new flags arg. Allow redirectiong from https to http it KS_HTTP_FETCH_ALLOW_DOWNGRADE is set. * dirmngr/loadswdb.c (fetch_file): Call with KS_HTTP_FETCH_NOCACHE. * dirmngr/ks-action.c (ks_action_get): Ditto. (ks_action_fetch): Ditto. * dirmngr/crlfetch.c (crl_fetch): Call with the appropriate flags. -- Signed-off-by: Werner Koch --- dirmngr/crlfetch.c | 13 ++++++++----- dirmngr/ks-action.c | 5 +++-- dirmngr/ks-engine-http.c | 31 ++++++++++++++++++++----------- dirmngr/ks-engine.h | 10 ++++++++-- dirmngr/loadswdb.c | 2 +- 5 files changed, 40 insertions(+), 21 deletions(-) (limited to 'dirmngr/ks-engine-http.c') diff --git a/dirmngr/crlfetch.c b/dirmngr/crlfetch.c index 0d27aa0f1..57ac51b93 100644 --- a/dirmngr/crlfetch.c +++ b/dirmngr/crlfetch.c @@ -175,11 +175,14 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader) else { /* Note that we also allow root certificates loaded from - * "/etc/gnupg/trusted-certs/". We also do not consult - * the CRL for the TLS connection - that may lwad to a - * loop. */ - err = ks_http_fetch (ctrl, url, 0, - (HTTP_FLAG_TRUST_CFG | HTTP_FLAG_NO_CRL), + * "/etc/gnupg/trusted-certs/". We also do not consult the + * CRL for the TLS connection - that may lead to a loop. + * Due to cacert.org redirecting their https URL to http we + * also allow such a downgrade. */ + err = ks_http_fetch (ctrl, url, + (KS_HTTP_FETCH_TRUST_CFG + | KS_HTTP_FETCH_NO_CRL + | KS_HTTP_FETCH_ALLOW_DOWNGRADE ), &httpfp); } diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c index eb15e40dd..c1ecafb58 100644 --- a/dirmngr/ks-action.c +++ b/dirmngr/ks-action.c @@ -257,7 +257,8 @@ ks_action_get (ctrl_t ctrl, uri_item_t keyservers, if (is_hkp_s) err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp); else if (is_http_s) - err = ks_http_fetch (ctrl, uri->parsed_uri->original, 1, 0, + err = ks_http_fetch (ctrl, uri->parsed_uri->original, + KS_HTTP_FETCH_NOCACHE, &infp); else BUG (); @@ -315,7 +316,7 @@ ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp) if (parsed_uri->is_http) { - err = ks_http_fetch (ctrl, url, 1, 0, &infp); + err = ks_http_fetch (ctrl, url, KS_HTTP_FETCH_NOCACHE, &infp); if (!err) { err = copy_stream (infp, outfp); diff --git a/dirmngr/ks-engine-http.c b/dirmngr/ks-engine-http.c index a03580373..946c92769 100644 --- a/dirmngr/ks-engine-http.c +++ b/dirmngr/ks-engine-http.c @@ -67,11 +67,12 @@ ks_http_help (ctrl_t ctrl, parsed_uri_t uri) * data via https or http. */ gpg_error_t -ks_http_fetch (ctrl_t ctrl, const char *url, int send_no_cache, - unsigned int extra_http_trust_flags, estream_t *r_fp) +ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags, + estream_t *r_fp) { gpg_error_t err; http_session_t session = NULL; + unsigned int session_flags; http_t http = NULL; int redirects_left = MAX_REDIRECTS; estream_t fp = NULL; @@ -85,14 +86,16 @@ ks_http_fetch (ctrl_t ctrl, const char *url, int send_no_cache, is_onion = uri->onion; is_https = uri->use_tls; - once_more: /* By default we only use the system provided certificates with this - * fetch command. However, EXTRA_HTTP_FLAGS can be used to add more - * flags. */ - err = http_session_new (&session, NULL, - ((ctrl->http_no_crl? HTTP_FLAG_NO_CRL : 0) - | HTTP_FLAG_TRUST_SYS - | extra_http_trust_flags), + * fetch command. */ + session_flags = HTTP_FLAG_TRUST_SYS; + if ((flags & KS_HTTP_FETCH_NO_CRL) || ctrl->http_no_crl) + session_flags |= HTTP_FLAG_NO_CRL; + if ((flags & KS_HTTP_FETCH_TRUST_CFG)) + session_flags |= HTTP_FLAG_TRUST_CFG; + + once_more: + err = http_session_new (&session, NULL, session_flags, gnupg_http_tls_verify_cb, ctrl); if (err) goto leave; @@ -120,7 +123,7 @@ ks_http_fetch (ctrl_t ctrl, const char *url, int send_no_cache, /* Avoid caches to get the most recent copy of the key. We set * both the Pragma and Cache-Control versions of the header, so * we're good with both HTTP 1.0 and 1.1. */ - if (send_no_cache) + if ((flags & KS_HTTP_FETCH_NOCACHE)) es_fputs ("Pragma: no-cache\r\n" "Cache-Control: no-cache\r\n", fp); http_start_data (http); @@ -172,7 +175,13 @@ ks_http_fetch (ctrl_t ctrl, const char *url, int send_no_cache, if (err) goto leave; - if ((is_onion && ! uri->onion) || (is_https && ! uri->use_tls)) + if (is_onion && !uri->onion) + { + err = gpg_error (GPG_ERR_FORBIDDEN); + goto leave; + } + if (!(flags & KS_HTTP_FETCH_ALLOW_DOWNGRADE) + && is_https && !uri->use_tls) { err = gpg_error (GPG_ERR_FORBIDDEN); goto leave; diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h index ce51141bd..d28c6ab71 100644 --- a/dirmngr/ks-engine.h +++ b/dirmngr/ks-engine.h @@ -41,9 +41,15 @@ gpg_error_t ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen); /*-- ks-engine-http.c --*/ + +/* Flags for the ks_http_fetch. */ +#define KS_HTTP_FETCH_NOCACHE 1 /* Request no caching. */ +#define KS_HTTP_FETCH_TRUST_CFG 2 /* Requests HTTP_FLAG_TRUST_CFG. */ +#define KS_HTTP_FETCH_NO_CRL 4 /* Requests HTTP_FLAG_NO_CRL. */ +#define KS_HTTP_FETCH_ALLOW_DOWNGRADE 8 /* Allow redirect https -> http. */ + gpg_error_t ks_http_help (ctrl_t ctrl, parsed_uri_t uri); -gpg_error_t ks_http_fetch (ctrl_t ctrl, const char *url, int send_no_cache, - unsigned int extra_http_trust_flags, +gpg_error_t ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags, estream_t *r_fp); diff --git a/dirmngr/loadswdb.c b/dirmngr/loadswdb.c index dfa027386..fb883722a 100644 --- a/dirmngr/loadswdb.c +++ b/dirmngr/loadswdb.c @@ -126,7 +126,7 @@ fetch_file (ctrl_t ctrl, const char *url, estream_t *r_fp) size_t nread, nwritten; char buffer[1024]; - if ((err = ks_http_fetch (ctrl, url, 1, 0, &httpfp))) + if ((err = ks_http_fetch (ctrl, url, KS_HTTP_FETCH_NOCACHE, &httpfp))) goto leave; /* We now read the data from the web server into a memory buffer. -- cgit