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