NeoMutt  2025-05-10-9-gb9f27b
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 "question/lib.h"
#include "send/lib.h"
#include "crypt.h"
#include "globals.h"
#include "gpgme_functions.h"
#include "handler.h"
#include "hook.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)   line_compare(_x, sizeof(_x) - 1, _y)
 
#define MESSAGE(_y)   _LINE_COMPARE("MESSAGE-----", _y)
 
#define SIGNED_MESSAGE(_y)   _LINE_COMPARE("SIGNED MESSAGE-----", _y)
 
#define PUBLIC_KEY_BLOCK(_y)   _LINE_COMPARE("PUBLIC KEY BLOCK-----", _y)
 
#define BEGIN_PGP_SIGNATURE(_y)    _LINE_COMPARE("-----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? - Implements CryptModuleSpecs::smime_verify_sender() -.
 
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

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

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

Definition in file crypt_gpgme.c.

Macro Definition Documentation

◆ CRYPT_KV_VALID

#define CRYPT_KV_VALID   (1 << 0)

Definition at line 74 of file crypt_gpgme.c.

◆ CRYPT_KV_ADDR

#define CRYPT_KV_ADDR   (1 << 1)

Definition at line 75 of file crypt_gpgme.c.

◆ CRYPT_KV_STRING

#define CRYPT_KV_STRING   (1 << 2)

Definition at line 76 of file crypt_gpgme.c.

◆ CRYPT_KV_STRONGID

#define CRYPT_KV_STRONGID   (1 << 3)

Definition at line 77 of file crypt_gpgme.c.

◆ CRYPT_KV_MATCH

#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)

Definition at line 78 of file crypt_gpgme.c.

◆ PKA_NOTATION_NAME

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

Definition at line 98 of file crypt_gpgme.c.

◆ _LINE_COMPARE

#define _LINE_COMPARE (   _x,
  _y 
)    line_compare(_x, sizeof(_x) - 1, _y)

Definition at line 100 of file crypt_gpgme.c.

◆ MESSAGE

#define MESSAGE (   _y)    _LINE_COMPARE("MESSAGE-----", _y)

Definition at line 101 of file crypt_gpgme.c.

◆ SIGNED_MESSAGE

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

Definition at line 102 of file crypt_gpgme.c.

◆ PUBLIC_KEY_BLOCK

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

Definition at line 103 of file crypt_gpgme.c.

◆ BEGIN_PGP_SIGNATURE

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

Definition at line 104 of file crypt_gpgme.c.

Function Documentation

◆ is_pka_notation()

static bool is_pka_notation ( gpgme_sig_notation_t  notation)
static

Is this the standard pka email address.

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

Definition at line 112 of file crypt_gpgme.c.

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

◆ redraw_if_needed()

static void redraw_if_needed ( gpgme_ctx_t  ctx)
static

Accommodate for a redraw if needed.

Parameters
ctxGPGME handle

Definition at line 121 of file crypt_gpgme.c.

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

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

◆ crypt_long_keyid()

static const char * crypt_long_keyid ( struct CryptKeyInfo k)
static

Find the Long ID for the key.

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

Return the long keyID for the key K.

Definition at line 163 of file crypt_gpgme.c.

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

◆ crypt_short_keyid()

static const char * crypt_short_keyid ( struct CryptKeyInfo k)
static

Get the short keyID for a key.

Parameters
kKey to use
Return values
ptrShort key string

Definition at line 180 of file crypt_gpgme.c.

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

◆ crypt_fpr()

static const char * crypt_fpr ( struct CryptKeyInfo k)
static

Get the hexstring fingerprint from a key.

Parameters
kKey to use
Return values
ptrHexstring fingerprint

Definition at line 199 of file crypt_gpgme.c.

200{
201 const char *s = "";
202
203 if (k->kobj && k->kobj->subkeys)
204 s = k->kobj->subkeys->fpr;
205
206 return s;
207}
+ Here is the caller graph for this function:

◆ crypt_fpr_or_lkeyid()

const char * crypt_fpr_or_lkeyid ( struct CryptKeyInfo k)

Find the fingerprint of a key.

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

Definition at line 214 of file crypt_gpgme.c.

215{
216 const char *s = "????????????????";
217
218 if (k->kobj && k->kobj->subkeys)
219 {
220 if (k->kobj->subkeys->fpr)
221 s = k->kobj->subkeys->fpr;
222 else
223 s = k->kobj->subkeys->keyid;
224 }
225
226 return s;
227}
+ Here is the caller graph for this function:

◆ crypt_copy_key()

struct CryptKeyInfo * crypt_copy_key ( struct CryptKeyInfo key)

Return a copy of KEY.

Parameters
keyKey to copy
Return values
ptrCopy of key

Definition at line 234 of file crypt_gpgme.c.

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

◆ crypt_key_free()

static void crypt_key_free ( struct CryptKeyInfo **  keylist)
static

Release all the keys in a list.

Parameters
[out]keylistList of keys

Definition at line 253 of file crypt_gpgme.c.

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

◆ crypt_id_is_strong()

bool crypt_id_is_strong ( struct CryptKeyInfo key)

Is the key strong.

Parameters
keyKey to test
Return values
trueValidity of key is sufficient

Definition at line 275 of file crypt_gpgme.c.

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

◆ crypt_id_is_valid()

int crypt_id_is_valid ( struct CryptKeyInfo key)

Is key ID valid.

Parameters
keyKey to test
Return values
trueKey is valid

When the key is not marked as unusable

Definition at line 310 of file crypt_gpgme.c.

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

◆ crypt_id_matches_addr()

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

Does the key ID match the address.

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

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

Definition at line 328 of file crypt_gpgme.c.

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

◆ create_gpgme_context()

gpgme_ctx_t create_gpgme_context ( bool  for_smime)

Create a new GPGME context.

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

Definition at line 361 of file crypt_gpgme.c.

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

◆ create_gpgme_data()

static gpgme_data_t create_gpgme_data ( void  )
static

Create a new GPGME data object.

Return values
ptrGPGPE data object

This is a wrapper to die on error.

Note
Call gpgme_data_release() to free the data object

Definition at line 400 of file crypt_gpgme.c.

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

◆ body_to_data_object()

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

Create GPGME object from the mail body.

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

Definition at line 419 of file crypt_gpgme.c.

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

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

◆ data_object_to_stream()

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

Write a GPGME data object to a file.

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

Definition at line 514 of file crypt_gpgme.c.

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

◆ data_object_to_tempfile()

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

Copy a data object to a temporary file.

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

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

Note
The caller must free the returned file name

Definition at line 563 of file crypt_gpgme.c.

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

◆ create_recipient_string()

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

Create a string of recipients.

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

Definition at line 622 of file crypt_gpgme.c.

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

◆ set_signer_from_address()

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

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

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

Definition at line 658 of file crypt_gpgme.c.

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

◆ set_signer()

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

Make sure that the correct signer is set.

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

Definition at line 717 of file crypt_gpgme.c.

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

◆ set_pka_sig_notation()

static gpgme_error_t set_pka_sig_notation ( gpgme_ctx_t  ctx)
static

Set the signature notation.

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

Definition at line 761 of file crypt_gpgme.c.

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

◆ encrypt_gpgme_object()

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

Encrypt the GPGPME data object.

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

Definition at line 781 of file crypt_gpgme.c.

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

◆ get_micalg()

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

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

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

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

Definition at line 853 of file crypt_gpgme.c.

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

◆ print_time()

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

Print the date/time according to the locale.

Parameters
tTimestamp
stateState to write to

Definition at line 891 of file crypt_gpgme.c.

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

◆ sign_message()

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

Sign a message.

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

Definition at line 906 of file crypt_gpgme.c.

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

◆ show_sig_summary()

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

Show a signature summary.

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

Display the common attributes of the signature summary SUM.

Definition at line 1133 of file crypt_gpgme.c.

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

◆ show_fingerprint()

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

Write a key's fingerprint.

Parameters
keyGPGME key
stateState to write to

Definition at line 1257 of file crypt_gpgme.c.

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

◆ show_one_sig_validity()

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

Show the validity of a key used for one signature.

Parameters
ctxGPGME handle
idxIndex of signature to check
stateState to use

Definition at line 1312 of file crypt_gpgme.c.

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

◆ print_smime_keyinfo()

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

Print key info about an SMIME key.

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

Definition at line 1351 of file crypt_gpgme.c.

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

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

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

◆ show_one_sig_status()

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

Show information about one signature.

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

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

Definition at line 1458 of file crypt_gpgme.c.

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

◆ verify_one()

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

Do the actual verification step.

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

With is_smime set to true we assume S/MIME.

Definition at line 1581 of file crypt_gpgme.c.

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

◆ decrypt_part()

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

Decrypt a PGP or SMIME message.

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

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

Definition at line 1732 of file crypt_gpgme.c.

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

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

2195{
2196 if (mutt_strn_equal(a, b, n))
2197 {
2198 /* at this point we know that 'b' is at least 'n' chars long */
2199 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2200 return true;
2201 }
2202 return false;
2203}
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:426
+ 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 2212 of file crypt_gpgme.c.

2213{
2214 char buf[8192] = { 0 };
2215 bool rc = false;
2216
2217 bool sgn = false;
2218 bool enc = false;
2219
2220 if (b->type != TYPE_TEXT)
2221 return 0;
2222
2223 struct Buffer *tempfile = buf_pool_get();
2224 buf_mktemp(tempfile);
2226 MUTT_SAVE_NO_FLAGS) != 0)
2227 {
2228 unlink(buf_string(tempfile));
2229 goto cleanup;
2230 }
2231
2232 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2233 if (!fp_tmp)
2234 {
2235 unlink(buf_string(tempfile));
2236 goto cleanup;
2237 }
2238
2239 while (fgets(buf, sizeof(buf), fp_tmp))
2240 {
2241 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2242 if (plen != 0)
2243 {
2244 if (MESSAGE(buf + plen))
2245 {
2246 enc = true;
2247 break;
2248 }
2249 else if (SIGNED_MESSAGE(buf + plen))
2250 {
2251 sgn = true;
2252 break;
2253 }
2254 }
2255 }
2256 mutt_file_fclose(&fp_tmp);
2257 unlink(buf_string(tempfile));
2258
2259 if (!enc && !sgn)
2260 goto cleanup;
2261
2262 /* fix the content type */
2263
2264 mutt_param_set(&b->parameter, "format", "fixed");
2265 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2266
2267 rc = true;
2268
2269cleanup:
2270 buf_pool_release(&tempfile);
2271 return rc;
2272}
#define SIGNED_MESSAGE(_y)
Definition: crypt_gpgme.c:102
#define MESSAGE(_y)
Definition: crypt_gpgme.c:101
@ 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:231
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:1039
@ 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 2413 of file crypt_gpgme.c.

2414{
2415 char buf[8192] = { 0 };
2416 bool complete, armor_header;
2417 FILE *fp = NULL;
2418
2419 char *fname = data_object_to_tempfile(data, &fp);
2420 if (!fname)
2421 {
2422 mutt_file_fclose(&fp);
2423 return;
2424 }
2425 unlink(fname);
2426 FREE(&fname);
2427
2428 /* fromcode comes from the MIME Content-Type charset label. It might
2429 * be a wrong label, so we want the ability to do corrections via
2430 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2432
2433 for (complete = true, armor_header = true;
2434 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2435 {
2436 if (!complete)
2437 {
2438 if (!armor_header)
2439 state_puts(state, buf);
2440 continue;
2441 }
2442
2443 if (BEGIN_PGP_SIGNATURE(buf))
2444 break;
2445
2446 if (armor_header)
2447 {
2448 if (buf[0] == '\n')
2449 armor_header = false;
2450 continue;
2451 }
2452
2453 if (state->prefix)
2454 state_puts(state, state->prefix);
2455
2456 if ((buf[0] == '-') && (buf[1] == ' '))
2457 state_puts(state, buf + 2);
2458 else
2459 state_puts(state, buf);
2460 }
2461
2464}
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:116
#define BEGIN_PGP_SIGNATURE(_y)
Definition: crypt_gpgme.c:104
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:933
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition: charset.c:1042
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition: charset.c:962
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:65
Cursor for converting a file's encoding.
Definition: charset.h:43
FILE * fp
Definition: charset.h:44
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 2946 of file crypt_gpgme.c.

2947{
2948 unsigned int rc = 0;
2949
2950 switch (cap)
2951 {
2953 rc = key->can_encrypt;
2954 if (rc == 0)
2955 {
2956 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2957 {
2958 rc = subkey->can_encrypt;
2959 if (rc != 0)
2960 break;
2961 }
2962 }
2963 break;
2964 case KEY_CAP_CAN_SIGN:
2965 rc = key->can_sign;
2966 if (rc == 0)
2967 {
2968 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2969 {
2970 rc = subkey->can_sign;
2971 if (rc != 0)
2972 break;
2973 }
2974 }
2975 break;
2977 rc = key->can_certify;
2978 if (rc == 0)
2979 {
2980 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2981 {
2982 rc = subkey->can_certify;
2983 if (rc != 0)
2984 break;
2985 }
2986 }
2987 break;
2988 }
2989
2990 return rc;
2991}
@ 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 3002 of file crypt_gpgme.c.

3003{
3004 char *pattern = NULL, *p = NULL;
3005 const char *s = NULL;
3006 size_t n;
3007
3008 n = 0;
3009 struct ListNode *np = NULL;
3010 STAILQ_FOREACH(np, list, entries)
3011 {
3012 for (s = np->data; *s; s++)
3013 {
3014 if ((*s == '%') || (*s == '+'))
3015 n += 2;
3016 n++;
3017 }
3018 n++; /* delimiter or end of string */
3019 }
3020 n++; /* make sure to allocate at least one byte */
3021 p = MUTT_MEM_CALLOC(n, char);
3022 pattern = p;
3023 STAILQ_FOREACH(np, list, entries)
3024 {
3025 s = np->data;
3026 if (*s)
3027 {
3028 if (np != STAILQ_FIRST(list))
3029 *p++ = ' ';
3030 for (s = np->data; *s; s++)
3031 {
3032 if (*s == '%')
3033 {
3034 *p++ = '%';
3035 *p++ = '2';
3036 *p++ = '5';
3037 }
3038 else if (*s == '+')
3039 {
3040 *p++ = '%';
3041 *p++ = '2';
3042 *p++ = 'B';
3043 }
3044 else if (*s == ' ')
3045 {
3046 *p++ = '+';
3047 }
3048 else
3049 {
3050 *p++ = *s;
3051 }
3052 }
3053 }
3054 }
3055 *p = '\0';
3056 return pattern;
3057}
#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 3069 of file crypt_gpgme.c.

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

3223{
3224 char *scratch = mutt_str_dup(str);
3225 if (!scratch)
3226 return;
3227
3228 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3229 {
3230 if (strlen(t) > 3)
3232 }
3233
3234 FREE(&scratch);
3235}
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 3246 of file crypt_gpgme.c.

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

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

3466{
3467 struct CryptKeyInfo *key = NULL;
3468 struct CryptCache *l = NULL;
3469 struct Buffer *resp = buf_pool_get();
3470
3472
3473 if (whatfor)
3474 {
3475 for (l = IdDefaults; l; l = l->next)
3476 {
3477 if (mutt_istr_equal(whatfor, l->what))
3478 {
3479 buf_strcpy(resp, l->dflt);
3480 break;
3481 }
3482 }
3483 }
3484
3485 while (true)
3486 {
3487 buf_reset(resp);
3488 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
3489 {
3490 goto done;
3491 }
3492
3493 if (whatfor)
3494 {
3495 if (l)
3496 {
3497 mutt_str_replace(&l->dflt, buf_string(resp));
3498 }
3499 else
3500 {
3501 l = MUTT_MEM_MALLOC(1, struct CryptCache);
3502 l->next = IdDefaults;
3503 IdDefaults = l;
3504 l->what = mutt_str_dup(whatfor);
3505 l->dflt = buf_strdup(resp);
3506 }
3507 }
3508
3509 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3510 if (key)
3511 goto done;
3512
3513 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3514 }
3515
3516done:
3517 buf_pool_release(&resp);
3518 return key;
3519}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
static struct CryptCache * IdDefaults
Cache of GPGME keys.
Definition: crypt_gpgme.c:92
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
Find a key by string.
Definition: crypt_gpgme.c:3380
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:273
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:58
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:281
#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)
Definition: mutt_logging.c:74
Internal cache for GPGME.
Definition: crypt_gpgme.c:85
char * what
Definition: crypt_gpgme.c:86
char * dflt
Definition: crypt_gpgme.c:87
struct CryptCache * next
Definition: crypt_gpgme.c:88
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ find_keys()

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

Find keys of the recipients of the message.

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

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

Definition at line 3532 of file crypt_gpgme.c.

3533{
3534 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3535 struct ListNode *crypt_hook = NULL;
3536 const char *keyid = NULL;
3537 char *keylist = NULL;
3538 size_t keylist_size = 0;
3539 size_t keylist_used = 0;
3540 struct Address *p = NULL;
3541 struct CryptKeyInfo *k_info = NULL;
3542 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3543 char buf[1024] = { 0 };
3544 bool forced_valid = false;
3545 bool key_selected;
3546 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3547
3548 struct Address *a = NULL;
3549 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3550 TAILQ_FOREACH(a, addrlist, entries)
3551 {
3552 key_selected = false;
3553 mutt_crypt_hook(&crypt_hook_list, a);
3554 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3555 do
3556 {
3557 p = a;
3558 forced_valid = false;
3559 k_info = NULL;
3560
3561 if (crypt_hook)
3562 {
3563 keyid = crypt_hook->data;
3564 enum QuadOption ans = MUTT_YES;
3565 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3566 {
3567 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3568 buf_string(p->mailbox));
3569 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3570 }
3571 if (ans == MUTT_YES)
3572 {
3573 if (crypt_is_numerical_keyid(keyid))
3574 {
3575 if (mutt_strn_equal(keyid, "0x", 2))
3576 keyid += 2;
3577 goto bypass_selection; /* you don't see this. */
3578 }
3579
3580 /* check for e-mail address */
3581 mutt_addrlist_clear(&hookal);
3582 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3583 {
3584 mutt_addrlist_qualify(&hookal, fqdn);
3585 p = TAILQ_FIRST(&hookal);
3586 }
3587 else if (!oppenc_mode)
3588 {
3589 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3590 }
3591 }
3592 else if (ans == MUTT_NO)
3593 {
3594 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3595 {
3596 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3597 continue;
3598 }
3599 }
3600 else if (ans == MUTT_ABORT)
3601 {
3602 FREE(&keylist);
3603 mutt_addrlist_clear(&hookal);
3604 mutt_list_free(&crypt_hook_list);
3605 return NULL;
3606 }
3607 }
3608
3609 if (!k_info)
3610 {
3611 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3612 }
3613
3614 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3615 {
3616 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3617
3618 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3619 KEYFLAG_CANENCRYPT, app, &forced_valid);
3620 }
3621
3622 if (!k_info)
3623 {
3624 FREE(&keylist);
3625 mutt_addrlist_clear(&hookal);
3626 mutt_list_free(&crypt_hook_list);
3627 return NULL;
3628 }
3629
3630 keyid = crypt_fpr_or_lkeyid(k_info);
3631
3632 bypass_selection:
3633 keylist_size += mutt_str_len(keyid) + 4 + 1;
3634 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
3635 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3636 keyid, forced_valid ? "!" : "");
3637 keylist_used = mutt_str_len(keylist);
3638
3639 key_selected = true;
3640
3641 crypt_key_free(&k_info);
3642 mutt_addrlist_clear(&hookal);
3643
3644 if (crypt_hook)
3645 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3646
3647 } while (crypt_hook);
3648
3649 mutt_list_free(&crypt_hook_list);
3650 }
3651 return keylist;
3652}
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:1472
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.
Definition: crypt_gpgme.c:3246
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
Definition: crypt_gpgme.c:214
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.
Definition: crypt_gpgme.c:3463
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:879
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition: memory.h:50
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:355
#define TAILQ_FIRST(head)
Definition: queue.h:780
#define STAILQ_NEXT(elm, field)
Definition: queue.h:439
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:707
+ 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 3683 of file crypt_gpgme.c.

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

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

◆ init_pgp()

static void init_pgp ( void  )
static

Initialise the PGP crypto backend.

Definition at line 3841 of file crypt_gpgme.c.

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

◆ init_smime()

static void init_smime ( void  )
static

Initialise the SMIME crypto backend.

Definition at line 3852 of file crypt_gpgme.c.

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

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

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

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

Variable Documentation

◆ IdDefaults

struct CryptCache* IdDefaults = NULL
static

Cache of GPGME keys.

Definition at line 92 of file crypt_gpgme.c.

◆ SignatureKey

gpgme_key_t SignatureKey = NULL
static

PGP Key to sign with.

Definition at line 94 of file crypt_gpgme.c.

◆ CurrentSender

char* CurrentSender = NULL
static

Email address of the sender.

Definition at line 96 of file crypt_gpgme.c.