diff options
author | Thomas Roessler <roessler@does-not-exist.org> | 1999-01-22 15:24:58 +0000 |
---|---|---|
committer | Thomas Roessler <roessler@does-not-exist.org> | 1999-01-22 15:24:58 +0000 |
commit | 1b3511a6a1bd35dbaa29b5aba2bac8e4089b3f67 (patch) | |
tree | 25faff13721c7017901130514378ae96b19c77fe /pgppubring.c | |
parent | 4a933a52f58b27f86dfc4e587d65424d524f60d5 (diff) |
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.
Diffstat (limited to 'pgppubring.c')
-rw-r--r-- | pgppubring.c | 1016 |
1 files changed, 589 insertions, 427 deletions
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 <stdio.h> @@ -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) |