PageRenderTime 293ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 1ms

/pith/smime.c

https://github.com/sergi/re-alpine
C | 2031 lines | 1350 code | 430 blank | 251 comment | 353 complexity | bde44461a159db2dcc00588a38fdc1f4 MD5 | raw file
  1. #if !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: smime.c 1176 2008-09-29 21:16:42Z hubert@u.washington.edu $";
  3. #endif
  4. /*
  5. * ========================================================================
  6. * Copyright 2008 University of Washington
  7. *
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * ========================================================================
  15. */
  16. /*
  17. * This is based on a contribution from Jonathan Paisley
  18. *
  19. * File: smime.c
  20. * Author: paisleyj@dcs.gla.ac.uk
  21. * Date: 01/2001
  22. */
  23. #include "../pith/headers.h"
  24. #ifdef SMIME
  25. #include "../pith/osdep/canaccess.h"
  26. #include "../pith/helptext.h"
  27. #include "../pith/store.h"
  28. #include "../pith/status.h"
  29. #include "../pith/detach.h"
  30. #include "../pith/conf.h"
  31. #include "../pith/smkeys.h"
  32. #include "../pith/smime.h"
  33. #include "../pith/mailpart.h"
  34. #include "../pith/reply.h"
  35. #include "../pith/tempfile.h"
  36. #include "../pith/readfile.h"
  37. #include "../pith/remote.h"
  38. #include <openssl/buffer.h>
  39. typedef enum {Public, Private, CACert} WhichCerts;
  40. /* internal prototypes */
  41. static void forget_private_keys(void);
  42. static int app_RAND_load_file(const char *file);
  43. static void openssl_extra_randomness(void);
  44. static int app_RAND_write_file(const char *file);
  45. static void smime_init(void);
  46. static const char *openssl_error_string(void);
  47. static void create_local_cache(char *base, BODY *b);
  48. static BIO *raw_part_to_bio(long msgno, const char *section);
  49. static long rfc822_output_func(void *b, char *string);
  50. static int load_private_key(PERSONAL_CERT *pcert);
  51. static void setup_pkcs7_body_for_signature(BODY *b, char *description,
  52. char *type, char *filename);
  53. static BIO *body_to_bio(BODY *body);
  54. static BIO *bio_from_store(STORE_S *store);
  55. static STORE_S *get_part_contents(long msgno, const char *section);
  56. static PKCS7 *get_pkcs7_from_part(long msgno, const char *section);
  57. static int do_signature_verify(PKCS7 *p7, BIO *in, BIO *out);
  58. static int do_detached_signature_verify(BODY *b, long msgno, char *section);
  59. static PERSONAL_CERT *find_certificate_matching_pkcs7(PKCS7 *p7);
  60. static int do_decoding(BODY *b, long msgno, const char *section);
  61. static void free_smime_struct(SMIME_STUFF_S **smime);
  62. static void setup_storage_locations(void);
  63. static int copy_dir_to_container(WhichCerts which);
  64. static int copy_container_to_dir(WhichCerts which);
  65. int (*pith_opt_smime_get_passphrase)(void);
  66. static X509_STORE *s_cert_store;
  67. /* State management for randomness functions below */
  68. static int seeded = 0;
  69. static int egdsocket = 0;
  70. /*
  71. * Forget any cached private keys
  72. */
  73. static void
  74. forget_private_keys(void)
  75. {
  76. PERSONAL_CERT *pcert;
  77. size_t len;
  78. volatile char *p;
  79. dprint((9, "forget_private_keys()"));
  80. if(ps_global->smime){
  81. for(pcert=(PERSONAL_CERT *) ps_global->smime->personal_certs;
  82. pcert;
  83. pcert=pcert->next){
  84. if(pcert->key){
  85. EVP_PKEY_free(pcert->key);
  86. pcert->key = NULL;
  87. }
  88. }
  89. ps_global->smime->entered_passphrase = 0;
  90. len = sizeof(ps_global->smime->passphrase);
  91. p = ps_global->smime->passphrase;
  92. while(len-- > 0)
  93. *p++ = '\0';
  94. }
  95. }
  96. /*
  97. * taken from openssl/apps/app_rand.c
  98. */
  99. static int
  100. app_RAND_load_file(const char *file)
  101. {
  102. char buffer[200];
  103. if(file == NULL)
  104. file = RAND_file_name(buffer, sizeof buffer);
  105. else if(RAND_egd(file) > 0){
  106. /* we try if the given filename is an EGD socket.
  107. if it is, we don't write anything back to the file. */
  108. egdsocket = 1;
  109. return 1;
  110. }
  111. if(file == NULL || !RAND_load_file(file, -1)){
  112. if(RAND_status() == 0){
  113. dprint((1, "unable to load 'random state'\n"));
  114. dprint((1, "This means that the random number generator has not been seeded\n"));
  115. dprint((1, "with much random data.\n"));
  116. }
  117. return 0;
  118. }
  119. seeded = 1;
  120. return 1;
  121. }
  122. /*
  123. * copied and fiddled from imap/src/osdep/unix/auth_ssl.c
  124. */
  125. static void
  126. openssl_extra_randomness(void)
  127. {
  128. #if !defined(WIN32)
  129. int fd;
  130. unsigned long i;
  131. char *tf = NULL;
  132. char tmp[MAXPATH];
  133. struct stat sbuf;
  134. /* if system doesn't have /dev/urandom */
  135. if(stat ("/dev/urandom", &sbuf)){
  136. tmp[0] = '0';
  137. tf = temp_nam(NULL, NULL);
  138. if(tf){
  139. strncpy(tmp, tf, sizeof(tmp));
  140. tmp[sizeof(tmp)-1] = '\0';
  141. fs_give((void **) &tf);
  142. }
  143. if((fd = open(tmp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0)
  144. i = (unsigned long) tmp;
  145. else{
  146. unlink(tmp); /* don't need the file */
  147. fstat(fd, &sbuf); /* get information about the file */
  148. i = sbuf.st_ino; /* remember its inode */
  149. close(fd); /* or its descriptor */
  150. }
  151. /* not great but it'll have to do */
  152. snprintf(tmp+strlen(tmp), sizeof(tmp)-strlen(tmp), "%.80s%lx%lx%lx",
  153. tcp_serverhost (),i,
  154. (unsigned long) (time (0) ^ gethostid ()),
  155. (unsigned long) getpid ());
  156. RAND_seed(tmp, strlen(tmp));
  157. }
  158. #endif
  159. }
  160. /* taken from openssl/apps/app_rand.c */
  161. static int
  162. app_RAND_write_file(const char *file)
  163. {
  164. char buffer[200];
  165. if(egdsocket || !seeded)
  166. /*
  167. * If we did not manage to read the seed file,
  168. * we should not write a low-entropy seed file back --
  169. * it would suppress a crucial warning the next time
  170. * we want to use it.
  171. */
  172. return 0;
  173. if(file == NULL)
  174. file = RAND_file_name(buffer, sizeof buffer);
  175. if(file == NULL || !RAND_write_file(file)){
  176. dprint((1, "unable to write 'random state'\n"));
  177. return 0;
  178. }
  179. return 1;
  180. }
  181. /* Installed as an atexit() handler to save the random data */
  182. void
  183. smime_deinit(void)
  184. {
  185. dprint((9, "smime_deinit()"));
  186. app_RAND_write_file(NULL);
  187. free_smime_struct(&ps_global->smime);
  188. }
  189. /* Initialise openssl stuff if needed */
  190. static void
  191. smime_init(void)
  192. {
  193. if(F_OFF(F_DONT_DO_SMIME, ps_global) && !(ps_global->smime && ps_global->smime->inited)){
  194. dprint((9, "smime_init()"));
  195. if(!ps_global->smime)
  196. ps_global->smime = new_smime_struct();
  197. setup_storage_locations();
  198. s_cert_store = get_ca_store();
  199. OpenSSL_add_all_algorithms();
  200. ERR_load_crypto_strings();
  201. app_RAND_load_file(NULL);
  202. openssl_extra_randomness();
  203. ps_global->smime->inited = 1;
  204. }
  205. ERR_clear_error();
  206. }
  207. static void
  208. setup_storage_locations(void)
  209. {
  210. int publiccertcontainer = 0, privatekeycontainer = 0, cacertcontainer = 0;
  211. char path[MAXPATH+1], *contents;
  212. if(!ps_global->smime)
  213. return;
  214. #ifdef APPLEKEYCHAIN
  215. if(F_ON(F_PUBLICCERTS_IN_KEYCHAIN, ps_global)){
  216. ps_global->smime->publictype = Keychain;
  217. }
  218. else{
  219. #endif /* APPLEKEYCHAIN */
  220. /* Public certificates in a container */
  221. if(ps_global->VAR_PUBLICCERT_CONTAINER && ps_global->VAR_PUBLICCERT_CONTAINER[0]){
  222. publiccertcontainer = 1;
  223. contents = NULL;
  224. path[0] = '\0';
  225. if(!signature_path(ps_global->VAR_PUBLICCERT_CONTAINER, path, MAXPATH))
  226. publiccertcontainer = 0;
  227. if(publiccertcontainer && !IS_REMOTE(path)
  228. && ps_global->VAR_OPER_DIR
  229. && !in_dir(ps_global->VAR_OPER_DIR, path)){
  230. q_status_message2(SM_ORDER | SM_DING, 3, 4,
  231. /* TRANSLATORS: First arg is the directory name, second is
  232. the file user wants to read but can't. */
  233. _("Can't read file outside %s: %s"),
  234. ps_global->VAR_OPER_DIR, path);
  235. publiccertcontainer = 0;
  236. }
  237. if(publiccertcontainer
  238. && (IS_REMOTE(path) || can_access(path, ACCESS_EXISTS) == 0)){
  239. if(!(IS_REMOTE(path) && (contents = simple_read_remote_file(path, REMOTE_SMIME_SUBTYPE)))
  240. &&
  241. !(contents = read_file(path, READ_FROM_LOCALE)))
  242. publiccertcontainer = 0;
  243. }
  244. if(publiccertcontainer && path[0]){
  245. ps_global->smime->publictype = Container;
  246. ps_global->smime->publicpath = cpystr(path);
  247. if(contents){
  248. ps_global->smime->publiccontent = contents;
  249. ps_global->smime->publiccertlist = mem_to_certlist(contents);
  250. }
  251. }
  252. }
  253. /* Public certificates in a directory of files */
  254. if(!publiccertcontainer){
  255. ps_global->smime->publictype = Directory;
  256. path[0] = '\0';
  257. if(!(signature_path(ps_global->VAR_PUBLICCERT_DIR, path, MAXPATH)
  258. && !IS_REMOTE(path)))
  259. ps_global->smime->publictype = Nada;
  260. else if(can_access(path, ACCESS_EXISTS)){
  261. if(our_mkpath(path, 0700)){
  262. q_status_message1(SM_ORDER, 3, 3, _("Can't create directory %s"), path);
  263. ps_global->smime->publictype = Nada;
  264. }
  265. }
  266. if(ps_global->smime->publictype == Directory)
  267. ps_global->smime->publicpath = cpystr(path);
  268. }
  269. #ifdef APPLEKEYCHAIN
  270. }
  271. #endif /* APPLEKEYCHAIN */
  272. /* private keys in a container */
  273. if(ps_global->VAR_PRIVATEKEY_CONTAINER && ps_global->VAR_PRIVATEKEY_CONTAINER[0]){
  274. privatekeycontainer = 1;
  275. contents = NULL;
  276. path[0] = '\0';
  277. if(!signature_path(ps_global->VAR_PRIVATEKEY_CONTAINER, path, MAXPATH))
  278. privatekeycontainer = 0;
  279. if(privatekeycontainer && !IS_REMOTE(path)
  280. && ps_global->VAR_OPER_DIR
  281. && !in_dir(ps_global->VAR_OPER_DIR, path)){
  282. q_status_message2(SM_ORDER | SM_DING, 3, 4,
  283. /* TRANSLATORS: First arg is the directory name, second is
  284. the file user wants to read but can't. */
  285. _("Can't read file outside %s: %s"),
  286. ps_global->VAR_OPER_DIR, path);
  287. privatekeycontainer = 0;
  288. }
  289. if(privatekeycontainer
  290. && (IS_REMOTE(path) || can_access(path, ACCESS_EXISTS) == 0)){
  291. if(!(IS_REMOTE(path) && (contents = simple_read_remote_file(path, REMOTE_SMIME_SUBTYPE)))
  292. &&
  293. !(contents = read_file(path, READ_FROM_LOCALE)))
  294. privatekeycontainer = 0;
  295. }
  296. if(privatekeycontainer && path[0]){
  297. ps_global->smime->privatetype = Container;
  298. ps_global->smime->privatepath = cpystr(path);
  299. if(contents){
  300. ps_global->smime->privatecontent = contents;
  301. ps_global->smime->personal_certs = mem_to_personal_certs(contents);
  302. }
  303. }
  304. }
  305. /* private keys in a directory of files */
  306. if(!privatekeycontainer){
  307. PERSONAL_CERT *result = NULL;
  308. ps_global->smime->privatetype = Directory;
  309. path[0] = '\0';
  310. if(!(signature_path(ps_global->VAR_PRIVATEKEY_DIR, path, MAXPATH)
  311. && !IS_REMOTE(path)))
  312. ps_global->smime->privatetype = Nada;
  313. else if(can_access(path, ACCESS_EXISTS)){
  314. if(our_mkpath(path, 0700)){
  315. q_status_message1(SM_ORDER, 3, 3, _("Can't create directory %s"), path);
  316. ps_global->smime->privatetype = Nada;
  317. }
  318. }
  319. if(ps_global->smime->privatetype == Directory){
  320. char buf2[MAXPATH];
  321. struct dirent *d;
  322. DIR *dirp;
  323. ps_global->smime->privatepath = cpystr(path);
  324. dirp = opendir(path);
  325. if(dirp){
  326. while((d=readdir(dirp)) != NULL){
  327. X509 *cert;
  328. size_t ll;
  329. if((ll=strlen(d->d_name)) && ll > 4 && !strcmp(d->d_name+ll-4, ".key")){
  330. /* copy file name to temp buffer */
  331. strncpy(buf2, d->d_name, sizeof(buf2)-1);
  332. buf2[sizeof(buf2)-1] = '\0';
  333. /* chop off ".key" trailier */
  334. buf2[strlen(buf2)-4] = 0;
  335. /* Look for certificate */
  336. cert = get_cert_for(buf2);
  337. if(cert){
  338. PERSONAL_CERT *pc;
  339. /* create a new PERSONAL_CERT, fill it in */
  340. pc = (PERSONAL_CERT *) fs_get(sizeof(*pc));
  341. pc->cert = cert;
  342. pc->name = cpystr(buf2);
  343. /* Try to load the key with an empty password */
  344. pc->key = load_key(pc, "");
  345. pc->next = result;
  346. result = pc;
  347. }
  348. }
  349. }
  350. closedir(dirp);
  351. }
  352. }
  353. ps_global->smime->personal_certs = result;
  354. }
  355. /* extra cacerts in a container */
  356. if(ps_global->VAR_CACERT_CONTAINER && ps_global->VAR_CACERT_CONTAINER[0]){
  357. cacertcontainer = 1;
  358. contents = NULL;
  359. path[0] = '\0';
  360. if(!signature_path(ps_global->VAR_CACERT_CONTAINER, path, MAXPATH))
  361. cacertcontainer = 0;
  362. if(cacertcontainer && !IS_REMOTE(path)
  363. && ps_global->VAR_OPER_DIR
  364. && !in_dir(ps_global->VAR_OPER_DIR, path)){
  365. q_status_message2(SM_ORDER | SM_DING, 3, 4,
  366. /* TRANSLATORS: First arg is the directory name, second is
  367. the file user wants to read but can't. */
  368. _("Can't read file outside %s: %s"),
  369. ps_global->VAR_OPER_DIR, path);
  370. cacertcontainer = 0;
  371. }
  372. if(cacertcontainer
  373. && (IS_REMOTE(path) || can_access(path, ACCESS_EXISTS) == 0)){
  374. if(!(IS_REMOTE(path) && (contents = simple_read_remote_file(path, REMOTE_SMIME_SUBTYPE)))
  375. &&
  376. !(contents = read_file(path, READ_FROM_LOCALE)))
  377. cacertcontainer = 0;
  378. }
  379. if(cacertcontainer && path[0]){
  380. ps_global->smime->catype = Container;
  381. ps_global->smime->capath = cpystr(path);
  382. ps_global->smime->cacontent = contents;
  383. }
  384. }
  385. if(!cacertcontainer){
  386. ps_global->smime->catype = Directory;
  387. path[0] = '\0';
  388. if(!(signature_path(ps_global->VAR_CACERT_DIR, path, MAXPATH)
  389. && !IS_REMOTE(path)))
  390. ps_global->smime->catype = Nada;
  391. else if(can_access(path, ACCESS_EXISTS)){
  392. if(our_mkpath(path, 0700)){
  393. q_status_message1(SM_ORDER, 3, 3, _("Can't create directory %s"), path);
  394. ps_global->smime->catype = Nada;
  395. }
  396. }
  397. if(ps_global->smime->catype == Directory)
  398. ps_global->smime->capath = cpystr(path);
  399. }
  400. }
  401. int
  402. copy_publiccert_dir_to_container(void)
  403. {
  404. return(copy_dir_to_container(Public));
  405. }
  406. int
  407. copy_publiccert_container_to_dir(void)
  408. {
  409. return(copy_container_to_dir(Public));
  410. }
  411. int
  412. copy_privatecert_dir_to_container(void)
  413. {
  414. return(copy_dir_to_container(Private));
  415. }
  416. int
  417. copy_privatecert_container_to_dir(void)
  418. {
  419. return(copy_container_to_dir(Private));
  420. }
  421. int
  422. copy_cacert_dir_to_container(void)
  423. {
  424. return(copy_dir_to_container(CACert));
  425. }
  426. int
  427. copy_cacert_container_to_dir(void)
  428. {
  429. return(copy_container_to_dir(CACert));
  430. }
  431. /*
  432. * returns 0 on success, -1 on failure
  433. */
  434. int
  435. copy_dir_to_container(WhichCerts which)
  436. {
  437. int ret = 0;
  438. BIO *bio_out = NULL, *bio_in = NULL;
  439. char srcpath[MAXPATH+1], dstpath[MAXPATH+1], emailaddr[MAXPATH], file[MAXPATH], line[4096];
  440. char *tempfile = NULL;
  441. DIR *dirp;
  442. struct dirent *d;
  443. REMDATA_S *rd = NULL;
  444. char *configdir = NULL;
  445. char *configpath = NULL;
  446. char *filesuffix = NULL;
  447. dprint((9, "copy_dir_to_container(%s)", which==Public ? "Public" : which==Private ? "Private" : which==CACert ? "CACert" : "?"));
  448. smime_init();
  449. srcpath[0] = '\0';
  450. dstpath[0] = '\0';
  451. file[0] = '\0';
  452. emailaddr[0] = '\0';
  453. if(which == Public){
  454. configdir = ps_global->VAR_PUBLICCERT_DIR;
  455. configpath = ps_global->smime->publicpath;
  456. filesuffix = ".crt";
  457. }
  458. else if(which == Private){
  459. configdir = ps_global->VAR_PRIVATEKEY_DIR;
  460. configpath = ps_global->smime->privatepath;
  461. filesuffix = ".key";
  462. }
  463. else if(which == CACert){
  464. configdir = ps_global->VAR_CACERT_DIR;
  465. configpath = ps_global->smime->capath;
  466. filesuffix = ".crt";
  467. }
  468. if(!(configdir && configdir[0])){
  469. q_status_message(SM_ORDER, 3, 3, _("Directory not defined"));
  470. return -1;
  471. }
  472. if(!(configpath && configpath[0])){
  473. #ifdef APPLEKEYCHAIN
  474. if(which == Public && F_ON(F_PUBLICCERTS_IN_KEYCHAIN, ps_global)){
  475. q_status_message(SM_ORDER, 3, 3, _("Turn off the Keychain feature above first"));
  476. return -1;
  477. }
  478. #endif /* APPLEKEYCHAIN */
  479. q_status_message(SM_ORDER, 3, 3, _("Container path is not defined"));
  480. return -1;
  481. }
  482. if(!(filesuffix && strlen(filesuffix) == 4)){
  483. return -1;
  484. }
  485. /*
  486. * If there is a legit directory to read from set up the
  487. * container file to write to.
  488. */
  489. if(signature_path(configdir, srcpath, MAXPATH) && !IS_REMOTE(srcpath)){
  490. if(IS_REMOTE(configpath)){
  491. rd = rd_create_remote(RemImap, configpath, REMOTE_SMIME_SUBTYPE,
  492. NULL, "Error: ",
  493. _("Can't access remote smime configuration."));
  494. if(!rd)
  495. return -1;
  496. (void) rd_read_metadata(rd);
  497. if(rd->access == MaybeRorW){
  498. if(rd->read_status == 'R')
  499. rd->access = ReadOnly;
  500. else
  501. rd->access = ReadWrite;
  502. }
  503. if(rd->access != NoExists){
  504. rd_check_remvalid(rd, 1L);
  505. /*
  506. * If the cached info says it is readonly but
  507. * it looks like it's been fixed now, change it to readwrite.
  508. */
  509. if(rd->read_status == 'R'){
  510. rd_check_readonly_access(rd);
  511. if(rd->read_status == 'W'){
  512. rd->access = ReadWrite;
  513. rd->flags |= REM_OUTOFDATE;
  514. }
  515. else
  516. rd->access = ReadOnly;
  517. }
  518. }
  519. if(rd->flags & REM_OUTOFDATE){
  520. if(rd_update_local(rd) != 0){
  521. dprint((1, "copy_dir_to_container: rd_update_local failed\n"));
  522. rd_close_remdata(&rd);
  523. return -1;
  524. }
  525. }
  526. else
  527. rd_open_remote(rd);
  528. if(rd->access != ReadWrite || rd_remote_is_readonly(rd)){
  529. rd_close_remdata(&rd);
  530. return -1;
  531. }
  532. rd->flags |= DO_REMTRIM;
  533. strncpy(dstpath, rd->lf, sizeof(dstpath)-1);
  534. dstpath[sizeof(dstpath)-1] = '\0';
  535. }
  536. else{
  537. strncpy(dstpath, configpath, sizeof(dstpath)-1);
  538. dstpath[sizeof(dstpath)-1] = '\0';
  539. }
  540. /*
  541. * dstpath is either the local Container file or the local cache file
  542. * for the remote Container file.
  543. */
  544. tempfile = tempfile_in_same_dir(dstpath, "az", NULL);
  545. }
  546. /*
  547. * If there is a legit directory to read from and a tempfile
  548. * to write to we continue.
  549. */
  550. if(tempfile && (bio_out=BIO_new_file(tempfile, "w")) != NULL){
  551. dirp = opendir(srcpath);
  552. if(dirp){
  553. while((d=readdir(dirp)) && !ret){
  554. size_t ll;
  555. if((ll=strlen(d->d_name)) && ll > 4 && !strcmp(d->d_name+ll-4, filesuffix)){
  556. /* copy file name to temp buffer */
  557. strncpy(emailaddr, d->d_name, sizeof(emailaddr)-1);
  558. emailaddr[sizeof(emailaddr)-1] = '\0';
  559. /* chop off suffix trailier */
  560. emailaddr[strlen(emailaddr)-4] = 0;
  561. /*
  562. * This is the separator between the contents of
  563. * different files.
  564. */
  565. if(which == CACert){
  566. if(!((BIO_puts(bio_out, CACERTSTORELEADER) > 0)
  567. && (BIO_puts(bio_out, emailaddr) > 0)
  568. && (BIO_puts(bio_out, "\n") > 0)))
  569. ret = -1;
  570. }
  571. else{
  572. if(!((BIO_puts(bio_out, EMAILADDRLEADER) > 0)
  573. && (BIO_puts(bio_out, emailaddr) > 0)
  574. && (BIO_puts(bio_out, "\n") > 0)))
  575. ret = -1;
  576. }
  577. /* read then write contents of file */
  578. build_path(file, srcpath, d->d_name, sizeof(file));
  579. if(!(bio_in = BIO_new_file(file, "r")))
  580. ret = -1;
  581. if(!ret){
  582. int good_stuff = 0;
  583. while(BIO_gets(bio_in, line, sizeof(line)) > 0){
  584. if(strncmp("-----BEGIN", line, strlen("-----BEGIN")) == 0)
  585. good_stuff = 1;
  586. if(good_stuff)
  587. BIO_puts(bio_out, line);
  588. if(strncmp("-----END", line, strlen("-----END")) == 0)
  589. good_stuff = 0;
  590. }
  591. }
  592. BIO_free(bio_in);
  593. }
  594. }
  595. closedir(dirp);
  596. }
  597. BIO_free(bio_out);
  598. if(!ret){
  599. if(rename_file(tempfile, dstpath) < 0){
  600. q_status_message2(SM_ORDER, 3, 3,
  601. _("Can't rename %s to %s"), tempfile, dstpath);
  602. ret = -1;
  603. }
  604. /* if the container is remote, copy it */
  605. if(!ret && IS_REMOTE(configpath)){
  606. int e;
  607. char datebuf[200];
  608. datebuf[0] = '\0';
  609. if((e = rd_update_remote(rd, datebuf)) != 0){
  610. if(e == -1){
  611. q_status_message2(SM_ORDER | SM_DING, 3, 5,
  612. _("Error opening temporary smime file %s: %s"),
  613. rd->lf, error_description(errno));
  614. dprint((1,
  615. "write_remote_smime: error opening temp file %s\n",
  616. rd->lf ? rd->lf : "?"));
  617. }
  618. else{
  619. q_status_message2(SM_ORDER | SM_DING, 3, 5,
  620. _("Error copying to %s: %s"),
  621. rd->rn, error_description(errno));
  622. dprint((1,
  623. "write_remote_smime: error copying from %s to %s\n",
  624. rd->lf ? rd->lf : "?", rd->rn ? rd->rn : "?"));
  625. }
  626. q_status_message(SM_ORDER | SM_DING, 5, 5,
  627. _("Copy of smime key to remote folder failed, NOT saved remotely"));
  628. }
  629. else{
  630. rd_update_metadata(rd, datebuf);
  631. rd->read_status = 'W';
  632. }
  633. rd_close_remdata(&rd);
  634. }
  635. }
  636. }
  637. if(tempfile)
  638. fs_give((void **) &tempfile);
  639. return ret;
  640. }
  641. /*
  642. * returns 0 on success, -1 on failure
  643. */
  644. int
  645. copy_container_to_dir(WhichCerts which)
  646. {
  647. char path[MAXPATH+1], file[MAXPATH+1], buf[MAXPATH+1];
  648. char iobuf[4096];
  649. char *contents = NULL;
  650. char *leader = NULL;
  651. char *filesuffix = NULL;
  652. char *configdir = NULL;
  653. char *configpath = NULL;
  654. char *tempfile = NULL;
  655. char *p, *q, *line, *name, *certtext, *save_p;
  656. int len;
  657. BIO *in, *out;
  658. dprint((9, "copy_container_to_dir(%s)", which==Public ? "Public" : which==Private ? "Private" : which==CACert ? "CACert" : "?"));
  659. smime_init();
  660. path[0] = '\0';
  661. if(which == Public){
  662. leader = EMAILADDRLEADER;
  663. contents = ps_global->smime->publiccontent;
  664. configdir = ps_global->VAR_PUBLICCERT_DIR;
  665. configpath = ps_global->smime->publicpath;
  666. filesuffix = ".crt";
  667. if(!(configpath && configpath[0])){
  668. #ifdef APPLEKEYCHAIN
  669. if(which == Public && F_ON(F_PUBLICCERTS_IN_KEYCHAIN, ps_global)){
  670. q_status_message(SM_ORDER, 3, 3, _("Turn off the Keychain feature above first"));
  671. return -1;
  672. }
  673. #endif /* APPLEKEYCHAIN */
  674. q_status_message(SM_ORDER, 3, 3, _("Container path is not defined"));
  675. return -1;
  676. }
  677. fs_give((void **) &ps_global->smime->publicpath);
  678. path[0] = '\0';
  679. if(!(signature_path(ps_global->VAR_PUBLICCERT_DIR, path, MAXPATH)
  680. && !IS_REMOTE(path))){
  681. q_status_message(SM_ORDER, 3, 3, _("Directory is not defined"));
  682. return -1;
  683. }
  684. if(can_access(path, ACCESS_EXISTS)){
  685. if(our_mkpath(path, 0700)){
  686. q_status_message1(SM_ORDER, 3, 3, _("Can't create directory %s"), path);
  687. return -1;
  688. }
  689. }
  690. ps_global->smime->publicpath = cpystr(path);
  691. configpath = ps_global->smime->publicpath;
  692. }
  693. else if(which == Private){
  694. leader = EMAILADDRLEADER;
  695. contents = ps_global->smime->privatecontent;
  696. configdir = ps_global->VAR_PRIVATEKEY_DIR;
  697. configpath = ps_global->smime->privatepath;
  698. filesuffix = ".key";
  699. if(!(configpath && configpath[0])){
  700. q_status_message(SM_ORDER, 3, 3, _("Container path is not defined"));
  701. return -1;
  702. }
  703. fs_give((void **) &ps_global->smime->privatepath);
  704. path[0] = '\0';
  705. if(!(signature_path(ps_global->VAR_PRIVATEKEY_DIR, path, MAXPATH)
  706. && !IS_REMOTE(path))){
  707. q_status_message(SM_ORDER, 3, 3, _("Directory is not defined"));
  708. return -1;
  709. }
  710. if(can_access(path, ACCESS_EXISTS)){
  711. if(our_mkpath(path, 0700)){
  712. q_status_message1(SM_ORDER, 3, 3, _("Can't create directory %s"), path);
  713. return -1;
  714. }
  715. }
  716. ps_global->smime->privatepath = cpystr(path);
  717. configpath = ps_global->smime->privatepath;
  718. }
  719. else if(which == CACert){
  720. leader = CACERTSTORELEADER;
  721. contents = ps_global->smime->cacontent;
  722. configdir = ps_global->VAR_CACERT_DIR;
  723. configpath = ps_global->smime->capath;
  724. filesuffix = ".crt";
  725. if(!(configpath && configpath[0])){
  726. q_status_message(SM_ORDER, 3, 3, _("Container path is not defined"));
  727. return -1;
  728. }
  729. fs_give((void **) &ps_global->smime->capath);
  730. path[0] = '\0';
  731. if(!(signature_path(ps_global->VAR_CACERT_DIR, path, MAXPATH)
  732. && !IS_REMOTE(path))){
  733. q_status_message(SM_ORDER, 3, 3, _("Directory is not defined"));
  734. return -1;
  735. }
  736. if(can_access(path, ACCESS_EXISTS)){
  737. if(our_mkpath(path, 0700)){
  738. q_status_message1(SM_ORDER, 3, 3, _("Can't create directory %s"), path);
  739. return -1;
  740. }
  741. }
  742. ps_global->smime->capath = cpystr(path);
  743. configpath = ps_global->smime->capath;
  744. }
  745. if(!(configdir && configdir[0])){
  746. q_status_message(SM_ORDER, 3, 3, _("Directory not defined"));
  747. return -1;
  748. }
  749. if(!(configpath && configpath[0])){
  750. q_status_message(SM_ORDER, 3, 3, _("Container path is not defined"));
  751. return -1;
  752. }
  753. if(!(filesuffix && strlen(filesuffix) == 4)){
  754. return -1;
  755. }
  756. if(contents && *contents){
  757. for(p = contents; *p != '\0';){
  758. line = p;
  759. while(*p && *p != '\n')
  760. p++;
  761. save_p = NULL;
  762. if(*p == '\n'){
  763. save_p = p;
  764. *p++ = '\0';
  765. }
  766. if(strncmp(leader, line, strlen(leader)) == 0){
  767. name = line + strlen(leader);
  768. certtext = p;
  769. if(strncmp("-----BEGIN", certtext, strlen("-----BEGIN")) == 0){
  770. if((q = strstr(certtext, leader)) != NULL){
  771. p = q;
  772. }
  773. else{ /* end of file */
  774. q = certtext + strlen(certtext);
  775. p = q;
  776. }
  777. strncpy(buf, name, sizeof(buf)-5);
  778. buf[sizeof(buf)-5] = '\0';
  779. strncat(buf, filesuffix, 5);
  780. build_path(file, configpath, buf, sizeof(file));
  781. in = BIO_new_mem_buf(certtext, q-certtext);
  782. if(in){
  783. tempfile = tempfile_in_same_dir(file, "az", NULL);
  784. out = NULL;
  785. if(tempfile)
  786. out = BIO_new_file(tempfile, "w");
  787. if(out){
  788. while((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0)
  789. BIO_write(out, iobuf, len);
  790. BIO_free(out);
  791. if(rename_file(tempfile, file) < 0){
  792. q_status_message2(SM_ORDER, 3, 3,
  793. _("Can't rename %s to %s"),
  794. tempfile, file);
  795. return -1;
  796. }
  797. fs_give((void **) &tempfile);
  798. }
  799. BIO_free(in);
  800. }
  801. }
  802. }
  803. if(save_p)
  804. *save_p = '\n';
  805. }
  806. }
  807. return 0;
  808. }
  809. #ifdef APPLEKEYCHAIN
  810. int
  811. copy_publiccert_container_to_keychain(void)
  812. {
  813. /* NOT IMPLEMNTED */
  814. return -1;
  815. }
  816. int
  817. copy_publiccert_keychain_to_container(void)
  818. {
  819. /* NOT IMPLEMNTED */
  820. return -1;
  821. }
  822. #endif /* APPLEKEYCHAIN */
  823. /*
  824. * Get a pointer to a string describing the most recent OpenSSL error.
  825. * It's statically allocated, so don't change or attempt to free it.
  826. */
  827. static const char *
  828. openssl_error_string(void)
  829. {
  830. char *errs;
  831. const char *data = NULL;
  832. long errn;
  833. errn = ERR_peek_error_line_data(NULL, NULL, &data, NULL);
  834. errs = (char*) ERR_reason_error_string(errn);
  835. if(errs)
  836. return errs;
  837. else if(data)
  838. return data;
  839. return "unknown error";
  840. }
  841. /* Return true if the body looks like a PKCS7 object */
  842. int
  843. is_pkcs7_body(BODY *body)
  844. {
  845. int result;
  846. result = body->type==TYPEAPPLICATION &&
  847. body->subtype &&
  848. (strucmp(body->subtype,"pkcs7-mime")==0 ||
  849. strucmp(body->subtype,"x-pkcs7-mime")==0 ||
  850. strucmp(body->subtype,"pkcs7-signature")==0 ||
  851. strucmp(body->subtype,"x-pkcs7-signature")==0);
  852. return result;
  853. }
  854. #ifdef notdef
  855. /*
  856. * Somewhat useful debug utility to dump the contents of a BIO to a file.
  857. * Note that a memory BIO will have its contents eliminated after they
  858. * are read so this will break the next step.
  859. */
  860. static void
  861. dump_bio_to_file(BIO *in, char *filename)
  862. {
  863. char iobuf[4096];
  864. int len;
  865. BIO *out;
  866. out = BIO_new_file(filename, "w");
  867. if(out){
  868. if(BIO_method_type(in) != BIO_TYPE_MEM)
  869. BIO_reset(in);
  870. while((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0)
  871. BIO_write(out, iobuf, len);
  872. BIO_free(out);
  873. }
  874. BIO_reset(in);
  875. }
  876. #endif
  877. /*
  878. * Recursively stash a pointer to the decrypted data in our
  879. * manufactured body.
  880. */
  881. static void
  882. create_local_cache(char *base, BODY *b)
  883. {
  884. if(b->type==TYPEMULTIPART){
  885. PART *p;
  886. #if 0
  887. cpytxt(&b->contents.text, base + b->contents.offset, b->size.bytes);
  888. #else
  889. /*
  890. * We don't really want to copy the real body contents. It shouldn't be
  891. * used, and in the case of a message with attachments, we'll be
  892. * duplicating the files multiple times.
  893. */
  894. cpytxt(&b->contents.text, "BODY UNAVAILABLE", 16);
  895. #endif
  896. for(p=b->nested.part; p; p=p->next)
  897. create_local_cache(base, (BODY*) p);
  898. }
  899. else{
  900. cpytxt(&b->contents.text, base + b->contents.offset, b->size.bytes);
  901. }
  902. }
  903. static long
  904. rfc822_output_func(void *b, char *string)
  905. {
  906. BIO *bio = (BIO *) b;
  907. return((BIO_puts(bio, string) > 0) ? 1L : 0L);
  908. }
  909. /*
  910. * Attempt to load the private key for the given PERSONAL_CERT.
  911. * This sets the appropriate passphrase globals in order to
  912. * interact with the user correctly.
  913. */
  914. static int
  915. load_private_key(PERSONAL_CERT *pcert)
  916. {
  917. if(!pcert->key){
  918. /* Try empty password by default */
  919. char *password = "";
  920. if(ps_global->smime
  921. && (ps_global->smime->need_passphrase
  922. || ps_global->smime->entered_passphrase)){
  923. /* We've already been in here and discovered we need a different password */
  924. if(ps_global->smime->entered_passphrase)
  925. password = (char *) ps_global->smime->passphrase; /* already entered */
  926. else
  927. return 0;
  928. }
  929. ERR_clear_error();
  930. if(!(pcert->key = load_key(pcert, password))){
  931. long err = ERR_get_error();
  932. /* Couldn't load key... */
  933. if(ps_global->smime && ps_global->smime->entered_passphrase){
  934. /* The user got the password wrong maybe? */
  935. if((ERR_GET_LIB(err)==ERR_LIB_EVP && ERR_GET_REASON(err)==EVP_R_BAD_DECRYPT) ||
  936. (ERR_GET_LIB(err)==ERR_LIB_PEM && ERR_GET_REASON(err)==PEM_R_BAD_DECRYPT))
  937. q_status_message(SM_ORDER | SM_DING, 4, 4, _("Incorrect passphrase"));
  938. else
  939. q_status_message1(SM_ORDER, 4, 4, _("Couldn't read key: %s"),(char*)openssl_error_string());
  940. /* This passphrase is no good; forget it */
  941. ps_global->smime->entered_passphrase = 0;
  942. }
  943. /* Indicate to the UI that we need re-entry (see mailcmd.c:process_cmd())*/
  944. if(ps_global->smime)
  945. ps_global->smime->need_passphrase = 1;
  946. if(ps_global->smime){
  947. if(ps_global->smime->passphrase_emailaddr)
  948. fs_give((void **) &ps_global->smime->passphrase_emailaddr);
  949. ps_global->smime->passphrase_emailaddr = get_x509_subject_email(pcert->cert);
  950. }
  951. return 0;
  952. }
  953. else{
  954. /* This key will be cached, so we won't be called again */
  955. if(ps_global->smime){
  956. ps_global->smime->entered_passphrase = 0;
  957. ps_global->smime->need_passphrase = 0;
  958. }
  959. }
  960. return 1;
  961. }
  962. return 0;
  963. }
  964. static void
  965. setup_pkcs7_body_for_signature(BODY *b, char *description, char *type, char *filename)
  966. {
  967. b->type = TYPEAPPLICATION;
  968. b->subtype = cpystr(type);
  969. b->encoding = ENCBINARY;
  970. b->description = cpystr(description);
  971. b->disposition.type = cpystr("attachment");
  972. set_parameter(&b->disposition.parameter, "filename", filename);
  973. set_parameter(&b->parameter, "name", filename);
  974. }
  975. /*
  976. * Look for a personal certificate matching the
  977. * given address
  978. */
  979. PERSONAL_CERT *
  980. match_personal_cert_to_email(ADDRESS *a)
  981. {
  982. PERSONAL_CERT *pcert = NULL;
  983. char buf[MAXPATH];
  984. char *email;
  985. if(!a || !a->mailbox || !a->host)
  986. return NULL;
  987. snprintf(buf, sizeof(buf), "%s@%s", a->mailbox, a->host);
  988. if(ps_global->smime){
  989. for(pcert=(PERSONAL_CERT *) ps_global->smime->personal_certs;
  990. pcert;
  991. pcert=pcert->next){
  992. if(!pcert->cert)
  993. continue;
  994. email = get_x509_subject_email(pcert->cert);
  995. if(email && strucmp(email,buf)==0){
  996. fs_give((void**) &email);
  997. break;
  998. }
  999. fs_give((void**) &email);
  1000. }
  1001. }
  1002. return pcert;
  1003. }
  1004. /*
  1005. * Look for a personal certificate matching the from
  1006. * (or reply_to? in the given envelope)
  1007. */
  1008. PERSONAL_CERT *
  1009. match_personal_cert(ENVELOPE *env)
  1010. {
  1011. PERSONAL_CERT *pcert;
  1012. pcert = match_personal_cert_to_email(env->reply_to);
  1013. if(!pcert)
  1014. pcert = match_personal_cert_to_email(env->from);
  1015. return pcert;
  1016. }
  1017. /*
  1018. * Flatten the given body into its MIME representation.
  1019. * Return the result in a BIO.
  1020. */
  1021. static BIO *
  1022. body_to_bio(BODY *body)
  1023. {
  1024. BIO *bio = NULL;
  1025. int len;
  1026. bio = BIO_new(BIO_s_mem());
  1027. if(!bio)
  1028. return NULL;
  1029. pine_encode_body(body); /* this attaches random boundary strings to multiparts */
  1030. pine_write_body_header(body, rfc822_output_func, bio);
  1031. pine_rfc822_output_body(body, rfc822_output_func, bio);
  1032. /*
  1033. * Now need to truncate by two characters since the above
  1034. * appends CRLF.
  1035. */
  1036. if((len=BIO_ctrl_pending(bio)) > 1){
  1037. BUF_MEM *biobuf = NULL;
  1038. BIO_get_mem_ptr(bio, &biobuf);
  1039. if(biobuf){
  1040. BUF_MEM_grow(biobuf, len-2); /* remove CRLF */
  1041. }
  1042. }
  1043. return bio;
  1044. }
  1045. static BIO *
  1046. bio_from_store(STORE_S *store)
  1047. {
  1048. BIO *ret = NULL;
  1049. if(store && store->src == BioType && store->txt){
  1050. ret = (BIO *) store->txt;
  1051. }
  1052. return(ret);
  1053. }
  1054. /*
  1055. * Encrypt a message on the way out. Called from call_mailer in send.c
  1056. * The body may be reallocated.
  1057. */
  1058. int
  1059. encrypt_outgoing_message(METAENV *header, BODY **bodyP)
  1060. {
  1061. PKCS7 *p7 = NULL;
  1062. BIO *in = NULL;
  1063. BIO *out = NULL;
  1064. const EVP_CIPHER *cipher = NULL;
  1065. STACK_OF(X509) *encerts = NULL;
  1066. STORE_S *outs = NULL;
  1067. PINEFIELD *pf;
  1068. ADDRESS *a;
  1069. BODY *body = *bodyP;
  1070. BODY *newBody = NULL;
  1071. int result = 0;
  1072. dprint((9, "encrypt_outgoing_message()"));
  1073. smime_init();
  1074. cipher = EVP_des_cbc();
  1075. encerts = sk_X509_new_null();
  1076. /* Look for a certificate for each of the recipients */
  1077. for(pf = header->local; pf && pf->name; pf = pf->next)
  1078. if(pf->type == Address && pf->rcptto && pf->addr && *pf->addr){
  1079. for(a=*pf->addr; a; a=a->next){
  1080. X509 *cert;
  1081. char buf[MAXPATH];
  1082. snprintf(buf, sizeof(buf), "%s@%s", a->mailbox, a->host);
  1083. cert = get_cert_for(buf);
  1084. if(cert)
  1085. sk_X509_push(encerts,cert);
  1086. else{
  1087. q_status_message2(SM_ORDER, 1, 1,
  1088. _("Unable to find certificate for <%s@%s>"),
  1089. a->mailbox, a->host);
  1090. goto end;
  1091. }
  1092. }
  1093. }
  1094. in = body_to_bio(body);
  1095. p7 = PKCS7_encrypt(encerts, in, cipher, 0);
  1096. outs = so_get(BioType, NULL, EDIT_ACCESS);
  1097. out = bio_from_store(outs);
  1098. i2d_PKCS7_bio(out, p7);
  1099. (void) BIO_flush(out);
  1100. so_seek(outs, 0, SEEK_SET);
  1101. newBody = mail_newbody();
  1102. newBody->type = TYPEAPPLICATION;
  1103. newBody->subtype = cpystr("pkcs7-mime");
  1104. newBody->encoding = ENCBINARY;
  1105. newBody->disposition.type = cpystr("attachment");
  1106. set_parameter(&newBody->disposition.parameter, "filename", "smime.p7m");
  1107. newBody->description = cpystr("S/MIME Encrypted Message");
  1108. set_parameter(&newBody->parameter, "smime-type", "enveloped-data");
  1109. set_parameter(&newBody->parameter, "name", "smime.p7m");
  1110. newBody->contents.text.data = (unsigned char *) outs;
  1111. *bodyP = newBody;
  1112. result = 1;
  1113. end:
  1114. BIO_free(in);
  1115. PKCS7_free(p7);
  1116. sk_X509_pop_free(encerts, X509_free);
  1117. dprint((9, "encrypt_outgoing_message returns %d", result));
  1118. return result;
  1119. }
  1120. /*
  1121. * Plonk the contents (mime headers and body) of the given
  1122. * section of a message to a BIO_s_mem BIO object.
  1123. */
  1124. static BIO *
  1125. raw_part_to_bio(long msgno, const char *section)
  1126. {
  1127. unsigned long len;
  1128. char *text;
  1129. BIO *bio;
  1130. bio = BIO_new(BIO_s_mem());
  1131. if(bio){
  1132. (void) BIO_reset(bio);
  1133. /* First grab headers of the chap */
  1134. text = mail_fetch_mime(ps_global->mail_stream, msgno, (char*) section, &len, 0);
  1135. if(text){
  1136. BIO_write(bio, text, len);
  1137. /** Now grab actual body */
  1138. text = mail_fetch_body (ps_global->mail_stream, msgno, (char*) section, &len, 0);
  1139. if(text){
  1140. BIO_write(bio, text, len);
  1141. }
  1142. else{
  1143. BIO_free(bio);
  1144. bio = NULL;
  1145. }
  1146. }
  1147. else{
  1148. BIO_free(bio);
  1149. bio = NULL;
  1150. }
  1151. }
  1152. return bio;
  1153. }
  1154. /*
  1155. Get (and decode) the body of the given section of msg
  1156. */
  1157. static STORE_S*
  1158. get_part_contents(long msgno, const char *section)
  1159. {
  1160. long len;
  1161. gf_io_t pc;
  1162. STORE_S *store = NULL;
  1163. char *err;
  1164. store = so_get(CharStar, NULL, EDIT_ACCESS);
  1165. if(store){
  1166. gf_set_so_writec(&pc,store);
  1167. err = detach(ps_global->mail_stream, msgno, (char*) section, 0L, &len, pc, NULL, 0L);
  1168. gf_clear_so_writec(store);
  1169. so_seek(store, 0, SEEK_SET);
  1170. if(err)
  1171. so_give(&store);
  1172. }
  1173. return store;
  1174. }
  1175. static PKCS7 *
  1176. get_pkcs7_from_part(long msgno,const char *section)
  1177. {
  1178. STORE_S *store = NULL;
  1179. PKCS7 *p7 = NULL;
  1180. BIO *in = NULL;
  1181. store = get_part_contents(msgno, section);
  1182. if(store){
  1183. if(store->src == CharStar){
  1184. int len;
  1185. /*
  1186. * We're reaching inside the STORE_S structure. We should
  1187. * probably have a way to get the length, instead.
  1188. */
  1189. len = (int) (store->eod - store->dp);
  1190. in = BIO_new_mem_buf(store->txt, len);
  1191. }
  1192. else{ /* just copy it */
  1193. unsigned char c;
  1194. in = BIO_new(BIO_s_mem());
  1195. (void) BIO_reset(in);
  1196. so_seek(store, 0L, 0);
  1197. while(so_readc(&c, store)){
  1198. BIO_write(in, &c, 1);
  1199. }
  1200. }
  1201. if(in){
  1202. /* dump_bio_to_file(in, "/tmp/decoded-signature"); */
  1203. if((p7=d2i_PKCS7_bio(in,NULL)) == NULL){
  1204. /* error */
  1205. }
  1206. BIO_free(in);
  1207. }
  1208. so_give(&store);
  1209. }
  1210. return p7;
  1211. }
  1212. /*
  1213. * Try to verify a signature.
  1214. *
  1215. * p7 - the pkcs7 object to verify
  1216. * in - the plain data to verify (NULL if not detached)
  1217. * out - BIO to which to write the opaque data
  1218. */
  1219. static int
  1220. do_signature_verify(PKCS7 *p7, BIO *in, BIO *out)
  1221. {
  1222. STACK_OF(X509) *otherCerts = NULL;
  1223. int result;
  1224. const char *data;
  1225. long err;
  1226. #if 0
  1227. dump_bio_to_file(in,"/tmp/verified-data");
  1228. #endif
  1229. if(!s_cert_store){
  1230. q_status_message(SM_ORDER | SM_DING, 2, 2,
  1231. _("Couldn't verify S/MIME signature: No CA Certs were loaded"));
  1232. return -1;
  1233. }
  1234. result = PKCS7_verify(p7, otherCerts, s_cert_store, in, out, 0);
  1235. if(result){
  1236. q_status_message(SM_ORDER, 1, 1, _("S/MIME signature verified ok"));
  1237. }
  1238. else{
  1239. err = ERR_peek_error_line_data(NULL, NULL, &data, NULL);
  1240. if(out && err==ERR_PACK(ERR_LIB_PKCS7,PKCS7_F_PKCS7_VERIFY,PKCS7_R_CERTIFICATE_VERIFY_ERROR)){
  1241. /* Retry verification so we can get the plain text */
  1242. /* Might be better to reimplement PKCS7_verify here? */
  1243. PKCS7_verify(p7, otherCerts, s_cert_store, in, out, PKCS7_NOVERIFY);
  1244. }
  1245. q_status_message1(SM_ORDER | SM_DING, 3, 3,
  1246. _("Couldn't verify S/MIME signature: %s"), (char*) openssl_error_string());
  1247. }
  1248. /* now try to extract the certificates of any signers */
  1249. {
  1250. STACK_OF(X509) *signers;
  1251. int i;
  1252. signers = PKCS7_get0_signers(p7, NULL, 0);
  1253. if(signers)
  1254. for(i=0; i<sk_X509_num(signers); i++){
  1255. char *email;
  1256. X509 *x = sk_X509_value(signers,i);
  1257. X509 *cert;
  1258. if(!x)
  1259. continue;
  1260. email = get_x509_subject_email(x);
  1261. if(email){
  1262. cert = get_cert_for(email);
  1263. if(cert)
  1264. X509_free(cert);
  1265. else
  1266. save_cert_for(email, x);
  1267. fs_give((void**) &email);
  1268. }
  1269. }
  1270. sk_X509_free(signers);
  1271. }
  1272. return result;
  1273. }
  1274. void
  1275. free_smime_body_sparep(void **sparep)
  1276. {
  1277. if(sparep && *sparep){
  1278. PKCS7_free((PKCS7 *) (*sparep));
  1279. *sparep = NULL;
  1280. }
  1281. }
  1282. /*
  1283. * Given a multipart body of type multipart/signed, attempt to verify it.
  1284. * Returns non-zero if the body was changed.
  1285. */
  1286. static int
  1287. do_detached_signature_verify(BODY *b, long msgno, char *section)
  1288. {
  1289. PKCS7 *p7 = NULL;
  1290. BIO *in = NULL;
  1291. PART *p;
  1292. int result, modified_the_body = 0;
  1293. char newSec[100];
  1294. char *what_we_did;
  1295. dprint((9, "do_detached_signature_verify(msgno=%ld type=%d subtype=%s section=%s)", msgno, b->type, b->subtype ? b->subtype : "NULL", (section && *section) ? section : (section != NULL) ? "Top" : "NULL"));
  1296. smime_init();
  1297. snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : "");
  1298. in = raw_part_to_bio(msgno, newSec);
  1299. if(in){
  1300. snprintf(newSec, sizeof(newSec), "%s%s2", section ? section : "", (section && *section) ? "." : "");
  1301. p7 = get_pkcs7_from_part(msgno, newSec);
  1302. if(!p7)
  1303. goto end;
  1304. result = do_signature_verify(p7, in, NULL);
  1305. if(b->subtype)
  1306. fs_give((void**) &b->subtype);
  1307. b->subtype = cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE);
  1308. b->encoding = ENC8BIT;
  1309. if(b->description)
  1310. fs_give ((void**) &b->description);
  1311. what_we_did = result ? _("This message was cryptographically signed.") :
  1312. _("This message was cryptographically signed but the signature could not be verified.");
  1313. b->description = cpystr(what_we_did);
  1314. b->sparep = p7;
  1315. p7 = NULL;
  1316. p = b->nested.part;
  1317. /* p is signed plaintext */
  1318. if(p && p->next)
  1319. mail_free_body_part(&p->next); /* hide the pkcs7 from the viewer */
  1320. BIO_free(in);
  1321. modified_the_body = 1;
  1322. }
  1323. end:
  1324. PKCS7_free(p7);
  1325. return modified_the_body;
  1326. }
  1327. PERSONAL_CERT *
  1328. find_certificate_matching_recip_info(PKCS7_RECIP_INFO *ri)
  1329. {
  1330. PERSONAL_CERT *x = NULL;
  1331. if(ps_global->smime){
  1332. for(x = (PERSONAL_CERT *) ps_global->smime->personal_certs; x; x=x->next){
  1333. X509 *mine;
  1334. mine = x->cert;
  1335. if(!X509_NAME_cmp(ri->issuer_and_serial->issuer,mine->cert_info->issuer) &&
  1336. !ASN1_INTEGER_cmp(ri->issuer_and_serial->serial,mine->cert_info->serialNumber)){
  1337. break;
  1338. }
  1339. }
  1340. }
  1341. return x;
  1342. }
  1343. static PERSONAL_CERT *
  1344. find_certificate_matching_pkcs7(PKCS7 *p7)
  1345. {
  1346. int i;
  1347. STACK_OF(PKCS7_RECIP_INFO) *recips;
  1348. PERSONAL_CERT *x = NULL;
  1349. recips = p7->d.enveloped->recipientinfo;
  1350. for(i=0; i<sk_PKCS7_RECIP_INFO_num(recips); i++){
  1351. PKCS7_RECIP_INFO *ri;
  1352. ri = sk_PKCS7_RECIP_INFO_value(recips, i);
  1353. if((x=find_certificate_matching_recip_info(ri))!=0){
  1354. break;
  1355. }
  1356. }
  1357. return x;
  1358. }
  1359. /*
  1360. * Try to decode (decrypt or verify a signature) a PKCS7 body
  1361. * Returns non-zero if something was changed.
  1362. */
  1363. static int
  1364. do_decoding(BODY *b, long msgno, const char *section)
  1365. {
  1366. int modified_the_body = 0;
  1367. BIO *out = NULL;
  1368. PKCS7 *p7 = NULL;
  1369. X509 *recip = NULL;
  1370. EVP_PKEY *key = NULL;
  1371. PERSONAL_CERT *pcert = NULL;
  1372. char *what_we_did = "";
  1373. char null[1];
  1374. char newSec[100];
  1375. dprint((9, "do_decoding(msgno=%ld type=%d subtype=%s section=%s)", msgno, b->type, b->subtype ? b->subtype : "NULL", (section && *section) ? section : (section != NULL) ? "Top" : "NULL"));
  1376. null[0] = '\0';
  1377. smime_init();
  1378. /*
  1379. * Extract binary data from part to an in-memory store
  1380. */
  1381. if(b->sparep){ /* already done */
  1382. p7 = (PKCS7*) b->sparep;
  1383. }
  1384. else{
  1385. snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : "");
  1386. p7 = get_pkcs7_from_part(msgno, newSec);
  1387. if(!p7){
  1388. q_status_message1(SM_ORDER, 2, 2, "Couldn't load PKCS7 object: %s",
  1389. (char*) openssl_error_string());
  1390. goto end;
  1391. }
  1392. /*
  1393. * Save the PKCS7 object for later dealings by the user interface.
  1394. * It will be cleaned up when the body is garbage collected.
  1395. */
  1396. b->sparep = p7;
  1397. }
  1398. if(PKCS7_type_is_signed(p7)){
  1399. int sigok;
  1400. out = BIO_new(BIO_s_mem());
  1401. (void) BIO_reset(out);
  1402. BIO_puts(out, "MIME-Version: 1.0\r\n"); /* needed so rfc822_parse_msg_full believes it's MIME */
  1403. sigok = do_signature_verify(p7, NULL, out);
  1404. /* shouldn't really duplicate these messages */
  1405. what_we_did = sigok ? _("This message was cryptographically signed.") :
  1406. _("This message was cryptographically signed but the signature could not be verified.");
  1407. /* make sure it's null terminated */
  1408. BIO_write(out, null, 1);
  1409. }
  1410. else if(!PKCS7_type_is_enveloped(p7)){
  1411. q_status_message(SM_ORDER, 1, 1, "PKCS7 object not recognised.");
  1412. goto end;
  1413. }
  1414. else{ /* It *is* enveloped */
  1415. int decrypt_result;
  1416. what_we_did = _("This message was encrypted.");
  1417. /* now need to find a cert that can decrypt this */
  1418. pcert = find_certificate_matching_pkcs7(p7);
  1419. if(!pcert){
  1420. q_status_message(SM_ORDER, 3, 3, _("Couldn't find the certificate needed to decrypt."));
  1421. goto end;
  1422. }
  1423. recip = pcert->cert;
  1424. if(!load_private_key(pcert)
  1425. && ps_global->smime
  1426. && ps_global->smime->need_passphrase
  1427. && !ps_global->smime->already_auto_asked){
  1428. /* Couldn't load key with blank password, ask user */
  1429. ps_global->smime->already_auto_asked = 1;
  1430. if(pith_opt_smime_get_passphrase){
  1431. (*pith_opt_smime_get_passphrase)();
  1432. load_private_key(pcert);
  1433. }
  1434. }
  1435. key = pcert->key;
  1436. if(!key)
  1437. goto end;
  1438. out = BIO_new(BIO_s_mem());
  1439. (void) BIO_reset(out);
  1440. BIO_puts(out, "MIME-Version: 1.0\r\n");
  1441. decrypt_result = PKCS7_decrypt(p7, key, recip, out, 0);
  1442. if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE,ps_global))
  1443. forget_private_keys();
  1444. if(!decrypt_result){
  1445. q_status_message1(SM_ORDER, 1, 1, _("Error decrypting: %s"),
  1446. (char*) openssl_error_string());
  1447. goto end;
  1448. }
  1449. BIO_write(out, null, 1);
  1450. }
  1451. /*
  1452. * We've now produced a flattened MIME object in BIO out.
  1453. * It needs to be turned back into a BODY.
  1454. */
  1455. if(out){
  1456. BODY *body;
  1457. ENVELOPE *env;
  1458. char *h = NULL;
  1459. char *bstart;
  1460. STRING s;
  1461. BUF_MEM *bptr = NULL;
  1462. BIO_get_mem_ptr(out, &bptr);
  1463. if(bptr)
  1464. h = bptr->data;
  1465. /* look for start of body */
  1466. bstart = strstr(h, "\r\n\r\n");
  1467. if(!bstart){
  1468. q_status_message(SM_ORDER, 3, 3, _("Encrypted data couldn't be parsed."));
  1469. }
  1470. else{
  1471. bstart += 4; /* skip over CRLF*2 */
  1472. INIT(&s, mail_string, bstart, strlen(bstart));
  1473. rfc822_parse_msg_full(&env, &body, h, bstart-h-2, &s, BADHOST, 0, 0);
  1474. mail_free_envelope(&env); /* Don't care about this */
  1475. /*
  1476. * Now convert original body (application/pkcs7-mime)
  1477. * to a multipart body with one sub-part (the decrypted body).
  1478. * Note that the sub-part may also be multipart!
  1479. */
  1480. b->type = TYPEMULTIPART;
  1481. if(b->subtype)
  1482. fs_give((void**) &b->subtype);
  1483. /*
  1484. * This subtype is used in mailview.c to annotate the display of
  1485. * encrypted or signed messages. We know for sure then that it's a PKCS7
  1486. * part because the sparep field is set to the PKCS7 object (see above).
  1487. */
  1488. b->subtype = cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE);
  1489. b->encoding = ENC8BIT;
  1490. if(b->description)
  1491. fs_give((void**) &b->description);
  1492. b->description = cpystr(what_we_did);
  1493. if(b->disposition.type)
  1494. fs_give((void **) &b->disposition.type);
  1495. if(b->contents.text.data)
  1496. fs_give((void **) &b->contents.text.data);
  1497. if(b->parameter)
  1498. mail_free_body_parameter(&b->parameter);
  1499. /* Allocate mem for the sub-part, and copy over the contents of our parsed body */
  1500. b->nested.part = fs_get(sizeof(PART));
  1501. b->nested.part->body = *body;
  1502. b->nested.part->next = NULL;
  1503. fs_give((void**) &body);
  1504. /*
  1505. * IMPORTANT BIT: set the body->contents.text.data elements to contain the decrypted
  1506. * data. Otherwise, it'll try to load it from the original data. Eek.
  1507. */
  1508. create_local_cache(bstart, &b->nested.part->body);
  1509. modified_the_body = 1;
  1510. }
  1511. }
  1512. end:
  1513. if(out)
  1514. BIO_free(out);
  1515. return modified_the_body;
  1516. }
  1517. /*
  1518. * Recursively handle PKCS7 bodies in our message.
  1519. *
  1520. * Returns non-zero if some fiddling was done.
  1521. */
  1522. static int
  1523. do_fiddle_smime_message(BODY *b, long msgno, char *section)
  1524. {
  1525. int modified_the_body = 0;
  1526. if(!b)
  1527. return 0;
  1528. dprint((9, "do_fiddle_smime_message(msgno=%ld type=%d subtype=%s section=%s)", msgno, b->type, b->subtype ? b->subtype : "NULL", (section && *section) ? section : (section != NULL) ? "Top" : "NULL"));
  1529. if(is_pkcs7_body(b)){
  1530. if(do_decoding(b, msgno, section)){
  1531. /*
  1532. * b should now be a multipart message:
  1533. * fiddle it too in case it's been multiply-encrypted!
  1534. */
  1535. /* fallthru */
  1536. modified_the_body = 1;
  1537. }
  1538. }
  1539. if(b->type==TYPEMULTIPART || MIME_MSG(b->type, b->subtype)){
  1540. PART *p;
  1541. int partNum;
  1542. char newSec[100];
  1543. if(MIME_MULT_SIGNED(b->type, b->subtype)){
  1544. /*
  1545. * Ahah. We have a multipart signed entity.
  1546. *
  1547. * Multipart/signed
  1548. * part 1 (signed thing)
  1549. * part 2 (the pkcs7 signature)
  1550. *
  1551. * We're going to convert that to
  1552. *
  1553. * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
  1554. * part 1 (signed thing)
  1555. * part 2 has been freed
  1556. *
  1557. * We also extract the signature from part 2 and save it
  1558. * in the multipart body->sparep, and we add a description
  1559. * in the multipart body->description.
  1560. *
  1561. *
  1562. * The results of a decrypted message will be similar. It
  1563. * will be
  1564. *
  1565. * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
  1566. * part 1 (decrypted thing)
  1567. */
  1568. modified_the_body += do_detached_signature_verify(b, msgno, section);
  1569. }
  1570. else if(MIME_MSG(b->type, b->subtype)){
  1571. modified_the_body += do_fiddle_smime_message(b->nested.msg->body, msgno, section);
  1572. }
  1573. else{
  1574. for(p=b->nested.part,partNum=1; p; p=p->next,partNum++){
  1575. /* Append part number to the section string */
  1576. snprintf(newSec, sizeof(newSec), "%s%s%d", section, *section ? "." : "", partNum);
  1577. modified_the_body += do_fiddle_smime_message(&p->body, msgno, newSec);
  1578. }
  1579. }
  1580. }
  1581. return modified_the_body;
  1582. }
  1583. /*
  1584. * Fiddle a message in-place by decrypting/verifying S/MIME entities.
  1585. * Returns non-zero if something was changed.
  1586. */
  1587. int
  1588. fiddle_smime_message(BODY *b, long msgno)
  1589. {
  1590. return do_fiddle_smime_message(b, msgno, "");
  1591. }
  1592. /********************************************************************************/
  1593. /*
  1594. * Output a string in a distinctive style
  1595. */
  1596. void
  1597. gf_puts_uline(char *txt, gf_io_t pc)
  1598. {
  1599. pc(TAG_EMBED); pc(TAG_BOLDON);
  1600. gf_puts(txt, pc);
  1601. pc(TAG_EMBED); pc(TAG_