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.
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))
"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;
}
}
+ FREE (&pfcopy);
crypt_free_key (&keys);
if (matches)
}
+/* 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;
+}
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 --*/
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;
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;
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;