changeset: 6420:47b4e57b2f1c user: Kevin McCarthy <ke...@8t8.us> date: Sun Feb 15 10:08:58 2015 -0800 link: http://dev.mutt.org/hg/mutt/rev/47b4e57b2f1c
Convert pgp_key_t fingerprint to a char* (see #3695) Currently only pgppubring.c is using the fingerprint field, and is using it to store a binary version of the fingerprint. Convert the field to store a null-terminated string. Modify pgppubring.c to use to use the new field. changeset: 6421:af5951f5d81c user: Kevin McCarthy <ke...@8t8.us> date: Sun Feb 15 10:09:10 2015 -0800 link: http://dev.mutt.org/hg/mutt/rev/af5951f5d81c Add fingerprint record parsing for pgp list keys. (see #3695) Modify parse_pub_line to parse fpr records and add the fingerprint to the pgp_key_t's fingerprint field. Add "--with-fingerprint --with-fingerprint" to the pgp_list_pubring_command and pgp_list_secring_command commands in contrib/gpg.rc. The second invocation generates fpr records for subkeys too. changeset: 6422:f5b1b75c5958 user: Eike Rathke <er...@erack.de> date: Wed Feb 11 21:38:37 2015 +0100 link: http://dev.mutt.org/hg/mutt/rev/f5b1b75c5958 Allow fingerprint user input for key selection. (see #3695) Accept and check input of a fingerprint and find the matching key. 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. diffs (422 lines): diff -r 385d7434c9d6 -r f5b1b75c5958 contrib/gpg.rc --- a/contrib/gpg.rc Tue Feb 10 12:14:20 2015 -0800 +++ b/contrib/gpg.rc Wed Feb 11 21:38:37 2015 +0100 @@ -65,10 +65,10 @@ set pgp_verify_key_command="gpg --verbose --batch --fingerprint --check-sigs %r" # read in the public key ring -set pgp_list_pubring_command="gpg --no-verbose --batch --quiet --with-colons --list-keys %r" +set pgp_list_pubring_command="gpg --no-verbose --batch --quiet --with-colons --with-fingerprint --with-fingerprint --list-keys %r" # read in the secret key ring -set pgp_list_secring_command="gpg --no-verbose --batch --quiet --with-colons --list-secret-keys %r" +set pgp_list_secring_command="gpg --no-verbose --batch --quiet --with-colons --with-fingerprint --with-fingerprint --list-secret-keys %r" # fetch keys # set pgp_getkeys_command="pkspxycwrap %r" diff -r 385d7434c9d6 -r f5b1b75c5958 crypt-gpgme.c --- a/crypt-gpgme.c Tue Feb 10 12:14:20 2015 -0800 +++ b/crypt-gpgme.c Wed Feb 11 21:38:37 2015 +0100 @@ -4188,32 +4188,23 @@ crypt_key_t *matches = NULL; crypt_key_t **matches_endp = &matches; crypt_key_t *k; - const char *ps, *pl; + const char *ps, *pl, *pfcopy, *phint; mutt_message (_("Looking for keys matching \"%s\"..."), p); *forced_valid = 0; - hints = crypt_add_string_to_hints (hints, p); + pfcopy = crypt_get_fingerprint_or_id (p, &phint, &pl, &ps); + hints = crypt_add_string_to_hints (hints, phint); keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN)); mutt_free_list (&hints); if (!keys) + { + FREE (&pfcopy); return NULL; - - /* User input may be short or long key ID, independent of OPTPGPLONGIDS. - * crypt_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); - - /* 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. */ - + } + for (k = keys; k; k = k->next) { if (abilities && !(k->flags & abilities)) @@ -4223,8 +4214,9 @@ "key %s, \"%s\": ", p, crypt_long_keyid (k), k->uid)); if (!*p - || (ps != pl && mutt_strcasecmp (pl, crypt_long_keyid (k)) == 0) - || (ps == pl && mutt_strcasecmp (ps, crypt_short_keyid (k)) == 0) + || (pfcopy && mutt_strcasecmp (pfcopy, crypt_fpr (k)) == 0) + || (pl && mutt_strcasecmp (pl, crypt_long_keyid (k)) == 0) + || (ps && mutt_strcasecmp (ps, crypt_short_keyid (k)) == 0) || mutt_stristr (k->uid, p)) { crypt_key_t *tmp; @@ -4236,6 +4228,7 @@ } } + FREE (&pfcopy); crypt_free_key (&keys); if (matches) diff -r 385d7434c9d6 -r f5b1b75c5958 crypt.c --- a/crypt.c Tue Feb 10 12:14:20 2015 -0800 +++ b/crypt.c Wed Feb 11 21:38:37 2015 +0100 @@ -900,3 +900,83 @@ } +/* 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; + size_t hexdigits; + + /* 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 */ + hexdigits = 0; + s1 = pf; + do + { + c = *(s1++); + if (('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f')) + { + ++hexdigits; + if (isid == 2) + isid = 1; /* it is an ID so far */ + } + else if (c) + { + isid = 0; /* not an ID */ + if (c == ' ' && ((hexdigits % 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 && ((hexdigits == 40) || (hexdigits == 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 -r 385d7434c9d6 -r f5b1b75c5958 gnupgparse.c --- a/gnupgparse.c Tue Feb 10 12:14:20 2015 -0800 +++ b/gnupgparse.c Wed Feb 11 21:38:37 2015 +0100 @@ -121,6 +121,7 @@ pgp_uid_t *uid = NULL; int field = 0, is_uid = 0; int is_pub = 0; + int is_fpr = 0; char *pend, *p; int trust = 0; int flags = 0; @@ -148,6 +149,9 @@ if (!*p && (field != 1) && (field != 10)) continue; + if (is_fpr && (field != 10)) + continue; + switch (field) { case 1: /* record type */ @@ -164,10 +168,12 @@ *is_subkey = 1; else if (!mutt_strcmp (p, "uid")) is_uid = 1; + else if (!mutt_strcmp (p, "fpr")) + is_fpr = 1; else return NULL; - if (!(is_uid || (*is_subkey && option (OPTPGPIGNORESUB)))) + if (!(is_uid || is_fpr || (*is_subkey && option (OPTPGPIGNORESUB)))) memset (&tmp, 0, sizeof (tmp)); break; @@ -290,6 +296,14 @@ if (!(pend && (*p || is_pub))) break; + if (is_fpr) + { + /* don't let a subkey fpr overwrite an existing primary key fpr */ + if (!tmp.fingerprint) + tmp.fingerprint = safe_strdup (p); + break; + } + /* ignore user IDs on subkeys */ if (!is_uid && (*is_subkey && option (OPTPGPIGNORESUB))) break; @@ -349,7 +363,7 @@ } /* merge temp key back into real key */ - if (!(is_uid || (*is_subkey && option (OPTPGPIGNORESUB)))) + if (!(is_uid || is_fpr || (*is_subkey && option (OPTPGPIGNORESUB)))) k = safe_malloc (sizeof (*k)); memcpy (k, &tmp, sizeof (*k)); /* fixup parentship of uids after mering the temp key into diff -r 385d7434c9d6 -r f5b1b75c5958 mutt_crypt.h --- a/mutt_crypt.h Tue Feb 10 12:14:20 2015 -0800 +++ b/mutt_crypt.h Wed Feb 11 21:38:37 2015 +0100 @@ -153,6 +153,20 @@ TEMPFILE. */ int crypt_write_signed(BODY *a, STATE *s, const char *tempf); +/* Obtain pointers to fingerprint or short or long key ID, if any. + + Upon return, at most one of return, *ppl and *pps pointers is non-NULL, + indicating the longest fingerprint or ID found, 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 -r 385d7434c9d6 -r f5b1b75c5958 pgpkey.c --- a/pgpkey.c Tue Feb 10 12:14:20 2015 -0800 +++ b/pgpkey.c Wed Feb 11 21:38:37 2015 +0100 @@ -932,29 +932,21 @@ 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; mutt_message (_("Looking for keys matching \"%s\"..."), p); - hints = pgp_add_string_to_hints (hints, p); + pfcopy = crypt_get_fingerprint_or_id (p, &phint, &pl, &ps); + 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 +964,10 @@ 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 (!*p || - (ps != pl && mutt_strcasecmp (pl, pgp_long_keyid (k)) == 0) || - (ps == pl && mutt_strcasecmp (ps, pgp_short_keyid (k)) == 0)) + (pfcopy && mutt_strcasecmp (pfcopy, k->fingerprint) == 0) || + (pl && mutt_strcasecmp (pl, pgp_long_keyid (k)) == 0) || + (ps && mutt_strcasecmp (ps, pgp_short_keyid (k)) == 0)) { dprint (5, (debugfile, "\t\tmatch.\n")); match = 1; @@ -1013,12 +1003,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; diff -r 385d7434c9d6 -r f5b1b75c5958 pgplib.c --- a/pgplib.c Tue Feb 10 12:14:20 2015 -0800 +++ b/pgplib.c Wed Feb 11 21:38:37 2015 +0100 @@ -183,6 +183,7 @@ pgp_free_uid (&kp->address); FREE (&kp->keyid); + FREE (&kp->fingerprint); /* mutt_crypt.h: 'typedef struct pgp_keyinfo *pgp_key_t;' */ FREE (kpp); /* __FREE_CHECKED__ */ } diff -r 385d7434c9d6 -r f5b1b75c5958 pgplib.h --- a/pgplib.h Tue Feb 10 12:14:20 2015 -0800 +++ b/pgplib.h Wed Feb 11 21:38:37 2015 +0100 @@ -34,6 +34,7 @@ struct pgp_keyinfo { char *keyid; + char *fingerprint; struct pgp_uid *address; int flags; short keylen; @@ -43,13 +44,6 @@ struct pgp_keyinfo *parent; struct pgp_signature *sigs; struct pgp_keyinfo *next; - - short fp_len; /* length of fingerprint. - * 20 for sha-1, 16 for md5. - */ - unsigned char fingerprint[20]; /* large enough to hold SHA-1 and RIPEMD160 - hashes (20 bytes), MD5 hashes just use the - first 16 bytes */ }; /* Note, that pgp_key_t is now pointer and declared in crypt.h */ diff -r 385d7434c9d6 -r f5b1b75c5958 pgppubring.c --- a/pgppubring.c Tue Feb 10 12:14:20 2015 -0800 +++ b/pgppubring.c Wed Feb 11 21:38:37 2015 +0100 @@ -156,6 +156,23 @@ return 0; } +static char *binary_fingerprint_to_string (unsigned char *buff, size_t length) +{ + int i; + char *fingerprint, *pf; + + pf = fingerprint = (char *)safe_malloc ((length * 2) + 1); + + for (i = 0; i < length; i++) + { + sprintf (pf, "%02X", buff[i]); + pf += 2; + } + *pf = 0; + + return fingerprint; +} + /* The actual key ring parser */ static void pgp_make_pgp2_fingerprint (unsigned char *buff, @@ -221,12 +238,9 @@ if (dump_fingerprints) { /* j now points to the key material, which we need for the fingerprint */ - p->fp_len = MD5_DIGEST_LENGTH; pgp_make_pgp2_fingerprint (&buff[j], digest); - memcpy (p->fingerprint, digest, MD5_DIGEST_LENGTH); + p->fingerprint = binary_fingerprint_to_string (digest, MD5_DIGEST_LENGTH); } - else /* just to be usre */ - memset (p->fingerprint, 0, MD5_DIGEST_LENGTH); expl = 0; for (i = 0; i < 2; i++) @@ -342,7 +356,10 @@ skip_bignum (buff, l, j, &j, 1); pgp_make_pgp3_fingerprint (buff, j, digest); - p->fp_len = SHA_DIGEST_LENGTH; + if (dump_fingerprints) + { + p->fingerprint = binary_fingerprint_to_string (digest, SHA_DIGEST_LENGTH); + } for (k = 0; k < 2; k++) { @@ -829,13 +846,10 @@ static void print_fingerprint (pgp_key_t p) { - int i = 0; + if (!p->fingerprint) + return; - printf ("fpr:::::::::"); - for (i = 0; i < p->fp_len; i++) - printf ("%02X", p->fingerprint[i]); - printf (":\n"); - + printf ("fpr:::::::::%s:\n", p->fingerprint); } /* print_fingerprint() */