aboutsummaryrefslogtreecommitdiffstats
path: root/dirmngr/ks-engine-hkp.c
diff options
context:
space:
mode:
Diffstat (limited to 'dirmngr/ks-engine-hkp.c')
-rw-r--r--dirmngr/ks-engine-hkp.c294
1 files changed, 211 insertions, 83 deletions
diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c
index 356f64348..662e9e4cb 100644
--- a/dirmngr/ks-engine-hkp.c
+++ b/dirmngr/ks-engine-hkp.c
@@ -37,6 +37,117 @@
#define MAX_REDIRECTS 2
+/* Send an HTTP request. On success returns an estream object at
+ R_FP. HOSTPORTSTR is only used for diagnostics. */
+static gpg_error_t
+send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
+ estream_t *r_fp)
+{
+ gpg_error_t err;
+ http_t http = NULL;
+ int redirects_left = MAX_REDIRECTS;
+ estream_t fp = NULL;
+ char *request_buffer = NULL;
+
+ *r_fp = NULL;
+ once_more:
+ err = http_open (&http, HTTP_REQ_GET, request,
+ /* fixme: AUTH */ NULL,
+ 0,
+ /* fixme: proxy*/ NULL,
+ NULL, NULL,
+ /*FIXME curl->srvtag*/NULL);
+ if (!err)
+ {
+ 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);
+ http_start_data (http);
+ if (es_ferror (fp))
+ err = gpg_error_from_syserror ();
+ }
+ if (err)
+ {
+ /* Fixme: After a redirection we show the old host name. */
+ log_error (_("error connecting to `%s': %s\n"),
+ hostportstr, gpg_strerror (err));
+ goto leave;
+ }
+
+ /* Wait for the response. */
+ dirmngr_tick (ctrl);
+ err = http_wait_response (http);
+ if (err)
+ {
+ log_error (_("error reading HTTP response for `%s': %s\n"),
+ hostportstr, gpg_strerror (err));
+ goto leave;
+ }
+
+ switch (http_get_status_code (http))
+ {
+ case 200:
+ err = 0;
+ break; /* Success. */
+
+ case 301:
+ case 302:
+ {
+ const char *s = http_get_header (http, "Location");
+
+ log_info (_("URL `%s' redirected to `%s' (%u)\n"),
+ request, s?s:"[none]", http_get_status_code (http));
+ if (s && *s && redirects_left-- )
+ {
+ xfree (request_buffer);
+ request_buffer = xtrystrdup (s);
+ if (request_buffer)
+ {
+ request = request_buffer;
+ http_close (http, 0);
+ http = NULL;
+ goto once_more;
+ }
+ err = gpg_error_from_syserror ();
+ }
+ else
+ err = gpg_error (GPG_ERR_NO_DATA);
+ log_error (_("too many redirections\n"));
+ }
+ goto leave;
+
+ default:
+ log_error (_("error accessing `%s': http status %u\n"),
+ request, http_get_status_code (http));
+ err = gpg_error (GPG_ERR_NO_DATA);
+ goto leave;
+ }
+
+ fp = http_get_read_ptr (http);
+ if (!fp)
+ {
+ err = gpg_error (GPG_ERR_BUG);
+ goto leave;
+ }
+
+ /* Return the read stream and close the HTTP context. */
+ *r_fp = fp;
+ fp = NULL;
+ http_close (http, 1);
+ http = NULL;
+
+ leave:
+ es_fclose (fp);
+ http_close (http, 0);
+ xfree (request_buffer);
+ return err;
+}
+
+
+
/* Search the keyserver identified by URI for keys matching PATTERN.
On success R_FP has an open stream to read the data. */
gpg_error_t
@@ -48,10 +159,8 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
char fprbuf[2+40+1];
const char *scheme;
char portstr[10];
- http_t http = NULL;
char *hostport = NULL;
char *request = NULL;
- int redirects_left = MAX_REDIRECTS;
estream_t fp = NULL;
*r_fp = NULL;
@@ -142,87 +251,11 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
}
/* Send the request. */
- once_more:
- err = http_open (&http, HTTP_REQ_GET, request,
- /* fixme: AUTH */ NULL,
- 0,
- /* fixme: proxy*/ NULL,
- NULL, NULL,
- /*FIXME curl->srvtag*/NULL);
- if (!err)
- {
- 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);
- http_start_data (http);
- if (es_ferror (fp))
- err = gpg_error_from_syserror ();
- }
+ err = send_request (ctrl, request, hostport, &fp);
if (err)
- {
- /* Fixme: After a redirection we show the old host name. */
- log_error (_("error connecting to `%s': %s\n"),
- hostport, gpg_strerror (err));
- goto leave;
- }
-
- /* Wait for the response. */
- dirmngr_tick (ctrl);
- err = http_wait_response (http);
- if (err)
- {
- log_error (_("error reading HTTP response for `%s': %s\n"),
- hostport, gpg_strerror (err));
- goto leave;
- }
-
- switch (http_get_status_code (http))
- {
- case 200:
- break; /* Success. */
-
- case 301:
- case 302:
- {
- const char *s = http_get_header (http, "Location");
-
- log_info (_("URL `%s' redirected to `%s' (%u)\n"),
- request, s?s:"[none]", http_get_status_code (http));
- if (s && *s && redirects_left-- )
- {
- xfree (request);
- request = xtrystrdup (s);
- if (request)
- {
- http_close (http, 0);
- http = NULL;
- goto once_more;
- }
- err = gpg_error_from_syserror ();
- }
- else
- err = gpg_error (GPG_ERR_NO_DATA);
- log_error (_("too many redirections\n"));
- }
- goto leave;
-
- default:
- log_error (_("error accessing `%s': http status %u\n"),
- request, http_get_status_code (http));
- err = gpg_error (GPG_ERR_NO_DATA);
- goto leave;
- }
+ goto leave;
/* Start reading the response. */
- fp = http_get_read_ptr (http);
- if (!fp)
- {
- err = gpg_error (GPG_ERR_BUG);
- goto leave;
- }
{
int c = es_getc (fp);
if (c == -1)
@@ -241,15 +274,110 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
es_ungetc (c, fp);
}
+ /* Return the read stream. */
+ *r_fp = fp;
+ fp = NULL;
+
+ leave:
+ es_fclose (fp);
+ xfree (request);
+ xfree (hostport);
+ return err;
+}
+
+
+/* Get the key described key the KEYSPEC string from the keyserver
+ identified by URI. On success R_FP has an open stream to read the
+ data. */
+gpg_error_t
+ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
+{
+ gpg_error_t err;
+ KEYDB_SEARCH_DESC desc;
+ char kidbuf[8+1];
+ const char *scheme;
+ char portstr[10];
+ char *hostport = NULL;
+ char *request = NULL;
+ estream_t fp = NULL;
+
+ *r_fp = NULL;
+
+ /* Remove search type indicator and adjust PATTERN accordingly.
+ Note that HKP keyservers like the 0x to be present when searching
+ by keyid. We need to re-format the fingerprint and keyids so to
+ remove the gpg specific force-use-of-this-key flag ("!"). */
+ err = classify_user_id (keyspec, &desc);
+ if (err)
+ return err;
+ switch (desc.mode)
+ {
+ case KEYDB_SEARCH_MODE_SHORT_KID:
+ case KEYDB_SEARCH_MODE_LONG_KID:
+ snprintf (kidbuf, sizeof kidbuf, "%08lX", (ulong)desc.u.kid[1]);
+ break;
+ case KEYDB_SEARCH_MODE_FPR20:
+ case KEYDB_SEARCH_MODE_FPR:
+ /* This is a v4 fingerprint. Take the last 8 hex digits from
+ the fingerprint which is the expected short keyid. */
+ bin2hex (desc.u.fpr+16, 4, kidbuf);
+ break;
+
+ case KEYDB_SEARCH_MODE_FPR16:
+ log_error ("HKP keyserver do not support v3 fingerprints\n");
+ default:
+ return gpg_error (GPG_ERR_INV_USER_ID);
+ }
+
+ /* Map scheme and port. */
+ if (!strcmp (uri->scheme,"hkps") || !strcmp (uri->scheme,"https"))
+ {
+ scheme = "https";
+ strcpy (portstr, "443");
+ }
+ else /* HKP or HTTP. */
+ {
+ scheme = "http";
+ strcpy (portstr, "11371");
+ }
+ if (uri->port)
+ snprintf (portstr, sizeof portstr, "%hu", uri->port);
+ else
+ {} /*fixme_do_srv_lookup ()*/
+
+ /* Build the request string. */
+ {
+ hostport = strconcat (scheme, "://",
+ *uri->host? uri->host: "localhost",
+ ":", portstr, NULL);
+ if (!hostport)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ request = strconcat (hostport,
+ "/pks/lookup?op=get&options=mr&search=0x",
+ kidbuf,
+ NULL);
+ if (!request)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ }
+
+ /* Send the request. */
+ err = send_request (ctrl, request, hostport, &fp);
+ if (err)
+ goto leave;
+
/* Return the read stream and close the HTTP context. */
*r_fp = fp;
fp = NULL;
- http_close (http, 1);
- http = NULL;
leave:
es_fclose (fp);
- http_close (http, 0);
xfree (request);
xfree (hostport);
return err;