NeoMutt  2025-12-11-1059-g2f5469
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 CryptKeyInfo * crypt_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 Body * sign_message (struct Body *b, const struct AddressList *from, bool use_smime)
 Sign a message.
struct Body * pgp_gpgme_sign_message (struct Body *b, const struct AddressList *from)
 Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
struct Body * smime_gpgme_sign_message (struct Body *b, const struct AddressList *from)
 Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
struct Body * pgp_gpgme_encrypt_message (struct Body *b, char *keylist, bool sign, const struct AddressList *from)
 PGP encrypt an email - Implements CryptModuleSpecs::pgp_encrypt_message() -.
struct Body * smime_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 Body * decrypt_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 CryptKeyInfo * get_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 CryptKeyInfo * crypt_getkeybyaddr (struct Address *a, KeyFlags abilities, unsigned int app, bool *forced_valid, bool oppenc_mode)
 Find a key by email address.
static struct CryptKeyInfo * crypt_getkeybystr (const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
 Find a key by string.
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.
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 Body * pgp_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, T)
Definition memory.h:68
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:92
struct CryptKeyInfo * next
Linked list.
Definition crypt_gpgme.h:46
Here is the caller graph for this function:

◆ crypt_id_is_strong()

bool crypt_id_is_strong ( struct CryptKeyInfo * key)

Is the key strong.

Parameters
keyKey to test
Return values
trueValidity of key is sufficient

Definition at line 269 of file crypt_gpgme.c.

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

◆ crypt_id_is_valid()

bool crypt_id_is_valid ( struct CryptKeyInfo * key)

Is key ID valid.

Parameters
keyKey to test
Return values
trueKey is valid

When the key is not marked as unusable

Definition at line 304 of file crypt_gpgme.c.

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

◆ crypt_id_matches_addr()

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

Does the key ID match the address.

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

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

Definition at line 322 of file crypt_gpgme.c.

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

◆ create_gpgme_context()

gpgme_ctx_t create_gpgme_context ( bool for_smime)

Create a new GPGME context.

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

Definition at line 355 of file crypt_gpgme.c.

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

◆ create_gpgme_data()

gpgme_data_t create_gpgme_data ( void )
static

Create a new GPGME data object.

Return values
ptrGPGPE data object

This is a wrapper to die on error.

Note
Call gpgme_data_release() to free the data object

Definition at line 394 of file crypt_gpgme.c.

395{
396 gpgme_data_t data = NULL;
397
398 gpgme_error_t err = gpgme_data_new(&data);
399 if (err != GPG_ERR_NO_ERROR)
400 {
401 mutt_error(_("error creating GPGME data object: %s"), gpgme_strerror(err));
402 mutt_exit(1);
403 }
404 return data;
405}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ body_to_data_object()

gpgme_data_t body_to_data_object ( struct Body * b,
bool convert )
static

Create GPGME object from the mail body.

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

Definition at line 413 of file crypt_gpgme.c.

414{
415 gpgme_error_t err = GPG_ERR_NO_ERROR;
416 gpgme_data_t data = NULL;
417
418 struct Buffer *tempfile = buf_pool_get();
419 buf_mktemp(tempfile);
420 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
421 if (!fp_tmp)
422 {
423 mutt_perror("%s", buf_string(tempfile));
424 goto cleanup;
425 }
426
428 fputc('\n', fp_tmp);
429 mutt_write_mime_body(b, fp_tmp, NeoMutt->sub);
430
431 if (convert)
432 {
433 int c;
434 int hadcr = 0;
435 unsigned char buf[1] = { 0 };
436
438 fseek(fp_tmp, 0, SEEK_SET);
439 clearerr(fp_tmp);
440 while ((c = fgetc(fp_tmp)) != EOF)
441 {
442 if (c == '\r')
443 {
444 hadcr = 1;
445 }
446 else
447 {
448 if ((c == '\n') && !hadcr)
449 {
450 buf[0] = '\r';
451 gpgme_data_write(data, buf, 1);
452 }
453
454 hadcr = 0;
455 }
456 /* FIXME: This is quite suboptimal */
457 buf[0] = c;
458 gpgme_data_write(data, buf, 1);
459 }
460 mutt_file_fclose(&fp_tmp);
461 gpgme_data_seek(data, 0, SEEK_SET);
462 }
463 else
464 {
465 mutt_file_fclose(&fp_tmp);
466 err = gpgme_data_new_from_file(&data, buf_string(tempfile), 1);
467 if (err != GPG_ERR_NO_ERROR)
468 {
469 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
470 gpgme_data_release(data);
471 data = NULL;
472 /* fall through to unlink the tempfile */
473 }
474 }
475 unlink(buf_string(tempfile));
476
477cleanup:
478 buf_pool_release(&tempfile);
479 return data;
480}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:99
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:37
char * data
Pointer to data.
Definition buffer.h:38
#define buf_mktemp(buf)
Definition tmp.h:33
Here is the call graph for this function:
Here is the caller graph for this function:

◆ file_to_data_object()

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

Create GPGME data object from file.

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

Definition at line 489 of file crypt_gpgme.c.

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

◆ data_object_to_stream()

int data_object_to_stream ( gpgme_data_t data,
FILE * fp )
static

Write a GPGME data object to a file.

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

Definition at line 510 of file crypt_gpgme.c.

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

◆ data_object_to_tempfile()

char * data_object_to_tempfile ( gpgme_data_t data,
FILE ** fp_ret )
static

Copy a data object to a temporary file.

Parameters
[in]dataGPGME data object
[out]fp_retTemporary file
Return values
ptrName of temporary file

If fp_ret is passed in, the file will be rewound, left open, and returned via that parameter.

Note
The caller must free the returned file name

Definition at line 559 of file crypt_gpgme.c.

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

◆ create_recipient_string()

void create_recipient_string ( const char * keylist,
struct Buffer * recpstring,
int use_smime )
static

Create a string of recipients.

Parameters
keylistKeys, space-separated
recpstringBuffer to store the recipients
use_smimeUse SMIME

Definition at line 621 of file crypt_gpgme.c.

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

◆ set_signer_from_address()

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

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

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

Definition at line 657 of file crypt_gpgme.c.

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

◆ set_signer()

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

Make sure that the correct signer is set.

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

Definition at line 716 of file crypt_gpgme.c.

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

◆ set_pka_sig_notation()

gpgme_error_t set_pka_sig_notation ( gpgme_ctx_t ctx)
static

Set the signature notation.

Parameters
ctxGPGME context
Return values
numGPGME error code, e.g. GPG_ERR_NO_ERROR

Definition at line 769 of file crypt_gpgme.c.

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

◆ encrypt_gpgme_object()

char * encrypt_gpgme_object ( gpgme_data_t plaintext,
char * keylist,
bool use_smime,
bool combined_signed,
const struct AddressList * from )
static

Encrypt the GPGPME data object.

Parameters
plaintextGPGME data object with plain text message
keylistList of keys to encrypt to
use_smimeIf true, use SMIME
combined_signedIf true, sign and encrypt the message (PGP only)
fromThe From header line
Return values
ptrName of temporary file containing encrypted text

Definition at line 791 of file crypt_gpgme.c.

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

◆ get_micalg()

int get_micalg ( gpgme_ctx_t ctx,
int use_smime,
char * buf,
size_t buflen )
static

Find the "micalg" parameter from the last GPGME operation.

Parameters
ctxGPGME handle
use_smimeIf set, use SMIME instead of PGP
bufBuffer for the result
buflenLength of buffer
Return values
0Success
-1Error

Find the "Message Integrity Check algorithm" from the last GPGME operation. It is expected that this operation was a sign operation.

Definition at line 863 of file crypt_gpgme.c.

864{
865 gpgme_sign_result_t result = NULL;
866 const char *algorithm_name = NULL;
867
868 if (buflen < 5)
869 return -1;
870
871 *buf = '\0';
872 result = gpgme_op_sign_result(ctx);
873 if (result && result->signatures)
874 {
875 algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
876 if (algorithm_name)
877 {
878 if (use_smime)
879 {
880 /* convert GPGME raw hash name to RFC2633 format */
881 snprintf(buf, buflen, "%s", algorithm_name);
882 mutt_str_lower(buf);
883 }
884 else
885 {
886 /* convert GPGME raw hash name to RFC3156 format */
887 snprintf(buf, buflen, "pgp-%s", algorithm_name);
888 mutt_str_lower(buf + 4);
889 }
890 }
891 }
892
893 return (buf[0] != '\0') ? 0 : -1;
894}
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition string.c:317
Here is the call graph for this function:
Here is the caller graph for this function:

◆ print_time()

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

Print the date/time according to the locale.

Parameters
tTimestamp
stateState to write to

Definition at line 901 of file crypt_gpgme.c.

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

◆ sign_message()

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

Sign a message.

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

Definition at line 916 of file crypt_gpgme.c.

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

◆ show_sig_summary()

int show_sig_summary ( unsigned long sum,
gpgme_ctx_t ctx,
gpgme_key_t key,
int idx,
struct State * state,
gpgme_signature_t sig )
static

Show a signature summary.

Parameters
sumFlags, e.g. GPGME_SIGSUM_KEY_REVOKED
ctxGPGME handle
keySet of keys
idxIndex into key set
stateState to use
sigGPGME signature
Return values
0Success
1There is a severe warning

Display the common attributes of the signature summary SUM.

Definition at line 1144 of file crypt_gpgme.c.

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

◆ show_fingerprint()

void show_fingerprint ( gpgme_key_t key,
struct State * state )
static

Write a key's fingerprint.

Parameters
keyGPGME key
stateState to write to

Definition at line 1269 of file crypt_gpgme.c.

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

◆ show_one_sig_validity()

void show_one_sig_validity ( gpgme_ctx_t ctx,
int idx,
struct State * state )
static

Show the validity of a key used for one signature.

Parameters
ctxGPGME handle
idxIndex of signature to check
stateState to use

Definition at line 1324 of file crypt_gpgme.c.

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

◆ print_smime_keyinfo()

void print_smime_keyinfo ( const char * msg,
gpgme_signature_t sig,
gpgme_key_t key,
struct State * state )
static

Print key info about an SMIME key.

Parameters
msgPrefix message to write
sigGPGME signature
keyGPGME key
stateState to write to

Definition at line 1365 of file crypt_gpgme.c.

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

◆ show_one_recipient()

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

Show information about one encryption recipient.

Parameters
stateState to write to
rEncryption recipient

Definition at line 1431 of file crypt_gpgme.c.

1432{
1433 const char *algo = gpgme_pubkey_algo_name(r->pubkey_algo);
1434 if (!algo)
1435 algo = "?";
1436
1437 // L10N: Show the algorithm and key ID of the encryption recipients, e.g
1438 // Recipient: RSA key, ID 1111111111111111
1439 state_printf(state, _("Recipient: %s key, ID %s\n"), algo, r->keyid);
1440}
int state_printf(struct State *state, const char *fmt,...)
Write a formatted string to the State.
Definition state.c:190
Here is the call graph for this function:
Here is the caller graph for this function:

◆ show_encryption_info()

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

Show encryption information.

Parameters
stateState to write to
resultDecryption result

Definition at line 1447 of file crypt_gpgme.c.

1448{
1449 if (!cs_subset_bool(NeoMutt->sub, "crypt_encryption_info"))
1450 return;
1451
1452 state_attach_puts(state, _("[-- Begin encryption information --]\n"));
1453
1454 for (gpgme_recipient_t r = result->recipients; r; r = r->next)
1455 show_one_recipient(state, r);
1456
1457 state_attach_puts(state, _("[-- End encryption information --]\n\n"));
1458}
static void show_one_recipient(struct State *state, gpgme_recipient_t r)
Show information about one encryption recipient.
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition state.c:104
Here is the call graph for this function:
Here is the caller graph for this function:

◆ show_one_sig_status()

int show_one_sig_status ( gpgme_ctx_t ctx,
int idx,
struct State * state )
static

Show information about one signature.

Parameters
ctxGPGME handle of a successful verification
idxIndex
stateState to use
Return values
0Normal procession
1A bad signature
2A signature with a warning
-1No more signature

The index should start at 0 and increment for each call/signature.

Definition at line 1472 of file crypt_gpgme.c.

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

◆ verify_one()

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

Do the actual verification step.

Parameters
bBody part containing signature
stateState to read from
tempfileTemporary file to read
is_smimeIs the key S/MIME?
Return values
0Success
1Bad signature
2Warnings
-1Error

With is_smime set to true we assume S/MIME.

Definition at line 1598 of file crypt_gpgme.c.

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

◆ decrypt_part()

struct Body * decrypt_part ( struct Body * b,
struct State * state,
FILE * fp_out,
bool is_smime,
int * r_is_signed )
static

Decrypt a PGP or SMIME message.

Parameters
[in]bBody of message
[in]stateState to use
[in]fp_outFile to write to
[in]is_smimeTrue if an SMIME message
[out]r_is_signedFlag, R_IS_SIGNED (PGP only)
Return values
ptrNewly allocated Body

For PGP returns a flag in R_IS_SIGNED to indicate whether this is a combined encrypted and signed message, for S/MIME it returns true when it is not a encrypted but a signed message.

Definition at line 1750 of file crypt_gpgme.c.

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

◆ pgp_gpgme_extract_keys()

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

Write PGP keys to a file.

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

Definition at line 2149 of file crypt_gpgme.c.

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

2233{
2234 if (mutt_strn_equal(a, b, n))
2235 {
2236 /* at this point we know that 'b' is at least 'n' chars long */
2237 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2238 return true;
2239 }
2240 return false;
2241}
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 2250 of file crypt_gpgme.c.

2251{
2252 char buf[8192] = { 0 };
2253 bool rc = false;
2254
2255 bool sgn = false;
2256 bool enc = false;
2257
2258 if (b->type != TYPE_TEXT)
2259 return 0;
2260
2261 struct Buffer *tempfile = buf_pool_get();
2262 buf_mktemp(tempfile);
2264 {
2265 unlink(buf_string(tempfile));
2266 goto cleanup;
2267 }
2268
2269 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2270 if (!fp_tmp)
2271 {
2272 unlink(buf_string(tempfile));
2273 goto cleanup;
2274 }
2275
2276 while (fgets(buf, sizeof(buf), fp_tmp))
2277 {
2278 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2279 if (plen != 0)
2280 {
2281 if (MESSAGE(buf + plen))
2282 {
2283 enc = true;
2284 break;
2285 }
2286 else if (SIGNED_MESSAGE(buf + plen))
2287 {
2288 sgn = true;
2289 break;
2290 }
2291 }
2292 }
2293 mutt_file_fclose(&fp_tmp);
2294 unlink(buf_string(tempfile));
2295
2296 if (!enc && !sgn)
2297 goto cleanup;
2298
2299 /* fix the content type */
2300
2301 mutt_param_set(&b->parameter, "format", "fixed");
2302 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2303
2304 rc = true;
2305
2306cleanup:
2307 buf_pool_release(&tempfile);
2308 return rc;
2309}
#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 2450 of file crypt_gpgme.c.

2451{
2452 char buf[8192] = { 0 };
2453 bool complete, armor_header;
2454 FILE *fp = NULL;
2455
2456 char *fname = data_object_to_tempfile(data, &fp);
2457 if (!fname)
2458 {
2459 mutt_file_fclose(&fp);
2460 return;
2461 }
2462 unlink(fname);
2463 FREE(&fname);
2464
2465 /* fromcode comes from the MIME Content-Type charset label. It might
2466 * be a wrong label, so we want the ability to do corrections via
2467 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2469
2470 for (complete = true, armor_header = true;
2471 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2472 {
2473 if (!complete)
2474 {
2475 if (!armor_header)
2476 state_puts(state, buf);
2477 continue;
2478 }
2479
2480 if (BEGIN_PGP_SIGNATURE(buf))
2481 break;
2482
2483 if (armor_header)
2484 {
2485 if (buf[0] == '\n')
2486 armor_header = false;
2487 continue;
2488 }
2489
2490 if (state->prefix)
2491 state_puts(state, state->prefix);
2492
2493 if ((buf[0] == '-') && (buf[1] == ' '))
2494 state_puts(state, buf + 2);
2495 else
2496 state_puts(state, buf);
2497 }
2498
2501}
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 2985 of file crypt_gpgme.c.

2986{
2987 unsigned int rc = 0;
2988
2989 switch (cap)
2990 {
2992 rc = key->can_encrypt;
2993 if (rc == 0)
2994 {
2995 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2996 {
2997 rc = subkey->can_encrypt;
2998 if (rc != 0)
2999 break;
3000 }
3001 }
3002 break;
3003 case KEY_CAP_CAN_SIGN:
3004 rc = key->can_sign;
3005 if (rc == 0)
3006 {
3007 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
3008 {
3009 rc = subkey->can_sign;
3010 if (rc != 0)
3011 break;
3012 }
3013 }
3014 break;
3016 rc = key->can_certify;
3017 if (rc == 0)
3018 {
3019 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
3020 {
3021 rc = subkey->can_certify;
3022 if (rc != 0)
3023 break;
3024 }
3025 }
3026 break;
3027 }
3028
3029 return rc;
3030}
@ 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 3041 of file crypt_gpgme.c.

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

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

3265{
3266 char *scratch = mutt_str_dup(str);
3267 if (!scratch)
3268 return;
3269
3270 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3271 {
3272 if (strlen(t) > 3)
3274 }
3275
3276 FREE(&scratch);
3277}
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 3288 of file crypt_gpgme.c.

3291{
3292 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3293
3294 int multi = false;
3295 int this_key_has_strong = false;
3296 int this_key_has_addr_match = false;
3297 int match = false;
3298
3299 struct CryptKeyInfo *keys = NULL;
3300 struct CryptKeyInfo *k = NULL;
3301 struct CryptKeyInfo *the_strong_valid_key = NULL;
3302 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3303 struct CryptKeyInfo *matches = NULL;
3304 struct CryptKeyInfo **matches_endp = &matches;
3305
3306 if (a && a->mailbox)
3308 if (a && a->personal)
3310
3311 if (!oppenc_mode)
3312 mutt_message(_("Looking for keys matching \"%s\"..."), a ? buf_string(a->mailbox) : "");
3313 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3314
3315 mutt_list_free(&hints);
3316
3317 if (!keys)
3318 return NULL;
3319
3320 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n",
3321 a ? buf_string(a->personal) : "", a ? buf_string(a->mailbox) : "");
3322
3323 for (k = keys; k; k = k->next)
3324 {
3325 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3326
3327 if (abilities && !(k->flags & abilities))
3328 {
3329 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3330 continue;
3331 }
3332
3333 this_key_has_strong = false; /* strong and valid match */
3334 this_key_has_addr_match = false;
3335 match = false; /* any match */
3336
3337 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3338 mutt_addrlist_parse(&alist, k->uid);
3339 struct Address *ka = NULL;
3340 TAILQ_FOREACH(ka, &alist, entries)
3341 {
3342 int validity = crypt_id_matches_addr(a, ka, k);
3343
3344 if (validity & CRYPT_KV_MATCH) /* something matches */
3345 {
3346 match = true;
3347
3348 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3349 {
3350 if (validity & CRYPT_KV_STRONGID)
3351 {
3352 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3353 multi = true;
3354 this_key_has_strong = true;
3355 }
3356 else
3357 {
3358 this_key_has_addr_match = true;
3359 }
3360 }
3361 }
3362 }
3363 mutt_addrlist_clear(&alist);
3364
3365 if (match)
3366 {
3367 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3368 *matches_endp = tmp;
3369 matches_endp = &tmp->next;
3370
3371 if (this_key_has_strong)
3372 the_strong_valid_key = tmp;
3373 else if (this_key_has_addr_match)
3374 a_valid_addrmatch_key = tmp;
3375 }
3376 }
3377
3378 crypt_key_free(&keys);
3379
3380 if (matches)
3381 {
3382 if (oppenc_mode || !isatty(STDIN_FILENO))
3383 {
3384 const bool c_crypt_opportunistic_encrypt_strong_keys =
3385 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3386 if (the_strong_valid_key)
3387 k = crypt_copy_key(the_strong_valid_key);
3388 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3389 k = crypt_copy_key(a_valid_addrmatch_key);
3390 else
3391 k = NULL;
3392 }
3393 else if (the_strong_valid_key && !multi)
3394 {
3395 /* There was precisely one strong match on a valid ID.
3396 * Proceed without asking the user. */
3397 k = crypt_copy_key(the_strong_valid_key);
3398 }
3399 else
3400 {
3401 /* Else: Ask the user. */
3402 k = dlg_gpgme(matches, a, NULL, app, forced_valid);
3403 }
3404
3405 crypt_key_free(&matches);
3406 }
3407 else
3408 {
3409 k = NULL;
3410 }
3411
3412 return k;
3413}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1473
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:481
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
static int crypt_id_matches_addr(struct Address *addr, struct Address *u_addr, struct CryptKeyInfo *key)
Does the key ID match the address.
static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
Split a string and add the parts to a List.
static struct CryptKeyInfo * get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
Get a list of keys which are candidates for the selection.
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
#define CRYPT_KV_MATCH
Definition crypt_gpgme.c:79
struct CryptKeyInfo * dlg_gpgme(struct CryptKeyInfo *keys, struct Address *p, const char *s, unsigned int app, bool *forced_valid)
Get the user to select a key -.
Definition dlg_gpgme.c:195
#define mutt_message(...)
Definition logging2.h:93
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition list.c:123
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:49
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
#define STAILQ_HEAD_INITIALIZER(head)
Definition queue.h:324
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
Here is the call graph for this function:
Here is the caller graph for this function:

◆ crypt_getkeybystr()

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

Find a key by string.

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

Definition at line 3423 of file crypt_gpgme.c.

3425{
3426 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3427 struct CryptKeyInfo *matches = NULL;
3428 struct CryptKeyInfo **matches_endp = &matches;
3429 struct CryptKeyInfo *k = NULL;
3430 const char *ps = NULL;
3431 const char *pl = NULL;
3432 const char *phint = NULL;
3433
3434 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3435
3436 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3437 crypt_add_string_to_hints(phint, &hints);
3438 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3439 mutt_list_free(&hints);
3440
3441 if (!keys)
3442 {
3443 FREE(&pfcopy);
3444 return NULL;
3445 }
3446
3447 for (k = keys; k; k = k->next)
3448 {
3449 if (abilities && !(k->flags & abilities))
3450 continue;
3451
3452 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3453 crypt_long_keyid(k), k->uid);
3454
3455 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3456 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3457 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3458 {
3459 mutt_debug(LL_DEBUG5, "match\n");
3460
3461 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3462 *matches_endp = tmp;
3463 matches_endp = &tmp->next;
3464 }
3465 else
3466 {
3467 mutt_debug(LL_DEBUG5, "no match\n");
3468 }
3469 }
3470
3471 FREE(&pfcopy);
3472 crypt_key_free(&keys);
3473
3474 if (matches)
3475 {
3476 if (isatty(STDIN_FILENO))
3477 {
3478 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3479
3480 crypt_key_free(&matches);
3481 return k;
3482 }
3483 else
3484 {
3485 if (crypt_keys_are_valid(matches))
3486 return matches;
3487
3488 crypt_key_free(&matches);
3489 return NULL;
3490 }
3491 }
3492
3493 return NULL;
3494}
const char * crypt_get_fingerprint_or_id(const char *p, const char **pphint, const char **ppl, const char **pps)
Get the fingerprint or long key ID.
Definition crypt.c:1397
static const char * crypt_short_keyid(struct CryptKeyInfo *k)
Get the short keyID for a key.
static const char * crypt_long_keyid(struct CryptKeyInfo *k)
Find the Long ID for the key.
static const char * crypt_fpr(struct CryptKeyInfo *k)
Get the hexstring fingerprint from a key.
bool crypt_keys_are_valid(struct CryptKeyInfo *keys)
Are all these keys valid?
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case).
Definition string.c:528
Here is the call graph for this function:
Here is the caller graph for this function:

◆ crypt_ask_for_key()

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

Ask the user for a key.

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

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

Definition at line 3508 of file crypt_gpgme.c.

3511{
3513 struct CryptKeyInfo *key = NULL;
3514 struct CryptCache *l = NULL;
3515 struct Buffer *resp = buf_pool_get();
3516
3518
3519 if (whatfor)
3520 {
3521 for (l = (struct CryptCache *) mod_data->gpgme_id_defaults; l; l = l->next)
3522 {
3523 if (mutt_istr_equal(whatfor, l->what))
3524 {
3525 buf_strcpy(resp, l->dflt);
3526 break;
3527 }
3528 }
3529 }
3530
3531 while (true)
3532 {
3533 buf_reset(resp);
3534 if (mw_get_field(tag, resp, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0)
3535 {
3536 goto done;
3537 }
3538
3539 if (buf_is_empty(resp))
3540 goto done;
3541
3542 if (whatfor)
3543 {
3544 if (l)
3545 {
3546 mutt_str_replace(&l->dflt, buf_string(resp));
3547 }
3548 else
3549 {
3550 l = MUTT_MEM_MALLOC(1, struct CryptCache);
3551 l->next = (struct CryptCache *) mod_data->gpgme_id_defaults;
3552 mod_data->gpgme_id_defaults = l;
3553 l->what = mutt_str_dup(whatfor);
3554 l->dflt = buf_strdup(resp);
3555 }
3556 }
3557
3558 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3559 if (key)
3560 goto done;
3561
3562 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3563 }
3564
3565done:
3566 buf_pool_release(&resp);
3567 return key;
3568}
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 3581 of file crypt_gpgme.c.

3582{
3583 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3584 struct ListNode *crypt_hook = NULL;
3585 const char *keyid = NULL;
3586 char *keylist = NULL;
3587 size_t keylist_size = 0;
3588 size_t keylist_used = 0;
3589 struct Address *p = NULL;
3590 struct CryptKeyInfo *k_info = NULL;
3591 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3592 char buf[1024] = { 0 };
3593 bool forced_valid = false;
3594 bool key_selected;
3595 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3596
3597 struct Address *a = NULL;
3598 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3599 /* Iterate through each recipient address to find an encryption key */
3600 TAILQ_FOREACH(a, addrlist, entries)
3601 {
3602 key_selected = false;
3603 /* Check for crypt-hook overrides for this recipient */
3604 mutt_crypt_hook(&crypt_hook_list, a);
3605 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3606 do
3607 {
3608 p = a;
3609 forced_valid = false;
3610 k_info = NULL;
3611
3612 /* If a crypt-hook provides a key ID, confirm with the user unless
3613 * in opportunistic encryption mode */
3614 if (crypt_hook)
3615 {
3616 keyid = crypt_hook->data;
3617 enum QuadOption ans = MUTT_YES;
3618 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3619 {
3620 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3621 buf_string(p->mailbox));
3622 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3623 }
3624 if (ans == MUTT_YES)
3625 {
3626 if (crypt_is_numerical_keyid(keyid))
3627 {
3628 if (mutt_strn_equal(keyid, "0x", 2))
3629 keyid += 2;
3630 goto bypass_selection; /* you don't see this. */
3631 }
3632
3633 /* check for e-mail address */
3634 mutt_addrlist_clear(&hookal);
3635 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3636 {
3637 mutt_addrlist_qualify(&hookal, fqdn);
3638 p = TAILQ_FIRST(&hookal);
3639 }
3640 else if (!oppenc_mode)
3641 {
3642 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3643 }
3644 }
3645 else if (ans == MUTT_NO)
3646 {
3647 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3648 {
3649 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3650 continue;
3651 }
3652 }
3653 else if (ans == MUTT_ABORT)
3654 {
3655 FREE(&keylist);
3656 mutt_addrlist_clear(&hookal);
3657 mutt_list_free(&crypt_hook_list);
3658 return NULL;
3659 }
3660 }
3661
3662 /* If no key found yet, try looking up by address in the keyring */
3663 if (!k_info)
3664 {
3665 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3666 }
3667
3668 /* Last resort: prompt the user to enter a key ID interactively */
3669 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3670 {
3671 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3672
3673 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3674 KEYFLAG_CANENCRYPT, app, &forced_valid);
3675 }
3676
3677 if (!k_info)
3678 {
3679 FREE(&keylist);
3680 mutt_addrlist_clear(&hookal);
3681 mutt_list_free(&crypt_hook_list);
3682 return NULL;
3683 }
3684
3685 keyid = crypt_fpr_or_lkeyid(k_info);
3686
3687 bypass_selection:
3688 /* Append the selected key ID to the space-separated keylist string */
3689 keylist_size += mutt_str_len(keyid) + 4 + 1;
3690 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
3691 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3692 keyid, forced_valid ? "!" : "");
3693 keylist_used = mutt_str_len(keylist);
3694
3695 key_selected = true;
3696
3697 crypt_key_free(&k_info);
3698 mutt_addrlist_clear(&hookal);
3699
3700 if (crypt_hook)
3701 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3702
3703 } while (crypt_hook);
3704
3705 mutt_list_free(&crypt_hook_list);
3706 }
3707 return keylist;
3708}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:687
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition crypt.c:1490
static struct CryptKeyInfo * crypt_getkeybyaddr(struct Address *a, KeyFlags abilities, unsigned int app, bool *forced_valid, bool oppenc_mode)
Find a key by email address.
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
static struct CryptKeyInfo * crypt_ask_for_key(const char *tag, const char *whatfor, KeyFlags abilities, unsigned int app, bool *forced_valid)
Ask the user for a key.
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition exec.c:319
#define MUTT_MEM_REALLOC(pptr, n, T)
Definition memory.h:78
QuadOption
Possible values for a quad-option.
Definition quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G).
Definition quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
enum QuadOption query_yesorno_help(const char *prompt, enum QuadOption def, struct ConfigSubset *sub, const char *name)
Ask the user a Yes/No question offering help.
Definition question.c:357
#define TAILQ_FIRST(head)
Definition queue.h:780
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:718
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mutt_gpgme_select_secret_key()

int mutt_gpgme_select_secret_key ( struct Buffer * keyid)

Select a private Autocrypt key for a new account.

Parameters
keyidAutocrypt Key id
Return values
0Success
-1Error

Unfortunately, the internal ncrypt/crypt_gpgme.c functions use CryptKeyInfo, and so aren't exportable.

This function queries all private keys, provides the crypt_select_keys() menu, and returns the selected key fingerprint in keyid.

Definition at line 3739 of file crypt_gpgme.c.

3740{
3741 int rc = -1;
3742 gpgme_error_t err = GPG_ERR_NO_ERROR;
3743 gpgme_key_t key = NULL;
3744 gpgme_user_id_t uid = NULL;
3745 struct CryptKeyInfo *results = NULL;
3746 struct CryptKeyInfo *k = NULL;
3747 struct CryptKeyInfo **kend = NULL;
3748 struct CryptKeyInfo *choice = NULL;
3749
3750 gpgme_ctx_t ctx = create_gpgme_context(false);
3751
3752 /* list all secret keys */
3753 if (gpgme_op_keylist_start(ctx, NULL, 1))
3754 goto cleanup;
3755
3756 kend = &results;
3757
3758 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3759 {
3761
3766
3767 if (key->revoked)
3769 if (key->expired)
3771 if (key->disabled)
3773
3774 int idx;
3775 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3776 {
3777 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3778 k->kobj = key;
3779 gpgme_key_ref(k->kobj);
3780 k->idx = idx;
3781 k->uid = uid->uid;
3782 k->flags = flags;
3783 if (uid->revoked)
3784 k->flags |= KEYFLAG_REVOKED;
3785 k->validity = uid->validity;
3786 *kend = k;
3787 kend = &k->next;
3788 }
3789 gpgme_key_unref(key);
3790 }
3791 if (gpg_err_code(err) != GPG_ERR_EOF)
3792 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3793 gpgme_op_keylist_end(ctx);
3794
3795 if (!results)
3796 {
3797 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3798 from. This error is displayed if no results were found. */
3799 mutt_error(_("No secret keys found"));
3800 goto cleanup;
3801 }
3802
3803 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3804 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3805 goto cleanup;
3806 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3807
3808 rc = 0;
3809
3810cleanup:
3811 crypt_key_free(&choice);
3812 crypt_key_free(&results);
3813 gpgme_release(ctx);
3814 return rc;
3815}
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 3879 of file crypt_gpgme.c.

3880{
3881 /* this initialization should only run one time, but it may be called by
3882 * either pgp_gpgme_init or smime_gpgme_init */
3883 static bool has_run = false;
3884 if (has_run)
3885 return;
3886
3887 gpgme_check_version(NULL);
3888 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3889#ifdef ENABLE_NLS
3890 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3891#endif
3892 has_run = true;
3893}
Here is the caller graph for this function:

◆ init_pgp()

void init_pgp ( void )
static

Initialise the PGP crypto backend.

Definition at line 3898 of file crypt_gpgme.c.

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

◆ init_smime()

void init_smime ( void )
static

Initialise the SMIME crypto backend.

Definition at line 3909 of file crypt_gpgme.c.

3910{
3911 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3912 {
3913 mutt_error(_("GPGME: CMS protocol not available"));
3914 }
3915}
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 3941 of file crypt_gpgme.c.

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

◆ verify_sender()

bool verify_sender ( struct Email * e)
static

Verify the sender of a message.

Parameters
eEmail
Return values
trueSender is verified

Definition at line 4123 of file crypt_gpgme.c.

4124{
4126 struct Address *sender = NULL;
4127 bool rc = true;
4128
4129 if (!TAILQ_EMPTY(&e->env->from))
4130 {
4132 sender = TAILQ_FIRST(&e->env->from);
4133 }
4134 else if (!TAILQ_EMPTY(&e->env->sender))
4135 {
4137 sender = TAILQ_FIRST(&e->env->sender);
4138 }
4139
4140 if (sender)
4141 {
4142 if ((gpgme_key_t) mod_data->signature_key)
4143 {
4144 gpgme_key_t key = (gpgme_key_t) mod_data->signature_key;
4145 gpgme_user_id_t uid = NULL;
4146 int sender_length = buf_len(sender->mailbox);
4147 for (uid = key->uids; uid && rc; uid = uid->next)
4148 {
4149 int uid_length = strlen(uid->email);
4150 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4151 (uid_length == (sender_length + 2)))
4152 {
4153 const char *at_sign = strchr(uid->email + 1, '@');
4154 if (at_sign)
4155 {
4156 /* Assume address is 'mailbox@domainname'.
4157 * The mailbox part is case-sensitive,
4158 * the domainname is not. (RFC2821) */
4159 const char *tmp_email = uid->email + 1;
4160 const char *tmp_sender = buf_string(sender->mailbox);
4161 /* length of mailbox part including '@' */
4162 int mailbox_length = at_sign - tmp_email + 1;
4163 int domainname_length = sender_length - mailbox_length;
4164 int mailbox_match;
4165 int domainname_match;
4166
4167 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4168 tmp_email += mailbox_length;
4169 tmp_sender += mailbox_length;
4170 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4171 if (mailbox_match && domainname_match)
4172 rc = false;
4173 }
4174 else
4175 {
4176 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4177 rc = false;
4178 }
4179 }
4180 }
4181 }
4182 else
4183 {
4184 mutt_any_key_to_continue(_("Failed to verify sender"));
4185 }
4186 }
4187 else
4188 {
4189 mutt_any_key_to_continue(_("Failed to figure out sender"));
4190 }
4191
4192 if ((gpgme_key_t) mod_data->signature_key)
4193 {
4194 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4195 mod_data->signature_key = NULL;
4196 }
4197
4198 return rc;
4199}
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 4224 of file crypt_gpgme.c.

4225{
4226 return GPGME_VERSION;
4227}
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 4233 of file crypt_gpgme.c.

4234{
4235 struct CryptCache *l = mod_data->gpgme_id_defaults;
4236 while (l)
4237 {
4238 struct CryptCache *next = l->next;
4239 FREE(&l->what);
4240 FREE(&l->dflt);
4241 FREE(&l);
4242 l = next;
4243 }
4244 mod_data->gpgme_id_defaults = NULL;
4245
4246 if ((gpgme_key_t) mod_data->signature_key)
4247 {
4248 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4249 mod_data->signature_key = NULL;
4250 }
4251}
Here is the caller graph for this function: