From a74902cccde539ee2bd216caec0da6eb54b67c1b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Sat, 18 Feb 2017 16:09:16 +0100 Subject: [PATCH] dirmngr: Add per-session verify callback to http.c * dirmngr/http.h (http_verify_cb_t): New type. * dirmngr/http.c (http_session_s): Add fields flags, verify_cb, and verify_cb_value. (http_session_new): Remove arg tls_priority. Add args verify_cb and verify-cb_value. Store them in the session object. (send_request): Use per-session verify callback. (http_verify_server_credentials) [HTTP_USE_NTBTLS]: Return GPG_ERR_NOT_IMPLEMENTED. * dirmngr/ks-engine-hkp.c (send_request): Adjust for changed http_session_new. * dirmngr/ks-engine-http.c (ks_http_fetch): Ditto. * dirmngr/t-http.c (main): Ditto. * dirmngr/server.c (do_get_cert_local): Replace xmalloc by malloc. Signed-off-by: Werner Koch --- dirmngr/http.c | 46 ++++++++++++++++++++++++++++++---------- dirmngr/http.h | 12 +++++++++-- dirmngr/ks-engine-hkp.c | 3 ++- dirmngr/ks-engine-http.c | 3 ++- dirmngr/server.c | 15 +++++++------ dirmngr/t-http.c | 2 +- 6 files changed, 58 insertions(+), 23 deletions(-) diff --git a/dirmngr/http.c b/dirmngr/http.c index 0f6cac652..51aec7e7c 100644 --- a/dirmngr/http.c +++ b/dirmngr/http.c @@ -221,6 +221,13 @@ struct http_session_s /* A callback function to log details of TLS certifciates. */ void (*cert_log_cb) (http_session_t, gpg_error_t, const char *, const void **, size_t *); + + /* The flags passed to the session object. */ + unsigned int flags; + + /* A per-session TLS verification callback. */ + http_verify_cb_t verify_cb; + void *verify_cb_value; }; @@ -606,8 +613,9 @@ http_session_release (http_session_t sess) * HTTP_FLAG_TRUST_SYS - Also use the CAs defined by the system */ gpg_error_t -http_session_new (http_session_t *r_session, const char *tls_priority, - const char *intended_hostname, unsigned int flags) +http_session_new (http_session_t *r_session, + const char *intended_hostname, unsigned int flags, + http_verify_cb_t verify_cb, void *verify_cb_value) { gpg_error_t err; http_session_t sess; @@ -618,6 +626,9 @@ http_session_new (http_session_t *r_session, const char *tls_priority, if (!sess) return gpg_error_from_syserror (); sess->refcount = 1; + sess->flags = flags; + sess->verify_cb = verify_cb; + sess->verify_cb_value = verify_cb_value; #if HTTP_USE_NTBTLS { @@ -630,8 +641,6 @@ http_session_new (http_session_t *r_session, const char *tls_priority, size_t buflen; char *pemname; - (void)tls_priority; - pemname = make_filename_try (gnupg_datadir (), "sks-keyservers.netCA.pem", NULL); if (!pemname) @@ -799,7 +808,7 @@ http_session_new (http_session_t *r_session, const char *tls_priority, gnutls_transport_set_ptr (sess->tls_session, NULL); rc = gnutls_priority_set_direct (sess->tls_session, - tls_priority? tls_priority : "NORMAL", + "NORMAL", &errpos); if (rc < 0) { @@ -1823,10 +1832,27 @@ send_request (http_t hd, const char *httphost, const char *auth, } hd->session->verify.done = 0; - if (tls_callback) + + + /* Try the available verify callbacks until one returns success + * or a real error. */ + err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + if (hd->session->verify_cb) + err = hd->session->verify_cb (hd->session->verify_cb_value, + hd, hd->session, + (hd->flags | hd->session->flags), + hd->session->tls_session); + + if (tls_callback + && gpg_err_source (err) == GPG_ERR_SOURCE_DIRMNGR + && gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED) err = tls_callback (hd, hd->session, 0); - else + + if (gpg_err_source (err) == GPG_ERR_SOURCE_DIRMNGR + && gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED) err = http_verify_server_credentials (hd->session); + if (err) { log_info ("TLS connection authentication failed: %s <%s>\n", @@ -1834,6 +1860,7 @@ send_request (http_t hd, const char *httphost, const char *auth, xfree (proxy_authstr); return err; } + } #elif HTTP_USE_GNUTLS if (hd->uri->use_tls) @@ -2910,10 +2937,7 @@ cookie_close (void *cookie) gpg_error_t http_verify_server_credentials (http_session_t sess) { -#if HTTP_USE_NTBTLS - (void)sess; - return 0; /* FIXME!! */ -#elif HTTP_USE_GNUTLS +#if HTTP_USE_GNUTLS static const char const errprefix[] = "TLS verification of peer failed"; int rc; unsigned int status; diff --git a/dirmngr/http.h b/dirmngr/http.h index 0b581fe3c..98ac4a31a 100644 --- a/dirmngr/http.h +++ b/dirmngr/http.h @@ -97,6 +97,13 @@ typedef struct http_session_s *http_session_t; struct http_context_s; typedef struct http_context_s *http_t; +/* A TLS verify callback function. */ +typedef gpg_error_t (*http_verify_cb_t) (void *opaque, + http_t http, + http_session_t session, + unsigned int flags, + void *tls_context); + void http_set_verbose (int verbose, int debug); void http_register_tls_callback (gpg_error_t (*cb)(http_t,http_session_t,int)); @@ -105,9 +112,10 @@ void http_register_netactivity_cb (void (*cb)(void)); gpg_error_t http_session_new (http_session_t *r_session, - const char *tls_priority, const char *intended_hostname, - unsigned int flags); + unsigned int flags, + http_verify_cb_t cb, + void *cb_value); http_session_t http_session_ref (http_session_t sess); void http_session_release (http_session_t sess); diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index e39d60ee6..b342f0968 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -1123,7 +1123,8 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr, *r_fp = NULL; - err = http_session_new (&session, NULL, httphost, HTTP_FLAG_TRUST_DEF); + err = http_session_new (&session, httphost, HTTP_FLAG_TRUST_DEF, + NULL, ctrl); if (err) goto leave; http_session_set_log_cb (session, cert_log_cb); diff --git a/dirmngr/ks-engine-http.c b/dirmngr/ks-engine-http.c index 69642ff98..f070019c1 100644 --- a/dirmngr/ks-engine-http.c +++ b/dirmngr/ks-engine-http.c @@ -76,7 +76,8 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp) once_more: /* Note that we only use the system provided certificates with the * fetch command. */ - err = http_session_new (&session, NULL, NULL, HTTP_FLAG_TRUST_SYS); + err = http_session_new (&session, NULL, HTTP_FLAG_TRUST_SYS, + NULL, ctrl); if (err) goto leave; http_session_set_log_cb (session, cert_log_cb); diff --git a/dirmngr/server.c b/dirmngr/server.c index 1134ac081..92bbc160b 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -370,14 +370,15 @@ do_get_cert_local (ctrl_t ctrl, const char *name, const char *command) char *buf; ksba_cert_t cert; - if (name) - buf = xstrconcat (command, " ", name, NULL); + buf = name? strconcat (command, " ", name, NULL) : xtrystrdup (command); + if (!buf) + rc = gpg_error_from_syserror (); else - buf = xstrdup (command); - - rc = assuan_inquire (ctrl->server_local->assuan_ctx, buf, - &value, &valuelen, MAX_CERT_LENGTH); - xfree (buf); + { + rc = assuan_inquire (ctrl->server_local->assuan_ctx, buf, + &value, &valuelen, MAX_CERT_LENGTH); + xfree (buf); + } if (rc) { log_error (_("assuan_inquire(%s) failed: %s\n"), diff --git a/dirmngr/t-http.c b/dirmngr/t-http.c index a87382a93..8b1d89ac0 100644 --- a/dirmngr/t-http.c +++ b/dirmngr/t-http.c @@ -262,7 +262,7 @@ main (int argc, char **argv) http_register_tls_callback (verify_callback); http_register_tls_ca (cafile); - err = http_session_new (&session, NULL, NULL, HTTP_FLAG_TRUST_DEF); + err = http_session_new (&session, NULL, HTTP_FLAG_TRUST_DEF, NULL, NULL); if (err) log_error ("http_session_new failed: %s\n", gpg_strerror (err));