From bbb5bfacc0d1f179cfec94fd32fee01a09df0f1d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 12 Apr 2018 11:24:54 +0200 Subject: agent,dirmngr: Add "getenv" to the getinfo command. * agent/command.c (cmd_getinfo): Add sub-command getenv. * dirmngr/server.c (cmd_getinfo): Ditto. -- It is sometimes helpful to be able to inspect certain envvars in a running agent. For example "http_proxy". Signed-off-by: Werner Koch --- dirmngr/server.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'dirmngr/server.c') diff --git a/dirmngr/server.c b/dirmngr/server.c index 60d980211..4315c4133 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -2489,7 +2489,8 @@ static const char hlp_getinfo[] = "dnsinfo - Return info about the DNS resolver\n" "socket_name - Return the name of the socket.\n" "session_id - Return the current session_id.\n" - "workqueue - Inspect the work queue\n"; + "workqueue - Inspect the work queue\n" + "getenv NAME - Return value of envvar NAME\n"; static gpg_error_t cmd_getinfo (assuan_context_t ctx, char *line) { @@ -2557,6 +2558,23 @@ cmd_getinfo (assuan_context_t ctx, char *line) workqueue_dump_queue (ctrl); err = 0; } + else if (!strncmp (line, "getenv", 6) + && (line[6] == ' ' || line[6] == '\t' || !line[6])) + { + line += 6; + while (*line == ' ' || *line == '\t') + line++; + if (!*line) + err = gpg_error (GPG_ERR_MISSING_VALUE); + else + { + const char *s = getenv (line); + if (!s) + err = set_error (GPG_ERR_NOT_FOUND, "No such envvar"); + else + err = assuan_send_data (ctx, s, strlen (s)); + } + } else err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT"); -- cgit From 460e3812be711bd18195053d74aa736215f21eee Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 24 Apr 2018 11:40:51 +0200 Subject: dirmngr: Fallback to CRL if no default OCSP responder is configured. * dirmngr/server.c (cmd_isvalid): Use option second arg to trigger OCSP checkibng. Fallback to CRL if no default OCSP responder has been configured. * sm/call-dirmngr.c (gpgsm_dirmngr_isvalid): Adjust accordingly. Signed-off-by: Werner Koch --- dirmngr/server.c | 65 +++++++++++++++++++++++++++++++++++-------------------- sm/call-dirmngr.c | 41 +++++++++++++++-------------------- 2 files changed, 59 insertions(+), 47 deletions(-) (limited to 'dirmngr/server.c') diff --git a/dirmngr/server.c b/dirmngr/server.c index 4315c4133..48244d4af 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -1105,7 +1105,7 @@ cmd_ldapserver (assuan_context_t ctx, char *line) static const char hlp_isvalid[] = "ISVALID [--only-ocsp] [--force-default-responder]" - " |\n" + " []\n" "\n" "This command checks whether the certificate identified by the\n" "certificate_id is valid. This is done by consulting CRLs or\n" @@ -1117,8 +1117,9 @@ static const char hlp_isvalid[] = "delimited by a single dot. The first part is the SHA-1 hash of the\n" "issuer name and the second part the serial number.\n" "\n" - "Alternatively the certificate's fingerprint may be given in which\n" - "case an OCSP request is done before consulting the CRL.\n" + "If an OCSP check is desired CERTIFICATE_FPR with the hex encoded\n" + "fingerprint of the certificate is required. In this case an OCSP\n" + "request is done before consulting the CRL.\n" "\n" "If the option --only-ocsp is given, no fallback to a CRL check will\n" "be used.\n" @@ -1130,7 +1131,7 @@ static gpg_error_t cmd_isvalid (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); - char *issuerhash, *serialno; + char *issuerhash, *serialno, *fpr; gpg_error_t err; int did_inquire = 0; int ocsp_mode = 0; @@ -1141,25 +1142,36 @@ cmd_isvalid (assuan_context_t ctx, char *line) force_default_responder = has_option (line, "--force-default-responder"); line = skip_options (line); - issuerhash = xstrdup (line); /* We need to work on a copy of the - line because that same Assuan - context may be used for an inquiry. - That is because Assuan reuses its - line buffer. - */ + /* We need to work on a copy of the line because that same Assuan + * context may be used for an inquiry. That is because Assuan + * reuses its line buffer. */ + issuerhash = xstrdup (line); serialno = strchr (issuerhash, '.'); - if (serialno) - *serialno++ = 0; - else + if (!serialno) + { + xfree (issuerhash); + return leave_cmd (ctx, PARM_ERROR (_("serialno missing in cert ID"))); + } + *serialno++ = 0; + if (strlen (issuerhash) != 40) { - char *endp = strchr (issuerhash, ' '); + xfree (issuerhash); + return leave_cmd (ctx, PARM_ERROR ("cert ID is too short")); + } + + fpr = strchr (serialno, ' '); + while (fpr && spacep (fpr)) + fpr++; + if (fpr && *fpr) + { + char *endp = strchr (fpr, ' '); if (endp) *endp = 0; - if (strlen (issuerhash) != 40) + if (strlen (fpr) != 40) { xfree (issuerhash); - return leave_cmd (ctx, PARM_ERROR (_("serialno missing in cert ID"))); + return leave_cmd (ctx, PARM_ERROR ("fingerprint too short")); } ocsp_mode = 1; } @@ -1168,17 +1180,24 @@ cmd_isvalid (assuan_context_t ctx, char *line) again: if (ocsp_mode) { - /* Note, that we ignore the given issuer hash and instead rely - on the current certificate semantics used with this - command. */ + /* Note, that we currently ignore the supplied fingerprint FPR; + * instead ocsp_isvalid does an inquire to ask for the cert. + * The fingerprint may eventually be used to lookup the + * certificate in a local cache. */ if (!opt.allow_ocsp) err = gpg_error (GPG_ERR_NOT_SUPPORTED); else err = ocsp_isvalid (ctrl, NULL, NULL, force_default_responder); - /* Fixme: If we got no ocsp response and --only-ocsp is not used - we should fall back to CRL mode. Thus we need to clear - OCSP_MODE, get the issuerhash and the serialno from the - current certificate and jump to again. */ + + if (gpg_err_code (err) == GPG_ERR_CONFIGURATION + && gpg_err_source (err) == GPG_ERR_SOURCE_DIRMNGR) + { + /* No default responder configured - fallback to CRL. */ + if (!only_ocsp) + log_info ("falling back to CRL check\n"); + ocsp_mode = 0; + goto again; + } } else if (only_ocsp) err = gpg_error (GPG_ERR_NO_CRL_KNOWN); diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index e94311892..3a38bca50 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -491,8 +491,8 @@ isvalid_status_cb (void *opaque, const char *line) Values for USE_OCSP: 0 = Do CRL check. - 1 = Do an OCSP check. - 2 = Do an OCSP check using only the default responder. + 1 = Do an OCSP check but fallback to CRL unless CRLS are disabled. + 2 = Do only an OCSP check using only the default responder. */ int gpgsm_dirmngr_isvalid (ctrl_t ctrl, @@ -500,7 +500,7 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl, { static int did_options; int rc; - char *certid; + char *certid, *certfpr; char line[ASSUAN_LINELENGTH]; struct inq_certificate_parm_s parm; struct isvalid_status_parm_s stparm; @@ -509,19 +509,13 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl, if (rc) return rc; - if (use_ocsp) + certfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1); + certid = gpgsm_get_certid (cert); + if (!certid) { - certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1); - } - else - { - certid = gpgsm_get_certid (cert); - if (!certid) - { - log_error ("error getting the certificate ID\n"); - release_dirmngr (ctrl); - return gpg_error (GPG_ERR_GENERAL); - } + log_error ("error getting the certificate ID\n"); + release_dirmngr (ctrl); + return gpg_error (GPG_ERR_GENERAL); } if (opt.verbose > 1) @@ -541,13 +535,8 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl, stparm.seen = 0; memset (stparm.fpr, 0, 20); - /* FIXME: If --disable-crl-checks has been set, we should pass an - option to dirmngr, so that no fallback CRL check is done after an - ocsp check. It is not a problem right now as dirmngr does not - fallback to CRL checking. */ - /* It is sufficient to send the options only once because we have - one connection per process only. */ + * one connection per process only. */ if (!did_options) { if (opt.force_crl_refresh) @@ -555,10 +544,14 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl, NULL, NULL, NULL, NULL, NULL, NULL); did_options = 1; } - snprintf (line, DIM(line), "ISVALID%s %s", - use_ocsp == 2? " --only-ocsp --force-default-responder":"", - certid); + snprintf (line, DIM(line), "ISVALID%s%s %s%s%s", + use_ocsp == 2 || opt.no_crl_check ? " --only-ocsp":"", + use_ocsp == 2? " --force-default-responder":"", + certid, + use_ocsp? " ":"", + use_ocsp? certfpr:""); xfree (certid); + xfree (certfpr); rc = assuan_transact (dirmngr_ctx, line, NULL, NULL, inq_certificate, &parm, -- cgit 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/certcache.c | 5 ++ dirmngr/crlfetch.c | 160 ++++++++++++++--------------------------------- dirmngr/http-ntbtls.c | 4 +- dirmngr/http.c | 48 ++++++++++++++ dirmngr/http.h | 6 +- dirmngr/ks-action.c | 5 +- dirmngr/ks-engine-http.c | 26 +++++--- dirmngr/ks-engine.h | 4 +- dirmngr/loadswdb.c | 2 +- dirmngr/server.c | 4 +- 10 files changed, 133 insertions(+), 131 deletions(-) (limited to 'dirmngr/server.c') diff --git a/dirmngr/certcache.c b/dirmngr/certcache.c index 56629fdda..adb005ec8 100644 --- a/dirmngr/certcache.c +++ b/dirmngr/certcache.c @@ -423,6 +423,9 @@ load_certs_from_dir (const char *dirname, unsigned int trustclass) log_info (_("certificate '%s' already cached\n"), fname); else if (!err) { + if ((trustclass & CERTTRUST_CLASS_CONFIG)) + http_register_cfg_ca (fname); + if (trustclass) log_info (_("trusted certificate '%s' loaded\n"), fname); else @@ -763,6 +766,8 @@ cert_cache_deinit (int full) } } + http_register_cfg_ca (NULL); + total_nonperm_certificates = 0; any_cert_of_class = 0; initialization_done = 0; diff --git a/dirmngr/crlfetch.c b/dirmngr/crlfetch.c index 0892421e9..0d27aa0f1 100644 --- a/dirmngr/crlfetch.c +++ b/dirmngr/crlfetch.c @@ -28,6 +28,7 @@ #include "dirmngr.h" #include "misc.h" #include "http.h" +#include "ks-engine.h" /* For ks_http_fetch. */ #if USE_LDAP # include "ldap-wrapper.h" @@ -154,41 +155,17 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader) { gpg_error_t err; parsed_uri_t uri; - char *free_this = NULL; - int redirects_left = 2; /* We allow for 2 redirect levels. */ + estream_t httpfp = NULL; *reader = NULL; if (!url) return gpg_error (GPG_ERR_INV_ARG); - once_more: err = http_parse_uri (&uri, url, 0); http_release_parsed_uri (uri); - if (err && !strncmp (url, "https:", 6)) - { - /* FIXME: We now support https. - * Our HTTP code does not support TLS, thus we can't use this - * scheme and it is frankly not useful for CRL retrieval anyway. - * We resort to using http, assuming that the server also - * provides plain http access. */ - free_this = xtrymalloc (strlen (url) + 1); - if (free_this) - { - strcpy (stpcpy (free_this,"http:"), url+6); - err = http_parse_uri (&uri, free_this, 0); - http_release_parsed_uri (uri); - if (!err) - { - log_info (_("using \"http\" instead of \"https\"\n")); - url = free_this; - } - } - } if (!err) /* Yes, our HTTP code groks that. */ { - http_t hd; - if (opt.disable_http) { log_error (_("CRL access not possible due to disabled %s\n"), @@ -196,97 +173,54 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader) err = gpg_error (GPG_ERR_NOT_SUPPORTED); } else - err = http_open_document (&hd, url, 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) - ), - ctrl->http_proxy, NULL, NULL, NULL); - - switch ( err? 99999 : http_get_status_code (hd) ) { - case 200: - { - estream_t fp = http_get_read_ptr (hd); - struct reader_cb_context_s *cb_ctx; - - cb_ctx = xtrycalloc (1, sizeof *cb_ctx); - if (!cb_ctx) - err = gpg_error_from_syserror (); - if (!err) - err = ksba_reader_new (reader); - if (!err) - { - cb_ctx->fp = fp; - err = ksba_reader_set_cb (*reader, &my_es_read, cb_ctx); - } - if (err) - { - log_error (_("error initializing reader object: %s\n"), - gpg_strerror (err)); - ksba_reader_release (*reader); - *reader = NULL; - http_close (hd, 0); - } - else - { - /* The ksba reader misses a user pointer thus we need - to come up with our own way of associating a file - pointer (or well the callback context) with the - reader. It is only required when closing the - reader thus there is no performance issue doing it - this way. FIXME: We now have a close notification - which might be used here. */ - register_file_reader (*reader, cb_ctx); - http_close (hd, 1); - } - } - break; + /* 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), + &httpfp); + } - case 301: /* Redirection (perm.). */ - case 302: /* Redirection (temp.). */ - { - const char *s = http_get_header (hd, "Location"); - - log_info (_("URL '%s' redirected to '%s' (%u)\n"), - url, s?s:"[none]", http_get_status_code (hd)); - if (s && *s && redirects_left-- ) - { - xfree (free_this); url = NULL; - free_this = xtrystrdup (s); - if (!free_this) - err = gpg_error_from_errno (errno); - else - { - url = free_this; - http_close (hd, 0); - /* Note, that our implementation of redirection - actually handles a redirect to LDAP. */ - goto once_more; - } - } - else - err = gpg_error (GPG_ERR_NO_DATA); - log_error (_("too many redirections\n")); /* Or no "Location". */ - http_close (hd, 0); - } - break; - - case 99999: /* Made up status code for error reporting. */ - log_error (_("error retrieving '%s': %s\n"), - url, gpg_strerror (err)); - break; - - default: - log_error (_("error retrieving '%s': http status %u\n"), - url, http_get_status_code (hd)); - err = gpg_error (GPG_ERR_NO_DATA); - http_close (hd, 0); + if (err) + log_error (_("error retrieving '%s': %s\n"), url, gpg_strerror (err)); + else + { + struct reader_cb_context_s *cb_ctx; + + cb_ctx = xtrycalloc (1, sizeof *cb_ctx); + if (!cb_ctx) + err = gpg_error_from_syserror (); + else if (!(err = ksba_reader_new (reader))) + { + cb_ctx->fp = httpfp; + err = ksba_reader_set_cb (*reader, &my_es_read, cb_ctx); + if (!err) + { + /* The ksba reader misses a user pointer thus we + * need to come up with our own way of associating a + * file pointer (or well the callback context) with + * the reader. It is only required when closing the + * reader thus there is no performance issue doing + * it this way. FIXME: We now have a close + * notification which might be used here. */ + register_file_reader (*reader, cb_ctx); + httpfp = NULL; + } + } + + if (err) + { + log_error (_("error initializing reader object: %s\n"), + gpg_strerror (err)); + ksba_reader_release (*reader); + *reader = NULL; + xfree (cb_ctx); + } } } - else /* Let the LDAP code try other schemes. */ + else /* Let the LDAP code parse other schemes. */ { if (opt.disable_ldap) { @@ -310,7 +244,7 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader) } } - xfree (free_this); + es_fclose (httpfp); return err; } diff --git a/dirmngr/http-ntbtls.c b/dirmngr/http-ntbtls.c index ea66a4d73..ed4cdd496 100644 --- a/dirmngr/http-ntbtls.c +++ b/dirmngr/http-ntbtls.c @@ -87,13 +87,15 @@ gnupg_http_tls_verify_cb (void *opaque, } else /* Use the certificates as requested from the HTTP module. */ { + if ((http_flags & HTTP_FLAG_TRUST_CFG)) + validate_flags |= VALIDATE_FLAG_TRUST_CONFIG; if ((http_flags & HTTP_FLAG_TRUST_DEF)) validate_flags |= VALIDATE_FLAG_TRUST_HKP; if ((http_flags & HTTP_FLAG_TRUST_SYS)) validate_flags |= VALIDATE_FLAG_TRUST_SYSTEM; /* If HKP trust is requested and there are no HKP certificates - * configured, also try thye standard system certificates. */ + * configured, also try the standard system certificates. */ if ((validate_flags & VALIDATE_FLAG_TRUST_HKP) && !cert_cache_any_in_class (CERTTRUST_CLASS_HKP)) validate_flags |= VALIDATE_FLAG_TRUST_SYSTEM; diff --git a/dirmngr/http.c b/dirmngr/http.c index 8e778dfa2..4624d5fe6 100644 --- a/dirmngr/http.c +++ b/dirmngr/http.c @@ -318,6 +318,9 @@ static gpg_error_t (*tls_callback) (http_t, http_session_t, int); /* The list of files with trusted CA certificates. */ static strlist_t tls_ca_certlist; +/* The list of files with extra trusted CA certificates. */ +static strlist_t cfg_ca_certlist; + /* The global callback for net activity. */ static void (*netactivity_cb)(void); @@ -596,6 +599,35 @@ http_register_tls_ca (const char *fname) } +/* Register a CA certificate for future use. The certificate is + * expected to be in FNAME. PEM format is assume if FNAME has a + * suffix of ".pem". If FNAME is NULL the list of CA files is + * removed. This is a variant of http_register_tls_ca which puts the + * certificate into a separate list enabled using HTTP_FLAG_TRUST_CFG. */ +void +http_register_cfg_ca (const char *fname) +{ + strlist_t sl; + + if (!fname) + { + free_strlist (cfg_ca_certlist); + cfg_ca_certlist = NULL; + } + else + { + /* Warn if we can't access right now, but register it anyway in + case it becomes accessible later */ + if (access (fname, F_OK)) + log_info (_("can't access '%s': %s\n"), fname, + gpg_strerror (gpg_error_from_syserror())); + sl = add_to_strlist (&cfg_ca_certlist, fname); + if (*sl->d && !strcmp (sl->d + strlen (sl->d) - 4, ".pem")) + sl->flags = 1; + } +} + + /* Register a callback which is called every time the HTTP mode has * made a successful connection to some server. */ void @@ -680,6 +712,7 @@ http_session_release (http_session_t sess) * Valid values for FLAGS are: * HTTP_FLAG_TRUST_DEF - Use the CAs set with http_register_tls_ca * HTTP_FLAG_TRUST_SYS - Also use the CAs defined by the system + * HTTP_FLAG_TRUST_CFG - Also use CAs set with http_register_cfg_ca * HTTP_FLAG_NO_CRL - Do not consult CRLs for https. */ gpg_error_t @@ -793,6 +826,21 @@ http_session_new (http_session_t *r_session, #endif /* gnutls >= 3.0.20 */ } + /* Add other configured certificates to the session. */ + if ((flags & HTTP_FLAG_TRUST_CFG)) + { + for (sl = cfg_ca_certlist; sl; sl = sl->next) + { + rc = gnutls_certificate_set_x509_trust_file + (sess->certcred, sl->d, + (sl->flags & 1)? GNUTLS_X509_FMT_PEM : GNUTLS_X509_FMT_DER); + if (rc < 0) + log_info ("setting extra CA from file '%s' failed: %s\n", + sl->d, gnutls_strerror (rc)); + } + } + + rc = gnutls_init (&sess->tls_session, GNUTLS_CLIENT); if (rc < 0) { diff --git a/dirmngr/http.h b/dirmngr/http.h index 9fa462c05..4cfb4c890 100644 --- a/dirmngr/http.h +++ b/dirmngr/http.h @@ -88,8 +88,9 @@ enum HTTP_FLAG_IGNORE_IPv4 = 64, /* Do not use IPv4. */ HTTP_FLAG_IGNORE_IPv6 = 128, /* Do not use IPv6. */ HTTP_FLAG_TRUST_DEF = 256, /* Use the CAs configured for HKP. */ - HTTP_FLAG_TRUST_SYS = 512, /* Also use the system defined CAs. */ - HTTP_FLAG_NO_CRL = 1024 /* Do not consult CRLs for https. */ + HTTP_FLAG_TRUST_SYS = 512, /* Also use the system defined CAs. */ + HTTP_FLAG_TRUST_CFG = 1024, /* Also use configured CAs. */ + HTTP_FLAG_NO_CRL = 2048 /* Do not consult CRLs for https. */ }; @@ -110,6 +111,7 @@ void http_set_verbose (int verbose, int debug); void http_register_tls_callback (gpg_error_t (*cb)(http_t,http_session_t,int)); void http_register_tls_ca (const char *fname); +void http_register_cfg_ca (const char *fname); void http_register_netactivity_cb (void (*cb)(void)); diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c index 38cd02feb..eb15e40dd 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, &infp); + err = ks_http_fetch (ctrl, uri->parsed_uri->original, 1, 0, + &infp); else BUG (); @@ -314,7 +315,7 @@ ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp) if (parsed_uri->is_http) { - err = ks_http_fetch (ctrl, url, &infp); + err = ks_http_fetch (ctrl, url, 1, 0, &infp); if (!err) { err = copy_stream (infp, outfp); 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 (); diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h index b5b4dd08b..ce51141bd 100644 --- a/dirmngr/ks-engine.h +++ b/dirmngr/ks-engine.h @@ -42,7 +42,9 @@ gpg_error_t ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, /*-- ks-engine-http.c --*/ 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, estream_t *r_fp); +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-engine-finger.c --*/ diff --git a/dirmngr/loadswdb.c b/dirmngr/loadswdb.c index bc004665d..dfa027386 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, &httpfp))) + if ((err = ks_http_fetch (ctrl, url, 1, 0, &httpfp))) goto leave; /* We now read the data from the web server into a memory buffer. diff --git a/dirmngr/server.c b/dirmngr/server.c index 48244d4af..8a0b940ce 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -1877,7 +1877,7 @@ static const char hlp_validate[] = " INQUIRE CERTLIST\n" "\n" "Here the first certificate is the target certificate, the remaining\n" - "certificates are suggested intermediary certificates. All certifciates\n" + "certificates are suggested intermediary certificates. All certificates\n" "need to be PEM encoded.\n" "\n" "The option --systrust changes the behaviour to include the system\n" @@ -1928,7 +1928,7 @@ cmd_validate (assuan_context_t ctx, char *line) err = gpg_error (GPG_ERR_MISSING_CERT); if (!err) { - /* Extraxt the first certificate from the list. */ + /* Extract the first certificate from the list. */ cert = certlist->cert; ksba_cert_ref (cert); } -- cgit From cc66108253c58583d6bad3d1e2da2b004701d0f0 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 26 Apr 2018 12:28:53 +0200 Subject: dirmngr: Fix handling of CNAMEed keyserver pools. * dirmngr/ks-engine-hkp.c (map_host): Don't use the cname for HTTPHOST. * dirmngr/server.c (make_keyserver_item): Map keys.gnupg.net. -- For a description of the problem see the comment in make_keyserver_item. GnuPG-bug-id: 3755 Signed-off-by: Werner Koch --- NEWS | 3 +++ dirmngr/ks-engine-hkp.c | 2 +- dirmngr/server.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) (limited to 'dirmngr/server.c') diff --git a/NEWS b/NEWS index 7547b2aa1..ca84e2089 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,9 @@ Noteworthy changes in version 2.2.7 (unreleased) * dirmngr: Fix a regression since 2.1.16 which caused corrupted CRL caches under Windows. [#2448,#3923] + * dirmngr: Fix a CNAME problem with pools and TLS. Also use a fixed + mapping of keys.gnupg.net to sks-keyservers.net. [#3755] + Noteworthy changes in version 2.2.6 (2018-04-09) ------------------------------------------------ diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index a9bb93666..eba7a1a48 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -583,7 +583,7 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect, /* Deal with the pool name before selecting a host. */ if (r_httphost) { - *r_httphost = xtrystrdup (hi->cname? hi->cname : hi->name); + *r_httphost = xtrystrdup (hi->name); if (!*r_httphost) return gpg_error_from_syserror (); } diff --git a/dirmngr/server.c b/dirmngr/server.c index 8a0b940ce..b7cdb24c9 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -1997,6 +1997,38 @@ make_keyserver_item (const char *uri, uri_item_t *r_item) uri_item_t item; *r_item = NULL; + + /* We used to have DNS CNAME redirection from the URLs below to + * sks-keyserver. pools. The idea was to allow for a quick way to + * switch to a different set of pools. The problem with that + * approach is that TLS needs to verify the hostname and - because + * DNS is not secured - it can only check the user supplied hostname + * and not a hostname from a CNAME RR. Thus the final server all + * need to have certificates with the actual pool name as well as + * for keys.gnupg.net - that would render the advantage of + * keys.gnupg.net useless and so we better give up on this. Because + * the keys.gnupg.net URL are still in widespread use we do a static + * mapping here. + */ + if (!strcmp (uri, "hkps://keys.gnupg.net") + || !strcmp (uri, "keys.gnupg.net")) + uri = "hkps://hkps.pool.sks-keyservers.net"; + else if (!strcmp (uri, "https://keys.gnupg.net")) + uri = "https://hkps.pool.sks-keyservers.net"; + else if (!strcmp (uri, "hkp://keys.gnupg.net")) + uri = "hkp://hkps.pool.sks-keyservers.net"; + else if (!strcmp (uri, "http://keys.gnupg.net")) + uri = "http://hkps.pool.sks-keyservers.net"; + else if (!strcmp (uri, "hkps://http-keys.gnupg.net") + || !strcmp (uri, "http-keys.gnupg.net")) + uri = "hkps://ha.pool.sks-keyservers.net"; + else if (!strcmp (uri, "https://http-keys.gnupg.net")) + uri = "https://ha.pool.sks-keyservers.net"; + else if (!strcmp (uri, "hkp://http-keys.gnupg.net")) + uri = "hkp://ha.pool.sks-keyservers.net"; + else if (!strcmp (uri, "http://http-keys.gnupg.net")) + uri = "http://ha.pool.sks-keyservers.net"; + item = xtrymalloc (sizeof *item + strlen (uri)); if (!item) return gpg_error_from_syserror (); -- cgit