NeoMutt  2024-02-01-25-ga71e95
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:714
#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:231
#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:97
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:148
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:147
#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:588
+ 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:258
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:243
+ 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:35
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:308
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:953
#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:445
+ 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->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:1748
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1318
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1578
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 if (more)
2110 {
2111 fprintf(*fp, "sub %5.5s %u/%8s %s\n", gpgme_pubkey_algo_name(subkey->pubkey_algo),
2112 subkey->length, shortid, date);
2113 }
2114 else
2115 {
2116 fprintf(*fp, "pub %5.5s %u/%8s %s %s\n", gpgme_pubkey_algo_name(subkey->pubkey_algo),
2117 subkey->length, shortid, date, (uid ? uid->uid : ""));
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 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 2844 of file crypt_gpgme.c.

2845{
2846 unsigned int rc = 0;
2847
2848 switch (cap)
2849 {
2851 rc = key->can_encrypt;
2852 if (rc == 0)
2853 {
2854 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2855 {
2856 rc = subkey->can_encrypt;
2857 if (rc != 0)
2858 break;
2859 }
2860 }
2861 break;
2862 case KEY_CAP_CAN_SIGN:
2863 rc = key->can_sign;
2864 if (rc == 0)
2865 {
2866 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2867 {
2868 rc = subkey->can_sign;
2869 if (rc != 0)
2870 break;
2871 }
2872 }
2873 break;
2875 rc = key->can_certify;
2876 if (rc == 0)
2877 {
2878 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2879 {
2880 rc = subkey->can_certify;
2881 if (rc != 0)
2882 break;
2883 }
2884 }
2885 break;
2886 }
2887
2888 return rc;
2889}
@ 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 2900 of file crypt_gpgme.c.

2901{
2902 char *pattern = NULL, *p = NULL;
2903 const char *s = NULL;
2904 size_t n;
2905
2906 n = 0;
2907 struct ListNode *np = NULL;
2908 STAILQ_FOREACH(np, list, entries)
2909 {
2910 for (s = np->data; *s; s++)
2911 {
2912 if ((*s == '%') || (*s == '+'))
2913 n += 2;
2914 n++;
2915 }
2916 n++; /* delimiter or end of string */
2917 }
2918 n++; /* make sure to allocate at least one byte */
2919 p = mutt_mem_calloc(1, n);
2920 pattern = p;
2921 STAILQ_FOREACH(np, list, entries)
2922 {
2923 s = np->data;
2924 if (*s)
2925 {
2926 if (np != STAILQ_FIRST(list))
2927 *p++ = ' ';
2928 for (s = np->data; *s; s++)
2929 {
2930 if (*s == '%')
2931 {
2932 *p++ = '%';
2933 *p++ = '2';
2934 *p++ = '5';
2935 }
2936 else if (*s == '+')
2937 {
2938 *p++ = '%';
2939 *p++ = '2';
2940 *p++ = 'B';
2941 }
2942 else if (*s == ' ')
2943 {
2944 *p++ = '+';
2945 }
2946 else
2947 {
2948 *p++ = *s;
2949 }
2950 }
2951 }
2952 }
2953 *p = '\0';
2954 return pattern;
2955}
#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 2967 of file crypt_gpgme.c.

2968{
2969 struct CryptKeyInfo *db = NULL, *k = NULL, **kend = NULL;
2970 gpgme_error_t err;
2971 gpgme_ctx_t ctx = NULL;
2972 gpgme_key_t key = NULL;
2973 int idx;
2974 gpgme_user_id_t uid = NULL;
2975
2976 char *pattern = list_to_pattern(hints);
2977 if (!pattern)
2978 return NULL;
2979
2980 ctx = create_gpgme_context(0);
2981 db = NULL;
2982 kend = &db;
2983
2984 if ((app & APPLICATION_PGP))
2985 {
2986 /* It's all a mess. That old GPGME expects different things depending on
2987 * the protocol. For gpg we don't need percent escaped pappert but simple
2988 * strings passed in an array to the keylist_ext_start function. */
2989 size_t n = 0;
2990 struct ListNode *np = NULL;
2991 STAILQ_FOREACH(np, hints, entries)
2992 {
2993 if (np->data && *np->data)
2994 n++;
2995 }
2996 if (n == 0)
2997 goto no_pgphints;
2998
2999 char **patarr = mutt_mem_calloc(n + 1, sizeof(*patarr));
3000 n = 0;
3001 STAILQ_FOREACH(np, hints, entries)
3002 {
3003 if (np->data && *np->data)
3004 patarr[n++] = mutt_str_dup(np->data);
3005 }
3006 patarr[n] = NULL;
3007 err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
3008 for (n = 0; patarr[n]; n++)
3009 FREE(&patarr[n]);
3010 FREE(&patarr);
3011 if (err != 0)
3012 {
3013 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3014 gpgme_release(ctx);
3015 FREE(&pattern);
3016 return NULL;
3017 }
3018
3019 while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
3020 {
3021 KeyFlags flags = KEYFLAG_NO_FLAGS;
3022
3024 flags |= KEYFLAG_CANENCRYPT;
3026 flags |= KEYFLAG_CANSIGN;
3027
3028 if (key->revoked)
3029 flags |= KEYFLAG_REVOKED;
3030 if (key->expired)
3031 flags |= KEYFLAG_EXPIRED;
3032 if (key->disabled)
3033 flags |= KEYFLAG_DISABLED;
3034
3035 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3036 {
3037 k = mutt_mem_calloc(1, sizeof(*k));
3038 k->kobj = key;
3039 gpgme_key_ref(k->kobj);
3040 k->idx = idx;
3041 k->uid = uid->uid;
3042 k->flags = flags;
3043 if (uid->revoked)
3044 k->flags |= KEYFLAG_REVOKED;
3045 k->validity = uid->validity;
3046 *kend = k;
3047 kend = &k->next;
3048 }
3049 gpgme_key_unref(key);
3050 }
3051 if (gpg_err_code(err) != GPG_ERR_EOF)
3052 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3053 gpgme_op_keylist_end(ctx);
3054 no_pgphints:;
3055 }
3056
3057 if ((app & APPLICATION_SMIME))
3058 {
3059 /* and now look for x509 certificates */
3060 gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
3061 err = gpgme_op_keylist_start(ctx, pattern, 0);
3062 if (err != 0)
3063 {
3064 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3065 gpgme_release(ctx);
3066 FREE(&pattern);
3067 return NULL;
3068 }
3069
3070 while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
3071 {
3072 KeyFlags flags = KEYFLAG_ISX509;
3073
3075 flags |= KEYFLAG_CANENCRYPT;
3077 flags |= KEYFLAG_CANSIGN;
3078
3079 if (key->revoked)
3080 flags |= KEYFLAG_REVOKED;
3081 if (key->expired)
3082 flags |= KEYFLAG_EXPIRED;
3083 if (key->disabled)
3084 flags |= KEYFLAG_DISABLED;
3085
3086 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3087 {
3088 k = mutt_mem_calloc(1, sizeof(*k));
3089 k->kobj = key;
3090 gpgme_key_ref(k->kobj);
3091 k->idx = idx;
3092 k->uid = uid->uid;
3093 k->flags = flags;
3094 if (uid->revoked)
3095 k->flags |= KEYFLAG_REVOKED;
3096 k->validity = uid->validity;
3097 *kend = k;
3098 kend = &k->next;
3099 }
3100 gpgme_key_unref(key);
3101 }
3102 if (gpg_err_code(err) != GPG_ERR_EOF)
3103 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3104 gpgme_op_keylist_end(ctx);
3105 }
3106
3107 gpgme_release(ctx);
3108 FREE(&pattern);
3109 return db;
3110}
static char * list_to_pattern(struct ListHead *list)
Convert STailQ to GPGME-compatible pattern.
Definition: crypt_gpgme.c:2900
unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
Definition: crypt_gpgme.c:2844
#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 3120 of file crypt_gpgme.c.

3121{
3122 char *scratch = mutt_str_dup(str);
3123 if (!scratch)
3124 return;
3125
3126 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3127 {
3128 if (strlen(t) > 3)
3130 }
3131
3132 FREE(&scratch);
3133}
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 3144 of file crypt_gpgme.c.

3147{
3148 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3149
3150 int multi = false;
3151 int this_key_has_strong = false;
3152 int this_key_has_addr_match = false;
3153 int match = false;
3154
3155 struct CryptKeyInfo *keys = NULL, *k = NULL;
3156 struct CryptKeyInfo *the_strong_valid_key = NULL;
3157 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3158 struct CryptKeyInfo *matches = NULL;
3159 struct CryptKeyInfo **matches_endp = &matches;
3160
3161 if (a && a->mailbox)
3163 if (a && a->personal)
3165
3166 if (!oppenc_mode)
3167 mutt_message(_("Looking for keys matching \"%s\"..."), a ? buf_string(a->mailbox) : "");
3168 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3169
3170 mutt_list_free(&hints);
3171
3172 if (!keys)
3173 return NULL;
3174
3175 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n",
3176 a ? buf_string(a->personal) : "", a ? buf_string(a->mailbox) : "");
3177
3178 for (k = keys; k; k = k->next)
3179 {
3180 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3181
3182 if (abilities && !(k->flags & abilities))
3183 {
3184 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3185 continue;
3186 }
3187
3188 this_key_has_strong = false; /* strong and valid match */
3189 this_key_has_addr_match = false;
3190 match = false; /* any match */
3191
3192 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3193 mutt_addrlist_parse(&alist, k->uid);
3194 struct Address *ka = NULL;
3195 TAILQ_FOREACH(ka, &alist, entries)
3196 {
3197 int validity = crypt_id_matches_addr(a, ka, k);
3198
3199 if (validity & CRYPT_KV_MATCH) /* something matches */
3200 {
3201 match = true;
3202
3203 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3204 {
3205 if (validity & CRYPT_KV_STRONGID)
3206 {
3207 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3208 multi = true;
3209 this_key_has_strong = true;
3210 }
3211 else
3212 {
3213 this_key_has_addr_match = true;
3214 }
3215 }
3216 }
3217 }
3218 mutt_addrlist_clear(&alist);
3219
3220 if (match)
3221 {
3222 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3223 *matches_endp = tmp;
3224 matches_endp = &tmp->next;
3225
3226 if (this_key_has_strong)
3227 the_strong_valid_key = tmp;
3228 else if (this_key_has_addr_match)
3229 a_valid_addrmatch_key = tmp;
3230 }
3231 }
3232
3233 crypt_key_free(&keys);
3234
3235 if (matches)
3236 {
3237 if (oppenc_mode || !isatty(STDIN_FILENO))
3238 {
3239 const bool c_crypt_opportunistic_encrypt_strong_keys =
3240 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3241 if (the_strong_valid_key)
3242 k = crypt_copy_key(the_strong_valid_key);
3243 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3244 k = crypt_copy_key(a_valid_addrmatch_key);
3245 else
3246 k = NULL;
3247 }
3248 else if (the_strong_valid_key && !multi)
3249 {
3250 /* There was precisely one strong match on a valid ID.
3251 * Proceed without asking the user. */
3252 k = crypt_copy_key(the_strong_valid_key);
3253 }
3254 else
3255 {
3256 /* Else: Ask the user. */
3257 k = dlg_gpgme(matches, a, NULL, app, forced_valid);
3258 }
3259
3260 crypt_key_free(&matches);
3261 }
3262 else
3263 {
3264 k = NULL;
3265 }
3266
3267 return k;
3268}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1464
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:3120
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:2967
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:625
#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 3278 of file crypt_gpgme.c.

3280{
3281 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3282 struct CryptKeyInfo *matches = NULL;
3283 struct CryptKeyInfo **matches_endp = &matches;
3284 struct CryptKeyInfo *k = NULL;
3285 const char *ps = NULL, *pl = NULL, *phint = NULL;
3286
3287 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3288
3289 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3290 crypt_add_string_to_hints(phint, &hints);
3291 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3292 mutt_list_free(&hints);
3293
3294 if (!keys)
3295 {
3296 FREE(&pfcopy);
3297 return NULL;
3298 }
3299
3300 for (k = keys; k; k = k->next)
3301 {
3302 if (abilities && !(k->flags & abilities))
3303 continue;
3304
3305 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3306 crypt_long_keyid(k), k->uid);
3307
3308 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3309 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3310 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3311 {
3312 mutt_debug(LL_DEBUG5, "match\n");
3313
3314 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3315 *matches_endp = tmp;
3316 matches_endp = &tmp->next;
3317 }
3318 else
3319 {
3320 mutt_debug(LL_DEBUG5, "no match\n");
3321 }
3322 }
3323
3324 FREE(&pfcopy);
3325 crypt_key_free(&keys);
3326
3327 if (matches)
3328 {
3329 if (isatty(STDIN_FILENO))
3330 {
3331 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3332
3333 crypt_key_free(&matches);
3334 return k;
3335 }
3336 else
3337 {
3338 if (crypt_keys_are_valid(matches))
3339 return matches;
3340
3341 crypt_key_free(&matches);
3342 return NULL;
3343 }
3344 }
3345
3346 return NULL;
3347}
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 3361 of file crypt_gpgme.c.

3364{
3365 struct CryptKeyInfo *key = NULL;
3366 struct CryptCache *l = NULL;
3367 struct Buffer *resp = buf_pool_get();
3368
3370
3371 if (whatfor)
3372 {
3373 for (l = IdDefaults; l; l = l->next)
3374 {
3375 if (mutt_istr_equal(whatfor, l->what))
3376 {
3377 buf_strcpy(resp, l->dflt);
3378 break;
3379 }
3380 }
3381 }
3382
3383 while (true)
3384 {
3385 buf_reset(resp);
3386 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
3387 {
3388 goto done;
3389 }
3390
3391 if (whatfor)
3392 {
3393 if (l)
3394 {
3395 mutt_str_replace(&l->dflt, buf_string(resp));
3396 }
3397 else
3398 {
3399 l = mutt_mem_malloc(sizeof(struct CryptCache));
3400 l->next = IdDefaults;
3401 IdDefaults = l;
3402 l->what = mutt_str_dup(whatfor);
3403 l->dflt = buf_strdup(resp);
3404 }
3405 }
3406
3407 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3408 if (key)
3409 goto done;
3410
3411 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3412 }
3413
3414done:
3415 buf_pool_release(&resp);
3416 return key;
3417}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:93
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:412
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:3278
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 3430 of file crypt_gpgme.c.

3431{
3432 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3433 struct ListNode *crypt_hook = NULL;
3434 const char *keyid = NULL;
3435 char *keylist = NULL;
3436 size_t keylist_size = 0;
3437 size_t keylist_used = 0;
3438 struct Address *p = NULL;
3439 struct CryptKeyInfo *k_info = NULL;
3440 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3441 char buf[1024] = { 0 };
3442 bool forced_valid = false;
3443 bool key_selected;
3444 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3445
3446 struct Address *a = NULL;
3447 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3448 TAILQ_FOREACH(a, addrlist, entries)
3449 {
3450 key_selected = false;
3451 mutt_crypt_hook(&crypt_hook_list, a);
3452 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3453 do
3454 {
3455 p = a;
3456 forced_valid = false;
3457 k_info = NULL;
3458
3459 if (crypt_hook)
3460 {
3461 keyid = crypt_hook->data;
3462 enum QuadOption ans = MUTT_YES;
3463 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3464 {
3465 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3466 buf_string(p->mailbox));
3467 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3468 }
3469 if (ans == MUTT_YES)
3470 {
3471 if (crypt_is_numerical_keyid(keyid))
3472 {
3473 if (mutt_strn_equal(keyid, "0x", 2))
3474 keyid += 2;
3475 goto bypass_selection; /* you don't see this. */
3476 }
3477
3478 /* check for e-mail address */
3479 mutt_addrlist_clear(&hookal);
3480 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3481 {
3482 mutt_addrlist_qualify(&hookal, fqdn);
3483 p = TAILQ_FIRST(&hookal);
3484 }
3485 else if (!oppenc_mode)
3486 {
3487 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3488 }
3489 }
3490 else if (ans == MUTT_NO)
3491 {
3492 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3493 {
3494 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3495 continue;
3496 }
3497 }
3498 else if (ans == MUTT_ABORT)
3499 {
3500 FREE(&keylist);
3501 mutt_addrlist_clear(&hookal);
3502 mutt_list_free(&crypt_hook_list);
3503 return NULL;
3504 }
3505 }
3506
3507 if (!k_info)
3508 {
3509 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3510 }
3511
3512 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3513 {
3514 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3515
3516 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3517 KEYFLAG_CANENCRYPT, app, &forced_valid);
3518 }
3519
3520 if (!k_info)
3521 {
3522 FREE(&keylist);
3523 mutt_addrlist_clear(&hookal);
3524 mutt_list_free(&crypt_hook_list);
3525 return NULL;
3526 }
3527
3528 keyid = crypt_fpr_or_lkeyid(k_info);
3529
3530 bypass_selection:
3531 keylist_size += mutt_str_len(keyid) + 4 + 1;
3532 mutt_mem_realloc(&keylist, keylist_size);
3533 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3534 keyid, forced_valid ? "!" : "");
3535 keylist_used = mutt_str_len(keylist);
3536
3537 key_selected = true;
3538
3539 crypt_key_free(&k_info);
3540 mutt_addrlist_clear(&hookal);
3541
3542 if (crypt_hook)
3543 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3544
3545 } while (crypt_hook);
3546
3547 mutt_list_free(&crypt_hook_list);
3548 }
3549 return keylist;
3550}
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:3144
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:3361
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:848
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:349
#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 3581 of file crypt_gpgme.c.

3582{
3583 int rc = -1;
3584 gpgme_error_t err;
3585 gpgme_key_t key = NULL;
3586 gpgme_user_id_t uid = NULL;
3587 struct CryptKeyInfo *results = NULL, *k = NULL;
3588 struct CryptKeyInfo **kend = NULL;
3589 struct CryptKeyInfo *choice = NULL;
3590
3591 gpgme_ctx_t ctx = create_gpgme_context(false);
3592
3593 /* list all secret keys */
3594 if (gpgme_op_keylist_start(ctx, NULL, 1))
3595 goto cleanup;
3596
3597 kend = &results;
3598
3599 while (!(err = gpgme_op_keylist_next(ctx, &key)))
3600 {
3602
3607
3608 if (key->revoked)
3610 if (key->expired)
3612 if (key->disabled)
3614
3615 int idx;
3616 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3617 {
3618 k = mutt_mem_calloc(1, sizeof(*k));
3619 k->kobj = key;
3620 gpgme_key_ref(k->kobj);
3621 k->idx = idx;
3622 k->uid = uid->uid;
3623 k->flags = flags;
3624 if (uid->revoked)
3625 k->flags |= KEYFLAG_REVOKED;
3626 k->validity = uid->validity;
3627 *kend = k;
3628 kend = &k->next;
3629 }
3630 gpgme_key_unref(key);
3631 }
3632 if (gpg_err_code(err) != GPG_ERR_EOF)
3633 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3634 gpgme_op_keylist_end(ctx);
3635
3636 if (!results)
3637 {
3638 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3639 from. This error is displayed if no results were found. */
3640 mutt_error(_("No secret keys found"));
3641 goto cleanup;
3642 }
3643
3644 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3645 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3646 goto cleanup;
3647 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3648
3649 rc = 0;
3650
3651cleanup:
3652 crypt_key_free(&choice);
3653 crypt_key_free(&results);
3654 gpgme_release(ctx);
3655 return rc;
3656}
+ 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 3721 of file crypt_gpgme.c.

3722{
3723 /* this initialization should only run one time, but it may be called by
3724 * either pgp_gpgme_init or smime_gpgme_init */
3725 static bool has_run = false;
3726 if (has_run)
3727 return;
3728
3729 gpgme_check_version(NULL);
3730 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3731#ifdef ENABLE_NLS
3732 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3733#endif
3734 has_run = true;
3735}
+ Here is the caller graph for this function:

◆ init_pgp()

static void init_pgp ( void  )
static

Initialise the PGP crypto backend.

Definition at line 3740 of file crypt_gpgme.c.

3741{
3742 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3743 {
3744 mutt_error(_("GPGME: OpenPGP protocol not available"));
3745 }
3746}
+ Here is the caller graph for this function:

◆ init_smime()

static void init_smime ( void  )
static

Initialise the SMIME crypto backend.

Definition at line 3751 of file crypt_gpgme.c.

3752{
3753 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3754 {
3755 mutt_error(_("GPGME: CMS protocol not available"));
3756 }
3757}
+ 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 3783 of file crypt_gpgme.c.

3784{
3785 struct CryptKeyInfo *p = NULL;
3786 const char *prompt = NULL;
3787 const char *letters = NULL;
3788 const char *choices = NULL;
3789 int choice;
3790
3791 if (is_smime)
3793 else
3795
3796 /* Opportunistic encrypt is controlling encryption.
3797 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3798 * letter choices for those.
3799 */
3800 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3801 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3802 {
3803 if (is_smime)
3804 {
3805 /* L10N: S/MIME options (opportunistic encryption is on) */
3806 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3807 /* L10N: S/MIME options (opportunistic encryption is on) */
3808 letters = _("sapco");
3809 choices = "SapCo";
3810 }
3811 else
3812 {
3813 /* L10N: PGP options (opportunistic encryption is on) */
3814 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3815 /* L10N: PGP options (opportunistic encryption is on) */
3816 letters = _("samco");
3817 choices = "SamCo";
3818 }
3819 }
3820 else if (c_crypt_opportunistic_encrypt)
3821 {
3822 /* Opportunistic encryption option is set, but is toggled off for this message. */
3823 if (is_smime)
3824 {
3825 /* L10N: S/MIME options (opportunistic encryption is off) */
3826 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3827 /* L10N: S/MIME options (opportunistic encryption is off) */
3828 letters = _("esabpco");
3829 choices = "esabpcO";
3830 }
3831 else
3832 {
3833 /* L10N: PGP options (opportunistic encryption is off) */
3834 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3835 /* L10N: PGP options (opportunistic encryption is off) */
3836 letters = _("esabmco");
3837 choices = "esabmcO";
3838 }
3839 }
3840 else
3841 {
3842 /* Opportunistic encryption is unset */
3843 if (is_smime)
3844 {
3845 /* L10N: S/MIME options */
3846 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
3847 /* L10N: S/MIME options */
3848 letters = _("esabpc");
3849 choices = "esabpc";
3850 }
3851 else
3852 {
3853 /* L10N: PGP options */
3854 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
3855 /* L10N: PGP options */
3856 letters = _("esabmc");
3857 choices = "esabmc";
3858 }
3859 }
3860
3861 choice = mw_multi_choice(prompt, letters);
3862 if (choice > 0)
3863 {
3864 switch (choices[choice - 1])
3865 {
3866 case 'a': /* sign (a)s */
3867 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3868 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
3869 if (p)
3870 {
3871 char input_signas[128] = { 0 };
3872 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
3873
3874 if (is_smime)
3875 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", input_signas, NULL);
3876 else
3877 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
3878
3879 crypt_key_free(&p);
3880
3881 e->security |= SEC_SIGN;
3882 }
3883 break;
3884
3885 case 'b': /* (b)oth */
3886 e->security |= (SEC_ENCRYPT | SEC_SIGN);
3887 break;
3888
3889 case 'C':
3890 e->security &= ~SEC_SIGN;
3891 break;
3892
3893 case 'c': /* (c)lear */
3894 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
3895 break;
3896
3897 case 'e': /* (e)ncrypt */
3898 e->security |= SEC_ENCRYPT;
3899 e->security &= ~SEC_SIGN;
3900 break;
3901
3902 case 'm': /* (p)gp or s/(m)ime */
3903 case 'p':
3904 is_smime = !is_smime;
3905 if (is_smime)
3906 {
3907 e->security &= ~APPLICATION_PGP;
3909 }
3910 else
3911 {
3912 e->security &= ~APPLICATION_SMIME;
3914 }
3916 break;
3917
3918 case 'O': /* oppenc mode on */
3921 break;
3922
3923 case 'o': /* oppenc mode off */
3924 e->security &= ~SEC_OPPENCRYPT;
3925 break;
3926
3927 case 'S': /* (s)ign in oppenc mode */
3928 e->security |= SEC_SIGN;
3929 break;
3930
3931 case 's': /* (s)ign */
3932 e->security &= ~SEC_ENCRYPT;
3933 e->security |= SEC_SIGN;
3934 break;
3935 }
3936 }
3937
3938 return e->security;
3939}
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 3962 of file crypt_gpgme.c.

3963{
3964 struct Address *sender = NULL;
3965 bool rc = true;
3966
3967 if (!TAILQ_EMPTY(&e->env->from))
3968 {
3970 sender = TAILQ_FIRST(&e->env->from);
3971 }
3972 else if (!TAILQ_EMPTY(&e->env->sender))
3973 {
3975 sender = TAILQ_FIRST(&e->env->sender);
3976 }
3977
3978 if (sender)
3979 {
3980 if (SignatureKey)
3981 {
3982 gpgme_key_t key = SignatureKey;
3983 gpgme_user_id_t uid = NULL;
3984 int sender_length = buf_len(sender->mailbox);
3985 for (uid = key->uids; uid && rc; uid = uid->next)
3986 {
3987 int uid_length = strlen(uid->email);
3988 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
3989 (uid_length == (sender_length + 2)))
3990 {
3991 const char *at_sign = strchr(uid->email + 1, '@');
3992 if (at_sign)
3993 {
3994 /* Assume address is 'mailbox@domainname'.
3995 * The mailbox part is case-sensitive,
3996 * the domainname is not. (RFC2821) */
3997 const char *tmp_email = uid->email + 1;
3998 const char *tmp_sender = buf_string(sender->mailbox);
3999 /* length of mailbox part including '@' */
4000 int mailbox_length = at_sign - tmp_email + 1;
4001 int domainname_length = sender_length - mailbox_length;
4002 int mailbox_match, domainname_match;
4003
4004 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4005 tmp_email += mailbox_length;
4006 tmp_sender += mailbox_length;
4007 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4008 if (mailbox_match && domainname_match)
4009 rc = false;
4010 }
4011 else
4012 {
4013 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4014 rc = false;
4015 }
4016 }
4017 }
4018 }
4019 else
4020 {
4021 mutt_any_key_to_continue(_("Failed to verify sender"));
4022 }
4023 }
4024 else
4025 {
4026 mutt_any_key_to_continue(_("Failed to figure out sender"));
4027 }
4028
4029 if (SignatureKey)
4030 {
4031 gpgme_key_unref(SignatureKey);
4032 SignatureKey = NULL;
4033 }
4034
4035 return rc;
4036}
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:300
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:508
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:175
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 4060 of file crypt_gpgme.c.

4061{
4062 return GPGME_VERSION;
4063}
+ 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.