2 * Copyright notice from original mutt:
3 * Copyright (C) 1996,1997 Michael R. Elkins <me@mutt.org>
4 * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
5 * Copyright (C) 2001 Thomas Roessler <roessler@does-not-exist.org>
6 * Oliver Ehli <elmy@acm.org>
7 * Copyright (C) 2003 Werner Koch <wk@gnupg.org>
8 * Copyright (C) 2004 g10code GmbH
10 * This file is part of mutt-ng, see http://www.muttng.org/.
11 * It's licensed under the GNU General Public License,
12 * please see the file GPL in the top level source directory.
15 #include <lib-lib/lib-lib.h>
17 #include <lib-mime/mime.h>
18 #include <lib-ui/curses.h>
19 #include <lib-mx/mx.h>
26 int mutt_protect (HEADER * msg, char *keylist)
28 BODY *pbody = NULL, *tmp_pbody = NULL;
29 BODY *tmp_smime_pbody = NULL;
30 BODY *tmp_pgp_pbody = NULL;
31 int flags = msg->security;
36 tmp_smime_pbody = msg->content;
37 tmp_pgp_pbody = msg->content;
39 if (msg->security & SIGN) {
40 if (msg->security & APPLICATION_SMIME) {
41 if (!(tmp_pbody = crypt_smime_sign_message (msg->content)))
43 pbody = tmp_smime_pbody = tmp_pbody;
46 if ((msg->security & APPLICATION_PGP)
47 && (!(flags & ENCRYPT) || option (OPTPGPRETAINABLESIG))) {
48 if (!(tmp_pbody = crypt_pgp_sign_message (msg->content)))
52 pbody = tmp_pgp_pbody = tmp_pbody;
55 if ((msg->security & APPLICATION_SMIME)
56 && (msg->security & APPLICATION_PGP)) {
57 /* here comes the draft ;-) */
62 if (msg->security & ENCRYPT) {
63 if ((msg->security & APPLICATION_SMIME)) {
64 if (!(tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody,
66 /* signed ? free it! */
69 /* free tmp_body if messages was signed AND encrypted ... */
70 if (tmp_smime_pbody != msg->content && tmp_smime_pbody != tmp_pbody) {
71 /* detatch and dont't delete msg->content,
72 which tmp_smime_pbody->parts after signing. */
73 tmp_smime_pbody->parts = tmp_smime_pbody->parts->next;
74 msg->content->next = NULL;
75 body_list_wipe(&tmp_smime_pbody);
80 if ((msg->security & APPLICATION_PGP)) {
81 if (!(pbody = crypt_pgp_encrypt_message (tmp_pgp_pbody, keylist,
84 /* did we perform a retainable signature? */
85 if (flags != msg->security) {
86 /* remove the outer multipart layer */
87 tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
88 /* get rid of the signature */
89 body_list_wipe(&tmp_pgp_pbody->next);
95 /* destroy temporary signature envelope when doing retainable
99 if (flags != msg->security) {
100 tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
101 body_list_wipe(&tmp_pgp_pbody->next);
107 msg->content = pbody;
113 int crypt_query (BODY * m)
120 if (m->type == TYPEAPPLICATION) {
121 t |= mutt_is_application_pgp (m);
123 t |= mutt_is_application_smime (m);
129 else if (m->type == TYPETEXT) {
130 t |= mutt_is_application_pgp (m);
135 if (m->type == TYPEMULTIPART) {
136 t |= mutt_is_multipart_encrypted (m);
137 t |= mutt_is_multipart_signed (m);
143 if (m->type == TYPEMULTIPART || m->type == TYPEMESSAGE) {
147 u = m->parts ? 0xffffffff : 0; /* Bits set in all parts */
148 w = 0; /* Bits set in any part */
150 for (p = m->parts; p; p = p->next) {
155 t |= u | (w & ~GOODSIGN);
157 if ((w & GOODSIGN) && !(u & GOODSIGN))
165 static void crypt_write_signed(BODY * a, STATE * s, FILE *fp)
171 fseeko (s->fpin, a->hdr_offset, 0);
172 bytes = a->length + a->offset - a->hdr_offset;
175 if ((c = fgetc (s->fpin)) == EOF)
183 if (c == '\n' && !hadcr)
194 void convert_to_7bit (BODY * a)
197 if (a->type == TYPEMULTIPART) {
198 if (a->encoding != ENC7BIT) {
199 a->encoding = ENC7BIT;
200 convert_to_7bit (a->parts);
202 convert_to_7bit (a->parts);
205 else if (a->type == TYPEMESSAGE &&
206 m_strcasecmp(a->subtype, "delivery-status")) {
207 if (a->encoding != ENC7BIT)
208 mutt_message_to_7bit (a, NULL);
210 else if (a->encoding == ENC8BIT)
211 a->encoding = ENCQUOTEDPRINTABLE;
212 else if (a->encoding == ENCBINARY)
213 a->encoding = ENCBASE64;
214 else if (a->content && a->encoding != ENCBASE64 &&
215 (a->content->from || a->content->space))
216 a->encoding = ENCQUOTEDPRINTABLE;
222 static void extract_keys_aux(FILE *fpout, HEADER *h)
224 mutt_parse_mime_message (Context, h);
227 if (h->security & APPLICATION_PGP) {
228 mutt_copy_message(fpout, Context, h, M_CM_DECODE | M_CM_CHARCONV, 0);
231 mutt_endwin (_("Trying to extract PGP keys...\n"));
234 if (h->security & APPLICATION_SMIME) {
235 if (h->security & ENCRYPT)
236 mutt_copy_message (fpout, Context, h, M_CM_NOHEADER
237 | M_CM_DECODE_CRYPT | M_CM_DECODE_SMIME, 0);
239 mutt_copy_message(fpout, Context, h, 0, 0);
242 mutt_message (_("Trying to extract S/MIME certificates...\n"));
246 crypt_invoke_import(fpout, h->security & APPLICATION_SMIME);
249 void crypt_extract_keys_from_messages(HEADER * h)
251 FILE *tmpfp = tmpfile();
253 mutt_error(_("Could not create temporary file"));
257 set_option(OPTDONTHANDLEPGPKEYS);
260 for (i = 0; i < Context->vcount; i++) {
261 if (!Context->hdrs[Context->v2r[i]]->tagged)
263 extract_keys_aux(tmpfp, Context->hdrs[Context->v2r[i]]);
266 extract_keys_aux(tmpfp, h);
268 unset_option(OPTDONTHANDLEPGPKEYS);
272 mutt_any_key_to_continue(NULL);
277 int crypt_get_keys (HEADER * msg, char **keylist)
279 /* Do a quick check to make sure that we can find all of the encryption
280 * keys if the user has requested this service.
283 set_option (OPTPGPCHECKTRUST);
287 if (msg->security & ENCRYPT) {
288 if (msg->security & APPLICATION_PGP) {
289 if ((*keylist = crypt_pgp_findkeys (msg->env->to, msg->env->cc,
290 msg->env->bcc)) == NULL)
292 unset_option (OPTPGPCHECKTRUST);
294 if (msg->security & APPLICATION_SMIME) {
295 if ((*keylist = crypt_smime_findkeys (msg->env->to, msg->env->cc,
296 msg->env->bcc)) == NULL)
306 static void crypt_fetch_signatures (BODY ***signatures, BODY * a, int *n)
308 for (; a; a = a->next) {
309 if (a->type == TYPEMULTIPART)
310 crypt_fetch_signatures (signatures, a->parts, n);
313 p_realloc(signatures, *n + 6);
315 (*signatures)[(*n)++] = a;
322 * This routine verifies a "multipart/signed" body.
325 int mutt_signed_handler (BODY * a, STATE * s)
327 char tempfile[_POSIX_PATH_MAX];
330 int protocol_major = TYPEOTHER;
331 char *protocol_minor = NULL;
334 BODY **signatures = NULL;
340 protocol = parameter_getval(a->parameter, "protocol");
343 /* extract the protocol information */
349 if ((protocol_minor = strchr (protocol, '/')))
352 m_strcpy(major, sizeof(major), protocol);
353 if ((t = strchr (major, '/')))
356 protocol_major = mutt_check_mime_type (major);
359 /* consistency check */
361 if (!(a && a->next && a->next->type == protocol_major &&
362 !m_strcasecmp(a->next->subtype, protocol_minor))) {
363 state_attach_puts (_("[-- Error: "
364 "Inconsistent multipart/signed structure! --]\n\n"),
366 return mutt_body_handler (a, s);
370 if (protocol_major == TYPEAPPLICATION
371 && !m_strcasecmp(protocol_minor, "pgp-signature"));
372 else if (protocol_major == TYPEAPPLICATION
373 && !(m_strcasecmp(protocol_minor, "x-pkcs7-signature")
374 && m_strcasecmp(protocol_minor, "pkcs7-signature")));
375 else if (protocol_major == TYPEMULTIPART
376 && !m_strcasecmp(protocol_minor, "mixed"));
378 state_printf (s, _("[-- Error: "
379 "Unknown multipart/signed protocol %s! --]\n\n"),
381 return mutt_body_handler (a, s);
384 if (s->flags & M_DISPLAY) {
386 crypt_fetch_signatures (&signatures, a->next, &sigcnt);
389 tempfp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
391 mutt_error(_("Could not create temporary file"));
393 crypt_write_signed(a, s, tempfp);
395 for (i = 0; i < sigcnt; i++) {
396 if (signatures[i]->type == TYPEAPPLICATION
397 && !m_strcasecmp(signatures[i]->subtype, "pgp-signature")) {
398 if (crypt_pgp_verify_one (signatures[i], s, tempfile) != 0)
404 if (signatures[i]->type == TYPEAPPLICATION
405 && (!m_strcasecmp(signatures[i]->subtype, "x-pkcs7-signature")
406 || !m_strcasecmp(signatures[i]->subtype, "pkcs7-signature")))
408 if (crypt_smime_verify_one (signatures[i], s, tempfile) != 0)
414 state_printf (s, _("[-- Warning: "
415 "We can't verify %s/%s signatures. --]\n\n"),
416 TYPE (signatures[i]), signatures[i]->subtype);
420 mutt_unlink (tempfile);
422 b->goodsig = goodsig;
423 b->badsig = !goodsig;
425 /* Now display the signed body */
426 state_attach_puts (_("[-- The following data is signed --]\n\n"), s);
429 p_delete(&signatures);
432 state_attach_puts (_("[-- Warning: Can't find any signatures. --]\n\n"),
436 rc = mutt_body_handler (a, s);
438 if (s->flags & M_DISPLAY && sigcnt)
439 state_attach_puts (_("\n[-- End of signed data --]\n"), s);