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

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

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

Go to the source code of this file.

Data Structures

struct  CryptCache
 Internal cache for GPGME. More...

Macros

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

Functions

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

Detailed Description

Wrapper for PGP/SMIME calls to GPGME.

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

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

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

Definition in file crypt_gpgme.c.

Macro Definition Documentation

◆ CRYPT_KV_VALID

#define CRYPT_KV_VALID   (1 << 0)

Definition at line 75 of file crypt_gpgme.c.

◆ CRYPT_KV_ADDR

#define CRYPT_KV_ADDR   (1 << 1)

Definition at line 76 of file crypt_gpgme.c.

◆ CRYPT_KV_STRING

#define CRYPT_KV_STRING   (1 << 2)

Definition at line 77 of file crypt_gpgme.c.

◆ CRYPT_KV_STRONGID

#define CRYPT_KV_STRONGID   (1 << 3)

Definition at line 78 of file crypt_gpgme.c.

◆ CRYPT_KV_MATCH

#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)

Definition at line 79 of file crypt_gpgme.c.

◆ PKA_NOTATION_NAME

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

Definition at line 92 of file crypt_gpgme.c.

◆ _LINE_COMPARE

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

Definition at line 94 of file crypt_gpgme.c.

◆ MESSAGE

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

Definition at line 95 of file crypt_gpgme.c.

◆ SIGNED_MESSAGE

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

Definition at line 96 of file crypt_gpgme.c.

◆ PUBLIC_KEY_BLOCK

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

Definition at line 97 of file crypt_gpgme.c.

◆ BEGIN_PGP_SIGNATURE

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

Definition at line 98 of file crypt_gpgme.c.

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

Function Documentation

◆ is_pka_notation()

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:666
Here is the call graph for this function:
Here is the caller graph for this function:

◆ redraw_if_needed()

void redraw_if_needed ( gpgme_ctx_t ctx)
static

Accommodate for a redraw if needed.

Parameters
ctxGPGME handle

Definition at line 115 of file crypt_gpgme.c.

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

◆ crypt_keyid()

const char * crypt_keyid ( struct CryptKeyInfo * k)

Find the ID for the key.

Parameters
kKey to use
Return values
ptrID string for the key

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

Definition at line 132 of file crypt_gpgme.c.

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

◆ crypt_long_keyid()

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()

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()

const char * crypt_fpr ( struct CryptKeyInfo * k)
static

Get the hexstring fingerprint from a key.

Parameters
kKey to use
Return values
ptrHexstring fingerprint

Definition at line 193 of file crypt_gpgme.c.

194{
195 const char *s = "";
196
197 if (k->kobj && k->kobj->subkeys)
198 s = k->kobj->subkeys->fpr;
199
200 return s;
201}
Here is the caller graph for this function:

◆ crypt_fpr_or_lkeyid()

const char * crypt_fpr_or_lkeyid ( struct CryptKeyInfo * k)

Find the fingerprint of a key.

Parameters
kKey to examine
Return values
ptrFingerprint if available, otherwise the long keyid

Definition at line 208 of file crypt_gpgme.c.

209{
210 const char *s = "????????????????";
211
212 if (k->kobj && k->kobj->subkeys)
213 {
214 if (k->kobj->subkeys->fpr)
215 s = k->kobj->subkeys->fpr;
216 else
217 s = k->kobj->subkeys->keyid;
218 }
219
220 return s;
221}
Here is the caller graph for this function:

◆ crypt_copy_key()

struct CryptKeyInfo * crypt_copy_key ( struct CryptKeyInfo * key)

Return a copy of KEY.

Parameters
keyKey to copy
Return values
ptrCopy of key

Definition at line 228 of file crypt_gpgme.c.

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

◆ crypt_key_free()

void crypt_key_free ( struct CryptKeyInfo ** keylist)
static

Release all the keys in a list.

Parameters
[out]keylistList of keys

Definition at line 247 of file crypt_gpgme.c.

248{
249 if (!keylist)
250 return;
251
252 struct CryptKeyInfo *k = NULL;
253
254 while (*keylist)
255 {
256 k = *keylist;
257 *keylist = (*keylist)->next;
258
259 gpgme_key_unref(k->kobj);
260 FREE(&k);
261 }
262}
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
struct CryptKeyInfo * next
Linked list.
Definition crypt_gpgme.h:46
Here is the caller graph for this function:

◆ crypt_id_is_strong()

bool crypt_id_is_strong ( struct CryptKeyInfo * key)

Is the key strong.

Parameters
keyKey to test
Return values
trueValidity of key is sufficient

Definition at line 269 of file crypt_gpgme.c.

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

◆ crypt_id_is_valid()

bool crypt_id_is_valid ( struct CryptKeyInfo * key)

Is key ID valid.

Parameters
keyKey to test
Return values
trueKey is valid

When the key is not marked as unusable

Definition at line 304 of file crypt_gpgme.c.

305{
306 if (!key)
307 return false;
308
309 return !(key->flags & KEYFLAG_CANTUSE);
310}
#define KEYFLAG_CANTUSE
Definition lib.h:161
Here is the caller graph for this function:

◆ crypt_id_matches_addr()

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

Does the key ID match the address.

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

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

Definition at line 322 of file crypt_gpgme.c.

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

◆ create_gpgme_context()

gpgme_ctx_t create_gpgme_context ( bool for_smime)

Create a new GPGME context.

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

Definition at line 355 of file crypt_gpgme.c.

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

◆ create_gpgme_data()

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()

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;
434 int hadcr = 0;
435 unsigned char buf[1] = { 0 };
436
438 fseek(fp_tmp, 0, SEEK_SET);
439 clearerr(fp_tmp);
440 while ((c = fgetc(fp_tmp)) != EOF)
441 {
442 if (c == '\r')
443 {
444 hadcr = 1;
445 }
446 else
447 {
448 if ((c == '\n') && !hadcr)
449 {
450 buf[0] = '\r';
451 gpgme_data_write(data, buf, 1);
452 }
453
454 hadcr = 0;
455 }
456 /* FIXME: This is quite suboptimal */
457 buf[0] = c;
458 gpgme_data_write(data, buf, 1);
459 }
460 mutt_file_fclose(&fp_tmp);
461 gpgme_data_seek(data, 0, SEEK_SET);
462 }
463 else
464 {
465 mutt_file_fclose(&fp_tmp);
466 err = gpgme_data_new_from_file(&data, buf_string(tempfile), 1);
467 if (err != GPG_ERR_NO_ERROR)
468 {
469 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
470 gpgme_data_release(data);
471 data = NULL;
472 /* fall through to unlink the tempfile */
473 }
474 }
475 unlink(buf_string(tempfile));
476
477cleanup:
478 buf_pool_release(&tempfile);
479 return data;
480}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
#define mutt_perror(...)
Definition logging2.h:95
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition body.c:304
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition header.c:763
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()

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

490{
491 gpgme_data_t data = NULL;
492
493 gpgme_error_t err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length);
494 if (err != GPG_ERR_NO_ERROR)
495 {
496 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
497 return NULL;
498 }
499
500 return data;
501}
Here is the caller graph for this function:

◆ data_object_to_stream()

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

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

◆ data_object_to_tempfile()

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

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

◆ create_recipient_string()

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

622{
623 unsigned int n = 0;
624
625 const char *s = keylist;
626 do
627 {
628 while (*s == ' ')
629 s++;
630 if (*s != '\0')
631 {
632 if (n == 0)
633 {
634 if (!use_smime)
635 buf_addstr(recpstring, "--\n");
636 }
637 else
638 {
639 buf_addch(recpstring, '\n');
640 }
641 n++;
642
643 while ((*s != '\0') && (*s != ' '))
644 buf_addch(recpstring, *s++);
645 }
646 } while (*s != '\0');
647}
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:248
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:233
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_signer_from_address()

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

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

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

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

◆ set_pka_sig_notation()

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

770{
772 gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME,
773 mod_data->current_sender, 0);
774 if (err != GPG_ERR_NO_ERROR)
775 {
776 mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
777 }
778
779 return err;
780}
@ MODULE_ID_NCRYPT
ModuleNcrypt, Ncrypt
Definition module_api.h:82
Ncrypt private Module data.
Definition module_data.h:39
char * current_sender
Current sender for GPGME.
Definition module_data.h:48
Here is the call graph for this function:
Here is the caller graph for this function:

◆ encrypt_gpgme_object()

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

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

◆ get_micalg()

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

864{
865 gpgme_sign_result_t result = NULL;
866 const char *algorithm_name = NULL;
867
868 if (buflen < 5)
869 return -1;
870
871 *buf = '\0';
872 result = gpgme_op_sign_result(ctx);
873 if (result && result->signatures)
874 {
875 algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
876 if (algorithm_name)
877 {
878 if (use_smime)
879 {
880 /* convert GPGME raw hash name to RFC2633 format */
881 snprintf(buf, buflen, "%s", algorithm_name);
882 mutt_str_lower(buf);
883 }
884 else
885 {
886 /* convert GPGME raw hash name to RFC3156 format */
887 snprintf(buf, buflen, "pgp-%s", algorithm_name);
888 mutt_str_lower(buf + 4);
889 }
890 }
891 }
892
893 return (buf[0] != '\0') ? 0 : -1;
894}
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()

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

902{
903 char p[256] = { 0 };
904 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
905 state_puts(state, p);
906}
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition date.c:957
#define state_puts(STATE, STR)
Definition state.h:64
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sign_message()

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

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

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

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

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

1270{
1271 if (!key)
1272 return;
1273
1274 const char *prefix = _("Fingerprint: ");
1275
1276 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1277 if (!s)
1278 return;
1279 bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1280
1281 char *buf = MUTT_MEM_MALLOC(strlen(prefix) + strlen(s) * 4 + 2, char);
1282 strcpy(buf, prefix);
1283 char *p = buf + strlen(buf);
1284 if (is_pgp && (strlen(s) == 40))
1285 { /* PGP v4 style formatted. */
1286 for (int i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
1287 {
1288 *p++ = s[0];
1289 *p++ = s[1];
1290 *p++ = s[2];
1291 *p++ = s[3];
1292 *p++ = ' ';
1293 if (i == 4)
1294 *p++ = ' ';
1295 }
1296 }
1297 else
1298 {
1299 for (int i = 0; *s && s[1] && s[2]; s += 2, i++)
1300 {
1301 *p++ = s[0];
1302 *p++ = s[1];
1303 *p++ = is_pgp ? ' ' : ':';
1304 if (is_pgp && (i == 7))
1305 *p++ = ' ';
1306 }
1307 }
1308
1309 /* just in case print remaining odd digits */
1310 for (; *s; s++)
1311 *p++ = *s;
1312 *p++ = '\n';
1313 *p = '\0';
1314 state_puts(state, buf);
1315 FREE(&buf);
1316}
#define MUTT_MEM_MALLOC(n, type)
Definition memory.h:53
Here is the caller graph for this function:

◆ show_one_sig_validity()

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

1325{
1326 gpgme_signature_t sig = NULL;
1327 const char *txt = NULL;
1328
1329 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1330 if (result)
1331 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--)
1332 ; // do nothing
1333
1334 switch (sig ? sig->validity : 0)
1335 {
1336 case GPGME_VALIDITY_UNKNOWN:
1337 txt = _("WARNING: We have NO indication whether the key belongs to the person named as shown above\n");
1338 break;
1339 case GPGME_VALIDITY_UNDEFINED:
1340 break;
1341 case GPGME_VALIDITY_NEVER:
1342 txt = _("WARNING: The key does NOT BELONG to the person named as shown above\n");
1343 break;
1344 case GPGME_VALIDITY_MARGINAL:
1345 txt = _("WARNING: It is NOT certain that the key belongs to the person named as shown above\n");
1346 break;
1347 case GPGME_VALIDITY_FULL:
1348 case GPGME_VALIDITY_ULTIMATE:
1349 txt = NULL;
1350 break;
1351 default:
1352 break;
1353 }
1354 if (txt)
1355 state_puts(state, txt);
1356}
Here is the caller graph for this function:

◆ print_smime_keyinfo()

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

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

◆ show_one_recipient()

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

1432{
1433 const char *algo = gpgme_pubkey_algo_name(r->pubkey_algo);
1434 if (!algo)
1435 algo = "?";
1436
1437 // L10N: Show the algorithm and key ID of the encryption recipients, e.g
1438 // Recipient: RSA key, ID 1111111111111111
1439 state_printf(state, _("Recipient: %s key, ID %s\n"), algo, r->keyid);
1440}
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()

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

1448{
1449 if (!cs_subset_bool(NeoMutt->sub, "crypt_encryption_info"))
1450 return;
1451
1452 state_attach_puts(state, _("[-- Begin encryption information --]\n"));
1453
1454 for (gpgme_recipient_t r = result->recipients; r; r = r->next)
1455 show_one_recipient(state, r);
1456
1457 state_attach_puts(state, _("[-- End encryption information --]\n\n"));
1458}
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()

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

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

◆ verify_one()

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

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

◆ decrypt_part()

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

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

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

2140{
2141 gpgme_ctx_t tmpctx = NULL;
2142 gpgme_key_t key = NULL;
2143 gpgme_user_id_t uid = NULL;
2144 gpgme_subkey_t subkey = NULL;
2145 const char *shortid = NULL;
2146 size_t len;
2147 char date[256] = { 0 };
2148 bool more;
2149 int rc = -1;
2150 time_t tt;
2151
2152 *fp = mutt_file_mkstemp();
2153 if (!*fp)
2154 {
2155 mutt_perror(_("Can't create temporary file"));
2156 return -1;
2157 }
2158
2159 tmpctx = create_gpgme_context(false);
2160
2161 gpgme_error_t err = gpgme_op_keylist_from_data_start(tmpctx, keydata, 0);
2162 while (err == GPG_ERR_NO_ERROR)
2163 {
2164 err = gpgme_op_keylist_next(tmpctx, &key);
2165 if (err != GPG_ERR_NO_ERROR)
2166 break;
2167 uid = key->uids;
2168 subkey = key->subkeys;
2169 more = false;
2170 while (subkey)
2171 {
2172 shortid = subkey->keyid;
2173 len = mutt_str_len(subkey->keyid);
2174 if (len > 8)
2175 shortid += len - 8;
2176 tt = subkey->timestamp;
2177 mutt_date_localtime_format(date, sizeof(date), "%Y-%m-%d", tt);
2178
2179 fprintf(*fp, "%s %5.5s %u/%8s %s\n", more ? "sub" : "pub",
2180 gpgme_pubkey_algo_name(subkey->pubkey_algo), subkey->length, shortid, date);
2181 if (!more)
2182 {
2183 while (uid)
2184 {
2185 fprintf(*fp, "uid %s\n", NONULL(uid->uid));
2186 uid = uid->next;
2187 }
2188 }
2189 subkey = subkey->next;
2190 more = true;
2191 }
2192 gpgme_key_unref(key);
2193 }
2194 if (gpg_err_code(err) != GPG_ERR_EOF)
2195 {
2196 mutt_debug(LL_DEBUG1, "Error listing keys\n");
2197 goto err_fp;
2198 }
2199
2200 rc = 0;
2201
2202err_fp:
2203 if (rc)
2204 mutt_file_fclose(fp);
2205
2206 gpgme_release(tmpctx);
2207
2208 return rc;
2209}
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()

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

2223{
2224 if (mutt_strn_equal(a, b, n))
2225 {
2226 /* at this point we know that 'b' is at least 'n' chars long */
2227 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2228 return true;
2229 }
2230 return false;
2231}
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()

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

2241{
2242 char buf[8192] = { 0 };
2243 bool rc = false;
2244
2245 bool sgn = false;
2246 bool enc = false;
2247
2248 if (b->type != TYPE_TEXT)
2249 return 0;
2250
2251 struct Buffer *tempfile = buf_pool_get();
2252 buf_mktemp(tempfile);
2254 {
2255 unlink(buf_string(tempfile));
2256 goto cleanup;
2257 }
2258
2259 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2260 if (!fp_tmp)
2261 {
2262 unlink(buf_string(tempfile));
2263 goto cleanup;
2264 }
2265
2266 while (fgets(buf, sizeof(buf), fp_tmp))
2267 {
2268 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2269 if (plen != 0)
2270 {
2271 if (MESSAGE(buf + plen))
2272 {
2273 enc = true;
2274 break;
2275 }
2276 else if (SIGNED_MESSAGE(buf + plen))
2277 {
2278 sgn = true;
2279 break;
2280 }
2281 }
2282 }
2283 mutt_file_fclose(&fp_tmp);
2284 unlink(buf_string(tempfile));
2285
2286 if (!enc && !sgn)
2287 goto cleanup;
2288
2289 /* fix the content type */
2290
2291 mutt_param_set(&b->parameter, "format", "fixed");
2292 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2293
2294 rc = true;
2295
2296cleanup:
2297 buf_pool_release(&tempfile);
2298 return rc;
2299}
#define SIGNED_MESSAGE(_y)
Definition crypt_gpgme.c:96
#define MESSAGE(_y)
Definition crypt_gpgme.c:95
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
@ STATE_NONE
No flags are set.
Definition state.h:36
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
@ MUTT_SAVE_NONE
Overwrite existing file (the default).
Definition mutt_attach.h:59
Here is the call graph for this function:
Here is the caller graph for this function:

◆ copy_clearsigned()

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

2441{
2442 char buf[8192] = { 0 };
2443 bool complete, armor_header;
2444 FILE *fp = NULL;
2445
2446 char *fname = data_object_to_tempfile(data, &fp);
2447 if (!fname)
2448 {
2449 mutt_file_fclose(&fp);
2450 return;
2451 }
2452 unlink(fname);
2453 FREE(&fname);
2454
2455 /* fromcode comes from the MIME Content-Type charset label. It might
2456 * be a wrong label, so we want the ability to do corrections via
2457 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2459
2460 for (complete = true, armor_header = true;
2461 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2462 {
2463 if (!complete)
2464 {
2465 if (!armor_header)
2466 state_puts(state, buf);
2467 continue;
2468 }
2469
2470 if (BEGIN_PGP_SIGNATURE(buf))
2471 break;
2472
2473 if (armor_header)
2474 {
2475 if (buf[0] == '\n')
2476 armor_header = false;
2477 continue;
2478 }
2479
2480 if (state->prefix)
2481 state_puts(state, state->prefix);
2482
2483 if ((buf[0] == '-') && (buf[1] == ' '))
2484 state_puts(state, buf + 2);
2485 else
2486 state_puts(state, buf);
2487 }
2488
2491}
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:921
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition charset.c:1030
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition charset.c:950
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition charset.h:67
Cursor for converting a file's encoding.
Definition charset.h:45
FILE * fp
File to read from.
Definition charset.h:46
const char * prefix
String to add to the beginning of each output line.
Definition state.h:57
Here is the call graph for this function:
Here is the caller graph for this function:

◆ key_check_cap()

unsigned int key_check_cap ( gpgme_key_t key,
enum KeyCap cap )

Check the capabilities of a key.

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

Definition at line 2975 of file crypt_gpgme.c.

2976{
2977 unsigned int rc = 0;
2978
2979 switch (cap)
2980 {
2982 rc = key->can_encrypt;
2983 if (rc == 0)
2984 {
2985 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2986 {
2987 rc = subkey->can_encrypt;
2988 if (rc != 0)
2989 break;
2990 }
2991 }
2992 break;
2993 case KEY_CAP_CAN_SIGN:
2994 rc = key->can_sign;
2995 if (rc == 0)
2996 {
2997 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2998 {
2999 rc = subkey->can_sign;
3000 if (rc != 0)
3001 break;
3002 }
3003 }
3004 break;
3006 rc = key->can_certify;
3007 if (rc == 0)
3008 {
3009 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
3010 {
3011 rc = subkey->can_certify;
3012 if (rc != 0)
3013 break;
3014 }
3015 }
3016 break;
3017 }
3018
3019 return rc;
3020}
@ KEY_CAP_CAN_CERTIFY
Key can be used to certify.
Definition crypt_gpgme.h:80
@ KEY_CAP_CAN_ENCRYPT
Key can be used for encryption.
Definition crypt_gpgme.h:78
@ KEY_CAP_CAN_SIGN
Key can be used for signing.
Definition crypt_gpgme.h:79
Here is the caller graph for this function:

◆ list_to_pattern()

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

3032{
3033 char *pattern = NULL;
3034 char *p = NULL;
3035 const char *s = NULL;
3036 size_t n;
3037
3038 n = 0;
3039 struct ListNode *np = NULL;
3040 STAILQ_FOREACH(np, list, entries)
3041 {
3042 for (s = np->data; *s; s++)
3043 {
3044 if ((*s == '%') || (*s == '+'))
3045 n += 2;
3046 n++;
3047 }
3048 n++; /* delimiter or end of string */
3049 }
3050 n++; /* make sure to allocate at least one byte */
3051 p = MUTT_MEM_CALLOC(n, char);
3052 pattern = p;
3053 STAILQ_FOREACH(np, list, entries)
3054 {
3055 s = np->data;
3056 if (*s)
3057 {
3058 if (np != STAILQ_FIRST(list))
3059 *p++ = ' ';
3060 for (s = np->data; *s; s++)
3061 {
3062 if (*s == '%')
3063 {
3064 *p++ = '%';
3065 *p++ = '2';
3066 *p++ = '5';
3067 }
3068 else if (*s == '+')
3069 {
3070 *p++ = '%';
3071 *p++ = '2';
3072 *p++ = 'B';
3073 }
3074 else if (*s == ' ')
3075 {
3076 *p++ = '+';
3077 }
3078 else
3079 {
3080 *p++ = *s;
3081 }
3082 }
3083 }
3084 }
3085 *p = '\0';
3086 return pattern;
3087}
#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()

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

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

◆ crypt_add_string_to_hints()

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

3255{
3256 char *scratch = mutt_str_dup(str);
3257 if (!scratch)
3258 return;
3259
3260 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3261 {
3262 if (strlen(t) > 3)
3264 }
3265
3266 FREE(&scratch);
3267}
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()

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

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

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

3415{
3416 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3417 struct CryptKeyInfo *matches = NULL;
3418 struct CryptKeyInfo **matches_endp = &matches;
3419 struct CryptKeyInfo *k = NULL;
3420 const char *ps = NULL;
3421 const char *pl = NULL;
3422 const char *phint = NULL;
3423
3424 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3425
3426 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3427 crypt_add_string_to_hints(phint, &hints);
3428 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3429 mutt_list_free(&hints);
3430
3431 if (!keys)
3432 {
3433 FREE(&pfcopy);
3434 return NULL;
3435 }
3436
3437 for (k = keys; k; k = k->next)
3438 {
3439 if (abilities && !(k->flags & abilities))
3440 continue;
3441
3442 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3443 crypt_long_keyid(k), k->uid);
3444
3445 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3446 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3447 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3448 {
3449 mutt_debug(LL_DEBUG5, "match\n");
3450
3451 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3452 *matches_endp = tmp;
3453 matches_endp = &tmp->next;
3454 }
3455 else
3456 {
3457 mutt_debug(LL_DEBUG5, "no match\n");
3458 }
3459 }
3460
3461 FREE(&pfcopy);
3462 crypt_key_free(&keys);
3463
3464 if (matches)
3465 {
3466 if (isatty(STDIN_FILENO))
3467 {
3468 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3469
3470 crypt_key_free(&matches);
3471 return k;
3472 }
3473 else
3474 {
3475 if (crypt_keys_are_valid(matches))
3476 return matches;
3477
3478 crypt_key_free(&matches);
3479 return NULL;
3480 }
3481 }
3482
3483 return NULL;
3484}
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:1397
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:678
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()

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

3501{
3503 struct CryptKeyInfo *key = NULL;
3504 struct CryptCache *l = NULL;
3505 struct Buffer *resp = buf_pool_get();
3506
3508
3509 if (whatfor)
3510 {
3511 for (l = (struct CryptCache *) mod_data->gpgme_id_defaults; l; l = l->next)
3512 {
3513 if (mutt_istr_equal(whatfor, l->what))
3514 {
3515 buf_strcpy(resp, l->dflt);
3516 break;
3517 }
3518 }
3519 }
3520
3521 while (true)
3522 {
3523 buf_reset(resp);
3524 if (mw_get_field(tag, resp, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0)
3525 {
3526 goto done;
3527 }
3528
3529 if (buf_is_empty(resp))
3530 goto done;
3531
3532 if (whatfor)
3533 {
3534 if (l)
3535 {
3536 mutt_str_replace(&l->dflt, buf_string(resp));
3537 }
3538 else
3539 {
3540 l = MUTT_MEM_MALLOC(1, struct CryptCache);
3541 l->next = (struct CryptCache *) mod_data->gpgme_id_defaults;
3542 mod_data->gpgme_id_defaults = l;
3543 l->what = mutt_str_dup(whatfor);
3544 l->dflt = buf_strdup(resp);
3545 }
3546 }
3547
3548 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3549 if (key)
3550 goto done;
3551
3552 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3553 }
3554
3555done:
3556 buf_pool_release(&resp);
3557 return key;
3558}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:89
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
Find a key by string.
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:502
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:61
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
void mutt_clear_error(void)
Clear the message line (bottom line of screen).
Internal cache for GPGME.
Definition crypt_gpgme.c:86
char * what
Cached key identifier.
Definition crypt_gpgme.c:87
char * dflt
Default key ID.
Definition crypt_gpgme.c:88
struct CryptCache * next
Linked list.
Definition crypt_gpgme.c:89
struct CryptCache * gpgme_id_defaults
GPGME IdDefaults cache.
Definition module_data.h:43
Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_keys()

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

3572{
3573 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3574 struct ListNode *crypt_hook = NULL;
3575 const char *keyid = NULL;
3576 char *keylist = NULL;
3577 size_t keylist_size = 0;
3578 size_t keylist_used = 0;
3579 struct Address *p = NULL;
3580 struct CryptKeyInfo *k_info = NULL;
3581 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3582 char buf[1024] = { 0 };
3583 bool forced_valid = false;
3584 bool key_selected;
3585 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3586
3587 struct Address *a = NULL;
3588 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3589 /* Iterate through each recipient address to find an encryption key */
3590 TAILQ_FOREACH(a, addrlist, entries)
3591 {
3592 key_selected = false;
3593 /* Check for crypt-hook overrides for this recipient */
3594 mutt_crypt_hook(&crypt_hook_list, a);
3595 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3596 do
3597 {
3598 p = a;
3599 forced_valid = false;
3600 k_info = NULL;
3601
3602 /* If a crypt-hook provides a key ID, confirm with the user unless
3603 * in opportunistic encryption mode */
3604 if (crypt_hook)
3605 {
3606 keyid = crypt_hook->data;
3607 enum QuadOption ans = MUTT_YES;
3608 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3609 {
3610 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3611 buf_string(p->mailbox));
3612 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3613 }
3614 if (ans == MUTT_YES)
3615 {
3616 if (crypt_is_numerical_keyid(keyid))
3617 {
3618 if (mutt_strn_equal(keyid, "0x", 2))
3619 keyid += 2;
3620 goto bypass_selection; /* you don't see this. */
3621 }
3622
3623 /* check for e-mail address */
3624 mutt_addrlist_clear(&hookal);
3625 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3626 {
3627 mutt_addrlist_qualify(&hookal, fqdn);
3628 p = TAILQ_FIRST(&hookal);
3629 }
3630 else if (!oppenc_mode)
3631 {
3632 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3633 }
3634 }
3635 else if (ans == MUTT_NO)
3636 {
3637 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3638 {
3639 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3640 continue;
3641 }
3642 }
3643 else if (ans == MUTT_ABORT)
3644 {
3645 FREE(&keylist);
3646 mutt_addrlist_clear(&hookal);
3647 mutt_list_free(&crypt_hook_list);
3648 return NULL;
3649 }
3650 }
3651
3652 /* If no key found yet, try looking up by address in the keyring */
3653 if (!k_info)
3654 {
3655 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3656 }
3657
3658 /* Last resort: prompt the user to enter a key ID interactively */
3659 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3660 {
3661 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3662
3663 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3664 KEYFLAG_CANENCRYPT, app, &forced_valid);
3665 }
3666
3667 if (!k_info)
3668 {
3669 FREE(&keylist);
3670 mutt_addrlist_clear(&hookal);
3671 mutt_list_free(&crypt_hook_list);
3672 return NULL;
3673 }
3674
3675 keyid = crypt_fpr_or_lkeyid(k_info);
3676
3677 bypass_selection:
3678 /* Append the selected key ID to the space-separated keylist string */
3679 keylist_size += mutt_str_len(keyid) + 4 + 1;
3680 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
3681 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3682 keyid, forced_valid ? "!" : "");
3683 keylist_used = mutt_str_len(keylist);
3684
3685 key_selected = true;
3686
3687 crypt_key_free(&k_info);
3688 mutt_addrlist_clear(&hookal);
3689
3690 if (crypt_hook)
3691 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3692
3693 } while (crypt_hook);
3694
3695 mutt_list_free(&crypt_hook_list);
3696 }
3697 return keylist;
3698}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:687
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition crypt.c:1490
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:718
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 3729 of file crypt_gpgme.c.

3730{
3731 int rc = -1;
3732 gpgme_error_t err = GPG_ERR_NO_ERROR;
3733 gpgme_key_t key = NULL;
3734 gpgme_user_id_t uid = NULL;
3735 struct CryptKeyInfo *results = NULL;
3736 struct CryptKeyInfo *k = NULL;
3737 struct CryptKeyInfo **kend = NULL;
3738 struct CryptKeyInfo *choice = NULL;
3739
3740 gpgme_ctx_t ctx = create_gpgme_context(false);
3741
3742 /* list all secret keys */
3743 if (gpgme_op_keylist_start(ctx, NULL, 1))
3744 goto cleanup;
3745
3746 kend = &results;
3747
3748 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3749 {
3751
3756
3757 if (key->revoked)
3759 if (key->expired)
3761 if (key->disabled)
3763
3764 int idx;
3765 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3766 {
3767 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3768 k->kobj = key;
3769 gpgme_key_ref(k->kobj);
3770 k->idx = idx;
3771 k->uid = uid->uid;
3772 k->flags = flags;
3773 if (uid->revoked)
3774 k->flags |= KEYFLAG_REVOKED;
3775 k->validity = uid->validity;
3776 *kend = k;
3777 kend = &k->next;
3778 }
3779 gpgme_key_unref(key);
3780 }
3781 if (gpg_err_code(err) != GPG_ERR_EOF)
3782 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3783 gpgme_op_keylist_end(ctx);
3784
3785 if (!results)
3786 {
3787 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3788 from. This error is displayed if no results were found. */
3789 mutt_error(_("No secret keys found"));
3790 goto cleanup;
3791 }
3792
3793 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3794 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3795 goto cleanup;
3796 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3797
3798 rc = 0;
3799
3800cleanup:
3801 crypt_key_free(&choice);
3802 crypt_key_free(&results);
3803 gpgme_release(ctx);
3804 return rc;
3805}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init_common()

void init_common ( void )
static

Initialise code common to PGP and SMIME parts of GPGME.

Definition at line 3869 of file crypt_gpgme.c.

3870{
3871 /* this initialization should only run one time, but it may be called by
3872 * either pgp_gpgme_init or smime_gpgme_init */
3873 static bool has_run = false;
3874 if (has_run)
3875 return;
3876
3877 gpgme_check_version(NULL);
3878 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3879#ifdef ENABLE_NLS
3880 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3881#endif
3882 has_run = true;
3883}
Here is the caller graph for this function:

◆ init_pgp()

void init_pgp ( void )
static

Initialise the PGP crypto backend.

Definition at line 3888 of file crypt_gpgme.c.

3889{
3890 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3891 {
3892 mutt_error(_("GPGME: OpenPGP protocol not available"));
3893 }
3894}
Here is the caller graph for this function:

◆ init_smime()

void init_smime ( void )
static

Initialise the SMIME crypto backend.

Definition at line 3899 of file crypt_gpgme.c.

3900{
3901 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3902 {
3903 mutt_error(_("GPGME: CMS protocol not available"));
3904 }
3905}
Here is the caller graph for this function:

◆ gpgme_send_menu()

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

3932{
3933 struct CryptKeyInfo *p = NULL;
3934 const char *prompt = NULL;
3935 const char *letters = NULL;
3936 const char *choices = NULL;
3937 int choice;
3938
3939 if (is_smime)
3941 else
3943
3944 /* Opportunistic encrypt is controlling encryption.
3945 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3946 * letter choices for those.
3947 */
3948 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3949 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3950 {
3951 if (is_smime)
3952 {
3953 /* L10N: S/MIME options (opportunistic encryption is on) */
3954 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3955 /* L10N: S/MIME options (opportunistic encryption is on) */
3956 letters = _("sapco");
3957 choices = "SapCo";
3958 }
3959 else
3960 {
3961 /* L10N: PGP options (opportunistic encryption is on) */
3962 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3963 /* L10N: PGP options (opportunistic encryption is on) */
3964 letters = _("samco");
3965 choices = "SamCo";
3966 }
3967 }
3968 else if (c_crypt_opportunistic_encrypt)
3969 {
3970 /* Opportunistic encryption option is set, but is toggled off for this message. */
3971 if (is_smime)
3972 {
3973 /* L10N: S/MIME options (opportunistic encryption is off) */
3974 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3975 /* L10N: S/MIME options (opportunistic encryption is off) */
3976 letters = _("esabpco");
3977 choices = "esabpcO";
3978 }
3979 else
3980 {
3981 /* L10N: PGP options (opportunistic encryption is off) */
3982 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3983 /* L10N: PGP options (opportunistic encryption is off) */
3984 letters = _("esabmco");
3985 choices = "esabmcO";
3986 }
3987 }
3988 else
3989 {
3990 /* Opportunistic encryption is unset */
3991 if (is_smime)
3992 {
3993 /* L10N: S/MIME options */
3994 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
3995 /* L10N: S/MIME options */
3996 letters = _("esabpc");
3997 choices = "esabpc";
3998 }
3999 else
4000 {
4001 /* L10N: PGP options */
4002 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
4003 /* L10N: PGP options */
4004 letters = _("esabmc");
4005 choices = "esabmc";
4006 }
4007 }
4008
4009 choice = mw_multi_choice(prompt, letters);
4010 if (choice > 0)
4011 {
4012 switch (choices[choice - 1])
4013 {
4014 case 'a': /* sign (a)s */
4015 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
4016 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
4017 if (p)
4018 {
4019 char input_signas[128] = { 0 };
4020 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
4021
4022 if (is_smime)
4023 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", input_signas, NULL);
4024 else
4025 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
4026
4027 crypt_key_free(&p);
4028
4029 e->security |= SEC_SIGN;
4030 }
4031 break;
4032
4033 case 'b': /* (b)oth */
4034 e->security |= (SEC_ENCRYPT | SEC_SIGN);
4035 break;
4036
4037 case 'C':
4038 e->security &= ~SEC_SIGN;
4039 break;
4040
4041 case 'c': /* (c)lear */
4042 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
4043 break;
4044
4045 case 'e': /* (e)ncrypt */
4046 e->security |= SEC_ENCRYPT;
4047 e->security &= ~SEC_SIGN;
4048 break;
4049
4050 case 'm': /* (p)gp or s/(m)ime */
4051 case 'p':
4052 is_smime = !is_smime;
4053 if (is_smime)
4054 {
4057 }
4058 else
4059 {
4062 }
4064 break;
4065
4066 case 'O': /* oppenc mode on */
4069 break;
4070
4071 case 'o': /* oppenc mode off */
4073 break;
4074
4075 case 'S': /* (s)ign in oppenc mode */
4076 e->security |= SEC_SIGN;
4077 break;
4078
4079 case 's': /* (s)ign */
4080 e->security &= ~SEC_ENCRYPT;
4081 e->security |= SEC_SIGN;
4082 break;
4083
4084 default:
4085 break;
4086 }
4087 }
4088
4089 return e->security;
4090}
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition crypt.c:1052
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition question.c:62
@ SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:100
@ SEC_SIGN
Email is signed.
Definition lib.h:93
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition subset.c:392
Here is the call graph for this function:
Here is the caller graph for this function:

◆ verify_sender()

bool verify_sender ( struct Email * e)
static

Verify the sender of a message.

Parameters
eEmail
Return values
trueSender is verified

Definition at line 4113 of file crypt_gpgme.c.

4114{
4116 struct Address *sender = NULL;
4117 bool rc = true;
4118
4119 if (!TAILQ_EMPTY(&e->env->from))
4120 {
4122 sender = TAILQ_FIRST(&e->env->from);
4123 }
4124 else if (!TAILQ_EMPTY(&e->env->sender))
4125 {
4127 sender = TAILQ_FIRST(&e->env->sender);
4128 }
4129
4130 if (sender)
4131 {
4132 if ((gpgme_key_t) mod_data->signature_key)
4133 {
4134 gpgme_key_t key = (gpgme_key_t) mod_data->signature_key;
4135 gpgme_user_id_t uid = NULL;
4136 int sender_length = buf_len(sender->mailbox);
4137 for (uid = key->uids; uid && rc; uid = uid->next)
4138 {
4139 int uid_length = strlen(uid->email);
4140 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4141 (uid_length == (sender_length + 2)))
4142 {
4143 const char *at_sign = strchr(uid->email + 1, '@');
4144 if (at_sign)
4145 {
4146 /* Assume address is 'mailbox@domainname'.
4147 * The mailbox part is case-sensitive,
4148 * the domainname is not. (RFC2821) */
4149 const char *tmp_email = uid->email + 1;
4150 const char *tmp_sender = buf_string(sender->mailbox);
4151 /* length of mailbox part including '@' */
4152 int mailbox_length = at_sign - tmp_email + 1;
4153 int domainname_length = sender_length - mailbox_length;
4154 int mailbox_match;
4155 int domainname_match;
4156
4157 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4158 tmp_email += mailbox_length;
4159 tmp_sender += mailbox_length;
4160 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4161 if (mailbox_match && domainname_match)
4162 rc = false;
4163 }
4164 else
4165 {
4166 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4167 rc = false;
4168 }
4169 }
4170 }
4171 }
4172 else
4173 {
4174 mutt_any_key_to_continue(_("Failed to verify sender"));
4175 }
4176 }
4177 else
4178 {
4179 mutt_any_key_to_continue(_("Failed to figure out sender"));
4180 }
4181
4182 if ((gpgme_key_t) mod_data->signature_key)
4183 {
4184 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4185 mod_data->signature_key = NULL;
4186 }
4187
4188 return rc;
4189}
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition alias.c:297
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:497
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:174
int mutt_istrn_cmp(const char *a, const char *b, size_t num)
Compare two strings ignoring case (to a maximum), safely.
Definition string.c:443
#define TAILQ_EMPTY(head)
Definition queue.h:778
struct Envelope * env
Envelope information.
Definition email.h:68
struct AddressList sender
Email's sender.
Definition envelope.h:63
struct AddressList from
Email's 'From' list.
Definition envelope.h:59
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mutt_gpgme_print_version()

const char * mutt_gpgme_print_version ( void )

Get version of GPGME.

Return values
ptrGPGME version string

Definition at line 4214 of file crypt_gpgme.c.

4215{
4216 return GPGME_VERSION;
4217}
Here is the caller graph for this function:

◆ gpgme_id_defaults_cleanup()

void gpgme_id_defaults_cleanup ( struct NcryptModuleData * mod_data)

Free the GPGME IdDefaults cache.

Parameters
mod_dataNcrypt module data

Definition at line 4223 of file crypt_gpgme.c.

4224{
4225 struct CryptCache *l = mod_data->gpgme_id_defaults;
4226 while (l)
4227 {
4228 struct CryptCache *next = l->next;
4229 FREE(&l->what);
4230 FREE(&l->dflt);
4231 FREE(&l);
4232 l = next;
4233 }
4234 mod_data->gpgme_id_defaults = NULL;
4235
4236 if ((gpgme_key_t) mod_data->signature_key)
4237 {
4238 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4239 mod_data->signature_key = NULL;
4240 }
4241}
Here is the caller graph for this function: