NeoMutt  2023-03-22
Teaching an old dog new tricks
DOXYGEN
crypt_gpgme.c File Reference

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

#include "config.h"
#include <errno.h>
#include <gpg-error.h>
#include <gpgme.h>
#include <langinfo.h>
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "crypt_gpgme.h"
#include "lib.h"
#include "attach/lib.h"
#include "enter/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "crypt.h"
#include "globals.h"
#include "handler.h"
#include "hook.h"
#include "mutt_logging.h"
#include "muttlib.h"
#include "autocrypt/lib.h"
+ Include dependency graph for crypt_gpgme.c:

Go to the source code of this file.

Data Structures

struct  CryptCache
 Internal cache for GPGME. More...
 

Macros

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

Functions

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

Variables

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

Detailed Description

Wrapper for PGP/SMIME calls to GPGME.

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

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file crypt_gpgme.c.

Macro Definition Documentation

◆ CRYPT_KV_VALID

#define CRYPT_KV_VALID   (1 << 0)

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

◆ _LINE_COMPARE

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

Definition at line 96 of file crypt_gpgme.c.

◆ MESSAGE

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

Definition at line 97 of file crypt_gpgme.c.

◆ SIGNED_MESSAGE

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

Definition at line 98 of file crypt_gpgme.c.

◆ PUBLIC_KEY_BLOCK

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

Definition at line 99 of file crypt_gpgme.c.

◆ BEGIN_PGP_SIGNATURE

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

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

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

◆ redraw_if_needed()

static void redraw_if_needed ( gpgme_ctx_t  ctx)
static

Accommodate for a redraw if needed.

Parameters
ctxGPGME handle

Definition at line 117 of file crypt_gpgme.c.

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

135{
136 const char *s = "????????";
137
138 if (k->kobj && k->kobj->subkeys)
139 {
140 s = k->kobj->subkeys->keyid;
141 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
142 if ((!c_pgp_long_ids) && (strlen(s) == 16))
143 {
144 /* Return only the short keyID. */
145 s += 8;
146 }
147 }
148
149 return s;
150}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
gpgme_key_t kobj
Definition: crypt_gpgme.h:46
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_long_keyid()

static const char * crypt_long_keyid ( struct CryptKeyInfo k)
static

Find the Long ID for the key.

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

Return the long keyID for the key K.

Definition at line 159 of file crypt_gpgme.c.

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

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

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

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

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

250{
251 if (!keylist)
252 return;
253
254 struct CryptKeyInfo *k = NULL;
255
256 while (*keylist)
257 {
258 k = *keylist;
259 *keylist = (*keylist)->next;
260
261 gpgme_key_unref(k->kobj);
262 FREE(&k);
263 }
264}
#define FREE(x)
Definition: memory.h:43
struct CryptKeyInfo * next
Linked list.
Definition: crypt_gpgme.h:45
+ Here is the caller graph for this function:

◆ crypt_id_is_strong()

bool crypt_id_is_strong ( struct CryptKeyInfo key)

Is the key strong.

Parameters
keyKey to test
Return values
trueValidity of key is sufficient

Definition at line 271 of file crypt_gpgme.c.

272{
273 if (!key)
274 return false;
275
276 bool is_strong = false;
277
278 if ((key->flags & KEYFLAG_ISX509))
279 return true;
280
281 switch (key->validity)
282 {
283 case GPGME_VALIDITY_MARGINAL:
284 case GPGME_VALIDITY_NEVER:
285 case GPGME_VALIDITY_UNDEFINED:
286 case GPGME_VALIDITY_UNKNOWN:
287 is_strong = false;
288 break;
289
290 case GPGME_VALIDITY_FULL:
291 case GPGME_VALIDITY_ULTIMATE:
292 is_strong = true;
293 break;
294 }
295
296 return is_strong;
297}
#define KEYFLAG_ISX509
Key is an X.509 key.
Definition: lib.h:129
+ Here is the caller graph for this function:

◆ crypt_id_is_valid()

int crypt_id_is_valid ( struct CryptKeyInfo key)

Is key ID valid.

Parameters
keyKey to test
Return values
trueKey is valid

When the key is not marked as unusable

Definition at line 306 of file crypt_gpgme.c.

307{
308 if (!key)
309 return 0;
310
311 return !(key->flags & KEYFLAG_CANTUSE);
312}
#define KEYFLAG_CANTUSE
Definition: lib.h:139
+ Here is the caller graph for this function:

◆ crypt_id_matches_addr()

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

Does the key ID match the address.

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

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

Definition at line 324 of file crypt_gpgme.c.

326{
327 int rc = 0;
328
329 if (crypt_id_is_valid(key))
330 rc |= CRYPT_KV_VALID;
331
332 if (crypt_id_is_strong(key))
333 rc |= CRYPT_KV_STRONGID;
334
335 if (addr && u_addr)
336 {
337 if (addr->mailbox && u_addr->mailbox &&
338 mutt_istr_equal(addr->mailbox, u_addr->mailbox))
339 {
340 rc |= CRYPT_KV_ADDR;
341 }
342
343 if (addr->personal && u_addr->personal &&
344 mutt_istr_equal(addr->personal, u_addr->personal))
345 {
346 rc |= CRYPT_KV_STRING;
347 }
348 }
349
350 return rc;
351}
#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:306
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
Definition: crypt_gpgme.c:271
#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
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
char * mailbox
Mailbox and host address.
Definition: address.h:38
char * personal
Real name of address.
Definition: address.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ create_gpgme_context()

gpgme_ctx_t create_gpgme_context ( bool  for_smime)

Create a new GPGME context.

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

Definition at line 358 of file crypt_gpgme.c.

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

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

417{
418 int err = 0;
419 gpgme_data_t data = NULL;
420
421 struct Buffer *tempfile = mutt_buffer_pool_get();
422 mutt_buffer_mktemp(tempfile);
423 FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
424 if (!fp_tmp)
425 {
427 goto cleanup;
428 }
429
431 fputc('\n', fp_tmp);
432 mutt_write_mime_body(a, fp_tmp, NeoMutt->sub);
433
434 if (convert)
435 {
436 int c, hadcr = 0;
437 unsigned char buf[1];
438
440 rewind(fp_tmp);
441 while ((c = fgetc(fp_tmp)) != EOF)
442 {
443 if (c == '\r')
444 hadcr = 1;
445 else
446 {
447 if ((c == '\n') && !hadcr)
448 {
449 buf[0] = '\r';
450 gpgme_data_write(data, buf, 1);
451 }
452
453 hadcr = 0;
454 }
455 /* FIXME: This is quite suboptimal */
456 buf[0] = c;
457 gpgme_data_write(data, buf, 1);
458 }
459 mutt_file_fclose(&fp_tmp);
460 gpgme_data_seek(data, 0, SEEK_SET);
461 }
462 else
463 {
464 mutt_file_fclose(&fp_tmp);
465 err = gpgme_data_new_from_file(&data, mutt_buffer_string(tempfile), 1);
466 if (err != 0)
467 {
468 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
469 gpgme_data_release(data);
470 data = NULL;
471 /* fall through to unlink the tempfile */
472 }
473 }
474 unlink(mutt_buffer_string(tempfile));
475
476cleanup:
477 mutt_buffer_pool_release(&tempfile);
478 return data;
479}
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
Definition: crypt_gpgme.c:397
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:634
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:151
#define mutt_perror(...)
Definition: logging.h:88
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:748
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ file_to_data_object()

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

Create GPGME data object from file.

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

Definition at line 488 of file crypt_gpgme.c.

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

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

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

614{
615 unsigned int n = 0;
616
617 const char *s = keylist;
618 do
619 {
620 while (*s == ' ')
621 s++;
622 if (*s != '\0')
623 {
624 if (n == 0)
625 {
626 if (!use_smime)
627 mutt_buffer_addstr(recpstring, "--\n");
628 }
629 else
630 mutt_buffer_addch(recpstring, '\n');
631 n++;
632
633 while ((*s != '\0') && (*s != ' '))
634 mutt_buffer_addch(recpstring, *s++);
635 }
636 } while (*s != '\0');
637}
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_signer_from_address()

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

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

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

Definition at line 647 of file crypt_gpgme.c.

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

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

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

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

842{
843 gpgme_sign_result_t result = NULL;
844 const char *algorithm_name = NULL;
845
846 if (buflen < 5)
847 return -1;
848
849 *buf = '\0';
850 result = gpgme_op_sign_result(ctx);
851 if (result && result->signatures)
852 {
853 algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
854 if (algorithm_name)
855 {
856 if (use_smime)
857 {
858 /* convert GPGME raw hash name to RFC2633 format */
859 snprintf(buf, buflen, "%s", algorithm_name);
860 mutt_str_lower(buf);
861 }
862 else
863 {
864 /* convert GPGME raw hash name to RFC3156 format */
865 snprintf(buf, buflen, "pgp-%s", algorithm_name);
866 mutt_str_lower(buf + 4);
867 }
868 }
869 }
870
871 return (buf[0] != '\0') ? 0 : -1;
872}
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition: string.c:384
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ print_time()

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

Print the date/time according to the locale.

Parameters
tTimestamp
stateState to write to

Definition at line 879 of file crypt_gpgme.c.

880{
881 char p[256] = { 0 };
882 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
883 state_puts(state, p);
884}
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:698
#define state_puts(STATE, STR)
Definition: state.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ sign_message()

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

Sign a message.

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

Definition at line 894 of file crypt_gpgme.c.

895{
896 struct Body *t = NULL;
897 char *sigfile = NULL;
898 int err = 0;
899 char buf[100] = { 0 };
900 gpgme_ctx_t ctx = NULL;
901 gpgme_data_t message = NULL, signature = NULL;
902 gpgme_sign_result_t sigres = NULL;
903
904 crypt_convert_to_7bit(a); /* Signed data _must_ be in 7-bit format. */
905
906 message = body_to_data_object(a, true);
907 if (!message)
908 return NULL;
909 signature = create_gpgme_data();
910
911 ctx = create_gpgme_context(use_smime);
912 if (!use_smime)
913 gpgme_set_armor(ctx, 1);
914
915 if (set_signer(ctx, from, use_smime))
916 {
917 gpgme_data_release(signature);
918 gpgme_data_release(message);
919 gpgme_release(ctx);
920 return NULL;
921 }
922
923 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
924 if (c_crypt_use_pka)
925 {
926 err = set_pka_sig_notation(ctx);
927 if (err != 0)
928 {
929 gpgme_data_release(signature);
930 gpgme_data_release(message);
931 gpgme_release(ctx);
932 return NULL;
933 }
934 }
935
936 err = gpgme_op_sign(ctx, message, signature, GPGME_SIG_MODE_DETACH);
937 redraw_if_needed(ctx);
938 gpgme_data_release(message);
939 if (err != 0)
940 {
941 gpgme_data_release(signature);
942 gpgme_release(ctx);
943 mutt_error(_("error signing data: %s"), gpgme_strerror(err));
944 return NULL;
945 }
946 /* Check for zero signatures generated. This can occur when $pgp_sign_as is
947 * unset and there is no default key specified in ~/.gnupg/gpg.conf */
948 sigres = gpgme_op_sign_result(ctx);
949 if (!sigres->signatures)
950 {
951 gpgme_data_release(signature);
952 gpgme_release(ctx);
953 mutt_error(_("$pgp_sign_as unset and no default key specified in ~/.gnupg/gpg.conf"));
954 return NULL;
955 }
956
957 sigfile = data_object_to_tempfile(signature, NULL);
958 gpgme_data_release(signature);
959 if (!sigfile)
960 {
961 gpgme_release(ctx);
962 return NULL;
963 }
964
965 t = mutt_body_new();
966 t->type = TYPE_MULTIPART;
967 t->subtype = mutt_str_dup("signed");
968 t->encoding = ENC_7BIT;
969 t->use_disp = false;
971
973 mutt_param_set(&t->parameter, "protocol",
974 use_smime ? "application/pkcs7-signature" : "application/pgp-signature");
975 /* Get the micalg from GPGME. Old gpgme versions don't support this
976 * for S/MIME so we assume sha-1 in this case. */
977 if (get_micalg(ctx, use_smime, buf, sizeof(buf)) == 0)
978 mutt_param_set(&t->parameter, "micalg", buf);
979 else if (use_smime)
980 mutt_param_set(&t->parameter, "micalg", "sha1");
981 gpgme_release(ctx);
982
983 t->parts = a;
984 a = t;
985
986 t->parts->next = mutt_body_new();
987 t = t->parts->next;
989 if (use_smime)
990 {
991 t->subtype = mutt_str_dup("pkcs7-signature");
992 mutt_param_set(&t->parameter, "name", "smime.p7s");
993 t->encoding = ENC_BASE64;
994 t->use_disp = true;
996 t->d_filename = mutt_str_dup("smime.p7s");
997 }
998 else
999 {
1000 t->subtype = mutt_str_dup("pgp-signature");
1001 mutt_param_set(&t->parameter, "name", "signature.asc");
1002 t->use_disp = false;
1004 t->encoding = ENC_7BIT;
1005 }
1006 t->filename = sigfile;
1007 t->unlink = true; /* ok to remove this file after sending. */
1008
1009 return a;
1010}
void crypt_convert_to_7bit(struct Body *a)
Convert an email to 7bit encoding.
Definition: crypt.c:793
static gpgme_data_t body_to_data_object(struct Body *a, bool convert)
Create GPGME object from the mail body.
Definition: crypt_gpgme.c:416
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:841
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
@ ENC_7BIT
7-bit text
Definition: mime.h:49
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ DISP_ATTACH
Content is attached.
Definition: mime.h:63
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
@ DISP_NONE
No preferred disposition.
Definition: mime.h:65
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:86
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
The body of an email.
Definition: body.h:36
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition: body.h:56
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:67
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:47
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
struct Body * next
next attachment in the list
Definition: body.h:71
char * subtype
content-type subtype
Definition: body.h:60
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ show_sig_summary()

static int show_sig_summary ( unsigned long  sum,
gpgme_ctx_t  ctx,
gpgme_key_t  key,
int  idx,
struct State 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 1121 of file crypt_gpgme.c.

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

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

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

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

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

◆ verify_one()

static int verify_one ( struct Body sigbdy,
struct State 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 1533 of file crypt_gpgme.c.

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

◆ decrypt_part()

static struct Body * decrypt_part ( struct Body a,
struct State 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 1686 of file crypt_gpgme.c.

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

◆ pgp_gpgme_extract_keys()

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

Write PGP keys to a file.

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

Definition at line 2058 of file crypt_gpgme.c.

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

◆ line_compare()

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

Compare two strings ignore line endings.

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

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

Definition at line 2142 of file crypt_gpgme.c.

2143{
2144 if (mutt_strn_equal(a, b, n))
2145 {
2146 /* at this point we know that 'b' is at least 'n' chars long */
2147 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2148 return true;
2149 }
2150 return false;
2151}
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:496
+ Here is the call graph for this function:

◆ pgp_check_traditional_one_body()

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

Check one inline PGP body part.

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

Definition at line 2160 of file crypt_gpgme.c.

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

◆ copy_clearsigned()

static void copy_clearsigned ( gpgme_data_t  data,
struct State 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 2359 of file crypt_gpgme.c.

2360{
2361 char buf[8192] = { 0 };
2362 bool complete, armor_header;
2363 FILE *fp = NULL;
2364
2365 char *fname = data_object_to_tempfile(data, &fp);
2366 if (!fname)
2367 {
2368 mutt_file_fclose(&fp);
2369 return;
2370 }
2371 unlink(fname);
2372 FREE(&fname);
2373
2374 /* fromcode comes from the MIME Content-Type charset label. It might
2375 * be a wrong label, so we want the ability to do corrections via
2376 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2377 const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
2378 struct FgetConv *fc = mutt_ch_fgetconv_open(fp, charset, c_charset, MUTT_ICONV_HOOK_FROM);
2379
2380 for (complete = true, armor_header = true;
2381 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2382 {
2383 if (!complete)
2384 {
2385 if (!armor_header)
2386 state_puts(state, buf);
2387 continue;
2388 }
2389
2390 if (BEGIN_PGP_SIGNATURE(buf))
2391 break;
2392
2393 if (armor_header)
2394 {
2395 if (buf[0] == '\n')
2396 armor_header = false;
2397 continue;
2398 }
2399
2400 if (state->prefix)
2401 state_puts(state, state->prefix);
2402
2403 if ((buf[0] == '-') && (buf[1] == ' '))
2404 state_puts(state, buf + 2);
2405 else
2406 state_puts(state, buf);
2407 }
2408
2411}
#define BEGIN_PGP_SIGNATURE(_y)
Definition: crypt_gpgme.c:100
void mutt_ch_fgetconv_close(struct FgetConv **fc)
Close an fgetconv handle.
Definition: charset.c:887
struct FgetConv * mutt_ch_fgetconv_open(FILE *fp, const char *from, const char *to, uint8_t flags)
Prepare a file for charset conversion.
Definition: charset.c:857
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition: charset.c:969
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:72
Cursor for converting a file's encoding.
Definition: charset.h:41
FILE * fp
Definition: charset.h:42
char * prefix
String to add to the beginning of each output line.
Definition: state.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ key_check_cap()

unsigned int key_check_cap ( gpgme_key_t  key,
enum KeyCap  cap 
)

Check the capabilities of a key.

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

Definition at line 2836 of file crypt_gpgme.c.

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

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

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

◆ crypt_add_string_to_hints()

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

Split a string and add the parts to a List.

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

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

Definition at line 3108 of file crypt_gpgme.c.

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

3135{
3136 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3137
3138 int multi = false;
3139 int this_key_has_strong = false;
3140 int this_key_has_addr_match = false;
3141 int match = false;
3142
3143 struct CryptKeyInfo *keys = NULL, *k = NULL;
3144 struct CryptKeyInfo *the_strong_valid_key = NULL;
3145 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3146 struct CryptKeyInfo *matches = NULL;
3147 struct CryptKeyInfo **matches_endp = &matches;
3148
3149 if (a && a->mailbox)
3151 if (a && a->personal)
3153
3154 if (!oppenc_mode)
3155 mutt_message(_("Looking for keys matching \"%s\"..."), a ? a->mailbox : "");
3156 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3157
3158 mutt_list_free(&hints);
3159
3160 if (!keys)
3161 return NULL;
3162
3163 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n", a ? NONULL(a->personal) : "",
3164 a ? NONULL(a->mailbox) : "");
3165
3166 for (k = keys; k; k = k->next)
3167 {
3168 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3169
3170 if (abilities && !(k->flags & abilities))
3171 {
3172 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3173 continue;
3174 }
3175
3176 this_key_has_strong = false; /* strong and valid match */
3177 this_key_has_addr_match = false;
3178 match = false; /* any match */
3179
3180 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3181 mutt_addrlist_parse(&alist, k->uid);
3182 struct Address *ka = NULL;
3183 TAILQ_FOREACH(ka, &alist, entries)
3184 {
3185 int validity = crypt_id_matches_addr(a, ka, k);
3186
3187 if (validity & CRYPT_KV_MATCH) /* something matches */
3188 {
3189 match = true;
3190
3191 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3192 {
3193 if (validity & CRYPT_KV_STRONGID)
3194 {
3195 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3196 multi = true;
3197 this_key_has_strong = true;
3198 }
3199 else
3200 this_key_has_addr_match = true;
3201 }
3202 }
3203 }
3204 mutt_addrlist_clear(&alist);
3205
3206 if (match)
3207 {
3208 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3209 *matches_endp = tmp;
3210 matches_endp = &tmp->next;
3211
3212 if (this_key_has_strong)
3213 the_strong_valid_key = tmp;
3214 else if (this_key_has_addr_match)
3215 a_valid_addrmatch_key = tmp;
3216 }
3217 }
3218
3219 crypt_key_free(&keys);
3220
3221 if (matches)
3222 {
3223 if (oppenc_mode)
3224 {
3225 const bool c_crypt_opportunistic_encrypt_strong_keys =
3226 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3227 if (the_strong_valid_key)
3228 k = crypt_copy_key(the_strong_valid_key);
3229 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3230 k = crypt_copy_key(a_valid_addrmatch_key);
3231 else
3232 k = NULL;
3233 }
3234 else if (the_strong_valid_key && !multi)
3235 {
3236 /* There was precisely one strong match on a valid ID.
3237 * Proceed without asking the user. */
3238 k = crypt_copy_key(the_strong_valid_key);
3239 }
3240 else
3241 {
3242 /* Else: Ask the user. */
3243 k = dlg_select_gpgme_key(matches, a, NULL, app, forced_valid);
3244 }
3245
3246 crypt_key_free(&matches);
3247 }
3248 else
3249 k = NULL;
3250
3251 return k;
3252}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1435
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
Definition: crypt_gpgme.c:230
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:324
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:3108
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:2955
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
Definition: crypt_gpgme.c:134
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
Definition: crypt_gpgme.c:249
#define CRYPT_KV_MATCH
Definition: crypt_gpgme.c:77
struct CryptKeyInfo * dlg_select_gpgme_key(struct CryptKeyInfo *keys, struct Address *p, const char *s, unsigned int app, bool *forced_valid)
Get the user to select a key.
Definition: dlg_gpgme.c:674
#define mutt_message(...)
Definition: logging.h:86
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
@ LL_DEBUG5
Log at debug level 5.
Definition: logging.h:44
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define NONULL(x)
Definition: string2.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_getkeybystr()

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

Find a key by string.

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

Definition at line 3262 of file crypt_gpgme.c.

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

◆ crypt_ask_for_key()

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

Ask the user for a key.

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

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

Definition at line 3333 of file crypt_gpgme.c.

3335{
3336 struct CryptKeyInfo *key = NULL;
3337 struct CryptCache *l = NULL;
3338 struct Buffer *resp = mutt_buffer_pool_get();
3339
3341
3342 if (whatfor)
3343 {
3344 for (l = id_defaults; l; l = l->next)
3345 {
3346 if (mutt_istr_equal(whatfor, l->what))
3347 {
3348 mutt_buffer_strcpy(resp, l->dflt);
3349 break;
3350 }
3351 }
3352 }
3353
3354 while (true)
3355 {
3356 mutt_buffer_reset(resp);
3357 if (mutt_buffer_get_field(tag, resp, MUTT_COMP_NO_FLAGS, false, NULL, NULL, NULL) != 0)
3358 {
3359 goto done;
3360 }
3361
3362 if (whatfor)
3363 {
3364 if (l)
3366 else
3367 {
3368 l = mutt_mem_malloc(sizeof(struct CryptCache));
3369 l->next = id_defaults;
3370 id_defaults = l;
3371 l->what = mutt_str_dup(whatfor);
3372 l->dflt = mutt_buffer_strdup(resp);
3373 }
3374 }
3375
3376 key = crypt_getkeybystr(mutt_buffer_string(resp), abilities, app, forced_valid);
3377 if (key)
3378 goto done;
3379
3380 mutt_error(_("No matching keys found for \"%s\""), mutt_buffer_string(resp));
3381 }
3382
3383done:
3385 return key;
3386}
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:365
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
static struct CryptCache * id_defaults
Definition: crypt_gpgme.c:90
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:3262
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:178
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h: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 3399 of file crypt_gpgme.c.

3400{
3401 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3402 struct ListNode *crypt_hook = NULL;
3403 const char *keyid = NULL;
3404 char *keylist = NULL;
3405 size_t keylist_size = 0;
3406 size_t keylist_used = 0;
3407 struct Address *p = NULL;
3408 struct CryptKeyInfo *k_info = NULL;
3409 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3410 char buf[1024] = { 0 };
3411 bool forced_valid = false;
3412 bool key_selected;
3413 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3414
3415 struct Address *a = NULL;
3416 TAILQ_FOREACH(a, addrlist, entries)
3417 {
3418 key_selected = false;
3419 mutt_crypt_hook(&crypt_hook_list, a);
3420 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3421 do
3422 {
3423 p = a;
3424 forced_valid = false;
3425 k_info = NULL;
3426
3427 if (crypt_hook)
3428 {
3429 keyid = crypt_hook->data;
3430 enum QuadOption ans = MUTT_YES;
3431 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3432 if (!oppenc_mode && c_crypt_confirm_hook)
3433 {
3434 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid, p->mailbox);
3435 ans = mutt_yesorno(buf, MUTT_YES);
3436 }
3437 if (ans == MUTT_YES)
3438 {
3439 if (crypt_is_numerical_keyid(keyid))
3440 {
3441 if (mutt_strn_equal(keyid, "0x", 2))
3442 keyid += 2;
3443 goto bypass_selection; /* you don't see this. */
3444 }
3445
3446 /* check for e-mail address */
3447 mutt_addrlist_clear(&hookal);
3448 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3449 {
3450 mutt_addrlist_qualify(&hookal, fqdn);
3451 p = TAILQ_FIRST(&hookal);
3452 }
3453 else if (!oppenc_mode)
3454 {
3455 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3456 }
3457 }
3458 else if (ans == MUTT_NO)
3459 {
3460 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3461 {
3462 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3463 continue;
3464 }
3465 }
3466 else if (ans == MUTT_ABORT)
3467 {
3468 FREE(&keylist);
3469 mutt_addrlist_clear(&hookal);
3470 mutt_list_free(&crypt_hook_list);
3471 return NULL;
3472 }
3473 }
3474
3475 if (!k_info)
3476 {
3477 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3478 }
3479
3480 if (!k_info && !oppenc_mode)
3481 {
3482 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), p->mailbox);
3483
3484 k_info = crypt_ask_for_key(buf, p->mailbox, KEYFLAG_CANENCRYPT, app, &forced_valid);
3485 }
3486
3487 if (!k_info)
3488 {
3489 FREE(&keylist);
3490 mutt_addrlist_clear(&hookal);
3491 mutt_list_free(&crypt_hook_list);
3492 return NULL;
3493 }
3494
3495 keyid = crypt_fpr_or_lkeyid(k_info);
3496
3497 bypass_selection:
3498 keylist_size += mutt_str_len(keyid) + 4 + 1;
3499 mutt_mem_realloc(&keylist, keylist_size);
3500 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3501 keyid, forced_valid ? "!" : "");
3502 keylist_used = mutt_str_len(keylist);
3503
3504 key_selected = true;
3505
3506 crypt_key_free(&k_info);
3507 mutt_addrlist_clear(&hookal);
3508
3509 if (crypt_hook)
3510 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3511
3512 } while (crypt_hook);
3513
3514 mutt_list_free(&crypt_hook_list);
3515 }
3516 return keylist;
3517}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:650
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition: crypt.c:1351
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:3132
static struct CryptKeyInfo * crypt_ask_for_key(char *tag, char *whatfor, KeyFlags abilities, unsigned int app, bool *forced_valid)
Ask the user for a key.
Definition: crypt_gpgme.c:3333
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
Definition: crypt_gpgme.c:210
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:832
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:696
+ 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 3548 of file crypt_gpgme.c.

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

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

◆ init_pgp()

static void init_pgp ( void  )
static

Initialise the PGP crypto backend.

Definition at line 3707 of file crypt_gpgme.c.

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

◆ init_smime()

static void init_smime ( void  )
static

Initialise the SMIME crypto backend.

Definition at line 3718 of file crypt_gpgme.c.

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

3751{
3752 struct CryptKeyInfo *p = NULL;
3753 const char *prompt = NULL;
3754 const char *letters = NULL;
3755 const char *choices = NULL;
3756 int choice;
3757
3758 if (is_smime)
3760 else
3762
3763 /* Opportunistic encrypt is controlling encryption.
3764 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3765 * letter choices for those.
3766 */
3767 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3768 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3769 {
3770 if (is_smime)
3771 {
3772 /* L10N: S/MIME options (opportunistic encryption is on) */
3773 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3774 /* L10N: S/MIME options (opportunistic encryption is on) */
3775 letters = _("sapco");
3776 choices = "SapCo";
3777 }
3778 else
3779 {
3780 /* L10N: PGP options (opportunistic encryption is on) */
3781 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3782 /* L10N: PGP options (opportunistic encryption is on) */
3783 letters = _("samco");
3784 choices = "SamCo";
3785 }
3786 }
3787 /* Opportunistic encryption option is set, but is toggled off for this message. */
3788 else if (c_crypt_opportunistic_encrypt)
3789 {
3790 if (is_smime)
3791 {
3792 /* L10N: S/MIME options (opportunistic encryption is off) */
3793 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3794 /* L10N: S/MIME options (opportunistic encryption is off) */
3795 letters = _("esabpco");
3796 choices = "esabpcO";
3797 }
3798 else
3799 {
3800 /* L10N: PGP options (opportunistic encryption is off) */
3801 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3802 /* L10N: PGP options (opportunistic encryption is off) */
3803 letters = _("esabmco");
3804 choices = "esabmcO";
3805 }
3806 }
3807 /* Opportunistic encryption is unset */
3808 else
3809 {
3810 if (is_smime)
3811 {
3812 /* L10N: S/MIME options */
3813 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
3814 /* L10N: S/MIME options */
3815 letters = _("esabpc");
3816 choices = "esabpc";
3817 }
3818 else
3819 {
3820 /* L10N: PGP options */
3821 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
3822 /* L10N: PGP options */
3823 letters = _("esabmc");
3824 choices = "esabmc";
3825 }
3826 }
3827
3828 choice = mutt_multi_choice(prompt, letters);
3829 if (choice > 0)
3830 {
3831 switch (choices[choice - 1])
3832 {
3833 case 'a': /* sign (a)s */
3834 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3835 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
3836 if (p)
3837 {
3838 char input_signas[128] = { 0 };
3839 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
3840
3841 if (is_smime)
3842 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", input_signas, NULL);
3843 else
3844 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
3845
3846 crypt_key_free(&p);
3847
3848 e->security |= SEC_SIGN;
3849 }
3850 break;
3851
3852 case 'b': /* (b)oth */
3853 e->security |= (SEC_ENCRYPT | SEC_SIGN);
3854 break;
3855
3856 case 'C':
3857 e->security &= ~SEC_SIGN;
3858 break;
3859
3860 case 'c': /* (c)lear */
3861 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
3862 break;
3863
3864 case 'e': /* (e)ncrypt */
3865 e->security |= SEC_ENCRYPT;
3866 e->security &= ~SEC_SIGN;
3867 break;
3868
3869 case 'm': /* (p)gp or s/(m)ime */
3870 case 'p':
3871 is_smime = !is_smime;
3872 if (is_smime)
3873 {
3874 e->security &= ~APPLICATION_PGP;
3876 }
3877 else
3878 {
3879 e->security &= ~APPLICATION_SMIME;
3881 }
3883 break;
3884
3885 case 'O': /* oppenc mode on */
3888 break;
3889
3890 case 'o': /* oppenc mode off */
3891 e->security &= ~SEC_OPPENCRYPT;
3892 break;
3893
3894 case 'S': /* (s)ign in oppenc mode */
3895 e->security |= SEC_SIGN;
3896 break;
3897
3898 case 's': /* (s)ign */
3899 e->security &= ~SEC_ENCRYPT;
3900 e->security |= SEC_SIGN;
3901 break;
3902 }
3903 }
3904
3905 return e->security;
3906}
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1023
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:54
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c:408
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ verify_sender()

static bool verify_sender ( struct Email e)
static

Verify the sender of a message.

Parameters
eEmail
Return values
trueSender is verified

Definition at line 3929 of file crypt_gpgme.c.

3930{
3931 struct Address *sender = NULL;
3932 bool rc = true;
3933
3934 if (!TAILQ_EMPTY(&e->env->from))
3935 {
3937 sender = TAILQ_FIRST(&e->env->from);
3938 }
3939 else if (!TAILQ_EMPTY(&e->env->sender))
3940 {
3942 sender = TAILQ_FIRST(&e->env->sender);
3943 }
3944
3945 if (sender)
3946 {
3947 if (signature_key)
3948 {
3949 gpgme_key_t key = signature_key;
3950 gpgme_user_id_t uid = NULL;
3951 int sender_length = strlen(sender->mailbox);
3952 for (uid = key->uids; uid && rc; uid = uid->next)
3953 {
3954 int uid_length = strlen(uid->email);
3955 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
3956 (uid_length == (sender_length + 2)))
3957 {
3958 const char *at_sign = strchr(uid->email + 1, '@');
3959 if (at_sign)
3960 {
3961 /* Assume address is 'mailbox@domainname'.
3962 * The mailbox part is case-sensitive,
3963 * the domainname is not. (RFC2821) */
3964 const char *tmp_email = uid->email + 1;
3965 const char *tmp_sender = sender->mailbox;
3966 /* length of mailbox part including '@' */
3967 int mailbox_length = at_sign - tmp_email + 1;
3968 int domainname_length = sender_length - mailbox_length;
3969 int mailbox_match, domainname_match;
3970
3971 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
3972 tmp_email += mailbox_length;
3973 tmp_sender += mailbox_length;
3974 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
3975 if (mailbox_match && domainname_match)
3976 rc = false;
3977 }
3978 else
3979 {
3980 if (mutt_strn_equal(uid->email + 1, sender->mailbox, sender_length))
3981 rc = false;
3982 }
3983 }
3984 }
3985 }
3986 else
3987 mutt_any_key_to_continue(_("Failed to verify sender"));
3988 }
3989 else
3990 mutt_any_key_to_continue(_("Failed to figure out sender"));
3991
3992 if (signature_key)
3993 {
3994 gpgme_key_unref(signature_key);
3995 signature_key = NULL;
3996 }
3997
3998 return rc;
3999}
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:298
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:386
int mutt_istrn_cmp(const char *a, const char *b, size_t num)
Compare two strings ignoring case (to a maximum), safely.
Definition: string.c:510
#define TAILQ_EMPTY(head)
Definition: queue.h:721
struct Envelope * env
Envelope information.
Definition: email.h:66
struct AddressList sender
Email's sender.
Definition: envelope.h:63
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_gpgme_print_version()

const char * mutt_gpgme_print_version ( void  )

Get version of GPGME.

Return values
ptrGPGME version string

Definition at line 4023 of file crypt_gpgme.c.

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

Variable Documentation

◆ id_defaults

struct CryptCache* id_defaults = NULL
static

Definition at line 90 of file crypt_gpgme.c.

◆ signature_key

gpgme_key_t signature_key = NULL
static

Definition at line 91 of file crypt_gpgme.c.

◆ current_sender

char* current_sender = NULL
static

Definition at line 92 of file crypt_gpgme.c.