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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include "mutt_curses.h"
27 #include "mutt_menu.h"
44 #ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
48 #ifdef HAVE_SYS_RESOURCE_H
49 # include <sys/resource.h>
52 #ifdef CRYPT_BACKEND_CLASSIC_SMIME
54 #include "mutt_crypt.h"
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 */
71 char trust; /* i=Invalid r=revoked e=expired u=unverified v=verified t=trusted */
72 short public; /* 1=public 0=private */
76 char SmimePass[STRING];
77 time_t SmimeExptime = 0; /* when does the cached passphrase expire? */
80 static char SmimeKeyToUse[_POSIX_PATH_MAX] = { 0 };
81 static char SmimeCertToUse[_POSIX_PATH_MAX];
82 static char SmimeIntermediateToUse[_POSIX_PATH_MAX];
86 * Queries and passphrase handling.
92 /* these are copies from pgp.c */
95 void smime_void_passphrase (void)
97 memset (SmimePass, 0, sizeof (SmimePass));
101 int smime_valid_passphrase (void)
103 time_t now = time (NULL);
105 if (now < SmimeExptime)
106 /* Use cached copy. */
109 smime_void_passphrase();
111 if (mutt_get_password (_("Enter S/MIME passphrase:"), SmimePass, sizeof (SmimePass)) == 0)
113 SmimeExptime = time (NULL) + SmimeTimeout;
124 * The OpenSSL interface
127 /* This is almost identical to ppgp's invoking interface. */
129 static const char *_mutt_fmt_smime_command (char *dest,
135 const char *ifstring,
136 const char *elsestring,
141 struct smime_command_context *cctx = (struct smime_command_context *) data;
142 int optional = (flags & M_FORMAT_OPTIONAL);
150 char path[_POSIX_PATH_MAX];
151 char buf1[LONG_STRING], buf2[LONG_STRING];
154 strfcpy (path, NONULL (SmimeCALocation), sizeof (path));
155 mutt_expand_path (path, sizeof (path));
156 mutt_quote_filename (buf1, sizeof (buf1), path);
158 if (stat (path, &sb) != 0 || !S_ISDIR (sb.st_mode))
159 snprintf (buf2, sizeof (buf2), "-CAfile %s", buf1);
161 snprintf (buf2, sizeof (buf2), "-CApath %s", buf1);
163 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
164 snprintf (dest, destlen, fmt, buf2);
166 else if (!SmimeCALocation)
172 { /* certificate (list) */
174 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
175 snprintf (dest, destlen, fmt, NONULL(cctx->certificates));
177 else if (!cctx->certificates)
183 { /* intermediate certificates */
185 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
186 snprintf (dest, destlen, fmt, NONULL(cctx->intermediates));
188 else if (!cctx->intermediates)
194 { /* detached signature */
197 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
198 snprintf (dest, destlen, fmt, NONULL (cctx->sig_fname));
200 else if (!cctx->sig_fname)
209 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
210 snprintf (dest, destlen, fmt, NONULL (cctx->key));
218 { /* algorithm for encryption */
220 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
221 snprintf (dest, destlen, fmt, NONULL (cctx->cryptalg));
229 { /* file to process */
232 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
233 snprintf (dest, destlen, fmt, NONULL (cctx->fname));
235 else if (!cctx->fname)
246 mutt_FormatString (dest, destlen, col, ifstring, _mutt_fmt_smime_command,
248 else if (flags & M_FORMAT_OPTIONAL)
249 mutt_FormatString (dest, destlen, col, elsestring, _mutt_fmt_smime_command,
257 static void mutt_smime_command (char *d, size_t dlen,
258 struct smime_command_context *cctx, const char *fmt)
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));
268 static pid_t smime_invoke (FILE **smimein, FILE **smimeout, FILE **smimeerr,
269 int smimeinfd, int smimeoutfd, int smimeerrfd,
271 const char *sig_fname,
272 const char *cryptalg,
274 const char *certificates,
275 const char *intermediates,
278 struct smime_command_context cctx;
279 char cmd[HUGE_STRING];
281 memset (&cctx, 0, sizeof (cctx));
283 if (!format || !*format)
287 cctx.sig_fname = sig_fname;
289 cctx.cryptalg = cryptalg;
290 cctx.certificates = certificates;
291 cctx.intermediates = intermediates;
293 mutt_smime_command (cmd, sizeof (cmd), &cctx, format);
295 return mutt_create_filter_fd (cmd, smimein, smimeout, smimeerr,
296 smimeinfd, smimeoutfd, smimeerrfd);
305 * Key and certificate handling.
311 Search the certificate index for given mailbox.
312 return certificate file name.
315 static void smime_entry (char *s, size_t l, MUTTMENU * menu, int num)
317 smime_id *Table = (smime_id*) menu->data;
318 smime_id this = Table[num];
322 truststate = N_("Trusted ");
325 truststate = N_("Verified ");
328 truststate = N_("Unverified");
331 truststate = N_("Expired ");
334 truststate = N_("Revoked ");
337 truststate = N_("Invalid ");
340 truststate = N_("Unknown ");
343 snprintf(s, l, " 0x%.8X.%i %s %-35.35s %s", this.hash, this.suffix, truststate, this.email, this.nick);
345 snprintf(s, l, " 0x%.8X.%i %-35.35s %s", this.hash, this.suffix, this.email, this.nick);
352 char* smime_ask_for_key (char *prompt, char *mailbox, short public)
356 long cert_num; /* Will contain the number of certificates.
357 * To be able to get it, the .index file will be read twice... */
358 char index_file[_POSIX_PATH_MAX];
360 char buf[LONG_STRING];
361 char fields[5][STRING];
362 int numFields, hash_suffix, done, cur; /* The current entry */
365 char helpstr[HUGE_STRING*3];
369 if (!prompt) prompt = _("Enter keyID: ");
370 snprintf(index_file, sizeof (index_file), "%s/.index",
371 public ? NONULL(SmimeCertificates) : NONULL(SmimeKeys));
373 index = fopen(index_file, "r");
376 mutt_perror (index_file);
381 while (!feof(index)) {
382 if (fgets(buf, sizeof(buf), index)) cert_num++;
384 safe_fclose (&index);
389 if (mutt_get_field(prompt,
390 qry, sizeof(qry), 0))
392 snprintf(title, sizeof(title), _("S/MIME certificates matching \"%s\"."),
396 index = fopen(index_file, "r");
399 mutt_perror (index_file);
404 Table = safe_calloc(cert_num, sizeof (smime_id));
405 while (!feof(index)) {
406 numFields = fscanf (index, MUTT_FORMAT(STRING) " %x.%i " MUTT_FORMAT(STRING), fields[0], &hash,
407 &hash_suffix, fields[2]);
409 fscanf (index, MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) "\n", fields[3], fields[4]);
411 /* 0=email 1=name 2=nick 3=intermediate 4=trust */
412 if (numFields < 2) continue;
414 /* Check if query matches this certificate */
415 if (!mutt_stristr(fields[0], qry) &&
416 !mutt_stristr(fields[2], qry))
419 Table[cur].hash = hash;
420 Table[cur].suffix = hash_suffix;
421 strncpy(Table[cur].email, fields[0], sizeof(Table[cur].email));
422 strncpy(Table[cur].nick, fields[2], sizeof(Table[cur].nick));
423 Table[cur].trust = *fields[4];
424 Table[cur].public = public;
428 safe_fclose (&index);
430 /* Make Helpstring */
432 mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_SMIME, OP_EXIT);
433 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
434 mutt_make_help (buf, sizeof (buf), _("Select "), MENU_SMIME,
435 OP_GENERIC_SELECT_ENTRY);
436 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
437 mutt_make_help (buf, sizeof(buf), _("Help"), MENU_SMIME, OP_HELP);
438 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
440 /* Create the menu */
441 menu = mutt_new_menu(MENU_SMIME);
443 menu->make_entry = smime_entry;
444 menu->help = helpstr;
447 /* sorting keys might be done later - TODO */
454 switch (mutt_menuLoop (menu)) {
455 case OP_GENERIC_SELECT_ENTRY:
467 fname = safe_malloc(13); /* Hash + '.' + Suffix + \0 */
468 sprintf(fname, "%.8x.%i", Table[cur].hash, Table[cur].suffix);
472 mutt_menuDestroy (&menu);
474 set_option (OPTNEEDREDRAW);
476 if (fname) return fname;
482 char *smime_get_field_from_db (char *mailbox, char *query, short public, short may_ask)
484 int addr_len, query_len, found = 0, ask = 0, choice = 0;
485 char cert_path[_POSIX_PATH_MAX];
486 char buf[LONG_STRING], prompt[STRING];
487 char fields[5][STRING];
491 char key_trust_level = 0;
494 if(!mailbox && !query) return(NULL);
496 addr_len = mailbox ? mutt_strlen (mailbox) : 0;
497 query_len = query ? mutt_strlen (query) : 0;
501 /* index-file format:
502 mailbox certfile label issuer_certfile trust_flags\n
504 certfile is a hash value generated by openssl.
505 Note that this was done according to the OpenSSL
506 specs on their CA-directory.
509 snprintf (cert_path, sizeof (cert_path), "%s/.index",
510 (public ? NONULL(SmimeCertificates) : NONULL(SmimeKeys)));
512 if (!stat (cert_path, &info))
514 if ((fp = safe_fopen (cert_path, "r")) == NULL)
516 mutt_perror (cert_path);
520 while (fgets (buf, sizeof (buf) - 1, fp) != NULL)
521 if (mailbox && !(mutt_strncasecmp (mailbox, buf, addr_len)))
523 numFields = sscanf (buf,
524 MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) " "
525 MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) " "
526 MUTT_FORMAT(STRING) "\n",
527 fields[0], fields[1],
528 fields[2], fields[3],
532 if (mailbox && public &&
533 (*fields[4] == 'i' || *fields[4] == 'e' || *fields[4] == 'r'))
538 if (public && *fields[4] == 'u' )
539 snprintf (prompt, sizeof (prompt),
540 _("ID %s is unverified. Do you want to use it for %s ?"),
542 else if (public && *fields[4] == 'v' )
543 snprintf (prompt, sizeof (prompt),
544 _("Use (untrusted!) ID %s for %s ?"),
547 snprintf (prompt, sizeof (prompt), _("Use ID %s for %s ?"),
551 if (may_ask && (choice = mutt_yesorno (prompt, M_NO)) == -1)
558 else if (choice == M_NO)
563 else if (choice == M_YES)
565 strfcpy (key, fields[1], sizeof (key));
573 key_trust_level = *fields[4];
574 strfcpy (key, fields[1], sizeof (key));
580 numFields = sscanf (buf,
581 MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) " "
582 MUTT_FORMAT(STRING) " " MUTT_FORMAT(STRING) " "
583 MUTT_FORMAT(STRING) "\n",
584 fields[0], fields[1],
585 fields[2], fields[3],
588 /* query = label: return certificate. */
589 if (numFields >= 3 &&
590 !(mutt_strncasecmp (query, fields[2], query_len)))
593 strfcpy (key, fields[1], sizeof (key));
595 /* query = certificate: return intermediate certificate. */
596 else if (numFields >= 4 &&
597 !(mutt_strncasecmp (query, fields[1], query_len)))
600 strfcpy (key, fields[3], sizeof (key));
608 if (public && *fields[4] == 'u' )
609 snprintf (prompt, sizeof (prompt),
610 _("ID %s is unverified. Do you want to use it for %s ?"),
612 else if (public && *fields[4] == 'v' )
613 snprintf (prompt, sizeof (prompt),
614 _("Use (untrusted!) ID %s for %s ?"),
617 snprintf (prompt, sizeof(prompt), _("Use ID %s for %s ?"), key,
619 choice = mutt_yesorno (prompt, M_NO);
620 if (choice == -1 || choice == M_NO)
623 else if (key_trust_level && may_ask)
625 if (key_trust_level == 'u' )
627 snprintf (prompt, sizeof (prompt),
628 _("ID %s is unverified. Do you want to use it for %s ?"),
630 choice = mutt_yesorno (prompt, M_NO);
634 else if (key_trust_level == 'v' )
636 mutt_error (_("Warning: You have not yet decided to trust ID %s. (any key to continue)"), key);
643 /* Note: safe_strdup ("") returns NULL. */
644 return safe_strdup (key);
651 This sets the '*ToUse' variables for an upcoming decryption, where
652 the reuquired key is different from SmimeDefaultKey.
655 void _smime_getkeys (char *mailbox)
660 k = smime_get_field_from_db (mailbox, NULL, 0, 1);
664 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "),
666 k = smime_ask_for_key(buf, mailbox, 0);
671 /* the key used last time. */
672 if (*SmimeKeyToUse &&
673 !mutt_strcasecmp (k, SmimeKeyToUse + mutt_strlen (SmimeKeys)+1))
678 else smime_void_passphrase ();
680 snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
681 NONULL(SmimeKeys), k);
683 snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
684 NONULL(SmimeCertificates), k);
686 if (mutt_strcasecmp (k, SmimeDefaultKey))
687 smime_void_passphrase ();
695 if (!mutt_strcasecmp (SmimeDefaultKey,
696 SmimeKeyToUse + mutt_strlen (SmimeKeys)+1))
699 smime_void_passphrase ();
702 snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
703 NONULL (SmimeKeys), NONULL (SmimeDefaultKey));
705 snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
706 NONULL (SmimeCertificates), NONULL (SmimeDefaultKey));
709 void smime_getkeys (ENVELOPE *env)
714 if (option (OPTSDEFAULTDECRYPTKEY) && SmimeDefaultKey && *SmimeDefaultKey)
716 snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
717 NONULL (SmimeKeys), SmimeDefaultKey);
719 snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
720 NONULL(SmimeCertificates), SmimeDefaultKey);
725 for (t = env->to; !found && t; t = t->next)
726 if (mutt_addr_is_user (t))
729 _smime_getkeys (t->mailbox);
731 for (t = env->cc; !found && t; t = t->next)
732 if (mutt_addr_is_user (t))
735 _smime_getkeys (t->mailbox);
737 if (!found && (t = mutt_default_from()))
739 _smime_getkeys (t->mailbox);
740 rfc822_free_address (&t);
744 /* This routine attempts to find the keyids of the recipients of a message.
745 * It returns NULL if any of the keys can not be found.
748 char *smime_findKeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc)
750 char *keyID, *keylist = NULL;
751 size_t keylist_size = 0;
752 size_t keylist_used = 0;
753 ADDRESS *tmp = NULL, *addr = NULL;
754 ADDRESS **last = &tmp;
758 const char *fqdn = mutt_fqdn (1);
760 for (i = 0; i < 3; i++)
764 case 0: p = to; break;
765 case 1: p = cc; break;
766 case 2: p = bcc; break;
770 *last = rfc822_cpy_adr (p, 0);
772 last = &((*last)->next);
776 rfc822_qualify (tmp, fqdn);
778 tmp = mutt_remove_duplicates (tmp);
780 for (p = tmp; p ; p = p->next)
782 char buf[LONG_STRING];
786 if ((keyID = smime_get_field_from_db (q->mailbox, NULL, 1, 1)) == NULL)
788 snprintf(buf, sizeof(buf),
789 _("Enter keyID for %s: "),
791 keyID = smime_ask_for_key(buf, q->mailbox, 1);
795 mutt_message (_("No (valid) certificate found for %s."), q->mailbox);
797 rfc822_free_address (&tmp);
798 rfc822_free_address (&addr);
802 keylist_size += mutt_strlen (keyID) + 2;
803 safe_realloc (&keylist, keylist_size);
804 sprintf (keylist + keylist_used, "%s\n", keyID); /* __SPRINTF_CHECKED__ */
805 keylist_used = mutt_strlen (keylist);
807 rfc822_free_address (&addr);
810 rfc822_free_address (&tmp);
819 static int smime_handle_cert_email (char *certificate, char *mailbox,
820 int copy, char ***buffer, int *num)
822 FILE *fpout = NULL, *fperr = NULL;
823 char tmpfname[_POSIX_PATH_MAX];
825 int ret = -1, count = 0;
828 mutt_mktemp (tmpfname);
829 if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
831 mutt_perror (tmpfname);
834 mutt_unlink (tmpfname);
836 mutt_mktemp (tmpfname);
837 if ((fpout = safe_fopen (tmpfname, "w+")) == NULL)
839 safe_fclose (&fperr);
840 mutt_perror (tmpfname);
843 mutt_unlink (tmpfname);
845 if ((thepid = smime_invoke (NULL, NULL, NULL,
846 -1, fileno (fpout), fileno (fperr),
847 certificate, NULL, NULL, NULL, NULL, NULL,
848 SmimeGetCertEmailCommand))== -1)
850 mutt_message (_("Error: unable to create OpenSSL subprocess!"));
851 safe_fclose (&fperr);
852 safe_fclose (&fpout);
856 mutt_wait_filter (thepid);
864 while ((fgets (email, sizeof (email), fpout)))
866 *(email + mutt_strlen (email)-1) = '\0';
867 if(mutt_strncasecmp (email, mailbox, mutt_strlen (mailbox)) == 0)
870 ret = ret < 0 ? 0 : ret;
877 mutt_copy_stream (fperr, stdout);
878 mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
885 if(copy && buffer && num)
888 *buffer = safe_calloc(sizeof(char*), count);
892 while ((fgets (email, sizeof (email), fpout)))
894 *(email + mutt_strlen (email) - 1) = '\0';
895 (*buffer)[count] = safe_calloc(1, mutt_strlen (email) + 1);
896 strncpy((*buffer)[count], email, mutt_strlen (email));
900 else if(copy) ret = 2;
902 safe_fclose (&fpout);
903 safe_fclose (&fperr);
910 static char *smime_extract_certificate (char *infile)
912 FILE *fpout = NULL, *fperr = NULL;
913 char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
914 char tmpfname[_POSIX_PATH_MAX];
919 mutt_mktemp (tmpfname);
920 if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
922 mutt_perror (tmpfname);
925 mutt_unlink (tmpfname);
927 mutt_mktemp (pk7out);
928 if ((fpout = safe_fopen (pk7out, "w+")) == NULL)
930 safe_fclose (&fperr);
931 mutt_perror (pk7out);
935 /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
936 extract the full set of certificates directly.
938 if ((thepid = smime_invoke (NULL, NULL, NULL,
939 -1, fileno (fpout), fileno (fperr),
940 infile, NULL, NULL, NULL, NULL, NULL,
941 SmimePk7outCommand))== -1)
943 mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
944 safe_fclose (&fperr);
945 safe_fclose (&fpout);
946 mutt_unlink (pk7out);
950 mutt_wait_filter (thepid);
957 empty = (fgetc (fpout) == EOF);
960 mutt_perror (pk7out);
961 mutt_copy_stream (fperr, stdout);
962 safe_fclose (&fpout);
963 safe_fclose (&fperr);
964 mutt_unlink (pk7out);
970 safe_fclose (&fpout);
971 mutt_mktemp (certfile);
972 if ((fpout = safe_fopen (certfile, "w+")) == NULL)
974 safe_fclose (&fperr);
975 mutt_unlink (pk7out);
976 mutt_perror (certfile);
980 /* Step 2: Extract the certificates from a PKCS#7 structure.
982 if ((thepid = smime_invoke (NULL, NULL, NULL,
983 -1, fileno (fpout), fileno (fperr),
984 pk7out, NULL, NULL, NULL, NULL, NULL,
985 SmimeGetCertCommand))== -1)
987 mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
988 safe_fclose (&fperr);
989 safe_fclose (&fpout);
990 mutt_unlink (pk7out);
991 mutt_unlink (certfile);
995 mutt_wait_filter (thepid);
997 mutt_unlink (pk7out);
1003 empty = (fgetc (fpout) == EOF);
1006 mutt_copy_stream (fperr, stdout);
1007 safe_fclose (&fpout);
1008 safe_fclose (&fperr);
1009 mutt_unlink (certfile);
1013 safe_fclose (&fpout);
1014 safe_fclose (&fperr);
1016 return safe_strdup (certfile);
1019 static char *smime_extract_signer_certificate (char *infile)
1021 FILE *fpout = NULL, *fperr = NULL;
1022 char pk7out[_POSIX_PATH_MAX], certfile[_POSIX_PATH_MAX];
1023 char tmpfname[_POSIX_PATH_MAX];
1028 mutt_mktemp (tmpfname);
1029 if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
1031 mutt_perror (tmpfname);
1034 mutt_unlink (tmpfname);
1037 mutt_mktemp (certfile);
1038 if ((fpout = safe_fopen (certfile, "w+")) == NULL)
1040 safe_fclose (&fperr);
1041 mutt_perror (certfile);
1045 /* Extract signer's certificate
1047 if ((thepid = smime_invoke (NULL, NULL, NULL,
1048 -1, -1, fileno (fperr),
1049 infile, NULL, NULL, NULL, certfile, NULL,
1050 SmimeGetSignerCertCommand))== -1)
1052 mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
1053 safe_fclose (&fperr);
1054 safe_fclose (&fpout);
1055 mutt_unlink (pk7out);
1056 mutt_unlink (certfile);
1060 mutt_wait_filter (thepid);
1066 empty = (fgetc (fpout) == EOF);
1070 mutt_copy_stream (fperr, stdout);
1071 mutt_any_key_to_continue (NULL);
1072 safe_fclose (&fpout);
1073 safe_fclose (&fperr);
1074 mutt_unlink (certfile);
1078 safe_fclose (&fpout);
1079 safe_fclose (&fperr);
1081 return safe_strdup (certfile);
1087 /* Add a certificate and update index file (externally). */
1089 void smime_invoke_import (char *infile, char *mailbox)
1091 char tmpfname[_POSIX_PATH_MAX], *certfile = NULL, buf[STRING];
1092 FILE *smimein=NULL, *fpout = NULL, *fperr = NULL;
1095 mutt_mktemp (tmpfname);
1096 if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
1098 mutt_perror (tmpfname);
1101 mutt_unlink (tmpfname);
1103 mutt_mktemp (tmpfname);
1104 if ((fpout = safe_fopen (tmpfname, "w+")) == NULL)
1106 safe_fclose (&fperr);
1107 mutt_perror (tmpfname);
1110 mutt_unlink (tmpfname);
1114 if (option (OPTASKCERTLABEL))
1115 mutt_get_field ("Label for certificate:", buf, sizeof (buf), 0);
1118 if ((certfile = smime_extract_certificate(infile)))
1122 if ((thepid = smime_invoke (&smimein, NULL, NULL,
1123 -1, fileno(fpout), fileno(fperr),
1124 certfile, NULL, NULL, NULL, NULL, NULL,
1125 SmimeImportCertCommand))== -1)
1127 mutt_message (_("Error: unable to create OpenSSL subprocess!"));
1130 fputs (buf, smimein);
1131 fputc ('\n', smimein);
1132 safe_fclose (&smimein);
1134 mutt_wait_filter (thepid);
1136 mutt_unlink (certfile);
1145 mutt_copy_stream (fpout, stdout);
1146 mutt_copy_stream (fperr, stdout);
1148 safe_fclose (&fpout);
1149 safe_fclose (&fperr);
1155 int smime_verify_sender(HEADER *h)
1157 char *mbox = NULL, *certfile, tempfname[_POSIX_PATH_MAX];
1161 mutt_mktemp (tempfname);
1162 if (!(fpout = safe_fopen (tempfname, "w")))
1164 mutt_perror (tempfname);
1168 if(h->security & ENCRYPT)
1169 mutt_copy_message (fpout, Context, h,
1170 M_CM_DECODE_CRYPT & M_CM_DECODE_SMIME,
1171 CH_MIME|CH_WEED|CH_NONEWLINE);
1173 mutt_copy_message (fpout, Context, h, 0, 0);
1176 safe_fclose (&fpout);
1180 h->env->from = mutt_expand_aliases (h->env->from);
1181 mbox = h->env->from->mailbox;
1183 else if (h->env->sender)
1185 h->env->sender = mutt_expand_aliases (h->env->sender);
1186 mbox = h->env->sender->mailbox;
1191 if ((certfile = smime_extract_signer_certificate(tempfname)))
1193 mutt_unlink(tempfname);
1194 if (smime_handle_cert_email (certfile, mbox, 0, NULL, NULL))
1197 mutt_any_key_to_continue(NULL);
1201 mutt_unlink(certfile);
1205 mutt_any_key_to_continue(_("no certfile"));
1208 mutt_any_key_to_continue(_("no mbox"));
1210 mutt_unlink(tempfname);
1223 * Creating S/MIME - bodies.
1230 pid_t smime_invoke_encrypt (FILE **smimein, FILE **smimeout, FILE **smimeerr,
1231 int smimeinfd, int smimeoutfd, int smimeerrfd,
1232 const char *fname, const char *uids)
1234 return smime_invoke (smimein, smimeout, smimeerr,
1235 smimeinfd, smimeoutfd, smimeerrfd,
1236 fname, NULL, SmimeCryptAlg, NULL, uids, NULL,
1237 SmimeEncryptCommand);
1242 pid_t smime_invoke_sign (FILE **smimein, FILE **smimeout, FILE **smimeerr,
1243 int smimeinfd, int smimeoutfd, int smimeerrfd,
1246 return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1247 smimeerrfd, fname, NULL, NULL, SmimeKeyToUse,
1248 SmimeCertToUse, SmimeIntermediateToUse,
1255 BODY *smime_build_smime_entity (BODY *a, char *certlist)
1257 char buf[LONG_STRING], certfile[LONG_STRING];
1258 char tempfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
1259 char smimeinfile[_POSIX_PATH_MAX];
1260 char *cert_start = certlist, *cert_end = certlist;
1261 FILE *smimein = NULL, *smimeerr = NULL, *fpout = NULL, *fptmp = NULL;
1266 mutt_mktemp (tempfile);
1267 if ((fpout = safe_fopen (tempfile, "w+")) == NULL)
1269 mutt_perror (tempfile);
1273 mutt_mktemp (smimeerrfile);
1274 if ((smimeerr = safe_fopen (smimeerrfile, "w+")) == NULL)
1276 mutt_perror (smimeerrfile);
1277 safe_fclose (&fpout);
1278 mutt_unlink (tempfile);
1281 mutt_unlink (smimeerrfile);
1283 mutt_mktemp (smimeinfile);
1284 if ((fptmp = safe_fopen (smimeinfile, "w+")) == NULL)
1286 mutt_perror (smimeinfile);
1287 mutt_unlink (tempfile);
1288 safe_fclose (&fpout);
1289 safe_fclose (&smimeerr);
1296 int off = mutt_strlen (certfile);
1297 while (*++cert_end && *cert_end != '\n');
1298 if (!*cert_end) break;
1300 snprintf (certfile+off, sizeof (certfile)-off, " %s/%s",
1301 NONULL(SmimeCertificates), cert_start);
1303 cert_start = cert_end;
1307 /* write a MIME entity */
1308 mutt_write_mime_header (a, fptmp);
1309 fputc ('\n', fptmp);
1310 mutt_write_mime_body (a, fptmp);
1311 safe_fclose (&fptmp);
1314 smime_invoke_encrypt (&smimein, NULL, NULL, -1,
1315 fileno (fpout), fileno (smimeerr),
1316 smimeinfile, certfile)) == -1)
1318 safe_fclose (&smimeerr);
1319 mutt_unlink (smimeinfile);
1320 mutt_unlink (certfile);
1324 safe_fclose (&smimein);
1326 mutt_wait_filter (thepid);
1327 mutt_unlink (smimeinfile);
1328 mutt_unlink (certfile);
1332 empty = (fgetc (fpout) == EOF);
1333 safe_fclose (&fpout);
1337 while (fgets (buf, sizeof (buf) - 1, smimeerr) != NULL)
1340 fputs (buf, stdout);
1342 safe_fclose (&smimeerr);
1344 /* pause if there is any error output from SMIME */
1346 mutt_any_key_to_continue (NULL);
1350 /* fatal error while trying to encrypt message */
1351 if (!err) mutt_any_key_to_continue _("No output from OpenSSL..");
1352 mutt_unlink (tempfile);
1356 t = mutt_new_body ();
1357 t->type = TYPEAPPLICATION;
1358 t->subtype = safe_strdup ("x-pkcs7-mime");
1359 mutt_set_parameter ("name", "smime.p7m", &t->parameter);
1360 mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter);
1361 t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */
1363 t->disposition = DISPATTACH;
1364 t->d_filename = safe_strdup ("smime.p7m");
1365 t->filename = safe_strdup (tempfile);
1366 t->unlink = 1; /*delete after sending the message */
1376 BODY *smime_sign_message (BODY *a )
1379 char buffer[LONG_STRING];
1380 char signedfile[_POSIX_PATH_MAX], filetosign[_POSIX_PATH_MAX];
1381 FILE *smimein = NULL, *smimeout = NULL, *smimeerr = NULL, *sfp = NULL;
1385 char *intermediates = smime_get_field_from_db(NULL, SmimeDefaultKey, 1, 1);
1387 if (!SmimeDefaultKey)
1389 mutt_error _("Can't sign: No key specified. Use Sign As.");
1390 FREE (&intermediates);
1396 mutt_message(_("Warning: Intermediate certificate not found."));
1397 intermediates = SmimeDefaultKey; /* so openssl won't complain in any case */
1400 convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */
1402 mutt_mktemp (filetosign);
1403 if ((sfp = safe_fopen (filetosign, "w+")) == NULL)
1405 mutt_perror (filetosign);
1406 if (intermediates != SmimeDefaultKey)
1407 FREE (&intermediates);
1411 mutt_mktemp (signedfile);
1412 if ((smimeout = safe_fopen (signedfile, "w+")) == NULL)
1414 mutt_perror (signedfile);
1416 mutt_unlink (filetosign);
1417 if (intermediates != SmimeDefaultKey)
1418 FREE (&intermediates);
1422 mutt_write_mime_header (a, sfp);
1424 mutt_write_mime_body (a, sfp);
1429 snprintf (SmimeKeyToUse, sizeof (SmimeKeyToUse), "%s/%s",
1430 NONULL(SmimeKeys), SmimeDefaultKey);
1432 snprintf (SmimeCertToUse, sizeof (SmimeCertToUse), "%s/%s",
1433 NONULL(SmimeCertificates), SmimeDefaultKey);
1435 snprintf (SmimeIntermediateToUse, sizeof (SmimeIntermediateToUse), "%s/%s",
1436 NONULL(SmimeCertificates), intermediates);
1440 if ((thepid = smime_invoke_sign (&smimein, NULL, &smimeerr,
1441 -1, fileno (smimeout), -1, filetosign)) == -1)
1443 mutt_perror _("Can't open OpenSSL subprocess!");
1444 safe_fclose (&smimeout);
1445 mutt_unlink (signedfile);
1446 mutt_unlink (filetosign);
1447 if (intermediates != SmimeDefaultKey)
1448 FREE (&intermediates);
1451 fputs (SmimePass, smimein);
1452 fputc ('\n', smimein);
1453 safe_fclose (&smimein);
1456 mutt_wait_filter (thepid);
1458 /* check for errors from OpenSSL */
1462 while (fgets (buffer, sizeof (buffer) - 1, smimeerr) != NULL)
1465 fputs (buffer, stdout);
1467 safe_fclose (&smimeerr);
1472 empty = (fgetc (smimeout) == EOF);
1473 safe_fclose (&smimeout);
1475 mutt_unlink (filetosign);
1479 mutt_any_key_to_continue (NULL);
1483 mutt_any_key_to_continue _("No output from OpenSSL...");
1484 mutt_unlink (signedfile);
1485 return (NULL); /* fatal error while signing */
1488 t = mutt_new_body ();
1489 t->type = TYPEMULTIPART;
1490 t->subtype = safe_strdup ("signed");
1491 t->encoding = ENC7BIT;
1493 t->disposition = DISPINLINE;
1495 mutt_generate_boundary (&t->parameter);
1496 /* check if this can be extracted from private key somehow.... */
1497 mutt_set_parameter ("micalg", "sha1", &t->parameter);
1498 mutt_set_parameter ("protocol", "application/x-pkcs7-signature",
1504 t->parts->next = mutt_new_body ();
1506 t->type = TYPEAPPLICATION;
1507 t->subtype = safe_strdup ("x-pkcs7-signature");
1508 t->filename = safe_strdup (signedfile);
1509 t->d_filename = safe_strdup ("smime.p7s");
1511 t->disposition = DISPATTACH;
1512 t->encoding = ENCBASE64;
1513 t->unlink = 1; /* ok to remove this file after sending. */
1525 * Handling S/MIME - bodies.
1534 pid_t smime_invoke_verify (FILE **smimein, FILE **smimeout, FILE **smimeerr,
1535 int smimeinfd, int smimeoutfd, int smimeerrfd,
1536 const char *fname, const char *sig_fname, int opaque)
1538 return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1539 smimeerrfd, fname, sig_fname, NULL, NULL, NULL, NULL,
1540 (opaque ? SmimeVerifyOpaqueCommand : SmimeVerifyCommand));
1545 pid_t smime_invoke_decrypt (FILE **smimein, FILE **smimeout, FILE **smimeerr,
1546 int smimeinfd, int smimeoutfd, int smimeerrfd,
1549 return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd,
1550 smimeerrfd, fname, NULL, NULL, SmimeKeyToUse,
1551 SmimeCertToUse, NULL, SmimeDecryptCommand);
1556 int smime_verify_one (BODY *sigbdy, STATE *s, const char *tempfile)
1558 char signedfile[_POSIX_PATH_MAX], smimeerrfile[_POSIX_PATH_MAX];
1559 FILE *fp=NULL, *smimeout=NULL, *smimeerr=NULL;
1564 size_t tmplength = 0;
1565 int origType = sigbdy->type;
1566 char *savePrefix = NULL;
1569 snprintf (signedfile, sizeof (signedfile), "%s.sig", tempfile);
1571 /* decode to a tempfile, saving the original destination */
1573 if ((s->fpout = safe_fopen (signedfile, "w")) == NULL)
1575 mutt_perror (signedfile);
1578 /* decoding the attachment changes the size and offset, so save a copy
1579 * of the "real" values now, and restore them after processing
1581 tmplength = sigbdy->length;
1582 tmpoffset = sigbdy->offset;
1584 /* if we are decoding binary bodies, we don't want to prefix each
1585 * line with the prefix or else the data will get corrupted.
1587 savePrefix = s->prefix;
1590 mutt_decode_attachment (sigbdy, s);
1592 sigbdy->length = ftello (s->fpout);
1594 safe_fclose (&s->fpout);
1596 /* restore final destination and substitute the tempfile for input */
1599 s->fpin = fopen (signedfile, "r");
1601 /* restore the prefix */
1602 s->prefix = savePrefix;
1604 sigbdy->type = origType;
1607 mutt_mktemp (smimeerrfile);
1608 if (!(smimeerr = safe_fopen (smimeerrfile, "w+")))
1610 mutt_perror (smimeerrfile);
1611 mutt_unlink (signedfile);
1615 crypt_current_time (s, "OpenSSL");
1617 if ((thepid = smime_invoke_verify (NULL, &smimeout, NULL,
1618 -1, -1, fileno (smimeerr),
1619 tempfile, signedfile, 0)) != -1)
1622 safe_fclose (&smimeout);
1624 if (mutt_wait_filter (thepid))
1635 line = mutt_read_line (line, &linelen, smimeerr, &lineno, 0);
1636 if (linelen && !ascii_strcasecmp (line, "verification successful"))
1645 mutt_copy_stream (smimeerr, s->fpout);
1646 safe_fclose (&smimeerr);
1648 state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
1650 mutt_unlink (signedfile);
1651 mutt_unlink (smimeerrfile);
1653 sigbdy->length = tmplength;
1654 sigbdy->offset = tmpoffset;
1656 /* restore the original source stream */
1657 safe_fclose (&s->fpin);
1669 This handles application/pkcs7-mime which can either be a signed
1670 or an encrypted message.
1673 static BODY *smime_handle_entity (BODY *m, STATE *s, FILE *outFile)
1678 char buf[HUGE_STRING];
1679 char outfile[_POSIX_PATH_MAX], errfile[_POSIX_PATH_MAX];
1680 char tmpfname[_POSIX_PATH_MAX];
1681 char tmptmpfname[_POSIX_PATH_MAX];
1682 FILE *smimeout = NULL, *smimein=NULL, *smimeerr=NULL;
1683 FILE *tmpfp=NULL, *tmpfp_buffer=NULL, *fpout=NULL;
1687 unsigned int type = mutt_is_application_smime (m);
1689 if (!(type & APPLICATION_SMIME)) return NULL;
1691 mutt_mktemp (outfile);
1692 if ((smimeout = safe_fopen (outfile, "w+")) == NULL)
1694 mutt_perror (outfile);
1698 mutt_mktemp (errfile);
1699 if ((smimeerr = safe_fopen (errfile, "w+")) == NULL)
1701 mutt_perror (errfile);
1702 safe_fclose (&smimeout); smimeout = NULL;
1705 mutt_unlink (errfile);
1708 mutt_mktemp (tmpfname);
1709 if ((tmpfp = safe_fopen (tmpfname, "w+")) == NULL)
1711 mutt_perror (tmpfname);
1712 safe_fclose (&smimeout); smimeout = NULL;
1713 safe_fclose (&smimeerr); smimeerr = NULL;
1717 fseeko (s->fpin, m->offset, 0);
1718 last_pos = m->offset;
1720 mutt_copy_bytes (s->fpin, tmpfp, m->length);
1723 safe_fclose (&tmpfp);
1725 if ((type & ENCRYPT) &&
1726 (thepid = smime_invoke_decrypt (&smimein, NULL, NULL, -1,
1727 fileno (smimeout), fileno (smimeerr), tmpfname)) == -1)
1729 safe_fclose (&smimeout); smimeout = NULL;
1730 mutt_unlink (tmpfname);
1731 if (s->flags & M_DISPLAY)
1732 state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
1735 else if ((type & SIGNOPAQUE) &&
1736 (thepid = smime_invoke_verify (&smimein, NULL, NULL, -1,
1737 fileno (smimeout), fileno (smimeerr), NULL,
1738 tmpfname, SIGNOPAQUE)) == -1)
1740 safe_fclose (&smimeout); smimeout = NULL;
1741 mutt_unlink (tmpfname);
1742 if (s->flags & M_DISPLAY)
1743 state_attach_puts (_("[-- Error: unable to create OpenSSL subprocess! --]\n"), s);
1750 if (!smime_valid_passphrase ())
1751 smime_void_passphrase ();
1752 fputs (SmimePass, smimein);
1753 fputc ('\n', smimein);
1756 safe_fclose (&smimein);
1758 mutt_wait_filter (thepid);
1759 mutt_unlink (tmpfname);
1762 if (s->flags & M_DISPLAY)
1767 if ((c = fgetc (smimeerr)) != EOF)
1769 ungetc (c, smimeerr);
1771 crypt_current_time (s, "OpenSSL");
1772 mutt_copy_stream (smimeerr, s->fpout);
1773 state_attach_puts (_("[-- End of OpenSSL output --]\n\n"), s);
1777 state_attach_puts (_("[-- The following data is S/MIME"
1778 " encrypted --]\n"), s);
1780 state_attach_puts (_("[-- The following data is S/MIME signed --]\n"), s);
1788 if (outFile) fpout = outFile;
1791 mutt_mktemp (tmptmpfname);
1792 if ((fpout = safe_fopen (tmptmpfname, "w+")) == NULL)
1794 mutt_perror(tmptmpfname);
1795 safe_fclose (&smimeout); smimeout = NULL;
1799 while (fgets (buf, sizeof (buf) - 1, smimeout) != NULL)
1801 len = mutt_strlen (buf);
1802 if (len > 1 && buf[len - 2] == '\r')
1813 if ((p = mutt_read_mime_header (fpout, 0)) != NULL)
1815 fstat (fileno (fpout), &info);
1816 p->length = info.st_size - p->offset;
1818 mutt_parse_part (fpout, p);
1822 tmpfp_buffer = s->fpin;
1824 mutt_body_handler (p, s);
1825 s->fpin = tmpfp_buffer;
1829 safe_fclose (&smimeout);
1831 mutt_unlink (outfile);
1835 safe_fclose (&fpout);
1836 mutt_unlink (tmptmpfname);
1841 if (s->flags & M_DISPLAY)
1844 state_attach_puts (_("\n[-- End of S/MIME encrypted data. --]\n"), s);
1846 state_attach_puts (_("\n[-- End of S/MIME signed data. --]\n"), s);
1849 if (type & SIGNOPAQUE)
1857 line = mutt_read_line (line, &linelen, smimeerr, &lineno, 0);
1858 if (linelen && !ascii_strcasecmp (line, "verification successful"))
1864 m->goodsig = p->goodsig;
1865 m->badsig = p->badsig;
1867 safe_fclose (&smimeerr);
1876 int smime_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
1880 char tempfile[_POSIX_PATH_MAX];
1882 long tmpoffset = b->offset;
1883 size_t tmplength = b->length;
1884 int origType = b->type;
1888 if (!mutt_is_application_smime (b))
1894 memset (&s, 0, sizeof (s));
1896 fseeko (s.fpin, b->offset, 0);
1898 mutt_mktemp (tempfile);
1899 if ((tmpfp = safe_fopen (tempfile, "w+")) == NULL)
1901 mutt_perror (tempfile);
1905 mutt_unlink (tempfile);
1907 mutt_decode_attachment (b, &s);
1909 b->length = ftello (s.fpout);
1915 mutt_mktemp (tempfile);
1916 if ((*fpout = safe_fopen (tempfile, "w+")) == NULL)
1918 mutt_perror (tempfile);
1922 mutt_unlink (tempfile);
1924 if (!(*cur = smime_handle_entity (b, &s, *fpout)))
1930 (*cur)->goodsig = b->goodsig;
1931 (*cur)->badsig = b->badsig;
1935 b->length = tmplength;
1936 b->offset = tmpoffset;
1937 safe_fclose (&tmpfp);
1945 int smime_application_smime_handler (BODY *m, STATE *s)
1947 return smime_handle_entity (m, s, NULL) ? 0 : -1;
1950 int smime_send_menu (HEADER *msg, int *redraw)
1954 if (!(WithCrypto & APPLICATION_SMIME))
1955 return msg->security;
1957 switch (mutt_multi_choice (_("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, or (c)lear? "),
1960 case 1: /* (e)ncrypt */
1961 msg->security |= ENCRYPT;
1962 msg->security &= ~SIGN;
1965 case 3: /* encrypt (w)ith */
1969 msg->security |= ENCRYPT;
1972 /* I use "dra" because "123" is recognized anyway */
1973 switch (mutt_multi_choice (_("Choose algorithm family:"
1974 " 1: DES, 2: RC2, 3: AES,"
1979 switch (choice = mutt_multi_choice (_("1: DES, 2: Triple-DES "),
1983 mutt_str_replace (&SmimeCryptAlg, "des");
1986 mutt_str_replace (&SmimeCryptAlg, "des3");
1992 switch (choice = mutt_multi_choice (_("1: RC2-40, 2: RC2-64, 3: RC2-128 "),
1996 mutt_str_replace (&SmimeCryptAlg, "rc2-40");
1999 mutt_str_replace (&SmimeCryptAlg, "rc2-64");
2002 mutt_str_replace (&SmimeCryptAlg, "rc2-128");
2008 switch (choice = mutt_multi_choice (_("1: AES128, 2: AES192, 3: AES256 "),
2012 mutt_str_replace (&SmimeCryptAlg, "aes128");
2015 mutt_str_replace (&SmimeCryptAlg, "aes192");
2018 mutt_str_replace (&SmimeCryptAlg, "aes256");
2023 case 4: /* (c)lear */
2024 FREE (&SmimeCryptAlg);
2026 case -1: /* Ctrl-G or Enter */
2030 } while (choice == -1);
2034 case 2: /* (s)ign */
2036 if(!SmimeDefaultKey)
2038 *redraw = REDRAW_FULL;
2040 if ((p = smime_ask_for_key (_("Sign as: "), NULL, 0)))
2041 mutt_str_replace (&SmimeDefaultKey, p);
2046 msg->security |= SIGN;
2047 msg->security &= ~ENCRYPT;
2050 case 4: /* sign (a)s */
2052 if ((p = smime_ask_for_key (_("Sign as: "), NULL, 0)))
2054 mutt_str_replace (&SmimeDefaultKey, p);
2056 msg->security |= SIGN;
2058 /* probably need a different passphrase */
2059 crypt_smime_void_passphrase ();
2063 msg->security &= ~SIGN;
2066 *redraw = REDRAW_FULL;
2069 case 5: /* (b)oth */
2070 msg->security |= (ENCRYPT | SIGN);
2073 case 6: /* (f)orget it */
2074 case 7: /* (c)lear */
2079 if (msg->security && msg->security != APPLICATION_SMIME)
2080 msg->security |= APPLICATION_SMIME;
2084 return (msg->security);
2088 #endif /* CRYPT_BACKEND_CLASSIC_SMIME */