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