NeoMutt  2025-12-11-769-g906513
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
crypt.c File Reference

Signing/encryption multiplexor. More...

#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.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.h"
#include "lib.h"
#include "attach/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "cryptglue.h"
#include "globals.h"
#include "mx.h"
#include "autocrypt/lib.h"
+ Include dependency graph for crypt.c:

Go to the source code of this file.

Functions

void crypt_current_time (struct State *state, const char *app_name)
 Print the current time.
 
void crypt_forget_passphrase (void)
 Forget a passphrase and display a message.
 
bool crypt_valid_passphrase (SecurityFlags flags)
 Check that we have a usable passphrase, ask if not.
 
int mutt_protect (struct Email *e, char *keylist, bool postpone)
 Encrypt and/or sign a message.
 
SecurityFlags mutt_is_multipart_signed (struct Body *b)
 Is a message signed?
 
SecurityFlags mutt_is_multipart_encrypted (struct Body *b)
 Does the message have encrypted parts?
 
int mutt_is_valid_multipart_pgp_encrypted (struct Body *b)
 Is this a valid multi-part encrypted message?
 
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted (struct Body *b)
 Check for malformed layout.
 
SecurityFlags mutt_is_application_pgp (const struct Body *b)
 Does the message use PGP?
 
SecurityFlags mutt_is_application_smime (struct Body *b)
 Does the message use S/MIME?
 
SecurityFlags crypt_query (struct Body *b)
 Check out the type of encryption used.
 
int crypt_write_signed (struct Body *b, struct State *state, const char *tempfile)
 Write the message body/part.
 
void crypt_convert_to_7bit (struct Body *b)
 Convert an email to 7bit encoding.
 
void crypt_extract_keys_from_messages (struct Mailbox *m, struct EmailArray *ea)
 Extract keys from a message.
 
int crypt_get_keys (struct Email *e, char **keylist, bool oppenc_mode)
 Check we have all the keys we need.
 
void crypt_opportunistic_encrypt (struct Email *e)
 Can all recipients be determined.
 
static void crypt_fetch_signatures (struct Body ***b_sigs, struct Body *b, int *n)
 Create an array of an emails parts.
 
bool mutt_should_hide_protected_subject (struct Email *e)
 Should NeoMutt hide the protected subject?
 
int mutt_protected_headers_handler (struct Body *b_email, struct State *state)
 Handler for protected headers - Implements handler_t -.
 
int mutt_signed_handler (struct Body *b_email, struct State *state)
 Handler for "multipart/signed" - Implements handler_t -.
 
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.
 
bool crypt_is_numerical_keyid (const char *s)
 Is this a numerical keyid.
 

Detailed Description

Signing/encryption multiplexor.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Anna Figueiredo Gomes
  • Alejandro Colomar
  • Rayford Shireman

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

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

Definition in file crypt.c.

Function Documentation

◆ crypt_current_time()

void crypt_current_time ( struct State * state,
const char * app_name )

Print the current time.

Parameters
stateState to use
app_nameApp name, e.g. "PGP"

print the current time to avoid spoofing of the signature output

Definition at line 64 of file crypt.c.

65{
66 char p[256] = { 0 };
67 char tmp[512] = { 0 };
68
69 if (!WithCrypto)
70 return;
71
72 const bool c_crypt_timestamp = cs_subset_bool(NeoMutt->sub, "crypt_timestamp");
73 if (c_crypt_timestamp)
74 {
75 mutt_date_localtime_format(p, sizeof(p), _(" (current time: %c)"), mutt_date_now());
76 }
77 else
78 {
79 *p = '\0';
80 }
81
82 snprintf(tmp, sizeof(tmp), _("[-- %s output follows%s --]\n"), NONULL(app_name), p);
83 state_attach_puts(state, tmp);
84}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition date.c:952
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
#define _(a)
Definition message.h:28
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition state.c:104
#define WithCrypto
Definition lib.h:125
#define NONULL(x)
Definition string2.h:44
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_forget_passphrase()

void crypt_forget_passphrase ( void )

Forget a passphrase and display a message.

Definition at line 89 of file crypt.c.

90{
93
96
97 if (WithCrypto)
98 {
99 /* L10N: Due to the implementation details (e.g. some passwords are managed
100 by gpg-agent) we can't know whether we forgot zero, 1, 12, ...
101 passwords. So in English we use "Passphrases". Your language might
102 have other means to express this. */
103 mutt_message(_("Passphrases forgotten"));
104 }
105}
void crypt_smime_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase()
Definition cryptglue.c:425
void crypt_pgp_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase()
Definition cryptglue.c:203
#define mutt_message(...)
Definition logging2.h:93
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:99
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:100
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_valid_passphrase()

bool crypt_valid_passphrase ( SecurityFlags flags)

Check that we have a usable passphrase, ask if not.

Parameters
flagsFlags, see SecurityFlags
Return values
trueSuccess
falseFailed

Definition at line 131 of file crypt.c.

132{
133 bool rc = false;
134
135#ifndef DEBUG
136 disable_coredumps();
137#endif
138
139 if (((WithCrypto & APPLICATION_PGP) != 0) && (flags & APPLICATION_PGP))
141
142 if (((WithCrypto & APPLICATION_SMIME) != 0) && (flags & APPLICATION_SMIME))
144
145 return rc;
146}
bool crypt_smime_valid_passphrase(void)
Wrapper for CryptModuleSpecs::valid_passphrase()
Definition cryptglue.c:434
bool crypt_pgp_valid_passphrase(void)
Wrapper for CryptModuleSpecs::valid_passphrase()
Definition cryptglue.c:212
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_protect()

int mutt_protect ( struct Email * e,
char * keylist,
bool postpone )

Encrypt and/or sign a message.

Parameters
eEmail
keylistList of keys to encrypt to (space-separated)
postponeWhen true, signing is automatically disabled
Return values
0Success
-1Error

Definition at line 156 of file crypt.c.

157{
158 struct Body *pbody = NULL, *tmp_pbody = NULL;
159 struct Body *tmp_smime_pbody = NULL;
160 struct Body *tmp_pgp_pbody = NULL;
161 bool has_retainable_sig = false;
162
163 if (!WithCrypto)
164 return -1;
165
166 SecurityFlags security = e->security;
167 int sign = security & (SEC_AUTOCRYPT | SEC_SIGN);
168 if (postpone)
169 {
170 sign = SEC_NO_FLAGS;
171 security &= ~SEC_SIGN;
172 }
173
174 if (!(security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) && !sign)
175 return 0;
176
177 if (sign && !(security & SEC_AUTOCRYPT) && !crypt_valid_passphrase(security))
178 return -1;
179
180 if (((WithCrypto & APPLICATION_PGP) != 0) && !(security & SEC_AUTOCRYPT) &&
181 ((security & PGP_INLINE) == PGP_INLINE))
182 {
183 if ((e->body->type != TYPE_TEXT) || !mutt_istr_equal(e->body->subtype, "plain"))
184 {
185 if (query_quadoption(_("Inline PGP can't be used with attachments. Revert to PGP/MIME?"),
186 NeoMutt->sub, "pgp_mime_auto") != MUTT_YES)
187 {
188 mutt_error(_("Mail not sent: inline PGP can't be used with attachments"));
189 return -1;
190 }
191 }
192 else if (mutt_istr_equal("flowed", mutt_param_get(&e->body->parameter, "format")))
193 {
194 if ((query_quadoption(_("Inline PGP can't be used with format=flowed. Revert to PGP/MIME?"),
195 NeoMutt->sub, "pgp_mime_auto")) != MUTT_YES)
196 {
197 mutt_error(_("Mail not sent: inline PGP can't be used with format=flowed"));
198 return -1;
199 }
200 }
201 else
202 {
203 /* they really want to send it inline... go for it */
204 if (!isendwin())
205 {
206 mutt_endwin();
207 puts(_("Invoking PGP..."));
208 }
209 pbody = crypt_pgp_traditional_encryptsign(e->body, security, keylist);
210 if (pbody)
211 {
212 e->body = pbody;
213 return 0;
214 }
215
216 /* otherwise inline won't work...ask for revert */
217 if (query_quadoption(_("Message can't be sent inline. Revert to using PGP/MIME?"),
218 NeoMutt->sub, "pgp_mime_auto") != MUTT_YES)
219 {
220 mutt_error(_("Mail not sent"));
221 return -1;
222 }
223 }
224
225 /* go ahead with PGP/MIME */
226 }
227
228 if (!isendwin())
229 mutt_endwin();
230
232 tmp_smime_pbody = e->body;
234 tmp_pgp_pbody = e->body;
235
236#ifdef CRYPT_BACKEND_GPGME
237 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
238 if (sign && c_crypt_use_pka)
239#else
240 if (sign)
241#endif
242 {
243 /* Set sender (necessary for e.g. PKA). */
244 const char *mailbox = NULL;
245 struct Address *from = TAILQ_FIRST(&e->env->from);
246 bool free_from = false;
247
248 if (!from)
249 {
250 free_from = true;
252 }
253
254 mailbox = buf_string(from->mailbox);
255 const struct Address *c_envelope_from_address = cs_subset_address(NeoMutt->sub, "envelope_from_address");
256 if (!mailbox && c_envelope_from_address)
257 mailbox = buf_string(c_envelope_from_address->mailbox);
258
259 if (((WithCrypto & APPLICATION_SMIME) != 0) && (security & APPLICATION_SMIME))
261 else if (((WithCrypto & APPLICATION_PGP) != 0) && (security & APPLICATION_PGP))
263
264 if (free_from)
265 mutt_addr_free(&from);
266 }
267
268 const bool c_crypt_protected_headers_write = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_write");
269 if (c_crypt_protected_headers_write)
270 {
271 const bool c_devel_security = cs_subset_bool(NeoMutt->sub, "devel_security");
272 struct Envelope *protected_headers = mutt_env_new();
273 mutt_env_set_subject(protected_headers, e->env->subject);
274 if (c_devel_security)
275 {
276 mutt_addrlist_copy(&protected_headers->return_path, &e->env->return_path, false);
277 mutt_addrlist_copy(&protected_headers->from, &e->env->from, false);
278 mutt_addrlist_copy(&protected_headers->to, &e->env->to, false);
279 mutt_addrlist_copy(&protected_headers->cc, &e->env->cc, false);
280 mutt_addrlist_copy(&protected_headers->sender, &e->env->sender, false);
281 mutt_addrlist_copy(&protected_headers->reply_to, &e->env->reply_to, false);
282 mutt_addrlist_copy(&protected_headers->mail_followup_to,
283 &e->env->mail_followup_to, false);
284 mutt_addrlist_copy(&protected_headers->x_original_to, &e->env->x_original_to, false);
285 mutt_str_replace(&protected_headers->message_id, e->env->message_id);
286 mutt_list_copy_tail(&protected_headers->references, &e->env->references);
287 mutt_list_copy_tail(&protected_headers->in_reply_to, &e->env->in_reply_to);
288 mutt_env_to_intl(protected_headers, NULL, NULL);
289 }
290 mutt_prepare_envelope(protected_headers, 0, NeoMutt->sub);
291
293 e->body->mime_headers = protected_headers;
294 mutt_param_set(&e->body->parameter, "protected-headers", "v1");
295 }
296
297#ifdef USE_AUTOCRYPT
298 /* A note about e->body->mime_headers. If postpone or send
299 * fails, the mime_headers is cleared out before returning to the
300 * compose menu. So despite the "robustness" code above and in the
301 * gen_gossip_list function below, mime_headers will not be set when
302 * entering mutt_protect().
303 *
304 * This is important to note because the user could toggle
305 * $crypt_protected_headers_write or $autocrypt off back in the
306 * compose menu. We don't want mutt_rfc822_write_header() to write
307 * stale data from one option if the other is set.
308 */
309 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
310 if (c_autocrypt && !postpone && (security & SEC_AUTOCRYPT))
311 {
313 }
314#endif
315
316 if (sign)
317 {
318 if (((WithCrypto & APPLICATION_SMIME) != 0) && (security & APPLICATION_SMIME))
319 {
320 tmp_pbody = crypt_smime_sign_message(e->body, &e->env->from);
321 if (!tmp_pbody)
322 goto bail;
323 pbody = tmp_pbody;
324 tmp_smime_pbody = tmp_pbody;
325 }
326
327 const bool c_pgp_retainable_sigs = cs_subset_bool(NeoMutt->sub, "pgp_retainable_sigs");
328 if (((WithCrypto & APPLICATION_PGP) != 0) && (security & APPLICATION_PGP) &&
329 (!(security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) || c_pgp_retainable_sigs))
330 {
331 tmp_pbody = crypt_pgp_sign_message(e->body, &e->env->from);
332 if (!tmp_pbody)
333 goto bail;
334
335 has_retainable_sig = true;
336 sign = SEC_NO_FLAGS;
337 pbody = tmp_pbody;
338 tmp_pgp_pbody = tmp_pbody;
339 }
340 }
341
342 if (security & (SEC_ENCRYPT | SEC_AUTOCRYPT))
343 {
344 if (((WithCrypto & APPLICATION_SMIME) != 0) && (security & APPLICATION_SMIME))
345 {
346 tmp_pbody = crypt_smime_build_smime_entity(tmp_smime_pbody, keylist);
347 if (!tmp_pbody)
348 {
349 /* signed ? free it! */
350 goto bail;
351 }
352 /* free tmp_body if messages was signed AND encrypted ... */
353 if ((tmp_smime_pbody != e->body) && (tmp_smime_pbody != tmp_pbody))
354 {
355 /* detach and don't delete e->body,
356 * which tmp_smime_pbody->parts after signing. */
357 tmp_smime_pbody->parts = tmp_smime_pbody->parts->next;
358 e->body->next = NULL;
359 mutt_body_free(&tmp_smime_pbody);
360 }
361 pbody = tmp_pbody;
362 }
363
364 if (((WithCrypto & APPLICATION_PGP) != 0) && (security & APPLICATION_PGP))
365 {
366 pbody = crypt_pgp_encrypt_message(e, tmp_pgp_pbody, keylist, sign, &e->env->from);
367 if (!pbody)
368 {
369 /* did we perform a retainable signature? */
370 if (has_retainable_sig)
371 {
372 /* remove the outer multipart layer */
373 tmp_pgp_pbody = mutt_remove_multipart(tmp_pgp_pbody);
374 /* get rid of the signature */
375 mutt_body_free(&tmp_pgp_pbody->next);
376 }
377
378 goto bail;
379 }
380
381 // destroy temporary signature envelope when doing retainable signatures.
382 if (has_retainable_sig)
383 {
384 tmp_pgp_pbody = mutt_remove_multipart(tmp_pgp_pbody);
385 mutt_body_free(&tmp_pgp_pbody->next);
386 }
387 }
388 }
389
390 if (pbody)
391 {
392 e->body = pbody;
393 return 0;
394 }
395
396bail:
398 mutt_param_delete(&e->body->parameter, "protected-headers");
399 return -1;
400}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:774
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition address.c:462
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
int mutt_autocrypt_generate_gossip_list(struct Email *e)
Create the gossip list headers.
Definition autocrypt.c:843
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition crypt.c:131
struct Body * crypt_smime_build_smime_entity(struct Body *b, char *certlist)
Wrapper for CryptModuleSpecs::smime_build_smime_entity()
Definition cryptglue.c:509
struct Body * crypt_smime_sign_message(struct Body *b, const struct AddressList *from)
Wrapper for CryptModuleSpecs::sign_message()
Definition cryptglue.c:498
struct Body * crypt_pgp_traditional_encryptsign(struct Body *b, SecurityFlags flags, char *keylist)
Wrapper for CryptModuleSpecs::pgp_traditional_encryptsign()
Definition cryptglue.c:306
struct Body * crypt_pgp_sign_message(struct Body *b, const struct AddressList *from)
Wrapper for CryptModuleSpecs::sign_message()
Definition cryptglue.c:339
void crypt_pgp_set_sender(const char *sender)
Wrapper for CryptModuleSpecs::set_sender()
Definition cryptglue.c:416
void crypt_smime_set_sender(const char *sender)
Wrapper for CryptModuleSpecs::set_sender()
Definition cryptglue.c:551
struct Body * crypt_pgp_encrypt_message(struct Email *e, struct Body *b, char *keylist, int sign, const struct AddressList *from)
Wrapper for CryptModuleSpecs::pgp_encrypt_message()
Definition cryptglue.c:350
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:153
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
int mutt_env_to_intl(struct Envelope *env, const char **tag, char **err)
Convert an Envelope's Address fields to Punycode format.
Definition envelope.c:350
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition envelope.c:45
void mutt_env_set_subject(struct Envelope *env, const char *subj)
Set both subject and real_subj to subj.
Definition envelope.c:68
#define mutt_error(...)
Definition logging2.h:94
void mutt_list_copy_tail(struct ListHead *dst, const struct ListHead *src)
Copy a list into another list.
Definition list.c:275
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
Definition multipart.c:133
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition lib.h:96
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition lib.h:85
#define PGP_INLINE
Email is inline PGP encrypted/signed.
Definition lib.h:109
#define SEC_NO_FLAGS
No flags are set.
Definition lib.h:86
#define SEC_ENCRYPT
Email is encrypted.
Definition lib.h:87
#define SEC_SIGN
Email is signed.
Definition lib.h:88
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition parameter.c:85
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition parameter.c:143
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition parameter.c:111
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
#define TAILQ_FIRST(head)
Definition queue.h:780
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition send.c:1405
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition sendlib.c:746
An email address.
Definition address.h:35
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
The body of an email.
Definition body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
struct Envelope * mime_headers
Memory hole protected headers.
Definition body.h:76
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
struct Body * next
next attachment in the list
Definition body.h:72
char * subtype
content-type subtype
Definition body.h:61
unsigned int type
content-type primary type, ContentType
Definition body.h:40
struct Envelope * env
Envelope information.
Definition email.h:68
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
struct Body * body
List of MIME parts.
Definition email.h:69
The header of an Email.
Definition envelope.h:57
struct AddressList return_path
Return path for the Email.
Definition envelope.h:58
char *const subject
Email's subject.
Definition envelope.h:70
struct AddressList to
Email's 'To' list.
Definition envelope.h:60
struct AddressList reply_to
Email's 'reply-to'.
Definition envelope.h:64
char * message_id
Message ID.
Definition envelope.h:73
struct AddressList x_original_to
Email's 'X-Original-to'.
Definition envelope.h:66
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition envelope.h:65
struct AddressList cc
Email's 'Cc' list.
Definition envelope.h:61
struct AddressList sender
Email's sender.
Definition envelope.h:63
struct ListHead references
message references (in reverse order)
Definition envelope.h:83
struct ListHead in_reply_to
in-reply-to header content
Definition envelope.h:84
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_is_multipart_signed()

SecurityFlags mutt_is_multipart_signed ( struct Body * b)

Is a message signed?

Parameters
bBody of email
Return values
numMessage is signed, see SecurityFlags
0Message is not signed (SEC_NO_FLAGS)

Definition at line 408 of file crypt.c.

409{
410 if (!b || (b->type != TYPE_MULTIPART) || !b->subtype || !mutt_istr_equal(b->subtype, "signed"))
411 {
412 return SEC_NO_FLAGS;
413 }
414
415 char *p = mutt_param_get(&b->parameter, "protocol");
416 if (!p)
417 return SEC_NO_FLAGS;
418
419 if (mutt_istr_equal(p, "multipart/mixed"))
420 return SEC_SIGN;
421
422 if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_istr_equal(p, "application/pgp-signature"))
423 {
424 return PGP_SIGN;
425 }
426
427 if (((WithCrypto & APPLICATION_SMIME) != 0) &&
428 (mutt_istr_equal(p, "application/x-pkcs7-signature") ||
429 mutt_istr_equal(p, "application/pkcs7-signature")))
430 {
431 return SMIME_SIGN;
432 }
433
434 return SEC_NO_FLAGS;
435}
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
#define PGP_SIGN
Email is PGP signed.
Definition lib.h:106
#define SMIME_SIGN
Email is S/MIME signed.
Definition lib.h:112
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_is_multipart_encrypted()

SecurityFlags mutt_is_multipart_encrypted ( struct Body * b)

Does the message have encrypted parts?

Parameters
bBody of email
Return values
numMessage has got encrypted parts, see SecurityFlags
0Message hasn't got encrypted parts (SEC_NO_FLAGS)

Definition at line 443 of file crypt.c.

444{
445 if ((WithCrypto & APPLICATION_PGP) == 0)
446 return SEC_NO_FLAGS;
447
448 char *p = NULL;
449
450 if (!b || (b->type != TYPE_MULTIPART) || !b->subtype ||
451 !mutt_istr_equal(b->subtype, "encrypted") ||
452 !(p = mutt_param_get(&b->parameter, "protocol")) ||
453 !mutt_istr_equal(p, "application/pgp-encrypted"))
454 {
455 return SEC_NO_FLAGS;
456 }
457
458 return PGP_ENCRYPT;
459}
#define PGP_ENCRYPT
Email is PGP encrypted.
Definition lib.h:105
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_is_valid_multipart_pgp_encrypted()

int mutt_is_valid_multipart_pgp_encrypted ( struct Body * b)

Is this a valid multi-part encrypted message?

Parameters
bBody of email
Return values
>0Message is valid, with encrypted parts, e.g. PGP_ENCRYPT
0Message hasn't got encrypted parts

Definition at line 467 of file crypt.c.

468{
470 return 0;
471
472 b = b->parts;
473 if (!b || (b->type != TYPE_APPLICATION) || !b->subtype ||
474 !mutt_istr_equal(b->subtype, "pgp-encrypted"))
475 {
476 return 0;
477 }
478
479 b = b->next;
480 if (!b || (b->type != TYPE_APPLICATION) || !b->subtype ||
481 !mutt_istr_equal(b->subtype, "octet-stream"))
482 {
483 return 0;
484 }
485
486 return PGP_ENCRYPT;
487}
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition crypt.c:443
@ TYPE_APPLICATION
Type: 'application/*'.
Definition mime.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_is_malformed_multipart_pgp_encrypted()

SecurityFlags mutt_is_malformed_multipart_pgp_encrypted ( struct Body * b)

Check for malformed layout.

Parameters
bBody of email
Return values
numSuccess, see SecurityFlags
0Error, (SEC_NO_FLAGS)

This checks for the malformed layout caused by MS Exchange in some cases:

<multipart/mixed>
<text/plain>
<application/pgp-encrypted> [BASE64-encoded]
<application/octet-stream> [BASE64-encoded]

Definition at line 504 of file crypt.c.

505{
507 return SEC_NO_FLAGS;
508
509 if (!b || (b->type != TYPE_MULTIPART) || !b->subtype || !mutt_istr_equal(b->subtype, "mixed"))
510 {
511 return SEC_NO_FLAGS;
512 }
513
514 b = b->parts;
515 if (!b || (b->type != TYPE_TEXT) || !b->subtype ||
516 !mutt_istr_equal(b->subtype, "plain") || (b->length != 0))
517 {
518 return SEC_NO_FLAGS;
519 }
520
521 b = b->next;
522 if (!b || (b->type != TYPE_APPLICATION) || !b->subtype ||
523 !mutt_istr_equal(b->subtype, "pgp-encrypted"))
524 {
525 return SEC_NO_FLAGS;
526 }
527
528 b = b->next;
529 if (!b || (b->type != TYPE_APPLICATION) || !b->subtype ||
530 !mutt_istr_equal(b->subtype, "octet-stream"))
531 {
532 return SEC_NO_FLAGS;
533 }
534
535 b = b->next;
536 if (b)
537 return SEC_NO_FLAGS;
538
539 return PGP_ENCRYPT;
540}
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_is_application_pgp()

SecurityFlags mutt_is_application_pgp ( const struct Body * b)

Does the message use PGP?

Parameters
bBody of email
Return values
>0Message uses PGP, e.g. PGP_ENCRYPT
0Message doesn't use PGP, (SEC_NO_FLAGS)

Definition at line 548 of file crypt.c.

549{
551 char *p = NULL;
552
553 if (b->type == TYPE_APPLICATION)
554 {
555 if (mutt_istr_equal(b->subtype, "pgp") || mutt_istr_equal(b->subtype, "x-pgp-message"))
556 {
557 p = mutt_param_get(&b->parameter, "x-action");
558 if (p && (mutt_istr_equal(p, "sign") || mutt_istr_equal(p, "signclear")))
559 {
560 t |= PGP_SIGN;
561 }
562
563 p = mutt_param_get(&b->parameter, "format");
564 if (p && mutt_istr_equal(p, "keys-only"))
565 {
566 t |= PGP_KEY;
567 }
568
569 if (t == SEC_NO_FLAGS)
570 t |= PGP_ENCRYPT; /* not necessarily correct, but... */
571 }
572
573 if (mutt_istr_equal(b->subtype, "pgp-signed"))
574 t |= PGP_SIGN;
575
576 if (mutt_istr_equal(b->subtype, "pgp-keys"))
577 t |= PGP_KEY;
578 }
579 else if ((b->type == TYPE_TEXT) && mutt_istr_equal("plain", b->subtype))
580 {
581 if (((p = mutt_param_get(&b->parameter, "x-mutt-action")) ||
582 (p = mutt_param_get(&b->parameter, "x-action")) ||
583 (p = mutt_param_get(&b->parameter, "action"))) &&
584 mutt_istr_startswith(p, "pgp-sign"))
585 {
586 t |= PGP_SIGN;
587 }
588 else if (p && mutt_istr_startswith(p, "pgp-encrypt"))
589 {
590 t |= PGP_ENCRYPT;
591 }
592 else if (p && mutt_istr_startswith(p, "pgp-keys"))
593 {
594 t |= PGP_KEY;
595 }
596 }
597 if (t)
598 t |= PGP_INLINE;
599
600 return t;
601}
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
#define PGP_KEY
Email contains a PGP key.
Definition lib.h:108
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_is_application_smime()

SecurityFlags mutt_is_application_smime ( struct Body * b)

Does the message use S/MIME?

Parameters
bBody of email
Return values
>0Message uses S/MIME, e.g. SMIME_ENCRYPT
0Message doesn't use S/MIME, (SEC_NO_FLAGS)

Definition at line 609 of file crypt.c.

610{
611 if (!b)
612 return SEC_NO_FLAGS;
613
614 if (((b->type & TYPE_APPLICATION) == 0) || !b->subtype)
615 return SEC_NO_FLAGS;
616
617 char *t = NULL;
618 bool complain = false;
619 /* S/MIME MIME types don't need x- anymore, see RFC2311 */
620 if (mutt_istr_equal(b->subtype, "x-pkcs7-mime") || mutt_istr_equal(b->subtype, "pkcs7-mime"))
621 {
622 t = mutt_param_get(&b->parameter, "smime-type");
623 if (t)
624 {
625 if (mutt_istr_equal(t, "enveloped-data"))
626 return SMIME_ENCRYPT;
627 if (mutt_istr_equal(t, "signed-data"))
628 return SMIME_SIGN | SMIME_OPAQUE;
629 return SEC_NO_FLAGS;
630 }
631 /* Netscape 4.7 uses
632 * Content-Description: S/MIME Encrypted Message
633 * instead of Content-Type parameter */
634 if (mutt_istr_equal(b->description, "S/MIME Encrypted Message"))
635 return SMIME_ENCRYPT;
636 complain = true;
637 }
638 else if (!mutt_istr_equal(b->subtype, "octet-stream"))
639 {
640 return SEC_NO_FLAGS;
641 }
642
643 t = mutt_param_get(&b->parameter, "name");
644
645 if (!t)
646 t = b->d_filename;
647 if (!t)
648 t = b->filename;
649 if (!t)
650 {
651 if (complain)
652 {
653 mutt_message(_("S/MIME messages with no hints on content are unsupported"));
654 }
655 return SEC_NO_FLAGS;
656 }
657
658 /* no .p7c, .p10 support yet. */
659
660 int len = mutt_str_len(t) - 4;
661 if ((len > 0) && (*(t + len) == '.'))
662 {
663 len++;
664 if (mutt_istr_equal((t + len), "p7m"))
665 {
666 const char *const c_smime_pkcs7_default_smime_type =
667 cs_subset_string(NeoMutt->sub, "smime_pkcs7_default_smime_type");
668 if (mutt_istr_equal(c_smime_pkcs7_default_smime_type, "signed"))
669 return SMIME_SIGN | SMIME_OPAQUE;
670 else if (mutt_istr_equal(c_smime_pkcs7_default_smime_type, "enveloped"))
671 return SMIME_ENCRYPT;
672 else
673 return SEC_NO_FLAGS;
674 }
675 else if (mutt_istr_equal((t + len), "p7s"))
676 {
677 return SMIME_SIGN | SMIME_OPAQUE;
678 }
679 }
680
681 return SEC_NO_FLAGS;
682}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
#define SMIME_OPAQUE
Email has an opaque S/MIME signature.
Definition lib.h:115
#define SMIME_ENCRYPT
Email is S/MIME encrypted.
Definition lib.h:111
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition body.h:56
char * description
content-description
Definition body.h:55
char * filename
When sending a message, this is the file to which this structure refers.
Definition body.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_query()

SecurityFlags crypt_query ( struct Body * b)

Check out the type of encryption used.

Parameters
bBody of email
Return values
numFlags, see SecurityFlags
0Error (SEC_NO_FLAGS)

Set the cached status values if there are any.

Definition at line 692 of file crypt.c.

693{
694 if (!WithCrypto || !b)
695 return SEC_NO_FLAGS;
696
698
699 if (b->type == TYPE_APPLICATION)
700 {
703
705 {
707 if (rc && b->goodsig)
708 rc |= SEC_GOODSIGN;
709 if (rc && b->badsig)
710 rc |= SEC_BADSIGN;
711 }
712 }
713 else if (((WithCrypto & APPLICATION_PGP) != 0) && (b->type == TYPE_TEXT))
714 {
716 if (rc && b->goodsig)
717 rc |= SEC_GOODSIGN;
718 }
719
720 if (b->type == TYPE_MULTIPART)
721 {
725
726 if (rc && b->goodsig)
727 rc |= SEC_GOODSIGN;
728#ifdef USE_AUTOCRYPT
729 if (rc && b->is_autocrypt)
730 rc |= SEC_AUTOCRYPT;
731#endif
732 }
733
734 if ((b->type == TYPE_MULTIPART) || (b->type == TYPE_MESSAGE))
735 {
736 SecurityFlags u = b->parts ? SEC_ALL_FLAGS : SEC_NO_FLAGS; /* Bits set in all parts */
737 SecurityFlags w = SEC_NO_FLAGS; /* Bits set in any part */
738
739 for (b = b->parts; b; b = b->next)
740 {
741 const SecurityFlags v = crypt_query(b);
742 u &= v;
743 w |= v;
744 }
745 rc |= u | (w & ~SEC_GOODSIGN);
746
747 if ((w & SEC_GOODSIGN) && !(u & SEC_GOODSIGN))
748 rc |= SEC_PARTSIGN;
749 }
750
751 return rc;
752}
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition crypt.c:408
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:609
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition crypt.c:504
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:548
SecurityFlags crypt_query(struct Body *b)
Check out the type of encryption used.
Definition crypt.c:692
@ TYPE_MESSAGE
Type: 'message/*'.
Definition mime.h:35
#define SEC_ALL_FLAGS
Mask for all security flags.
Definition lib.h:103
#define SEC_GOODSIGN
Email has a valid signature.
Definition lib.h:89
#define SEC_BADSIGN
Email has a bad signature.
Definition lib.h:90
#define SEC_PARTSIGN
Not all parts of the email is signed.
Definition lib.h:91
bool badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition body.h:43
bool is_autocrypt
Flag autocrypt-decrypted messages for replying.
Definition body.h:50
bool goodsig
Good cryptographic signature.
Definition body.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_write_signed()

int crypt_write_signed ( struct Body * b,
struct State * state,
const char * tempfile )

Write the message body/part.

Parameters
bBody to write
stateState to use
tempfileFile to write to
Return values
0Success
-1Error

Body/part A described by state state to the given TEMPFILE.

Definition at line 764 of file crypt.c.

765{
766 if (!WithCrypto)
767 return -1;
768
769 FILE *fp = mutt_file_fopen(tempfile, "w");
770 if (!fp)
771 {
772 mutt_perror("%s", tempfile);
773 return -1;
774 }
775
776 if (!mutt_file_seek(state->fp_in, b->hdr_offset, SEEK_SET))
777 {
778 mutt_file_fclose(&fp);
779 return -1;
780 }
781 size_t bytes = b->length + b->offset - b->hdr_offset;
782 bool hadcr = false;
783 while (bytes > 0)
784 {
785 const int c = fgetc(state->fp_in);
786 if (c == EOF)
787 break;
788
789 bytes--;
790
791 if (c == '\r')
792 {
793 hadcr = true;
794 }
795 else
796 {
797 if ((c == '\n') && !hadcr)
798 fputc('\r', fp);
799
800 hadcr = false;
801 }
802
803 fputc(c, fp);
804 }
805 mutt_file_fclose(&fp);
806
807 return 0;
808}
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
#define mutt_perror(...)
Definition logging2.h:95
LOFF_T offset
offset where the actual data begins
Definition body.h:52
long hdr_offset
Offset in stream where the headers begin.
Definition body.h:81
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:

◆ crypt_convert_to_7bit()

void crypt_convert_to_7bit ( struct Body * b)

Convert an email to 7bit encoding.

Parameters
bBody of email to convert

Definition at line 814 of file crypt.c.

815{
816 if (!WithCrypto)
817 return;
818
819 const bool c_pgp_strict_enc = cs_subset_bool(NeoMutt->sub, "pgp_strict_enc");
820 while (b)
821 {
822 if (b->type == TYPE_MULTIPART)
823 {
824 if (b->encoding != ENC_7BIT)
825 {
826 b->encoding = ENC_7BIT;
828 }
829 else if (((WithCrypto & APPLICATION_PGP) != 0) && c_pgp_strict_enc)
830 {
832 }
833 }
834 else if ((b->type == TYPE_MESSAGE) && !mutt_istr_equal(b->subtype, "delivery-status"))
835 {
836 if (b->encoding != ENC_7BIT)
838 }
839 else if (b->encoding == ENC_8BIT)
840 {
842 }
843 else if (b->encoding == ENC_BINARY)
844 {
845 b->encoding = ENC_BASE64;
846 }
847 else if (b->content && (b->encoding != ENC_BASE64) &&
848 (b->content->from || (b->content->space && c_pgp_strict_enc)))
849 {
851 }
852 b = b->next;
853 }
854}
void crypt_convert_to_7bit(struct Body *b)
Convert an email to 7bit encoding.
Definition crypt.c:814
@ ENC_7BIT
7-bit text
Definition mime.h:49
@ ENC_BINARY
Binary.
Definition mime.h:53
@ ENC_BASE64
Base-64 encoded text.
Definition mime.h:52
@ ENC_8BIT
8-bit text
Definition mime.h:50
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition mime.h:51
void mutt_message_to_7bit(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Convert an email's MIME parts to 7-bit.
Definition sendlib.c:258
struct Content * content
Detailed info about the content of the attachment.
Definition body.h:70
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition body.h:41
bool space
Whitespace at the end of lines?
Definition content.h:42
bool from
Has a line beginning with "From "?
Definition content.h:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_extract_keys_from_messages()

void crypt_extract_keys_from_messages ( struct Mailbox * m,
struct EmailArray * ea )

Extract keys from a message.

Parameters
mMailbox
eaArray of Emails to process

The extracted keys will be added to the user's keyring.

Definition at line 863 of file crypt.c.

864{
865 if (!WithCrypto)
866 return;
867
868 struct Buffer *tempfile = buf_pool_get();
869 buf_mktemp(tempfile);
870 FILE *fp_out = mutt_file_fopen(buf_string(tempfile), "w");
871 if (!fp_out)
872 {
873 mutt_perror("%s", buf_string(tempfile));
874 goto cleanup;
875 }
876
879
880 struct Email **ep = NULL;
881 ARRAY_FOREACH(ep, ea)
882 {
883 struct Email *e = *ep;
884 struct Message *msg = mx_msg_open(m, e);
885 if (!msg)
886 {
887 continue;
888 }
891 {
892 mx_msg_close(m, &msg);
893 mutt_file_fclose(&fp_out);
894 break;
895 }
896
897 if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
898 {
900 fflush(fp_out);
901
902 mutt_endwin();
903 puts(_("Trying to extract PGP keys...\n"));
905 }
906
908 {
909 const bool encrypt = e->security & SEC_ENCRYPT;
910 mutt_copy_message(fp_out, e, msg,
913 CH_NO_FLAGS, 0);
914 fflush(fp_out);
915
916 const char *mbox = NULL;
917 if (!TAILQ_EMPTY(&e->env->from))
918 {
920 mbox = buf_string(TAILQ_FIRST(&e->env->from)->mailbox);
921 }
922 else if (!TAILQ_EMPTY(&e->env->sender))
923 {
925 mbox = buf_string(TAILQ_FIRST(&e->env->sender)->mailbox);
926 }
927 if (mbox)
928 {
929 mutt_endwin();
930 puts(_("Trying to extract S/MIME certificates..."));
931 crypt_smime_invoke_import(buf_string(tempfile), mbox);
932 }
933 }
934 mx_msg_close(m, &msg);
935
936 rewind(fp_out);
937 }
938
939 mutt_file_fclose(&fp_out);
940 if (isendwin())
942
943 mutt_file_unlink(buf_string(tempfile));
944
946 OptDontHandlePgpKeys = false;
947
948cleanup:
949 buf_pool_release(&tempfile);
950}
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition alias.c:296
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition commands.c:627
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition copy_email.c:917
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition copy_email.h:40
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition copy_email.h:44
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition copy_email.h:48
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition copy_email.h:37
#define MUTT_CM_DECODE_CRYPT
Combination flag for decoding any kind of cryptography (PGP or S/MIME)
Definition copy_email.h:52
#define MUTT_CM_NOHEADER
Don't copy the message header.
Definition copy_email.h:38
#define CH_NO_FLAGS
No flags are set.
Definition copy_email.h:55
void crypt_pgp_invoke_import(const char *fname)
Wrapper for CryptModuleSpecs::pgp_invoke_import()
Definition cryptglue.c:376
void crypt_smime_invoke_import(const char *infile, const char *mailbox)
Wrapper for CryptModuleSpecs::smime_invoke_import()
Definition cryptglue.c:520
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:175
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
bool OptDontHandlePgpKeys
(pseudo) used to extract PGP keys
Definition globals.c:46
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1182
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1136
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define TAILQ_EMPTY(head)
Definition queue.h:778
String manipulation buffer.
Definition buffer.h:36
The envelope/body of an email.
Definition email.h:39
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
#define buf_mktemp(buf)
Definition tmp.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_get_keys()

int crypt_get_keys ( struct Email * e,
char ** keylist,
bool oppenc_mode )

Check we have all the keys we need.

Parameters
[in]eEmail with addresses to match
[out]keylistKeys needed
[in]oppenc_modeIf true, use opportunistic encryption
Return values
0Success
-1Error

Do a quick check to make sure that we can find all of the encryption keys if the user has requested this service. Return the list of keys in KEYLIST. If oppenc_mode is true, only keys that can be determined without prompting will be used.

Definition at line 966 of file crypt.c.

967{
968 if (!WithCrypto)
969 return 0;
970
971 struct AddressList addrlist = TAILQ_HEAD_INITIALIZER(addrlist);
972 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
973 const char *self_encrypt = NULL;
974
975 /* Do a quick check to make sure that we can find all of the encryption
976 * keys if the user has requested this service. */
977
978 *keylist = NULL;
979
980#ifdef USE_AUTOCRYPT
981 if (!oppenc_mode && (e->security & SEC_AUTOCRYPT))
982 {
984 return -1;
985 return 0;
986 }
987#endif
988
990 OptPgpCheckTrust = true;
991
992 mutt_addrlist_copy(&addrlist, &e->env->to, false);
993 mutt_addrlist_copy(&addrlist, &e->env->cc, false);
994 mutt_addrlist_copy(&addrlist, &e->env->bcc, false);
995 mutt_addrlist_qualify(&addrlist, fqdn);
996 mutt_addrlist_dedupe(&addrlist);
997
998 if (oppenc_mode || (e->security & SEC_ENCRYPT))
999 {
1000 if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
1001 {
1002 *keylist = crypt_pgp_find_keys(&addrlist, oppenc_mode);
1003 if (!*keylist)
1004 {
1005 mutt_addrlist_clear(&addrlist);
1006 return -1;
1007 }
1008 OptPgpCheckTrust = false;
1009 const bool c_pgp_self_encrypt = cs_subset_bool(NeoMutt->sub, "pgp_self_encrypt");
1010 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
1011 const enum QuadOption c_pgp_encrypt_self = cs_subset_quad(NeoMutt->sub, "pgp_encrypt_self");
1012 if (c_pgp_self_encrypt || (c_pgp_encrypt_self == MUTT_YES))
1013 self_encrypt = c_pgp_default_key;
1014 }
1015 if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME))
1016 {
1017 *keylist = crypt_smime_find_keys(&addrlist, oppenc_mode);
1018 if (!*keylist)
1019 {
1020 mutt_addrlist_clear(&addrlist);
1021 return -1;
1022 }
1023 const bool c_smime_self_encrypt = cs_subset_bool(NeoMutt->sub, "smime_self_encrypt");
1024 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
1025 const enum QuadOption c_smime_encrypt_self = cs_subset_quad(NeoMutt->sub, "smime_encrypt_self");
1026 if (c_smime_self_encrypt || (c_smime_encrypt_self == MUTT_YES))
1027 self_encrypt = c_smime_default_key;
1028 }
1029 }
1030
1031 if (!oppenc_mode && self_encrypt)
1032 {
1033 const size_t keylist_size = mutt_str_len(*keylist);
1034 MUTT_MEM_REALLOC(keylist, keylist_size + mutt_str_len(self_encrypt) + 2, char);
1035 sprintf(*keylist + keylist_size, " %s", self_encrypt);
1036 }
1037
1038 mutt_addrlist_clear(&addrlist);
1039
1040 return 0;
1041}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:685
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1469
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition address.c:1406
@ AUTOCRYPT_REC_NO
Do no use Autocrypt.
Definition lib.h:168
enum AutocryptRec mutt_autocrypt_ui_recommendation(const struct Email *e, char **keylist)
Get the recommended action for an Email.
Definition autocrypt.c:577
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition helpers.c:192
char * crypt_smime_find_keys(struct AddressList *addrlist, bool oppenc_mode)
Wrapper for CryptModuleSpecs::find_keys()
Definition cryptglue.c:487
char * crypt_pgp_find_keys(struct AddressList *addrlist, bool oppenc_mode)
Wrapper for CryptModuleSpecs::find_keys()
Definition cryptglue.c:328
bool OptPgpCheckTrust
(pseudo) used by dlg_pgp()
Definition globals.c:55
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
QuadOption
Possible values for a quad-option.
Definition quad.h:36
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:713
struct AddressList bcc
Email's 'Bcc' list.
Definition envelope.h:62
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_opportunistic_encrypt()

void crypt_opportunistic_encrypt ( struct Email * e)

Can all recipients be determined.

Parameters
eEmail

Check if all recipients keys can be automatically determined. Enable encryption if they can, otherwise disable encryption.

Definition at line 1050 of file crypt.c.

1051{
1052 if (!WithCrypto)
1053 return;
1054
1055 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
1056 if (!(c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT)))
1057 return;
1058
1059 char *pgpkeylist = NULL;
1060
1061 crypt_get_keys(e, &pgpkeylist, true);
1062 if (pgpkeylist)
1063 {
1064 e->security |= SEC_ENCRYPT;
1065 FREE(&pgpkeylist);
1066 }
1067 else
1068 {
1069 e->security &= ~SEC_ENCRYPT;
1070 }
1071}
int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
Check we have all the keys we need.
Definition crypt.c:966
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:95
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_fetch_signatures()

static void crypt_fetch_signatures ( struct Body *** b_sigs,
struct Body * b,
int * n )
static

Create an array of an emails parts.

Parameters
[out]b_sigsArray of Body parts
[in]bBody part to examine
[out]nCumulative count of parts

Definition at line 1079 of file crypt.c.

1080{
1081 if (!WithCrypto)
1082 return;
1083
1084 for (; b; b = b->next)
1085 {
1086 if (b->type == TYPE_MULTIPART)
1087 {
1088 crypt_fetch_signatures(b_sigs, b->parts, n);
1089 }
1090 else
1091 {
1092 if ((*n % 5) == 0)
1093 MUTT_MEM_REALLOC(b_sigs, *n + 6, struct Body *);
1094
1095 (*b_sigs)[(*n)++] = b;
1096 }
1097 }
1098}
static void crypt_fetch_signatures(struct Body ***b_sigs, struct Body *b, int *n)
Create an array of an emails parts.
Definition crypt.c:1079
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_should_hide_protected_subject()

bool mutt_should_hide_protected_subject ( struct Email * e)

Should NeoMutt hide the protected subject?

Parameters
eEmail to test
Return values
trueThe subject should be protected

Definition at line 1105 of file crypt.c.

1106{
1107 const bool c_crypt_protected_headers_write = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_write");
1108 const char *const c_crypt_protected_headers_subject =
1109 cs_subset_string(NeoMutt->sub, "crypt_protected_headers_subject");
1110 if (c_crypt_protected_headers_write && (e->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) &&
1111 !(e->security & SEC_INLINE) && c_crypt_protected_headers_subject)
1112 {
1113 return true;
1114 }
1115
1116 return false;
1117}
#define SEC_INLINE
Email has an inline signature.
Definition lib.h:94
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_get_fingerprint_or_id()

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.

Parameters
[in]pString to examine
[out]pphintStart of string to be passed to pgp_add_string_to_hints() or crypt_add_string_to_hints()
[out]pplStart of long key ID if detected, else NULL
[out]ppsStart of short key ID if detected, else NULL
Return values
ptrCopy of fingerprint, if any, stripped of all spaces. Must be FREE'd by caller
NULLOtherwise

Obtain pointers to fingerprint or short or long key ID, if any.

Upon return, at most one of return, *ppl and *pps pointers is non-NULL, indicating the longest fingerprint or ID found, if any.

Definition at line 1395 of file crypt.c.

1397{
1398 const char *ps = NULL, *pl = NULL, *phint = NULL;
1399 char *pfcopy = NULL, *s1 = NULL, *s2 = NULL;
1400 char c;
1401 int isid;
1402 size_t hexdigits;
1403
1404 /* User input may be partial name, fingerprint or short or long key ID,
1405 * independent of `$pgp_long_ids`.
1406 * Fingerprint without spaces is 40 hex digits (SHA-1) or 32 hex digits (MD5).
1407 * Strip leading "0x" for key ID detection and prepare pl and ps to indicate
1408 * if an ID was found and to simplify logic in the key loop's inner
1409 * condition of the caller. */
1410
1411 char *pf = mutt_str_skip_whitespace(p);
1412 if (mutt_istr_startswith(pf, "0x"))
1413 pf += 2;
1414
1415 /* Check if a fingerprint is given, must be hex digits only, blanks
1416 * separating groups of 4 hex digits are allowed. Also pre-check for ID. */
1417 isid = 2; /* unknown */
1418 hexdigits = 0;
1419 s1 = pf;
1420 do
1421 {
1422 c = *(s1++);
1423 if ((('0' <= c) && (c <= '9')) || (('A' <= c) && (c <= 'F')) ||
1424 (('a' <= c) && (c <= 'f')))
1425 {
1426 hexdigits++;
1427 if (isid == 2)
1428 isid = 1; /* it is an ID so far */
1429 }
1430 else if (c)
1431 {
1432 isid = 0; /* not an ID */
1433 if ((c == ' ') && ((hexdigits % 4) == 0))
1434 ; /* skip blank before or after 4 hex digits */
1435 else
1436 break; /* any other character or position */
1437 }
1438 } while (c);
1439
1440 /* If at end of input, check for correct fingerprint length and copy if. */
1441 pfcopy = (!c && ((hexdigits == 40) || (hexdigits == 32)) ? mutt_str_dup(pf) : NULL);
1442
1443 if (pfcopy)
1444 {
1445 /* Use pfcopy to strip all spaces from fingerprint and as hint. */
1446 s1 = pfcopy;
1447 s2 = pfcopy;
1448 do
1449 {
1450 *(s1++) = *(s2 = mutt_str_skip_whitespace(s2));
1451 } while (*(s2++));
1452
1453 phint = pfcopy;
1454 ps = NULL;
1455 pl = NULL;
1456 }
1457 else
1458 {
1459 phint = p;
1460 ps = NULL;
1461 pl = NULL;
1462 if (isid == 1)
1463 {
1464 if (mutt_str_len(pf) == 16)
1465 pl = pf; /* long key ID */
1466 else if (mutt_str_len(pf) == 8)
1467 ps = pf; /* short key ID */
1468 }
1469 }
1470
1471 *pphint = phint;
1472 *ppl = pl;
1473 *pps = ps;
1474 return pfcopy;
1475}
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition string.c:556
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_is_numerical_keyid()

bool crypt_is_numerical_keyid ( const char * s)

Is this a numerical keyid.

Parameters
sKey to test
Return values
trueKeyid is numeric

Check if a crypt-hook value is a key id.

Definition at line 1484 of file crypt.c.

1485{
1486 /* or should we require the "0x"? */
1487 if (mutt_strn_equal(s, "0x", 2))
1488 s += 2;
1489 if (strlen(s) % 8)
1490 return false;
1491 while (*s)
1492 if (!strchr("0123456789ABCDEFabcdef", *s++))
1493 return false;
1494
1495 return true;
1496}
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
+ Here is the call graph for this function:
+ Here is the caller graph for this function: