NeoMutt  2024-04-25-76-g20fe7b
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
crypt_gpgme.c File Reference

Wrapper for PGP/SMIME calls to GPGME. More...

#include "config.h"
#include <errno.h>
#include <gpg-error.h>
#include <gpgme.h>
#include <langinfo.h>
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "crypt_gpgme.h"
#include "lib.h"
#include "attach/lib.h"
#include "editor/lib.h"
#include "history/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "crypt.h"
#include "globals.h"
#include "gpgme_functions.h"
#include "handler.h"
#include "hook.h"
#include "mutt_logging.h"
#include "autocrypt/lib.h"
+ Include dependency graph for crypt_gpgme.c:

Go to the source code of this file.

Data Structures

struct  CryptCache
 Internal cache for GPGME. More...
 

Macros

#define CRYPT_KV_VALID   (1 << 0)
 
#define CRYPT_KV_ADDR   (1 << 1)
 
#define CRYPT_KV_STRING   (1 << 2)
 
#define CRYPT_KV_STRONGID   (1 << 3)
 
#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)
 
#define PKA_NOTATION_NAME   "pka-address@gnupg.org"
 
#define _LINE_COMPARE(_x, _y)   line_compare(_x, sizeof(_x) - 1, _y)
 
#define MESSAGE(_y)   _LINE_COMPARE("MESSAGE-----", _y)
 
#define SIGNED_MESSAGE(_y)   _LINE_COMPARE("SIGNED MESSAGE-----", _y)
 
#define PUBLIC_KEY_BLOCK(_y)   _LINE_COMPARE("PUBLIC KEY BLOCK-----", _y)
 
#define BEGIN_PGP_SIGNATURE(_y)    _LINE_COMPARE("-----BEGIN PGP SIGNATURE-----", _y)
 

Functions

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

Variables

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

Detailed Description

Wrapper for PGP/SMIME calls to GPGME.

Authors
  • Pietro Cerutti
  • Richard Russon
  • Federico Kircheis
  • Ian Zimmerman
  • ftilde
  • Anna Figueiredo Gomes
  • Alejandro Colomar

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

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

Definition in file crypt_gpgme.c.

Macro Definition Documentation

◆ CRYPT_KV_VALID

#define CRYPT_KV_VALID   (1 << 0)

Definition at line 74 of file crypt_gpgme.c.

◆ CRYPT_KV_ADDR

#define CRYPT_KV_ADDR   (1 << 1)

Definition at line 75 of file crypt_gpgme.c.

◆ CRYPT_KV_STRING

#define CRYPT_KV_STRING   (1 << 2)

Definition at line 76 of file crypt_gpgme.c.

◆ CRYPT_KV_STRONGID

#define CRYPT_KV_STRONGID   (1 << 3)

Definition at line 77 of file crypt_gpgme.c.

◆ CRYPT_KV_MATCH

#define CRYPT_KV_MATCH   (CRYPT_KV_ADDR | CRYPT_KV_STRING)

Definition at line 78 of file crypt_gpgme.c.

◆ PKA_NOTATION_NAME

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

Definition at line 98 of file crypt_gpgme.c.

◆ _LINE_COMPARE

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

Definition at line 100 of file crypt_gpgme.c.

◆ MESSAGE

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

Definition at line 101 of file crypt_gpgme.c.

◆ SIGNED_MESSAGE

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

Definition at line 102 of file crypt_gpgme.c.

◆ PUBLIC_KEY_BLOCK

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

Definition at line 103 of file crypt_gpgme.c.

◆ BEGIN_PGP_SIGNATURE

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

Definition at line 104 of file crypt_gpgme.c.

Function Documentation

◆ is_pka_notation()

static bool is_pka_notation ( gpgme_sig_notation_t  notation)
static

Is this the standard pka email address.

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

Definition at line 112 of file crypt_gpgme.c.

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

◆ redraw_if_needed()

static void redraw_if_needed ( gpgme_ctx_t  ctx)
static

Accommodate for a redraw if needed.

Parameters
ctxGPGME handle

Definition at line 121 of file crypt_gpgme.c.

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

◆ crypt_keyid()

const char * crypt_keyid ( struct CryptKeyInfo k)

Find the ID for the key.

Parameters
kKey to use
Return values
ptrID string for the key

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

Definition at line 138 of file crypt_gpgme.c.

139{
140 const char *s = "????????";
141
142 if (k->kobj && k->kobj->subkeys)
143 {
144 s = k->kobj->subkeys->keyid;
145 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
146 if ((!c_pgp_long_ids) && (strlen(s) == 16))
147 {
148 /* Return only the short keyID. */
149 s += 8;
150 }
151 }
152
153 return s;
154}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
gpgme_key_t kobj
Definition: crypt_gpgme.h:46
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ 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:51
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:697
#define CRYPT_KV_STRING
Definition: crypt_gpgme.c:76
int crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
Definition: crypt_gpgme.c:310
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
Definition: crypt_gpgme.c:275
#define CRYPT_KV_VALID
Definition: crypt_gpgme.c:74
#define CRYPT_KV_STRONGID
Definition: crypt_gpgme.c:77
#define CRYPT_KV_ADDR
Definition: crypt_gpgme.c:75
struct Buffer * personal
Real name of address.
Definition: address.h:37
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ create_gpgme_context()

gpgme_ctx_t create_gpgme_context ( bool  for_smime)

Create a new GPGME context.

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

Definition at line 361 of file crypt_gpgme.c.

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

◆ create_gpgme_data()

static gpgme_data_t create_gpgme_data ( void  )
static

Create a new GPGME data object.

Return values
ptrGPGPE data object

This is a wrapper to die on error.

Note
Call gpgme_data_release() to free the data object

Definition at line 400 of file crypt_gpgme.c.

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

◆ body_to_data_object()

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

Create GPGME object from the mail body.

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

Definition at line 419 of file crypt_gpgme.c.

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

◆ data_object_to_stream()

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

Write a GPGME data object to a file.

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

Definition at line 514 of file crypt_gpgme.c.

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

◆ data_object_to_tempfile()

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

Copy a data object to a temporary file.

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

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

Note
The caller must free the returned file name

Definition at line 563 of file crypt_gpgme.c.

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

◆ create_recipient_string()

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

Create a string of recipients.

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

Definition at line 622 of file crypt_gpgme.c.

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

◆ set_signer_from_address()

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

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

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

Definition at line 658 of file crypt_gpgme.c.

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

◆ set_signer()

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

Make sure that the correct signer is set.

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

Definition at line 717 of file crypt_gpgme.c.

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

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

◆ encrypt_gpgme_object()

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

Encrypt the GPGPME data object.

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

Definition at line 781 of file crypt_gpgme.c.

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

◆ get_micalg()

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

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

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

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

Definition at line 853 of file crypt_gpgme.c.

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

◆ print_time()

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

Print the date/time according to the locale.

Parameters
tTimestamp
stateState to write to

Definition at line 891 of file crypt_gpgme.c.

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

◆ sign_message()

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

Sign a message.

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

Definition at line 906 of file crypt_gpgme.c.

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

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

◆ show_fingerprint()

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

Write a key's fingerprint.

Parameters
keyGPGME key
stateState to write to

Definition at line 1257 of file crypt_gpgme.c.

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

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

◆ print_smime_keyinfo()

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

Print key info about an SMIME key.

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

Definition at line 1351 of file crypt_gpgme.c.

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

◆ show_one_recipient()

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

Show information about one encryption recipient.

Parameters
stateState to write to
rEncryption recipient

Definition at line 1417 of file crypt_gpgme.c.

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

◆ show_encryption_info()

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

Show encryption information.

Parameters
stateState to write to
resultDecryption result

Definition at line 1433 of file crypt_gpgme.c.

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

◆ show_one_sig_status()

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

Show information about one signature.

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

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

Definition at line 1458 of file crypt_gpgme.c.

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

◆ verify_one()

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

Do the actual verification step.

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

With is_smime set to true we assume S/MIME.

Definition at line 1581 of file crypt_gpgme.c.

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

◆ decrypt_part()

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

Decrypt a PGP or SMIME message.

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

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

Definition at line 1732 of file crypt_gpgme.c.

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

◆ pgp_gpgme_extract_keys()

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

Write PGP keys to a file.

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

Definition at line 2112 of file crypt_gpgme.c.

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

◆ line_compare()

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

Compare two strings ignore line endings.

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

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

Definition at line 2195 of file crypt_gpgme.c.

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

◆ pgp_check_traditional_one_body()

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

Check one inline PGP body part.

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

Definition at line 2213 of file crypt_gpgme.c.

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

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

◆ key_check_cap()

unsigned int key_check_cap ( gpgme_key_t  key,
enum KeyCap  cap 
)

Check the capabilities of a key.

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

Definition at line 2948 of file crypt_gpgme.c.

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

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

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

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

◆ crypt_getkeybyaddr()

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

Find a key by email address.

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

Definition at line 3248 of file crypt_gpgme.c.

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

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

3468{
3469 struct CryptKeyInfo *key = NULL;
3470 struct CryptCache *l = NULL;
3471 struct Buffer *resp = buf_pool_get();
3472
3474
3475 if (whatfor)
3476 {
3477 for (l = IdDefaults; l; l = l->next)
3478 {
3479 if (mutt_istr_equal(whatfor, l->what))
3480 {
3481 buf_strcpy(resp, l->dflt);
3482 break;
3483 }
3484 }
3485 }
3486
3487 while (true)
3488 {
3489 buf_reset(resp);
3490 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
3491 {
3492 goto done;
3493 }
3494
3495 if (whatfor)
3496 {
3497 if (l)
3498 {
3499 mutt_str_replace(&l->dflt, buf_string(resp));
3500 }
3501 else
3502 {
3503 l = mutt_mem_malloc(sizeof(struct CryptCache));
3504 l->next = IdDefaults;
3505 IdDefaults = l;
3506 l->what = mutt_str_dup(whatfor);
3507 l->dflt = buf_strdup(resp);
3508 }
3509 }
3510
3511 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3512 if (key)
3513 goto done;
3514
3515 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3516 }
3517
3518done:
3519 buf_pool_release(&resp);
3520 return key;
3521}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
static struct CryptCache * IdDefaults
Cache of GPGME keys.
Definition: crypt_gpgme.c:92
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
Find a key by string.
Definition: crypt_gpgme.c:3382
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:280
#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 3534 of file crypt_gpgme.c.

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

◆ mutt_gpgme_select_secret_key()

int mutt_gpgme_select_secret_key ( struct Buffer keyid)

Select a private Autocrypt key for a new account.

Parameters
keyidAutocrypt Key id
Return values
0Success
-1Error

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

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

Definition at line 3685 of file crypt_gpgme.c.

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

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

◆ init_pgp()

static void init_pgp ( void  )
static

Initialise the PGP crypto backend.

Definition at line 3843 of file crypt_gpgme.c.

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

◆ init_smime()

static void init_smime ( void  )
static

Initialise the SMIME crypto backend.

Definition at line 3854 of file crypt_gpgme.c.

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

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

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

4164{
4165 return GPGME_VERSION;
4166}
+ 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.