--- gnupg-2.1.21/dirmngr/ks-engine-http.c 2017-04-03 20:58:25.000000000 +0200 +++ gnupg-2.1.21/dirmngr/ks-engine-http.c.new 2017-10-19 15:32:38.000000000 +0200 @@ -72,6 +72,14 @@ ks_http_fetch (ctrl_t ctrl, const char * int redirects_left = MAX_REDIRECTS; estream_t fp = NULL; char *request_buffer = NULL; + parsed_uri_t uri = NULL; + int is_onion, is_https; + + err = http_parse_uri (&uri, url, 0); + if (err) + goto leave; + is_onion = uri->onion; + is_https = uri->use_tls; once_more: /* Note that we only use the system provided certificates with the @@ -83,6 +91,7 @@ ks_http_fetch (ctrl_t ctrl, const char * if (err) goto leave; http_session_set_log_cb (session, cert_log_cb); + http_session_set_timeout (session, ctrl->timeout); *r_fp = NULL; err = http_open (&http, @@ -144,6 +153,24 @@ ks_http_fetch (ctrl_t ctrl, const char * url, s?s:"[none]", http_get_status_code (http)); if (s && *s && redirects_left-- ) { + if (is_onion || is_https) + { + /* Make sure that an onion address only redirects to + * another onion address, or that a https address + * only redirects to a https address. */ + http_release_parsed_uri (uri); + uri = NULL; + err = http_parse_uri (&uri, s, 0); + if (err) + goto leave; + + if ((is_onion && ! uri->onion) || (is_https && ! uri->use_tls)) + { + err = gpg_error (GPG_ERR_FORBIDDEN); + goto leave; + } + } + xfree (request_buffer); request_buffer = xtrystrdup (s); if (request_buffer) @@ -185,5 +212,6 @@ ks_http_fetch (ctrl_t ctrl, const char * http_close (http, 0); http_session_release (session); xfree (request_buffer); + http_release_parsed_uri (uri); return err; } --- gnupg-2.1.21/dirmngr/ks-engine-hkp.c 2017-05-15 14:13:22.000000000 +0200 +++ gnupg-2.1.21/dirmngr/ks-engine-hkp.c.new 2019-02-22 12:43:33.469455447 +0100 @@ -1122,9 +1122,16 @@ send_request (ctrl_t ctrl, const char *r int redirects_left = MAX_REDIRECTS; estream_t fp = NULL; char *request_buffer = NULL; + parsed_uri_t uri = NULL; + int is_onion; *r_fp = NULL; + err = http_parse_uri (&uri, request, 0); + if (err) + goto leave; + is_onion = uri->onion; + err = http_session_new (&session, httphost, ((ctrl->http_no_crl? HTTP_FLAG_NO_CRL : 0) | HTTP_FLAG_TRUST_DEF), @@ -1132,6 +1139,7 @@ send_request (ctrl_t ctrl, const char *r if (err) goto leave; http_session_set_log_cb (session, cert_log_cb); + http_session_set_timeout (session, ctrl->timeout); once_more: err = http_open (&http, @@ -1209,6 +1217,23 @@ send_request (ctrl_t ctrl, const char *r request, s?s:"[none]", http_get_status_code (http)); if (s && *s && redirects_left-- ) { + if (is_onion) + { + /* Make sure that an onion address only redirects to + * another onion address. */ + http_release_parsed_uri (uri); + uri = NULL; + err = http_parse_uri (&uri, s, 0); + if (err) + goto leave; + + if (! uri->onion) + { + err = gpg_error (GPG_ERR_FORBIDDEN); + goto leave; + } + } + xfree (request_buffer); request_buffer = xtrystrdup (s); if (request_buffer) @@ -1257,6 +1282,7 @@ send_request (ctrl_t ctrl, const char *r http_close (http, 0); http_session_release (session); xfree (request_buffer); + http_release_parsed_uri (uri); return err; } --- gnupg-2.1.21/dirmngr/http.h 2017-03-17 09:34:37.000000000 +0100 +++ gnupg-2.1.21/dirmngr/http.h.new 2019-02-22 13:03:52.070903333 +0100 @@ -47,6 +47,7 @@ typedef struct uri_tuple_s *uri_tuple_t; struct parsed_uri_s { /* All these pointers point into BUFFER; most stuff is not escaped. */ + char *original; /* Unmodified copy of the parsed URI. */ char *scheme; /* Pointer to the scheme string (always lowercase). */ unsigned int is_http:1; /* This is a HTTP style URI. */ unsigned int use_tls:1; /* Whether TLS should be used. */ @@ -124,6 +125,7 @@ void http_session_set_log_cb (http_sessi void (*cb)(http_session_t, gpg_error_t, const char *, const void **, size_t *)); +void http_session_set_timeout (http_session_t sess, unsigned int timeout); gpg_error_t http_parse_uri (parsed_uri_t *ret_uri, const char *uri, --- gnupg-2.1.21/dirmngr/dirmngr.h 2017-04-03 20:58:25.000000000 +0200 +++ gnupg-2.1.21/dirmngr/dirmngr.h.new 2019-02-22 13:12:41.781983031 +0100 @@ -194,6 +194,8 @@ struct server_control_s int audit_events; /* Send audit events to client. */ char *http_proxy; /* The used http_proxy or NULL. */ + unsigned int timeout; /* Timeout for connect calls in ms. */ + unsigned int http_no_crl:1; /* Do not check CRLs for https. */ }; --- gnupg-2.1.21/dirmngr/http.c 2017-05-15 14:13:22.000000000 +0200 +++ gnupg-2.1.21/dirmngr/http.c.new 2019-03-05 10:21:52.618356815 +0100 @@ -259,6 +259,9 @@ struct http_session_s /* A per-session TLS verification callback. */ http_verify_cb_t verify_cb; void *verify_cb_value; + + /* The connect timeout */ + unsigned int connect_timeout; }; @@ -695,6 +698,7 @@ http_session_new (http_session_t *r_sess sess->flags = flags; sess->verify_cb = verify_cb; sess->verify_cb_value = verify_cb_value; + sess->connect_timeout = 0; #if HTTP_USE_NTBTLS { @@ -867,6 +871,15 @@ http_session_set_log_cb (http_session_t } +/* Set the TIMEOUT in milliseconds for the connection's connect + * calls. Using 0 disables the timeout. */ +void +http_session_set_timeout (http_session_t sess, unsigned int timeout) +{ + sess->connect_timeout = timeout; +} + + /* Start a HTTP retrieval and on success store at R_HD a context @@ -1202,10 +1215,12 @@ parse_uri (parsed_uri_t *ret_uri, const { gpg_err_code_t ec; - *ret_uri = xtrycalloc (1, sizeof **ret_uri + strlen (uri)); + *ret_uri = xtrycalloc (1, sizeof **ret_uri + 2 * strlen (uri) + 1); if (!*ret_uri) return gpg_err_make (default_errsource, gpg_err_code_from_syserror ()); strcpy ((*ret_uri)->buffer, uri); + strcpy ((*ret_uri)->buffer + strlen (uri) + 1, uri); + (*ret_uri)->original = (*ret_uri)->buffer + strlen (uri) + 1; ec = do_parse_uri (*ret_uri, 0, no_scheme_check, force_tls); if (ec) {