NeoMutt  2022-04-29-145-g9b6a0e
Teaching an old dog new tricks
DOXYGEN
sign_message()

Cryptographically sign the Body of a message. More...

+ Collaboration diagram for sign_message():

Functions

struct Bodypgp_gpgme_sign_message (struct Body *a, const struct AddressList *from)
 Implements CryptModuleSpecs::sign_message() -. More...
 
struct Bodysmime_gpgme_sign_message (struct Body *a, const struct AddressList *from)
 Implements CryptModuleSpecs::sign_message() -. More...
 
struct Bodypgp_class_sign_message (struct Body *a, const struct AddressList *from)
 Implements CryptModuleSpecs::sign_message() -. More...
 
struct Bodysmime_class_sign_message (struct Body *a, const struct AddressList *from)
 Implements CryptModuleSpecs::sign_message() -. More...
 

Detailed Description

Cryptographically sign the Body of a message.

Parameters
aBody of the message
fromFrom line
Return values
ptrNew encrypted Body
NULLError

Function Documentation

◆ pgp_gpgme_sign_message()

struct Body* pgp_gpgme_sign_message ( struct Body a,
const struct AddressList *  from 
)

Implements CryptModuleSpecs::sign_message() -.

Definition at line 1384 of file crypt_gpgme.c.

1385 {
1386  return sign_message(a, from, false);
1387 }
static struct Body * sign_message(struct Body *a, const struct AddressList *from, bool use_smime)
Sign a message.
Definition: crypt_gpgme.c:1263
+ Here is the call graph for this function:

◆ smime_gpgme_sign_message()

struct Body* smime_gpgme_sign_message ( struct Body a,
const struct AddressList *  from 
)

Implements CryptModuleSpecs::sign_message() -.

Definition at line 1392 of file crypt_gpgme.c.

1393 {
1394  return sign_message(a, from, true);
1395 }
+ Here is the call graph for this function:

◆ pgp_class_sign_message()

struct Body* pgp_class_sign_message ( struct Body a,
const struct AddressList *  from 
)

Implements CryptModuleSpecs::sign_message() -.

Definition at line 1315 of file pgp.c.

1316 {
1317  struct Body *t = NULL, *rv = NULL;
1318  char buf[1024];
1319  FILE *fp_pgp_in = NULL, *fp_pgp_out = NULL, *fp_pgp_err = NULL, *fp_signed = NULL;
1320  bool err = false;
1321  bool empty = true;
1322  pid_t pid;
1323  struct Buffer *sigfile = mutt_buffer_pool_get();
1324  struct Buffer *signedfile = mutt_buffer_pool_get();
1325 
1326  crypt_convert_to_7bit(a); /* Signed data _must_ be in 7-bit format. */
1327 
1328  mutt_buffer_mktemp(sigfile);
1329  FILE *fp_sig = mutt_file_fopen(mutt_buffer_string(sigfile), "w");
1330  if (!fp_sig)
1331  {
1332  goto cleanup;
1333  }
1334 
1335  mutt_buffer_mktemp(signedfile);
1336  fp_signed = mutt_file_fopen(mutt_buffer_string(signedfile), "w");
1337  if (!fp_signed)
1338  {
1339  mutt_perror(mutt_buffer_string(signedfile));
1340  mutt_file_fclose(&fp_sig);
1341  unlink(mutt_buffer_string(sigfile));
1342  goto cleanup;
1343  }
1344 
1345  mutt_write_mime_header(a, fp_signed, NeoMutt->sub);
1346  fputc('\n', fp_signed);
1347  mutt_write_mime_body(a, fp_signed, NeoMutt->sub);
1348  mutt_file_fclose(&fp_signed);
1349 
1350  pid = pgp_invoke_sign(&fp_pgp_in, &fp_pgp_out, &fp_pgp_err, -1, -1, -1,
1351  mutt_buffer_string(signedfile));
1352  if (pid == -1)
1353  {
1354  mutt_perror(_("Can't open PGP subprocess"));
1355  mutt_file_fclose(&fp_sig);
1356  unlink(mutt_buffer_string(sigfile));
1357  unlink(mutt_buffer_string(signedfile));
1358  goto cleanup;
1359  }
1360 
1361  if (!pgp_use_gpg_agent())
1362  fputs(PgpPass, fp_pgp_in);
1363  fputc('\n', fp_pgp_in);
1364  mutt_file_fclose(&fp_pgp_in);
1365 
1366  /* Read back the PGP signature. Also, change MESSAGE=>SIGNATURE as
1367  * recommended for future releases of PGP. */
1368  while (fgets(buf, sizeof(buf) - 1, fp_pgp_out))
1369  {
1370  if (mutt_str_equal("-----BEGIN PGP MESSAGE-----\n", buf))
1371  fputs("-----BEGIN PGP SIGNATURE-----\n", fp_sig);
1372  else if (mutt_str_equal("-----END PGP MESSAGE-----\n", buf))
1373  fputs("-----END PGP SIGNATURE-----\n", fp_sig);
1374  else
1375  fputs(buf, fp_sig);
1376  empty = false; /* got some output, so we're ok */
1377  }
1378 
1379  /* check for errors from PGP */
1380  err = false;
1381  while (fgets(buf, sizeof(buf) - 1, fp_pgp_err))
1382  {
1383  err = true;
1384  fputs(buf, stdout);
1385  }
1386 
1387  const bool c_pgp_check_exit = cs_subset_bool(NeoMutt->sub, "pgp_check_exit");
1388  if (filter_wait(pid) && c_pgp_check_exit)
1389  empty = true;
1390 
1391  mutt_file_fclose(&fp_pgp_err);
1392  mutt_file_fclose(&fp_pgp_out);
1393  unlink(mutt_buffer_string(signedfile));
1394 
1395  if (mutt_file_fclose(&fp_sig) != 0)
1396  {
1397  mutt_perror("fclose");
1398  unlink(mutt_buffer_string(sigfile));
1399  goto cleanup;
1400  }
1401 
1402  if (err)
1404  if (empty)
1405  {
1406  unlink(mutt_buffer_string(sigfile));
1407  /* most likely error is a bad passphrase, so automatically forget it */
1409  goto cleanup; /* fatal error while signing */
1410  }
1411 
1412  t = mutt_body_new();
1413  t->type = TYPE_MULTIPART;
1414  t->subtype = mutt_str_dup("signed");
1415  t->encoding = ENC_7BIT;
1416  t->use_disp = false;
1417  t->disposition = DISP_INLINE;
1418  rv = t;
1419 
1421  mutt_param_set(&t->parameter, "protocol", "application/pgp-signature");
1422  mutt_param_set(&t->parameter, "micalg", pgp_micalg(mutt_buffer_string(sigfile)));
1423 
1424  t->parts = a;
1425 
1426  t->parts->next = mutt_body_new();
1427  t = t->parts->next;
1428  t->type = TYPE_APPLICATION;
1429  t->subtype = mutt_str_dup("pgp-signature");
1430  t->filename = mutt_buffer_strdup(sigfile);
1431  t->use_disp = false;
1432  t->disposition = DISP_NONE;
1433  t->encoding = ENC_7BIT;
1434  t->unlink = true; /* ok to remove this file after sending. */
1435  mutt_param_set(&t->parameter, "name", "signature.asc");
1436 
1437 cleanup:
1438  mutt_buffer_pool_release(&sigfile);
1439  mutt_buffer_pool_release(&signedfile);
1440  return rv;
1441 }
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:430
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
void crypt_convert_to_7bit(struct Body *a)
Convert an email to 7bit encoding.
Definition: crypt.c:795
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:388
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
void pgp_class_void_passphrase(void)
Implements CryptModuleSpecs::void_passphrase() -.
Definition: pgp.c:75
#define mutt_perror(...)
Definition: logging.h:88
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:760
@ ENC_7BIT
7-bit text
Definition: mime.h:49
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
@ DISP_NONE
No preferred disposition.
Definition: mime.h:65
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:86
#define _(a)
Definition: message.h:28
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:784
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
char PgpPass[1024]
Definition: pgp.c:69
bool pgp_use_gpg_agent(void)
Does the user want to use the gpg agent?
Definition: pgp.c:127
pid_t pgp_invoke_sign(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
Use PGP to sign a file.
Definition: pgpinvoke.c:325
const char * pgp_micalg(const char *fname)
Find the hash algorithm of a file.
Definition: pgpmicalg.c:227
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
The body of an email.
Definition: body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:67
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:47
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
struct Body * next
next attachment in the list
Definition: body.h:71
char * subtype
content-type subtype
Definition: body.h:60
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
String manipulation buffer.
Definition: buffer.h:34
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:

◆ smime_class_sign_message()

struct Body* smime_class_sign_message ( struct Body a,
const struct AddressList *  from 
)

Implements CryptModuleSpecs::sign_message() -.

Definition at line 1519 of file smime.c.

1520 {
1521  struct Body *t = NULL;
1522  struct Body *retval = NULL;
1523  char buf[1024];
1524  struct Buffer *filetosign = NULL, *signedfile = NULL;
1525  FILE *fp_smime_in = NULL, *fp_smime_out = NULL, *fp_smime_err = NULL, *fp_sign = NULL;
1526  int err = 0;
1527  int empty = 0;
1528  pid_t pid;
1529  const char *intermediates = NULL;
1530 
1531  const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
1532  const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
1533  const char *signas = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
1534  if (!signas || (*signas == '\0'))
1535  {
1536  mutt_error(_("Can't sign: No key specified. Use Sign As."));
1537  return NULL;
1538  }
1539 
1540  crypt_convert_to_7bit(a); /* Signed data _must_ be in 7-bit format. */
1541 
1542  filetosign = mutt_buffer_pool_get();
1543  signedfile = mutt_buffer_pool_get();
1544 
1545  mutt_buffer_mktemp(filetosign);
1546  fp_sign = mutt_file_fopen(mutt_buffer_string(filetosign), "w+");
1547  if (!fp_sign)
1548  {
1549  mutt_perror(mutt_buffer_string(filetosign));
1550  goto cleanup;
1551  }
1552 
1553  mutt_buffer_mktemp(signedfile);
1554  fp_smime_out = mutt_file_fopen(mutt_buffer_string(signedfile), "w+");
1555  if (!fp_smime_out)
1556  {
1557  mutt_perror(mutt_buffer_string(signedfile));
1558  goto cleanup;
1559  }
1560 
1561  mutt_write_mime_header(a, fp_sign, NeoMutt->sub);
1562  fputc('\n', fp_sign);
1563  mutt_write_mime_body(a, fp_sign, NeoMutt->sub);
1564  mutt_file_fclose(&fp_sign);
1565 
1566  const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
1567  const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
1568  mutt_buffer_printf(&SmimeKeyToUse, "%s/%s", NONULL(c_smime_keys), signas);
1569  mutt_buffer_printf(&SmimeCertToUse, "%s/%s", NONULL(c_smime_certificates), signas);
1570 
1571  struct SmimeKey *signas_key = smime_get_key_by_hash(signas, 1);
1572  if (!signas_key || mutt_str_equal("?", signas_key->issuer))
1573  intermediates = signas; /* so openssl won't complain in any case */
1574  else
1575  intermediates = signas_key->issuer;
1576 
1578  NONULL(c_smime_certificates), intermediates);
1579 
1580  smime_key_free(&signas_key);
1581 
1582  pid = smime_invoke_sign(&fp_smime_in, NULL, &fp_smime_err, -1,
1583  fileno(fp_smime_out), -1, mutt_buffer_string(filetosign));
1584  if (pid == -1)
1585  {
1586  mutt_perror(_("Can't open OpenSSL subprocess"));
1587  mutt_file_unlink(mutt_buffer_string(filetosign));
1588  goto cleanup;
1589  }
1590  fputs(SmimePass, fp_smime_in);
1591  fputc('\n', fp_smime_in);
1592  mutt_file_fclose(&fp_smime_in);
1593 
1594  filter_wait(pid);
1595 
1596  /* check for errors from OpenSSL */
1597  err = 0;
1598  fflush(fp_smime_err);
1599  rewind(fp_smime_err);
1600  while (fgets(buf, sizeof(buf) - 1, fp_smime_err))
1601  {
1602  err = 1;
1603  fputs(buf, stdout);
1604  }
1605  mutt_file_fclose(&fp_smime_err);
1606 
1607  fflush(fp_smime_out);
1608  rewind(fp_smime_out);
1609  empty = (fgetc(fp_smime_out) == EOF);
1610  mutt_file_fclose(&fp_smime_out);
1611 
1612  mutt_file_unlink(mutt_buffer_string(filetosign));
1613 
1614  if (err)
1616 
1617  if (empty)
1618  {
1619  mutt_any_key_to_continue(_("No output from OpenSSL..."));
1620  mutt_file_unlink(mutt_buffer_string(signedfile));
1621  goto cleanup; /* fatal error while signing */
1622  }
1623 
1624  t = mutt_body_new();
1625  t->type = TYPE_MULTIPART;
1626  t->subtype = mutt_str_dup("signed");
1627  t->encoding = ENC_7BIT;
1628  t->use_disp = false;
1629  t->disposition = DISP_INLINE;
1630 
1632 
1633  const char *const c_smime_sign_digest_alg = cs_subset_string(NeoMutt->sub, "smime_sign_digest_alg");
1634  char *micalg = openssl_md_to_smime_micalg(c_smime_sign_digest_alg);
1635  mutt_param_set(&t->parameter, "micalg", micalg);
1636  FREE(&micalg);
1637 
1638  mutt_param_set(&t->parameter, "protocol", "application/x-pkcs7-signature");
1639 
1640  t->parts = a;
1641  retval = t;
1642 
1643  t->parts->next = mutt_body_new();
1644  t = t->parts->next;
1645  t->type = TYPE_APPLICATION;
1646  t->subtype = mutt_str_dup("x-pkcs7-signature");
1647  t->filename = mutt_buffer_strdup(signedfile);
1648  t->d_filename = mutt_str_dup("smime.p7s");
1649  t->use_disp = true;
1650  t->disposition = DISP_ATTACH;
1651  t->encoding = ENC_BASE64;
1652  t->unlink = true; /* ok to remove this file after sending. */
1653 
1654 cleanup:
1655  if (fp_sign)
1656  {
1657  mutt_file_fclose(&fp_sign);
1658  mutt_file_unlink(mutt_buffer_string(filetosign));
1659  }
1660  if (fp_smime_out)
1661  {
1662  mutt_file_fclose(&fp_smime_out);
1663  mutt_file_unlink(mutt_buffer_string(signedfile));
1664  }
1665  mutt_buffer_pool_release(&filetosign);
1666  mutt_buffer_pool_release(&signedfile);
1667  return retval;
1668 }
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:158
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
#define mutt_error(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:43
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ DISP_ATTACH
Content is attached.
Definition: mime.h:63
static struct Buffer SmimeIntermediateToUse
Definition: smime.c:83
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.
Definition: smime.c:1337
char SmimePass[256]
Definition: smime.c:78
static char * openssl_md_to_smime_micalg(const char *md)
Change the algorithm names.
Definition: smime.c:1496
static struct Buffer SmimeKeyToUse
Definition: smime.c:81
static struct Buffer SmimeCertToUse
Definition: smime.c:82
static struct SmimeKey * smime_get_key_by_hash(const char *hash, bool only_public_key)
Find a key by its hash.
Definition: smime.c:567
static void smime_key_free(struct SmimeKey **keylist)
Free a list of SMIME keys.
Definition: smime.c:109
#define NONULL(x)
Definition: string2.h:37
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition: body.h:56
An SIME key.
Definition: smime.h:44
char * issuer
Definition: smime.h:48
+ Here is the call graph for this function: