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
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 #include "mutt_curses.h"
23 #include "mutt_menu.h"
40 #ifdef HAVE_SYS_TIME_H
41 # include <sys/time.h>
44 #ifdef HAVE_SYS_RESOURCE_H
45 # include <sys/resource.h>
48 #ifdef CRYPT_BACKEND_CLASSIC_SMIME
50 #include "mutt_crypt.h"
52 struct smime_command_context {
53 const char *key; /* %k */
54 const char *cryptalg; /* %a */
55 const char *fname; /* %f */
56 const char *sig_fname; /* %s */
57 const char *certificates; /* %c */
58 const char *intermediates; /* %i */
67 char trust; /* i=Invalid r=revoked e=expired u=unverified v=verified t=trusted */
68 short public; /* 1=public 0=private */
72 char SmimePass[STRING];
73 time_t SmimeExptime = 0; /* when does the cached passphrase expire? */
76 static char SmimeKeyToUse[_POSIX_PATH_MAX] = { 0 };
77 static char SmimeCertToUse[_POSIX_PATH_MAX];
78 static char SmimeIntermediateToUse[_POSIX_PATH_MAX];
82 * Queries and passphrase handling.
88 /* these are copies from pgp.c */
91 void smime_void_passphrase (void)
93 memset (SmimePass, 0, sizeof (SmimePass));
97 int smime_valid_passphrase (void)
99 time_t now = time (NULL);
101 if (now < SmimeExptime)
102 /* Use cached copy. */
105 smime_void_passphrase();
107 if (mutt_get_password (_("Enter SMIME passphrase:"), SmimePass, sizeof (SmimePass)) == 0)
109 SmimeExptime = time (NULL) + SmimeTimeout;
120 * The OpenSSL interface
123 /* This is almost identical to ppgp's invoking interface. */
125 static const char *_mutt_fmt_smime_command (char *dest,
130 const char *ifstring,
131 const char *elsestring,
136 struct smime_command_context *cctx = (struct smime_command_context *) data;
137 int optional = (flags & M_FORMAT_OPTIONAL);
145 char path[_POSIX_PATH_MAX];
146 char buf1[LONG_STRING], buf2[LONG_STRING];
149 strfcpy (path, NONULL (SmimeCALocation), sizeof (path));
150 mutt_expand_path (path, sizeof (path));
151 mutt_quote_filename (buf1, sizeof (buf1), path);
153 if (stat (path, &sb) != 0 || !S_ISDIR (sb.st_mode))
154 snprintf (buf2, sizeof (buf2), "-CAfile %s", buf1);
156 snprintf (buf2, sizeof (buf2), "-CApath %s", buf1);
158 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
159 snprintf (dest, destlen, fmt, buf2);
161 else if (!SmimeCALocation)
167 { /* certificate (list) */
169 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
170 snprintf (dest, destlen, fmt, NONULL(cctx->certificates));
172 else if (!cctx->certificates)
178 { /* intermediate certificates */
180 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
181 snprintf (dest, destlen, fmt, NONULL(cctx->intermediates));
183 else if (!cctx->intermediates)
189 { /* detached signature */
192 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
193 snprintf (dest, destlen, fmt, NONULL (cctx->sig_fname));
195 else if (!cctx->sig_fname)
204 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
205 snprintf (dest, destlen, fmt, NONULL (cctx->key));
213 { /* algorithm for encryption */
215 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
216 snprintf (dest, destlen, fmt, NONULL (cctx->cryptalg));
224 { /* file to process */
227 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
228 snprintf (dest, destlen, fmt, NONULL (cctx->fname));
230 else if (!cctx->fname)
241 mutt_FormatString (dest, destlen, ifstring, _mutt_fmt_smime_command,
243 else if (flags & M_FORMAT_OPTIONAL)
244 mutt_FormatString (dest, destlen, elsestring, _mutt_fmt_smime_command,
252 static void mutt_smime_command (char *d, size_t dlen,
253 struct smime_command_context *cctx, const char *fmt)
255 mutt_FormatString (d, dlen, NONULL(fmt), _mutt_fmt_smime_command,
256 (unsigned long) cctx, 0);
257 dprint (2,(debugfile, "mutt_smime_command: %s\n", d));
263 static pid_t smime_invoke (FILE **smimein, FILE **smimeout, FILE **smimeerr,
264 int smimeinfd, int smimeoutfd, int smimeerrfd,
266 const char *sig_fname,
267 const char *cryptalg,
269 const char *certificates,
270 const char *intermediates,
273 struct smime_command_context cctx;
274 char cmd[HUGE_STRING];
276 memset (&cctx, 0, sizeof (cctx));
278 if (!format || !*format)
282 cctx.sig_fname = sig_fname;
284 cctx.cryptalg = cryptalg;
285 cctx.certificates = certificates;
286 cctx.intermediates = intermediates;
288 mutt_smime_command (cmd, sizeof (cmd), &cctx, format);
290 return mutt_create_filter_fd (cmd, smimein, smimeout, smimeerr,
291 smimeinfd, smimeoutfd, smimeerrfd);
300 * Key and certificate handling.
306 Search the certificate index for given mailbox.
307 return certificate file name.
310 static void smime_entry (char *s, size_t l, MUTTMENU * menu, int num)
312 smime_id *Table = (smime_id*) menu->data;
313 smime_id this = Table[num];
317 truststate = N_("Trusted ");
320 truststate = N_("Verified ");
323 truststate = N_("Unverified");
326 truststate = N_("Expired ");
329 truststate = N_("Revoked ");
332 truststate = N_("Invalid ");
335 truststate = N_("Unknown ");
338 snprintf(s, l, " 0x%.8X.%i %s %-35.35s %s", this.hash, this.suffix, truststate, this.email, this.nick);
340 snprintf(s, l, " 0x%.8X.%i %-35.35s %s", this.hash, this.suffix, this.email, this.nick);
347 char* smime_ask_for_key (char *prompt, char *mailbox, short public)
351 long cert_num; /* Will contain the number of certificates.
352 * To be able to get it, the .index file will be read twice... */
353 char index_file[_POSIX_PATH_MAX];
355 char buf[LONG_STRING];
356 char fields[5][STRING];
357 int numFields, hash_suffix, done, cur; /* The current entry */
360 char helpstr[HUGE_STRING*3];
364 if (!prompt) prompt = _("Enter keyID: ");
365 snprintf(index_file, sizeof (index_file), "%s/.index",
366 public ? NONULL(SmimeCertificates) : NONULL(SmimeKeys));
368 index = fopen(index_file, "r");
371 mutt_perror (index_file);
376 while (!feof(index)) {
377 if (fgets(buf, sizeof(buf), index)) cert_num++;
384 if (mutt_get_field(prompt,
385 qry, sizeof(qry), 0))
387 snprintf(title, sizeof(title), _("S/MIME certificates matching \"%s\"."),
391 index = fopen(index_file, "r");
394 mutt_perror (index_file);
399 Table = safe_calloc(cert_num, sizeof (smime_id));
400 while (!feof(index)) {
401 numFields = fscanf (index, MUTT_FORMAT(STRING) " %x.%i " MUTT_FORMAT(STRING), fields[0], &hash,
402 &hash_suffix, fields[2]);
404 fscanf (index, MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) "\n", fields[3], fields[4]);
406 /* 0=email 1=name 2=nick 3=intermediate 4=trust */
407 if (numFields < 2) continue;
409 /* Check if query matches this certificate */
410 if (!mutt_stristr(fields[0], qry) &&
411 !mutt_stristr(fields[2], qry))
414 Table[cur].hash = hash;
415 Table[cur].suffix = hash_suffix;
416 strncpy(Table[cur].email, fields[0], sizeof(Table[cur].email));
417 strncpy(Table[cur].nick, fields[2], sizeof(Table[cur].nick));
418 Table[cur].trust = *fields[4];
419 Table[cur].public = public;
425 /* Make Helpstring */
427 mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_SMIME, OP_EXIT);
428 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
429 mutt_make_help (buf, sizeof (buf), _("Select "), MENU_SMIME,
430 OP_GENERIC_SELECT_ENTRY);
431 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
432 mutt_make_help (buf, sizeof(buf), _("Help"), MENU_SMIME, OP_HELP);
433 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
435 /* Create the menu */
436 menu = mutt_new_menu();
438 menu->make_entry = smime_entry;
439 menu->menu = MENU_SMIME;
440 menu->help = helpstr;
443 /* sorting keys might be done later - TODO */
450 switch (mutt_menuLoop (menu)) {
451 case OP_GENERIC_SELECT_ENTRY:
463 fname = safe_malloc(14); /* Hash + '.' + Suffix + \n + \0 */
464 sprintf(fname, "%.8x.%i\n", Table[cur].hash, Table[cur].suffix);
468 mutt_menuDestroy (&menu);
470 set_option (OPTNEEDREDRAW);
472 if (fname) return fname;
478 char *smime_get_field_from_db (char *mailbox, char *query, short public, short may_ask)
480 int addr_len, query_len, found = 0, ask = 0, choice = 0;
481 char cert_path[_POSIX_PATH_MAX];
482 char buf[LONG_STRING], prompt[STRING];
483 char fields[5][STRING];
487 char key_trust_level = 0;
490 if(!mailbox && !query) return(NULL);
492 addr_len = mailbox ? mutt_strlen (mailbox) : 0;
493 query_len = query ? mutt_strlen (query) : 0;
497 /* index-file format:
498 mailbox certfile label issuer_certfile trust_flags\n
500 certfile is a hash value generated by openssl.
501 Note that this was done according to the OpenSSL
502 specs on their CA-directory.
505 snprintf (cert_path, sizeof (cert_path), "%s/.index",
506 (public ? NONULL(SmimeCertificates) : NONULL(SmimeKeys)));
508 if (!stat (cert_path, &info))
510 if ((fp = safe_fopen (cert_path, "r")) == NULL)
512 mutt_perror (cert_path);
516 while (fgets (buf, sizeof (buf) - 1, fp) != NULL)
517 if (mailbox && !(mutt_strncasecmp (mailbox, buf, addr_len)))
519 numFields = sscanf (buf,
520 MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) " "
521 MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) " "
522 MUTT_FORMAT(STRING) "\n",
523 fields[0], fields[1],
524 fields[2], fields[3],
528 if (mailbox && public &&
530 *fields[4] == 'i' || *fields[4] == 'e' || *fields[4] == 'r'))
535 if (public && *fields[4] == 'u' )
536 snprintf (prompt, sizeof (prompt),
537 _("ID %s is unverified. Do you want to use it for %s ?"),
539 else if (public && *fields[4] == 'v' )
540 snprintf (prompt, sizeof (prompt),
541 _("Use (untrusted!) ID %s for %s ?"),
544 snprintf (prompt, sizeof (prompt), _("Use ID %s for %s ?"),
548 if (may_ask && (choice = mutt_yesorno (prompt, M_NO)) == -1)
555 else if (choice == M_NO)
560 else if (choice == M_YES)
562 strfcpy (key, fields[1], sizeof (key));
570 key_trust_level = *fields[4];
571 strfcpy (key, fields[1], sizeof (key));
577 numFields = sscanf (buf,
578 MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) " "
579 MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) " "
580 MUTT_FORMAT(STRING) "\n",
581 fields[0], fields[1],
582 fields[2], fields[3],
585 /* query = label: return certificate. */
586 if (numFields >= 3 &&
587 !(mutt_strncasecmp (query, fields[2], query_len)))
590 strfcpy (key, fields[1], sizeof (key));
592 /* query = certificate: return intermediate certificate. */
593 else if (numFields >= 4 &&
594 !(mutt_strncasecmp (query, fields[1], query_len)))
597 strfcpy (key, fields[3], sizeof (key));
605 if (public && *fields[4] == 'u' )
606 snprintf (prompt, sizeof (prompt),
607 _("ID %s is unverified. Do you want to use it for %s ?"),
609 else if (public && *fields[4] == 'v' )
610 snprintf (prompt, sizeof (prompt),
611 _("Use (untrusted!) ID %s for %s ?"),
614 snprintf (prompt, sizeof(prompt), _("Use ID %s for %s ?"), key,
616 choice = mutt_yesorno (prompt, M_NO);
617 if (choice == -1 || choice == M_NO)
620 else if (key_trust_level && may_ask)
622 if (key_trust_level == 'u' )
624 snprintf (prompt, sizeof (prompt),
625 _("ID %s is unverified. Do you want to use it for %s ?"),
627 choice = mutt_yesorno (prompt, M_NO);
631 else if (key_trust_level == 'v' )
633 mutt_error (_("Warning: You have not yet decided to trust ID %s. (any key to continue)"), key);
640 /* Note: safe_strdup ("") returns NULL. */
641 return safe_strdup (key);
648 This sets the '*ToUse' variables for an upcoming decryption, where
649 the reuquired key is different from SmimeDefaultKey.
652 void _smime_getkeys (char *mailbox)
657 k = smime_get_field_from_db (mailbox, NULL, 0, 1);
661 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "),
663 k = smime_ask_for_key(buf, mailbox, 0);
668 /* the key used last time. */
669 if (*SmimeKeyToUse &&
670 !mutt_strcasecmp (k, SmimeKeyToUse + mutt_strlen (SmimeKeys)+1))
675 else smime_void_passphrase ();
677 snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
678 NONULL(SmimeKeys), k);
680 snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
681 NONULL(SmimeCertificates), k);
683 if (mutt_strcasecmp (k, SmimeDefaultKey))
684 smime_void_passphrase ();
692 if (!mutt_strcasecmp (SmimeDefaultKey,
693 SmimeKeyToUse + mutt_strlen (SmimeKeys)+1))
696 smime_void_passphrase ();
699 snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
700 NONULL (SmimeKeys), NONULL (SmimeDefaultKey));
702 snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
703 NONULL (SmimeCertificates), NONULL (SmimeDefaultKey));
706 void smime_getkeys (ENVELOPE *env)
711 if (option (OPTSDEFAULTDECRYPTKEY) && SmimeDefaultKey && *SmimeDefaultKey)
713 snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
714 NONULL (SmimeKeys), SmimeDefaultKey);
716 snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
717 NONULL(SmimeCertificates), SmimeDefaultKey);
722 for (t = env->to; !found && t; t = t->next)
723 if (mutt_addr_is_user (t))
726 _smime_getkeys (t->mailbox);
728 for (t = env->cc; !found && t; t = t->next)
729 if (mutt_addr_is_user (t))
732 _smime_getkeys (t->mailbox);
734 if (!found && (t = mutt_default_from()))
736 _smime_getkeys (t->mailbox);
737 rfc822_free_address (&t);
741 /* This routine attempts to find the keyids of the recipients of a message.
742 * It returns NULL if any of the keys can not be found.
745 char *smime_findKeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc)
747 char *keyID, *keylist = NULL;
748 size_t keylist_size = 0;
749 size_t keylist_used = 0;
750 ADDRESS *tmp = NULL, *addr = NULL;
751 ADDRESS **last = &tmp;
755 const char *fqdn = mutt_fqdn (1);
757 for (i = 0; i < 3; i++)
761 case 0: p = to; break;
762 case 1: p = cc; break;
763 case 2: p = bcc; break;
767 *last = rfc822_cpy_adr (p);
769 last = &((*last)->next);
773 rfc822_qualify (tmp, fqdn);
775 tmp = mutt_remove_duplicates (tmp);
777 for (p = tmp; p ; p = p->next)
779 char buf[LONG_STRING];
783 if ((keyID = smime_get_field_from_db (q->mailbox, NULL, 1, 1)) == NULL)
785 snprintf(buf, sizeof(buf),
786 _("Enter keyID for %s: "),
788 keyID = smime_ask_for_key(buf, q->mailbox, 1);
792 mutt_message (_("No (valid) certificate found for %s."), q->mailbox);
794 rfc822_free_address (&tmp);
795 rfc822_free_address (&addr);
799 keylist_size += mutt_strlen (keyID) + 2;
800 safe_realloc (&keylist, keylist_size);
801 sprintf (keylist + keylist_used, "%s\n", keyID); /* __SPRINTF_CHECKED__ */
802 keylist_used = mutt_strlen (keylist);
804 rfc822_free_address (&addr);
807 rfc822_free_address (&tmp);
816 static int smime_handle_cert_email (char *certificate, char *mailbox,
817 int copy, char ***buffer, int *num)
819 FILE *fpout = NULL, *fperr = NULL;
820 char tmpfname[_POSIX_PATH_MAX];
822 int ret = -1, count = 0;
825 mutt_mktemp (tmpfname);
826 if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
828 mutt_perror (tmpfname);
831 mutt_unlink (tmpfname);
833 mutt_mktemp (tmpfname);
834 if ((fpout = safe_fopen (tmpfname, "w+")) == NULL)
837 mutt_perror (tmpfname);
840 mutt_unlink (tmpfname);
842 if ((thepid = smime_invoke (NULL, NULL, NULL,
843 -1, fileno (fpout), fileno (fperr),
844 certificate, NULL, NULL, NULL, NULL, NULL,
845 SmimeGetCertEmailCommand))== -1)
847 mutt_message (_("Error: unable to create OpenSSL subprocess!"));
853 mutt_wait_filter (thepid);
861 while ((fgets (email, sizeof (email), fpout)))
863 *(email + mutt_strlen (email)-1) = '\0';
864 if(mutt_strncasecmp (email, mailbox, mutt_strlen (mailbox)) == 0)
867 ret = ret < 0 ? 0 : ret;
874 mutt_copy_stream (fperr, stdout);
875 mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
882 if(copy && buffer && num)
885 *buffer = safe_calloc(sizeof(char*), count);
889 while ((fgets (email, sizeof (email), fpout)))
891 *(email + mutt_strlen (email) - 1) = '\0';
892 (*buffer)[count] = safe_calloc(1, mutt_strlen (email) + 1);
893 strncpy((*buffer)[count], email, mutt_strlen (email));
897 else if(copy) ret = 2;
907 static char *smime_extract_certificate (char *infile)
909 FILE *fpout = NULL, *fperr = NULL;
910 char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
911 char tmpfname[_POSIX_PATH_MAX];
916 mutt_mktemp (tmpfname);
917 if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
919 mutt_perror (tmpfname);
922 mutt_unlink (tmpfname);
924 mutt_mktemp (pk7out);
925 if ((fpout = safe_fopen (pk7out, "w+")) == NULL)
928 mutt_perror (pk7out);
932 /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
933 extract the full set of certificates directly.
935 if ((thepid = smime_invoke (NULL, NULL, NULL,
936 -1, fileno (fpout), fileno (fperr),
937 infile, NULL, NULL, NULL, NULL, NULL,
938 SmimePk7outCommand))== -1)
940 mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
943 mutt_unlink (pk7out);
947 mutt_wait_filter (thepid);
954 empty = (fgetc (fpout) == EOF);
957 mutt_perror (pk7out);
958 mutt_copy_stream (fperr, stdout);
961 mutt_unlink (pk7out);
968 mutt_mktemp (certfile);
969 if ((fpout = safe_fopen (certfile, "w+")) == NULL)
972 mutt_unlink (pk7out);
973 mutt_perror (certfile);
977 /* Step 2: Extract the certificates from a PKCS#7 structure.
979 if ((thepid = smime_invoke (NULL, NULL, NULL,
980 -1, fileno (fpout), fileno (fperr),
981 pk7out, NULL, NULL, NULL, NULL, NULL,
982 SmimeGetCertCommand))== -1)
984 mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
987 mutt_unlink (pk7out);
988 mutt_unlink (certfile);
992 mutt_wait_filter (thepid);
994 mutt_unlink (pk7out);
1000 empty = (fgetc (fpout) == EOF);
1003 mutt_copy_stream (fperr, stdout);
1006 mutt_unlink (certfile);
1013 return safe_strdup (certfile);
1016 static char *smime_extract_signer_certificate (char *infile)
1018 FILE *fpout = NULL, *fperr = NULL;
1019 char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
1020 char tmpfname[_POSIX_PATH_MAX];
1025 mutt_mktemp (tmpfname);
1026 if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
1028 mutt_perror (tmpfname);
1031 mutt_unlink (tmpfname);
1034 mutt_mktemp (certfile);
1035 if ((fpout = safe_fopen (certfile, "w+")) == NULL)
1038 mutt_perror (certfile);
1042 /* Extract signer's certificate
1044 if ((thepid = smime_invoke (NULL, NULL, NULL,
1045 -1, -1, fileno (fperr),
1046 infile, NULL, NULL, NULL, certfile, NULL,
1047 SmimeGetSignerCertCommand))== -1)
1049 mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
1052 mutt_unlink (pk7out);
1053 mutt_unlink (certfile);
1057 mutt_wait_filter (thepid);
1063 empty = (fgetc (fpout) == EOF);
1067 mutt_copy_stream (fperr, stdout);
1068 mutt_any_key_to_continue (NULL);
1071 mutt_unlink (certfile);
1078 return safe_strdup (certfile);
1084 /* Add a certificate and update index file (externally). */
1086 void smime_invoke_import (char *infile, char *mailbox)
1088 char tmpfname[_POSIX_PATH_MAX], *certfile = NULL, buf[STRING];
1089 FILE *smimein=NULL, *fpout = NULL, *fperr = NULL;
1092 mutt_mktemp (tmpfname);
1093 if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
1095 mutt_perror (tmpfname);
1098 mutt_unlink (tmpfname);
1100 mutt_mktemp (tmpfname);
1101 if ((fpout = safe_fopen (tmpfname, "w+")) == NULL)
1104 mutt_perror (tmpfname);
1107 mutt_unlink (tmpfname);
1111 if (option (OPTASKCERTLABEL))
1112 mutt_get_field ("Label for certificate:", buf, sizeof (buf), 0);
1115 if ((certfile = smime_extract_certificate(infile)))
1119 if ((thepid = smime_invoke (&smimein, NULL, NULL,
1120 -1, fileno(fpout), fileno(fperr),
1121 certfile, NULL, NULL, NULL, NULL, NULL,
1122 SmimeImportCertCommand))== -1)
1124 mutt_message (_("Error: unable to create OpenSSL subprocess!"));
1127 fputs (buf, smimein);
1128 fputc ('\n', smimein);
1131 mutt_wait_filter (thepid);
1133 mutt_unlink (certfile);
1142 mutt_copy_stream (fpout, stdout);
1143 mutt_copy_stream (fperr, stdout);
1152 int smime_verify_sender(HEADER *h)
1154 char *mbox = NULL, *certfile, tempfname[_POSIX_PATH_MAX];
1158 mutt_mktemp (tempfname);
1159 if (!(fpout = safe_fopen (tempfname, "w")))
1161 mutt_perror (tempfname);
1165 if(h->security & ENCRYPT)
1166 mutt_copy_message (fpout, Context, h,
1167 M_CM_DECODE_CRYPT & M_CM_DECODE_SMIME,
1168 CH_MIME|CH_WEED|CH_NONEWLINE);
1170 mutt_copy_message (fpout, Context, h, 0, 0);
1177 h->env->from = mutt_expand_aliases (h->env->from);
1178 mbox = h->env->from->mailbox;
1180 else if (h->env->sender)
1182 h->env->sender = mutt_expand_aliases (h->env->sender);
1183 mbox = h->env->sender->mailbox;
1188 if ((certfile = smime_extract_signer_certificate(tempfname)))
1190 mutt_unlink(tempfname);
1191 if (smime_handle_cert_email (certfile, mbox, 0, NULL, NULL))
1194 mutt_any_key_to_continue(NULL);
1198 mutt_unlink(certfile);
1202 mutt_any_key_to_continue(_("no certfile"));
1205 mutt_any_key_to_continue(_("no mbox"));
1207 mutt_unlink(tempfname);
1220 * Creating S/MIME - bodies.
1227 pid_t smime_invoke_encrypt (FILE **smimein, FILE **smimeout, FILE **smimeerr,
1228 int smimeinfd, int smimeoutfd, int smimeerrfd,
1229 const char *fname, const char *uids)
1231 return smime_invoke (smimein, smimeout, smimeerr,
1232 smimeinfd, smimeoutfd, smimeerrfd,
1233 fname, NULL, SmimeCryptAlg, NULL, uids, NULL,
1234 SmimeEncryptCommand);
1239 pid_t smime_invoke_sign (FILE **smimein, FILE **smimeout, FILE **smimeerr,
1240 int smimeinfd, int smimeoutfd, int smimeerrfd,
1243 return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1244 smimeerrfd, fname, NULL, NULL, SmimeKeyToUse,
1245 SmimeCertToUse, SmimeIntermediateToUse,
1252 BODY *smime_build_smime_entity (BODY *a, char *certlist)
1254 char buf[LONG_STRING], certfile[LONG_STRING];
1255 char tempfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
1256 char smimeinfile[_POSIX_PATH_MAX];
1257 char *cert_start = certlist, *cert_end = certlist;
1258 FILE *smimein = NULL, *smimeerr = NULL, *fpout = NULL, *fptmp = NULL;
1263 mutt_mktemp (tempfile);
1264 if ((fpout = safe_fopen (tempfile, "w+")) == NULL)
1266 mutt_perror (tempfile);
1270 mutt_mktemp (smimeerrfile);
1271 if ((smimeerr = safe_fopen (smimeerrfile, "w+")) == NULL)
1273 mutt_perror (smimeerrfile);
1275 mutt_unlink (tempfile);
1278 mutt_unlink (smimeerrfile);
1280 mutt_mktemp (smimeinfile);
1281 if ((fptmp = safe_fopen (smimeinfile, "w+")) == NULL)
1283 mutt_perror (smimeinfile);
1284 mutt_unlink (tempfile);
1293 int off = mutt_strlen (certfile);
1294 while (*++cert_end && *cert_end != '\n');
1295 if (!*cert_end) break;
1297 snprintf (certfile+off, sizeof (certfile)-off, " %s/%s",
1298 NONULL(SmimeCertificates), cert_start);
1300 cert_start = cert_end;
1304 /* write a MIME entity */
1305 mutt_write_mime_header (a, fptmp);
1306 fputc ('\n', fptmp);
1307 mutt_write_mime_body (a, fptmp);
1311 smime_invoke_encrypt (&smimein, NULL, NULL, -1,
1312 fileno (fpout), fileno (smimeerr),
1313 smimeinfile, certfile)) == -1)
1316 mutt_unlink (smimeinfile);
1317 mutt_unlink (certfile);
1323 mutt_wait_filter (thepid);
1324 mutt_unlink (smimeinfile);
1325 mutt_unlink (certfile);
1329 empty = (fgetc (fpout) == EOF);
1334 while (fgets (buf, sizeof (buf) - 1, smimeerr) != NULL)
1337 fputs (buf, stdout);
1341 /* pause if there is any error output from SMIME */
1343 mutt_any_key_to_continue (NULL);
1347 /* fatal error while trying to encrypt message */
1348 if (!err) mutt_any_key_to_continue _("No output from OpenSSL..");
1349 mutt_unlink (tempfile);
1353 t = mutt_new_body ();
1354 t->type = TYPEAPPLICATION;
1355 t->subtype = safe_strdup ("x-pkcs7-mime");
1356 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
1357 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
1358 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
1360 t->disposition = DISPATTACH;
1361 t->d_filename = safe_strdup ("smime.p7m");
1362 t->filename = safe_strdup (tempfile);
1363 t->unlink = 1; /*delete after sending the message */
1373 BODY *smime_sign_message (BODY *a )
1376 char buffer[LONG_STRING];
1377 char signedfile[_POSIX_PATH_MAX], filetosign[_POSIX_PATH_MAX];
1378 FILE *smimein = NULL, *smimeout = NULL, *smimeerr = NULL, *sfp = NULL;
1382 char *intermediates = smime_get_field_from_db(NULL, SmimeDefaultKey, 1, 1);
1386 mutt_message(_("Warning: Intermediate certificate not found."));
1387 intermediates = SmimeDefaultKey; /* so openssl won't complain in any case */
1390 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
1392 mutt_mktemp (filetosign);
1393 if ((sfp = safe_fopen (filetosign, "w+")) == NULL)
1395 mutt_perror (filetosign);
1399 mutt_mktemp (signedfile);
1400 if ((smimeout = safe_fopen (signedfile, "w+")) == NULL)
1402 mutt_perror (signedfile);
1404 mutt_unlink (filetosign);
1408 mutt_write_mime_header (a, sfp);
1410 mutt_write_mime_body (a, sfp);
1415 snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
1416 NONULL(SmimeKeys), SmimeDefaultKey);
1418 snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
1419 NONULL(SmimeCertificates), SmimeDefaultKey);
1421 snprintf (SmimeIntermediateToUse, sizeof (SmimeIntermediateToUse), "%s/%s",
1422 NONULL(SmimeCertificates), intermediates);
1426 if ((thepid = smime_invoke_sign (&smimein, NULL, &smimeerr,
1427 -1, fileno (smimeout), -1, filetosign)) == -1)
1429 mutt_perror _("Can't open OpenSSL subprocess!");
1431 mutt_unlink (signedfile);
1432 mutt_unlink (filetosign);
1435 fputs (SmimePass, smimein);
1436 fputc ('\n', smimein);
1440 mutt_wait_filter (thepid);
1442 /* check for errors from OpenSSL */
1446 while (fgets (buffer, sizeof (buffer) - 1, smimeerr) != NULL)
1449 fputs (buffer, stdout);
1456 empty = (fgetc (smimeout) == EOF);
1459 mutt_unlink (filetosign);
1463 mutt_any_key_to_continue (NULL);
1467 mutt_any_key_to_continue _("No output from OpenSSL...");
1468 mutt_unlink (signedfile);
1469 return (NULL); /* fatal error while signing */
1472 t = mutt_new_body ();
1473 t->type = TYPEMULTIPART;
1474 t->subtype = safe_strdup ("signed");
1475 t->encoding = ENC7BIT;
1477 t->disposition = DISPINLINE;
1479 mutt_generate_boundary (&t->parameter);
1480 /* check if this can be extracted from private key somehow.... */
1481 mutt_set_parameter ("micalg", "sha1", &t->parameter);
1482 mutt_set_parameter ("protocol", "application/x-pkcs7-signature",
1488 t->parts->next = mutt_new_body ();
1490 t->type = TYPEAPPLICATION;
1491 t->subtype = safe_strdup ("x-pkcs7-signature");
1492 t->filename = safe_strdup (signedfile);
1493 t->d_filename = safe_strdup ("smime.p7s");
1495 t->disposition = DISPATTACH;
1496 t->encoding = ENCBASE64;
1497 t->unlink = 1; /* ok to remove this file after sending. */
1509 * Handling S/MIME - bodies.
1518 pid_t smime_invoke_verify (FILE **smimein, FILE **smimeout, FILE **smimeerr,
1519 int smimeinfd, int smimeoutfd, int smimeerrfd,
1520 const char *fname, const char *sig_fname, int opaque)
1522 return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1523 smimeerrfd, fname, sig_fname, NULL, NULL, NULL, NULL,
1524 (opaque ? SmimeVerifyOpaqueCommand : SmimeVerifyCommand));
1529 pid_t smime_invoke_decrypt (FILE **smimein, FILE **smimeout, FILE **smimeerr,
1530 int smimeinfd, int smimeoutfd, int smimeerrfd,
1533 return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1534 smimeerrfd, fname, NULL, NULL, SmimeKeyToUse,
1535 SmimeCertToUse, NULL, SmimeDecryptCommand);
1540 int smime_verify_one (BODY *sigbdy, STATE *s, const char *tempfile)
1542 char signedfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
1543 FILE *fp=NULL, *smimeout=NULL, *smimeerr=NULL;
1548 size_t tmplength = 0;
1549 int origType = sigbdy->type;
1550 char *savePrefix = NULL;
1553 snprintf (signedfile, sizeof (signedfile), "%s.sig", tempfile);
1555 /* decode to a tempfile, saving the original destination */
1557 if ((s->fpout = safe_fopen (signedfile, "w")) == NULL)
1559 mutt_perror (signedfile);
1562 /* decoding the attachment changes the size and offset, so save a copy
1563 * of the "real" values now, and restore them after processing
1565 tmplength = sigbdy->length;
1566 tmpoffset = sigbdy->offset;
1568 /* if we are decoding binary bodies, we don't want to prefix each
1569 * line with the prefix or else the data will get corrupted.
1571 savePrefix = s->prefix;
1574 mutt_decode_attachment (sigbdy, s);
1576 sigbdy->length = ftell (s->fpout);
1580 /* restore final destination and substitute the tempfile for input */
1583 s->fpin = fopen (signedfile, "r");
1585 /* restore the prefix */
1586 s->prefix = savePrefix;
1588 sigbdy->type = origType;
1591 mutt_mktemp (smimeerrfile);
1592 if (!(smimeerr = safe_fopen (smimeerrfile, "w+")))
1594 mutt_perror (smimeerrfile);
1595 mutt_unlink (signedfile);
1599 crypt_current_time (s, "OpenSSL");
1601 if ((thepid = smime_invoke_verify (NULL, &smimeout, NULL,
1602 -1, -1, fileno (smimeerr),
1603 tempfile, signedfile, 0)) != -1)
1608 if (mutt_wait_filter (thepid))
1619 line = mutt_read_line (line, &linelen, smimeerr, &lineno);
1620 if (linelen && !mutt_strcasecmp (line, "verification successful"))
1629 mutt_copy_stream (smimeerr, s->fpout);
1632 state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
1634 mutt_unlink (signedfile);
1635 mutt_unlink (smimeerrfile);
1637 sigbdy->length = tmplength;
1638 sigbdy->offset = tmpoffset;
1640 /* restore the original source stream */
1653 This handles application/pkcs7-mime which can either be a signed
1654 or an encrypted message.
1657 static BODY *smime_handle_entity (BODY *m, STATE *s, FILE *outFile)
1662 char buf[HUGE_STRING];
1663 char outfile[_POSIX_PATH_MAX], errfile[_POSIX_PATH_MAX];
1664 char tmpfname[_POSIX_PATH_MAX];
1665 char tmptmpfname[_POSIX_PATH_MAX];
1666 FILE *smimeout = NULL, *smimein=NULL, *smimeerr=NULL;
1667 FILE *tmpfp=NULL, *tmpfp_buffer=NULL, *fpout=NULL;
1671 unsigned int type = mutt_is_application_smime (m);
1673 if (!(type & APPLICATION_SMIME)) return NULL;
1675 mutt_mktemp (outfile);
1676 if ((smimeout = safe_fopen (outfile, "w+")) == NULL)
1678 mutt_perror (outfile);
1682 mutt_mktemp (errfile);
1683 if ((smimeerr = safe_fopen (errfile, "w+")) == NULL)
1685 mutt_perror (errfile);
1686 fclose (smimeout); smimeout = NULL;
1689 mutt_unlink (errfile);
1692 mutt_mktemp (tmpfname);
1693 if ((tmpfp = safe_fopen (tmpfname, "w+")) == NULL)
1695 mutt_perror (tmpfname);
1696 fclose (smimeout); smimeout = NULL;
1697 fclose (smimeerr); smimeerr = NULL;
1701 fseek (s->fpin, m->offset, 0);
1702 last_pos = m->offset;
1704 mutt_copy_bytes (s->fpin, tmpfp, m->length);
1709 if ((type & ENCRYPT) &&
1710 (thepid = smime_invoke_decrypt (&smimein, NULL, NULL, -1,
1711 fileno (smimeout), fileno (smimeerr), tmpfname)) == -1)
1713 fclose (smimeout); smimeout = NULL;
1714 mutt_unlink (tmpfname);
1715 state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
1718 else if ((type & SIGNOPAQUE) &&
1719 (thepid = smime_invoke_verify (&smimein, NULL, NULL, -1,
1720 fileno (smimeout), fileno (smimeerr), NULL,
1721 tmpfname, SIGNOPAQUE)) == -1)
1723 fclose (smimeout); smimeout = NULL;
1724 mutt_unlink (tmpfname);
1725 state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
1732 if (!smime_valid_passphrase ())
1733 smime_void_passphrase ();
1734 fputs (SmimePass, smimein);
1735 fputc ('\n', smimein);
1740 mutt_wait_filter (thepid);
1741 mutt_unlink (tmpfname);
1744 if (s->flags & M_DISPLAY)
1748 if ((c = fgetc (smimeerr)) != EOF)
1750 ungetc (c, smimeerr);
1752 crypt_current_time (s, "OpenSSL");
1753 mutt_copy_stream (smimeerr, s->fpout);
1754 state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
1758 state_attach_puts (_("[-- The following data is S/MIME"
1759 " encrypted --]\n"), s);
1761 state_attach_puts (_("[-- The following data is S/MIME signed --]\n"), s);
1769 if (outFile) fpout = outFile;
1772 mutt_mktemp (tmptmpfname);
1773 if ((fpout = safe_fopen (tmptmpfname, "w+")) == NULL)
1775 mutt_perror(tmptmpfname);
1776 fclose (smimeout); smimeout = NULL;
1780 while (fgets (buf, sizeof (buf) - 1, smimeout) != NULL)
1782 len = mutt_strlen (buf);
1783 if (len > 1 && buf[len - 2] == '\r')
1794 if ((p = mutt_read_mime_header (fpout, 0)) != NULL)
1796 fstat (fileno (fpout), &info);
1797 p->length = info.st_size - p->offset;
1799 mutt_parse_part (fpout, p);
1803 tmpfp_buffer = s->fpin;
1805 mutt_body_handler (p, s);
1806 s->fpin = tmpfp_buffer;
1812 mutt_unlink (outfile);
1817 mutt_unlink (tmptmpfname);
1822 if (s->flags & M_DISPLAY)
1825 state_attach_puts (_("\n[-- End of S/MIME encrypted data. --]\n"), s);
1827 state_attach_puts (_("\n[-- End of S/MIME signed data. --]\n"), s);
1830 if (type & SIGNOPAQUE)
1838 line = mutt_read_line (line, &linelen, smimeerr, &lineno);
1839 if (linelen && !mutt_strcasecmp (line, "verification successful"))
1845 m->goodsig = p->goodsig;
1846 m->badsig = p->badsig;
1857 int smime_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
1861 char tempfile[_POSIX_PATH_MAX];
1863 long tmpoffset = b->offset;
1864 size_t tmplength = b->length;
1865 int origType = b->type;
1868 if (!mutt_is_application_smime (b))
1874 memset (&s, 0, sizeof (s));
1876 fseek (s.fpin, b->offset, 0);
1878 mutt_mktemp (tempfile);
1879 if ((tmpfp = safe_fopen (tempfile, "w+")) == NULL)
1881 mutt_perror (tempfile);
1885 mutt_unlink (tempfile);
1887 mutt_decode_attachment (b, &s);
1889 b->length = ftell (s.fpout);
1895 mutt_mktemp (tempfile);
1896 if ((*fpout = safe_fopen (tempfile, "w+")) == NULL)
1898 mutt_perror (tempfile);
1901 mutt_unlink (tempfile);
1903 *cur = smime_handle_entity (b, &s, *fpout);
1904 (*cur)->goodsig = b->goodsig;
1905 (*cur)->badsig = b->badsig;
1907 b->length = tmplength;
1908 b->offset = tmpoffset;
1917 void smime_application_smime_handler (BODY *m, STATE *s)
1920 smime_handle_entity (m, s, NULL);
1924 int smime_send_menu (HEADER *msg, int *redraw)
1928 if (!(WithCrypto & APPLICATION_SMIME))
1929 return msg->security;
1931 switch (mutt_multi_choice (_("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, or (c)lear? "),
1934 case 1: /* (e)ncrypt */
1935 msg->security |= ENCRYPT;
1936 msg->security &= ~SIGN;
1939 case 3: /* encrypt (w)ith */
1940 msg->security |= ENCRYPT;
1941 switch (mutt_multi_choice (_("1: DES, 2: Triple-DES, 3: RC2-40,"
1942 " 4: RC2-64, 5: RC2-128, or (f)orget it? "),
1945 mutt_str_replace (&SmimeCryptAlg, "des");
1948 mutt_str_replace (&SmimeCryptAlg, "des3");
1951 mutt_str_replace (&SmimeCryptAlg, "rc2-40");
1954 mutt_str_replace (&SmimeCryptAlg, "rc2-64");
1957 mutt_str_replace (&SmimeCryptAlg, "rc2-128");
1959 case 6: /* forget it */
1964 case 2: /* (s)ign */
1966 if(!SmimeDefaultKey)
1967 mutt_message _("Can't sign: No key specified. Use Sign As.");
1970 msg->security |= SIGN;
1971 msg->security &= ~ENCRYPT;
1975 case 4: /* sign (a)s */
1977 if ((p = smime_ask_for_key (_("Sign as: "), NULL, 0)))
1979 p[mutt_strlen (p)-1] = '\0';
1980 mutt_str_replace (&SmimeDefaultKey, p);
1982 msg->security |= SIGN;
1984 /* probably need a different passphrase */
1985 crypt_smime_void_passphrase ();
1989 msg->security &= ~SIGN;
1992 *redraw = REDRAW_FULL;
1995 case 5: /* (b)oth */
1996 msg->security |= (ENCRYPT | SIGN);
1999 case 6: /* (f)orget it */
2000 case 7: /* (c)lear */
2005 if (msg->security && msg->security != APPLICATION_SMIME)
2006 msg->security |= APPLICATION_SMIME;
2010 return (msg->security);
2014 #endif /* CRYPT_BACKEND_CLASSIC_SMIME */