1 /* ks-engine-hkp.c - HKP keyserver engine
2 * Copyright (C) 2011, 2012 Free Software Foundation, Inc.
3 * Copyright (C) 2011, 2012, 2014 Werner Koch
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <https://www.gnu.org/licenses/>.
27 #ifdef HAVE_W32_SYSTEM
28 # ifdef HAVE_WINSOCK2_H
29 # include <winsock2.h>
32 #else /*!HAVE_W32_SYSTEM*/
33 # include <sys/types.h>
34 # include <sys/socket.h>
36 #endif /*!HAVE_W32_SYSTEM*/
41 #include "dns-stuff.h"
42 #include "ks-engine.h"
44 /* Substitutes for missing Mingw macro. The EAI_SYSTEM mechanism
45 seems not to be available (probably because there is only one set
46 of error codes anyway). For now we use WSAEINVAL. */
48 # define EAI_OVERFLOW EAI_FAIL
50 #ifdef HAVE_W32_SYSTEM
52 # define EAI_SYSTEM WSAEINVAL
57 /* Number of seconds after a host is marked as resurrected. */
58 #define RESURRECT_INTERVAL (3600*3) /* 3 hours */
60 /* To match the behaviour of our old gpgkeys helper code we escape
61 more characters than actually needed. */
62 #define EXTRA_ESCAPE_CHARS "@!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
64 /* How many redirections do we allow. */
65 #define MAX_REDIRECTS 2
67 /* Number of retries done for a dead host etc. */
68 #define SEND_REQUEST_RETRIES 3
70 /* Objects used to maintain information about hosts. */
72 typedef struct hostinfo_s *hostinfo_t;
75 time_t lastfail; /* Time we tried to connect and failed. */
76 time_t lastused; /* Time of last use. */
77 int *pool; /* A -1 terminated array with indices into
78 HOSTTABLE or NULL if NAME is not a pool
80 int poolidx; /* Index into POOL with the used host. -1 if not set. */
81 unsigned int v4:1; /* Host supports AF_INET. */
82 unsigned int v6:1; /* Host supports AF_INET6. */
83 unsigned int onion:1;/* NAME is an onion (Tor HS) address. */
84 unsigned int dead:1; /* Host is currently unresponsive. */
85 time_t died_at; /* The time the host was marked dead. If this is
86 0 the host has been manually marked dead. */
87 char *cname; /* Canonical name of the host. Only set if this
89 char *v4addr; /* A string with the v4 IP address of the host.
90 NULL if NAME has a numeric IP address or no v4
91 address is available. */
92 char *v6addr; /* A string with the v6 IP address of the host.
93 NULL if NAME has a numeric IP address or no v6
94 address is available. */
95 unsigned short port; /* The port used by the host, 0 if unknown. */
96 char name[1]; /* The hostname. */
100 /* An array of hostinfo_t for all hosts requested by the caller or
101 resolved from a pool name and its allocated size.*/
102 static hostinfo_t *hosttable;
103 static int hosttable_size;
105 /* The number of host slots we initially allocate for HOSTTABLE. */
106 #define INITIAL_HOSTTABLE_SIZE 10
109 /* Create a new hostinfo object, fill in NAME and put it into
110 HOSTTABLE. Return the index into hosttable on success or -1 on
113 create_new_hostinfo (const char *name)
115 hostinfo_t hi, *newtable;
119 hi = xtrymalloc (sizeof *hi + strlen (name));
122 strcpy (hi->name, name);
125 hi->lastused = (time_t)(-1);
126 hi->lastfail = (time_t)(-1);
137 /* Add it to the hosttable. */
138 for (idx=0; idx < hosttable_size; idx++)
144 /* Need to extend the hosttable. */
145 newsize = hosttable_size + INITIAL_HOSTTABLE_SIZE;
146 newtable = xtryrealloc (hosttable, newsize * sizeof *hosttable);
152 hosttable = newtable;
153 idx = hosttable_size;
154 hosttable_size = newsize;
156 hosttable[idx++] = hi;
157 while (idx < hosttable_size)
158 hosttable[idx++] = NULL;
164 /* Find the host NAME in our table. Return the index into the
165 hosttable or -1 if not found. */
167 find_hostinfo (const char *name)
171 for (idx=0; idx < hosttable_size; idx++)
172 if (hosttable[idx] && !ascii_strcasecmp (hosttable[idx]->name, name))
179 sort_hostpool (const void *xa, const void *xb)
184 assert (a >= 0 && a < hosttable_size);
185 assert (b >= 0 && b < hosttable_size);
186 assert (hosttable[a]);
187 assert (hosttable[b]);
189 return ascii_strcasecmp (hosttable[a]->name, hosttable[b]->name);
193 /* Return true if the host with the hosttable index TBLIDX is in POOL. */
195 host_in_pool_p (int *pool, int tblidx)
199 for (i=0; (pidx = pool[i]) != -1; i++)
200 if (pidx == tblidx && hosttable[pidx])
206 /* Select a random host. Consult TABLE which indices into the global
207 hosttable. Returns index into TABLE or -1 if no host could be
210 select_random_host (int *table)
216 /* We create a new table so that we randomly select only from
217 currently alive hosts. */
218 for (idx=0, tblsize=0; (pidx = table[idx]) != -1; idx++)
219 if (hosttable[pidx] && !hosttable[pidx]->dead)
222 return -1; /* No hosts. */
224 tbl = xtrymalloc (tblsize * sizeof *tbl);
227 for (idx=0, tblsize=0; (pidx = table[idx]) != -1; idx++)
228 if (hosttable[pidx] && !hosttable[pidx]->dead)
229 tbl[tblsize++] = pidx;
231 if (tblsize == 1) /* Save a get_uint_nonce. */
234 pidx = tbl[get_uint_nonce () % tblsize];
241 /* Figure out if a set of DNS records looks like a pool. */
243 arecords_is_pool (dns_addrinfo_t aibuf)
249 for (ai = aibuf; ai; ai = ai->next)
251 if (ai->family == AF_INET6)
253 else if (ai->family == AF_INET)
257 return n_v6 > 1 || n_v4 > 1;
261 /* Add the host AI under the NAME into the HOSTTABLE. If PORT is not
262 zero, it specifies which port to use to talk to the host. If NAME
263 specifies a pool (as indicated by IS_POOL), update the given
264 reference table accordingly. */
266 add_host (const char *name, int is_pool,
267 const dns_addrinfo_t ai, unsigned short port,
268 int *reftbl, size_t reftblsize, int *refidx)
276 idx = find_hostinfo (name);
278 if (!is_pool && !is_ip_address (name))
280 /* This is a hostname but not a pool. Use the name
281 as given without going through resolve_dns_addr. */
282 tmphost = xtrystrdup (name);
284 tmperr = gpg_error_from_syserror ();
290 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
291 DNS_WITHBRACKET, &tmphost);
292 if (tmphost && is_ip_address (tmphost))
298 log_info ("resolve_dns_addr failed while checking '%s': %s\n",
299 name, gpg_strerror (tmperr));
301 else if ((*refidx) + 1 >= reftblsize)
303 log_error ("resolve_dns_addr for '%s': '%s'"
304 " [index table full - ignored]\n", name, tmphost);
308 if (!is_pool && is_ip_address (name))
309 /* Update the original entry. */
312 tmpidx = find_hostinfo (tmphost);
313 log_info ("resolve_dns_addr for '%s': '%s'%s\n",
315 tmpidx == -1? "" : " [already known]");
317 if (tmpidx == -1) /* Create a new entry. */
318 tmpidx = create_new_hostinfo (tmphost);
322 log_error ("map_host for '%s' problem: %s - '%s'"
324 name, strerror (errno), tmphost);
326 else /* Set or update the entry. */
331 hosttable[tmpidx]->port = port;
336 tmperr = resolve_dns_addr (ai->addr, ai->addrlen,
341 log_info ("resolve_dns_addr failed: %s\n",
342 gpg_strerror (tmperr));
350 if (ai->family == AF_INET6)
352 hosttable[tmpidx]->v6 = 1;
353 xfree (hosttable[tmpidx]->v6addr);
354 hosttable[tmpidx]->v6addr = ipaddr;
356 else if (ai->family == AF_INET)
358 hosttable[tmpidx]->v4 = 1;
359 xfree (hosttable[tmpidx]->v4addr);
360 hosttable[tmpidx]->v4addr = ipaddr;
365 for (i=0; i < *refidx; i++)
366 if (reftbl[i] == tmpidx)
368 if (!(i < *refidx) && tmpidx != idx)
369 reftbl[(*refidx)++] = tmpidx;
376 /* Map the host name NAME to the actual to be used host name. This
377 allows us to manage round robin DNS names. We use our own strategy
378 to choose one of the hosts. For example we skip those hosts which
379 failed for some time and we stick to one host for a time
380 independent of DNS retry times. If FORCE_RESELECT is true a new
381 host is always selected. The selected host is stored as a malloced
382 string at R_HOST; on error NULL is stored. If we know the port
383 used by the selected host, a string representation is written to
384 R_PORTSTR, otherwise it is left untouched. If R_HTTPFLAGS is not
385 NULL it will receive flags which are to be passed to http_open. If
386 R_POOLNAME is not NULL a malloced name of the pool is stored or
387 NULL if it is not a pool. */
389 map_host (ctrl_t ctrl, const char *name, int force_reselect,
390 char **r_host, char *r_portstr,
391 unsigned int *r_httpflags, char **r_poolname)
403 /* No hostname means localhost. */
406 *r_host = xtrystrdup ("localhost");
407 return *r_host? 0 : gpg_error_from_syserror ();
410 /* See whether the host is in our table. */
411 idx = find_hostinfo (name);
412 if (idx == -1 && is_onion_address (name))
414 idx = create_new_hostinfo (name);
416 return gpg_error_from_syserror ();
422 /* We never saw this host. Allocate a new entry. */
423 dns_addrinfo_t aibuf, ai;
430 struct srventry *srvs;
431 unsigned int srvscount;
434 reftbl = xtrymalloc (reftblsize * sizeof *reftbl);
436 return gpg_error_from_syserror ();
439 idx = create_new_hostinfo (name);
442 err = gpg_error_from_syserror ();
448 if (!is_ip_address (name))
450 /* Check for SRV records. */
451 srvrecord = xtryasprintf ("_hkp._tcp.%s", name);
452 if (srvrecord == NULL)
454 err = gpg_error_from_syserror ();
459 err = get_dns_srv (srvrecord, &srvs, &srvscount);
470 is_pool = srvscount > 1;
472 for (i = 0; i < srvscount; i++)
474 err = resolve_dns_name (srvs[i].target, 0,
475 AF_UNSPEC, SOCK_STREAM,
480 add_host (name, is_pool, ai, srvs[i].port,
481 reftbl, reftblsize, &refidx);
488 /* Find all A records for this entry and put them into the pool
490 err = resolve_dns_name (name, 0, 0, SOCK_STREAM, &aibuf, &cname);
493 log_error ("resolving '%s' failed: %s\n", name, gpg_strerror (err));
498 /* First figure out whether this is a pool. For a pool we
499 use a different strategy than for a plain server: We use
500 the canonical name of the pool as the virtual host along
501 with the IP addresses. If it is not a pool, we use the
504 is_pool = arecords_is_pool (aibuf);
505 if (is_pool && cname)
511 for (ai = aibuf; ai; ai = ai->next)
513 if (ai->family != AF_INET && ai->family != AF_INET6)
517 add_host (name, is_pool, ai, 0, reftbl, reftblsize, &refidx);
522 free_dns_addrinfo (aibuf);
524 if (refidx && is_pool)
527 hi->pool = xtryrealloc (reftbl, (refidx+1) * sizeof *reftbl);
530 err = gpg_error_from_syserror ();
531 log_error ("shrinking index table in map_host failed: %s\n",
536 qsort (hi->pool, refidx, sizeof *reftbl, sort_hostpool);
545 /* Deal with the pool name before selecting a host. */
548 *r_poolname = xtrystrdup (hi->cname? hi->cname : hi->name);
550 return gpg_error_from_syserror ();
553 /* If the currently selected host is now marked dead, force a
557 else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size
558 && hosttable[hi->poolidx] && hosttable[hi->poolidx]->dead)
561 /* Select a host if needed. */
562 if (hi->poolidx == -1)
564 hi->poolidx = select_random_host (hi->pool);
565 if (hi->poolidx == -1)
567 log_error ("no alive host found in pool '%s'\n", name);
573 return gpg_error (GPG_ERR_NO_KEYSERVER);
577 assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size);
578 hi = hosttable[hi->poolidx];
584 log_error ("host '%s' marked as dead\n", hi->name);
590 return gpg_error (GPG_ERR_NO_KEYSERVER);
595 /* If the hosttable does not indicate that a certain host
596 supports IPv<N>, we explicit set the corresponding http
597 flags. The reason for this is that a host might be listed in
598 a pool as not v6 only but actually support v6 when later
599 the name is resolved by our http layer. */
601 *r_httpflags |= HTTP_FLAG_IGNORE_IPv4;
603 *r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
605 /* Note that we do not set the HTTP_FLAG_FORCE_TOR for onion
606 addresses because the http module detects this itself. This
607 also allows us to use an onion address without Tor mode being
611 *r_host = xtrystrdup (hi->name);
614 err = gpg_error_from_syserror ();
623 snprintf (r_portstr, 6 /* five digits and the sentinel */,
629 /* Mark the host NAME as dead. NAME may be given as an URL. Returns
630 true if a host was really marked as dead or was already marked dead
631 (e.g. by a concurrent session). */
633 mark_host_dead (const char *name)
636 char *host_buffer = NULL;
637 parsed_uri_t parsed_uri = NULL;
640 if (name && *name && !http_parse_uri (&parsed_uri, name, 1))
642 if (parsed_uri->v6lit)
644 host_buffer = strconcat ("[", parsed_uri->host, "]", NULL);
646 log_error ("out of core in mark_host_dead");
650 host = parsed_uri->host;
655 if (host && *host && strcmp (host, "localhost"))
660 idx = find_hostinfo (host);
664 log_info ("marking host '%s' as dead%s\n",
665 hi->name, hi->dead? " (again)":"");
667 hi->died_at = gnupg_get_time ();
674 http_release_parsed_uri (parsed_uri);
680 /* Mark a host in the hosttable as dead or - if ALIVE is true - as
683 ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
687 int idx, idx2, idx3, n;
689 if (!name || !*name || !strcmp (name, "localhost"))
692 idx = find_hostinfo (name);
694 return gpg_error (GPG_ERR_NOT_FOUND);
697 if (alive && hi->dead)
700 err = ks_printf_help (ctrl, "marking '%s' as alive", name);
702 else if (!alive && !hi->dead)
705 hi->died_at = 0; /* Manually set dead. */
706 err = ks_printf_help (ctrl, "marking '%s' as dead", name);
709 /* If the host is a pool mark all member hosts. */
710 if (!err && hi->pool)
712 for (idx2=0; !err && (n=hi->pool[idx2]) != -1; idx2++)
714 assert (n >= 0 && n < hosttable_size);
718 /* Do not mark a host from a pool dead if it is also a
719 member in another pool. */
720 for (idx3=0; idx3 < hosttable_size; idx3++)
723 && hosttable[idx3]->pool
725 && host_in_pool_p (hosttable[idx3]->pool, n))
728 if (idx3 < hosttable_size)
729 continue; /* Host is also a member of another pool. */
735 else if (alive && hi2->dead)
738 err = ks_printf_help (ctrl, "marking '%s' as alive",
741 else if (!alive && !hi2->dead)
744 hi2->died_at = 0; /* Manually set dead. */
745 err = ks_printf_help (ctrl, "marking '%s' as dead",
755 /* Debug function to print the entire hosttable. */
757 ks_hkp_print_hosttable (ctrl_t ctrl)
767 err = ks_print_help (ctrl, "hosttable (idx, ipv6, ipv4, dead, name, time):");
771 curtime = gnupg_get_time ();
772 for (idx=0; idx < hosttable_size; idx++)
773 if ((hi=hosttable[idx]))
775 if (hi->dead && hi->died_at)
777 died = elapsed_time_string (hi->died_at, curtime);
778 diedstr = died? died : "error";
781 diedstr = died = NULL;
782 err = ks_printf_help (ctrl, "%3d %s %s %s %s%s%s%s%s%s%s%s\n",
784 hi->onion? "O" : hi->v6? "6":" ",
788 hi->v6addr? " v6=":"",
789 hi->v6addr? hi->v6addr:"",
790 hi->v4addr? " v4=":"",
791 hi->v4addr? hi->v4addr:"",
800 err = ks_printf_help (ctrl, " . %s", hi->cname);
806 init_membuf (&mb, 256);
807 put_membuf_printf (&mb, " . -->");
808 for (idx2=0; hi->pool[idx2] != -1; idx2++)
810 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
811 if (hi->poolidx == hi->pool[idx2])
812 put_membuf_printf (&mb, "*");
814 put_membuf( &mb, "", 1);
815 p = get_membuf (&mb, NULL);
817 return gpg_error_from_syserror ();
818 err = ks_print_help (ctrl, p);
829 /* Print a help output for the schemata supported by this module. */
831 ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
833 const char const data[] =
834 "Handler for HKP URLs:\n"
836 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
839 "Supported methods: search, get, put\n";
842 #if HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
843 const char data2[] = " hkp\n hkps";
845 const char data2[] = " hkp";
849 err = ks_print_help (ctrl, data2);
850 else if (uri->is_http && (!strcmp (uri->scheme, "hkp")
851 || !strcmp (uri->scheme, "hkps")))
852 err = ks_print_help (ctrl, data);
860 /* Build the remote part of the URL from SCHEME, HOST and an optional
861 PORT. Returns an allocated string at R_HOSTPORT or NULL on failure
862 If R_POOLNAME is not NULL it receives a malloced string with the
865 make_host_part (ctrl_t ctrl,
866 const char *scheme, const char *host, unsigned short port,
868 char **r_hostport, unsigned int *r_httpflags, char **r_poolname)
877 err = map_host (ctrl, host, force_reselect,
878 &hostname, portstr, r_httpflags, r_poolname);
882 /* Map scheme and port. */
883 if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
887 strcpy (portstr, "443");
889 else /* HKP or HTTP. */
893 strcpy (portstr, "11371");
896 snprintf (portstr, sizeof portstr, "%hu", port);
899 /*fixme_do_srv_lookup ()*/
902 *r_hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
911 return gpg_error_from_syserror ();
917 /* Resolve all known keyserver names and update the hosttable. This
918 is mainly useful for debugging because the resolving is anyway done
921 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
924 char *hostport = NULL;
926 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, 1,
927 &hostport, NULL, NULL);
930 err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
931 uri->scheme, uri->host, uri->port,
936 err = ks_printf_help (ctrl, "%s", hostport);
943 /* Housekeeping function called from the housekeeping thread. It is
944 used to mark dead hosts alive so that they may be tried again after
947 ks_hkp_housekeeping (time_t curtime)
952 for (idx=0; idx < hosttable_size; idx++)
960 continue; /* Do not resurrect manually shot hosts. */
961 if (hi->died_at + RESURRECT_INTERVAL <= curtime
962 || hi->died_at > curtime)
965 log_info ("resurrected host '%s'", hi->name);
971 /* Send an HTTP request. On success returns an estream object at
972 R_FP. HOSTPORTSTR is only used for diagnostics. If HTTPHOST is
973 not NULL it will be used as HTTP "Host" header. If POST_CB is not
974 NULL a post request is used and that callback is called to allow
975 writing the post data. If R_HTTP_STATUS is not NULL, the http
976 status code will be stored there. */
978 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
979 const char *httphost, unsigned int httpflags,
980 gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
981 estream_t *r_fp, unsigned int *r_http_status)
984 http_session_t session = NULL;
986 int redirects_left = MAX_REDIRECTS;
988 char *request_buffer = NULL;
992 err = http_session_new (&session, NULL, httphost, HTTP_FLAG_TRUST_DEF);
995 http_session_set_log_cb (session, cert_log_cb);
998 err = http_open (&http,
999 post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
1002 /* fixme: AUTH */ NULL,
1004 |(opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
1005 |(opt.use_tor? HTTP_FLAG_FORCE_TOR:0)),
1009 /*FIXME curl->srvtag*/NULL);
1012 fp = http_get_write_ptr (http);
1013 /* Avoid caches to get the most recent copy of the key. We set
1014 both the Pragma and Cache-Control versions of the header, so
1015 we're good with both HTTP 1.0 and 1.1. */
1016 es_fputs ("Pragma: no-cache\r\n"
1017 "Cache-Control: no-cache\r\n", fp);
1019 err = post_cb (post_cb_value, http);
1022 http_start_data (http);
1024 err = gpg_error_from_syserror ();
1029 /* Fixme: After a redirection we show the old host name. */
1030 log_error (_("error connecting to '%s': %s\n"),
1031 hostportstr, gpg_strerror (err));
1035 /* Wait for the response. */
1036 dirmngr_tick (ctrl);
1037 err = http_wait_response (http);
1040 log_error (_("error reading HTTP response for '%s': %s\n"),
1041 hostportstr, gpg_strerror (err));
1045 if (http_get_tls_info (http, NULL))
1047 /* Update the httpflags so that a redirect won't fallback to an
1048 unencrypted connection. */
1049 httpflags |= HTTP_FLAG_FORCE_TLS;
1053 *r_http_status = http_get_status_code (http);
1055 switch (http_get_status_code (http))
1059 break; /* Success. */
1065 const char *s = http_get_header (http, "Location");
1067 log_info (_("URL '%s' redirected to '%s' (%u)\n"),
1068 request, s?s:"[none]", http_get_status_code (http));
1069 if (s && *s && redirects_left-- )
1071 xfree (request_buffer);
1072 request_buffer = xtrystrdup (s);
1075 request = request_buffer;
1076 http_close (http, 0);
1080 err = gpg_error_from_syserror ();
1083 err = gpg_error (GPG_ERR_NO_DATA);
1084 log_error (_("too many redirections\n"));
1089 err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1093 log_error (_("error accessing '%s': http status %u\n"),
1094 request, http_get_status_code (http));
1095 err = gpg_error (GPG_ERR_NO_DATA);
1099 /* FIXME: We should register a permanent redirection and whether a
1100 host has ever used TLS so that future calls will always use
1103 fp = http_get_read_ptr (http);
1106 err = gpg_error (GPG_ERR_BUG);
1110 /* Return the read stream and close the HTTP context. */
1112 http_close (http, 1);
1116 http_close (http, 0);
1117 http_session_release (session);
1118 xfree (request_buffer);
1123 /* Helper to evaluate the error code ERR form a send_request() call
1124 with REQUEST. The function returns true if the caller shall try
1125 again. TRIES_LEFT points to a variable to track the number of
1126 retries; this function decrements it and won't return true if it is
1129 handle_send_request_error (gpg_error_t err, const char *request,
1130 unsigned int *tries_left)
1134 switch (gpg_err_code (err))
1136 case GPG_ERR_ECONNREFUSED:
1137 case GPG_ERR_ENETUNREACH:
1138 case GPG_ERR_UNKNOWN_HOST:
1139 case GPG_ERR_NETWORK:
1140 if (mark_host_dead (request) && *tries_left)
1144 case GPG_ERR_ETIMEDOUT:
1147 log_info ("selecting a different host due to a timeout\n");
1162 /* Search the keyserver identified by URI for keys matching PATTERN.
1163 On success R_FP has an open stream to read the data. If
1164 R_HTTP_STATUS is not NULL, the http status code will be stored
1167 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
1168 estream_t *r_fp, unsigned int *r_http_status)
1171 KEYDB_SEARCH_DESC desc;
1172 char fprbuf[2+40+1];
1173 char *hostport = NULL;
1174 char *request = NULL;
1175 estream_t fp = NULL;
1177 unsigned int httpflags;
1178 char *httphost = NULL;
1179 unsigned int tries = SEND_REQUEST_RETRIES;
1183 /* Remove search type indicator and adjust PATTERN accordingly.
1184 Note that HKP keyservers like the 0x to be present when searching
1185 by keyid. We need to re-format the fingerprint and keyids so to
1186 remove the gpg specific force-use-of-this-key flag ("!"). */
1187 err = classify_user_id (pattern, &desc, 1);
1192 case KEYDB_SEARCH_MODE_EXACT:
1193 case KEYDB_SEARCH_MODE_SUBSTR:
1194 case KEYDB_SEARCH_MODE_MAIL:
1195 case KEYDB_SEARCH_MODE_MAILSUB:
1196 pattern = desc.u.name;
1198 case KEYDB_SEARCH_MODE_SHORT_KID:
1199 snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1202 case KEYDB_SEARCH_MODE_LONG_KID:
1203 snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
1204 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1207 case KEYDB_SEARCH_MODE_FPR16:
1210 bin2hex (desc.u.fpr, 16, fprbuf+2);
1213 case KEYDB_SEARCH_MODE_FPR20:
1214 case KEYDB_SEARCH_MODE_FPR:
1217 bin2hex (desc.u.fpr, 20, fprbuf+2);
1221 return gpg_error (GPG_ERR_INV_USER_ID);
1224 /* Build the request string. */
1230 xfree (hostport); hostport = NULL;
1231 xfree (httphost); httphost = NULL;
1232 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1233 &hostport, &httpflags, &httphost);
1237 searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
1240 err = gpg_error_from_syserror ();
1245 request = strconcat (hostport,
1246 "/pks/lookup?op=index&options=mr&search=",
1252 err = gpg_error_from_syserror ();
1257 /* Send the request. */
1258 err = send_request (ctrl, request, hostport, httphost, httpflags,
1259 NULL, NULL, &fp, r_http_status);
1260 if (handle_send_request_error (err, request, &tries))
1268 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1272 /* Peek at the response. */
1274 int c = es_getc (fp);
1277 err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
1278 log_error ("error reading response: %s\n", gpg_strerror (err));
1283 /* The document begins with a '<': Assume a HTML response,
1284 which we don't support. */
1285 err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
1291 /* Return the read stream. */
1304 /* Get the key described key the KEYSPEC string from the keyserver
1305 identified by URI. On success R_FP has an open stream to read the
1306 data. The data will be provided in a format GnuPG can import
1307 (either a binary OpenPGP message or an armored one). */
1309 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1312 KEYDB_SEARCH_DESC desc;
1313 char kidbuf[2+40+1];
1314 const char *exactname = NULL;
1315 char *searchkey = NULL;
1316 char *hostport = NULL;
1317 char *request = NULL;
1318 estream_t fp = NULL;
1320 char *httphost = NULL;
1321 unsigned int httpflags;
1322 unsigned int tries = SEND_REQUEST_RETRIES;
1326 /* Remove search type indicator and adjust PATTERN accordingly.
1327 Note that HKP keyservers like the 0x to be present when searching
1328 by keyid. We need to re-format the fingerprint and keyids so to
1329 remove the gpg specific force-use-of-this-key flag ("!"). */
1330 err = classify_user_id (keyspec, &desc, 1);
1335 case KEYDB_SEARCH_MODE_SHORT_KID:
1336 snprintf (kidbuf, sizeof kidbuf, "0x%08lX", (ulong)desc.u.kid[1]);
1338 case KEYDB_SEARCH_MODE_LONG_KID:
1339 snprintf (kidbuf, sizeof kidbuf, "0x%08lX%08lX",
1340 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1342 case KEYDB_SEARCH_MODE_FPR20:
1343 case KEYDB_SEARCH_MODE_FPR:
1344 /* This is a v4 fingerprint. */
1347 bin2hex (desc.u.fpr, 20, kidbuf+2);
1350 case KEYDB_SEARCH_MODE_EXACT:
1351 exactname = desc.u.name;
1354 case KEYDB_SEARCH_MODE_FPR16:
1355 log_error ("HKP keyservers do not support v3 fingerprints\n");
1357 return gpg_error (GPG_ERR_INV_USER_ID);
1360 searchkey = http_escape_string (exactname? exactname : kidbuf,
1361 EXTRA_ESCAPE_CHARS);
1364 err = gpg_error_from_syserror ();
1370 /* Build the request string. */
1371 xfree (hostport); hostport = NULL;
1372 xfree (httphost); httphost = NULL;
1373 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1374 &hostport, &httpflags, &httphost);
1379 request = strconcat (hostport,
1380 "/pks/lookup?op=get&options=mr&search=",
1382 exactname? "&exact=on":"",
1386 err = gpg_error_from_syserror ();
1390 /* Send the request. */
1391 err = send_request (ctrl, request, hostport, httphost, httpflags,
1392 NULL, NULL, &fp, NULL);
1393 if (handle_send_request_error (err, request, &tries))
1401 err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1405 /* Return the read stream and close the HTTP context. */
1421 /* Callback parameters for put_post_cb. */
1422 struct put_post_parm_s
1428 /* Helper for ks_hkp_put. */
1430 put_post_cb (void *opaque, http_t http)
1432 struct put_post_parm_s *parm = opaque;
1433 gpg_error_t err = 0;
1437 fp = http_get_write_ptr (http);
1438 len = strlen (parm->datastring);
1441 "Content-Type: application/x-www-form-urlencoded\r\n"
1442 "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1443 http_start_data (http);
1444 if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1445 err = gpg_error_from_syserror ();
1450 /* Send the key in {DATA,DATALEN} to the keyserver identified by URI. */
1452 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1455 char *hostport = NULL;
1456 char *request = NULL;
1457 estream_t fp = NULL;
1458 struct put_post_parm_s parm;
1459 char *armored = NULL;
1461 char *httphost = NULL;
1462 unsigned int httpflags;
1463 unsigned int tries = SEND_REQUEST_RETRIES;
1465 parm.datastring = NULL;
1467 err = armor_data (&armored, data, datalen);
1471 parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1472 if (!parm.datastring)
1474 err = gpg_error_from_syserror ();
1480 /* Build the request string. */
1483 xfree (hostport); hostport = NULL;
1484 xfree (httphost); httphost = NULL;
1485 err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect,
1486 &hostport, &httpflags, &httphost);
1491 request = strconcat (hostport, "/pks/add", NULL);
1494 err = gpg_error_from_syserror ();
1498 /* Send the request. */
1499 err = send_request (ctrl, request, hostport, httphost, 0,
1500 put_post_cb, &parm, &fp, NULL);
1501 if (handle_send_request_error (err, request, &tries))
1511 xfree (parm.datastring);