NeoMutt  2025-12-11-949-g4870ee
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
crypt_gpgme.c File Reference

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

#include "config.h"
#include <errno.h>
#include <gpg-error.h>
#include <gpgme.h>
#include <langinfo.h>
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "crypt_gpgme.h"
#include "lib.h"
#include "attach/lib.h"
#include "editor/lib.h"
#include "history/lib.h"
#include "hooks/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "crypt.h"
#include "globals.h"
#include "gpgme_functions.h"
#include "module_data.h"
#include "mutt_logging.h"
#include "autocrypt/lib.h"
+ Include dependency graph for crypt_gpgme.c:

Go to the source code of this file.

Data Structures

struct  CryptCache
 Internal cache for GPGME. More...
 

Macros

#define CRYPT_KV_VALID   (1 << 0)
 
#define CRYPT_KV_ADDR   (1 << 1)
 
#define CRYPT_KV_STRING   (1 << 2)
 
#define CRYPT_KV_STRONGID   (1 << 3)
 
#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)
 
#define PKA_NOTATION_NAME   "pka-address@gnupg.org"
 
#define _LINE_COMPARE(_x, _y)
 
#define MESSAGE(_y)
 
#define SIGNED_MESSAGE(_y)
 
#define PUBLIC_KEY_BLOCK(_y)
 
#define BEGIN_PGP_SIGNATURE(_y)
 

Functions

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

Detailed Description

Wrapper for PGP/SMIME calls to GPGME.

Authors
  • Pietro Cerutti
  • Richard Russon
  • Federico Kircheis
  • Ian Zimmerman
  • ftilde
  • Anna Figueiredo Gomes
  • Alejandro Colomar
  • Rayford Shireman

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

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

Definition in file crypt_gpgme.c.

Macro Definition Documentation

◆ CRYPT_KV_VALID

#define CRYPT_KV_VALID   (1 << 0)

Definition at line 75 of file crypt_gpgme.c.

◆ CRYPT_KV_ADDR

#define CRYPT_KV_ADDR   (1 << 1)

Definition at line 76 of file crypt_gpgme.c.

◆ CRYPT_KV_STRING

#define CRYPT_KV_STRING   (1 << 2)

Definition at line 77 of file crypt_gpgme.c.

◆ CRYPT_KV_STRONGID

#define CRYPT_KV_STRONGID   (1 << 3)

Definition at line 78 of file crypt_gpgme.c.

◆ CRYPT_KV_MATCH

#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)

Definition at line 79 of file crypt_gpgme.c.

◆ PKA_NOTATION_NAME

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

Definition at line 92 of file crypt_gpgme.c.

◆ _LINE_COMPARE

#define _LINE_COMPARE ( _x,
_y )
Value:
line_compare(_x, sizeof(_x) - 1, _y)
static int line_compare(const char *a, size_t n, const char *b)
Compare two strings ignore line endings.

Definition at line 94 of file crypt_gpgme.c.

◆ MESSAGE

#define MESSAGE ( _y)
Value:
_LINE_COMPARE("MESSAGE-----", _y)
#define _LINE_COMPARE(_x, _y)
Definition crypt_gpgme.c:94

Definition at line 95 of file crypt_gpgme.c.

◆ SIGNED_MESSAGE

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

Definition at line 96 of file crypt_gpgme.c.

◆ PUBLIC_KEY_BLOCK

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

Definition at line 97 of file crypt_gpgme.c.

◆ BEGIN_PGP_SIGNATURE

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

Definition at line 98 of file crypt_gpgme.c.

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

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

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

116{
117 const char *s = gpgme_get_ctx_flag(ctx, "redraw");
118 if (!s /* flag not known */ || *s /* flag true */)
119 {
121 }
122}
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition curs_lib.c:101
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_keyid()

const char * crypt_keyid ( struct CryptKeyInfo * k)

Find the ID for the key.

Parameters
kKey to use
Return values
ptrID string for the key

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

Definition at line 132 of file crypt_gpgme.c.

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

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

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

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

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

229{
230 struct CryptKeyInfo *k = NULL;
231
232 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
233 k->kobj = key->kobj;
234 gpgme_key_ref(key->kobj);
235 k->idx = key->idx;
236 k->uid = key->uid;
237 k->flags = key->flags;
238 k->validity = key->validity;
239
240 return k;
241}
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
A stored PGP key.
Definition crypt_gpgme.h:45
gpgme_validity_t validity
uid validity (cached for convenience)
Definition crypt_gpgme.h:51
KeyFlags flags
global and per uid flags (for convenience)
Definition crypt_gpgme.h:50
int idx
and the user ID at this index
Definition crypt_gpgme.h:48
const char * uid
and for convenience point to this user ID
Definition crypt_gpgme.h:49
+ 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 247 of file crypt_gpgme.c.

248{
249 if (!keylist)
250 return;
251
252 struct CryptKeyInfo *k = NULL;
253
254 while (*keylist)
255 {
256 k = *keylist;
257 *keylist = (*keylist)->next;
258
259 gpgme_key_unref(k->kobj);
260 FREE(&k);
261 }
262}
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
struct CryptKeyInfo * next
Linked list.
Definition crypt_gpgme.h:46
+ 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 269 of file crypt_gpgme.c.

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

◆ crypt_id_is_valid()

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

305{
306 if (!key)
307 return false;
308
309 return !(key->flags & KEYFLAG_CANTUSE);
310}
#define KEYFLAG_CANTUSE
Definition lib.h:161
+ 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 322 of file crypt_gpgme.c.

324{
325 int rc = 0;
326
327 if (crypt_id_is_valid(key))
328 rc |= CRYPT_KV_VALID;
329
330 if (crypt_id_is_strong(key))
331 rc |= CRYPT_KV_STRONGID;
332
333 if (addr && u_addr)
334 {
335 if (addr->mailbox && u_addr->mailbox && buf_istr_equal(addr->mailbox, u_addr->mailbox))
336 {
337 rc |= CRYPT_KV_ADDR;
338 }
339
340 if (addr->personal && u_addr->personal &&
341 buf_istr_equal(addr->personal, u_addr->personal))
342 {
343 rc |= CRYPT_KV_STRING;
344 }
345 }
346
347 return rc;
348}
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition buffer.c:701
#define CRYPT_KV_STRING
Definition crypt_gpgme.c:77
bool crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
#define CRYPT_KV_VALID
Definition crypt_gpgme.c:75
#define CRYPT_KV_STRONGID
Definition crypt_gpgme.c:78
#define CRYPT_KV_ADDR
Definition crypt_gpgme.c:76
struct Buffer * personal
Real name of address.
Definition address.h:36
struct Buffer * mailbox
Mailbox and host 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 355 of file crypt_gpgme.c.

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

395{
396 gpgme_data_t data = NULL;
397
398 gpgme_error_t err = gpgme_data_new(&data);
399 if (err != GPG_ERR_NO_ERROR)
400 {
401 mutt_error(_("error creating GPGME data object: %s"), gpgme_strerror(err));
402 mutt_exit(1);
403 }
404 return data;
405}
+ 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 * b,
bool convert )
static

Create GPGME object from the mail body.

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

Definition at line 413 of file crypt_gpgme.c.

414{
415 gpgme_error_t err = GPG_ERR_NO_ERROR;
416 gpgme_data_t data = NULL;
417
418 struct Buffer *tempfile = buf_pool_get();
419 buf_mktemp(tempfile);
420 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
421 if (!fp_tmp)
422 {
423 mutt_perror("%s", buf_string(tempfile));
424 goto cleanup;
425 }
426
428 fputc('\n', fp_tmp);
429 mutt_write_mime_body(b, fp_tmp, NeoMutt->sub);
430
431 if (convert)
432 {
433 int c, hadcr = 0;
434 unsigned char buf[1];
435
437 rewind(fp_tmp);
438 while ((c = fgetc(fp_tmp)) != EOF)
439 {
440 if (c == '\r')
441 {
442 hadcr = 1;
443 }
444 else
445 {
446 if ((c == '\n') && !hadcr)
447 {
448 buf[0] = '\r';
449 gpgme_data_write(data, buf, 1);
450 }
451
452 hadcr = 0;
453 }
454 /* FIXME: This is quite suboptimal */
455 buf[0] = c;
456 gpgme_data_write(data, buf, 1);
457 }
458 mutt_file_fclose(&fp_tmp);
459 gpgme_data_seek(data, 0, SEEK_SET);
460 }
461 else
462 {
463 mutt_file_fclose(&fp_tmp);
464 err = gpgme_data_new_from_file(&data, buf_string(tempfile), 1);
465 if (err != GPG_ERR_NO_ERROR)
466 {
467 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
468 gpgme_data_release(data);
469 data = NULL;
470 /* fall through to unlink the tempfile */
471 }
472 }
473 unlink(buf_string(tempfile));
474
475cleanup:
476 buf_pool_release(&tempfile);
477 return data;
478}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
#define mutt_perror(...)
Definition logging2.h:95
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition body.c:302
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition header.c:757
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
#define buf_mktemp(buf)
Definition tmp.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ file_to_data_object()

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

Create GPGME data object from file.

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

Definition at line 487 of file crypt_gpgme.c.

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

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

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

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

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

◆ set_signer()

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

Make sure that the correct signer is set.

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

Definition at line 711 of file crypt_gpgme.c.

712{
713 const char *signid = NULL;
714
715 const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
716 const char *const c_pgp_sign_as = cs_subset_string(NeoMutt->sub, "pgp_sign_as");
717 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
718 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
719 if (for_smime)
720 {
721 signid = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
722 }
723#ifdef USE_AUTOCRYPT
724 else if (OptAutocryptGpgme)
725 {
727 ASSERT(mod_data);
728
729 signid = mod_data->autocrypt_sign_as;
730 }
731#endif
732 else
733 {
734 signid = c_pgp_sign_as ? c_pgp_sign_as : c_pgp_default_key;
735 }
736
737 /* Try getting the signing key from config entries */
738 if (signid && set_signer_from_address(ctx, signid, for_smime))
739 {
740 return 0;
741 }
742
743 /* Try getting the signing key from the From line */
744 if (al)
745 {
746 struct Address *a;
747 TAILQ_FOREACH(a, al, entries)
748 {
749 if (a->mailbox && set_signer_from_address(ctx, buf_string(a->mailbox), for_smime))
750 {
751 return 0;
752 }
753 }
754 }
755
756 return (!signid && !al) ? 0 : -1;
757}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
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.
@ MODULE_ID_AUTOCRYPT
ModuleAutocrypt, Autocrypt
Definition module_api.h:50
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
#define ASSERT(COND)
Definition signal2.h:59
An email address.
Definition address.h:35
Autocrypt private Module data.
Definition module_data.h:32
char * autocrypt_sign_as
Autocrypt Key id to sign as.
Definition module_data.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 764 of file crypt_gpgme.c.

765{
767 gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME,
768 mod_data->current_sender, 0);
769 if (err != GPG_ERR_NO_ERROR)
770 {
771 mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
772 }
773
774 return err;
775}
@ MODULE_ID_NCRYPT
ModuleNcrypt, Ncrypt
Definition module_api.h:82
Ncrypt private Module data.
Definition module_data.h:39
char * current_sender
Current sender for GPGME.
Definition module_data.h:48
+ Here is the call graph for this function:
+ 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 786 of file crypt_gpgme.c.

788{
789 gpgme_error_t err = GPG_ERR_NO_ERROR;
790 gpgme_ctx_t ctx = NULL;
791 gpgme_data_t ciphertext = NULL;
792 char *outfile = NULL;
793
794 struct Buffer *recpstring = buf_pool_get();
795 create_recipient_string(keylist, recpstring, use_smime);
796 if (buf_is_empty(recpstring))
797 {
798 buf_pool_release(&recpstring);
799 return NULL;
800 }
801
802 ctx = create_gpgme_context(use_smime);
803 if (!use_smime)
804 gpgme_set_armor(ctx, 1);
805
806 ciphertext = create_gpgme_data();
807
808 if (combined_signed)
809 {
810 if (set_signer(ctx, from, use_smime))
811 goto cleanup;
812
813 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
814 if (c_crypt_use_pka)
815 {
816 err = set_pka_sig_notation(ctx);
817 if (err != GPG_ERR_NO_ERROR)
818 goto cleanup;
819 }
820
821 err = gpgme_op_encrypt_sign_ext(ctx, NULL, buf_string(recpstring),
822 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
823 }
824 else
825 {
826 err = gpgme_op_encrypt_ext(ctx, NULL, buf_string(recpstring),
827 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
828 }
829
830 redraw_if_needed(ctx);
831 if (err != GPG_ERR_NO_ERROR)
832 {
833 mutt_error(_("error encrypting data: %s"), gpgme_strerror(err));
834 goto cleanup;
835 }
836
837 outfile = data_object_to_tempfile(ciphertext, NULL);
838
839cleanup:
840 buf_pool_release(&recpstring);
841 gpgme_release(ctx);
842 gpgme_data_release(ciphertext);
843 return outfile;
844}
bool buf_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.
static void create_recipient_string(const char *keylist, struct Buffer *recpstring, int use_smime)
Create a string of recipients.
static int set_signer(gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
Make sure that the correct signer is set.
static char * data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
Copy a data object to a temporary file.
static void redraw_if_needed(gpgme_ctx_t ctx)
Accommodate for a redraw if needed.
+ 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 858 of file crypt_gpgme.c.

859{
860 gpgme_sign_result_t result = NULL;
861 const char *algorithm_name = NULL;
862
863 if (buflen < 5)
864 return -1;
865
866 *buf = '\0';
867 result = gpgme_op_sign_result(ctx);
868 if (result && result->signatures)
869 {
870 algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
871 if (algorithm_name)
872 {
873 if (use_smime)
874 {
875 /* convert GPGME raw hash name to RFC2633 format */
876 snprintf(buf, buflen, "%s", algorithm_name);
877 mutt_str_lower(buf);
878 }
879 else
880 {
881 /* convert GPGME raw hash name to RFC3156 format */
882 snprintf(buf, buflen, "pgp-%s", algorithm_name);
883 mutt_str_lower(buf + 4);
884 }
885 }
886 }
887
888 return (buf[0] != '\0') ? 0 : -1;
889}
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition string.c:317
+ 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 896 of file crypt_gpgme.c.

897{
898 char p[256] = { 0 };
899 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
900 state_puts(state, p);
901}
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition date.c:952
#define state_puts(STATE, STR)
Definition state.h:64
+ 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 * b,
const struct AddressList * from,
bool use_smime )
static

Sign a message.

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

Definition at line 911 of file crypt_gpgme.c.

912{
913 struct Body *b_sign = NULL;
914 char *sigfile = NULL;
915 gpgme_error_t err = GPG_ERR_NO_ERROR;
916 char buf[100] = { 0 };
917 gpgme_ctx_t ctx = NULL;
918 gpgme_data_t message = NULL, signature = NULL;
919 gpgme_sign_result_t sigres = NULL;
920
921 crypt_convert_to_7bit(b); /* Signed data _must_ be in 7-bit format. */
922
923 message = body_to_data_object(b, true);
924 if (!message)
925 return NULL;
926 signature = create_gpgme_data();
927
928 ctx = create_gpgme_context(use_smime);
929 if (!use_smime)
930 gpgme_set_armor(ctx, 1);
931
932 if (set_signer(ctx, from, use_smime))
933 {
934 gpgme_data_release(signature);
935 gpgme_data_release(message);
936 gpgme_release(ctx);
937 return NULL;
938 }
939
940 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
941 if (c_crypt_use_pka)
942 {
943 err = set_pka_sig_notation(ctx);
944 if (err != GPG_ERR_NO_ERROR)
945 {
946 gpgme_data_release(signature);
947 gpgme_data_release(message);
948 gpgme_release(ctx);
949 return NULL;
950 }
951 }
952
953 err = gpgme_op_sign(ctx, message, signature, GPGME_SIG_MODE_DETACH);
954 redraw_if_needed(ctx);
955 gpgme_data_release(message);
956 if (err != GPG_ERR_NO_ERROR)
957 {
958 gpgme_data_release(signature);
959 gpgme_release(ctx);
960 mutt_error(_("error signing data: %s"), gpgme_strerror(err));
961 return NULL;
962 }
963 /* Check for zero signatures generated. This can occur when $pgp_sign_as is
964 * unset and there is no default key specified in ~/.gnupg/gpg.conf */
965 sigres = gpgme_op_sign_result(ctx);
966 if (!sigres->signatures)
967 {
968 gpgme_data_release(signature);
969 gpgme_release(ctx);
970 mutt_error(_("$pgp_sign_as unset and no default key specified in ~/.gnupg/gpg.conf"));
971 return NULL;
972 }
973
974 sigfile = data_object_to_tempfile(signature, NULL);
975 gpgme_data_release(signature);
976 if (!sigfile)
977 {
978 gpgme_release(ctx);
979 return NULL;
980 }
981
982 b_sign = mutt_body_new();
983 b_sign->type = TYPE_MULTIPART;
984 b_sign->subtype = mutt_str_dup("signed");
985 b_sign->encoding = ENC_7BIT;
986 b_sign->use_disp = false;
987 b_sign->disposition = DISP_INLINE;
988
990 mutt_param_set(&b_sign->parameter, "protocol",
991 use_smime ? "application/pkcs7-signature" : "application/pgp-signature");
992 /* Get the micalg from GPGME. Old gpgme versions don't support this
993 * for S/MIME so we assume sha-1 in this case. */
994 if (get_micalg(ctx, use_smime, buf, sizeof(buf)) == 0)
995 mutt_param_set(&b_sign->parameter, "micalg", buf);
996 else if (use_smime)
997 mutt_param_set(&b_sign->parameter, "micalg", "sha1");
998 gpgme_release(ctx);
999
1000 b_sign->parts = b;
1001 b = b_sign;
1002
1003 b_sign->parts->next = mutt_body_new();
1004 b_sign = b_sign->parts->next;
1005 b_sign->type = TYPE_APPLICATION;
1006 if (use_smime)
1007 {
1008 b_sign->subtype = mutt_str_dup("pkcs7-signature");
1009 mutt_param_set(&b_sign->parameter, "name", "smime.p7s");
1010 b_sign->encoding = ENC_BASE64;
1011 b_sign->use_disp = true;
1012 b_sign->disposition = DISP_ATTACH;
1013 b_sign->d_filename = mutt_str_dup("smime.p7s");
1014 }
1015 else
1016 {
1017 b_sign->subtype = mutt_str_dup("pgp-signature");
1018 mutt_param_set(&b_sign->parameter, "name", "signature.asc");
1019 b_sign->use_disp = false;
1020 b_sign->disposition = DISP_NONE;
1021 b_sign->encoding = ENC_7BIT;
1022 }
1023 b_sign->filename = sigfile;
1024 b_sign->unlink = true; /* ok to remove this file after sending. */
1025
1026 return b;
1027}
void crypt_convert_to_7bit(struct Body *b)
Convert an email to 7bit encoding.
Definition crypt.c:814
static gpgme_data_t body_to_data_object(struct Body *b, bool convert)
Create GPGME object from the mail body.
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.
struct Body * mutt_body_new(void)
Create a new Body.
Definition body.c:44
@ 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:93
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition parameter.c:111
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:73
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition body.h:68
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
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:72
char * subtype
content-type subtype
Definition body.h:61
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:59
+ 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 1138 of file crypt_gpgme.c.

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

1263{
1264 if (!key)
1265 return;
1266
1267 const char *prefix = _("Fingerprint: ");
1268
1269 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1270 if (!s)
1271 return;
1272 bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1273
1274 char *buf = MUTT_MEM_MALLOC(strlen(prefix) + strlen(s) * 4 + 2, char);
1275 strcpy(buf, prefix);
1276 char *p = buf + strlen(buf);
1277 if (is_pgp && (strlen(s) == 40))
1278 { /* PGP v4 style formatted. */
1279 for (int i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
1280 {
1281 *p++ = s[0];
1282 *p++ = s[1];
1283 *p++ = s[2];
1284 *p++ = s[3];
1285 *p++ = ' ';
1286 if (i == 4)
1287 *p++ = ' ';
1288 }
1289 }
1290 else
1291 {
1292 for (int i = 0; *s && s[1] && s[2]; s += 2, i++)
1293 {
1294 *p++ = s[0];
1295 *p++ = s[1];
1296 *p++ = is_pgp ? ' ' : ':';
1297 if (is_pgp && (i == 7))
1298 *p++ = ' ';
1299 }
1300 }
1301
1302 /* just in case print remaining odd digits */
1303 for (; *s; s++)
1304 *p++ = *s;
1305 *p++ = '\n';
1306 *p = '\0';
1307 state_puts(state, buf);
1308 FREE(&buf);
1309}
#define MUTT_MEM_MALLOC(n, type)
Definition memory.h:53
+ 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 1317 of file crypt_gpgme.c.

1318{
1319 gpgme_signature_t sig = NULL;
1320 const char *txt = NULL;
1321
1322 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1323 if (result)
1324 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--)
1325 ; // do nothing
1326
1327 switch (sig ? sig->validity : 0)
1328 {
1329 case GPGME_VALIDITY_UNKNOWN:
1330 txt = _("WARNING: We have NO indication whether the key belongs to the person named as shown above\n");
1331 break;
1332 case GPGME_VALIDITY_UNDEFINED:
1333 break;
1334 case GPGME_VALIDITY_NEVER:
1335 txt = _("WARNING: The key does NOT BELONG to the person named as shown above\n");
1336 break;
1337 case GPGME_VALIDITY_MARGINAL:
1338 txt = _("WARNING: It is NOT certain that the key belongs to the person named as shown above\n");
1339 break;
1340 case GPGME_VALIDITY_FULL:
1341 case GPGME_VALIDITY_ULTIMATE:
1342 txt = NULL;
1343 break;
1344 }
1345 if (txt)
1346 state_puts(state, txt);
1347}
+ 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 1356 of file crypt_gpgme.c.

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

◆ show_one_recipient()

static void show_one_recipient ( struct State * state,
gpgme_recipient_t r )
static

Show information about one encryption recipient.

Parameters
stateState to write to
rEncryption recipient

Definition at line 1422 of file crypt_gpgme.c.

1423{
1424 const char *algo = gpgme_pubkey_algo_name(r->pubkey_algo);
1425 if (!algo)
1426 algo = "?";
1427
1428 // L10N: Show the algorithm and key ID of the encryption recipients, e.g
1429 // Recipient: RSA key, ID 1111111111111111
1430 state_printf(state, _("Recipient: %s key, ID %s\n"), algo, r->keyid);
1431}
int state_printf(struct State *state, const char *fmt,...)
Write a formatted string to the State.
Definition state.c:190
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ show_encryption_info()

static void show_encryption_info ( struct State * state,
gpgme_decrypt_result_t result )
static

Show encryption information.

Parameters
stateState to write to
resultDecryption result

Definition at line 1438 of file crypt_gpgme.c.

1439{
1440 if (!cs_subset_bool(NeoMutt->sub, "crypt_encryption_info"))
1441 return;
1442
1443 state_attach_puts(state, _("[-- Begin encryption information --]\n"));
1444
1445 for (gpgme_recipient_t r = result->recipients; r; r = r->next)
1446 show_one_recipient(state, r);
1447
1448 state_attach_puts(state, _("[-- End encryption information --]\n\n"));
1449}
static void show_one_recipient(struct State *state, gpgme_recipient_t r)
Show information about one encryption recipient.
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition state.c:104
+ 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 1463 of file crypt_gpgme.c.

1464{
1466 const char *fpr = NULL;
1467 gpgme_key_t key = NULL;
1468 bool anybad = false, anywarn = false;
1469 gpgme_signature_t sig = NULL;
1470 gpgme_error_t err = GPG_ERR_NO_ERROR;
1471
1472 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1473 if (result)
1474 {
1475 /* FIXME: this code should use a static variable and remember
1476 * the current position in the list of signatures, IMHO.
1477 * -moritz. */
1478 int i;
1479 for (i = 0, sig = result->signatures; sig && (i < idx); i++, sig = sig->next)
1480 ; // do nothing
1481
1482 if (!sig)
1483 return -1; /* Signature not found. */
1484
1485 if ((gpgme_key_t) mod_data->signature_key)
1486 {
1487 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
1488 mod_data->signature_key = NULL;
1489 }
1490
1491 fpr = sig->fpr;
1492 const unsigned int sum = sig->summary;
1493
1494 if (gpg_err_code(sig->status) != GPG_ERR_NO_ERROR)
1495 anybad = true;
1496
1497 if (gpg_err_code(sig->status) != GPG_ERR_NO_PUBKEY)
1498 {
1499 err = gpgme_get_key(ctx, fpr, &key, 0); /* secret key? */
1500 if (err == GPG_ERR_NO_ERROR)
1501 {
1502 /* Only cache the signer key for S/MIME sender verification.
1503 * (For OpenPGP, this cached key isn't used and would leak if left set.) */
1504 if (!mod_data->signature_key && key && (key->protocol == GPGME_PROTOCOL_CMS))
1505 mod_data->signature_key = key;
1506 }
1507 else
1508 {
1509 key = NULL; /* Old GPGME versions did not set KEY to NULL on
1510 error. Do it here to avoid a double free. */
1511 }
1512 }
1513 else
1514 {
1515 /* pubkey not present */
1516 }
1517
1518 if (!state || !state->fp_out || !(state->flags & STATE_DISPLAY))
1519 {
1520 ; /* No state information so no way to print anything. */
1521 }
1522 else if (err != GPG_ERR_NO_ERROR)
1523 {
1524 char buf[1024] = { 0 };
1525 snprintf(buf, sizeof(buf), _("Error getting key information for KeyID %s: %s\n"),
1526 fpr, gpgme_strerror(err));
1527 state_puts(state, buf);
1528 anybad = true;
1529 }
1530 else if ((sum & GPGME_SIGSUM_GREEN))
1531 {
1532 print_smime_keyinfo(_("Good signature from:"), sig, key, state);
1533 if (show_sig_summary(sum, ctx, key, idx, state, sig))
1534 anywarn = true;
1535 show_one_sig_validity(ctx, idx, state);
1536 }
1537 else if ((sum & GPGME_SIGSUM_RED))
1538 {
1539 print_smime_keyinfo(_("*BAD* signature from:"), sig, key, state);
1540 show_sig_summary(sum, ctx, key, idx, state, sig);
1541 }
1542 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP))
1543 { /* We can't decide (yellow) but this is a PGP key with a good
1544 signature, so we display what a PGP user expects: The name,
1545 fingerprint and the key validity (which is neither fully or
1546 ultimate). */
1547 print_smime_keyinfo(_("Good signature from:"), sig, key, state);
1548 show_one_sig_validity(ctx, idx, state);
1549 show_fingerprint(key, state);
1550 if (show_sig_summary(sum, ctx, key, idx, state, sig))
1551 anywarn = true;
1552 }
1553 else /* can't decide (yellow) */
1554 {
1555 print_smime_keyinfo(_("Problem signature from:"), sig, key, state);
1556 /* 0 indicates no expiration */
1557 if (sig->exp_timestamp)
1558 {
1559 /* L10N: This is trying to match the width of the
1560 "Problem signature from:" translation just above. */
1561 state_puts(state, _(" expires: "));
1562 print_time(sig->exp_timestamp, state);
1563 state_puts(state, "\n");
1564 }
1565 show_sig_summary(sum, ctx, key, idx, state, sig);
1566 anywarn = true;
1567 }
1568
1569 if (key != (gpgme_key_t) mod_data->signature_key)
1570 gpgme_key_unref(key);
1571 }
1572
1573 return anybad ? 1 : anywarn ? 2 : 0;
1574}
static int show_sig_summary(unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key, int idx, struct State *state, gpgme_signature_t sig)
Show a signature summary.
static void show_fingerprint(gpgme_key_t key, struct State *state)
Write a key's fingerprint.
static void print_smime_keyinfo(const char *msg, gpgme_signature_t sig, gpgme_key_t key, struct State *state)
Print key info about an SMIME key.
static void show_one_sig_validity(gpgme_ctx_t ctx, int idx, struct State *state)
Show the validity of a key used for one signature.
@ STATE_DISPLAY
Output is displayed to the user.
Definition state.h:37
gpgme_key_t signature_key
GPGME Signature key.
Definition module_data.h:45
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:58
FILE * fp_out
File to write to.
Definition state.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ verify_one()

static int verify_one ( struct Body * b,
struct State * state,
const char * tempfile,
bool is_smime )
static

Do the actual verification step.

Parameters
bBody 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 1589 of file crypt_gpgme.c.

1590{
1592 int badsig = -1;
1593 int anywarn = 0;
1594 gpgme_ctx_t ctx = NULL;
1595 gpgme_data_t message = NULL;
1596
1597 gpgme_data_t signature = file_to_data_object(state->fp_in, b->offset, b->length);
1598 if (!signature)
1599 return -1;
1600
1601 /* We need to tell GPGME about the encoding because the backend can't
1602 * auto-detect plain base-64 encoding which is used by S/MIME. */
1603 if (is_smime)
1604 gpgme_data_set_encoding(signature, GPGME_DATA_ENCODING_BASE64);
1605
1606 gpgme_error_t err = gpgme_data_new_from_file(&message, tempfile, 1);
1607 if (err != GPG_ERR_NO_ERROR)
1608 {
1609 gpgme_data_release(signature);
1610 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
1611 return -1;
1612 }
1613 ctx = create_gpgme_context(is_smime);
1614
1615 /* Note: We don't need a current time output because GPGME avoids
1616 * such an attack by separating the meta information from the data. */
1617 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1618
1619 err = gpgme_op_verify(ctx, signature, message, NULL);
1620 gpgme_data_release(message);
1621 gpgme_data_release(signature);
1622
1623 redraw_if_needed(ctx);
1624 if (err != GPG_ERR_NO_ERROR)
1625 {
1626 char buf[200] = { 0 };
1627
1628 snprintf(buf, sizeof(buf) - 1, _("Error: verification failed: %s\n"),
1629 gpgme_strerror(err));
1630 state_puts(state, buf);
1631 }
1632 else
1633 { /* Verification succeeded, see what the result is. */
1634 gpgme_verify_result_t verify_result = NULL;
1635
1636 if ((gpgme_key_t) mod_data->signature_key)
1637 {
1638 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
1639 mod_data->signature_key = NULL;
1640 }
1641
1642 verify_result = gpgme_op_verify_result(ctx);
1643 if (verify_result && verify_result->signatures)
1644 {
1645 bool anybad = false;
1646 int res;
1647 for (int idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1648 {
1649 if (res == 1)
1650 anybad = true;
1651 else if (res == 2)
1652 anywarn = 2;
1653 }
1654 if (!anybad)
1655 badsig = 0;
1656 }
1657 }
1658
1659 if (badsig == 0)
1660 {
1661 gpgme_verify_result_t result = NULL;
1662 gpgme_sig_notation_t notation = NULL;
1663 gpgme_signature_t sig = NULL;
1664
1665 result = gpgme_op_verify_result(ctx);
1666 if (result)
1667 {
1668 for (sig = result->signatures; sig; sig = sig->next)
1669 {
1670 int non_pka_notations = 0;
1671 for (notation = sig->notations; notation; notation = notation->next)
1672 if (!is_pka_notation(notation))
1673 non_pka_notations++;
1674
1675 if (non_pka_notations)
1676 {
1677 char buf[128] = { 0 };
1678 snprintf(buf, sizeof(buf),
1679 _("*** Begin Notation (signature by: %s) ***\n"), sig->fpr);
1680 state_puts(state, buf);
1681 for (notation = sig->notations; notation; notation = notation->next)
1682 {
1683 if (is_pka_notation(notation))
1684 continue;
1685
1686 if (notation->name)
1687 {
1688 state_puts(state, notation->name);
1689 state_puts(state, "=");
1690 }
1691 if (notation->value)
1692 {
1693 state_puts(state, notation->value);
1694 if (!(*notation->value && (notation->value[strlen(notation->value) - 1] == '\n')))
1695 state_puts(state, "\n");
1696 }
1697 }
1698 state_puts(state, _("*** End Notation ***\n"));
1699 }
1700 }
1701 }
1702 }
1703
1704 gpgme_release(ctx);
1705
1706 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1707 mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
1708
1709 return badsig ? 1 : anywarn ? 2 : 0;
1710}
static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
Create GPGME data object from file.
static bool is_pka_notation(gpgme_sig_notation_t notation)
Is this the standard pka email address.
static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *state)
Show information about one signature.
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
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:55
+ 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 * b,
struct State * state,
FILE * fp_out,
bool is_smime,
int * r_is_signed )
static

Decrypt a PGP or SMIME message.

Parameters
[in]bBody 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 1741 of file crypt_gpgme.c.

1743{
1744 if (!b || !state || !fp_out)
1745 return NULL;
1746
1747 struct Body *tattach = NULL;
1748 gpgme_error_t err = GPG_ERR_NO_ERROR;
1749 gpgme_data_t ciphertext = NULL, plaintext = NULL;
1750 gpgme_decrypt_result_t result = NULL;
1751 bool maybe_signed = false;
1752 bool anywarn = false;
1753 int sig_stat = 0;
1754
1755 if (r_is_signed)
1756 *r_is_signed = 0;
1757
1758 gpgme_ctx_t ctx = NULL;
1759restart:
1760 ctx = create_gpgme_context(is_smime);
1761
1762 if (b->length < 0)
1763 return NULL;
1764 /* Make a data object from the body, create context etc. */
1765 ciphertext = file_to_data_object(state->fp_in, b->offset, b->length);
1766 if (!ciphertext)
1767 goto cleanup;
1768 plaintext = create_gpgme_data();
1769
1770 /* Do the decryption or the verification in case of the S/MIME hack. */
1771 if ((!is_smime) || maybe_signed)
1772 {
1773 if (!is_smime)
1774 err = gpgme_op_decrypt_verify(ctx, ciphertext, plaintext);
1775 else if (maybe_signed)
1776 err = gpgme_op_verify(ctx, ciphertext, NULL, plaintext);
1777
1778 if (err == GPG_ERR_NO_ERROR)
1779 {
1780 /* Check whether signatures have been verified. */
1781 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
1782 if (verify_result->signatures)
1783 sig_stat = 1;
1784 }
1785 }
1786 else
1787 {
1788 err = gpgme_op_decrypt(ctx, ciphertext, plaintext);
1789 }
1790 gpgme_data_release(ciphertext);
1791 ciphertext = NULL;
1792
1793#ifdef USE_AUTOCRYPT
1794 // Abort right away and silently. Autocrypt will retry on the normal keyring.
1795 if (OptAutocryptGpgme && (err != GPG_ERR_NO_ERROR))
1796 goto cleanup;
1797#endif
1798
1799 result = gpgme_op_decrypt_result(ctx);
1800 if (result && (state->flags & STATE_DISPLAY))
1801 show_encryption_info(state, result);
1802
1803 if (err != GPG_ERR_NO_ERROR)
1804 {
1805 if (is_smime && !maybe_signed && (gpg_err_code(err) == GPG_ERR_NO_DATA))
1806 {
1807 /* Check whether this might be a signed message despite what the mime
1808 * header told us. Retry then. gpgsm returns the error information
1809 * "unsupported Algorithm '?'" but GPGME will not store this unknown
1810 * algorithm, thus we test that it has not been set. */
1811 if (result && !result->unsupported_algorithm)
1812 {
1813 maybe_signed = true;
1814 gpgme_data_release(plaintext);
1815 plaintext = NULL;
1816 /* gpgsm ends the session after an error; restart it */
1817 gpgme_release(ctx);
1818 goto restart;
1819 }
1820 }
1821 redraw_if_needed(ctx);
1822 if ((state->flags & STATE_DISPLAY))
1823 {
1824 char buf[200] = { 0 };
1825
1826 snprintf(buf, sizeof(buf) - 1,
1827 _("[-- Error: decryption failed: %s --]\n\n"), gpgme_strerror(err));
1828 state_attach_puts(state, buf);
1829 }
1830 goto cleanup;
1831 }
1832 redraw_if_needed(ctx);
1833
1834 /* Read the output from GPGME, and make sure to change CRLF to LF,
1835 * otherwise read_mime_header has a hard time parsing the message. */
1836 if (data_object_to_stream(plaintext, fp_out))
1837 {
1838 goto cleanup;
1839 }
1840 gpgme_data_release(plaintext);
1841 plaintext = NULL;
1842
1843 if (sig_stat)
1844 {
1845 int res, idx;
1846 int anybad = 0;
1847
1848 if (r_is_signed)
1849 *r_is_signed = -1; /* A signature exists. */
1850
1851 if ((state->flags & STATE_DISPLAY))
1852 {
1853 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1854 }
1855 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1856 {
1857 if (res == 1)
1858 anybad = 1;
1859 else if (res == 2)
1860 anywarn = true;
1861 }
1862 if (!anybad && idx && r_is_signed && *r_is_signed)
1863 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1864
1865 if ((state->flags & STATE_DISPLAY))
1866 {
1867 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1868 }
1869 }
1870 gpgme_release(ctx);
1871 ctx = NULL;
1872
1873 fflush(fp_out);
1874 rewind(fp_out);
1875 const long size = mutt_file_get_size_fp(fp_out);
1876 if (size == 0)
1877 {
1878 goto cleanup;
1879 }
1880 tattach = mutt_read_mime_header(fp_out, 0);
1881 if (tattach)
1882 {
1883 /* Need to set the length of this body part. */
1884 tattach->length = size - tattach->offset;
1885
1886 tattach->warnsig = anywarn;
1887
1888 /* See if we need to recurse on this MIME part. */
1889 mutt_parse_part(fp_out, tattach);
1890 }
1891
1892cleanup:
1893 gpgme_data_release(ciphertext);
1894 gpgme_data_release(plaintext);
1895 gpgme_release(ctx);
1896
1897 return tattach;
1898}
static void show_encryption_info(struct State *state, gpgme_decrypt_result_t result)
Show encryption information.
static int data_object_to_stream(gpgme_data_t data, FILE *fp)
Write a GPGME data object to a file.
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition parse.c:1947
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1484
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1432
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 2121 of file crypt_gpgme.c.

2122{
2123 gpgme_ctx_t tmpctx = NULL;
2124 gpgme_key_t key = NULL;
2125 gpgme_user_id_t uid = NULL;
2126 gpgme_subkey_t subkey = NULL;
2127 const char *shortid = NULL;
2128 size_t len;
2129 char date[256] = { 0 };
2130 bool more;
2131 int rc = -1;
2132 time_t tt;
2133
2134 *fp = mutt_file_mkstemp();
2135 if (!*fp)
2136 {
2137 mutt_perror(_("Can't create temporary file"));
2138 return -1;
2139 }
2140
2141 tmpctx = create_gpgme_context(false);
2142
2143 gpgme_error_t err = gpgme_op_keylist_from_data_start(tmpctx, keydata, 0);
2144 while (err == GPG_ERR_NO_ERROR)
2145 {
2146 err = gpgme_op_keylist_next(tmpctx, &key);
2147 if (err != GPG_ERR_NO_ERROR)
2148 break;
2149 uid = key->uids;
2150 subkey = key->subkeys;
2151 more = false;
2152 while (subkey)
2153 {
2154 shortid = subkey->keyid;
2155 len = mutt_str_len(subkey->keyid);
2156 if (len > 8)
2157 shortid += len - 8;
2158 tt = subkey->timestamp;
2159 mutt_date_localtime_format(date, sizeof(date), "%Y-%m-%d", tt);
2160
2161 fprintf(*fp, "%s %5.5s %u/%8s %s\n", more ? "sub" : "pub",
2162 gpgme_pubkey_algo_name(subkey->pubkey_algo), subkey->length, shortid, date);
2163 if (!more)
2164 {
2165 while (uid)
2166 {
2167 fprintf(*fp, "uid %s\n", NONULL(uid->uid));
2168 uid = uid->next;
2169 }
2170 }
2171 subkey = subkey->next;
2172 more = true;
2173 }
2174 gpgme_key_unref(key);
2175 }
2176 if (gpg_err_code(err) != GPG_ERR_EOF)
2177 {
2178 mutt_debug(LL_DEBUG1, "Error listing keys\n");
2179 goto err_fp;
2180 }
2181
2182 rc = 0;
2183
2184err_fp:
2185 if (rc)
2186 mutt_file_fclose(fp);
2187
2188 gpgme_release(tmpctx);
2189
2190 return rc;
2191}
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
#define NONULL(x)
Definition string2.h:44
#define mutt_file_mkstemp()
Definition tmp.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ line_compare()

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

Compare two strings ignore line endings.

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

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

Definition at line 2204 of file crypt_gpgme.c.

2205{
2206 if (mutt_strn_equal(a, b, n))
2207 {
2208 /* at this point we know that 'b' is at least 'n' chars long */
2209 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2210 return true;
2211 }
2212 return false;
2213}
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:429
+ 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 2222 of file crypt_gpgme.c.

2223{
2224 char buf[8192] = { 0 };
2225 bool rc = false;
2226
2227 bool sgn = false;
2228 bool enc = false;
2229
2230 if (b->type != TYPE_TEXT)
2231 return 0;
2232
2233 struct Buffer *tempfile = buf_pool_get();
2234 buf_mktemp(tempfile);
2236 {
2237 unlink(buf_string(tempfile));
2238 goto cleanup;
2239 }
2240
2241 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2242 if (!fp_tmp)
2243 {
2244 unlink(buf_string(tempfile));
2245 goto cleanup;
2246 }
2247
2248 while (fgets(buf, sizeof(buf), fp_tmp))
2249 {
2250 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2251 if (plen != 0)
2252 {
2253 if (MESSAGE(buf + plen))
2254 {
2255 enc = true;
2256 break;
2257 }
2258 else if (SIGNED_MESSAGE(buf + plen))
2259 {
2260 sgn = true;
2261 break;
2262 }
2263 }
2264 }
2265 mutt_file_fclose(&fp_tmp);
2266 unlink(buf_string(tempfile));
2267
2268 if (!enc && !sgn)
2269 goto cleanup;
2270
2271 /* fix the content type */
2272
2273 mutt_param_set(&b->parameter, "format", "fixed");
2274 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2275
2276 rc = true;
2277
2278cleanup:
2279 buf_pool_release(&tempfile);
2280 return rc;
2281}
#define SIGNED_MESSAGE(_y)
Definition crypt_gpgme.c:96
#define MESSAGE(_y)
Definition crypt_gpgme.c:95
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
@ STATE_NONE
No flags are set.
Definition state.h:36
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
@ MUTT_SAVE_NONE
Overwrite existing file (the default)
Definition mutt_attach.h:59
+ 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 2422 of file crypt_gpgme.c.

2423{
2424 char buf[8192] = { 0 };
2425 bool complete, armor_header;
2426 FILE *fp = NULL;
2427
2428 char *fname = data_object_to_tempfile(data, &fp);
2429 if (!fname)
2430 {
2431 mutt_file_fclose(&fp);
2432 return;
2433 }
2434 unlink(fname);
2435 FREE(&fname);
2436
2437 /* fromcode comes from the MIME Content-Type charset label. It might
2438 * be a wrong label, so we want the ability to do corrections via
2439 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2441
2442 for (complete = true, armor_header = true;
2443 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2444 {
2445 if (!complete)
2446 {
2447 if (!armor_header)
2448 state_puts(state, buf);
2449 continue;
2450 }
2451
2452 if (BEGIN_PGP_SIGNATURE(buf))
2453 break;
2454
2455 if (armor_header)
2456 {
2457 if (buf[0] == '\n')
2458 armor_header = false;
2459 continue;
2460 }
2461
2462 if (state->prefix)
2463 state_puts(state, state->prefix);
2464
2465 if ((buf[0] == '-') && (buf[1] == ' '))
2466 state_puts(state, buf + 2);
2467 else
2468 state_puts(state, buf);
2469 }
2470
2473}
const char * cc_charset(void)
Get the cached value of $charset.
#define BEGIN_PGP_SIGNATURE(_y)
Definition crypt_gpgme.c:98
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:919
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition charset.c:1028
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition charset.c:948
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition charset.h:67
Cursor for converting a file's encoding.
Definition charset.h:45
FILE * fp
File to read from.
Definition charset.h:46
const char * prefix
String to add to the beginning of each output line.
Definition state.h:57
+ 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 2955 of file crypt_gpgme.c.

2956{
2957 unsigned int rc = 0;
2958
2959 switch (cap)
2960 {
2962 rc = key->can_encrypt;
2963 if (rc == 0)
2964 {
2965 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2966 {
2967 rc = subkey->can_encrypt;
2968 if (rc != 0)
2969 break;
2970 }
2971 }
2972 break;
2973 case KEY_CAP_CAN_SIGN:
2974 rc = key->can_sign;
2975 if (rc == 0)
2976 {
2977 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2978 {
2979 rc = subkey->can_sign;
2980 if (rc != 0)
2981 break;
2982 }
2983 }
2984 break;
2986 rc = key->can_certify;
2987 if (rc == 0)
2988 {
2989 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2990 {
2991 rc = subkey->can_certify;
2992 if (rc != 0)
2993 break;
2994 }
2995 }
2996 break;
2997 }
2998
2999 return rc;
3000}
@ KEY_CAP_CAN_CERTIFY
Key can be used to certify.
Definition crypt_gpgme.h:80
@ KEY_CAP_CAN_ENCRYPT
Key can be used for encryption.
Definition crypt_gpgme.h:78
@ KEY_CAP_CAN_SIGN
Key can be used for signing.
Definition crypt_gpgme.h:79
+ Here is the caller graph for this function:

◆ list_to_pattern()

static char * list_to_pattern ( struct ListHead * list)
static

Convert STailQ to GPGME-compatible pattern.

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

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

Note
The caller must free the returned pattern

Definition at line 3011 of file crypt_gpgme.c.

3012{
3013 char *pattern = NULL, *p = NULL;
3014 const char *s = NULL;
3015 size_t n;
3016
3017 n = 0;
3018 struct ListNode *np = NULL;
3019 STAILQ_FOREACH(np, list, entries)
3020 {
3021 for (s = np->data; *s; s++)
3022 {
3023 if ((*s == '%') || (*s == '+'))
3024 n += 2;
3025 n++;
3026 }
3027 n++; /* delimiter or end of string */
3028 }
3029 n++; /* make sure to allocate at least one byte */
3030 p = MUTT_MEM_CALLOC(n, char);
3031 pattern = p;
3032 STAILQ_FOREACH(np, list, entries)
3033 {
3034 s = np->data;
3035 if (*s)
3036 {
3037 if (np != STAILQ_FIRST(list))
3038 *p++ = ' ';
3039 for (s = np->data; *s; s++)
3040 {
3041 if (*s == '%')
3042 {
3043 *p++ = '%';
3044 *p++ = '2';
3045 *p++ = '5';
3046 }
3047 else if (*s == '+')
3048 {
3049 *p++ = '%';
3050 *p++ = '2';
3051 *p++ = 'B';
3052 }
3053 else if (*s == ' ')
3054 {
3055 *p++ = '+';
3056 }
3057 else
3058 {
3059 *p++ = *s;
3060 }
3061 }
3062 }
3063 }
3064 *p = '\0';
3065 return pattern;
3066}
#define STAILQ_FIRST(head)
Definition queue.h:388
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
+ 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 3078 of file crypt_gpgme.c.

3079{
3080 struct CryptKeyInfo *db = NULL, *k = NULL, **kend = NULL;
3081 gpgme_error_t err = GPG_ERR_NO_ERROR;
3082 gpgme_ctx_t ctx = NULL;
3083 gpgme_key_t key = NULL;
3084 int idx;
3085 gpgme_user_id_t uid = NULL;
3086
3087 char *pattern = list_to_pattern(hints);
3088 if (!pattern)
3089 return NULL;
3090
3091 ctx = create_gpgme_context(0);
3092 db = NULL;
3093 kend = &db;
3094
3095 if ((app & APPLICATION_PGP))
3096 {
3097 /* It's all a mess. That old GPGME expects different things depending on
3098 * the protocol. For gpg we don't need percent escaped pappert but simple
3099 * strings passed in an array to the keylist_ext_start function. */
3100 size_t n = 0;
3101 struct ListNode *np = NULL;
3102 STAILQ_FOREACH(np, hints, entries)
3103 {
3104 if (np->data && *np->data)
3105 n++;
3106 }
3107 if (n == 0)
3108 goto no_pgphints;
3109
3110 char **patarr = MUTT_MEM_CALLOC(n + 1, char *);
3111 n = 0;
3112 STAILQ_FOREACH(np, hints, entries)
3113 {
3114 if (np->data && *np->data)
3115 patarr[n++] = mutt_str_dup(np->data);
3116 }
3117 patarr[n] = NULL;
3118 err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
3119 for (n = 0; patarr[n]; n++)
3120 FREE(&patarr[n]);
3121 FREE(&patarr);
3122 if (err != GPG_ERR_NO_ERROR)
3123 {
3124 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3125 gpgme_release(ctx);
3126 FREE(&pattern);
3127 return NULL;
3128 }
3129
3130 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3131 {
3132 KeyFlags flags = KEYFLAG_NONE;
3133
3135 flags |= KEYFLAG_CANENCRYPT;
3137 flags |= KEYFLAG_CANSIGN;
3138
3139 if (key->revoked)
3140 flags |= KEYFLAG_REVOKED;
3141 if (key->expired)
3142 flags |= KEYFLAG_EXPIRED;
3143 if (key->disabled)
3144 flags |= KEYFLAG_DISABLED;
3145
3146 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3147 {
3148 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3149 k->kobj = key;
3150 gpgme_key_ref(k->kobj);
3151 k->idx = idx;
3152 k->uid = uid->uid;
3153 k->flags = flags;
3154 if (uid->revoked)
3155 k->flags |= KEYFLAG_REVOKED;
3156 k->validity = uid->validity;
3157 *kend = k;
3158 kend = &k->next;
3159 }
3160 gpgme_key_unref(key);
3161 }
3162 if (gpg_err_code(err) != GPG_ERR_EOF)
3163 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3164 gpgme_op_keylist_end(ctx);
3165 no_pgphints:;
3166 }
3167
3168 if ((app & APPLICATION_SMIME))
3169 {
3170 /* and now look for x509 certificates */
3171 gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
3172 err = gpgme_op_keylist_start(ctx, pattern, 0);
3173 if (err != GPG_ERR_NO_ERROR)
3174 {
3175 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3176 gpgme_release(ctx);
3177 FREE(&pattern);
3178 return NULL;
3179 }
3180
3181 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3182 {
3183 KeyFlags flags = KEYFLAG_ISX509;
3184
3186 flags |= KEYFLAG_CANENCRYPT;
3188 flags |= KEYFLAG_CANSIGN;
3189
3190 if (key->revoked)
3191 flags |= KEYFLAG_REVOKED;
3192 if (key->expired)
3193 flags |= KEYFLAG_EXPIRED;
3194 if (key->disabled)
3195 flags |= KEYFLAG_DISABLED;
3196
3197 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3198 {
3199 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3200 k->kobj = key;
3201 gpgme_key_ref(k->kobj);
3202 k->idx = idx;
3203 k->uid = uid->uid;
3204 k->flags = flags;
3205 if (uid->revoked)
3206 k->flags |= KEYFLAG_REVOKED;
3207 k->validity = uid->validity;
3208 *kend = k;
3209 kend = &k->next;
3210 }
3211 gpgme_key_unref(key);
3212 }
3213 if (gpg_err_code(err) != GPG_ERR_EOF)
3214 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3215 gpgme_op_keylist_end(ctx);
3216 }
3217
3218 gpgme_release(ctx);
3219 FREE(&pattern);
3220 return db;
3221}
static char * list_to_pattern(struct ListHead *list)
Convert STailQ to GPGME-compatible pattern.
unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
uint16_t KeyFlags
Definition lib.h:159
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
@ KEYFLAG_REVOKED
Key is revoked.
Definition lib.h:152
@ KEYFLAG_NONE
No flags are set.
Definition lib.h:146
@ KEYFLAG_CANSIGN
Key is suitable for signing.
Definition lib.h:147
@ KEYFLAG_EXPIRED
Key is expired.
Definition lib.h:151
@ KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition lib.h:148
@ KEYFLAG_DISABLED
Key is marked disabled.
Definition lib.h:153
+ 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 3231 of file crypt_gpgme.c.

3232{
3233 char *scratch = mutt_str_dup(str);
3234 if (!scratch)
3235 return;
3236
3237 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3238 {
3239 if (strlen(t) > 3)
3241 }
3242
3243 FREE(&scratch);
3244}
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition list.c:65
+ 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 3255 of file crypt_gpgme.c.

3258{
3259 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3260
3261 int multi = false;
3262 int this_key_has_strong = false;
3263 int this_key_has_addr_match = false;
3264 int match = false;
3265
3266 struct CryptKeyInfo *keys = NULL, *k = NULL;
3267 struct CryptKeyInfo *the_strong_valid_key = NULL;
3268 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3269 struct CryptKeyInfo *matches = NULL;
3270 struct CryptKeyInfo **matches_endp = &matches;
3271
3272 if (a && a->mailbox)
3274 if (a && a->personal)
3276
3277 if (!oppenc_mode)
3278 mutt_message(_("Looking for keys matching \"%s\"..."), a ? buf_string(a->mailbox) : "");
3279 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3280
3281 mutt_list_free(&hints);
3282
3283 if (!keys)
3284 return NULL;
3285
3286 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n",
3287 a ? buf_string(a->personal) : "", a ? buf_string(a->mailbox) : "");
3288
3289 for (k = keys; k; k = k->next)
3290 {
3291 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3292
3293 if (abilities && !(k->flags & abilities))
3294 {
3295 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3296 continue;
3297 }
3298
3299 this_key_has_strong = false; /* strong and valid match */
3300 this_key_has_addr_match = false;
3301 match = false; /* any match */
3302
3303 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3304 mutt_addrlist_parse(&alist, k->uid);
3305 struct Address *ka = NULL;
3306 TAILQ_FOREACH(ka, &alist, entries)
3307 {
3308 int validity = crypt_id_matches_addr(a, ka, k);
3309
3310 if (validity & CRYPT_KV_MATCH) /* something matches */
3311 {
3312 match = true;
3313
3314 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3315 {
3316 if (validity & CRYPT_KV_STRONGID)
3317 {
3318 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3319 multi = true;
3320 this_key_has_strong = true;
3321 }
3322 else
3323 {
3324 this_key_has_addr_match = true;
3325 }
3326 }
3327 }
3328 }
3329 mutt_addrlist_clear(&alist);
3330
3331 if (match)
3332 {
3333 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3334 *matches_endp = tmp;
3335 matches_endp = &tmp->next;
3336
3337 if (this_key_has_strong)
3338 the_strong_valid_key = tmp;
3339 else if (this_key_has_addr_match)
3340 a_valid_addrmatch_key = tmp;
3341 }
3342 }
3343
3344 crypt_key_free(&keys);
3345
3346 if (matches)
3347 {
3348 if (oppenc_mode || !isatty(STDIN_FILENO))
3349 {
3350 const bool c_crypt_opportunistic_encrypt_strong_keys =
3351 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3352 if (the_strong_valid_key)
3353 k = crypt_copy_key(the_strong_valid_key);
3354 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3355 k = crypt_copy_key(a_valid_addrmatch_key);
3356 else
3357 k = NULL;
3358 }
3359 else if (the_strong_valid_key && !multi)
3360 {
3361 /* There was precisely one strong match on a valid ID.
3362 * Proceed without asking the user. */
3363 k = crypt_copy_key(the_strong_valid_key);
3364 }
3365 else
3366 {
3367 /* Else: Ask the user. */
3368 k = dlg_gpgme(matches, a, NULL, app, forced_valid);
3369 }
3370
3371 crypt_key_free(&matches);
3372 }
3373 else
3374 {
3375 k = NULL;
3376 }
3377
3378 return k;
3379}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1470
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:480
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
static int crypt_id_matches_addr(struct Address *addr, struct Address *u_addr, struct CryptKeyInfo *key)
Does the key ID match the address.
static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
Split a string and add the parts to a List.
static struct CryptKeyInfo * get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
Get a list of keys which are candidates for the selection.
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
#define CRYPT_KV_MATCH
Definition crypt_gpgme.c:79
struct CryptKeyInfo * dlg_gpgme(struct CryptKeyInfo *keys, struct Address *p, const char *s, unsigned int app, bool *forced_valid)
Get the user to select a key -.
Definition dlg_gpgme.c:195
#define mutt_message(...)
Definition logging2.h:93
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition list.c:123
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:49
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
#define STAILQ_HEAD_INITIALIZER(head)
Definition queue.h:324
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
+ 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 3389 of file crypt_gpgme.c.

3391{
3392 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3393 struct CryptKeyInfo *matches = NULL;
3394 struct CryptKeyInfo **matches_endp = &matches;
3395 struct CryptKeyInfo *k = NULL;
3396 const char *ps = NULL, *pl = NULL, *phint = NULL;
3397
3398 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3399
3400 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3401 crypt_add_string_to_hints(phint, &hints);
3402 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3403 mutt_list_free(&hints);
3404
3405 if (!keys)
3406 {
3407 FREE(&pfcopy);
3408 return NULL;
3409 }
3410
3411 for (k = keys; k; k = k->next)
3412 {
3413 if (abilities && !(k->flags & abilities))
3414 continue;
3415
3416 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3417 crypt_long_keyid(k), k->uid);
3418
3419 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3420 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3421 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3422 {
3423 mutt_debug(LL_DEBUG5, "match\n");
3424
3425 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3426 *matches_endp = tmp;
3427 matches_endp = &tmp->next;
3428 }
3429 else
3430 {
3431 mutt_debug(LL_DEBUG5, "no match\n");
3432 }
3433 }
3434
3435 FREE(&pfcopy);
3436 crypt_key_free(&keys);
3437
3438 if (matches)
3439 {
3440 if (isatty(STDIN_FILENO))
3441 {
3442 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3443
3444 crypt_key_free(&matches);
3445 return k;
3446 }
3447 else
3448 {
3449 if (crypt_keys_are_valid(matches))
3450 return matches;
3451
3452 crypt_key_free(&matches);
3453 return NULL;
3454 }
3455 }
3456
3457 return NULL;
3458}
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:1395
static const char * crypt_short_keyid(struct CryptKeyInfo *k)
Get the short keyID for a key.
static const char * crypt_long_keyid(struct CryptKeyInfo *k)
Find the Long ID for the key.
static const char * crypt_fpr(struct CryptKeyInfo *k)
Get the hexstring fingerprint from a key.
bool crypt_keys_are_valid(struct CryptKeyInfo *keys)
Are all these keys valid?
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition string.c:528
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_ask_for_key()

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

Ask the user for a key.

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

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

Definition at line 3472 of file crypt_gpgme.c.

3475{
3477 struct CryptKeyInfo *key = NULL;
3478 struct CryptCache *l = NULL;
3479 struct Buffer *resp = buf_pool_get();
3480
3482
3483 if (whatfor)
3484 {
3485 for (l = (struct CryptCache *) mod_data->gpgme_id_defaults; l; l = l->next)
3486 {
3487 if (mutt_istr_equal(whatfor, l->what))
3488 {
3489 buf_strcpy(resp, l->dflt);
3490 break;
3491 }
3492 }
3493 }
3494
3495 while (true)
3496 {
3497 buf_reset(resp);
3498 if (mw_get_field(tag, resp, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0)
3499 {
3500 goto done;
3501 }
3502
3503 if (whatfor)
3504 {
3505 if (l)
3506 {
3507 mutt_str_replace(&l->dflt, buf_string(resp));
3508 }
3509 else
3510 {
3511 l = MUTT_MEM_MALLOC(1, struct CryptCache);
3512 l->next = (struct CryptCache *) mod_data->gpgme_id_defaults;
3513 mod_data->gpgme_id_defaults = l;
3514 l->what = mutt_str_dup(whatfor);
3515 l->dflt = buf_strdup(resp);
3516 }
3517 }
3518
3519 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3520 if (key)
3521 goto done;
3522
3523 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3524 }
3525
3526done:
3527 buf_pool_release(&resp);
3528 return key;
3529}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:89
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
Find a key by string.
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:502
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:61
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Internal cache for GPGME.
Definition crypt_gpgme.c:86
char * what
Cached key identifier.
Definition crypt_gpgme.c:87
char * dflt
Default key ID.
Definition crypt_gpgme.c:88
struct CryptCache * next
Linked list.
Definition crypt_gpgme.c:89
struct CryptCache * gpgme_id_defaults
GPGME IdDefaults cache.
Definition module_data.h:43
+ 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 3542 of file crypt_gpgme.c.

3543{
3544 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3545 struct ListNode *crypt_hook = NULL;
3546 const char *keyid = NULL;
3547 char *keylist = NULL;
3548 size_t keylist_size = 0;
3549 size_t keylist_used = 0;
3550 struct Address *p = NULL;
3551 struct CryptKeyInfo *k_info = NULL;
3552 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3553 char buf[1024] = { 0 };
3554 bool forced_valid = false;
3555 bool key_selected;
3556 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3557
3558 struct Address *a = NULL;
3559 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3560 /* Iterate through each recipient address to find an encryption key */
3561 TAILQ_FOREACH(a, addrlist, entries)
3562 {
3563 key_selected = false;
3564 /* Check for crypt-hook overrides for this recipient */
3565 mutt_crypt_hook(&crypt_hook_list, a);
3566 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3567 do
3568 {
3569 p = a;
3570 forced_valid = false;
3571 k_info = NULL;
3572
3573 /* If a crypt-hook provides a key ID, confirm with the user unless
3574 * in opportunistic encryption mode */
3575 if (crypt_hook)
3576 {
3577 keyid = crypt_hook->data;
3578 enum QuadOption ans = MUTT_YES;
3579 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3580 {
3581 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3582 buf_string(p->mailbox));
3583 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3584 }
3585 if (ans == MUTT_YES)
3586 {
3587 if (crypt_is_numerical_keyid(keyid))
3588 {
3589 if (mutt_strn_equal(keyid, "0x", 2))
3590 keyid += 2;
3591 goto bypass_selection; /* you don't see this. */
3592 }
3593
3594 /* check for e-mail address */
3595 mutt_addrlist_clear(&hookal);
3596 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3597 {
3598 mutt_addrlist_qualify(&hookal, fqdn);
3599 p = TAILQ_FIRST(&hookal);
3600 }
3601 else if (!oppenc_mode)
3602 {
3603 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3604 }
3605 }
3606 else if (ans == MUTT_NO)
3607 {
3608 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3609 {
3610 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3611 continue;
3612 }
3613 }
3614 else if (ans == MUTT_ABORT)
3615 {
3616 FREE(&keylist);
3617 mutt_addrlist_clear(&hookal);
3618 mutt_list_free(&crypt_hook_list);
3619 return NULL;
3620 }
3621 }
3622
3623 /* If no key found yet, try looking up by address in the keyring */
3624 if (!k_info)
3625 {
3626 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3627 }
3628
3629 /* Last resort: prompt the user to enter a key ID interactively */
3630 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3631 {
3632 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3633
3634 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3635 KEYFLAG_CANENCRYPT, app, &forced_valid);
3636 }
3637
3638 if (!k_info)
3639 {
3640 FREE(&keylist);
3641 mutt_addrlist_clear(&hookal);
3642 mutt_list_free(&crypt_hook_list);
3643 return NULL;
3644 }
3645
3646 keyid = crypt_fpr_or_lkeyid(k_info);
3647
3648 bypass_selection:
3649 /* Append the selected key ID to the space-separated keylist string */
3650 keylist_size += mutt_str_len(keyid) + 4 + 1;
3651 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
3652 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3653 keyid, forced_valid ? "!" : "");
3654 keylist_used = mutt_str_len(keylist);
3655
3656 key_selected = true;
3657
3658 crypt_key_free(&k_info);
3659 mutt_addrlist_clear(&hookal);
3660
3661 if (crypt_hook)
3662 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3663
3664 } while (crypt_hook);
3665
3666 mutt_list_free(&crypt_hook_list);
3667 }
3668 return keylist;
3669}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:685
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition crypt.c:1484
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.
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
static struct CryptKeyInfo * crypt_ask_for_key(const char *tag, const char *whatfor, KeyFlags abilities, unsigned int app, bool *forced_valid)
Ask the user for a key.
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition exec.c:319
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
QuadOption
Possible values for a quad-option.
Definition quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
enum QuadOption query_yesorno_help(const char *prompt, enum QuadOption def, struct ConfigSubset *sub, const char *name)
Ask the user a Yes/No question offering help.
Definition question.c:357
#define TAILQ_FIRST(head)
Definition queue.h:780
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:713
+ 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 3700 of file crypt_gpgme.c.

3701{
3702 int rc = -1;
3703 gpgme_error_t err = GPG_ERR_NO_ERROR;
3704 gpgme_key_t key = NULL;
3705 gpgme_user_id_t uid = NULL;
3706 struct CryptKeyInfo *results = NULL, *k = NULL;
3707 struct CryptKeyInfo **kend = NULL;
3708 struct CryptKeyInfo *choice = NULL;
3709
3710 gpgme_ctx_t ctx = create_gpgme_context(false);
3711
3712 /* list all secret keys */
3713 if (gpgme_op_keylist_start(ctx, NULL, 1))
3714 goto cleanup;
3715
3716 kend = &results;
3717
3718 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3719 {
3721
3726
3727 if (key->revoked)
3729 if (key->expired)
3731 if (key->disabled)
3733
3734 int idx;
3735 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3736 {
3737 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3738 k->kobj = key;
3739 gpgme_key_ref(k->kobj);
3740 k->idx = idx;
3741 k->uid = uid->uid;
3742 k->flags = flags;
3743 if (uid->revoked)
3744 k->flags |= KEYFLAG_REVOKED;
3745 k->validity = uid->validity;
3746 *kend = k;
3747 kend = &k->next;
3748 }
3749 gpgme_key_unref(key);
3750 }
3751 if (gpg_err_code(err) != GPG_ERR_EOF)
3752 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3753 gpgme_op_keylist_end(ctx);
3754
3755 if (!results)
3756 {
3757 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3758 from. This error is displayed if no results were found. */
3759 mutt_error(_("No secret keys found"));
3760 goto cleanup;
3761 }
3762
3763 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3764 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3765 goto cleanup;
3766 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3767
3768 rc = 0;
3769
3770cleanup:
3771 crypt_key_free(&choice);
3772 crypt_key_free(&results);
3773 gpgme_release(ctx);
3774 return rc;
3775}
+ 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 3839 of file crypt_gpgme.c.

3840{
3841 /* this initialization should only run one time, but it may be called by
3842 * either pgp_gpgme_init or smime_gpgme_init */
3843 static bool has_run = false;
3844 if (has_run)
3845 return;
3846
3847 gpgme_check_version(NULL);
3848 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3849#ifdef ENABLE_NLS
3850 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3851#endif
3852 has_run = true;
3853}
+ Here is the caller graph for this function:

◆ init_pgp()

static void init_pgp ( void )
static

Initialise the PGP crypto backend.

Definition at line 3858 of file crypt_gpgme.c.

3859{
3860 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3861 {
3862 mutt_error(_("GPGME: OpenPGP protocol not available"));
3863 }
3864}
+ Here is the caller graph for this function:

◆ init_smime()

static void init_smime ( void )
static

Initialise the SMIME crypto backend.

Definition at line 3869 of file crypt_gpgme.c.

3870{
3871 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3872 {
3873 mutt_error(_("GPGME: CMS protocol not available"));
3874 }
3875}
+ 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 3901 of file crypt_gpgme.c.

3902{
3903 struct CryptKeyInfo *p = NULL;
3904 const char *prompt = NULL;
3905 const char *letters = NULL;
3906 const char *choices = NULL;
3907 int choice;
3908
3909 if (is_smime)
3911 else
3913
3914 /* Opportunistic encrypt is controlling encryption.
3915 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3916 * letter choices for those.
3917 */
3918 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3919 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3920 {
3921 if (is_smime)
3922 {
3923 /* L10N: S/MIME options (opportunistic encryption is on) */
3924 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3925 /* L10N: S/MIME options (opportunistic encryption is on) */
3926 letters = _("sapco");
3927 choices = "SapCo";
3928 }
3929 else
3930 {
3931 /* L10N: PGP options (opportunistic encryption is on) */
3932 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3933 /* L10N: PGP options (opportunistic encryption is on) */
3934 letters = _("samco");
3935 choices = "SamCo";
3936 }
3937 }
3938 else if (c_crypt_opportunistic_encrypt)
3939 {
3940 /* Opportunistic encryption option is set, but is toggled off for this message. */
3941 if (is_smime)
3942 {
3943 /* L10N: S/MIME options (opportunistic encryption is off) */
3944 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3945 /* L10N: S/MIME options (opportunistic encryption is off) */
3946 letters = _("esabpco");
3947 choices = "esabpcO";
3948 }
3949 else
3950 {
3951 /* L10N: PGP options (opportunistic encryption is off) */
3952 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3953 /* L10N: PGP options (opportunistic encryption is off) */
3954 letters = _("esabmco");
3955 choices = "esabmcO";
3956 }
3957 }
3958 else
3959 {
3960 /* Opportunistic encryption is unset */
3961 if (is_smime)
3962 {
3963 /* L10N: S/MIME options */
3964 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
3965 /* L10N: S/MIME options */
3966 letters = _("esabpc");
3967 choices = "esabpc";
3968 }
3969 else
3970 {
3971 /* L10N: PGP options */
3972 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
3973 /* L10N: PGP options */
3974 letters = _("esabmc");
3975 choices = "esabmc";
3976 }
3977 }
3978
3979 choice = mw_multi_choice(prompt, letters);
3980 if (choice > 0)
3981 {
3982 switch (choices[choice - 1])
3983 {
3984 case 'a': /* sign (a)s */
3985 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3986 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
3987 if (p)
3988 {
3989 char input_signas[128] = { 0 };
3990 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
3991
3992 if (is_smime)
3993 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", input_signas, NULL);
3994 else
3995 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
3996
3997 crypt_key_free(&p);
3998
3999 e->security |= SEC_SIGN;
4000 }
4001 break;
4002
4003 case 'b': /* (b)oth */
4004 e->security |= (SEC_ENCRYPT | SEC_SIGN);
4005 break;
4006
4007 case 'C':
4008 e->security &= ~SEC_SIGN;
4009 break;
4010
4011 case 'c': /* (c)lear */
4012 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
4013 break;
4014
4015 case 'e': /* (e)ncrypt */
4016 e->security |= SEC_ENCRYPT;
4017 e->security &= ~SEC_SIGN;
4018 break;
4019
4020 case 'm': /* (p)gp or s/(m)ime */
4021 case 'p':
4022 is_smime = !is_smime;
4023 if (is_smime)
4024 {
4027 }
4028 else
4029 {
4032 }
4034 break;
4035
4036 case 'O': /* oppenc mode on */
4039 break;
4040
4041 case 'o': /* oppenc mode off */
4043 break;
4044
4045 case 'S': /* (s)ign in oppenc mode */
4046 e->security |= SEC_SIGN;
4047 break;
4048
4049 case 's': /* (s)ign */
4050 e->security &= ~SEC_ENCRYPT;
4051 e->security |= SEC_SIGN;
4052 break;
4053 }
4054 }
4055
4056 return e->security;
4057}
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition crypt.c:1050
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition question.c:62
@ SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:100
@ SEC_SIGN
Email is signed.
Definition lib.h:93
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
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:392
+ 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 4080 of file crypt_gpgme.c.

4081{
4083 struct Address *sender = NULL;
4084 bool rc = true;
4085
4086 if (!TAILQ_EMPTY(&e->env->from))
4087 {
4089 sender = TAILQ_FIRST(&e->env->from);
4090 }
4091 else if (!TAILQ_EMPTY(&e->env->sender))
4092 {
4094 sender = TAILQ_FIRST(&e->env->sender);
4095 }
4096
4097 if (sender)
4098 {
4099 if ((gpgme_key_t) mod_data->signature_key)
4100 {
4101 gpgme_key_t key = (gpgme_key_t) mod_data->signature_key;
4102 gpgme_user_id_t uid = NULL;
4103 int sender_length = buf_len(sender->mailbox);
4104 for (uid = key->uids; uid && rc; uid = uid->next)
4105 {
4106 int uid_length = strlen(uid->email);
4107 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4108 (uid_length == (sender_length + 2)))
4109 {
4110 const char *at_sign = strchr(uid->email + 1, '@');
4111 if (at_sign)
4112 {
4113 /* Assume address is 'mailbox@domainname'.
4114 * The mailbox part is case-sensitive,
4115 * the domainname is not. (RFC2821) */
4116 const char *tmp_email = uid->email + 1;
4117 const char *tmp_sender = buf_string(sender->mailbox);
4118 /* length of mailbox part including '@' */
4119 int mailbox_length = at_sign - tmp_email + 1;
4120 int domainname_length = sender_length - mailbox_length;
4121 int mailbox_match, domainname_match;
4122
4123 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4124 tmp_email += mailbox_length;
4125 tmp_sender += mailbox_length;
4126 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4127 if (mailbox_match && domainname_match)
4128 rc = false;
4129 }
4130 else
4131 {
4132 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4133 rc = false;
4134 }
4135 }
4136 }
4137 }
4138 else
4139 {
4140 mutt_any_key_to_continue(_("Failed to verify sender"));
4141 }
4142 }
4143 else
4144 {
4145 mutt_any_key_to_continue(_("Failed to figure out sender"));
4146 }
4147
4148 if ((gpgme_key_t) mod_data->signature_key)
4149 {
4150 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4151 mod_data->signature_key = NULL;
4152 }
4153
4154 return rc;
4155}
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition alias.c:296
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:497
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:174
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:443
#define TAILQ_EMPTY(head)
Definition queue.h:778
struct Envelope * env
Envelope information.
Definition email.h:68
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 4180 of file crypt_gpgme.c.

4181{
4182 return GPGME_VERSION;
4183}
+ Here is the caller graph for this function:

◆ gpgme_id_defaults_cleanup()

void gpgme_id_defaults_cleanup ( struct NcryptModuleData * mod_data)

Free the GPGME IdDefaults cache.

Parameters
mod_dataNcrypt module data

Definition at line 4189 of file crypt_gpgme.c.

4190{
4191 struct CryptCache *l = mod_data->gpgme_id_defaults;
4192 while (l)
4193 {
4194 struct CryptCache *next = l->next;
4195 FREE(&l->what);
4196 FREE(&l->dflt);
4197 FREE(&l);
4198 l = next;
4199 }
4200 mod_data->gpgme_id_defaults = NULL;
4201
4202 if ((gpgme_key_t) mod_data->signature_key)
4203 {
4204 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4205 mod_data->signature_key = NULL;
4206 }
4207}
+ Here is the caller graph for this function: