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.
This commit is contained in:
Werner Koch 2014-05-16 20:58:58 +02:00
parent 25036ec6ab
commit 8b90d79818
7 changed files with 52 additions and 28 deletions

View File

@ -168,7 +168,8 @@ static int remove_escapes (char *string);
static int insert_escapes (char *buffer, const char *string, static int insert_escapes (char *buffer, const char *string,
const char *special); const char *special);
static uri_tuple_t parse_tuple (char *string); 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); const char *srvtag,strlist_t headers);
static char *build_rel_path (parsed_uri_t uri); static char *build_rel_path (parsed_uri_t uri);
static gpg_error_t parse_response (http_t hd); 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 /* Start a HTTP retrieval and on success store at R_HD a context
pointer for completing the the request and to wait for the pointer for completing the request and to wait for the response.
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 gpg_error_t
http_open (http_t *r_hd, http_req_t reqtype, const char *url, 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, const char *auth, unsigned int flags, const char *proxy,
http_session_t session, const char *srvtag, strlist_t headers) 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)); err = parse_uri (&hd->uri, url, 0, !!(flags & HTTP_FLAG_FORCE_TLS));
if (!err) if (!err)
err = send_request (hd, auth, proxy, srvtag, headers); err = send_request (hd, httphost, auth, proxy, srvtag, headers);
if (err) if (err)
{ {
@ -868,7 +871,7 @@ http_open_document (http_t *r_hd, const char *document,
{ {
gpg_error_t err; 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); proxy, session, srvtag, headers);
if (err) if (err)
return err; return err;
@ -1353,7 +1356,7 @@ parse_tuple (char *string)
* Returns 0 if the request was successful * Returns 0 if the request was successful
*/ */
static gpg_error_t 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) const char *proxy, const char *srvtag, strlist_t headers)
{ {
gpg_error_t err; gpg_error_t err;
@ -1389,7 +1392,7 @@ send_request (http_t hd, const char *auth,
int rc; int rc;
xfree (hd->session->servername); xfree (hd->session->servername);
hd->session->servername = xtrystrdup (server); hd->session->servername = xtrystrdup (httphost? httphost : server);
if (!hd->session->servername) if (!hd->session->servername)
{ {
err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ()); 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) if (http_proxy && *http_proxy)
{ {
request = es_asprintf 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_GET ? "GET" :
hd->req_type == HTTP_REQ_HEAD ? "HEAD" : hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS", 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 : "", authstr ? authstr : "",
proxy_authstr ? proxy_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_GET ? "GET" :
hd->req_type == HTTP_REQ_HEAD ? "HEAD" : hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS", hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
*p == '/' ? "" : "/", p, server, portstr, *p == '/' ? "" : "/", p,
httphost? httphost : server,
portstr,
authstr? authstr:""); authstr? authstr:"");
} }
xfree (p); xfree (p);
@ -2442,6 +2449,7 @@ http_verify_server_credentials (http_session_t sess)
const gnutls_datum_t *certlist; const gnutls_datum_t *certlist;
unsigned int certlistlen; unsigned int certlistlen;
gnutls_x509_crt_t cert; gnutls_x509_crt_t cert;
gpg_error_t err = 0;
sess->verify.done = 1; sess->verify.done = 1;
sess->verify.status = 0; sess->verify.status = 0;
@ -2458,27 +2466,35 @@ http_verify_server_credentials (http_session_t sess)
if (rc) if (rc)
{ {
log_error ("%s: %s\n", errprefix, gnutls_strerror (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); log_error ("%s: status=0x%04x\n", errprefix, status);
sess->verify.status = status; sess->verify.status = status;
return gpg_error (GPG_ERR_GENERAL); if (!err)
err = gpg_error (GPG_ERR_GENERAL);
} }
hostname = sess->servername; hostname = sess->servername;
if (!hostname || !strchr (hostname, '.')) if (!hostname || !strchr (hostname, '.'))
{ {
log_error ("%s: %s\n", errprefix, "hostname missing"); 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); certlist = gnutls_certificate_get_peers (sess->tls_session, &certlistlen);
if (!certlistlen) if (!certlistlen)
{ {
log_error ("%s: %s\n", errprefix, "server did not send a certificate"); 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); */ /* 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); rc = gnutls_x509_crt_init (&cert);
if (rc < 0) 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); 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", log_error ("%s: %s: %s\n", errprefix, "error importing certificate",
gnutls_strerror (rc)); gnutls_strerror (rc));
gnutls_x509_crt_deinit (cert); if (!err)
return gpg_error (GPG_ERR_GENERAL); err = gpg_error (GPG_ERR_GENERAL);
} }
if (!gnutls_x509_crt_check_hostname (cert, hostname)) if (!gnutls_x509_crt_check_hostname (cert, hostname))
{ {
log_error ("%s: %s\n", errprefix, "hostname does not match"); log_error ("%s: %s\n", errprefix, "hostname does not match");
gnutls_x509_crt_deinit (cert); log_info ("(expected '%s')\n", hostname);
return gpg_error (GPG_ERR_GENERAL); if (!err)
err = gpg_error (GPG_ERR_GENERAL);
} }
gnutls_x509_crt_deinit (cert); gnutls_x509_crt_deinit (cert);
sess->verify.rc = 0; if (!err)
return 0; /* Verification succeeded. */ sess->verify.rc = 0;
return err;
#else /*!HTTP_USE_GNUTLS*/ #else /*!HTTP_USE_GNUTLS*/
(void)sess; (void)sess;
return gpg_error (GPG_ERR_NOT_IMPLEMENTED); return gpg_error (GPG_ERR_NOT_IMPLEMENTED);

View File

@ -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, gpg_error_t http_open (http_t *r_hd, http_req_t reqtype,
const char *url, const char *url,
const char *httphost,
const char *auth, const char *auth,
unsigned int flags, unsigned int flags,
const char *proxy, const char *proxy,

View File

@ -765,6 +765,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
err = http_open (&http, err = http_open (&http,
post_cb? HTTP_REQ_POST : HTTP_REQ_GET, post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
request, request,
NULL,
/* fixme: AUTH */ NULL, /* fixme: AUTH */ NULL,
httpflags, httpflags,
/* fixme: proxy*/ NULL, /* fixme: proxy*/ NULL,

View File

@ -68,6 +68,7 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
err = http_open (&http, err = http_open (&http,
HTTP_REQ_GET, HTTP_REQ_GET,
url, url,
/* httphost */ NULL,
/* fixme: AUTH */ NULL, /* fixme: AUTH */ NULL,
0, 0,
/* fixme: proxy*/ NULL, /* fixme: proxy*/ NULL,

View File

@ -165,7 +165,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
} }
once_more: 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.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0),
opt.http_proxy, NULL, NULL, NULL); opt.http_proxy, NULL, NULL, NULL);
if (err) if (err)

View File

@ -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 of the process or to root. On error FAILTEXT is set as Assuan
error string. */ error string. */
static gpg_error_t static gpg_error_t

View File

@ -198,7 +198,7 @@ curl_easy_perform(CURL *curl)
if(curl->flags.post) 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, 0, proxy, NULL, curl->srvtag,
curl->headers?curl->headers->list:NULL); curl->headers?curl->headers->list:NULL);
if (!rc) if (!rc)
@ -222,7 +222,7 @@ curl_easy_perform(CURL *curl)
} }
else 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, 0, proxy, NULL, curl->srvtag,
curl->headers?curl->headers->list:NULL); curl->headers?curl->headers->list:NULL);
if (!rc) if (!rc)
@ -282,7 +282,7 @@ curl_easy_perform(CURL *curl)
err=CURLE_COULDNT_CONNECT; err=CURLE_COULDNT_CONNECT;
break; break;
} }
return handle_error(curl,err,errstr); return handle_error(curl,err,errstr);
} }