NeoMutt  2022-04-29-81-g9c5a59
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 <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 "attach/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "crypt.h"
#include "handler.h"
#include "hook.h"
#include "mutt_logging.h"
#include "muttlib.h"
#include "options.h"
#include "autocrypt/lib.h"
#include <libintl.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() -. 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, bool *forced_valid, bool oppenc_mode)
 Find a key by email address. More...
 
static struct CryptKeyInfocrypt_getkeybystr (const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
 Find a key by string. More...
 
static struct CryptKeyInfocrypt_ask_for_key (char *tag, char *whatfor, KeyFlags abilities, unsigned int app, bool *forced_valid)
 Ask the user for a key. More...
 
static char * find_keys (const struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
 Find keys of the recipients of the message. More...
 
char * pgp_gpgme_find_keys (const struct AddressList *addrlist, bool oppenc_mode)
 Implements CryptModuleSpecs::find_keys() -. More...
 
char * smime_gpgme_find_keys (const 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 Email *e, bool is_smime)
 Show the user the encryption/signing menu. More...
 
SecurityFlags pgp_gpgme_send_menu (struct Email *e)
 Implements CryptModuleSpecs::send_menu() -. More...
 
SecurityFlags smime_gpgme_send_menu (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 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 85 of file crypt_gpgme.c.

◆ CRYPT_KV_ADDR

#define CRYPT_KV_ADDR   (1 << 1)

Definition at line 86 of file crypt_gpgme.c.

◆ CRYPT_KV_STRING

#define CRYPT_KV_STRING   (1 << 2)

Definition at line 87 of file crypt_gpgme.c.

◆ CRYPT_KV_STRONGID

#define CRYPT_KV_STRONGID   (1 << 3)

Definition at line 88 of file crypt_gpgme.c.

◆ CRYPT_KV_MATCH

#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)

Definition at line 89 of file crypt_gpgme.c.

◆ PKA_NOTATION_NAME

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

Definition at line 106 of file crypt_gpgme.c.

◆ _LINE_COMPARE

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

Definition at line 108 of file crypt_gpgme.c.

◆ MESSAGE

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

Definition at line 109 of file crypt_gpgme.c.

◆ SIGNED_MESSAGE

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

Definition at line 110 of file crypt_gpgme.c.

◆ PUBLIC_KEY_BLOCK

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

Definition at line 111 of file crypt_gpgme.c.

◆ BEGIN_PGP_SIGNATURE

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

Definition at line 112 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 120 of file crypt_gpgme.c.

121 {
122  return mutt_str_equal(notation->name, PKA_NOTATION_NAME);
123 }
#define PKA_NOTATION_NAME
Definition: crypt_gpgme.c:106
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:784
+ 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 129 of file crypt_gpgme.c.

130 {
131 #if (GPGME_VERSION_NUMBER < 0x010800) // GPGME < 1.8.0
132  /* gpgme_get_ctx_flag is not available.
133  * In this case, stay on the safe side and always redraw. */
134  (void) ctx;
136 #else
137  const char *s = gpgme_get_ctx_flag(ctx, "redraw");
138  if (!s /* flag not known */ || *s /* flag true */)
139  {
141  }
142 #endif
143 }
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:178
+ 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 357 of file crypt_gpgme.c.

358 {
359  const char *s = "????????";
360 
361  if (k->kobj && k->kobj->subkeys)
362  {
363  s = k->kobj->subkeys->keyid;
364  const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
365  if ((!c_pgp_long_ids) && (strlen(s) == 16))
366  {
367  /* Return only the short keyID. */
368  s += 8;
369  }
370  }
371 
372  return s;
373 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
gpgme_key_t kobj
Definition: crypt_gpgme.h:46
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ 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 382 of file crypt_gpgme.c.

383 {
384  const char *s = "????????????????";
385 
386  if (k->kobj && k->kobj->subkeys)
387  {
388  s = k->kobj->subkeys->keyid;
389  }
390 
391  return s;
392 }
+ 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 399 of file crypt_gpgme.c.

400 {
401  const char *s = "????????";
402 
403  if (k->kobj && k->kobj->subkeys)
404  {
405  s = k->kobj->subkeys->keyid;
406  if (strlen(s) == 16)
407  s += 8;
408  }
409 
410  return s;
411 }
+ 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 418 of file crypt_gpgme.c.

419 {
420  const char *s = "";
421 
422  if (k->kobj && k->kobj->subkeys)
423  s = k->kobj->subkeys->fpr;
424 
425  return s;
426 }
+ 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 433 of file crypt_gpgme.c.

434 {
435  const char *s = "????????????????";
436 
437  if (k->kobj && k->kobj->subkeys)
438  {
439  if (k->kobj->subkeys->fpr)
440  s = k->kobj->subkeys->fpr;
441  else
442  s = k->kobj->subkeys->keyid;
443  }
444 
445  return s;
446 }
+ 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 453 of file crypt_gpgme.c.

454 {
455  struct CryptKeyInfo *k = NULL;
456 
457  k = mutt_mem_calloc(1, sizeof(*k));
458  k->kobj = key->kobj;
459  gpgme_key_ref(key->kobj);
460  k->idx = key->idx;
461  k->uid = key->uid;
462  k->flags = key->flags;
463  k->validity = key->validity;
464 
465  return k;
466 }
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
gpgme_validity_t validity
uid validity (cached for convenience)
Definition: crypt_gpgme.h:50
KeyFlags flags
global and per uid flags (for convenience)
Definition: crypt_gpgme.h:49
int idx
and the user ID at this index
Definition: crypt_gpgme.h:47
const char * uid
and for convenience point to this user ID
Definition: crypt_gpgme.h:48
+ 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 472 of file crypt_gpgme.c.

473 {
474  if (!keylist)
475  return;
476 
477  struct CryptKeyInfo *k = NULL;
478 
479  while (*keylist)
480  {
481  k = *keylist;
482  *keylist = (*keylist)->next;
483 
484  gpgme_key_unref(k->kobj);
485  FREE(&k);
486  }
487 }
#define FREE(x)
Definition: memory.h:40
struct CryptKeyInfo * next
Linked list.
Definition: crypt_gpgme.h:45
+ 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 494 of file crypt_gpgme.c.

495 {
496  if (!key)
497  return false;
498 
499  bool is_strong = false;
500 
501  if ((key->flags & KEYFLAG_ISX509))
502  return true;
503 
504  switch (key->validity)
505  {
506  case GPGME_VALIDITY_MARGINAL:
507  case GPGME_VALIDITY_NEVER:
508  case GPGME_VALIDITY_UNDEFINED:
509  case GPGME_VALIDITY_UNKNOWN:
510  is_strong = false;
511  break;
512 
513  case GPGME_VALIDITY_FULL:
514  case GPGME_VALIDITY_ULTIMATE:
515  is_strong = true;
516  break;
517  }
518 
519  return is_strong;
520 }
#define KEYFLAG_ISX509
Key is an X.509 key.
Definition: lib.h:129
+ 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 529 of file crypt_gpgme.c.

530 {
531  if (!key)
532  return 0;
533 
534  return !(key->flags & KEYFLAG_CANTUSE);
535 }
#define KEYFLAG_CANTUSE
Definition: lib.h:139
+ 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 547 of file crypt_gpgme.c.

549 {
550  int rc = 0;
551 
552  if (crypt_id_is_valid(key))
553  rc |= CRYPT_KV_VALID;
554 
555  if (crypt_id_is_strong(key))
556  rc |= CRYPT_KV_STRONGID;
557 
558  if (addr && u_addr)
559  {
560  if (addr->mailbox && u_addr->mailbox &&
561  mutt_istr_equal(addr->mailbox, u_addr->mailbox))
562  {
563  rc |= CRYPT_KV_ADDR;
564  }
565 
566  if (addr->personal && u_addr->personal &&
567  mutt_istr_equal(addr->personal, u_addr->personal))
568  {
569  rc |= CRYPT_KV_STRING;
570  }
571  }
572 
573  return rc;
574 }
#define CRYPT_KV_STRING
Definition: crypt_gpgme.c:87
int crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
Definition: crypt_gpgme.c:529
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
Definition: crypt_gpgme.c:494
#define CRYPT_KV_VALID
Definition: crypt_gpgme.c:85
#define CRYPT_KV_STRONGID
Definition: crypt_gpgme.c:88
#define CRYPT_KV_ADDR
Definition: crypt_gpgme.c:86
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:796
char * mailbox
Mailbox and host address.
Definition: address.h:38
char * personal
Real name of address.
Definition: address.h:37
+ 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 581 of file crypt_gpgme.c.

582 {
583  gpgme_ctx_t ctx = NULL;
584 
585  gpgme_error_t err = gpgme_new(&ctx);
586 
587 #ifdef USE_AUTOCRYPT
588  const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
589  if (!err && OptAutocryptGpgme)
590  err = gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_OpenPGP, NULL, c_autocrypt_dir);
591 #endif
592 
593  if (err != 0)
594  {
595  mutt_error(_("error creating GPGME context: %s"), gpgme_strerror(err));
596  mutt_exit(1);
597  }
598 
599  if (for_smime)
600  {
601  err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
602  if (err != 0)
603  {
604  mutt_error(_("error enabling CMS protocol: %s"), gpgme_strerror(err));
605  mutt_exit(1);
606  }
607  }
608 
609  return ctx;
610 }
#define mutt_error(...)
Definition: logging.h:87
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:248
#define _(a)
Definition: message.h:28
bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: options.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 620 of file crypt_gpgme.c.

621 {
622  gpgme_data_t data = NULL;
623 
624  gpgme_error_t err = gpgme_data_new(&data);
625  if (err != 0)
626  {
627  mutt_error(_("error creating GPGME data object: %s"), gpgme_strerror(err));
628  mutt_exit(1);
629  }
630  return data;
631 }
+ 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 676 of file crypt_gpgme.c.

677 {
678  int err = 0;
679  gpgme_data_t data = NULL;
680 
681  struct Buffer *tempfile = mutt_buffer_pool_get();
682  mutt_buffer_mktemp(tempfile);
683  FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
684  if (!fp_tmp)
685  {
686  mutt_perror(mutt_buffer_string(tempfile));
687  goto cleanup;
688  }
689 
690  mutt_write_mime_header(a, fp_tmp, NeoMutt->sub);
691  fputc('\n', fp_tmp);
692  mutt_write_mime_body(a, fp_tmp, NeoMutt->sub);
693 
694  if (convert)
695  {
696  int c, hadcr = 0;
697  unsigned char buf[1];
698 
700  rewind(fp_tmp);
701  while ((c = fgetc(fp_tmp)) != EOF)
702  {
703  if (c == '\r')
704  hadcr = 1;
705  else
706  {
707  if ((c == '\n') && !hadcr)
708  {
709  buf[0] = '\r';
710  gpgme_data_write(data, buf, 1);
711  }
712 
713  hadcr = 0;
714  }
715  /* FIXME: This is quite suboptimal */
716  buf[0] = c;
717  gpgme_data_write(data, buf, 1);
718  }
719  mutt_file_fclose(&fp_tmp);
720  gpgme_data_seek(data, 0, SEEK_SET);
721  }
722  else
723  {
724  mutt_file_fclose(&fp_tmp);
725  err = gpgme_data_new_from_file(&data, mutt_buffer_string(tempfile), 1);
726  if (err != 0)
727  {
728  mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
729  gpgme_data_release(data);
730  data = NULL;
731  /* fall through to unlink the tempfile */
732  }
733  }
734  unlink(mutt_buffer_string(tempfile));
735 
736 cleanup:
737  mutt_buffer_pool_release(&tempfile);
738  return data;
739 }
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
Definition: crypt_gpgme.c:620
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
#define mutt_perror(...)
Definition: logging.h:88
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:760
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
+ 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 748 of file crypt_gpgme.c.

749 {
750  gpgme_data_t data = NULL;
751 
752  int err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length);
753  if (err != 0)
754  {
755  mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
756  return NULL;
757  }
758 
759  return data;
760 }
+ 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 769 of file crypt_gpgme.c.

770 {
771  char buf[4096];
772  ssize_t nread;
773 
774  int err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno(errno) : 0);
775  if (err != 0)
776  {
777  mutt_error(_("error rewinding data object: %s"), gpgme_strerror(err));
778  return -1;
779  }
780 
781  while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
782  {
783  /* fixme: we are not really converting CRLF to LF but just
784  * skipping CR. Doing it correctly needs a more complex logic */
785  for (char *p = buf; nread; p++, nread--)
786  {
787  if (*p != '\r')
788  putc(*p, fp);
789  }
790 
791  if (ferror(fp))
792  {
793  mutt_perror(_("[tempfile]"));
794  return -1;
795  }
796  }
797  if (nread == -1)
798  {
799  mutt_error(_("error reading data object: %s"), strerror(errno));
800  return -1;
801  }
802  return 0;
803 }
+ 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 816 of file crypt_gpgme.c.

817 {
818  ssize_t nread = 0;
819  char *rv = NULL;
820  struct Buffer *tempf = mutt_buffer_pool_get();
821 
822  mutt_buffer_mktemp(tempf);
823 
824  FILE *fp = mutt_file_fopen(mutt_buffer_string(tempf), "w+");
825  if (!fp)
826  {
827  mutt_perror(_("Can't create temporary file"));
828  goto cleanup;
829  }
830 
831  int err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno(errno) : 0);
832  if (err == 0)
833  {
834  char buf[4096];
835 
836  while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
837  {
838  if (fwrite(buf, nread, 1, fp) != 1)
839  {
841  mutt_file_fclose(&fp);
842  unlink(mutt_buffer_string(tempf));
843  goto cleanup;
844  }
845  }
846  }
847  if (fp_ret)
848  rewind(fp);
849  else
850  mutt_file_fclose(&fp);
851  if (nread == -1)
852  {
853  mutt_error(_("error reading data object: %s"), gpgme_strerror(err));
854  unlink(mutt_buffer_string(tempf));
855  mutt_file_fclose(&fp);
856  goto cleanup;
857  }
858  if (fp_ret)
859  *fp_ret = fp;
860  rv = mutt_buffer_strdup(tempf);
861 
862 cleanup:
863  mutt_buffer_pool_release(&tempf);
864  return rv;
865 }
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:432
+ 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 905 of file crypt_gpgme.c.

906 {
907  gpgme_key_t *rset = NULL;
908 
909  if (!p_rset)
910  return;
911 
912  rset = *p_rset;
913  if (!rset)
914  return;
915 
916  while (*rset)
917  {
918  gpgme_key_t k = *rset;
919  gpgme_key_unref(k);
920  rset++;
921  }
922 
923  FREE(p_rset);
924 }
+ 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 932 of file crypt_gpgme.c.

933 {
934  int err;
935  const char *s = NULL;
936  char buf[100];
937  gpgme_key_t *rset = NULL;
938  unsigned int rset_n = 0;
939  gpgme_key_t key = NULL;
940 
941  gpgme_ctx_t context = create_gpgme_context(use_smime);
942  s = keylist;
943  do
944  {
945  while (*s == ' ')
946  s++;
947  int i;
948  for (i = 0; *s && *s != ' ' && i < sizeof(buf) - 1;)
949  buf[i++] = *s++;
950  buf[i] = '\0';
951  if (*buf != '\0')
952  {
953  if ((i > 1) && (buf[i - 1] == '!'))
954  {
955  /* The user selected to override the validity of that key. */
956  buf[i - 1] = '\0';
957 
958  err = gpgme_get_key(context, buf, &key, 0);
959  if (err == 0)
960  key->uids->validity = GPGME_VALIDITY_FULL;
961  buf[i - 1] = '!';
962  }
963  else
964  err = gpgme_get_key(context, buf, &key, 0);
965  mutt_mem_realloc(&rset, sizeof(*rset) * (rset_n + 1));
966  if (err == 0)
967  rset[rset_n++] = key;
968  else
969  {
970  mutt_error(_("error adding recipient '%s': %s"), buf, gpgme_strerror(err));
971  rset[rset_n] = NULL;
972  recipient_set_free(&rset);
973  gpgme_release(context);
974  return NULL;
975  }
976  }
977  } while (*s);
978 
979  /* NULL terminate. */
980  mutt_mem_realloc(&rset, sizeof(*rset) * (rset_n + 1));
981  rset[rset_n++] = NULL;
982 
983  gpgme_release(context);
984 
985  return rset;
986 }
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:581
static void recipient_set_free(gpgme_key_t **p_rset)
Free a set of recipients.
Definition: crypt_gpgme.c:905
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
+ 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 997 of file crypt_gpgme.c.

998 {
999  gpgme_error_t err;
1000  gpgme_key_t key = NULL, key2 = NULL;
1001  gpgme_ctx_t listctx = create_gpgme_context(for_smime);
1002  err = gpgme_op_keylist_start(listctx, address, 1);
1003  if (err == 0)
1004  err = gpgme_op_keylist_next(listctx, &key);
1005  if (err)
1006  {
1007  gpgme_release(listctx);
1008  mutt_error(_("secret key '%s' not found: %s"), address, gpgme_strerror(err));
1009  return false;
1010  }
1011 
1012  char *fpr = "fpr1";
1013  if (key->subkeys)
1014  fpr = key->subkeys->fpr ? key->subkeys->fpr : key->subkeys->keyid;
1015  while (gpgme_op_keylist_next(listctx, &key2) == 0)
1016  {
1017  char *fpr2 = "fpr2";
1018  if (key2->subkeys)
1019  fpr2 = key2->subkeys->fpr ? key2->subkeys->fpr : key2->subkeys->keyid;
1020  if (!mutt_str_equal(fpr, fpr2))
1021  {
1022  gpgme_key_unref(key);
1023  gpgme_key_unref(key2);
1024  gpgme_release(listctx);
1025  mutt_error(_("ambiguous specification of secret key '%s'"), address);
1026  return false;
1027  }
1028  else
1029  {
1030  gpgme_key_unref(key2);
1031  }
1032  }
1033  gpgme_op_keylist_end(listctx);
1034  gpgme_release(listctx);
1035 
1036  gpgme_signers_clear(ctx);
1037  err = gpgme_signers_add(ctx, key);
1038  gpgme_key_unref(key);
1039  if (err)
1040  {
1041  mutt_error(_("error setting secret key '%s': %s"), address, gpgme_strerror(err));
1042  return false;
1043  }
1044  return true;
1045 }
+ 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 1055 of file crypt_gpgme.c.

1056 {
1057  const char *signid = NULL;
1058 
1059  const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
1060  const char *const c_pgp_sign_as = cs_subset_string(NeoMutt->sub, "pgp_sign_as");
1061  const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
1062  const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
1063  if (for_smime)
1064  signid = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
1065 #ifdef USE_AUTOCRYPT
1066  else if (OptAutocryptGpgme)
1067  signid = AutocryptSignAs;
1068 #endif
1069  else
1070  signid = c_pgp_sign_as ? c_pgp_sign_as : c_pgp_default_key;
1071 
1072  /* Try getting the signing key from config entries */
1073  if (signid && set_signer_from_address(ctx, signid, for_smime))
1074  {
1075  return 0;
1076  }
1077 
1078  /* Try getting the signing key from the From line */
1079  if (al)
1080  {
1081  struct Address *a;
1082  TAILQ_FOREACH(a, al, entries)
1083  {
1084  if (a->mailbox && set_signer_from_address(ctx, a->mailbox, for_smime))
1085  {
1086  return 0;
1087  }
1088  }
1089  }
1090 
1091  return (!signid && !al) ? 0 : -1;
1092 }
char * AutocryptSignAs
Autocrypt Key id to sign as.
Definition: config.c:35
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.
Definition: crypt_gpgme.c:997
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
An email address.
Definition: address.h:36
+ 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 1099 of file crypt_gpgme.c.

1100 {
1101  gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME, current_sender, 0);
1102  if (err)
1103  {
1104  mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
1105  }
1106 
1107  return err;
1108 }
static char * current_sender
Definition: crypt_gpgme.c:104
+ 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 1119 of file crypt_gpgme.c.

1121 {
1122  gpgme_error_t err;
1123  gpgme_ctx_t ctx = NULL;
1124  gpgme_data_t ciphertext = NULL;
1125  char *outfile = NULL;
1126 
1127 #if (GPGME_VERSION_NUMBER >= 0x010b00) // GPGME >= 1.11.0
1128  struct Buffer *recpstring = mutt_buffer_pool_get();
1129  create_recipient_string(keylist, recpstring, use_smime);
1130  if (mutt_buffer_is_empty(recpstring))
1131  {
1132  mutt_buffer_pool_release(&recpstring);
1133  return NULL;
1134  }
1135 #else
1136  gpgme_key_t *rset = create_recipient_set(keylist, use_smime);
1137  if (!rset)
1138  return NULL;
1139 #endif
1140 
1141  ctx = create_gpgme_context(use_smime);
1142  if (!use_smime)
1143  gpgme_set_armor(ctx, 1);
1144 
1145  ciphertext = create_gpgme_data();
1146 
1147  if (combined_signed)
1148  {
1149  if (set_signer(ctx, from, use_smime))
1150  goto cleanup;
1151 
1152  const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
1153  if (c_crypt_use_pka)
1154  {
1155  err = set_pka_sig_notation(ctx);
1156  if (err != 0)
1157  goto cleanup;
1158  }
1159 
1160 #if (GPGME_VERSION_NUMBER >= 0x010b00) // GPGME >= 1.11.0
1161  err = gpgme_op_encrypt_sign_ext(ctx, NULL, mutt_buffer_string(recpstring),
1162  GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
1163 #else
1164  err = gpgme_op_encrypt_sign(ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
1165 #endif
1166  }
1167  else
1168  {
1169 #if (GPGME_VERSION_NUMBER >= 0x010b00) // GPGME >= 1.11.0
1170  err = gpgme_op_encrypt_ext(ctx, NULL, mutt_buffer_string(recpstring),
1171  GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
1172 #else
1173  err = gpgme_op_encrypt(ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
1174 #endif
1175  }
1176 
1177  redraw_if_needed(ctx);
1178  if (err != 0)
1179  {
1180  mutt_error(_("error encrypting data: %s"), gpgme_strerror(err));
1181  goto cleanup;
1182  }
1183 
1184  outfile = data_object_to_tempfile(ciphertext, NULL);
1185 
1186 cleanup:
1187 #if (GPGME_VERSION_NUMBER >= 0x010b00) // GPGME >= 1.11.0
1188  mutt_buffer_pool_release(&recpstring);
1189 #else
1190  recipient_set_free(&rset);
1191 #endif
1192  gpgme_release(ctx);
1193  gpgme_data_release(ciphertext);
1194  return outfile;
1195 }
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
Set the signature notation.
Definition: crypt_gpgme.c:1099
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:932
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:1055
static void redraw_if_needed(gpgme_ctx_t ctx)
Accommodate for a redraw if needed.
Definition: crypt_gpgme.c:129
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:816
+ 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 1209 of file crypt_gpgme.c.

1210 {
1211  gpgme_sign_result_t result = NULL;
1212  const char *algorithm_name = NULL;
1213 
1214  if (buflen < 5)
1215  return -1;
1216 
1217  *buf = '\0';
1218  result = gpgme_op_sign_result(ctx);
1219  if (result && result->signatures)
1220  {
1221  algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
1222  if (algorithm_name)
1223  {
1224  if (use_smime)
1225  {
1226  /* convert GPGME raw hash name to RFC2633 format */
1227  snprintf(buf, buflen, "%s", algorithm_name);
1228  mutt_str_lower(buf);
1229  }
1230  else
1231  {
1232  /* convert GPGME raw hash name to RFC3156 format */
1233  snprintf(buf, buflen, "pgp-%s", algorithm_name);
1234  mutt_str_lower(buf + 4);
1235  }
1236  }
1237  }
1238 
1239  return (buf[0] != '\0') ? 0 : -1;
1240 }
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition: string.c:384
+ 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 1247 of file crypt_gpgme.c.

1248 {
1249  char p[256];
1250  mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
1251  state_puts(s, p);
1252 }
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:56
+ 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 1262 of file crypt_gpgme.c.

1263 {
1264  struct Body *t = NULL;
1265  char *sigfile = NULL;
1266  int err = 0;
1267  char buf[100];
1268  gpgme_ctx_t ctx = NULL;
1269  gpgme_data_t message = NULL, signature = NULL;
1270  gpgme_sign_result_t sigres = NULL;
1271 
1272  crypt_convert_to_7bit(a); /* Signed data _must_ be in 7-bit format. */
1273 
1274  message = body_to_data_object(a, true);
1275  if (!message)
1276  return NULL;
1277  signature = create_gpgme_data();
1278 
1279  ctx = create_gpgme_context(use_smime);
1280  if (!use_smime)
1281  gpgme_set_armor(ctx, 1);
1282 
1283  if (set_signer(ctx, from, use_smime))
1284  {
1285  gpgme_data_release(signature);
1286  gpgme_data_release(message);
1287  gpgme_release(ctx);
1288  return NULL;
1289  }
1290 
1291  const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
1292  if (c_crypt_use_pka)
1293  {
1294  err = set_pka_sig_notation(ctx);
1295  if (err != 0)
1296  {
1297  gpgme_data_release(signature);
1298  gpgme_data_release(message);
1299  gpgme_release(ctx);
1300  return NULL;
1301  }
1302  }
1303 
1304  err = gpgme_op_sign(ctx, message, signature, GPGME_SIG_MODE_DETACH);
1305  redraw_if_needed(ctx);
1306  gpgme_data_release(message);
1307  if (err != 0)
1308  {
1309  gpgme_data_release(signature);
1310  gpgme_release(ctx);
1311  mutt_error(_("error signing data: %s"), gpgme_strerror(err));
1312  return NULL;
1313  }
1314  /* Check for zero signatures generated. This can occur when $pgp_sign_as is
1315  * unset and there is no default key specified in ~/.gnupg/gpg.conf */
1316  sigres = gpgme_op_sign_result(ctx);
1317  if (!sigres->signatures)
1318  {
1319  gpgme_data_release(signature);
1320  gpgme_release(ctx);
1321  mutt_error(_("$pgp_sign_as unset and no default key specified in ~/.gnupg/gpg.conf"));
1322  return NULL;
1323  }
1324 
1325  sigfile = data_object_to_tempfile(signature, NULL);
1326  gpgme_data_release(signature);
1327  if (!sigfile)
1328  {
1329  gpgme_release(ctx);
1330  return NULL;
1331  }
1332 
1333  t = mutt_body_new();
1334  t->type = TYPE_MULTIPART;
1335  t->subtype = mutt_str_dup("signed");
1336  t->encoding = ENC_7BIT;
1337  t->use_disp = false;
1338  t->disposition = DISP_INLINE;
1339 
1341  mutt_param_set(&t->parameter, "protocol",
1342  use_smime ? "application/pkcs7-signature" : "application/pgp-signature");
1343  /* Get the micalg from GPGME. Old gpgme versions don't support this
1344  * for S/MIME so we assume sha-1 in this case. */
1345  if (get_micalg(ctx, use_smime, buf, sizeof(buf)) == 0)
1346  mutt_param_set(&t->parameter, "micalg", buf);
1347  else if (use_smime)
1348  mutt_param_set(&t->parameter, "micalg", "sha1");
1349  gpgme_release(ctx);
1350 
1351  t->parts = a;
1352  a = t;
1353 
1354  t->parts->next = mutt_body_new();
1355  t = t->parts->next;
1356  t->type = TYPE_APPLICATION;
1357  if (use_smime)
1358  {
1359  t->subtype = mutt_str_dup("pkcs7-signature");
1360  mutt_param_set(&t->parameter, "name", "smime.p7s");
1361  t->encoding = ENC_BASE64;
1362  t->use_disp = true;
1363  t->disposition = DISP_ATTACH;
1364  t->d_filename = mutt_str_dup("smime.p7s");
1365  }
1366  else
1367  {
1368  t->subtype = mutt_str_dup("pgp-signature");
1369  mutt_param_set(&t->parameter, "name", "signature.asc");
1370  t->use_disp = false;
1371  t->disposition = DISP_NONE;
1372  t->encoding = ENC_7BIT;
1373  }
1374  t->filename = sigfile;
1375  t->unlink = true; /* ok to remove this file after sending. */
1376 
1377  return a;
1378 }
void crypt_convert_to_7bit(struct Body *a)
Convert an email to 7bit encoding.
Definition: crypt.c:795
static gpgme_data_t body_to_data_object(struct Body *a, bool convert)
Create GPGME object from the mail body.
Definition: crypt_gpgme.c:676
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:1209
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
@ ENC_7BIT
7-bit text
Definition: mime.h:49
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ DISP_ATTACH
Content is attached.
Definition: mime.h:63
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
@ DISP_NONE
No preferred disposition.
Definition: mime.h:65
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:86
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
The body of an email.
Definition: body.h:36
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition: body.h:56
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:67
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:47
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
struct Body * next
next attachment in the list
Definition: body.h:71
char * subtype
content-type subtype
Definition: body.h:60
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
+ 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 1489 of file crypt_gpgme.c.

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

1614 {
1615  if (!key)
1616  return;
1617 
1618  const char *prefix = _("Fingerprint: ");
1619 
1620  const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1621  if (!s)
1622  return;
1623  bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1624 
1625  char *buf = mutt_mem_malloc(strlen(prefix) + strlen(s) * 4 + 2);
1626  strcpy(buf, prefix);
1627  char *p = buf + strlen(buf);
1628  if (is_pgp && (strlen(s) == 40))
1629  { /* PGP v4 style formatted. */
1630  for (int i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
1631  {
1632  *p++ = s[0];
1633  *p++ = s[1];
1634  *p++ = s[2];
1635  *p++ = s[3];
1636  *p++ = ' ';
1637  if (i == 4)
1638  *p++ = ' ';
1639  }
1640  }
1641  else
1642  {
1643  for (int i = 0; *s && s[1] && s[2]; s += 2, i++)
1644  {
1645  *p++ = s[0];
1646  *p++ = s[1];
1647  *p++ = is_pgp ? ' ' : ':';
1648  if (is_pgp && (i == 7))
1649  *p++ = ' ';
1650  }
1651  }
1652 
1653  /* just in case print remaining odd digits */
1654  for (; *s; s++)
1655  *p++ = *s;
1656  *p++ = '\n';
1657  *p = '\0';
1658  state_puts(state, buf);
1659  FREE(&buf);
1660 }
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
+ 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 1668 of file crypt_gpgme.c.

1669 {
1670  gpgme_signature_t sig = NULL;
1671  const char *txt = NULL;
1672 
1673  gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1674  if (result)
1675  for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--)
1676  ; // do nothing
1677 
1678  switch (sig ? sig->validity : 0)
1679  {
1680  case GPGME_VALIDITY_UNKNOWN:
1681  txt = _("WARNING: We have NO indication whether the key belongs to the person named as shown above\n");
1682  break;
1683  case GPGME_VALIDITY_UNDEFINED:
1684  break;
1685  case GPGME_VALIDITY_NEVER:
1686  txt = _("WARNING: The key does NOT BELONG to the person named as shown above\n");
1687  break;
1688  case GPGME_VALIDITY_MARGINAL:
1689  txt = _("WARNING: It is NOT certain that the key belongs to the person named as shown above\n");
1690  break;
1691  case GPGME_VALIDITY_FULL:
1692  case GPGME_VALIDITY_ULTIMATE:
1693  txt = NULL;
1694  break;
1695  }
1696  if (txt)
1697  state_puts(s, txt);
1698 }
+ 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 1707 of file crypt_gpgme.c.

1709 {
1710  int msgwid;
1711 
1712  state_puts(s, msg);
1713  state_puts(s, " ");
1714  /* key is NULL when not present in the user's keyring */
1715  if (key)
1716  {
1717  bool aka = false;
1718  for (gpgme_user_id_t uids = key->uids; uids; uids = uids->next)
1719  {
1720  if (uids->revoked)
1721  continue;
1722  if (aka)
1723  {
1724  msgwid = mutt_strwidth(msg) - mutt_strwidth(_("aka: ")) + 1;
1725  if (msgwid < 0)
1726  msgwid = 0;
1727  for (int i = 0; i < msgwid; i++)
1728  state_puts(s, " ");
1729  state_puts(s, _("aka: "));
1730  }
1731  state_puts(s, uids->uid);
1732  state_puts(s, "\n");
1733 
1734  aka = true;
1735  }
1736  }
1737  else
1738  {
1739  if (sig->fpr)
1740  {
1741  state_puts(s, _("KeyID "));
1742  state_puts(s, sig->fpr);
1743  }
1744  else
1745  {
1746  /* L10N: You will see this message in place of "KeyID "
1747  if the S/MIME key has no ID. This is quite an error. */
1748  state_puts(s, _("no signature fingerprint available"));
1749  }
1750  state_puts(s, "\n");
1751  }
1752 
1753  /* timestamp is 0 when verification failed.
1754  * "Jan 1 1970" is not the created date. */
1755  if (sig->timestamp)
1756  {
1757  msgwid = mutt_strwidth(msg) - mutt_strwidth(_("created: ")) + 1;
1758  if (msgwid < 0)
1759  msgwid = 0;
1760  for (int i = 0; i < msgwid; i++)
1761  state_puts(s, " ");
1762  state_puts(s, _("created: "));
1763  print_time(sig->timestamp, s);
1764  state_puts(s, "\n");
1765  }
1766 }
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:1014
+ 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 1780 of file crypt_gpgme.c.

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

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

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

2425 {
2426  /* Before GPGME 1.9.0 and gpg 2.1.14 there was no side-effect free
2427  * way to view key data in GPGME, so we import the key into a
2428  * temporary keyring if we detect an older system. */
2429  bool legacy_api;
2430  struct Buffer *tmpdir = NULL;
2431  gpgme_ctx_t tmpctx = NULL;
2432  gpgme_error_t err;
2433  gpgme_engine_info_t engineinfo = NULL;
2434  gpgme_key_t key = NULL;
2435  gpgme_user_id_t uid = NULL;
2436  gpgme_subkey_t subkey = NULL;
2437  const char *shortid = NULL;
2438  size_t len;
2439  char date[256];
2440  bool more;
2441  int rc = -1;
2442  time_t tt;
2443 
2444 #if (GPGME_VERSION_NUMBER >= 0x010900) // GPGME >= 1.9.0
2445  legacy_api = !have_gpg_version("2.1.14");
2446 #else
2447  legacy_api = true;
2448 #endif
2449 
2450  tmpctx = create_gpgme_context(false);
2451 
2452  if (legacy_api)
2453  {
2454  tmpdir = mutt_buffer_pool_get();
2455  const char *const c_tmpdir = cs_subset_path(NeoMutt->sub, "tmpdir");
2456  mutt_buffer_printf(tmpdir, "%s/neomutt-gpgme-XXXXXX", NONULL(c_tmpdir));
2457  if (!mkdtemp(tmpdir->data))
2458  {
2459  mutt_debug(LL_DEBUG1, "Error creating temporary GPGME home\n");
2460  goto err_ctx;
2461  }
2462 
2463  engineinfo = gpgme_ctx_get_engine_info(tmpctx);
2464  while (engineinfo && (engineinfo->protocol != GPGME_PROTOCOL_OpenPGP))
2465  engineinfo = engineinfo->next;
2466  if (!engineinfo)
2467  {
2468  mutt_debug(LL_DEBUG1, "Error finding GPGME PGP engine\n");
2469  goto err_tmpdir;
2470  }
2471 
2472  err = gpgme_ctx_set_engine_info(tmpctx, GPGME_PROTOCOL_OpenPGP, engineinfo->file_name,
2473  mutt_buffer_string(tmpdir));
2474  if (err != GPG_ERR_NO_ERROR)
2475  {
2476  mutt_debug(LL_DEBUG1, "Error setting GPGME context home\n");
2477  goto err_tmpdir;
2478  }
2479  }
2480 
2481  *fp = mutt_file_mkstemp();
2482  if (!*fp)
2483  {
2484  mutt_perror(_("Can't create temporary file"));
2485  goto err_tmpdir;
2486  }
2487 
2488 #if (GPGME_VERSION_NUMBER >= 0x010900) // GPGME >= 1.9.0
2489  if (!legacy_api)
2490  err = gpgme_op_keylist_from_data_start(tmpctx, keydata, 0);
2491  else
2492 #endif
2493  {
2494  err = gpgme_op_keylist_start(tmpctx, NULL, 0);
2495  }
2496  while (err == 0)
2497  {
2498  err = gpgme_op_keylist_next(tmpctx, &key);
2499  if (err != 0)
2500  break;
2501  uid = key->uids;
2502  subkey = key->subkeys;
2503  more = false;
2504  while (subkey)
2505  {
2506  shortid = subkey->keyid;
2507  len = mutt_str_len(subkey->keyid);
2508  if (len > 8)
2509  shortid += len - 8;
2510  tt = subkey->timestamp;
2511  mutt_date_localtime_format(date, sizeof(date), "%Y-%m-%d", tt);
2512 
2513  if (more)
2514  {
2515  fprintf(*fp, "sub %5.5s %u/%8s %s\n", gpgme_pubkey_algo_name(subkey->pubkey_algo),
2516  subkey->length, shortid, date);
2517  }
2518  else
2519  {
2520  fprintf(*fp, "pub %5.5s %u/%8s %s %s\n", gpgme_pubkey_algo_name(subkey->pubkey_algo),
2521  subkey->length, shortid, date, (uid ? uid->uid : ""));
2522  }
2523  subkey = subkey->next;
2524  more = true;
2525  }
2526  gpgme_key_unref(key);
2527  }
2528  if (gpg_err_code(err) != GPG_ERR_EOF)
2529  {
2530  mutt_debug(LL_DEBUG1, "Error listing keys\n");
2531  goto err_fp;
2532  }
2533 
2534  rc = 0;
2535 
2536 err_fp:
2537  if (rc)
2538  mutt_file_fclose(fp);
2539 err_tmpdir:
2540  if (legacy_api)
2542 err_ctx:
2543  gpgme_release(tmpctx);
2544 
2545  mutt_buffer_pool_release(&tmpdir);
2546 
2547  return rc;
2548 }
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
int mutt_file_rmtree(const char *path)
Recursively remove a directory.
Definition: file.c:459
#define mutt_file_mkstemp()
Definition: file.h:112
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:544
#define NONULL(x)
Definition: string2.h:37
+ 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 2561 of file crypt_gpgme.c.

2562 {
2563  if (mutt_strn_equal(a, b, n))
2564  {
2565  /* at this point we know that 'b' is at least 'n' chars long */
2566  if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2567  return true;
2568  }
2569  return false;
2570 }
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:473
+ 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 2579 of file crypt_gpgme.c.

2580 {
2581  char buf[8192];
2582  bool rc = false;
2583 
2584  bool sgn = false;
2585  bool enc = false;
2586 
2587  if (b->type != TYPE_TEXT)
2588  return 0;
2589 
2590  struct Buffer *tempfile = mutt_buffer_pool_get();
2591  mutt_buffer_mktemp(tempfile);
2592  if (mutt_decode_save_attachment(fp, b, mutt_buffer_string(tempfile), 0,
2593  MUTT_SAVE_NO_FLAGS) != 0)
2594  {
2595  unlink(mutt_buffer_string(tempfile));
2596  goto cleanup;
2597  }
2598 
2599  FILE *fp_tmp = fopen(mutt_buffer_string(tempfile), "r");
2600  if (!fp_tmp)
2601  {
2602  unlink(mutt_buffer_string(tempfile));
2603  goto cleanup;
2604  }
2605 
2606  while (fgets(buf, sizeof(buf), fp_tmp))
2607  {
2608  size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2609  if (plen != 0)
2610  {
2611  if (MESSAGE(buf + plen))
2612  {
2613  enc = true;
2614  break;
2615  }
2616  else if (SIGNED_MESSAGE(buf + plen))
2617  {
2618  sgn = true;
2619  break;
2620  }
2621  }
2622  }
2623  mutt_file_fclose(&fp_tmp);
2624  unlink(mutt_buffer_string(tempfile));
2625 
2626  if (!enc && !sgn)
2627  goto cleanup;
2628 
2629  /* fix the content type */
2630 
2631  mutt_param_set(&b->parameter, "format", "fixed");
2632  mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2633 
2634  rc = true;
2635 
2636 cleanup:
2637  mutt_buffer_pool_release(&tempfile);
2638  return rc;
2639 }
#define SIGNED_MESSAGE(_y)
Definition: crypt_gpgme.c:110
#define MESSAGE(_y)
Definition: crypt_gpgme.c:109
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
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:1031
@ MUTT_SAVE_NO_FLAGS
No flags set.
Definition: mutt_attach.h:57
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
+ 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 2778 of file crypt_gpgme.c.

2779 {
2780  char buf[8192];
2781  bool complete, armor_header;
2782  FILE *fp = NULL;
2783 
2784  char *fname = data_object_to_tempfile(data, &fp);
2785  if (!fname)
2786  {
2787  mutt_file_fclose(&fp);
2788  return;
2789  }
2790  unlink(fname);
2791  FREE(&fname);
2792 
2793  /* fromcode comes from the MIME Content-Type charset label. It might
2794  * be a wrong label, so we want the ability to do corrections via
2795  * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2796  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
2797  struct FgetConv *fc = mutt_ch_fgetconv_open(fp, charset, c_charset, MUTT_ICONV_HOOK_FROM);
2798 
2799  for (complete = true, armor_header = true;
2800  mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2801  {
2802  if (!complete)
2803  {
2804  if (!armor_header)
2805  state_puts(s, buf);
2806  continue;
2807  }
2808 
2809  if (BEGIN_PGP_SIGNATURE(buf))
2810  break;
2811 
2812  if (armor_header)
2813  {
2814  if (buf[0] == '\n')
2815  armor_header = false;
2816  continue;
2817  }
2818 
2819  if (s->prefix)
2820  state_puts(s, s->prefix);
2821 
2822  if ((buf[0] == '-') && (buf[1] == ' '))
2823  state_puts(s, buf + 2);
2824  else
2825  state_puts(s, buf);
2826  }
2827 
2829  mutt_file_fclose(&fp);
2830 }
#define BEGIN_PGP_SIGNATURE(_y)
Definition: crypt_gpgme.c:112
void mutt_ch_fgetconv_close(struct FgetConv **fc)
Close an fgetconv handle.
Definition: charset.c:887
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:857
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition: charset.c:969
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:72
Cursor for converting a file's encoding.
Definition: charset.h:41
FILE * fp
Definition: charset.h:42
char * prefix
String to add to the beginning of each output line.
Definition: state.h:49
+ 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 3254 of file crypt_gpgme.c.

3255 {
3256  unsigned int rc = 0;
3257 
3258  switch (cap)
3259  {
3260  case KEY_CAP_CAN_ENCRYPT:
3261  rc = key->can_encrypt;
3262  if (rc == 0)
3263  {
3264  for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
3265  {
3266  rc = subkey->can_encrypt;
3267  if (rc != 0)
3268  break;
3269  }
3270  }
3271  break;
3272  case KEY_CAP_CAN_SIGN:
3273  rc = key->can_sign;
3274  if (rc == 0)
3275  {
3276  for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
3277  {
3278  rc = subkey->can_sign;
3279  if (rc != 0)
3280  break;
3281  }
3282  }
3283  break;
3284  case KEY_CAP_CAN_CERTIFY:
3285  rc = key->can_certify;
3286  if (rc == 0)
3287  {
3288  for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
3289  {
3290  rc = subkey->can_certify;
3291  if (rc != 0)
3292  break;
3293  }
3294  }
3295  break;
3296  }
3297 
3298  return rc;
3299 }
@ KEY_CAP_CAN_CERTIFY
Key can be used to certify.
Definition: crypt_gpgme.h:78
@ KEY_CAP_CAN_ENCRYPT
Key can be used for encryption.
Definition: crypt_gpgme.h:76
@ KEY_CAP_CAN_SIGN
Key can be used for signing.
Definition: crypt_gpgme.h:77
+ 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 3310 of file crypt_gpgme.c.

3311 {
3312  char *pattern = NULL, *p = NULL;
3313  const char *s = NULL;
3314  size_t n;
3315 
3316  n = 0;
3317  struct ListNode *np = NULL;
3318  STAILQ_FOREACH(np, list, entries)
3319  {
3320  for (s = np->data; *s; s++)
3321  {
3322  if ((*s == '%') || (*s == '+'))
3323  n += 2;
3324  n++;
3325  }
3326  n++; /* delimiter or end of string */
3327  }
3328  n++; /* make sure to allocate at least one byte */
3329  p = mutt_mem_calloc(1, n);
3330  pattern = p;
3331  STAILQ_FOREACH(np, list, entries)
3332  {
3333  s = np->data;
3334  if (*s)
3335  {
3336  if (np != STAILQ_FIRST(list))
3337  *p++ = ' ';
3338  for (s = np->data; *s; s++)
3339  {
3340  if (*s == '%')
3341  {
3342  *p++ = '%';
3343  *p++ = '2';
3344  *p++ = '5';
3345  }
3346  else if (*s == '+')
3347  {
3348  *p++ = '%';
3349  *p++ = '2';
3350  *p++ = 'B';
3351  }
3352  else if (*s == ' ')
3353  *p++ = '+';
3354  else
3355  *p++ = *s;
3356  }
3357  }
3358  }
3359  *p = '\0';
3360  return pattern;
3361 }
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
+ 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 3373 of file crypt_gpgme.c.

3374 {
3375  struct CryptKeyInfo *db = NULL, *k = NULL, **kend = NULL;
3376  gpgme_error_t err;
3377  gpgme_ctx_t ctx = NULL;
3378  gpgme_key_t key = NULL;
3379  int idx;
3380  gpgme_user_id_t uid = NULL;
3381 
3382  char *pattern = list_to_pattern(hints);
3383  if (!pattern)
3384  return NULL;
3385 
3386  ctx = create_gpgme_context(0);
3387  db = NULL;
3388  kend = &db;
3389 
3390  if ((app & APPLICATION_PGP))
3391  {
3392  /* It's all a mess. That old GPGME expects different things depending on
3393  * the protocol. For gpg we don't need percent escaped pappert but simple
3394  * strings passed in an array to the keylist_ext_start function. */
3395  size_t n = 0;
3396  struct ListNode *np = NULL;
3397  STAILQ_FOREACH(np, hints, entries)
3398  {
3399  if (np->data && *np->data)
3400  n++;
3401  }
3402  if (n == 0)
3403  goto no_pgphints;
3404 
3405  char **patarr = mutt_mem_calloc(n + 1, sizeof(*patarr));
3406  n = 0;
3407  STAILQ_FOREACH(np, hints, entries)
3408  {
3409  if (np->data && *np->data)
3410  patarr[n++] = mutt_str_dup(np->data);
3411  }
3412  patarr[n] = NULL;
3413  err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
3414  for (n = 0; patarr[n]; n++)
3415  FREE(&patarr[n]);
3416  FREE(&patarr);
3417  if (err != 0)
3418  {
3419  mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3420  gpgme_release(ctx);
3421  FREE(&pattern);
3422  return NULL;
3423  }
3424 
3425  while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
3426  {
3427  KeyFlags flags = KEYFLAG_NO_FLAGS;
3428 
3430  flags |= KEYFLAG_CANENCRYPT;
3431  if (key_check_cap(key, KEY_CAP_CAN_SIGN))
3432  flags |= KEYFLAG_CANSIGN;
3433 
3434  if (key->revoked)
3435  flags |= KEYFLAG_REVOKED;
3436  if (key->expired)
3437  flags |= KEYFLAG_EXPIRED;
3438  if (key->disabled)
3439  flags |= KEYFLAG_DISABLED;
3440 
3441  for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3442  {
3443  k = mutt_mem_calloc(1, sizeof(*k));
3444  k->kobj = key;
3445  gpgme_key_ref(k->kobj);
3446  k->idx = idx;
3447  k->uid = uid->uid;
3448  k->flags = flags;
3449  if (uid->revoked)
3450  k->flags |= KEYFLAG_REVOKED;
3451  k->validity = uid->validity;
3452  *kend = k;
3453  kend = &k->next;
3454  }
3455  gpgme_key_unref(key);
3456  }
3457  if (gpg_err_code(err) != GPG_ERR_EOF)
3458  mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3459  gpgme_op_keylist_end(ctx);
3460  no_pgphints:;
3461  }
3462 
3463  if ((app & APPLICATION_SMIME))
3464  {
3465  /* and now look for x509 certificates */
3466  gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
3467  err = gpgme_op_keylist_start(ctx, pattern, 0);
3468  if (err != 0)
3469  {
3470  mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3471  gpgme_release(ctx);
3472  FREE(&pattern);
3473  return NULL;
3474  }
3475 
3476  while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
3477  {
3478  KeyFlags flags = KEYFLAG_ISX509;
3479 
3481  flags |= KEYFLAG_CANENCRYPT;
3482  if (key_check_cap(key, KEY_CAP_CAN_SIGN))
3483  flags |= KEYFLAG_CANSIGN;
3484 
3485  if (key->revoked)
3486  flags |= KEYFLAG_REVOKED;
3487  if (key->expired)
3488  flags |= KEYFLAG_EXPIRED;
3489  if (key->disabled)
3490  flags |= KEYFLAG_DISABLED;
3491 
3492  for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3493  {
3494  k = mutt_mem_calloc(1, sizeof(*k));
3495  k->kobj = key;
3496  gpgme_key_ref(k->kobj);
3497  k->idx = idx;
3498  k->uid = uid->uid;
3499  k->flags = flags;
3500  if (uid->revoked)
3501  k->flags |= KEYFLAG_REVOKED;
3502  k->validity = uid->validity;
3503  *kend = k;
3504  kend = &k->next;
3505  }
3506  gpgme_key_unref(key);
3507  }
3508  if (gpg_err_code(err) != GPG_ERR_EOF)
3509  mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3510  gpgme_op_keylist_end(ctx);
3511  }
3512 
3513  gpgme_release(ctx);
3514  FREE(&pattern);
3515  return db;
3516 }
static char * list_to_pattern(struct ListHead *list)
Convert STailQ to GPGME-compatible pattern.
Definition: crypt_gpgme.c:3310
unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
Definition: crypt_gpgme.c:3254
#define KEYFLAG_EXPIRED
Key is expired.
Definition: lib.h:131
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:125
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:128
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define KEYFLAG_NO_FLAGS
No flags are set.
Definition: lib.h:126
#define KEYFLAG_DISABLED
Key is marked disabled.
Definition: lib.h:133
#define KEYFLAG_REVOKED
Key is revoked.
Definition: lib.h:132
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:127
+ 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 3526 of file crypt_gpgme.c.

3527 {
3528  char *scratch = mutt_str_dup(str);
3529  if (!scratch)
3530  return;
3531 
3532  for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3533  {
3534  if (strlen(t) > 3)
3536  }
3537 
3538  FREE(&scratch);
3539 }
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
+ 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,
bool *  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 3550 of file crypt_gpgme.c.

3553 {
3554  struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3555 
3556  int multi = false;
3557  int this_key_has_strong = false;
3558  int this_key_has_addr_match = false;
3559  int match = false;
3560 
3561  struct CryptKeyInfo *keys = NULL, *k = NULL;
3562  struct CryptKeyInfo *the_strong_valid_key = NULL;
3563  struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3564  struct CryptKeyInfo *matches = NULL;
3565  struct CryptKeyInfo **matches_endp = &matches;
3566 
3567  if (a && a->mailbox)
3569  if (a && a->personal)
3570  crypt_add_string_to_hints(a->personal, &hints);
3571 
3572  if (!oppenc_mode)
3573  mutt_message(_("Looking for keys matching \"%s\"..."), a ? a->mailbox : "");
3574  keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3575 
3576  mutt_list_free(&hints);
3577 
3578  if (!keys)
3579  return NULL;
3580 
3581  mutt_debug(LL_DEBUG5, "looking for %s <%s>\n", a ? NONULL(a->personal) : "",
3582  a ? NONULL(a->mailbox) : "");
3583 
3584  for (k = keys; k; k = k->next)
3585  {
3586  mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3587 
3588  if (abilities && !(k->flags & abilities))
3589  {
3590  mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3591  continue;
3592  }
3593 
3594  this_key_has_strong = false; /* strong and valid match */
3595  this_key_has_addr_match = false;
3596  match = false; /* any match */
3597 
3598  struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3599  mutt_addrlist_parse(&alist, k->uid);
3600  struct Address *ka = NULL;
3601  TAILQ_FOREACH(ka, &alist, entries)
3602  {
3603  int validity = crypt_id_matches_addr(a, ka, k);
3604 
3605  if (validity & CRYPT_KV_MATCH) /* something matches */
3606  {
3607  match = true;
3608 
3609  if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3610  {
3611  if (validity & CRYPT_KV_STRONGID)
3612  {
3613  if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3614  multi = true;
3615  this_key_has_strong = true;
3616  }
3617  else
3618  this_key_has_addr_match = true;
3619  }
3620  }
3621  }
3622  mutt_addrlist_clear(&alist);
3623 
3624  if (match)
3625  {
3626  struct CryptKeyInfo *tmp = crypt_copy_key(k);
3627  *matches_endp = tmp;
3628  matches_endp = &tmp->next;
3629 
3630  if (this_key_has_strong)
3631  the_strong_valid_key = tmp;
3632  else if (this_key_has_addr_match)
3633  a_valid_addrmatch_key = tmp;
3634  }
3635  }
3636 
3637  crypt_key_free(&keys);
3638 
3639  if (matches)
3640  {
3641  if (oppenc_mode)
3642  {
3643  const bool c_crypt_opportunistic_encrypt_strong_keys =
3644  cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3645  if (the_strong_valid_key)
3646  k = crypt_copy_key(the_strong_valid_key);
3647  else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3648  k = crypt_copy_key(a_valid_addrmatch_key);
3649  else
3650  k = NULL;
3651  }
3652  else if (the_strong_valid_key && !multi)
3653  {
3654  /* There was precisely one strong match on a valid ID.
3655  * Proceed without asking the user. */
3656  k = crypt_copy_key(the_strong_valid_key);
3657  }
3658  else
3659  {
3660  /* Else: Ask the user. */
3661  k = dlg_select_gpgme_key(matches, a, NULL, app, forced_valid);
3662  }
3663 
3664  crypt_key_free(&matches);
3665  }
3666  else
3667  k = NULL;
3668 
3669  return k;
3670 }
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
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:547
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:3526
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
Definition: crypt_gpgme.c:453
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
Definition: crypt_gpgme.c:357
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
Definition: crypt_gpgme.c:472
#define CRYPT_KV_MATCH
Definition: crypt_gpgme.c:89
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:3373
struct CryptKeyInfo * dlg_select_gpgme_key(struct CryptKeyInfo *keys, struct Address *p, const char *s, unsigned int app, bool *forced_valid)
Get the user to select a key.
Definition: dlg_gpgme.c:662
#define mutt_message(...)
Definition: logging.h:86
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
@ LL_DEBUG5
Log at debug level 5.
Definition: logging.h:44
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#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,
bool *  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 3680 of file crypt_gpgme.c.

3682 {
3683  struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3684  struct CryptKeyInfo *matches = NULL;
3685  struct CryptKeyInfo **matches_endp = &matches;
3686  struct CryptKeyInfo *k = NULL;
3687  const char *ps = NULL, *pl = NULL, *phint = NULL;
3688 
3689  mutt_message(_("Looking for keys matching \"%s\"..."), p);
3690 
3691  const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3692  crypt_add_string_to_hints(phint, &hints);
3693  struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3694  mutt_list_free(&hints);
3695 
3696  if (!keys)
3697  {
3698  FREE(&pfcopy);
3699  return NULL;
3700  }
3701 
3702  for (k = keys; k; k = k->next)
3703  {
3704  if (abilities && !(k->flags & abilities))
3705  continue;
3706 
3707  mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3708  crypt_long_keyid(k), k->uid);
3709 
3710  if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3711  (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3712  (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3713  {
3714  mutt_debug(LL_DEBUG5, "match\n");
3715 
3716  struct CryptKeyInfo *tmp = crypt_copy_key(k);
3717  *matches_endp = tmp;
3718  matches_endp = &tmp->next;
3719  }
3720  else
3721  {
3722  mutt_debug(LL_DEBUG5, "no match\n");
3723  }
3724  }
3725 
3726  FREE(&pfcopy);
3727  crypt_key_free(&keys);
3728 
3729  if (matches)
3730  {
3731  k = dlg_select_gpgme_key(matches, NULL, p, app, forced_valid);
3732  crypt_key_free(&matches);
3733  return k;
3734  }
3735 
3736  return NULL;
3737 }
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:1263
static const char * crypt_short_keyid(struct CryptKeyInfo *k)
Get the short keyID for a key.
Definition: crypt_gpgme.c:399
static const char * crypt_fpr(struct CryptKeyInfo *k)
Get the hexstring fingerprint from a key.
Definition: crypt_gpgme.c:418
static const char * crypt_long_keyid(struct CryptKeyInfo *k)
Find the Long ID for the key.
Definition: crypt_gpgme.c:382
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:569
+ 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,
bool *  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 3751 of file crypt_gpgme.c.

3753 {
3754  struct CryptKeyInfo *key = NULL;
3755  struct CryptCache *l = NULL;
3756  struct Buffer *resp = mutt_buffer_pool_get();
3757 
3758  mutt_clear_error();
3759 
3760  if (whatfor)
3761  {
3762  for (l = id_defaults; l; l = l->next)
3763  {
3764  if (mutt_istr_equal(whatfor, l->what))
3765  {
3766  mutt_buffer_strcpy(resp, l->dflt);
3767  break;
3768  }
3769  }
3770  }
3771 
3772  while (true)
3773  {
3774  mutt_buffer_reset(resp);
3775  if (mutt_buffer_get_field(tag, resp, MUTT_COMP_NO_FLAGS, false, NULL, NULL, NULL) != 0)
3776  {
3777  goto done;
3778  }
3779 
3780  if (whatfor)
3781  {
3782  if (l)
3784  else
3785  {
3786  l = mutt_mem_malloc(sizeof(struct CryptCache));
3787  l->next = id_defaults;
3788  id_defaults = l;
3789  l->what = mutt_str_dup(whatfor);
3790  l->dflt = mutt_buffer_strdup(resp);
3791  }
3792  }
3793 
3794  key = crypt_getkeybystr(mutt_buffer_string(resp), abilities, app, forced_valid);
3795  if (key)
3796  goto done;
3797 
3798  mutt_error(_("No matching keys found for \"%s\""), mutt_buffer_string(resp));
3799  }
3800 
3801 done:
3802  mutt_buffer_pool_release(&resp);
3803  return key;
3804 }
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
static struct CryptCache * id_defaults
Definition: crypt_gpgme.c:102
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
Find a key by string.
Definition: crypt_gpgme.c:3680
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:337
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
#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:74
Internal cache for GPGME.
Definition: crypt_gpgme.c:96
char * what
Definition: crypt_gpgme.c:97
char * dflt
Definition: crypt_gpgme.c:98
struct CryptCache * next
Definition: crypt_gpgme.c:99
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_keys()

static char* find_keys ( const 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 3817 of file crypt_gpgme.c.

3818 {
3819  struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3820  struct ListNode *crypt_hook = NULL;
3821  const char *keyid = NULL;
3822  char *keylist = NULL;
3823  size_t keylist_size = 0;
3824  size_t keylist_used = 0;
3825  struct Address *p = NULL;
3826  struct CryptKeyInfo *k_info = NULL;
3827  const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3828  char buf[1024];
3829  bool forced_valid = false;
3830  bool key_selected;
3831  struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3832 
3833  struct Address *a = NULL;
3834  TAILQ_FOREACH(a, addrlist, entries)
3835  {
3836  key_selected = false;
3837  mutt_crypt_hook(&crypt_hook_list, a);
3838  crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3839  do
3840  {
3841  p = a;
3842  forced_valid = false;
3843  k_info = NULL;
3844 
3845  if (crypt_hook)
3846  {
3847  keyid = crypt_hook->data;
3848  enum QuadOption ans = MUTT_YES;
3849  const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3850  if (!oppenc_mode && c_crypt_confirm_hook)
3851  {
3852  snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid, p->mailbox);
3853  ans = mutt_yesorno(buf, MUTT_YES);
3854  }
3855  if (ans == MUTT_YES)
3856  {
3857  if (crypt_is_numerical_keyid(keyid))
3858  {
3859  if (mutt_strn_equal(keyid, "0x", 2))
3860  keyid += 2;
3861  goto bypass_selection; /* you don't see this. */
3862  }
3863 
3864  /* check for e-mail address */
3865  mutt_addrlist_clear(&hookal);
3866  if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3867  {
3868  mutt_addrlist_qualify(&hookal, fqdn);
3869  p = TAILQ_FIRST(&hookal);
3870  }
3871  else if (!oppenc_mode)
3872  {
3873  k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3874  }
3875  }
3876  else if (ans == MUTT_NO)
3877  {
3878  if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3879  {
3880  crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3881  continue;
3882  }
3883  }
3884  else if (ans == MUTT_ABORT)
3885  {
3886  FREE(&keylist);
3887  mutt_addrlist_clear(&hookal);
3888  mutt_list_free(&crypt_hook_list);
3889  return NULL;
3890  }
3891  }
3892 
3893  if (!k_info)
3894  {
3895  k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3896  }
3897 
3898  if (!k_info && !oppenc_mode)
3899  {
3900  snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), p->mailbox);
3901 
3902  k_info = crypt_ask_for_key(buf, p->mailbox, KEYFLAG_CANENCRYPT, app, &forced_valid);
3903  }
3904 
3905  if (!k_info)
3906  {
3907  FREE(&keylist);
3908  mutt_addrlist_clear(&hookal);
3909  mutt_list_free(&crypt_hook_list);
3910  return NULL;
3911  }
3912 
3913  keyid = crypt_fpr_or_lkeyid(k_info);
3914 
3915  bypass_selection:
3916  keylist_size += mutt_str_len(keyid) + 4 + 1;
3917  mutt_mem_realloc(&keylist, keylist_size);
3918  sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3919  keyid, forced_valid ? "!" : "");
3920  keylist_used = mutt_str_len(keylist);
3921 
3922  key_selected = true;
3923 
3924  crypt_key_free(&k_info);
3925  mutt_addrlist_clear(&hookal);
3926 
3927  if (crypt_hook)
3928  crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3929 
3930  } while (crypt_hook);
3931 
3932  mutt_list_free(&crypt_hook_list);
3933  }
3934  return keylist;
3935 }
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:650
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition: crypt.c:1352
static struct CryptKeyInfo * crypt_getkeybyaddr(struct Address *a, KeyFlags abilities, unsigned int app, bool *forced_valid, bool oppenc_mode)
Find a key by email address.
Definition: crypt_gpgme.c:3550
static struct CryptKeyInfo * crypt_ask_for_key(char *tag, char *whatfor, KeyFlags abilities, unsigned int app, bool *forced_valid)
Ask the user for a key.
Definition: crypt_gpgme.c:3751
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
Definition: crypt_gpgme.c:433
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:807
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:698
+ 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 3966 of file crypt_gpgme.c.

3967 {
3968  int rc = -1;
3969  gpgme_error_t err;
3970  gpgme_key_t key = NULL;
3971  gpgme_user_id_t uid = NULL;
3972  struct CryptKeyInfo *results = NULL, *k = NULL;
3973  struct CryptKeyInfo **kend = NULL;
3974  struct CryptKeyInfo *choice = NULL;
3975 
3976  gpgme_ctx_t ctx = create_gpgme_context(false);
3977 
3978  /* list all secret keys */
3979  if (gpgme_op_keylist_start(ctx, NULL, 1))
3980  goto cleanup;
3981 
3982  kend = &results;
3983 
3984  while (!(err = gpgme_op_keylist_next(ctx, &key)))
3985  {
3987 
3990  if (key_check_cap(key, KEY_CAP_CAN_SIGN))
3992 
3993  if (key->revoked)
3995  if (key->expired)
3997  if (key->disabled)
3999 
4000  int idx;
4001  for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
4002  {
4003  k = mutt_mem_calloc(1, sizeof(*k));
4004  k->kobj = key;
4005  gpgme_key_ref(k->kobj);
4006  k->idx = idx;
4007  k->uid = uid->uid;
4008  k->flags = flags;
4009  if (uid->revoked)
4010  k->flags |= KEYFLAG_REVOKED;
4011  k->validity = uid->validity;
4012  *kend = k;
4013  kend = &k->next;
4014  }
4015  gpgme_key_unref(key);
4016  }
4017  if (gpg_err_code(err) != GPG_ERR_EOF)
4018  mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
4019  gpgme_op_keylist_end(ctx);
4020 
4021  if (!results)
4022  {
4023  /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
4024  from. This error is displayed if no results were found. */
4025  mutt_error(_("No secret keys found"));
4026  goto cleanup;
4027  }
4028 
4029  choice = dlg_select_gpgme_key(results, NULL, "*", APPLICATION_PGP, NULL);
4030  if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
4031  goto cleanup;
4032  mutt_buffer_strcpy(keyid, choice->kobj->subkeys->fpr);
4033 
4034  rc = 0;
4035 
4036 cleanup:
4037  crypt_key_free(&choice);
4038  crypt_key_free(&results);
4039  gpgme_release(ctx);
4040  return rc;
4041 }
+ 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 4111 of file crypt_gpgme.c.

4112 {
4113  /* this initialization should only run one time, but it may be called by
4114  * either pgp_gpgme_init or smime_gpgme_init */
4115  static bool has_run = false;
4116  if (has_run)
4117  return;
4118 
4119  gpgme_check_version(NULL);
4120  gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
4121 #ifdef ENABLE_NLS
4122  gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
4123 #endif
4124  has_run = true;
4125 }
+ Here is the caller graph for this function:

◆ init_pgp()

static void init_pgp ( void  )
static

Initialise the PGP crypto backend.

Definition at line 4130 of file crypt_gpgme.c.

4131 {
4132  if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
4133  {
4134  mutt_error(_("GPGME: OpenPGP protocol not available"));
4135  }
4136 }
+ Here is the caller graph for this function:

◆ init_smime()

static void init_smime ( void  )
static

Initialise the SMIME crypto backend.

Definition at line 4141 of file crypt_gpgme.c.

4142 {
4143  if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
4144  {
4145  mutt_error(_("GPGME: CMS protocol not available"));
4146  }
4147 }
+ Here is the caller graph for this function:

◆ gpgme_send_menu()

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

Show the user the encryption/signing menu.

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

Definition at line 4173 of file crypt_gpgme.c.

4174 {
4175  struct CryptKeyInfo *p = NULL;
4176  const char *prompt = NULL;
4177  const char *letters = NULL;
4178  const char *choices = NULL;
4179  int choice;
4180 
4181  if (is_smime)
4183  else
4184  e->security |= APPLICATION_PGP;
4185 
4186  /* Opportunistic encrypt is controlling encryption.
4187  * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
4188  * letter choices for those.
4189  */
4190  const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
4191  if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
4192  {
4193  if (is_smime)
4194  {
4195  /* L10N: S/MIME options (opportunistic encryption is on) */
4196  prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
4197  /* L10N: S/MIME options (opportunistic encryption is on) */
4198  letters = _("sapco");
4199  choices = "SapCo";
4200  }
4201  else
4202  {
4203  /* L10N: PGP options (opportunistic encryption is on) */
4204  prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
4205  /* L10N: PGP options (opportunistic encryption is on) */
4206  letters = _("samco");
4207  choices = "SamCo";
4208  }
4209  }
4210  /* Opportunistic encryption option is set, but is toggled off for this message. */
4211  else if (c_crypt_opportunistic_encrypt)
4212  {
4213  if (is_smime)
4214  {
4215  /* L10N: S/MIME options (opportunistic encryption is off) */
4216  prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
4217  /* L10N: S/MIME options (opportunistic encryption is off) */
4218  letters = _("esabpco");
4219  choices = "esabpcO";
4220  }
4221  else
4222  {
4223  /* L10N: PGP options (opportunistic encryption is off) */
4224  prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
4225  /* L10N: PGP options (opportunistic encryption is off) */
4226  letters = _("esabmco");
4227  choices = "esabmcO";
4228  }
4229  }
4230  /* Opportunistic encryption is unset */
4231  else
4232  {
4233  if (is_smime)
4234  {
4235  /* L10N: S/MIME options */
4236  prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
4237  /* L10N: S/MIME options */
4238  letters = _("esabpc");
4239  choices = "esabpc";
4240  }
4241  else
4242  {
4243  /* L10N: PGP options */
4244  prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
4245  /* L10N: PGP options */
4246  letters = _("esabmc");
4247  choices = "esabmc";
4248  }
4249  }
4250 
4251  choice = mutt_multi_choice(prompt, letters);
4252  if (choice > 0)
4253  {
4254  switch (choices[choice - 1])
4255  {
4256  case 'a': /* sign (a)s */
4257  p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
4258  is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
4259  if (p)
4260  {
4261  char input_signas[128];
4262  snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
4263 
4264  if (is_smime)
4265  cs_subset_str_string_set(NeoMutt->sub, "smime_default_key", input_signas, NULL);
4266  else
4267  cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
4268 
4269  crypt_key_free(&p);
4270 
4271  e->security |= SEC_SIGN;
4272  }
4273  break;
4274 
4275  case 'b': /* (b)oth */
4276  e->security |= (SEC_ENCRYPT | SEC_SIGN);
4277  break;
4278 
4279  case 'C':
4280  e->security &= ~SEC_SIGN;
4281  break;
4282 
4283  case 'c': /* (c)lear */
4284  e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
4285  break;
4286 
4287  case 'e': /* (e)ncrypt */
4288  e->security |= SEC_ENCRYPT;
4289  e->security &= ~SEC_SIGN;
4290  break;
4291 
4292  case 'm': /* (p)gp or s/(m)ime */
4293  case 'p':
4294  is_smime = !is_smime;
4295  if (is_smime)
4296  {
4297  e->security &= ~APPLICATION_PGP;
4299  }
4300  else
4301  {
4302  e->security &= ~APPLICATION_SMIME;
4303  e->security |= APPLICATION_PGP;
4304  }
4306  break;
4307 
4308  case 'O': /* oppenc mode on */
4309  e->security |= SEC_OPPENCRYPT;
4311  break;
4312 
4313  case 'o': /* oppenc mode off */
4314  e->security &= ~SEC_OPPENCRYPT;
4315  break;
4316 
4317  case 'S': /* (s)ign in oppenc mode */
4318  e->security |= SEC_SIGN;
4319  break;
4320 
4321  case 's': /* (s)ign */
4322  e->security &= ~SEC_ENCRYPT;
4323  e->security |= SEC_SIGN;
4324  break;
4325  }
4326  }
4327 
4328  return e->security;
4329 }
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1025
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:54
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
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
+ 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 4352 of file crypt_gpgme.c.

4353 {
4354  struct Address *sender = NULL;
4355  bool rc = true;
4356 
4357  if (!TAILQ_EMPTY(&e->env->from))
4358  {
4360  sender = TAILQ_FIRST(&e->env->from);
4361  }
4362  else if (!TAILQ_EMPTY(&e->env->sender))
4363  {
4365  sender = TAILQ_FIRST(&e->env->sender);
4366  }
4367 
4368  if (sender)
4369  {
4370  if (signature_key)
4371  {
4372  gpgme_key_t key = signature_key;
4373  gpgme_user_id_t uid = NULL;
4374  int sender_length = strlen(sender->mailbox);
4375  for (uid = key->uids; uid && rc; uid = uid->next)
4376  {
4377  int uid_length = strlen(uid->email);
4378  if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4379  (uid_length == (sender_length + 2)))
4380  {
4381  const char *at_sign = strchr(uid->email + 1, '@');
4382  if (at_sign)
4383  {
4384  /* Assume address is 'mailbox@domainname'.
4385  * The mailbox part is case-sensitive,
4386  * the domainname is not. (RFC2821) */
4387  const char *tmp_email = uid->email + 1;
4388  const char *tmp_sender = sender->mailbox;
4389  /* length of mailbox part including '@' */
4390  int mailbox_length = at_sign - tmp_email + 1;
4391  int domainname_length = sender_length - mailbox_length;
4392  int mailbox_match, domainname_match;
4393 
4394  mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4395  tmp_email += mailbox_length;
4396  tmp_sender += mailbox_length;
4397  domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4398  if (mailbox_match && domainname_match)
4399  rc = false;
4400  }
4401  else
4402  {
4403  if (mutt_strn_equal(uid->email + 1, sender->mailbox, sender_length))
4404  rc = false;
4405  }
4406  }
4407  }
4408  }
4409  else
4410  mutt_any_key_to_continue(_("Failed to verify sender"));
4411  }
4412  else
4413  mutt_any_key_to_continue(_("Failed to figure out sender"));
4414 
4415  if (signature_key)
4416  {
4417  gpgme_key_unref(signature_key);
4418  signature_key = NULL;
4419  }
4420 
4421  return rc;
4422 }
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:297
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:498
int mutt_istrn_cmp(const char *a, const char *b, size_t num)
Compare two strings ignoring case (to a maximum), safely.
Definition: string.c:487
#define TAILQ_EMPTY(head)
Definition: queue.h:721
struct Envelope * env
Envelope information.
Definition: email.h:66
struct AddressList sender
Email's sender.
Definition: envelope.h:63
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
+ 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 4446 of file crypt_gpgme.c.

4447 {
4448  return GPGME_VERSION;
4449 }
+ Here is the caller graph for this function:

Variable Documentation

◆ id_defaults

struct CryptCache* id_defaults = NULL
static

Definition at line 102 of file crypt_gpgme.c.

◆ signature_key

gpgme_key_t signature_key = NULL
static

Definition at line 103 of file crypt_gpgme.c.

◆ current_sender

char* current_sender = NULL
static

Definition at line 104 of file crypt_gpgme.c.