changeset: 6452:aabd030b25cb user: Kevin McCarthy <ke...@8t8.us> date: Sun Jun 07 13:59:19 2015 -0700 link: http://dev.mutt.org/hg/mutt/rev/aabd030b25cb
smime_keys: Add purpose flag to index. A subsequent patch will change smime.c to use the purpose to filter certs and keys that can't be used for signing or encryption. Issuer, trust, and purpose flags were also added to the keys index file, to keep parsing simpler in smime_keys as well as smime.c. The trust and purpose are derived from the cert. Issuer is set to '?' as this should never be needed for keys. changeset: 6453:106914bc9406 user: Kevin McCarthy <ke...@8t8.us> date: Sun Jun 07 13:59:23 2015 -0700 link: http://dev.mutt.org/hg/mutt/rev/106914bc9406 smime_keys: Add refresh command. Refresh verifies the trust of each certificate and adds the purpose flag if it is missing. It pushes those values to the private keys' index file too. changeset: 6454:17a4f92e4a95 user: Kevin McCarthy <ke...@8t8.us> date: Sun Jun 07 13:59:32 2015 -0700 link: http://dev.mutt.org/hg/mutt/rev/17a4f92e4a95 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. diffs (truncated from 1591 to 950 lines): diff -r 0255b37be491 -r 17a4f92e4a95 smime.c --- a/smime.c Mon May 25 10:59:50 2015 -0700 +++ b/smime.c Sun Jun 07 13:59:32 2015 -0700 @@ -63,16 +63,6 @@ }; -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? */ @@ -82,6 +72,45 @@ 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. */ @@ -306,18 +335,32 @@ */ +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; @@ -339,300 +382,382 @@ 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. @@ -640,25 +765,28 @@ 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 (); @@ -672,7 +800,7 @@ if (mutt_strcasecmp (k, SmimeDefaultKey)) smime_void_passphrase (); - FREE (&k); + smime_free_key (&key); return; } @@ -735,6 +863,7 @@ 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; @@ -746,15 +875,15 @@ 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); @@ -762,11 +891,13 @@ 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); } @@ -1342,29 +1473,21 @@ 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; } @@ -1374,8 +1497,6 @@ mutt_perror (signedfile); safe_fclose (&sfp); mutt_unlink (filetosign); - if (intermediates != SmimeDefaultKey) - FREE (&intermediates); return NULL; } @@ -1392,8 +1513,17 @@ 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); @@ -1404,8 +1534,6 @@ safe_fclose (&smimeout); mutt_unlink (signedfile); mutt_unlink (filetosign); - if (intermediates != SmimeDefaultKey) - FREE (&intermediates); return NULL; } fputs (SmimePass, smimein); @@ -1907,7 +2035,7 @@ int smime_send_menu (HEADER *msg, int *redraw) { - char *p; + smime_key_t *key; char *prompt, *letters, *choices; int choice; @@ -2031,8 +2159,11 @@ { *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; } @@ -2043,9 +2174,10 @@ 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);