This is "part 3" of the S/MIME purpose flag addition. The patch is actually a rewrite of the searching in smime.c, though, so testing and feedback are appreciated.
If you test it, please run 'smime_keys refresh' to generate index files with the purpose flag. (You may, of course, also test it against old-style index files too.). I found it helpful to enable opportunistic encryption during testing: set crypt_opportunistic_encrypt This allows you to see it matching or failing to match against certs without encryption ability. Correspondingly, selecting "sign (a)s" in the S/MIME send menu allows searching for keys, which should also be filtered by purpose. -Kevin
# HG changeset patch # User Kevin McCarthy <[email protected]> # Date 1433107606 25200 # Sun May 31 14:26:46 2015 -0700 # Node ID 1c47a13d7e9b2f6213bbc4dc0946fadeb47c8bfe # Parent e5e2b5b33e31c689c978bd6d0812c52d65032666 Rewrite S/MIME key searching. Add purpose checking. Model the smime.c searching off of classic pgp searching. Create smime_get_key_by_hash()/addr()/str() functions that use a single smime_get_candidates() function to search the index. Use the new smime_keys generated purpose flag in the index to filter by KEYFLAG_CANENCRYPT and KEYFLAG_CANSIGN. Old style indices fall back to all-inclusive behavior. diff --git a/smime.c b/smime.c --- a/smime.c +++ b/smime.c @@ -58,35 +58,64 @@ const char *cryptalg; /* %a */ const char *fname; /* %f */ const char *sig_fname; /* %s */ const char *certificates; /* %c */ const char *intermediates; /* %i */ }; -typedef struct { - unsigned int hash; - char suffix; - char email[256]; - char nick[256]; - char trust; /* i=Invalid r=revoked e=expired u=unverified v=verified t=trusted */ - short public; /* 1=public 0=private */ -} smime_id; - - char SmimePass[STRING]; time_t SmimeExptime = 0; /* when does the cached passphrase expire? */ static char SmimeKeyToUse[_POSIX_PATH_MAX] = { 0 }; static char SmimeCertToUse[_POSIX_PATH_MAX]; static char SmimeIntermediateToUse[_POSIX_PATH_MAX]; +void smime_free_key (smime_key_t **keylist) +{ + smime_key_t *key; + + if (!keylist) + return; + + while (*keylist) + { + key = *keylist; + *keylist = (*keylist)->next; + + FREE (&key->email); + FREE (&key->hash); + FREE (&key->label); + FREE (&key->issuer); + FREE (&key); + } +} + +static smime_key_t *smime_copy_key (smime_key_t *key) +{ + smime_key_t *copy; + + if (!key) + return NULL; + + copy = safe_calloc (sizeof (smime_key_t), 1); + copy->email = safe_strdup(key->email); + copy->hash = safe_strdup(key->hash); + copy->label = safe_strdup(key->label); + copy->issuer = safe_strdup(key->issuer); + copy->trust = key->trust; + copy->flags = key->flags; + + return copy; +} + + /* * Queries and passphrase handling. */ /* these are copies from pgp.c */ @@ -301,28 +330,42 @@ /* * Key and certificate handling. */ +static char *smime_key_flags (int flags) +{ + static char buff[3]; -/* - Search the certificate index for given mailbox. - return certificate file name. -*/ + if (!(flags & KEYFLAG_CANENCRYPT)) + buff[0] = '-'; + else + buff[0] = 'e'; + + if (!(flags & KEYFLAG_CANSIGN)) + buff[1] = '-'; + else + buff[1] = 's'; + + buff[2] = '\0'; + + return buff; +} + static void smime_entry (char *s, size_t l, MUTTMENU * menu, int num) { - smime_id *Table = (smime_id*) menu->data; - smime_id this = Table[num]; + smime_key_t **Table = (smime_key_t **) menu->data; + smime_key_t *this = Table[num]; char* truststate; - switch(this.trust) { + switch(this->trust) { case 't': truststate = N_("Trusted "); break; case 'v': truststate = N_("Verified "); break; case 'u': truststate = N_("Unverified"); @@ -334,350 +377,435 @@ truststate = N_("Revoked "); break; case 'i': truststate = N_("Invalid "); break; default: truststate = N_("Unknown "); } - if (this.public) - snprintf(s, l, " 0x%.8X.%i %s %-35.35s %s", this.hash, this.suffix, truststate, this.email, this.nick); - else - snprintf(s, l, " 0x%.8X.%i %-35.35s %s", this.hash, this.suffix, this.email, this.nick); + snprintf(s, l, " 0x%s %s %s %-35.35s %s", this->hash, + smime_key_flags (this->flags), truststate, this->email, this->label); } +static smime_key_t *smime_select_key (smime_key_t *keys, char *query) +{ + smime_key_t **table = NULL; + int table_size = 0; + int table_index = 0; + smime_key_t *key = NULL; + smime_key_t *selected_key = NULL; + char helpstr[LONG_STRING]; + char buf[LONG_STRING]; + char title[256]; + MUTTMENU* menu; + char *s = ""; + int done = 0; + for (table_index = 0, key = keys; key; key = key->next) + { + if (table_index == table_size) + { + table_size += 5; + safe_realloc (&table, sizeof (smime_key_t *) * table_size); + } + table[table_index++] = key; + } -char* smime_ask_for_key (char *prompt, char *mailbox, short public) + snprintf(title, sizeof(title), _("S/MIME certificates matching \"%s\"."), + query); + + /* Make Helpstring */ + helpstr[0] = 0; + mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_SMIME, OP_EXIT); + strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ + mutt_make_help (buf, sizeof (buf), _("Select "), MENU_SMIME, + OP_GENERIC_SELECT_ENTRY); + strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ + mutt_make_help (buf, sizeof(buf), _("Help"), MENU_SMIME, OP_HELP); + strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ + + /* Create the menu */ + menu = mutt_new_menu(MENU_SMIME); + menu->max = table_index; + menu->make_entry = smime_entry; + menu->help = helpstr; + menu->data = table; + menu->title = title; + /* sorting keys might be done later - TODO */ + + mutt_clear_error(); + + done = 0; + while (!done) + { + switch (mutt_menuLoop (menu)) + { + case OP_GENERIC_SELECT_ENTRY: + if (table[menu->current]->trust != 't') + { + switch (table[menu->current]->trust) + { + case 'i': + case 'r': + case 'e': + s = N_("ID is expired/disabled/revoked."); + break; + case 'u': + s = N_("ID has undefined validity."); + break; + case 'v': + s = N_("ID is not trusted."); + break; + } + + snprintf (buf, sizeof (buf), _("%s Do you really want to use the key?"), + _(s)); + + if (mutt_yesorno (buf, M_NO) != M_YES) + { + mutt_clear_error (); + break; + } + } + + selected_key = table[menu->current]; + done = 1; + break; + case OP_EXIT: + done = 1; + break; + } + } + + mutt_menuDestroy (&menu); + FREE (&table); + set_option (OPTNEEDREDRAW); + + return selected_key; +} + +static smime_key_t *smime_parse_key(char *buf) { - char *fname; - smime_id *table = 0; - int table_count; + smime_key_t *key; + char *pend, *p; + int field = 0; + + key = safe_calloc (sizeof (smime_key_t), 1); + + for (p = buf; p; p = pend) + { + if ((pend = strchr (p, ' ')) || (pend = strchr (p, '\n'))) + *pend++ = 0; + + /* For backward compatibility, don't count consecutive delimiters + * as an empty field. + */ + if (!*p) + continue; + + field++; + + switch (field) + { + case 1: /* mailbox */ + key->email = safe_strdup (p); + break; + case 2: /* hash */ + key->hash = safe_strdup (p); + break; + case 3: /* label */ + key->label = safe_strdup (p); + break; + case 4: /* issuer */ + key->issuer = safe_strdup (p); + break; + case 5: /* trust */ + key->trust = *p; + break; + case 6: /* purpose */ + while (*p) + { + switch (*p++) + { + case 'e': + key->flags |= KEYFLAG_CANENCRYPT; + break; + + case 's': + key->flags |= KEYFLAG_CANSIGN; + break; + } + } + break; + } + } + + /* Old index files could be missing issuer, trust, and purpose, + * but anything less than that is an error. */ + if (field < 3) + { + smime_free_key (&key); + return NULL; + } + + if (field < 4) + key->issuer = safe_strdup ("?"); + + if (field < 5) + key->trust = 't'; + + if (field < 6) + key->flags = (KEYFLAG_CANENCRYPT | KEYFLAG_CANSIGN); + + return key; +} + +static smime_key_t *smime_get_candidates(char *search, short public) +{ char index_file[_POSIX_PATH_MAX]; - FILE *index; + FILE *fp; char buf[LONG_STRING]; - char fields[5][STRING+1]; /* +1 due to use of fscanf() below. the max field width does not include the null terminator (see http://dev.mutt.org/trac/ticket/3636) */ - int numFields, hash_suffix, done, cur; /* The current entry */ - MUTTMENU* menu; - unsigned int hash; - char helpstr[HUGE_STRING*3]; - char qry[256]; - char title[256]; + smime_key_t *key, *results, **results_end; + + results = NULL; + results_end = &results; + + snprintf(index_file, sizeof (index_file), "%s/.index", + public ? NONULL(SmimeCertificates) : NONULL(SmimeKeys)); + + if ((fp = safe_fopen (index_file, "r")) == NULL) + { + mutt_perror (index_file); + return NULL; + } + + while (fgets (buf, sizeof (buf), fp)) + { + if ((! *search) || mutt_stristr (buf, search)) + { + key = smime_parse_key (buf); + if (key) + { + *results_end = key; + results_end = &key->next; + } + } + } + + safe_fclose (&fp); + + return results; +} + +/* Returns the first matching key record, without prompting or checking of + * abilities or trust. + */ +static smime_key_t *smime_get_key_by_hash(char *hash, short public) +{ + smime_key_t *results, *result; + smime_key_t *match = NULL; + + results = smime_get_candidates(hash, public); + for (result = results; result; result = result->next) + { + if (mutt_strcasecmp (hash, result->hash) == 0) + { + match = smime_copy_key (result); + break; + } + } + + smime_free_key (&results); + + return match; +} + +static smime_key_t *smime_get_key_by_addr(char *mailbox, short abilities, short public, short may_ask) +{ + smime_key_t *results, *result; + smime_key_t *matches = NULL; + smime_key_t **matches_end = &matches; + smime_key_t *match; + smime_key_t *trusted_match = NULL; + smime_key_t *valid_match = NULL; + smime_key_t *return_key = NULL; + int multi_trusted_matches = 0; + + if (! mailbox) + return NULL; + + results = smime_get_candidates(mailbox, public); + for (result = results; result; result = result->next) + { + if (abilities && !(result->flags & abilities)) + { + continue; + } + + if (mutt_strcasecmp (mailbox, result->email) == 0) + { + match = smime_copy_key (result); + *matches_end = match; + matches_end = &match->next; + + if (match->trust == 't') + { + if (trusted_match && + (mutt_strcasecmp (match->hash, trusted_match->hash) != 0)) + { + multi_trusted_matches = 1; + } + trusted_match = match; + } + else if ((match->trust == 'u') || (match->trust == 'v')) + { + valid_match = match; + } + } + } + + smime_free_key (&results); + + if (matches) + { + if (! may_ask) + { + if (trusted_match) + return_key = smime_copy_key (trusted_match); + else if (valid_match) + return_key = smime_copy_key (valid_match); + else + return_key = NULL; + } + else if (trusted_match && !multi_trusted_matches) + { + return_key = smime_copy_key (trusted_match); + } + else + { + return_key = smime_copy_key (smime_select_key (matches, mailbox)); + } + + smime_free_key (&matches); + } + + return return_key; +} + +static smime_key_t *smime_get_key_by_str(char *str, short abilities, short public) +{ + smime_key_t *results, *result; + smime_key_t *matches = NULL; + smime_key_t **matches_end = &matches; + smime_key_t *match; + smime_key_t *return_key = NULL; + + if (! str) + return NULL; + + results = smime_get_candidates(str, public); + for (result = results; result; result = result->next) + { + if (abilities && !(result->flags & abilities)) + { + continue; + } + + if ((mutt_strcasecmp (str, result->hash) == 0) || + mutt_stristr(result->email, str) || + mutt_stristr(result->label, str)) + { + match = smime_copy_key (result); + *matches_end = match; + matches_end = &match->next; + } + } + + smime_free_key (&results); + + if (matches) + { + return_key = smime_copy_key (smime_select_key (matches, str)); + smime_free_key (&matches); + } + + return return_key; +} + + +smime_key_t *smime_ask_for_key(char *prompt, short abilities, short public) +{ + smime_key_t *key; + char resp[SHORT_STRING]; if (!prompt) prompt = _("Enter keyID: "); - snprintf(index_file, sizeof (index_file), "%s/.index", - public ? NONULL(SmimeCertificates) : NONULL(SmimeKeys)); - + + mutt_clear_error (); + FOREVER { - *qry = 0; - if (mutt_get_field(prompt, - qry, sizeof(qry), 0)) + resp[0] = 0; + if (mutt_get_field (prompt, resp, sizeof (resp), M_CLEAR) != 0) return NULL; - snprintf(title, sizeof(title), _("S/MIME certificates matching \"%s\"."), - qry); - - index = fopen(index_file, "r"); - if (index == NULL) - { - mutt_perror (index_file); - return NULL; - } - /* Read Entries */ - cur = 0; - table_count = 0; - while (!feof(index)) { - numFields = fscanf (index, MUTT_FORMAT(STRING) " %x.%i " MUTT_FORMAT(STRING), fields[0], &hash, - &hash_suffix, fields[2]); - if (public) - fscanf (index, MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) "\n", fields[3], fields[4]); - - /* 0=email 1=name 2=nick 3=intermediate 4=trust */ - if (numFields < 2) continue; - - /* Check if query matches this certificate */ - if (!mutt_stristr(fields[0], qry) && - !mutt_stristr(fields[2], qry)) - continue; - - ++table_count; - safe_realloc(&table, sizeof(smime_id) * table_count); - table[cur].hash = hash; - table[cur].suffix = hash_suffix; - strncpy(table[cur].email, fields[0], sizeof(table[cur].email)); - strncpy(table[cur].nick, fields[2], sizeof(table[cur].nick)); - table[cur].trust = *fields[4]; - table[cur].public = public; - - cur++; - } - safe_fclose (&index); - - /* Make Helpstring */ - helpstr[0] = 0; - mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_SMIME, OP_EXIT); - strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ - mutt_make_help (buf, sizeof (buf), _("Select "), MENU_SMIME, - OP_GENERIC_SELECT_ENTRY); - strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ - mutt_make_help (buf, sizeof(buf), _("Help"), MENU_SMIME, OP_HELP); - strcat (helpstr, buf); /* __STRCAT_CHECKED__ */ - - /* Create the menu */ - menu = mutt_new_menu(MENU_SMIME); - menu->max = cur; - menu->make_entry = smime_entry; - menu->help = helpstr; - menu->data = table; - menu->title = title; - /* sorting keys might be done later - TODO */ - - mutt_clear_error(); - - done = 0; - hash = 0; - while (!done) { - switch (mutt_menuLoop (menu)) { - case OP_GENERIC_SELECT_ENTRY: - cur = menu->current; - hash = 1; - done = 1; - break; - case OP_EXIT: - hash = 0; - done = 1; - break; - } - } - if (table_count && hash) - safe_asprintf(&fname, "%.8x.%i", table[cur].hash, table[cur].suffix); - else fname = NULL; - - mutt_menuDestroy (&menu); - FREE (&table); - set_option (OPTNEEDREDRAW); - - if (fname) return fname; + if ((key = smime_get_key_by_str (resp, abilities, public))) + return key; + + BEEP (); } } -char *smime_get_field_from_db (char *mailbox, char *query, short public, short may_ask) -{ - int addr_len, query_len, found = 0, ask = 0, choice = 0; - char cert_path[_POSIX_PATH_MAX]; - char buf[LONG_STRING], prompt[STRING]; - char fields[5][STRING+1]; /* +1 due to use of fscanf() below. the max field width does not include the null terminator (see http://dev.mutt.org/trac/ticket/3636) */ - char key[STRING]; - int numFields; - struct stat info; - char key_trust_level = 0; - FILE *fp; - - if(!mailbox && !query) return(NULL); - - addr_len = mailbox ? mutt_strlen (mailbox) : 0; - query_len = query ? mutt_strlen (query) : 0; - - *key = '\0'; - - /* index-file format: - mailbox certfile label issuer_certfile trust_flags\n - - certfile is a hash value generated by openssl. - Note that this was done according to the OpenSSL - specs on their CA-directory. - - */ - snprintf (cert_path, sizeof (cert_path), "%s/.index", - (public ? NONULL(SmimeCertificates) : NONULL(SmimeKeys))); - - if (!stat (cert_path, &info)) - { - if ((fp = safe_fopen (cert_path, "r")) == NULL) - { - mutt_perror (cert_path); - return (NULL); - } - - while (fgets (buf, sizeof (buf) - 1, fp) != NULL) - if (mailbox && !(mutt_strncasecmp (mailbox, buf, addr_len))) - { - numFields = sscanf (buf, - MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) " " - MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) " " - MUTT_FORMAT(STRING) "\n", - fields[0], fields[1], - fields[2], fields[3], - fields[4]); - if (numFields < 2) - continue; - if (mailbox && public && - (*fields[4] == 'i' || *fields[4] == 'e' || *fields[4] == 'r')) - continue; - - if (found) - { - if (public && *fields[4] == 'u' ) - snprintf (prompt, sizeof (prompt), - _("ID %s is unverified. Do you want to use it for %s ?"), - fields[1], mailbox); - else if (public && *fields[4] == 'v' ) - snprintf (prompt, sizeof (prompt), - _("Use (untrusted!) ID %s for %s ?"), - fields[1], mailbox); - else - snprintf (prompt, sizeof (prompt), _("Use ID %s for %s ?"), - fields[1], mailbox); - if (may_ask == 0) - choice = M_YES; - if (may_ask && (choice = mutt_yesorno (prompt, M_NO)) == -1) - { - found = 0; - ask = 0; - *key = '\0'; - break; - } - else if (choice == M_NO) - { - ask = 1; - continue; - } - else if (choice == M_YES) - { - strfcpy (key, fields[1], sizeof (key)); - ask = 0; - break; - } - } - else - { - if (public) - key_trust_level = *fields[4]; - strfcpy (key, fields[1], sizeof (key)); - } - found = 1; - } - else if(query) - { - numFields = sscanf (buf, - MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) " " - MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) " " - MUTT_FORMAT(STRING) "\n", - fields[0], fields[1], - fields[2], fields[3], - fields[4]); - - /* query = label: return certificate. */ - if (numFields >= 3 && - !(mutt_strncasecmp (query, fields[2], query_len))) - { - ask = 0; - strfcpy (key, fields[1], sizeof (key)); - } - /* query = certificate: return intermediate certificate. */ - else if (numFields >= 4 && - !(mutt_strncasecmp (query, fields[1], query_len))) - { - ask = 0; - strfcpy (key, fields[3], sizeof (key)); - } - } - - safe_fclose (&fp); - - if (ask) - { - if (public && *fields[4] == 'u' ) - snprintf (prompt, sizeof (prompt), - _("ID %s is unverified. Do you want to use it for %s ?"), - fields[1], mailbox); - else if (public && *fields[4] == 'v' ) - snprintf (prompt, sizeof (prompt), - _("Use (untrusted!) ID %s for %s ?"), - fields[1], mailbox); - else - snprintf (prompt, sizeof(prompt), _("Use ID %s for %s ?"), key, - mailbox); - choice = mutt_yesorno (prompt, M_NO); - if (choice == -1 || choice == M_NO) - *key = '\0'; - } - else if (key_trust_level && may_ask) - { - if (key_trust_level == 'u' ) - { - snprintf (prompt, sizeof (prompt), - _("ID %s is unverified. Do you want to use it for %s ?"), - key, mailbox); - choice = mutt_yesorno (prompt, M_NO); - if (choice != M_YES) - *key = '\0'; - } - else if (key_trust_level == 'v' ) - { - mutt_error (_("Warning: You have not yet decided to trust ID %s. (any key to continue)"), key); - mutt_sleep (5); - } - } - - } - - /* Note: safe_strdup ("") returns NULL. */ - return safe_strdup (key); -} - - - - /* This sets the '*ToUse' variables for an upcoming decryption, where the required key is different from SmimeDefaultKey. */ void _smime_getkeys (char *mailbox) { + smime_key_t *key = NULL; char *k = NULL; char buf[STRING]; - k = smime_get_field_from_db (mailbox, NULL, 0, 1); + key = smime_get_key_by_addr (mailbox, KEYFLAG_CANENCRYPT, 0, 1); - if (!k) + if (!key) { snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), mailbox); - k = smime_ask_for_key(buf, mailbox, 0); + key = smime_ask_for_key (buf, KEYFLAG_CANENCRYPT, 0); } - if (k) + if (key) { + k = key->hash; + /* the key used last time. */ if (*SmimeKeyToUse && !mutt_strcasecmp (k, SmimeKeyToUse + mutt_strlen (SmimeKeys)+1)) { - FREE (&k); + smime_free_key (&key); return; } else smime_void_passphrase (); snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s", NONULL(SmimeKeys), k); snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s", NONULL(SmimeCertificates), k); if (mutt_strcasecmp (k, SmimeDefaultKey)) smime_void_passphrase (); - FREE (&k); + smime_free_key (&key); return; } if (*SmimeKeyToUse) { if (!mutt_strcasecmp (SmimeDefaultKey, SmimeKeyToUse + mutt_strlen (SmimeKeys)+1)) return; @@ -730,48 +858,51 @@ /* This routine attempts to find the keyids of the recipients of a message. * It returns NULL if any of the keys can not be found. * If oppenc_mode is true, only keys that can be determined without * prompting will be used. */ char *smime_findKeys (ADDRESS *adrlist, int oppenc_mode) { + smime_key_t *key = NULL; char *keyID, *keylist = NULL; size_t keylist_size = 0; size_t keylist_used = 0; ADDRESS *p, *q; for (p = adrlist; p ; p = p->next) { char buf[LONG_STRING]; q = p; - keyID = smime_get_field_from_db (q->mailbox, NULL, 1, !oppenc_mode); - if ((keyID == NULL) && (! oppenc_mode)) + key = smime_get_key_by_addr (q->mailbox, KEYFLAG_CANENCRYPT, 1, !oppenc_mode); + if ((key == NULL) && (! oppenc_mode)) { snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), q->mailbox); - keyID = smime_ask_for_key(buf, q->mailbox, 1); + key = smime_ask_for_key (buf, KEYFLAG_CANENCRYPT, 1); } - if(!keyID) + if (!key) { if (! oppenc_mode) mutt_message (_("No (valid) certificate found for %s."), q->mailbox); FREE (&keylist); return NULL; } + keyID = key->hash; keylist_size += mutt_strlen (keyID) + 2; safe_realloc (&keylist, keylist_size); sprintf (keylist + keylist_used, "%s\n", keyID); /* __SPRINTF_CHECKED__ */ keylist_used = mutt_strlen (keylist); + smime_free_key (&key); } return (keylist); } @@ -1337,80 +1468,77 @@ { BODY *t; char buffer[LONG_STRING]; char signedfile[_POSIX_PATH_MAX], filetosign[_POSIX_PATH_MAX]; FILE *smimein = NULL, *smimeout = NULL, *smimeerr = NULL, *sfp = NULL; int err = 0; int empty = 0; pid_t thepid; - char *intermediates = smime_get_field_from_db(NULL, SmimeDefaultKey, 1, 1); + smime_key_t *default_key; + char *intermediates; if (!SmimeDefaultKey) { mutt_error _("Can't sign: No key specified. Use Sign As."); - FREE (&intermediates); return NULL; } - if (!intermediates) - { - mutt_message(_("Warning: Intermediate certificate not found.")); - intermediates = SmimeDefaultKey; /* so openssl won't complain in any case */ - } - convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */ mutt_mktemp (filetosign, sizeof (filetosign)); if ((sfp = safe_fopen (filetosign, "w+")) == NULL) { mutt_perror (filetosign); - if (intermediates != SmimeDefaultKey) - FREE (&intermediates); return NULL; } mutt_mktemp (signedfile, sizeof (signedfile)); if ((smimeout = safe_fopen (signedfile, "w+")) == NULL) { mutt_perror (signedfile); safe_fclose (&sfp); mutt_unlink (filetosign); - if (intermediates != SmimeDefaultKey) - FREE (&intermediates); return NULL; } mutt_write_mime_header (a, sfp); fputc ('\n', sfp); mutt_write_mime_body (a, sfp); safe_fclose (&sfp); snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s", NONULL(SmimeKeys), SmimeDefaultKey); snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s", NONULL(SmimeCertificates), SmimeDefaultKey); + default_key = smime_get_key_by_hash (SmimeDefaultKey, 1); + if ((! default_key) || + (! mutt_strcmp ("?", default_key->issuer))) + intermediates = SmimeDefaultKey; /* so openssl won't complain in any case */ + else + intermediates = default_key->issuer; + snprintf (SmimeIntermediateToUse, sizeof (SmimeIntermediateToUse), "%s/%s", NONULL(SmimeCertificates), intermediates); + + smime_free_key (&default_key); if ((thepid = smime_invoke_sign (&smimein, NULL, &smimeerr, -1, fileno (smimeout), -1, filetosign)) == -1) { mutt_perror _("Can't open OpenSSL subprocess!"); safe_fclose (&smimeout); mutt_unlink (signedfile); mutt_unlink (filetosign); - if (intermediates != SmimeDefaultKey) - FREE (&intermediates); return NULL; } fputs (SmimePass, smimein); fputc ('\n', smimein); safe_fclose (&smimein); mutt_wait_filter (thepid); @@ -1902,17 +2030,17 @@ int smime_application_smime_handler (BODY *m, STATE *s) { return smime_handle_entity (m, s, NULL) ? 0 : -1; } int smime_send_menu (HEADER *msg, int *redraw) { - char *p; + smime_key_t *key; char *prompt, *letters, *choices; int choice; if (!(WithCrypto & APPLICATION_SMIME)) return msg->security; msg->security |= APPLICATION_SMIME; @@ -2026,31 +2154,35 @@ break; case 's': /* (s)ign */ case 'S': /* (s)ign in oppenc mode */ if(!SmimeDefaultKey) { *redraw = REDRAW_FULL; - if ((p = smime_ask_for_key (_("Sign as: "), NULL, 0))) - mutt_str_replace (&SmimeDefaultKey, p); + if ((key = smime_ask_for_key (_("Sign as: "), KEYFLAG_CANSIGN, 0))) + { + mutt_str_replace (&SmimeDefaultKey, key->hash); + smime_free_key (&key); + } else break; } if (choices[choice - 1] == 's') msg->security &= ~ENCRYPT; msg->security |= SIGN; break; case 'a': /* sign (a)s */ - if ((p = smime_ask_for_key (_("Sign as: "), NULL, 0))) + if ((key = smime_ask_for_key (_("Sign as: "), KEYFLAG_CANSIGN, 0))) { - mutt_str_replace (&SmimeDefaultKey, p); + mutt_str_replace (&SmimeDefaultKey, key->hash); + smime_free_key (&key); msg->security |= SIGN; /* probably need a different passphrase */ crypt_smime_void_passphrase (); } *redraw = REDRAW_FULL; diff --git a/smime.h b/smime.h --- a/smime.h +++ b/smime.h @@ -17,19 +17,28 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef CRYPT_BACKEND_CLASSIC_SMIME #include "mutt_crypt.h" +typedef struct smime_key { + char *email; + char *hash; + char *label; + char *issuer; + char trust; /* i=Invalid r=revoked e=expired u=unverified v=verified t=trusted */ + int flags; + struct smime_key *next; +} smime_key_t; - +void smime_free_key (smime_key_t **); void smime_void_passphrase (void); int smime_valid_passphrase (void); int smime_decrypt_mime (FILE *, FILE **, BODY *, BODY **); int smime_application_smime_handler (BODY *, STATE *); @@ -43,17 +52,17 @@ int smime_verify_sender(HEADER *); char* smime_get_field_from_db (char *, char *, short, short); void smime_getkeys (ENVELOPE *); -char* smime_ask_for_key (char *, char *, short); +smime_key_t *smime_ask_for_key(char *, short, short); char *smime_findKeys (ADDRESS *adrlist, int oppenc_mode); void smime_invoke_import (char *, char *); int smime_send_menu (HEADER *msg, int *redraw); #endif
signature.asc
Description: PGP signature
