NeoMutt  2025-12-11-1009-ga75d9e
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 rewind(fp_tmp);
439 while ((c = fgetc(fp_tmp)) != EOF)
440 {
441 if (c == '\r')
442 {
443 hadcr = 1;
444 }
445 else
446 {
447 if ((c == '\n') && !hadcr)
448 {
449 buf[0] = '\r';
450 gpgme_data_write(data, buf, 1);
451 }
452
453 hadcr = 0;
454 }
455 /* FIXME: This is quite suboptimal */
456 buf[0] = c;
457 gpgme_data_write(data, buf, 1);
458 }
459 mutt_file_fclose(&fp_tmp);
460 gpgme_data_seek(data, 0, SEEK_SET);
461 }
462 else
463 {
464 mutt_file_fclose(&fp_tmp);
465 err = gpgme_data_new_from_file(&data, buf_string(tempfile), 1);
466 if (err != GPG_ERR_NO_ERROR)
467 {
468 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
469 gpgme_data_release(data);
470 data = NULL;
471 /* fall through to unlink the tempfile */
472 }
473 }
474 unlink(buf_string(tempfile));
475
476cleanup:
477 buf_pool_release(&tempfile);
478 return data;
479}
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 488 of file crypt_gpgme.c.

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

◆ data_object_to_stream()

int data_object_to_stream ( gpgme_data_t data,
FILE * fp )
static

Write a GPGME data object to a file.

Parameters
dataGPGME data object
fpFile to write to
Return values
0Success
-1Error

Definition at line 509 of file crypt_gpgme.c.

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

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

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

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

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

766{
768 gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME,
769 mod_data->current_sender, 0);
770 if (err != GPG_ERR_NO_ERROR)
771 {
772 mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
773 }
774
775 return err;
776}
@ 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 787 of file crypt_gpgme.c.

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

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

898{
899 char p[256] = { 0 };
900 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
901 state_puts(state, p);
902}
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 912 of file crypt_gpgme.c.

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

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

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

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

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

1426{
1427 const char *algo = gpgme_pubkey_algo_name(r->pubkey_algo);
1428 if (!algo)
1429 algo = "?";
1430
1431 // L10N: Show the algorithm and key ID of the encryption recipients, e.g
1432 // Recipient: RSA key, ID 1111111111111111
1433 state_printf(state, _("Recipient: %s key, ID %s\n"), algo, r->keyid);
1434}
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 1441 of file crypt_gpgme.c.

1442{
1443 if (!cs_subset_bool(NeoMutt->sub, "crypt_encryption_info"))
1444 return;
1445
1446 state_attach_puts(state, _("[-- Begin encryption information --]\n"));
1447
1448 for (gpgme_recipient_t r = result->recipients; r; r = r->next)
1449 show_one_recipient(state, r);
1450
1451 state_attach_puts(state, _("[-- End encryption information --]\n\n"));
1452}
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 1466 of file crypt_gpgme.c.

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

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

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

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

2210{
2211 if (mutt_strn_equal(a, b, n))
2212 {
2213 /* at this point we know that 'b' is at least 'n' chars long */
2214 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2215 return true;
2216 }
2217 return false;
2218}
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 2227 of file crypt_gpgme.c.

2228{
2229 char buf[8192] = { 0 };
2230 bool rc = false;
2231
2232 bool sgn = false;
2233 bool enc = false;
2234
2235 if (b->type != TYPE_TEXT)
2236 return 0;
2237
2238 struct Buffer *tempfile = buf_pool_get();
2239 buf_mktemp(tempfile);
2241 {
2242 unlink(buf_string(tempfile));
2243 goto cleanup;
2244 }
2245
2246 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2247 if (!fp_tmp)
2248 {
2249 unlink(buf_string(tempfile));
2250 goto cleanup;
2251 }
2252
2253 while (fgets(buf, sizeof(buf), fp_tmp))
2254 {
2255 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2256 if (plen != 0)
2257 {
2258 if (MESSAGE(buf + plen))
2259 {
2260 enc = true;
2261 break;
2262 }
2263 else if (SIGNED_MESSAGE(buf + plen))
2264 {
2265 sgn = true;
2266 break;
2267 }
2268 }
2269 }
2270 mutt_file_fclose(&fp_tmp);
2271 unlink(buf_string(tempfile));
2272
2273 if (!enc && !sgn)
2274 goto cleanup;
2275
2276 /* fix the content type */
2277
2278 mutt_param_set(&b->parameter, "format", "fixed");
2279 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2280
2281 rc = true;
2282
2283cleanup:
2284 buf_pool_release(&tempfile);
2285 return rc;
2286}
#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 2427 of file crypt_gpgme.c.

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

2962{
2963 unsigned int rc = 0;
2964
2965 switch (cap)
2966 {
2968 rc = key->can_encrypt;
2969 if (rc == 0)
2970 {
2971 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2972 {
2973 rc = subkey->can_encrypt;
2974 if (rc != 0)
2975 break;
2976 }
2977 }
2978 break;
2979 case KEY_CAP_CAN_SIGN:
2980 rc = key->can_sign;
2981 if (rc == 0)
2982 {
2983 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2984 {
2985 rc = subkey->can_sign;
2986 if (rc != 0)
2987 break;
2988 }
2989 }
2990 break;
2992 rc = key->can_certify;
2993 if (rc == 0)
2994 {
2995 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2996 {
2997 rc = subkey->can_certify;
2998 if (rc != 0)
2999 break;
3000 }
3001 }
3002 break;
3003 }
3004
3005 return rc;
3006}
@ 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 3017 of file crypt_gpgme.c.

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

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

3241{
3242 char *scratch = mutt_str_dup(str);
3243 if (!scratch)
3244 return;
3245
3246 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3247 {
3248 if (strlen(t) > 3)
3250 }
3251
3252 FREE(&scratch);
3253}
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 3264 of file crypt_gpgme.c.

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

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

3487{
3489 struct CryptKeyInfo *key = NULL;
3490 struct CryptCache *l = NULL;
3491 struct Buffer *resp = buf_pool_get();
3492
3494
3495 if (whatfor)
3496 {
3497 for (l = (struct CryptCache *) mod_data->gpgme_id_defaults; l; l = l->next)
3498 {
3499 if (mutt_istr_equal(whatfor, l->what))
3500 {
3501 buf_strcpy(resp, l->dflt);
3502 break;
3503 }
3504 }
3505 }
3506
3507 while (true)
3508 {
3509 buf_reset(resp);
3510 if (mw_get_field(tag, resp, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0)
3511 {
3512 goto done;
3513 }
3514
3515 if (buf_is_empty(resp))
3516 goto done;
3517
3518 if (whatfor)
3519 {
3520 if (l)
3521 {
3522 mutt_str_replace(&l->dflt, buf_string(resp));
3523 }
3524 else
3525 {
3526 l = MUTT_MEM_MALLOC(1, struct CryptCache);
3527 l->next = (struct CryptCache *) mod_data->gpgme_id_defaults;
3528 mod_data->gpgme_id_defaults = l;
3529 l->what = mutt_str_dup(whatfor);
3530 l->dflt = buf_strdup(resp);
3531 }
3532 }
3533
3534 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3535 if (key)
3536 goto done;
3537
3538 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3539 }
3540
3541done:
3542 buf_pool_release(&resp);
3543 return key;
3544}
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 3557 of file crypt_gpgme.c.

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

3716{
3717 int rc = -1;
3718 gpgme_error_t err = GPG_ERR_NO_ERROR;
3719 gpgme_key_t key = NULL;
3720 gpgme_user_id_t uid = NULL;
3721 struct CryptKeyInfo *results = NULL;
3722 struct CryptKeyInfo *k = NULL;
3723 struct CryptKeyInfo **kend = NULL;
3724 struct CryptKeyInfo *choice = NULL;
3725
3726 gpgme_ctx_t ctx = create_gpgme_context(false);
3727
3728 /* list all secret keys */
3729 if (gpgme_op_keylist_start(ctx, NULL, 1))
3730 goto cleanup;
3731
3732 kend = &results;
3733
3734 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3735 {
3737
3742
3743 if (key->revoked)
3745 if (key->expired)
3747 if (key->disabled)
3749
3750 int idx;
3751 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3752 {
3753 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3754 k->kobj = key;
3755 gpgme_key_ref(k->kobj);
3756 k->idx = idx;
3757 k->uid = uid->uid;
3758 k->flags = flags;
3759 if (uid->revoked)
3760 k->flags |= KEYFLAG_REVOKED;
3761 k->validity = uid->validity;
3762 *kend = k;
3763 kend = &k->next;
3764 }
3765 gpgme_key_unref(key);
3766 }
3767 if (gpg_err_code(err) != GPG_ERR_EOF)
3768 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3769 gpgme_op_keylist_end(ctx);
3770
3771 if (!results)
3772 {
3773 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3774 from. This error is displayed if no results were found. */
3775 mutt_error(_("No secret keys found"));
3776 goto cleanup;
3777 }
3778
3779 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3780 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3781 goto cleanup;
3782 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3783
3784 rc = 0;
3785
3786cleanup:
3787 crypt_key_free(&choice);
3788 crypt_key_free(&results);
3789 gpgme_release(ctx);
3790 return rc;
3791}
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 3855 of file crypt_gpgme.c.

3856{
3857 /* this initialization should only run one time, but it may be called by
3858 * either pgp_gpgme_init or smime_gpgme_init */
3859 static bool has_run = false;
3860 if (has_run)
3861 return;
3862
3863 gpgme_check_version(NULL);
3864 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3865#ifdef ENABLE_NLS
3866 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3867#endif
3868 has_run = true;
3869}
Here is the caller graph for this function:

◆ init_pgp()

void init_pgp ( void )
static

Initialise the PGP crypto backend.

Definition at line 3874 of file crypt_gpgme.c.

3875{
3876 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3877 {
3878 mutt_error(_("GPGME: OpenPGP protocol not available"));
3879 }
3880}
Here is the caller graph for this function:

◆ init_smime()

void init_smime ( void )
static

Initialise the SMIME crypto backend.

Definition at line 3885 of file crypt_gpgme.c.

3886{
3887 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3888 {
3889 mutt_error(_("GPGME: CMS protocol not available"));
3890 }
3891}
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 3917 of file crypt_gpgme.c.

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

4097{
4099 struct Address *sender = NULL;
4100 bool rc = true;
4101
4102 if (!TAILQ_EMPTY(&e->env->from))
4103 {
4105 sender = TAILQ_FIRST(&e->env->from);
4106 }
4107 else if (!TAILQ_EMPTY(&e->env->sender))
4108 {
4110 sender = TAILQ_FIRST(&e->env->sender);
4111 }
4112
4113 if (sender)
4114 {
4115 if ((gpgme_key_t) mod_data->signature_key)
4116 {
4117 gpgme_key_t key = (gpgme_key_t) mod_data->signature_key;
4118 gpgme_user_id_t uid = NULL;
4119 int sender_length = buf_len(sender->mailbox);
4120 for (uid = key->uids; uid && rc; uid = uid->next)
4121 {
4122 int uid_length = strlen(uid->email);
4123 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4124 (uid_length == (sender_length + 2)))
4125 {
4126 const char *at_sign = strchr(uid->email + 1, '@');
4127 if (at_sign)
4128 {
4129 /* Assume address is 'mailbox@domainname'.
4130 * The mailbox part is case-sensitive,
4131 * the domainname is not. (RFC2821) */
4132 const char *tmp_email = uid->email + 1;
4133 const char *tmp_sender = buf_string(sender->mailbox);
4134 /* length of mailbox part including '@' */
4135 int mailbox_length = at_sign - tmp_email + 1;
4136 int domainname_length = sender_length - mailbox_length;
4137 int mailbox_match;
4138 int domainname_match;
4139
4140 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4141 tmp_email += mailbox_length;
4142 tmp_sender += mailbox_length;
4143 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4144 if (mailbox_match && domainname_match)
4145 rc = false;
4146 }
4147 else
4148 {
4149 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4150 rc = false;
4151 }
4152 }
4153 }
4154 }
4155 else
4156 {
4157 mutt_any_key_to_continue(_("Failed to verify sender"));
4158 }
4159 }
4160 else
4161 {
4162 mutt_any_key_to_continue(_("Failed to figure out sender"));
4163 }
4164
4165 if ((gpgme_key_t) mod_data->signature_key)
4166 {
4167 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4168 mod_data->signature_key = NULL;
4169 }
4170
4171 return rc;
4172}
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 4197 of file crypt_gpgme.c.

4198{
4199 return GPGME_VERSION;
4200}
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 4206 of file crypt_gpgme.c.

4207{
4208 struct CryptCache *l = mod_data->gpgme_id_defaults;
4209 while (l)
4210 {
4211 struct CryptCache *next = l->next;
4212 FREE(&l->what);
4213 FREE(&l->dflt);
4214 FREE(&l);
4215 l = next;
4216 }
4217 mod_data->gpgme_id_defaults = NULL;
4218
4219 if ((gpgme_key_t) mod_data->signature_key)
4220 {
4221 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4222 mod_data->signature_key = NULL;
4223 }
4224}
Here is the caller graph for this function: