3040268929f7c42e7c2c6315ad908c738d2d4043
[apps/madmutt.git] / lib-crypt / smime.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 2001,2002 Oliver Ehli <elmy@acm.org>
4  * Copyright (C) 2002 Mike Schiraldi <raldi@research.netsol.com>
5  * Copyright (C) 2004 g10 Code GmbH
6  *
7  * This file is part of mutt-ng, see http://www.muttng.org/.
8  * It's licensed under the GNU General Public License,
9  * please see the file GPL in the top level source directory.
10  */
11
12 #if HAVE_CONFIG_H
13 # include "config.h"
14 #endif
15
16 #include <lib-lib/mem.h>
17 #include <lib-lib/str.h>
18 #include <lib-lib/macros.h>
19 #include <lib-lib/file.h>
20
21 #include <lib-mime/mime.h>
22
23 #include "mutt.h"
24 #include "enter.h"
25 #include "handler.h"
26 #include "mutt_curses.h"
27 #include "mutt_menu.h"
28 #include "copy.h"
29
30 #include "lib/debug.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 #include "crypt.h"
53
54 struct smime_command_context {
55   const char *key;              /* %k */
56   const char *cryptalg;         /* %a */
57   const char *fname;            /* %f */
58   const char *sig_fname;        /* %s */
59   const char *certificates;     /* %c */
60   const char *intermediates;    /* %i */
61 };
62
63
64 typedef struct {
65   unsigned int hash;
66   char suffix;
67   char email[256];
68   char nick[256];
69   char trust;                   /* i=Invalid r=revoked e=expired u=unverified v=verified t=trusted */
70   short public;                 /* 1=public 0=private */
71 } smime_id;
72
73
74 char SmimePass[STRING];
75 time_t SmimeExptime = 0;        /* when does the cached passphrase expire? */
76
77
78 static char SmimeKeyToUse[_POSIX_PATH_MAX] = { 0 };
79 static char SmimeCertToUse[_POSIX_PATH_MAX];
80 static char SmimeIntermediateToUse[_POSIX_PATH_MAX];
81
82
83 /*
84  * Create a format string to be used with scanf.
85  * To use it, write, for instance, MUTT_FORMAT(HUGE_STRING).
86  * 
87  * See K&R 2nd ed, p. 231 for an explanation.
88  */
89 #define _MUTT_FORMAT_2(a,b)     "%" a  b
90 #define _MUTT_FORMAT_1(a, b)    _MUTT_FORMAT_2(#a, b)
91 #define MUTT_FORMAT(a)          _MUTT_FORMAT_1(a, "s")
92
93
94 /*
95  *     Queries and passphrase handling.
96  */
97
98
99 /* these are copies from pgp.c */
100
101
102 void smime_void_passphrase (void)
103 {
104   p_clear(SmimePass, sizeof(SmimePass));
105   SmimeExptime = 0;
106 }
107
108 int smime_valid_passphrase (void)
109 {
110   time_t now = time (NULL);
111
112   if (now < SmimeExptime)
113     /* Use cached copy.  */
114     return 1;
115
116   smime_void_passphrase ();
117
118   if (mutt_get_field_unbuffered (_("Enter S/MIME passphrase:"), SmimePass,
119                                  sizeof (SmimePass), M_PASS) == 0) {
120     SmimeExptime = time (NULL) + SmimeTimeout;
121     return (1);
122   }
123   else
124     SmimeExptime = 0;
125
126   return 0;
127 }
128
129
130 /*
131  *     The OpenSSL interface
132  */
133
134 /* This is almost identical to ppgp's invoking interface. */
135
136 static const char *_mutt_fmt_smime_command (char *dest,
137                                             size_t destlen,
138                                             char op,
139                                             const char *src,
140                                             const char *prefix,
141                                             const char *ifstring,
142                                             const char *elsestring,
143                                             unsigned long data,
144                                             format_flag flags)
145 {
146   char fmt[16];
147   struct smime_command_context *cctx = (struct smime_command_context *) data;
148   int optional = (flags & M_FORMAT_OPTIONAL);
149
150   switch (op) {
151   case 'C':
152     {
153       if (!optional) {
154         char path[_POSIX_PATH_MAX];
155         char buf1[LONG_STRING], buf2[LONG_STRING];
156         struct stat sb;
157
158         m_strcpy(path, sizeof(path), NONULL(SmimeCALocation));
159         mutt_expand_path (path, sizeof (path));
160         mutt_quote_filename (buf1, sizeof (buf1), path);
161
162         if (stat (path, &sb) != 0 || !S_ISDIR (sb.st_mode))
163           snprintf (buf2, sizeof (buf2), "-CAfile %s", buf1);
164         else
165           snprintf (buf2, sizeof (buf2), "-CApath %s", buf1);
166
167         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
168         snprintf (dest, destlen, fmt, buf2);
169       }
170       else if (!SmimeCALocation)
171         optional = 0;
172       break;
173     }
174
175   case 'c':
176     {                           /* certificate (list) */
177       if (!optional) {
178         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
179         snprintf (dest, destlen, fmt, NONULL (cctx->certificates));
180       }
181       else if (!cctx->certificates)
182         optional = 0;
183       break;
184     }
185
186   case 'i':
187     {                           /* intermediate certificates  */
188       if (!optional) {
189         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
190         snprintf (dest, destlen, fmt, NONULL (cctx->intermediates));
191       }
192       else if (!cctx->intermediates)
193         optional = 0;
194       break;
195     }
196
197   case 's':
198     {                           /* detached signature */
199       if (!optional) {
200         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
201         snprintf (dest, destlen, fmt, NONULL (cctx->sig_fname));
202       }
203       else if (!cctx->sig_fname)
204         optional = 0;
205       break;
206     }
207
208   case 'k':
209     {                           /* private key */
210       if (!optional) {
211         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
212         snprintf (dest, destlen, fmt, NONULL (cctx->key));
213       }
214       else if (!cctx->key)
215         optional = 0;
216       break;
217     }
218
219   case 'a':
220     {                           /* algorithm for encryption */
221       if (!optional) {
222         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
223         snprintf (dest, destlen, fmt, NONULL (cctx->cryptalg));
224       }
225       else if (!cctx->key)
226         optional = 0;
227       break;
228     }
229
230   case 'f':
231     {                           /* file to process */
232       if (!optional) {
233         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
234         snprintf (dest, destlen, fmt, NONULL (cctx->fname));
235       }
236       else if (!cctx->fname)
237         optional = 0;
238       break;
239     }
240
241   default:
242     *dest = '\0';
243     break;
244   }
245
246   if (optional)
247     mutt_FormatString (dest, destlen, ifstring, _mutt_fmt_smime_command,
248                        data, 0);
249   else if (flags & M_FORMAT_OPTIONAL)
250     mutt_FormatString (dest, destlen, elsestring, _mutt_fmt_smime_command,
251                        data, 0);
252
253   return (src);
254 }
255
256
257
258 static void mutt_smime_command (char *d, size_t dlen,
259                                 struct smime_command_context *cctx,
260                                 const char *fmt)
261 {
262   mutt_FormatString (d, dlen, NONULL (fmt), _mutt_fmt_smime_command,
263                      (unsigned long) cctx, 0);
264   debug_print (2, ("%s\n", d));
265 }
266
267 static pid_t smime_invoke (FILE ** smimein, FILE ** smimeout,
268                            FILE ** smimeerr, int smimeinfd, int smimeoutfd,
269                            int smimeerrfd, const char *fname,
270                            const char *sig_fname, const char *cryptalg,
271                            const char *key, const char *certificates,
272                            const char *intermediates, const char *format)
273 {
274   struct smime_command_context cctx;
275   char cmd[HUGE_STRING];
276
277   p_clear(&cctx, 1);
278
279   if (!format || !*format)
280     return (pid_t) - 1;
281
282   cctx.fname = fname;
283   cctx.sig_fname = sig_fname;
284   cctx.key = key;
285   cctx.cryptalg = cryptalg;
286   cctx.certificates = certificates;
287   cctx.intermediates = intermediates;
288
289   mutt_smime_command (cmd, sizeof (cmd), &cctx, format);
290
291   return mutt_create_filter_fd (cmd, smimein, smimeout, smimeerr,
292                                 smimeinfd, smimeoutfd, smimeerrfd);
293 }
294
295
296
297
298
299
300 /*
301  *    Key and certificate handling.
302  */
303
304
305
306 /* 
307    Search the certificate index for given mailbox.
308    return certificate file name.
309 */
310
311 static void smime_entry (char *s, size_t l, MUTTMENU * menu, int num)
312 {
313   smime_id *Table = (smime_id *) menu->data;
314   smime_id this = Table[num];
315   const char *truststate;
316
317   switch (this.trust) {
318   case 't':
319     truststate = N_("Trusted   ");
320     break;
321   case 'v':
322     truststate = N_("Verified  ");
323     break;
324   case 'u':
325     truststate = N_("Unverified");
326     break;
327   case 'e':
328     truststate = N_("Expired   ");
329     break;
330   case 'r':
331     truststate = N_("Revoked   ");
332     break;
333   case 'i':
334     truststate = N_("Invalid   ");
335     break;
336   default:
337     truststate = N_("Unknown   ");
338   }
339   if (this.public)
340     snprintf (s, l, " 0x%.8X.%i %s %-35.35s %s", this.hash, this.suffix,
341               truststate, this.email, this.nick);
342   else
343     snprintf (s, l, " 0x%.8X.%i %-35.35s %s", this.hash, this.suffix,
344               this.email, this.nick);
345 }
346
347
348
349
350
351 char *smime_ask_for_key (char *prompt, char *mailbox, short public)
352 {
353   char *fname;
354   smime_id *Table;
355   long cert_num;                /* Will contain the number of certificates.
356                                  * To be able to get it, the .index file will be read twice... */
357   char index_file[_POSIX_PATH_MAX];
358   FILE *index;
359   char buf[LONG_STRING];
360   char fields[5][STRING];
361   int numFields, hash_suffix, done, cur;        /* The current entry */
362   MUTTMENU *menu;
363   unsigned int hash;
364   char helpstr[HUGE_STRING * 3];
365   char qry[256];
366   char title[256];
367
368   if (!prompt)
369     prompt = _("Enter keyID: ");
370   snprintf (index_file, sizeof (index_file), "%s/.index",
371             public ? NONULL (SmimeCertificates) : NONULL (SmimeKeys));
372
373   index = fopen (index_file, "r");
374   if (index == NULL) {
375     mutt_perror (index_file);
376     return NULL;
377   }
378   /* Count Lines */
379   cert_num = 0;
380   while (!feof (index)) {
381     if (fgets (buf, sizeof (buf), index))
382       cert_num++;
383   }
384   fclose (index);
385
386   for (;;) {
387     *qry = 0;
388     if (mutt_get_field (prompt, qry, sizeof (qry), 0))
389       return NULL;
390     snprintf (title, sizeof (title),
391               _("S/MIME certificates matching \"%s\"."), qry);
392
393
394     index = fopen (index_file, "r");
395     if (index == NULL) {
396       mutt_perror (index_file);
397       return NULL;
398     }
399     /* Read Entries */
400     cur = 0;
401     Table = p_new(smime_id, cert_num);
402     while (!feof (index)) {
403       numFields =
404         fscanf (index, MUTT_FORMAT (STRING) " %x.%i " MUTT_FORMAT (STRING),
405                 fields[0], &hash, &hash_suffix, fields[2]);
406       if (public)
407         fscanf (index, MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) "\n",
408                 fields[3], fields[4]);
409
410       /* 0=email 1=name 2=nick 3=intermediate 4=trust */
411       if (numFields < 2)
412         continue;
413
414       /* Check if query matches this certificate */
415       if (!m_stristr(fields[0], qry) && !m_stristr(fields[2], qry))
416         continue;
417
418       Table[cur].hash = hash;
419       Table[cur].suffix = hash_suffix;
420       m_strcpy(Table[cur].email, sizeof(Table[cur].email), fields[0]);
421       m_strcpy(Table[cur].nick,  sizeof(Table[cur].nick),  fields[2]);
422       Table[cur].trust = *fields[4];
423       Table[cur].public = public;
424
425       cur++;
426     }
427     fclose (index);
428
429     /* Make Helpstring */
430     helpstr[0] = 0;
431     mutt_make_help (buf, sizeof (buf), _("Exit  "), MENU_SMIME, OP_EXIT);
432     strcat (helpstr, buf);      /* __STRCAT_CHECKED__ */
433     mutt_make_help (buf, sizeof (buf), _("Select  "), MENU_SMIME,
434                     OP_GENERIC_SELECT_ENTRY);
435     strcat (helpstr, buf);      /* __STRCAT_CHECKED__ */
436     mutt_make_help (buf, sizeof (buf), _("Help"), MENU_SMIME, OP_HELP);
437     strcat (helpstr, buf);      /* __STRCAT_CHECKED__ */
438
439     /* Create the menu */
440     menu = mutt_new_menu ();
441     menu->max = cur;
442     menu->make_entry = smime_entry;
443     menu->menu = MENU_SMIME;
444     menu->help = helpstr;
445     menu->data = Table;
446     menu->title = title;
447     /* sorting keys might be done later - TODO */
448
449     mutt_clear_error ();
450
451     done = 0;
452     hash = 0;
453     while (!done) {
454       switch (mutt_menuLoop (menu)) {
455       case OP_GENERIC_SELECT_ENTRY:
456         cur = menu->current;
457         hash = 1;
458         done = 1;
459         break;
460       case OP_EXIT:
461         hash = 0;
462         done = 1;
463         break;
464       }
465     }
466     if (hash) {
467       fname = p_new(char, 13); /* Hash + '.' + Suffix + \0 */
468       sprintf (fname, "%.8x.%i", Table[cur].hash, Table[cur].suffix);
469     }
470     else
471       fname = NULL;
472
473     mutt_menuDestroy (&menu);
474     p_delete(&Table);
475     set_option (OPTNEEDREDRAW);
476
477     if (fname)
478       return fname;
479   }
480 }
481
482
483
484 char *smime_get_field_from_db (char *mailbox, char *query, short public,
485                                short may_ask)
486 {
487   int addr_len, query_len, found = 0, ask = 0, choice = 0;
488   char cert_path[_POSIX_PATH_MAX];
489   char buf[LONG_STRING], prompt[STRING];
490   char fields[5][STRING];
491   char key[STRING];
492   int numFields;
493   struct stat info;
494   char key_trust_level = 0;
495   FILE *fp;
496
497   if (!mailbox && !query)
498     return (NULL);
499
500   addr_len = mailbox ? m_strlen(mailbox) : 0;
501   query_len = query ? m_strlen(query) : 0;
502
503   *key = '\0';
504
505   /* index-file format:
506      mailbox certfile label issuer_certfile trust_flags\n
507
508      certfile is a hash value generated by openssl.
509      Note that this was done according to the OpenSSL
510      specs on their CA-directory.
511
512    */
513   snprintf (cert_path, sizeof (cert_path), "%s/.index",
514             (public ? NONULL (SmimeCertificates) : NONULL (SmimeKeys)));
515
516   if (!stat (cert_path, &info)) {
517     if ((fp = safe_fopen (cert_path, "r")) == NULL) {
518       mutt_perror (cert_path);
519       return (NULL);
520     }
521
522     while (fgets (buf, sizeof (buf) - 1, fp) != NULL)
523       if (mailbox && !(m_strncasecmp(mailbox, buf, addr_len))) {
524         numFields = sscanf (buf,
525                             MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) " "
526                             MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) " "
527                             MUTT_FORMAT (STRING) "\n",
528                             fields[0], fields[1],
529                             fields[2], fields[3], fields[4]);
530         if (numFields < 2)
531           continue;
532         if (mailbox && public &&
533             (!fields[4] ||
534              *fields[4] == 'i' || *fields[4] == 'e' || *fields[4] == 'r'))
535           continue;
536
537         if (found) {
538           if (public && *fields[4] == 'u')
539             snprintf (prompt, sizeof (prompt),
540                       _
541                       ("ID %s is unverified. Do you want to use it for %s ?"),
542                       fields[1], mailbox);
543           else if (public && *fields[4] == 'v')
544             snprintf (prompt, sizeof (prompt),
545                       _("Use (untrusted!) ID %s for %s ?"),
546                       fields[1], mailbox);
547           else
548             snprintf (prompt, sizeof (prompt), _("Use ID %s for %s ?"),
549                       fields[1], mailbox);
550           if (may_ask == 0)
551             choice = M_YES;
552           if (may_ask && (choice = mutt_yesorno (prompt, M_NO)) == -1) {
553             found = 0;
554             ask = 0;
555             *key = '\0';
556             break;
557           }
558           else if (choice == M_NO) {
559             ask = 1;
560             continue;
561           }
562           else if (choice == M_YES) {
563             m_strcpy(key, sizeof(key), fields[1]);
564             ask = 0;
565             break;
566           }
567         }
568         else {
569           if (public)
570             key_trust_level = *fields[4];
571           m_strcpy(key, sizeof(key), fields[1]);
572         }
573         found = 1;
574       }
575       else if (query) {
576         numFields = sscanf (buf,
577                             MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) " "
578                             MUTT_FORMAT (STRING) " " MUTT_FORMAT (STRING) " "
579                             MUTT_FORMAT (STRING) "\n",
580                             fields[0], fields[1],
581                             fields[2], fields[3], fields[4]);
582
583         /* query = label: return certificate. */
584         if (numFields >= 3 &&
585             !(m_strncasecmp(query, fields[2], query_len))) {
586           ask = 0;
587           m_strcpy(key, sizeof(key), fields[1]);
588         }
589         /* query = certificate: return intermediate certificate. */
590         else if (numFields >= 4 &&
591                  !(m_strncasecmp(query, fields[1], query_len))) {
592           ask = 0;
593           m_strcpy(key, sizeof(key), fields[3]);
594         }
595       }
596
597     safe_fclose (&fp);
598
599     if (ask) {
600       if (public && *fields[4] == 'u')
601         snprintf (prompt, sizeof (prompt),
602                   _("ID %s is unverified. Do you want to use it for %s ?"),
603                   fields[1], mailbox);
604       else if (public && *fields[4] == 'v')
605         snprintf (prompt, sizeof (prompt),
606                   _("Use (untrusted!) ID %s for %s ?"), fields[1], mailbox);
607       else
608         snprintf (prompt, sizeof (prompt), _("Use ID %s for %s ?"), key,
609                   mailbox);
610       choice = mutt_yesorno (prompt, M_NO);
611       if (choice == -1 || choice == M_NO)
612         *key = '\0';
613     }
614     else if (key_trust_level && may_ask) {
615       if (key_trust_level == 'u') {
616         snprintf (prompt, sizeof (prompt),
617                   _("ID %s is unverified. Do you want to use it for %s ?"),
618                   key, mailbox);
619         choice = mutt_yesorno (prompt, M_NO);
620         if (choice != M_YES)
621           *key = '\0';
622       }
623       else if (key_trust_level == 'v') {
624         mutt_error (_
625                     ("Warning: You have not yet decided to trust ID %s. (any key to continue)"),
626                     key);
627         mutt_sleep (5);
628       }
629     }
630
631   }
632
633   /* Note: m_strdup("") returns NULL. */
634   return m_strdup(key);
635 }
636
637
638
639
640 /* 
641    This sets the '*ToUse' variables for an upcoming decryption, where
642    the reuquired key is different from SmimeDefaultKey.
643 */
644
645 void _smime_getkeys (char *mailbox)
646 {
647   char *k = NULL;
648   char buf[STRING];
649
650   k = smime_get_field_from_db (mailbox, NULL, 0, 1);
651
652   if (!k) {
653     snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), mailbox);
654     k = smime_ask_for_key (buf, mailbox, 0);
655   }
656
657   if (k) {
658     /* the key used last time. */
659     if (*SmimeKeyToUse &&
660         !m_strcasecmp(k, SmimeKeyToUse + m_strlen(SmimeKeys) + 1)) {
661       p_delete(&k);
662       return;
663     }
664     else
665       smime_void_passphrase ();
666
667     snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
668               NONULL (SmimeKeys), k);
669
670     snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
671               NONULL (SmimeCertificates), k);
672
673     if (m_strcasecmp(k, SmimeDefaultKey))
674       smime_void_passphrase ();
675
676     p_delete(&k);
677     return;
678   }
679
680   if (*SmimeKeyToUse) {
681     if (!m_strcasecmp(SmimeDefaultKey,
682                           SmimeKeyToUse + m_strlen(SmimeKeys) + 1))
683       return;
684
685     smime_void_passphrase ();
686   }
687
688   snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
689             NONULL (SmimeKeys), NONULL (SmimeDefaultKey));
690
691   snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
692             NONULL (SmimeCertificates), NONULL (SmimeDefaultKey));
693 }
694
695 void smime_getkeys (ENVELOPE * env)
696 {
697   address_t *t;
698   int found = 0;
699
700   if (option (OPTSDEFAULTDECRYPTKEY) && SmimeDefaultKey && *SmimeDefaultKey) {
701     snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
702               NONULL (SmimeKeys), SmimeDefaultKey);
703
704     snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
705               NONULL (SmimeCertificates), SmimeDefaultKey);
706
707     return;
708   }
709
710   for (t = env->to; !found && t; t = t->next)
711     if (mutt_addr_is_user (t)) {
712       found = 1;
713       _smime_getkeys (t->mailbox);
714     }
715   for (t = env->cc; !found && t; t = t->next)
716     if (mutt_addr_is_user (t)) {
717       found = 1;
718       _smime_getkeys (t->mailbox);
719     }
720   if (!found && (t = mutt_default_from ())) {
721     _smime_getkeys (t->mailbox);
722     address_delete (&t);
723   }
724 }
725
726 /* This routine attempts to find the keyids of the recipients of a message.
727  * It returns NULL if any of the keys can not be found.
728  */
729
730 char *smime_findKeys (address_t * to, address_t * cc, address_t * bcc)
731 {
732   char *keyID, *keylist = NULL;
733   size_t keylist_size = 0;
734   size_t keylist_used = 0;
735   address_t *tmp = NULL, *addr = NULL;
736   address_t **last = &tmp;
737   address_t *p, *q;
738   int i;
739
740   const char *fqdn = mutt_fqdn (1);
741
742   for (i = 0; i < 3; i++) {
743     switch (i) {
744     case 0:
745       p = to;
746       break;
747     case 1:
748       p = cc;
749       break;
750     case 2:
751       p = bcc;
752       break;
753     default:
754       abort ();
755     }
756
757     *last = address_list_dup (p);
758     while (*last)
759       last = &((*last)->next);
760   }
761
762   if (fqdn)
763     rfc822_qualify (tmp, fqdn);
764
765   tmp = mutt_remove_duplicates (tmp);
766
767   for (p = tmp; p; p = p->next) {
768     char buf[LONG_STRING];
769
770     q = p;
771
772     if ((keyID = smime_get_field_from_db (q->mailbox, NULL, 1, 1)) == NULL) {
773       snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
774       keyID = smime_ask_for_key (buf, q->mailbox, 1);
775     }
776     if (!keyID) {
777       mutt_message (_("No (valid) certificate found for %s."), q->mailbox);
778       p_delete(&keylist);
779       address_delete (&tmp);
780       address_delete (&addr);
781       return NULL;
782     }
783
784     keylist_size += m_strlen(keyID) + 2;
785     p_realloc(&keylist, keylist_size);
786     sprintf (keylist + keylist_used, "%s\n", keyID);    /* __SPRINTF_CHECKED__ */
787     keylist_used = m_strlen(keylist);
788
789     address_delete (&addr);
790
791   }
792   address_delete (&tmp);
793   return (keylist);
794 }
795
796
797
798
799
800
801 static int smime_handle_cert_email (char *certificate, char *mailbox,
802                                     int copy, char ***buffer, int *num)
803 {
804   FILE *fpout = NULL, *fperr = NULL;
805   char tmpfname[_POSIX_PATH_MAX];
806   char email[STRING];
807   int ret = -1, count = 0;
808   pid_t thepid;
809
810   mutt_mktemp (tmpfname);
811   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL) {
812     mutt_perror (tmpfname);
813     return 1;
814   }
815   mutt_unlink (tmpfname);
816
817   mutt_mktemp (tmpfname);
818   if ((fpout = safe_fopen (tmpfname, "w+")) == NULL) {
819     fclose (fperr);
820     mutt_perror (tmpfname);
821     return 1;
822   }
823   mutt_unlink (tmpfname);
824
825   if ((thepid = smime_invoke (NULL, NULL, NULL,
826                               -1, fileno (fpout), fileno (fperr),
827                               certificate, NULL, NULL, NULL, NULL, NULL,
828                               SmimeGetCertEmailCommand)) == -1) {
829     mutt_message (_("Error: unable to create OpenSSL subprocess!"));
830     fclose (fperr);
831     fclose (fpout);
832     return 1;
833   }
834
835   mutt_wait_filter (thepid);
836
837   fflush (fpout);
838   rewind (fpout);
839   rewind (fperr);
840   fflush (fperr);
841
842
843   while ((fgets (email, sizeof (email), fpout))) {
844     *(email + m_strlen(email) - 1) = '\0';
845     if (m_strncasecmp(email, mailbox, m_strlen(mailbox)) == 0)
846       ret = 1;
847
848     ret = ret < 0 ? 0 : ret;
849     count++;
850   }
851
852   if (ret == -1) {
853     mutt_endwin (NULL);
854     mutt_copy_stream (fperr, stdout);
855     mutt_any_key_to_continue (_
856                               ("Error: unable to create OpenSSL subprocess!"));
857     ret = 1;
858   }
859   else if (!ret)
860     ret = 1;
861   else
862     ret = 0;
863
864   if (copy && buffer && num) {
865     (*num) = count;
866     *buffer = p_new(char *, count);
867     count = 0;
868
869     rewind (fpout);
870     while ((fgets (email, sizeof (email), fpout))) {
871       *(email + m_strlen(email) - 1) = '\0';
872       (*buffer)[count] = p_dupstr(email, m_strlen(email));
873       count++;
874     }
875   }
876   else if (copy)
877     ret = 2;
878
879   fclose (fpout);
880   fclose (fperr);
881
882   return ret;
883 }
884
885
886
887 static char *smime_extract_certificate (char *infile)
888 {
889   FILE *fpout = NULL, *fperr = NULL;
890   char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
891   char tmpfname[_POSIX_PATH_MAX];
892   pid_t thepid;
893   int empty;
894
895
896   mutt_mktemp (tmpfname);
897   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL) {
898     mutt_perror (tmpfname);
899     return NULL;
900   }
901   mutt_unlink (tmpfname);
902
903   mutt_mktemp (pk7out);
904   if ((fpout = safe_fopen (pk7out, "w+")) == NULL) {
905     fclose (fperr);
906     mutt_perror (pk7out);
907     return NULL;
908   }
909
910   /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
911      extract the full set of certificates directly.
912    */
913   if ((thepid = smime_invoke (NULL, NULL, NULL,
914                               -1, fileno (fpout), fileno (fperr),
915                               infile, NULL, NULL, NULL, NULL, NULL,
916                               SmimePk7outCommand)) == -1) {
917     mutt_any_key_to_continue (_
918                               ("Error: unable to create OpenSSL subprocess!"));
919     fclose (fperr);
920     fclose (fpout);
921     mutt_unlink (pk7out);
922     return NULL;
923   }
924
925   mutt_wait_filter (thepid);
926
927
928   fflush (fpout);
929   rewind (fpout);
930   rewind (fperr);
931   fflush (fperr);
932   empty = (fgetc (fpout) == EOF);
933   if (empty) {
934     mutt_perror (pk7out);
935     mutt_copy_stream (fperr, stdout);
936     fclose (fpout);
937     fclose (fperr);
938     mutt_unlink (pk7out);
939     return NULL;
940
941   }
942
943
944   fclose (fpout);
945   mutt_mktemp (certfile);
946   if ((fpout = safe_fopen (certfile, "w+")) == NULL) {
947     fclose (fperr);
948     mutt_unlink (pk7out);
949     mutt_perror (certfile);
950     return NULL;
951   }
952
953   /* Step 2: Extract the certificates from a PKCS#7 structure.
954    */
955   if ((thepid = smime_invoke (NULL, NULL, NULL,
956                               -1, fileno (fpout), fileno (fperr),
957                               pk7out, NULL, NULL, NULL, NULL, NULL,
958                               SmimeGetCertCommand)) == -1) {
959     mutt_any_key_to_continue (_
960                               ("Error: unable to create OpenSSL subprocess!"));
961     fclose (fperr);
962     fclose (fpout);
963     mutt_unlink (pk7out);
964     mutt_unlink (certfile);
965     return NULL;
966   }
967
968   mutt_wait_filter (thepid);
969
970   mutt_unlink (pk7out);
971
972   fflush (fpout);
973   rewind (fpout);
974   rewind (fperr);
975   fflush (fperr);
976   empty = (fgetc (fpout) == EOF);
977   if (empty) {
978     mutt_copy_stream (fperr, stdout);
979     fclose (fpout);
980     fclose (fperr);
981     mutt_unlink (certfile);
982     return NULL;
983   }
984
985   fclose (fpout);
986   fclose (fperr);
987
988   return m_strdup(certfile);
989 }
990
991 static char *smime_extract_signer_certificate (char *infile)
992 {
993   FILE *fpout = NULL, *fperr = NULL;
994   char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
995   char tmpfname[_POSIX_PATH_MAX];
996   pid_t thepid;
997   int empty;
998
999
1000   mutt_mktemp (tmpfname);
1001   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL) {
1002     mutt_perror (tmpfname);
1003     return NULL;
1004   }
1005   mutt_unlink (tmpfname);
1006
1007
1008   mutt_mktemp (certfile);
1009   if ((fpout = safe_fopen (certfile, "w+")) == NULL) {
1010     fclose (fperr);
1011     mutt_perror (certfile);
1012     return NULL;
1013   }
1014
1015   /* Extract signer's certificate
1016    */
1017   if ((thepid = smime_invoke (NULL, NULL, NULL,
1018                               -1, -1, fileno (fperr),
1019                               infile, NULL, NULL, NULL, certfile, NULL,
1020                               SmimeGetSignerCertCommand)) == -1) {
1021     mutt_any_key_to_continue (_
1022                               ("Error: unable to create OpenSSL subprocess!"));
1023     fclose (fperr);
1024     fclose (fpout);
1025     mutt_unlink (pk7out);
1026     mutt_unlink (certfile);
1027     return NULL;
1028   }
1029
1030   mutt_wait_filter (thepid);
1031
1032   fflush (fpout);
1033   rewind (fpout);
1034   rewind (fperr);
1035   fflush (fperr);
1036   empty = (fgetc (fpout) == EOF);
1037   if (empty) {
1038     mutt_endwin (NULL);
1039     mutt_copy_stream (fperr, stdout);
1040     mutt_any_key_to_continue (NULL);
1041     fclose (fpout);
1042     fclose (fperr);
1043     mutt_unlink (certfile);
1044     return NULL;
1045   }
1046
1047   fclose (fpout);
1048   fclose (fperr);
1049
1050   return m_strdup(certfile);
1051 }
1052
1053
1054
1055
1056 /* Add a certificate and update index file (externally). */
1057
1058 void smime_invoke_import (char *infile, char *mailbox)
1059 {
1060   char tmpfname[_POSIX_PATH_MAX], *certfile = NULL, buf[STRING];
1061   FILE *smimein = NULL, *fpout = NULL, *fperr = NULL;
1062   pid_t thepid = -1;
1063
1064   mutt_mktemp (tmpfname);
1065   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL) {
1066     mutt_perror (tmpfname);
1067     return;
1068   }
1069   mutt_unlink (tmpfname);
1070
1071   mutt_mktemp (tmpfname);
1072   if ((fpout = safe_fopen (tmpfname, "w+")) == NULL) {
1073     fclose (fperr);
1074     mutt_perror (tmpfname);
1075     return;
1076   }
1077   mutt_unlink (tmpfname);
1078
1079
1080   buf[0] = '\0';
1081   if (option (OPTASKCERTLABEL))
1082     mutt_get_field ("Label for certificate:", buf, sizeof (buf), 0);
1083
1084   mutt_endwin (NULL);
1085   if ((certfile = smime_extract_certificate (infile))) {
1086     mutt_endwin (NULL);
1087
1088     if ((thepid = smime_invoke (&smimein, NULL, NULL,
1089                                 -1, fileno (fpout), fileno (fperr),
1090                                 certfile, NULL, NULL, NULL, NULL, NULL,
1091                                 SmimeImportCertCommand)) == -1) {
1092       mutt_message (_("Error: unable to create OpenSSL subprocess!"));
1093       return;
1094     }
1095     fputs (buf, smimein);
1096     fputc ('\n', smimein);
1097     fclose (smimein);
1098
1099     mutt_wait_filter (thepid);
1100
1101     mutt_unlink (certfile);
1102     p_delete(&certfile);
1103   }
1104
1105   fflush (fpout);
1106   rewind (fpout);
1107   fflush (fperr);
1108   rewind (fperr);
1109
1110   mutt_copy_stream (fpout, stdout);
1111   mutt_copy_stream (fperr, stdout);
1112
1113   fclose (fpout);
1114   fclose (fperr);
1115
1116 }
1117
1118
1119
1120 int smime_verify_sender (HEADER * h)
1121 {
1122   char *mbox = NULL, *certfile, tempfname[_POSIX_PATH_MAX];
1123   FILE *fpout;
1124   int retval = 1;
1125
1126   mutt_mktemp (tempfname);
1127   if (!(fpout = safe_fopen (tempfname, "w"))) {
1128     mutt_perror (tempfname);
1129     return 1;
1130   }
1131
1132   if (h->security & ENCRYPT)
1133     mutt_copy_message (fpout, Context, h,
1134                        M_CM_DECODE_CRYPT & M_CM_DECODE_SMIME,
1135                        CH_MIME | CH_WEED | CH_NONEWLINE);
1136   else
1137     mutt_copy_message (fpout, Context, h, 0, 0);
1138
1139   fflush (fpout);
1140   fclose (fpout);
1141
1142   if (h->env->from) {
1143     h->env->from = mutt_expand_aliases (h->env->from);
1144     mbox = h->env->from->mailbox;
1145   }
1146   else if (h->env->sender) {
1147     h->env->sender = mutt_expand_aliases (h->env->sender);
1148     mbox = h->env->sender->mailbox;
1149   }
1150
1151   if (mbox) {
1152     if ((certfile = smime_extract_signer_certificate (tempfname))) {
1153       mutt_unlink (tempfname);
1154       if (smime_handle_cert_email (certfile, mbox, 0, NULL, NULL)) {
1155         if (isendwin ())
1156           mutt_any_key_to_continue (NULL);
1157       }
1158       else
1159         retval = 0;
1160       mutt_unlink (certfile);
1161       p_delete(&certfile);
1162     }
1163     else
1164       mutt_any_key_to_continue (_("no certfile"));
1165   }
1166   else
1167     mutt_any_key_to_continue (_("no mbox"));
1168
1169   mutt_unlink (tempfname);
1170   return retval;
1171 }
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181 /*
1182  *    Creating S/MIME - bodies.
1183  */
1184
1185
1186
1187
1188 static
1189 pid_t smime_invoke_encrypt (FILE ** smimein, FILE ** smimeout,
1190                             FILE ** smimeerr, int smimeinfd, int smimeoutfd,
1191                             int smimeerrfd, const char *fname,
1192                             const char *uids)
1193 {
1194   return smime_invoke (smimein, smimeout, smimeerr,
1195                        smimeinfd, smimeoutfd, smimeerrfd,
1196                        fname, NULL, SmimeCryptAlg, NULL, uids, NULL,
1197                        SmimeEncryptCommand);
1198 }
1199
1200
1201 static
1202 pid_t smime_invoke_sign (FILE ** smimein, FILE ** smimeout, FILE ** smimeerr,
1203                          int smimeinfd, int smimeoutfd, int smimeerrfd,
1204                          const char *fname)
1205 {
1206   return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1207                        smimeerrfd, fname, NULL, NULL, SmimeKeyToUse,
1208                        SmimeCertToUse, SmimeIntermediateToUse,
1209                        SmimeSignCommand);
1210 }
1211
1212
1213
1214
1215 BODY *smime_build_smime_entity (BODY * a, char *certlist)
1216 {
1217   char buf[LONG_STRING], certfile[LONG_STRING];
1218   char tempfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
1219   char smimeinfile[_POSIX_PATH_MAX];
1220   char *cert_start = certlist, *cert_end = certlist;
1221   FILE *smimein = NULL, *smimeerr = NULL, *fpout = NULL, *fptmp = NULL;
1222   BODY *t;
1223   int err = 0, empty;
1224   pid_t thepid;
1225
1226   mutt_mktemp (tempfile);
1227   if ((fpout = safe_fopen (tempfile, "w+")) == NULL) {
1228     mutt_perror (tempfile);
1229     return (NULL);
1230   }
1231
1232   mutt_mktemp (smimeerrfile);
1233   if ((smimeerr = safe_fopen (smimeerrfile, "w+")) == NULL) {
1234     mutt_perror (smimeerrfile);
1235     fclose (fpout);
1236     mutt_unlink (tempfile);
1237     return NULL;
1238   }
1239   mutt_unlink (smimeerrfile);
1240
1241   mutt_mktemp (smimeinfile);
1242   if ((fptmp = safe_fopen (smimeinfile, "w+")) == NULL) {
1243     mutt_perror (smimeinfile);
1244     mutt_unlink (tempfile);
1245     fclose (fpout);
1246     fclose (smimeerr);
1247     return NULL;
1248   }
1249
1250   *certfile = '\0';
1251   while (1) {
1252     int off = m_strlen(certfile);
1253
1254     while (*++cert_end && *cert_end != '\n');
1255     if (!*cert_end)
1256       break;
1257     *cert_end = '\0';
1258     snprintf (certfile + off, sizeof (certfile) - off, " %s/%s",
1259               NONULL (SmimeCertificates), cert_start);
1260     *cert_end = '\n';
1261     cert_start = cert_end;
1262     cert_start++;
1263   }
1264
1265   /* write a MIME entity */
1266   mutt_write_mime_header (a, fptmp);
1267   fputc ('\n', fptmp);
1268   mutt_write_mime_body (a, fptmp);
1269   fclose (fptmp);
1270
1271   if ((thepid =
1272        smime_invoke_encrypt (&smimein, NULL, NULL, -1,
1273                              fileno (fpout), fileno (smimeerr),
1274                              smimeinfile, certfile)) == -1) {
1275     fclose (smimeerr);
1276     mutt_unlink (smimeinfile);
1277     mutt_unlink (certfile);
1278     return (NULL);
1279   }
1280
1281   fclose (smimein);
1282
1283   mutt_wait_filter (thepid);
1284   mutt_unlink (smimeinfile);
1285   mutt_unlink (certfile);
1286
1287   fflush (fpout);
1288   rewind (fpout);
1289   empty = (fgetc (fpout) == EOF);
1290   fclose (fpout);
1291
1292   fflush (smimeerr);
1293   rewind (smimeerr);
1294   while (fgets (buf, sizeof (buf) - 1, smimeerr) != NULL) {
1295     err = 1;
1296     fputs (buf, stdout);
1297   }
1298   fclose (smimeerr);
1299
1300   /* pause if there is any error output from SMIME */
1301   if (err)
1302     mutt_any_key_to_continue (NULL);
1303
1304   if (empty) {
1305     /* fatal error while trying to encrypt message */
1306     if (!err)
1307       mutt_any_key_to_continue _("No output from OpenSSL..");
1308
1309     mutt_unlink (tempfile);
1310     return (NULL);
1311   }
1312
1313   t = mutt_new_body ();
1314   t->type = TYPEAPPLICATION;
1315   t->subtype = m_strdup("x-pkcs7-mime");
1316   mutt_set_parameter ("name", "smime.p7m", &t->parameter);
1317   mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
1318   t->encoding = ENCBASE64;      /* The output of OpenSSL SHOULD be binary */
1319   t->use_disp = 1;
1320   t->disposition = DISPATTACH;
1321   t->d_filename = m_strdup("smime.p7m");
1322   t->filename = m_strdup(tempfile);
1323   t->unlink = 1;                /*delete after sending the message */
1324   t->parts = 0;
1325   t->next = 0;
1326
1327   return (t);
1328 }
1329
1330
1331
1332
1333 BODY *smime_sign_message (BODY * a)
1334 {
1335   BODY *t;
1336   char buffer[LONG_STRING];
1337   char signedfile[_POSIX_PATH_MAX], filetosign[_POSIX_PATH_MAX];
1338   FILE *smimein = NULL, *smimeout = NULL, *smimeerr = NULL, *sfp = NULL;
1339   int err = 0;
1340   int empty = 0;
1341   pid_t thepid;
1342   char *intermediates = smime_get_field_from_db (NULL, SmimeDefaultKey, 1, 1);
1343
1344   if (!intermediates) {
1345     mutt_message (_("Warning: Intermediate certificate not found."));
1346     intermediates = SmimeDefaultKey;    /* so openssl won't complain in any case */
1347   }
1348
1349   convert_to_7bit (a);          /* Signed data _must_ be in 7-bit format. */
1350
1351   mutt_mktemp (filetosign);
1352   if ((sfp = safe_fopen (filetosign, "w+")) == NULL) {
1353     mutt_perror (filetosign);
1354     return NULL;
1355   }
1356
1357   mutt_mktemp (signedfile);
1358   if ((smimeout = safe_fopen (signedfile, "w+")) == NULL) {
1359     mutt_perror (signedfile);
1360     fclose (sfp);
1361     mutt_unlink (filetosign);
1362     return NULL;
1363   }
1364
1365   mutt_write_mime_header (a, sfp);
1366   fputc ('\n', sfp);
1367   mutt_write_mime_body (a, sfp);
1368   fclose (sfp);
1369
1370
1371
1372   snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
1373             NONULL (SmimeKeys), SmimeDefaultKey);
1374
1375   snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
1376             NONULL (SmimeCertificates), SmimeDefaultKey);
1377
1378   snprintf (SmimeIntermediateToUse, sizeof (SmimeIntermediateToUse), "%s/%s",
1379             NONULL (SmimeCertificates), intermediates);
1380
1381
1382
1383   if ((thepid = smime_invoke_sign (&smimein, NULL, &smimeerr,
1384                                    -1, fileno (smimeout), -1,
1385                                    filetosign)) == -1) {
1386     mutt_perror (_("Can't open OpenSSL subprocess!"));
1387
1388     fclose (smimeout);
1389     mutt_unlink (signedfile);
1390     mutt_unlink (filetosign);
1391     return NULL;
1392   }
1393   fputs (SmimePass, smimein);
1394   fputc ('\n', smimein);
1395   fclose (smimein);
1396
1397
1398   mutt_wait_filter (thepid);
1399
1400   /* check for errors from OpenSSL */
1401   err = 0;
1402   fflush (smimeerr);
1403   rewind (smimeerr);
1404   while (fgets (buffer, sizeof (buffer) - 1, smimeerr) != NULL) {
1405     err = 1;
1406     fputs (buffer, stdout);
1407   }
1408   fclose (smimeerr);
1409
1410
1411   fflush (smimeout);
1412   rewind (smimeout);
1413   empty = (fgetc (smimeout) == EOF);
1414   fclose (smimeout);
1415
1416   mutt_unlink (filetosign);
1417
1418
1419   if (err)
1420     mutt_any_key_to_continue (NULL);
1421
1422   if (empty) {
1423     mutt_any_key_to_continue _("No output from OpenSSL...");
1424
1425     mutt_unlink (signedfile);
1426     return (NULL);              /* fatal error while signing */
1427   }
1428
1429   t = mutt_new_body ();
1430   t->type = TYPEMULTIPART;
1431   t->subtype = m_strdup("signed");
1432   t->encoding = ENC7BIT;
1433   t->use_disp = 0;
1434   t->disposition = DISPINLINE;
1435
1436   mutt_generate_boundary (&t->parameter);
1437   /* check if this can be extracted from private key somehow.... */
1438   mutt_set_parameter ("micalg", "sha1", &t->parameter);
1439   mutt_set_parameter ("protocol", "application/x-pkcs7-signature",
1440                       &t->parameter);
1441
1442   t->parts = a;
1443   a = t;
1444
1445   t->parts->next = mutt_new_body ();
1446   t = t->parts->next;
1447   t->type = TYPEAPPLICATION;
1448   t->subtype = m_strdup("x-pkcs7-signature");
1449   t->filename = m_strdup(signedfile);
1450   t->d_filename = m_strdup("smime.p7s");
1451   t->use_disp = 1;
1452   t->disposition = DISPATTACH;
1453   t->encoding = ENCBASE64;
1454   t->unlink = 1;                /* ok to remove this file after sending. */
1455
1456   return (a);
1457
1458 }
1459
1460
1461
1462
1463
1464
1465 /*
1466  *    Handling S/MIME - bodies.
1467  */
1468
1469
1470
1471
1472
1473
1474 static
1475 pid_t smime_invoke_verify (FILE ** smimein, FILE ** smimeout,
1476                            FILE ** smimeerr, int smimeinfd, int smimeoutfd,
1477                            int smimeerrfd, const char *fname,
1478                            const char *sig_fname, int opaque)
1479 {
1480   return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1481                        smimeerrfd, fname, sig_fname, NULL, NULL, NULL, NULL,
1482                        (opaque ? SmimeVerifyOpaqueCommand :
1483                         SmimeVerifyCommand));
1484 }
1485
1486
1487 static
1488 pid_t smime_invoke_decrypt (FILE ** smimein, FILE ** smimeout,
1489                             FILE ** smimeerr, int smimeinfd, int smimeoutfd,
1490                             int smimeerrfd, const char *fname)
1491 {
1492   return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1493                        smimeerrfd, fname, NULL, NULL, SmimeKeyToUse,
1494                        SmimeCertToUse, NULL, SmimeDecryptCommand);
1495 }
1496
1497
1498
1499 int smime_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
1500 {
1501   char signedfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
1502   FILE *fp = NULL, *smimeout = NULL, *smimeerr = NULL;
1503   pid_t thepid;
1504   int badsig = -1;
1505
1506   long tmpoffset = 0;
1507   size_t tmplength = 0;
1508   int origType = sigbdy->type;
1509   char *savePrefix = NULL;
1510
1511
1512   snprintf (signedfile, sizeof (signedfile), "%s.sig", tempfile);
1513
1514   /* decode to a tempfile, saving the original destination */
1515   fp = s->fpout;
1516   if ((s->fpout = safe_fopen (signedfile, "w")) == NULL) {
1517     mutt_perror (signedfile);
1518     return -1;
1519   }
1520   /* decoding the attachment changes the size and offset, so save a copy
1521    * of the "real" values now, and restore them after processing
1522    */
1523   tmplength = sigbdy->length;
1524   tmpoffset = sigbdy->offset;
1525
1526   /* if we are decoding binary bodies, we don't want to prefix each
1527    * line with the prefix or else the data will get corrupted.
1528    */
1529   savePrefix = s->prefix;
1530   s->prefix = NULL;
1531
1532   mutt_decode_attachment (sigbdy, s);
1533
1534   sigbdy->length = ftello (s->fpout);
1535   sigbdy->offset = 0;
1536   fclose (s->fpout);
1537
1538   /* restore final destination and substitute the tempfile for input */
1539   s->fpout = fp;
1540   fp = s->fpin;
1541   s->fpin = fopen (signedfile, "r");
1542
1543   /* restore the prefix */
1544   s->prefix = savePrefix;
1545
1546   sigbdy->type = origType;
1547
1548
1549   mutt_mktemp (smimeerrfile);
1550   if (!(smimeerr = safe_fopen (smimeerrfile, "w+"))) {
1551     mutt_perror (smimeerrfile);
1552     mutt_unlink (signedfile);
1553     return -1;
1554   }
1555
1556   crypt_current_time (s, "OpenSSL");
1557
1558   if ((thepid = smime_invoke_verify (NULL, &smimeout, NULL,
1559                                      -1, -1, fileno (smimeerr),
1560                                      tempfile, signedfile, 0)) != -1) {
1561     fflush (smimeout);
1562     fclose (smimeout);
1563
1564     if (mutt_wait_filter (thepid))
1565       badsig = -1;
1566     else {
1567       char *line = NULL;
1568       int lineno = 0;
1569       size_t linelen;
1570
1571       fflush (smimeerr);
1572       rewind (smimeerr);
1573
1574       line = mutt_read_line (line, &linelen, smimeerr, &lineno);
1575       if (linelen && !m_strcasecmp(line, "verification successful"))
1576         badsig = 0;
1577
1578       p_delete(&line);
1579     }
1580   }
1581
1582   fflush (smimeerr);
1583   rewind (smimeerr);
1584   mutt_copy_stream (smimeerr, s->fpout);
1585   fclose (smimeerr);
1586
1587   state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
1588
1589   mutt_unlink (signedfile);
1590   mutt_unlink (smimeerrfile);
1591
1592   sigbdy->length = tmplength;
1593   sigbdy->offset = tmpoffset;
1594
1595   /* restore the original source stream */
1596   fclose (s->fpin);
1597   s->fpin = fp;
1598
1599
1600   return badsig;
1601 }
1602
1603
1604
1605
1606
1607 /*
1608   This handles application/pkcs7-mime which can either be a signed
1609   or an encrypted message.
1610 */
1611
1612 static BODY *smime_handle_entity (BODY * m, STATE * s, FILE * outFile)
1613 {
1614   int len = 0;
1615   int c;
1616   long last_pos;
1617   char buf[HUGE_STRING];
1618   char outfile[_POSIX_PATH_MAX], errfile[_POSIX_PATH_MAX];
1619   char tmpfname[_POSIX_PATH_MAX];
1620   char tmptmpfname[_POSIX_PATH_MAX];
1621   FILE *smimeout = NULL, *smimein = NULL, *smimeerr = NULL;
1622   FILE *tmpfp = NULL, *tmpfp_buffer = NULL, *fpout = NULL;
1623   struct stat info;
1624   BODY *p = NULL;
1625   pid_t thepid = -1;
1626   unsigned int type = mutt_is_application_smime (m);
1627
1628   if (!(type & APPLICATION_SMIME))
1629     return NULL;
1630
1631   mutt_mktemp (outfile);
1632   if ((smimeout = safe_fopen (outfile, "w+")) == NULL) {
1633     mutt_perror (outfile);
1634     return NULL;
1635   }
1636
1637   mutt_mktemp (errfile);
1638   if ((smimeerr = safe_fopen (errfile, "w+")) == NULL) {
1639     mutt_perror (errfile);
1640     fclose (smimeout);
1641     smimeout = NULL;
1642     return NULL;
1643   }
1644   mutt_unlink (errfile);
1645
1646
1647   mutt_mktemp (tmpfname);
1648   if ((tmpfp = safe_fopen (tmpfname, "w+")) == NULL) {
1649     mutt_perror (tmpfname);
1650     fclose (smimeout);
1651     smimeout = NULL;
1652     fclose (smimeerr);
1653     smimeerr = NULL;
1654     return NULL;
1655   }
1656
1657   fseeko (s->fpin, m->offset, 0);
1658   last_pos = m->offset;
1659
1660   mutt_copy_bytes (s->fpin, tmpfp, m->length);
1661
1662   fflush (tmpfp);
1663   fclose (tmpfp);
1664
1665   if ((type & ENCRYPT) &&
1666       (thepid = smime_invoke_decrypt (&smimein, NULL, NULL, -1,
1667                                       fileno (smimeout), fileno (smimeerr),
1668                                       tmpfname)) == -1) {
1669     fclose (smimeout);
1670     smimeout = NULL;
1671     mutt_unlink (tmpfname);
1672     if (s->flags & M_DISPLAY)
1673       state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
1674     return NULL;
1675   }
1676   else if ((type & SIGNOPAQUE) &&
1677            (thepid = smime_invoke_verify (&smimein, NULL, NULL, -1,
1678                                           fileno (smimeout),
1679                                           fileno (smimeerr), NULL, tmpfname,
1680                                           SIGNOPAQUE)) == -1) {
1681     fclose (smimeout);
1682     smimeout = NULL;
1683     mutt_unlink (tmpfname);
1684     if (s->flags & M_DISPLAY)
1685       state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
1686     return NULL;
1687   }
1688
1689
1690   if (type & ENCRYPT) {
1691     if (!smime_valid_passphrase ())
1692       smime_void_passphrase ();
1693     fputs (SmimePass, smimein);
1694     fputc ('\n', smimein);
1695   }
1696
1697   fclose (smimein);
1698
1699   mutt_wait_filter (thepid);
1700   mutt_unlink (tmpfname);
1701
1702
1703   if (s->flags & M_DISPLAY) {
1704     rewind (smimeerr);
1705
1706     if ((c = fgetc (smimeerr)) != EOF) {
1707       ungetc (c, smimeerr);
1708
1709       crypt_current_time (s, "OpenSSL");
1710       mutt_copy_stream (smimeerr, s->fpout);
1711       state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
1712     }
1713
1714     if (type & ENCRYPT)
1715       state_attach_puts (_("[-- The following data is S/MIME"
1716                            " encrypted --]\n"), s);
1717     else
1718       state_attach_puts (_("[-- The following data is S/MIME signed --]\n"),
1719                          s);
1720   }
1721
1722   if (smimeout) {
1723     fflush (smimeout);
1724     rewind (smimeout);
1725
1726     if (outFile)
1727       fpout = outFile;
1728     else {
1729       mutt_mktemp (tmptmpfname);
1730       if ((fpout = safe_fopen (tmptmpfname, "w+")) == NULL) {
1731         mutt_perror (tmptmpfname);
1732         fclose (smimeout);
1733         smimeout = NULL;
1734         return NULL;
1735       }
1736     }
1737     while (fgets (buf, sizeof (buf) - 1, smimeout) != NULL) {
1738       len = m_strlen(buf);
1739       if (len > 1 && buf[len - 2] == '\r') {
1740         buf[len - 2] = '\n';
1741         buf[len - 1] = '\0';
1742       }
1743       fputs (buf, fpout);
1744     }
1745     fflush (fpout);
1746     rewind (fpout);
1747
1748
1749     if ((p = mutt_read_mime_header (fpout, 0)) != NULL) {
1750       fstat (fileno (fpout), &info);
1751       p->length = info.st_size - p->offset;
1752
1753       mutt_parse_part (fpout, p);
1754       if (s->fpout) {
1755         rewind (fpout);
1756         tmpfp_buffer = s->fpin;
1757         s->fpin = fpout;
1758         mutt_body_handler (p, s);
1759         s->fpin = tmpfp_buffer;
1760       }
1761
1762     }
1763     fclose (smimeout);
1764     smimeout = NULL;
1765     mutt_unlink (outfile);
1766
1767     if (!outFile) {
1768       fclose (fpout);
1769       mutt_unlink (tmptmpfname);
1770     }
1771     fpout = NULL;
1772   }
1773
1774   if (s->flags & M_DISPLAY) {
1775     if (type & ENCRYPT)
1776       state_attach_puts (_("\n[-- End of S/MIME encrypted data. --]\n"), s);
1777     else
1778       state_attach_puts (_("\n[-- End of S/MIME signed data. --]\n"), s);
1779   }
1780
1781   if (type & SIGNOPAQUE) {
1782     char *line = NULL;
1783     int lineno = 0;
1784     size_t linelen;
1785
1786     rewind (smimeerr);
1787
1788     line = mutt_read_line (line, &linelen, smimeerr, &lineno);
1789     if (linelen && !m_strcasecmp(line, "verification successful"))
1790       m->goodsig = 1;
1791     p_delete(&line);
1792   }
1793   else {
1794     m->goodsig = p->goodsig;
1795     m->badsig = p->badsig;
1796   }
1797   fclose (smimeerr);
1798
1799   return (p);
1800 }
1801
1802
1803
1804
1805
1806 int smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1807 {
1808
1809
1810   char tempfile[_POSIX_PATH_MAX];
1811   STATE s;
1812   long tmpoffset = b->offset;
1813   size_t tmplength = b->length;
1814   int origType = b->type;
1815   FILE *tmpfp = NULL;
1816   int rv = 0;
1817
1818   if (!mutt_is_application_smime (b))
1819     return -1;
1820
1821   if (b->parts)
1822     return -1;
1823
1824   p_clear(&s, 1);
1825   s.fpin = fpin;
1826   fseeko (s.fpin, b->offset, 0);
1827
1828   mutt_mktemp (tempfile);
1829   if ((tmpfp = safe_fopen (tempfile, "w+")) == NULL) {
1830     mutt_perror (tempfile);
1831     return (-1);
1832   }
1833
1834   mutt_unlink (tempfile);
1835   s.fpout = tmpfp;
1836   mutt_decode_attachment (b, &s);
1837   fflush (tmpfp);
1838   b->length = ftello (s.fpout);
1839   b->offset = 0;
1840   rewind (tmpfp);
1841   s.fpin = tmpfp;
1842   s.fpout = 0;
1843
1844   mutt_mktemp (tempfile);
1845   if ((*fpout = safe_fopen (tempfile, "w+")) == NULL) {
1846     mutt_perror (tempfile);
1847     rv = -1;
1848     goto bail;
1849   }
1850   mutt_unlink (tempfile);
1851
1852   if (!(*cur = smime_handle_entity (b, &s, *fpout))) {
1853     rv = -1;
1854     goto bail;
1855   }
1856
1857   (*cur)->goodsig = b->goodsig;
1858   (*cur)->badsig  = b->badsig;
1859
1860 bail:
1861   b->type = origType;
1862   b->length = tmplength;
1863   b->offset = tmpoffset;
1864
1865   safe_fclose (&tmpfp);
1866   if (*fpout)
1867     rewind (*fpout);
1868   return (rv);
1869 }
1870
1871
1872 int smime_application_smime_handler (BODY * m, STATE * s)
1873 {
1874   return smime_handle_entity (m, s, NULL) ? 0 : -1;
1875 }
1876
1877 int smime_send_menu (HEADER * msg, int *redraw)
1878 {
1879   char *p;
1880
1881   switch (mutt_multi_choice
1882           (_("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, or (c)lear? "),
1883            _("eswabfc"))) {
1884   case 1:                      /* (e)ncrypt */
1885     msg->security |= ENCRYPT;
1886     msg->security &= ~SIGN;
1887     break;
1888
1889   case 3:                      /* encrypt (w)ith */
1890     {
1891       int choice = 0;
1892       msg->security |= ENCRYPT;
1893
1894       do {
1895         /* I use "dra" because "123" is recognized anyway */
1896         switch (mutt_multi_choice (_("Choose algorithm family:"
1897                                      " 1: DES, 2: RC2, 3: AES,"
1898                                      " or (c)lear? "), _("drac"))) {
1899           case 1:
1900             switch (choice = mutt_multi_choice (_("1: DES, 2: Triple-DES "),
1901                                                 _("dt"))) {
1902               case 1:
1903                 m_strreplace(&SmimeCryptAlg, "des");
1904                 break;
1905               case 2:
1906                 m_strreplace(&SmimeCryptAlg, "des3");
1907                 break;
1908             }
1909             break;
1910
1911           case 2:
1912             switch (choice = mutt_multi_choice (_("1: RC2-40, 2: RC2-64, 3: RC2-128 "),
1913                                                 _("468"))) {
1914               case 1:
1915                 m_strreplace(&SmimeCryptAlg, "rc2-40");
1916                 break;
1917               case 2:
1918                 m_strreplace(&SmimeCryptAlg, "rc2-64");
1919                 break;
1920               case 3:
1921                 m_strreplace(&SmimeCryptAlg, "rc2-128");
1922                 break;
1923             }
1924             break;
1925
1926           case 3:
1927             switch (choice = mutt_multi_choice (_("1: AES128, 2: AES192, 3: AES256 "),
1928                                                 _("895"))) {
1929               case 1:
1930                 m_strreplace(&SmimeCryptAlg, "aes128");
1931                 break;
1932               case 2:
1933                 m_strreplace(&SmimeCryptAlg, "aes192");
1934                 break;
1935               case 3:
1936                 m_strreplace(&SmimeCryptAlg, "aes256");
1937                 break;
1938             }
1939             break;
1940
1941           case 4: /* (c)lear */
1942             p_delete(&SmimeCryptAlg);
1943             /* fallback */
1944           case -1: /* Ctrl-G or Enter */
1945             choice = 0;
1946             break;
1947         }
1948       } while (choice == -1);
1949     }
1950     break;
1951
1952   case 2:                      /* (s)ign */
1953
1954     if (!SmimeDefaultKey)
1955       mutt_message (_("Can't sign: No key specified. Use Sign As."));
1956
1957     else {
1958       msg->security |= SIGN;
1959       msg->security &= ~ENCRYPT;
1960     }
1961     break;
1962
1963   case 4:                      /* sign (a)s */
1964
1965     if ((p = smime_ask_for_key (_("Sign as: "), NULL, 0))) {
1966       m_strreplace(&SmimeDefaultKey, p);
1967
1968       msg->security |= SIGN;
1969
1970       /* probably need a different passphrase */
1971       crypt_smime_void_passphrase ();
1972     }
1973 #if 0
1974     else
1975       msg->security &= ~SIGN;
1976 #endif
1977
1978     *redraw = REDRAW_FULL;
1979     break;
1980
1981   case 5:                      /* (b)oth */
1982     msg->security |= (ENCRYPT | SIGN);
1983     break;
1984
1985   case 6:                      /* (f)orget it */
1986   case 7:                      /* (c)lear */
1987     msg->security = 0;
1988     break;
1989   }
1990
1991   if (msg->security && msg->security != APPLICATION_SMIME)
1992     msg->security |= APPLICATION_SMIME;
1993   else
1994     msg->security = 0;
1995
1996   return (msg->security);
1997 }