mutt stable branch with some hacks
1/*
2 * Copyright (C) 2001-2002 Oliver Ehli <elmy@acm.org>
3 * Copyright (C) 2002 Mike Schiraldi <raldi@research.netsol.com>
4 * Copyright (C) 2004 g10 Code GmbH
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21#if HAVE_CONFIG_H
22# include "config.h"
23#endif
24
25#include "mutt.h"
26#include "mutt_curses.h"
27#include "mutt_menu.h"
28#include "smime.h"
29#include "mime.h"
30#include "copy.h"
31
32#include <sys/wait.h>
33#include <string.h>
34#include <stdlib.h>
35#include <unistd.h>
36#include <sys/stat.h>
37#include <errno.h>
38#include <ctype.h>
39
40#ifdef HAVE_LOCALE_H
41#include <locale.h>
42#endif
43
44#ifdef HAVE_SYS_TIME_H
45# include <sys/time.h>
46#endif
47
48#ifdef HAVE_SYS_RESOURCE_H
49# include <sys/resource.h>
50#endif
51
52#ifdef CRYPT_BACKEND_CLASSIC_SMIME
53
54#include "mutt_crypt.h"
55
56struct smime_command_context {
57 const char *key; /* %k */
58 const char *cryptalg; /* %a */
59 const char *digestalg; /* %d */
60 const char *fname; /* %f */
61 const char *sig_fname; /* %s */
62 const char *certificates; /* %c */
63 const char *intermediates; /* %i */
64};
65
66
67char SmimePass[STRING];
68time_t SmimeExptime = 0; /* when does the cached passphrase expire? */
69
70
71static char SmimeKeyToUse[_POSIX_PATH_MAX] = { 0 };
72static char SmimeCertToUse[_POSIX_PATH_MAX];
73static char SmimeIntermediateToUse[_POSIX_PATH_MAX];
74
75
76void smime_free_key (smime_key_t **keylist)
77{
78 smime_key_t *key;
79
80 if (!keylist)
81 return;
82
83 while (*keylist)
84 {
85 key = *keylist;
86 *keylist = (*keylist)->next;
87
88 FREE (&key->email);
89 FREE (&key->hash);
90 FREE (&key->label);
91 FREE (&key->issuer);
92 FREE (&key);
93 }
94}
95
96static smime_key_t *smime_copy_key (smime_key_t *key)
97{
98 smime_key_t *copy;
99
100 if (!key)
101 return NULL;
102
103 copy = safe_calloc (sizeof (smime_key_t), 1);
104 copy->email = safe_strdup(key->email);
105 copy->hash = safe_strdup(key->hash);
106 copy->label = safe_strdup(key->label);
107 copy->issuer = safe_strdup(key->issuer);
108 copy->trust = key->trust;
109 copy->flags = key->flags;
110
111 return copy;
112}
113
114
115/*
116 * Queries and passphrase handling.
117 */
118
119
120
121
122/* these are copies from pgp.c */
123
124
125void smime_void_passphrase (void)
126{
127 memset (SmimePass, 0, sizeof (SmimePass));
128 SmimeExptime = 0;
129}
130
131int smime_valid_passphrase (void)
132{
133 time_t now = time (NULL);
134
135 if (now < SmimeExptime)
136 /* Use cached copy. */
137 return 1;
138
139 smime_void_passphrase();
140
141 if (mutt_get_password (_("Enter S/MIME passphrase:"), SmimePass, sizeof (SmimePass)) == 0)
142 {
143 SmimeExptime = time (NULL) + SmimeTimeout;
144 return (1);
145 }
146 else
147 SmimeExptime = 0;
148
149 return 0;
150}
151
152
153/*
154 * The OpenSSL interface
155 */
156
157/* This is almost identical to ppgp's invoking interface. */
158
159static const char *_mutt_fmt_smime_command (char *dest,
160 size_t destlen,
161 size_t col,
162 int cols,
163 char op,
164 const char *src,
165 const char *prefix,
166 const char *ifstring,
167 const char *elsestring,
168 unsigned long data,
169 format_flag flags)
170{
171 char fmt[16];
172 struct smime_command_context *cctx = (struct smime_command_context *) data;
173 int optional = (flags & MUTT_FORMAT_OPTIONAL);
174
175 switch (op)
176 {
177 case 'C':
178 {
179 if (!optional)
180 {
181 char path[_POSIX_PATH_MAX];
182 char buf1[LONG_STRING], buf2[LONG_STRING];
183 struct stat sb;
184
185 strfcpy (path, NONULL (SmimeCALocation), sizeof (path));
186 mutt_expand_path (path, sizeof (path));
187 mutt_quote_filename (buf1, sizeof (buf1), path);
188
189 if (stat (path, &sb) != 0 || !S_ISDIR (sb.st_mode))
190 snprintf (buf2, sizeof (buf2), "-CAfile %s", buf1);
191 else
192 snprintf (buf2, sizeof (buf2), "-CApath %s", buf1);
193
194 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
195 snprintf (dest, destlen, fmt, buf2);
196 }
197 else if (!SmimeCALocation)
198 optional = 0;
199 break;
200 }
201
202 case 'c':
203 { /* certificate (list) */
204 if (!optional) {
205 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
206 snprintf (dest, destlen, fmt, NONULL(cctx->certificates));
207 }
208 else if (!cctx->certificates)
209 optional = 0;
210 break;
211 }
212
213 case 'i':
214 { /* intermediate certificates */
215 if (!optional) {
216 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
217 snprintf (dest, destlen, fmt, NONULL(cctx->intermediates));
218 }
219 else if (!cctx->intermediates)
220 optional = 0;
221 break;
222 }
223
224 case 's':
225 { /* detached signature */
226 if (!optional)
227 {
228 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
229 snprintf (dest, destlen, fmt, NONULL (cctx->sig_fname));
230 }
231 else if (!cctx->sig_fname)
232 optional = 0;
233 break;
234 }
235
236 case 'k':
237 { /* private key */
238 if (!optional)
239 {
240 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
241 snprintf (dest, destlen, fmt, NONULL (cctx->key));
242 }
243 else if (!cctx->key)
244 optional = 0;
245 break;
246 }
247
248 case 'a':
249 { /* algorithm for encryption */
250 if (!optional) {
251 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
252 snprintf (dest, destlen, fmt, NONULL (cctx->cryptalg));
253 }
254 else if (!cctx->key)
255 optional = 0;
256 break;
257 }
258
259 case 'f':
260 { /* file to process */
261 if (!optional)
262 {
263 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
264 snprintf (dest, destlen, fmt, NONULL (cctx->fname));
265 }
266 else if (!cctx->fname)
267 optional = 0;
268 break;
269 }
270
271 case 'd':
272 { /* algorithm for the signature message digest */
273 if (!optional) {
274 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
275 snprintf (dest, destlen, fmt, NONULL (cctx->digestalg));
276 }
277 else if (!cctx->key)
278 optional = 0;
279 break;
280 }
281
282 default:
283 *dest = '\0';
284 break;
285 }
286
287 if (optional)
288 mutt_FormatString (dest, destlen, col, cols, ifstring, _mutt_fmt_smime_command,
289 data, 0);
290 else if (flags & MUTT_FORMAT_OPTIONAL)
291 mutt_FormatString (dest, destlen, col, cols, elsestring, _mutt_fmt_smime_command,
292 data, 0);
293
294 return (src);
295}
296
297
298
299static void mutt_smime_command (char *d, size_t dlen,
300 struct smime_command_context *cctx, const char *fmt)
301{
302 mutt_FormatString (d, dlen, 0, MuttIndexWindow->cols, NONULL(fmt), _mutt_fmt_smime_command,
303 (unsigned long) cctx, 0);
304 dprint (2,(debugfile, "mutt_smime_command: %s\n", d));
305}
306
307
308
309
310static pid_t smime_invoke (FILE **smimein, FILE **smimeout, FILE **smimeerr,
311 int smimeinfd, int smimeoutfd, int smimeerrfd,
312 const char *fname,
313 const char *sig_fname,
314 const char *cryptalg,
315 const char *digestalg,
316 const char *key,
317 const char *certificates,
318 const char *intermediates,
319 const char *format)
320{
321 struct smime_command_context cctx;
322 char cmd[HUGE_STRING];
323
324 memset (&cctx, 0, sizeof (cctx));
325
326 if (!format || !*format)
327 return (pid_t) -1;
328
329 cctx.fname = fname;
330 cctx.sig_fname = sig_fname;
331 cctx.key = key;
332 cctx.cryptalg = cryptalg;
333 cctx.digestalg = digestalg;
334 cctx.certificates = certificates;
335 cctx.intermediates = intermediates;
336
337 mutt_smime_command (cmd, sizeof (cmd), &cctx, format);
338
339 return mutt_create_filter_fd (cmd, smimein, smimeout, smimeerr,
340 smimeinfd, smimeoutfd, smimeerrfd);
341}
342
343
344
345
346
347
348/*
349 * Key and certificate handling.
350 */
351
352
353static char *smime_key_flags (int flags)
354{
355 static char buff[3];
356
357 if (!(flags & KEYFLAG_CANENCRYPT))
358 buff[0] = '-';
359 else
360 buff[0] = 'e';
361
362 if (!(flags & KEYFLAG_CANSIGN))
363 buff[1] = '-';
364 else
365 buff[1] = 's';
366
367 buff[2] = '\0';
368
369 return buff;
370}
371
372
373static void smime_entry (char *s, size_t l, MUTTMENU * menu, int num)
374{
375 smime_key_t **Table = (smime_key_t **) menu->data;
376 smime_key_t *this = Table[num];
377 char* truststate;
378 switch(this->trust) {
379 case 't':
380 truststate = N_("Trusted ");
381 break;
382 case 'v':
383 truststate = N_("Verified ");
384 break;
385 case 'u':
386 truststate = N_("Unverified");
387 break;
388 case 'e':
389 truststate = N_("Expired ");
390 break;
391 case 'r':
392 truststate = N_("Revoked ");
393 break;
394 case 'i':
395 truststate = N_("Invalid ");
396 break;
397 default:
398 truststate = N_("Unknown ");
399 }
400 snprintf(s, l, " 0x%s %s %s %-35.35s %s", this->hash,
401 smime_key_flags (this->flags), truststate, this->email, this->label);
402}
403
404
405static smime_key_t *smime_select_key (smime_key_t *keys, char *query)
406{
407 smime_key_t **table = NULL;
408 int table_size = 0;
409 int table_index = 0;
410 smime_key_t *key = NULL;
411 smime_key_t *selected_key = NULL;
412 char helpstr[LONG_STRING];
413 char buf[LONG_STRING];
414 char title[256];
415 MUTTMENU* menu;
416 char *s = "";
417 int done = 0;
418
419 for (table_index = 0, key = keys; key; key = key->next)
420 {
421 if (table_index == table_size)
422 {
423 table_size += 5;
424 safe_realloc (&table, sizeof (smime_key_t *) * table_size);
425 }
426
427 table[table_index++] = key;
428 }
429
430 snprintf(title, sizeof(title), _("S/MIME certificates matching \"%s\"."),
431 query);
432
433 /* Make Helpstring */
434 helpstr[0] = 0;
435 mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_SMIME, OP_EXIT);
436 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
437 mutt_make_help (buf, sizeof (buf), _("Select "), MENU_SMIME,
438 OP_GENERIC_SELECT_ENTRY);
439 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
440 mutt_make_help (buf, sizeof(buf), _("Help"), MENU_SMIME, OP_HELP);
441 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
442
443 /* Create the menu */
444 menu = mutt_new_menu(MENU_SMIME);
445 menu->max = table_index;
446 menu->make_entry = smime_entry;
447 menu->help = helpstr;
448 menu->data = table;
449 menu->title = title;
450 /* sorting keys might be done later - TODO */
451
452 mutt_clear_error();
453
454 done = 0;
455 while (!done)
456 {
457 switch (mutt_menuLoop (menu))
458 {
459 case OP_GENERIC_SELECT_ENTRY:
460 if (table[menu->current]->trust != 't')
461 {
462 switch (table[menu->current]->trust)
463 {
464 case 'i':
465 case 'r':
466 case 'e':
467 s = N_("ID is expired/disabled/revoked.");
468 break;
469 case 'u':
470 s = N_("ID has undefined validity.");
471 break;
472 case 'v':
473 s = N_("ID is not trusted.");
474 break;
475 }
476
477 snprintf (buf, sizeof (buf), _("%s Do you really want to use the key?"),
478 _(s));
479
480 if (mutt_yesorno (buf, MUTT_NO) != MUTT_YES)
481 {
482 mutt_clear_error ();
483 break;
484 }
485 }
486
487 selected_key = table[menu->current];
488 done = 1;
489 break;
490 case OP_EXIT:
491 done = 1;
492 break;
493 }
494 }
495
496 mutt_menuDestroy (&menu);
497 FREE (&table);
498 set_option (OPTNEEDREDRAW);
499
500 return selected_key;
501}
502
503static smime_key_t *smime_parse_key(char *buf)
504{
505 smime_key_t *key;
506 char *pend, *p;
507 int field = 0;
508
509 key = safe_calloc (sizeof (smime_key_t), 1);
510
511 for (p = buf; p; p = pend)
512 {
513 /* Some users manually maintain their .index file, and use a tab
514 * as a delimiter, which the old parsing code (using fscanf)
515 * happened to allow. smime_keys.pl uses a space, so search for both.
516 */
517 if ((pend = strchr (p, ' ')) || (pend = strchr (p, '\t')) ||
518 (pend = strchr (p, '\n')))
519 *pend++ = 0;
520
521 /* For backward compatibility, don't count consecutive delimiters
522 * as an empty field.
523 */
524 if (!*p)
525 continue;
526
527 field++;
528
529 switch (field)
530 {
531 case 1: /* mailbox */
532 key->email = safe_strdup (p);
533 break;
534 case 2: /* hash */
535 key->hash = safe_strdup (p);
536 break;
537 case 3: /* label */
538 key->label = safe_strdup (p);
539 break;
540 case 4: /* issuer */
541 key->issuer = safe_strdup (p);
542 break;
543 case 5: /* trust */
544 key->trust = *p;
545 break;
546 case 6: /* purpose */
547 while (*p)
548 {
549 switch (*p++)
550 {
551 case 'e':
552 key->flags |= KEYFLAG_CANENCRYPT;
553 break;
554
555 case 's':
556 key->flags |= KEYFLAG_CANSIGN;
557 break;
558 }
559 }
560 break;
561 }
562 }
563
564 /* Old index files could be missing issuer, trust, and purpose,
565 * but anything less than that is an error. */
566 if (field < 3)
567 {
568 smime_free_key (&key);
569 return NULL;
570 }
571
572 if (field < 4)
573 key->issuer = safe_strdup ("?");
574
575 if (field < 5)
576 key->trust = 't';
577
578 if (field < 6)
579 key->flags = (KEYFLAG_CANENCRYPT | KEYFLAG_CANSIGN);
580
581 return key;
582}
583
584static smime_key_t *smime_get_candidates(char *search, short public)
585{
586 char index_file[_POSIX_PATH_MAX];
587 FILE *fp;
588 char buf[LONG_STRING];
589 smime_key_t *key, *results, **results_end;
590
591 results = NULL;
592 results_end = &results;
593
594 snprintf(index_file, sizeof (index_file), "%s/.index",
595 public ? NONULL(SmimeCertificates) : NONULL(SmimeKeys));
596
597 if ((fp = safe_fopen (index_file, "r")) == NULL)
598 {
599 mutt_perror (index_file);
600 return NULL;
601 }
602
603 while (fgets (buf, sizeof (buf), fp))
604 {
605 if ((! *search) || mutt_stristr (buf, search))
606 {
607 key = smime_parse_key (buf);
608 if (key)
609 {
610 *results_end = key;
611 results_end = &key->next;
612 }
613 }
614 }
615
616 safe_fclose (&fp);
617
618 return results;
619}
620
621/* Returns the first matching key record, without prompting or checking of
622 * abilities or trust.
623 */
624static smime_key_t *smime_get_key_by_hash(char *hash, short public)
625{
626 smime_key_t *results, *result;
627 smime_key_t *match = NULL;
628
629 results = smime_get_candidates(hash, public);
630 for (result = results; result; result = result->next)
631 {
632 if (mutt_strcasecmp (hash, result->hash) == 0)
633 {
634 match = smime_copy_key (result);
635 break;
636 }
637 }
638
639 smime_free_key (&results);
640
641 return match;
642}
643
644static smime_key_t *smime_get_key_by_addr(char *mailbox, short abilities, short public, short may_ask)
645{
646 smime_key_t *results, *result;
647 smime_key_t *matches = NULL;
648 smime_key_t **matches_end = &matches;
649 smime_key_t *match;
650 smime_key_t *trusted_match = NULL;
651 smime_key_t *valid_match = NULL;
652 smime_key_t *return_key = NULL;
653 int multi_trusted_matches = 0;
654
655 if (! mailbox)
656 return NULL;
657
658 results = smime_get_candidates(mailbox, public);
659 for (result = results; result; result = result->next)
660 {
661 if (abilities && !(result->flags & abilities))
662 {
663 continue;
664 }
665
666 if (mutt_strcasecmp (mailbox, result->email) == 0)
667 {
668 match = smime_copy_key (result);
669 *matches_end = match;
670 matches_end = &match->next;
671
672 if (match->trust == 't')
673 {
674 if (trusted_match &&
675 (mutt_strcasecmp (match->hash, trusted_match->hash) != 0))
676 {
677 multi_trusted_matches = 1;
678 }
679 trusted_match = match;
680 }
681 else if ((match->trust == 'u') || (match->trust == 'v'))
682 {
683 valid_match = match;
684 }
685 }
686 }
687
688 smime_free_key (&results);
689
690 if (matches)
691 {
692 if (! may_ask)
693 {
694 if (trusted_match)
695 return_key = smime_copy_key (trusted_match);
696 else if (valid_match)
697 return_key = smime_copy_key (valid_match);
698 else
699 return_key = NULL;
700 }
701 else if (trusted_match && !multi_trusted_matches)
702 {
703 return_key = smime_copy_key (trusted_match);
704 }
705 else
706 {
707 return_key = smime_copy_key (smime_select_key (matches, mailbox));
708 }
709
710 smime_free_key (&matches);
711 }
712
713 return return_key;
714}
715
716static smime_key_t *smime_get_key_by_str(char *str, short abilities, short public)
717{
718 smime_key_t *results, *result;
719 smime_key_t *matches = NULL;
720 smime_key_t **matches_end = &matches;
721 smime_key_t *match;
722 smime_key_t *return_key = NULL;
723
724 if (! str)
725 return NULL;
726
727 results = smime_get_candidates(str, public);
728 for (result = results; result; result = result->next)
729 {
730 if (abilities && !(result->flags & abilities))
731 {
732 continue;
733 }
734
735 if ((mutt_strcasecmp (str, result->hash) == 0) ||
736 mutt_stristr(result->email, str) ||
737 mutt_stristr(result->label, str))
738 {
739 match = smime_copy_key (result);
740 *matches_end = match;
741 matches_end = &match->next;
742 }
743 }
744
745 smime_free_key (&results);
746
747 if (matches)
748 {
749 return_key = smime_copy_key (smime_select_key (matches, str));
750 smime_free_key (&matches);
751 }
752
753 return return_key;
754}
755
756
757smime_key_t *smime_ask_for_key(char *prompt, short abilities, short public)
758{
759 smime_key_t *key;
760 char resp[SHORT_STRING];
761
762 if (!prompt) prompt = _("Enter keyID: ");
763
764 mutt_clear_error ();
765
766 FOREVER
767 {
768 resp[0] = 0;
769 if (mutt_get_field (prompt, resp, sizeof (resp), MUTT_CLEAR) != 0)
770 return NULL;
771
772 if ((key = smime_get_key_by_str (resp, abilities, public)))
773 return key;
774
775 BEEP ();
776 }
777}
778
779
780
781/*
782 This sets the '*ToUse' variables for an upcoming decryption, where
783 the required key is different from SmimeDefaultKey.
784*/
785
786void _smime_getkeys (char *mailbox)
787{
788 smime_key_t *key = NULL;
789 char *k = NULL;
790 char buf[STRING];
791
792 key = smime_get_key_by_addr (mailbox, KEYFLAG_CANENCRYPT, 0, 1);
793
794 if (!key)
795 {
796 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "),
797 mailbox);
798 key = smime_ask_for_key (buf, KEYFLAG_CANENCRYPT, 0);
799 }
800
801 if (key)
802 {
803 k = key->hash;
804
805 /* the key used last time. */
806 if (*SmimeKeyToUse &&
807 !mutt_strcasecmp (k, SmimeKeyToUse + mutt_strlen (SmimeKeys)+1))
808 {
809 smime_free_key (&key);
810 return;
811 }
812 else smime_void_passphrase ();
813
814 snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
815 NONULL(SmimeKeys), k);
816
817 snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
818 NONULL(SmimeCertificates), k);
819
820 if (mutt_strcasecmp (k, SmimeDefaultKey))
821 smime_void_passphrase ();
822
823 smime_free_key (&key);
824 return;
825 }
826
827 if (*SmimeKeyToUse)
828 {
829 if (!mutt_strcasecmp (SmimeDefaultKey,
830 SmimeKeyToUse + mutt_strlen (SmimeKeys)+1))
831 return;
832
833 smime_void_passphrase ();
834 }
835
836 snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
837 NONULL (SmimeKeys), NONULL (SmimeDefaultKey));
838
839 snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
840 NONULL (SmimeCertificates), NONULL (SmimeDefaultKey));
841}
842
843void smime_getkeys (ENVELOPE *env)
844{
845 ADDRESS *t;
846 int found = 0;
847
848 if (option (OPTSDEFAULTDECRYPTKEY) && SmimeDefaultKey && *SmimeDefaultKey)
849 {
850 snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
851 NONULL (SmimeKeys), SmimeDefaultKey);
852
853 snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
854 NONULL(SmimeCertificates), SmimeDefaultKey);
855
856 return;
857 }
858
859 for (t = env->to; !found && t; t = t->next)
860 if (mutt_addr_is_user (t))
861 {
862 found = 1;
863 _smime_getkeys (t->mailbox);
864 }
865 for (t = env->cc; !found && t; t = t->next)
866 if (mutt_addr_is_user (t))
867 {
868 found = 1;
869 _smime_getkeys (t->mailbox);
870 }
871 if (!found && (t = mutt_default_from()))
872 {
873 _smime_getkeys (t->mailbox);
874 rfc822_free_address (&t);
875 }
876}
877
878/* This routine attempts to find the keyids of the recipients of a message.
879 * It returns NULL if any of the keys can not be found.
880 * If oppenc_mode is true, only keys that can be determined without
881 * prompting will be used.
882 */
883
884char *smime_findKeys (ADDRESS *adrlist, int oppenc_mode)
885{
886 smime_key_t *key = NULL;
887 char *keyID, *keylist = NULL;
888 size_t keylist_size = 0;
889 size_t keylist_used = 0;
890 ADDRESS *p, *q;
891
892 for (p = adrlist; p ; p = p->next)
893 {
894 char buf[LONG_STRING];
895
896 q = p;
897
898 key = smime_get_key_by_addr (q->mailbox, KEYFLAG_CANENCRYPT, 1, !oppenc_mode);
899 if ((key == NULL) && (! oppenc_mode))
900 {
901 snprintf(buf, sizeof(buf),
902 _("Enter keyID for %s: "),
903 q->mailbox);
904 key = smime_ask_for_key (buf, KEYFLAG_CANENCRYPT, 1);
905 }
906 if (!key)
907 {
908 if (! oppenc_mode)
909 mutt_message (_("No (valid) certificate found for %s."), q->mailbox);
910 FREE (&keylist);
911 return NULL;
912 }
913
914 keyID = key->hash;
915 keylist_size += mutt_strlen (keyID) + 2;
916 safe_realloc (&keylist, keylist_size);
917 sprintf (keylist + keylist_used, "%s\n", keyID); /* __SPRINTF_CHECKED__ */
918 keylist_used = mutt_strlen (keylist);
919
920 smime_free_key (&key);
921 }
922 return (keylist);
923}
924
925
926
927
928
929
930static int smime_handle_cert_email (char *certificate, char *mailbox,
931 int copy, char ***buffer, int *num)
932{
933 FILE *fpout = NULL, *fperr = NULL;
934 char tmpfname[_POSIX_PATH_MAX];
935 char email[STRING];
936 int ret = -1, count = 0;
937 pid_t thepid;
938 size_t len = 0;
939
940 mutt_mktemp (tmpfname, sizeof (tmpfname));
941 if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
942 {
943 mutt_perror (tmpfname);
944 return 1;
945 }
946 mutt_unlink (tmpfname);
947
948 mutt_mktemp (tmpfname, sizeof (tmpfname));
949 if ((fpout = safe_fopen (tmpfname, "w+")) == NULL)
950 {
951 safe_fclose (&fperr);
952 mutt_perror (tmpfname);
953 return 1;
954 }
955 mutt_unlink (tmpfname);
956
957 if ((thepid = smime_invoke (NULL, NULL, NULL,
958 -1, fileno (fpout), fileno (fperr),
959 certificate, NULL, NULL, NULL, NULL, NULL, NULL,
960 SmimeGetCertEmailCommand))== -1)
961 {
962 mutt_message (_("Error: unable to create OpenSSL subprocess!"));
963 safe_fclose (&fperr);
964 safe_fclose (&fpout);
965 return 1;
966 }
967
968 mutt_wait_filter (thepid);
969
970 fflush (fpout);
971 rewind (fpout);
972 fflush (fperr);
973 rewind (fperr);
974
975
976 while ((fgets (email, sizeof (email), fpout)))
977 {
978 len = mutt_strlen (email);
979 if (len && (email[len - 1] == '\n'))
980 email[len - 1] = '\0';
981 if(mutt_strncasecmp (email, mailbox, mutt_strlen (mailbox)) == 0)
982 ret=1;
983
984 ret = ret < 0 ? 0 : ret;
985 count++;
986 }
987
988 if (ret == -1)
989 {
990 mutt_endwin(NULL);
991 mutt_copy_stream (fperr, stdout);
992 mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
993 ret = 1;
994 }
995 else if (!ret)
996 ret = 1;
997 else ret = 0;
998
999 if(copy && buffer && num)
1000 {
1001 (*num) = count;
1002 *buffer = safe_calloc(sizeof(char*), count);
1003 count = 0;
1004
1005 rewind (fpout);
1006 while ((fgets (email, sizeof (email), fpout)))
1007 {
1008 len = mutt_strlen (email);
1009 if (len && (email[len - 1] == '\n'))
1010 email[len - 1] = '\0';
1011 (*buffer)[count] = safe_calloc(1, mutt_strlen (email) + 1);
1012 strncpy((*buffer)[count], email, mutt_strlen (email));
1013 count++;
1014 }
1015 }
1016 else if(copy) ret = 2;
1017
1018 safe_fclose (&fpout);
1019 safe_fclose (&fperr);
1020
1021 return ret;
1022}
1023
1024
1025
1026static char *smime_extract_certificate (char *infile)
1027{
1028 FILE *fpout = NULL, *fperr = NULL;
1029 char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
1030 char tmpfname[_POSIX_PATH_MAX];
1031 pid_t thepid;
1032 int empty;
1033
1034
1035 mutt_mktemp (tmpfname, sizeof (tmpfname));
1036 if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
1037 {
1038 mutt_perror (tmpfname);
1039 return NULL;
1040 }
1041 mutt_unlink (tmpfname);
1042
1043 mutt_mktemp (pk7out, sizeof (pk7out));
1044 if ((fpout = safe_fopen (pk7out, "w+")) == NULL)
1045 {
1046 safe_fclose (&fperr);
1047 mutt_perror (pk7out);
1048 return NULL;
1049 }
1050
1051 /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
1052 extract the full set of certificates directly.
1053 */
1054 if ((thepid = smime_invoke (NULL, NULL, NULL,
1055 -1, fileno (fpout), fileno (fperr),
1056 infile, NULL, NULL, NULL, NULL, NULL, NULL,
1057 SmimePk7outCommand))== -1)
1058 {
1059 mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
1060 safe_fclose (&fperr);
1061 safe_fclose (&fpout);
1062 mutt_unlink (pk7out);
1063 return NULL;
1064 }
1065
1066 mutt_wait_filter (thepid);
1067
1068
1069 fflush (fpout);
1070 rewind (fpout);
1071 fflush (fperr);
1072 rewind (fperr);
1073 empty = (fgetc (fpout) == EOF);
1074 if (empty)
1075 {
1076 mutt_perror (pk7out);
1077 mutt_copy_stream (fperr, stdout);
1078 safe_fclose (&fpout);
1079 safe_fclose (&fperr);
1080 mutt_unlink (pk7out);
1081 return NULL;
1082
1083 }
1084
1085
1086 safe_fclose (&fpout);
1087 mutt_mktemp (certfile, sizeof (certfile));
1088 if ((fpout = safe_fopen (certfile, "w+")) == NULL)
1089 {
1090 safe_fclose (&fperr);
1091 mutt_unlink (pk7out);
1092 mutt_perror (certfile);
1093 return NULL;
1094 }
1095
1096 /* Step 2: Extract the certificates from a PKCS#7 structure.
1097 */
1098 if ((thepid = smime_invoke (NULL, NULL, NULL,
1099 -1, fileno (fpout), fileno (fperr),
1100 pk7out, NULL, NULL, NULL, NULL, NULL, NULL,
1101 SmimeGetCertCommand))== -1)
1102 {
1103 mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
1104 safe_fclose (&fperr);
1105 safe_fclose (&fpout);
1106 mutt_unlink (pk7out);
1107 mutt_unlink (certfile);
1108 return NULL;
1109 }
1110
1111 mutt_wait_filter (thepid);
1112
1113 mutt_unlink (pk7out);
1114
1115 fflush (fpout);
1116 rewind (fpout);
1117 fflush (fperr);
1118 rewind (fperr);
1119 empty = (fgetc (fpout) == EOF);
1120 if (empty)
1121 {
1122 mutt_copy_stream (fperr, stdout);
1123 safe_fclose (&fpout);
1124 safe_fclose (&fperr);
1125 mutt_unlink (certfile);
1126 return NULL;
1127 }
1128
1129 safe_fclose (&fpout);
1130 safe_fclose (&fperr);
1131
1132 return safe_strdup (certfile);
1133}
1134
1135static char *smime_extract_signer_certificate (char *infile)
1136{
1137 FILE *fpout = NULL, *fperr = NULL;
1138 char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
1139 char tmpfname[_POSIX_PATH_MAX];
1140 pid_t thepid;
1141 int empty;
1142
1143
1144 mutt_mktemp (tmpfname, sizeof (tmpfname));
1145 if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
1146 {
1147 mutt_perror (tmpfname);
1148 return NULL;
1149 }
1150 mutt_unlink (tmpfname);
1151
1152
1153 mutt_mktemp (certfile, sizeof (certfile));
1154 if ((fpout = safe_fopen (certfile, "w+")) == NULL)
1155 {
1156 safe_fclose (&fperr);
1157 mutt_perror (certfile);
1158 return NULL;
1159 }
1160
1161 /* Extract signer's certificate
1162 */
1163 if ((thepid = smime_invoke (NULL, NULL, NULL,
1164 -1, -1, fileno (fperr),
1165 infile, NULL, NULL, NULL, NULL, certfile, NULL,
1166 SmimeGetSignerCertCommand))== -1)
1167 {
1168 mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
1169 safe_fclose (&fperr);
1170 safe_fclose (&fpout);
1171 mutt_unlink (pk7out);
1172 mutt_unlink (certfile);
1173 return NULL;
1174 }
1175
1176 mutt_wait_filter (thepid);
1177
1178 fflush (fpout);
1179 rewind (fpout);
1180 fflush (fperr);
1181 rewind (fperr);
1182 empty = (fgetc (fpout) == EOF);
1183 if (empty)
1184 {
1185 mutt_endwin (NULL);
1186 mutt_copy_stream (fperr, stdout);
1187 mutt_any_key_to_continue (NULL);
1188 safe_fclose (&fpout);
1189 safe_fclose (&fperr);
1190 mutt_unlink (certfile);
1191 return NULL;
1192 }
1193
1194 safe_fclose (&fpout);
1195 safe_fclose (&fperr);
1196
1197 return safe_strdup (certfile);
1198}
1199
1200
1201
1202
1203/* Add a certificate and update index file (externally). */
1204
1205void smime_invoke_import (char *infile, char *mailbox)
1206{
1207 char tmpfname[_POSIX_PATH_MAX], *certfile = NULL, buf[STRING];
1208 FILE *smimein=NULL, *fpout = NULL, *fperr = NULL;
1209 pid_t thepid=-1;
1210
1211 mutt_mktemp (tmpfname, sizeof (tmpfname));
1212 if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
1213 {
1214 mutt_perror (tmpfname);
1215 return;
1216 }
1217 mutt_unlink (tmpfname);
1218
1219 mutt_mktemp (tmpfname, sizeof (tmpfname));
1220 if ((fpout = safe_fopen (tmpfname, "w+")) == NULL)
1221 {
1222 safe_fclose (&fperr);
1223 mutt_perror (tmpfname);
1224 return;
1225 }
1226 mutt_unlink (tmpfname);
1227
1228
1229 buf[0] = '\0';
1230 if (option (OPTASKCERTLABEL))
1231 mutt_get_field (_("Label for certificate: "), buf, sizeof (buf), 0);
1232
1233 mutt_endwin (NULL);
1234 if ((certfile = smime_extract_certificate(infile)))
1235 {
1236 mutt_endwin (NULL);
1237
1238 if ((thepid = smime_invoke (&smimein, NULL, NULL,
1239 -1, fileno(fpout), fileno(fperr),
1240 certfile, NULL, NULL, NULL, NULL, NULL, NULL,
1241 SmimeImportCertCommand))== -1)
1242 {
1243 mutt_message (_("Error: unable to create OpenSSL subprocess!"));
1244 return;
1245 }
1246 fputs (buf, smimein);
1247 fputc ('\n', smimein);
1248 safe_fclose (&smimein);
1249
1250 mutt_wait_filter (thepid);
1251
1252 mutt_unlink (certfile);
1253 FREE (&certfile);
1254 }
1255
1256 fflush (fpout);
1257 rewind (fpout);
1258 fflush (fperr);
1259 rewind (fperr);
1260
1261 mutt_copy_stream (fpout, stdout);
1262 mutt_copy_stream (fperr, stdout);
1263
1264 safe_fclose (&fpout);
1265 safe_fclose (&fperr);
1266
1267}
1268
1269
1270
1271int smime_verify_sender(HEADER *h)
1272{
1273 char *mbox = NULL, *certfile, tempfname[_POSIX_PATH_MAX];
1274 FILE *fpout;
1275 int retval=1;
1276
1277 mutt_mktemp (tempfname, sizeof (tempfname));
1278 if (!(fpout = safe_fopen (tempfname, "w")))
1279 {
1280 mutt_perror (tempfname);
1281 return 1;
1282 }
1283
1284 if(h->security & ENCRYPT)
1285 mutt_copy_message (fpout, Context, h,
1286 MUTT_CM_DECODE_CRYPT & MUTT_CM_DECODE_SMIME,
1287 CH_MIME|CH_WEED|CH_NONEWLINE);
1288 else
1289 mutt_copy_message (fpout, Context, h, 0, 0);
1290
1291 fflush(fpout);
1292 safe_fclose (&fpout);
1293
1294 if (h->env->from)
1295 {
1296 h->env->from = mutt_expand_aliases (h->env->from);
1297 mbox = h->env->from->mailbox;
1298 }
1299 else if (h->env->sender)
1300 {
1301 h->env->sender = mutt_expand_aliases (h->env->sender);
1302 mbox = h->env->sender->mailbox;
1303 }
1304
1305 if (mbox)
1306 {
1307 if ((certfile = smime_extract_signer_certificate(tempfname)))
1308 {
1309 mutt_unlink(tempfname);
1310 if (smime_handle_cert_email (certfile, mbox, 0, NULL, NULL))
1311 {
1312 if(isendwin())
1313 mutt_any_key_to_continue(NULL);
1314 }
1315 else
1316 retval = 0;
1317 mutt_unlink(certfile);
1318 FREE (&certfile);
1319 }
1320 else
1321 mutt_any_key_to_continue(_("no certfile"));
1322 }
1323 else
1324 mutt_any_key_to_continue(_("no mbox"));
1325
1326 mutt_unlink(tempfname);
1327 return retval;
1328}
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338/*
1339 * Creating S/MIME - bodies.
1340 */
1341
1342
1343
1344
1345static
1346pid_t smime_invoke_encrypt (FILE **smimein, FILE **smimeout, FILE **smimeerr,
1347 int smimeinfd, int smimeoutfd, int smimeerrfd,
1348 const char *fname, const char *uids)
1349{
1350 return smime_invoke (smimein, smimeout, smimeerr,
1351 smimeinfd, smimeoutfd, smimeerrfd,
1352 fname, NULL, SmimeCryptAlg, NULL, NULL, uids, NULL,
1353 SmimeEncryptCommand);
1354}
1355
1356
1357static
1358pid_t smime_invoke_sign (FILE **smimein, FILE **smimeout, FILE **smimeerr,
1359 int smimeinfd, int smimeoutfd, int smimeerrfd,
1360 const char *fname)
1361{
1362 return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1363 smimeerrfd, fname, NULL, NULL, SmimeDigestAlg, SmimeKeyToUse,
1364 SmimeCertToUse, SmimeIntermediateToUse,
1365 SmimeSignCommand);
1366}
1367
1368
1369
1370
1371BODY *smime_build_smime_entity (BODY *a, char *certlist)
1372{
1373 char buf[LONG_STRING], certfile[LONG_STRING];
1374 char tempfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
1375 char smimeinfile[_POSIX_PATH_MAX];
1376 char *cert_start = certlist, *cert_end = certlist;
1377 FILE *smimein = NULL, *smimeerr = NULL, *fpout = NULL, *fptmp = NULL;
1378 BODY *t;
1379 int err = 0, empty;
1380 pid_t thepid;
1381
1382 mutt_mktemp (tempfile, sizeof (tempfile));
1383 if ((fpout = safe_fopen (tempfile, "w+")) == NULL)
1384 {
1385 mutt_perror (tempfile);
1386 return (NULL);
1387 }
1388
1389 mutt_mktemp (smimeerrfile, sizeof (smimeerrfile));
1390 if ((smimeerr = safe_fopen (smimeerrfile, "w+")) == NULL)
1391 {
1392 mutt_perror (smimeerrfile);
1393 safe_fclose (&fpout);
1394 mutt_unlink (tempfile);
1395 return NULL;
1396 }
1397 mutt_unlink (smimeerrfile);
1398
1399 mutt_mktemp (smimeinfile, sizeof (smimeinfile));
1400 if ((fptmp = safe_fopen (smimeinfile, "w+")) == NULL)
1401 {
1402 mutt_perror (smimeinfile);
1403 mutt_unlink (tempfile);
1404 safe_fclose (&fpout);
1405 safe_fclose (&smimeerr);
1406 return NULL;
1407 }
1408
1409 *certfile = '\0';
1410 while (1)
1411 {
1412 int off = mutt_strlen (certfile);
1413 while (*++cert_end && *cert_end != '\n');
1414 if (!*cert_end) break;
1415 *cert_end = '\0';
1416 snprintf (certfile+off, sizeof (certfile)-off, " %s/%s",
1417 NONULL(SmimeCertificates), cert_start);
1418 *cert_end = '\n';
1419 cert_start = cert_end;
1420 cert_start++;
1421 }
1422
1423 /* write a MIME entity */
1424 mutt_write_mime_header (a, fptmp);
1425 fputc ('\n', fptmp);
1426 mutt_write_mime_body (a, fptmp);
1427 safe_fclose (&fptmp);
1428
1429 if ((thepid =
1430 smime_invoke_encrypt (&smimein, NULL, NULL, -1,
1431 fileno (fpout), fileno (smimeerr),
1432 smimeinfile, certfile)) == -1)
1433 {
1434 safe_fclose (&smimeerr);
1435 mutt_unlink (smimeinfile);
1436 mutt_unlink (certfile);
1437 return (NULL);
1438 }
1439
1440 safe_fclose (&smimein);
1441
1442 mutt_wait_filter (thepid);
1443 mutt_unlink (smimeinfile);
1444 mutt_unlink (certfile);
1445
1446 fflush (fpout);
1447 rewind (fpout);
1448 empty = (fgetc (fpout) == EOF);
1449 safe_fclose (&fpout);
1450
1451 fflush (smimeerr);
1452 rewind (smimeerr);
1453 while (fgets (buf, sizeof (buf) - 1, smimeerr) != NULL)
1454 {
1455 err = 1;
1456 fputs (buf, stdout);
1457 }
1458 safe_fclose (&smimeerr);
1459
1460 /* pause if there is any error output from SMIME */
1461 if (err)
1462 mutt_any_key_to_continue (NULL);
1463
1464 if (empty)
1465 {
1466 /* fatal error while trying to encrypt message */
1467 if (!err) mutt_any_key_to_continue _("No output from OpenSSL...");
1468 mutt_unlink (tempfile);
1469 return (NULL);
1470 }
1471
1472 t = mutt_new_body ();
1473 t->type = TYPEAPPLICATION;
1474 t->subtype = safe_strdup ("x-pkcs7-mime");
1475 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
1476 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
1477 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
1478 t->use_disp = 1;
1479 t->disposition = DISPATTACH;
1480 t->d_filename = safe_strdup ("smime.p7m");
1481 t->filename = safe_strdup (tempfile);
1482 t->unlink = 1; /*delete after sending the message */
1483 t->parts=0;
1484 t->next=0;
1485
1486 return (t);
1487}
1488
1489
1490/* The openssl -md doesn't want hyphens:
1491 * md5, sha1, sha224, sha256, sha384, sha512
1492 * However, the micalg does:
1493 * md5, sha-1, sha-224, sha-256, sha-384, sha-512
1494 */
1495static char *openssl_md_to_smime_micalg(char *md)
1496{
1497 char *micalg;
1498 size_t l;
1499
1500 if (!md)
1501 return 0;
1502
1503 if (mutt_strncasecmp ("sha", md, 3) == 0)
1504 {
1505 l = strlen (md) + 2;
1506 micalg = (char *)safe_malloc (l);
1507 snprintf (micalg, l, "sha-%s", md +3);
1508 }
1509 else
1510 {
1511 micalg = safe_strdup (md);
1512 }
1513
1514 return micalg;
1515}
1516
1517
1518
1519BODY *smime_sign_message (BODY *a )
1520{
1521 BODY *t;
1522 char buffer[LONG_STRING];
1523 char signedfile[_POSIX_PATH_MAX], filetosign[_POSIX_PATH_MAX];
1524 FILE *smimein = NULL, *smimeout = NULL, *smimeerr = NULL, *sfp = NULL;
1525 int err = 0;
1526 int empty = 0;
1527 pid_t thepid;
1528 smime_key_t *default_key;
1529 char *intermediates;
1530 char *micalg;
1531
1532 if (!SmimeDefaultKey)
1533 {
1534 mutt_error _("Can't sign: No key specified. Use Sign As.");
1535 return NULL;
1536 }
1537
1538 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
1539
1540 mutt_mktemp (filetosign, sizeof (filetosign));
1541 if ((sfp = safe_fopen (filetosign, "w+")) == NULL)
1542 {
1543 mutt_perror (filetosign);
1544 return NULL;
1545 }
1546
1547 mutt_mktemp (signedfile, sizeof (signedfile));
1548 if ((smimeout = safe_fopen (signedfile, "w+")) == NULL)
1549 {
1550 mutt_perror (signedfile);
1551 safe_fclose (&sfp);
1552 mutt_unlink (filetosign);
1553 return NULL;
1554 }
1555
1556 mutt_write_mime_header (a, sfp);
1557 fputc ('\n', sfp);
1558 mutt_write_mime_body (a, sfp);
1559 safe_fclose (&sfp);
1560
1561
1562
1563 snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
1564 NONULL(SmimeKeys), SmimeDefaultKey);
1565
1566 snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
1567 NONULL(SmimeCertificates), SmimeDefaultKey);
1568
1569 default_key = smime_get_key_by_hash (SmimeDefaultKey, 1);
1570 if ((! default_key) ||
1571 (! mutt_strcmp ("?", default_key->issuer)))
1572 intermediates = SmimeDefaultKey; /* so openssl won't complain in any case */
1573 else
1574 intermediates = default_key->issuer;
1575
1576 snprintf (SmimeIntermediateToUse, sizeof (SmimeIntermediateToUse), "%s/%s",
1577 NONULL(SmimeCertificates), intermediates);
1578
1579 smime_free_key (&default_key);
1580
1581
1582
1583 if ((thepid = smime_invoke_sign (&smimein, NULL, &smimeerr,
1584 -1, fileno (smimeout), -1, filetosign)) == -1)
1585 {
1586 mutt_perror _("Can't open OpenSSL subprocess!");
1587 safe_fclose (&smimeout);
1588 mutt_unlink (signedfile);
1589 mutt_unlink (filetosign);
1590 return NULL;
1591 }
1592 fputs (SmimePass, smimein);
1593 fputc ('\n', smimein);
1594 safe_fclose (&smimein);
1595
1596
1597 mutt_wait_filter (thepid);
1598
1599 /* check for errors from OpenSSL */
1600 err = 0;
1601 fflush (smimeerr);
1602 rewind (smimeerr);
1603 while (fgets (buffer, sizeof (buffer) - 1, smimeerr) != NULL)
1604 {
1605 err = 1;
1606 fputs (buffer, stdout);
1607 }
1608 safe_fclose (&smimeerr);
1609
1610
1611 fflush (smimeout);
1612 rewind (smimeout);
1613 empty = (fgetc (smimeout) == EOF);
1614 safe_fclose (&smimeout);
1615
1616 mutt_unlink (filetosign);
1617
1618
1619 if (err)
1620 mutt_any_key_to_continue (NULL);
1621
1622 if (empty)
1623 {
1624 mutt_any_key_to_continue _("No output from OpenSSL...");
1625 mutt_unlink (signedfile);
1626 return (NULL); /* fatal error while signing */
1627 }
1628
1629 t = mutt_new_body ();
1630 t->type = TYPEMULTIPART;
1631 t->subtype = safe_strdup ("signed");
1632 t->encoding = ENC7BIT;
1633 t->use_disp = 0;
1634 t->disposition = DISPINLINE;
1635
1636 mutt_generate_boundary (&t->parameter);
1637
1638 micalg = openssl_md_to_smime_micalg (SmimeDigestAlg);
1639 mutt_set_parameter ("micalg", micalg, &t->parameter);
1640 FREE (&micalg);
1641
1642 mutt_set_parameter ("protocol", "application/x-pkcs7-signature",
1643 &t->parameter);
1644
1645 t->parts = a;
1646 a = t;
1647
1648 t->parts->next = mutt_new_body ();
1649 t = t->parts->next;
1650 t->type = TYPEAPPLICATION;
1651 t->subtype = safe_strdup ("x-pkcs7-signature");
1652 t->filename = safe_strdup (signedfile);
1653 t->d_filename = safe_strdup ("smime.p7s");
1654 t->use_disp = 1;
1655 t->disposition = DISPATTACH;
1656 t->encoding = ENCBASE64;
1657 t->unlink = 1; /* ok to remove this file after sending. */
1658
1659 return (a);
1660
1661}
1662
1663
1664
1665
1666
1667
1668/*
1669 * Handling S/MIME - bodies.
1670 */
1671
1672
1673
1674
1675
1676
1677static
1678pid_t smime_invoke_verify (FILE **smimein, FILE **smimeout, FILE **smimeerr,
1679 int smimeinfd, int smimeoutfd, int smimeerrfd,
1680 const char *fname, const char *sig_fname, int opaque)
1681{
1682 return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1683 smimeerrfd, fname, sig_fname, NULL, NULL, NULL, NULL, NULL,
1684 (opaque ? SmimeVerifyOpaqueCommand : SmimeVerifyCommand));
1685}
1686
1687
1688static
1689pid_t smime_invoke_decrypt (FILE **smimein, FILE **smimeout, FILE **smimeerr,
1690 int smimeinfd, int smimeoutfd, int smimeerrfd,
1691 const char *fname)
1692{
1693 return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1694 smimeerrfd, fname, NULL, NULL, NULL, SmimeKeyToUse,
1695 SmimeCertToUse, NULL, SmimeDecryptCommand);
1696}
1697
1698
1699
1700int smime_verify_one (BODY *sigbdy, STATE *s, const char *tempfile)
1701{
1702 char signedfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
1703 FILE *fp=NULL, *smimeout=NULL, *smimeerr=NULL;
1704 pid_t thepid;
1705 int badsig = -1;
1706
1707 LOFF_T tmpoffset = 0;
1708 size_t tmplength = 0;
1709 int origType = sigbdy->type;
1710 char *savePrefix = NULL;
1711
1712
1713 snprintf (signedfile, sizeof (signedfile), "%s.sig", tempfile);
1714
1715 /* decode to a tempfile, saving the original destination */
1716 fp = s->fpout;
1717 if ((s->fpout = safe_fopen (signedfile, "w")) == NULL)
1718 {
1719 mutt_perror (signedfile);
1720 return -1;
1721 }
1722 /* decoding the attachment changes the size and offset, so save a copy
1723 * of the "real" values now, and restore them after processing
1724 */
1725 tmplength = sigbdy->length;
1726 tmpoffset = sigbdy->offset;
1727
1728 /* if we are decoding binary bodies, we don't want to prefix each
1729 * line with the prefix or else the data will get corrupted.
1730 */
1731 savePrefix = s->prefix;
1732 s->prefix = NULL;
1733
1734 mutt_decode_attachment (sigbdy, s);
1735
1736 sigbdy->length = ftello (s->fpout);
1737 sigbdy->offset = 0;
1738 safe_fclose (&s->fpout);
1739
1740 /* restore final destination and substitute the tempfile for input */
1741 s->fpout = fp;
1742 fp = s->fpin;
1743 s->fpin = fopen (signedfile, "r");
1744
1745 /* restore the prefix */
1746 s->prefix = savePrefix;
1747
1748 sigbdy->type = origType;
1749
1750
1751 mutt_mktemp (smimeerrfile, sizeof (smimeerrfile));
1752 if (!(smimeerr = safe_fopen (smimeerrfile, "w+")))
1753 {
1754 mutt_perror (smimeerrfile);
1755 mutt_unlink (signedfile);
1756 return -1;
1757 }
1758
1759 crypt_current_time (s, "OpenSSL");
1760
1761 if ((thepid = smime_invoke_verify (NULL, &smimeout, NULL,
1762 -1, -1, fileno (smimeerr),
1763 tempfile, signedfile, 0)) != -1)
1764 {
1765 fflush (smimeout);
1766 safe_fclose (&smimeout);
1767
1768 if (mutt_wait_filter (thepid))
1769 badsig = -1;
1770 else
1771 {
1772 char *line = NULL;
1773 int lineno = 0;
1774 size_t linelen;
1775
1776 fflush (smimeerr);
1777 rewind (smimeerr);
1778
1779 line = mutt_read_line (line, &linelen, smimeerr, &lineno, 0);
1780 if (linelen && !ascii_strcasecmp (line, "verification successful"))
1781 badsig = 0;
1782
1783 FREE (&line);
1784 }
1785 }
1786
1787 fflush (smimeerr);
1788 rewind (smimeerr);
1789 mutt_copy_stream (smimeerr, s->fpout);
1790 safe_fclose (&smimeerr);
1791
1792 state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
1793
1794 mutt_unlink (signedfile);
1795 mutt_unlink (smimeerrfile);
1796
1797 sigbdy->length = tmplength;
1798 sigbdy->offset = tmpoffset;
1799
1800 /* restore the original source stream */
1801 safe_fclose (&s->fpin);
1802 s->fpin = fp;
1803
1804
1805 return badsig;
1806}
1807
1808
1809
1810
1811
1812/*
1813 This handles application/pkcs7-mime which can either be a signed
1814 or an encrypted message.
1815*/
1816
1817static BODY *smime_handle_entity (BODY *m, STATE *s, FILE *outFile)
1818{
1819 int len=0;
1820 int c;
1821 char buf[HUGE_STRING];
1822 char outfile[_POSIX_PATH_MAX], errfile[_POSIX_PATH_MAX];
1823 char tmpfname[_POSIX_PATH_MAX];
1824 char tmptmpfname[_POSIX_PATH_MAX];
1825 FILE *smimeout = NULL, *smimein=NULL, *smimeerr=NULL;
1826 FILE *tmpfp=NULL, *tmpfp_buffer=NULL, *fpout=NULL;
1827 struct stat info;
1828 BODY *p=NULL;
1829 pid_t thepid=-1;
1830 unsigned int type = mutt_is_application_smime (m);
1831
1832 if (!(type & APPLICATION_SMIME)) return NULL;
1833
1834 mutt_mktemp (outfile, sizeof (outfile));
1835 if ((smimeout = safe_fopen (outfile, "w+")) == NULL)
1836 {
1837 mutt_perror (outfile);
1838 return NULL;
1839 }
1840
1841 mutt_mktemp (errfile, sizeof (errfile));
1842 if ((smimeerr = safe_fopen (errfile, "w+")) == NULL)
1843 {
1844 mutt_perror (errfile);
1845 safe_fclose (&smimeout); smimeout = NULL;
1846 return NULL;
1847 }
1848 mutt_unlink (errfile);
1849
1850
1851 mutt_mktemp (tmpfname, sizeof (tmpfname));
1852 if ((tmpfp = safe_fopen (tmpfname, "w+")) == NULL)
1853 {
1854 mutt_perror (tmpfname);
1855 safe_fclose (&smimeout); smimeout = NULL;
1856 safe_fclose (&smimeerr); smimeerr = NULL;
1857 return NULL;
1858 }
1859
1860 fseeko (s->fpin, m->offset, 0);
1861
1862 mutt_copy_bytes (s->fpin, tmpfp, m->length);
1863
1864 fflush (tmpfp);
1865 safe_fclose (&tmpfp);
1866
1867 if ((type & ENCRYPT) &&
1868 (thepid = smime_invoke_decrypt (&smimein, NULL, NULL, -1,
1869 fileno (smimeout), fileno (smimeerr), tmpfname)) == -1)
1870 {
1871 safe_fclose (&smimeout); smimeout = NULL;
1872 mutt_unlink (tmpfname);
1873 if (s->flags & MUTT_DISPLAY)
1874 state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
1875 return NULL;
1876 }
1877 else if ((type & SIGNOPAQUE) &&
1878 (thepid = smime_invoke_verify (&smimein, NULL, NULL, -1,
1879 fileno (smimeout), fileno (smimeerr), NULL,
1880 tmpfname, SIGNOPAQUE)) == -1)
1881 {
1882 safe_fclose (&smimeout); smimeout = NULL;
1883 mutt_unlink (tmpfname);
1884 if (s->flags & MUTT_DISPLAY)
1885 state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
1886 return NULL;
1887 }
1888
1889
1890 if (type & ENCRYPT)
1891 {
1892 if (!smime_valid_passphrase ())
1893 smime_void_passphrase ();
1894 fputs (SmimePass, smimein);
1895 fputc ('\n', smimein);
1896 }
1897
1898 safe_fclose (&smimein);
1899
1900 mutt_wait_filter (thepid);
1901 mutt_unlink (tmpfname);
1902
1903
1904 if (s->flags & MUTT_DISPLAY)
1905 {
1906 fflush (smimeerr);
1907 rewind (smimeerr);
1908
1909 if ((c = fgetc (smimeerr)) != EOF)
1910 {
1911 ungetc (c, smimeerr);
1912
1913 crypt_current_time (s, "OpenSSL");
1914 mutt_copy_stream (smimeerr, s->fpout);
1915 state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
1916 }
1917
1918 if (type & ENCRYPT)
1919 state_attach_puts (_("[-- The following data is S/MIME"
1920 " encrypted --]\n"), s);
1921 else
1922 state_attach_puts (_("[-- The following data is S/MIME signed --]\n"), s);
1923 }
1924
1925 if (smimeout)
1926 {
1927 fflush (smimeout);
1928 rewind (smimeout);
1929
1930 if (outFile) fpout = outFile;
1931 else
1932 {
1933 mutt_mktemp (tmptmpfname, sizeof (tmptmpfname));
1934 if ((fpout = safe_fopen (tmptmpfname, "w+")) == NULL)
1935 {
1936 mutt_perror(tmptmpfname);
1937 safe_fclose (&smimeout); smimeout = NULL;
1938 return NULL;
1939 }
1940 }
1941 while (fgets (buf, sizeof (buf) - 1, smimeout) != NULL)
1942 {
1943 len = mutt_strlen (buf);
1944 if (len > 1 && buf[len - 2] == '\r')
1945 {
1946 buf[len-2] = '\n';
1947 buf[len-1] = '\0';
1948 }
1949 fputs (buf, fpout);
1950 }
1951 fflush (fpout);
1952 rewind (fpout);
1953
1954
1955 if ((p = mutt_read_mime_header (fpout, 0)) != NULL)
1956 {
1957 fstat (fileno (fpout), &info);
1958 p->length = info.st_size - p->offset;
1959
1960 mutt_parse_part (fpout, p);
1961 if (s->fpout)
1962 {
1963 rewind (fpout);
1964 tmpfp_buffer = s->fpin;
1965 s->fpin = fpout;
1966 mutt_body_handler (p, s);
1967 s->fpin = tmpfp_buffer;
1968 }
1969
1970 }
1971 safe_fclose (&smimeout);
1972 smimeout = NULL;
1973 mutt_unlink (outfile);
1974
1975 if (!outFile)
1976 {
1977 safe_fclose (&fpout);
1978 mutt_unlink (tmptmpfname);
1979 }
1980 fpout = NULL;
1981 }
1982
1983 if (s->flags & MUTT_DISPLAY)
1984 {
1985 if (type & ENCRYPT)
1986 state_attach_puts (_("\n[-- End of S/MIME encrypted data. --]\n"), s);
1987 else
1988 state_attach_puts (_("\n[-- End of S/MIME signed data. --]\n"), s);
1989 }
1990
1991 if (type & SIGNOPAQUE)
1992 {
1993 char *line = NULL;
1994 int lineno = 0;
1995 size_t linelen;
1996
1997 rewind (smimeerr);
1998
1999 line = mutt_read_line (line, &linelen, smimeerr, &lineno, 0);
2000 if (linelen && !ascii_strcasecmp (line, "verification successful"))
2001 m->goodsig = 1;
2002 FREE (&line);
2003 }
2004 else
2005 {
2006 m->goodsig = p->goodsig;
2007 m->badsig = p->badsig;
2008 }
2009 safe_fclose (&smimeerr);
2010
2011 return (p);
2012}
2013
2014
2015
2016
2017
2018int smime_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
2019{
2020
2021
2022 char tempfile[_POSIX_PATH_MAX];
2023 STATE s;
2024 LOFF_T tmpoffset = b->offset;
2025 size_t tmplength = b->length;
2026 int origType = b->type;
2027 FILE *tmpfp=NULL;
2028 int rv = 0;
2029
2030 if (!mutt_is_application_smime (b))
2031 return -1;
2032
2033 if (b->parts)
2034 return -1;
2035
2036 memset (&s, 0, sizeof (s));
2037 s.fpin = fpin;
2038 fseeko (s.fpin, b->offset, 0);
2039
2040 mutt_mktemp (tempfile, sizeof (tempfile));
2041 if ((tmpfp = safe_fopen (tempfile, "w+")) == NULL)
2042 {
2043 mutt_perror (tempfile);
2044 return (-1);
2045 }
2046
2047 mutt_unlink (tempfile);
2048 s.fpout = tmpfp;
2049 mutt_decode_attachment (b, &s);
2050 fflush (tmpfp);
2051 b->length = ftello (s.fpout);
2052 b->offset = 0;
2053 rewind (tmpfp);
2054 s.fpin = tmpfp;
2055 s.fpout = 0;
2056
2057 mutt_mktemp (tempfile, sizeof (tempfile));
2058 if ((*fpout = safe_fopen (tempfile, "w+")) == NULL)
2059 {
2060 mutt_perror (tempfile);
2061 rv = -1;
2062 goto bail;
2063 }
2064 mutt_unlink (tempfile);
2065
2066 if (!(*cur = smime_handle_entity (b, &s, *fpout)))
2067 {
2068 rv = -1;
2069 goto bail;
2070 }
2071
2072 (*cur)->goodsig = b->goodsig;
2073 (*cur)->badsig = b->badsig;
2074
2075bail:
2076 b->type = origType;
2077 b->length = tmplength;
2078 b->offset = tmpoffset;
2079 safe_fclose (&tmpfp);
2080 if (*fpout)
2081 rewind (*fpout);
2082
2083 return rv;
2084}
2085
2086
2087int smime_application_smime_handler (BODY *m, STATE *s)
2088{
2089 return smime_handle_entity (m, s, NULL) ? 0 : -1;
2090}
2091
2092int smime_send_menu (HEADER *msg, int *redraw)
2093{
2094 smime_key_t *key;
2095 char *prompt, *letters, *choices;
2096 int choice;
2097
2098 if (!(WithCrypto & APPLICATION_SMIME))
2099 return msg->security;
2100
2101 msg->security |= APPLICATION_SMIME;
2102
2103 /*
2104 * Opportunistic encrypt is controlling encryption.
2105 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
2106 * letter choices for those.
2107 */
2108 if (option (OPTCRYPTOPPORTUNISTICENCRYPT) && (msg->security & OPPENCRYPT))
2109 {
2110 prompt = _("S/MIME (s)ign, encrypt (w)ith, sign (a)s, (c)lear, or (o)ppenc mode off? ");
2111 /* L10N: The 'f' is from "forget it", an old undocumented synonym of
2112 'clear'. Please use a corresponding letter in your language.
2113 Alternatively, you may duplicate the letter 'c' is translated to.
2114 This comment also applies to the two following letter sequences. */
2115 letters = _("swafco");
2116 choices = "SwaFCo";
2117 }
2118 /*
2119 * Opportunistic encryption option is set, but is toggled off
2120 * for this message.
2121 */
2122 else if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
2123 {
2124 prompt = _("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, (c)lear, or (o)ppenc mode? ");
2125 letters = _("eswabfco");
2126 choices = "eswabfcO";
2127 }
2128 /*
2129 * Opportunistic encryption is unset
2130 */
2131 else
2132 {
2133 prompt = _("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, or (c)lear? ");
2134 letters = _("eswabfc");
2135 choices = "eswabfc";
2136 }
2137
2138
2139 choice = mutt_multi_choice (prompt, letters);
2140 if (choice > 0)
2141 {
2142 switch (choices[choice - 1])
2143 {
2144 case 'e': /* (e)ncrypt */
2145 msg->security |= ENCRYPT;
2146 msg->security &= ~SIGN;
2147 break;
2148
2149 case 'w': /* encrypt (w)ith */
2150 {
2151 msg->security |= ENCRYPT;
2152 do
2153 {
2154 /* I use "dra" because "123" is recognized anyway */
2155 switch (mutt_multi_choice (_("Choose algorithm family:"
2156 " 1: DES, 2: RC2, 3: AES,"
2157 " or (c)lear? "),
2158 _("drac")))
2159 {
2160 case 1:
2161 switch (choice = mutt_multi_choice (_("1: DES, 2: Triple-DES "),
2162 _("dt")))
2163 {
2164 case 1:
2165 mutt_str_replace (&SmimeCryptAlg, "des");
2166 break;
2167 case 2:
2168 mutt_str_replace (&SmimeCryptAlg, "des3");
2169 break;
2170 }
2171 break;
2172
2173 case 2:
2174 switch (choice = mutt_multi_choice (_("1: RC2-40, 2: RC2-64, 3: RC2-128 "),
2175 _("468")))
2176 {
2177 case 1:
2178 mutt_str_replace (&SmimeCryptAlg, "rc2-40");
2179 break;
2180 case 2:
2181 mutt_str_replace (&SmimeCryptAlg, "rc2-64");
2182 break;
2183 case 3:
2184 mutt_str_replace (&SmimeCryptAlg, "rc2-128");
2185 break;
2186 }
2187 break;
2188
2189 case 3:
2190 switch (choice = mutt_multi_choice (_("1: AES128, 2: AES192, 3: AES256 "),
2191 _("895")))
2192 {
2193 case 1:
2194 mutt_str_replace (&SmimeCryptAlg, "aes128");
2195 break;
2196 case 2:
2197 mutt_str_replace (&SmimeCryptAlg, "aes192");
2198 break;
2199 case 3:
2200 mutt_str_replace (&SmimeCryptAlg, "aes256");
2201 break;
2202 }
2203 break;
2204
2205 case 4: /* (c)lear */
2206 FREE (&SmimeCryptAlg);
2207 /* fallback */
2208 case -1: /* Ctrl-G or Enter */
2209 choice = 0;
2210 break;
2211 }
2212 } while (choice == -1);
2213 }
2214 break;
2215
2216 case 's': /* (s)ign */
2217 case 'S': /* (s)ign in oppenc mode */
2218 if(!SmimeDefaultKey)
2219 {
2220 *redraw = REDRAW_FULL;
2221
2222 if ((key = smime_ask_for_key (_("Sign as: "), KEYFLAG_CANSIGN, 0)))
2223 {
2224 mutt_str_replace (&SmimeDefaultKey, key->hash);
2225 smime_free_key (&key);
2226 }
2227 else
2228 break;
2229 }
2230 if (choices[choice - 1] == 's')
2231 msg->security &= ~ENCRYPT;
2232 msg->security |= SIGN;
2233 break;
2234
2235 case 'a': /* sign (a)s */
2236
2237 if ((key = smime_ask_for_key (_("Sign as: "), KEYFLAG_CANSIGN, 0)))
2238 {
2239 mutt_str_replace (&SmimeDefaultKey, key->hash);
2240 smime_free_key (&key);
2241
2242 msg->security |= SIGN;
2243
2244 /* probably need a different passphrase */
2245 crypt_smime_void_passphrase ();
2246 }
2247
2248 *redraw = REDRAW_FULL;
2249 break;
2250
2251 case 'b': /* (b)oth */
2252 msg->security |= (ENCRYPT | SIGN);
2253 break;
2254
2255 case 'f': /* (f)orget it: kept for backward compatibility. */
2256 case 'c': /* (c)lear */
2257 msg->security &= ~(ENCRYPT | SIGN);
2258 break;
2259
2260 case 'F': /* (f)orget it or (c)lear in oppenc mode */
2261 case 'C':
2262 msg->security &= ~SIGN;
2263 break;
2264
2265 case 'O': /* oppenc mode on */
2266 msg->security |= OPPENCRYPT;
2267 crypt_opportunistic_encrypt (msg);
2268 break;
2269
2270 case 'o': /* oppenc mode off */
2271 msg->security &= ~OPPENCRYPT;
2272 break;
2273 }
2274 }
2275
2276 return (msg->security);
2277}
2278
2279
2280#endif /* CRYPT_BACKEND_CLASSIC_SMIME */