NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
crypt_gpgme.c File Reference

Wrapper for PGP/SMIME calls to GPGME. More...

#include "config.h"
#include <errno.h>
#include <gpg-error.h>
#include <gpgme.h>
#include <langinfo.h>
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/stat.h>
#include <time.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 "crypt_gpgme.h"
#include "lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "crypt.h"
#include "handler.h"
#include "hook.h"
#include "mutt_attach.h"
#include "mutt_logging.h"
#include "muttlib.h"
#include "options.h"
#include "autocrypt/lib.h"
+ Include dependency graph for crypt_gpgme.c:

Go to the source code of this file.

Data Structures

struct  CryptCache
 Internal cache for GPGME. More...
 

Macros

#define CRYPT_KV_VALID   (1 << 0)
 
#define CRYPT_KV_ADDR   (1 << 1)
 
#define CRYPT_KV_STRING   (1 << 2)
 
#define CRYPT_KV_STRONGID   (1 << 3)
 
#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)
 
#define PKA_NOTATION_NAME   "pka-address@gnupg.org"
 
#define _LINE_COMPARE(_x, _y)   line_compare(_x, sizeof(_x) - 1, _y)
 
#define MESSAGE(_y)   _LINE_COMPARE("MESSAGE-----", _y)
 
#define SIGNED_MESSAGE(_y)   _LINE_COMPARE("SIGNED MESSAGE-----", _y)
 
#define PUBLIC_KEY_BLOCK(_y)   _LINE_COMPARE("PUBLIC KEY BLOCK-----", _y)
 
#define BEGIN_PGP_SIGNATURE(_y)   _LINE_COMPARE("-----BEGIN PGP SIGNATURE-----", _y)
 

Functions

static bool is_pka_notation (gpgme_sig_notation_t notation)
 Is this the standard pka email address. More...
 
static void redraw_if_needed (gpgme_ctx_t ctx)
 accommodate for a redraw if needed More...
 
const char * crypt_keyid (struct CryptKeyInfo *k)
 Find the ID for the key. More...
 
static const char * crypt_long_keyid (struct CryptKeyInfo *k)
 Find the Long ID for the key. More...
 
static const char * crypt_short_keyid (struct CryptKeyInfo *k)
 Get the short keyID for a key. More...
 
static const char * crypt_fpr (struct CryptKeyInfo *k)
 Get the hexstring fingerprint from a key. More...
 
const char * crypt_fpr_or_lkeyid (struct CryptKeyInfo *k)
 Find the fingerprint of a key. More...
 
struct CryptKeyInfocrypt_copy_key (struct CryptKeyInfo *key)
 Return a copy of KEY. More...
 
static void crypt_key_free (struct CryptKeyInfo **keylist)
 Release all the keys in a list. More...
 
bool crypt_id_is_strong (struct CryptKeyInfo *key)
 Is the key strong. More...
 
int crypt_id_is_valid (struct CryptKeyInfo *key)
 Is key ID valid. More...
 
static int crypt_id_matches_addr (struct Address *addr, struct Address *u_addr, struct CryptKeyInfo *key)
 Does the key ID match the address. More...
 
gpgme_ctx_t create_gpgme_context (bool for_smime)
 Create a new GPGME context. More...
 
static gpgme_data_t create_gpgme_data (void)
 Create a new GPGME data object. More...
 
static gpgme_data_t body_to_data_object (struct Body *a, bool convert)
 Create GPGME object from the mail body. More...
 
static gpgme_data_t file_to_data_object (FILE *fp, long offset, size_t length)
 Create GPGME data object from file. More...
 
static int data_object_to_stream (gpgme_data_t data, FILE *fp)
 Write a GPGME data object to a file. More...
 
static char * data_object_to_tempfile (gpgme_data_t data, FILE **fp_ret)
 Copy a data object to a temporary file. More...
 
static void recipient_set_free (gpgme_key_t **p_rset)
 Free a set of recipients. More...
 
static gpgme_key_t * create_recipient_set (const char *keylist, bool use_smime)
 Create a GpgmeRecipientSet from a string of keys. More...
 
static bool set_signer_from_address (gpgme_ctx_t ctx, const char *address, bool for_smime)
 Try to set the context's signer from the address. More...
 
static int set_signer (gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
 Make sure that the correct signer is set. More...
 
static gpgme_error_t set_pka_sig_notation (gpgme_ctx_t ctx)
 Set the signature notation. More...
 
static char * encrypt_gpgme_object (gpgme_data_t plaintext, char *keylist, bool use_smime, bool combined_signed, const struct AddressList *from)
 Encrypt the GPGPME data object. More...
 
static int get_micalg (gpgme_ctx_t ctx, int use_smime, char *buf, size_t buflen)
 Find the "micalg" parameter from the last GPGME operation. More...
 
static void print_time (time_t t, struct State *s)
 Print the date/time according to the locale. More...
 
static struct Bodysign_message (struct Body *a, const struct AddressList *from, bool use_smime)
 Sign a message. More...
 
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_gpgme_encrypt_message (struct Body *a, char *keylist, bool sign, const struct AddressList *from)
 Implements CryptModuleSpecs::pgp_encrypt_message() -. More...
 
struct Bodysmime_gpgme_build_smime_entity (struct Body *a, char *keylist)
 Implements CryptModuleSpecs::smime_build_smime_entity() -. More...
 
static int show_sig_summary (unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key, int idx, struct State *s, gpgme_signature_t sig)
 Show a signature summary. More...
 
static void show_fingerprint (gpgme_key_t key, struct State *state)
 Write a key's fingerprint. More...
 
static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, struct State *s)
 Show the validity of a key used for one signature. More...
 
static void print_smime_keyinfo (const char *msg, gpgme_signature_t sig, gpgme_key_t key, struct State *s)
 Print key info about an SMIME key. More...
 
static int show_one_sig_status (gpgme_ctx_t ctx, int idx, struct State *s)
 Show information about one signature. More...
 
static int verify_one (struct Body *sigbdy, struct State *s, const char *tempfile, bool is_smime)
 Do the actual verification step. More...
 
int pgp_gpgme_verify_one (struct Body *sigbdy, struct State *s, const char *tempfile)
 Implements CryptModuleSpecs::verify_one() -. More...
 
int smime_gpgme_verify_one (struct Body *sigbdy, struct State *s, const char *tempfile)
 Implements CryptModuleSpecs::verify_one() -. More...
 
static struct Bodydecrypt_part (struct Body *a, struct State *s, FILE *fp_out, bool is_smime, int *r_is_signed)
 Decrypt a PGP or SMIME message. More...
 
int pgp_gpgme_decrypt_mime (FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
 Implements CryptModuleSpecs::decrypt_mime() -. More...
 
int smime_gpgme_decrypt_mime (FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
 Implements CryptModuleSpecs::decrypt_mime() -. More...
 
static int pgp_gpgme_extract_keys (gpgme_data_t keydata, FILE **fp)
 Write PGP keys to a file. More...
 
static int line_compare (const char *a, size_t n, const char *b)
 Compare two strings ignore line endings. More...
 
static int pgp_check_traditional_one_body (FILE *fp, struct Body *b)
 Check one inline PGP body part. More...
 
bool pgp_gpgme_check_traditional (FILE *fp, struct Body *b, bool just_one)
 Implements CryptModuleSpecs::pgp_check_traditional() -. More...
 
void pgp_gpgme_invoke_import (const char *fname)
 Implements CryptModuleSpecs::pgp_invoke_import() -. More...
 
static void copy_clearsigned (gpgme_data_t data, struct State *s, char *charset)
 Copy a clearsigned message. More...
 
int pgp_gpgme_application_handler (struct Body *m, struct State *s)
 Implements CryptModuleSpecs::application_handler() -. More...
 
int pgp_gpgme_encrypted_handler (struct Body *a, struct State *s)
 Implements CryptModuleSpecs::encrypted_handler() -This handler is passed the application/octet-stream directly. More...
 
int smime_gpgme_application_handler (struct Body *a, struct State *s)
 Implements CryptModuleSpecs::application_handler() -. More...
 
unsigned int key_check_cap (gpgme_key_t key, enum KeyCap cap)
 Check the capabilities of a key. More...
 
static char * list_to_pattern (struct ListHead *list)
 Convert STailQ to GPGME-compatible pattern. More...
 
static struct CryptKeyInfoget_candidates (struct ListHead *hints, SecurityFlags app, int secret)
 Get a list of keys which are candidates for the selection. More...
 
static void crypt_add_string_to_hints (const char *str, struct ListHead *hints)
 Split a string and add the parts to a List. More...
 
static struct CryptKeyInfocrypt_getkeybyaddr (struct Address *a, KeyFlags abilities, unsigned int app, int *forced_valid, bool oppenc_mode)
 Find a key by email address. More...
 
static struct CryptKeyInfocrypt_getkeybystr (const char *p, KeyFlags abilities, unsigned int app, int *forced_valid)
 Find a key by string. More...
 
static struct CryptKeyInfocrypt_ask_for_key (char *tag, char *whatfor, KeyFlags abilities, unsigned int app, int *forced_valid)
 Ask the user for a key. More...
 
static char * find_keys (struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
 Find keys of the recipients of the message. More...
 
char * pgp_gpgme_find_keys (struct AddressList *addrlist, bool oppenc_mode)
 Implements CryptModuleSpecs::find_keys() -. More...
 
char * smime_gpgme_find_keys (struct AddressList *addrlist, bool oppenc_mode)
 Implements CryptModuleSpecs::find_keys() -. More...
 
int mutt_gpgme_select_secret_key (struct Buffer *keyid)
 Select a private Autocrypt key for a new account. More...
 
struct Bodypgp_gpgme_make_key_attachment (void)
 Implements CryptModuleSpecs::pgp_make_key_attachment() -. More...
 
static void init_common (void)
 Initialise code common to PGP and SMIME parts of GPGME. More...
 
static void init_pgp (void)
 Initialise the PGP crypto backend. More...
 
static void init_smime (void)
 Initialise the SMIME crypto backend. More...
 
void pgp_gpgme_init (void)
 Implements CryptModuleSpecs::init() -. More...
 
void smime_gpgme_init (void)
 Implements CryptModuleSpecs::init() -. More...
 
static SecurityFlags gpgme_send_menu (struct Mailbox *m, struct Email *e, bool is_smime)
 Show the user the encryption/signing menu. More...
 
SecurityFlags pgp_gpgme_send_menu (struct Mailbox *m, struct Email *e)
 Implements CryptModuleSpecs::send_menu() -. More...
 
SecurityFlags smime_gpgme_send_menu (struct Mailbox *m, struct Email *e)
 Implements CryptModuleSpecs::send_menu() -. More...
 
static bool verify_sender (struct Email *e)
 Verify the sender of a message. More...
 
int smime_gpgme_verify_sender (struct Mailbox *m, struct Email *e, struct Message *msg)
 Implements CryptModuleSpecs::smime_verify_sender() -. More...
 
void pgp_gpgme_set_sender (const char *sender)
 Implements CryptModuleSpecs::set_sender() -. More...
 
const char * mutt_gpgme_print_version (void)
 Get version of GPGME. More...
 

Variables

static struct CryptCacheid_defaults = NULL
 
static gpgme_key_t signature_key = NULL
 
static char * current_sender = NULL
 

Detailed Description

Wrapper for PGP/SMIME calls to GPGME.

Authors
  • Michael R. Elkins
  • Thomas Roessler
  • Thomas Roessler
  • Oliver Ehli
  • 2018 g10 Code GmbH
  • Michael R. Elkins
  • Pietro Cerutti

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 crypt_gpgme.c.

Macro Definition Documentation

◆ CRYPT_KV_VALID

#define CRYPT_KV_VALID   (1 << 0)

Definition at line 75 of file crypt_gpgme.c.

◆ CRYPT_KV_ADDR

#define CRYPT_KV_ADDR   (1 << 1)

Definition at line 76 of file crypt_gpgme.c.

◆ CRYPT_KV_STRING

#define CRYPT_KV_STRING   (1 << 2)

Definition at line 77 of file crypt_gpgme.c.

◆ CRYPT_KV_STRONGID

#define CRYPT_KV_STRONGID   (1 << 3)

Definition at line 78 of file crypt_gpgme.c.

◆ CRYPT_KV_MATCH

#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)

Definition at line 79 of file crypt_gpgme.c.

◆ PKA_NOTATION_NAME

#define PKA_NOTATION_NAME   "pka-address@gnupg.org"

Definition at line 96 of file crypt_gpgme.c.

◆ _LINE_COMPARE

#define _LINE_COMPARE (   _x,
  _y 
)    line_compare(_x, sizeof(_x) - 1, _y)

Definition at line 98 of file crypt_gpgme.c.

◆ MESSAGE

#define MESSAGE (   _y)    _LINE_COMPARE("MESSAGE-----", _y)

Definition at line 99 of file crypt_gpgme.c.

◆ SIGNED_MESSAGE

#define SIGNED_MESSAGE (   _y)    _LINE_COMPARE("SIGNED MESSAGE-----", _y)

Definition at line 100 of file crypt_gpgme.c.

◆ PUBLIC_KEY_BLOCK

#define PUBLIC_KEY_BLOCK (   _y)    _LINE_COMPARE("PUBLIC KEY BLOCK-----", _y)

Definition at line 101 of file crypt_gpgme.c.

◆ BEGIN_PGP_SIGNATURE

#define BEGIN_PGP_SIGNATURE (   _y)    _LINE_COMPARE("-----BEGIN PGP SIGNATURE-----", _y)

Definition at line 102 of file crypt_gpgme.c.

Function Documentation

◆ is_pka_notation()

static bool is_pka_notation ( gpgme_sig_notation_t  notation)
static

Is this the standard pka email address.

Parameters
notationGPGME notation
Return values
trueIt is the standard pka email address

Definition at line 110 of file crypt_gpgme.c.

111 {
112  return mutt_str_equal(notation->name, PKA_NOTATION_NAME);
113 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
#define PKA_NOTATION_NAME
Definition: crypt_gpgme.c:96
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ redraw_if_needed()

static void redraw_if_needed ( gpgme_ctx_t  ctx)
static

accommodate for a redraw if needed

Parameters
ctxGPGME handle

Definition at line 119 of file crypt_gpgme.c.

120 {
121 #if (GPGME_VERSION_NUMBER < 0x010800)
122  /* gpgme_get_ctx_flag is not available in GPGME < 1.8.0. In this case, stay
123  * on the safe side and always redraw. */
124  (void) ctx;
126 #else
127  const char *s = gpgme_get_ctx_flag(ctx, "redraw");
128  if (!s /* flag not known */ || *s /* flag true */)
129  {
131  }
132 #endif
133 }
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:137
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_keyid()

const char* crypt_keyid ( struct CryptKeyInfo k)

Find the ID for the key.

Parameters
kKey to use
Return values
ptrID string for the key

Return the keyID for the key K. Note that this string is valid as long as K is valid

Definition at line 347 of file crypt_gpgme.c.

348 {
349  const char *s = "????????";
350 
351  if (k->kobj && k->kobj->subkeys)
352  {
353  s = k->kobj->subkeys->keyid;
354  const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
355  if ((!c_pgp_long_ids) && (strlen(s) == 16))
356  {
357  /* Return only the short keyID. */
358  s += 8;
359  }
360  }
361 
362  return s;
363 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Container for Accounts, Notifications.
Definition: neomutt.h:36
gpgme_key_t kobj
Definition: crypt_gpgme.h:47
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_long_keyid()

static const char* crypt_long_keyid ( struct CryptKeyInfo k)
static

Find the Long ID for the key.

Parameters
kKey to use
Return values
ptrLong ID string for the key

Return the long keyID for the key K.

Definition at line 372 of file crypt_gpgme.c.

373 {
374  const char *s = "????????????????";
375 
376  if (k->kobj && k->kobj->subkeys)
377  {
378  s = k->kobj->subkeys->keyid;
379  }
380 
381  return s;
382 }
gpgme_key_t kobj
Definition: crypt_gpgme.h:47
+ Here is the caller graph for this function:

◆ crypt_short_keyid()

static const char* crypt_short_keyid ( struct CryptKeyInfo k)
static

Get the short keyID for a key.

Parameters
kKey to use
Return values
ptrShort key string

Definition at line 389 of file crypt_gpgme.c.

390 {
391  const char *s = "????????";
392 
393  if (k->kobj && k->kobj->subkeys)
394  {
395  s = k->kobj->subkeys->keyid;
396  if (strlen(s) == 16)
397  s += 8;
398  }
399 
400  return s;
401 }
gpgme_key_t kobj
Definition: crypt_gpgme.h:47
+ Here is the caller graph for this function:

◆ crypt_fpr()

static const char* crypt_fpr ( struct CryptKeyInfo k)
static

Get the hexstring fingerprint from a key.

Parameters
kKey to use
Return values
ptrHexstring fingerprint

Definition at line 408 of file crypt_gpgme.c.

409 {
410  const char *s = "";
411 
412  if (k->kobj && k->kobj->subkeys)
413  s = k->kobj->subkeys->fpr;
414 
415  return s;
416 }
gpgme_key_t kobj
Definition: crypt_gpgme.h:47
+ Here is the caller graph for this function:

◆ crypt_fpr_or_lkeyid()

const char* crypt_fpr_or_lkeyid ( struct CryptKeyInfo k)

Find the fingerprint of a key.

Parameters
kKey to examine
Return values
ptrFingerprint if available, otherwise the long keyid

Definition at line 423 of file crypt_gpgme.c.

424 {
425  const char *s = "????????????????";
426 
427  if (k->kobj && k->kobj->subkeys)
428  {
429  if (k->kobj->subkeys->fpr)
430  s = k->kobj->subkeys->fpr;
431  else
432  s = k->kobj->subkeys->keyid;
433  }
434 
435  return s;
436 }
gpgme_key_t kobj
Definition: crypt_gpgme.h:47
+ Here is the caller graph for this function:

◆ crypt_copy_key()

struct CryptKeyInfo* crypt_copy_key ( struct CryptKeyInfo key)

Return a copy of KEY.

Parameters
keyKey to copy
Return values
ptrCopy of key

Definition at line 443 of file crypt_gpgme.c.

444 {
445  struct CryptKeyInfo *k = NULL;
446 
447  k = mutt_mem_calloc(1, sizeof(*k));
448  k->kobj = key->kobj;
449  gpgme_key_ref(key->kobj);
450  k->idx = key->idx;
451  k->uid = key->uid;
452  k->flags = key->flags;
453  k->validity = key->validity;
454 
455  return k;
456 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
A stored PGP key.
Definition: crypt_gpgme.h:44
int idx
and the user ID at this index
Definition: crypt_gpgme.h:48
const char * uid
and for convenience point to this user ID
Definition: crypt_gpgme.h:49
gpgme_key_t kobj
Definition: crypt_gpgme.h:47
KeyFlags flags
global and per uid flags (for convenience)
Definition: crypt_gpgme.h:50
gpgme_validity_t validity
uid validity (cached for convenience)
Definition: crypt_gpgme.h:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_key_free()

static void crypt_key_free ( struct CryptKeyInfo **  keylist)
static

Release all the keys in a list.

Parameters
[out]keylistList of keys

Definition at line 462 of file crypt_gpgme.c.

463 {
464  if (!keylist)
465  return;
466 
467  struct CryptKeyInfo *k = NULL;
468 
469  while (*keylist)
470  {
471  k = *keylist;
472  *keylist = (*keylist)->next;
473 
474  gpgme_key_unref(k->kobj);
475  FREE(&k);
476  }
477 }
struct CryptKeyInfo * next
Definition: crypt_gpgme.h:46
A stored PGP key.
Definition: crypt_gpgme.h:44
gpgme_key_t kobj
Definition: crypt_gpgme.h:47
#define FREE(x)
Definition: memory.h:40
+ Here is the caller graph for this function:

◆ crypt_id_is_strong()

bool crypt_id_is_strong ( struct CryptKeyInfo key)

Is the key strong.

Parameters
keyKey to test
Return values
trueValidity of key is sufficient

Definition at line 484 of file crypt_gpgme.c.

485 {
486  if (!key)
487  return false;
488 
489  bool is_strong = false;
490 
491  if ((key->flags & KEYFLAG_ISX509))
492  return true;
493 
494  switch (key->validity)
495  {
496  case GPGME_VALIDITY_MARGINAL:
497  case GPGME_VALIDITY_NEVER:
498  case GPGME_VALIDITY_UNDEFINED:
499  case GPGME_VALIDITY_UNKNOWN:
500  is_strong = false;
501  break;
502 
503  case GPGME_VALIDITY_FULL:
504  case GPGME_VALIDITY_ULTIMATE:
505  is_strong = true;
506  break;
507  }
508 
509  return is_strong;
510 }
#define KEYFLAG_ISX509
Key is an X.509 key.
Definition: lib.h:126
KeyFlags flags
global and per uid flags (for convenience)
Definition: crypt_gpgme.h:50
gpgme_validity_t validity
uid validity (cached for convenience)
Definition: crypt_gpgme.h:51
+ Here is the caller graph for this function:

◆ crypt_id_is_valid()

int crypt_id_is_valid ( struct CryptKeyInfo key)

Is key ID valid.

Parameters
keyKey to test
Return values
trueKey is valid

When the key is not marked as unusable

Definition at line 519 of file crypt_gpgme.c.

520 {
521  if (!key)
522  return 0;
523 
524  return !(key->flags & KEYFLAG_CANTUSE);
525 }
#define KEYFLAG_CANTUSE
Definition: lib.h:136
KeyFlags flags
global and per uid flags (for convenience)
Definition: crypt_gpgme.h:50
+ Here is the caller graph for this function:

◆ crypt_id_matches_addr()

static int crypt_id_matches_addr ( struct Address addr,
struct Address u_addr,
struct CryptKeyInfo key 
)
static

Does the key ID match the address.

Parameters
addrFirst email address
u_addrSecond email address
keyKey to use
Return values
numFlags, e.g. CRYPT_KV_VALID

Return a bit vector describing how well the addresses ADDR and U_ADDR match and whether KEY is valid.

Definition at line 537 of file crypt_gpgme.c.

539 {
540  int rc = 0;
541 
542  if (crypt_id_is_valid(key))
543  rc |= CRYPT_KV_VALID;
544 
545  if (crypt_id_is_strong(key))
546  rc |= CRYPT_KV_STRONGID;
547 
548  if (addr && u_addr)
549  {
550  if (addr->mailbox && u_addr->mailbox &&
551  mutt_istr_equal(addr->mailbox, u_addr->mailbox))
552  {
553  rc |= CRYPT_KV_ADDR;
554  }
555 
556  if (addr->personal && u_addr->personal &&
557  mutt_istr_equal(addr->personal, u_addr->personal))
558  {
559  rc |= CRYPT_KV_STRING;
560  }
561  }
562 
563  return rc;
564 }
#define CRYPT_KV_STRONGID
Definition: crypt_gpgme.c:78
#define CRYPT_KV_ADDR
Definition: crypt_gpgme.c:76
char * mailbox
Mailbox and host address.
Definition: address.h:38
#define CRYPT_KV_STRING
Definition: crypt_gpgme.c:77
int crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
Definition: crypt_gpgme.c:519
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
Definition: crypt_gpgme.c:484
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
char * personal
Real name of address.
Definition: address.h:37
#define CRYPT_KV_VALID
Definition: crypt_gpgme.c:75
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ create_gpgme_context()

gpgme_ctx_t create_gpgme_context ( bool  for_smime)

Create a new GPGME context.

Parameters
for_smimeIf true, protocol of the context is set to CMS
Return values
ptrNew GPGME context

Definition at line 571 of file crypt_gpgme.c.

572 {
573  gpgme_ctx_t ctx = NULL;
574 
575  gpgme_error_t err = gpgme_new(&ctx);
576 
577 #ifdef USE_AUTOCRYPT
578  const char *const c_autocrypt_dir =
579  cs_subset_path(NeoMutt->sub, "autocrypt_dir");
580  if (!err && OptAutocryptGpgme)
581  err = gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_OpenPGP, NULL, c_autocrypt_dir);
582 #endif
583 
584  if (err != 0)
585  {
586  mutt_error(_("error creating GPGME context: %s"), gpgme_strerror(err));
587  mutt_exit(1);
588  }
589 
590  if (for_smime)
591  {
592  err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
593  if (err != 0)
594  {
595  mutt_error(_("error enabling CMS protocol: %s"), gpgme_strerror(err));
596  mutt_exit(1);
597  }
598  }
599 
600  return ctx;
601 }
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
WHERE bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: options.h:33
Container for Accounts, Notifications.
Definition: neomutt.h:36
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_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:279
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ create_gpgme_data()

static gpgme_data_t create_gpgme_data ( void  )
static

Create a new GPGME data object.

Return values
ptrGPGPE data object

This is a wrapper to die on error.

Note
Call gpgme_data_release() to free the data object

Definition at line 611 of file crypt_gpgme.c.

612 {
613  gpgme_data_t data = NULL;
614 
615  gpgme_error_t err = gpgme_data_new(&data);
616  if (err != 0)
617  {
618  mutt_error(_("error creating GPGME data object: %s"), gpgme_strerror(err));
619  mutt_exit(1);
620  }
621  return data;
622 }
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:279
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ body_to_data_object()

static gpgme_data_t body_to_data_object ( struct Body a,
bool  convert 
)
static

Create GPGME object from the mail body.

Parameters
aBody to use
convertIf true, lines are converted to CR-LF if required
Return values
ptrNewly created GPGME data object

Definition at line 667 of file crypt_gpgme.c.

668 {
669  int err = 0;
670  gpgme_data_t data = NULL;
671 
672  struct Buffer *tempfile = mutt_buffer_pool_get();
673  mutt_buffer_mktemp(tempfile);
674  FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
675  if (!fp_tmp)
676  {
677  mutt_perror(mutt_buffer_string(tempfile));
678  goto cleanup;
679  }
680 
681  mutt_write_mime_header(a, fp_tmp, NeoMutt->sub);
682  fputc('\n', fp_tmp);
683  mutt_write_mime_body(a, fp_tmp, NeoMutt->sub);
684 
685  if (convert)
686  {
687  int c, hadcr = 0;
688  unsigned char buf[1];
689 
690  data = create_gpgme_data();
691  rewind(fp_tmp);
692  while ((c = fgetc(fp_tmp)) != EOF)
693  {
694  if (c == '\r')
695  hadcr = 1;
696  else
697  {
698  if ((c == '\n') && !hadcr)
699  {
700  buf[0] = '\r';
701  gpgme_data_write(data, buf, 1);
702  }
703 
704  hadcr = 0;
705  }
706  /* FIXME: This is quite suboptimal */
707  buf[0] = c;
708  gpgme_data_write(data, buf, 1);
709  }
710  mutt_file_fclose(&fp_tmp);
711  gpgme_data_seek(data, 0, SEEK_SET);
712  }
713  else
714  {
715  mutt_file_fclose(&fp_tmp);
716  err = gpgme_data_new_from_file(&data, mutt_buffer_string(tempfile), 1);
717  if (err != 0)
718  {
719  mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
720  gpgme_data_release(data);
721  data = NULL;
722  /* fall through to unlink the tempfile */
723  }
724  }
725  unlink(mutt_buffer_string(tempfile));
726 
727 cleanup:
728  mutt_buffer_pool_release(&tempfile);
729  return data;
730 }
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_error(...)
Definition: logging.h:88
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
#define mutt_perror(...)
Definition: logging.h:89
Container for Accounts, Notifications.
Definition: neomutt.h:36
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:764
char * data
Pointer to data.
Definition: buffer.h:35
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
Definition: crypt_gpgme.c:611
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ file_to_data_object()

static gpgme_data_t file_to_data_object ( FILE *  fp,
long  offset,
size_t  length 
)
static

Create GPGME data object from file.

Parameters
fpFile to read from
offsetOffset to start reading from
lengthLength of data to read
Return values
ptrNewly created GPGME data object

Definition at line 739 of file crypt_gpgme.c.

740 {
741  gpgme_data_t data = NULL;
742 
743  int err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length);
744  if (err != 0)
745  {
746  mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
747  return NULL;
748  }
749 
750  return data;
751 }
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
char * data
Pointer to data.
Definition: buffer.h:35
+ Here is the caller graph for this function:

◆ data_object_to_stream()

static int data_object_to_stream ( gpgme_data_t  data,
FILE *  fp 
)
static

Write a GPGME data object to a file.

Parameters
dataGPGME data object
fpFile to write to
Return values
0Success
-1Error

Definition at line 760 of file crypt_gpgme.c.

761 {
762  char buf[4096];
763  ssize_t nread;
764 
765  int err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno(errno) : 0);
766  if (err != 0)
767  {
768  mutt_error(_("error rewinding data object: %s"), gpgme_strerror(err));
769  return -1;
770  }
771 
772  while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
773  {
774  /* fixme: we are not really converting CRLF to LF but just
775  * skipping CR. Doing it correctly needs a more complex logic */
776  for (char *p = buf; nread; p++, nread--)
777  {
778  if (*p != '\r')
779  putc(*p, fp);
780  }
781 
782  if (ferror(fp))
783  {
784  mutt_perror(_("[tempfile]"));
785  return -1;
786  }
787  }
788  if (nread == -1)
789  {
790  mutt_error(_("error reading data object: %s"), strerror(errno));
791  return -1;
792  }
793  return 0;
794 }
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
#define mutt_perror(...)
Definition: logging.h:89
char * data
Pointer to data.
Definition: buffer.h:35
+ Here is the caller graph for this function:

◆ data_object_to_tempfile()

static char* data_object_to_tempfile ( gpgme_data_t  data,
FILE **  fp_ret 
)
static

Copy a data object to a temporary file.

Parameters
[in]dataGPGME data object
[out]fp_retTemporary file
Return values
ptrName of temporary file

If fp_ret is passed in, the file will be rewound, left open, and returned via that parameter.

Note
The caller must free the returned file name

Definition at line 807 of file crypt_gpgme.c.

808 {
809  ssize_t nread = 0;
810  char *rv = NULL;
811  struct Buffer *tempf = mutt_buffer_pool_get();
812 
813  mutt_buffer_mktemp(tempf);
814 
815  FILE *fp = mutt_file_fopen(mutt_buffer_string(tempf), "w+");
816  if (!fp)
817  {
818  mutt_perror(_("Can't create temporary file"));
819  goto cleanup;
820  }
821 
822  int err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno(errno) : 0);
823  if (err == 0)
824  {
825  char buf[4096];
826 
827  while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
828  {
829  if (fwrite(buf, nread, 1, fp) != 1)
830  {
832  mutt_file_fclose(&fp);
833  unlink(mutt_buffer_string(tempf));
834  goto cleanup;
835  }
836  }
837  }
838  if (fp_ret)
839  rewind(fp);
840  else
841  mutt_file_fclose(&fp);
842  if (nread == -1)
843  {
844  mutt_error(_("error reading data object: %s"), gpgme_strerror(err));
845  unlink(mutt_buffer_string(tempf));
846  mutt_file_fclose(&fp);
847  goto cleanup;
848  }
849  if (fp_ret)
850  *fp_ret = fp;
851  rv = mutt_buffer_strdup(tempf);
852 
853 cleanup:
854  mutt_buffer_pool_release(&tempf);
855  return rv;
856 }
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_error(...)
Definition: logging.h:88
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
#define mutt_perror(...)
Definition: logging.h:89
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
char * data
Pointer to data.
Definition: buffer.h:35
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ recipient_set_free()

static void recipient_set_free ( gpgme_key_t **  p_rset)
static

Free a set of recipients.

Parameters
p_rsetSet of GPGME keys

Definition at line 896 of file crypt_gpgme.c.

897 {
898  gpgme_key_t *rset = NULL;
899 
900  if (!p_rset)
901  return;
902 
903  rset = *p_rset;
904  if (!rset)
905  return;
906 
907  while (*rset)
908  {
909  gpgme_key_t k = *rset;
910  gpgme_key_unref(k);
911  rset++;
912  }
913 
914  FREE(p_rset);
915 }
#define FREE(x)
Definition: memory.h:40
+ Here is the caller graph for this function:

◆ create_recipient_set()

static gpgme_key_t* create_recipient_set ( const char *  keylist,
bool  use_smime 
)
static

Create a GpgmeRecipientSet from a string of keys.

Parameters
keylistKeys, space-separated
use_smimeUse SMIME
Return values
ptrGPGME key set

Definition at line 923 of file crypt_gpgme.c.

924 {
925  int err;
926  const char *s = NULL;
927  char buf[100];
928  gpgme_key_t *rset = NULL;
929  unsigned int rset_n = 0;
930  gpgme_key_t key = NULL;
931 
932  gpgme_ctx_t context = create_gpgme_context(use_smime);
933  s = keylist;
934  do
935  {
936  while (*s == ' ')
937  s++;
938  int i;
939  for (i = 0; *s && *s != ' ' && i < sizeof(buf) - 1;)
940  buf[i++] = *s++;
941  buf[i] = '\0';
942  if (*buf != '\0')
943  {
944  if ((i > 1) && (buf[i - 1] == '!'))
945  {
946  /* The user selected to override the validity of that key. */
947  buf[i - 1] = '\0';
948 
949  err = gpgme_get_key(context, buf, &key, 0);
950  if (err == 0)
951  key->uids->validity = GPGME_VALIDITY_FULL;
952  buf[i - 1] = '!';
953  }
954  else
955  err = gpgme_get_key(context, buf, &key, 0);
956  mutt_mem_realloc(&rset, sizeof(*rset) * (rset_n + 1));
957  if (err == 0)
958  rset[rset_n++] = key;
959  else
960  {
961  mutt_error(_("error adding recipient '%s': %s"), buf, gpgme_strerror(err));
962  rset[rset_n] = NULL;
963  recipient_set_free(&rset);
964  gpgme_release(context);
965  return NULL;
966  }
967  }
968  } while (*s);
969 
970  /* NULL terminate. */
971  mutt_mem_realloc(&rset, sizeof(*rset) * (rset_n + 1));
972  rset[rset_n++] = NULL;
973 
974  gpgme_release(context);
975 
976  return rset;
977 }
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
static void recipient_set_free(gpgme_key_t **p_rset)
Free a set of recipients.
Definition: crypt_gpgme.c:896
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:571
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_signer_from_address()

static bool set_signer_from_address ( gpgme_ctx_t  ctx,
const char *  address,
bool  for_smime 
)
static

Try to set the context's signer from the address.

Parameters
ctxGPGME handle
addressAddress to try to set as a signer
for_smimeUse S/MIME
Return values
trueAddress was set as a signer
falseAddress could not be set as a signer

Definition at line 988 of file crypt_gpgme.c.

989 {
990  gpgme_error_t err;
991  gpgme_key_t key = NULL, key2 = NULL;
992  gpgme_ctx_t listctx = create_gpgme_context(for_smime);
993  err = gpgme_op_keylist_start(listctx, address, 1);
994  if (err == 0)
995  err = gpgme_op_keylist_next(listctx, &key);
996  if (err)
997  {
998  gpgme_release(listctx);
999  mutt_error(_("secret key '%s' not found: %s"), address, gpgme_strerror(err));
1000  return false;
1001  }
1002 
1003  char *fpr = "fpr1";
1004  if (key->subkeys)
1005  fpr = key->subkeys->fpr ? key->subkeys->fpr : key->subkeys->keyid;
1006  while (gpgme_op_keylist_next(listctx, &key2) == 0)
1007  {
1008  char *fpr2 = "fpr2";
1009  if (key2->subkeys)
1010  fpr2 = key2->subkeys->fpr ? key2->subkeys->fpr : key2->subkeys->keyid;
1011  if (!mutt_str_equal(fpr, fpr2))
1012  {
1013  gpgme_key_unref(key);
1014  gpgme_key_unref(key2);
1015  gpgme_release(listctx);
1016  mutt_error(_("ambiguous specification of secret key '%s'\n"), address);
1017  return false;
1018  }
1019  else
1020  {
1021  gpgme_key_unref(key2);
1022  }
1023  }
1024  gpgme_op_keylist_end(listctx);
1025  gpgme_release(listctx);
1026 
1027  gpgme_signers_clear(ctx);
1028  err = gpgme_signers_add(ctx, key);
1029  gpgme_key_unref(key);
1030  if (err)
1031  {
1032  mutt_error(_("error setting secret key '%s': %s"), address, gpgme_strerror(err));
1033  return false;
1034  }
1035  return true;
1036 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:571
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_signer()

static int set_signer ( gpgme_ctx_t  ctx,
const struct AddressList *  al,
bool  for_smime 
)
static

Make sure that the correct signer is set.

Parameters
ctxGPGME handle
alFrom AddressList
for_smimeUse S/MIME
Return values
0Success
-1Error

Definition at line 1046 of file crypt_gpgme.c.

1047 {
1048  const char *signid = NULL;
1049 
1050  const char *const c_smime_sign_as =
1051  cs_subset_string(NeoMutt->sub, "smime_sign_as");
1052  const char *const c_pgp_sign_as =
1053  cs_subset_string(NeoMutt->sub, "pgp_sign_as");
1054  const char *const c_pgp_default_key =
1055  cs_subset_string(NeoMutt->sub, "pgp_default_key");
1056  const char *const c_smime_default_key =
1057  cs_subset_string(NeoMutt->sub, "smime_default_key");
1058  if (for_smime)
1059  signid = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
1060 #ifdef USE_AUTOCRYPT
1061  else if (OptAutocryptGpgme)
1062  signid = AutocryptSignAs;
1063 #endif
1064  else
1065  signid = c_pgp_sign_as ? c_pgp_sign_as : c_pgp_default_key;
1066 
1067  /* Try getting the signing key from config entries */
1068  if (signid && set_signer_from_address(ctx, signid, for_smime))
1069  {
1070  return 0;
1071  }
1072 
1073  /* Try getting the signing key from the From line */
1074  if (al)
1075  {
1076  struct Address *a;
1077  TAILQ_FOREACH(a, al, entries)
1078  {
1079  if (a->mailbox && set_signer_from_address(ctx, a->mailbox, for_smime))
1080  {
1081  return 0;
1082  }
1083  }
1084  }
1085 
1086  return (!signid && !al) ? 0 : -1;
1087 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
static bool set_signer_from_address(gpgme_ctx_t ctx, const char *address, bool for_smime)
Try to set the context&#39;s signer from the address.
Definition: crypt_gpgme.c:988
An email address.
Definition: address.h:35
WHERE bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: options.h:33
char * mailbox
Mailbox and host address.
Definition: address.h:38
char * AutocryptSignAs
Autocrypt Key id to sign as.
Definition: config.c:35
Container for Accounts, Notifications.
Definition: neomutt.h:36
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_pka_sig_notation()

static gpgme_error_t set_pka_sig_notation ( gpgme_ctx_t  ctx)
static

Set the signature notation.

Parameters
ctxGPGME context
Return values
numGPGME error code, e.g. GPG_ERR_NO_ERROR

Definition at line 1094 of file crypt_gpgme.c.

1095 {
1096  gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME, current_sender, 0);
1097  if (err)
1098  {
1099  mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
1100  }
1101 
1102  return err;
1103 }
#define PKA_NOTATION_NAME
Definition: crypt_gpgme.c:96
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
static char * current_sender
Definition: crypt_gpgme.c:94
+ Here is the caller graph for this function:

◆ encrypt_gpgme_object()

static char* encrypt_gpgme_object ( gpgme_data_t  plaintext,
char *  keylist,
bool  use_smime,
bool  combined_signed,
const struct AddressList *  from 
)
static

Encrypt the GPGPME data object.

Parameters
plaintextGPGME data object with plain text message
keylistList of keys to encrypt to
use_smimeIf true, use SMIME
combined_signedIf true, sign and encrypt the message (PGP only)
fromThe From header line
Return values
ptrName of temporary file containing encrypted text

Definition at line 1114 of file crypt_gpgme.c.

1116 {
1117  gpgme_error_t err;
1118  gpgme_ctx_t ctx = NULL;
1119  gpgme_data_t ciphertext = NULL;
1120  char *outfile = NULL;
1121 
1122 #if GPGME_VERSION_NUMBER >= 0x010b00 /* GPGME >= 1.11.0 */
1123  struct Buffer *recpstring = mutt_buffer_pool_get();
1124  create_recipient_string(keylist, recpstring, use_smime);
1125  if (mutt_buffer_is_empty(recpstring))
1126  {
1127  mutt_buffer_pool_release(&recpstring);
1128  return NULL;
1129  }
1130 #else
1131  gpgme_key_t *rset = create_recipient_set(keylist, use_smime);
1132  if (!rset)
1133  return NULL;
1134 #endif /* GPGME_VERSION_NUMBER >= 0x010b00 */
1135 
1136  ctx = create_gpgme_context(use_smime);
1137  if (!use_smime)
1138  gpgme_set_armor(ctx, 1);
1139 
1140  ciphertext = create_gpgme_data();
1141 
1142  if (combined_signed)
1143  {
1144  if (set_signer(ctx, from, use_smime))
1145  goto cleanup;
1146 
1147  const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
1148  if (c_crypt_use_pka)
1149  {
1150  err = set_pka_sig_notation(ctx);
1151  if (err != 0)
1152  goto cleanup;
1153  }
1154 
1155 #if (GPGME_VERSION_NUMBER >= 0x010b00) /* GPGME >= 1.11.0 */
1156  err = gpgme_op_encrypt_sign_ext(ctx, NULL, mutt_buffer_string(recpstring),
1157  GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
1158 #else
1159  err = gpgme_op_encrypt_sign(ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
1160 #endif
1161  }
1162  else
1163  {
1164 #if (GPGME_VERSION_NUMBER >= 0x010b00) /* GPGME >= 1.11.0 */
1165  err = gpgme_op_encrypt_ext(ctx, NULL, mutt_buffer_string(recpstring),
1166  GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
1167 #else
1168  err = gpgme_op_encrypt(ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
1169 #endif
1170  }
1171 
1172  redraw_if_needed(ctx);
1173  if (err != 0)
1174  {
1175  mutt_error(_("error encrypting data: %s"), gpgme_strerror(err));
1176  goto cleanup;
1177  }
1178 
1179  outfile = data_object_to_tempfile(ciphertext, NULL);
1180 
1181 cleanup:
1182 #if (GPGME_VERSION_NUMBER >= 0x010b00) /* GPGME >= 1.11.0 */
1183  mutt_buffer_pool_release(&recpstring);
1184 #else
1185  recipient_set_free(&rset);
1186 #endif
1187  gpgme_release(ctx);
1188  gpgme_data_release(ciphertext);
1189  return outfile;
1190 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
static char * data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
Copy a data object to a temporary file.
Definition: crypt_gpgme.c:807
#define mutt_error(...)
Definition: logging.h:88
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
static void recipient_set_free(gpgme_key_t **p_rset)
Free a set of recipients.
Definition: crypt_gpgme.c:896
Container for Accounts, Notifications.
Definition: neomutt.h:36
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:571
static gpgme_key_t * create_recipient_set(const char *keylist, bool use_smime)
Create a GpgmeRecipientSet from a string of keys.
Definition: crypt_gpgme.c:923
static int set_signer(gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
Make sure that the correct signer is set.
Definition: crypt_gpgme.c:1046
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
Definition: crypt_gpgme.c:611
static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
Set the signature notation.
Definition: crypt_gpgme.c:1094
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
static void redraw_if_needed(gpgme_ctx_t ctx)
accommodate for a redraw if needed
Definition: crypt_gpgme.c:119
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_micalg()

static int get_micalg ( gpgme_ctx_t  ctx,
int  use_smime,
char *  buf,
size_t  buflen 
)
static

Find the "micalg" parameter from the last GPGME operation.

Parameters
ctxGPGME handle
use_smimeIf set, use SMIME instead of PGP
bufBuffer for the result
buflenLength of buffer
Return values
0Success
-1Error

Find the "Message Integrity Check algorithm" from the last GPGME operation. It is expected that this operation was a sign operation.

Definition at line 1204 of file crypt_gpgme.c.

1205 {
1206  gpgme_sign_result_t result = NULL;
1207  const char *algorithm_name = NULL;
1208 
1209  if (buflen < 5)
1210  return -1;
1211 
1212  *buf = '\0';
1213  result = gpgme_op_sign_result(ctx);
1214  if (result && result->signatures)
1215  {
1216  algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
1217  if (algorithm_name)
1218  {
1219  if (use_smime)
1220  {
1221  /* convert GPGME raw hash name to RFC2633 format */
1222  snprintf(buf, buflen, "%s", algorithm_name);
1223  mutt_str_lower(buf);
1224  }
1225  else
1226  {
1227  /* convert GPGME raw hash name to RFC3156 format */
1228  snprintf(buf, buflen, "pgp-%s", algorithm_name);
1229  mutt_str_lower(buf + 4);
1230  }
1231  }
1232  }
1233 
1234  return (buf[0] != '\0') ? 0 : -1;
1235 }
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition: string.c:504
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ print_time()

static void print_time ( time_t  t,
struct State s 
)
static

Print the date/time according to the locale.

Parameters
tTimestamp
sState to write to

Definition at line 1242 of file crypt_gpgme.c.

1243 {
1244  char p[256];
1245  mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
1246  state_puts(s, p);
1247 }
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:691
#define state_puts(STATE, STR)
Definition: state.h:55
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ sign_message()

static struct Body* sign_message ( struct Body a,
const struct AddressList *  from,
bool  use_smime 
)
static

Sign a message.

Parameters
aMessage to sign
fromThe From header line
use_smimeIf set, use SMIME instead of PGP
Return values
ptrnew Body
NULLerror

Definition at line 1257 of file crypt_gpgme.c.

1258 {
1259  struct Body *t = NULL;
1260  char *sigfile = NULL;
1261  int err = 0;
1262  char buf[100];
1263  gpgme_ctx_t ctx = NULL;
1264  gpgme_data_t message = NULL, signature = NULL;
1265  gpgme_sign_result_t sigres = NULL;
1266 
1267  crypt_convert_to_7bit(a); /* Signed data _must_ be in 7-bit format. */
1268 
1269  message = body_to_data_object(a, true);
1270  if (!message)
1271  return NULL;
1272  signature = create_gpgme_data();
1273 
1274  ctx = create_gpgme_context(use_smime);
1275  if (!use_smime)
1276  gpgme_set_armor(ctx, 1);
1277 
1278  if (set_signer(ctx, from, use_smime))
1279  {
1280  gpgme_data_release(signature);
1281  gpgme_data_release(message);
1282  gpgme_release(ctx);
1283  return NULL;
1284  }
1285 
1286  const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
1287  if (c_crypt_use_pka)
1288  {
1289  err = set_pka_sig_notation(ctx);
1290  if (err != 0)
1291  {
1292  gpgme_data_release(signature);
1293  gpgme_data_release(message);
1294  gpgme_release(ctx);
1295  return NULL;
1296  }
1297  }
1298 
1299  err = gpgme_op_sign(ctx, message, signature, GPGME_SIG_MODE_DETACH);
1300  redraw_if_needed(ctx);
1301  gpgme_data_release(message);
1302  if (err != 0)
1303  {
1304  gpgme_data_release(signature);
1305  gpgme_release(ctx);
1306  mutt_error(_("error signing data: %s"), gpgme_strerror(err));
1307  return NULL;
1308  }
1309  /* Check for zero signatures generated. This can occur when $pgp_sign_as is
1310  * unset and there is no default key specified in ~/.gnupg/gpg.conf */
1311  sigres = gpgme_op_sign_result(ctx);
1312  if (!sigres->signatures)
1313  {
1314  gpgme_data_release(signature);
1315  gpgme_release(ctx);
1316  mutt_error(_("$pgp_sign_as unset and no default key specified in "
1317  "~/.gnupg/gpg.conf"));
1318  return NULL;
1319  }
1320 
1321  sigfile = data_object_to_tempfile(signature, NULL);
1322  gpgme_data_release(signature);
1323  if (!sigfile)
1324  {
1325  gpgme_release(ctx);
1326  return NULL;
1327  }
1328 
1329  t = mutt_body_new();
1330  t->type = TYPE_MULTIPART;
1331  t->subtype = mutt_str_dup("signed");
1332  t->encoding = ENC_7BIT;
1333  t->use_disp = false;
1334  t->disposition = DISP_INLINE;
1335 
1337  mutt_param_set(&t->parameter, "protocol",
1338  use_smime ? "application/pkcs7-signature" : "application/pgp-signature");
1339  /* Get the micalg from GPGME. Old gpgme versions don't support this
1340  * for S/MIME so we assume sha-1 in this case. */
1341  if (get_micalg(ctx, use_smime, buf, sizeof(buf)) == 0)
1342  mutt_param_set(&t->parameter, "micalg", buf);
1343  else if (use_smime)
1344  mutt_param_set(&t->parameter, "micalg", "sha1");
1345  gpgme_release(ctx);
1346 
1347  t->parts = a;
1348  a = t;
1349 
1350  t->parts->next = mutt_body_new();
1351  t = t->parts->next;
1352  t->type = TYPE_APPLICATION;
1353  if (use_smime)
1354  {
1355  t->subtype = mutt_str_dup("pkcs7-signature");
1356  mutt_param_set(&t->parameter, "name", "smime.p7s");
1357  t->encoding = ENC_BASE64;
1358  t->use_disp = true;
1359  t->disposition = DISP_ATTACH;
1360  t->d_filename = mutt_str_dup("smime.p7s");
1361  }
1362  else
1363  {
1364  t->subtype = mutt_str_dup("pgp-signature");
1365  mutt_param_set(&t->parameter, "name", "signature.asc");
1366  t->use_disp = false;
1367  t->disposition = DISP_NONE;
1368  t->encoding = ENC_7BIT;
1369  }
1370  t->filename = sigfile;
1371  t->unlink = true; /* ok to remove this file after sending. */
1372 
1373  return a;
1374 }
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
static char * data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
Copy a data object to a temporary file.
Definition: crypt_gpgme.c:807
#define mutt_error(...)
Definition: logging.h:88
7-bit text
Definition: mime.h:49
void crypt_convert_to_7bit(struct Body *a)
Convert an email to 7bit encoding.
Definition: crypt.c:814
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:53
Container for Accounts, Notifications.
Definition: neomutt.h:36
The body of an email.
Definition: body.h:34
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:86
Content is attached.
Definition: mime.h:63
static int get_micalg(gpgme_ctx_t ctx, int use_smime, char *buf, size_t buflen)
Find the "micalg" parameter from the last GPGME operation.
Definition: crypt_gpgme.c:1204
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
char * subtype
content-type subtype
Definition: body.h:37
static gpgme_data_t body_to_data_object(struct Body *a, bool convert)
Create GPGME object from the mail body.
Definition: crypt_gpgme.c:667
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:571
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
static int set_signer(gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
Make sure that the correct signer is set.
Definition: crypt_gpgme.c:1046
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
No preferred disposition.
Definition: mime.h:65
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:68
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
Definition: crypt_gpgme.c:611
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
Set the signature notation.
Definition: crypt_gpgme.c:1094
char * d_filename
filename to be used for the content-disposition header.
Definition: body.h:47
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
static void redraw_if_needed(gpgme_ctx_t ctx)
accommodate for a redraw if needed
Definition: crypt_gpgme.c:119
Content is inline.
Definition: mime.h:62
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
Type: &#39;application/*&#39;.
Definition: mime.h:33
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ show_sig_summary()

static int show_sig_summary ( unsigned long  sum,
gpgme_ctx_t  ctx,
gpgme_key_t  key,
int  idx,
struct State s,
gpgme_signature_t  sig 
)
static

Show a signature summary.

Parameters
sumFlags, e.g. GPGME_SIGSUM_KEY_REVOKED
ctxGPGME handle
keySet of keys
idxIndex into key set
sState to use
sigGPGME signature
Return values
0Success
1There is a severe warning

Display the common attributes of the signature summary SUM.

Definition at line 1485 of file crypt_gpgme.c.

1487 {
1488  if (!key)
1489  return 1;
1490 
1491  bool severe = false;
1492 
1493  if ((sum & GPGME_SIGSUM_KEY_REVOKED))
1494  {
1495  state_puts(s, _("Warning: One of the keys has been revoked\n"));
1496  severe = true;
1497  }
1498 
1499  if ((sum & GPGME_SIGSUM_KEY_EXPIRED))
1500  {
1501  time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
1502  if (at)
1503  {
1504  state_puts(
1505  s, _("Warning: The key used to create the signature expired at: "));
1506  print_time(at, s);
1507  state_puts(s, "\n");
1508  }
1509  else
1510  {
1511  state_puts(s, _("Warning: At least one certification key has expired\n"));
1512  }
1513  }
1514 
1515  if ((sum & GPGME_SIGSUM_SIG_EXPIRED))
1516  {
1517  gpgme_signature_t sig2 = NULL;
1518  unsigned int i;
1519 
1520  gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1521 
1522  for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1523  ; // do nothing
1524 
1525  state_puts(s, _("Warning: The signature expired at: "));
1526  print_time(sig2 ? sig2->exp_timestamp : 0, s);
1527  state_puts(s, "\n");
1528  }
1529 
1530  if ((sum & GPGME_SIGSUM_KEY_MISSING))
1531  {
1532  state_puts(s, _("Can't verify due to a missing key or certificate\n"));
1533  }
1534 
1535  if ((sum & GPGME_SIGSUM_CRL_MISSING))
1536  {
1537  state_puts(s, _("The CRL is not available\n"));
1538  severe = true;
1539  }
1540 
1541  if ((sum & GPGME_SIGSUM_CRL_TOO_OLD))
1542  {
1543  state_puts(s, _("Available CRL is too old\n"));
1544  severe = true;
1545  }
1546 
1547  if ((sum & GPGME_SIGSUM_BAD_POLICY))
1548  state_puts(s, _("A policy requirement was not met\n"));
1549 
1550  if ((sum & GPGME_SIGSUM_SYS_ERROR))
1551  {
1552  const char *t0 = NULL, *t1 = NULL;
1553  gpgme_verify_result_t result = NULL;
1554  gpgme_signature_t sig2 = NULL;
1555  unsigned int i;
1556 
1557  state_puts(s, _("A system error occurred"));
1558 
1559  /* Try to figure out some more detailed system error information. */
1560  result = gpgme_op_verify_result(ctx);
1561  for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1562  ; // do nothing
1563 
1564  if (sig2)
1565  {
1566  t0 = "";
1567  t1 = sig2->wrong_key_usage ? "Wrong_Key_Usage" : "";
1568  }
1569 
1570  if (t0 || t1)
1571  {
1572  state_puts(s, ": ");
1573  if (t0)
1574  state_puts(s, t0);
1575  if (t1 && !(t0 && (strcmp(t0, t1) == 0)))
1576  {
1577  if (t0)
1578  state_puts(s, ",");
1579  state_puts(s, t1);
1580  }
1581  }
1582  state_puts(s, "\n");
1583  }
1584 
1585  const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
1586  if (c_crypt_use_pka)
1587  {
1588  if ((sig->pka_trust == 1) && sig->pka_address)
1589  {
1590  state_puts(s, _("WARNING: PKA entry does not match signer's address: "));
1591  state_puts(s, sig->pka_address);
1592  state_puts(s, "\n");
1593  }
1594  else if ((sig->pka_trust == 2) && sig->pka_address)
1595  {
1596  state_puts(s, _("PKA verified signer's address is: "));
1597  state_puts(s, sig->pka_address);
1598  state_puts(s, "\n");
1599  }
1600  }
1601 
1602  return severe;
1603 }
static void print_time(time_t t, struct State *s)
Print the date/time according to the locale.
Definition: crypt_gpgme.c:1242
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define state_puts(STATE, STR)
Definition: state.h:55
size_t idx
Definition: mailbox.c:257
#define _(a)
Definition: message.h:28
Container for Accounts, Notifications.
Definition: neomutt.h:36
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ show_fingerprint()

static void show_fingerprint ( gpgme_key_t  key,
struct State state 
)
static

Write a key's fingerprint.

Parameters
keyGPGME key
stateState to write to

Definition at line 1610 of file crypt_gpgme.c.

1611 {
1612  if (!key)
1613  return;
1614 
1615  const char *prefix = _("Fingerprint: ");
1616 
1617  const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1618  if (!s)
1619  return;
1620  bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1621 
1622  char *buf = mutt_mem_malloc(strlen(prefix) + strlen(s) * 4 + 2);
1623  strcpy(buf, prefix);
1624  char *p = buf + strlen(buf);
1625  if (is_pgp && (strlen(s) == 40))
1626  { /* PGP v4 style formatted. */
1627  for (int i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
1628  {
1629  *p++ = s[0];
1630  *p++ = s[1];
1631  *p++ = s[2];
1632  *p++ = s[3];
1633  *p++ = ' ';
1634  if (i == 4)
1635  *p++ = ' ';
1636  }
1637  }
1638  else
1639  {
1640  for (int i = 0; *s && s[1] && s[2]; s += 2, i++)
1641  {
1642  *p++ = s[0];
1643  *p++ = s[1];
1644  *p++ = is_pgp ? ' ' : ':';
1645  if (is_pgp && (i == 7))
1646  *p++ = ' ';
1647  }
1648  }
1649 
1650  /* just in case print remaining odd digits */
1651  for (; *s; s++)
1652  *p++ = *s;
1653  *p++ = '\n';
1654  *p = '\0';
1655  state_puts(state, buf);
1656  FREE(&buf);
1657 }
#define state_puts(STATE, STR)
Definition: state.h:55
#define _(a)
Definition: message.h:28
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ show_one_sig_validity()

static void show_one_sig_validity ( gpgme_ctx_t  ctx,
int  idx,
struct State s 
)
static

Show the validity of a key used for one signature.

Parameters
ctxGPGME handle
idxIndex of signature to check
sState to use

Definition at line 1665 of file crypt_gpgme.c.

1666 {
1667  gpgme_signature_t sig = NULL;
1668  const char *txt = NULL;
1669 
1670  gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1671  if (result)
1672  for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--)
1673  ; // do nothing
1674 
1675  switch (sig ? sig->validity : 0)
1676  {
1677  case GPGME_VALIDITY_UNKNOWN:
1678  txt = _("WARNING: We have NO indication whether "
1679  "the key belongs to the person named "
1680  "as shown above\n");
1681  break;
1682  case GPGME_VALIDITY_UNDEFINED:
1683  break;
1684  case GPGME_VALIDITY_NEVER:
1685  txt = _("WARNING: The key does NOT BELONG to "
1686  "the person named as shown above\n");
1687  break;
1688  case GPGME_VALIDITY_MARGINAL:
1689  txt = _("WARNING: It is NOT certain that the key "
1690  "belongs to the person named as shown above\n");
1691  break;
1692  case GPGME_VALIDITY_FULL:
1693  case GPGME_VALIDITY_ULTIMATE:
1694  txt = NULL;
1695  break;
1696  }
1697  if (txt)
1698  state_puts(s, txt);
1699 }
#define state_puts(STATE, STR)
Definition: state.h:55
size_t idx
Definition: mailbox.c:257
#define _(a)
Definition: message.h:28
+ Here is the caller graph for this function:

◆ print_smime_keyinfo()

static void print_smime_keyinfo ( const char *  msg,
gpgme_signature_t  sig,
gpgme_key_t  key,
struct State s 
)
static

Print key info about an SMIME key.

Parameters
msgPrefix message to write
sigGPGME signature
keyGPGME key
sState to write to

Definition at line 1708 of file crypt_gpgme.c.

1710 {
1711  int msgwid;
1712 
1713  state_puts(s, msg);
1714  state_puts(s, " ");
1715  /* key is NULL when not present in the user's keyring */
1716  if (key)
1717  {
1718  bool aka = false;
1719  for (gpgme_user_id_t uids = key->uids; uids; uids = uids->next)
1720  {
1721  if (uids->revoked)
1722  continue;
1723  if (aka)
1724  {
1725  msgwid = mutt_strwidth(msg) - mutt_strwidth(_("aka: ")) + 1;
1726  if (msgwid < 0)
1727  msgwid = 0;
1728  for (int i = 0; i < msgwid; i++)
1729  state_puts(s, " ");
1730  state_puts(s, _("aka: "));
1731  }
1732  state_puts(s, uids->uid);
1733  state_puts(s, "\n");
1734 
1735  aka = true;
1736  }
1737  }
1738  else
1739  {
1740  if (sig->fpr)
1741  {
1742  state_puts(s, _("KeyID "));
1743  state_puts(s, sig->fpr);
1744  }
1745  else
1746  {
1747  /* L10N: You will see this message in place of "KeyID "
1748  if the S/MIME key has no ID. This is quite an error. */
1749  state_puts(s, _("no signature fingerprint available"));
1750  }
1751  state_puts(s, "\n");
1752  }
1753 
1754  /* timestamp is 0 when verification failed.
1755  * "Jan 1 1970" is not the created date. */
1756  if (sig->timestamp)
1757  {
1758  msgwid = mutt_strwidth(msg) - mutt_strwidth(_("created: ")) + 1;
1759  if (msgwid < 0)
1760  msgwid = 0;
1761  for (int i = 0; i < msgwid; i++)
1762  state_puts(s, " ");
1763  state_puts(s, _("created: "));
1764  print_time(sig->timestamp, s);
1765  state_puts(s, "\n");
1766  }
1767 }
static void print_time(time_t t, struct State *s)
Print the date/time according to the locale.
Definition: crypt_gpgme.c:1242
#define state_puts(STATE, STR)
Definition: state.h:55
#define _(a)
Definition: message.h:28
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:983
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ show_one_sig_status()

static int show_one_sig_status ( gpgme_ctx_t  ctx,
int  idx,
struct State s 
)
static

Show information about one signature.

Parameters
ctxGPGME handle of a successful verification
idxIndex
sState to use
Return values
0Normal procession
1A bad signature
2A signature with a warning
-1No more signature

The index should start at 0 and increment for each call/signature.

Definition at line 1781 of file crypt_gpgme.c.

1782 {
1783  const char *fpr = NULL;
1784  gpgme_key_t key = NULL;
1785  bool anybad = false, anywarn = false;
1786  gpgme_signature_t sig = NULL;
1787  gpgme_error_t err = GPG_ERR_NO_ERROR;
1788 
1789  gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1790  if (result)
1791  {
1792  /* FIXME: this code should use a static variable and remember
1793  * the current position in the list of signatures, IMHO.
1794  * -moritz. */
1795  int i;
1796  for (i = 0, sig = result->signatures; sig && (i < idx); i++, sig = sig->next)
1797  ; // do nothing
1798 
1799  if (!sig)
1800  return -1; /* Signature not found. */
1801 
1802  if (signature_key)
1803  {
1804  gpgme_key_unref(signature_key);
1805  signature_key = NULL;
1806  }
1807 
1808  fpr = sig->fpr;
1809  const unsigned int sum = sig->summary;
1810 
1811  if (gpg_err_code(sig->status) != GPG_ERR_NO_ERROR)
1812  anybad = true;
1813 
1814  if (gpg_err_code(sig->status) != GPG_ERR_NO_PUBKEY)
1815  {
1816  err = gpgme_get_key(ctx, fpr, &key, 0); /* secret key? */
1817  if (err == 0)
1818  {
1819  if (!signature_key)
1820  signature_key = key;
1821  }
1822  else
1823  {
1824  key = NULL; /* Old GPGME versions did not set KEY to NULL on
1825  error. Do it here to avoid a double free. */
1826  }
1827  }
1828  else
1829  {
1830  /* pubkey not present */
1831  }
1832 
1833  if (!s || !s->fp_out || !(s->flags & MUTT_DISPLAY))
1834  ; /* No state information so no way to print anything. */
1835  else if (err != 0)
1836  {
1837  char buf[1024];
1838  snprintf(buf, sizeof(buf), _("Error getting key information for KeyID %s: %s\n"),
1839  fpr, gpgme_strerror(err));
1840  state_puts(s, buf);
1841  anybad = true;
1842  }
1843  else if ((sum & GPGME_SIGSUM_GREEN))
1844  {
1845  print_smime_keyinfo(_("Good signature from:"), sig, key, s);
1846  if (show_sig_summary(sum, ctx, key, idx, s, sig))
1847  anywarn = true;
1848  show_one_sig_validity(ctx, idx, s);
1849  }
1850  else if ((sum & GPGME_SIGSUM_RED))
1851  {
1852  print_smime_keyinfo(_("*BAD* signature from:"), sig, key, s);
1853  show_sig_summary(sum, ctx, key, idx, s, sig);
1854  }
1855  else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP))
1856  { /* We can't decide (yellow) but this is a PGP key with a good
1857  signature, so we display what a PGP user expects: The name,
1858  fingerprint and the key validity (which is neither fully or
1859  ultimate). */
1860  print_smime_keyinfo(_("Good signature from:"), sig, key, s);
1861  show_one_sig_validity(ctx, idx, s);
1862  show_fingerprint(key, s);
1863  if (show_sig_summary(sum, ctx, key, idx, s, sig))
1864  anywarn = true;
1865  }
1866  else /* can't decide (yellow) */
1867  {
1868  print_smime_keyinfo(_("Problem signature from:"), sig, key, s);
1869  /* 0 indicates no expiration */
1870  if (sig->exp_timestamp)
1871  {
1872  /* L10N: This is trying to match the width of the
1873  "Problem signature from:" translation just above. */
1874  state_puts(s, _(" expires: "));
1875  print_time(sig->exp_timestamp, s);
1876  state_puts(s, "\n");
1877  }
1878  show_sig_summary(sum, ctx, key, idx, s, sig);
1879  anywarn = true;
1880  }
1881 
1882  if (key != signature_key)
1883  gpgme_key_unref(key);
1884  }
1885 
1886  return anybad ? 1 : anywarn ? 2 : 0;
1887 }
static void print_time(time_t t, struct State *s)
Print the date/time according to the locale.
Definition: crypt_gpgme.c:1242
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
#define state_puts(STATE, STR)
Definition: state.h:55
static void show_one_sig_validity(gpgme_ctx_t ctx, int idx, struct State *s)
Show the validity of a key used for one signature.
Definition: crypt_gpgme.c:1665
size_t idx
Definition: mailbox.c:257
static void print_smime_keyinfo(const char *msg, gpgme_signature_t sig, gpgme_key_t key, struct State *s)
Print key info about an SMIME key.
Definition: crypt_gpgme.c:1708
#define _(a)
Definition: message.h:28
FILE * fp_out
File to write to.
Definition: state.h:47
static int show_sig_summary(unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key, int idx, struct State *s, gpgme_signature_t sig)
Show a signature summary.
Definition: crypt_gpgme.c:1485
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
static void show_fingerprint(gpgme_key_t key, struct State *state)
Write a key&#39;s fingerprint.
Definition: crypt_gpgme.c:1610
static gpgme_key_t signature_key
Definition: crypt_gpgme.c:93
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ verify_one()

static int verify_one ( struct Body sigbdy,
struct State s,
const char *  tempfile,
bool  is_smime 
)
static

Do the actual verification step.

Parameters
sigbdyMime part containing signature
sState to read from
tempfileTemporary file to read
is_smimeIs the key S/MIME?
Return values
0Success
1Bad signature
2Warnings
-1Error

With is_smime set to true we assume S/MIME.

Definition at line 1902 of file crypt_gpgme.c.

1903 {
1904  int badsig = -1;
1905  int anywarn = 0;
1906  gpgme_ctx_t ctx = NULL;
1907  gpgme_data_t message = NULL;
1908 
1909  gpgme_data_t signature = file_to_data_object(s->fp_in, sigbdy->offset, sigbdy->length);
1910  if (!signature)
1911  return -1;
1912 
1913  /* We need to tell GPGME about the encoding because the backend can't
1914  * auto-detect plain base-64 encoding which is used by S/MIME. */
1915  if (is_smime)
1916  gpgme_data_set_encoding(signature, GPGME_DATA_ENCODING_BASE64);
1917 
1918  int err = gpgme_data_new_from_file(&message, tempfile, 1);
1919  if (err != 0)
1920  {
1921  gpgme_data_release(signature);
1922  mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
1923  return -1;
1924  }
1925  ctx = create_gpgme_context(is_smime);
1926 
1927  /* Note: We don't need a current time output because GPGME avoids
1928  * such an attack by separating the meta information from the data. */
1929  state_attach_puts(s, _("[-- Begin signature information --]\n"));
1930 
1931  err = gpgme_op_verify(ctx, signature, message, NULL);
1932  gpgme_data_release(message);
1933  gpgme_data_release(signature);
1934 
1935  redraw_if_needed(ctx);
1936  if (err != 0)
1937  {
1938  char buf[200];
1939 
1940  snprintf(buf, sizeof(buf) - 1, _("Error: verification failed: %s\n"),
1941  gpgme_strerror(err));
1942  state_puts(s, buf);
1943  }
1944  else
1945  { /* Verification succeeded, see what the result is. */
1946  gpgme_verify_result_t verify_result = NULL;
1947 
1948  if (signature_key)
1949  {
1950  gpgme_key_unref(signature_key);
1951  signature_key = NULL;
1952  }
1953 
1954  verify_result = gpgme_op_verify_result(ctx);
1955  if (verify_result && verify_result->signatures)
1956  {
1957  bool anybad = false;
1958  int res;
1959  for (int idx = 0; (res = show_one_sig_status(ctx, idx, s)) != -1; idx++)
1960  {
1961  if (res == 1)
1962  anybad = true;
1963  else if (res == 2)
1964  anywarn = 2;
1965  }
1966  if (!anybad)
1967  badsig = 0;
1968  }
1969  }
1970 
1971  if (badsig == 0)
1972  {
1973  gpgme_verify_result_t result = NULL;
1974  gpgme_sig_notation_t notation = NULL;
1975  gpgme_signature_t sig = NULL;
1976 
1977  result = gpgme_op_verify_result(ctx);
1978  if (result)
1979  {
1980  for (sig = result->signatures; sig; sig = sig->next)
1981  {
1982  int non_pka_notations = 0;
1983  for (notation = sig->notations; notation; notation = notation->next)
1984  if (!is_pka_notation(notation))
1985  non_pka_notations++;
1986 
1987  if (non_pka_notations)
1988  {
1989  char buf[128];
1990  snprintf(buf, sizeof(buf),
1991  _("*** Begin Notation (signature by: %s) ***\n"), sig->fpr);
1992  state_puts(s, buf);
1993  for (notation = sig->notations; notation; notation = notation->next)
1994  {
1995  if (is_pka_notation(notation))
1996  continue;
1997 
1998  if (notation->name)
1999  {
2000  state_puts(s, notation->name);
2001  state_puts(s, "=");
2002  }
2003  if (notation->value)
2004  {
2005  state_puts(s, notation->value);
2006  if (!(*notation->value && (notation->value[strlen(notation->value) - 1] == '\n')))
2007  state_puts(s, "\n");
2008  }
2009  }
2010  state_puts(s, _("*** End Notation ***\n"));
2011  }
2012  }
2013  }
2014  }
2015 
2016  gpgme_release(ctx);
2017 
2018  state_attach_puts(s, _("[-- End signature information --]\n\n"));
2019  mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
2020 
2021  return badsig ? 1 : anywarn ? 2 : 0;
2022 }
static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
Create GPGME data object from file.
Definition: crypt_gpgme.c:739
#define state_puts(STATE, STR)
Definition: state.h:55
#define mutt_error(...)
Definition: logging.h:88
size_t idx
Definition: mailbox.c:257
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define _(a)
Definition: message.h:28
FILE * fp_in
File to read from.
Definition: state.h:46
bool badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition: body.h:78
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:571
static bool is_pka_notation(gpgme_sig_notation_t notation)
Is this the standard pka email address.
Definition: crypt_gpgme.c:110
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
void state_attach_puts(struct State *s, const char *t)
Write a string to the state.
Definition: state.c:104
Log at debug level 1.
Definition: logging.h:40
static void redraw_if_needed(gpgme_ctx_t ctx)
accommodate for a redraw if needed
Definition: crypt_gpgme.c:119
static gpgme_key_t signature_key
Definition: crypt_gpgme.c:93
static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *s)
Show information about one signature.
Definition: crypt_gpgme.c:1781
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ decrypt_part()

static struct Body* decrypt_part ( struct Body a,
struct State s,
FILE *  fp_out,
bool  is_smime,
int *  r_is_signed 
)
static

Decrypt a PGP or SMIME message.

Parameters
[in]aBody of message
[in]sState to use
[in]fp_outFile to write to
[in]is_smimeTrue if an SMIME message
[out]r_is_signedFlag, R_IS_SIGNED (PGP only)
Return values
ptrNewly allocated Body

For PGP returns a flag in R_IS_SIGNED to indicate whether this is a combined encrypted and signed message, for S/MIME it returns true when it is not a encrypted but a signed message.

Definition at line 2053 of file crypt_gpgme.c.

2055 {
2056  if (!a || !s || !fp_out)
2057  return NULL;
2058 
2059  struct stat info;
2060  struct Body *tattach = NULL;
2061  int err = 0;
2062  gpgme_data_t ciphertext = NULL, plaintext = NULL;
2063  bool maybe_signed = false;
2064  bool anywarn = false;
2065  int sig_stat = 0;
2066 
2067  if (r_is_signed)
2068  *r_is_signed = 0;
2069 
2070  gpgme_ctx_t ctx = NULL;
2071 restart:
2072  ctx = create_gpgme_context(is_smime);
2073 
2074  if (a->length < 0)
2075  return NULL;
2076  /* Make a data object from the body, create context etc. */
2077  ciphertext = file_to_data_object(s->fp_in, a->offset, a->length);
2078  if (!ciphertext)
2079  goto cleanup;
2080  plaintext = create_gpgme_data();
2081 
2082  /* Do the decryption or the verification in case of the S/MIME hack. */
2083  if ((!is_smime) || maybe_signed)
2084  {
2085  if (!is_smime)
2086  err = gpgme_op_decrypt_verify(ctx, ciphertext, plaintext);
2087  else if (maybe_signed)
2088  err = gpgme_op_verify(ctx, ciphertext, NULL, plaintext);
2089 
2090  if (err == GPG_ERR_NO_ERROR)
2091  {
2092  /* Check whether signatures have been verified. */
2093  gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
2094  if (verify_result->signatures)
2095  sig_stat = 1;
2096  }
2097  }
2098  else
2099  err = gpgme_op_decrypt(ctx, ciphertext, plaintext);
2100  gpgme_data_release(ciphertext);
2101  ciphertext = NULL;
2102  if (err != 0)
2103  {
2104 #ifdef USE_AUTOCRYPT
2105  /* Abort right away and silently.
2106  * Autocrypt will retry on the normal keyring. */
2107  if (OptAutocryptGpgme)
2108  goto cleanup;
2109 #endif
2110  if (is_smime && !maybe_signed && (gpg_err_code(err) == GPG_ERR_NO_DATA))
2111  {
2112  /* Check whether this might be a signed message despite what the mime
2113  * header told us. Retry then. gpgsm returns the error information
2114  * "unsupported Algorithm '?'" but GPGME will not store this unknown
2115  * algorithm, thus we test that it has not been set. */
2116  gpgme_decrypt_result_t result;
2117 
2118  result = gpgme_op_decrypt_result(ctx);
2119  if (!result->unsupported_algorithm)
2120  {
2121  maybe_signed = true;
2122  gpgme_data_release(plaintext);
2123  plaintext = NULL;
2124  /* gpgsm ends the session after an error; restart it */
2125  gpgme_release(ctx);
2126  ctx = NULL;
2127  goto restart;
2128  }
2129  }
2130  redraw_if_needed(ctx);
2131  if ((s->flags & MUTT_DISPLAY))
2132  {
2133  char buf[200];
2134 
2135  snprintf(buf, sizeof(buf) - 1,
2136  _("[-- Error: decryption failed: %s --]\n\n"), gpgme_strerror(err));
2137  state_attach_puts(s, buf);
2138  }
2139  goto cleanup;
2140  }
2141  redraw_if_needed(ctx);
2142 
2143  /* Read the output from GPGME, and make sure to change CRLF to LF,
2144  * otherwise read_mime_header has a hard time parsing the message. */
2145  if (data_object_to_stream(plaintext, fp_out))
2146  {
2147  goto cleanup;
2148  }
2149  gpgme_data_release(plaintext);
2150  plaintext = NULL;
2151 
2152  if (sig_stat)
2153  {
2154  int res, idx;
2155  int anybad = 0;
2156 
2157  if (r_is_signed)
2158  *r_is_signed = -1; /* A signature exists. */
2159 
2160  if ((s->flags & MUTT_DISPLAY))
2161  {
2162  state_attach_puts(s, _("[-- Begin signature information --]\n"));
2163  }
2164  for (idx = 0; (res = show_one_sig_status(ctx, idx, s)) != -1; idx++)
2165  {
2166  if (res == 1)
2167  anybad = 1;
2168  else if (res == 2)
2169  anywarn = true;
2170  }
2171  if (!anybad && idx && r_is_signed && *r_is_signed)
2172  *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
2173 
2174  if ((s->flags & MUTT_DISPLAY))
2175  {
2176  state_attach_puts(s, _("[-- End signature information --]\n\n"));
2177  }
2178  }
2179  gpgme_release(ctx);
2180  ctx = NULL;
2181 
2182  fflush(fp_out);
2183  rewind(fp_out);
2184  tattach = mutt_read_mime_header(fp_out, 0);
2185  if (tattach)
2186  {
2187  /* Need to set the length of this body part. */
2188  fstat(fileno(fp_out), &info);
2189  tattach->length = info.st_size - tattach->offset;
2190 
2191  tattach->warnsig = anywarn;
2192 
2193  /* See if we need to recurse on this MIME part. */
2194  mutt_parse_part(fp_out, tattach);
2195  }
2196 
2197 cleanup:
2198  gpgme_data_release(ciphertext);
2199  gpgme_data_release(plaintext);
2200  gpgme_release(ctx);
2201 
2202  return tattach;
2203 }
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
Create GPGME data object from file.
Definition: crypt_gpgme.c:739
static int data_object_to_stream(gpgme_data_t data, FILE *fp)
Write a GPGME data object to a file.
Definition: crypt_gpgme.c:760
size_t idx
Definition: mailbox.c:257
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define _(a)
Definition: message.h:28
WHERE bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: options.h:33
FILE * fp_in
File to read from.
Definition: state.h:46
The body of an email.
Definition: body.h:34
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:571
void state_attach_puts(struct State *s, const char *t)
Write a string to the state.
Definition: state.c:104
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1678
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
Definition: crypt_gpgme.c:611
static void redraw_if_needed(gpgme_ctx_t ctx)
accommodate for a redraw if needed
Definition: crypt_gpgme.c:119
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1286
static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *s)
Show information about one signature.
Definition: crypt_gpgme.c:1781
bool warnsig
Maybe good signature.
Definition: body.h:77
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pgp_gpgme_extract_keys()

static int pgp_gpgme_extract_keys ( gpgme_data_t  keydata,
FILE **  fp 
)
static

Write PGP keys to a file.

Parameters
[in]keydataGPGME key data
[out]fpTemporary file created with key info
Return values
0Success
-1Error

Definition at line 2420 of file crypt_gpgme.c.

2421 {
2422  /* Before GPGME 1.9.0 and gpg 2.1.14 there was no side-effect free
2423  * way to view key data in GPGME, so we import the key into a
2424  * temporary keyring if we detect an older system. */
2425  bool legacy_api;
2426  struct Buffer *tmpdir = NULL;
2427  gpgme_ctx_t tmpctx = NULL;
2428  gpgme_error_t err;
2429  gpgme_engine_info_t engineinfo = NULL;
2430  gpgme_key_t key = NULL;
2431  gpgme_user_id_t uid = NULL;
2432  gpgme_subkey_t subkey = NULL;
2433  const char *shortid = NULL;
2434  size_t len;
2435  char date[256];
2436  bool more;
2437  int rc = -1;
2438  time_t tt;
2439 
2440 #if (GPGME_VERSION_NUMBER >= 0x010900) /* GPGME >= 1.9.0 */
2441  legacy_api = !have_gpg_version("2.1.14");
2442 #else /* GPGME < 1.9.0 */
2443  legacy_api = true;
2444 #endif
2445 
2446  tmpctx = create_gpgme_context(false);
2447 
2448  if (legacy_api)
2449  {
2450  tmpdir = mutt_buffer_pool_get();
2451  const char *const c_tmpdir = cs_subset_path(NeoMutt->sub, "tmpdir");
2452  mutt_buffer_printf(tmpdir, "%s/neomutt-gpgme-XXXXXX", NONULL(c_tmpdir));
2453  if (!mkdtemp(tmpdir->data))
2454  {
2455  mutt_debug(LL_DEBUG1, "Error creating temporary GPGME home\n");
2456  goto err_ctx;
2457  }
2458 
2459  engineinfo = gpgme_ctx_get_engine_info(tmpctx);
2460  while (engineinfo && (engineinfo->protocol != GPGME_PROTOCOL_OpenPGP))
2461  engineinfo = engineinfo->next;
2462  if (!engineinfo)
2463  {
2464  mutt_debug(LL_DEBUG1, "Error finding GPGME PGP engine\n");
2465  goto err_tmpdir;
2466  }
2467 
2468  err = gpgme_ctx_set_engine_info(tmpctx, GPGME_PROTOCOL_OpenPGP, engineinfo->file_name,
2469  mutt_buffer_string(tmpdir));
2470  if (err != GPG_ERR_NO_ERROR)
2471  {
2472  mutt_debug(LL_DEBUG1, "Error setting GPGME context home\n");
2473  goto err_tmpdir;
2474  }
2475  }
2476 
2477  *fp = mutt_file_mkstemp();
2478  if (!*fp)
2479  {
2480  mutt_perror(_("Can't create temporary file"));
2481  goto err_tmpdir;
2482  }
2483 
2484 #if GPGME_VERSION_NUMBER >= 0x010900 /* 1.9.0 */
2485  if (!legacy_api)
2486  err = gpgme_op_keylist_from_data_start(tmpctx, keydata, 0);
2487  else
2488 #endif /* GPGME >= 1.9.0 */
2489  {
2490  err = gpgme_op_keylist_start(tmpctx, NULL, 0);
2491  }
2492  while (err == 0)
2493  {
2494  err = gpgme_op_keylist_next(tmpctx, &key);
2495  if (err != 0)
2496  break;
2497  uid = key->uids;
2498  subkey = key->subkeys;
2499  more = false;
2500  while (subkey)
2501  {
2502  shortid = subkey->keyid;
2503  len = mutt_str_len(subkey->keyid);
2504  if (len > 8)
2505  shortid += len - 8;
2506  tt = subkey->timestamp;
2507  mutt_date_localtime_format(date, sizeof(date), "%Y-%m-%d", tt);
2508 
2509  if (more)
2510  {
2511  fprintf(*fp, "sub %5.5s %u/%8s %s\n", gpgme_pubkey_algo_name(subkey->pubkey_algo),
2512  subkey->length, shortid, date);
2513  }
2514  else
2515  {
2516  fprintf(*fp, "pub %5.5s %u/%8s %s %s\n", gpgme_pubkey_algo_name(subkey->pubkey_algo),
2517  subkey->length, shortid, date, uid->uid);
2518  }
2519  subkey = subkey->next;
2520  more = true;
2521  }
2522  gpgme_key_unref(key);
2523  }
2524  if (gpg_err_code(err) != GPG_ERR_EOF)
2525  {
2526  mutt_debug(LL_DEBUG1, "Error listing keys\n");
2527  goto err_fp;
2528  }
2529 
2530  rc = 0;
2531 
2532 err_fp:
2533  if (rc)
2534  mutt_file_fclose(fp);
2535 err_tmpdir:
2536  if (legacy_api)
2538 err_ctx:
2539  gpgme_release(tmpctx);
2540 
2541  mutt_buffer_pool_release(&tmpdir);
2542 
2543  return rc;
2544 }
#define NONULL(x)
Definition: string2.h:37
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:691
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
int mutt_file_rmtree(const char *path)
Recursively remove a directory.
Definition: file.c:468
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
#define mutt_perror(...)
Definition: logging.h:89
Container for Accounts, Notifications.
Definition: neomutt.h:36
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:571
char * data
Pointer to data.
Definition: buffer.h:35
#define mutt_file_mkstemp()
Definition: file.h:108
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
Log at debug level 1.
Definition: logging.h:40
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ line_compare()

static int line_compare ( const char *  a,
size_t  n,
const char *  b 
)
static

Compare two strings ignore line endings.

Parameters
aString a
nMaximum length to compare
bString b
Return values
0Strings match
-1Strings differ

Check that b is a complete line containing a followed by either LF or CRLF.

Definition at line 2557 of file crypt_gpgme.c.

2558 {
2559  if (mutt_strn_equal(a, b, n))
2560  {
2561  /* at this point we know that 'b' is at least 'n' chars long */
2562  if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2563  return true;
2564  }
2565  return false;
2566 }
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:593
+ Here is the call graph for this function:

◆ pgp_check_traditional_one_body()

static int pgp_check_traditional_one_body ( FILE *  fp,
struct Body b 
)
static

Check one inline PGP body part.

Parameters
fpFile to read from
bBody of the email
Return values
trueSuccess
falseError

Definition at line 2575 of file crypt_gpgme.c.

2576 {
2577  char buf[8192];
2578  bool rc = false;
2579 
2580  bool sgn = false;
2581  bool enc = false;
2582 
2583  if (b->type != TYPE_TEXT)
2584  return 0;
2585 
2586  struct Buffer *tempfile = mutt_buffer_pool_get();
2587  mutt_buffer_mktemp(tempfile);
2588  if (mutt_decode_save_attachment(fp, b, mutt_buffer_string(tempfile), 0,
2589  MUTT_SAVE_NO_FLAGS) != 0)
2590  {
2591  unlink(mutt_buffer_string(tempfile));
2592  goto cleanup;
2593  }
2594 
2595  FILE *fp_tmp = fopen(mutt_buffer_string(tempfile), "r");
2596  if (!fp_tmp)
2597  {
2598  unlink(mutt_buffer_string(tempfile));
2599  goto cleanup;
2600  }
2601 
2602  while (fgets(buf, sizeof(buf), fp_tmp))
2603  {
2604  size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2605  if (plen != 0)
2606  {
2607  if (MESSAGE(buf + plen))
2608  {
2609  enc = true;
2610  break;
2611  }
2612  else if (SIGNED_MESSAGE(buf + plen))
2613  {
2614  sgn = true;
2615  break;
2616  }
2617  }
2618  }
2619  mutt_file_fclose(&fp_tmp);
2620  unlink(mutt_buffer_string(tempfile));
2621 
2622  if (!enc && !sgn)
2623  goto cleanup;
2624 
2625  /* fix the content type */
2626 
2627  mutt_param_set(&b->parameter, "format", "fixed");
2628  mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2629 
2630  rc = true;
2631 
2632 cleanup:
2633  mutt_buffer_pool_release(&tempfile);
2634  return rc;
2635 }
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define SIGNED_MESSAGE(_y)
Definition: crypt_gpgme.c:100
No flags set.
Definition: mutt_attach.h:57
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
#define MESSAGE(_y)
Definition: crypt_gpgme.c:99
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:160
int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path, int displaying, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:1009
Type: &#39;text/*&#39;.
Definition: mime.h:38
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ copy_clearsigned()

static void copy_clearsigned ( gpgme_data_t  data,
struct State s,
char *  charset 
)
static

Copy a clearsigned message.

Parameters
dataGPGME data object
sState to use
charsetCharset of message

strip the signature and PGP's dash-escaping.

XXX charset handling: We assume that it is safe to do character set decoding first, dash decoding second here, while we do it the other way around in the main handler.

(Note that we aren't worse than Outlook & Cie in this, and also note that we can successfully handle anything produced by any existing versions of neomutt.)

Definition at line 2774 of file crypt_gpgme.c.

2775 {
2776  char buf[8192];
2777  bool complete, armor_header;
2778  FILE *fp = NULL;
2779 
2780  char *fname = data_object_to_tempfile(data, &fp);
2781  if (!fname)
2782  {
2783  mutt_file_fclose(&fp);
2784  return;
2785  }
2786  unlink(fname);
2787  FREE(&fname);
2788 
2789  /* fromcode comes from the MIME Content-Type charset label. It might
2790  * be a wrong label, so we want the ability to do corrections via
2791  * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2792  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
2793  struct FgetConv *fc = mutt_ch_fgetconv_open(fp, charset, c_charset, MUTT_ICONV_HOOK_FROM);
2794 
2795  for (complete = true, armor_header = true;
2796  mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2797  {
2798  if (!complete)
2799  {
2800  if (!armor_header)
2801  state_puts(s, buf);
2802  continue;
2803  }
2804 
2805  if (BEGIN_PGP_SIGNATURE(buf))
2806  break;
2807 
2808  if (armor_header)
2809  {
2810  if (buf[0] == '\n')
2811  armor_header = false;
2812  continue;
2813  }
2814 
2815  if (s->prefix)
2816  state_puts(s, s->prefix);
2817 
2818  if ((buf[0] == '-') && (buf[1] == ' '))
2819  state_puts(s, buf + 2);
2820  else
2821  state_puts(s, buf);
2822  }
2823 
2825  mutt_file_fclose(&fp);
2826 }
#define state_puts(STATE, STR)
Definition: state.h:55
static char * data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
Copy a data object to a temporary file.
Definition: crypt_gpgme.c:807
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
Container for Accounts, Notifications.
Definition: neomutt.h:36
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file&#39;s charset into a string buffer.
Definition: charset.c:974
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:72
char * data
Pointer to data.
Definition: buffer.h:35
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
#define BEGIN_PGP_SIGNATURE(_y)
Definition: crypt_gpgme.c:102
void mutt_ch_fgetconv_close(struct FgetConv **fc)
Close an fgetconv handle.
Definition: charset.c:892
#define FREE(x)
Definition: memory.h:40
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Cursor for converting a file&#39;s encoding.
Definition: charset.h:40
struct FgetConv * mutt_ch_fgetconv_open(FILE *fp, const char *from, const char *to, uint8_t flags)
Prepare a file for charset conversion.
Definition: charset.c:862
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ key_check_cap()

unsigned int key_check_cap ( gpgme_key_t  key,
enum KeyCap  cap 
)

Check the capabilities of a key.

Parameters
keyGPGME key
capFlags, e.g. KEY_CAP_CAN_ENCRYPT
Return values
>0Key has the capabilities

Definition at line 3256 of file crypt_gpgme.c.

3257 {
3258  unsigned int ret = 0;
3259 
3260  switch (cap)
3261  {
3262  case KEY_CAP_CAN_ENCRYPT:
3263  ret = key->can_encrypt;
3264  if (ret == 0)
3265  {
3266  for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
3267  {
3268  ret = subkey->can_encrypt;
3269  if (ret != 0)
3270  break;
3271  }
3272  }
3273  break;
3274  case KEY_CAP_CAN_SIGN:
3275  ret = key->can_sign;
3276  if (ret == 0)
3277  {
3278  for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
3279  {
3280  ret = subkey->can_sign;
3281  if (ret != 0)
3282  break;
3283  }
3284  }
3285  break;
3286  case KEY_CAP_CAN_CERTIFY:
3287  ret = key->can_certify;
3288  if (ret == 0)
3289  {
3290  for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
3291  {
3292  ret = subkey->can_certify;
3293  if (ret != 0)
3294  break;
3295  }
3296  }
3297  break;
3298  }
3299 
3300  return ret;
3301 }
Key can be used for encryption.
Definition: crypt_gpgme.h:77
Key can be used for signing.
Definition: crypt_gpgme.h:78
Key can be used to certify.
Definition: crypt_gpgme.h:79
+ Here is the caller graph for this function:

◆ list_to_pattern()

static char* list_to_pattern ( struct ListHead *  list)
static

Convert STailQ to GPGME-compatible pattern.

Parameters
listList of strings to convert
Return values
ptrGPGME-compatible pattern

We need to convert spaces in an item into a '+' and '' into "%25".

Note
The caller must free the returned pattern

Definition at line 3312 of file crypt_gpgme.c.

3313 {
3314  char *pattern = NULL, *p = NULL;
3315  const char *s = NULL;
3316  size_t n;
3317 
3318  n = 0;
3319  struct ListNode *np = NULL;
3320  STAILQ_FOREACH(np, list, entries)
3321  {
3322  for (s = np->data; *s; s++)
3323  {
3324  if ((*s == '%') || (*s == '+'))
3325  n += 2;
3326  n++;
3327  }
3328  n++; /* delimiter or end of string */
3329  }
3330  n++; /* make sure to allocate at least one byte */
3331  p = mutt_mem_calloc(1, n);
3332  pattern = p;
3333  STAILQ_FOREACH(np, list, entries)
3334  {
3335  s = np->data;
3336  if (*s)
3337  {
3338  if (np != STAILQ_FIRST(list))
3339  *p++ = ' ';
3340  for (s = np->data; *s; s++)
3341  {
3342  if (*s == '%')
3343  {
3344  *p++ = '%';
3345  *p++ = '2';
3346  *p++ = '5';
3347  }
3348  else if (*s == '+')
3349  {
3350  *p++ = '%';
3351  *p++ = '2';
3352  *p++ = 'B';
3353  }
3354  else if (*s == ' ')
3355  *p++ = '+';
3356  else
3357  *p++ = *s;
3358  }
3359  }
3360  }
3361  *p = '\0';
3362  return pattern;
3363 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
char * p
Definition: charset.h:46
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
char * data
String.
Definition: list.h:36
A List node for strings.
Definition: list.h:34
#define STAILQ_FIRST(head)
Definition: queue.h:350
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_candidates()

static struct CryptKeyInfo* get_candidates ( struct ListHead *  hints,
SecurityFlags  app,
int  secret 
)
static

Get a list of keys which are candidates for the selection.

Parameters
hintsList of strings to match
appApplication type, e.g. APPLICATION_PGP
secretIf true, only match secret keys
Return values
ptrKey List
NULLError

Select by looking at the HINTS list.

Definition at line 3375 of file crypt_gpgme.c.

3376 {
3377  struct CryptKeyInfo *db = NULL, *k = NULL, **kend = NULL;
3378  gpgme_error_t err;
3379  gpgme_ctx_t ctx = NULL;
3380  gpgme_key_t key = NULL;
3381  int idx;
3382  gpgme_user_id_t uid = NULL;
3383 
3384  char *pattern = list_to_pattern(hints);
3385  if (!pattern)
3386  return NULL;
3387 
3388  ctx = create_gpgme_context(0);
3389  db = NULL;
3390  kend = &db;
3391 
3392  if ((app & APPLICATION_PGP))
3393  {
3394  /* It's all a mess. That old GPGME expects different things depending on
3395  * the protocol. For gpg we don't need percent escaped pappert but simple
3396  * strings passed in an array to the keylist_ext_start function. */
3397  size_t n = 0;
3398  struct ListNode *np = NULL;
3399  STAILQ_FOREACH(np, hints, entries)
3400  {
3401  if (np->data && *np->data)
3402  n++;
3403  }
3404  if (n == 0)
3405  goto no_pgphints;
3406 
3407  char **patarr = mutt_mem_calloc(n + 1, sizeof(*patarr));
3408  n = 0;
3409  STAILQ_FOREACH(np, hints, entries)
3410  {
3411  if (np->data && *np->data)
3412  patarr[n++] = mutt_str_dup(np->data);
3413  }
3414  patarr[n] = NULL;
3415  err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
3416  for (n = 0; patarr[n]; n++)
3417  FREE(&patarr[n]);
3418  FREE(&patarr);
3419  if (err != 0)
3420  {
3421  mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3422  gpgme_release(ctx);
3423  FREE(&pattern);
3424  return NULL;
3425  }
3426 
3427  while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
3428  {
3429  KeyFlags flags = KEYFLAG_NO_FLAGS;
3430 
3432  flags |= KEYFLAG_CANENCRYPT;
3433  if (key_check_cap(key, KEY_CAP_CAN_SIGN))
3434  flags |= KEYFLAG_CANSIGN;
3435 
3436  if (key->revoked)
3437  flags |= KEYFLAG_REVOKED;
3438  if (key->expired)
3439  flags |= KEYFLAG_EXPIRED;
3440  if (key->disabled)
3441  flags |= KEYFLAG_DISABLED;
3442 
3443  for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3444  {
3445  k = mutt_mem_calloc(1, sizeof(*k));
3446  k->kobj = key;
3447  gpgme_key_ref(k->kobj);
3448  k->idx = idx;
3449  k->uid = uid->uid;
3450  k->flags = flags;
3451  if (uid->revoked)
3452  k->flags |= KEYFLAG_REVOKED;
3453  k->validity = uid->validity;
3454  *kend = k;
3455  kend = &k->next;
3456  }
3457  gpgme_key_unref(key);
3458  }
3459  if (gpg_err_code(err) != GPG_ERR_EOF)
3460  mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3461  gpgme_op_keylist_end(ctx);
3462  no_pgphints:;
3463  }
3464 
3465  if ((app & APPLICATION_SMIME))
3466  {
3467  /* and now look for x509 certificates */
3468  gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
3469  err = gpgme_op_keylist_start(ctx, pattern, 0);
3470  if (err != 0)
3471  {
3472  mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3473  gpgme_release(ctx);
3474  FREE(&pattern);
3475  return NULL;
3476  }
3477 
3478  while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
3479  {
3480  KeyFlags flags = KEYFLAG_ISX509;
3481 
3483  flags |= KEYFLAG_CANENCRYPT;
3484  if (key_check_cap(key, KEY_CAP_CAN_SIGN))
3485  flags |= KEYFLAG_CANSIGN;
3486 
3487  if (key->revoked)
3488  flags |= KEYFLAG_REVOKED;
3489  if (key->expired)
3490  flags |= KEYFLAG_EXPIRED;
3491  if (key->disabled)
3492  flags |= KEYFLAG_DISABLED;
3493 
3494  for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3495  {
3496  k = mutt_mem_calloc(1, sizeof(*k));
3497  k->kobj = key;
3498  gpgme_key_ref(k->kobj);
3499  k->idx = idx;
3500  k->uid = uid->uid;
3501  k->flags = flags;
3502  if (uid->revoked)
3503  k->flags |= KEYFLAG_REVOKED;
3504  k->validity = uid->validity;
3505  *kend = k;
3506  kend = &k->next;
3507  }
3508  gpgme_key_unref(key);
3509  }
3510  if (gpg_err_code(err) != GPG_ERR_EOF)
3511  mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3512  gpgme_op_keylist_end(ctx);
3513  }
3514 
3515  gpgme_release(ctx);
3516  FREE(&pattern);
3517  return db;
3518 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define mutt_error(...)
Definition: logging.h:88
size_t idx
Definition: mailbox.c:257
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
Key can be used for encryption.
Definition: crypt_gpgme.h:77
#define KEYFLAG_ISX509
Key is an X.509 key.
Definition: lib.h:126
Key can be used for signing.
Definition: crypt_gpgme.h:78
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:125
A stored PGP key.
Definition: crypt_gpgme.h:44
#define KEYFLAG_EXPIRED
Key is expired.
Definition: lib.h:128
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
const char * uid
and for convenience point to this user ID
Definition: crypt_gpgme.h:49
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
#define KEYFLAG_NO_FLAGS
No flags are set.
Definition: lib.h:123
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:571
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:122
unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
Definition: crypt_gpgme.c:3256
static char * list_to_pattern(struct ListHead *list)
Convert STailQ to GPGME-compatible pattern.
Definition: crypt_gpgme.c:3312
#define KEYFLAG_DISABLED
Key is marked disabled.
Definition: lib.h:130
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:124
char * data
String.
Definition: list.h:36
#define FREE(x)
Definition: memory.h:40
A List node for strings.
Definition: list.h:34
#define KEYFLAG_REVOKED
Key is revoked.
Definition: lib.h:129
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_add_string_to_hints()

static void crypt_add_string_to_hints ( const char *  str,
struct ListHead *  hints 
)
static

Split a string and add the parts to a List.

Parameters
[in]strString to parse
[out]hintsList of string parts

The string str is split by whitespace and punctuation and the parts added to hints. This list is later used to match addresses.

Definition at line 3528 of file crypt_gpgme.c.

3529 {
3530  char *scratch = mutt_str_dup(str);
3531  if (!scratch)
3532  return;
3533 
3534  for (char *t = strtok(scratch, " ,.:\"()<>\n"); t;
3535  t = strtok(NULL, " ,.:\"()<>\n"))
3536  {
3537  if (strlen(t) > 3)
3539  }
3540 
3541  FREE(&scratch);
3542 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
#define FREE(x)
Definition: memory.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_getkeybyaddr()

static struct CryptKeyInfo* crypt_getkeybyaddr ( struct Address a,
KeyFlags  abilities,
unsigned int  app,
int *  forced_valid,
bool  oppenc_mode 
)
static

Find a key by email address.

Parameters
[in]aAddress to match
[in]abilitiesAbilities to match, see KeyFlags
[in]appApplication type, e.g. APPLICATION_PGP
[out]forced_validSet to true if user overrode key's validity
[in]oppenc_modeIf true, use opportunistic encryption
Return values
ptrMatching key

Definition at line 3553 of file crypt_gpgme.c.

3556 {
3557  struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3558 
3559  int multi = false;
3560  int this_key_has_strong = false;
3561  int this_key_has_addr_match = false;
3562  int match = false;
3563 
3564  struct CryptKeyInfo *keys = NULL, *k = NULL;
3565  struct CryptKeyInfo *the_strong_valid_key = NULL;
3566  struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3567  struct CryptKeyInfo *matches = NULL;
3568  struct CryptKeyInfo **matches_endp = &matches;
3569 
3570  *forced_valid = 0;
3571 
3572  if (a && a->mailbox)
3573  crypt_add_string_to_hints(a->mailbox, &hints);
3574  if (a && a->personal)
3575  crypt_add_string_to_hints(a->personal, &hints);
3576 
3577  if (!oppenc_mode)
3578  mutt_message(_("Looking for keys matching \"%s\"..."), a ? a->mailbox : "");
3579  keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3580 
3581  mutt_list_free(&hints);
3582 
3583  if (!keys)
3584  return NULL;
3585 
3586  mutt_debug(LL_DEBUG5, "looking for %s <%s>\n", a ? a->personal : "", a ? a->mailbox : "");
3587 
3588  for (k = keys; k; k = k->next)
3589  {
3590  mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3591 
3592  if (abilities && !(k->flags & abilities))
3593  {
3594  mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3595  continue;
3596  }
3597 
3598  this_key_has_strong = false; /* strong and valid match */
3599  this_key_has_addr_match = false;
3600  match = false; /* any match */
3601 
3602  struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3603  mutt_addrlist_parse(&alist, k->uid);
3604  struct Address *ka = NULL;
3605  TAILQ_FOREACH(ka, &alist, entries)
3606  {
3607  int validity = crypt_id_matches_addr(a, ka, k);
3608 
3609  if (validity & CRYPT_KV_MATCH) /* something matches */
3610  {
3611  match = true;
3612 
3613  if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3614  {
3615  if (validity & CRYPT_KV_STRONGID)
3616  {
3617  if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3618  multi = true;
3619  this_key_has_strong = true;
3620  }
3621  else
3622  this_key_has_addr_match = true;
3623  }
3624  }
3625  }
3626  mutt_addrlist_clear(&alist);
3627 
3628  if (match)
3629  {
3630  struct CryptKeyInfo *tmp = crypt_copy_key(k);
3631  *matches_endp = tmp;
3632  matches_endp = &tmp->next;
3633 
3634  if (this_key_has_strong)
3635  the_strong_valid_key = tmp;
3636  else if (this_key_has_addr_match)
3637  a_valid_addrmatch_key = tmp;
3638  }
3639  }
3640 
3641  crypt_key_free(&keys);
3642 
3643  if (matches)
3644  {
3645  if (oppenc_mode)
3646  {
3647  const bool c_crypt_opportunistic_encrypt_strong_keys = cs_subset_bool(
3648  NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3649  if (the_strong_valid_key)
3650  k = crypt_copy_key(the_strong_valid_key);
3651  else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3652  k = crypt_copy_key(a_valid_addrmatch_key);
3653  else
3654  k = NULL;
3655  }
3656  else if (the_strong_valid_key && !multi)
3657  {
3658  /* There was precisely one strong match on a valid ID.
3659  * Proceed without asking the user. */
3660  k = crypt_copy_key(the_strong_valid_key);
3661  }
3662  else
3663  {
3664  /* Else: Ask the user. */
3665  k = dlg_select_gpgme_key(matches, a, NULL, app, forced_valid);
3666  }
3667 
3668  crypt_key_free(&matches);
3669  }
3670  else
3671  k = NULL;
3672 
3673  return k;
3674 }
#define CRYPT_KV_STRONGID
Definition: crypt_gpgme.c:78
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
Definition: crypt_gpgme.c:462
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define CRYPT_KV_ADDR
Definition: crypt_gpgme.c:76
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
struct CryptKeyInfo * dlg_select_gpgme_key(struct CryptKeyInfo *keys, struct Address *p, const char *s, unsigned int app, int *forced_valid)
Get the user to select a key.
Definition: dlggpgme.c:1317
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
Definition: crypt_gpgme.c:347
#define _(a)
Definition: message.h:28
An email address.
Definition: address.h:35
char * mailbox
Mailbox and host address.
Definition: address.h:38
struct CryptKeyInfo * next
Definition: crypt_gpgme.h:46
Container for Accounts, Notifications.
Definition: neomutt.h:36
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
Split a string and add the parts to a List.
Definition: crypt_gpgme.c:3528
A stored PGP key.
Definition: crypt_gpgme.h:44
static int crypt_id_matches_addr(struct Address *addr, struct Address *u_addr, struct CryptKeyInfo *key)
Does the key ID match the address.
Definition: crypt_gpgme.c:537
Log at debug level 2.
Definition: logging.h:41
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
Definition: crypt_gpgme.c:443
#define CRYPT_KV_MATCH
Definition: crypt_gpgme.c:79
gpgme_key_t kobj
Definition: crypt_gpgme.h:47
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:124
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
char * personal
Real name of address.
Definition: address.h:37
#define mutt_message(...)
Definition: logging.h:87
#define CRYPT_KV_VALID
Definition: crypt_gpgme.c:75
static struct CryptKeyInfo * get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
Get a list of keys which are candidates for the selection.
Definition: crypt_gpgme.c:3375
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Log at debug level 5.
Definition: logging.h:44
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_getkeybystr()

static struct CryptKeyInfo* crypt_getkeybystr ( const char *  p,
KeyFlags  abilities,
unsigned int  app,
int *  forced_valid 
)
static

Find a key by string.

Parameters
[in]pString to match
[in]abilitiesAbilities to match, see KeyFlags
[in]appApplication type, e.g. APPLICATION_PGP
[out]forced_validSet to true if user overrode key's validity
Return values
ptrMatching key

Definition at line 3684 of file crypt_gpgme.c.

3686 {
3687  struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3688  struct CryptKeyInfo *matches = NULL;
3689  struct CryptKeyInfo **matches_endp = &matches;
3690  struct CryptKeyInfo *k = NULL;
3691  const char *ps = NULL, *pl = NULL, *phint = NULL;
3692 
3693  mutt_message(_("Looking for keys matching \"%s\"..."), p);
3694 
3695  *forced_valid = 0;
3696 
3697  const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3698  crypt_add_string_to_hints(phint, &hints);
3699  struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3700  mutt_list_free(&hints);
3701 
3702  if (!keys)
3703  {
3704  FREE(&pfcopy);
3705  return NULL;
3706  }
3707 
3708  for (k = keys; k; k = k->next)
3709  {
3710  if (abilities && !(k->flags & abilities))
3711  continue;
3712 
3713  mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3714  crypt_long_keyid(k), k->uid);
3715 
3716  if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3717  (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3718  (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3719  {
3720  mutt_debug(LL_DEBUG5, "match\n");
3721 
3722  struct CryptKeyInfo *tmp = crypt_copy_key(k);
3723  *matches_endp = tmp;
3724  matches_endp = &tmp->next;
3725  }
3726  else
3727  {
3728  mutt_debug(LL_DEBUG5, "no match\n");
3729  }
3730  }
3731 
3732  FREE(&pfcopy);
3733  crypt_key_free(&keys);
3734 
3735  if (matches)
3736  {
3737  k = dlg_select_gpgme_key(matches, NULL, p, app, forced_valid);
3738  crypt_key_free(&matches);
3739  return k;
3740  }
3741 
3742  return NULL;
3743 }
const char * crypt_get_fingerprint_or_id(const char *p, const char **pphint, const char **ppl, const char **pps)
Get the fingerprint or long key ID.
Definition: crypt.c:1301
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
Definition: crypt_gpgme.c:462
struct CryptKeyInfo * dlg_select_gpgme_key(struct CryptKeyInfo *keys, struct Address *p, const char *s, unsigned int app, int *forced_valid)
Get the user to select a key.
Definition: dlggpgme.c:1317
#define _(a)
Definition: message.h:28
struct CryptKeyInfo * next
Definition: crypt_gpgme.h:46
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
Split a string and add the parts to a List.
Definition: crypt_gpgme.c:3528
A stored PGP key.
Definition: crypt_gpgme.h:44
static const char * crypt_fpr(struct CryptKeyInfo *k)
Get the hexstring fingerprint from a key.
Definition: crypt_gpgme.c:408
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
Definition: crypt_gpgme.c:443
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
const char * uid
and for convenience point to this user ID
Definition: crypt_gpgme.h:49
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:124
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:689
static const char * crypt_long_keyid(struct CryptKeyInfo *k)
Find the Long ID for the key.
Definition: crypt_gpgme.c:372
KeyFlags flags
global and per uid flags (for convenience)
Definition: crypt_gpgme.h:50
static const char * crypt_short_keyid(struct CryptKeyInfo *k)
Get the short keyID for a key.
Definition: crypt_gpgme.c:389
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
static struct CryptKeyInfo * get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
Get a list of keys which are candidates for the selection.
Definition: crypt_gpgme.c:3375
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
Log at debug level 5.
Definition: logging.h:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_ask_for_key()

static struct CryptKeyInfo* crypt_ask_for_key ( char *  tag,
char *  whatfor,
KeyFlags  abilities,
unsigned int  app,
int *  forced_valid 
)
static

Ask the user for a key.

Parameters
[in]tagPrompt to display
[in]whatforLabel to use (OPTIONAL)
[in]abilitiesFlags, see KeyFlags
[in]appApplication type, e.g. APPLICATION_PGP
[out]forced_validSet to true if user overrode key's validity
Return values
ptrCopy of the selected key

If whatfor is not null use it as default and store it under that label as the next default.

Definition at line 3757 of file crypt_gpgme.c.

3759 {
3760  struct CryptKeyInfo *key = NULL;
3761  char resp[128];
3762  struct CryptCache *l = NULL;
3763  int dummy;
3764 
3765  if (!forced_valid)
3766  forced_valid = &dummy;
3767 
3768  mutt_clear_error();
3769 
3770  *forced_valid = 0;
3771  resp[0] = '\0';
3772  if (whatfor)
3773  {
3774  for (l = id_defaults; l; l = l->next)
3775  {
3776  if (mutt_istr_equal(whatfor, l->what))
3777  {
3778  mutt_str_copy(resp, l->dflt, sizeof(resp));
3779  break;
3780  }
3781  }
3782  }
3783 
3784  while (true)
3785  {
3786  resp[0] = '\0';
3787  if (mutt_get_field(tag, resp, sizeof(resp), MUTT_COMP_NO_FLAGS, false, NULL, NULL) != 0)
3788  {
3789  return NULL;
3790  }
3791 
3792  if (whatfor)
3793  {
3794  if (l)
3795  mutt_str_replace(&l->dflt, resp);
3796  else
3797  {
3798  l = mutt_mem_malloc(sizeof(struct CryptCache));
3799  l->next = id_defaults;
3800  id_defaults = l;
3801  l->what = mutt_str_dup(whatfor);
3802  l->dflt = mutt_str_dup(resp);
3803  }
3804  }
3805 
3806  key = crypt_getkeybystr(resp, abilities, app, forced_valid);
3807  if (key)
3808  return key;
3809 
3810  mutt_error(_("No matching keys found for \"%s\""), resp);
3811  }
3812  /* not reached */
3813 }
#define mutt_error(...)
Definition: logging.h:88
int mutt_get_field(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:335
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, int *forced_valid)
Find a key by string.
Definition: crypt_gpgme.c:3684
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
Internal cache for GPGME.
Definition: crypt_gpgme.c:85
A stored PGP key.
Definition: crypt_gpgme.h:44
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
static struct CryptCache * id_defaults
Definition: crypt_gpgme.c:92
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
struct CryptCache * next
Definition: crypt_gpgme.c:89
char * dflt
Definition: crypt_gpgme.c:88
char * what
Definition: crypt_gpgme.c:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_keys()

static char* find_keys ( struct AddressList *  addrlist,
unsigned int  app,
bool  oppenc_mode 
)
static

Find keys of the recipients of the message.

Parameters
addrlistAddress List
appApplication type, e.g. APPLICATION_PGP
oppenc_modeIf true, use opportunistic encryption
Return values
ptrSpace-separated string of keys
NULLAt least one of the keys can't be found

If oppenc_mode is true, only keys that can be determined without prompting will be used.

Definition at line 3826 of file crypt_gpgme.c.

3827 {
3828  struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3829  struct ListNode *crypt_hook = NULL;
3830  const char *keyid = NULL;
3831  char *keylist = NULL;
3832  size_t keylist_size = 0;
3833  size_t keylist_used = 0;
3834  struct Address *p = NULL;
3835  struct CryptKeyInfo *k_info = NULL;
3836  const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3837  char buf[1024];
3838  int forced_valid;
3839  bool key_selected;
3840  struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3841 
3842  struct Address *a = NULL;
3843  TAILQ_FOREACH(a, addrlist, entries)
3844  {
3845  key_selected = false;
3846  mutt_crypt_hook(&crypt_hook_list, a);
3847  crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3848  do
3849  {
3850  p = a;
3851  forced_valid = 0;
3852  k_info = NULL;
3853 
3854  if (crypt_hook)
3855  {
3856  keyid = crypt_hook->data;
3857  enum QuadOption ans = MUTT_YES;
3858  const bool c_crypt_confirm_hook =
3859  cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3860  if (!oppenc_mode && c_crypt_confirm_hook)
3861  {
3862  snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid, p->mailbox);
3863  ans = mutt_yesorno(buf, MUTT_YES);
3864  }
3865  if (ans == MUTT_YES)
3866  {
3867  if (crypt_is_numerical_keyid(keyid))
3868  {
3869  if (mutt_strn_equal(keyid, "0x", 2))
3870  keyid += 2;
3871  goto bypass_selection; /* you don't see this. */
3872  }
3873 
3874  /* check for e-mail address */
3875  mutt_addrlist_clear(&hookal);
3876  if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3877  {
3878  mutt_addrlist_qualify(&hookal, fqdn);
3879  p = TAILQ_FIRST(&hookal);
3880  }
3881  else if (!oppenc_mode)
3882  {
3883  k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3884  }
3885  }
3886  else if (ans == MUTT_NO)
3887  {
3888  if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3889  {
3890  crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3891  continue;
3892  }
3893  }
3894  else if (ans == MUTT_ABORT)
3895  {
3896  FREE(&keylist);
3897  mutt_addrlist_clear(&hookal);
3898  mutt_list_free(&crypt_hook_list);
3899  return NULL;
3900  }
3901  }
3902 
3903  if (!k_info)
3904  {
3905  k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3906  }
3907 
3908  if (!k_info && !oppenc_mode)
3909  {
3910  snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), p->mailbox);
3911 
3912  k_info = crypt_ask_for_key(buf, p->mailbox, KEYFLAG_CANENCRYPT, app, &forced_valid);
3913  }
3914 
3915  if (!k_info)
3916  {
3917  FREE(&keylist);
3918  mutt_addrlist_clear(&hookal);
3919  mutt_list_free(&crypt_hook_list);
3920  return NULL;
3921  }
3922 
3923  keyid = crypt_fpr_or_lkeyid(k_info);
3924 
3925  bypass_selection:
3926  keylist_size += mutt_str_len(keyid) + 4 + 1;
3927  mutt_mem_realloc(&keylist, keylist_size);
3928  sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3929  keyid, forced_valid ? "!" : "");
3930  keylist_used = mutt_str_len(keylist);
3931 
3932  key_selected = true;
3933 
3934  crypt_key_free(&k_info);
3935  mutt_addrlist_clear(&hookal);
3936 
3937  if (crypt_hook)
3938  crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3939 
3940  } while (crypt_hook);
3941 
3942  mutt_list_free(&crypt_hook_list);
3943  }
3944  return keylist;
3945 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define TAILQ_FIRST(head)
Definition: queue.h:723
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
Definition: crypt_gpgme.c:462
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, int *forced_valid)
Find a key by string.
Definition: crypt_gpgme.c:3684
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition: crypt.c:1390
#define _(a)
Definition: message.h:28
An email address.
Definition: address.h:35
char * mailbox
Mailbox and host address.
Definition: address.h:38
Container for Accounts, Notifications.
Definition: neomutt.h:36
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:125
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
static struct CryptKeyInfo * crypt_getkeybyaddr(struct Address *a, KeyFlags abilities, unsigned int app, int *forced_valid, bool oppenc_mode)
Find a key by email address.
Definition: crypt_gpgme.c:3553
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
A stored PGP key.
Definition: crypt_gpgme.h:44
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:773
User aborted the question (with Ctrl-G)
Definition: quad.h:37
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
Definition: crypt_gpgme.c:423
static struct CryptKeyInfo * crypt_ask_for_key(char *tag, char *whatfor, KeyFlags abilities, unsigned int app, int *forced_valid)
Ask the user for a key.
Definition: crypt_gpgme.c:3757
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:180
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:650
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:1187
char * data
String.
Definition: list.h:36
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:593
#define FREE(x)
Definition: memory.h:40
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
A List node for strings.
Definition: list.h:34
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define STAILQ_FIRST(head)
Definition: queue.h:350
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_gpgme_select_secret_key()

int mutt_gpgme_select_secret_key ( struct Buffer keyid)

Select a private Autocrypt key for a new account.

Parameters
keyidAutocrypt Key id
Return values
0Success
-1Error

Unfortunately, the internal ncrypt/crypt_gpgme.c functions use CryptKeyInfo, and so aren't exportable.

This function queries all private keys, provides the crypt_select_keys() menu, and returns the selected key fingerprint in keyid.

Definition at line 3976 of file crypt_gpgme.c.

3977 {
3978  int rc = -1, junk;
3979  gpgme_error_t err;
3980  gpgme_key_t key = NULL;
3981  gpgme_user_id_t uid = NULL;
3982  struct CryptKeyInfo *results = NULL, *k = NULL;
3983  struct CryptKeyInfo **kend = NULL;
3984  struct CryptKeyInfo *choice = NULL;
3985 
3986  gpgme_ctx_t ctx = create_gpgme_context(false);
3987 
3988  /* list all secret keys */
3989  if (gpgme_op_keylist_start(ctx, NULL, 1))
3990  goto cleanup;
3991 
3992  kend = &results;
3993 
3994  while (!(err = gpgme_op_keylist_next(ctx, &key)))
3995  {
3997 
3999  flags |= KEYFLAG_CANENCRYPT;
4000  if (key_check_cap(key, KEY_CAP_CAN_SIGN))
4001  flags |= KEYFLAG_CANSIGN;
4002 
4003  if (key->revoked)
4004  flags |= KEYFLAG_REVOKED;
4005  if (key->expired)
4006  flags |= KEYFLAG_EXPIRED;
4007  if (key->disabled)
4008  flags |= KEYFLAG_DISABLED;
4009 
4010  int idx;
4011  for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
4012  {
4013  k = mutt_mem_calloc(1, sizeof(*k));
4014  k->kobj = key;
4015  gpgme_key_ref(k->kobj);
4016  k->idx = idx;
4017  k->uid = uid->uid;
4018  k->flags = flags;
4019  if (uid->revoked)
4020  k->flags |= KEYFLAG_REVOKED;
4021  k->validity = uid->validity;
4022  *kend = k;
4023  kend = &k->next;
4024  }
4025  gpgme_key_unref(key);
4026  }
4027  if (gpg_err_code(err) != GPG_ERR_EOF)
4028  mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
4029  gpgme_op_keylist_end(ctx);
4030 
4031  if (!results)
4032  {
4033  /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
4034  from. This error is displayed if no results were found. */
4035  mutt_error(_("No secret keys found"));
4036  goto cleanup;
4037  }
4038 
4039  choice = dlg_select_gpgme_key(results, NULL, "*", APPLICATION_PGP, &junk);
4040  if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
4041  goto cleanup;
4042  mutt_buffer_strcpy(keyid, choice->kobj->subkeys->fpr);
4043 
4044  rc = 0;
4045 
4046 cleanup:
4047  crypt_key_free(&choice);
4048  crypt_key_free(&results);
4049  gpgme_release(ctx);
4050  return rc;
4051 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
Definition: crypt_gpgme.c:462
#define mutt_error(...)
Definition: logging.h:88
struct CryptKeyInfo * dlg_select_gpgme_key(struct CryptKeyInfo *keys, struct Address *p, const char *s, unsigned int app, int *forced_valid)
Get the user to select a key.
Definition: dlggpgme.c:1317
size_t idx
Definition: mailbox.c:257
#define _(a)
Definition: message.h:28
Key can be used for encryption.
Definition: crypt_gpgme.h:77
Key can be used for signing.
Definition: crypt_gpgme.h:78
struct CryptKeyInfo * next
Definition: crypt_gpgme.h:46
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:125
A stored PGP key.
Definition: crypt_gpgme.h:44
#define KEYFLAG_EXPIRED
Key is expired.
Definition: lib.h:128
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
#define KEYFLAG_NO_FLAGS
No flags are set.
Definition: lib.h:123
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:571
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:122
gpgme_key_t kobj
Definition: crypt_gpgme.h:47
unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
Definition: crypt_gpgme.c:3256
#define KEYFLAG_DISABLED
Key is marked disabled.
Definition: lib.h:130
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:124
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
KeyFlags flags
global and per uid flags (for convenience)
Definition: crypt_gpgme.h:50
#define KEYFLAG_REVOKED
Key is revoked.
Definition: lib.h:129
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ init_common()

static void init_common ( void  )
static

Initialise code common to PGP and SMIME parts of GPGME.

Definition at line 4123 of file crypt_gpgme.c.

4124 {
4125  /* this initialization should only run one time, but it may be called by
4126  * either pgp_gpgme_init or smime_gpgme_init */
4127  static bool has_run = false;
4128  if (has_run)
4129  return;
4130 
4131  gpgme_check_version(NULL);
4132  gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
4133 #ifdef ENABLE_NLS
4134  gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
4135 #endif
4136  has_run = true;
4137 }
+ Here is the caller graph for this function:

◆ init_pgp()

static void init_pgp ( void  )
static

Initialise the PGP crypto backend.

Definition at line 4142 of file crypt_gpgme.c.

4143 {
4144  if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
4145  {
4146  mutt_error(_("GPGME: OpenPGP protocol not available"));
4147  }
4148 }
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
+ Here is the caller graph for this function:

◆ init_smime()

static void init_smime ( void  )
static

Initialise the SMIME crypto backend.

Definition at line 4153 of file crypt_gpgme.c.

4154 {
4155  if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
4156  {
4157  mutt_error(_("GPGME: CMS protocol not available"));
4158  }
4159 }
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
+ Here is the caller graph for this function:

◆ gpgme_send_menu()

static SecurityFlags gpgme_send_menu ( struct Mailbox m,
struct Email e,
bool  is_smime 
)
static

Show the user the encryption/signing menu.

Parameters
mCurrent Mailbox
eEmail
is_smimeTrue if an SMIME message
Return values
numFlags, e.g. APPLICATION_SMIME | SEC_ENCRYPT

Definition at line 4186 of file crypt_gpgme.c.

4187 {
4188  struct CryptKeyInfo *p = NULL;
4189  const char *prompt = NULL;
4190  const char *letters = NULL;
4191  const char *choices = NULL;
4192  int choice;
4193 
4194  if (is_smime)
4196  else
4197  e->security |= APPLICATION_PGP;
4198 
4199  /* Opportunistic encrypt is controlling encryption.
4200  * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
4201  * letter choices for those.
4202  */
4203  const bool c_crypt_opportunistic_encrypt =
4204  cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
4205  if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
4206  {
4207  if (is_smime)
4208  {
4209  /* L10N: S/MIME options (opportunistic encryption is on) */
4210  prompt =
4211  _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
4212  /* L10N: S/MIME options (opportunistic encryption is on) */
4213  letters = _("sapco");
4214  choices = "SapCo";
4215  }
4216  else
4217  {
4218  /* L10N: PGP options (opportunistic encryption is on) */
4219  prompt =
4220  _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
4221  /* L10N: PGP options (opportunistic encryption is on) */
4222  letters = _("samco");
4223  choices = "SamCo";
4224  }
4225  }
4226  /* Opportunistic encryption option is set, but is toggled off for this message. */
4227  else if (c_crypt_opportunistic_encrypt)
4228  {
4229  if (is_smime)
4230  {
4231  /* L10N: S/MIME options (opportunistic encryption is off) */
4232  prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, "
4233  "or (o)ppenc mode?");
4234  /* L10N: S/MIME options (opportunistic encryption is off) */
4235  letters = _("esabpco");
4236  choices = "esabpcO";
4237  }
4238  else
4239  {
4240  /* L10N: PGP options (opportunistic encryption is off) */
4241  prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, "
4242  "or (o)ppenc mode?");
4243  /* L10N: PGP options (opportunistic encryption is off) */
4244  letters = _("esabmco");
4245  choices = "esabmcO";
4246  }
4247  }
4248  /* Opportunistic encryption is unset */
4249  else
4250  {
4251  if (is_smime)
4252  {
4253  /* L10N: S/MIME options */
4254  prompt =
4255  _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
4256  /* L10N: S/MIME options */
4257  letters = _("esabpc");
4258  choices = "esabpc";
4259  }
4260  else
4261  {
4262  /* L10N: PGP options */
4263  prompt =
4264  _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
4265  /* L10N: PGP options */
4266  letters = _("esabmc");
4267  choices = "esabmc";
4268  }
4269  }
4270 
4271  choice = mutt_multi_choice(prompt, letters);
4272  if (choice > 0)
4273  {
4274  switch (choices[choice - 1])
4275  {
4276  case 'a': /* sign (a)s */
4277  p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
4278  is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
4279  if (p)
4280  {
4281  char input_signas[128];
4282  snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
4283 
4284  if (is_smime)
4285  cs_subset_str_string_set(NeoMutt->sub, "smime_default_key", input_signas, NULL);
4286  else
4287  cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
4288 
4289  crypt_key_free(&p);
4290 
4291  e->security |= SEC_SIGN;
4292  }
4293  break;
4294 
4295  case 'b': /* (b)oth */
4296  e->security |= (SEC_ENCRYPT | SEC_SIGN);
4297  break;
4298 
4299  case 'C':
4300  e->security &= ~SEC_SIGN;
4301  break;
4302 
4303  case 'c': /* (c)lear */
4304  e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
4305  break;
4306 
4307  case 'e': /* (e)ncrypt */
4308  e->security |= SEC_ENCRYPT;
4309  e->security &= ~SEC_SIGN;
4310  break;
4311 
4312  case 'm': /* (p)gp or s/(m)ime */
4313  case 'p':
4314  is_smime = !is_smime;
4315  if (is_smime)
4316  {
4317  e->security &= ~APPLICATION_PGP;
4319  }
4320  else
4321  {
4322  e->security &= ~APPLICATION_SMIME;
4323  e->security |= APPLICATION_PGP;
4324  }
4326  break;
4327 
4328  case 'O': /* oppenc mode on */
4329  e->security |= SEC_OPPENCRYPT;
4331  break;
4332 
4333  case 'o': /* oppenc mode off */
4334  e->security &= ~SEC_OPPENCRYPT;
4335  break;
4336 
4337  case 'S': /* (s)ign in oppenc mode */
4338  e->security |= SEC_SIGN;
4339  break;
4340 
4341  case 's': /* (s)ign */
4342  e->security &= ~SEC_ENCRYPT;
4343  e->security |= SEC_SIGN;
4344  break;
4345  }
4346  }
4347 
4348  return e->security;
4349 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
Definition: crypt_gpgme.c:462
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
#define _(a)
Definition: message.h:28
Container for Accounts, Notifications.
Definition: neomutt.h:36
A stored PGP key.
Definition: crypt_gpgme.h:44
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c:408
void crypt_opportunistic_encrypt(struct Mailbox *m, struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1054
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
Definition: crypt_gpgme.c:423
static struct CryptKeyInfo * crypt_ask_for_key(char *tag, char *whatfor, KeyFlags abilities, unsigned int app, int *forced_valid)
Ask the user for a key.
Definition: crypt_gpgme.c:3757
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:49
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:124
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:83
#define SEC_SIGN
Email is signed.
Definition: lib.h:76
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ verify_sender()

static bool verify_sender ( struct Email e)
static

Verify the sender of a message.

Parameters
eEmail
Return values
trueSender is verified

Definition at line 4372 of file crypt_gpgme.c.

4373 {
4374  struct Address *sender = NULL;
4375  bool rc = true;
4376 
4377  if (!TAILQ_EMPTY(&e->env->from))
4378  {
4380  sender = TAILQ_FIRST(&e->env->from);
4381  }
4382  else if (!TAILQ_EMPTY(&e->env->sender))
4383  {
4385  sender = TAILQ_FIRST(&e->env->sender);
4386  }
4387 
4388  if (sender)
4389  {
4390  if (signature_key)
4391  {
4392  gpgme_key_t key = signature_key;
4393  gpgme_user_id_t uid = NULL;
4394  int sender_length = strlen(sender->mailbox);
4395  for (uid = key->uids; uid && rc; uid = uid->next)
4396  {
4397  int uid_length = strlen(uid->email);
4398  if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4399  (uid_length == (sender_length + 2)))
4400  {
4401  const char *at_sign = strchr(uid->email + 1, '@');
4402  if (at_sign)
4403  {
4404  /* Assume address is 'mailbox@domainname'.
4405  * The mailbox part is case-sensitive,
4406  * the domainname is not. (RFC2821) */
4407  const char *tmp_email = uid->email + 1;
4408  const char *tmp_sender = sender->mailbox;
4409  /* length of mailbox part including '@' */
4410  int mailbox_length = at_sign - tmp_email + 1;
4411  int domainname_length = sender_length - mailbox_length;
4412  int mailbox_match, domainname_match;
4413 
4414  mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4415  tmp_email += mailbox_length;
4416  tmp_sender += mailbox_length;
4417  domainname_match =
4418  (strncasecmp(tmp_email, tmp_sender, domainname_length) == 0);
4419  if (mailbox_match && domainname_match)
4420  rc = false;
4421  }
4422  else
4423  {
4424  if (mutt_strn_equal(uid->email + 1, sender->mailbox, sender_length))
4425  rc = false;
4426  }
4427  }
4428  }
4429  }
4430  else
4431  mutt_any_key_to_continue(_("Failed to verify sender"));
4432  }
4433  else
4434  mutt_any_key_to_continue(_("Failed to figure out sender"));
4435 
4436  if (signature_key)
4437  {
4438  gpgme_key_unref(signature_key);
4439  signature_key = NULL;
4440  }
4441 
4442  return rc;
4443 }
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:300
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define _(a)
Definition: message.h:28
An email address.
Definition: address.h:35
char * mailbox
Mailbox and host address.
Definition: address.h:38
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
struct Envelope * env
Envelope information.
Definition: email.h:90
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:455
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:593
struct AddressList sender
Email&#39;s sender.
Definition: envelope.h:61
#define TAILQ_EMPTY(head)
Definition: queue.h:721
static gpgme_key_t signature_key
Definition: crypt_gpgme.c:93
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_gpgme_print_version()

const char* mutt_gpgme_print_version ( void  )

Get version of GPGME.

Return values
ptrGPGME version string

Definition at line 4467 of file crypt_gpgme.c.

4468 {
4469  return GPGME_VERSION;
4470 }
+ Here is the caller graph for this function:

Variable Documentation

◆ id_defaults

struct CryptCache* id_defaults = NULL
static

Definition at line 92 of file crypt_gpgme.c.

◆ signature_key

gpgme_key_t signature_key = NULL
static

Definition at line 93 of file crypt_gpgme.c.

◆ current_sender

char* current_sender = NULL
static

Definition at line 94 of file crypt_gpgme.c.