NeoMutt  2025-12-11-694-ga89709
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 "mutt_logging.h"
#include "autocrypt/lib.h"
+ Include dependency graph for crypt_gpgme.c:

Go to the source code of this file.

Data Structures

struct  CryptCache
 Internal cache for GPGME. More...
 

Macros

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

Functions

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

Variables

static struct CryptCacheIdDefaults = NULL
 Cache of GPGME keys.
 
static gpgme_key_t SignatureKey = NULL
 PGP Key to sign with.
 
static char * CurrentSender = NULL
 Email address of the sender.
 

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

◆ CRYPT_KV_ADDR

#define CRYPT_KV_ADDR   (1 << 1)

Definition at line 75 of file crypt_gpgme.c.

◆ CRYPT_KV_STRING

#define CRYPT_KV_STRING   (1 << 2)

Definition at line 76 of file crypt_gpgme.c.

◆ CRYPT_KV_STRONGID

#define CRYPT_KV_STRONGID   (1 << 3)

Definition at line 77 of file crypt_gpgme.c.

◆ CRYPT_KV_MATCH

#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)

Definition at line 78 of file crypt_gpgme.c.

◆ PKA_NOTATION_NAME

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

Definition at line 98 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 100 of file crypt_gpgme.c.

◆ MESSAGE

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

Definition at line 101 of file crypt_gpgme.c.

◆ SIGNED_MESSAGE

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

Definition at line 102 of file crypt_gpgme.c.

◆ PUBLIC_KEY_BLOCK

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

Definition at line 103 of file crypt_gpgme.c.

◆ BEGIN_PGP_SIGNATURE

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

Definition at line 104 of file crypt_gpgme.c.

104#define BEGIN_PGP_SIGNATURE(_y) \
105 _LINE_COMPARE("-----BEGIN PGP SIGNATURE-----", _y)

Function Documentation

◆ is_pka_notation()

static bool is_pka_notation ( gpgme_sig_notation_t notation)
static

Is this the standard pka email address.

Parameters
notationGPGME notation
Return values
trueIt is the standard pka email address

Definition at line 112 of file crypt_gpgme.c.

113{
114 return mutt_str_equal(notation->name, PKA_NOTATION_NAME);
115}
#define PKA_NOTATION_NAME
Definition crypt_gpgme.c:98
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ redraw_if_needed()

static void redraw_if_needed ( gpgme_ctx_t ctx)
static

Accommodate for a redraw if needed.

Parameters
ctxGPGME handle

Definition at line 121 of file crypt_gpgme.c.

122{
123 const char *s = gpgme_get_ctx_flag(ctx, "redraw");
124 if (!s /* flag not known */ || *s /* flag true */)
125 {
127 }
128}
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition curs_lib.c:100
+ 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 138 of file crypt_gpgme.c.

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

◆ crypt_long_keyid()

static const char * crypt_long_keyid ( struct CryptKeyInfo * k)
static

Find the Long ID for the key.

Parameters
kKey to use
Return values
ptrLong ID string for the key

Return the long keyID for the key K.

Definition at line 163 of file crypt_gpgme.c.

164{
165 const char *s = "????????????????";
166
167 if (k->kobj && k->kobj->subkeys)
168 {
169 s = k->kobj->subkeys->keyid;
170 }
171
172 return s;
173}
+ Here is the caller graph for this function:

◆ crypt_short_keyid()

static const char * crypt_short_keyid ( struct CryptKeyInfo * k)
static

Get the short keyID for a key.

Parameters
kKey to use
Return values
ptrShort key string

Definition at line 180 of file crypt_gpgme.c.

181{
182 const char *s = "????????";
183
184 if (k->kobj && k->kobj->subkeys)
185 {
186 s = k->kobj->subkeys->keyid;
187 if (strlen(s) == 16)
188 s += 8;
189 }
190
191 return s;
192}
+ Here is the caller graph for this function:

◆ crypt_fpr()

static const char * crypt_fpr ( struct CryptKeyInfo * k)
static

Get the hexstring fingerprint from a key.

Parameters
kKey to use
Return values
ptrHexstring fingerprint

Definition at line 199 of file crypt_gpgme.c.

200{
201 const char *s = "";
202
203 if (k->kobj && k->kobj->subkeys)
204 s = k->kobj->subkeys->fpr;
205
206 return s;
207}
+ 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 214 of file crypt_gpgme.c.

215{
216 const char *s = "????????????????";
217
218 if (k->kobj && k->kobj->subkeys)
219 {
220 if (k->kobj->subkeys->fpr)
221 s = k->kobj->subkeys->fpr;
222 else
223 s = k->kobj->subkeys->keyid;
224 }
225
226 return s;
227}
+ 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 234 of file crypt_gpgme.c.

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

◆ crypt_key_free()

static void crypt_key_free ( struct CryptKeyInfo ** keylist)
static

Release all the keys in a list.

Parameters
[out]keylistList of keys

Definition at line 253 of file crypt_gpgme.c.

254{
255 if (!keylist)
256 return;
257
258 struct CryptKeyInfo *k = NULL;
259
260 while (*keylist)
261 {
262 k = *keylist;
263 *keylist = (*keylist)->next;
264
265 gpgme_key_unref(k->kobj);
266 FREE(&k);
267 }
268}
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
struct CryptKeyInfo * next
Linked list.
Definition crypt_gpgme.h:45
+ Here is the caller graph for this function:

◆ crypt_id_is_strong()

bool crypt_id_is_strong ( struct CryptKeyInfo * key)

Is the key strong.

Parameters
keyKey to test
Return values
trueValidity of key is sufficient

Definition at line 275 of file crypt_gpgme.c.

276{
277 if (!key)
278 return false;
279
280 bool is_strong = false;
281
282 if ((key->flags & KEYFLAG_ISX509))
283 return true;
284
285 switch (key->validity)
286 {
287 case GPGME_VALIDITY_MARGINAL:
288 case GPGME_VALIDITY_NEVER:
289 case GPGME_VALIDITY_UNDEFINED:
290 case GPGME_VALIDITY_UNKNOWN:
291 is_strong = false;
292 break;
293
294 case GPGME_VALIDITY_FULL:
295 case GPGME_VALIDITY_ULTIMATE:
296 is_strong = true;
297 break;
298 }
299
300 return is_strong;
301}
#define KEYFLAG_ISX509
Key is an X.509 key.
Definition lib.h:137
+ Here is the caller graph for this function:

◆ crypt_id_is_valid()

int crypt_id_is_valid ( struct CryptKeyInfo * key)

Is key ID valid.

Parameters
keyKey to test
Return values
trueKey is valid

When the key is not marked as unusable

Definition at line 310 of file crypt_gpgme.c.

311{
312 if (!key)
313 return 0;
314
315 return !(key->flags & KEYFLAG_CANTUSE);
316}
#define KEYFLAG_CANTUSE
Definition lib.h:147
+ Here is the caller graph for this function:

◆ crypt_id_matches_addr()

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

Does the key ID match the address.

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

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

Definition at line 328 of file crypt_gpgme.c.

330{
331 int rc = 0;
332
333 if (crypt_id_is_valid(key))
334 rc |= CRYPT_KV_VALID;
335
336 if (crypt_id_is_strong(key))
337 rc |= CRYPT_KV_STRONGID;
338
339 if (addr && u_addr)
340 {
341 if (addr->mailbox && u_addr->mailbox && buf_istr_equal(addr->mailbox, u_addr->mailbox))
342 {
343 rc |= CRYPT_KV_ADDR;
344 }
345
346 if (addr->personal && u_addr->personal &&
347 buf_istr_equal(addr->personal, u_addr->personal))
348 {
349 rc |= CRYPT_KV_STRING;
350 }
351 }
352
353 return rc;
354}
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition buffer.c:695
#define CRYPT_KV_STRING
Definition crypt_gpgme.c:76
int crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
#define CRYPT_KV_VALID
Definition crypt_gpgme.c:74
#define CRYPT_KV_STRONGID
Definition crypt_gpgme.c:77
#define CRYPT_KV_ADDR
Definition crypt_gpgme.c:75
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 361 of file crypt_gpgme.c.

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

◆ create_gpgme_data()

static gpgme_data_t create_gpgme_data ( void )
static

Create a new GPGME data object.

Return values
ptrGPGPE data object

This is a wrapper to die on error.

Note
Call gpgme_data_release() to free the data object

Definition at line 400 of file crypt_gpgme.c.

401{
402 gpgme_data_t data = NULL;
403
404 gpgme_error_t err = gpgme_data_new(&data);
405 if (err != GPG_ERR_NO_ERROR)
406 {
407 mutt_error(_("error creating GPGME data object: %s"), gpgme_strerror(err));
408 mutt_exit(1);
409 }
410 return data;
411}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ body_to_data_object()

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

Create GPGME object from the mail body.

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

Definition at line 419 of file crypt_gpgme.c.

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

◆ file_to_data_object()

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

Create GPGME data object from file.

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

Definition at line 493 of file crypt_gpgme.c.

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

◆ data_object_to_stream()

static int data_object_to_stream ( gpgme_data_t data,
FILE * fp )
static

Write a GPGME data object to a file.

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

Definition at line 514 of file crypt_gpgme.c.

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

◆ data_object_to_tempfile()

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

Copy a data object to a temporary file.

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

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

Note
The caller must free the returned file name

Definition at line 563 of file crypt_gpgme.c.

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

◆ create_recipient_string()

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

Create a string of recipients.

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

Definition at line 622 of file crypt_gpgme.c.

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

◆ set_signer_from_address()

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

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

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

Definition at line 658 of file crypt_gpgme.c.

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

◆ set_signer()

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

Make sure that the correct signer is set.

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

Definition at line 717 of file crypt_gpgme.c.

718{
719 const char *signid = NULL;
720
721 const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
722 const char *const c_pgp_sign_as = cs_subset_string(NeoMutt->sub, "pgp_sign_as");
723 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
724 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
725 if (for_smime)
726 signid = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
727#ifdef USE_AUTOCRYPT
728 else if (OptAutocryptGpgme)
729 signid = AutocryptSignAs;
730#endif
731 else
732 signid = c_pgp_sign_as ? c_pgp_sign_as : c_pgp_default_key;
733
734 /* Try getting the signing key from config entries */
735 if (signid && set_signer_from_address(ctx, signid, for_smime))
736 {
737 return 0;
738 }
739
740 /* Try getting the signing key from the From line */
741 if (al)
742 {
743 struct Address *a;
744 TAILQ_FOREACH(a, al, entries)
745 {
746 if (a->mailbox && set_signer_from_address(ctx, buf_string(a->mailbox), for_smime))
747 {
748 return 0;
749 }
750 }
751 }
752
753 return (!signid && !al) ? 0 : -1;
754}
char * AutocryptSignAs
Autocrypt Key id to sign as.
Definition config.c:37
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.
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
An email address.
Definition address.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_pka_sig_notation()

static gpgme_error_t set_pka_sig_notation ( gpgme_ctx_t ctx)
static

Set the signature notation.

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

Definition at line 761 of file crypt_gpgme.c.

762{
763 gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME, CurrentSender, 0);
764 if (err != GPG_ERR_NO_ERROR)
765 {
766 mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
767 }
768
769 return err;
770}
static char * CurrentSender
Email address of the sender.
Definition crypt_gpgme.c:96
+ Here is the caller graph for this function:

◆ encrypt_gpgme_object()

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

Encrypt the GPGPME data object.

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

Definition at line 781 of file crypt_gpgme.c.

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

◆ get_micalg()

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

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

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

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

Definition at line 853 of file crypt_gpgme.c.

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

◆ print_time()

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

Print the date/time according to the locale.

Parameters
tTimestamp
stateState to write to

Definition at line 891 of file crypt_gpgme.c.

892{
893 char p[256] = { 0 };
894 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
895 state_puts(state, p);
896}
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition date.c:952
#define state_puts(STATE, STR)
Definition state.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ sign_message()

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

Sign a message.

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

Definition at line 906 of file crypt_gpgme.c.

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

◆ show_sig_summary()

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

Show a signature summary.

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

Display the common attributes of the signature summary SUM.

Definition at line 1133 of file crypt_gpgme.c.

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

◆ show_fingerprint()

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

Write a key's fingerprint.

Parameters
keyGPGME key
stateState to write to

Definition at line 1257 of file crypt_gpgme.c.

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

◆ show_one_sig_validity()

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

Show the validity of a key used for one signature.

Parameters
ctxGPGME handle
idxIndex of signature to check
stateState to use

Definition at line 1312 of file crypt_gpgme.c.

1313{
1314 gpgme_signature_t sig = NULL;
1315 const char *txt = NULL;
1316
1317 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1318 if (result)
1319 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--)
1320 ; // do nothing
1321
1322 switch (sig ? sig->validity : 0)
1323 {
1324 case GPGME_VALIDITY_UNKNOWN:
1325 txt = _("WARNING: We have NO indication whether the key belongs to the person named as shown above\n");
1326 break;
1327 case GPGME_VALIDITY_UNDEFINED:
1328 break;
1329 case GPGME_VALIDITY_NEVER:
1330 txt = _("WARNING: The key does NOT BELONG to the person named as shown above\n");
1331 break;
1332 case GPGME_VALIDITY_MARGINAL:
1333 txt = _("WARNING: It is NOT certain that the key belongs to the person named as shown above\n");
1334 break;
1335 case GPGME_VALIDITY_FULL:
1336 case GPGME_VALIDITY_ULTIMATE:
1337 txt = NULL;
1338 break;
1339 }
1340 if (txt)
1341 state_puts(state, txt);
1342}
+ Here is the caller graph for this function:

◆ print_smime_keyinfo()

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

Print key info about an SMIME key.

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

Definition at line 1351 of file crypt_gpgme.c.

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

◆ show_one_recipient()

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

Show information about one encryption recipient.

Parameters
stateState to write to
rEncryption recipient

Definition at line 1417 of file crypt_gpgme.c.

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

◆ show_encryption_info()

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

Show encryption information.

Parameters
stateState to write to
resultDecryption result

Definition at line 1433 of file crypt_gpgme.c.

1434{
1435 if (!cs_subset_bool(NeoMutt->sub, "crypt_encryption_info"))
1436 return;
1437
1438 state_attach_puts(state, _("[-- Begin encryption information --]\n"));
1439
1440 for (gpgme_recipient_t r = result->recipients; r; r = r->next)
1441 show_one_recipient(state, r);
1442
1443 state_attach_puts(state, _("[-- End encryption information --]\n\n"));
1444}
static void show_one_recipient(struct State *state, gpgme_recipient_t r)
Show information about one encryption recipient.
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition state.c:104
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ show_one_sig_status()

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

Show information about one signature.

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

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

Definition at line 1458 of file crypt_gpgme.c.

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

◆ verify_one()

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

Do the actual verification step.

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

With is_smime set to true we assume S/MIME.

Definition at line 1581 of file crypt_gpgme.c.

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

◆ decrypt_part()

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

Decrypt a PGP or SMIME message.

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

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

Definition at line 1732 of file crypt_gpgme.c.

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

◆ pgp_gpgme_extract_keys()

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

Write PGP keys to a file.

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

Definition at line 2112 of file crypt_gpgme.c.

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

◆ line_compare()

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

Compare two strings ignore line endings.

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

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

Definition at line 2195 of file crypt_gpgme.c.

2196{
2197 if (mutt_strn_equal(a, b, n))
2198 {
2199 /* at this point we know that 'b' is at least 'n' chars long */
2200 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2201 return true;
2202 }
2203 return false;
2204}
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
+ Here is the call graph for this function:

◆ pgp_check_traditional_one_body()

static int pgp_check_traditional_one_body ( FILE * fp,
struct Body * b )
static

Check one inline PGP body part.

Parameters
fpFile to read from
bBody of the email
Return values
trueSuccess
falseError

Definition at line 2213 of file crypt_gpgme.c.

2214{
2215 char buf[8192] = { 0 };
2216 bool rc = false;
2217
2218 bool sgn = false;
2219 bool enc = false;
2220
2221 if (b->type != TYPE_TEXT)
2222 return 0;
2223
2224 struct Buffer *tempfile = buf_pool_get();
2225 buf_mktemp(tempfile);
2227 MUTT_SAVE_NO_FLAGS) != 0)
2228 {
2229 unlink(buf_string(tempfile));
2230 goto cleanup;
2231 }
2232
2233 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2234 if (!fp_tmp)
2235 {
2236 unlink(buf_string(tempfile));
2237 goto cleanup;
2238 }
2239
2240 while (fgets(buf, sizeof(buf), fp_tmp))
2241 {
2242 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2243 if (plen != 0)
2244 {
2245 if (MESSAGE(buf + plen))
2246 {
2247 enc = true;
2248 break;
2249 }
2250 else if (SIGNED_MESSAGE(buf + plen))
2251 {
2252 sgn = true;
2253 break;
2254 }
2255 }
2256 }
2257 mutt_file_fclose(&fp_tmp);
2258 unlink(buf_string(tempfile));
2259
2260 if (!enc && !sgn)
2261 goto cleanup;
2262
2263 /* fix the content type */
2264
2265 mutt_param_set(&b->parameter, "format", "fixed");
2266 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2267
2268 rc = true;
2269
2270cleanup:
2271 buf_pool_release(&tempfile);
2272 return rc;
2273}
#define SIGNED_MESSAGE(_y)
#define MESSAGE(_y)
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
#define STATE_NO_FLAGS
No flags are set.
Definition state.h:32
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
@ MUTT_SAVE_NO_FLAGS
Overwrite existing file (the default)
Definition mutt_attach.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ copy_clearsigned()

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

Copy a clearsigned message.

Parameters
dataGPGME data object
stateState to use
charsetCharset of message

strip the signature and PGP's dash-escaping.

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

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

Definition at line 2414 of file crypt_gpgme.c.

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

◆ key_check_cap()

unsigned int key_check_cap ( gpgme_key_t key,
enum KeyCap cap )

Check the capabilities of a key.

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

Definition at line 2947 of file crypt_gpgme.c.

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

◆ list_to_pattern()

static char * list_to_pattern ( struct ListHead * list)
static

Convert STailQ to GPGME-compatible pattern.

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

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

Note
The caller must free the returned pattern

Definition at line 3003 of file crypt_gpgme.c.

3004{
3005 char *pattern = NULL, *p = NULL;
3006 const char *s = NULL;
3007 size_t n;
3008
3009 n = 0;
3010 struct ListNode *np = NULL;
3011 STAILQ_FOREACH(np, list, entries)
3012 {
3013 for (s = np->data; *s; s++)
3014 {
3015 if ((*s == '%') || (*s == '+'))
3016 n += 2;
3017 n++;
3018 }
3019 n++; /* delimiter or end of string */
3020 }
3021 n++; /* make sure to allocate at least one byte */
3022 p = MUTT_MEM_CALLOC(n, char);
3023 pattern = p;
3024 STAILQ_FOREACH(np, list, entries)
3025 {
3026 s = np->data;
3027 if (*s)
3028 {
3029 if (np != STAILQ_FIRST(list))
3030 *p++ = ' ';
3031 for (s = np->data; *s; s++)
3032 {
3033 if (*s == '%')
3034 {
3035 *p++ = '%';
3036 *p++ = '2';
3037 *p++ = '5';
3038 }
3039 else if (*s == '+')
3040 {
3041 *p++ = '%';
3042 *p++ = '2';
3043 *p++ = 'B';
3044 }
3045 else if (*s == ' ')
3046 {
3047 *p++ = '+';
3048 }
3049 else
3050 {
3051 *p++ = *s;
3052 }
3053 }
3054 }
3055 }
3056 *p = '\0';
3057 return pattern;
3058}
#define STAILQ_FIRST(head)
Definition queue.h:388
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
+ Here is the caller graph for this function:

◆ get_candidates()

static struct CryptKeyInfo * get_candidates ( struct ListHead * hints,
SecurityFlags app,
int secret )
static

Get a list of keys which are candidates for the selection.

Parameters
hintsList of strings to match
appApplication type, e.g. APPLICATION_PGP
secretIf true, only match secret keys
Return values
ptrKey List
NULLError

Select by looking at the HINTS list.

Definition at line 3070 of file crypt_gpgme.c.

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

◆ crypt_add_string_to_hints()

static void crypt_add_string_to_hints ( const char * str,
struct ListHead * hints )
static

Split a string and add the parts to a List.

Parameters
[in]strString to parse
[out]hintsList of string parts

The string str is split by whitespace and punctuation and the parts added to hints. This list is later used to match addresses.

Definition at line 3223 of file crypt_gpgme.c.

3224{
3225 char *scratch = mutt_str_dup(str);
3226 if (!scratch)
3227 return;
3228
3229 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3230 {
3231 if (strlen(t) > 3)
3233 }
3234
3235 FREE(&scratch);
3236}
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition list.c:65
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_getkeybyaddr()

static struct CryptKeyInfo * crypt_getkeybyaddr ( struct Address * a,
KeyFlags abilities,
unsigned int app,
bool * forced_valid,
bool oppenc_mode )
static

Find a key by email address.

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

Definition at line 3247 of file crypt_gpgme.c.

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

◆ crypt_getkeybystr()

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

Find a key by string.

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

Definition at line 3381 of file crypt_gpgme.c.

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

◆ crypt_ask_for_key()

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

Ask the user for a key.

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

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

Definition at line 3464 of file crypt_gpgme.c.

3467{
3468 struct CryptKeyInfo *key = NULL;
3469 struct CryptCache *l = NULL;
3470 struct Buffer *resp = buf_pool_get();
3471
3473
3474 if (whatfor)
3475 {
3476 for (l = IdDefaults; l; l = l->next)
3477 {
3478 if (mutt_istr_equal(whatfor, l->what))
3479 {
3480 buf_strcpy(resp, l->dflt);
3481 break;
3482 }
3483 }
3484 }
3485
3486 while (true)
3487 {
3488 buf_reset(resp);
3489 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
3490 {
3491 goto done;
3492 }
3493
3494 if (whatfor)
3495 {
3496 if (l)
3497 {
3498 mutt_str_replace(&l->dflt, buf_string(resp));
3499 }
3500 else
3501 {
3502 l = MUTT_MEM_MALLOC(1, struct CryptCache);
3503 l->next = IdDefaults;
3504 IdDefaults = l;
3505 l->what = mutt_str_dup(whatfor);
3506 l->dflt = buf_strdup(resp);
3507 }
3508 }
3509
3510 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3511 if (key)
3512 goto done;
3513
3514 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3515 }
3516
3517done:
3518 buf_pool_release(&resp);
3519 return key;
3520}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
static struct CryptCache * IdDefaults
Cache of GPGME keys.
Definition crypt_gpgme.c:92
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
Find a key by string.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition wdata.h:42
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:463
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:60
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Internal cache for GPGME.
Definition crypt_gpgme.c:85
char * what
Cached key identifier.
Definition crypt_gpgme.c:86
char * dflt
Default key ID.
Definition crypt_gpgme.c:87
struct CryptCache * next
Linked list.
Definition crypt_gpgme.c:88
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_keys()

static char * find_keys ( const struct AddressList * addrlist,
unsigned int app,
bool oppenc_mode )
static

Find keys of the recipients of the message.

Parameters
addrlistAddress List
appApplication type, e.g. APPLICATION_PGP
oppenc_modeIf true, use opportunistic encryption
Return values
ptrSpace-separated string of keys
NULLAt least one of the keys can't be found

If oppenc_mode is true, only keys that can be determined without prompting will be used.

Definition at line 3533 of file crypt_gpgme.c.

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

◆ mutt_gpgme_select_secret_key()

int mutt_gpgme_select_secret_key ( struct Buffer * keyid)

Select a private Autocrypt key for a new account.

Parameters
keyidAutocrypt Key id
Return values
0Success
-1Error

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

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

Definition at line 3691 of file crypt_gpgme.c.

3692{
3693 int rc = -1;
3694 gpgme_error_t err = GPG_ERR_NO_ERROR;
3695 gpgme_key_t key = NULL;
3696 gpgme_user_id_t uid = NULL;
3697 struct CryptKeyInfo *results = NULL, *k = NULL;
3698 struct CryptKeyInfo **kend = NULL;
3699 struct CryptKeyInfo *choice = NULL;
3700
3701 gpgme_ctx_t ctx = create_gpgme_context(false);
3702
3703 /* list all secret keys */
3704 if (gpgme_op_keylist_start(ctx, NULL, 1))
3705 goto cleanup;
3706
3707 kend = &results;
3708
3709 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3710 {
3712
3717
3718 if (key->revoked)
3720 if (key->expired)
3722 if (key->disabled)
3724
3725 int idx;
3726 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3727 {
3728 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3729 k->kobj = key;
3730 gpgme_key_ref(k->kobj);
3731 k->idx = idx;
3732 k->uid = uid->uid;
3733 k->flags = flags;
3734 if (uid->revoked)
3735 k->flags |= KEYFLAG_REVOKED;
3736 k->validity = uid->validity;
3737 *kend = k;
3738 kend = &k->next;
3739 }
3740 gpgme_key_unref(key);
3741 }
3742 if (gpg_err_code(err) != GPG_ERR_EOF)
3743 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3744 gpgme_op_keylist_end(ctx);
3745
3746 if (!results)
3747 {
3748 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3749 from. This error is displayed if no results were found. */
3750 mutt_error(_("No secret keys found"));
3751 goto cleanup;
3752 }
3753
3754 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3755 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3756 goto cleanup;
3757 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3758
3759 rc = 0;
3760
3761cleanup:
3762 crypt_key_free(&choice);
3763 crypt_key_free(&results);
3764 gpgme_release(ctx);
3765 return rc;
3766}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ init_common()

static void init_common ( void )
static

Initialise code common to PGP and SMIME parts of GPGME.

Definition at line 3830 of file crypt_gpgme.c.

3831{
3832 /* this initialization should only run one time, but it may be called by
3833 * either pgp_gpgme_init or smime_gpgme_init */
3834 static bool has_run = false;
3835 if (has_run)
3836 return;
3837
3838 gpgme_check_version(NULL);
3839 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3840#ifdef ENABLE_NLS
3841 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3842#endif
3843 has_run = true;
3844}
+ Here is the caller graph for this function:

◆ init_pgp()

static void init_pgp ( void )
static

Initialise the PGP crypto backend.

Definition at line 3849 of file crypt_gpgme.c.

3850{
3851 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3852 {
3853 mutt_error(_("GPGME: OpenPGP protocol not available"));
3854 }
3855}
+ Here is the caller graph for this function:

◆ init_smime()

static void init_smime ( void )
static

Initialise the SMIME crypto backend.

Definition at line 3860 of file crypt_gpgme.c.

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

◆ gpgme_send_menu()

static SecurityFlags gpgme_send_menu ( struct Email * e,
bool is_smime )
static

Show the user the encryption/signing menu.

Parameters
eEmail
is_smimeTrue if an SMIME message
Return values
numFlags, e.g. APPLICATION_SMIME | SEC_ENCRYPT

Definition at line 3892 of file crypt_gpgme.c.

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

◆ verify_sender()

static bool verify_sender ( struct Email * e)
static

Verify the sender of a message.

Parameters
eEmail
Return values
trueSender is verified

Definition at line 4071 of file crypt_gpgme.c.

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

4170{
4171 return GPGME_VERSION;
4172}
+ Here is the caller graph for this function:

Variable Documentation

◆ IdDefaults

struct CryptCache* IdDefaults = NULL
static

Cache of GPGME keys.

Definition at line 92 of file crypt_gpgme.c.

◆ SignatureKey

gpgme_key_t SignatureKey = NULL
static

PGP Key to sign with.

Definition at line 94 of file crypt_gpgme.c.

◆ CurrentSender

char* CurrentSender = NULL
static

Email address of the sender.

Definition at line 96 of file crypt_gpgme.c.