NeoMutt  2025-09-05-43-g177ed6
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 "copy.h"
#include "crypt.h"
#include "cryptglue.h"
#include "expando_smime.h"
#include "handler.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 (void)
 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() -.
 

Variables

static char SmimePass [256]
 Cached Smime Passphrase.
 
static time_t SmimeExpTime = 0
 Unix time when SmimePass expires.
 
static struct Buffer SmimeKeyToUse = { 0 }
 Smime key to use.
 
static struct Buffer SmimeCertToUse = { 0 }
 Smime certificate to use.
 
static struct Buffer SmimeIntermediateToUse = { 0 }
 Smime intermediate certificate to use.
 

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 81 of file smime.c.

82{
86}
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:337
static struct Buffer SmimeIntermediateToUse
Smime intermediate certificate to use.
Definition smime.c:76
static struct Buffer SmimeKeyToUse
Smime key to use.
Definition smime.c:72
static struct Buffer SmimeCertToUse
Smime certificate to use.
Definition smime.c:74
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ smime_cleanup()

void smime_cleanup ( void )

Clean up smime globals.

Definition at line 91 of file smime.c.

92{
96}
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition buffer.c:377
+ 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 102 of file smime.c.

103{
104 if (!keylist)
105 return;
106
107 struct SmimeKey *key = NULL;
108
109 while (*keylist)
110 {
111 key = *keylist;
112 *keylist = (*keylist)->next;
113
114 FREE(&key->email);
115 FREE(&key->hash);
116 FREE(&key->label);
117 FREE(&key->issuer);
118 FREE(&key);
119 }
120}
#define FREE(x)
Definition memory.h:62
An SIME key.
Definition smime.h:43
char * hash
Definition smime.h:45
struct SmimeKey * next
Definition smime.h:50
char * issuer
Definition smime.h:47
char * email
Definition smime.h:44
char * 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 127 of file smime.c.

128{
129 if (!key)
130 return NULL;
131
132 struct SmimeKey *copy = NULL;
133
134 copy = MUTT_MEM_CALLOC(1, struct SmimeKey);
135 copy->email = mutt_str_dup(key->email);
136 copy->hash = mutt_str_dup(key->hash);
137 copy->label = mutt_str_dup(key->label);
138 copy->issuer = mutt_str_dup(key->issuer);
139 copy->trust = key->trust;
140 copy->flags = key->flags;
141
142 return copy;
143}
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:47
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:255
KeyFlags 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 194 of file smime.c.

196{
198 buf->dsize, buf);
199 mutt_debug(LL_DEBUG2, "%s\n", buf_string(buf));
200}
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:90
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:45
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition render.h:33
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 224 of file smime.c.

229{
230 struct SmimeCommandContext cctx = { 0 };
231
232 if (!exp)
233 return (pid_t) -1;
234
235 cctx.fname = fname;
236 cctx.sig_fname = sig_fname;
237 cctx.key = key;
238 cctx.cryptalg = cryptalg;
239 cctx.digestalg = digestalg;
242
243 struct Buffer *cmd = buf_pool_get();
244 smime_command(cmd, &cctx, exp);
245
246 pid_t pid = filter_create_fd(buf_string(cmd), fp_smime_in, fp_smime_out,
247 fp_smime_err, fp_smime_infd, fp_smime_outfd,
248 fp_smime_errfd, NeoMutt->env);
249 buf_pool_release(&cmd);
250 return pid;
251}
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:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
static void smime_command(struct Buffer *buf, struct SmimeCommandContext *cctx, const struct Expando *exp)
Format an SMIME command string.
Definition smime.c:194
String manipulation buffer.
Definition buffer.h:36
Container for Accounts, Notifications.
Definition neomutt.h:43
char ** env
Private copy of the environment variables.
Definition neomutt.h:55
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 259 of file smime.c.

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

343{
344 char buf[1024] = { 0 };
345 struct SmimeKey *key = NULL, *results = NULL;
346 struct SmimeKey **results_end = &results;
347
348 struct Buffer *index_file = buf_pool_get();
349 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
350 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
351 buf_printf(index_file, "%s/.index",
352 only_public_key ? NONULL(c_smime_certificates) : NONULL(c_smime_keys));
353
354 FILE *fp = mutt_file_fopen(buf_string(index_file), "r");
355 if (!fp)
356 {
357 mutt_perror("%s", buf_string(index_file));
358 buf_pool_release(&index_file);
359 return NULL;
360 }
361 buf_pool_release(&index_file);
362
363 while (fgets(buf, sizeof(buf), fp))
364 {
365 if (((*search == '\0')) || mutt_istr_find(buf, search))
366 {
367 key = smime_parse_key(buf);
368 if (key)
369 {
370 *results_end = key;
371 results_end = &key->next;
372 }
373 }
374 }
375
376 mutt_file_fclose(&fp);
377
378 return results;
379}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
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:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
#define mutt_perror(...)
Definition logging2.h:94
static int search(struct Menu *menu, int op)
Search a menu.
Definition functions.c:58
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition string.c:523
static struct SmimeKey * smime_parse_key(char *buf)
Parse an SMIME key block.
Definition smime.c:259
#define NONULL(x)
Definition string2.h:43
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:47
+ 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 390 of file smime.c.

391{
392 struct SmimeKey *match = NULL;
393 struct SmimeKey *results = smime_get_candidates(hash, only_public_key);
394 for (struct SmimeKey *result = results; result; result = result->next)
395 {
396 if (mutt_istr_equal(hash, result->hash))
397 {
398 match = smime_copy_key(result);
399 break;
400 }
401 }
402
403 smime_key_free(&results);
404
405 return match;
406}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:672
static struct SmimeKey * smime_copy_key(struct SmimeKey *key)
Copy an SMIME key.
Definition smime.c:127
static struct SmimeKey * smime_get_candidates(const char *search, bool only_public_key)
Find keys matching a string.
Definition smime.c:342
+ 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 416 of file smime.c.

418{
419 if (!mailbox)
420 return NULL;
421
422 struct SmimeKey *results = NULL, *result = NULL;
423 struct SmimeKey *matches = NULL;
424 struct SmimeKey **matches_end = &matches;
425 struct SmimeKey *match = NULL;
426 struct SmimeKey *trusted_match = NULL;
427 struct SmimeKey *valid_match = NULL;
428 struct SmimeKey *return_key = NULL;
429 bool multi_trusted_matches = false;
430
431 results = smime_get_candidates(mailbox, only_public_key);
432 for (result = results; result; result = result->next)
433 {
434 if (abilities && !(result->flags & abilities))
435 {
436 continue;
437 }
438
439 if (mutt_istr_equal(mailbox, result->email))
440 {
441 match = smime_copy_key(result);
442 *matches_end = match;
443 matches_end = &match->next;
444
445 if (match->trust == 't')
446 {
447 if (trusted_match && !mutt_istr_equal(match->hash, trusted_match->hash))
448 {
449 multi_trusted_matches = true;
450 }
451 trusted_match = match;
452 }
453 else if ((match->trust == 'u') || (match->trust == 'v'))
454 {
455 valid_match = match;
456 }
457 }
458 }
459
460 smime_key_free(&results);
461
462 if (matches)
463 {
464 if (oppenc_mode || !isatty(STDIN_FILENO))
465 {
466 const bool c_crypt_opportunistic_encrypt_strong_keys =
467 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
468 if (trusted_match)
469 return_key = smime_copy_key(trusted_match);
470 else if (valid_match && !c_crypt_opportunistic_encrypt_strong_keys)
471 return_key = smime_copy_key(valid_match);
472 else
473 return_key = NULL;
474 }
475 else if (trusted_match && !multi_trusted_matches)
476 {
477 return_key = smime_copy_key(trusted_match);
478 }
479 else
480 {
481 return_key = smime_copy_key(dlg_smime(matches, mailbox));
482 }
483
484 smime_key_free(&matches);
485 }
486
487 return return_key;
488}
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:194
+ 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 497 of file smime.c.

498{
499 if (!str)
500 return NULL;
501
502 struct SmimeKey *results = NULL, *result = NULL;
503 struct SmimeKey *matches = NULL;
504 struct SmimeKey **matches_end = &matches;
505 struct SmimeKey *match = NULL;
506 struct SmimeKey *return_key = NULL;
507
508 results = smime_get_candidates(str, only_public_key);
509 for (result = results; result; result = result->next)
510 {
511 if (abilities && !(result->flags & abilities))
512 {
513 continue;
514 }
515
516 if (mutt_istr_equal(str, result->hash) ||
517 mutt_istr_find(result->email, str) || mutt_istr_find(result->label, str))
518 {
519 match = smime_copy_key(result);
520 *matches_end = match;
521 matches_end = &match->next;
522 }
523 }
524
525 smime_key_free(&results);
526
527 if (matches)
528 {
529 return_key = smime_copy_key(dlg_smime(matches, str));
530 smime_key_free(&matches);
531 }
532
533 return return_key;
534}
+ 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 543 of file smime.c.

544{
545 if (!prompt)
546 return NULL;
547
548 struct SmimeKey *key = NULL;
549 struct Buffer *resp = buf_pool_get();
550
552
553 while (true)
554 {
555 buf_reset(resp);
556 if (mw_get_field(prompt, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
557 {
558 goto done;
559 }
560
561 key = smime_get_key_by_str(buf_string(resp), abilities, only_public_key);
562 if (key)
563 goto done;
564
565 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
566 }
567
568done:
569 buf_pool_release(&resp);
570 return key;
571}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
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:273
#define mutt_error(...)
Definition logging2.h:93
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:59
#define _(a)
Definition message.h:28
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition mutt.h:56
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:497
+ 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 580 of file smime.c.

581{
582 const char *k = NULL;
583
584 struct SmimeKey *key = smime_get_key_by_addr(mailbox, KEYFLAG_CANENCRYPT, false, false);
585
586 if (!key)
587 {
588 struct Buffer *prompt = buf_pool_get();
589 buf_printf(prompt, _("Enter keyID for %s: "), mailbox);
590 key = smime_ask_for_key(buf_string(prompt), KEYFLAG_CANENCRYPT, false);
591 buf_pool_release(&prompt);
592 }
593
594 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
595 size_t smime_keys_len = mutt_str_len(c_smime_keys);
596
597 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
598 k = key ? key->hash : NONULL(c_smime_default_key);
599
600 /* if the key is different from last time */
601 if ((buf_len(&SmimeKeyToUse) <= smime_keys_len) ||
602 !mutt_istr_equal(k, SmimeKeyToUse.data + smime_keys_len + 1))
603 {
605 buf_printf(&SmimeKeyToUse, "%s/%s", NONULL(c_smime_keys), k);
606 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
607 buf_printf(&SmimeCertToUse, "%s/%s", NONULL(c_smime_certificates), k);
608 }
609
610 smime_key_free(&key);
611}
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:491
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:148
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:498
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:416
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:543
+ 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 704 of file smime.c.

706{
707 char email[256] = { 0 };
708 int rc = -1, count = 0;
709 pid_t pid;
710
711 FILE *fp_err = mutt_file_mkstemp();
712 if (!fp_err)
713 {
714 mutt_perror(_("Can't create temporary file"));
715 return 1;
716 }
717
718 FILE *fp_out = mutt_file_mkstemp();
719 if (!fp_out)
720 {
721 mutt_file_fclose(&fp_err);
722 mutt_perror(_("Can't create temporary file"));
723 return 1;
724 }
725
726 const struct Expando *c_smime_get_cert_email_command =
727 cs_subset_expando(NeoMutt->sub, "smime_get_cert_email_command");
728 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), certificate,
729 NULL, NULL, NULL, NULL, NULL, NULL, c_smime_get_cert_email_command);
730 if (pid == -1)
731 {
732 mutt_message(_("Error: unable to create OpenSSL subprocess"));
733 mutt_file_fclose(&fp_err);
734 mutt_file_fclose(&fp_out);
735 return 1;
736 }
737
738 filter_wait(pid);
739
740 fflush(fp_out);
741 rewind(fp_out);
742 fflush(fp_err);
743 rewind(fp_err);
744
745 while ((fgets(email, sizeof(email), fp_out)))
746 {
747 size_t len = mutt_str_len(email);
748 if (len && (email[len - 1] == '\n'))
749 email[len - 1] = '\0';
750 if (mutt_istr_startswith(email, mailbox))
751 rc = 1;
752
753 rc = (rc < 0) ? 0 : rc;
754 count++;
755 }
756
757 if (rc == -1)
758 {
759 mutt_endwin();
760 mutt_file_copy_stream(fp_err, stdout);
761 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
762 rc = 1;
763 }
764 else if (rc == 0)
765 {
766 rc = 1;
767 }
768 else
769 {
770 rc = 0;
771 }
772
773 if (copy && buffer && num)
774 {
775 (*num) = count;
776 *buffer = MUTT_MEM_CALLOC(count, char *);
777 count = 0;
778
779 rewind(fp_out);
780 while ((fgets(email, sizeof(email), fp_out)))
781 {
782 size_t len = mutt_str_len(email);
783 if (len && (email[len - 1] == '\n'))
784 email[len - 1] = '\0';
785 (*buffer)[count] = MUTT_MEM_CALLOC(mutt_str_len(email) + 1, char);
786 strncpy((*buffer)[count], email, mutt_str_len(email));
787 count++;
788 }
789 }
790 else if (copy)
791 {
792 rc = 2;
793 }
794
795 mutt_file_fclose(&fp_out);
796 mutt_file_fclose(&fp_err);
797
798 return rc;
799}
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:225
#define mutt_message(...)
Definition logging2.h:92
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:220
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:244
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:224
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 806 of file smime.c.

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

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

1153{
1154 const char *const c_smime_encrypt_with = cs_subset_string(NeoMutt->sub, "smime_encrypt_with");
1155 const struct Expando *c_smime_encrypt_command = cs_subset_expando(NeoMutt->sub, "smime_encrypt_command");
1156 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1157 fp_smime_outfd, fp_smime_errfd, fname, NULL, c_smime_encrypt_with,
1158 NULL, NULL, uids, NULL, c_smime_encrypt_command);
1159}
+ 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 1176 of file smime.c.

1179{
1180 const char *const c_smime_sign_digest_alg = cs_subset_string(NeoMutt->sub, "smime_sign_digest_alg");
1181 const struct Expando *c_smime_sign_command = cs_subset_expando(NeoMutt->sub, "smime_sign_command");
1182 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd, fp_smime_outfd,
1183 fp_smime_errfd, fname, NULL, NULL, c_smime_sign_digest_alg,
1185 buf_string(&SmimeIntermediateToUse), c_smime_sign_command);
1186}
+ 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 1335 of file smime.c.

1336{
1337 if (!md)
1338 return NULL;
1339
1340 char *micalg = NULL;
1341 if (mutt_istr_startswith(md, "sha"))
1342 {
1343 mutt_str_asprintf(&micalg, "sha-%s", md + 3);
1344 }
1345 else
1346 {
1347 micalg = mutt_str_dup(md);
1348 }
1349
1350 return micalg;
1351}
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:803
+ 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 1526 of file smime.c.

1530{
1531 const struct Expando *c_smime_verify_opaque_command =
1532 cs_subset_expando(NeoMutt->sub, "smime_verify_opaque_command");
1533 const struct Expando *c_smime_verify_command = cs_subset_expando(NeoMutt->sub, "smime_verify_command");
1534 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd, fp_smime_outfd,
1535 fp_smime_errfd, fname, sig_fname, NULL, NULL, NULL, NULL, NULL,
1536 (opaque ? c_smime_verify_opaque_command : c_smime_verify_command));
1537}
+ 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 1554 of file smime.c.

1557{
1558 const struct Expando *c_smime_decrypt_command = cs_subset_expando(NeoMutt->sub, "smime_decrypt_command");
1559 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1560 fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL, NULL,
1562 NULL, c_smime_decrypt_command);
1563}
+ 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 1682 of file smime.c.

1683{
1684 struct Buffer *tmpfname = buf_pool_get();
1685 FILE *fp_smime_out = NULL, *fp_smime_in = NULL, *fp_smime_err = NULL;
1686 FILE *fp_tmp = NULL, *fp_out = NULL;
1687 struct Body *p = NULL;
1688 pid_t pid = -1;
1690
1691 if (!(type & APPLICATION_SMIME))
1692 return NULL;
1693
1694 /* Because of the mutt_body_handler() we avoid the buffer pool. */
1695 fp_smime_out = mutt_file_mkstemp();
1696 if (!fp_smime_out)
1697 {
1698 mutt_perror(_("Can't create temporary file"));
1699 goto cleanup;
1700 }
1701
1702 fp_smime_err = mutt_file_mkstemp();
1703 if (!fp_smime_err)
1704 {
1705 mutt_perror(_("Can't create temporary file"));
1706 goto cleanup;
1707 }
1708
1709 buf_mktemp(tmpfname);
1710 fp_tmp = mutt_file_fopen(buf_string(tmpfname), "w+");
1711 if (!fp_tmp)
1712 {
1713 mutt_perror("%s", buf_string(tmpfname));
1714 goto cleanup;
1715 }
1716
1717 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
1718 {
1719 goto cleanup;
1720 }
1721
1722 mutt_file_copy_bytes(state->fp_in, fp_tmp, b->length);
1723
1724 fflush(fp_tmp);
1725 mutt_file_fclose(&fp_tmp);
1726
1727 if ((type & SEC_ENCRYPT) &&
1728 ((pid = smime_invoke_decrypt(&fp_smime_in, NULL, NULL, -1, fileno(fp_smime_out),
1729 fileno(fp_smime_err), buf_string(tmpfname))) == -1))
1730 {
1731 mutt_file_unlink(buf_string(tmpfname));
1732 if (state->flags & STATE_DISPLAY)
1733 {
1734 state_attach_puts(state, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1735 }
1736 goto cleanup;
1737 }
1738 else if ((type & SEC_SIGNOPAQUE) &&
1739 ((pid = smime_invoke_verify(&fp_smime_in, NULL, NULL, -1,
1740 fileno(fp_smime_out), fileno(fp_smime_err), NULL,
1741 buf_string(tmpfname), SEC_SIGNOPAQUE)) == -1))
1742 {
1743 mutt_file_unlink(buf_string(tmpfname));
1744 if (state->flags & STATE_DISPLAY)
1745 {
1746 state_attach_puts(state, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1747 }
1748 goto cleanup;
1749 }
1750
1751 if (type & SEC_ENCRYPT)
1752 {
1755 fputs(SmimePass, fp_smime_in);
1756 fputc('\n', fp_smime_in);
1757 }
1758
1759 mutt_file_fclose(&fp_smime_in);
1760
1761 filter_wait(pid);
1762 mutt_file_unlink(buf_string(tmpfname));
1763
1764 if (state->flags & STATE_DISPLAY)
1765 {
1766 fflush(fp_smime_err);
1767 rewind(fp_smime_err);
1768
1769 const int c = fgetc(fp_smime_err);
1770 if (c != EOF)
1771 {
1772 ungetc(c, fp_smime_err);
1773
1774 crypt_current_time(state, "OpenSSL");
1775 mutt_file_copy_stream(fp_smime_err, state->fp_out);
1776 state_attach_puts(state, _("[-- End of OpenSSL output --]\n\n"));
1777 }
1778
1779 if (type & SEC_ENCRYPT)
1780 {
1781 state_attach_puts(state, _("[-- The following data is S/MIME encrypted --]\n"));
1782 }
1783 else
1784 {
1785 state_attach_puts(state, _("[-- The following data is S/MIME signed --]\n"));
1786 }
1787 }
1788
1789 fflush(fp_smime_out);
1790 rewind(fp_smime_out);
1791
1792 if (type & SEC_ENCRYPT)
1793 {
1794 /* void the passphrase, even if that wasn't the problem */
1795 if (fgetc(fp_smime_out) == EOF)
1796 {
1797 mutt_error(_("Decryption failed"));
1799 }
1800 rewind(fp_smime_out);
1801 }
1802
1803 if (fp_out_file)
1804 {
1805 fp_out = fp_out_file;
1806 }
1807 else
1808 {
1809 fp_out = mutt_file_mkstemp();
1810 if (!fp_out)
1811 {
1812 mutt_perror(_("Can't create temporary file"));
1813 goto cleanup;
1814 }
1815 }
1816 char buf[8192] = { 0 };
1817 while (fgets(buf, sizeof(buf) - 1, fp_smime_out))
1818 {
1819 const size_t len = mutt_str_len(buf);
1820 if ((len > 1) && (buf[len - 2] == '\r'))
1821 {
1822 buf[len - 2] = '\n';
1823 buf[len - 1] = '\0';
1824 }
1825 fputs(buf, fp_out);
1826 }
1827 fflush(fp_out);
1828 rewind(fp_out);
1829
1830 const long size = mutt_file_get_size_fp(fp_out);
1831 if (size == 0)
1832 {
1833 goto cleanup;
1834 }
1835 p = mutt_read_mime_header(fp_out, 0);
1836 if (p)
1837 {
1838 p->length = size - p->offset;
1839
1840 mutt_parse_part(fp_out, p);
1841
1842 if (state->flags & STATE_DISPLAY)
1844
1845 /* Store any protected headers in the parent so they can be
1846 * accessed for index updates after the handler recursion is done.
1847 * This is done before the handler to prevent a nested encrypted
1848 * handler from freeing the headers. */
1850 b->mime_headers = p->mime_headers;
1851 p->mime_headers = NULL;
1852
1853 if (state->fp_out)
1854 {
1855 rewind(fp_out);
1856 FILE *fp_tmp_buffer = state->fp_in;
1857 state->fp_in = fp_out;
1858 mutt_body_handler(p, state);
1859 state->fp_in = fp_tmp_buffer;
1860 }
1861
1862 /* Embedded multipart signed protected headers override the
1863 * encrypted headers. We need to do this after the handler so
1864 * they can be printed in the pager. */
1865 if (!(type & SMIME_SIGN) && mutt_is_multipart_signed(p) && p->parts &&
1866 p->parts->mime_headers)
1867 {
1870 p->parts->mime_headers = NULL;
1871 }
1872 }
1873 mutt_file_fclose(&fp_smime_out);
1874
1875 if (!fp_out_file)
1876 {
1877 mutt_file_fclose(&fp_out);
1878 mutt_file_unlink(buf_string(tmpfname));
1879 }
1880 fp_out = NULL;
1881
1882 if (state->flags & STATE_DISPLAY)
1883 {
1884 if (type & SEC_ENCRYPT)
1885 state_attach_puts(state, _("[-- End of S/MIME encrypted data --]\n"));
1886 else
1887 state_attach_puts(state, _("[-- End of S/MIME signed data --]\n"));
1888 }
1889
1890 if (type & SEC_SIGNOPAQUE)
1891 {
1892 char *line = NULL;
1893 size_t linelen;
1894
1895 rewind(fp_smime_err);
1896
1897 line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, MUTT_RL_NO_FLAGS);
1898 if (linelen && mutt_istr_equal(line, "verification successful"))
1899 b->goodsig = true;
1900 FREE(&line);
1901 }
1902 else if (p)
1903 {
1904 b->goodsig = p->goodsig;
1905 b->badsig = p->badsig;
1906 }
1907
1908cleanup:
1909 mutt_file_fclose(&fp_smime_out);
1910 mutt_file_fclose(&fp_smime_err);
1911 mutt_file_fclose(&fp_tmp);
1912 mutt_file_fclose(&fp_out);
1913 buf_pool_release(&tmpfname);
1914 return p;
1915}
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:65
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition parse.c:1821
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1361
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:126
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:685
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:195
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1430
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:655
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition file.h:40
bool smime_class_valid_passphrase(void)
Ensure we have a valid passphrase - Implements CryptModuleSpecs::valid_passphrase() -.
Definition smime.c:157
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition crypt.c:1118
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1632
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition state.c:104
#define STATE_DISPLAY
Output is displayed to the user.
Definition state.h:33
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition lib.h:82
#define SEC_SIGNOPAQUE
Email has an opaque signature (encrypted)
Definition lib.h:89
#define SMIME_SIGN
Definition lib.h:109
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:97
#define SEC_ENCRYPT
Email is encrypted.
Definition lib.h:84
static char SmimePass[256]
Cached Smime Passphrase.
Definition smime.c:67
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:1526
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:1554
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
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:52
FILE * fp_out
File to write to.
Definition state.h:50
FILE * fp_in
File to read from.
Definition state.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ SmimePass

char SmimePass[256]
static

Cached Smime Passphrase.

Definition at line 67 of file smime.c.

◆ SmimeExpTime

time_t SmimeExpTime = 0
static

Unix time when SmimePass expires.

Definition at line 69 of file smime.c.

◆ SmimeKeyToUse

struct Buffer SmimeKeyToUse = { 0 }
static

Smime key to use.

Definition at line 72 of file smime.c.

72{ 0 };

◆ SmimeCertToUse

struct Buffer SmimeCertToUse = { 0 }
static

Smime certificate to use.

Definition at line 74 of file smime.c.

74{ 0 };

◆ SmimeIntermediateToUse

struct Buffer SmimeIntermediateToUse = { 0 }
static

Smime intermediate certificate to use.

Definition at line 76 of file smime.c.

76{ 0 };