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