NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 <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 "editor/lib.h"
#include "history/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "crypt.h"
#include "globals.h"
#include "handler.h"
#include "hook.h"
#include "mutt_logging.h"
#include "autocrypt/lib.h"
+ Include dependency graph for crypt_gpgme.c:

Go to the source code of this file.

Data Structures

struct  CryptCache
 Internal cache for GPGME. More...
 

Macros

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

Functions

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

Variables

static struct CryptCacheIdDefaults = NULL
 Cache of GPGME keys.
 
static gpgme_key_t SignatureKey = NULL
 PGP Key to sign with.
 
static char * CurrentSender = NULL
 Email address of the sender.
 

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 73 of file crypt_gpgme.c.

◆ CRYPT_KV_ADDR

#define CRYPT_KV_ADDR   (1 << 1)

Definition at line 74 of file crypt_gpgme.c.

◆ CRYPT_KV_STRING

#define CRYPT_KV_STRING   (1 << 2)

Definition at line 75 of file crypt_gpgme.c.

◆ CRYPT_KV_STRONGID

#define CRYPT_KV_STRONGID   (1 << 3)

Definition at line 76 of file crypt_gpgme.c.

◆ CRYPT_KV_MATCH

#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)

Definition at line 77 of file crypt_gpgme.c.

◆ PKA_NOTATION_NAME

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

Definition at line 97 of file crypt_gpgme.c.

◆ _LINE_COMPARE

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

Definition at line 99 of file crypt_gpgme.c.

◆ MESSAGE

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

Definition at line 100 of file crypt_gpgme.c.

◆ SIGNED_MESSAGE

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

Definition at line 101 of file crypt_gpgme.c.

◆ PUBLIC_KEY_BLOCK

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

Definition at line 102 of file crypt_gpgme.c.

◆ BEGIN_PGP_SIGNATURE

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

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

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

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

138{
139 const char *s = "????????";
140
141 if (k->kobj && k->kobj->subkeys)
142 {
143 s = k->kobj->subkeys->keyid;
144 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
145 if ((!c_pgp_long_ids) && (strlen(s) == 16))
146 {
147 /* Return only the short keyID. */
148 s += 8;
149 }
150 }
151
152 return s;
153}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
gpgme_key_t kobj
Definition: crypt_gpgme.h:46
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ 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 162 of file crypt_gpgme.c.

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

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

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

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

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

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

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

310{
311 if (!key)
312 return 0;
313
314 return !(key->flags & KEYFLAG_CANTUSE);
315}
#define KEYFLAG_CANTUSE
Definition: lib.h:140
+ 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 327 of file crypt_gpgme.c.

329{
330 int rc = 0;
331
332 if (crypt_id_is_valid(key))
333 rc |= CRYPT_KV_VALID;
334
335 if (crypt_id_is_strong(key))
336 rc |= CRYPT_KV_STRONGID;
337
338 if (addr && u_addr)
339 {
340 if (addr->mailbox && u_addr->mailbox && buf_istr_equal(addr->mailbox, u_addr->mailbox))
341 {
342 rc |= CRYPT_KV_ADDR;
343 }
344
345 if (addr->personal && u_addr->personal &&
346 buf_istr_equal(addr->personal, u_addr->personal))
347 {
348 rc |= CRYPT_KV_STRING;
349 }
350 }
351
352 return rc;
353}
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition: buffer.c:665
#define CRYPT_KV_STRING
Definition: crypt_gpgme.c:75
int crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
Definition: crypt_gpgme.c:309
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
Definition: crypt_gpgme.c:274
#define CRYPT_KV_VALID
Definition: crypt_gpgme.c:73
#define CRYPT_KV_STRONGID
Definition: crypt_gpgme.c:76
#define CRYPT_KV_ADDR
Definition: crypt_gpgme.c:74
struct Buffer * personal
Real name of address.
Definition: address.h:37
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
+ 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 360 of file crypt_gpgme.c.

361{
362 gpgme_ctx_t ctx = NULL;
363
364 gpgme_error_t err = gpgme_new(&ctx);
365
366#ifdef USE_AUTOCRYPT
367 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
368 if (!err && OptAutocryptGpgme)
369 err = gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_OpenPGP, NULL, c_autocrypt_dir);
370#endif
371
372 if (err != 0)
373 {
374 mutt_error(_("error creating GPGME context: %s"), gpgme_strerror(err));
375 mutt_exit(1);
376 }
377
378 if (for_smime)
379 {
380 err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
381 if (err != 0)
382 {
383 mutt_error(_("error enabling CMS protocol: %s"), gpgme_strerror(err));
384 mutt_exit(1);
385 }
386 }
387
388 return ctx;
389}
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:169
bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: globals.c:67
#define mutt_error(...)
Definition: logging2.h:92
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:236
#define _(a)
Definition: message.h:28
+ 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 399 of file crypt_gpgme.c.

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

419{
420 int err = 0;
421 gpgme_data_t data = NULL;
422
423 struct Buffer *tempfile = buf_pool_get();
424 buf_mktemp(tempfile);
425 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
426 if (!fp_tmp)
427 {
428 mutt_perror("%s", buf_string(tempfile));
429 goto cleanup;
430 }
431
433 fputc('\n', fp_tmp);
434 mutt_write_mime_body(a, fp_tmp, NeoMutt->sub);
435
436 if (convert)
437 {
438 int c, hadcr = 0;
439 unsigned char buf[1];
440
442 rewind(fp_tmp);
443 while ((c = fgetc(fp_tmp)) != EOF)
444 {
445 if (c == '\r')
446 {
447 hadcr = 1;
448 }
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, buf_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(buf_string(tempfile));
479
480cleanup:
481 buf_pool_release(&tempfile);
482 return data;
483}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
Definition: crypt_gpgme.c:399
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define mutt_perror(...)
Definition: logging2.h:93
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:758
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:301
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
#define buf_mktemp(buf)
Definition: tmp.h:33
+ 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 = buf_pool_get();
565
566 buf_mktemp(tempf);
567
568 FILE *fp = mutt_file_fopen(buf_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 {
584 mutt_perror("%s", buf_string(tempf));
585 mutt_file_fclose(&fp);
586 unlink(buf_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(buf_string(tempf));
599 mutt_file_fclose(&fp);
600 goto cleanup;
601 }
602 if (fp_ret)
603 *fp_ret = fp;
604 rv = buf_strdup(tempf);
605
606cleanup:
607 buf_pool_release(&tempf);
608 return rv;
609}
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:542
+ 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 buf_addstr(recpstring, "--\n");
632 }
633 else
634 {
635 buf_addch(recpstring, '\n');
636 }
637 n++;
638
639 while ((*s != '\0') && (*s != ' '))
640 buf_addch(recpstring, *s++);
641 }
642 } while (*s != '\0');
643}
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
+ 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 653 of file crypt_gpgme.c.

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

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

756{
757 gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME, CurrentSender, 0);
758 if (err)
759 {
760 mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
761 }
762
763 return err;
764}
static char * CurrentSender
Email address of the sender.
Definition: crypt_gpgme.c:95
+ 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 775 of file crypt_gpgme.c.

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

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

Print the date/time according to the locale.

Parameters
tTimestamp
stateState to write to

Definition at line 885 of file crypt_gpgme.c.

886{
887 char p[256] = { 0 };
888 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
889 state_puts(state, p);
890}
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:924
#define state_puts(STATE, STR)
Definition: state.h:57
+ 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 900 of file crypt_gpgme.c.

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

Display the common attributes of the signature summary SUM.

Definition at line 1127 of file crypt_gpgme.c.

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

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

Show the validity of a key used for one signature.

Parameters
ctxGPGME handle
idxIndex of signature to check
stateState to use

Definition at line 1306 of file crypt_gpgme.c.

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

Print key info about an SMIME key.

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

Definition at line 1345 of file crypt_gpgme.c.

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

Show information about one signature.

Parameters
ctxGPGME handle of a successful verification
idxIndex
stateState 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 1418 of file crypt_gpgme.c.

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

Do the actual verification step.

Parameters
sigbdyMime part containing signature
stateState 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 1541 of file crypt_gpgme.c.

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

Decrypt a PGP or SMIME message.

Parameters
[in]aBody of message
[in]stateState 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 1694 of file crypt_gpgme.c.

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

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

2154{
2155 if (mutt_strn_equal(a, b, n))
2156 {
2157 /* at this point we know that 'b' is at least 'n' chars long */
2158 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2159 return true;
2160 }
2161 return false;
2162}
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:497
+ 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 2171 of file crypt_gpgme.c.

2172{
2173 char buf[8192] = { 0 };
2174 bool rc = false;
2175
2176 bool sgn = false;
2177 bool enc = false;
2178
2179 if (b->type != TYPE_TEXT)
2180 return 0;
2181
2182 struct Buffer *tempfile = buf_pool_get();
2183 buf_mktemp(tempfile);
2185 MUTT_SAVE_NO_FLAGS) != 0)
2186 {
2187 unlink(buf_string(tempfile));
2188 goto cleanup;
2189 }
2190
2191 FILE *fp_tmp = fopen(buf_string(tempfile), "r");
2192 if (!fp_tmp)
2193 {
2194 unlink(buf_string(tempfile));
2195 goto cleanup;
2196 }
2197
2198 while (fgets(buf, sizeof(buf), fp_tmp))
2199 {
2200 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2201 if (plen != 0)
2202 {
2203 if (MESSAGE(buf + plen))
2204 {
2205 enc = true;
2206 break;
2207 }
2208 else if (SIGNED_MESSAGE(buf + plen))
2209 {
2210 sgn = true;
2211 break;
2212 }
2213 }
2214 }
2215 mutt_file_fclose(&fp_tmp);
2216 unlink(buf_string(tempfile));
2217
2218 if (!enc && !sgn)
2219 goto cleanup;
2220
2221 /* fix the content type */
2222
2223 mutt_param_set(&b->parameter, "format", "fixed");
2224 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2225
2226 rc = true;
2227
2228cleanup:
2229 buf_pool_release(&tempfile);
2230 return rc;
2231}
#define SIGNED_MESSAGE(_y)
Definition: crypt_gpgme.c:101
#define MESSAGE(_y)
Definition: crypt_gpgme.c:100
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
#define STATE_NO_FLAGS
No flags are set.
Definition: state.h:31
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:228
int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:1048
@ MUTT_SAVE_NO_FLAGS
No flags set.
Definition: mutt_attach.h:58
+ 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 state,
char *  charset 
)
static

Copy a clearsigned message.

Parameters
dataGPGME data object
stateState 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 2372 of file crypt_gpgme.c.

2373{
2374 char buf[8192] = { 0 };
2375 bool complete, armor_header;
2376 FILE *fp = NULL;
2377
2378 char *fname = data_object_to_tempfile(data, &fp);
2379 if (!fname)
2380 {
2381 mutt_file_fclose(&fp);
2382 return;
2383 }
2384 unlink(fname);
2385 FREE(&fname);
2386
2387 /* fromcode comes from the MIME Content-Type charset label. It might
2388 * be a wrong label, so we want the ability to do corrections via
2389 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2391
2392 for (complete = true, armor_header = true;
2393 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2394 {
2395 if (!complete)
2396 {
2397 if (!armor_header)
2398 state_puts(state, buf);
2399 continue;
2400 }
2401
2402 if (BEGIN_PGP_SIGNATURE(buf))
2403 break;
2404
2405 if (armor_header)
2406 {
2407 if (buf[0] == '\n')
2408 armor_header = false;
2409 continue;
2410 }
2411
2412 if (state->prefix)
2413 state_puts(state, state->prefix);
2414
2415 if ((buf[0] == '-') && (buf[1] == ' '))
2416 state_puts(state, buf + 2);
2417 else
2418 state_puts(state, buf);
2419 }
2420
2423}
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:115
#define BEGIN_PGP_SIGNATURE(_y)
Definition: crypt_gpgme.c:103
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:928
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition: charset.c:1040
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition: charset.c:960
#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:50
+ 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 2845 of file crypt_gpgme.c.

2846{
2847 unsigned int rc = 0;
2848
2849 switch (cap)
2850 {
2852 rc = key->can_encrypt;
2853 if (rc == 0)
2854 {
2855 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2856 {
2857 rc = subkey->can_encrypt;
2858 if (rc != 0)
2859 break;
2860 }
2861 }
2862 break;
2863 case KEY_CAP_CAN_SIGN:
2864 rc = key->can_sign;
2865 if (rc == 0)
2866 {
2867 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2868 {
2869 rc = subkey->can_sign;
2870 if (rc != 0)
2871 break;
2872 }
2873 }
2874 break;
2876 rc = key->can_certify;
2877 if (rc == 0)
2878 {
2879 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2880 {
2881 rc = subkey->can_certify;
2882 if (rc != 0)
2883 break;
2884 }
2885 }
2886 break;
2887 }
2888
2889 return rc;
2890}
@ 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 2901 of file crypt_gpgme.c.

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

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

3122{
3123 char *scratch = mutt_str_dup(str);
3124 if (!scratch)
3125 return;
3126
3127 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3128 {
3129 if (strlen(t) > 3)
3131 }
3132
3133 FREE(&scratch);
3134}
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 3145 of file crypt_gpgme.c.

3148{
3149 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3150
3151 int multi = false;
3152 int this_key_has_strong = false;
3153 int this_key_has_addr_match = false;
3154 int match = false;
3155
3156 struct CryptKeyInfo *keys = NULL, *k = NULL;
3157 struct CryptKeyInfo *the_strong_valid_key = NULL;
3158 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3159 struct CryptKeyInfo *matches = NULL;
3160 struct CryptKeyInfo **matches_endp = &matches;
3161
3162 if (a && a->mailbox)
3164 if (a && a->personal)
3166
3167 if (!oppenc_mode)
3168 mutt_message(_("Looking for keys matching \"%s\"..."), a ? buf_string(a->mailbox) : "");
3169 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3170
3171 mutt_list_free(&hints);
3172
3173 if (!keys)
3174 return NULL;
3175
3176 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n",
3177 a ? buf_string(a->personal) : "", a ? buf_string(a->mailbox) : "");
3178
3179 for (k = keys; k; k = k->next)
3180 {
3181 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3182
3183 if (abilities && !(k->flags & abilities))
3184 {
3185 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3186 continue;
3187 }
3188
3189 this_key_has_strong = false; /* strong and valid match */
3190 this_key_has_addr_match = false;
3191 match = false; /* any match */
3192
3193 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3194 mutt_addrlist_parse(&alist, k->uid);
3195 struct Address *ka = NULL;
3196 TAILQ_FOREACH(ka, &alist, entries)
3197 {
3198 int validity = crypt_id_matches_addr(a, ka, k);
3199
3200 if (validity & CRYPT_KV_MATCH) /* something matches */
3201 {
3202 match = true;
3203
3204 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3205 {
3206 if (validity & CRYPT_KV_STRONGID)
3207 {
3208 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3209 multi = true;
3210 this_key_has_strong = true;
3211 }
3212 else
3213 {
3214 this_key_has_addr_match = true;
3215 }
3216 }
3217 }
3218 }
3219 mutt_addrlist_clear(&alist);
3220
3221 if (match)
3222 {
3223 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3224 *matches_endp = tmp;
3225 matches_endp = &tmp->next;
3226
3227 if (this_key_has_strong)
3228 the_strong_valid_key = tmp;
3229 else if (this_key_has_addr_match)
3230 a_valid_addrmatch_key = tmp;
3231 }
3232 }
3233
3234 crypt_key_free(&keys);
3235
3236 if (matches)
3237 {
3238 if (oppenc_mode)
3239 {
3240 const bool c_crypt_opportunistic_encrypt_strong_keys =
3241 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3242 if (the_strong_valid_key)
3243 k = crypt_copy_key(the_strong_valid_key);
3244 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3245 k = crypt_copy_key(a_valid_addrmatch_key);
3246 else
3247 k = NULL;
3248 }
3249 else if (the_strong_valid_key && !multi)
3250 {
3251 /* There was precisely one strong match on a valid ID.
3252 * Proceed without asking the user. */
3253 k = crypt_copy_key(the_strong_valid_key);
3254 }
3255 else
3256 {
3257 /* Else: Ask the user. */
3258 k = dlg_gpgme(matches, a, NULL, app, forced_valid);
3259 }
3260
3261 crypt_key_free(&matches);
3262 }
3263 else
3264 {
3265 k = NULL;
3266 }
3267
3268 return k;
3269}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1461
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:478
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
Definition: crypt_gpgme.c:233
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:327
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:3121
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:2968
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
Definition: crypt_gpgme.c:137
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
Definition: crypt_gpgme.c:252
#define CRYPT_KV_MATCH
Definition: crypt_gpgme.c:77
struct CryptKeyInfo * dlg_gpgme(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:631
#define mutt_message(...)
Definition: logging2.h:91
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: logging2.h:47
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_getkeybystr()

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

Find a key by string.

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

Definition at line 3279 of file crypt_gpgme.c.

3281{
3282 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3283 struct CryptKeyInfo *matches = NULL;
3284 struct CryptKeyInfo **matches_endp = &matches;
3285 struct CryptKeyInfo *k = NULL;
3286 const char *ps = NULL, *pl = NULL, *phint = NULL;
3287
3288 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3289
3290 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3291 crypt_add_string_to_hints(phint, &hints);
3292 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3293 mutt_list_free(&hints);
3294
3295 if (!keys)
3296 {
3297 FREE(&pfcopy);
3298 return NULL;
3299 }
3300
3301 for (k = keys; k; k = k->next)
3302 {
3303 if (abilities && !(k->flags & abilities))
3304 continue;
3305
3306 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3307 crypt_long_keyid(k), k->uid);
3308
3309 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3310 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3311 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3312 {
3313 mutt_debug(LL_DEBUG5, "match\n");
3314
3315 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3316 *matches_endp = tmp;
3317 matches_endp = &tmp->next;
3318 }
3319 else
3320 {
3321 mutt_debug(LL_DEBUG5, "no match\n");
3322 }
3323 }
3324
3325 FREE(&pfcopy);
3326 crypt_key_free(&keys);
3327
3328 if (matches)
3329 {
3330 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3331 crypt_key_free(&matches);
3332 return k;
3333 }
3334
3335 return NULL;
3336}
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:1277
static const char * crypt_short_keyid(struct CryptKeyInfo *k)
Get the short keyID for a key.
Definition: crypt_gpgme.c:179
static const char * crypt_long_keyid(struct CryptKeyInfo *k)
Find the Long ID for the key.
Definition: crypt_gpgme.c:162
static const char * crypt_fpr(struct CryptKeyInfo *k)
Get the hexstring fingerprint from a key.
Definition: crypt_gpgme.c:198
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:810
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:593
+ 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 ( const char *  tag,
const 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 3350 of file crypt_gpgme.c.

3353{
3354 struct CryptKeyInfo *key = NULL;
3355 struct CryptCache *l = NULL;
3356 struct Buffer *resp = buf_pool_get();
3357
3359
3360 if (whatfor)
3361 {
3362 for (l = IdDefaults; l; l = l->next)
3363 {
3364 if (mutt_istr_equal(whatfor, l->what))
3365 {
3366 buf_strcpy(resp, l->dflt);
3367 break;
3368 }
3369 }
3370 }
3371
3372 while (true)
3373 {
3374 buf_reset(resp);
3375 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
3376 {
3377 goto done;
3378 }
3379
3380 if (whatfor)
3381 {
3382 if (l)
3383 {
3384 mutt_str_replace(&l->dflt, buf_string(resp));
3385 }
3386 else
3387 {
3388 l = mutt_mem_malloc(sizeof(struct CryptCache));
3389 l->next = IdDefaults;
3390 IdDefaults = l;
3391 l->what = mutt_str_dup(whatfor);
3392 l->dflt = buf_strdup(resp);
3393 }
3394 }
3395
3396 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3397 if (key)
3398 goto done;
3399
3400 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3401 }
3402
3403done:
3404 buf_pool_release(&resp);
3405 return key;
3406}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
static struct CryptCache * IdDefaults
Cache of GPGME keys.
Definition: crypt_gpgme.c:91
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:3279
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:275
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:54
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:55
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:73
Internal cache for GPGME.
Definition: crypt_gpgme.c:84
char * what
Definition: crypt_gpgme.c:85
char * dflt
Definition: crypt_gpgme.c:86
struct CryptCache * next
Definition: crypt_gpgme.c:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_keys()

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

3420{
3421 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3422 struct ListNode *crypt_hook = NULL;
3423 const char *keyid = NULL;
3424 char *keylist = NULL;
3425 size_t keylist_size = 0;
3426 size_t keylist_used = 0;
3427 struct Address *p = NULL;
3428 struct CryptKeyInfo *k_info = NULL;
3429 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3430 char buf[1024] = { 0 };
3431 bool forced_valid = false;
3432 bool key_selected;
3433 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3434
3435 struct Address *a = NULL;
3436 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3437 TAILQ_FOREACH(a, addrlist, entries)
3438 {
3439 key_selected = false;
3440 mutt_crypt_hook(&crypt_hook_list, a);
3441 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3442 do
3443 {
3444 p = a;
3445 forced_valid = false;
3446 k_info = NULL;
3447
3448 if (crypt_hook)
3449 {
3450 keyid = crypt_hook->data;
3451 enum QuadOption ans = MUTT_YES;
3452 if (!oppenc_mode && c_crypt_confirm_hook)
3453 {
3454 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3455 buf_string(p->mailbox));
3456 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3457 }
3458 if (ans == MUTT_YES)
3459 {
3460 if (crypt_is_numerical_keyid(keyid))
3461 {
3462 if (mutt_strn_equal(keyid, "0x", 2))
3463 keyid += 2;
3464 goto bypass_selection; /* you don't see this. */
3465 }
3466
3467 /* check for e-mail address */
3468 mutt_addrlist_clear(&hookal);
3469 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3470 {
3471 mutt_addrlist_qualify(&hookal, fqdn);
3472 p = TAILQ_FIRST(&hookal);
3473 }
3474 else if (!oppenc_mode)
3475 {
3476 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3477 }
3478 }
3479 else if (ans == MUTT_NO)
3480 {
3481 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3482 {
3483 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3484 continue;
3485 }
3486 }
3487 else if (ans == MUTT_ABORT)
3488 {
3489 FREE(&keylist);
3490 mutt_addrlist_clear(&hookal);
3491 mutt_list_free(&crypt_hook_list);
3492 return NULL;
3493 }
3494 }
3495
3496 if (!k_info)
3497 {
3498 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3499 }
3500
3501 if (!k_info && !oppenc_mode)
3502 {
3503 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3504
3505 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3506 KEYFLAG_CANENCRYPT, app, &forced_valid);
3507 }
3508
3509 if (!k_info)
3510 {
3511 FREE(&keylist);
3512 mutt_addrlist_clear(&hookal);
3513 mutt_list_free(&crypt_hook_list);
3514 return NULL;
3515 }
3516
3517 keyid = crypt_fpr_or_lkeyid(k_info);
3518
3519 bypass_selection:
3520 keylist_size += mutt_str_len(keyid) + 4 + 1;
3521 mutt_mem_realloc(&keylist, keylist_size);
3522 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3523 keyid, forced_valid ? "!" : "");
3524 keylist_used = mutt_str_len(keylist);
3525
3526 key_selected = true;
3527
3528 crypt_key_free(&k_info);
3529 mutt_addrlist_clear(&hookal);
3530
3531 if (crypt_hook)
3532 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3533
3534 } while (crypt_hook);
3535
3536 mutt_list_free(&crypt_hook_list);
3537 }
3538 return keylist;
3539}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:677
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition: crypt.c:1366
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:3145
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
Definition: crypt_gpgme.c:213
static struct CryptKeyInfo * crypt_ask_for_key(const char *tag, const char *whatfor, KeyFlags abilities, unsigned int app, bool *forced_valid)
Ask the user for a key.
Definition: crypt_gpgme.c:3350
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:837
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 query_yesorno_help(const char *prompt, enum QuadOption def, struct ConfigSubset *sub, const char *name)
Ask the user a Yes/No question offering help.
Definition: question.c:345
#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:705
+ 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 3570 of file crypt_gpgme.c.

3571{
3572 int rc = -1;
3573 gpgme_error_t err;
3574 gpgme_key_t key = NULL;
3575 gpgme_user_id_t uid = NULL;
3576 struct CryptKeyInfo *results = NULL, *k = NULL;
3577 struct CryptKeyInfo **kend = NULL;
3578 struct CryptKeyInfo *choice = NULL;
3579
3580 gpgme_ctx_t ctx = create_gpgme_context(false);
3581
3582 /* list all secret keys */
3583 if (gpgme_op_keylist_start(ctx, NULL, 1))
3584 goto cleanup;
3585
3586 kend = &results;
3587
3588 while (!(err = gpgme_op_keylist_next(ctx, &key)))
3589 {
3591
3596
3597 if (key->revoked)
3599 if (key->expired)
3601 if (key->disabled)
3603
3604 int idx;
3605 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3606 {
3607 k = mutt_mem_calloc(1, sizeof(*k));
3608 k->kobj = key;
3609 gpgme_key_ref(k->kobj);
3610 k->idx = idx;
3611 k->uid = uid->uid;
3612 k->flags = flags;
3613 if (uid->revoked)
3614 k->flags |= KEYFLAG_REVOKED;
3615 k->validity = uid->validity;
3616 *kend = k;
3617 kend = &k->next;
3618 }
3619 gpgme_key_unref(key);
3620 }
3621 if (gpg_err_code(err) != GPG_ERR_EOF)
3622 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3623 gpgme_op_keylist_end(ctx);
3624
3625 if (!results)
3626 {
3627 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3628 from. This error is displayed if no results were found. */
3629 mutt_error(_("No secret keys found"));
3630 goto cleanup;
3631 }
3632
3633 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3634 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3635 goto cleanup;
3636 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3637
3638 rc = 0;
3639
3640cleanup:
3641 crypt_key_free(&choice);
3642 crypt_key_free(&results);
3643 gpgme_release(ctx);
3644 return rc;
3645}
+ 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 3710 of file crypt_gpgme.c.

3711{
3712 /* this initialization should only run one time, but it may be called by
3713 * either pgp_gpgme_init or smime_gpgme_init */
3714 static bool has_run = false;
3715 if (has_run)
3716 return;
3717
3718 gpgme_check_version(NULL);
3719 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3720#ifdef ENABLE_NLS
3721 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3722#endif
3723 has_run = true;
3724}
+ Here is the caller graph for this function:

◆ init_pgp()

static void init_pgp ( void  )
static

Initialise the PGP crypto backend.

Definition at line 3729 of file crypt_gpgme.c.

3730{
3731 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3732 {
3733 mutt_error(_("GPGME: OpenPGP protocol not available"));
3734 }
3735}
+ Here is the caller graph for this function:

◆ init_smime()

static void init_smime ( void  )
static

Initialise the SMIME crypto backend.

Definition at line 3740 of file crypt_gpgme.c.

3741{
3742 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3743 {
3744 mutt_error(_("GPGME: CMS protocol not available"));
3745 }
3746}
+ 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 3772 of file crypt_gpgme.c.

3773{
3774 struct CryptKeyInfo *p = NULL;
3775 const char *prompt = NULL;
3776 const char *letters = NULL;
3777 const char *choices = NULL;
3778 int choice;
3779
3780 if (is_smime)
3782 else
3784
3785 /* Opportunistic encrypt is controlling encryption.
3786 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3787 * letter choices for those.
3788 */
3789 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3790 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3791 {
3792 if (is_smime)
3793 {
3794 /* L10N: S/MIME options (opportunistic encryption is on) */
3795 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3796 /* L10N: S/MIME options (opportunistic encryption is on) */
3797 letters = _("sapco");
3798 choices = "SapCo";
3799 }
3800 else
3801 {
3802 /* L10N: PGP options (opportunistic encryption is on) */
3803 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3804 /* L10N: PGP options (opportunistic encryption is on) */
3805 letters = _("samco");
3806 choices = "SamCo";
3807 }
3808 }
3809 else if (c_crypt_opportunistic_encrypt)
3810 {
3811 /* Opportunistic encryption option is set, but is toggled off for this message. */
3812 if (is_smime)
3813 {
3814 /* L10N: S/MIME options (opportunistic encryption is off) */
3815 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3816 /* L10N: S/MIME options (opportunistic encryption is off) */
3817 letters = _("esabpco");
3818 choices = "esabpcO";
3819 }
3820 else
3821 {
3822 /* L10N: PGP options (opportunistic encryption is off) */
3823 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3824 /* L10N: PGP options (opportunistic encryption is off) */
3825 letters = _("esabmco");
3826 choices = "esabmcO";
3827 }
3828 }
3829 else
3830 {
3831 /* Opportunistic encryption is unset */
3832 if (is_smime)
3833 {
3834 /* L10N: S/MIME options */
3835 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
3836 /* L10N: S/MIME options */
3837 letters = _("esabpc");
3838 choices = "esabpc";
3839 }
3840 else
3841 {
3842 /* L10N: PGP options */
3843 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
3844 /* L10N: PGP options */
3845 letters = _("esabmc");
3846 choices = "esabmc";
3847 }
3848 }
3849
3850 choice = mw_multi_choice(prompt, letters);
3851 if (choice > 0)
3852 {
3853 switch (choices[choice - 1])
3854 {
3855 case 'a': /* sign (a)s */
3856 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3857 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
3858 if (p)
3859 {
3860 char input_signas[128] = { 0 };
3861 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
3862
3863 if (is_smime)
3864 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", input_signas, NULL);
3865 else
3866 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
3867
3868 crypt_key_free(&p);
3869
3870 e->security |= SEC_SIGN;
3871 }
3872 break;
3873
3874 case 'b': /* (b)oth */
3875 e->security |= (SEC_ENCRYPT | SEC_SIGN);
3876 break;
3877
3878 case 'C':
3879 e->security &= ~SEC_SIGN;
3880 break;
3881
3882 case 'c': /* (c)lear */
3883 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
3884 break;
3885
3886 case 'e': /* (e)ncrypt */
3887 e->security |= SEC_ENCRYPT;
3888 e->security &= ~SEC_SIGN;
3889 break;
3890
3891 case 'm': /* (p)gp or s/(m)ime */
3892 case 'p':
3893 is_smime = !is_smime;
3894 if (is_smime)
3895 {
3896 e->security &= ~APPLICATION_PGP;
3898 }
3899 else
3900 {
3901 e->security &= ~APPLICATION_SMIME;
3903 }
3905 break;
3906
3907 case 'O': /* oppenc mode on */
3910 break;
3911
3912 case 'o': /* oppenc mode off */
3913 e->security &= ~SEC_OPPENCRYPT;
3914 break;
3915
3916 case 'S': /* (s)ign in oppenc mode */
3917 e->security |= SEC_SIGN;
3918 break;
3919
3920 case 's': /* (s)ign */
3921 e->security &= ~SEC_ENCRYPT;
3922 e->security |= SEC_SIGN;
3923 break;
3924 }
3925 }
3926
3927 return e->security;
3928}
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1034
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition: question.c:60
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:87
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:79
#define SEC_SIGN
Email is signed.
Definition: lib.h:80
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:407
+ 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 3951 of file crypt_gpgme.c.

3952{
3953 struct Address *sender = NULL;
3954 bool rc = true;
3955
3956 if (!TAILQ_EMPTY(&e->env->from))
3957 {
3959 sender = TAILQ_FIRST(&e->env->from);
3960 }
3961 else if (!TAILQ_EMPTY(&e->env->sender))
3962 {
3964 sender = TAILQ_FIRST(&e->env->sender);
3965 }
3966
3967 if (sender)
3968 {
3969 if (SignatureKey)
3970 {
3971 gpgme_key_t key = SignatureKey;
3972 gpgme_user_id_t uid = NULL;
3973 int sender_length = buf_len(sender->mailbox);
3974 for (uid = key->uids; uid && rc; uid = uid->next)
3975 {
3976 int uid_length = strlen(uid->email);
3977 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
3978 (uid_length == (sender_length + 2)))
3979 {
3980 const char *at_sign = strchr(uid->email + 1, '@');
3981 if (at_sign)
3982 {
3983 /* Assume address is 'mailbox@domainname'.
3984 * The mailbox part is case-sensitive,
3985 * the domainname is not. (RFC2821) */
3986 const char *tmp_email = uid->email + 1;
3987 const char *tmp_sender = buf_string(sender->mailbox);
3988 /* length of mailbox part including '@' */
3989 int mailbox_length = at_sign - tmp_email + 1;
3990 int domainname_length = sender_length - mailbox_length;
3991 int mailbox_match, domainname_match;
3992
3993 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
3994 tmp_email += mailbox_length;
3995 tmp_sender += mailbox_length;
3996 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
3997 if (mailbox_match && domainname_match)
3998 rc = false;
3999 }
4000 else
4001 {
4002 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4003 rc = false;
4004 }
4005 }
4006 }
4007 }
4008 else
4009 {
4010 mutt_any_key_to_continue(_("Failed to verify sender"));
4011 }
4012 }
4013 else
4014 {
4015 mutt_any_key_to_continue(_("Failed to figure out sender"));
4016 }
4017
4018 if (SignatureKey)
4019 {
4020 gpgme_key_unref(SignatureKey);
4021 SignatureKey = NULL;
4022 }
4023
4024 return rc;
4025}
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:298
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:466
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:188
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:511
#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 4049 of file crypt_gpgme.c.

4050{
4051 return GPGME_VERSION;
4052}
+ Here is the caller graph for this function:

Variable Documentation

◆ IdDefaults

struct CryptCache* IdDefaults = NULL
static

Cache of GPGME keys.

Definition at line 91 of file crypt_gpgme.c.

◆ SignatureKey

gpgme_key_t SignatureKey = NULL
static

PGP Key to sign with.

Definition at line 93 of file crypt_gpgme.c.

◆ CurrentSender

char* CurrentSender = NULL
static

Email address of the sender.

Definition at line 95 of file crypt_gpgme.c.