NeoMutt  2022-04-29-249-gaae397
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 "enter/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 create_recipient_string (const char *keylist, struct Buffer *recpstring, int use_smime)
 Create a string of recipients. 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 77 of file crypt_gpgme.c.

◆ CRYPT_KV_ADDR

#define CRYPT_KV_ADDR   (1 << 1)

Definition at line 78 of file crypt_gpgme.c.

◆ CRYPT_KV_STRING

#define CRYPT_KV_STRING   (1 << 2)

Definition at line 79 of file crypt_gpgme.c.

◆ CRYPT_KV_STRONGID

#define CRYPT_KV_STRONGID   (1 << 3)

Definition at line 80 of file crypt_gpgme.c.

◆ CRYPT_KV_MATCH

#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)

Definition at line 81 of file crypt_gpgme.c.

◆ PKA_NOTATION_NAME

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

Definition at line 98 of file crypt_gpgme.c.

◆ _LINE_COMPARE

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

Definition at line 100 of file crypt_gpgme.c.

◆ MESSAGE

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

Definition at line 101 of file crypt_gpgme.c.

◆ SIGNED_MESSAGE

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

Definition at line 102 of file crypt_gpgme.c.

◆ PUBLIC_KEY_BLOCK

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

Definition at line 103 of file crypt_gpgme.c.

◆ BEGIN_PGP_SIGNATURE

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

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

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

122{
123 const char *s = gpgme_get_ctx_flag(ctx, "redraw");
124 if (!s /* flag not known */ || *s /* flag true */)
125 {
127 }
128}
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:162
+ 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 138 of file crypt_gpgme.c.

139{
140 const char *s = "????????";
141
142 if (k->kobj && k->kobj->subkeys)
143 {
144 s = k->kobj->subkeys->keyid;
145 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
146 if ((!c_pgp_long_ids) && (strlen(s) == 16))
147 {
148 /* Return only the short keyID. */
149 s += 8;
150 }
151 }
152
153 return s;
154}
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 163 of file crypt_gpgme.c.

164{
165 const char *s = "????????????????";
166
167 if (k->kobj && k->kobj->subkeys)
168 {
169 s = k->kobj->subkeys->keyid;
170 }
171
172 return s;
173}
+ 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 180 of file crypt_gpgme.c.

181{
182 const char *s = "????????";
183
184 if (k->kobj && k->kobj->subkeys)
185 {
186 s = k->kobj->subkeys->keyid;
187 if (strlen(s) == 16)
188 s += 8;
189 }
190
191 return s;
192}
+ 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 199 of file crypt_gpgme.c.

200{
201 const char *s = "";
202
203 if (k->kobj && k->kobj->subkeys)
204 s = k->kobj->subkeys->fpr;
205
206 return s;
207}
+ 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 214 of file crypt_gpgme.c.

215{
216 const char *s = "????????????????";
217
218 if (k->kobj && k->kobj->subkeys)
219 {
220 if (k->kobj->subkeys->fpr)
221 s = k->kobj->subkeys->fpr;
222 else
223 s = k->kobj->subkeys->keyid;
224 }
225
226 return s;
227}
+ 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 234 of file crypt_gpgme.c.

235{
236 struct CryptKeyInfo *k = NULL;
237
238 k = mutt_mem_calloc(1, sizeof(*k));
239 k->kobj = key->kobj;
240 gpgme_key_ref(key->kobj);
241 k->idx = key->idx;
242 k->uid = key->uid;
243 k->flags = key->flags;
244 k->validity = key->validity;
245
246 return k;
247}
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 253 of file crypt_gpgme.c.

254{
255 if (!keylist)
256 return;
257
258 struct CryptKeyInfo *k = NULL;
259
260 while (*keylist)
261 {
262 k = *keylist;
263 *keylist = (*keylist)->next;
264
265 gpgme_key_unref(k->kobj);
266 FREE(&k);
267 }
268}
#define FREE(x)
Definition: memory.h:43
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 275 of file crypt_gpgme.c.

276{
277 if (!key)
278 return false;
279
280 bool is_strong = false;
281
282 if ((key->flags & KEYFLAG_ISX509))
283 return true;
284
285 switch (key->validity)
286 {
287 case GPGME_VALIDITY_MARGINAL:
288 case GPGME_VALIDITY_NEVER:
289 case GPGME_VALIDITY_UNDEFINED:
290 case GPGME_VALIDITY_UNKNOWN:
291 is_strong = false;
292 break;
293
294 case GPGME_VALIDITY_FULL:
295 case GPGME_VALIDITY_ULTIMATE:
296 is_strong = true;
297 break;
298 }
299
300 return is_strong;
301}
#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 310 of file crypt_gpgme.c.

311{
312 if (!key)
313 return 0;
314
315 return !(key->flags & KEYFLAG_CANTUSE);
316}
#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 328 of file crypt_gpgme.c.

330{
331 int rc = 0;
332
333 if (crypt_id_is_valid(key))
334 rc |= CRYPT_KV_VALID;
335
336 if (crypt_id_is_strong(key))
337 rc |= CRYPT_KV_STRONGID;
338
339 if (addr && u_addr)
340 {
341 if (addr->mailbox && u_addr->mailbox &&
342 mutt_istr_equal(addr->mailbox, u_addr->mailbox))
343 {
344 rc |= CRYPT_KV_ADDR;
345 }
346
347 if (addr->personal && u_addr->personal &&
348 mutt_istr_equal(addr->personal, u_addr->personal))
349 {
350 rc |= CRYPT_KV_STRING;
351 }
352 }
353
354 return rc;
355}
#define CRYPT_KV_STRING
Definition: crypt_gpgme.c:79
int crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
Definition: crypt_gpgme.c:310
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
Definition: crypt_gpgme.c:275
#define CRYPT_KV_VALID
Definition: crypt_gpgme.c:77
#define CRYPT_KV_STRONGID
Definition: crypt_gpgme.c:80
#define CRYPT_KV_ADDR
Definition: crypt_gpgme.c:78
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
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 362 of file crypt_gpgme.c.

363{
364 gpgme_ctx_t ctx = NULL;
365
366 gpgme_error_t err = gpgme_new(&ctx);
367
368#ifdef USE_AUTOCRYPT
369 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
370 if (!err && OptAutocryptGpgme)
371 err = gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_OpenPGP, NULL, c_autocrypt_dir);
372#endif
373
374 if (err != 0)
375 {
376 mutt_error(_("error creating GPGME context: %s"), gpgme_strerror(err));
377 mutt_exit(1);
378 }
379
380 if (for_smime)
381 {
382 err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
383 if (err != 0)
384 {
385 mutt_error(_("error enabling CMS protocol: %s"), gpgme_strerror(err));
386 mutt_exit(1);
387 }
388 }
389
390 return ctx;
391}
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
#define mutt_error(...)
Definition: logging.h:87
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 401 of file crypt_gpgme.c.

402{
403 gpgme_data_t data = NULL;
404
405 gpgme_error_t err = gpgme_data_new(&data);
406 if (err != 0)
407 {
408 mutt_error(_("error creating GPGME data object: %s"), gpgme_strerror(err));
409 mutt_exit(1);
410 }
411 return data;
412}
+ 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 420 of file crypt_gpgme.c.

421{
422 int err = 0;
423 gpgme_data_t data = NULL;
424
425 struct Buffer *tempfile = mutt_buffer_pool_get();
426 mutt_buffer_mktemp(tempfile);
427 FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
428 if (!fp_tmp)
429 {
431 goto cleanup;
432 }
433
435 fputc('\n', fp_tmp);
436 mutt_write_mime_body(a, fp_tmp, NeoMutt->sub);
437
438 if (convert)
439 {
440 int c, hadcr = 0;
441 unsigned char buf[1];
442
444 rewind(fp_tmp);
445 while ((c = fgetc(fp_tmp)) != EOF)
446 {
447 if (c == '\r')
448 hadcr = 1;
449 else
450 {
451 if ((c == '\n') && !hadcr)
452 {
453 buf[0] = '\r';
454 gpgme_data_write(data, buf, 1);
455 }
456
457 hadcr = 0;
458 }
459 /* FIXME: This is quite suboptimal */
460 buf[0] = c;
461 gpgme_data_write(data, buf, 1);
462 }
463 mutt_file_fclose(&fp_tmp);
464 gpgme_data_seek(data, 0, SEEK_SET);
465 }
466 else
467 {
468 mutt_file_fclose(&fp_tmp);
469 err = gpgme_data_new_from_file(&data, mutt_buffer_string(tempfile), 1);
470 if (err != 0)
471 {
472 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
473 gpgme_data_release(data);
474 data = NULL;
475 /* fall through to unlink the tempfile */
476 }
477 }
478 unlink(mutt_buffer_string(tempfile));
479
480cleanup:
481 mutt_buffer_pool_release(&tempfile);
482 return data;
483}
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:401
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#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 492 of file crypt_gpgme.c.

493{
494 gpgme_data_t data = NULL;
495
496 int err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length);
497 if (err != 0)
498 {
499 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
500 return NULL;
501 }
502
503 return data;
504}
+ 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 513 of file crypt_gpgme.c.

514{
515 char buf[4096] = { 0 };
516 ssize_t nread;
517
518 int err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno(errno) : 0);
519 if (err != 0)
520 {
521 mutt_error(_("error rewinding data object: %s"), gpgme_strerror(err));
522 return -1;
523 }
524
525 while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
526 {
527 /* fixme: we are not really converting CRLF to LF but just
528 * skipping CR. Doing it correctly needs a more complex logic */
529 for (char *p = buf; nread; p++, nread--)
530 {
531 if (*p != '\r')
532 putc(*p, fp);
533 }
534
535 if (ferror(fp))
536 {
537 mutt_perror(_("[tempfile]"));
538 return -1;
539 }
540 }
541 if (nread == -1)
542 {
543 mutt_error(_("error reading data object: %s"), strerror(errno));
544 return -1;
545 }
546 return 0;
547}
+ 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 560 of file crypt_gpgme.c.

561{
562 ssize_t nread = 0;
563 char *rv = NULL;
564 struct Buffer *tempf = mutt_buffer_pool_get();
565
566 mutt_buffer_mktemp(tempf);
567
568 FILE *fp = mutt_file_fopen(mutt_buffer_string(tempf), "w+");
569 if (!fp)
570 {
571 mutt_perror(_("Can't create temporary file"));
572 goto cleanup;
573 }
574
575 int err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno(errno) : 0);
576 if (err == 0)
577 {
578 char buf[4096] = { 0 };
579
580 while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
581 {
582 if (fwrite(buf, nread, 1, fp) != 1)
583 {
585 mutt_file_fclose(&fp);
586 unlink(mutt_buffer_string(tempf));
587 goto cleanup;
588 }
589 }
590 }
591 if (fp_ret)
592 rewind(fp);
593 else
594 mutt_file_fclose(&fp);
595 if (nread == -1)
596 {
597 mutt_error(_("error reading data object: %s"), gpgme_strerror(err));
598 unlink(mutt_buffer_string(tempf));
599 mutt_file_fclose(&fp);
600 goto cleanup;
601 }
602 if (fp_ret)
603 *fp_ret = fp;
604 rv = mutt_buffer_strdup(tempf);
605
606cleanup:
608 return rv;
609}
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:447
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ create_recipient_string()

static void create_recipient_string ( const char *  keylist,
struct Buffer recpstring,
int  use_smime 
)
static

Create a string of recipients.

Parameters
keylistKeys, space-separated
recpstringBuffer to store the recipients
use_smimeUse SMIME

Definition at line 617 of file crypt_gpgme.c.

618{
619 unsigned int n = 0;
620
621 const char *s = keylist;
622 do
623 {
624 while (*s == ' ')
625 s++;
626 if (*s != '\0')
627 {
628 if (n == 0)
629 {
630 if (!use_smime)
631 mutt_buffer_addstr(recpstring, "--\n");
632 }
633 else
634 mutt_buffer_addch(recpstring, '\n');
635 n++;
636
637 while ((*s != '\0') && (*s != ' '))
638 mutt_buffer_addch(recpstring, *s++);
639 }
640 } while (*s != '\0');
641}
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
+ 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 651 of file crypt_gpgme.c.

652{
653 gpgme_error_t err;
654 gpgme_key_t key = NULL, key2 = NULL;
655 gpgme_ctx_t listctx = create_gpgme_context(for_smime);
656 err = gpgme_op_keylist_start(listctx, address, 1);
657 if (err == 0)
658 err = gpgme_op_keylist_next(listctx, &key);
659 if (err)
660 {
661 gpgme_release(listctx);
662 mutt_error(_("secret key '%s' not found: %s"), address, gpgme_strerror(err));
663 return false;
664 }
665
666 char *fpr = "fpr1";
667 if (key->subkeys)
668 fpr = key->subkeys->fpr ? key->subkeys->fpr : key->subkeys->keyid;
669 while (gpgme_op_keylist_next(listctx, &key2) == 0)
670 {
671 char *fpr2 = "fpr2";
672 if (key2->subkeys)
673 fpr2 = key2->subkeys->fpr ? key2->subkeys->fpr : key2->subkeys->keyid;
674 if (!mutt_str_equal(fpr, fpr2))
675 {
676 gpgme_key_unref(key);
677 gpgme_key_unref(key2);
678 gpgme_release(listctx);
679 mutt_error(_("ambiguous specification of secret key '%s'"), address);
680 return false;
681 }
682 else
683 {
684 gpgme_key_unref(key2);
685 }
686 }
687 gpgme_op_keylist_end(listctx);
688 gpgme_release(listctx);
689
690 gpgme_signers_clear(ctx);
691 err = gpgme_signers_add(ctx, key);
692 gpgme_key_unref(key);
693 if (err)
694 {
695 mutt_error(_("error setting secret key '%s': %s"), address, gpgme_strerror(err));
696 return false;
697 }
698 return true;
699}
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:362
+ 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 709 of file crypt_gpgme.c.

710{
711 const char *signid = NULL;
712
713 const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
714 const char *const c_pgp_sign_as = cs_subset_string(NeoMutt->sub, "pgp_sign_as");
715 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
716 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
717 if (for_smime)
718 signid = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
719#ifdef USE_AUTOCRYPT
720 else if (OptAutocryptGpgme)
721 signid = AutocryptSignAs;
722#endif
723 else
724 signid = c_pgp_sign_as ? c_pgp_sign_as : c_pgp_default_key;
725
726 /* Try getting the signing key from config entries */
727 if (signid && set_signer_from_address(ctx, signid, for_smime))
728 {
729 return 0;
730 }
731
732 /* Try getting the signing key from the From line */
733 if (al)
734 {
735 struct Address *a;
736 TAILQ_FOREACH(a, al, entries)
737 {
738 if (a->mailbox && set_signer_from_address(ctx, a->mailbox, for_smime))
739 {
740 return 0;
741 }
742 }
743 }
744
745 return (!signid && !al) ? 0 : -1;
746}
char * AutocryptSignAs
Autocrypt Key id to sign as.
Definition: config.c:35
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
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:651
#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 753 of file crypt_gpgme.c.

754{
755 gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME, current_sender, 0);
756 if (err)
757 {
758 mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
759 }
760
761 return err;
762}
static char * current_sender
Definition: crypt_gpgme.c:96
+ 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 773 of file crypt_gpgme.c.

775{
776 gpgme_error_t err;
777 gpgme_ctx_t ctx = NULL;
778 gpgme_data_t ciphertext = NULL;
779 char *outfile = NULL;
780
781 struct Buffer *recpstring = mutt_buffer_pool_get();
782 create_recipient_string(keylist, recpstring, use_smime);
783 if (mutt_buffer_is_empty(recpstring))
784 {
785 mutt_buffer_pool_release(&recpstring);
786 return NULL;
787 }
788
789 ctx = create_gpgme_context(use_smime);
790 if (!use_smime)
791 gpgme_set_armor(ctx, 1);
792
793 ciphertext = create_gpgme_data();
794
795 if (combined_signed)
796 {
797 if (set_signer(ctx, from, use_smime))
798 goto cleanup;
799
800 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
801 if (c_crypt_use_pka)
802 {
803 err = set_pka_sig_notation(ctx);
804 if (err != 0)
805 goto cleanup;
806 }
807
808 err = gpgme_op_encrypt_sign_ext(ctx, NULL, mutt_buffer_string(recpstring),
809 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
810 }
811 else
812 {
813 err = gpgme_op_encrypt_ext(ctx, NULL, mutt_buffer_string(recpstring),
814 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
815 }
816
817 redraw_if_needed(ctx);
818 if (err != 0)
819 {
820 mutt_error(_("error encrypting data: %s"), gpgme_strerror(err));
821 goto cleanup;
822 }
823
824 outfile = data_object_to_tempfile(ciphertext, NULL);
825
826cleanup:
827 mutt_buffer_pool_release(&recpstring);
828 gpgme_release(ctx);
829 gpgme_data_release(ciphertext);
830 return outfile;
831}
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
Set the signature notation.
Definition: crypt_gpgme.c:753
static void create_recipient_string(const char *keylist, struct Buffer *recpstring, int use_smime)
Create a string of recipients.
Definition: crypt_gpgme.c:617
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:709
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:560
static void redraw_if_needed(gpgme_ctx_t ctx)
Accommodate for a redraw if needed.
Definition: crypt_gpgme.c:121
+ 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 845 of file crypt_gpgme.c.

846{
847 gpgme_sign_result_t result = NULL;
848 const char *algorithm_name = NULL;
849
850 if (buflen < 5)
851 return -1;
852
853 *buf = '\0';
854 result = gpgme_op_sign_result(ctx);
855 if (result && result->signatures)
856 {
857 algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
858 if (algorithm_name)
859 {
860 if (use_smime)
861 {
862 /* convert GPGME raw hash name to RFC2633 format */
863 snprintf(buf, buflen, "%s", algorithm_name);
864 mutt_str_lower(buf);
865 }
866 else
867 {
868 /* convert GPGME raw hash name to RFC3156 format */
869 snprintf(buf, buflen, "pgp-%s", algorithm_name);
870 mutt_str_lower(buf + 4);
871 }
872 }
873 }
874
875 return (buf[0] != '\0') ? 0 : -1;
876}
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 883 of file crypt_gpgme.c.

884{
885 char p[256] = { 0 };
886 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
887 state_puts(s, p);
888}
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:692
#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 898 of file crypt_gpgme.c.

899{
900 struct Body *t = NULL;
901 char *sigfile = NULL;
902 int err = 0;
903 char buf[100] = { 0 };
904 gpgme_ctx_t ctx = NULL;
905 gpgme_data_t message = NULL, signature = NULL;
906 gpgme_sign_result_t sigres = NULL;
907
908 crypt_convert_to_7bit(a); /* Signed data _must_ be in 7-bit format. */
909
910 message = body_to_data_object(a, true);
911 if (!message)
912 return NULL;
913 signature = create_gpgme_data();
914
915 ctx = create_gpgme_context(use_smime);
916 if (!use_smime)
917 gpgme_set_armor(ctx, 1);
918
919 if (set_signer(ctx, from, use_smime))
920 {
921 gpgme_data_release(signature);
922 gpgme_data_release(message);
923 gpgme_release(ctx);
924 return NULL;
925 }
926
927 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
928 if (c_crypt_use_pka)
929 {
930 err = set_pka_sig_notation(ctx);
931 if (err != 0)
932 {
933 gpgme_data_release(signature);
934 gpgme_data_release(message);
935 gpgme_release(ctx);
936 return NULL;
937 }
938 }
939
940 err = gpgme_op_sign(ctx, message, signature, GPGME_SIG_MODE_DETACH);
941 redraw_if_needed(ctx);
942 gpgme_data_release(message);
943 if (err != 0)
944 {
945 gpgme_data_release(signature);
946 gpgme_release(ctx);
947 mutt_error(_("error signing data: %s"), gpgme_strerror(err));
948 return NULL;
949 }
950 /* Check for zero signatures generated. This can occur when $pgp_sign_as is
951 * unset and there is no default key specified in ~/.gnupg/gpg.conf */
952 sigres = gpgme_op_sign_result(ctx);
953 if (!sigres->signatures)
954 {
955 gpgme_data_release(signature);
956 gpgme_release(ctx);
957 mutt_error(_("$pgp_sign_as unset and no default key specified in ~/.gnupg/gpg.conf"));
958 return NULL;
959 }
960
961 sigfile = data_object_to_tempfile(signature, NULL);
962 gpgme_data_release(signature);
963 if (!sigfile)
964 {
965 gpgme_release(ctx);
966 return NULL;
967 }
968
969 t = mutt_body_new();
970 t->type = TYPE_MULTIPART;
971 t->subtype = mutt_str_dup("signed");
972 t->encoding = ENC_7BIT;
973 t->use_disp = false;
975
977 mutt_param_set(&t->parameter, "protocol",
978 use_smime ? "application/pkcs7-signature" : "application/pgp-signature");
979 /* Get the micalg from GPGME. Old gpgme versions don't support this
980 * for S/MIME so we assume sha-1 in this case. */
981 if (get_micalg(ctx, use_smime, buf, sizeof(buf)) == 0)
982 mutt_param_set(&t->parameter, "micalg", buf);
983 else if (use_smime)
984 mutt_param_set(&t->parameter, "micalg", "sha1");
985 gpgme_release(ctx);
986
987 t->parts = a;
988 a = t;
989
990 t->parts->next = mutt_body_new();
991 t = t->parts->next;
993 if (use_smime)
994 {
995 t->subtype = mutt_str_dup("pkcs7-signature");
996 mutt_param_set(&t->parameter, "name", "smime.p7s");
997 t->encoding = ENC_BASE64;
998 t->use_disp = true;
1000 t->d_filename = mutt_str_dup("smime.p7s");
1001 }
1002 else
1003 {
1004 t->subtype = mutt_str_dup("pgp-signature");
1005 mutt_param_set(&t->parameter, "name", "signature.asc");
1006 t->use_disp = false;
1008 t->encoding = ENC_7BIT;
1009 }
1010 t->filename = sigfile;
1011 t->unlink = true; /* ok to remove this file after sending. */
1012
1013 return a;
1014}
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:420
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:845
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 1125 of file crypt_gpgme.c.

1127{
1128 if (!key)
1129 return 1;
1130
1131 bool severe = false;
1132
1133 if ((sum & GPGME_SIGSUM_KEY_REVOKED))
1134 {
1135 state_puts(s, _("Warning: One of the keys has been revoked\n"));
1136 severe = true;
1137 }
1138
1139 if ((sum & GPGME_SIGSUM_KEY_EXPIRED))
1140 {
1141 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
1142 if (at)
1143 {
1144 state_puts(s, _("Warning: The key used to create the signature expired at: "));
1145 print_time(at, s);
1146 state_puts(s, "\n");
1147 }
1148 else
1149 {
1150 state_puts(s, _("Warning: At least one certification key has expired\n"));
1151 }
1152 }
1153
1154 if ((sum & GPGME_SIGSUM_SIG_EXPIRED))
1155 {
1156 gpgme_signature_t sig2 = NULL;
1157 unsigned int i;
1158
1159 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1160
1161 for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1162 ; // do nothing
1163
1164 state_puts(s, _("Warning: The signature expired at: "));
1165 print_time(sig2 ? sig2->exp_timestamp : 0, s);
1166 state_puts(s, "\n");
1167 }
1168
1169 if ((sum & GPGME_SIGSUM_KEY_MISSING))
1170 {
1171 state_puts(s, _("Can't verify due to a missing key or certificate\n"));
1172 }
1173
1174 if ((sum & GPGME_SIGSUM_CRL_MISSING))
1175 {
1176 state_puts(s, _("The CRL is not available\n"));
1177 severe = true;
1178 }
1179
1180 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD))
1181 {
1182 state_puts(s, _("Available CRL is too old\n"));
1183 severe = true;
1184 }
1185
1186 if ((sum & GPGME_SIGSUM_BAD_POLICY))
1187 state_puts(s, _("A policy requirement was not met\n"));
1188
1189 if ((sum & GPGME_SIGSUM_SYS_ERROR))
1190 {
1191 const char *t0 = NULL, *t1 = NULL;
1192 gpgme_verify_result_t result = NULL;
1193 gpgme_signature_t sig2 = NULL;
1194 unsigned int i;
1195
1196 state_puts(s, _("A system error occurred"));
1197
1198 /* Try to figure out some more detailed system error information. */
1199 result = gpgme_op_verify_result(ctx);
1200 for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1201 ; // do nothing
1202
1203 if (sig2)
1204 {
1205 t0 = "";
1206 t1 = sig2->wrong_key_usage ? "Wrong_Key_Usage" : "";
1207 }
1208
1209 if (t0 || t1)
1210 {
1211 state_puts(s, ": ");
1212 if (t0)
1213 state_puts(s, t0);
1214 if (t1 && !(t0 && (strcmp(t0, t1) == 0)))
1215 {
1216 if (t0)
1217 state_puts(s, ",");
1218 state_puts(s, t1);
1219 }
1220 }
1221 state_puts(s, "\n");
1222 }
1223
1224 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
1225 if (c_crypt_use_pka)
1226 {
1227 if ((sig->pka_trust == 1) && sig->pka_address)
1228 {
1229 state_puts(s, _("WARNING: PKA entry does not match signer's address: "));
1230 state_puts(s, sig->pka_address);
1231 state_puts(s, "\n");
1232 }
1233 else if ((sig->pka_trust == 2) && sig->pka_address)
1234 {
1235 state_puts(s, _("PKA verified signer's address is: "));
1236 state_puts(s, sig->pka_address);
1237 state_puts(s, "\n");
1238 }
1239 }
1240
1241 return severe;
1242}
static void print_time(time_t t, struct State *s)
Print the date/time according to the locale.
Definition: crypt_gpgme.c:883
+ 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 1249 of file crypt_gpgme.c.

1250{
1251 if (!key)
1252 return;
1253
1254 const char *prefix = _("Fingerprint: ");
1255
1256 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1257 if (!s)
1258 return;
1259 bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1260
1261 char *buf = mutt_mem_malloc(strlen(prefix) + strlen(s) * 4 + 2);
1262 strcpy(buf, prefix);
1263 char *p = buf + strlen(buf);
1264 if (is_pgp && (strlen(s) == 40))
1265 { /* PGP v4 style formatted. */
1266 for (int i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
1267 {
1268 *p++ = s[0];
1269 *p++ = s[1];
1270 *p++ = s[2];
1271 *p++ = s[3];
1272 *p++ = ' ';
1273 if (i == 4)
1274 *p++ = ' ';
1275 }
1276 }
1277 else
1278 {
1279 for (int i = 0; *s && s[1] && s[2]; s += 2, i++)
1280 {
1281 *p++ = s[0];
1282 *p++ = s[1];
1283 *p++ = is_pgp ? ' ' : ':';
1284 if (is_pgp && (i == 7))
1285 *p++ = ' ';
1286 }
1287 }
1288
1289 /* just in case print remaining odd digits */
1290 for (; *s; s++)
1291 *p++ = *s;
1292 *p++ = '\n';
1293 *p = '\0';
1294 state_puts(state, buf);
1295 FREE(&buf);
1296}
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 1304 of file crypt_gpgme.c.

1305{
1306 gpgme_signature_t sig = NULL;
1307 const char *txt = NULL;
1308
1309 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1310 if (result)
1311 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--)
1312 ; // do nothing
1313
1314 switch (sig ? sig->validity : 0)
1315 {
1316 case GPGME_VALIDITY_UNKNOWN:
1317 txt = _("WARNING: We have NO indication whether the key belongs to the person named as shown above\n");
1318 break;
1319 case GPGME_VALIDITY_UNDEFINED:
1320 break;
1321 case GPGME_VALIDITY_NEVER:
1322 txt = _("WARNING: The key does NOT BELONG to the person named as shown above\n");
1323 break;
1324 case GPGME_VALIDITY_MARGINAL:
1325 txt = _("WARNING: It is NOT certain that the key belongs to the person named as shown above\n");
1326 break;
1327 case GPGME_VALIDITY_FULL:
1328 case GPGME_VALIDITY_ULTIMATE:
1329 txt = NULL;
1330 break;
1331 }
1332 if (txt)
1333 state_puts(s, txt);
1334}
+ 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 1343 of file crypt_gpgme.c.

1345{
1346 int msgwid;
1347
1348 state_puts(s, msg);
1349 state_puts(s, " ");
1350 /* key is NULL when not present in the user's keyring */
1351 if (key)
1352 {
1353 bool aka = false;
1354 for (gpgme_user_id_t uids = key->uids; uids; uids = uids->next)
1355 {
1356 if (uids->revoked)
1357 continue;
1358 if (aka)
1359 {
1360 msgwid = mutt_strwidth(msg) - mutt_strwidth(_("aka: ")) + 1;
1361 if (msgwid < 0)
1362 msgwid = 0;
1363 for (int i = 0; i < msgwid; i++)
1364 state_puts(s, " ");
1365 state_puts(s, _("aka: "));
1366 }
1367 state_puts(s, uids->uid);
1368 state_puts(s, "\n");
1369
1370 aka = true;
1371 }
1372 }
1373 else
1374 {
1375 if (sig->fpr)
1376 {
1377 state_puts(s, _("KeyID "));
1378 state_puts(s, sig->fpr);
1379 }
1380 else
1381 {
1382 /* L10N: You will see this message in place of "KeyID "
1383 if the S/MIME key has no ID. This is quite an error. */
1384 state_puts(s, _("no signature fingerprint available"));
1385 }
1386 state_puts(s, "\n");
1387 }
1388
1389 /* timestamp is 0 when verification failed.
1390 * "Jan 1 1970" is not the created date. */
1391 if (sig->timestamp)
1392 {
1393 msgwid = mutt_strwidth(msg) - mutt_strwidth(_("created: ")) + 1;
1394 if (msgwid < 0)
1395 msgwid = 0;
1396 for (int i = 0; i < msgwid; i++)
1397 state_puts(s, " ");
1398 state_puts(s, _("created: "));
1399 print_time(sig->timestamp, s);
1400 state_puts(s, "\n");
1401 }
1402}
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:907
+ 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 1416 of file crypt_gpgme.c.

1417{
1418 const char *fpr = NULL;
1419 gpgme_key_t key = NULL;
1420 bool anybad = false, anywarn = false;
1421 gpgme_signature_t sig = NULL;
1422 gpgme_error_t err = GPG_ERR_NO_ERROR;
1423
1424 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1425 if (result)
1426 {
1427 /* FIXME: this code should use a static variable and remember
1428 * the current position in the list of signatures, IMHO.
1429 * -moritz. */
1430 int i;
1431 for (i = 0, sig = result->signatures; sig && (i < idx); i++, sig = sig->next)
1432 ; // do nothing
1433
1434 if (!sig)
1435 return -1; /* Signature not found. */
1436
1437 if (signature_key)
1438 {
1439 gpgme_key_unref(signature_key);
1440 signature_key = NULL;
1441 }
1442
1443 fpr = sig->fpr;
1444 const unsigned int sum = sig->summary;
1445
1446 if (gpg_err_code(sig->status) != GPG_ERR_NO_ERROR)
1447 anybad = true;
1448
1449 if (gpg_err_code(sig->status) != GPG_ERR_NO_PUBKEY)
1450 {
1451 err = gpgme_get_key(ctx, fpr, &key, 0); /* secret key? */
1452 if (err == 0)
1453 {
1454 if (!signature_key)
1455 signature_key = key;
1456 }
1457 else
1458 {
1459 key = NULL; /* Old GPGME versions did not set KEY to NULL on
1460 error. Do it here to avoid a double free. */
1461 }
1462 }
1463 else
1464 {
1465 /* pubkey not present */
1466 }
1467
1468 if (!s || !s->fp_out || !(s->flags & MUTT_DISPLAY))
1469 ; /* No state information so no way to print anything. */
1470 else if (err != 0)
1471 {
1472 char buf[1024] = { 0 };
1473 snprintf(buf, sizeof(buf), _("Error getting key information for KeyID %s: %s\n"),
1474 fpr, gpgme_strerror(err));
1475 state_puts(s, buf);
1476 anybad = true;
1477 }
1478 else if ((sum & GPGME_SIGSUM_GREEN))
1479 {
1480 print_smime_keyinfo(_("Good signature from:"), sig, key, s);
1481 if (show_sig_summary(sum, ctx, key, idx, s, sig))
1482 anywarn = true;
1483 show_one_sig_validity(ctx, idx, s);
1484 }
1485 else if ((sum & GPGME_SIGSUM_RED))
1486 {
1487 print_smime_keyinfo(_("*BAD* signature from:"), sig, key, s);
1488 show_sig_summary(sum, ctx, key, idx, s, sig);
1489 }
1490 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP))
1491 { /* We can't decide (yellow) but this is a PGP key with a good
1492 signature, so we display what a PGP user expects: The name,
1493 fingerprint and the key validity (which is neither fully or
1494 ultimate). */
1495 print_smime_keyinfo(_("Good signature from:"), sig, key, s);
1496 show_one_sig_validity(ctx, idx, s);
1497 show_fingerprint(key, s);
1498 if (show_sig_summary(sum, ctx, key, idx, s, sig))
1499 anywarn = true;
1500 }
1501 else /* can't decide (yellow) */
1502 {
1503 print_smime_keyinfo(_("Problem signature from:"), sig, key, s);
1504 /* 0 indicates no expiration */
1505 if (sig->exp_timestamp)
1506 {
1507 /* L10N: This is trying to match the width of the
1508 "Problem signature from:" translation just above. */
1509 state_puts(s, _(" expires: "));
1510 print_time(sig->exp_timestamp, s);
1511 state_puts(s, "\n");
1512 }
1513 show_sig_summary(sum, ctx, key, idx, s, sig);
1514 anywarn = true;
1515 }
1516
1517 if (key != signature_key)
1518 gpgme_key_unref(key);
1519 }
1520
1521 return anybad ? 1 : anywarn ? 2 : 0;
1522}
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:1125
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:1343
static void show_fingerprint(gpgme_key_t key, struct State *state)
Write a key's fingerprint.
Definition: crypt_gpgme.c:1249
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:1304
static gpgme_key_t signature_key
Definition: crypt_gpgme.c:95
#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 1537 of file crypt_gpgme.c.

1538{
1539 int badsig = -1;
1540 int anywarn = 0;
1541 gpgme_ctx_t ctx = NULL;
1542 gpgme_data_t message = NULL;
1543
1544 gpgme_data_t signature = file_to_data_object(s->fp_in, sigbdy->offset, sigbdy->length);
1545 if (!signature)
1546 return -1;
1547
1548 /* We need to tell GPGME about the encoding because the backend can't
1549 * auto-detect plain base-64 encoding which is used by S/MIME. */
1550 if (is_smime)
1551 gpgme_data_set_encoding(signature, GPGME_DATA_ENCODING_BASE64);
1552
1553 int err = gpgme_data_new_from_file(&message, tempfile, 1);
1554 if (err != 0)
1555 {
1556 gpgme_data_release(signature);
1557 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
1558 return -1;
1559 }
1560 ctx = create_gpgme_context(is_smime);
1561
1562 /* Note: We don't need a current time output because GPGME avoids
1563 * such an attack by separating the meta information from the data. */
1564 state_attach_puts(s, _("[-- Begin signature information --]\n"));
1565
1566 err = gpgme_op_verify(ctx, signature, message, NULL);
1567 gpgme_data_release(message);
1568 gpgme_data_release(signature);
1569
1570 redraw_if_needed(ctx);
1571 if (err != 0)
1572 {
1573 char buf[200] = { 0 };
1574
1575 snprintf(buf, sizeof(buf) - 1, _("Error: verification failed: %s\n"),
1576 gpgme_strerror(err));
1577 state_puts(s, buf);
1578 }
1579 else
1580 { /* Verification succeeded, see what the result is. */
1581 gpgme_verify_result_t verify_result = NULL;
1582
1583 if (signature_key)
1584 {
1585 gpgme_key_unref(signature_key);
1586 signature_key = NULL;
1587 }
1588
1589 verify_result = gpgme_op_verify_result(ctx);
1590 if (verify_result && verify_result->signatures)
1591 {
1592 bool anybad = false;
1593 int res;
1594 for (int idx = 0; (res = show_one_sig_status(ctx, idx, s)) != -1; idx++)
1595 {
1596 if (res == 1)
1597 anybad = true;
1598 else if (res == 2)
1599 anywarn = 2;
1600 }
1601 if (!anybad)
1602 badsig = 0;
1603 }
1604 }
1605
1606 if (badsig == 0)
1607 {
1608 gpgme_verify_result_t result = NULL;
1609 gpgme_sig_notation_t notation = NULL;
1610 gpgme_signature_t sig = NULL;
1611
1612 result = gpgme_op_verify_result(ctx);
1613 if (result)
1614 {
1615 for (sig = result->signatures; sig; sig = sig->next)
1616 {
1617 int non_pka_notations = 0;
1618 for (notation = sig->notations; notation; notation = notation->next)
1619 if (!is_pka_notation(notation))
1620 non_pka_notations++;
1621
1622 if (non_pka_notations)
1623 {
1624 char buf[128] = { 0 };
1625 snprintf(buf, sizeof(buf),
1626 _("*** Begin Notation (signature by: %s) ***\n"), sig->fpr);
1627 state_puts(s, buf);
1628 for (notation = sig->notations; notation; notation = notation->next)
1629 {
1630 if (is_pka_notation(notation))
1631 continue;
1632
1633 if (notation->name)
1634 {
1635 state_puts(s, notation->name);
1636 state_puts(s, "=");
1637 }
1638 if (notation->value)
1639 {
1640 state_puts(s, notation->value);
1641 if (!(*notation->value && (notation->value[strlen(notation->value) - 1] == '\n')))
1642 state_puts(s, "\n");
1643 }
1644 }
1645 state_puts(s, _("*** End Notation ***\n"));
1646 }
1647 }
1648 }
1649 }
1650
1651 gpgme_release(ctx);
1652
1653 state_attach_puts(s, _("[-- End signature information --]\n\n"));
1654 mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
1655
1656 return badsig ? 1 : anywarn ? 2 : 0;
1657}
static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *s)
Show information about one signature.
Definition: crypt_gpgme.c:1416
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:492
static bool is_pka_notation(gpgme_sig_notation_t notation)
Is this the standard pka email address.
Definition: crypt_gpgme.c:112
#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 1688 of file crypt_gpgme.c.

1690{
1691 if (!a || !s || !fp_out)
1692 return NULL;
1693
1694 struct Body *tattach = NULL;
1695 int err = 0;
1696 gpgme_data_t ciphertext = NULL, plaintext = NULL;
1697 bool maybe_signed = false;
1698 bool anywarn = false;
1699 int sig_stat = 0;
1700
1701 if (r_is_signed)
1702 *r_is_signed = 0;
1703
1704 gpgme_ctx_t ctx = NULL;
1705restart:
1706 ctx = create_gpgme_context(is_smime);
1707
1708 if (a->length < 0)
1709 return NULL;
1710 /* Make a data object from the body, create context etc. */
1711 ciphertext = file_to_data_object(s->fp_in, a->offset, a->length);
1712 if (!ciphertext)
1713 goto cleanup;
1714 plaintext = create_gpgme_data();
1715
1716 /* Do the decryption or the verification in case of the S/MIME hack. */
1717 if ((!is_smime) || maybe_signed)
1718 {
1719 if (!is_smime)
1720 err = gpgme_op_decrypt_verify(ctx, ciphertext, plaintext);
1721 else if (maybe_signed)
1722 err = gpgme_op_verify(ctx, ciphertext, NULL, plaintext);
1723
1724 if (err == GPG_ERR_NO_ERROR)
1725 {
1726 /* Check whether signatures have been verified. */
1727 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
1728 if (verify_result->signatures)
1729 sig_stat = 1;
1730 }
1731 }
1732 else
1733 err = gpgme_op_decrypt(ctx, ciphertext, plaintext);
1734 gpgme_data_release(ciphertext);
1735 ciphertext = NULL;
1736 if (err != 0)
1737 {
1738#ifdef USE_AUTOCRYPT
1739 /* Abort right away and silently.
1740 * Autocrypt will retry on the normal keyring. */
1742 goto cleanup;
1743#endif
1744 if (is_smime && !maybe_signed && (gpg_err_code(err) == GPG_ERR_NO_DATA))
1745 {
1746 /* Check whether this might be a signed message despite what the mime
1747 * header told us. Retry then. gpgsm returns the error information
1748 * "unsupported Algorithm '?'" but GPGME will not store this unknown
1749 * algorithm, thus we test that it has not been set. */
1750 gpgme_decrypt_result_t result = NULL;
1751
1752 result = gpgme_op_decrypt_result(ctx);
1753 if (!result->unsupported_algorithm)
1754 {
1755 maybe_signed = true;
1756 gpgme_data_release(plaintext);
1757 plaintext = NULL;
1758 /* gpgsm ends the session after an error; restart it */
1759 gpgme_release(ctx);
1760 ctx = NULL;
1761 goto restart;
1762 }
1763 }
1764 redraw_if_needed(ctx);
1765 if ((s->flags & MUTT_DISPLAY))
1766 {
1767 char buf[200] = { 0 };
1768
1769 snprintf(buf, sizeof(buf) - 1,
1770 _("[-- Error: decryption failed: %s --]\n\n"), gpgme_strerror(err));
1771 state_attach_puts(s, buf);
1772 }
1773 goto cleanup;
1774 }
1775 redraw_if_needed(ctx);
1776
1777 /* Read the output from GPGME, and make sure to change CRLF to LF,
1778 * otherwise read_mime_header has a hard time parsing the message. */
1779 if (data_object_to_stream(plaintext, fp_out))
1780 {
1781 goto cleanup;
1782 }
1783 gpgme_data_release(plaintext);
1784 plaintext = NULL;
1785
1786 if (sig_stat)
1787 {
1788 int res, idx;
1789 int anybad = 0;
1790
1791 if (r_is_signed)
1792 *r_is_signed = -1; /* A signature exists. */
1793
1794 if ((s->flags & MUTT_DISPLAY))
1795 {
1796 state_attach_puts(s, _("[-- Begin signature information --]\n"));
1797 }
1798 for (idx = 0; (res = show_one_sig_status(ctx, idx, s)) != -1; idx++)
1799 {
1800 if (res == 1)
1801 anybad = 1;
1802 else if (res == 2)
1803 anywarn = true;
1804 }
1805 if (!anybad && idx && r_is_signed && *r_is_signed)
1806 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1807
1808 if ((s->flags & MUTT_DISPLAY))
1809 {
1810 state_attach_puts(s, _("[-- End signature information --]\n\n"));
1811 }
1812 }
1813 gpgme_release(ctx);
1814 ctx = NULL;
1815
1816 fflush(fp_out);
1817 rewind(fp_out);
1818 const long size = mutt_file_get_size_fp(fp_out);
1819 if (size == 0)
1820 {
1821 goto cleanup;
1822 }
1823 tattach = mutt_read_mime_header(fp_out, 0);
1824 if (tattach)
1825 {
1826 /* Need to set the length of this body part. */
1827 tattach->length = size - tattach->offset;
1828
1829 tattach->warnsig = anywarn;
1830
1831 /* See if we need to recurse on this MIME part. */
1832 mutt_parse_part(fp_out, tattach);
1833 }
1834
1835cleanup:
1836 gpgme_data_release(ciphertext);
1837 gpgme_data_release(plaintext);
1838 gpgme_release(ctx);
1839
1840 return tattach;
1841}
static int data_object_to_stream(gpgme_data_t data, FILE *fp)
Write a GPGME data object to a file.
Definition: crypt_gpgme.c:513
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:1736
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1317
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 2060 of file crypt_gpgme.c.

2061{
2062 gpgme_ctx_t tmpctx = NULL;
2063 gpgme_error_t err;
2064 gpgme_key_t key = NULL;
2065 gpgme_user_id_t uid = NULL;
2066 gpgme_subkey_t subkey = NULL;
2067 const char *shortid = NULL;
2068 size_t len;
2069 char date[256] = { 0 };
2070 bool more;
2071 int rc = -1;
2072 time_t tt;
2073
2074 *fp = mutt_file_mkstemp();
2075 if (!*fp)
2076 {
2077 mutt_perror(_("Can't create temporary file"));
2078 return -1;
2079 }
2080
2081 tmpctx = create_gpgme_context(false);
2082
2083 err = gpgme_op_keylist_from_data_start(tmpctx, keydata, 0);
2084 while (err == 0)
2085 {
2086 err = gpgme_op_keylist_next(tmpctx, &key);
2087 if (err != 0)
2088 break;
2089 uid = key->uids;
2090 subkey = key->subkeys;
2091 more = false;
2092 while (subkey)
2093 {
2094 shortid = subkey->keyid;
2095 len = mutt_str_len(subkey->keyid);
2096 if (len > 8)
2097 shortid += len - 8;
2098 tt = subkey->timestamp;
2099 mutt_date_localtime_format(date, sizeof(date), "%Y-%m-%d", tt);
2100
2101 if (more)
2102 {
2103 fprintf(*fp, "sub %5.5s %u/%8s %s\n", gpgme_pubkey_algo_name(subkey->pubkey_algo),
2104 subkey->length, shortid, date);
2105 }
2106 else
2107 {
2108 fprintf(*fp, "pub %5.5s %u/%8s %s %s\n", gpgme_pubkey_algo_name(subkey->pubkey_algo),
2109 subkey->length, shortid, date, (uid ? uid->uid : ""));
2110 }
2111 subkey = subkey->next;
2112 more = true;
2113 }
2114 gpgme_key_unref(key);
2115 }
2116 if (gpg_err_code(err) != GPG_ERR_EOF)
2117 {
2118 mutt_debug(LL_DEBUG1, "Error listing keys\n");
2119 goto err_fp;
2120 }
2121
2122 rc = 0;
2123
2124err_fp:
2125 if (rc)
2126 mutt_file_fclose(fp);
2127
2128 gpgme_release(tmpctx);
2129
2130 return rc;
2131}
#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:567
+ 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 2144 of file crypt_gpgme.c.

2145{
2146 if (mutt_strn_equal(a, b, n))
2147 {
2148 /* at this point we know that 'b' is at least 'n' chars long */
2149 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2150 return true;
2151 }
2152 return false;
2153}
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:496
+ 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 2162 of file crypt_gpgme.c.

2163{
2164 char buf[8192] = { 0 };
2165 bool rc = false;
2166
2167 bool sgn = false;
2168 bool enc = false;
2169
2170 if (b->type != TYPE_TEXT)
2171 return 0;
2172
2173 struct Buffer *tempfile = mutt_buffer_pool_get();
2174 mutt_buffer_mktemp(tempfile);
2175 if (mutt_decode_save_attachment(fp, b, mutt_buffer_string(tempfile), 0,
2176 MUTT_SAVE_NO_FLAGS) != 0)
2177 {
2178 unlink(mutt_buffer_string(tempfile));
2179 goto cleanup;
2180 }
2181
2182 FILE *fp_tmp = fopen(mutt_buffer_string(tempfile), "r");
2183 if (!fp_tmp)
2184 {
2185 unlink(mutt_buffer_string(tempfile));
2186 goto cleanup;
2187 }
2188
2189 while (fgets(buf, sizeof(buf), fp_tmp))
2190 {
2191 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2192 if (plen != 0)
2193 {
2194 if (MESSAGE(buf + plen))
2195 {
2196 enc = true;
2197 break;
2198 }
2199 else if (SIGNED_MESSAGE(buf + plen))
2200 {
2201 sgn = true;
2202 break;
2203 }
2204 }
2205 }
2206 mutt_file_fclose(&fp_tmp);
2207 unlink(mutt_buffer_string(tempfile));
2208
2209 if (!enc && !sgn)
2210 goto cleanup;
2211
2212 /* fix the content type */
2213
2214 mutt_param_set(&b->parameter, "format", "fixed");
2215 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2216
2217 rc = true;
2218
2219cleanup:
2220 mutt_buffer_pool_release(&tempfile);
2221 return rc;
2222}
#define SIGNED_MESSAGE(_y)
Definition: crypt_gpgme.c:102
#define MESSAGE(_y)
Definition: crypt_gpgme.c:101
@ 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:1030
@ 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 2361 of file crypt_gpgme.c.

2362{
2363 char buf[8192] = { 0 };
2364 bool complete, armor_header;
2365 FILE *fp = NULL;
2366
2367 char *fname = data_object_to_tempfile(data, &fp);
2368 if (!fname)
2369 {
2370 mutt_file_fclose(&fp);
2371 return;
2372 }
2373 unlink(fname);
2374 FREE(&fname);
2375
2376 /* fromcode comes from the MIME Content-Type charset label. It might
2377 * be a wrong label, so we want the ability to do corrections via
2378 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2379 const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
2380 struct FgetConv *fc = mutt_ch_fgetconv_open(fp, charset, c_charset, MUTT_ICONV_HOOK_FROM);
2381
2382 for (complete = true, armor_header = true;
2383 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2384 {
2385 if (!complete)
2386 {
2387 if (!armor_header)
2388 state_puts(s, buf);
2389 continue;
2390 }
2391
2392 if (BEGIN_PGP_SIGNATURE(buf))
2393 break;
2394
2395 if (armor_header)
2396 {
2397 if (buf[0] == '\n')
2398 armor_header = false;
2399 continue;
2400 }
2401
2402 if (s->prefix)
2403 state_puts(s, s->prefix);
2404
2405 if ((buf[0] == '-') && (buf[1] == ' '))
2406 state_puts(s, buf + 2);
2407 else
2408 state_puts(s, buf);
2409 }
2410
2413}
#define BEGIN_PGP_SIGNATURE(_y)
Definition: crypt_gpgme.c:104
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 2837 of file crypt_gpgme.c.

2838{
2839 unsigned int rc = 0;
2840
2841 switch (cap)
2842 {
2844 rc = key->can_encrypt;
2845 if (rc == 0)
2846 {
2847 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2848 {
2849 rc = subkey->can_encrypt;
2850 if (rc != 0)
2851 break;
2852 }
2853 }
2854 break;
2855 case KEY_CAP_CAN_SIGN:
2856 rc = key->can_sign;
2857 if (rc == 0)
2858 {
2859 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2860 {
2861 rc = subkey->can_sign;
2862 if (rc != 0)
2863 break;
2864 }
2865 }
2866 break;
2868 rc = key->can_certify;
2869 if (rc == 0)
2870 {
2871 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2872 {
2873 rc = subkey->can_certify;
2874 if (rc != 0)
2875 break;
2876 }
2877 }
2878 break;
2879 }
2880
2881 return rc;
2882}
@ 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 2893 of file crypt_gpgme.c.

2894{
2895 char *pattern = NULL, *p = NULL;
2896 const char *s = NULL;
2897 size_t n;
2898
2899 n = 0;
2900 struct ListNode *np = NULL;
2901 STAILQ_FOREACH(np, list, entries)
2902 {
2903 for (s = np->data; *s; s++)
2904 {
2905 if ((*s == '%') || (*s == '+'))
2906 n += 2;
2907 n++;
2908 }
2909 n++; /* delimiter or end of string */
2910 }
2911 n++; /* make sure to allocate at least one byte */
2912 p = mutt_mem_calloc(1, n);
2913 pattern = p;
2914 STAILQ_FOREACH(np, list, entries)
2915 {
2916 s = np->data;
2917 if (*s)
2918 {
2919 if (np != STAILQ_FIRST(list))
2920 *p++ = ' ';
2921 for (s = np->data; *s; s++)
2922 {
2923 if (*s == '%')
2924 {
2925 *p++ = '%';
2926 *p++ = '2';
2927 *p++ = '5';
2928 }
2929 else if (*s == '+')
2930 {
2931 *p++ = '%';
2932 *p++ = '2';
2933 *p++ = 'B';
2934 }
2935 else if (*s == ' ')
2936 *p++ = '+';
2937 else
2938 *p++ = *s;
2939 }
2940 }
2941 }
2942 *p = '\0';
2943 return pattern;
2944}
#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 2956 of file crypt_gpgme.c.

2957{
2958 struct CryptKeyInfo *db = NULL, *k = NULL, **kend = NULL;
2959 gpgme_error_t err;
2960 gpgme_ctx_t ctx = NULL;
2961 gpgme_key_t key = NULL;
2962 int idx;
2963 gpgme_user_id_t uid = NULL;
2964
2965 char *pattern = list_to_pattern(hints);
2966 if (!pattern)
2967 return NULL;
2968
2969 ctx = create_gpgme_context(0);
2970 db = NULL;
2971 kend = &db;
2972
2973 if ((app & APPLICATION_PGP))
2974 {
2975 /* It's all a mess. That old GPGME expects different things depending on
2976 * the protocol. For gpg we don't need percent escaped pappert but simple
2977 * strings passed in an array to the keylist_ext_start function. */
2978 size_t n = 0;
2979 struct ListNode *np = NULL;
2980 STAILQ_FOREACH(np, hints, entries)
2981 {
2982 if (np->data && *np->data)
2983 n++;
2984 }
2985 if (n == 0)
2986 goto no_pgphints;
2987
2988 char **patarr = mutt_mem_calloc(n + 1, sizeof(*patarr));
2989 n = 0;
2990 STAILQ_FOREACH(np, hints, entries)
2991 {
2992 if (np->data && *np->data)
2993 patarr[n++] = mutt_str_dup(np->data);
2994 }
2995 patarr[n] = NULL;
2996 err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
2997 for (n = 0; patarr[n]; n++)
2998 FREE(&patarr[n]);
2999 FREE(&patarr);
3000 if (err != 0)
3001 {
3002 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3003 gpgme_release(ctx);
3004 FREE(&pattern);
3005 return NULL;
3006 }
3007
3008 while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
3009 {
3010 KeyFlags flags = KEYFLAG_NO_FLAGS;
3011
3013 flags |= KEYFLAG_CANENCRYPT;
3015 flags |= KEYFLAG_CANSIGN;
3016
3017 if (key->revoked)
3018 flags |= KEYFLAG_REVOKED;
3019 if (key->expired)
3020 flags |= KEYFLAG_EXPIRED;
3021 if (key->disabled)
3022 flags |= KEYFLAG_DISABLED;
3023
3024 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3025 {
3026 k = mutt_mem_calloc(1, sizeof(*k));
3027 k->kobj = key;
3028 gpgme_key_ref(k->kobj);
3029 k->idx = idx;
3030 k->uid = uid->uid;
3031 k->flags = flags;
3032 if (uid->revoked)
3033 k->flags |= KEYFLAG_REVOKED;
3034 k->validity = uid->validity;
3035 *kend = k;
3036 kend = &k->next;
3037 }
3038 gpgme_key_unref(key);
3039 }
3040 if (gpg_err_code(err) != GPG_ERR_EOF)
3041 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3042 gpgme_op_keylist_end(ctx);
3043 no_pgphints:;
3044 }
3045
3046 if ((app & APPLICATION_SMIME))
3047 {
3048 /* and now look for x509 certificates */
3049 gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
3050 err = gpgme_op_keylist_start(ctx, pattern, 0);
3051 if (err != 0)
3052 {
3053 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3054 gpgme_release(ctx);
3055 FREE(&pattern);
3056 return NULL;
3057 }
3058
3059 while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
3060 {
3061 KeyFlags flags = KEYFLAG_ISX509;
3062
3064 flags |= KEYFLAG_CANENCRYPT;
3066 flags |= KEYFLAG_CANSIGN;
3067
3068 if (key->revoked)
3069 flags |= KEYFLAG_REVOKED;
3070 if (key->expired)
3071 flags |= KEYFLAG_EXPIRED;
3072 if (key->disabled)
3073 flags |= KEYFLAG_DISABLED;
3074
3075 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3076 {
3077 k = mutt_mem_calloc(1, sizeof(*k));
3078 k->kobj = key;
3079 gpgme_key_ref(k->kobj);
3080 k->idx = idx;
3081 k->uid = uid->uid;
3082 k->flags = flags;
3083 if (uid->revoked)
3084 k->flags |= KEYFLAG_REVOKED;
3085 k->validity = uid->validity;
3086 *kend = k;
3087 kend = &k->next;
3088 }
3089 gpgme_key_unref(key);
3090 }
3091 if (gpg_err_code(err) != GPG_ERR_EOF)
3092 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3093 gpgme_op_keylist_end(ctx);
3094 }
3095
3096 gpgme_release(ctx);
3097 FREE(&pattern);
3098 return db;
3099}
static char * list_to_pattern(struct ListHead *list)
Convert STailQ to GPGME-compatible pattern.
Definition: crypt_gpgme.c:2893
unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
Definition: crypt_gpgme.c:2837
#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 3109 of file crypt_gpgme.c.

3110{
3111 char *scratch = mutt_str_dup(str);
3112 if (!scratch)
3113 return;
3114
3115 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3116 {
3117 if (strlen(t) > 3)
3119 }
3120
3121 FREE(&scratch);
3122}
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 3133 of file crypt_gpgme.c.

3136{
3137 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3138
3139 int multi = false;
3140 int this_key_has_strong = false;
3141 int this_key_has_addr_match = false;
3142 int match = false;
3143
3144 struct CryptKeyInfo *keys = NULL, *k = NULL;
3145 struct CryptKeyInfo *the_strong_valid_key = NULL;
3146 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3147 struct CryptKeyInfo *matches = NULL;
3148 struct CryptKeyInfo **matches_endp = &matches;
3149
3150 if (a && a->mailbox)
3152 if (a && a->personal)
3154
3155 if (!oppenc_mode)
3156 mutt_message(_("Looking for keys matching \"%s\"..."), a ? a->mailbox : "");
3157 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3158
3159 mutt_list_free(&hints);
3160
3161 if (!keys)
3162 return NULL;
3163
3164 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n", a ? NONULL(a->personal) : "",
3165 a ? NONULL(a->mailbox) : "");
3166
3167 for (k = keys; k; k = k->next)
3168 {
3169 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3170
3171 if (abilities && !(k->flags & abilities))
3172 {
3173 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3174 continue;
3175 }
3176
3177 this_key_has_strong = false; /* strong and valid match */
3178 this_key_has_addr_match = false;
3179 match = false; /* any match */
3180
3181 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3182 mutt_addrlist_parse(&alist, k->uid);
3183 struct Address *ka = NULL;
3184 TAILQ_FOREACH(ka, &alist, entries)
3185 {
3186 int validity = crypt_id_matches_addr(a, ka, k);
3187
3188 if (validity & CRYPT_KV_MATCH) /* something matches */
3189 {
3190 match = true;
3191
3192 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3193 {
3194 if (validity & CRYPT_KV_STRONGID)
3195 {
3196 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3197 multi = true;
3198 this_key_has_strong = true;
3199 }
3200 else
3201 this_key_has_addr_match = true;
3202 }
3203 }
3204 }
3205 mutt_addrlist_clear(&alist);
3206
3207 if (match)
3208 {
3209 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3210 *matches_endp = tmp;
3211 matches_endp = &tmp->next;
3212
3213 if (this_key_has_strong)
3214 the_strong_valid_key = tmp;
3215 else if (this_key_has_addr_match)
3216 a_valid_addrmatch_key = tmp;
3217 }
3218 }
3219
3220 crypt_key_free(&keys);
3221
3222 if (matches)
3223 {
3224 if (oppenc_mode)
3225 {
3226 const bool c_crypt_opportunistic_encrypt_strong_keys =
3227 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3228 if (the_strong_valid_key)
3229 k = crypt_copy_key(the_strong_valid_key);
3230 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3231 k = crypt_copy_key(a_valid_addrmatch_key);
3232 else
3233 k = NULL;
3234 }
3235 else if (the_strong_valid_key && !multi)
3236 {
3237 /* There was precisely one strong match on a valid ID.
3238 * Proceed without asking the user. */
3239 k = crypt_copy_key(the_strong_valid_key);
3240 }
3241 else
3242 {
3243 /* Else: Ask the user. */
3244 k = dlg_select_gpgme_key(matches, a, NULL, app, forced_valid);
3245 }
3246
3247 crypt_key_free(&matches);
3248 }
3249 else
3250 k = NULL;
3251
3252 return k;
3253}
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
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
Definition: crypt_gpgme.c:234
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:328
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:3109
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:2956
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
Definition: crypt_gpgme.c:138
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
Definition: crypt_gpgme.c:253
#define CRYPT_KV_MATCH
Definition: crypt_gpgme.c:81
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:665
#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
#define NONULL(x)
Definition: string2.h:37
+ 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 3263 of file crypt_gpgme.c.

3265{
3266 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3267 struct CryptKeyInfo *matches = NULL;
3268 struct CryptKeyInfo **matches_endp = &matches;
3269 struct CryptKeyInfo *k = NULL;
3270 const char *ps = NULL, *pl = NULL, *phint = NULL;
3271
3272 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3273
3274 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3275 crypt_add_string_to_hints(phint, &hints);
3276 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3277 mutt_list_free(&hints);
3278
3279 if (!keys)
3280 {
3281 FREE(&pfcopy);
3282 return NULL;
3283 }
3284
3285 for (k = keys; k; k = k->next)
3286 {
3287 if (abilities && !(k->flags & abilities))
3288 continue;
3289
3290 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3291 crypt_long_keyid(k), k->uid);
3292
3293 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3294 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3295 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3296 {
3297 mutt_debug(LL_DEBUG5, "match\n");
3298
3299 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3300 *matches_endp = tmp;
3301 matches_endp = &tmp->next;
3302 }
3303 else
3304 {
3305 mutt_debug(LL_DEBUG5, "no match\n");
3306 }
3307 }
3308
3309 FREE(&pfcopy);
3310 crypt_key_free(&keys);
3311
3312 if (matches)
3313 {
3314 k = dlg_select_gpgme_key(matches, NULL, p, app, forced_valid);
3315 crypt_key_free(&matches);
3316 return k;
3317 }
3318
3319 return NULL;
3320}
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:180
static const char * crypt_long_keyid(struct CryptKeyInfo *k)
Find the Long ID for the key.
Definition: crypt_gpgme.c:163
static const char * crypt_fpr(struct CryptKeyInfo *k)
Get the hexstring fingerprint from a key.
Definition: crypt_gpgme.c:199
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:592
+ 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 3334 of file crypt_gpgme.c.

3336{
3337 struct CryptKeyInfo *key = NULL;
3338 struct CryptCache *l = NULL;
3339 struct Buffer *resp = mutt_buffer_pool_get();
3340
3342
3343 if (whatfor)
3344 {
3345 for (l = id_defaults; l; l = l->next)
3346 {
3347 if (mutt_istr_equal(whatfor, l->what))
3348 {
3349 mutt_buffer_strcpy(resp, l->dflt);
3350 break;
3351 }
3352 }
3353 }
3354
3355 while (true)
3356 {
3357 mutt_buffer_reset(resp);
3358 if (mutt_buffer_get_field(tag, resp, MUTT_COMP_NO_FLAGS, false, NULL, NULL, NULL) != 0)
3359 {
3360 goto done;
3361 }
3362
3363 if (whatfor)
3364 {
3365 if (l)
3367 else
3368 {
3369 l = mutt_mem_malloc(sizeof(struct CryptCache));
3370 l->next = id_defaults;
3371 id_defaults = l;
3372 l->what = mutt_str_dup(whatfor);
3373 l->dflt = mutt_buffer_strdup(resp);
3374 }
3375 }
3376
3377 key = crypt_getkeybystr(mutt_buffer_string(resp), abilities, app, forced_valid);
3378 if (key)
3379 goto done;
3380
3381 mutt_error(_("No matching keys found for \"%s\""), mutt_buffer_string(resp));
3382 }
3383
3384done:
3386 return key;
3387}
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
static struct CryptCache * id_defaults
Definition: crypt_gpgme.c:94
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:3263
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: window.c:180
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:88
char * what
Definition: crypt_gpgme.c:89
char * dflt
Definition: crypt_gpgme.c:90
struct CryptCache * next
Definition: crypt_gpgme.c:91
+ 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 3400 of file crypt_gpgme.c.

3401{
3402 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3403 struct ListNode *crypt_hook = NULL;
3404 const char *keyid = NULL;
3405 char *keylist = NULL;
3406 size_t keylist_size = 0;
3407 size_t keylist_used = 0;
3408 struct Address *p = NULL;
3409 struct CryptKeyInfo *k_info = NULL;
3410 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3411 char buf[1024] = { 0 };
3412 bool forced_valid = false;
3413 bool key_selected;
3414 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3415
3416 struct Address *a = NULL;
3417 TAILQ_FOREACH(a, addrlist, entries)
3418 {
3419 key_selected = false;
3420 mutt_crypt_hook(&crypt_hook_list, a);
3421 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3422 do
3423 {
3424 p = a;
3425 forced_valid = false;
3426 k_info = NULL;
3427
3428 if (crypt_hook)
3429 {
3430 keyid = crypt_hook->data;
3431 enum QuadOption ans = MUTT_YES;
3432 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3433 if (!oppenc_mode && c_crypt_confirm_hook)
3434 {
3435 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid, p->mailbox);
3436 ans = mutt_yesorno(buf, MUTT_YES);
3437 }
3438 if (ans == MUTT_YES)
3439 {
3440 if (crypt_is_numerical_keyid(keyid))
3441 {
3442 if (mutt_strn_equal(keyid, "0x", 2))
3443 keyid += 2;
3444 goto bypass_selection; /* you don't see this. */
3445 }
3446
3447 /* check for e-mail address */
3448 mutt_addrlist_clear(&hookal);
3449 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3450 {
3451 mutt_addrlist_qualify(&hookal, fqdn);
3452 p = TAILQ_FIRST(&hookal);
3453 }
3454 else if (!oppenc_mode)
3455 {
3456 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3457 }
3458 }
3459 else if (ans == MUTT_NO)
3460 {
3461 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3462 {
3463 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3464 continue;
3465 }
3466 }
3467 else if (ans == MUTT_ABORT)
3468 {
3469 FREE(&keylist);
3470 mutt_addrlist_clear(&hookal);
3471 mutt_list_free(&crypt_hook_list);
3472 return NULL;
3473 }
3474 }
3475
3476 if (!k_info)
3477 {
3478 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3479 }
3480
3481 if (!k_info && !oppenc_mode)
3482 {
3483 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), p->mailbox);
3484
3485 k_info = crypt_ask_for_key(buf, p->mailbox, KEYFLAG_CANENCRYPT, app, &forced_valid);
3486 }
3487
3488 if (!k_info)
3489 {
3490 FREE(&keylist);
3491 mutt_addrlist_clear(&hookal);
3492 mutt_list_free(&crypt_hook_list);
3493 return NULL;
3494 }
3495
3496 keyid = crypt_fpr_or_lkeyid(k_info);
3497
3498 bypass_selection:
3499 keylist_size += mutt_str_len(keyid) + 4 + 1;
3500 mutt_mem_realloc(&keylist, keylist_size);
3501 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3502 keyid, forced_valid ? "!" : "");
3503 keylist_used = mutt_str_len(keylist);
3504
3505 key_selected = true;
3506
3507 crypt_key_free(&k_info);
3508 mutt_addrlist_clear(&hookal);
3509
3510 if (crypt_hook)
3511 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3512
3513 } while (crypt_hook);
3514
3515 mutt_list_free(&crypt_hook_list);
3516 }
3517 return keylist;
3518}
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:3133
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:3334
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
Definition: crypt_gpgme.c:214
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:834
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
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 3549 of file crypt_gpgme.c.

3550{
3551 int rc = -1;
3552 gpgme_error_t err;
3553 gpgme_key_t key = NULL;
3554 gpgme_user_id_t uid = NULL;
3555 struct CryptKeyInfo *results = NULL, *k = NULL;
3556 struct CryptKeyInfo **kend = NULL;
3557 struct CryptKeyInfo *choice = NULL;
3558
3559 gpgme_ctx_t ctx = create_gpgme_context(false);
3560
3561 /* list all secret keys */
3562 if (gpgme_op_keylist_start(ctx, NULL, 1))
3563 goto cleanup;
3564
3565 kend = &results;
3566
3567 while (!(err = gpgme_op_keylist_next(ctx, &key)))
3568 {
3570
3575
3576 if (key->revoked)
3578 if (key->expired)
3580 if (key->disabled)
3582
3583 int idx;
3584 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3585 {
3586 k = mutt_mem_calloc(1, sizeof(*k));
3587 k->kobj = key;
3588 gpgme_key_ref(k->kobj);
3589 k->idx = idx;
3590 k->uid = uid->uid;
3591 k->flags = flags;
3592 if (uid->revoked)
3593 k->flags |= KEYFLAG_REVOKED;
3594 k->validity = uid->validity;
3595 *kend = k;
3596 kend = &k->next;
3597 }
3598 gpgme_key_unref(key);
3599 }
3600 if (gpg_err_code(err) != GPG_ERR_EOF)
3601 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3602 gpgme_op_keylist_end(ctx);
3603
3604 if (!results)
3605 {
3606 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3607 from. This error is displayed if no results were found. */
3608 mutt_error(_("No secret keys found"));
3609 goto cleanup;
3610 }
3611
3612 choice = dlg_select_gpgme_key(results, NULL, "*", APPLICATION_PGP, NULL);
3613 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3614 goto cleanup;
3615 mutt_buffer_strcpy(keyid, choice->kobj->subkeys->fpr);
3616
3617 rc = 0;
3618
3619cleanup:
3620 crypt_key_free(&choice);
3621 crypt_key_free(&results);
3622 gpgme_release(ctx);
3623 return rc;
3624}
+ 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 3689 of file crypt_gpgme.c.

3690{
3691 /* this initialization should only run one time, but it may be called by
3692 * either pgp_gpgme_init or smime_gpgme_init */
3693 static bool has_run = false;
3694 if (has_run)
3695 return;
3696
3697 gpgme_check_version(NULL);
3698 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3699#ifdef ENABLE_NLS
3700 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3701#endif
3702 has_run = true;
3703}
+ Here is the caller graph for this function:

◆ init_pgp()

static void init_pgp ( void  )
static

Initialise the PGP crypto backend.

Definition at line 3708 of file crypt_gpgme.c.

3709{
3710 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3711 {
3712 mutt_error(_("GPGME: OpenPGP protocol not available"));
3713 }
3714}
+ Here is the caller graph for this function:

◆ init_smime()

static void init_smime ( void  )
static

Initialise the SMIME crypto backend.

Definition at line 3719 of file crypt_gpgme.c.

3720{
3721 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3722 {
3723 mutt_error(_("GPGME: CMS protocol not available"));
3724 }
3725}
+ 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 3751 of file crypt_gpgme.c.

3752{
3753 struct CryptKeyInfo *p = NULL;
3754 const char *prompt = NULL;
3755 const char *letters = NULL;
3756 const char *choices = NULL;
3757 int choice;
3758
3759 if (is_smime)
3761 else
3763
3764 /* Opportunistic encrypt is controlling encryption.
3765 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3766 * letter choices for those.
3767 */
3768 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3769 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3770 {
3771 if (is_smime)
3772 {
3773 /* L10N: S/MIME options (opportunistic encryption is on) */
3774 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3775 /* L10N: S/MIME options (opportunistic encryption is on) */
3776 letters = _("sapco");
3777 choices = "SapCo";
3778 }
3779 else
3780 {
3781 /* L10N: PGP options (opportunistic encryption is on) */
3782 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3783 /* L10N: PGP options (opportunistic encryption is on) */
3784 letters = _("samco");
3785 choices = "SamCo";
3786 }
3787 }
3788 /* Opportunistic encryption option is set, but is toggled off for this message. */
3789 else if (c_crypt_opportunistic_encrypt)
3790 {
3791 if (is_smime)
3792 {
3793 /* L10N: S/MIME options (opportunistic encryption is off) */
3794 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3795 /* L10N: S/MIME options (opportunistic encryption is off) */
3796 letters = _("esabpco");
3797 choices = "esabpcO";
3798 }
3799 else
3800 {
3801 /* L10N: PGP options (opportunistic encryption is off) */
3802 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3803 /* L10N: PGP options (opportunistic encryption is off) */
3804 letters = _("esabmco");
3805 choices = "esabmcO";
3806 }
3807 }
3808 /* Opportunistic encryption is unset */
3809 else
3810 {
3811 if (is_smime)
3812 {
3813 /* L10N: S/MIME options */
3814 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
3815 /* L10N: S/MIME options */
3816 letters = _("esabpc");
3817 choices = "esabpc";
3818 }
3819 else
3820 {
3821 /* L10N: PGP options */
3822 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
3823 /* L10N: PGP options */
3824 letters = _("esabmc");
3825 choices = "esabmc";
3826 }
3827 }
3828
3829 choice = mutt_multi_choice(prompt, letters);
3830 if (choice > 0)
3831 {
3832 switch (choices[choice - 1])
3833 {
3834 case 'a': /* sign (a)s */
3835 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3836 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
3837 if (p)
3838 {
3839 char input_signas[128] = { 0 };
3840 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
3841
3842 if (is_smime)
3843 cs_subset_str_string_set(NeoMutt->sub, "smime_default_key", input_signas, NULL);
3844 else
3845 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
3846
3847 crypt_key_free(&p);
3848
3849 e->security |= SEC_SIGN;
3850 }
3851 break;
3852
3853 case 'b': /* (b)oth */
3854 e->security |= (SEC_ENCRYPT | SEC_SIGN);
3855 break;
3856
3857 case 'C':
3858 e->security &= ~SEC_SIGN;
3859 break;
3860
3861 case 'c': /* (c)lear */
3862 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
3863 break;
3864
3865 case 'e': /* (e)ncrypt */
3866 e->security |= SEC_ENCRYPT;
3867 e->security &= ~SEC_SIGN;
3868 break;
3869
3870 case 'm': /* (p)gp or s/(m)ime */
3871 case 'p':
3872 is_smime = !is_smime;
3873 if (is_smime)
3874 {
3875 e->security &= ~APPLICATION_PGP;
3877 }
3878 else
3879 {
3880 e->security &= ~APPLICATION_SMIME;
3882 }
3884 break;
3885
3886 case 'O': /* oppenc mode on */
3889 break;
3890
3891 case 'o': /* oppenc mode off */
3892 e->security &= ~SEC_OPPENCRYPT;
3893 break;
3894
3895 case 'S': /* (s)ign in oppenc mode */
3896 e->security |= SEC_SIGN;
3897 break;
3898
3899 case 's': /* (s)ign */
3900 e->security &= ~SEC_ENCRYPT;
3901 e->security |= SEC_SIGN;
3902 break;
3903 }
3904 }
3905
3906 return e->security;
3907}
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 3930 of file crypt_gpgme.c.

3931{
3932 struct Address *sender = NULL;
3933 bool rc = true;
3934
3935 if (!TAILQ_EMPTY(&e->env->from))
3936 {
3938 sender = TAILQ_FIRST(&e->env->from);
3939 }
3940 else if (!TAILQ_EMPTY(&e->env->sender))
3941 {
3943 sender = TAILQ_FIRST(&e->env->sender);
3944 }
3945
3946 if (sender)
3947 {
3948 if (signature_key)
3949 {
3950 gpgme_key_t key = signature_key;
3951 gpgme_user_id_t uid = NULL;
3952 int sender_length = strlen(sender->mailbox);
3953 for (uid = key->uids; uid && rc; uid = uid->next)
3954 {
3955 int uid_length = strlen(uid->email);
3956 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
3957 (uid_length == (sender_length + 2)))
3958 {
3959 const char *at_sign = strchr(uid->email + 1, '@');
3960 if (at_sign)
3961 {
3962 /* Assume address is 'mailbox@domainname'.
3963 * The mailbox part is case-sensitive,
3964 * the domainname is not. (RFC2821) */
3965 const char *tmp_email = uid->email + 1;
3966 const char *tmp_sender = sender->mailbox;
3967 /* length of mailbox part including '@' */
3968 int mailbox_length = at_sign - tmp_email + 1;
3969 int domainname_length = sender_length - mailbox_length;
3970 int mailbox_match, domainname_match;
3971
3972 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
3973 tmp_email += mailbox_length;
3974 tmp_sender += mailbox_length;
3975 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
3976 if (mailbox_match && domainname_match)
3977 rc = false;
3978 }
3979 else
3980 {
3981 if (mutt_strn_equal(uid->email + 1, sender->mailbox, sender_length))
3982 rc = false;
3983 }
3984 }
3985 }
3986 }
3987 else
3988 mutt_any_key_to_continue(_("Failed to verify sender"));
3989 }
3990 else
3991 mutt_any_key_to_continue(_("Failed to figure out sender"));
3992
3993 if (signature_key)
3994 {
3995 gpgme_key_unref(signature_key);
3996 signature_key = NULL;
3997 }
3998
3999 return rc;
4000}
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:298
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:387
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:510
#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 4024 of file crypt_gpgme.c.

4025{
4026 return GPGME_VERSION;
4027}
+ Here is the caller graph for this function:

Variable Documentation

◆ id_defaults

struct CryptCache* id_defaults = NULL
static

Definition at line 94 of file crypt_gpgme.c.

◆ signature_key

gpgme_key_t signature_key = NULL
static

Definition at line 95 of file crypt_gpgme.c.

◆ current_sender

char* current_sender = NULL
static

Definition at line 96 of file crypt_gpgme.c.