NeoMutt  2024-03-23-147-g885fbc
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 <time.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 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:709
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ redraw_if_needed()

static void redraw_if_needed ( gpgme_ctx_t  ctx)
static

Accommodate for a redraw if needed.

Parameters
ctxGPGME handle

Definition at line 121 of file crypt_gpgme.c.

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

◆ crypt_keyid()

const char * crypt_keyid ( struct CryptKeyInfo k)

Find the ID for the key.

Parameters
kKey to use
Return values
ptrID string for the key

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

Definition at line 138 of file crypt_gpgme.c.

139{
140 const char *s = "????????";
141
142 if (k->kobj && k->kobj->subkeys)
143 {
144 s = k->kobj->subkeys->keyid;
145 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
146 if ((!c_pgp_long_ids) && (strlen(s) == 16))
147 {
148 /* Return only the short keyID. */
149 s += 8;
150 }
151 }
152
153 return s;
154}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
gpgme_key_t kobj
Definition: crypt_gpgme.h:46
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ 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, sizeof(*k));
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}
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
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 call graph for this function:
+ 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:45
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:129
+ 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:139
+ 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:696
#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 && OptAutocryptGpgme)
370 err = gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_OpenPGP, NULL, c_autocrypt_dir);
371#endif
372
373 if (err != 0)
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 != 0)
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:169
bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: globals.c:62
#define mutt_error(...)
Definition: logging2.h:92
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:268
#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 != 0)
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 int err = 0;
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 != 0)
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:147
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:146
#define mutt_perror(...)
Definition: logging2.h:93
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:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
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 int err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length);
498 if (err != 0)
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 int err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno(errno) : 0);
520 if (err != 0)
521 {
522 mutt_error(_("error rewinding data object: %s"), gpgme_strerror(err));
523 return -1;
524 }
525
526 while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
527 {
528 /* fixme: we are not really converting CRLF to LF but just
529 * skipping CR. Doing it correctly needs a more complex logic */
530 for (char *p = buf; nread; p++, nread--)
531 {
532 if (*p != '\r')
533 putc(*p, fp);
534 }
535
536 if (ferror(fp))
537 {
538 mutt_perror(_("[tempfile]"));
539 return -1;
540 }
541 }
542 if (nread == -1)
543 {
544 mutt_error(_("error reading data object: %s"), strerror(errno));
545 return -1;
546 }
547 return 0;
548}
+ 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 561 of file crypt_gpgme.c.

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

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

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

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

757{
758 gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME, CurrentSender, 0);
759 if (err)
760 {
761 mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
762 }
763
764 return err;
765}
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 776 of file crypt_gpgme.c.

778{
779 gpgme_error_t err;
780 gpgme_ctx_t ctx = NULL;
781 gpgme_data_t ciphertext = NULL;
782 char *outfile = NULL;
783
784 struct Buffer *recpstring = buf_pool_get();
785 create_recipient_string(keylist, recpstring, use_smime);
786 if (buf_is_empty(recpstring))
787 {
788 buf_pool_release(&recpstring);
789 return NULL;
790 }
791
792 ctx = create_gpgme_context(use_smime);
793 if (!use_smime)
794 gpgme_set_armor(ctx, 1);
795
796 ciphertext = create_gpgme_data();
797
798 if (combined_signed)
799 {
800 if (set_signer(ctx, from, use_smime))
801 goto cleanup;
802
803 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
804 if (c_crypt_use_pka)
805 {
806 err = set_pka_sig_notation(ctx);
807 if (err != 0)
808 goto cleanup;
809 }
810
811 err = gpgme_op_encrypt_sign_ext(ctx, NULL, buf_string(recpstring),
812 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
813 }
814 else
815 {
816 err = gpgme_op_encrypt_ext(ctx, NULL, buf_string(recpstring),
817 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
818 }
819
820 redraw_if_needed(ctx);
821 if (err != 0)
822 {
823 mutt_error(_("error encrypting data: %s"), gpgme_strerror(err));
824 goto cleanup;
825 }
826
827 outfile = data_object_to_tempfile(ciphertext, NULL);
828
829cleanup:
830 buf_pool_release(&recpstring);
831 gpgme_release(ctx);
832 gpgme_data_release(ciphertext);
833 return outfile;
834}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:290
static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
Set the signature notation.
Definition: crypt_gpgme.c:756
static void create_recipient_string(const char *keylist, struct Buffer *recpstring, int use_smime)
Create a string of recipients.
Definition: crypt_gpgme.c:618
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:712
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:561
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 848 of file crypt_gpgme.c.

849{
850 gpgme_sign_result_t result = NULL;
851 const char *algorithm_name = NULL;
852
853 if (buflen < 5)
854 return -1;
855
856 *buf = '\0';
857 result = gpgme_op_sign_result(ctx);
858 if (result && result->signatures)
859 {
860 algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
861 if (algorithm_name)
862 {
863 if (use_smime)
864 {
865 /* convert GPGME raw hash name to RFC2633 format */
866 snprintf(buf, buflen, "%s", algorithm_name);
867 mutt_str_lower(buf);
868 }
869 else
870 {
871 /* convert GPGME raw hash name to RFC3156 format */
872 snprintf(buf, buflen, "pgp-%s", algorithm_name);
873 mutt_str_lower(buf + 4);
874 }
875 }
876 }
877
878 return (buf[0] != '\0') ? 0 : -1;
879}
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition: string.c:362
+ 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 886 of file crypt_gpgme.c.

887{
888 char p[256] = { 0 };
889 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
890 state_puts(state, p);
891}
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:950
#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 901 of file crypt_gpgme.c.

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

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

1253{
1254 if (!key)
1255 return;
1256
1257 const char *prefix = _("Fingerprint: ");
1258
1259 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1260 if (!s)
1261 return;
1262 bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1263
1264 char *buf = mutt_mem_malloc(strlen(prefix) + strlen(s) * 4 + 2);
1265 strcpy(buf, prefix);
1266 char *p = buf + strlen(buf);
1267 if (is_pgp && (strlen(s) == 40))
1268 { /* PGP v4 style formatted. */
1269 for (int i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
1270 {
1271 *p++ = s[0];
1272 *p++ = s[1];
1273 *p++ = s[2];
1274 *p++ = s[3];
1275 *p++ = ' ';
1276 if (i == 4)
1277 *p++ = ' ';
1278 }
1279 }
1280 else
1281 {
1282 for (int i = 0; *s && s[1] && s[2]; s += 2, i++)
1283 {
1284 *p++ = s[0];
1285 *p++ = s[1];
1286 *p++ = is_pgp ? ' ' : ':';
1287 if (is_pgp && (i == 7))
1288 *p++ = ' ';
1289 }
1290 }
1291
1292 /* just in case print remaining odd digits */
1293 for (; *s; s++)
1294 *p++ = *s;
1295 *p++ = '\n';
1296 *p = '\0';
1297 state_puts(state, buf);
1298 FREE(&buf);
1299}
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
+ Here is the call graph for this function:
+ 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 1307 of file crypt_gpgme.c.

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

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

1420{
1421 const char *fpr = NULL;
1422 gpgme_key_t key = NULL;
1423 bool anybad = false, anywarn = false;
1424 gpgme_signature_t sig = NULL;
1425 gpgme_error_t err = GPG_ERR_NO_ERROR;
1426
1427 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1428 if (result)
1429 {
1430 /* FIXME: this code should use a static variable and remember
1431 * the current position in the list of signatures, IMHO.
1432 * -moritz. */
1433 int i;
1434 for (i = 0, sig = result->signatures; sig && (i < idx); i++, sig = sig->next)
1435 ; // do nothing
1436
1437 if (!sig)
1438 return -1; /* Signature not found. */
1439
1440 if (SignatureKey)
1441 {
1442 gpgme_key_unref(SignatureKey);
1443 SignatureKey = NULL;
1444 }
1445
1446 fpr = sig->fpr;
1447 const unsigned int sum = sig->summary;
1448
1449 if (gpg_err_code(sig->status) != GPG_ERR_NO_ERROR)
1450 anybad = true;
1451
1452 if (gpg_err_code(sig->status) != GPG_ERR_NO_PUBKEY)
1453 {
1454 err = gpgme_get_key(ctx, fpr, &key, 0); /* secret key? */
1455 if (err == 0)
1456 {
1457 if (!SignatureKey)
1458 SignatureKey = key;
1459 }
1460 else
1461 {
1462 key = NULL; /* Old GPGME versions did not set KEY to NULL on
1463 error. Do it here to avoid a double free. */
1464 }
1465 }
1466 else
1467 {
1468 /* pubkey not present */
1469 }
1470
1471 if (!state || !state->fp_out || !(state->flags & STATE_DISPLAY))
1472 {
1473 ; /* No state information so no way to print anything. */
1474 }
1475 else if (err != 0)
1476 {
1477 char buf[1024] = { 0 };
1478 snprintf(buf, sizeof(buf), _("Error getting key information for KeyID %s: %s\n"),
1479 fpr, gpgme_strerror(err));
1480 state_puts(state, buf);
1481 anybad = true;
1482 }
1483 else if ((sum & GPGME_SIGSUM_GREEN))
1484 {
1485 print_smime_keyinfo(_("Good signature from:"), sig, key, state);
1486 if (show_sig_summary(sum, ctx, key, idx, state, sig))
1487 anywarn = true;
1488 show_one_sig_validity(ctx, idx, state);
1489 }
1490 else if ((sum & GPGME_SIGSUM_RED))
1491 {
1492 print_smime_keyinfo(_("*BAD* signature from:"), sig, key, state);
1493 show_sig_summary(sum, ctx, key, idx, state, sig);
1494 }
1495 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP))
1496 { /* We can't decide (yellow) but this is a PGP key with a good
1497 signature, so we display what a PGP user expects: The name,
1498 fingerprint and the key validity (which is neither fully or
1499 ultimate). */
1500 print_smime_keyinfo(_("Good signature from:"), sig, key, state);
1501 show_one_sig_validity(ctx, idx, state);
1502 show_fingerprint(key, state);
1503 if (show_sig_summary(sum, ctx, key, idx, state, sig))
1504 anywarn = true;
1505 }
1506 else /* can't decide (yellow) */
1507 {
1508 print_smime_keyinfo(_("Problem signature from:"), sig, key, state);
1509 /* 0 indicates no expiration */
1510 if (sig->exp_timestamp)
1511 {
1512 /* L10N: This is trying to match the width of the
1513 "Problem signature from:" translation just above. */
1514 state_puts(state, _(" expires: "));
1515 print_time(sig->exp_timestamp, state);
1516 state_puts(state, "\n");
1517 }
1518 show_sig_summary(sum, ctx, key, idx, state, sig);
1519 anywarn = true;
1520 }
1521
1522 if (key != SignatureKey)
1523 gpgme_key_unref(key);
1524 }
1525
1526 return anybad ? 1 : anywarn ? 2 : 0;
1527}
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:1128
static void show_fingerprint(gpgme_key_t key, struct State *state)
Write a key's fingerprint.
Definition: crypt_gpgme.c:1252
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:1346
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:1307
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 1542 of file crypt_gpgme.c.

1543{
1544 int badsig = -1;
1545 int anywarn = 0;
1546 gpgme_ctx_t ctx = NULL;
1547 gpgme_data_t message = NULL;
1548
1549 gpgme_data_t signature = file_to_data_object(state->fp_in, b->offset, b->length);
1550 if (!signature)
1551 return -1;
1552
1553 /* We need to tell GPGME about the encoding because the backend can't
1554 * auto-detect plain base-64 encoding which is used by S/MIME. */
1555 if (is_smime)
1556 gpgme_data_set_encoding(signature, GPGME_DATA_ENCODING_BASE64);
1557
1558 int err = gpgme_data_new_from_file(&message, tempfile, 1);
1559 if (err != 0)
1560 {
1561 gpgme_data_release(signature);
1562 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
1563 return -1;
1564 }
1565 ctx = create_gpgme_context(is_smime);
1566
1567 /* Note: We don't need a current time output because GPGME avoids
1568 * such an attack by separating the meta information from the data. */
1569 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1570
1571 err = gpgme_op_verify(ctx, signature, message, NULL);
1572 gpgme_data_release(message);
1573 gpgme_data_release(signature);
1574
1575 redraw_if_needed(ctx);
1576 if (err != 0)
1577 {
1578 char buf[200] = { 0 };
1579
1580 snprintf(buf, sizeof(buf) - 1, _("Error: verification failed: %s\n"),
1581 gpgme_strerror(err));
1582 state_puts(state, buf);
1583 }
1584 else
1585 { /* Verification succeeded, see what the result is. */
1586 gpgme_verify_result_t verify_result = NULL;
1587
1588 if (SignatureKey)
1589 {
1590 gpgme_key_unref(SignatureKey);
1591 SignatureKey = NULL;
1592 }
1593
1594 verify_result = gpgme_op_verify_result(ctx);
1595 if (verify_result && verify_result->signatures)
1596 {
1597 bool anybad = false;
1598 int res;
1599 for (int idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1600 {
1601 if (res == 1)
1602 anybad = true;
1603 else if (res == 2)
1604 anywarn = 2;
1605 }
1606 if (!anybad)
1607 badsig = 0;
1608 }
1609 }
1610
1611 if (badsig == 0)
1612 {
1613 gpgme_verify_result_t result = NULL;
1614 gpgme_sig_notation_t notation = NULL;
1615 gpgme_signature_t sig = NULL;
1616
1617 result = gpgme_op_verify_result(ctx);
1618 if (result)
1619 {
1620 for (sig = result->signatures; sig; sig = sig->next)
1621 {
1622 int non_pka_notations = 0;
1623 for (notation = sig->notations; notation; notation = notation->next)
1624 if (!is_pka_notation(notation))
1625 non_pka_notations++;
1626
1627 if (non_pka_notations)
1628 {
1629 char buf[128] = { 0 };
1630 snprintf(buf, sizeof(buf),
1631 _("*** Begin Notation (signature by: %s) ***\n"), sig->fpr);
1632 state_puts(state, buf);
1633 for (notation = sig->notations; notation; notation = notation->next)
1634 {
1635 if (is_pka_notation(notation))
1636 continue;
1637
1638 if (notation->name)
1639 {
1640 state_puts(state, notation->name);
1641 state_puts(state, "=");
1642 }
1643 if (notation->value)
1644 {
1645 state_puts(state, notation->value);
1646 if (!(*notation->value && (notation->value[strlen(notation->value) - 1] == '\n')))
1647 state_puts(state, "\n");
1648 }
1649 }
1650 state_puts(state, _("*** End Notation ***\n"));
1651 }
1652 }
1653 }
1654 }
1655
1656 gpgme_release(ctx);
1657
1658 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1659 mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
1660
1661 return badsig ? 1 : anywarn ? 2 : 0;
1662}
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:1419
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition: state.c:103
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 1693 of file crypt_gpgme.c.

1695{
1696 if (!b || !state || !fp_out)
1697 return NULL;
1698
1699 struct Body *tattach = NULL;
1700 int err = 0;
1701 gpgme_data_t ciphertext = NULL, plaintext = NULL;
1702 bool maybe_signed = false;
1703 bool anywarn = false;
1704 int sig_stat = 0;
1705
1706 if (r_is_signed)
1707 *r_is_signed = 0;
1708
1709 gpgme_ctx_t ctx = NULL;
1710restart:
1711 ctx = create_gpgme_context(is_smime);
1712
1713 if (b->length < 0)
1714 return NULL;
1715 /* Make a data object from the body, create context etc. */
1716 ciphertext = file_to_data_object(state->fp_in, b->offset, b->length);
1717 if (!ciphertext)
1718 goto cleanup;
1719 plaintext = create_gpgme_data();
1720
1721 /* Do the decryption or the verification in case of the S/MIME hack. */
1722 if ((!is_smime) || maybe_signed)
1723 {
1724 if (!is_smime)
1725 err = gpgme_op_decrypt_verify(ctx, ciphertext, plaintext);
1726 else if (maybe_signed)
1727 err = gpgme_op_verify(ctx, ciphertext, NULL, plaintext);
1728
1729 if (err == GPG_ERR_NO_ERROR)
1730 {
1731 /* Check whether signatures have been verified. */
1732 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
1733 if (verify_result->signatures)
1734 sig_stat = 1;
1735 }
1736 }
1737 else
1738 {
1739 err = gpgme_op_decrypt(ctx, ciphertext, plaintext);
1740 }
1741 gpgme_data_release(ciphertext);
1742 ciphertext = NULL;
1743 if (err != 0)
1744 {
1745#ifdef USE_AUTOCRYPT
1746 /* Abort right away and silently.
1747 * Autocrypt will retry on the normal keyring. */
1749 goto cleanup;
1750#endif
1751 if (is_smime && !maybe_signed && (gpg_err_code(err) == GPG_ERR_NO_DATA))
1752 {
1753 /* Check whether this might be a signed message despite what the mime
1754 * header told us. Retry then. gpgsm returns the error information
1755 * "unsupported Algorithm '?'" but GPGME will not store this unknown
1756 * algorithm, thus we test that it has not been set. */
1757 gpgme_decrypt_result_t result = NULL;
1758
1759 result = gpgme_op_decrypt_result(ctx);
1760 if (result && !result->unsupported_algorithm)
1761 {
1762 maybe_signed = true;
1763 gpgme_data_release(plaintext);
1764 plaintext = NULL;
1765 /* gpgsm ends the session after an error; restart it */
1766 gpgme_release(ctx);
1767 goto restart;
1768 }
1769 }
1770 redraw_if_needed(ctx);
1771 if ((state->flags & STATE_DISPLAY))
1772 {
1773 char buf[200] = { 0 };
1774
1775 snprintf(buf, sizeof(buf) - 1,
1776 _("[-- Error: decryption failed: %s --]\n\n"), gpgme_strerror(err));
1777 state_attach_puts(state, buf);
1778 }
1779 goto cleanup;
1780 }
1781 redraw_if_needed(ctx);
1782
1783 /* Read the output from GPGME, and make sure to change CRLF to LF,
1784 * otherwise read_mime_header has a hard time parsing the message. */
1785 if (data_object_to_stream(plaintext, fp_out))
1786 {
1787 goto cleanup;
1788 }
1789 gpgme_data_release(plaintext);
1790 plaintext = NULL;
1791
1792 if (sig_stat)
1793 {
1794 int res, idx;
1795 int anybad = 0;
1796
1797 if (r_is_signed)
1798 *r_is_signed = -1; /* A signature exists. */
1799
1800 if ((state->flags & STATE_DISPLAY))
1801 {
1802 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1803 }
1804 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1805 {
1806 if (res == 1)
1807 anybad = 1;
1808 else if (res == 2)
1809 anywarn = true;
1810 }
1811 if (!anybad && idx && r_is_signed && *r_is_signed)
1812 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1813
1814 if ((state->flags & STATE_DISPLAY))
1815 {
1816 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1817 }
1818 }
1819 gpgme_release(ctx);
1820 ctx = NULL;
1821
1822 fflush(fp_out);
1823 rewind(fp_out);
1824 const long size = mutt_file_get_size_fp(fp_out);
1825 if (size == 0)
1826 {
1827 goto cleanup;
1828 }
1829 tattach = mutt_read_mime_header(fp_out, 0);
1830 if (tattach)
1831 {
1832 /* Need to set the length of this body part. */
1833 tattach->length = size - tattach->offset;
1834
1835 tattach->warnsig = anywarn;
1836
1837 /* See if we need to recurse on this MIME part. */
1838 mutt_parse_part(fp_out, tattach);
1839 }
1840
1841cleanup:
1842 gpgme_data_release(ciphertext);
1843 gpgme_data_release(plaintext);
1844 gpgme_release(ctx);
1845
1846 return tattach;
1847}
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:1817
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1357
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1534
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 2068 of file crypt_gpgme.c.

2069{
2070 gpgme_ctx_t tmpctx = NULL;
2071 gpgme_error_t err;
2072 gpgme_key_t key = NULL;
2073 gpgme_user_id_t uid = NULL;
2074 gpgme_subkey_t subkey = NULL;
2075 const char *shortid = NULL;
2076 size_t len;
2077 char date[256] = { 0 };
2078 bool more;
2079 int rc = -1;
2080 time_t tt;
2081
2082 *fp = mutt_file_mkstemp();
2083 if (!*fp)
2084 {
2085 mutt_perror(_("Can't create temporary file"));
2086 return -1;
2087 }
2088
2089 tmpctx = create_gpgme_context(false);
2090
2091 err = gpgme_op_keylist_from_data_start(tmpctx, keydata, 0);
2092 while (err == 0)
2093 {
2094 err = gpgme_op_keylist_next(tmpctx, &key);
2095 if (err != 0)
2096 break;
2097 uid = key->uids;
2098 subkey = key->subkeys;
2099 more = false;
2100 while (subkey)
2101 {
2102 shortid = subkey->keyid;
2103 len = mutt_str_len(subkey->keyid);
2104 if (len > 8)
2105 shortid += len - 8;
2106 tt = subkey->timestamp;
2107 mutt_date_localtime_format(date, sizeof(date), "%Y-%m-%d", tt);
2108
2109 fprintf(*fp, "%s %5.5s %u/%8s %s\n", more ? "sub" : "pub",
2110 gpgme_pubkey_algo_name(subkey->pubkey_algo), subkey->length, shortid, date);
2111 if (!more)
2112 {
2113 while (uid)
2114 {
2115 fprintf(*fp, "uid %s\n", NONULL(uid->uid));
2116 uid = uid->next;
2117 }
2118 }
2119 subkey = subkey->next;
2120 more = true;
2121 }
2122 gpgme_key_unref(key);
2123 }
2124 if (gpg_err_code(err) != GPG_ERR_EOF)
2125 {
2126 mutt_debug(LL_DEBUG1, "Error listing keys\n");
2127 goto err_fp;
2128 }
2129
2130 rc = 0;
2131
2132err_fp:
2133 if (rc)
2134 mutt_file_fclose(fp);
2135
2136 gpgme_release(tmpctx);
2137
2138 return rc;
2139}
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:545
#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 2152 of file crypt_gpgme.c.

2153{
2154 if (mutt_strn_equal(a, b, n))
2155 {
2156 /* at this point we know that 'b' is at least 'n' chars long */
2157 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2158 return true;
2159 }
2160 return false;
2161}
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:474
+ 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 2170 of file crypt_gpgme.c.

2171{
2172 char buf[8192] = { 0 };
2173 bool rc = false;
2174
2175 bool sgn = false;
2176 bool enc = false;
2177
2178 if (b->type != TYPE_TEXT)
2179 return 0;
2180
2181 struct Buffer *tempfile = buf_pool_get();
2182 buf_mktemp(tempfile);
2184 MUTT_SAVE_NO_FLAGS) != 0)
2185 {
2186 unlink(buf_string(tempfile));
2187 goto cleanup;
2188 }
2189
2190 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2191 if (!fp_tmp)
2192 {
2193 unlink(buf_string(tempfile));
2194 goto cleanup;
2195 }
2196
2197 while (fgets(buf, sizeof(buf), fp_tmp))
2198 {
2199 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2200 if (plen != 0)
2201 {
2202 if (MESSAGE(buf + plen))
2203 {
2204 enc = true;
2205 break;
2206 }
2207 else if (SIGNED_MESSAGE(buf + plen))
2208 {
2209 sgn = true;
2210 break;
2211 }
2212 }
2213 }
2214 mutt_file_fclose(&fp_tmp);
2215 unlink(buf_string(tempfile));
2216
2217 if (!enc && !sgn)
2218 goto cleanup;
2219
2220 /* fix the content type */
2221
2222 mutt_param_set(&b->parameter, "format", "fixed");
2223 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2224
2225 rc = true;
2226
2227cleanup:
2228 buf_pool_release(&tempfile);
2229 return rc;
2230}
#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:230
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
No flags set.
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 2371 of file crypt_gpgme.c.

2372{
2373 char buf[8192] = { 0 };
2374 bool complete, armor_header;
2375 FILE *fp = NULL;
2376
2377 char *fname = data_object_to_tempfile(data, &fp);
2378 if (!fname)
2379 {
2380 mutt_file_fclose(&fp);
2381 return;
2382 }
2383 unlink(fname);
2384 FREE(&fname);
2385
2386 /* fromcode comes from the MIME Content-Type charset label. It might
2387 * be a wrong label, so we want the ability to do corrections via
2388 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2390
2391 for (complete = true, armor_header = true;
2392 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2393 {
2394 if (!complete)
2395 {
2396 if (!armor_header)
2397 state_puts(state, buf);
2398 continue;
2399 }
2400
2401 if (BEGIN_PGP_SIGNATURE(buf))
2402 break;
2403
2404 if (armor_header)
2405 {
2406 if (buf[0] == '\n')
2407 armor_header = false;
2408 continue;
2409 }
2410
2411 if (state->prefix)
2412 state_puts(state, state->prefix);
2413
2414 if ((buf[0] == '-') && (buf[1] == ' '))
2415 state_puts(state, buf + 2);
2416 else
2417 state_puts(state, buf);
2418 }
2419
2422}
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:932
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition: charset.c:1044
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition: charset.c:964
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:73
Cursor for converting a file's encoding.
Definition: charset.h:42
FILE * fp
Definition: charset.h:43
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 2902 of file crypt_gpgme.c.

2903{
2904 unsigned int rc = 0;
2905
2906 switch (cap)
2907 {
2909 rc = key->can_encrypt;
2910 if (rc == 0)
2911 {
2912 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2913 {
2914 rc = subkey->can_encrypt;
2915 if (rc != 0)
2916 break;
2917 }
2918 }
2919 break;
2920 case KEY_CAP_CAN_SIGN:
2921 rc = key->can_sign;
2922 if (rc == 0)
2923 {
2924 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2925 {
2926 rc = subkey->can_sign;
2927 if (rc != 0)
2928 break;
2929 }
2930 }
2931 break;
2933 rc = key->can_certify;
2934 if (rc == 0)
2935 {
2936 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2937 {
2938 rc = subkey->can_certify;
2939 if (rc != 0)
2940 break;
2941 }
2942 }
2943 break;
2944 }
2945
2946 return rc;
2947}
@ KEY_CAP_CAN_CERTIFY
Key can be used to certify.
Definition: crypt_gpgme.h:78
@ KEY_CAP_CAN_ENCRYPT
Key can be used for encryption.
Definition: crypt_gpgme.h:76
@ KEY_CAP_CAN_SIGN
Key can be used for signing.
Definition: crypt_gpgme.h:77
+ 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 2958 of file crypt_gpgme.c.

2959{
2960 char *pattern = NULL, *p = NULL;
2961 const char *s = NULL;
2962 size_t n;
2963
2964 n = 0;
2965 struct ListNode *np = NULL;
2966 STAILQ_FOREACH(np, list, entries)
2967 {
2968 for (s = np->data; *s; s++)
2969 {
2970 if ((*s == '%') || (*s == '+'))
2971 n += 2;
2972 n++;
2973 }
2974 n++; /* delimiter or end of string */
2975 }
2976 n++; /* make sure to allocate at least one byte */
2977 p = mutt_mem_calloc(1, n);
2978 pattern = p;
2979 STAILQ_FOREACH(np, list, entries)
2980 {
2981 s = np->data;
2982 if (*s)
2983 {
2984 if (np != STAILQ_FIRST(list))
2985 *p++ = ' ';
2986 for (s = np->data; *s; s++)
2987 {
2988 if (*s == '%')
2989 {
2990 *p++ = '%';
2991 *p++ = '2';
2992 *p++ = '5';
2993 }
2994 else if (*s == '+')
2995 {
2996 *p++ = '%';
2997 *p++ = '2';
2998 *p++ = 'B';
2999 }
3000 else if (*s == ' ')
3001 {
3002 *p++ = '+';
3003 }
3004 else
3005 {
3006 *p++ = *s;
3007 }
3008 }
3009 }
3010 }
3011 *p = '\0';
3012 return pattern;
3013}
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
+ Here is the call graph for this function:
+ 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 3025 of file crypt_gpgme.c.

3026{
3027 struct CryptKeyInfo *db = NULL, *k = NULL, **kend = NULL;
3028 gpgme_error_t err;
3029 gpgme_ctx_t ctx = NULL;
3030 gpgme_key_t key = NULL;
3031 int idx;
3032 gpgme_user_id_t uid = NULL;
3033
3034 char *pattern = list_to_pattern(hints);
3035 if (!pattern)
3036 return NULL;
3037
3038 ctx = create_gpgme_context(0);
3039 db = NULL;
3040 kend = &db;
3041
3042 if ((app & APPLICATION_PGP))
3043 {
3044 /* It's all a mess. That old GPGME expects different things depending on
3045 * the protocol. For gpg we don't need percent escaped pappert but simple
3046 * strings passed in an array to the keylist_ext_start function. */
3047 size_t n = 0;
3048 struct ListNode *np = NULL;
3049 STAILQ_FOREACH(np, hints, entries)
3050 {
3051 if (np->data && *np->data)
3052 n++;
3053 }
3054 if (n == 0)
3055 goto no_pgphints;
3056
3057 char **patarr = mutt_mem_calloc(n + 1, sizeof(*patarr));
3058 n = 0;
3059 STAILQ_FOREACH(np, hints, entries)
3060 {
3061 if (np->data && *np->data)
3062 patarr[n++] = mutt_str_dup(np->data);
3063 }
3064 patarr[n] = NULL;
3065 err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
3066 for (n = 0; patarr[n]; n++)
3067 FREE(&patarr[n]);
3068 FREE(&patarr);
3069 if (err != 0)
3070 {
3071 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3072 gpgme_release(ctx);
3073 FREE(&pattern);
3074 return NULL;
3075 }
3076
3077 while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
3078 {
3079 KeyFlags flags = KEYFLAG_NO_FLAGS;
3080
3082 flags |= KEYFLAG_CANENCRYPT;
3084 flags |= KEYFLAG_CANSIGN;
3085
3086 if (key->revoked)
3087 flags |= KEYFLAG_REVOKED;
3088 if (key->expired)
3089 flags |= KEYFLAG_EXPIRED;
3090 if (key->disabled)
3091 flags |= KEYFLAG_DISABLED;
3092
3093 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3094 {
3095 k = mutt_mem_calloc(1, sizeof(*k));
3096 k->kobj = key;
3097 gpgme_key_ref(k->kobj);
3098 k->idx = idx;
3099 k->uid = uid->uid;
3100 k->flags = flags;
3101 if (uid->revoked)
3102 k->flags |= KEYFLAG_REVOKED;
3103 k->validity = uid->validity;
3104 *kend = k;
3105 kend = &k->next;
3106 }
3107 gpgme_key_unref(key);
3108 }
3109 if (gpg_err_code(err) != GPG_ERR_EOF)
3110 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3111 gpgme_op_keylist_end(ctx);
3112 no_pgphints:;
3113 }
3114
3115 if ((app & APPLICATION_SMIME))
3116 {
3117 /* and now look for x509 certificates */
3118 gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
3119 err = gpgme_op_keylist_start(ctx, pattern, 0);
3120 if (err != 0)
3121 {
3122 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3123 gpgme_release(ctx);
3124 FREE(&pattern);
3125 return NULL;
3126 }
3127
3128 while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
3129 {
3130 KeyFlags flags = KEYFLAG_ISX509;
3131
3133 flags |= KEYFLAG_CANENCRYPT;
3135 flags |= KEYFLAG_CANSIGN;
3136
3137 if (key->revoked)
3138 flags |= KEYFLAG_REVOKED;
3139 if (key->expired)
3140 flags |= KEYFLAG_EXPIRED;
3141 if (key->disabled)
3142 flags |= KEYFLAG_DISABLED;
3143
3144 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3145 {
3146 k = mutt_mem_calloc(1, sizeof(*k));
3147 k->kobj = key;
3148 gpgme_key_ref(k->kobj);
3149 k->idx = idx;
3150 k->uid = uid->uid;
3151 k->flags = flags;
3152 if (uid->revoked)
3153 k->flags |= KEYFLAG_REVOKED;
3154 k->validity = uid->validity;
3155 *kend = k;
3156 kend = &k->next;
3157 }
3158 gpgme_key_unref(key);
3159 }
3160 if (gpg_err_code(err) != GPG_ERR_EOF)
3161 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3162 gpgme_op_keylist_end(ctx);
3163 }
3164
3165 gpgme_release(ctx);
3166 FREE(&pattern);
3167 return db;
3168}
static char * list_to_pattern(struct ListHead *list)
Convert STailQ to GPGME-compatible pattern.
Definition: crypt_gpgme.c:2958
unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
Definition: crypt_gpgme.c:2902
#define KEYFLAG_EXPIRED
Key is expired.
Definition: lib.h:131
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:125
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:128
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define KEYFLAG_NO_FLAGS
No flags are set.
Definition: lib.h:126
#define KEYFLAG_DISABLED
Key is marked disabled.
Definition: lib.h:133
#define KEYFLAG_REVOKED
Key is revoked.
Definition: lib.h:132
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:127
+ 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 3178 of file crypt_gpgme.c.

3179{
3180 char *scratch = mutt_str_dup(str);
3181 if (!scratch)
3182 return;
3183
3184 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3185 {
3186 if (strlen(t) > 3)
3188 }
3189
3190 FREE(&scratch);
3191}
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
+ 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 3202 of file crypt_gpgme.c.

3205{
3206 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3207
3208 int multi = false;
3209 int this_key_has_strong = false;
3210 int this_key_has_addr_match = false;
3211 int match = false;
3212
3213 struct CryptKeyInfo *keys = NULL, *k = NULL;
3214 struct CryptKeyInfo *the_strong_valid_key = NULL;
3215 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3216 struct CryptKeyInfo *matches = NULL;
3217 struct CryptKeyInfo **matches_endp = &matches;
3218
3219 if (a && a->mailbox)
3221 if (a && a->personal)
3223
3224 if (!oppenc_mode)
3225 mutt_message(_("Looking for keys matching \"%s\"..."), a ? buf_string(a->mailbox) : "");
3226 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3227
3228 mutt_list_free(&hints);
3229
3230 if (!keys)
3231 return NULL;
3232
3233 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n",
3234 a ? buf_string(a->personal) : "", a ? buf_string(a->mailbox) : "");
3235
3236 for (k = keys; k; k = k->next)
3237 {
3238 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3239
3240 if (abilities && !(k->flags & abilities))
3241 {
3242 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3243 continue;
3244 }
3245
3246 this_key_has_strong = false; /* strong and valid match */
3247 this_key_has_addr_match = false;
3248 match = false; /* any match */
3249
3250 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3251 mutt_addrlist_parse(&alist, k->uid);
3252 struct Address *ka = NULL;
3253 TAILQ_FOREACH(ka, &alist, entries)
3254 {
3255 int validity = crypt_id_matches_addr(a, ka, k);
3256
3257 if (validity & CRYPT_KV_MATCH) /* something matches */
3258 {
3259 match = true;
3260
3261 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3262 {
3263 if (validity & CRYPT_KV_STRONGID)
3264 {
3265 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3266 multi = true;
3267 this_key_has_strong = true;
3268 }
3269 else
3270 {
3271 this_key_has_addr_match = true;
3272 }
3273 }
3274 }
3275 }
3276 mutt_addrlist_clear(&alist);
3277
3278 if (match)
3279 {
3280 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3281 *matches_endp = tmp;
3282 matches_endp = &tmp->next;
3283
3284 if (this_key_has_strong)
3285 the_strong_valid_key = tmp;
3286 else if (this_key_has_addr_match)
3287 a_valid_addrmatch_key = tmp;
3288 }
3289 }
3290
3291 crypt_key_free(&keys);
3292
3293 if (matches)
3294 {
3295 if (oppenc_mode || !isatty(STDIN_FILENO))
3296 {
3297 const bool c_crypt_opportunistic_encrypt_strong_keys =
3298 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3299 if (the_strong_valid_key)
3300 k = crypt_copy_key(the_strong_valid_key);
3301 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3302 k = crypt_copy_key(a_valid_addrmatch_key);
3303 else
3304 k = NULL;
3305 }
3306 else if (the_strong_valid_key && !multi)
3307 {
3308 /* There was precisely one strong match on a valid ID.
3309 * Proceed without asking the user. */
3310 k = crypt_copy_key(the_strong_valid_key);
3311 }
3312 else
3313 {
3314 /* Else: Ask the user. */
3315 k = dlg_gpgme(matches, a, NULL, app, forced_valid);
3316 }
3317
3318 crypt_key_free(&matches);
3319 }
3320 else
3321 {
3322 k = NULL;
3323 }
3324
3325 return k;
3326}
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:3178
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:3025
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:637
#define mutt_message(...)
Definition: logging2.h:91
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
+ 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 3336 of file crypt_gpgme.c.

3338{
3339 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3340 struct CryptKeyInfo *matches = NULL;
3341 struct CryptKeyInfo **matches_endp = &matches;
3342 struct CryptKeyInfo *k = NULL;
3343 const char *ps = NULL, *pl = NULL, *phint = NULL;
3344
3345 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3346
3347 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3348 crypt_add_string_to_hints(phint, &hints);
3349 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3350 mutt_list_free(&hints);
3351
3352 if (!keys)
3353 {
3354 FREE(&pfcopy);
3355 return NULL;
3356 }
3357
3358 for (k = keys; k; k = k->next)
3359 {
3360 if (abilities && !(k->flags & abilities))
3361 continue;
3362
3363 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3364 crypt_long_keyid(k), k->uid);
3365
3366 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3367 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3368 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3369 {
3370 mutt_debug(LL_DEBUG5, "match\n");
3371
3372 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3373 *matches_endp = tmp;
3374 matches_endp = &tmp->next;
3375 }
3376 else
3377 {
3378 mutt_debug(LL_DEBUG5, "no match\n");
3379 }
3380 }
3381
3382 FREE(&pfcopy);
3383 crypt_key_free(&keys);
3384
3385 if (matches)
3386 {
3387 if (isatty(STDIN_FILENO))
3388 {
3389 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3390
3391 crypt_key_free(&matches);
3392 return k;
3393 }
3394 else
3395 {
3396 if (crypt_keys_are_valid(matches))
3397 return matches;
3398
3399 crypt_key_free(&matches);
3400 return NULL;
3401 }
3402 }
3403
3404 return NULL;
3405}
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:1275
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:721
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:570
+ 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 3419 of file crypt_gpgme.c.

3422{
3423 struct CryptKeyInfo *key = NULL;
3424 struct CryptCache *l = NULL;
3425 struct Buffer *resp = buf_pool_get();
3426
3428
3429 if (whatfor)
3430 {
3431 for (l = IdDefaults; l; l = l->next)
3432 {
3433 if (mutt_istr_equal(whatfor, l->what))
3434 {
3435 buf_strcpy(resp, l->dflt);
3436 break;
3437 }
3438 }
3439 }
3440
3441 while (true)
3442 {
3443 buf_reset(resp);
3444 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
3445 {
3446 goto done;
3447 }
3448
3449 if (whatfor)
3450 {
3451 if (l)
3452 {
3453 mutt_str_replace(&l->dflt, buf_string(resp));
3454 }
3455 else
3456 {
3457 l = mutt_mem_malloc(sizeof(struct CryptCache));
3458 l->next = IdDefaults;
3459 IdDefaults = l;
3460 l->what = mutt_str_dup(whatfor);
3461 l->dflt = buf_strdup(resp);
3462 }
3463 }
3464
3465 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3466 if (key)
3467 goto done;
3468
3469 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3470 }
3471
3472done:
3473 buf_pool_release(&resp);
3474 return key;
3475}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:75
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:394
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:3336
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:274
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:56
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:329
#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 3488 of file crypt_gpgme.c.

3489{
3490 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3491 struct ListNode *crypt_hook = NULL;
3492 const char *keyid = NULL;
3493 char *keylist = NULL;
3494 size_t keylist_size = 0;
3495 size_t keylist_used = 0;
3496 struct Address *p = NULL;
3497 struct CryptKeyInfo *k_info = NULL;
3498 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3499 char buf[1024] = { 0 };
3500 bool forced_valid = false;
3501 bool key_selected;
3502 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3503
3504 struct Address *a = NULL;
3505 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3506 TAILQ_FOREACH(a, addrlist, entries)
3507 {
3508 key_selected = false;
3509 mutt_crypt_hook(&crypt_hook_list, a);
3510 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3511 do
3512 {
3513 p = a;
3514 forced_valid = false;
3515 k_info = NULL;
3516
3517 if (crypt_hook)
3518 {
3519 keyid = crypt_hook->data;
3520 enum QuadOption ans = MUTT_YES;
3521 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3522 {
3523 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3524 buf_string(p->mailbox));
3525 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3526 }
3527 if (ans == MUTT_YES)
3528 {
3529 if (crypt_is_numerical_keyid(keyid))
3530 {
3531 if (mutt_strn_equal(keyid, "0x", 2))
3532 keyid += 2;
3533 goto bypass_selection; /* you don't see this. */
3534 }
3535
3536 /* check for e-mail address */
3537 mutt_addrlist_clear(&hookal);
3538 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3539 {
3540 mutt_addrlist_qualify(&hookal, fqdn);
3541 p = TAILQ_FIRST(&hookal);
3542 }
3543 else if (!oppenc_mode)
3544 {
3545 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3546 }
3547 }
3548 else if (ans == MUTT_NO)
3549 {
3550 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3551 {
3552 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3553 continue;
3554 }
3555 }
3556 else if (ans == MUTT_ABORT)
3557 {
3558 FREE(&keylist);
3559 mutt_addrlist_clear(&hookal);
3560 mutt_list_free(&crypt_hook_list);
3561 return NULL;
3562 }
3563 }
3564
3565 if (!k_info)
3566 {
3567 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3568 }
3569
3570 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3571 {
3572 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3573
3574 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3575 KEYFLAG_CANENCRYPT, app, &forced_valid);
3576 }
3577
3578 if (!k_info)
3579 {
3580 FREE(&keylist);
3581 mutt_addrlist_clear(&hookal);
3582 mutt_list_free(&crypt_hook_list);
3583 return NULL;
3584 }
3585
3586 keyid = crypt_fpr_or_lkeyid(k_info);
3587
3588 bypass_selection:
3589 keylist_size += mutt_str_len(keyid) + 4 + 1;
3590 mutt_mem_realloc(&keylist, keylist_size);
3591 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3592 keyid, forced_valid ? "!" : "");
3593 keylist_used = mutt_str_len(keylist);
3594
3595 key_selected = true;
3596
3597 crypt_key_free(&k_info);
3598 mutt_addrlist_clear(&hookal);
3599
3600 if (crypt_hook)
3601 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3602
3603 } while (crypt_hook);
3604
3605 mutt_list_free(&crypt_hook_list);
3606 }
3607 return keylist;
3608}
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:1364
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:3202
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:3419
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:870
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
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:342
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:706
+ 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 3639 of file crypt_gpgme.c.

3640{
3641 int rc = -1;
3642 gpgme_error_t err;
3643 gpgme_key_t key = NULL;
3644 gpgme_user_id_t uid = NULL;
3645 struct CryptKeyInfo *results = NULL, *k = NULL;
3646 struct CryptKeyInfo **kend = NULL;
3647 struct CryptKeyInfo *choice = NULL;
3648
3649 gpgme_ctx_t ctx = create_gpgme_context(false);
3650
3651 /* list all secret keys */
3652 if (gpgme_op_keylist_start(ctx, NULL, 1))
3653 goto cleanup;
3654
3655 kend = &results;
3656
3657 while (!(err = gpgme_op_keylist_next(ctx, &key)))
3658 {
3660
3665
3666 if (key->revoked)
3668 if (key->expired)
3670 if (key->disabled)
3672
3673 int idx;
3674 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3675 {
3676 k = mutt_mem_calloc(1, sizeof(*k));
3677 k->kobj = key;
3678 gpgme_key_ref(k->kobj);
3679 k->idx = idx;
3680 k->uid = uid->uid;
3681 k->flags = flags;
3682 if (uid->revoked)
3683 k->flags |= KEYFLAG_REVOKED;
3684 k->validity = uid->validity;
3685 *kend = k;
3686 kend = &k->next;
3687 }
3688 gpgme_key_unref(key);
3689 }
3690 if (gpg_err_code(err) != GPG_ERR_EOF)
3691 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3692 gpgme_op_keylist_end(ctx);
3693
3694 if (!results)
3695 {
3696 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3697 from. This error is displayed if no results were found. */
3698 mutt_error(_("No secret keys found"));
3699 goto cleanup;
3700 }
3701
3702 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3703 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3704 goto cleanup;
3705 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3706
3707 rc = 0;
3708
3709cleanup:
3710 crypt_key_free(&choice);
3711 crypt_key_free(&results);
3712 gpgme_release(ctx);
3713 return rc;
3714}
+ 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 3779 of file crypt_gpgme.c.

3780{
3781 /* this initialization should only run one time, but it may be called by
3782 * either pgp_gpgme_init or smime_gpgme_init */
3783 static bool has_run = false;
3784 if (has_run)
3785 return;
3786
3787 gpgme_check_version(NULL);
3788 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3789#ifdef ENABLE_NLS
3790 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3791#endif
3792 has_run = true;
3793}
+ Here is the caller graph for this function:

◆ init_pgp()

static void init_pgp ( void  )
static

Initialise the PGP crypto backend.

Definition at line 3798 of file crypt_gpgme.c.

3799{
3800 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3801 {
3802 mutt_error(_("GPGME: OpenPGP protocol not available"));
3803 }
3804}
+ Here is the caller graph for this function:

◆ init_smime()

static void init_smime ( void  )
static

Initialise the SMIME crypto backend.

Definition at line 3809 of file crypt_gpgme.c.

3810{
3811 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3812 {
3813 mutt_error(_("GPGME: CMS protocol not available"));
3814 }
3815}
+ 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 3841 of file crypt_gpgme.c.

3842{
3843 struct CryptKeyInfo *p = NULL;
3844 const char *prompt = NULL;
3845 const char *letters = NULL;
3846 const char *choices = NULL;
3847 int choice;
3848
3849 if (is_smime)
3851 else
3853
3854 /* Opportunistic encrypt is controlling encryption.
3855 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3856 * letter choices for those.
3857 */
3858 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3859 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3860 {
3861 if (is_smime)
3862 {
3863 /* L10N: S/MIME options (opportunistic encryption is on) */
3864 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3865 /* L10N: S/MIME options (opportunistic encryption is on) */
3866 letters = _("sapco");
3867 choices = "SapCo";
3868 }
3869 else
3870 {
3871 /* L10N: PGP options (opportunistic encryption is on) */
3872 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3873 /* L10N: PGP options (opportunistic encryption is on) */
3874 letters = _("samco");
3875 choices = "SamCo";
3876 }
3877 }
3878 else if (c_crypt_opportunistic_encrypt)
3879 {
3880 /* Opportunistic encryption option is set, but is toggled off for this message. */
3881 if (is_smime)
3882 {
3883 /* L10N: S/MIME options (opportunistic encryption is off) */
3884 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3885 /* L10N: S/MIME options (opportunistic encryption is off) */
3886 letters = _("esabpco");
3887 choices = "esabpcO";
3888 }
3889 else
3890 {
3891 /* L10N: PGP options (opportunistic encryption is off) */
3892 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3893 /* L10N: PGP options (opportunistic encryption is off) */
3894 letters = _("esabmco");
3895 choices = "esabmcO";
3896 }
3897 }
3898 else
3899 {
3900 /* Opportunistic encryption is unset */
3901 if (is_smime)
3902 {
3903 /* L10N: S/MIME options */
3904 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
3905 /* L10N: S/MIME options */
3906 letters = _("esabpc");
3907 choices = "esabpc";
3908 }
3909 else
3910 {
3911 /* L10N: PGP options */
3912 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
3913 /* L10N: PGP options */
3914 letters = _("esabmc");
3915 choices = "esabmc";
3916 }
3917 }
3918
3919 choice = mw_multi_choice(prompt, letters);
3920 if (choice > 0)
3921 {
3922 switch (choices[choice - 1])
3923 {
3924 case 'a': /* sign (a)s */
3925 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3926 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
3927 if (p)
3928 {
3929 char input_signas[128] = { 0 };
3930 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
3931
3932 if (is_smime)
3933 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", input_signas, NULL);
3934 else
3935 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
3936
3937 crypt_key_free(&p);
3938
3939 e->security |= SEC_SIGN;
3940 }
3941 break;
3942
3943 case 'b': /* (b)oth */
3944 e->security |= (SEC_ENCRYPT | SEC_SIGN);
3945 break;
3946
3947 case 'C':
3948 e->security &= ~SEC_SIGN;
3949 break;
3950
3951 case 'c': /* (c)lear */
3952 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
3953 break;
3954
3955 case 'e': /* (e)ncrypt */
3956 e->security |= SEC_ENCRYPT;
3957 e->security &= ~SEC_SIGN;
3958 break;
3959
3960 case 'm': /* (p)gp or s/(m)ime */
3961 case 'p':
3962 is_smime = !is_smime;
3963 if (is_smime)
3964 {
3965 e->security &= ~APPLICATION_PGP;
3967 }
3968 else
3969 {
3970 e->security &= ~APPLICATION_SMIME;
3972 }
3974 break;
3975
3976 case 'O': /* oppenc mode on */
3979 break;
3980
3981 case 'o': /* oppenc mode off */
3982 e->security &= ~SEC_OPPENCRYPT;
3983 break;
3984
3985 case 'S': /* (s)ign in oppenc mode */
3986 e->security |= SEC_SIGN;
3987 break;
3988
3989 case 's': /* (s)ign */
3990 e->security &= ~SEC_ENCRYPT;
3991 e->security |= SEC_SIGN;
3992 break;
3993 }
3994 }
3995
3996 return e->security;
3997}
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1031
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition: question.c:64
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
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:386
+ 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 4020 of file crypt_gpgme.c.

4021{
4022 struct Address *sender = NULL;
4023 bool rc = true;
4024
4025 if (!TAILQ_EMPTY(&e->env->from))
4026 {
4028 sender = TAILQ_FIRST(&e->env->from);
4029 }
4030 else if (!TAILQ_EMPTY(&e->env->sender))
4031 {
4033 sender = TAILQ_FIRST(&e->env->sender);
4034 }
4035
4036 if (sender)
4037 {
4038 if (SignatureKey)
4039 {
4040 gpgme_key_t key = SignatureKey;
4041 gpgme_user_id_t uid = NULL;
4042 int sender_length = buf_len(sender->mailbox);
4043 for (uid = key->uids; uid && rc; uid = uid->next)
4044 {
4045 int uid_length = strlen(uid->email);
4046 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4047 (uid_length == (sender_length + 2)))
4048 {
4049 const char *at_sign = strchr(uid->email + 1, '@');
4050 if (at_sign)
4051 {
4052 /* Assume address is 'mailbox@domainname'.
4053 * The mailbox part is case-sensitive,
4054 * the domainname is not. (RFC2821) */
4055 const char *tmp_email = uid->email + 1;
4056 const char *tmp_sender = buf_string(sender->mailbox);
4057 /* length of mailbox part including '@' */
4058 int mailbox_length = at_sign - tmp_email + 1;
4059 int domainname_length = sender_length - mailbox_length;
4060 int mailbox_match, domainname_match;
4061
4062 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4063 tmp_email += mailbox_length;
4064 tmp_sender += mailbox_length;
4065 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4066 if (mailbox_match && domainname_match)
4067 rc = false;
4068 }
4069 else
4070 {
4071 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4072 rc = false;
4073 }
4074 }
4075 }
4076 }
4077 else
4078 {
4079 mutt_any_key_to_continue(_("Failed to verify sender"));
4080 }
4081 }
4082 else
4083 {
4084 mutt_any_key_to_continue(_("Failed to figure out sender"));
4085 }
4086
4087 if (SignatureKey)
4088 {
4089 gpgme_key_unref(SignatureKey);
4090 SignatureKey = NULL;
4091 }
4092
4093 return rc;
4094}
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:490
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:173
int mutt_istrn_cmp(const char *a, const char *b, size_t num)
Compare two strings ignoring case (to a maximum), safely.
Definition: string.c:488
#define TAILQ_EMPTY(head)
Definition: queue.h:721
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 4118 of file crypt_gpgme.c.

4119{
4120 return GPGME_VERSION;
4121}
+ 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.