From 8b90d79818355b81ce223e1cb96cd0c939096fe2 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 16 May 2014 20:58:58 +0200 Subject: [PATCH] http: Allow overriding of the Host header. * common/http.c (http_open): Add arg httphost. (http_open_document): Pass NULL for httphost. (send_request): Add arg httphost. If given, use HTTPHOST instead of SERVER. Use https with a proxy if requested. (http_verify_server_credentials): Do not stop at the first error message. * dirmngr/ocsp.c (do_ocsp_request): Adjust call to http_open. * keyserver/curl-shim.c (curl_easy_perform): Ditto. * dirmngr/ks-engine-http.c (ks_http_fetch): Ditto. * dirmngr/ks-engine-hkp.c (ks_hkp_help): Ditto. --- common/http.c | 67 ++++++++++++++++++++++++++-------------- common/http.h | 1 + dirmngr/ks-engine-hkp.c | 1 + dirmngr/ks-engine-http.c | 1 + dirmngr/ocsp.c | 2 +- dirmngr/server.c | 2 +- keyserver/curl-shim.c | 6 ++-- 7 files changed, 52 insertions(+), 28 deletions(-) diff --git a/common/http.c b/common/http.c index eb95dcb66..8a1ad67c2 100644 --- a/common/http.c +++ b/common/http.c @@ -168,7 +168,8 @@ static int remove_escapes (char *string); static int insert_escapes (char *buffer, const char *string, const char *special); static uri_tuple_t parse_tuple (char *string); -static gpg_error_t send_request (http_t hd, const char *auth,const char *proxy, +static gpg_error_t send_request (http_t hd, const char *httphost, + const char *auth,const char *proxy, const char *srvtag,strlist_t headers); static char *build_rel_path (parsed_uri_t uri); static gpg_error_t parse_response (http_t hd); @@ -643,11 +644,13 @@ http_session_ref (http_session_t sess) } -/* Start a HTTP retrieval and return on success in R_HD a context - pointer for completing the the request and to wait for the - response. */ +/* Start a HTTP retrieval and on success store at R_HD a context + pointer for completing the request and to wait for the response. + If HTTPHOST is not NULL it is used hor the Host header instead of a + Host header derived from the URL. */ gpg_error_t http_open (http_t *r_hd, http_req_t reqtype, const char *url, + const char *httphost, const char *auth, unsigned int flags, const char *proxy, http_session_t session, const char *srvtag, strlist_t headers) { @@ -669,7 +672,7 @@ http_open (http_t *r_hd, http_req_t reqtype, const char *url, err = parse_uri (&hd->uri, url, 0, !!(flags & HTTP_FLAG_FORCE_TLS)); if (!err) - err = send_request (hd, auth, proxy, srvtag, headers); + err = send_request (hd, httphost, auth, proxy, srvtag, headers); if (err) { @@ -868,7 +871,7 @@ http_open_document (http_t *r_hd, const char *document, { gpg_error_t err; - err = http_open (r_hd, HTTP_REQ_GET, document, auth, flags, + err = http_open (r_hd, HTTP_REQ_GET, document, NULL, auth, flags, proxy, session, srvtag, headers); if (err) return err; @@ -1353,7 +1356,7 @@ parse_tuple (char *string) * Returns 0 if the request was successful */ static gpg_error_t -send_request (http_t hd, const char *auth, +send_request (http_t hd, const char *httphost, const char *auth, const char *proxy, const char *srvtag, strlist_t headers) { gpg_error_t err; @@ -1389,7 +1392,7 @@ send_request (http_t hd, const char *auth, int rc; xfree (hd->session->servername); - hd->session->servername = xtrystrdup (server); + hd->session->servername = xtrystrdup (httphost? httphost : server); if (!hd->session->servername) { err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ()); @@ -1549,11 +1552,13 @@ send_request (http_t hd, const char *auth, if (http_proxy && *http_proxy) { request = es_asprintf - ("%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s", + ("%s %s://%s:%hu%s%s HTTP/1.0\r\n%s%s", hd->req_type == HTTP_REQ_GET ? "GET" : hd->req_type == HTTP_REQ_HEAD ? "HEAD" : hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS", - server, port, *p == '/' ? "" : "/", p, + hd->uri->use_tls? "https" : "http", + httphost? httphost : server, + port, *p == '/' ? "" : "/", p, authstr ? authstr : "", proxy_authstr ? proxy_authstr : ""); } @@ -1571,7 +1576,9 @@ send_request (http_t hd, const char *auth, hd->req_type == HTTP_REQ_GET ? "GET" : hd->req_type == HTTP_REQ_HEAD ? "HEAD" : hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS", - *p == '/' ? "" : "/", p, server, portstr, + *p == '/' ? "" : "/", p, + httphost? httphost : server, + portstr, authstr? authstr:""); } xfree (p); @@ -2442,6 +2449,7 @@ http_verify_server_credentials (http_session_t sess) const gnutls_datum_t *certlist; unsigned int certlistlen; gnutls_x509_crt_t cert; + gpg_error_t err = 0; sess->verify.done = 1; sess->verify.status = 0; @@ -2458,27 +2466,35 @@ http_verify_server_credentials (http_session_t sess) if (rc) { log_error ("%s: %s\n", errprefix, gnutls_strerror (rc)); - return gpg_error (GPG_ERR_GENERAL); + if (!err) + err = gpg_error (GPG_ERR_GENERAL); } - if (status) + else if (status) { log_error ("%s: status=0x%04x\n", errprefix, status); sess->verify.status = status; - return gpg_error (GPG_ERR_GENERAL); + if (!err) + err = gpg_error (GPG_ERR_GENERAL); } hostname = sess->servername; if (!hostname || !strchr (hostname, '.')) { log_error ("%s: %s\n", errprefix, "hostname missing"); - return gpg_error (GPG_ERR_GENERAL); + if (!err) + err = gpg_error (GPG_ERR_GENERAL); } certlist = gnutls_certificate_get_peers (sess->tls_session, &certlistlen); if (!certlistlen) { log_error ("%s: %s\n", errprefix, "server did not send a certificate"); - return gpg_error (GPG_ERR_GENERAL); + if (!err) + err = gpg_error (GPG_ERR_GENERAL); + + /* Need to stop here. */ + if (err) + return err; } /* log_debug ("Server sent %u certs\n", certlistlen); */ @@ -2502,7 +2518,10 @@ http_verify_server_credentials (http_session_t sess) rc = gnutls_x509_crt_init (&cert); if (rc < 0) { - return gpg_error (GPG_ERR_GENERAL); + if (!err) + err = gpg_error (GPG_ERR_GENERAL); + if (err) + return err; } rc = gnutls_x509_crt_import (cert, &certlist[0], GNUTLS_X509_FMT_DER); @@ -2510,20 +2529,22 @@ http_verify_server_credentials (http_session_t sess) { log_error ("%s: %s: %s\n", errprefix, "error importing certificate", gnutls_strerror (rc)); - gnutls_x509_crt_deinit (cert); - return gpg_error (GPG_ERR_GENERAL); + if (!err) + err = gpg_error (GPG_ERR_GENERAL); } if (!gnutls_x509_crt_check_hostname (cert, hostname)) { log_error ("%s: %s\n", errprefix, "hostname does not match"); - gnutls_x509_crt_deinit (cert); - return gpg_error (GPG_ERR_GENERAL); + log_info ("(expected '%s')\n", hostname); + if (!err) + err = gpg_error (GPG_ERR_GENERAL); } gnutls_x509_crt_deinit (cert); - sess->verify.rc = 0; - return 0; /* Verification succeeded. */ + if (!err) + sess->verify.rc = 0; + return err; #else /*!HTTP_USE_GNUTLS*/ (void)sess; return gpg_error (GPG_ERR_NOT_IMPLEMENTED); diff --git a/common/http.h b/common/http.h index b6471b6b8..acfdc0fe6 100644 --- a/common/http.h +++ b/common/http.h @@ -110,6 +110,7 @@ gpg_error_t http_raw_connect (http_t *r_hd, gpg_error_t http_open (http_t *r_hd, http_req_t reqtype, const char *url, + const char *httphost, const char *auth, unsigned int flags, const char *proxy, diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 8c3384d49..541c46f55 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -765,6 +765,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr, err = http_open (&http, post_cb? HTTP_REQ_POST : HTTP_REQ_GET, request, + NULL, /* fixme: AUTH */ NULL, httpflags, /* fixme: proxy*/ NULL, diff --git a/dirmngr/ks-engine-http.c b/dirmngr/ks-engine-http.c index a9399a137..aed3aaa84 100644 --- a/dirmngr/ks-engine-http.c +++ b/dirmngr/ks-engine-http.c @@ -68,6 +68,7 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp) err = http_open (&http, HTTP_REQ_GET, url, + /* httphost */ NULL, /* fixme: AUTH */ NULL, 0, /* fixme: proxy*/ NULL, diff --git a/dirmngr/ocsp.c b/dirmngr/ocsp.c index b941b5c81..0d506efcd 100644 --- a/dirmngr/ocsp.c +++ b/dirmngr/ocsp.c @@ -165,7 +165,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md, } once_more: - err = http_open (&http, HTTP_REQ_POST, url, NULL, + err = http_open (&http, HTTP_REQ_POST, url, NULL, NULL, (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0), opt.http_proxy, NULL, NULL, NULL); if (err) diff --git a/dirmngr/server.c b/dirmngr/server.c index bdfb755d3..6cf4dd668 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -298,7 +298,7 @@ skip_options (char *line) } -/* Return an error if the assuan context does not belong to teh owner +/* Return an error if the assuan context does not belong to the owner of the process or to root. On error FAILTEXT is set as Assuan error string. */ static gpg_error_t diff --git a/keyserver/curl-shim.c b/keyserver/curl-shim.c index 500d9f562..696efe2c7 100644 --- a/keyserver/curl-shim.c +++ b/keyserver/curl-shim.c @@ -198,7 +198,7 @@ curl_easy_perform(CURL *curl) if(curl->flags.post) { - rc = http_open (&curl->hd, HTTP_REQ_POST, curl->url, curl->auth, + rc = http_open (&curl->hd, HTTP_REQ_POST, curl->url, NULL, curl->auth, 0, proxy, NULL, curl->srvtag, curl->headers?curl->headers->list:NULL); if (!rc) @@ -222,7 +222,7 @@ curl_easy_perform(CURL *curl) } else { - rc = http_open (&curl->hd, HTTP_REQ_GET, curl->url, curl->auth, + rc = http_open (&curl->hd, HTTP_REQ_GET, curl->url, NULL, curl->auth, 0, proxy, NULL, curl->srvtag, curl->headers?curl->headers->list:NULL); if (!rc) @@ -282,7 +282,7 @@ curl_easy_perform(CURL *curl) err=CURLE_COULDNT_CONNECT; break; } - + return handle_error(curl,err,errstr); }