# HG changeset patch # User Eike Rathke <er...@erack.de> # Date 1423687117 -3600 # Node ID 01f6559e4bb51bfe86e9f48812480bd4d57adc03 # Parent 385d7434c9d6f44c732fd12fc76d543f9d5d7233 Allow fingerprint user input in pgp_getkeybystr() (part of #3695)
Accept and check input of a fingerprint and find the matching key. Also, along with the addresses an entry with the fingerprint (without any spaces) is now displayed for each key in the list of matches. Note that for both to work, match against and display of fingerprint, the pgp_list_pubring_command and pgp_list_secring_command need to contain the --with-fingerprint option, or have with-fingerprint in ~/.gnupg/gpg.conf diff --git a/crypt.c b/crypt.c --- a/crypt.c +++ b/crypt.c @@ -900,3 +900,81 @@ } +/* Obtain pointers to fingerprint or short or long key ID, if any. + * See mutt_crypt.h for details. + */ +const char* crypt_get_fingerprint_or_id (char *p, const char **pphint, + const char **ppl, const char **pps) +{ + const char *ps, *pl, *phint; + char *pfcopy, *pf, *s1, *s2; + char c; + int isid; + + /* User input may be partial name, fingerprint or short or long key ID, + * independent of OPTPGPLONGIDS. + * Fingerprint without spaces is 40 hex digits (SHA-1) or 32 hex digits (MD5). + * Strip leading "0x" for key ID detection and prepare pl and ps to indicate + * if an ID was found and to simplify logic in the key loop's inner + * condition of the caller. */ + + pf = mutt_skip_whitespace (p); + if (!mutt_strncasecmp (pf, "0x", 2)) + pf += 2; + + /* Check if a fingerprint is given, must be hex digits only, blanks + * separating groups of 4 hex digits are allowed. Also pre-check for ID. */ + isid = 2; /* unknown */ + s1 = s2 = pf; + do + { + c = *(s2++); + if (('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f')) + { + ++s1; /* hex digit */ + if (isid == 2) + isid = 1; /* it is an ID so far */ + } + else if (c) + { + isid = 0; /* not an ID */ + if (c == ' ' && (((s1 - pf) % 4) == 0)) + ; /* skip blank before or after 4 hex digits */ + else + break; /* any other character or position */ + } + } while (c); + + /* If at end of input, check for correct fingerprint length and copy if. */ + pfcopy = (!c && (((s1 - pf) == 40) || ((s1 - pf) == 32)) ? safe_strdup (pf) : NULL); + + if (pfcopy) + { + /* Use pfcopy to strip all spaces from fingerprint and as hint. */ + s1 = s2 = pfcopy; + do + { + *(s1++) = *(s2 = mutt_skip_whitespace (s2)); + } while (*(s2++)); + + phint = pfcopy; + ps = pl = NULL; + } + else + { + phint = p; + ps = pl = NULL; + if (isid == 1) + { + if (mutt_strlen (pf) == 16) + pl = pf; /* long key ID */ + else if (mutt_strlen (pf) == 8) + ps = pf; /* short key ID */ + } + } + + *pphint = phint; + *ppl = pl; + *pps = ps; + return pfcopy; +} diff --git a/gnupgparse.c b/gnupgparse.c --- a/gnupgparse.c +++ b/gnupgparse.c @@ -164,6 +164,11 @@ *is_subkey = 1; else if (!mutt_strcmp (p, "uid")) is_uid = 1; + else if (!mutt_strcmp (p, "fpr")) + { + is_uid = 1; + flags |= KEYFLAG_FINGERPRINT; + } else return NULL; diff --git a/mutt_crypt.h b/mutt_crypt.h --- a/mutt_crypt.h +++ b/mutt_crypt.h @@ -86,6 +86,7 @@ #define KEYFLAG_CRITICAL (1 << 12) #define KEYFLAG_PREFER_ENCRYPTION (1 << 13) #define KEYFLAG_PREFER_SIGNING (1 << 14) +#define KEYFLAG_FINGERPRINT (1 << 15) #define KEYFLAG_CANTUSE (KEYFLAG_DISABLED|KEYFLAG_REVOKED|KEYFLAG_EXPIRED) #define KEYFLAG_RESTRICTIONS (KEYFLAG_CANTUSE|KEYFLAG_CRITICAL) @@ -153,6 +154,16 @@ TEMPFILE. */ int crypt_write_signed(BODY *a, STATE *s, const char *tempf); +/* Obtain pointers to fingerprint or short or long key ID, if any. + Return: Copy of fingerprint, if any, stripped of all spaces, else NULL. + Must be FREE'd by caller. + *pphint Start of string to be passed to pgp_add_string_to_hints() or + crypt_add_string_to_hints(). + *ppl Start of long key ID if detected, else NULL. + *pps Start of short key ID if detected, else NULL. */ +const char* crypt_get_fingerprint_or_id (char *p, const char **pphint, + const char **ppl, const char **pps); + /*-- cryptglue.c --*/ diff --git a/pgpkey.c b/pgpkey.c --- a/pgpkey.c +++ b/pgpkey.c @@ -932,29 +932,22 @@ pgp_uid_t *a; short match; size_t l; - const char *ps, *pl; + const char *ps, *pl, *pfcopy, *phint; if ((l = mutt_strlen (p)) && p[l-1] == '!') p[l-1] = 0; + pfcopy = crypt_get_fingerprint_or_id (p, &phint, &pl, &ps); + mutt_message (_("Looking for keys matching \"%s\"..."), p); - hints = pgp_add_string_to_hints (hints, p); + hints = pgp_add_string_to_hints (hints, phint); keys = pgp_get_candidates (keyring, hints); mutt_free_list (&hints); if (!keys) goto out; - /* User input may be short or long key ID, independent of OPTPGPLONGIDS. - * pgp_key_t->keyid should always contain a long key ID without 0x. - * Strip leading "0x" before loops so it doesn't have to be done over and - * over again, and prepare pl and ps to simplify logic in the loop's inner - * condition. - */ - pl = (!mutt_strncasecmp (p, "0x", 2) ? p + 2 : p); - ps = (mutt_strlen (pl) == 16 ? pl + 8 : pl); - for (k = keys; k; k = kn) { kn = k->next; @@ -972,12 +965,17 @@ dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s:\n", p, pgp_long_keyid (k))); - /* If ps != pl it means a long ID (or name of 16 characters) was given, do - * not attempt to match short IDs then. Also, it is unnecessary to try to - * match pl against long IDs if ps == pl as pl could not be a long ID. */ + /* If pfcopy != NULL it means a fingerprint was given, do not attempt to + * match long or short IDs then. The fingerprint is in the name/addr field + * of a 'fpr' record, kept as a pgp_key_t->address->addr value. + * If pl != NULL it means a long ID was given, do not attempt to match + * short IDs then. + * If ps != NULL it means a short ID was given. + */ if (!*p || - (ps != pl && mutt_strcasecmp (pl, pgp_long_keyid (k)) == 0) || - (ps == pl && mutt_strcasecmp (ps, pgp_short_keyid (k)) == 0)) + (!pfcopy && + ((pl && mutt_strcasecmp (pl, pgp_long_keyid (k)) == 0) || + (ps && !pl && mutt_strcasecmp (ps, pgp_short_keyid (k)) == 0)))) { dprint (5, (debugfile, "\t\tmatch.\n")); match = 1; @@ -988,7 +986,9 @@ { dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s, \"%s\":\n", p, pgp_long_keyid (k), NONULL (a->addr))); - if (mutt_stristr (a->addr, p)) + if ((pfcopy && ((a->flags & KEYFLAG_FINGERPRINT) != 0) && + mutt_strcasecmp (a->addr, pfcopy) == 0) || + mutt_stristr (a->addr, p)) { dprint (5, (debugfile, "\t\tmatch.\n")); match = 1; @@ -1013,12 +1013,14 @@ pgp_remove_key (&matches, k); pgp_free_key (&matches); + FREE (&pfcopy); if (l && !p[l-1]) p[l-1] = '!'; return k; } out: + FREE (&pfcopy); if (l && !p[l-1]) p[l-1] = '!'; return NULL;
signature.asc
Description: Digital signature