NeoMutt  2025-12-11-769-g906513
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.
 
int crypt_id_is_valid (struct CryptKeyInfo *key)
 Is key ID valid.
 
static int crypt_id_matches_addr (struct Address *addr, struct Address *u_addr, struct CryptKeyInfo *key)
 Does the key ID match the address.
 
gpgme_ctx_t create_gpgme_context (bool for_smime)
 Create a new GPGME context.
 
static gpgme_data_t create_gpgme_data (void)
 Create a new GPGME data object.
 
static gpgme_data_t body_to_data_object (struct Body *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 (void)
 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:102
+ 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:46
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:44
gpgme_validity_t validity
uid validity (cached for convenience)
Definition crypt_gpgme.h:50
KeyFlags flags
global and per uid flags (for convenience)
Definition crypt_gpgme.h:49
int idx
and the user ID at this index
Definition crypt_gpgme.h:47
const char * uid
and for convenience point to this user ID
Definition crypt_gpgme.h:48
+ Here is the 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:45
+ Here is the caller graph for this function:

◆ crypt_id_is_strong()

bool crypt_id_is_strong ( struct CryptKeyInfo * key)

Is the key strong.

Parameters
keyKey to test
Return values
trueValidity of key is sufficient

Definition at line 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}
#define KEYFLAG_ISX509
Key is an X.509 key.
Definition lib.h:138
+ Here is the caller graph for this function:

◆ crypt_id_is_valid()

int crypt_id_is_valid ( struct CryptKeyInfo * key)

Is key ID valid.

Parameters
keyKey to test
Return values
trueKey is valid

When the key is not marked as unusable

Definition at line 304 of file crypt_gpgme.c.

305{
306 if (!key)
307 return 0;
308
309 return !(key->flags & KEYFLAG_CANTUSE);
310}
#define KEYFLAG_CANTUSE
Definition lib.h:148
+ 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:695
#define CRYPT_KV_STRING
Definition crypt_gpgme.c:77
int 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:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
#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:571
+ 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:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
+ 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:665
#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:80
Ncrypt private Module data.
Definition module_data.h:38
char * current_sender
Current sender for GPGME.
Definition module_data.h:47
+ 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:291
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:58
+ 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:446
+ 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.
#define STATE_DISPLAY
Output is displayed to the user.
Definition state.h:33
gpgme_key_t signature_key
GPGME Signature key.
Definition module_data.h:44
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:52
FILE * fp_out
File to write to.
Definition state.h:50
+ 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:49
+ 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:1794
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1331
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 MUTT_SAVE_NO_FLAGS) != 0)
2237 {
2238 unlink(buf_string(tempfile));
2239 goto cleanup;
2240 }
2241
2242 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2243 if (!fp_tmp)
2244 {
2245 unlink(buf_string(tempfile));
2246 goto cleanup;
2247 }
2248
2249 while (fgets(buf, sizeof(buf), fp_tmp))
2250 {
2251 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2252 if (plen != 0)
2253 {
2254 if (MESSAGE(buf + plen))
2255 {
2256 enc = true;
2257 break;
2258 }
2259 else if (SIGNED_MESSAGE(buf + plen))
2260 {
2261 sgn = true;
2262 break;
2263 }
2264 }
2265 }
2266 mutt_file_fclose(&fp_tmp);
2267 unlink(buf_string(tempfile));
2268
2269 if (!enc && !sgn)
2270 goto cleanup;
2271
2272 /* fix the content type */
2273
2274 mutt_param_set(&b->parameter, "format", "fixed");
2275 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2276
2277 rc = true;
2278
2279cleanup:
2280 buf_pool_release(&tempfile);
2281 return rc;
2282}
#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
#define STATE_NO_FLAGS
No flags are set.
Definition state.h:32
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_NO_FLAGS
Overwrite existing file (the default)
Definition mutt_attach.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ copy_clearsigned()

static void copy_clearsigned ( gpgme_data_t data,
struct State * state,
char * charset )
static

Copy a clearsigned message.

Parameters
dataGPGME data object
stateState to use
charsetCharset of message

strip the signature and PGP's dash-escaping.

XXX charset handling: We assume that it is safe to do character set decoding first, dash decoding second here, while we do it the other way around in the main handler.

(Note that we aren't worse than Outlook & Cie in this, and also note that we can successfully handle anything produced by any existing versions of neomutt.)

Definition at line 2423 of file crypt_gpgme.c.

2424{
2425 char buf[8192] = { 0 };
2426 bool complete, armor_header;
2427 FILE *fp = NULL;
2428
2429 char *fname = data_object_to_tempfile(data, &fp);
2430 if (!fname)
2431 {
2432 mutt_file_fclose(&fp);
2433 return;
2434 }
2435 unlink(fname);
2436 FREE(&fname);
2437
2438 /* fromcode comes from the MIME Content-Type charset label. It might
2439 * be a wrong label, so we want the ability to do corrections via
2440 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2442
2443 for (complete = true, armor_header = true;
2444 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2445 {
2446 if (!complete)
2447 {
2448 if (!armor_header)
2449 state_puts(state, buf);
2450 continue;
2451 }
2452
2453 if (BEGIN_PGP_SIGNATURE(buf))
2454 break;
2455
2456 if (armor_header)
2457 {
2458 if (buf[0] == '\n')
2459 armor_header = false;
2460 continue;
2461 }
2462
2463 if (state->prefix)
2464 state_puts(state, state->prefix);
2465
2466 if ((buf[0] == '-') && (buf[1] == ' '))
2467 state_puts(state, buf + 2);
2468 else
2469 state_puts(state, buf);
2470 }
2471
2474}
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:51
+ 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 2956 of file crypt_gpgme.c.

2957{
2958 unsigned int rc = 0;
2959
2960 switch (cap)
2961 {
2963 rc = key->can_encrypt;
2964 if (rc == 0)
2965 {
2966 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2967 {
2968 rc = subkey->can_encrypt;
2969 if (rc != 0)
2970 break;
2971 }
2972 }
2973 break;
2974 case KEY_CAP_CAN_SIGN:
2975 rc = key->can_sign;
2976 if (rc == 0)
2977 {
2978 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2979 {
2980 rc = subkey->can_sign;
2981 if (rc != 0)
2982 break;
2983 }
2984 }
2985 break;
2987 rc = key->can_certify;
2988 if (rc == 0)
2989 {
2990 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2991 {
2992 rc = subkey->can_certify;
2993 if (rc != 0)
2994 break;
2995 }
2996 }
2997 break;
2998 }
2999
3000 return rc;
3001}
@ KEY_CAP_CAN_CERTIFY
Key can be used to certify.
Definition crypt_gpgme.h:79
@ KEY_CAP_CAN_ENCRYPT
Key can be used for encryption.
Definition crypt_gpgme.h:77
@ KEY_CAP_CAN_SIGN
Key can be used for signing.
Definition crypt_gpgme.h:78
+ 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 3012 of file crypt_gpgme.c.

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

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

3233{
3234 char *scratch = mutt_str_dup(str);
3235 if (!scratch)
3236 return;
3237
3238 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3239 {
3240 if (strlen(t) > 3)
3242 }
3243
3244 FREE(&scratch);
3245}
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 3256 of file crypt_gpgme.c.

3259{
3260 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3261
3262 int multi = false;
3263 int this_key_has_strong = false;
3264 int this_key_has_addr_match = false;
3265 int match = false;
3266
3267 struct CryptKeyInfo *keys = NULL, *k = NULL;
3268 struct CryptKeyInfo *the_strong_valid_key = NULL;
3269 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3270 struct CryptKeyInfo *matches = NULL;
3271 struct CryptKeyInfo **matches_endp = &matches;
3272
3273 if (a && a->mailbox)
3275 if (a && a->personal)
3277
3278 if (!oppenc_mode)
3279 mutt_message(_("Looking for keys matching \"%s\"..."), a ? buf_string(a->mailbox) : "");
3280 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3281
3282 mutt_list_free(&hints);
3283
3284 if (!keys)
3285 return NULL;
3286
3287 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n",
3288 a ? buf_string(a->personal) : "", a ? buf_string(a->mailbox) : "");
3289
3290 for (k = keys; k; k = k->next)
3291 {
3292 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3293
3294 if (abilities && !(k->flags & abilities))
3295 {
3296 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3297 continue;
3298 }
3299
3300 this_key_has_strong = false; /* strong and valid match */
3301 this_key_has_addr_match = false;
3302 match = false; /* any match */
3303
3304 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3305 mutt_addrlist_parse(&alist, k->uid);
3306 struct Address *ka = NULL;
3307 TAILQ_FOREACH(ka, &alist, entries)
3308 {
3309 int validity = crypt_id_matches_addr(a, ka, k);
3310
3311 if (validity & CRYPT_KV_MATCH) /* something matches */
3312 {
3313 match = true;
3314
3315 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3316 {
3317 if (validity & CRYPT_KV_STRONGID)
3318 {
3319 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3320 multi = true;
3321 this_key_has_strong = true;
3322 }
3323 else
3324 {
3325 this_key_has_addr_match = true;
3326 }
3327 }
3328 }
3329 }
3330 mutt_addrlist_clear(&alist);
3331
3332 if (match)
3333 {
3334 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3335 *matches_endp = tmp;
3336 matches_endp = &tmp->next;
3337
3338 if (this_key_has_strong)
3339 the_strong_valid_key = tmp;
3340 else if (this_key_has_addr_match)
3341 a_valid_addrmatch_key = tmp;
3342 }
3343 }
3344
3345 crypt_key_free(&keys);
3346
3347 if (matches)
3348 {
3349 if (oppenc_mode || !isatty(STDIN_FILENO))
3350 {
3351 const bool c_crypt_opportunistic_encrypt_strong_keys =
3352 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3353 if (the_strong_valid_key)
3354 k = crypt_copy_key(the_strong_valid_key);
3355 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3356 k = crypt_copy_key(a_valid_addrmatch_key);
3357 else
3358 k = NULL;
3359 }
3360 else if (the_strong_valid_key && !multi)
3361 {
3362 /* There was precisely one strong match on a valid ID.
3363 * Proceed without asking the user. */
3364 k = crypt_copy_key(the_strong_valid_key);
3365 }
3366 else
3367 {
3368 /* Else: Ask the user. */
3369 k = dlg_gpgme(matches, a, NULL, app, forced_valid);
3370 }
3371
3372 crypt_key_free(&matches);
3373 }
3374 else
3375 {
3376 k = NULL;
3377 }
3378
3379 return k;
3380}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1469
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 3390 of file crypt_gpgme.c.

3392{
3393 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3394 struct CryptKeyInfo *matches = NULL;
3395 struct CryptKeyInfo **matches_endp = &matches;
3396 struct CryptKeyInfo *k = NULL;
3397 const char *ps = NULL, *pl = NULL, *phint = NULL;
3398
3399 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3400
3401 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3402 crypt_add_string_to_hints(phint, &hints);
3403 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3404 mutt_list_free(&hints);
3405
3406 if (!keys)
3407 {
3408 FREE(&pfcopy);
3409 return NULL;
3410 }
3411
3412 for (k = keys; k; k = k->next)
3413 {
3414 if (abilities && !(k->flags & abilities))
3415 continue;
3416
3417 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3418 crypt_long_keyid(k), k->uid);
3419
3420 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3421 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3422 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3423 {
3424 mutt_debug(LL_DEBUG5, "match\n");
3425
3426 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3427 *matches_endp = tmp;
3428 matches_endp = &tmp->next;
3429 }
3430 else
3431 {
3432 mutt_debug(LL_DEBUG5, "no match\n");
3433 }
3434 }
3435
3436 FREE(&pfcopy);
3437 crypt_key_free(&keys);
3438
3439 if (matches)
3440 {
3441 if (isatty(STDIN_FILENO))
3442 {
3443 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3444
3445 crypt_key_free(&matches);
3446 return k;
3447 }
3448 else
3449 {
3450 if (crypt_keys_are_valid(matches))
3451 return matches;
3452
3453 crypt_key_free(&matches);
3454 return NULL;
3455 }
3456 }
3457
3458 return NULL;
3459}
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 3473 of file crypt_gpgme.c.

3476{
3478 struct CryptKeyInfo *key = NULL;
3479 struct CryptCache *l = NULL;
3480 struct Buffer *resp = buf_pool_get();
3481
3483
3484 if (whatfor)
3485 {
3486 for (l = (struct CryptCache *) mod_data->gpgme_id_defaults; l; l = l->next)
3487 {
3488 if (mutt_istr_equal(whatfor, l->what))
3489 {
3490 buf_strcpy(resp, l->dflt);
3491 break;
3492 }
3493 }
3494 }
3495
3496 while (true)
3497 {
3498 buf_reset(resp);
3499 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
3500 {
3501 goto done;
3502 }
3503
3504 if (whatfor)
3505 {
3506 if (l)
3507 {
3508 mutt_str_replace(&l->dflt, buf_string(resp));
3509 }
3510 else
3511 {
3512 l = MUTT_MEM_MALLOC(1, struct CryptCache);
3513 l->next = (struct CryptCache *) mod_data->gpgme_id_defaults;
3514 mod_data->gpgme_id_defaults = l;
3515 l->what = mutt_str_dup(whatfor);
3516 l->dflt = buf_strdup(resp);
3517 }
3518 }
3519
3520 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3521 if (key)
3522 goto done;
3523
3524 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3525 }
3526
3527done:
3528 buf_pool_release(&resp);
3529 return key;
3530}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
Find a key by string.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition wdata.h:42
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:467
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:60
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:42
+ 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 3543 of file crypt_gpgme.c.

3544{
3545 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3546 struct ListNode *crypt_hook = NULL;
3547 const char *keyid = NULL;
3548 char *keylist = NULL;
3549 size_t keylist_size = 0;
3550 size_t keylist_used = 0;
3551 struct Address *p = NULL;
3552 struct CryptKeyInfo *k_info = NULL;
3553 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3554 char buf[1024] = { 0 };
3555 bool forced_valid = false;
3556 bool key_selected;
3557 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3558
3559 struct Address *a = NULL;
3560 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3561 /* Iterate through each recipient address to find an encryption key */
3562 TAILQ_FOREACH(a, addrlist, entries)
3563 {
3564 key_selected = false;
3565 /* Check for crypt-hook overrides for this recipient */
3566 mutt_crypt_hook(&crypt_hook_list, a);
3567 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3568 do
3569 {
3570 p = a;
3571 forced_valid = false;
3572 k_info = NULL;
3573
3574 /* If a crypt-hook provides a key ID, confirm with the user unless
3575 * in opportunistic encryption mode */
3576 if (crypt_hook)
3577 {
3578 keyid = crypt_hook->data;
3579 enum QuadOption ans = MUTT_YES;
3580 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3581 {
3582 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3583 buf_string(p->mailbox));
3584 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3585 }
3586 if (ans == MUTT_YES)
3587 {
3588 if (crypt_is_numerical_keyid(keyid))
3589 {
3590 if (mutt_strn_equal(keyid, "0x", 2))
3591 keyid += 2;
3592 goto bypass_selection; /* you don't see this. */
3593 }
3594
3595 /* check for e-mail address */
3596 mutt_addrlist_clear(&hookal);
3597 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3598 {
3599 mutt_addrlist_qualify(&hookal, fqdn);
3600 p = TAILQ_FIRST(&hookal);
3601 }
3602 else if (!oppenc_mode)
3603 {
3604 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3605 }
3606 }
3607 else if (ans == MUTT_NO)
3608 {
3609 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3610 {
3611 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3612 continue;
3613 }
3614 }
3615 else if (ans == MUTT_ABORT)
3616 {
3617 FREE(&keylist);
3618 mutt_addrlist_clear(&hookal);
3619 mutt_list_free(&crypt_hook_list);
3620 return NULL;
3621 }
3622 }
3623
3624 /* If no key found yet, try looking up by address in the keyring */
3625 if (!k_info)
3626 {
3627 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3628 }
3629
3630 /* Last resort: prompt the user to enter a key ID interactively */
3631 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3632 {
3633 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3634
3635 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3636 KEYFLAG_CANENCRYPT, app, &forced_valid);
3637 }
3638
3639 if (!k_info)
3640 {
3641 FREE(&keylist);
3642 mutt_addrlist_clear(&hookal);
3643 mutt_list_free(&crypt_hook_list);
3644 return NULL;
3645 }
3646
3647 keyid = crypt_fpr_or_lkeyid(k_info);
3648
3649 bypass_selection:
3650 /* Append the selected key ID to the space-separated keylist string */
3651 keylist_size += mutt_str_len(keyid) + 4 + 1;
3652 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
3653 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3654 keyid, forced_valid ? "!" : "");
3655 keylist_used = mutt_str_len(keylist);
3656
3657 key_selected = true;
3658
3659 crypt_key_free(&k_info);
3660 mutt_addrlist_clear(&hookal);
3661
3662 if (crypt_hook)
3663 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3664
3665 } while (crypt_hook);
3666
3667 mutt_list_free(&crypt_hook_list);
3668 }
3669 return keylist;
3670}
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 3701 of file crypt_gpgme.c.

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

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

◆ init_pgp()

static void init_pgp ( void )
static

Initialise the PGP crypto backend.

Definition at line 3859 of file crypt_gpgme.c.

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

◆ init_smime()

static void init_smime ( void )
static

Initialise the SMIME crypto backend.

Definition at line 3870 of file crypt_gpgme.c.

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

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

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

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

◆ gpgme_id_defaults_cleanup()

void gpgme_id_defaults_cleanup ( void )

Free the GPGME IdDefaults cache.

Definition at line 4189 of file crypt_gpgme.c.

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