NeoMutt  2025-12-11-117-gc1a713
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 "handler.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 75 of file crypt_gpgme.c.

◆ CRYPT_KV_ADDR

#define CRYPT_KV_ADDR   (1 << 1)

Definition at line 76 of file crypt_gpgme.c.

◆ CRYPT_KV_STRING

#define CRYPT_KV_STRING   (1 << 2)

Definition at line 77 of file crypt_gpgme.c.

◆ CRYPT_KV_STRONGID

#define CRYPT_KV_STRONGID   (1 << 3)

Definition at line 78 of file crypt_gpgme.c.

◆ CRYPT_KV_MATCH

#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)

Definition at line 79 of file crypt_gpgme.c.

◆ PKA_NOTATION_NAME

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

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

◆ MESSAGE

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

Definition at line 102 of file crypt_gpgme.c.

◆ SIGNED_MESSAGE

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

Definition at line 103 of file crypt_gpgme.c.

◆ PUBLIC_KEY_BLOCK

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

Definition at line 104 of file crypt_gpgme.c.

◆ BEGIN_PGP_SIGNATURE

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

Definition at line 105 of file crypt_gpgme.c.

105#define BEGIN_PGP_SIGNATURE(_y) \
106 _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 113 of file crypt_gpgme.c.

114{
115 return mutt_str_equal(notation->name, PKA_NOTATION_NAME);
116}
#define PKA_NOTATION_NAME
Definition crypt_gpgme.c:99
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:662
+ 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 122 of file crypt_gpgme.c.

123{
124 const char *s = gpgme_get_ctx_flag(ctx, "redraw");
125 if (!s /* flag not known */ || *s /* flag true */)
126 {
128 }
129}
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition curs_lib.c:101
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_keyid()

const char * crypt_keyid ( struct CryptKeyInfo * k)

Find the ID for the key.

Parameters
kKey to use
Return values
ptrID string for the key

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

Definition at line 139 of file crypt_gpgme.c.

140{
141 const char *s = "????????";
142
143 if (k->kobj && k->kobj->subkeys)
144 {
145 s = k->kobj->subkeys->keyid;
146 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
147 if ((!c_pgp_long_ids) && (strlen(s) == 16))
148 {
149 /* Return only the short keyID. */
150 s += 8;
151 }
152 }
153
154 return s;
155}
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:128
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:134
+ 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 164 of file crypt_gpgme.c.

165{
166 const char *s = "????????????????";
167
168 if (k->kobj && k->kobj->subkeys)
169 {
170 s = k->kobj->subkeys->keyid;
171 }
172
173 return s;
174}
+ 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 181 of file crypt_gpgme.c.

182{
183 const char *s = "????????";
184
185 if (k->kobj && k->kobj->subkeys)
186 {
187 s = k->kobj->subkeys->keyid;
188 if (strlen(s) == 16)
189 s += 8;
190 }
191
192 return s;
193}
+ 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 200 of file crypt_gpgme.c.

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

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

236{
237 struct CryptKeyInfo *k = NULL;
238
239 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
240 k->kobj = key->kobj;
241 gpgme_key_ref(key->kobj);
242 k->idx = key->idx;
243 k->uid = key->uid;
244 k->flags = key->flags;
245 k->validity = key->validity;
246
247 return k;
248}
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:48
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 254 of file crypt_gpgme.c.

255{
256 if (!keylist)
257 return;
258
259 struct CryptKeyInfo *k = NULL;
260
261 while (*keylist)
262 {
263 k = *keylist;
264 *keylist = (*keylist)->next;
265
266 gpgme_key_unref(k->kobj);
267 FREE(&k);
268 }
269}
#define FREE(x)
Definition memory.h:63
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 276 of file crypt_gpgme.c.

277{
278 if (!key)
279 return false;
280
281 bool is_strong = false;
282
283 if ((key->flags & KEYFLAG_ISX509))
284 return true;
285
286 switch (key->validity)
287 {
288 case GPGME_VALIDITY_MARGINAL:
289 case GPGME_VALIDITY_NEVER:
290 case GPGME_VALIDITY_UNDEFINED:
291 case GPGME_VALIDITY_UNKNOWN:
292 is_strong = false;
293 break;
294
295 case GPGME_VALIDITY_FULL:
296 case GPGME_VALIDITY_ULTIMATE:
297 is_strong = true;
298 break;
299 }
300
301 return is_strong;
302}
#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 311 of file crypt_gpgme.c.

312{
313 if (!key)
314 return 0;
315
316 return !(key->flags & KEYFLAG_CANTUSE);
317}
#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 329 of file crypt_gpgme.c.

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

◆ create_gpgme_context()

gpgme_ctx_t create_gpgme_context ( bool for_smime)

Create a new GPGME context.

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

Definition at line 362 of file crypt_gpgme.c.

363{
364 gpgme_ctx_t ctx = NULL;
365
366 gpgme_error_t err = gpgme_new(&ctx);
367
368#ifdef USE_AUTOCRYPT
369 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
370 if ((err == GPG_ERR_NO_ERROR) && OptAutocryptGpgme)
371 err = gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_OpenPGP, NULL, c_autocrypt_dir);
372#endif
373
374 if (err != GPG_ERR_NO_ERROR)
375 {
376 mutt_error(_("error creating GPGME context: %s"), gpgme_strerror(err));
377 mutt_exit(1);
378 }
379
380 if (for_smime)
381 {
382 err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
383 if (err != GPG_ERR_NO_ERROR)
384 {
385 mutt_error(_("error enabling CMS protocol: %s"), gpgme_strerror(err));
386 mutt_exit(1);
387 }
388 }
389
390 return ctx;
391}
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:55
#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 401 of file crypt_gpgme.c.

402{
403 gpgme_data_t data = NULL;
404
405 gpgme_error_t err = gpgme_data_new(&data);
406 if (err != GPG_ERR_NO_ERROR)
407 {
408 mutt_error(_("error creating GPGME data object: %s"), gpgme_strerror(err));
409 mutt_exit(1);
410 }
411 return data;
412}
+ 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 420 of file crypt_gpgme.c.

421{
422 gpgme_error_t err = GPG_ERR_NO_ERROR;
423 gpgme_data_t data = NULL;
424
425 struct Buffer *tempfile = buf_pool_get();
426 buf_mktemp(tempfile);
427 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
428 if (!fp_tmp)
429 {
430 mutt_perror("%s", buf_string(tempfile));
431 goto cleanup;
432 }
433
435 fputc('\n', fp_tmp);
436 mutt_write_mime_body(b, fp_tmp, NeoMutt->sub);
437
438 if (convert)
439 {
440 int c, hadcr = 0;
441 unsigned char buf[1];
442
444 rewind(fp_tmp);
445 while ((c = fgetc(fp_tmp)) != EOF)
446 {
447 if (c == '\r')
448 {
449 hadcr = 1;
450 }
451 else
452 {
453 if ((c == '\n') && !hadcr)
454 {
455 buf[0] = '\r';
456 gpgme_data_write(data, buf, 1);
457 }
458
459 hadcr = 0;
460 }
461 /* FIXME: This is quite suboptimal */
462 buf[0] = c;
463 gpgme_data_write(data, buf, 1);
464 }
465 mutt_file_fclose(&fp_tmp);
466 gpgme_data_seek(data, 0, SEEK_SET);
467 }
468 else
469 {
470 mutt_file_fclose(&fp_tmp);
471 err = gpgme_data_new_from_file(&data, buf_string(tempfile), 1);
472 if (err != GPG_ERR_NO_ERROR)
473 {
474 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
475 gpgme_data_release(data);
476 data = NULL;
477 /* fall through to unlink the tempfile */
478 }
479 }
480 unlink(buf_string(tempfile));
481
482cleanup:
483 buf_pool_release(&tempfile);
484 return data;
485}
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
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition header.c:757
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition body.c:300
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 494 of file crypt_gpgme.c.

495{
496 gpgme_data_t data = NULL;
497
498 gpgme_error_t err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length);
499 if (err != GPG_ERR_NO_ERROR)
500 {
501 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
502 return NULL;
503 }
504
505 return data;
506}
+ 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 515 of file crypt_gpgme.c.

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

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

624{
625 unsigned int n = 0;
626
627 const char *s = keylist;
628 do
629 {
630 while (*s == ' ')
631 s++;
632 if (*s != '\0')
633 {
634 if (n == 0)
635 {
636 if (!use_smime)
637 buf_addstr(recpstring, "--\n");
638 }
639 else
640 {
641 buf_addch(recpstring, '\n');
642 }
643 n++;
644
645 while ((*s != '\0') && (*s != ' '))
646 buf_addch(recpstring, *s++);
647 }
648 } while (*s != '\0');
649}
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 659 of file crypt_gpgme.c.

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

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

763{
764 gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME, CurrentSender, 0);
765 if (err != GPG_ERR_NO_ERROR)
766 {
767 mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
768 }
769
770 return err;
771}
static char * CurrentSender
Email address of the sender.
Definition crypt_gpgme.c:97
+ 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 782 of file crypt_gpgme.c.

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

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

893{
894 char p[256] = { 0 };
895 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
896 state_puts(state, p);
897}
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 907 of file crypt_gpgme.c.

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

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

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

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

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

1419{
1420 const char *algo = gpgme_pubkey_algo_name(r->pubkey_algo);
1421 if (!algo)
1422 algo = "?";
1423
1424 // L10N: Show the algorithm and key ID of the encryption recipients, e.g
1425 // Recipient: RSA key, ID 1111111111111111
1426 state_printf(state, _("Recipient: %s key, ID %s\n"), algo, r->keyid);
1427}
int state_printf(struct State *state, const char *fmt,...)
Write a formatted string to the State.
Definition state.c:187
+ 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 1434 of file crypt_gpgme.c.

1435{
1436 if (!cs_subset_bool(NeoMutt->sub, "crypt_encryption_info"))
1437 return;
1438
1439 state_attach_puts(state, _("[-- Begin encryption information --]\n"));
1440
1441 for (gpgme_recipient_t r = result->recipients; r; r = r->next)
1442 show_one_recipient(state, r);
1443
1444 state_attach_puts(state, _("[-- End encryption information --]\n\n"));
1445}
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 1459 of file crypt_gpgme.c.

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

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

1735{
1736 if (!b || !state || !fp_out)
1737 return NULL;
1738
1739 struct Body *tattach = NULL;
1740 gpgme_error_t err = GPG_ERR_NO_ERROR;
1741 gpgme_data_t ciphertext = NULL, plaintext = NULL;
1742 gpgme_decrypt_result_t result = NULL;
1743 bool maybe_signed = false;
1744 bool anywarn = false;
1745 int sig_stat = 0;
1746
1747 if (r_is_signed)
1748 *r_is_signed = 0;
1749
1750 gpgme_ctx_t ctx = NULL;
1751restart:
1752 ctx = create_gpgme_context(is_smime);
1753
1754 if (b->length < 0)
1755 return NULL;
1756 /* Make a data object from the body, create context etc. */
1757 ciphertext = file_to_data_object(state->fp_in, b->offset, b->length);
1758 if (!ciphertext)
1759 goto cleanup;
1760 plaintext = create_gpgme_data();
1761
1762 /* Do the decryption or the verification in case of the S/MIME hack. */
1763 if ((!is_smime) || maybe_signed)
1764 {
1765 if (!is_smime)
1766 err = gpgme_op_decrypt_verify(ctx, ciphertext, plaintext);
1767 else if (maybe_signed)
1768 err = gpgme_op_verify(ctx, ciphertext, NULL, plaintext);
1769
1770 if (err == GPG_ERR_NO_ERROR)
1771 {
1772 /* Check whether signatures have been verified. */
1773 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
1774 if (verify_result->signatures)
1775 sig_stat = 1;
1776 }
1777 }
1778 else
1779 {
1780 err = gpgme_op_decrypt(ctx, ciphertext, plaintext);
1781 }
1782 gpgme_data_release(ciphertext);
1783 ciphertext = NULL;
1784
1785#ifdef USE_AUTOCRYPT
1786 // Abort right away and silently. Autocrypt will retry on the normal keyring.
1787 if (OptAutocryptGpgme && (err != GPG_ERR_NO_ERROR))
1788 goto cleanup;
1789#endif
1790
1791 result = gpgme_op_decrypt_result(ctx);
1792 if (result && (state->flags & STATE_DISPLAY))
1793 show_encryption_info(state, result);
1794
1795 if (err != GPG_ERR_NO_ERROR)
1796 {
1797 if (is_smime && !maybe_signed && (gpg_err_code(err) == GPG_ERR_NO_DATA))
1798 {
1799 /* Check whether this might be a signed message despite what the mime
1800 * header told us. Retry then. gpgsm returns the error information
1801 * "unsupported Algorithm '?'" but GPGME will not store this unknown
1802 * algorithm, thus we test that it has not been set. */
1803 if (result && !result->unsupported_algorithm)
1804 {
1805 maybe_signed = true;
1806 gpgme_data_release(plaintext);
1807 plaintext = NULL;
1808 /* gpgsm ends the session after an error; restart it */
1809 gpgme_release(ctx);
1810 goto restart;
1811 }
1812 }
1813 redraw_if_needed(ctx);
1814 if ((state->flags & STATE_DISPLAY))
1815 {
1816 char buf[200] = { 0 };
1817
1818 snprintf(buf, sizeof(buf) - 1,
1819 _("[-- Error: decryption failed: %s --]\n\n"), gpgme_strerror(err));
1820 state_attach_puts(state, buf);
1821 }
1822 goto cleanup;
1823 }
1824 redraw_if_needed(ctx);
1825
1826 /* Read the output from GPGME, and make sure to change CRLF to LF,
1827 * otherwise read_mime_header has a hard time parsing the message. */
1828 if (data_object_to_stream(plaintext, fp_out))
1829 {
1830 goto cleanup;
1831 }
1832 gpgme_data_release(plaintext);
1833 plaintext = NULL;
1834
1835 if (sig_stat)
1836 {
1837 int res, idx;
1838 int anybad = 0;
1839
1840 if (r_is_signed)
1841 *r_is_signed = -1; /* A signature exists. */
1842
1843 if ((state->flags & STATE_DISPLAY))
1844 {
1845 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1846 }
1847 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1848 {
1849 if (res == 1)
1850 anybad = 1;
1851 else if (res == 2)
1852 anywarn = true;
1853 }
1854 if (!anybad && idx && r_is_signed && *r_is_signed)
1855 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1856
1857 if ((state->flags & STATE_DISPLAY))
1858 {
1859 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1860 }
1861 }
1862 gpgme_release(ctx);
1863 ctx = NULL;
1864
1865 fflush(fp_out);
1866 rewind(fp_out);
1867 const long size = mutt_file_get_size_fp(fp_out);
1868 if (size == 0)
1869 {
1870 goto cleanup;
1871 }
1872 tattach = mutt_read_mime_header(fp_out, 0);
1873 if (tattach)
1874 {
1875 /* Need to set the length of this body part. */
1876 tattach->length = size - tattach->offset;
1877
1878 tattach->warnsig = anywarn;
1879
1880 /* See if we need to recurse on this MIME part. */
1881 mutt_parse_part(fp_out, tattach);
1882 }
1883
1884cleanup:
1885 gpgme_data_release(ciphertext);
1886 gpgme_data_release(plaintext);
1887 gpgme_release(ctx);
1888
1889 return tattach;
1890}
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:1822
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1362
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1431
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:500
#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:1460
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:480
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
static int crypt_id_matches_addr(struct Address *addr, struct Address *u_addr, struct CryptKeyInfo *key)
Does the key ID match the address.
static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
Split a string and add the parts to a List.
static struct CryptKeyInfo * get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
Get a list of keys which are candidates for the selection.
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
#define CRYPT_KV_MATCH
Definition crypt_gpgme.c:79
struct CryptKeyInfo * dlg_gpgme(struct CryptKeyInfo *keys, struct Address *p, const char *s, unsigned int app, bool *forced_valid)
Get the user to select a key -.
Definition dlg_gpgme.c:194
#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:1385
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:674
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition string.c:525
+ 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:93
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
Find a key by string.
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:272
@ 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
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition mutt.h:56
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Internal cache for GPGME.
Definition crypt_gpgme.c:86
char * what
Cached key identifier.
Definition crypt_gpgme.c:87
char * dflt
Default key ID.
Definition crypt_gpgme.c:88
struct CryptCache * next
Linked list.
Definition crypt_gpgme.c:89
+ 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 TAILQ_FOREACH(a, addrlist, entries)
3552 {
3553 key_selected = false;
3554 mutt_crypt_hook(&crypt_hook_list, a);
3555 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3556 do
3557 {
3558 p = a;
3559 forced_valid = false;
3560 k_info = NULL;
3561
3562 if (crypt_hook)
3563 {
3564 keyid = crypt_hook->data;
3565 enum QuadOption ans = MUTT_YES;
3566 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3567 {
3568 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3569 buf_string(p->mailbox));
3570 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3571 }
3572 if (ans == MUTT_YES)
3573 {
3574 if (crypt_is_numerical_keyid(keyid))
3575 {
3576 if (mutt_strn_equal(keyid, "0x", 2))
3577 keyid += 2;
3578 goto bypass_selection; /* you don't see this. */
3579 }
3580
3581 /* check for e-mail address */
3582 mutt_addrlist_clear(&hookal);
3583 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3584 {
3585 mutt_addrlist_qualify(&hookal, fqdn);
3586 p = TAILQ_FIRST(&hookal);
3587 }
3588 else if (!oppenc_mode)
3589 {
3590 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3591 }
3592 }
3593 else if (ans == MUTT_NO)
3594 {
3595 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3596 {
3597 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3598 continue;
3599 }
3600 }
3601 else if (ans == MUTT_ABORT)
3602 {
3603 FREE(&keylist);
3604 mutt_addrlist_clear(&hookal);
3605 mutt_list_free(&crypt_hook_list);
3606 return NULL;
3607 }
3608 }
3609
3610 if (!k_info)
3611 {
3612 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3613 }
3614
3615 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3616 {
3617 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3618
3619 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3620 KEYFLAG_CANENCRYPT, app, &forced_valid);
3621 }
3622
3623 if (!k_info)
3624 {
3625 FREE(&keylist);
3626 mutt_addrlist_clear(&hookal);
3627 mutt_list_free(&crypt_hook_list);
3628 return NULL;
3629 }
3630
3631 keyid = crypt_fpr_or_lkeyid(k_info);
3632
3633 bypass_selection:
3634 keylist_size += mutt_str_len(keyid) + 4 + 1;
3635 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
3636 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3637 keyid, forced_valid ? "!" : "");
3638 keylist_used = mutt_str_len(keylist);
3639
3640 key_selected = true;
3641
3642 crypt_key_free(&k_info);
3643 mutt_addrlist_clear(&hookal);
3644
3645 if (crypt_hook)
3646 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3647
3648 } while (crypt_hook);
3649
3650 mutt_list_free(&crypt_hook_list);
3651 }
3652 return keylist;
3653}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:680
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition crypt.c:1474
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.
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:51
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:354
#define TAILQ_FIRST(head)
Definition queue.h:780
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition run.c:311
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:708
+ 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 3684 of file crypt_gpgme.c.

3685{
3686 int rc = -1;
3687 gpgme_error_t err = GPG_ERR_NO_ERROR;
3688 gpgme_key_t key = NULL;
3689 gpgme_user_id_t uid = NULL;
3690 struct CryptKeyInfo *results = NULL, *k = NULL;
3691 struct CryptKeyInfo **kend = NULL;
3692 struct CryptKeyInfo *choice = NULL;
3693
3694 gpgme_ctx_t ctx = create_gpgme_context(false);
3695
3696 /* list all secret keys */
3697 if (gpgme_op_keylist_start(ctx, NULL, 1))
3698 goto cleanup;
3699
3700 kend = &results;
3701
3702 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3703 {
3705
3710
3711 if (key->revoked)
3713 if (key->expired)
3715 if (key->disabled)
3717
3718 int idx;
3719 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3720 {
3721 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3722 k->kobj = key;
3723 gpgme_key_ref(k->kobj);
3724 k->idx = idx;
3725 k->uid = uid->uid;
3726 k->flags = flags;
3727 if (uid->revoked)
3728 k->flags |= KEYFLAG_REVOKED;
3729 k->validity = uid->validity;
3730 *kend = k;
3731 kend = &k->next;
3732 }
3733 gpgme_key_unref(key);
3734 }
3735 if (gpg_err_code(err) != GPG_ERR_EOF)
3736 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3737 gpgme_op_keylist_end(ctx);
3738
3739 if (!results)
3740 {
3741 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3742 from. This error is displayed if no results were found. */
3743 mutt_error(_("No secret keys found"));
3744 goto cleanup;
3745 }
3746
3747 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3748 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3749 goto cleanup;
3750 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3751
3752 rc = 0;
3753
3754cleanup:
3755 crypt_key_free(&choice);
3756 crypt_key_free(&results);
3757 gpgme_release(ctx);
3758 return rc;
3759}
+ 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 3823 of file crypt_gpgme.c.

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

◆ init_pgp()

static void init_pgp ( void )
static

Initialise the PGP crypto backend.

Definition at line 3842 of file crypt_gpgme.c.

3843{
3844 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3845 {
3846 mutt_error(_("GPGME: OpenPGP protocol not available"));
3847 }
3848}
+ Here is the caller graph for this function:

◆ init_smime()

static void init_smime ( void )
static

Initialise the SMIME crypto backend.

Definition at line 3853 of file crypt_gpgme.c.

3854{
3855 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3856 {
3857 mutt_error(_("GPGME: CMS protocol not available"));
3858 }
3859}
+ 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 3885 of file crypt_gpgme.c.

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

4065{
4066 struct Address *sender = NULL;
4067 bool rc = true;
4068
4069 if (!TAILQ_EMPTY(&e->env->from))
4070 {
4072 sender = TAILQ_FIRST(&e->env->from);
4073 }
4074 else if (!TAILQ_EMPTY(&e->env->sender))
4075 {
4077 sender = TAILQ_FIRST(&e->env->sender);
4078 }
4079
4080 if (sender)
4081 {
4082 if (SignatureKey)
4083 {
4084 gpgme_key_t key = SignatureKey;
4085 gpgme_user_id_t uid = NULL;
4086 int sender_length = buf_len(sender->mailbox);
4087 for (uid = key->uids; uid && rc; uid = uid->next)
4088 {
4089 int uid_length = strlen(uid->email);
4090 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4091 (uid_length == (sender_length + 2)))
4092 {
4093 const char *at_sign = strchr(uid->email + 1, '@');
4094 if (at_sign)
4095 {
4096 /* Assume address is 'mailbox@domainname'.
4097 * The mailbox part is case-sensitive,
4098 * the domainname is not. (RFC2821) */
4099 const char *tmp_email = uid->email + 1;
4100 const char *tmp_sender = buf_string(sender->mailbox);
4101 /* length of mailbox part including '@' */
4102 int mailbox_length = at_sign - tmp_email + 1;
4103 int domainname_length = sender_length - mailbox_length;
4104 int mailbox_match, domainname_match;
4105
4106 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4107 tmp_email += mailbox_length;
4108 tmp_sender += mailbox_length;
4109 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4110 if (mailbox_match && domainname_match)
4111 rc = false;
4112 }
4113 else
4114 {
4115 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4116 rc = false;
4117 }
4118 }
4119 }
4120 }
4121 else
4122 {
4123 mutt_any_key_to_continue(_("Failed to verify sender"));
4124 }
4125 }
4126 else
4127 {
4128 mutt_any_key_to_continue(_("Failed to figure out sender"));
4129 }
4130
4131 if (SignatureKey)
4132 {
4133 gpgme_key_unref(SignatureKey);
4134 SignatureKey = NULL;
4135 }
4136
4137 return rc;
4138}
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition alias.c:294
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:174
int mutt_istrn_cmp(const char *a, const char *b, size_t num)
Compare two strings ignoring case (to a maximum), safely.
Definition string.c:443
#define TAILQ_EMPTY(head)
Definition queue.h:778
struct Envelope * env
Envelope information.
Definition email.h:68
struct AddressList sender
Email's sender.
Definition envelope.h:63
struct AddressList from
Email's 'From' list.
Definition envelope.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_gpgme_print_version()

const char * mutt_gpgme_print_version ( void )

Get version of GPGME.

Return values
ptrGPGME version string

Definition at line 4162 of file crypt_gpgme.c.

4163{
4164 return GPGME_VERSION;
4165}
+ Here is the caller graph for this function:

Variable Documentation

◆ IdDefaults

struct CryptCache* IdDefaults = NULL
static

Cache of GPGME keys.

Definition at line 93 of file crypt_gpgme.c.

◆ SignatureKey

gpgme_key_t SignatureKey = NULL
static

PGP Key to sign with.

Definition at line 95 of file crypt_gpgme.c.

◆ CurrentSender

char* CurrentSender = NULL
static

Email address of the sender.

Definition at line 97 of file crypt_gpgme.c.