mutt stable branch with some hacks
at jcs 1244 lines 31 kB view raw
1/* 2 * Copyright (C) 1996-1997 Michael R. Elkins <me@mutt.org> 3 * Copyright (C) 1999-2000,2002-2004,2006 Thomas Roessler <roessler@does-not-exist.org> 4 * Copyright (C) 2001 Thomas Roessler <roessler@does-not-exist.org> 5 * Oliver Ehli <elmy@acm.org> 6 * Copyright (C) 2003 Werner Koch <wk@gnupg.org> 7 * Copyright (C) 2004 g10code GmbH 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 */ 23 24#if HAVE_CONFIG_H 25# include "config.h" 26#endif 27 28#include "mutt.h" 29#include "mutt_curses.h" 30#include "mime.h" 31#include "copy.h" 32#include "mutt_crypt.h" 33 34#ifdef USE_AUTOCRYPT 35#include "autocrypt.h" 36#endif 37 38#include <sys/wait.h> 39#include <string.h> 40#include <stdlib.h> 41#include <unistd.h> 42#include <sys/stat.h> 43#include <errno.h> 44#include <ctype.h> 45 46#ifdef HAVE_LOCALE_H 47#include <locale.h> 48#endif 49 50#ifdef HAVE_SYS_TIME_H 51# include <sys/time.h> 52#endif 53 54#ifdef HAVE_SYS_RESOURCE_H 55# include <sys/resource.h> 56#endif 57 58 59/* print the current time to avoid spoofing of the signature output */ 60void crypt_current_time(STATE *s, char *app_name) 61{ 62 time_t t; 63 char p[STRING], tmp[STRING]; 64 65 if (!WithCrypto) 66 return; 67 68 if (option (OPTCRYPTTIMESTAMP)) 69 { 70 t = time(NULL); 71 strftime (p, sizeof (p), _(" (current time: %c)"), localtime (&t)); 72 } 73 else 74 *p = '\0'; 75 76 snprintf (tmp, sizeof (tmp), _("[-- %s output follows%s --]\n"), NONULL(app_name), p); 77 state_attach_puts (tmp, s); 78} 79 80 81 82void crypt_forget_passphrase (void) 83{ 84 if ((WithCrypto & APPLICATION_PGP)) 85 crypt_pgp_void_passphrase (); 86 87 if ((WithCrypto & APPLICATION_SMIME)) 88 crypt_smime_void_passphrase (); 89 90 if (WithCrypto) 91 mutt_message _("Passphrase(s) forgotten."); 92} 93 94 95#if defined(HAVE_SETRLIMIT) && (!defined(DEBUG)) 96 97static void disable_coredumps (void) 98{ 99 struct rlimit rl = {0, 0}; 100 static short done = 0; 101 102 if (!done) 103 { 104 setrlimit (RLIMIT_CORE, &rl); 105 done = 1; 106 } 107} 108 109#endif /* HAVE_SETRLIMIT */ 110 111 112int crypt_valid_passphrase(int flags) 113{ 114 int ret = 0; 115 116# if defined(HAVE_SETRLIMIT) &&(!defined(DEBUG)) 117 disable_coredumps (); 118# endif 119 120 if ((WithCrypto & APPLICATION_PGP) && (flags & APPLICATION_PGP)) 121 ret = crypt_pgp_valid_passphrase (); 122 123 if ((WithCrypto & APPLICATION_SMIME) && (flags & APPLICATION_SMIME)) 124 ret = crypt_smime_valid_passphrase (); 125 126 return ret; 127} 128 129 130/* In postpone mode, signing is automatically disabled. */ 131int mutt_protect (HEADER *msg, char *keylist, int postpone) 132{ 133 BODY *pbody = NULL, *tmp_pbody = NULL; 134 BODY *tmp_smime_pbody = NULL; 135 BODY *tmp_pgp_pbody = NULL; 136 ENVELOPE *protected_headers = NULL; 137 int security, sign, has_retainable_sig = 0; 138 int i; 139 140 if (!WithCrypto) 141 return -1; 142 143 security = msg->security; 144 sign = security & (AUTOCRYPT | SIGN); 145 if (postpone) 146 { 147 sign = 0; 148 security &= ~SIGN; 149 } 150 151 if (!(security & (ENCRYPT | AUTOCRYPT)) && !sign) 152 return 0; 153 154 if (sign && 155 !(security & AUTOCRYPT) && 156 !crypt_valid_passphrase (security)) 157 return (-1); 158 159 if ((WithCrypto & APPLICATION_PGP) && 160 !(security & AUTOCRYPT) && 161 ((security & PGPINLINE) == PGPINLINE)) 162 { 163 if ((msg->content->type != TYPETEXT) || 164 ascii_strcasecmp (msg->content->subtype, "plain")) 165 { 166 if ((i = query_quadoption (OPT_PGPMIMEAUTO, 167 _("Inline PGP can't be used with attachments. Revert to PGP/MIME?"))) != MUTT_YES) 168 { 169 mutt_error _("Mail not sent: inline PGP can't be used with attachments."); 170 return -1; 171 } 172 } 173 else if (!mutt_strcasecmp ("flowed", 174 mutt_get_parameter ("format", msg->content->parameter))) 175 { 176 if ((i = query_quadoption (OPT_PGPMIMEAUTO, 177 _("Inline PGP can't be used with format=flowed. Revert to PGP/MIME?"))) != MUTT_YES) 178 { 179 mutt_error _("Mail not sent: inline PGP can't be used with format=flowed."); 180 return -1; 181 } 182 } 183 else 184 { 185 /* they really want to send it inline... go for it */ 186 if (!isendwin ()) mutt_endwin _("Invoking PGP..."); 187 pbody = crypt_pgp_traditional_encryptsign (msg->content, security, keylist); 188 if (pbody) 189 { 190 msg->content = pbody; 191 return 0; 192 } 193 194 /* otherwise inline won't work...ask for revert */ 195 if ((i = query_quadoption (OPT_PGPMIMEAUTO, _("Message can't be sent inline. Revert to using PGP/MIME?"))) != MUTT_YES) 196 { 197 mutt_error _("Mail not sent."); 198 return -1; 199 } 200 } 201 202 /* go ahead with PGP/MIME */ 203 } 204 205 if (!isendwin ()) mutt_endwin (NULL); 206 207 if ((WithCrypto & APPLICATION_SMIME)) 208 tmp_smime_pbody = msg->content; 209 if ((WithCrypto & APPLICATION_PGP)) 210 tmp_pgp_pbody = msg->content; 211 212 if (option (OPTCRYPTUSEPKA) && sign) 213 { 214 /* Set sender (necessary for e.g. PKA). */ 215 216 if ((WithCrypto & APPLICATION_SMIME) 217 && (security & APPLICATION_SMIME)) 218 crypt_smime_set_sender (msg->env->from->mailbox); 219 else if ((WithCrypto & APPLICATION_PGP) 220 && (security & APPLICATION_PGP)) 221 crypt_pgp_set_sender (msg->env->from->mailbox); 222 } 223 224 if (option (OPTCRYPTPROTHDRSWRITE)) 225 { 226 protected_headers = mutt_new_envelope (); 227 mutt_str_replace (&protected_headers->subject, msg->env->subject); 228 /* Note: if other headers get added, such as to, cc, then a call to 229 * mutt_env_to_intl() will need to be added here too. */ 230 mutt_prepare_envelope (protected_headers, 0); 231 232 mutt_free_envelope (&msg->content->mime_headers); 233 msg->content->mime_headers = protected_headers; 234 } 235 236 /* A note about msg->content->mime_headers. If postpone or send 237 * fails, the mime_headers is cleared out before returning to the 238 * compose menu. So despite the "robustness" code above and in the 239 * gen_gossip_list function below, mime_headers will not be set when 240 * entering mutt_protect(). 241 * 242 * This is important to note because the user could toggle 243 * $crypt_protected_headers_write or $autocrypt off back in the 244 * compose menu. We don't want mutt_write_rfc822_header() to write 245 * stale data from one option if the other is set. 246 */ 247#ifdef USE_AUTOCRYPT 248 if (option (OPTAUTOCRYPT) && 249 !postpone && 250 (security & AUTOCRYPT)) 251 { 252 mutt_autocrypt_generate_gossip_list (msg); 253 } 254#endif 255 256 if (sign) 257 { 258 if ((WithCrypto & APPLICATION_SMIME) 259 && (security & APPLICATION_SMIME)) 260 { 261 if (!(tmp_pbody = crypt_smime_sign_message (msg->content))) 262 goto bail; 263 pbody = tmp_smime_pbody = tmp_pbody; 264 } 265 266 if ((WithCrypto & APPLICATION_PGP) 267 && (security & APPLICATION_PGP) 268 && (!(security & (ENCRYPT | AUTOCRYPT)) || option (OPTPGPRETAINABLESIG))) 269 { 270 if (!(tmp_pbody = crypt_pgp_sign_message (msg->content))) 271 goto bail; 272 273 has_retainable_sig = 1; 274 sign = 0; 275 pbody = tmp_pgp_pbody = tmp_pbody; 276 } 277 278 if (WithCrypto 279 && (security & APPLICATION_SMIME) 280 && (security & APPLICATION_PGP)) 281 { 282 /* here comes the draft ;-) */ 283 } 284 } 285 286 287 if (security & (ENCRYPT | AUTOCRYPT)) 288 { 289 if ((WithCrypto & APPLICATION_SMIME) 290 && (security & APPLICATION_SMIME)) 291 { 292 if (!(tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody, 293 keylist))) 294 { 295 /* signed ? free it! */ 296 goto bail; 297 } 298 /* free tmp_body if messages was signed AND encrypted ... */ 299 if (tmp_smime_pbody != msg->content && tmp_smime_pbody != tmp_pbody) 300 { 301 /* detach and don't delete msg->content, 302 which tmp_smime_pbody->parts after signing. */ 303 tmp_smime_pbody->parts = tmp_smime_pbody->parts->next; 304 msg->content->next = NULL; 305 mutt_free_body (&tmp_smime_pbody); 306 } 307 pbody = tmp_pbody; 308 } 309 310 if ((WithCrypto & APPLICATION_PGP) 311 && (security & APPLICATION_PGP)) 312 { 313 if (!(pbody = crypt_pgp_encrypt_message (msg, tmp_pgp_pbody, keylist, 314 sign))) 315 { 316 317 /* did we perform a retainable signature? */ 318 if (has_retainable_sig) 319 { 320 /* remove the outer multipart layer */ 321 tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody); 322 /* get rid of the signature */ 323 mutt_free_body (&tmp_pgp_pbody->next); 324 } 325 326 goto bail; 327 } 328 329 /* destroy temporary signature envelope when doing retainable 330 * signatures. 331 332 */ 333 if (has_retainable_sig) 334 { 335 tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody); 336 mutt_free_body (&tmp_pgp_pbody->next); 337 } 338 } 339 } 340 341 if (pbody) 342 { 343 msg->content = pbody; 344 return 0; 345 } 346 347bail: 348 mutt_free_envelope (&msg->content->mime_headers); 349 return -1; 350} 351 352 353 354 355int mutt_is_multipart_signed (BODY *b) 356{ 357 char *p; 358 359 if (!b || !(b->type == TYPEMULTIPART) || 360 !b->subtype || ascii_strcasecmp(b->subtype, "signed")) 361 return 0; 362 363 if (!(p = mutt_get_parameter("protocol", b->parameter))) 364 return 0; 365 366 if (!(ascii_strcasecmp (p, "multipart/mixed"))) 367 return SIGN; 368 369 if ((WithCrypto & APPLICATION_PGP) 370 && !(ascii_strcasecmp (p, "application/pgp-signature"))) 371 return PGPSIGN; 372 373 if ((WithCrypto & APPLICATION_SMIME) 374 && !(ascii_strcasecmp (p, "application/x-pkcs7-signature"))) 375 return SMIMESIGN; 376 if ((WithCrypto & APPLICATION_SMIME) 377 && !(ascii_strcasecmp (p, "application/pkcs7-signature"))) 378 return SMIMESIGN; 379 380 return 0; 381} 382 383 384int mutt_is_multipart_encrypted (BODY *b) 385{ 386 if ((WithCrypto & APPLICATION_PGP)) 387 { 388 char *p; 389 390 if (!b || b->type != TYPEMULTIPART || 391 !b->subtype || ascii_strcasecmp (b->subtype, "encrypted") || 392 !(p = mutt_get_parameter ("protocol", b->parameter)) || 393 ascii_strcasecmp (p, "application/pgp-encrypted")) 394 return 0; 395 396 return PGPENCRYPT; 397 } 398 399 return 0; 400} 401 402 403int mutt_is_valid_multipart_pgp_encrypted (BODY *b) 404{ 405 if (! mutt_is_multipart_encrypted (b)) 406 return 0; 407 408 b = b->parts; 409 if (!b || b->type != TYPEAPPLICATION || 410 !b->subtype || ascii_strcasecmp (b->subtype, "pgp-encrypted")) 411 return 0; 412 413 b = b->next; 414 if (!b || b->type != TYPEAPPLICATION || 415 !b->subtype || ascii_strcasecmp (b->subtype, "octet-stream")) 416 return 0; 417 418 return PGPENCRYPT; 419} 420 421 422/* 423 * This checks for the malformed layout caused by MS Exchange in 424 * some cases: 425 * <multipart/mixed> 426 * <text/plain> 427 * <application/pgp-encrypted> [BASE64-encoded] 428 * <application/octet-stream> [BASE64-encoded] 429 * See ticket #3742 430 */ 431int mutt_is_malformed_multipart_pgp_encrypted (BODY *b) 432{ 433 if (!(WithCrypto & APPLICATION_PGP)) 434 return 0; 435 436 if (!b || b->type != TYPEMULTIPART || 437 !b->subtype || ascii_strcasecmp (b->subtype, "mixed")) 438 return 0; 439 440 b = b->parts; 441 if (!b || b->type != TYPETEXT || 442 !b->subtype || ascii_strcasecmp (b->subtype, "plain") || 443 b->length != 0) 444 return 0; 445 446 b = b->next; 447 if (!b || b->type != TYPEAPPLICATION || 448 !b->subtype || ascii_strcasecmp (b->subtype, "pgp-encrypted")) 449 return 0; 450 451 b = b->next; 452 if (!b || b->type != TYPEAPPLICATION || 453 !b->subtype || ascii_strcasecmp (b->subtype, "octet-stream")) 454 return 0; 455 456 b = b->next; 457 if (b) 458 return 0; 459 460 return PGPENCRYPT; 461} 462 463 464int mutt_is_application_pgp (BODY *m) 465{ 466 int t = 0; 467 char *p; 468 469 if (m->type == TYPEAPPLICATION) 470 { 471 if (!ascii_strcasecmp (m->subtype, "pgp") || !ascii_strcasecmp (m->subtype, "x-pgp-message")) 472 { 473 if ((p = mutt_get_parameter ("x-action", m->parameter)) 474 && (!ascii_strcasecmp (p, "sign") || !ascii_strcasecmp (p, "signclear"))) 475 t |= PGPSIGN; 476 477 if ((p = mutt_get_parameter ("format", m->parameter)) && 478 !ascii_strcasecmp (p, "keys-only")) 479 t |= PGPKEY; 480 481 if (!t) t |= PGPENCRYPT; /* not necessarily correct, but... */ 482 } 483 484 if (!ascii_strcasecmp (m->subtype, "pgp-signed")) 485 t |= PGPSIGN; 486 487 if (!ascii_strcasecmp (m->subtype, "pgp-keys")) 488 t |= PGPKEY; 489 } 490 else if (m->type == TYPETEXT && ascii_strcasecmp ("plain", m->subtype) == 0) 491 { 492 if (((p = mutt_get_parameter ("x-mutt-action", m->parameter)) 493 || (p = mutt_get_parameter ("x-action", m->parameter)) 494 || (p = mutt_get_parameter ("action", m->parameter))) 495 && !ascii_strncasecmp ("pgp-sign", p, 8)) 496 t |= PGPSIGN; 497 else if (p && !ascii_strncasecmp ("pgp-encrypt", p, 11)) 498 t |= PGPENCRYPT; 499 else if (p && !ascii_strncasecmp ("pgp-keys", p, 7)) 500 t |= PGPKEY; 501 } 502 if (t) 503 t |= PGPINLINE; 504 505 return t; 506} 507 508int mutt_is_application_smime (BODY *m) 509{ 510 char *t=NULL; 511 int len, complain=0; 512 513 if (!m) 514 return 0; 515 516 if ((m->type & TYPEAPPLICATION) && m->subtype) 517 { 518 /* S/MIME MIME types don't need x- anymore, see RFC2311 */ 519 if (!ascii_strcasecmp (m->subtype, "x-pkcs7-mime") || 520 !ascii_strcasecmp (m->subtype, "pkcs7-mime")) 521 { 522 if ((t = mutt_get_parameter ("smime-type", m->parameter))) 523 { 524 if (!ascii_strcasecmp (t, "enveloped-data")) 525 return SMIMEENCRYPT; 526 else if (!ascii_strcasecmp (t, "signed-data")) 527 return (SMIMESIGN|SMIMEOPAQUE); 528 else return 0; 529 } 530 /* Netscape 4.7 uses 531 * Content-Description: S/MIME Encrypted Message 532 * instead of Content-Type parameter 533 */ 534 if (!ascii_strcasecmp (m->description, "S/MIME Encrypted Message")) 535 return SMIMEENCRYPT; 536 complain = 1; 537 } 538 else if (ascii_strcasecmp (m->subtype, "octet-stream")) 539 return 0; 540 541 t = mutt_get_parameter ("name", m->parameter); 542 543 if (!t) t = m->d_filename; 544 if (!t) t = m->filename; 545 if (!t) 546 { 547 if (complain) 548 mutt_message (_("S/MIME messages with no hints on content are unsupported.")); 549 return 0; 550 } 551 552 /* no .p7c, .p10 support yet. */ 553 554 len = mutt_strlen (t) - 4; 555 if (len > 0 && *(t+len) == '.') 556 { 557 len++; 558 if (!ascii_strcasecmp ((t+len), "p7m")) 559 /* Not sure if this is the correct thing to do, but 560 it's required for compatibility with Outlook */ 561 return (SMIMESIGN|SMIMEOPAQUE); 562 else if (!ascii_strcasecmp ((t+len), "p7s")) 563 return (SMIMESIGN|SMIMEOPAQUE); 564 } 565 } 566 567 return 0; 568} 569 570 571 572 573 574 575int crypt_query (BODY *m) 576{ 577 int t = 0; 578 579 if (!WithCrypto) 580 return 0; 581 582 if (!m) 583 return 0; 584 585 if (m->type == TYPEAPPLICATION) 586 { 587 if ((WithCrypto & APPLICATION_PGP)) 588 t |= mutt_is_application_pgp(m); 589 590 if ((WithCrypto & APPLICATION_SMIME)) 591 { 592 t |= mutt_is_application_smime(m); 593 if (t && m->goodsig) t |= GOODSIGN; 594 if (t && m->badsig) t |= BADSIGN; 595 } 596 } 597 else if ((WithCrypto & APPLICATION_PGP) && m->type == TYPETEXT) 598 { 599 t |= mutt_is_application_pgp (m); 600 if (t && m->goodsig) 601 t |= GOODSIGN; 602 } 603 604 if (m->type == TYPEMULTIPART) 605 { 606 t |= mutt_is_multipart_encrypted(m); 607 t |= mutt_is_multipart_signed (m); 608 t |= mutt_is_malformed_multipart_pgp_encrypted (m); 609 610 if (t && m->goodsig) 611 t |= GOODSIGN; 612#ifdef USE_AUTOCRYPT 613 if (t && m->is_autocrypt) 614 t |= AUTOCRYPT; 615#endif 616 } 617 618 if (m->type == TYPEMULTIPART || m->type == TYPEMESSAGE) 619 { 620 BODY *p; 621 int u, v, w; 622 623 u = m->parts ? 0xffffffff : 0; /* Bits set in all parts */ 624 w = 0; /* Bits set in any part */ 625 626 for (p = m->parts; p; p = p->next) 627 { 628 v = crypt_query (p); 629 u &= v; w |= v; 630 } 631 t |= u | (w & ~GOODSIGN); 632 633 if ((w & GOODSIGN) && !(u & GOODSIGN)) 634 t |= PARTSIGN; 635 } 636 637 return t; 638} 639 640 641 642 643int crypt_write_signed(BODY *a, STATE *s, const char *tempfile) 644{ 645 FILE *fp; 646 int c; 647 short hadcr; 648 size_t bytes; 649 650 if (!WithCrypto) 651 return -1; 652 653 if (!(fp = safe_fopen (tempfile, "w"))) 654 { 655 mutt_perror (tempfile); 656 return -1; 657 } 658 659 fseeko (s->fpin, a->hdr_offset, 0); 660 bytes = a->length + a->offset - a->hdr_offset; 661 hadcr = 0; 662 while (bytes > 0) 663 { 664 if ((c = fgetc (s->fpin)) == EOF) 665 break; 666 667 bytes--; 668 669 if (c == '\r') 670 hadcr = 1; 671 else 672 { 673 if (c == '\n' && !hadcr) 674 fputc ('\r', fp); 675 676 hadcr = 0; 677 } 678 679 fputc (c, fp); 680 681 } 682 safe_fclose (&fp); 683 684 return 0; 685} 686 687 688 689void convert_to_7bit (BODY *a) 690{ 691 if (!WithCrypto) 692 return; 693 694 while (a) 695 { 696 if (a->type == TYPEMULTIPART) 697 { 698 if (a->encoding != ENC7BIT) 699 { 700 a->encoding = ENC7BIT; 701 convert_to_7bit(a->parts); 702 } 703 else if ((WithCrypto & APPLICATION_PGP) && option (OPTPGPSTRICTENC)) 704 convert_to_7bit (a->parts); 705 } 706 else if (a->type == TYPEMESSAGE && 707 ascii_strcasecmp(a->subtype, "delivery-status")) 708 { 709 if (a->encoding != ENC7BIT) 710 mutt_message_to_7bit (a, NULL); 711 } 712 else if (a->encoding == ENC8BIT) 713 a->encoding = ENCQUOTEDPRINTABLE; 714 else if (a->encoding == ENCBINARY) 715 a->encoding = ENCBASE64; 716 else if (a->content && a->encoding != ENCBASE64 && 717 (a->content->from || (a->content->space && 718 option (OPTPGPSTRICTENC)))) 719 a->encoding = ENCQUOTEDPRINTABLE; 720 a = a->next; 721 } 722} 723 724 725 726 727void crypt_extract_keys_from_messages (HEADER * h) 728{ 729 int i; 730 BUFFER *tempfname = NULL; 731 char *mbox; 732 ADDRESS *tmp = NULL; 733 FILE *fpout; 734 735 if (!WithCrypto) 736 return; 737 738 tempfname = mutt_buffer_pool_get (); 739 mutt_buffer_mktemp (tempfname); 740 if (!(fpout = safe_fopen (mutt_b2s (tempfname), "w"))) 741 { 742 mutt_perror (mutt_b2s (tempfname)); 743 goto cleanup; 744 } 745 746 if ((WithCrypto & APPLICATION_PGP)) 747 set_option (OPTDONTHANDLEPGPKEYS); 748 749 if (!h) 750 { 751 for (i = 0; i < Context->vcount; i++) 752 { 753 if (Context->hdrs[Context->v2r[i]]->tagged) 754 { 755 mutt_parse_mime_message (Context, Context->hdrs[Context->v2r[i]]); 756 if (Context->hdrs[Context->v2r[i]]->security & ENCRYPT && 757 !crypt_valid_passphrase (Context->hdrs[Context->v2r[i]]->security)) 758 { 759 safe_fclose (&fpout); 760 break; 761 } 762 763 if ((WithCrypto & APPLICATION_PGP) 764 && (Context->hdrs[Context->v2r[i]]->security & APPLICATION_PGP)) 765 { 766 mutt_copy_message (fpout, Context, Context->hdrs[Context->v2r[i]], 767 MUTT_CM_DECODE|MUTT_CM_CHARCONV, 0); 768 fflush(fpout); 769 770 mutt_endwin (_("Trying to extract PGP keys...\n")); 771 crypt_pgp_invoke_import (mutt_b2s (tempfname)); 772 } 773 774 if ((WithCrypto & APPLICATION_SMIME) 775 && (Context->hdrs[Context->v2r[i]]->security & APPLICATION_SMIME)) 776 { 777 if (Context->hdrs[Context->v2r[i]]->security & ENCRYPT) 778 mutt_copy_message (fpout, Context, Context->hdrs[Context->v2r[i]], 779 MUTT_CM_NOHEADER|MUTT_CM_DECODE_CRYPT 780 |MUTT_CM_DECODE_SMIME, 0); 781 else 782 mutt_copy_message (fpout, Context, 783 Context->hdrs[Context->v2r[i]], 0, 0); 784 fflush(fpout); 785 786 if (Context->hdrs[Context->v2r[i]]->env->from) 787 tmp = mutt_expand_aliases (Context->hdrs[Context->v2r[i]]->env->from); 788 else if (Context->hdrs[Context->v2r[i]]->env->sender) 789 tmp = mutt_expand_aliases (Context->hdrs[Context->v2r[i]]->env->sender); 790 mbox = tmp ? tmp->mailbox : NULL; 791 if (mbox) 792 { 793 mutt_endwin (_("Trying to extract S/MIME certificates...\n")); 794 crypt_smime_invoke_import (mutt_b2s (tempfname), mbox); 795 tmp = NULL; 796 } 797 } 798 799 rewind (fpout); 800 } 801 } 802 } 803 else 804 { 805 mutt_parse_mime_message (Context, h); 806 if (!(h->security & ENCRYPT && !crypt_valid_passphrase (h->security))) 807 { 808 if ((WithCrypto & APPLICATION_PGP) 809 && (h->security & APPLICATION_PGP)) 810 { 811 mutt_copy_message (fpout, Context, h, MUTT_CM_DECODE|MUTT_CM_CHARCONV, 0); 812 fflush(fpout); 813 mutt_endwin (_("Trying to extract PGP keys...\n")); 814 crypt_pgp_invoke_import (mutt_b2s (tempfname)); 815 } 816 817 if ((WithCrypto & APPLICATION_SMIME) 818 && (h->security & APPLICATION_SMIME)) 819 { 820 if (h->security & ENCRYPT) 821 mutt_copy_message (fpout, Context, h, 822 MUTT_CM_NOHEADER | MUTT_CM_DECODE_CRYPT | MUTT_CM_DECODE_SMIME, 823 0); 824 else 825 mutt_copy_message (fpout, Context, h, 0, 0); 826 827 fflush(fpout); 828 if (h->env->from) tmp = mutt_expand_aliases (h->env->from); 829 else if (h->env->sender) tmp = mutt_expand_aliases (h->env->sender); 830 mbox = tmp ? tmp->mailbox : NULL; 831 if (mbox) /* else ? */ 832 { 833 mutt_message (_("Trying to extract S/MIME certificates...\n")); 834 crypt_smime_invoke_import (mutt_b2s (tempfname), mbox); 835 } 836 } 837 } 838 } 839 840 safe_fclose (&fpout); 841 if (isendwin()) 842 mutt_any_key_to_continue (NULL); 843 844 mutt_unlink (mutt_b2s (tempfname)); 845 846 if ((WithCrypto & APPLICATION_PGP)) 847 unset_option (OPTDONTHANDLEPGPKEYS); 848 849cleanup: 850 mutt_buffer_pool_release (&tempfname); 851} 852 853 854 855int crypt_get_keys (HEADER *msg, char **keylist, int oppenc_mode) 856{ 857 ADDRESS *adrlist = NULL, *last = NULL; 858 const char *fqdn = mutt_fqdn (1); 859 char *self_encrypt = NULL; 860 size_t keylist_size; 861 862 /* Do a quick check to make sure that we can find all of the encryption 863 * keys if the user has requested this service. 864 */ 865 866 if (!WithCrypto) 867 return 0; 868 869 *keylist = NULL; 870 871#ifdef USE_AUTOCRYPT 872 if (!oppenc_mode && (msg->security & AUTOCRYPT)) 873 { 874 if (mutt_autocrypt_ui_recommendation (msg, keylist) <= AUTOCRYPT_REC_NO) 875 return (-1); 876 return (0); 877 } 878#endif 879 880 if ((WithCrypto & APPLICATION_PGP)) 881 set_option (OPTPGPCHECKTRUST); 882 883 last = rfc822_append (&adrlist, msg->env->to, 0); 884 last = rfc822_append (last ? &last : &adrlist, msg->env->cc, 0); 885 rfc822_append (last ? &last : &adrlist, msg->env->bcc, 0); 886 887 if (fqdn) 888 rfc822_qualify (adrlist, fqdn); 889 adrlist = mutt_remove_duplicates (adrlist); 890 891 if (oppenc_mode || (msg->security & ENCRYPT)) 892 { 893 if ((WithCrypto & APPLICATION_PGP) 894 && (msg->security & APPLICATION_PGP)) 895 { 896 if ((*keylist = crypt_pgp_findkeys (adrlist, oppenc_mode)) == NULL) 897 { 898 rfc822_free_address (&adrlist); 899 return (-1); 900 } 901 unset_option (OPTPGPCHECKTRUST); 902 if (option (OPTPGPSELFENCRYPT)) 903 self_encrypt = PgpDefaultKey; 904 } 905 if ((WithCrypto & APPLICATION_SMIME) 906 && (msg->security & APPLICATION_SMIME)) 907 { 908 if ((*keylist = crypt_smime_findkeys (adrlist, oppenc_mode)) == NULL) 909 { 910 rfc822_free_address (&adrlist); 911 return (-1); 912 } 913 if (option (OPTSMIMESELFENCRYPT)) 914 self_encrypt = SmimeDefaultKey; 915 } 916 } 917 918 if (!oppenc_mode && self_encrypt) 919 { 920 keylist_size = mutt_strlen (*keylist); 921 safe_realloc (keylist, keylist_size + mutt_strlen (self_encrypt) + 2); 922 sprintf (*keylist + keylist_size, " %s", self_encrypt); /* __SPRINTF_CHECKED__ */ 923 } 924 925 rfc822_free_address (&adrlist); 926 927 return (0); 928} 929 930 931/* 932 * Check if all recipients keys can be automatically determined. 933 * Enable encryption if they can, otherwise disable encryption. 934 */ 935 936void crypt_opportunistic_encrypt(HEADER *msg) 937{ 938 char *pgpkeylist = NULL; 939 940 if (!WithCrypto) 941 return; 942 943 if (! (option (OPTCRYPTOPPORTUNISTICENCRYPT) && (msg->security & OPPENCRYPT)) ) 944 return; 945 946 crypt_get_keys (msg, &pgpkeylist, 1); 947 if (pgpkeylist != NULL ) 948 { 949 msg->security |= ENCRYPT; 950 FREE (&pgpkeylist); 951 } 952 else 953 { 954 msg->security &= ~ENCRYPT; 955 } 956} 957 958 959 960static void crypt_fetch_signatures (BODY ***signatures, BODY *a, int *n) 961{ 962 if (!WithCrypto) 963 return; 964 965 for (; a; a = a->next) 966 { 967 if (a->type == TYPEMULTIPART) 968 crypt_fetch_signatures (signatures, a->parts, n); 969 else 970 { 971 if ((*n % 5) == 0) 972 safe_realloc (signatures, (*n + 6) * sizeof (BODY **)); 973 974 (*signatures)[(*n)++] = a; 975 } 976 } 977} 978 979int mutt_should_hide_protected_subject (HEADER *h) 980{ 981 if (option (OPTCRYPTPROTHDRSWRITE) && 982 (h->security & (ENCRYPT | AUTOCRYPT)) && 983 !(h->security & INLINE) && 984 ProtHdrSubject) 985 return 1; 986 987 return 0; 988} 989 990int mutt_protected_headers_handler (BODY *a, STATE *s) 991{ 992 if (option (OPTCRYPTPROTHDRSREAD) && a->mime_headers) 993 { 994 if (a->mime_headers->subject) 995 { 996 if ((s->flags & MUTT_DISPLAY) && option (OPTWEED) && 997 mutt_matches_ignore ("subject", Ignore) && 998 !mutt_matches_ignore ("subject", UnIgnore)) 999 return 0; 1000 1001 state_mark_protected_header (s); 1002 mutt_write_one_header (s->fpout, "Subject", a->mime_headers->subject, 1003 s->prefix, 1004 mutt_window_wrap_cols (MuttIndexWindow, Wrap), 1005 (s->flags & MUTT_DISPLAY) ? CH_DISPLAY : 0); 1006 state_puts ("\n", s); 1007 } 1008 } 1009 1010 return 0; 1011} 1012 1013/* 1014 * This routine verifies a "multipart/signed" body. 1015 */ 1016 1017int mutt_signed_handler (BODY *a, STATE *s) 1018{ 1019 BUFFER *tempfile = NULL; 1020 int signed_type; 1021 int inconsistent = 0; 1022 1023 BODY *b = a; 1024 BODY **signatures = NULL; 1025 int sigcnt = 0; 1026 int i; 1027 short goodsig = 1; 1028 int rc = 0; 1029 1030 if (!WithCrypto) 1031 return -1; 1032 1033 a = a->parts; 1034 signed_type = mutt_is_multipart_signed (b); 1035 if (!signed_type) 1036 { 1037 /* A null protocol value is already checked for in mutt_body_handler() */ 1038 state_printf (s, _("[-- Error: " 1039 "Unknown multipart/signed protocol %s! --]\n\n"), 1040 mutt_get_parameter ("protocol", b->parameter)); 1041 return mutt_body_handler (a, s); 1042 } 1043 1044 if (!(a && a->next)) 1045 inconsistent = 1; 1046 else 1047 { 1048 switch (signed_type) 1049 { 1050 case SIGN: 1051 if (a->next->type != TYPEMULTIPART || 1052 ascii_strcasecmp (a->next->subtype, "mixed")) 1053 inconsistent = 1; 1054 break; 1055 case PGPSIGN: 1056 if (a->next->type != TYPEAPPLICATION || 1057 ascii_strcasecmp (a->next->subtype, "pgp-signature")) 1058 inconsistent = 1; 1059 break; 1060 case SMIMESIGN: 1061 if (a->next->type != TYPEAPPLICATION || 1062 (ascii_strcasecmp (a->next->subtype, "x-pkcs7-signature") && 1063 ascii_strcasecmp (a->next->subtype, "pkcs7-signature"))) 1064 inconsistent = 1; 1065 break; 1066 default: 1067 inconsistent = 1; 1068 } 1069 } 1070 if (inconsistent) 1071 { 1072 state_attach_puts (_("[-- Error: " 1073 "Missing or bad-format multipart/signed signature!" 1074 " --]\n\n"), 1075 s); 1076 return mutt_body_handler (a, s); 1077 } 1078 1079 if (s->flags & MUTT_DISPLAY) 1080 { 1081 1082 crypt_fetch_signatures (&signatures, a->next, &sigcnt); 1083 1084 if (sigcnt) 1085 { 1086 tempfile = mutt_buffer_pool_get (); 1087 mutt_buffer_mktemp (tempfile); 1088 if (crypt_write_signed (a, s, mutt_b2s (tempfile)) == 0) 1089 { 1090 for (i = 0; i < sigcnt; i++) 1091 { 1092 if ((WithCrypto & APPLICATION_PGP) 1093 && signatures[i]->type == TYPEAPPLICATION 1094 && !ascii_strcasecmp (signatures[i]->subtype, "pgp-signature")) 1095 { 1096 if (crypt_pgp_verify_one (signatures[i], s, mutt_b2s (tempfile)) != 0) 1097 goodsig = 0; 1098 1099 continue; 1100 } 1101 1102 if ((WithCrypto & APPLICATION_SMIME) 1103 && signatures[i]->type == TYPEAPPLICATION 1104 && (!ascii_strcasecmp(signatures[i]->subtype, "x-pkcs7-signature") 1105 || !ascii_strcasecmp(signatures[i]->subtype, "pkcs7-signature"))) 1106 { 1107 if (crypt_smime_verify_one (signatures[i], s, mutt_b2s (tempfile)) != 0) 1108 goodsig = 0; 1109 1110 continue; 1111 } 1112 1113 state_printf (s, _("[-- Warning: " 1114 "We can't verify %s/%s signatures. --]\n\n"), 1115 TYPE(signatures[i]), signatures[i]->subtype); 1116 } 1117 } 1118 1119 mutt_unlink (mutt_b2s (tempfile)); 1120 mutt_buffer_pool_release (&tempfile); 1121 1122 b->goodsig = goodsig; 1123 b->badsig = !goodsig; 1124 1125 /* Now display the signed body */ 1126 state_attach_puts (_("[-- The following data is signed --]\n\n"), s); 1127 1128 mutt_protected_headers_handler (a, s); 1129 1130 FREE (&signatures); 1131 } 1132 else 1133 state_attach_puts (_("[-- Warning: Can't find any signatures. --]\n\n"), s); 1134 } 1135 1136 rc = mutt_body_handler (a, s); 1137 1138 if (s->flags & MUTT_DISPLAY && sigcnt) 1139 state_attach_puts (_("\n[-- End of signed data --]\n"), s); 1140 1141 return rc; 1142} 1143 1144 1145/* Obtain pointers to fingerprint or short or long key ID, if any. 1146 * See mutt_crypt.h for details. 1147 */ 1148const char* crypt_get_fingerprint_or_id (char *p, const char **pphint, 1149 const char **ppl, const char **pps) 1150{ 1151 const char *ps, *pl, *phint; 1152 char *pfcopy, *pf, *s1, *s2; 1153 char c; 1154 int isid; 1155 size_t hexdigits; 1156 1157 /* User input may be partial name, fingerprint or short or long key ID, 1158 * independent of OPTPGPLONGIDS. 1159 * Fingerprint without spaces is 40 hex digits (SHA-1) or 32 hex digits (MD5). 1160 * Strip leading "0x" for key ID detection and prepare pl and ps to indicate 1161 * if an ID was found and to simplify logic in the key loop's inner 1162 * condition of the caller. */ 1163 1164 pf = mutt_skip_whitespace (p); 1165 if (!mutt_strncasecmp (pf, "0x", 2)) 1166 pf += 2; 1167 1168 /* Check if a fingerprint is given, must be hex digits only, blanks 1169 * separating groups of 4 hex digits are allowed. Also pre-check for ID. */ 1170 isid = 2; /* unknown */ 1171 hexdigits = 0; 1172 s1 = pf; 1173 do 1174 { 1175 c = *(s1++); 1176 if (('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f')) 1177 { 1178 ++hexdigits; 1179 if (isid == 2) 1180 isid = 1; /* it is an ID so far */ 1181 } 1182 else if (c) 1183 { 1184 isid = 0; /* not an ID */ 1185 if (c == ' ' && ((hexdigits % 4) == 0)) 1186 ; /* skip blank before or after 4 hex digits */ 1187 else 1188 break; /* any other character or position */ 1189 } 1190 } while (c); 1191 1192 /* If at end of input, check for correct fingerprint length and copy if. */ 1193 pfcopy = (!c && ((hexdigits == 40) || (hexdigits == 32)) ? safe_strdup (pf) : NULL); 1194 1195 if (pfcopy) 1196 { 1197 /* Use pfcopy to strip all spaces from fingerprint and as hint. */ 1198 s1 = s2 = pfcopy; 1199 do 1200 { 1201 *(s1++) = *(s2 = mutt_skip_whitespace (s2)); 1202 } while (*(s2++)); 1203 1204 phint = pfcopy; 1205 ps = pl = NULL; 1206 } 1207 else 1208 { 1209 phint = p; 1210 ps = pl = NULL; 1211 if (isid == 1) 1212 { 1213 if (mutt_strlen (pf) == 16) 1214 pl = pf; /* long key ID */ 1215 else if (mutt_strlen (pf) == 8) 1216 ps = pf; /* short key ID */ 1217 } 1218 } 1219 1220 *pphint = phint; 1221 *ppl = pl; 1222 *pps = ps; 1223 return pfcopy; 1224} 1225 1226 1227/* 1228 * Used by pgp_findKeys and find_keys to check if a crypt-hook 1229 * value is a key id. 1230 */ 1231 1232short crypt_is_numerical_keyid (const char *s) 1233{ 1234 /* or should we require the "0x"? */ 1235 if (strncmp (s, "0x", 2) == 0) 1236 s += 2; 1237 if (strlen (s) % 8) 1238 return 0; 1239 while (*s) 1240 if (strchr ("0123456789ABCDEFabcdef", *s++) == NULL) 1241 return 0; 1242 1243 return 1; 1244}