NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
smime.c File Reference

SMIME helper routines. More...

#include "config.h"
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "lib.h"
#include "editor/lib.h"
#include "expando/lib.h"
#include "history/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "crypt.h"
#include "cryptglue.h"
#include "expando_smime.h"
#include "module_data.h"
#include "mutt_logging.h"
#include "smime.h"
+ Include dependency graph for smime.c:

Go to the source code of this file.

Functions

void smime_init (void)
 Initialise smime globals.
 
void smime_cleanup (struct NcryptModuleData *mod_data)
 Clean up smime globals.
 
static void smime_key_free (struct SmimeKey **keylist)
 Free a list of SMIME keys.
 
static struct SmimeKeysmime_copy_key (struct SmimeKey *key)
 Copy an SMIME key.
 
void smime_class_void_passphrase (void)
 Forget the cached passphrase - Implements CryptModuleSpecs::void_passphrase() -.
 
bool smime_class_valid_passphrase (void)
 Ensure we have a valid passphrase - Implements CryptModuleSpecs::valid_passphrase() -.
 
static void smime_command (struct Buffer *buf, struct SmimeCommandContext *cctx, const struct Expando *exp)
 Format an SMIME command string.
 
static pid_t smime_invoke (FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, const char *cryptalg, const char *digestalg, const char *key, const char *certificates, const char *intermediates, const struct Expando *exp)
 Run an SMIME command.
 
static struct SmimeKeysmime_parse_key (char *buf)
 Parse an SMIME key block.
 
static struct SmimeKeysmime_get_candidates (const char *search, bool only_public_key)
 Find keys matching a string.
 
static struct SmimeKeysmime_get_key_by_hash (const char *hash, bool only_public_key)
 Find a key by its hash.
 
static struct SmimeKeysmime_get_key_by_addr (const char *mailbox, KeyFlags abilities, bool only_public_key, bool oppenc_mode)
 Find an SIME key by address.
 
static struct SmimeKeysmime_get_key_by_str (const char *str, KeyFlags abilities, bool only_public_key)
 Find an SMIME key by string.
 
static struct SmimeKeysmime_ask_for_key (const char *prompt, KeyFlags abilities, bool only_public_key)
 Ask the user to select a key.
 
static void getkeys (const char *mailbox)
 Get the keys for a mailbox.
 
void smime_class_getkeys (struct Envelope *env)
 Get the S/MIME keys required to encrypt this email - Implements CryptModuleSpecs::smime_getkeys() -.
 
char * smime_class_find_keys (const struct AddressList *al, bool oppenc_mode)
 Find the keyids of the recipients of a message - Implements CryptModuleSpecs::find_keys() -.
 
static int smime_handle_cert_email (const char *certificate, const char *mailbox, bool copy, char ***buffer, int *num)
 Process an email containing certificates.
 
static char * smime_extract_certificate (const char *infile)
 Extract an SMIME certificate from a file.
 
static char * smime_extract_signer_certificate (const char *infile)
 Extract the signer's certificate.
 
void smime_class_invoke_import (const char *infile, const char *mailbox)
 Add a certificate and update index file (externally) - Implements CryptModuleSpecs::smime_invoke_import() -.
 
int smime_class_verify_sender (struct Email *e, struct Message *msg)
 Does the sender match the certificate?
 
static pid_t smime_invoke_encrypt (FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *uids)
 Use SMIME to encrypt a file.
 
static pid_t smime_invoke_sign (FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname)
 Use SMIME to sign a file.
 
struct Bodysmime_class_build_smime_entity (struct Body *b, char *certlist)
 Encrypt the email body to all recipients - Implements CryptModuleSpecs::smime_build_smime_entity() -.
 
static char * openssl_md_to_smime_micalg (const char *md)
 Change the algorithm names.
 
struct Bodysmime_class_sign_message (struct Body *b, const struct AddressList *from)
 Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
 
static pid_t smime_invoke_verify (FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, int opaque)
 Use SMIME to verify a file.
 
static pid_t smime_invoke_decrypt (FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname)
 Use SMIME to decrypt a file.
 
int smime_class_verify_one (struct Body *b, struct State *state, const char *tempfile)
 Check a signed MIME part against a signature - Implements CryptModuleSpecs::verify_one() -.
 
static struct Bodysmime_handle_entity (struct Body *b, struct State *state, FILE *fp_out_file)
 Handle type application/pkcs7-mime.
 
int smime_class_decrypt_mime (FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
 Decrypt an encrypted MIME part - Implements CryptModuleSpecs::decrypt_mime() -.
 
int smime_class_application_handler (struct Body *b, struct State *state)
 Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::application_handler() -.
 
SecurityFlags smime_class_send_menu (struct Email *e)
 Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
 

Detailed Description

SMIME helper routines.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Lars Haalck
  • Anna Figueiredo Gomes
  • Alejandro Colomar
  • Tóth János

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, see http://www.gnu.org/licenses/.

Definition in file smime.c.

Function Documentation

◆ smime_init()

void smime_init ( void )

Initialise smime globals.

Definition at line 68 of file smime.c.

69{
71 buf_alloc(&mod_data->smime_key_to_use, 256);
72 buf_alloc(&mod_data->smime_cert_to_use, 256);
73 buf_alloc(&mod_data->smime_intermediate_to_use, 256);
74}
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:342
@ MODULE_ID_NCRYPT
ModuleNcrypt, Ncrypt
Definition module_api.h:82
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
Ncrypt private Module data.
Definition module_data.h:39
struct Buffer smime_cert_to_use
S/MIME certificate to use.
Definition module_data.h:59
struct Buffer smime_intermediate_to_use
S/MIME intermediate certificate to use.
Definition module_data.h:60
struct Buffer smime_key_to_use
S/MIME key to use.
Definition module_data.h:58
Container for Accounts, Notifications.
Definition neomutt.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_cleanup()

void smime_cleanup ( struct NcryptModuleData * mod_data)

Clean up smime globals.

Parameters
mod_dataNcrypt module data

Definition at line 80 of file smime.c.

81{
82 buf_dealloc(&mod_data->smime_key_to_use);
85}
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition buffer.c:383
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_key_free()

static void smime_key_free ( struct SmimeKey ** keylist)
static

Free a list of SMIME keys.

Parameters
[out]keylistList of keys to free

Definition at line 91 of file smime.c.

92{
93 if (!keylist)
94 return;
95
96 struct SmimeKey *key = NULL;
97
98 while (*keylist)
99 {
100 key = *keylist;
101 *keylist = (*keylist)->next;
102
103 FREE(&key->email);
104 FREE(&key->hash);
105 FREE(&key->label);
106 FREE(&key->issuer);
107 FREE(&key);
108 }
109}
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
An SIME key.
Definition smime.h:43
char * hash
Key hash.
Definition smime.h:45
struct SmimeKey * next
Linked list.
Definition smime.h:50
char * issuer
Key issuer.
Definition smime.h:47
char * email
Email address.
Definition smime.h:44
char * label
Key label.
Definition smime.h:46
+ Here is the caller graph for this function:

◆ smime_copy_key()

static struct SmimeKey * smime_copy_key ( struct SmimeKey * key)
static

Copy an SMIME key.

Parameters
keyKey to copy
Return values
ptrNewly allocated SMIME key

Definition at line 116 of file smime.c.

117{
118 if (!key)
119 return NULL;
120
121 struct SmimeKey *copy = NULL;
122
123 copy = MUTT_MEM_CALLOC(1, struct SmimeKey);
124 copy->email = mutt_str_dup(key->email);
125 copy->hash = mutt_str_dup(key->hash);
126 copy->label = mutt_str_dup(key->label);
127 copy->issuer = mutt_str_dup(key->issuer);
128 copy->trust = key->trust;
129 copy->flags = key->flags;
130
131 return copy;
132}
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
KeyFlags flags
Key flags.
Definition smime.h:49
char trust
i=Invalid r=revoked e=expired u=unverified v=verified t=trusted
Definition smime.h:48
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_command()

static void smime_command ( struct Buffer * buf,
struct SmimeCommandContext * cctx,
const struct Expando * exp )
static

Format an SMIME command string.

Parameters
bufBuffer for the result
cctxData to pass to the formatter
expExpando to use

Definition at line 185 of file smime.c.

187{
189 mutt_debug(LL_DEBUG2, "%s\n", buf_string(buf));
190}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
int expando_render(const struct Expando *exp, const struct ExpandoRenderCallback *erc, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Render an Expando + data into a string.
Definition expando.c:118
const struct ExpandoRenderCallback SmimeCommandRenderCallbacks[]
Callbacks for Smime Command Expandos.
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
@ MUTT_FORMAT_NONE
No flags are set.
Definition render.h:37
size_t dsize
Length of data.
Definition buffer.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_invoke()

static pid_t smime_invoke ( FILE ** fp_smime_in,
FILE ** fp_smime_out,
FILE ** fp_smime_err,
int fp_smime_infd,
int fp_smime_outfd,
int fp_smime_errfd,
const char * fname,
const char * sig_fname,
const char * cryptalg,
const char * digestalg,
const char * key,
const char * certificates,
const char * intermediates,
const struct Expando * exp )
static

Run an SMIME command.

Parameters
[out]fp_smime_instdin for the command, or NULL (OPTIONAL)
[out]fp_smime_outstdout for the command, or NULL (OPTIONAL)
[out]fp_smime_errstderr for the command, or NULL (OPTIONAL)
[in]fp_smime_infdstdin for the command, or -1 (OPTIONAL)
[in]fp_smime_outfdstdout for the command, or -1 (OPTIONAL)
[in]fp_smime_errfdstderr for the command, or -1 (OPTIONAL)
[in]fnameFilename to pass to the command
[in]sig_fnameSignature filename to pass to the command
[in]cryptalgEncryption algorithm
[in]digestalgHashing algorithm
[in]keySMIME key
[in]certificatesPublic certificates
[in]intermediatesIntermediate certificates
[in]expExpando format string
Return values
numPID of the created process
-1Error creating pipes or forking
Note
fp_smime_in has priority over fp_smime_infd. Likewise fp_smime_out and fp_smime_err.

Definition at line 214 of file smime.c.

219{
220 struct SmimeCommandContext cctx = { 0 };
221
222 if (!exp)
223 return (pid_t) -1;
224
225 cctx.fname = fname;
226 cctx.sig_fname = sig_fname;
227 cctx.key = key;
228 cctx.cryptalg = cryptalg;
229 cctx.digestalg = digestalg;
232
233 struct Buffer *cmd = buf_pool_get();
234 smime_command(cmd, &cctx, exp);
235
236 pid_t pid = filter_create_fd(buf_string(cmd), fp_smime_in, fp_smime_out,
237 fp_smime_err, fp_smime_infd, fp_smime_outfd,
238 fp_smime_errfd, NeoMutt->env);
239 buf_pool_release(&cmd);
240 return pid;
241}
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr, char **envlist)
Run a command on a pipe (optionally connect stdin/stdout)
Definition filter.c:62
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
static void smime_command(struct Buffer *buf, struct SmimeCommandContext *cctx, const struct Expando *exp)
Format an SMIME command string.
Definition smime.c:185
String manipulation buffer.
Definition buffer.h:36
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
Data for a SIME command.
Definition smime.h:58
const char * sig_fname
s
Definition smime.h:63
const char * intermediates
i
Definition smime.h:65
const char * digestalg
d
Definition smime.h:61
const char * cryptalg
a
Definition smime.h:60
const char * key
k
Definition smime.h:59
const char * fname
f
Definition smime.h:62
const char * certificates
c
Definition smime.h:64
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_parse_key()

static struct SmimeKey * smime_parse_key ( char * buf)
static

Parse an SMIME key block.

Parameters
bufString to parse
Return values
ptrSMIME key
NULLError

Definition at line 249 of file smime.c.

250{
251 char *pend = NULL;
252 char *p = NULL;
253 int field = 0;
254
255 struct SmimeKey *key = MUTT_MEM_CALLOC(1, struct SmimeKey);
256
257 for (p = buf; p; p = pend)
258 {
259 /* Some users manually maintain their .index file, and use a tab
260 * as a delimiter, which the old parsing code (using fscanf)
261 * happened to allow. smime_keys uses a space, so search for both. */
262 if ((pend = strchr(p, ' ')) || (pend = strchr(p, '\t')) || (pend = strchr(p, '\n')))
263 *pend++ = 0;
264
265 /* For backward compatibility, don't count consecutive delimiters
266 * as an empty field. */
267 if (*p == '\0')
268 continue;
269
270 field++;
271
272 switch (field)
273 {
274 case 1: /* mailbox */
275 key->email = mutt_str_dup(p);
276 break;
277 case 2: /* hash */
278 key->hash = mutt_str_dup(p);
279 break;
280 case 3: /* label */
281 key->label = mutt_str_dup(p);
282 break;
283 case 4: /* issuer */
284 key->issuer = mutt_str_dup(p);
285 break;
286 case 5: /* trust */
287 key->trust = *p;
288 break;
289 case 6: /* purpose */
290 while (*p)
291 {
292 switch (*p++)
293 {
294 case 'e':
296 break;
297
298 case 's':
299 key->flags |= KEYFLAG_CANSIGN;
300 break;
301 }
302 }
303 break;
304 }
305 }
306
307 /* Old index files could be missing issuer, trust, and purpose,
308 * but anything less than that is an error. */
309 if (field < 3)
310 {
311 smime_key_free(&key);
312 return NULL;
313 }
314
315 if (field < 4)
316 key->issuer = mutt_str_dup("?");
317
318 if (field < 5)
319 key->trust = 't';
320
321 if (field < 6)
323
324 return key;
325}
@ KEYFLAG_CANSIGN
Key is suitable for signing.
Definition lib.h:147
@ KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition lib.h:148
static void smime_key_free(struct SmimeKey **keylist)
Free a list of SMIME keys.
Definition smime.c:91
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_get_candidates()

static struct SmimeKey * smime_get_candidates ( const char * search,
bool only_public_key )
static

Find keys matching a string.

Parameters
searchString to match
only_public_keyIf true, only get the public keys
Return values
ptrMatching key

Definition at line 333 of file smime.c.

334{
335 char buf[1024] = { 0 };
336 struct SmimeKey *key = NULL;
337 struct SmimeKey *results = NULL;
338 struct SmimeKey **results_end = &results;
339
340 struct Buffer *index_file = buf_pool_get();
341 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
342 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
343 buf_printf(index_file, "%s/.index",
344 only_public_key ? NONULL(c_smime_certificates) : NONULL(c_smime_keys));
345
346 FILE *fp = mutt_file_fopen(buf_string(index_file), "r");
347 if (!fp)
348 {
349 mutt_perror("%s", buf_string(index_file));
350 buf_pool_release(&index_file);
351 return NULL;
352 }
353 buf_pool_release(&index_file);
354
355 while (fgets(buf, sizeof(buf), fp))
356 {
357 if (((*search == '\0')) || mutt_istr_find(buf, search))
358 {
359 key = smime_parse_key(buf);
360 if (key)
361 {
362 *results_end = key;
363 results_end = &key->next;
364 }
365 }
366 }
367
368 mutt_file_fclose(&fp);
369
370 return results;
371}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
#define mutt_perror(...)
Definition logging2.h:95
static int search(struct Menu *menu, int op, int *match)
Search a menu.
Definition functions.c:59
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition string.c:528
static struct SmimeKey * smime_parse_key(char *buf)
Parse an SMIME key block.
Definition smime.c:249
#define NONULL(x)
Definition string2.h:44
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_get_key_by_hash()

static struct SmimeKey * smime_get_key_by_hash ( const char * hash,
bool only_public_key )
static

Find a key by its hash.

Parameters
hashHash to find
only_public_keyIf true, only get the public keys
Return values
ptrMatching key

Returns the first matching key record, without prompting or checking of abilities or trust.

Definition at line 382 of file smime.c.

383{
384 struct SmimeKey *match = NULL;
385 struct SmimeKey *results = smime_get_candidates(hash, only_public_key);
386 for (struct SmimeKey *result = results; result; result = result->next)
387 {
388 if (mutt_istr_equal(hash, result->hash))
389 {
390 match = smime_copy_key(result);
391 break;
392 }
393 }
394
395 smime_key_free(&results);
396
397 return match;
398}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
static struct SmimeKey * smime_copy_key(struct SmimeKey *key)
Copy an SMIME key.
Definition smime.c:116
static struct SmimeKey * smime_get_candidates(const char *search, bool only_public_key)
Find keys matching a string.
Definition smime.c:333
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_get_key_by_addr()

static struct SmimeKey * smime_get_key_by_addr ( const char * mailbox,
KeyFlags abilities,
bool only_public_key,
bool oppenc_mode )
static

Find an SIME key by address.

Parameters
mailboxEmail address to match
abilitiesAbilities to match, see KeyFlags
only_public_keyIf true, only get the public keys
oppenc_modeIf true, use opportunistic encryption
Return values
ptrMatching key

Definition at line 408 of file smime.c.

410{
411 if (!mailbox)
412 return NULL;
413
414 struct SmimeKey *results = NULL;
415 struct SmimeKey *result = NULL;
416 struct SmimeKey *matches = NULL;
417 struct SmimeKey **matches_end = &matches;
418 struct SmimeKey *match = NULL;
419 struct SmimeKey *trusted_match = NULL;
420 struct SmimeKey *valid_match = NULL;
421 struct SmimeKey *return_key = NULL;
422 bool multi_trusted_matches = false;
423
424 results = smime_get_candidates(mailbox, only_public_key);
425 for (result = results; result; result = result->next)
426 {
427 if (abilities && !(result->flags & abilities))
428 {
429 continue;
430 }
431
432 if (mutt_istr_equal(mailbox, result->email))
433 {
434 match = smime_copy_key(result);
435 *matches_end = match;
436 matches_end = &match->next;
437
438 if (match->trust == 't')
439 {
440 if (trusted_match && !mutt_istr_equal(match->hash, trusted_match->hash))
441 {
442 multi_trusted_matches = true;
443 }
444 trusted_match = match;
445 }
446 else if ((match->trust == 'u') || (match->trust == 'v'))
447 {
448 valid_match = match;
449 }
450 }
451 }
452
453 smime_key_free(&results);
454
455 if (matches)
456 {
457 if (oppenc_mode || !isatty(STDIN_FILENO))
458 {
459 const bool c_crypt_opportunistic_encrypt_strong_keys =
460 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
461 if (trusted_match)
462 return_key = smime_copy_key(trusted_match);
463 else if (valid_match && !c_crypt_opportunistic_encrypt_strong_keys)
464 return_key = smime_copy_key(valid_match);
465 else
466 return_key = NULL;
467 }
468 else if (trusted_match && !multi_trusted_matches)
469 {
470 return_key = smime_copy_key(trusted_match);
471 }
472 else
473 {
474 return_key = smime_copy_key(dlg_smime(matches, mailbox));
475 }
476
477 smime_key_free(&matches);
478 }
479
480 return return_key;
481}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
struct SmimeKey * dlg_smime(struct SmimeKey *keys, const char *query)
Get the user to select a key -.
Definition dlg_smime.c:195
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_get_key_by_str()

static struct SmimeKey * smime_get_key_by_str ( const char * str,
KeyFlags abilities,
bool only_public_key )
static

Find an SMIME key by string.

Parameters
strString to match
abilitiesAbilities to match, see KeyFlags
only_public_keyIf true, only get the public keys
Return values
ptrMatching key

Definition at line 490 of file smime.c.

491{
492 if (!str)
493 return NULL;
494
495 struct SmimeKey *results = NULL;
496 struct SmimeKey *result = NULL;
497 struct SmimeKey *matches = NULL;
498 struct SmimeKey **matches_end = &matches;
499 struct SmimeKey *match = NULL;
500 struct SmimeKey *return_key = NULL;
501
502 results = smime_get_candidates(str, only_public_key);
503 for (result = results; result; result = result->next)
504 {
505 if (abilities && !(result->flags & abilities))
506 {
507 continue;
508 }
509
510 if (mutt_istr_equal(str, result->hash) ||
511 mutt_istr_find(result->email, str) || mutt_istr_find(result->label, str))
512 {
513 match = smime_copy_key(result);
514 *matches_end = match;
515 matches_end = &match->next;
516 }
517 }
518
519 smime_key_free(&results);
520
521 if (matches)
522 {
523 return_key = smime_copy_key(dlg_smime(matches, str));
524 smime_key_free(&matches);
525 }
526
527 return return_key;
528}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_ask_for_key()

static struct SmimeKey * smime_ask_for_key ( const char * prompt,
KeyFlags abilities,
bool only_public_key )
static

Ask the user to select a key.

Parameters
promptPrompt to show the user
abilitiesAbilities to match, see KeyFlags
only_public_keyIf true, only get the public keys
Return values
ptrSelected SMIME key

Definition at line 537 of file smime.c.

538{
539 if (!prompt)
540 return NULL;
541
542 struct SmimeKey *key = NULL;
543 struct Buffer *resp = buf_pool_get();
544
546
547 while (true)
548 {
549 buf_reset(resp);
550 if (mw_get_field(prompt, resp, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0)
551 {
552 goto done;
553 }
554
555 if (buf_is_empty(resp))
556 goto done;
557
558 key = smime_get_key_by_str(buf_string(resp), abilities, only_public_key);
559 if (key)
560 goto done;
561
562 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
563 }
564
565done:
566 buf_pool_release(&resp);
567 return key;
568}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:89
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:502
#define mutt_error(...)
Definition logging2.h:94
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:61
#define _(a)
Definition message.h:28
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
static struct SmimeKey * smime_get_key_by_str(const char *str, KeyFlags abilities, bool only_public_key)
Find an SMIME key by string.
Definition smime.c:490
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getkeys()

static void getkeys ( const char * mailbox)
static

Get the keys for a mailbox.

Parameters
mailboxEmail address

This sets the '*ToUse' variables for an upcoming decryption, where the required key is different from $smime_default_key.

Definition at line 577 of file smime.c.

578{
580 const char *k = NULL;
581
582 struct SmimeKey *key = smime_get_key_by_addr(mailbox, KEYFLAG_CANENCRYPT, false, false);
583
584 if (!key)
585 {
586 struct Buffer *prompt = buf_pool_get();
587 buf_printf(prompt, _("Enter keyID for %s: "), mailbox);
588 key = smime_ask_for_key(buf_string(prompt), KEYFLAG_CANENCRYPT, false);
589 buf_pool_release(&prompt);
590 }
591
592 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
593 size_t smime_keys_len = mutt_str_len(c_smime_keys);
594
595 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
596 k = key ? key->hash : NONULL(c_smime_default_key);
597
598 /* if the key is different from last time */
599 if ((buf_len(&mod_data->smime_key_to_use) <= smime_keys_len) ||
600 !mutt_istr_equal(k, mod_data->smime_key_to_use.data + smime_keys_len + 1))
601 {
603 buf_printf(&mod_data->smime_key_to_use, "%s/%s", NONULL(c_smime_keys), k);
604 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
605 buf_printf(&mod_data->smime_cert_to_use, "%s/%s", NONULL(c_smime_certificates), k);
606 }
607
608 smime_key_free(&key);
609}
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:497
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
void smime_class_void_passphrase(void)
Forget the cached passphrase - Implements CryptModuleSpecs::void_passphrase() -.
Definition smime.c:137
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
static struct SmimeKey * smime_get_key_by_addr(const char *mailbox, KeyFlags abilities, bool only_public_key, bool oppenc_mode)
Find an SIME key by address.
Definition smime.c:408
static struct SmimeKey * smime_ask_for_key(const char *prompt, KeyFlags abilities, bool only_public_key)
Ask the user to select a key.
Definition smime.c:537
char * data
Pointer to data.
Definition buffer.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_handle_cert_email()

static int smime_handle_cert_email ( const char * certificate,
const char * mailbox,
bool copy,
char *** buffer,
int * num )
static

Process an email containing certificates.

Parameters
[in]certificateEmail with certificates
[in]mailboxEmail address
[in]copyIf true, save the certificates to buffer
[out]bufferBuffer allocated to hold certificates
[out]numNumber of certificates in buffer
Return values
0Success
-1Error
-2Error

Definition at line 705 of file smime.c.

707{
708 char email[256] = { 0 };
709 int rc = -1;
710 int count = 0;
711 pid_t pid;
712
713 FILE *fp_err = mutt_file_mkstemp();
714 if (!fp_err)
715 {
716 mutt_perror(_("Can't create temporary file"));
717 return 1;
718 }
719
720 FILE *fp_out = mutt_file_mkstemp();
721 if (!fp_out)
722 {
723 mutt_file_fclose(&fp_err);
724 mutt_perror(_("Can't create temporary file"));
725 return 1;
726 }
727
728 const struct Expando *c_smime_get_cert_email_command =
729 cs_subset_expando(NeoMutt->sub, "smime_get_cert_email_command");
730 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), certificate,
731 NULL, NULL, NULL, NULL, NULL, NULL, c_smime_get_cert_email_command);
732 if (pid == -1)
733 {
734 mutt_message(_("Error: unable to create OpenSSL subprocess"));
735 mutt_file_fclose(&fp_err);
736 mutt_file_fclose(&fp_out);
737 return 1;
738 }
739
740 filter_wait(pid);
741
742 fflush(fp_out);
743 rewind(fp_out);
744 fflush(fp_err);
745 rewind(fp_err);
746
747 while ((fgets(email, sizeof(email), fp_out)))
748 {
749 size_t len = mutt_str_len(email);
750 if (len && (email[len - 1] == '\n'))
751 email[len - 1] = '\0';
752 if (mutt_istr_startswith(email, mailbox))
753 rc = 1;
754
755 rc = (rc < 0) ? 0 : rc;
756 count++;
757 }
758
759 if (rc == -1)
760 {
761 mutt_endwin();
762 mutt_file_copy_stream(fp_err, stdout);
763 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
764 rc = 1;
765 }
766 else if (rc == 0)
767 {
768 rc = 1;
769 }
770 else
771 {
772 rc = 0;
773 }
774
775 if (copy && buffer && num)
776 {
777 (*num) = count;
778 *buffer = MUTT_MEM_CALLOC(count, char *);
779 count = 0;
780
781 rewind(fp_out);
782 while ((fgets(email, sizeof(email), fp_out)))
783 {
784 size_t len = mutt_str_len(email);
785 if (len && (email[len - 1] == '\n'))
786 email[len - 1] = '\0';
787 (*buffer)[count] = MUTT_MEM_CALLOC(mutt_str_len(email) + 1, char);
788 strncpy((*buffer)[count], email, mutt_str_len(email));
789 count++;
790 }
791 }
792 else if (copy)
793 {
794 rc = 2;
795 }
796
797 mutt_file_fclose(&fp_out);
798 mutt_file_fclose(&fp_err);
799
800 return rc;
801}
const struct Expando * cs_subset_expando(const struct ConfigSubset *sub, const char *name)
Get an Expando config item by name.
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:174
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:152
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
#define mutt_message(...)
Definition logging2.h:93
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:231
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
static pid_t smime_invoke(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, const char *cryptalg, const char *digestalg, const char *key, const char *certificates, const char *intermediates, const struct Expando *exp)
Run an SMIME command.
Definition smime.c:214
Parsed Expando trees.
Definition expando.h:41
#define mutt_file_mkstemp()
Definition tmp.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_extract_certificate()

static char * smime_extract_certificate ( const char * infile)
static

Extract an SMIME certificate from a file.

Parameters
infileFile to read
Return values
ptrFilename of temporary file containing certificate

Definition at line 808 of file smime.c.

809{
810 FILE *fp_err = NULL;
811 FILE *fp_out = NULL;
812 FILE *fp_cert = NULL;
813 char *rc = NULL;
814 pid_t pid;
815 int empty;
816
817 struct Buffer *pk7out = buf_pool_get();
818 struct Buffer *certfile = buf_pool_get();
819
820 fp_err = mutt_file_mkstemp();
821 if (!fp_err)
822 {
823 mutt_perror(_("Can't create temporary file"));
824 goto cleanup;
825 }
826
827 buf_mktemp(pk7out);
828 fp_out = mutt_file_fopen(buf_string(pk7out), "w+");
829 if (!fp_out)
830 {
831 mutt_perror("%s", buf_string(pk7out));
832 goto cleanup;
833 }
834
835 /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
836 * extract the full set of certificates directly. */
837 const struct Expando *c_smime_pk7out_command = cs_subset_expando(NeoMutt->sub, "smime_pk7out_command");
838 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), infile,
839 NULL, NULL, NULL, NULL, NULL, NULL, c_smime_pk7out_command);
840 if (pid == -1)
841 {
842 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
843 goto cleanup;
844 }
845
846 filter_wait(pid);
847
848 fflush(fp_out);
849 rewind(fp_out);
850 fflush(fp_err);
851 rewind(fp_err);
852 empty = (fgetc(fp_out) == EOF);
853 if (empty)
854 {
855 mutt_perror("%s", buf_string(pk7out));
856 mutt_file_copy_stream(fp_err, stdout);
857 goto cleanup;
858 }
859 mutt_file_fclose(&fp_out);
860
861 buf_mktemp(certfile);
862 fp_cert = mutt_file_fopen(buf_string(certfile), "w+");
863 if (!fp_cert)
864 {
865 mutt_perror("%s", buf_string(certfile));
867 goto cleanup;
868 }
869
870 // Step 2: Extract the certificates from a PKCS#7 structure.
871 const struct Expando *c_smime_get_cert_command = cs_subset_expando(NeoMutt->sub, "smime_get_cert_command");
872 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_cert), fileno(fp_err),
873 buf_string(pk7out), NULL, NULL, NULL, NULL, NULL, NULL,
874 c_smime_get_cert_command);
875 if (pid == -1)
876 {
877 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
879 goto cleanup;
880 }
881
882 filter_wait(pid);
883
885
886 fflush(fp_cert);
887 rewind(fp_cert);
888 fflush(fp_err);
889 rewind(fp_err);
890 empty = (fgetc(fp_cert) == EOF);
891 if (empty)
892 {
893 mutt_file_copy_stream(fp_err, stdout);
894 goto cleanup;
895 }
896
897 mutt_file_fclose(&fp_cert);
898
899 rc = buf_strdup(certfile);
900
901cleanup:
902 mutt_file_fclose(&fp_err);
903 if (fp_out)
904 {
905 mutt_file_fclose(&fp_out);
907 }
908 if (fp_cert)
909 {
910 mutt_file_fclose(&fp_cert);
911 mutt_file_unlink(buf_string(certfile));
912 }
913 buf_pool_release(&pk7out);
914 buf_pool_release(&certfile);
915 return rc;
916}
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
#define buf_mktemp(buf)
Definition tmp.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_extract_signer_certificate()

static char * smime_extract_signer_certificate ( const char * infile)
static

Extract the signer's certificate.

Parameters
infileFile to read
Return values
ptrName of temporary file containing certificate

Definition at line 923 of file smime.c.

924{
925 char *cert = NULL;
926 struct Buffer *certfile = NULL;
927 pid_t pid;
928 int empty;
929
930 FILE *fp_err = mutt_file_mkstemp();
931 if (!fp_err)
932 {
933 mutt_perror(_("Can't create temporary file"));
934 return NULL;
935 }
936
937 certfile = buf_pool_get();
938 buf_mktemp(certfile);
939 FILE *fp_out = mutt_file_fopen(buf_string(certfile), "w+");
940 if (!fp_out)
941 {
942 mutt_file_fclose(&fp_err);
943 mutt_perror("%s", buf_string(certfile));
944 goto cleanup;
945 }
946
947 /* Extract signer's certificate
948 */
949 const struct Expando *c_smime_get_signer_cert_command =
950 cs_subset_expando(NeoMutt->sub, "smime_get_signer_cert_command");
951 pid = smime_invoke(NULL, NULL, NULL, -1, -1, fileno(fp_err), infile, NULL, NULL, NULL,
952 NULL, buf_string(certfile), NULL, c_smime_get_signer_cert_command);
953 if (pid == -1)
954 {
955 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
956 goto cleanup;
957 }
958
959 filter_wait(pid);
960
961 fflush(fp_out);
962 rewind(fp_out);
963 fflush(fp_err);
964 rewind(fp_err);
965 empty = (fgetc(fp_out) == EOF);
966 if (empty)
967 {
968 mutt_endwin();
969 mutt_file_copy_stream(fp_err, stdout);
971 goto cleanup;
972 }
973
974 mutt_file_fclose(&fp_out);
975 cert = buf_strdup(certfile);
976
977cleanup:
978 mutt_file_fclose(&fp_err);
979 if (fp_out)
980 {
981 mutt_file_fclose(&fp_out);
982 mutt_file_unlink(buf_string(certfile));
983 }
984 buf_pool_release(&certfile);
985 return cert;
986}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_invoke_encrypt()

static pid_t smime_invoke_encrypt ( FILE ** fp_smime_in,
FILE ** fp_smime_out,
FILE ** fp_smime_err,
int fp_smime_infd,
int fp_smime_outfd,
int fp_smime_errfd,
const char * fname,
const char * uids )
static

Use SMIME to encrypt a file.

Parameters
[out]fp_smime_instdin for the command, or NULL (OPTIONAL)
[out]fp_smime_outstdout for the command, or NULL (OPTIONAL)
[out]fp_smime_errstderr for the command, or NULL (OPTIONAL)
[in]fp_smime_infdstdin for the command, or -1 (OPTIONAL)
[in]fp_smime_outfdstdout for the command, or -1 (OPTIONAL)
[in]fp_smime_errfdstderr for the command, or -1 (OPTIONAL)
[in]fnameFilename to pass to the command
[in]uidsList of IDs/fingerprints, space separated
Return values
numPID of the created process
-1Error creating pipes or forking
Note
fp_smime_in has priority over fp_smime_infd. Likewise fp_smime_out and fp_smime_err.

Definition at line 1152 of file smime.c.

1156{
1157 const char *const c_smime_encrypt_with = cs_subset_string(NeoMutt->sub, "smime_encrypt_with");
1158 const struct Expando *c_smime_encrypt_command = cs_subset_expando(NeoMutt->sub, "smime_encrypt_command");
1159 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1160 fp_smime_outfd, fp_smime_errfd, fname, NULL, c_smime_encrypt_with,
1161 NULL, NULL, uids, NULL, c_smime_encrypt_command);
1162}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_invoke_sign()

static pid_t smime_invoke_sign ( FILE ** fp_smime_in,
FILE ** fp_smime_out,
FILE ** fp_smime_err,
int fp_smime_infd,
int fp_smime_outfd,
int fp_smime_errfd,
const char * fname )
static

Use SMIME to sign a file.

Parameters
[out]fp_smime_instdin for the command, or NULL (OPTIONAL)
[out]fp_smime_outstdout for the command, or NULL (OPTIONAL)
[out]fp_smime_errstderr for the command, or NULL (OPTIONAL)
[in]fp_smime_infdstdin for the command, or -1 (OPTIONAL)
[in]fp_smime_outfdstdout for the command, or -1 (OPTIONAL)
[in]fp_smime_errfdstderr for the command, or -1 (OPTIONAL)
[in]fnameFilename to pass to the command
Return values
numPID of the created process
-1Error creating pipes or forking
Note
fp_smime_in has priority over fp_smime_infd. Likewise fp_smime_out and fp_smime_err.

Definition at line 1179 of file smime.c.

1182{
1184 const char *const c_smime_sign_digest_alg = cs_subset_string(NeoMutt->sub, "smime_sign_digest_alg");
1185 const struct Expando *c_smime_sign_command = cs_subset_expando(NeoMutt->sub, "smime_sign_command");
1186 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1187 fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL,
1188 c_smime_sign_digest_alg, buf_string(&mod_data->smime_key_to_use),
1189 buf_string(&mod_data->smime_cert_to_use),
1190 buf_string(&mod_data->smime_intermediate_to_use), c_smime_sign_command);
1191}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ openssl_md_to_smime_micalg()

static char * openssl_md_to_smime_micalg ( const char * md)
static

Change the algorithm names.

Parameters
mdOpenSSL message digest name
Return values
ptrSMIME Message Integrity Check algorithm

The openssl -md doesn't want hyphens: md5, sha1, sha224, sha256, sha384, sha512 However, the micalg does: md5, sha-1, sha-224, sha-256, sha-384, sha-512

Note
The caller should free the returned string

Definition at line 1344 of file smime.c.

1345{
1346 if (!md)
1347 return NULL;
1348
1349 char *micalg = NULL;
1350 if (mutt_istr_startswith(md, "sha"))
1351 {
1352 mutt_str_asprintf(&micalg, "sha-%s", md + 3);
1353 }
1354 else
1355 {
1356 micalg = mutt_str_dup(md);
1357 }
1358
1359 return micalg;
1360}
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:809
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_invoke_verify()

static pid_t smime_invoke_verify ( FILE ** fp_smime_in,
FILE ** fp_smime_out,
FILE ** fp_smime_err,
int fp_smime_infd,
int fp_smime_outfd,
int fp_smime_errfd,
const char * fname,
const char * sig_fname,
int opaque )
static

Use SMIME to verify a file.

Parameters
[out]fp_smime_instdin for the command, or NULL (OPTIONAL)
[out]fp_smime_outstdout for the command, or NULL (OPTIONAL)
[out]fp_smime_errstderr for the command, or NULL (OPTIONAL)
[in]fp_smime_infdstdin for the command, or -1 (OPTIONAL)
[in]fp_smime_outfdstdout for the command, or -1 (OPTIONAL)
[in]fp_smime_errfdstderr for the command, or -1 (OPTIONAL)
[in]fnameFilename to pass to the command
[in]sig_fnameSignature filename to pass to the command
[in]opaqueIf true, use $smime_verify_opaque_command else $smime_verify_command
Return values
numPID of the created process
-1Error creating pipes or forking
Note
fp_smime_in has priority over fp_smime_infd. Likewise fp_smime_out and fp_smime_err.

Definition at line 1541 of file smime.c.

1545{
1546 const struct Expando *c_smime_verify_opaque_command =
1547 cs_subset_expando(NeoMutt->sub, "smime_verify_opaque_command");
1548 const struct Expando *c_smime_verify_command = cs_subset_expando(NeoMutt->sub, "smime_verify_command");
1549 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd, fp_smime_outfd,
1550 fp_smime_errfd, fname, sig_fname, NULL, NULL, NULL, NULL, NULL,
1551 (opaque ? c_smime_verify_opaque_command : c_smime_verify_command));
1552}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_invoke_decrypt()

static pid_t smime_invoke_decrypt ( FILE ** fp_smime_in,
FILE ** fp_smime_out,
FILE ** fp_smime_err,
int fp_smime_infd,
int fp_smime_outfd,
int fp_smime_errfd,
const char * fname )
static

Use SMIME to decrypt a file.

Parameters
[out]fp_smime_instdin for the command, or NULL (OPTIONAL)
[out]fp_smime_outstdout for the command, or NULL (OPTIONAL)
[out]fp_smime_errstderr for the command, or NULL (OPTIONAL)
[in]fp_smime_infdstdin for the command, or -1 (OPTIONAL)
[in]fp_smime_outfdstdout for the command, or -1 (OPTIONAL)
[in]fp_smime_errfdstderr for the command, or -1 (OPTIONAL)
[in]fnameFilename to pass to the command
Return values
numPID of the created process
-1Error creating pipes or forking
Note
fp_smime_in has priority over fp_smime_infd. Likewise fp_smime_out and fp_smime_err.

Definition at line 1569 of file smime.c.

1572{
1574 const struct Expando *c_smime_decrypt_command = cs_subset_expando(NeoMutt->sub, "smime_decrypt_command");
1575 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1576 fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL, NULL,
1577 buf_string(&mod_data->smime_key_to_use),
1578 buf_string(&mod_data->smime_cert_to_use), NULL,
1579 c_smime_decrypt_command);
1580}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_handle_entity()

static struct Body * smime_handle_entity ( struct Body * b,
struct State * state,
FILE * fp_out_file )
static

Handle type application/pkcs7-mime.

Parameters
bBody to handle
stateState to use
fp_out_fileFile for the result
Return values
ptrBody for parsed MIME part

This can either be a signed or an encrypted message.

Definition at line 1701 of file smime.c.

1702{
1704 struct Buffer *tmpfname = buf_pool_get();
1705 FILE *fp_smime_out = NULL;
1706 FILE *fp_smime_in = NULL;
1707 FILE *fp_smime_err = NULL;
1708 FILE *fp_tmp = NULL;
1709 FILE *fp_out = NULL;
1710 struct Body *p = NULL;
1711 pid_t pid = -1;
1713
1714 if (!(type & APPLICATION_SMIME))
1715 return NULL;
1716
1717 /* Because of the mutt_body_handler() we avoid the buffer pool. */
1718 fp_smime_out = mutt_file_mkstemp();
1719 if (!fp_smime_out)
1720 {
1721 mutt_perror(_("Can't create temporary file"));
1722 goto cleanup;
1723 }
1724
1725 fp_smime_err = mutt_file_mkstemp();
1726 if (!fp_smime_err)
1727 {
1728 mutt_perror(_("Can't create temporary file"));
1729 goto cleanup;
1730 }
1731
1732 buf_mktemp(tmpfname);
1733 fp_tmp = mutt_file_fopen(buf_string(tmpfname), "w+");
1734 if (!fp_tmp)
1735 {
1736 mutt_perror("%s", buf_string(tmpfname));
1737 goto cleanup;
1738 }
1739
1740 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
1741 {
1742 goto cleanup;
1743 }
1744
1745 mutt_file_copy_bytes(state->fp_in, fp_tmp, b->length);
1746
1747 fflush(fp_tmp);
1748 mutt_file_fclose(&fp_tmp);
1749
1750 if ((type & SEC_ENCRYPT) &&
1751 ((pid = smime_invoke_decrypt(&fp_smime_in, NULL, NULL, -1, fileno(fp_smime_out),
1752 fileno(fp_smime_err), buf_string(tmpfname))) == -1))
1753 {
1754 mutt_file_unlink(buf_string(tmpfname));
1755 if (state->flags & STATE_DISPLAY)
1756 {
1757 state_attach_puts(state, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1758 }
1759 goto cleanup;
1760 }
1761 else if ((type & SEC_SIGNOPAQUE) &&
1762 ((pid = smime_invoke_verify(&fp_smime_in, NULL, NULL, -1,
1763 fileno(fp_smime_out), fileno(fp_smime_err), NULL,
1764 buf_string(tmpfname), SEC_SIGNOPAQUE)) == -1))
1765 {
1766 mutt_file_unlink(buf_string(tmpfname));
1767 if (state->flags & STATE_DISPLAY)
1768 {
1769 state_attach_puts(state, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1770 }
1771 goto cleanup;
1772 }
1773
1774 if (type & SEC_ENCRYPT)
1775 {
1778 fputs(mod_data->smime_pass, fp_smime_in);
1779 fputc('\n', fp_smime_in);
1780 }
1781
1782 mutt_file_fclose(&fp_smime_in);
1783
1784 filter_wait(pid);
1785 mutt_file_unlink(buf_string(tmpfname));
1786
1787 if (state->flags & STATE_DISPLAY)
1788 {
1789 fflush(fp_smime_err);
1790 rewind(fp_smime_err);
1791
1792 const int c = fgetc(fp_smime_err);
1793 if (c != EOF)
1794 {
1795 ungetc(c, fp_smime_err);
1796
1797 crypt_current_time(state, "OpenSSL");
1798 mutt_file_copy_stream(fp_smime_err, state->fp_out);
1799 state_attach_puts(state, _("[-- End of OpenSSL output --]\n\n"));
1800 }
1801
1802 if (type & SEC_ENCRYPT)
1803 {
1804 state_attach_puts(state, _("[-- The following data is S/MIME encrypted --]\n"));
1805 }
1806 else
1807 {
1808 state_attach_puts(state, _("[-- The following data is S/MIME signed --]\n"));
1809 }
1810 }
1811
1812 fflush(fp_smime_out);
1813 rewind(fp_smime_out);
1814
1815 if (type & SEC_ENCRYPT)
1816 {
1817 /* void the passphrase, even if that wasn't the problem */
1818 if (fgetc(fp_smime_out) == EOF)
1819 {
1820 mutt_error(_("Decryption failed"));
1822 }
1823 rewind(fp_smime_out);
1824 }
1825
1826 if (fp_out_file)
1827 {
1828 fp_out = fp_out_file;
1829 }
1830 else
1831 {
1832 fp_out = mutt_file_mkstemp();
1833 if (!fp_out)
1834 {
1835 mutt_perror(_("Can't create temporary file"));
1836 goto cleanup;
1837 }
1838 }
1839 char buf[8192] = { 0 };
1840 while (fgets(buf, sizeof(buf) - 1, fp_smime_out))
1841 {
1842 const size_t len = mutt_str_len(buf);
1843 if ((len > 1) && (buf[len - 2] == '\r'))
1844 {
1845 buf[len - 2] = '\n';
1846 buf[len - 1] = '\0';
1847 }
1848 fputs(buf, fp_out);
1849 }
1850 fflush(fp_out);
1851 rewind(fp_out);
1852
1853 const long size = mutt_file_get_size_fp(fp_out);
1854 if (size == 0)
1855 {
1856 goto cleanup;
1857 }
1858 p = mutt_read_mime_header(fp_out, 0);
1859 if (p)
1860 {
1861 p->length = size - p->offset;
1862
1863 mutt_parse_part(fp_out, p);
1864
1865 if (state->flags & STATE_DISPLAY)
1867
1868 /* Store any protected headers in the parent so they can be
1869 * accessed for index updates after the handler recursion is done.
1870 * This is done before the handler to prevent a nested encrypted
1871 * handler from freeing the headers. */
1873 b->mime_headers = p->mime_headers;
1874 p->mime_headers = NULL;
1875
1876 if (state->fp_out)
1877 {
1878 rewind(fp_out);
1879 FILE *fp_tmp_buffer = state->fp_in;
1880 state->fp_in = fp_out;
1881 mutt_body_handler(p, state);
1882 state->fp_in = fp_tmp_buffer;
1883 }
1884
1885 /* Embedded multipart signed protected headers override the
1886 * encrypted headers. We need to do this after the handler so
1887 * they can be printed in the pager. */
1888 if (!(type & SMIME_SIGN) && mutt_is_multipart_signed(p) && p->parts &&
1889 p->parts->mime_headers)
1890 {
1893 p->parts->mime_headers = NULL;
1894 }
1895 }
1896 mutt_file_fclose(&fp_smime_out);
1897
1898 if (!fp_out_file)
1899 {
1900 mutt_file_fclose(&fp_out);
1901 mutt_file_unlink(buf_string(tmpfname));
1902 }
1903 fp_out = NULL;
1904
1905 if (state->flags & STATE_DISPLAY)
1906 {
1907 if (type & SEC_ENCRYPT)
1908 state_attach_puts(state, _("[-- End of S/MIME encrypted data --]\n"));
1909 else
1910 state_attach_puts(state, _("[-- End of S/MIME signed data --]\n"));
1911 }
1912
1913 if (type & SEC_SIGNOPAQUE)
1914 {
1915 char *line = NULL;
1916 size_t linelen = 0;
1917
1918 rewind(fp_smime_err);
1919
1920 line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, MUTT_RL_NONE);
1921 if (linelen && mutt_istr_equal(line, "verification successful"))
1922 b->goodsig = true;
1923 FREE(&line);
1924 }
1925 else if (p)
1926 {
1927 b->goodsig = p->goodsig;
1928 b->badsig = p->badsig;
1929 }
1930
1931cleanup:
1932 mutt_file_fclose(&fp_smime_out);
1933 mutt_file_fclose(&fp_smime_err);
1934 mutt_file_fclose(&fp_tmp);
1935 mutt_file_fclose(&fp_out);
1936 buf_pool_release(&tmpfname);
1937 return p;
1938}
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition crypt.c:409
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:610
void crypt_current_time(struct State *state, const char *app_name)
Print the current time.
Definition crypt.c:64
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition parse.c:1949
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1484
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition file.c:678
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition file.c:192
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1433
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
@ MUTT_RL_NONE
No flags are set.
Definition file.h:43
bool smime_class_valid_passphrase(void)
Ensure we have a valid passphrase - Implements CryptModuleSpecs::valid_passphrase() -.
Definition smime.c:147
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition crypt.c:1123
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1668
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition state.c:104
@ STATE_DISPLAY
Output is displayed to the user.
Definition state.h:37
uint16_t SecurityFlags
Definition lib.h:104
@ SEC_SIGNOPAQUE
Email has an opaque signature (encrypted)
Definition lib.h:97
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
#define SMIME_SIGN
Email is S/MIME signed.
Definition lib.h:119
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
static pid_t smime_invoke_verify(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, int opaque)
Use SMIME to verify a file.
Definition smime.c:1541
static pid_t smime_invoke_decrypt(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname)
Use SMIME to decrypt a file.
Definition smime.c:1569
The body of an email.
Definition body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
LOFF_T offset
offset where the actual data begins
Definition body.h:52
bool badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition body.h:43
struct Envelope * mime_headers
Memory hole protected headers.
Definition body.h:76
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
bool goodsig
Good cryptographic signature.
Definition body.h:45
unsigned int type
content-type primary type, ContentType
Definition body.h:40
char smime_pass[256]
Cached S/MIME Passphrase.
Definition module_data.h:56
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:58
FILE * fp_out
File to write to.
Definition state.h:56
FILE * fp_in
File to read from.
Definition state.h:55
+ Here is the call graph for this function:
+ Here is the caller graph for this function: