From 1b3511a6a1bd35dbaa29b5aba2bac8e4089b3f67 Mon Sep 17 00:00:00 2001 From: Thomas Roessler Date: Fri, 22 Jan 1999 15:24:58 +0000 Subject: [PATCH] Heavy hacking on mutt's pgp support. We no longer read the complete key ring into memory. For gpg, performance is heavily improved due to the fact that we are passing a couple of key hints to the key ring parsing back-end. --- compose.c | 54 +-- gnupgparse.c | 340 +++++++++-------- handler.c | 2 +- lib.c | 20 + pgp.c | 49 ++- pgp.h | 378 ++++++++++--------- pgpkey.c | 653 +++++++++++++++++--------------- pgppubring.c | 1016 +++++++++++++++++++++++++++++--------------------- protos.h | 2 + 9 files changed, 1392 insertions(+), 1122 deletions(-) diff --git a/compose.c b/compose.c index 40255811..caa192dc 100644 --- a/compose.c +++ b/compose.c @@ -127,11 +127,9 @@ static void redraw_pgp_lines (int pgp) static int pgp_send_menu (int bits, int *redraw) { - char *p; - char *micalg = NULL; + pgp_key_t *p; char input_signas[SHORT_STRING]; char input_micalg[SHORT_STRING]; - KEYINFO *secring; struct pgp_vinfo *pgp = pgp_get_vinfo(PGP_SIGN); @@ -147,39 +145,27 @@ static int pgp_send_menu (int bits, int *redraw) break; case 3: /* sign (a)s */ + unset_option(OPTPGPCHECKTRUST); - if(pgp) + if (pgp && (p = pgp_ask_for_key (pgp, _("Sign as: "), NULL, KEYFLAG_CANSIGN, PGP_PUBRING))) { - if(!(secring = pgp->read_secring(pgp))) - { - mutt_error _("Can't open your secret key ring!"); - bits &= ~PGPSIGN; - } - else - { - if ((p = pgp_ask_for_key (pgp, secring, _("Sign as: "), - NULL, KEYFLAG_CANSIGN, &micalg))) - { - snprintf (input_signas, sizeof (input_signas), "0x%s", p); - safe_free((void **) &PgpSignAs); - PgpSignAs = safe_strdup(input_signas); - safe_free((void **) &PgpSignMicalg); - PgpSignMicalg = micalg; /* micalg is malloc()ed by pgp_ask_for_key */ - pgp_void_passphrase (); /* probably need a different passphrase */ - safe_free ((void **) &p); - bits |= PGPSIGN; - } - - pgp_close_keydb(&secring); - *redraw = REDRAW_FULL; - } + snprintf (input_signas, sizeof (input_signas), "0x%s", pgp_keyid (p)); + safe_free((void **) &PgpSignAs); PgpSignAs = safe_strdup (input_signas); + safe_free((void **) &PgpSignMicalg); PgpSignMicalg = safe_strdup (pgp_pkalg_to_mic (p->algorithm)); + pgp_free_key (&p); + + bits |= PGPSIGN; + + pgp_void_passphrase (); /* probably need a different passphrase */ } else { bits &= ~PGPSIGN; mutt_error _("An unkown PGP version was defined for signing."); } + + *redraw = REDRAW_FULL; break; case 4: /* (b)oth */ @@ -187,24 +173,24 @@ static int pgp_send_menu (int bits, int *redraw) break; case 5: /* select (m)ic algorithm */ - if(!(bits & PGPSIGN)) + if (!(bits & PGPSIGN)) mutt_error _("This doesn't make sense if you don't want to sign the message."); else { /* Copy the existing MIC algorithm into place */ - strfcpy(input_micalg, NONULL(PgpSignMicalg), sizeof(input_micalg)); + strfcpy(input_micalg, NONULL (PgpSignMicalg), sizeof (input_micalg)); - if(mutt_get_field (_("MIC algorithm: "), input_micalg, sizeof(input_micalg), 0) == 0) + if (mutt_get_field (_("MIC algorithm: "), input_micalg, sizeof (input_micalg), 0) == 0) { - if(mutt_strcasecmp(input_micalg, "pgp-md5") && mutt_strcasecmp(input_micalg, "pgp-sha1") - && mutt_strcasecmp(input_micalg, "pgp-rmd160")) + if (mutt_strcasecmp (input_micalg, "pgp-md5") && mutt_strcasecmp (input_micalg, "pgp-sha1") + && mutt_strcasecmp (input_micalg, "pgp-rmd160")) { mutt_error _("Unknown MIC algorithm, valid ones are: pgp-md5, pgp-sha1, pgp-rmd160"); } else { - safe_free((void **) &PgpSignMicalg); - PgpSignMicalg = safe_strdup(input_micalg); + safe_free ((void **) &PgpSignMicalg); + PgpSignMicalg = safe_strdup (input_micalg); } } } diff --git a/gnupgparse.c b/gnupgparse.c index 306b6c87..f62bb659 100644 --- a/gnupgparse.c +++ b/gnupgparse.c @@ -1,19 +1,23 @@ /* * Copyright (C) 1998 Werner Koch + * Copyright (C) 1999 Thomas Roessler * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later + * version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more + * details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA + * 02139, USA. */ @@ -48,169 +52,209 @@ * - signature class */ -static KEYINFO *parse_pub_line( char *buf, int *is_subkey ) +static pgp_key_t *parse_pub_line (char *buf, int *is_subkey, pgp_key_t *k) { - KEYINFO *k=NULL; - PGPUID *uid = NULL; - int field = 0; - char *pend, *p; - int trust = 0; - - *is_subkey = 0; - if( !*buf ) - return NULL; - for( p = buf; p; p = pend ) { - if( (pend = strchr(p, ':')) ) - *pend++ = 0; - field++; - if( field > 1 && !*p ) - continue; - - switch( field ) { - case 1: /* record type */ - if( !mutt_strcmp(p,"pub") ) - ; - else if( !mutt_strcmp(p,"sub") ) - *is_subkey = 1; - else if( !mutt_strcmp(p,"sec") ) - ; - else if( !mutt_strcmp(p,"ssb") ) - *is_subkey = 1; - else - return NULL; - k = safe_malloc( sizeof(KEYINFO) ); - memset(k, 0, sizeof(KEYINFO) ); - break; - case 2: /* trust info */ - switch( *p ) { /* look only at the first letter */ - case 'e': k->flags |= KEYFLAG_EXPIRED; break; - case 'n': trust = 1; break; - case 'm': trust = 2; break; - case 'f': trust = 3; break; - case 'u': trust = 3; break; - case 'r': k->flags |= KEYFLAG_REVOKED; break; - } - break; - case 3: /* key length */ - k->keylen = atoi(p); /* fixme: add validation checks */ - break; - case 4: /* pubkey algo */ - k->algorithm = pgp_pkalgbytype(atoi(p)); - k->flags |= pgp_get_abilities(atoi(p)); - break; - case 5: /* 16 hex digits with the long keyid. */ - /* We really should do a check here */ - k->keyid = safe_strdup(p); - break; - case 6: /* timestamp (1998-02-28) */ - break; - case 7: /* valid for n days */ + pgp_uid_t *uid = NULL; + int field = 0, is_uid = 0; + char *pend, *p; + int trust = 0; + + *is_subkey = 0; + if (!*buf) + return NULL; + for (p = buf; p; p = pend) + { + if ((pend = strchr (p, ':'))) + *pend++ = 0; + field++; + if (field > 1 && !*p) + continue; + + switch (field) + { + case 1: /* record type */ + { + if (!mutt_strcmp (p, "pub")) + ; + else if (!mutt_strcmp (p, "sub")) + *is_subkey = 1; + else if (!mutt_strcmp (p, "sec")) + ; + else if (!mutt_strcmp (p, "ssb")) + *is_subkey = 1; + else if (!mutt_strcmp (p, "uid")) + is_uid = 1; + else + return NULL; + + if (!is_uid) + k = safe_calloc (sizeof (pgp_key_t), 1); + + break; + } + case 2: /* trust info */ + /* + * XXX - is this the owner-trust field? + * + * Actually, we'd need the trust gpg has into the + * association between a user ID and a key. + * + * - tlr + */ + { + switch (*p) + { /* look only at the first letter */ + case 'e': + k->flags |= KEYFLAG_EXPIRED; break; - case 8: /* Local id */ + case 'n': + trust = 1; break; - case 9: /* ownertrust */ + case 'm': + trust = 2; break; - case 10: /* name */ - if( !pend || !*p ) - break; /* empty field or no trailing colon */ - k->address = mutt_new_list(); - k->address->data = safe_malloc( sizeof(PGPUID) ); - uid = (PGPUID *)k->address->data; - uid->addr = safe_strdup(p); - uid->trust = trust; + case 'f': + trust = 3; break; - case 11: /* signature class */ + case 'u': + trust = 3; break; - default: + case 'r': + k->flags |= KEYFLAG_REVOKED; break; } + break; + } + case 3: /* key length */ + { + k->keylen = atoi (p); /* fixme: add validation checks */ + break; + } + case 4: /* pubkey algo */ + { + k->algorithm = pgp_pkalgbytype (atoi (p)); + k->flags |= pgp_get_abilities (atoi (p)); + break; + } + case 5: /* 16 hex digits with the long keyid. */ + { + /* We really should do a check here */ + k->keyid = safe_strdup (p); + break; + + } + case 6: /* timestamp (1998-02-28) */ + break; + case 7: /* valid for n days */ + break; + case 8: /* Local id */ + break; + case 9: /* ownertrust */ + break; + case 10: /* name */ + { + if (!pend || !*p) + break; /* empty field or no trailing colon */ + uid = safe_calloc (sizeof (pgp_uid_t), 1); + uid->addr = safe_strdup (p); + uid->trust = trust; + uid->parent = k; + uid->next = k->address; + k->address = uid; + + if (strstr (p, "ENCR")) + k->flags |= KEYFLAG_PREFER_ENCRYPTION; + if (strstr (p, "SIGN")) + k->flags |= KEYFLAG_PREFER_SIGNING; + + break; + } + case 11: /* signature class */ + break; + default: + break; } - return k; + } + return k; } -static pid_t gpg_invoke_list_keys(struct pgp_vinfo *pgp, - FILE **pgpin, FILE **pgpout, FILE **pgperr, - int pgpinfd, int pgpoutfd, int pgperrfd, - const char *uids, int secret) +static pid_t gpg_invoke_list_keys (struct pgp_vinfo *pgp, + FILE ** pgpin, FILE ** pgpout, FILE ** pgperr, + int pgpinfd, int pgpoutfd, int pgperrfd, + pgp_ring_t keyring, + LIST * hints) { char cmd[HUGE_STRING]; char tmpcmd[HUGE_STRING]; - char *cp; - char *keylist; - + /* we use gpgm here */ - snprintf(cmd, sizeof(cmd), - "%sm --no-verbose --batch --with-colons --list-%skeys ", - NONULL(*pgp->binary), secret? "secret-":""); + snprintf (cmd, sizeof (cmd), + "%sm --no-verbose --batch --with-colons --list-%skeys ", + NONULL (*pgp->binary), keyring == PGP_SECRING ? "secret-" : ""); - keylist = safe_strdup(uids); - for(cp = strtok(keylist, " "); cp ; cp = strtok(NULL, " ")) + for (; hints; hints = hints->next) { - snprintf(tmpcmd, sizeof(tmpcmd), "%s %s", - cmd, cp); - strcpy(cmd, tmpcmd); + snprintf (tmpcmd, sizeof (tmpcmd), "%s %s", cmd, (char *) hints->data); + strcpy (cmd, tmpcmd); } - safe_free((void **) &keylist); - return mutt_create_filter_fd(cmd, pgpin, pgpout, pgperr, - pgpinfd, pgpoutfd, pgperrfd); + + return mutt_create_filter_fd (cmd, pgpin, pgpout, pgperr, + pgpinfd, pgpoutfd, pgperrfd); } -static KEYINFO *read_ring(struct pgp_vinfo *pgp, int secret ) +pgp_key_t *gpg_get_candidates (struct pgp_vinfo * pgp, pgp_ring_t keyring, + LIST * hints) { - FILE *fp; - pid_t thepid; - char buf[LONG_STRING]; - KEYINFO *db = NULL, **kend, *k = NULL, *kk, *mainkey=NULL; - int is_sub; - int devnull; - - if((devnull = open("/dev/null", O_RDWR)) == -1) - return NULL; - - thepid = gpg_invoke_list_keys(pgp, NULL, &fp, NULL, -1, -1, devnull, - NULL, secret); - if( thepid == -1 ) - { - close(devnull); - return NULL; - } + FILE *fp; + pid_t thepid; + char buf[LONG_STRING]; + pgp_key_t *db = NULL, **kend, *k = NULL, *kk, *mainkey = NULL; + int is_sub; + int devnull; - kend = &db; - k = NULL; - while( fgets( buf, sizeof(buf)-1, fp ) ) { - kk = parse_pub_line(buf, &is_sub ); - if( !kk ) - continue; - if( k ) - kend = &k->next; - *kend = k = kk; - - if( is_sub ) { - k->flags |= KEYFLAG_SUBKEY; - k->mainkey = mainkey; - } - else - mainkey = k; - } - if( ferror(fp) ) - mutt_perror("fgets"); + if ((devnull = open ("/dev/null", O_RDWR)) == -1) + return NULL; - fclose( fp ); - mutt_wait_filter( thepid ); + thepid = gpg_invoke_list_keys (pgp, NULL, &fp, NULL, -1, -1, devnull, + keyring, hints); + if (thepid == -1) + { + close (devnull); + return NULL; + } - close(devnull); - - return db; -} + kend = &db; + k = NULL; + while (fgets (buf, sizeof (buf) - 1, fp)) + { + kk = parse_pub_line (buf, &is_sub, k); + if (!kk) + continue; + /* Only append kk to the list if it's new. */ + if (kk != k) + { + if (k) + kend = &k->next; + *kend = k = kk; + + if (is_sub) + { + k->flags |= KEYFLAG_SUBKEY; + k->parent = mainkey; + } + else + mainkey = k; + } + } + if (ferror (fp)) + mutt_perror ("fgets"); -KEYINFO *gpg_read_pubring(struct pgp_vinfo *pgp) -{ - return read_ring( pgp, 0 ); -} + fclose (fp); + mutt_wait_filter (thepid); + close (devnull); -KEYINFO *gpg_read_secring(struct pgp_vinfo *pgp) -{ - return read_ring( pgp, 1 ); + return db; } + diff --git a/handler.c b/handler.c index 20d46e08..ba1bc991 100644 --- a/handler.c +++ b/handler.c @@ -1406,7 +1406,7 @@ void mutt_body_handler (BODY *b, STATE *s) else if (b->type == TYPEAPPLICATION) { if (mutt_is_application_pgp(b)) - handler = application_pgp_handler; + handler = pgp_application_pgp_handler; } #endif /* _PGPPATH */ diff --git a/lib.c b/lib.c index 4653e977..5466d79d 100644 --- a/lib.c +++ b/lib.c @@ -1314,3 +1314,23 @@ size_t mutt_strlen(const char *a) { return a ? strlen (a) : 0; } + +const char *mutt_stristr (const char *haystack, const char *needle) +{ + const char *p, *q; + + if (!haystack) + return NULL; + if (!needle) + return (haystack); + + while (*(p = haystack)) + { + for (q = needle; *p && *q && tolower (*p) == tolower (*q); p++, q++) + ; + if (!*q) + return (haystack); + haystack++; + } + return NULL; +} diff --git a/pgp.c b/pgp.c index 4ec0dae1..375cb6a2 100644 --- a/pgp.c +++ b/pgp.c @@ -51,7 +51,7 @@ static struct pgp_vinfo pgp_vinfo[] = { PGP_V2, "pgp2", &PgpV2, &PgpV2Pubring, &PgpV2Secring, &PgpV2Language, - pgp_read_pubring, pgp_read_secring, + pgp_get_candidates, pgp_v2_invoke_decode, pgp_v2_invoke_verify, pgp_v2_invoke_decrypt, pgp_v2_invoke_sign, pgp_v2_invoke_encrypt, pgp_v2_invoke_import, pgp_v2_invoke_export, pgp_v2_invoke_verify_key @@ -60,7 +60,7 @@ static struct pgp_vinfo pgp_vinfo[] = { PGP_V3, "pgp3", &PgpV3, &PgpV3Pubring, &PgpV3Secring, &PgpV3Language, - pgp_read_pubring, pgp_read_secring, + pgp_get_candidates, pgp_v3_invoke_decode, pgp_v3_invoke_verify, pgp_v3_invoke_decrypt, pgp_v3_invoke_sign, pgp_v3_invoke_encrypt, pgp_v3_invoke_import, pgp_v3_invoke_export, pgp_v3_invoke_verify_key @@ -69,7 +69,7 @@ static struct pgp_vinfo pgp_vinfo[] = { PGP_V3, "pgp5", &PgpV3, &PgpV3Pubring, &PgpV3Secring, &PgpV3Language, - pgp_read_pubring, pgp_read_secring, + pgp_get_candidates, pgp_v3_invoke_decode, pgp_v3_invoke_verify, pgp_v3_invoke_decrypt, pgp_v3_invoke_sign, pgp_v3_invoke_encrypt, pgp_v3_invoke_import, pgp_v3_invoke_export, pgp_v3_invoke_verify_key @@ -78,7 +78,7 @@ static struct pgp_vinfo pgp_vinfo[] = { PGP_GPG, "gpg", &PgpGpg, &PgpGpgDummy, &PgpGpgDummy, &PgpGpgDummy, - gpg_read_pubring, gpg_read_secring, + gpg_get_candidates, pgp_gpg_invoke_decode, pgp_gpg_invoke_verify, pgp_gpg_invoke_decrypt, pgp_gpg_invoke_sign, pgp_gpg_invoke_encrypt, pgp_gpg_invoke_import, pgp_gpg_invoke_export, pgp_gpg_invoke_verify_key @@ -178,15 +178,15 @@ struct pgp_vinfo *pgp_get_vinfo(enum pgp_ops op) return NULL; } -char *pgp_keyid(KEYINFO *k) +char *pgp_keyid(pgp_key_t *k) { - if((k->flags & KEYFLAG_SUBKEY) && k->mainkey) - k = k->mainkey; + if((k->flags & KEYFLAG_SUBKEY) && k->parent) + k = k->parent; return _pgp_keyid(k); } -char *_pgp_keyid(KEYINFO *k) +char *_pgp_keyid(pgp_key_t *k) { if(option(OPTPGPLONGIDS)) return k->keyid; @@ -217,7 +217,7 @@ static void pgp_current_time (STATE *s) /* Support for the Application/PGP Content Type. */ -void application_pgp_handler (BODY *m, STATE *s) +void pgp_application_pgp_handler (BODY *m, STATE *s) { int needpass = -1, pgp_keyblock = 0; int clearsign = 0; @@ -1231,22 +1231,19 @@ static BODY *pgp_sign_message (BODY *a) */ char *pgp_findKeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc) { - char *key, *keyID, *keylist = NULL; + char *keyID, *keylist = NULL; size_t keylist_size = 0; size_t keylist_used = 0; ADDRESS *tmp = NULL; ADDRESS **last = &tmp; ADDRESS *p; int i; - KEYINFO *db; - KEYINFO *k_info; - struct pgp_vinfo *pgp = pgp_get_vinfo(PGP_ENCRYPT); + pgp_key_t *k_info, *key; + struct pgp_vinfo *pgp = pgp_get_vinfo (PGP_ENCRYPT); - if(!pgp) + if (!pgp) return NULL; - db = pgp->read_pubring(pgp); - for (i = 0; i < 3; i++) { switch (i) @@ -1273,32 +1270,34 @@ char *pgp_findKeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc) { snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), keyID, p->mailbox); if (mutt_yesorno (buf, M_YES) == M_YES) - k_info = ki_getkeybystr (pgp, keyID, db, KEYFLAG_CANENCRYPT); + k_info = pgp_getkeybystr (pgp, keyID, KEYFLAG_CANENCRYPT, PGP_PUBRING); } - if (k_info == NULL && (k_info = ki_getkeybyaddr (pgp, p, db, KEYFLAG_CANENCRYPT)) == NULL) + + if (k_info == NULL && (k_info = pgp_getkeybyaddr (pgp, p, KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL) { snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), p->mailbox); - if ((key = pgp_ask_for_key (pgp, db, buf, p->mailbox, - KEYFLAG_CANENCRYPT, NULL)) == NULL) + if ((key = pgp_ask_for_key (pgp, buf, p->mailbox, + KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL) { - pgp_close_keydb (&db); safe_free ((void **)&keylist); rfc822_free_address (&tmp); return NULL; } } else - key = pgp_keyid(k_info); + key = k_info; - keylist_size += mutt_strlen (key) + 4; + keyID = pgp_keyid (key); + pgp_free_key (&key); + + keylist_size += mutt_strlen (keyID) + 4; safe_realloc ((void **)&keylist, keylist_size); sprintf (keylist + keylist_used, "%s0x%s", keylist_used ? " " : "", - key); + keyID); keylist_used = mutt_strlen (keylist); } rfc822_free_address (&tmp); - pgp_close_keydb (&db); return (keylist); } diff --git a/pgp.h b/pgp.h index 74384845..24490903 100644 --- a/pgp.h +++ b/pgp.h @@ -1,6 +1,7 @@ /* * Copyright (C) 1996,1997 Michael R. Elkins - * + * Copyright (C) 1999 Thoms Roessler + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -14,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ + */ #ifdef _PGPPATH @@ -32,92 +33,105 @@ #define KEYFLAG_PREFER_ENCRYPTION (1 << 13) #define KEYFLAG_PREFER_SIGNING (1 << 14) -typedef struct keyinfo +#define KEYFLAG_CANTUSE (KEYFLAG_DISABLED|KEYFLAG_REVOKED|KEYFLAG_EXPIRED) + +typedef struct pgp_keyinfo { char *keyid; - LIST *address; + struct pgp_uid *address; short flags; short keylen; unsigned long gen_time; const char *algorithm; - struct keyinfo *mainkey; - struct keyinfo *next; -} KEYINFO; + struct pgp_keyinfo *parent; + struct pgp_keyinfo *next; +} +pgp_key_t; typedef struct pgp_uid { char *addr; short trust; -} PGPUID; + struct pgp_keyinfo *parent; + struct pgp_uid *next; +} +pgp_uid_t; -enum pgp_version +enum pgp_version { - PGP_V2, + PGP_V2, PGP_V3, PGP_GPG, PGP_UNKNOWN }; +enum pgp_ring +{ + PGP_PUBRING, + PGP_SECRING +}; + +typedef enum pgp_ring pgp_ring_t; + enum pgp_ops { - PGP_DECODE, /* application/pgp */ - PGP_VERIFY, /* PGP/MIME, signed */ - PGP_DECRYPT, /* PGP/MIME, encrypted */ - PGP_SIGN, /* sign data */ - PGP_ENCRYPT, /* encrypt data */ - PGP_IMPORT, /* extract keys from messages */ - PGP_VERIFY_KEY, /* verify key when selecting */ - PGP_EXPORT, /* extract keys from key ring */ + PGP_DECODE, /* application/pgp */ + PGP_VERIFY, /* PGP/MIME, signed */ + PGP_DECRYPT, /* PGP/MIME, encrypted */ + PGP_SIGN, /* sign data */ + PGP_ENCRYPT, /* encrypt data */ + PGP_IMPORT, /* extract keys from messages */ + PGP_VERIFY_KEY, /* verify key when selecting */ + PGP_EXPORT, /* extract keys from key ring */ PGP_LAST_OP }; struct pgp_vinfo { - + /* data */ - + enum pgp_version v; char *name; char **binary; char **pubring; char **secring; char **language; - + /* functions */ + + pgp_key_t *(*get_candidates) (struct pgp_vinfo *, pgp_ring_t, LIST *); - KEYINFO * (*read_pubring)(struct pgp_vinfo *); - KEYINFO * (*read_secring)(struct pgp_vinfo *); - - pid_t (*invoke_decode)(struct pgp_vinfo *, FILE **, FILE **, FILE **, - int, int, int, - const char *, int); + pid_t (*invoke_decode) (struct pgp_vinfo *, FILE **, FILE **, FILE **, + int, int, int, + const char *, int); - pid_t (*invoke_verify)(struct pgp_vinfo *, FILE **, FILE **, FILE **, - int, int, int, - const char *, const char *); + pid_t (*invoke_verify) (struct pgp_vinfo *, FILE **, FILE **, FILE **, + int, int, int, + const char *, const char *); - pid_t (*invoke_decrypt)(struct pgp_vinfo *, FILE **, FILE **, FILE **, - int, int, int, - const char *); + pid_t (*invoke_decrypt) (struct pgp_vinfo *, FILE **, FILE **, FILE **, + int, int, int, + const char *); - pid_t (*invoke_sign)(struct pgp_vinfo *, FILE **, FILE **, FILE **, - int, int, int, - const char *); - - pid_t (*invoke_encrypt)(struct pgp_vinfo *, FILE **, FILE **, FILE **, - int, int, int, - const char *, const char *, int); + pid_t (*invoke_sign) (struct pgp_vinfo *, FILE **, FILE **, FILE **, + int, int, int, + const char *); - void (*invoke_import)(struct pgp_vinfo *, const char *); + pid_t (*invoke_encrypt) (struct pgp_vinfo *, FILE **, FILE **, FILE **, + int, int, int, + const char *, const char *, int); - pid_t (*invoke_export)(struct pgp_vinfo *, FILE **, FILE **, FILE **, - int, int, int, - const char *); + void (*invoke_import) (struct pgp_vinfo *, const char *); - pid_t (*invoke_verify_key)(struct pgp_vinfo *, FILE **, FILE **, FILE **, + pid_t (*invoke_export) (struct pgp_vinfo *, FILE **, FILE **, FILE **, int, int, int, const char *); + pid_t (*invoke_verify_key) (struct pgp_vinfo *, FILE **, FILE **, FILE **, + int, int, int, + const char *); + }; @@ -150,176 +164,172 @@ WHERE char *PgpSignMicalg; WHERE short PgpTimeout; - - BODY *pgp_decrypt_part (BODY *, STATE *, FILE *); BODY *pgp_make_key_attachment (char *); -const char *pgp_pkalg_to_mic(const char *); - -char *pgp_ask_for_key (struct pgp_vinfo *, KEYINFO *, char *, char *, short, char **); -char *pgp_keyid(KEYINFO *); -char *_pgp_keyid(KEYINFO *); +char *_pgp_keyid (pgp_key_t *); +char *pgp_keyid (pgp_key_t *); -struct pgp_vinfo *pgp_get_vinfo(enum pgp_ops); +const char *pgp_pkalg_to_mic (const char *); +const char *pgp_pkalgbytype (unsigned char); -int mutt_check_pgp (HEADER *h); +int mutt_check_pgp (HEADER * h); +int mutt_is_application_pgp (BODY *); +int mutt_is_multipart_encrypted (BODY *); +int mutt_is_multipart_signed (BODY *); int mutt_parse_pgp_hdr (char *, int); - -int mutt_is_multipart_encrypted(BODY *); -int mutt_is_multipart_signed(BODY *); -int mutt_is_application_pgp(BODY *); - int pgp_decrypt_mime (FILE *, FILE **, BODY *, BODY **); int pgp_get_keys (HEADER *, char **); int pgp_protect (HEADER *, char *); int pgp_query (BODY *); +int pgp_string_matches_hint (const char *s, LIST * hints); int pgp_valid_passphrase (void); -KEYINFO *ki_getkeybyaddr (struct pgp_vinfo *pgp, ADDRESS *, KEYINFO *, short); -KEYINFO *ki_getkeybystr (struct pgp_vinfo *pgp, char *, KEYINFO *, short); -KEYINFO *pgp_read_pubring(struct pgp_vinfo *pgp); -KEYINFO *pgp_read_secring(struct pgp_vinfo *pgp); -KEYINFO *gpg_read_pubring(struct pgp_vinfo *pgp); -KEYINFO *gpg_read_secring(struct pgp_vinfo *pgp); +pgp_key_t *gpg_get_candidates (struct pgp_vinfo *, pgp_ring_t, LIST *); +pgp_key_t *pgp_ask_for_key (struct pgp_vinfo *, char *, char *, short, pgp_ring_t); +pgp_key_t *pgp_get_candidates (struct pgp_vinfo *, pgp_ring_t, LIST *); +pgp_key_t *pgp_getkeybyaddr (struct pgp_vinfo *pgp, ADDRESS *, short, pgp_ring_t); +pgp_key_t *pgp_getkeybystr (struct pgp_vinfo *pgp, char *, short, pgp_ring_t); +pgp_key_t *pgp_remove_key (pgp_key_t **, pgp_key_t *); + +short pgp_canencrypt (unsigned char); +short pgp_cansign (unsigned char); +short pgp_get_abilities (unsigned char); + +struct pgp_vinfo *pgp_get_vinfo (enum pgp_ops); -void application_pgp_handler (BODY *, STATE *); void mutt_forget_passphrase (void); -void pgp_close_keydb (KEYINFO **); +void pgp_application_pgp_handler (BODY *, STATE *); void pgp_encrypted_handler (BODY *, STATE *); -void pgp_extract_keys_from_attachment_list (FILE *fp, int tag, BODY *top); -void pgp_extract_keys_from_messages(HEADER *hdr); +void pgp_extract_keys_from_attachment_list (FILE * fp, int tag, BODY * top); +void pgp_extract_keys_from_messages (HEADER * hdr); +void pgp_free_key (pgp_key_t **kpp); void pgp_signed_handler (BODY *, STATE *); void pgp_void_passphrase (void); -short pgp_canencrypt(unsigned char); -short pgp_cansign(unsigned char); -short pgp_get_abilities(unsigned char); -const char *pgp_pkalgbytype(unsigned char); - #define pgp_secring(a) pgp_getring(a, 0) #define pgp_pubring(a) pgp_getring(a, 1) /* PGP V2 prototypes */ -pid_t pgp_v2_invoke_decode(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *, int); +pid_t pgp_v2_invoke_decode (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *, int); -pid_t pgp_v2_invoke_verify(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *, const char *); +pid_t pgp_v2_invoke_verify (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *, const char *); -pid_t pgp_v2_invoke_decrypt(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *); +pid_t pgp_v2_invoke_decrypt (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); -pid_t pgp_v2_invoke_sign(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *); +pid_t pgp_v2_invoke_sign (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); -pid_t pgp_v2_invoke_encrypt(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *, const char *, int); +pid_t pgp_v2_invoke_encrypt (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *, const char *, int); -void pgp_v2_invoke_import(struct pgp_vinfo *, const char *); +void pgp_v2_invoke_import (struct pgp_vinfo *, const char *); -pid_t pgp_v2_invoke_export(struct pgp_vinfo*, +pid_t pgp_v2_invoke_export (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); + +pid_t pgp_v2_invoke_verify_key (struct pgp_vinfo *, FILE **, FILE **, FILE **, int, int, int, const char *); -pid_t pgp_v2_invoke_verify_key(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *); - /* PGP V3 prototypes */ -pid_t pgp_v3_invoke_decode(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *, int); +pid_t pgp_v3_invoke_decode (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *, int); -pid_t pgp_v3_invoke_verify(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *, const char *); +pid_t pgp_v3_invoke_verify (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *, const char *); -pid_t pgp_v3_invoke_decrypt(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *); +pid_t pgp_v3_invoke_decrypt (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); -pid_t pgp_v3_invoke_sign(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *); +pid_t pgp_v3_invoke_sign (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); -pid_t pgp_v3_invoke_encrypt(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *, const char *, int); +pid_t pgp_v3_invoke_encrypt (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *, const char *, int); -void pgp_v3_invoke_import(struct pgp_vinfo *, const char *); +void pgp_v3_invoke_import (struct pgp_vinfo *, const char *); -pid_t pgp_v3_invoke_export(struct pgp_vinfo*, +pid_t pgp_v3_invoke_export (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); + +pid_t pgp_v3_invoke_verify_key (struct pgp_vinfo *, FILE **, FILE **, FILE **, int, int, int, const char *); -pid_t pgp_v3_invoke_verify_key(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *); - /* GNU Privacy Guard Prototypes */ -pid_t pgp_gpg_invoke_decode(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *, int); +pid_t pgp_gpg_invoke_decode (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *, int); -pid_t pgp_gpg_invoke_verify(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *, const char *); +pid_t pgp_gpg_invoke_verify (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *, const char *); -pid_t pgp_gpg_invoke_decrypt(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *); - -pid_t pgp_gpg_invoke_sign(struct pgp_vinfo *, +pid_t pgp_gpg_invoke_decrypt (struct pgp_vinfo *, FILE **, FILE **, FILE **, int, int, int, const char *); -pid_t pgp_gpg_invoke_encrypt(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *, const char *, int); +pid_t pgp_gpg_invoke_sign (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); -void pgp_gpg_invoke_import(struct pgp_vinfo *, const char *); +pid_t pgp_gpg_invoke_encrypt (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *, const char *, int); -pid_t pgp_gpg_invoke_export(struct pgp_vinfo*, - FILE **, FILE **, FILE **, - int, int, int, - const char *); +void pgp_gpg_invoke_import (struct pgp_vinfo *, const char *); + +pid_t pgp_gpg_invoke_export (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); -pid_t pgp_gpg_invoke_verify_key(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *); +pid_t pgp_gpg_invoke_verify_key (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); @@ -329,43 +339,43 @@ pid_t pgp_gpg_invoke_verify_key(struct pgp_vinfo *, /* use these as templates for your own prototypes */ -pid_t pgp_VERSION_invoke_decode(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *, int); - -pid_t pgp_VERSION_invoke_verify(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *, const char *); - - -pid_t pgp_VERSION_invoke_decrypt(struct pgp_vinfo *, +pid_t pgp_VERSION_invoke_decode (struct pgp_vinfo *, FILE **, FILE **, FILE **, int, int, int, - const char *); + const char *, int); -pid_t pgp_VERSION_invoke_sign(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *); - -pid_t pgp_VERSION_invoke_encrypt(struct pgp_vinfo *, +pid_t pgp_VERSION_invoke_verify (struct pgp_vinfo *, FILE **, FILE **, FILE **, int, int, int, - const char *, const char *, int); + const char *, const char *); -void pgp_VERSION_invoke_import(struct pgp_vinfo *, const char *); -pid_t pgp_VERSION_invoke_export(struct pgp_vinfo*, - FILE **, FILE **, FILE **, - int, int, int, - const char *); +pid_t pgp_VERSION_invoke_decrypt (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); + +pid_t pgp_VERSION_invoke_sign (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); + +pid_t pgp_VERSION_invoke_encrypt (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *, const char *, int); + +void pgp_VERSION_invoke_import (struct pgp_vinfo *, const char *); + +pid_t pgp_VERSION_invoke_export (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); -pid_t pgp_VERSION_invoke_verify_key(struct pgp_vinfo *, - FILE **, FILE **, FILE **, - int, int, int, - const char *); +pid_t pgp_VERSION_invoke_verify_key (struct pgp_vinfo *, + FILE **, FILE **, FILE **, + int, int, int, + const char *); #endif diff --git a/pgpkey.c b/pgpkey.c index 281c956e..62890f97 100644 --- a/pgpkey.c +++ b/pgpkey.c @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ + */ #include "mutt.h" #include "mutt_curses.h" @@ -33,63 +33,85 @@ #ifdef _PGPPATH -static struct pgp_cache { +struct pgp_cache +{ char *what; char *dflt; struct pgp_cache *next; -} * id_defaults = NULL; +}; -typedef struct -{ - KEYINFO *k; - PGPUID *a; -} pgp_key_t; +static struct pgp_cache *id_defaults = NULL; static char trust_flags[] = "?- +"; -static char *pgp_key_abilities(int flags) +static char *pgp_key_abilities (int flags) { static char buff[3]; - - if(!(flags & KEYFLAG_CANENCRYPT)) + + if (!(flags & KEYFLAG_CANENCRYPT)) buff[0] = '-'; - else if(flags & KEYFLAG_PREFER_SIGNING) + else if (flags & KEYFLAG_PREFER_SIGNING) buff[0] = '.'; else buff[0] = 'e'; - - if(!(flags & KEYFLAG_CANSIGN)) + + if (!(flags & KEYFLAG_CANSIGN)) buff[1] = '-'; - else if(flags & KEYFLAG_PREFER_ENCRYPTION) + else if (flags & KEYFLAG_PREFER_ENCRYPTION) buff[1] = '.'; else buff[1] = 's'; - + buff[2] = '\0'; - + return buff; } -static void pgp_entry (char *s, size_t l, MUTTMENU *menu, int num) +static char pgp_flags (int flags) +{ + if (flags & KEYFLAG_REVOKED) + return 'R'; + else if (flags & KEYFLAG_EXPIRED) + return 'X'; + else if (flags & KEYFLAG_DISABLED) + return 'd'; + else if (flags & KEYFLAG_CRITICAL) + return 'c'; + else + return ' '; +} + +static pgp_key_t *pgp_principal_key (pgp_key_t *key) { - pgp_key_t *KeyTable = (pgp_key_t *) menu->data; + if (key->flags & KEYFLAG_SUBKEY && key->parent) + return key->parent; + else + return key; +} +static void pgp_entry (char *s, size_t l, MUTTMENU * menu, int num) +{ + pgp_uid_t **KeyTable = (pgp_uid_t **) menu->data; + pgp_uid_t *entry; + pgp_key_t *key; + + entry = KeyTable[num]; + key = pgp_principal_key (entry->parent); + snprintf (s, l, "%4d %c%c %4d/0x%s %-4s %2s %s", - num + 1, - trust_flags[KeyTable[num].a->trust & 0x03], - (KeyTable[num].k->flags & KEYFLAG_CRITICAL ? - 'c' : ' '), - KeyTable[num].k->keylen, - _pgp_keyid(KeyTable[num].k), - KeyTable[num].k->algorithm, - pgp_key_abilities(KeyTable[num].k->flags), - KeyTable[num].a->addr); + num + 1, trust_flags[entry->trust & 0x03], + pgp_flags (key->flags), + entry->parent->keylen, + _pgp_keyid (key), + key->algorithm, + pgp_key_abilities (key->flags), + entry->addr); } -static int pgp_search (MUTTMENU *m, regex_t *re, int n) +static int pgp_search (MUTTMENU * m, regex_t * re, int n) { char buf[LONG_STRING]; - + pgp_entry (buf, sizeof (buf), m, n); return (regexec (re, buf, 0, NULL, 0)); } @@ -97,82 +119,55 @@ static int pgp_search (MUTTMENU *m, regex_t *re, int n) static int pgp_compare (const void *a, const void *b) { int r; - - pgp_key_t *s = (pgp_key_t *) a; - pgp_key_t *t = (pgp_key_t *) b; - if((r = mutt_strcasecmp (s->a->addr, t->a->addr)) != 0) + pgp_uid_t **s = (pgp_uid_t **) a; + pgp_uid_t **t = (pgp_uid_t **) b; + + if ((r = mutt_strcasecmp ((*s)->addr, (*t)->addr)) != 0) return r; else - return mutt_strcasecmp(pgp_keyid(s->k), pgp_keyid(t->k)); + return mutt_strcasecmp (pgp_keyid ((*s)->parent), pgp_keyid ((*t)->parent)); } -static KEYINFO *pgp_select_key (struct pgp_vinfo *pgp, - LIST *keys, - ADDRESS *p, const char *s) +static pgp_key_t *pgp_select_key (struct pgp_vinfo *pgp, + pgp_key_t *keys, + ADDRESS * p, const char *s) { int keymax; - pgp_key_t *KeyTable; + pgp_uid_t **KeyTable; MUTTMENU *menu; - LIST *a; - int i; - int done = 0; - LIST *l; + int i, done = 0; char helpstr[SHORT_STRING], buf[LONG_STRING]; char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX]; FILE *fp, *devnull; pid_t thepid; - KEYINFO *info; - - - for (i = 0, l = keys; l; l = l->next) + pgp_key_t *kp; + pgp_uid_t *a; + + for (i = 0, kp = keys; kp; kp = kp->next) { - int did_main_key = 0; - - info = (KEYINFO *) l->data; - a = info->address; - retry1: - for (; a; i++, a = a->next) + for (a = kp->address; a; i++, a = a->next) ; - - if(!did_main_key && info->flags & KEYFLAG_SUBKEY && info->mainkey) - { - did_main_key = 1; - a = info->mainkey->address; - goto retry1; - } } - - if (i == 0) return NULL; + + if (i == 0) + return NULL; keymax = i; - KeyTable = safe_malloc (sizeof (pgp_key_t) * i); + KeyTable = safe_malloc (sizeof (pgp_key_t *) * i); - for (i = 0, l = keys; l; l = l->next) + for (i = 0, kp = keys; kp; kp = kp->next) { - int did_main_key = 0; - info = (KEYINFO *)l->data; - a = info->address; - retry2: - for (; a ; i++, a = a->next) - { - KeyTable[i].k = (KEYINFO *) l->data; - KeyTable[i].a = (PGPUID *)a->data; - } - if(!did_main_key && info->flags & KEYFLAG_SUBKEY && info->mainkey) - { - did_main_key = 1; - a = info->mainkey->address; - goto retry2; - } + for (a = kp->address; a; i++, a = a->next) + KeyTable[i] = a; } - - qsort (KeyTable, i, sizeof (pgp_key_t), pgp_compare); + + qsort (KeyTable, i, sizeof (pgp_key_t *), pgp_compare); helpstr[0] = 0; mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_PGP, OP_EXIT); strcat (helpstr, buf); - mutt_make_help (buf, sizeof (buf), _("Select "), MENU_PGP, + mutt_make_help (buf, sizeof (buf), _("Select "), MENU_PGP, OP_GENERIC_SELECT_ENTRY); strcat (helpstr, buf); mutt_make_help (buf, sizeof (buf), _("Check key "), MENU_PGP, OP_VERIFY_KEY); @@ -195,114 +190,141 @@ static KEYINFO *pgp_select_key (struct pgp_vinfo *pgp, strcat (buf, s); menu->title = buf; - info = NULL; - + kp = NULL; + while (!done) { switch (mutt_menuLoop (menu)) { - case OP_VERIFY_KEY: + case OP_VERIFY_KEY: - mutt_mktemp (tempfile); - if ((devnull = fopen ("/dev/null", "w")) == NULL) + mutt_mktemp (tempfile); + if ((devnull = fopen ("/dev/null", "w")) == NULL) + { + mutt_perror _("Can't open /dev/null"); + break; + } + if ((fp = safe_fopen (tempfile, "w")) == NULL) + { + fclose (devnull); + mutt_perror _("Can't create temporary file"); + break; + } + + mutt_message _("Invoking PGP..."); + + if ((thepid = pgp->invoke_verify_key (pgp, NULL, NULL, NULL, -1, + fileno (fp), fileno (devnull), + pgp_keyid (pgp_principal_key (KeyTable[menu->current]->parent)))) == -1) + { + mutt_perror _("Can't create filter"); + unlink (tempfile); + fclose (fp); + fclose (devnull); + } + + mutt_wait_filter (thepid); + fclose (fp); + fclose (devnull); + mutt_clear_error (); + snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), + pgp_keyid (pgp_principal_key (KeyTable[menu->current]->parent))); + mutt_do_pager (cmd, tempfile, 0, NULL); + menu->redraw = REDRAW_FULL; + + break; + + case OP_VIEW_ID: + + mutt_message (KeyTable[menu->current]->addr); + break; + + case OP_GENERIC_SELECT_ENTRY: + + + /* XXX make error reporting more verbose */ + + if (option (OPTPGPCHECKTRUST)) + { + pgp_key_t *key, *principal; + + key = KeyTable[menu->current]->parent; + principal = pgp_principal_key (key); + + if ((key->flags | principal->flags) & KEYFLAG_CANTUSE) { - mutt_perror _("Can't open /dev/null"); + mutt_error _("This key can't be used: expired/disabled/revoked."); break; } - if ((fp = safe_fopen (tempfile, "w")) == NULL) + } + + if (option (OPTPGPCHECKTRUST) && + (KeyTable[menu->current]->trust & 0x03) < 3) + { + char *s = ""; + char buff[LONG_STRING]; + + switch (KeyTable[menu->current]->trust & 0x03) { - fclose (devnull); - mutt_perror _("Can't create temporary file"); + case 0: + s = N_("This ID's trust level is undefined."); + break; + case 1: + s = N_("This ID is not trusted."); + break; + case 2: + s = N_("This ID is only marginally trusted."); break; - } - - mutt_message _("Invoking PGP..."); - - if((thepid = pgp->invoke_verify_key(pgp, NULL, NULL, NULL, -1, - fileno(fp), fileno(devnull), - pgp_keyid(KeyTable[menu->current].k))) == -1) - { - mutt_perror _("Can't create filter"); - unlink (tempfile); - fclose (fp); - fclose (devnull); } - mutt_wait_filter (thepid); - fclose (fp); - fclose (devnull); - mutt_clear_error (); - snprintf(cmd, sizeof(cmd), _("Key ID: 0x%s"), pgp_keyid(KeyTable[menu->current].k)); - mutt_do_pager (cmd, tempfile, 0, NULL); - menu->redraw = REDRAW_FULL; - - break; + snprintf (buff, sizeof (buff), _("%s Do you really want to use it?"), + _(s)); - case OP_VIEW_ID: - - mutt_message (KeyTable[menu->current].a->addr); - break; - - case OP_GENERIC_SELECT_ENTRY: - - if (option (OPTPGPCHECKTRUST) && - (KeyTable[menu->current].a->trust & 0x03) < 3) + if (mutt_yesorno (buff, 0) != 1) { - char *s = ""; - char buff[LONG_STRING]; - - switch (KeyTable[menu->current].a->trust & 0x03) - { - case 0: s = N_("This ID's trust level is undefined."); break; - case 1: s = N_("This ID is not trusted."); break; - case 2: s = N_("This ID is only marginally trusted."); break; - } - - snprintf (buff, sizeof(buff), _("%s Do you really want to use it?"), - _(s)); - - if (mutt_yesorno (buff, 0) != 1) - { - mutt_clear_error (); - break; - } + mutt_clear_error (); + break; } + } - info = KeyTable[menu->current].k; - done = 1; - break; +# if 0 + kp = pgp_principal_key (KeyTable[menu->current]->parent); +# else + kp = KeyTable[menu->current]->parent; +# endif + done = 1; + break; - case OP_EXIT: + case OP_EXIT: - info = NULL; - done = 1; - break; + kp = NULL; + done = 1; + break; } } mutt_menuDestroy (&menu); safe_free ((void **) &KeyTable); - return (info); + return (kp); } -char *pgp_ask_for_key (struct pgp_vinfo *pgp, KEYINFO *db, char *tag, char *whatfor, - short abilities, char **alg) +pgp_key_t *pgp_ask_for_key (struct pgp_vinfo *pgp, char *tag, char *whatfor, + short abilities, pgp_ring_t keyring) { - KEYINFO *key; - char *key_id; + pgp_key_t *key; char resp[SHORT_STRING]; struct pgp_cache *l = NULL; resp[0] = 0; - if (whatfor) + if (whatfor) { for (l = id_defaults; l; l = l->next) if (!mutt_strcasecmp (whatfor, l->what)) { - strcpy (resp, NONULL(l->dflt)); + strcpy (resp, NONULL (l->dflt)); break; } } @@ -313,14 +335,14 @@ char *pgp_ask_for_key (struct pgp_vinfo *pgp, KEYINFO *db, char *tag, char *what resp[0] = 0; if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0) return NULL; - - if (whatfor) + + if (whatfor) { if (l) { - safe_free ((void **)&l->dflt); + safe_free ((void **) &l->dflt); l->dflt = safe_strdup (resp); - } + } else { l = safe_malloc (sizeof (struct pgp_cache)); @@ -331,15 +353,9 @@ char *pgp_ask_for_key (struct pgp_vinfo *pgp, KEYINFO *db, char *tag, char *what } } - if ((key = ki_getkeybystr (pgp, resp, db, abilities))) - { - key_id = safe_strdup(pgp_keyid (key)); + if ((key = pgp_getkeybystr (pgp, resp, abilities, keyring))) + return key; - if (alg) - *alg = safe_strdup(pgp_pkalg_to_mic(key->algorithm)); - - return (key_id); - } BEEP (); } /* not reached */ @@ -347,7 +363,7 @@ char *pgp_ask_for_key (struct pgp_vinfo *pgp, KEYINFO *db, char *tag, char *what /* generate a public key attachment */ -BODY *pgp_make_key_attachment (char * tempf) +BODY *pgp_make_key_attachment (char *tempf) { BODY *att; char buff[LONG_STRING]; @@ -357,54 +373,60 @@ BODY *pgp_make_key_attachment (char * tempf) FILE *devnull; struct stat sb; pid_t thepid; - KEYINFO *db; - struct pgp_vinfo *pgp = pgp_get_vinfo(PGP_EXPORT); + pgp_key_t *key; + struct pgp_vinfo *pgp = pgp_get_vinfo (PGP_EXPORT); - if(!pgp) + if (!pgp) return NULL; - + unset_option (OPTPGPCHECKTRUST); - - db = pgp->read_pubring(pgp); - id = pgp_ask_for_key (pgp, db, _("Please enter the key ID: "), NULL, 0, NULL); - pgp_close_keydb(&db); - - if(!id) - return NULL; - if (!tempf) { + key = pgp_ask_for_key (pgp, _("Please enter the key ID: "), NULL, 0, PGP_PUBRING); + + if (!key) return NULL; + + id = safe_strdup (pgp_keyid (pgp_principal_key(key))); + pgp_free_key (&key); + + if (!tempf) + { mutt_mktemp (tempfb); tempf = tempfb; } - if ((tempfp = safe_fopen (tempf, tempf == tempfb ? "w" : "a")) == NULL) { + if ((tempfp = safe_fopen (tempf, tempf == tempfb ? "w" : "a")) == NULL) + { mutt_perror _("Can't create temporary file"); - safe_free ((void **)&id); + safe_free ((void **) &id); return NULL; } - if ((devnull = fopen ("/dev/null", "w")) == NULL) { + if ((devnull = fopen ("/dev/null", "w")) == NULL) + { mutt_perror _("Can't open /dev/null"); - safe_free ((void **)&id); + safe_free ((void **) &id); fclose (tempfp); - if (tempf == tempfb) unlink (tempf); + if (tempf == tempfb) + unlink (tempf); return NULL; } - if ((thepid = pgp->invoke_export(pgp, - NULL, NULL, NULL, -1, - fileno(tempfp), fileno(devnull), id)) == -1) + mutt_message _("Invoking pgp..."); + + if ((thepid = + pgp->invoke_export (pgp, NULL, NULL, NULL, -1, + fileno (tempfp), fileno (devnull), id)) == -1) { mutt_perror _("Can't create filter"); unlink (tempf); fclose (tempfp); fclose (devnull); - safe_free ((void **)&id); + safe_free ((void **) &id); return NULL; } - + mutt_wait_filter (thepid); - + fclose (tempfp); fclose (devnull); @@ -412,86 +434,89 @@ BODY *pgp_make_key_attachment (char * tempf) att->filename = safe_strdup (tempf); att->unlink = 1; att->type = TYPEAPPLICATION; - att->subtype = safe_strdup ("pgp-keys"); + att->subtype = safe_strdup ("pgp-keys"); snprintf (buff, sizeof (buff), _("PGP Key 0x%s."), id); att->description = safe_strdup (buff); mutt_update_encoding (att); - + stat (tempf, &sb); att->length = sb.st_size; - safe_free ((void **)&id); + safe_free ((void **) &id); return att; } -static char *mutt_stristr (char *haystack, char *needle) +static LIST *pgp_add_string_to_hints (LIST *hints, const char *str) { - char *p, *q; - - if (!haystack) - return NULL; - if (!needle) - return (haystack); - - while (*(p = haystack)) + char *scratch = safe_strdup (str); + char *t; + + t = strtok (scratch, " \n"); + while (t) { - for (q = needle ; *p && *q && tolower (*p) == tolower (*q) ; p++, q++) - ; - if (!*q) - return (haystack); - haystack++; + hints = mutt_add_list (hints, t); + t = strtok (NULL, " \n"); } - return NULL; + + safe_free ((void **) &scratch); + return hints; } -KEYINFO *ki_getkeybyaddr (struct pgp_vinfo *pgp, - ADDRESS *a, KEYINFO *k, short abilities) + +pgp_key_t *pgp_getkeybyaddr (struct pgp_vinfo * pgp, + ADDRESS * a, short abilities, pgp_ring_t keyring) { ADDRESS *r, *p; - LIST *l = NULL, *t = NULL; - LIST *q; + LIST *hints = NULL; int weak = 0; int weak_association; int match; - int did_main_key; - PGPUID *u; + pgp_uid_t *q; + pgp_key_t *keys, *k, *kn; + pgp_key_t *matches = NULL; + pgp_key_t **last = &matches; - dprint (5, (debugfile, "ki_getkeybyaddr: looking for %s <%s>.", - a->personal, a->mailbox)); + if (a && a->mailbox) + hints = pgp_add_string_to_hints (hints, a->mailbox); + if (a && a->personal) + hints = pgp_add_string_to_hints (hints, a->personal); + + mutt_message _("Looking for keys..."); + keys = pgp->get_candidates (pgp, keyring, hints); + mutt_free_list (&hints); - for ( ; k ; k = k->next) + if (!keys) + return NULL; + + dprint (5, (debugfile, "pgp_getkeybyaddr: looking for %s <%s>.", + a->personal, a->mailbox)); + + + for (k = keys; k; k = kn) { + kn = k->next; + dprint (5, (debugfile, " looking at key: %s\n", pgp_keyid (k))); - - if(k->flags & (KEYFLAG_REVOKED | KEYFLAG_EXPIRED | KEYFLAG_DISABLED)) - { - dprint (5, (debugfile, " key disabled/revoked/expired\n")); - continue; - } - - if(abilities && !(k->flags & abilities)) + + if (abilities && !(k->flags & abilities)) { dprint (5, (debugfile, " insufficient abilities: Has %x, want %x\n", k->flags, abilities)); continue; } - + q = k->address; - did_main_key = 0; weak_association = 1; match = 0; - - retry: - - for (;q ; q = q->next) + + for (; q; q = q->next) { - u = (PGPUID *) q->data; - r = rfc822_parse_adrlist(NULL, u->addr); + r = rfc822_parse_adrlist (NULL, q->addr); - - for(p = r; p && weak_association; p = p->next) + + for (p = r; p && weak_association; p = p->next) { if ((p->mailbox && a->mailbox && mutt_strcasecmp (p->mailbox, a->mailbox) == 0) || @@ -500,116 +525,138 @@ KEYINFO *ki_getkeybyaddr (struct pgp_vinfo *pgp, { match = 1; - if(((u->trust & 0x03) == 3) && - (p->mailbox && a->mailbox && !mutt_strcasecmp(p->mailbox, a->mailbox))) + if (((q->trust & 0x03) == 3) && + (p->mailbox && a->mailbox && !mutt_strcasecmp (p->mailbox, a->mailbox))) weak_association = 0; } } - rfc822_free_address(&r); + rfc822_free_address (&r); } - if(match) + if (match) { - t = mutt_new_list (); - t->data = (void *) k; - t->next = l; - l = t; - - if(weak_association) - weak = 1; + pgp_key_t *_p, *_k; + + _k = pgp_principal_key (k); - } + *last = _k; + kn = pgp_remove_key (&keys, _k); - if(!did_main_key && !match && k->flags & KEYFLAG_SUBKEY && k->mainkey) - { - did_main_key = 1; - q = k->mainkey->address; - goto retry; + /* start with k, not with _k: k is always a successor of _k. */ + + for (_p = k; _p; _p = _p->next) + { + if (!_p->next) + { + last = &_p->next; + break; + } + } } } + + pgp_free_key (&keys); - if (l) + if (matches) { - if (l->next || weak) + if (matches->next || weak) { /* query for which key the user wants */ - k = pgp_select_key (pgp, l, a, NULL); + k = pgp_select_key (pgp, matches, a, NULL); + if (k) + pgp_remove_key (&matches, k); + + pgp_free_key (&matches); } else - k = (KEYINFO *)l->data; - - /* mutt_free_list() frees the .data member, so clear the pointers */ - - for(t = l; t; t = t->next) - t->data = NULL; + k = matches; - mutt_free_list (&l); + return k; } - return (k); + return NULL; } -KEYINFO *ki_getkeybystr (struct pgp_vinfo *pgp, - char *p, KEYINFO *k, short abilities) +pgp_key_t *pgp_getkeybystr (struct pgp_vinfo * pgp, + char *p, short abilities, pgp_ring_t keyring) { - LIST *t = NULL, *l = NULL; - LIST *a; + LIST *hints = NULL; + pgp_key_t *keys; + pgp_key_t *matches = NULL; + pgp_key_t **last = &matches; + pgp_key_t *k, *kn; + pgp_uid_t *a; + short match; + + mutt_message _("Looking for keys..."); + + hints = pgp_add_string_to_hints (hints, p); + keys = pgp->get_candidates (pgp, keyring, hints); + mutt_free_list (&hints); + + if (!keys) + return NULL; - for(; k; k = k->next) + + for (k = keys; k; k = kn) { - int did_main_key = 0; - - if(k->flags & (KEYFLAG_REVOKED | KEYFLAG_EXPIRED | KEYFLAG_DISABLED)) - continue; - - if(abilities && !(k->flags & abilities)) + kn = k->next; + if (abilities && !(k->flags & abilities)) continue; - a = k->address; - - retry: + match = 0; - for(; a ; a = a->next) + for (a = k->address; a; a = a->next) { - dprint (5, (debugfile, "ki_getkeybystr: matching \"%s\" against key %s, \"%s\": ", - p, pgp_keyid (k), ((PGPUID *)a->data)->addr)); - if (!*p || mutt_strcasecmp (p, pgp_keyid(k)) == 0 || - (!mutt_strncasecmp(p, "0x", 2) && !mutt_strcasecmp(p+2, pgp_keyid(k))) || - (option(OPTPGPLONGIDS) && !mutt_strncasecmp(p, "0x", 2) && - !mutt_strcasecmp(p+2, k->keyid+8)) || - mutt_stristr(((PGPUID *)a->data)->addr,p)) + dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s, \"%s\": ", + p, pgp_keyid (k), a->addr)); + if (!*p || mutt_strcasecmp (p, pgp_keyid (k)) == 0 || + (!mutt_strncasecmp (p, "0x", 2) && !mutt_strcasecmp (p + 2, pgp_keyid (k))) || + (option (OPTPGPLONGIDS) && !mutt_strncasecmp (p, "0x", 2) && + !mutt_strcasecmp (p + 2, k->keyid + 8)) || + mutt_stristr (a->addr, p)) { dprint (5, (debugfile, "match.\n")); - t = mutt_new_list (); - t->data = (void *)k; - t->next = l; - l = t; + match = 1; break; } - else - dprint (5, (debugfile, "no match.\n")); } - if(!did_main_key && k->flags & KEYFLAG_SUBKEY && k->mainkey) + if (match) { - did_main_key = 1; - a = k->mainkey->address; - goto retry; + pgp_key_t *_p, *_k; + + _k = pgp_principal_key (k); + + *last = _k; + kn = pgp_remove_key (&keys, _k); + + /* start with k, not with _k: k is always a successor of _k. */ + + for (_p = k; _p; _p = _p->next) + { + if (!_p->next) + { + last = &_p->next; + break; + } + } } } - if (l) - { - k = pgp_select_key (pgp, l, NULL, p); - set_option(OPTNEEDREDRAW); - - for(t = l; t; t = t->next) - t->data = NULL; + pgp_free_key (&keys); - mutt_free_list (&l); + if (matches) + { + k = pgp_select_key (pgp, matches, NULL, p); + if (k) + pgp_remove_key (&matches, k); + + pgp_free_key (&matches); + return k; } - return (k); + return NULL; } diff --git a/pgppubring.c b/pgppubring.c index c093c216..ff878e1b 100644 --- a/pgppubring.c +++ b/pgppubring.c @@ -17,7 +17,7 @@ * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA * 02139, USA. - */ + */ #include @@ -36,28 +36,30 @@ static unsigned char *pbuf = NULL; static size_t plen = 0; -enum packet_tags { - PT_RES0 = 0, /* reserved */ - PT_ESK, /* Encrypted Session Key */ - PT_SIG, /* Signature Packet */ - PT_CESK, /* Conventionally Encrypted Session Key Packet */ - PT_OPS, /* One-Pass Signature Packet */ - PT_SECKEY, /* Secret Key Packet */ - PT_PUBKEY, /* Public Key Packet */ - PT_SUBSECKEY, /* Secret Subkey Packet */ - PT_COMPRESSED, /* Compressed Data Packet */ - PT_SKE, /* Symmetrically Encrypted Data Packet */ - PT_MARKER, /* Marker Packet */ - PT_LITERAL, /* Literal Data Packet */ - PT_TRUST, /* Trust Packet */ - PT_NAME, /* Name Packet */ - PT_SUBKEY, /* Subkey Packet */ - PT_RES15, /* Reserved */ - PT_COMMENT /* Comment Packet */ +enum packet_tags +{ + PT_RES0 = 0, /* reserved */ + PT_ESK, /* Encrypted Session Key */ + PT_SIG, /* Signature Packet */ + PT_CESK, /* Conventionally Encrypted Session Key Packet */ + PT_OPS, /* One-Pass Signature Packet */ + PT_SECKEY, /* Secret Key Packet */ + PT_PUBKEY, /* Public Key Packet */ + PT_SUBSECKEY, /* Secret Subkey Packet */ + PT_COMPRESSED, /* Compressed Data Packet */ + PT_SKE, /* Symmetrically Encrypted Data Packet */ + PT_MARKER, /* Marker Packet */ + PT_LITERAL, /* Literal Data Packet */ + PT_TRUST, /* Trust Packet */ + PT_NAME, /* Name Packet */ + PT_SUBKEY, /* Subkey Packet */ + PT_RES15, /* Reserved */ + PT_COMMENT /* Comment Packet */ }; /* FIXME I can't find where those strings are displayed! */ -const char *pgp_packet_name[] = { +const char *pgp_packet_name[] = +{ N_("reserved"), N_("Encrypted Session Key"), N_("Signature Packet"), @@ -77,17 +79,24 @@ const char *pgp_packet_name[] = { N_("Comment Packet") }; -const char *pgp_pkalgbytype(unsigned char type) +const char *pgp_pkalgbytype (unsigned char type) { - switch(type) + switch (type) { - case 1: return "RSA"; - case 2: return "RSA"; - case 3: return "RSA"; - case 16: return "ElG"; - case 17: return "DSA"; - case 20: return "ElG"; - default: return "unk"; + case 1: + return "RSA"; + case 2: + return "RSA"; + case 3: + return "RSA"; + case 16: + return "ElG"; + case 17: + return "DSA"; + case 20: + return "ElG"; + default: + return "unk"; } } @@ -97,25 +106,36 @@ static struct char *pkalg; char *micalg; } -pktomic[] = +pktomic[] = { - { "RSA", "pgp-md5" }, - { "ElG", "pgp-rmd160" }, - { "DSA", "pgp-sha1" }, - { NULL, "x-unknown" } + { + "RSA", "pgp-md5" + } + , + { + "ElG", "pgp-rmd160" + } + , + { + "DSA", "pgp-sha1" + } + , + { + NULL, "x-unknown" + } }; -const char *pgp_pkalg_to_mic(const char *alg) +const char *pgp_pkalg_to_mic (const char *alg) { int i; - - for(i = 0; pktomic[i].pkalg; i++) + + for (i = 0; pktomic[i].pkalg; i++) { - if(!mutt_strcasecmp(pktomic[i].pkalg, alg)) + if (!mutt_strcasecmp (pktomic[i].pkalg, alg)) break; } - + return pktomic[i].micalg; } @@ -124,255 +144,349 @@ const char *pgp_pkalg_to_mic(const char *alg) #if 0 -static const char *hashalgbytype(unsigned char type) +static const char *hashalgbytype (unsigned char type) { - switch(type) + switch (type) { - case 1: return "MD5"; - case 2: return "SHA1"; - case 3: return "RIPE-MD/160"; - case 4: return "HAVAL"; - default: return "unknown"; + case 1: + return "MD5"; + case 2: + return "SHA1"; + case 3: + return "RIPE-MD/160"; + case 4: + return "HAVAL"; + default: + return "unknown"; } } #endif -short pgp_canencrypt(unsigned char type) +short pgp_canencrypt (unsigned char type) { - switch(type) + switch (type) { - case 1: - case 2: - case 16: - case 20: - return 1; - default: - return 0; + case 1: + case 2: + case 16: + case 20: + return 1; + default: + return 0; } } -short pgp_cansign(unsigned char type) +short pgp_cansign (unsigned char type) { - switch(type) + switch (type) { - case 1: - case 3: - case 16: - case 17: - case 20: - return 1; - default: - return 0; + case 1: + case 3: + case 16: + case 17: + case 20: + return 1; + default: + return 0; } } /* return values: - * + * 1 = sign only * 2 = encrypt only * 3 = both */ -short pgp_get_abilities(unsigned char type) +short pgp_get_abilities (unsigned char type) { - return (pgp_canencrypt(type) << 1) | pgp_cansign(type); + return (pgp_canencrypt (type) << 1) | pgp_cansign (type); } -static int read_material(size_t material, size_t *used, FILE *fp) +static int read_material (size_t material, size_t * used, FILE * fp) { - if(*used + material >= plen) + if (*used + material >= plen) { unsigned char *p; size_t nplen; - + nplen = *used + material + CHUNKSIZE; - if(!(p = realloc(pbuf, nplen))) + if (!(p = realloc (pbuf, nplen))) { - mutt_perror("realloc"); + mutt_perror ("realloc"); return -1; } plen = nplen; pbuf = p; } - - if(fread(pbuf + *used, 1, material, fp) < material) + + if (fread (pbuf + *used, 1, material, fp) < material) { - mutt_perror("fread"); + mutt_perror ("fread"); return -1; } - + *used += material; return 0; } -static unsigned char *pgp_read_packet(FILE *fp, size_t *len) +static unsigned char *pgp_read_packet (FILE * fp, size_t * len) { size_t used = 0; long startpos; unsigned char ctb; unsigned char b; size_t material; - - startpos = ftell(fp); - - if(!plen) + + startpos = ftell (fp); + + if (!plen) { plen = CHUNKSIZE; - pbuf = safe_malloc(plen); + pbuf = safe_malloc (plen); } - if(fread(&ctb, 1, 1, fp) < 1) + if (fread (&ctb, 1, 1, fp) < 1) { - if(!feof(fp)) - mutt_perror("fread"); + if (!feof (fp)) + mutt_perror ("fread"); goto bail; } - if(!(ctb & 0x80)) + if (!(ctb & 0x80)) { goto bail; } - if(ctb & 0x40) /* handle PGP 5.0 packets. */ + if (ctb & 0x40) /* handle PGP 5.0 packets. */ { int partial = 0; - pbuf[0] = ctb; used++; - - do { - if(fread(&b, 1, 1, fp) < 1) + pbuf[0] = ctb; + used++; + + do + { + if (fread (&b, 1, 1, fp) < 1) { - mutt_perror("fread"); + mutt_perror ("fread"); goto bail; } - - if(b < 192) + + if (b < 192) { material = b; partial = 0; material -= 1; - } - else if(192 <= b && b <= 223) + } + else if (192 <= b && b <= 223) { material = (b - 192) * 256; - if(fread(&b, 1, 1, fp) < 1) + if (fread (&b, 1, 1, fp) < 1) { - mutt_perror("fread"); + mutt_perror ("fread"); goto bail; } material += b + 192; partial = 0; material -= 2; } - else if(b < 255) + else if (b < 255) { material = 1 << (b & 0x1f); partial = 1; material -= 1; } - else /* b == 255 */ + else + /* b == 255 */ { unsigned char buf[4]; - if( fread( buf, 4, 1, fp ) < 1) + if (fread (buf, 4, 1, fp) < 1) { - mutt_perror("fread"); - goto bail; + mutt_perror ("fread"); + goto bail; } - /*assert( sizeof(material) >= 4 );*/ - material = buf[0] << 24; + /*assert( sizeof(material) >= 4 ); */ + material = buf[0] << 24; material |= buf[1] << 16; material |= buf[2] << 8; material |= buf[3]; partial = 0; material -= 5; } - - if(read_material(material, &used, fp) == -1) + + if (read_material (material, &used, fp) == -1) goto bail; - } while (partial); + } + while (partial); } - else /* Old-Style PGP */ + else + /* Old-Style PGP */ { int bytes = 0; pbuf[0] = 0x80 | ((ctb >> 2) & 0x0f); used++; - - switch(ctb & 0x03) + + switch (ctb & 0x03) { case 0: { - if(fread(&b, 1, 1, fp) < 1) + if (fread (&b, 1, 1, fp) < 1) { - mutt_perror("fread"); + mutt_perror ("fread"); goto bail; } - + material = b; break; } - + case 1: - bytes = 2; - + bytes = 2; + case 2: { int i; - if(!bytes) bytes = 4; - + if (!bytes) + bytes = 4; + material = 0; - - for(i = 0; i < bytes; i++) + + for (i = 0; i < bytes; i++) { - if(fread(&b, 1, 1, fp) < 1) + if (fread (&b, 1, 1, fp) < 1) { - mutt_perror("fread"); + mutt_perror ("fread"); goto bail; } - + material = (material << 8) + b; } break; } - + default: - goto bail; + goto bail; } - - if(read_material(material, &used, fp) == -1) + + if (read_material (material, &used, fp) == -1) goto bail; } - - if(len) + + if (len) *len = used; - + return pbuf; - - bail: - - fseek(fp, startpos, SEEK_SET); + +bail: + + fseek (fp, startpos, SEEK_SET); return NULL; } -static KEYINFO *pgp_new_keyinfo(void) +static pgp_key_t *pgp_new_keyinfo (void) { - KEYINFO *p; + return safe_calloc (sizeof (pgp_key_t), 1); +} - p = safe_malloc(sizeof(KEYINFO)); - p->keyid = NULL; - p->address = NULL; - p->flags = 0; - p->next = NULL; - p->keylen = 0; +void pgp_free_uid (pgp_uid_t ** upp) +{ + pgp_uid_t *up, *q; - return p; + if (!upp || !*upp) + return; + for (up = *upp; up; up = q) + { + q = up->next; + safe_free ((void **) &up->addr); + safe_free ((void **) &up); + } + + *upp = NULL; +} + +static void _pgp_free_key (pgp_key_t ** kpp) +{ + pgp_key_t *kp; + + if (!kpp || !*kpp) + return; + + kp = *kpp; + + pgp_free_uid (&kp->address); + safe_free ((void **) &kp->keyid); + safe_free ((void **) kpp); } -static KEYINFO *pgp_parse_pgp2_key(unsigned char *buff, size_t l) +pgp_key_t *pgp_remove_key (pgp_key_t ** klist, pgp_key_t * key) { - KEYINFO *p; + pgp_key_t **last; + pgp_key_t *p, *q, *r; + + if (!klist || !*klist || !key) + return NULL; + + if (key->parent && key->parent != key) + key = key->parent; + + last = klist; + for (p = *klist; p && p != key; p = p->next) + last = &p->next; + + if (!p) + return NULL; + + for (q = p->next, r = p; q && q->parent == p; q = q->next) + r = q; + + if (r) + r->next = NULL; + + *last = q; + return q; +} + +void pgp_free_key (pgp_key_t ** kpp) +{ + pgp_key_t *p, *q, *r; + + if (!kpp || !*kpp) + return; + + if ((*kpp)->parent && (*kpp)->parent != *kpp) + *kpp = (*kpp)->parent; + + /* Order is important here: + * + * - First free all children. + * - If we are an orphan (i.e., our parent was not in the key list), + * free our parent. + * - free ourselves. + */ + + for (p = *kpp; p; p = q) + { + for (q = p->next; q && q->parent == p; q = r) + { + r = q->next; + _pgp_free_key (&q); + } + if (p->parent) + _pgp_free_key (&p->parent); + + _pgp_free_key (&p); + } + + *kpp = NULL; +} + +static pgp_key_t *pgp_parse_pgp2_key (unsigned char *buff, size_t l) +{ + pgp_key_t *p; unsigned char alg; size_t expl; unsigned long id; @@ -381,100 +495,102 @@ static KEYINFO *pgp_parse_pgp2_key(unsigned char *buff, size_t l) size_t j; int i, k; unsigned char scratch[LONG_STRING]; - - if(l < 12) + + if (l < 12) return NULL; - - p = pgp_new_keyinfo(); - - for(i = 0, j = 2; i < 4; i++) + + p = pgp_new_keyinfo (); + + for (i = 0, j = 2; i < 4; i++) gen_time = (gen_time << 8) + buff[j++]; - - for(i = 0; i < 2; i++) + + for (i = 0; i < 2; i++) exp_days = (exp_days << 8) + buff[j++]; - - if(exp_days && time(NULL) > gen_time + exp_days * 24 * 3600) + + if (exp_days && time (NULL) > gen_time + exp_days * 24 * 3600) p->flags |= KEYFLAG_EXPIRED; - + alg = buff[j++]; - - p->algorithm = pgp_pkalgbytype(alg); - p->flags |= pgp_get_abilities(alg); - + + p->algorithm = pgp_pkalgbytype (alg); + p->flags |= pgp_get_abilities (alg); + expl = 0; - for(i = 0; i < 2; i++) + for (i = 0; i < 2; i++) expl = (expl << 8) + buff[j++]; - + p->keylen = expl; - - expl = (expl + 7)/ 8; - if(expl < 4) + + expl = (expl + 7) / 8; + if (expl < 4) goto bailout; - + j += expl - 8; - - for(k = 0; k < 2; k++) + + for (k = 0; k < 2; k++) { - for(id = 0, i = 0; i < 4; i++) + for (id = 0, i = 0; i < 4; i++) id = (id << 8) + buff[j++]; - - snprintf((char *)scratch + k * 8, sizeof(scratch) - k * 8, - "%08lX", id); + + snprintf ((char *) scratch + k * 8, sizeof (scratch) - k * 8, + "%08lX", id); } - - p->keyid = safe_strdup((char *)scratch); - + + p->keyid = safe_strdup ((char *) scratch); + return p; - - bailout: - - safe_free((void **)&p); + +bailout: + + safe_free ((void **) &p); return NULL; } -static void pgp_make_pgp3_fingerprint(unsigned char *buff, size_t l, - unsigned char *digest) +static void pgp_make_pgp3_fingerprint (unsigned char *buff, size_t l, + unsigned char *digest) { unsigned char dummy; SHA_CTX context; - SHA1_Init(&context); - + SHA1_Init (&context); + dummy = buff[0] & 0x3f; - if(dummy == PT_SUBSECKEY || dummy == PT_SUBKEY || dummy == PT_SECKEY) + if (dummy == PT_SUBSECKEY || dummy == PT_SUBKEY || dummy == PT_SECKEY) dummy = PT_PUBKEY; dummy = (dummy << 2) | 0x81; - SHA1_Update(&context, &dummy, 1); + SHA1_Update (&context, &dummy, 1); dummy = ((l - 1) >> 8) & 0xff; - SHA1_Update(&context, &dummy, 1); - dummy = (l - 1) & 0xff; - SHA1_Update(&context, &dummy, 1); - SHA1_Update(&context, buff + 1, l - 1); - SHA1_Final(digest, &context); + SHA1_Update (&context, &dummy, 1); + dummy = (l - 1) & 0xff; + SHA1_Update (&context, &dummy, 1); + SHA1_Update (&context, buff + 1, l - 1); + SHA1_Final (digest, &context); } -static void skip_bignum(unsigned char *buff, size_t l, size_t j, - size_t *toff, size_t n) +static void skip_bignum (unsigned char *buff, size_t l, size_t j, + size_t * toff, size_t n) { size_t len; - + do { - len = (buff[j] << 8) + buff[j+1]; + len = (buff[j] << 8) + buff[j + 1]; j += (len + 7) / 8 + 2; - } while(j <= l && --n > 0); - - if(toff) *toff = j; + } + while (j <= l && --n > 0); + + if (toff) + *toff = j; } - -static KEYINFO *pgp_parse_pgp3_key(unsigned char *buff, size_t l) + +static pgp_key_t *pgp_parse_pgp3_key (unsigned char *buff, size_t l) { - KEYINFO *p; + pgp_key_t *p; unsigned char alg; unsigned char digest[SHA_DIGEST_LENGTH]; unsigned char scratch[LONG_STRING]; @@ -483,98 +599,98 @@ static KEYINFO *pgp_parse_pgp3_key(unsigned char *buff, size_t l) int i, k; short len; size_t j; - - p = pgp_new_keyinfo(); + + p = pgp_new_keyinfo (); j = 2; - - for(i = 0; i < 4; i++) + + for (i = 0; i < 4; i++) gen_time = (gen_time << 8) + buff[j++]; p->gen_time = gen_time; - + alg = buff[j++]; - - p->algorithm = pgp_pkalgbytype(alg); - p->flags |= pgp_get_abilities(alg); + + p->algorithm = pgp_pkalgbytype (alg); + p->flags |= pgp_get_abilities (alg); if (alg == 17) - skip_bignum(buff, l, j, &j, 3); - else if(alg == 16 || alg == 20 ) - skip_bignum(buff, l, j, &j, 2); - - len = (buff[j] << 8) + buff[j+1]; + skip_bignum (buff, l, j, &j, 3); + else if (alg == 16 || alg == 20) + skip_bignum (buff, l, j, &j, 2); + + len = (buff[j] << 8) + buff[j + 1]; p->keylen = len; - if (alg >=1 && alg <= 3) - skip_bignum(buff, l, j, &j, 2); - else if(alg == 17 || alg == 16) - skip_bignum(buff, l, j, &j, 1); - - pgp_make_pgp3_fingerprint(buff, j, digest); + if (alg >= 1 && alg <= 3) + skip_bignum (buff, l, j, &j, 2); + else if (alg == 17 || alg == 16) + skip_bignum (buff, l, j, &j, 1); + + pgp_make_pgp3_fingerprint (buff, j, digest); - for(k = 0; k < 2; k++) + for (k = 0; k < 2; k++) { - for(id = 0, i = SHA_DIGEST_LENGTH - 8 + k*4; - i < SHA_DIGEST_LENGTH + (k - 1) * 4; i++) + for (id = 0, i = SHA_DIGEST_LENGTH - 8 + k * 4; + i < SHA_DIGEST_LENGTH + (k - 1) * 4; i++) id = (id << 8) + digest[i]; - - snprintf((char *)scratch + k * 8, sizeof(scratch) - k * 8, "%08lX", id); + + snprintf ((char *) scratch + k * 8, sizeof (scratch) - k * 8, "%08lX", id); } - - p->keyid = safe_strdup((char *)scratch); - + + p->keyid = safe_strdup ((char *) scratch); + return p; } -static KEYINFO *pgp_parse_keyinfo(unsigned char *buff, size_t l) +static pgp_key_t *pgp_parse_keyinfo (unsigned char *buff, size_t l) { - if(!buff || l < 2) + if (!buff || l < 2) return NULL; dprint (5, (debugfile, " version: %d ", buff[1])); - - switch(buff[1]) + + switch (buff[1]) { - case 2: - case 3: - return pgp_parse_pgp2_key(buff, l); - case 4: - return pgp_parse_pgp3_key(buff, l); - default: - return NULL; + case 2: + case 3: + return pgp_parse_pgp2_key (buff, l); + case 4: + return pgp_parse_pgp3_key (buff, l); + default: + return NULL; } } -static int pgp_parse_pgp2_sig(unsigned char *buff, size_t l, KEYINFO *p) +static int pgp_parse_pgp2_sig (unsigned char *buff, size_t l, pgp_key_t * p) { unsigned char sigtype; long sig_gen_time; unsigned long signerid; size_t j; int i; - - if(l < 22) + + if (l < 22) return -1; - + j = 3; sigtype = buff[j++]; - + sig_gen_time = 0; - for(i = 0; i < 4; i++) + for (i = 0; i < 4; i++) sig_gen_time = (sig_gen_time << 8) + buff[j++]; - + j += 4; signerid = 0; - for(i = 0; i < 4; i++) + for (i = 0; i < 4; i++) signerid = (signerid << 8) + buff[j++]; - - if(sigtype == 0x20 || sigtype == 0x28) + + if (sigtype == 0x20 || sigtype == 0x28) p->flags |= KEYFLAG_REVOKED; - + return 0; } -static int pgp_parse_pgp3_sig(unsigned char *buff, size_t l, KEYINFO *p) +static int pgp_parse_pgp3_sig (unsigned char *buff, size_t l, pgp_key_t * p) { unsigned char sigtype; unsigned char pkalg; @@ -588,228 +704,226 @@ static int pgp_parse_pgp3_sig(unsigned char *buff, size_t l, KEYINFO *p) size_t j; int i; short ii; - short have_critical_spks=0; - - if(l < 7) + short have_critical_spks = 0; + + if (l < 7) return -1; - + j = 2; - + sigtype = buff[j++]; pkalg = buff[j++]; hashalg = buff[j++]; - - for(ii = 0; ii < 2; ii++) + + for (ii = 0; ii < 2; ii++) { size_t skl; size_t nextone; - - ml = (buff[j] << 8) + buff[j+1]; + + ml = (buff[j] << 8) + buff[j + 1]; j += 2; - - if(j + ml > l) break; - + + if (j + ml > l) + break; + nextone = j; - while(ml) + while (ml) { j = nextone; skl = buff[j++]; - if(!--ml) break; - - if(skl >= 192) + if (!--ml) + break; + + if (skl >= 192) { skl = (skl - 192) * 256 + buff[j++] + 192; - if(!--ml) break; + if (!--ml) + break; } - - if((int) ml - (int) skl < 0) + + if ((int) ml - (int) skl < 0) break; ml -= skl; - + nextone = j + skl; skt = buff[j++]; - - switch(skt & 0x7f) + + switch (skt & 0x7f) { - case 2: /* creation time */ + case 2: /* creation time */ { - if(skl < 4) + if (skl < 4) break; sig_gen_time = 0; - for(i = 0; i < 4; i++) + for (i = 0; i < 4; i++) sig_gen_time = (sig_gen_time << 8) + buff[j++]; - + break; } - case 3: /* expiration time */ + case 3: /* expiration time */ { - if(skl < 4) + if (skl < 4) break; validity = 0; - for(i = 0; i < 4; i++) + for (i = 0; i < 4; i++) validity = (validity << 8) + buff[j++]; break; } - case 9: /* key expiration time */ + case 9: /* key expiration time */ { - if(skl < 4) + if (skl < 4) break; key_validity = 0; - for(i = 0; i < 4; i++) + for (i = 0; i < 4; i++) key_validity = (key_validity << 8) + buff[j++]; break; } - case 16: /* issuer key ID */ + case 16: /* issuer key ID */ { - if(skl < 8) + if (skl < 8) break; j += 4; signerid = 0; - for(i = 0; i < 4; i++) + for (i = 0; i < 4; i++) signerid = (signerid << 8) + buff[j++]; break; } - case 10: /* CMR key */ break; - case 4: /* exportable */ - case 5: /* trust */ - case 6: /* regexp */ - case 7: /* revocable */ - case 11: /* Pref. symm. alg. */ - case 12: /* revocation key */ - case 20: /* notation data */ - case 21: /* pref. hash */ - case 22: /* pref. comp.alg. */ - case 23: /* key server prefs. */ - case 24: /* pref. key server */ + case 10: /* CMR key */ + break; + case 4: /* exportable */ + case 5: /* trust */ + case 6: /* regexp */ + case 7: /* revocable */ + case 11: /* Pref. symm. alg. */ + case 12: /* revocation key */ + case 20: /* notation data */ + case 21: /* pref. hash */ + case 22: /* pref. comp.alg. */ + case 23: /* key server prefs. */ + case 24: /* pref. key server */ default: { - if(skt & 0x80) + if (skt & 0x80) have_critical_spks = 1; } } } j = nextone; } - - if(sigtype == 0x20 || sigtype == 0x28) + + if (sigtype == 0x20 || sigtype == 0x28) p->flags |= KEYFLAG_REVOKED; - if(key_validity != -1 && time(NULL) > p->gen_time + key_validity) + if (key_validity != -1 && time (NULL) > p->gen_time + key_validity) p->flags |= KEYFLAG_EXPIRED; - if(have_critical_spks) + if (have_critical_spks) p->flags |= KEYFLAG_CRITICAL; return 0; - + } - -static int pgp_parse_sig(unsigned char *buff, size_t l, KEYINFO *p) + +static int pgp_parse_sig (unsigned char *buff, size_t l, pgp_key_t * p) { - if(!buff || l < 2 || !p) + if (!buff || l < 2 || !p) return -1; - - switch(buff[1]) + + switch (buff[1]) { - case 2: - case 3: - return pgp_parse_pgp2_sig(buff, l, p); - case 4: - return pgp_parse_pgp3_sig(buff, l, p); - default: + case 2: + case 3: + return pgp_parse_pgp2_sig (buff, l, p); + case 4: + return pgp_parse_pgp3_sig (buff, l, p); + default: return -1; } } - -static KEYINFO *pgp_read_keyring(const char *fname) +/* parse one key block, including all subkeys. */ + +static pgp_key_t *pgp_parse_keyblock (FILE * fp) { - FILE *fp; unsigned char *buff; unsigned char pt = 0; unsigned char last_pt; size_t l; - KEYINFO *db = NULL, **end, *p = NULL; - KEYINFO *supkey = NULL; - PGPUID *uid = NULL; - LIST **addr = NULL; - CHARSET *chs = mutt_get_charset(Charset); + short err = 0; + + fpos_t pos; - if(!(fp = fopen(fname, "r"))) - { - mutt_perror("fopen"); - return NULL; - - } + pgp_key_t *root = NULL; + pgp_key_t **last = &root; + pgp_key_t *p = NULL; + pgp_uid_t *uid = NULL; + pgp_uid_t **addr = NULL; + + CHARSET *chs = mutt_get_charset (Charset); - end = &db; + fgetpos (fp, &pos); - while((buff = pgp_read_packet(fp, &l)) != NULL) + while (!err && (buff = pgp_read_packet (fp, &l)) != NULL) { last_pt = pt; pt = buff[0] & 0x3f; - if(l < 1) - continue; - - switch(pt) + /* check if we have read the complete key block. */ + + if ((pt == PT_SECKEY || pt == PT_PUBKEY) && root) + { + fsetpos (fp, &pos); + return root; + } + + switch (pt) { case PT_SECKEY: case PT_PUBKEY: case PT_SUBKEY: case PT_SUBSECKEY: { - switch (pt) + if (!(*last = p = pgp_parse_keyinfo (buff, l))) { - case PT_SECKEY: dprint (5, (debugfile, "PT_SECKEY: ")); break; - case PT_PUBKEY: dprint (5, (debugfile, "PT_PUBKEY: ")); break; - case PT_SUBKEY: dprint (5, (debugfile, "PT_SUBKEY: ")); break; - case PT_SUBSECKEY: dprint (5, (debugfile, "PT_SUBSECKEY: ")); break; + err = 1; + break; } - if(p) - end = &(p->next); - - if(!(*end = p = pgp_parse_keyinfo(buff, l))) - break; - - dprint (5, (debugfile, " key-id: %s ", p->keyid)); - + last = &p->next; addr = &p->address; - - if(pt == PT_SUBKEY || pt == PT_SUBSECKEY) + + if (pt == PT_SUBKEY || pt == PT_SUBSECKEY) { p->flags |= KEYFLAG_SUBKEY; - p->mainkey = supkey; + if (p != root) + p->parent = root; } - else - supkey = p; - break; } - + case PT_SIG: { dprint (5, (debugfile, "PT_SIG\n")); - pgp_parse_sig(buff, l, p); + pgp_parse_sig (buff, l, p); break; } + case PT_TRUST: { dprint (5, (debugfile, "PT_TRUST: ")); - if(last_pt == PT_SECKEY || last_pt == PT_PUBKEY || - last_pt == PT_SUBKEY || last_pt == PT_SUBSECKEY) + if (p && (last_pt == PT_SECKEY || last_pt == PT_PUBKEY || + last_pt == PT_SUBKEY || last_pt == PT_SUBSECKEY)) { - if(buff[1] & 0x20) + if (buff[1] & 0x20) { dprint (5, (debugfile, " disabling %s\n", p->keyid)); p->flags |= KEYFLAG_DISABLED; } } - else if(last_pt == PT_NAME) + else if (last_pt == PT_NAME && uid) { uid->trust = buff[1]; - dprint (5, (debugfile, " setting trust for \"%s\" to %d.\n", - uid->addr, uid->trust)); + dprint (5, (debugfile, " setting trust for \"%s\" to %d.\n", + uid->addr, uid->trust)); } break; } @@ -818,94 +932,142 @@ static KEYINFO *pgp_read_keyring(const char *fname) char *chr; dprint (5, (debugfile, "PT_NAME: ")); - - if(!addr) break; - - chr = safe_malloc(l); - memcpy(chr, buff + 1, l - 1); - chr[l-1] = '\0'; - + + if (!addr) + break; + + chr = safe_malloc (l); + memcpy (chr, buff + 1, l - 1); + chr[l - 1] = '\0'; + dprint (5, (debugfile, "\"%s\"\n", chr)); - - mutt_decode_utf8_string(chr, chs); - *addr = mutt_new_list(); - (*addr)->data = safe_malloc(sizeof(PGPUID)); - uid = (PGPUID *) (*addr)->data; + + mutt_decode_utf8_string (chr, chs); + *addr = uid = safe_calloc (sizeof (pgp_uid_t), 1); /* XXX */ uid->addr = chr; + uid->parent = p; uid->trust = 0; - addr = &(*addr)->next; - + addr = &uid->next; + /* the following tags are generated by * pgp 2.6.3in. */ - - if(strstr(chr, "ENCR")) + + if (strstr (chr, "ENCR")) p->flags |= KEYFLAG_PREFER_ENCRYPTION; - if(strstr(chr, "SIGN")) + if (strstr (chr, "SIGN")) p->flags |= KEYFLAG_PREFER_SIGNING; - + break; } } - } - fclose(fp); - -#ifdef DEBUG - if (debuglevel >= 4) - { - KEYINFO *dbp; - LIST *lp; - fprintf (debugfile, "\n\npgp_read_keyring: START KEYRING DUMP.\n"); - - for (dbp = db; dbp; dbp = dbp->next) - { - fprintf (debugfile, "%s [len=%d, flags=%d]\n", dbp->keyid, dbp->keylen, dbp->flags); - for (lp = dbp->address; lp; lp=lp->next) - { - fprintf (debugfile, " %s [%d]\n", ((PGPUID *)lp->data)->addr, - ((PGPUID *)lp->data)->trust); - } - } - - fprintf (debugfile, "\nEND KEYRING DUMP.\n\n"); + fgetpos (fp, &pos); } -#endif + + if (err) + pgp_free_key (&root); - return db; + return root; } -KEYINFO *pgp_read_pubring(struct pgp_vinfo *pgp) +int pgp_string_matches_hint (const char *s, LIST * hints) { - return pgp_read_keyring(NONULL(*pgp->pubring)); -} + if (!hints) + return 1; -KEYINFO *pgp_read_secring(struct pgp_vinfo *pgp) -{ - return pgp_read_keyring(NONULL(*pgp->secring)); + for (; hints; hints = hints->next) + { + if (mutt_stristr (s, (char *) hints->data) != NULL) + return 1; + } + + return 0; } -void pgp_close_keydb (KEYINFO **ki) +/* Go through the key ring file and look for keys with + * matching IDs. + */ + +pgp_key_t *pgp_get_candidates (struct pgp_vinfo * pgp, pgp_ring_t keyring, + LIST * hints) { - KEYINFO *tmp, *k = *ki; - PGPUID *uid; - LIST *p, *q; - - while (k) + char *ringfile; + FILE *rfp; + fpos_t pos, keypos; + + unsigned char *buff = NULL; + unsigned char pt = 0; + size_t l = 0; + + CHARSET *chs = mutt_get_charset (Charset); + + pgp_key_t *keys = NULL; + pgp_key_t **last = &keys; + short err = 0; + + switch (keyring) + { + case PGP_PUBRING: + ringfile = *pgp->pubring; + break; + case PGP_SECRING: + ringfile = *pgp->secring; + break; + default: + return NULL; + } + + if ((rfp = fopen (ringfile, "r")) == NULL) + { + mutt_perror ("fopen"); + return NULL; + } + + fgetpos (rfp, &pos); + fgetpos (rfp, &keypos); + + while (!err && (buff = pgp_read_packet (rfp, &l)) != NULL) { - if (k->keyid) safe_free ((void **)&k->keyid); - for(q = k->address; q; q = p) + pt = buff[0] & 0x3f; + + if (l < 1) + continue; + + if ((pt == PT_SECKEY) || (pt == PT_PUBKEY)) + { + keypos = pos; + } + else if (pt == PT_NAME) { - uid = (PGPUID *) q->data; - p = q->next; + char *tmp = safe_malloc (l); - safe_free((void **)&uid->addr); - safe_free((void **)&q->data); - safe_free((void **)&q); + memcpy (tmp, buff + 1, l - 1); + tmp[l - 1] = '\0'; + mutt_decode_utf8_string (tmp, chs); + + if (pgp_string_matches_hint (tmp, hints)) + { + pgp_key_t *p; + + fsetpos (rfp, &keypos); + + /* Not bailing out here would lead us into an endless loop. */ + + if ((*last = pgp_parse_keyblock (rfp)) == NULL) + err = 1; + + for (p = *last; p; p = p->next) + last = &p->next; + } + + safe_free ((void **) &tmp); } - tmp = k; - k = k->next; - safe_free ((void **)&tmp); + + fgetpos (rfp, &pos); } - *ki = NULL; + + fclose (rfp); + + return keys; } diff --git a/protos.h b/protos.h index ea8240ac..a5d18c66 100644 --- a/protos.h +++ b/protos.h @@ -108,6 +108,8 @@ const char *mutt_attach_fmt ( const char *elsestring, unsigned long data, format_flag flags); +const char *mutt_stristr (const char *, const char *); + char *mutt_charset_hook (const char *); char *mutt_expand_path (char *, size_t); -- 2.49.0