[seahorse/bpereto/seahorse-feature-hkps] pgp: add HKPS support
- From: Niels De Graef <nielsdg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [seahorse/bpereto/seahorse-feature-hkps] pgp: add HKPS support
- Date: Sat, 5 Dec 2020 22:26:19 +0000 (UTC)
commit a9c379a7df8114387bb9a5a604deedbfc9e4557d
Author: Benjamin Pereto <benjamin sandchaschte ch>
Date: Wed Apr 29 19:02:48 2020 +0200
pgp: add HKPS support
Add support for HKPS keyservers, which runs HKP over TLS.
Use machine readable format for HKP protocol instead of filtering HTML.
pgp/seahorse-hkp-source.c | 307 ++++++++++++++++++++++---------------------
pgp/seahorse-server-source.c | 77 ++++++-----
2 files changed, 197 insertions(+), 187 deletions(-)
---
diff --git a/pgp/seahorse-hkp-source.c b/pgp/seahorse-hkp-source.c
index 35d741f7..569b5c1c 100644
--- a/pgp/seahorse-hkp-source.c
+++ b/pgp/seahorse-hkp-source.c
@@ -71,32 +71,28 @@ G_DEFINE_TYPE (SeahorseHKPSource, seahorse_hkp_source, SEAHORSE_TYPE_SERVER_SOUR
*
* Returns: A #SoupUri with server, port and paths
*/
-static SoupURI*
+static SoupURI *
get_http_server_uri (SeahorseHKPSource *self, const char *path)
{
g_autoptr(SoupURI) uri = NULL;
g_autofree gchar *server = NULL;
- gchar *port;
+ g_autofree char *conf_uri = NULL;
g_object_get (self, "key-server", &server, NULL);
g_return_val_if_fail (server != NULL, NULL);
-
- uri = soup_uri_new (NULL);
- soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTP);
-
- /* If it already has a port then use that */
- port = strchr (server, ':');
- if (port) {
- *port++ = '\0';
- soup_uri_set_port (uri, atoi (port));
- } else {
- /* default HKP port */
- soup_uri_set_port (uri, 11371);
+ g_object_get (self, "uri", &conf_uri, NULL);
+
+ if (strncasecmp (conf_uri, "hkp:", 4) == 0) {
+ g_autofree char *t = g_strdup_printf ("http:%s", conf_uri + 4);
+ uri = soup_uri_new (t);
+ } else if (strncasecmp (conf_uri, "hkps:", 5) == 0) {
+ g_autofree char *t = g_strdup_printf ("https:%s", conf_uri + 5);
+ uri = soup_uri_new (t);
}
- soup_uri_set_host (uri, server);
soup_uri_set_path (uri, path);
+ g_debug ("HTTP Server URI: %s", soup_uri_to_string(uri, FALSE));
return g_steal_pointer (&uri);
}
@@ -196,54 +192,31 @@ dehtmlize (gchar *line)
}
}
-/**
- * parse_hkp_date:
- * @text: The date string to parse, YYYY-MM-DD
- *
+/*
+ * @flags: combintation of [rei] representing the key's status
*
+ * Parses the flags from the HKP output
*
- * Returns: 0 on error or the timestamp
+ * returns 0 on error or a combination of seahorse flags based on input
*/
-static unsigned int
-parse_hkp_date (const gchar *text)
-{
- int year, month, day;
- struct tm tmbuf;
- time_t stamp;
-
- if (strlen (text) != 10 || text[4] != '-' || text[7] != '-')
- return 0;
-
- /* YYYY-MM-DD */
- sscanf (text, "%4d-%2d-%2d", &year, &month, &day);
-
- /* some basic checks */
- if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31)
- return 0;
-
- memset (&tmbuf, 0, sizeof tmbuf);
- tmbuf.tm_mday = day;
- tmbuf.tm_mon = month - 1;
- tmbuf.tm_year = year - 1900;
- tmbuf.tm_isdst = -1;
-
- stamp = mktime (&tmbuf);
- return stamp == (time_t)-1 ? 0 : stamp;
-}
-
-static const gchar *
-get_fingerprint_string (const gchar *line)
+static guint
+parse_hkp_flags (char *flags)
{
- const gchar *p;
-
- p = line;
- while (*p && g_ascii_isspace (*p))
- p++;
-
- if (g_ascii_strncasecmp (p, "fingerprint=", 12) == 0)
- return p + 12;
-
- return NULL;
+ char flag = 0;
+ for (char *f = flags; f && *f; f++) {
+ switch (*f) {
+ case 'r':
+ flag |= SEAHORSE_FLAG_REVOKED;
+ break;
+ case 'e':
+ flag |= SEAHORSE_FLAG_EXPIRED;
+ break;
+ case 'd':
+ flag |= SEAHORSE_FLAG_DISABLED;
+ break;
+ }
+ }
+ return flag;
}
/**
@@ -256,157 +229,190 @@ get_fingerprint_string (const gchar *line)
static GList*
parse_hkp_index (const gchar *response)
{
- /* Luckily enough, both the HKP server and NAI HKP interface to their
- * LDAP server are close enough in output so the same function can
- * parse them both. */
-
- /* pub 2048/<a href="/pks/lookup?op=get&search=0x3CB3B415">3CB3B415</a> 1998/04/03 David M. Shaw <<a
href="/pks/lookup?op=get&search=0x3CB3B415">dshaw jabberwocky com</a>> */
-
+ /*
+ * Use The OpenPGP HTTP Keyserver Protocol (HKP) to search and get keys
+ * https://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-5
+ */
g_auto(GStrv) lines = NULL;
+ g_auto(GStrv) columns = NULL;
gchar **l;
-
SeahorsePgpKey *key = NULL;
- SeahorsePgpSubkey *subkey_with_id = NULL;
GList *keys = NULL;
GList *subkeys = NULL;
GList *uids = NULL;
SeahorseFlags flags;
+ gboolean has_uid = FALSE;
+ char *uid_string;
+ guint key_total = 0, key_count = 0;
lines = g_strsplit (response, "\n", 0);
for (l = lines; *l; l++) {
- gchar *line, *t;
+ char *line;
line = *l;
- dehtmlize (line);
g_debug ("%s", line);
- /* Start a new key */
- if (g_ascii_strncasecmp (line, "pub ", 4) == 0) {
- g_auto(GStrv) v = NULL;
+ if (strlen(line) == 0) {
+ g_debug ("HKP Parser: skip empty line");
+ continue;
+ }
+
+ /* split the line using hkp delimiter */
+ columns = g_strsplit_set(line, ":", 7);
+
+ /* info header */
+ if (g_ascii_strncasecmp (columns[0], "info", 4) == 0) {
+ if (!columns[1] && !columns[2]) {
+ g_debug("HKP Parse: Invalid info line: %s", line);
+ } else {
+ key_total = strtol (columns[2], NULL, 10);
+ }
+
+ /* start a new key */
+ /* pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags> */
+ } else if (g_ascii_strncasecmp (columns[0], "pub", 3) == 0) {
gchar *fingerprint, *fpr = NULL;
const gchar *algo;
- gboolean has_uid = TRUE;
SeahorsePgpSubkey *subkey;
+ long created = 0, expired = 0;
- t = line + 4;
- while (*t && g_ascii_isspace (*t))
- t++;
+ key_count++;
- v = g_strsplit_set (t, " ", 3);
- if (!v[0] || !v[1] || !v[2]) {
+ /* reset previous key */
+ if (key) {
+ g_debug ("HKP Parse: previous key found");
+ if (has_uid) {
+ seahorse_pgp_key_set_uids (SEAHORSE_PGP_KEY (key), uids);
+ g_list_free_full (uids, g_object_unref);
+ seahorse_pgp_key_set_subkeys (SEAHORSE_PGP_KEY (key), subkeys);
+ g_list_free_full (subkeys, g_object_unref);
+ seahorse_pgp_key_realize (SEAHORSE_PGP_KEY (key));
+ keys = g_list_prepend (keys, key);
+ } else {
+ g_debug ("HKP Parse: no uid found");
+ }
+ uids = subkeys = NULL;
+ has_uid = FALSE;
+ key = NULL;
+ }
+
+ if (!columns[0] || !columns[1] || !columns[2] || !columns[3] || !columns[4]) {
g_message ("Invalid key line from server: %s", line);
continue;
}
- flags = SEAHORSE_FLAG_EXPORTABLE;
-
/* Cut the length and fingerprint */
- fpr = strchr (v[0], '/');
+ fpr = columns[1];
if (fpr == NULL) {
g_message ("couldn't find key fingerprint in line from server: %s", line);
- fpr = "";
- } else {
- *(fpr++) = 0;
}
/* Check out the key type */
- switch (g_ascii_toupper (v[0][strlen (v[0]) - 1])) {
- case 'D':
- algo = "DSA";
- break;
- case 'R':
- algo = "RSA";
- break;
- default:
- algo = "";
- break;
- };
-
- /* Format the date for our parse function */
- g_strdelimit (v[1], "/", '-');
+ switch (strtol (columns[2], NULL, 10)) {
+ case 1:
+ case 2:
+ case 3:
+ algo = "RSA";
+ break;
+ case 17:
+ algo = "DSA";
+ break;
+ default:
+ break;
+ }
+ g_debug ("Algo: %s", algo);
- /* Cleanup the UID */
- g_strstrip (v[2]);
+ /* set dates */
+ /* created */
+ if (!columns[4]) {
+ g_debug ("HKP Parse: No created date for key on line: %s",
+ line);
+ } else {
+ created = strtol (columns[4], NULL, 10);
+ }
- if (g_ascii_strcasecmp (v[2], "*** KEY REVOKED ***") == 0) {
- flags |= SEAHORSE_FLAG_REVOKED;
- has_uid = FALSE;
+ /* expires (optional) */
+ if (columns[5]) {
+ expired = strtol (columns[5], NULL, 10);
}
- if (key) {
- seahorse_pgp_key_set_uids (SEAHORSE_PGP_KEY (key), uids);
- g_list_free_full (uids, g_object_unref);
- seahorse_pgp_key_set_subkeys (SEAHORSE_PGP_KEY (key), subkeys);
- g_list_free_full (subkeys, g_object_unref);
- seahorse_pgp_key_realize (SEAHORSE_PGP_KEY (key));
- uids = subkeys = NULL;
- subkey_with_id = NULL;
- key = NULL;
+ /* set flags (optional) */
+ flags = SEAHORSE_FLAG_EXPORTABLE;
+ if (columns[6]) {
+ flags |= parse_hkp_flags (columns[6]);
}
+ /* create key */
+ g_debug ("HKP Parse: found new key");
key = seahorse_pgp_key_new ();
- keys = g_list_prepend (keys, key);
g_object_set (key, "object-flags", flags, NULL);
/* Add all the info to the key */
subkey = seahorse_pgp_subkey_new ();
seahorse_pgp_subkey_set_keyid (subkey, fpr);
- subkey_with_id = subkey;
fingerprint = seahorse_pgp_subkey_calc_fingerprint (fpr);
seahorse_pgp_subkey_set_fingerprint (subkey, fingerprint);
g_free (fingerprint);
seahorse_pgp_subkey_set_flags (subkey, flags);
- seahorse_pgp_subkey_set_created (subkey, parse_hkp_date (v[1]));
- seahorse_pgp_subkey_set_length (subkey, strtol (v[0], NULL, 10));
+
+ seahorse_pgp_subkey_set_created (subkey, created);
+ seahorse_pgp_subkey_set_expires (subkey, expired);
+ seahorse_pgp_subkey_set_length (subkey, strtol (columns[3], NULL, 10));
seahorse_pgp_subkey_set_algorithm (subkey, algo);
subkeys = g_list_prepend (subkeys, subkey);
- /* And the UID if one was found */
- if (has_uid) {
- SeahorsePgpUid *uid = seahorse_pgp_uid_new (key, v[2]);
- uids = g_list_prepend (uids, uid);
- }
-
/* A UID for the key */
- } else if (key && g_ascii_strncasecmp (line, " ", 4) == 0) {
+ } else if (g_ascii_strncasecmp (columns[0], "uid", 3) == 0) {
SeahorsePgpUid *uid;
- g_strstrip (line);
- uid = seahorse_pgp_uid_new (key, line);
- uids = g_list_prepend (uids, uid);
-
- /* Signatures */
- } else if (key && g_ascii_strncasecmp (line, "sig ", 4) == 0) {
- /* TODO: Implement signatures */
+ if (!key) {
+ g_debug ("HKP Parse: Warning: seen uid line before keyline, skipping");
+ g_strfreev (columns);
+ continue;
+ }
- } else if (key && subkey_with_id) {
- const char *fingerprint_str;
- g_autofree gchar *pretty_fingerprint = NULL;
+ g_debug ("HKP Parse: handle uid");
+ has_uid = TRUE;
- fingerprint_str = get_fingerprint_string (line);
- if (fingerprint_str == NULL)
+ if (!columns[0] || !columns[1] || !columns[2]) {
+ g_message ("HKP Parse: Invalid uid line from server: %s", line);
continue;
+ }
- pretty_fingerprint = seahorse_pgp_subkey_calc_fingerprint (fingerprint_str);
+ uid_string = g_uri_unescape_string (columns[1], NULL);
+ g_debug ("HKP Parse: decoded uid string: %s", uid_string);
- /* FIXME: we don't check that the fingerprint actually matches
- * the key's ID. We also don't validate the fingerprint at
- * all; the keyserver may have returned some garbage and we
- * don't notice. */
- if (pretty_fingerprint[0] != 0)
- seahorse_pgp_subkey_set_fingerprint (subkey_with_id, pretty_fingerprint);
+ uid = seahorse_pgp_uid_new (key, uid_string);
+ uids = g_list_prepend (uids, uid);
}
}
+ /* handle last entry */
if (key) {
- seahorse_pgp_key_set_uids (SEAHORSE_PGP_KEY (key), g_list_reverse (uids));
- g_list_free_full (uids, g_object_unref);
- seahorse_pgp_key_set_subkeys (SEAHORSE_PGP_KEY (key), g_list_reverse (subkeys));
- g_list_free_full (subkeys, g_object_unref);
- seahorse_pgp_key_realize (SEAHORSE_PGP_KEY (key));
+ if (has_uid) {
+ seahorse_pgp_key_set_uids (SEAHORSE_PGP_KEY (key), uids);
+ g_list_free_full (uids, g_object_unref);
+ seahorse_pgp_key_set_subkeys (SEAHORSE_PGP_KEY (key), subkeys);
+ g_list_free_full (subkeys, g_object_unref);
+ seahorse_pgp_key_realize (SEAHORSE_PGP_KEY (key));
+ keys = g_list_prepend (keys, key);
+ } else {
+ g_debug ("HKP Parse: No UID found.");
+ }
+ uids = subkeys = NULL;
+ has_uid = FALSE;
+ key = NULL;
+ }
+
+ if (key_total != 0 && key_total != key_count) {
+ g_message ("HKP Parse; Warning: Issue during HKP parsing, "
+ "only %d keys were parsed out of %d", key_count, key_total);
+
+ } else {
+ g_debug ("HKP Parse: %d keys parsed successfully", key_count);
}
return keys;
@@ -641,13 +647,14 @@ seahorse_hkp_source_search_async (SeahorseServerSource *source,
form = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (form, "op", "index");
+ g_hash_table_insert (form, "options", "mr");
if (is_hex_keyid (match)) {
strncpy (hexfpr, "0x", 3);
strncpy (hexfpr + 2, match, 9);
g_hash_table_insert (form, "search", hexfpr);
} else {
- g_hash_table_insert (form, "search", (char *)match);
+ g_hash_table_insert (form, "search", (char *) match);
}
g_hash_table_insert (form, "fingerprint", "on");
@@ -994,6 +1001,7 @@ seahorse_hkp_source_class_init (SeahorseHKPSourceClass *klass)
server_class->import_finish = seahorse_hkp_source_import_finish;
seahorse_servers_register_type ("hkp", _("HTTP Key Server"), seahorse_hkp_is_valid_uri);
+ seahorse_servers_register_type ("hkps", _("HTTPS Key Server"), seahorse_hkp_is_valid_uri);
}
/**
* seahorse_hkp_source_new:
@@ -1032,6 +1040,9 @@ seahorse_hkp_is_valid_uri (const gchar *uri)
g_autofree gchar *t = g_strdup_printf ("http:%s", uri + 4);
soup = soup_uri_new (t);
/* Not 'hkp', but maybe 'http' */
+ } else if (strncasecmp (uri, "hkps:", 5) == 0) {
+ g_autofree gchar *t = g_strdup_printf ("https:%s", uri + 5);
+ soup = soup_uri_new (t);
} else {
soup = soup_uri_new (uri);
}
diff --git a/pgp/seahorse-server-source.c b/pgp/seahorse-server-source.c
index c23ddb1e..70201ffe 100644
--- a/pgp/seahorse-server-source.c
+++ b/pgp/seahorse-server-source.c
@@ -245,14 +245,14 @@ seahorse_server_source_place_iface (SeahorsePlaceIface *iface)
* PROP_KEY_SERVER, PROP_URI
*
**/
-static void
-seahorse_server_set_property (GObject *object, guint prop_id,
+static void
+seahorse_server_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
SeahorseServerSource *ssrc = SEAHORSE_SERVER_SOURCE (object);
SeahorseServerSourcePrivate *priv =
seahorse_server_source_get_instance_private (ssrc);
-
+
switch (prop_id) {
case PROP_LABEL:
seahorse_server_source_set_label (SEAHORSE_PLACE (ssrc),
@@ -270,7 +270,7 @@ seahorse_server_set_property (GObject *object, guint prop_id,
break;
default:
break;
- }
+ }
}
/**
@@ -283,7 +283,7 @@ seahorse_server_set_property (GObject *object, guint prop_id,
* PROP_KEY_SERVER, PROP_URI
*
**/
-static void
+static void
seahorse_server_get_property (GObject *obj,
guint prop_id,
GValue *value,
@@ -373,7 +373,7 @@ seahorse_server_source_collection_init (GcrCollectionIface *iface)
*
* Returns FALSE if the separation failed
**/
-static gboolean
+static gboolean
parse_keyserver_uri (char *uri, const char **scheme, const char **host)
{
int assume_ldap = 0;
@@ -423,59 +423,58 @@ parse_keyserver_uri (char *uri, const char **scheme, const char **host)
*
* Returns: A new SeahorseServerSource or NULL
*/
-SeahorseServerSource*
+SeahorseServerSource*
seahorse_server_source_new (const gchar *server)
{
SeahorseServerSource *ssrc = NULL;
const gchar *scheme;
const gchar *host;
gchar *uri, *t;
-
+
g_return_val_if_fail (server && server[0], NULL);
-
+
uri = g_strdup (server);
-
+
if (!parse_keyserver_uri (uri, &scheme, &host)) {
g_warning ("invalid uri passed: %s", server);
-
+
} else {
-
-#ifdef WITH_LDAP
- /* LDAP Uris */
- if (g_ascii_strcasecmp (scheme, "ldap") == 0)
- ssrc = SEAHORSE_SERVER_SOURCE (seahorse_ldap_source_new (server, host));
- else
+
+#ifdef WITH_LDAP
+ /* LDAP Uris */
+ if (g_ascii_strcasecmp (scheme, "ldap") == 0)
+ ssrc = SEAHORSE_SERVER_SOURCE (seahorse_ldap_source_new (server, host));
+ else
#endif /* WITH_LDAP */
-
+
#ifdef WITH_HKP
- /* HKP Uris */
- if (g_ascii_strcasecmp (scheme, "hkp") == 0) {
-
- ssrc = SEAHORSE_SERVER_SOURCE (seahorse_hkp_source_new (server, host));
+ /* HKP Uris */
+ if (g_ascii_strcasecmp (scheme, "hkp") == 0 ||
+ g_ascii_strcasecmp (scheme, "hkps") == 0) {
+
+ ssrc = SEAHORSE_SERVER_SOURCE (seahorse_hkp_source_new (server, host));
- /* HTTP Uris */
- } else if (g_ascii_strcasecmp (scheme, "http") == 0 ||
- g_ascii_strcasecmp (scheme, "https") == 0) {
+ /* HTTP Uris */
+ } else if (g_ascii_strcasecmp (scheme, "http") == 0 ||
+ g_ascii_strcasecmp (scheme, "https") == 0) {
- /* If already have a port */
- if (strchr (host, ':'))
- ssrc = SEAHORSE_SERVER_SOURCE (seahorse_hkp_source_new (server, host));
+ /* If already have a port */
+ if (strchr (host, ':'))
+ ssrc = SEAHORSE_SERVER_SOURCE (seahorse_hkp_source_new (server, host));
- /* No port make sure to use defaults */
- else {
- t = g_strdup_printf ("%s:%d", host,
- (g_ascii_strcasecmp (scheme, "http") == 0) ? 80 : 443);
- ssrc = SEAHORSE_SERVER_SOURCE (seahorse_hkp_source_new (server, t));
- g_free (t);
- }
+ /* No port make sure to use defaults */
+ else {
+ t = g_strdup_printf ("%s:%d", host, (g_ascii_strcasecmp (scheme, "http") == 0) ? 80 : 443);
+ ssrc = SEAHORSE_SERVER_SOURCE (seahorse_hkp_source_new (server, t));
+ g_free (t);
+ }
- } else
+ } else
#endif /* WITH_HKP */
-
- g_message ("unsupported key server uri scheme: %s", scheme);
+ g_message ("unsupported key server uri scheme: %s", scheme);
}
-
+
g_free (uri);
return ssrc;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]