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 * ========================================================================
7 * Copyright 2013-2021 Eduardo Chappa
8 * Copyright 2008 University of Washington
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * ========================================================================
17 */
18
19 /*
20 * This is based on a contribution from Jonathan Paisley
21 *
22 * File: smime.c
23 * Author: paisleyj@dcs.gla.ac.uk
24 * Date: 01/2001
25 */
26
27
28 #include "../pith/headers.h"
29
30 #ifdef SMIME
31
32 #include "../pith/osdep/canaccess.h"
33 #include "../pith/helptext.h"
34 #include "../pith/store.h"
35 #include "../pith/status.h"
36 #include "../pith/detach.h"
37 #include "../pith/conf.h"
38 #include "../pith/smkeys.h"
39 #include "../pith/smime.h"
40 #include "../pith/mailpart.h"
41 #include "../pith/reply.h"
42 #include "../pith/tempfile.h"
43 #include "../pith/readfile.h"
44 #include "../pith/remote.h"
45 #include "../pith/body.h"
46 #ifdef PASSFILE
47 #include "../pith/imap.h"
48 #endif /* PASSFILE */
49
50 #include <openssl/buffer.h>
51 #include <openssl/x509v3.h>
52 #include <openssl/evp.h>
53
54 /* internal prototypes */
55 static void forget_private_keys(void);
56 static int app_RAND_load_file(const char *file);
57 static void openssl_extra_randomness(void);
58 static int app_RAND_write_file(const char *file);
59 static const char *openssl_error_string(void);
60 static int load_private_key(PERSONAL_CERT *pcert);
61 static void create_local_cache(char *h, char *base, BODY *b, int type);
62 static long rfc822_output_func(void *b, char *string);
63 static void setup_pkcs7_body_for_signature(BODY *b, char *description,
64 char *type, char *filename, char *smime_type);
65 static BIO *body_to_bio(BODY *body);
66 static BIO *bio_from_store(STORE_S *store);
67 static STORE_S *get_part_contents(long msgno, const char *section);
68 static PKCS7 *get_pkcs7_from_part(long msgno, const char *section);
69 static int do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent);
70 static int do_detached_signature_verify(BODY *b, long msgno, char *section);
71 static PERSONAL_CERT *find_certificate_matching_pkcs7(PKCS7 *p7);
72 static int do_decoding(BODY *b, long msgno, const char *section);
73 static void free_smime_struct(SMIME_STUFF_S **smime);
74 static void setup_storage_locations(void);
75 static int copy_container_to_dir(WhichCerts which);
76 static int do_fiddle_smime_message(BODY *b, long msgno, char *section);
77 void setup_privatekey_storage(void);
78 int smime_extract_and_save_cert(PKCS7 *p7);
79 int same_cert(X509 *, X509 *);
80 #ifdef PASSFILE
81 int load_key_and_cert(char *pathkeydir, char *pathcertdir, char **keyfile, char **certfile, EVP_PKEY **pkey, X509 **pcert);
82 #endif /* PASSFILE */
83 EVP_PKEY *load_pkey_with_prompt(char *fpath, char *text, char *prompt, int *);
84 void smime_remove_trailing_crlf(char **mimetext, unsigned long *mimelen, char **bodytext, unsigned long *bodylen);
85 void smime_remove_folding_space(char **mimetext, unsigned long *mimelen, char **bodytext, unsigned long *bodylen);
86 int smime_validate_extra_test(char *mimetext, unsigned long mimelen, char *bodytext, unsigned long bodylen, PKCS7 *p7, int nflag);
87
88 int (*pith_opt_smime_get_passphrase)(void);
89 int (*pith_smime_import_certificate)(char *, char *, char *, size_t);
90 int (*pith_smime_enter_password)(char *, char *, size_t);
91 int (*pith_smime_confirm_save)(char *);
92
93 static X509_STORE *s_cert_store;
94
95 /* State management for randomness functions below */
96 static int seeded = 0;
97
98 #ifdef PASSFILE
99 /*
100 * This code does not work in Windows, because of the PASSFILE thing, so
101 * I did not try to fix it. If you think it does need to be applied to
102 * the Windows version of alpine, there are more changes that are needed
103 * than fixing this function in this module. E. Chappa 09/28/17.
104 *
105 * load key from pathkeydir and cert from pathcertdir. It chooses the first
106 * key/certificate pair that matches. Delete pairs that you do not want used,
107 * if you do not want them selected. All parameters must be non-null.
108 * Memory freed by caller.
109 * Return values:
110 * -1 : user cancelled load
111 * 0 : load was successful
112 * 1 : there was an error in the loading.
113 */
114 int
load_key_and_cert(char * pathkeydir,char * pathcertdir,char ** keyfile,char ** certfile,EVP_PKEY ** pkey,X509 ** pcert)115 load_key_and_cert(char *pathkeydir, char *pathcertdir, char **keyfile,
116 char **certfile, EVP_PKEY **pkey, X509 **pcert)
117 {
118 char buf[MAXPATH+1], pathkey[MAXPATH+1], prompt[MAILTMPLEN];
119 DIR *dirp;
120 struct dirent *d;
121 int b = 0, ret = 1; /* assume error */
122
123 if(pathkeydir == NULL || pathcertdir == NULL || keyfile == NULL
124 || pkey == NULL || certfile == NULL || pcert == NULL)
125 return 1;
126
127 *keyfile = NULL;
128 *certfile = NULL;
129 *pkey = NULL;
130 *pcert = NULL;
131
132 if((dirp = opendir(pathkeydir)) != NULL){
133 while(b == 0 && (d=readdir(dirp)) != NULL){
134 size_t ll;
135
136 if((ll=strlen(d->d_name)) && ll > 4){
137 if(!strcmp(d->d_name+ll-4, ".key")){
138 strncpy(buf, d->d_name, sizeof(buf));
139 buf[sizeof(buf)-1] = '\0';
140 build_path(pathkey, pathkeydir, buf, sizeof(pathkey));
141 buf[strlen(buf)-4] = '\0';
142 snprintf(prompt, sizeof(prompt),
143 _("Enter password of key <%s> to unlock password file: "), buf);
144 if((*pkey = load_pkey_with_prompt(pathkey, NULL, prompt, &ret)) != NULL){
145 if(load_cert_for_key(pathcertdir, *pkey, certfile, pcert)){
146 b = 1; /* break */
147 *keyfile = cpystr(buf);
148 } else {
149 EVP_PKEY_free(*pkey);
150 *pkey = NULL;
151 q_status_message1(SM_ORDER, 0, 2,
152 _("Cannot find certificate that matches key <%s>. Continuing..."), buf);
153 }
154 }
155 }
156 }
157 }
158 closedir(dirp);
159 }
160 return ret;
161 }
162
163
164 /* setup a key and certificate to encrypt and decrypt a password file.
165 * These files will be saved in the .alpine-smime/.pwd directory, but its
166 * location can be setup in the command line with the -pwdcertdir option.
167 * Here are the rules:
168 *
169 * Check if the .alpine-smime/.pwd (or -pwdcertdir directory) exists,
170 * if not create it. If we are successful, move to the next step
171 *
172 * - If the user has a key/cert pair, in the .alpine-smime/.pwd dir
173 * setup is successful;
174 * - if the user does not have a key/cert pair, look to see if
175 * ps_global->smime->personal_certs is already setup, if so, use it.
176 * - if ps_global->smime->personal_certs is not set up, see if we can
177 * find a certificate/cert pair in the default locations at compilation
178 * time. (~/.alpine-smime/private and ~/.alpine-smime/public
179 * - if none of this is successful, create a key/certificate pair
180 * (TODO: implement this)
181 * - in any other case, setup is not successful.
182 *
183 * If setup is successful, setup ps_global->pwdcert.
184 * If any of this fails, ps_global->pwdcert will be null.
185 * Ok, that should do it.
186 *
187 * return values: 0 - everything is normal
188 * 1 - User could not unlock key or no key in directory.
189 * 2 - User cancelled to create self signed certificate
190 * -1 - we do not know which directory to use
191 * -2 - "-pwdcertdir" was given by user, but directory does not exist
192 * -3 - "DF_PASSWORD_DIR" exists but it is not a directory!!??
193 * -4 - we tried to create DF_PASSWORD_DIR but failed.
194 * -5 - password directory exists, but it is empty
195 *
196 */
197 int
setup_pwdcert(void ** pwdcert)198 setup_pwdcert(void **pwdcert)
199 {
200 int rv;
201 int we_inited = 0;
202 int setup_dir = 0; /* make it non zero if we know which dir to use */
203 struct stat sbuf;
204 char pathdir[MAXPATH+1], pathkey[MAXPATH+1], fpath[MAXPATH+1], pathcert[MAXPATH+1];
205 char fpath2[MAXPATH+1], prompt[MAILTMPLEN];
206 char *keyfile, *certfile, *text = NULL;
207 EVP_PKEY *pkey = NULL;
208 X509 *pcert = NULL;
209 PERSONAL_CERT *pc, *pc2 = NULL;
210 static int was_here = 0;
211
212 if(pwdcert == NULL || was_here == 1)
213 return -1;
214
215 was_here++;
216 if(ps_global->pwdcertdir){
217 if(our_stat(ps_global->pwdcertdir, &sbuf) == 0
218 && ((sbuf.st_mode & S_IFMT) == S_IFDIR)){
219 setup_dir++;
220 strncpy(pathdir, ps_global->pwdcertdir, sizeof(pathdir));
221 pathdir[sizeof(pathdir)-1] = '\0';
222 }
223 else rv = -2;
224 } else {
225 smime_path(DF_PASSWORD_DIR, pathdir, sizeof(pathdir));
226 if(our_stat(pathdir, &sbuf) == 0){
227 if((sbuf.st_mode & S_IFMT) == S_IFDIR)
228 setup_dir++;
229 else rv = -3;
230 } else if(can_access(pathdir, ACCESS_EXISTS) != 0
231 && our_mkpath(pathdir, 0700) == 0)
232 setup_dir++;
233 else rv = -4;
234 }
235
236 if(setup_dir == 0){
237 was_here = 0;
238 return rv;
239 }
240
241 if(load_key_and_cert(pathdir, pathdir, &keyfile, &certfile, &pkey, &pcert) < 0){
242 was_here = 0;
243 return 1;
244 }
245
246 if(ps_global->pwdcertdir == NULL){ /* save the result of pwdcertdir */
247 ps_global->pwdcertdir = cpystr(pathdir);
248 /* if the user gave a pwdcertdir and there is nothing there, do not
249 * continue. Let the user initialize on their own this directory.
250 */
251 if(certfile == NULL || keyfile == NULL){
252 was_here = 0;
253 return -5;
254 }
255 }
256
257 if(certfile && keyfile){
258 pc = (PERSONAL_CERT *) fs_get(sizeof(PERSONAL_CERT));
259 memset((void *)pc, 0, sizeof(PERSONAL_CERT));
260 pc->name = keyfile;
261 pc->key = pkey;
262 pc->cert = pcert;
263 pc->cname = certfile;
264 *pwdcert = (void *) pc;
265 was_here = 0;
266 return 0;
267 }
268
269 /* look to see if there are any certificates lying around, first
270 * we try to load ps_global->smime to see if that has information
271 * we can use. If we are the process filling the smime structure
272 * we deinit at the end, since this might not do a full init.
273 */
274 if(ps_global && ps_global->smime && !ps_global->smime->inited){
275 we_inited++;
276 smime_init();
277 }
278
279 /* at this point ps_global->smime->inited == 1 */
280 if(ps_global->smime && ps_global->smime->personal_certs != NULL){
281 pc = (PERSONAL_CERT *) ps_global->smime->personal_certs;
282 if(ps_global->smime->privatetype == Directory){
283 build_path(pathkey, ps_global->smime->privatepath, pc->name, sizeof(pathkey));
284 strncat(pathkey, ".key", 5);
285 pathkey[sizeof(pathkey)-1] = '\0';
286 text = NULL;
287 } else if (ps_global->smime->privatetype == Container){
288 if(pc->keytext == NULL){ /* we should *never* be here, but just in case */
289 if(ps_global->smime->privatecontent != NULL){
290 char tmp[MAILTMPLEN], *s, *t, c;
291 snprintf(tmp, sizeof(tmp), "%s%s", EMAILADDRLEADER, pc->name);
292 tmp[sizeof(tmp)-1] = '\0';
293 if((s = strstr(ps_global->smime->privatecontent, tmp)) != NULL){
294 if((t = strstr(s+strlen(tmp), EMAILADDRLEADER)) != NULL){
295 c = *t;
296 *t = '\0';
297 pc->keytext = cpystr(s + strlen(tmp) + strlen(NEWLINE));
298 *t = c;
299 }
300 else
301 pc->keytext = cpystr(s + strlen(tmp) + strlen(NEWLINE));
302 }
303 }
304 }
305 if(pc->keytext != NULL) /* we should go straight here */
306 text = pc->keytext;
307 } else if (ps_global->smime->privatetype == Keychain){
308 pathkey[0] = '\0'; /* no apple key chain support yet */
309 text = NULL;
310 }
311 if((pathkey && *pathkey) || text){
312 snprintf(prompt, sizeof(prompt),
313 _("Enter password of key <%s> to unlock password file: "), pc->name);
314
315 if((pkey = load_pkey_with_prompt(pathkey, text, prompt, NULL)) != NULL){
316 pc2 = (PERSONAL_CERT *) fs_get(sizeof(PERSONAL_CERT));
317 memset((void *)pc2, 0, sizeof(PERSONAL_CERT));
318 pc2->name = cpystr(pc->name);
319 pc2->key = pkey;
320 pc2->cert = X509_dup(pc->cert);
321
322 /* now copy the keys and certs, starting by the key... */
323 build_path(fpath, pathdir, pc->name, sizeof(fpath));
324 strncat(fpath, ".key", 5);
325 fpath[sizeof(fpath)-1] = '\0';
326 if(our_stat(fpath, &sbuf) == 0){ /* if fpath exists */
327 if((sbuf.st_mode & S_IFMT) == S_IFREG) /* and is a regular file */
328 setup_dir++; /* we are done */
329 } else if(ps_global->smime->privatetype == Directory){
330 if(our_copy(fpath, pathkey) == 0)
331 setup_dir++;
332 } else if(ps_global->smime->privatetype == Container){
333 BIO *out;
334 if((out = BIO_new_file(fpath, "w")) != NULL){
335 if(BIO_puts(out, pc->keytext) > 0)
336 setup_dir++;
337 BIO_free(out);
338 }
339 } else if(ps_global->smime->privatetype == Keychain){
340 /* add support for Apple Mac OS X */
341 }
342 }
343
344 /* successful copy of key, now continue with certificate */
345 if(setup_dir){
346 setup_dir = 0;
347
348 build_path(pathkey, ps_global->smime->publicpath, pc->name, sizeof(pathkey));
349 strncat(pathkey, ".crt", 5);
350 pathkey[sizeof(pathkey)-1] = '\0';
351
352 build_path(fpath, pathdir, pc->name, sizeof(fpath));
353 strncat(fpath, ".crt", 5);
354 fpath[sizeof(fpath)-1] = '\0';
355
356 if(our_stat(fpath, &sbuf) == 0){
357 if((sbuf.st_mode & S_IFMT) == S_IFREG)
358 setup_dir++;
359 }
360 else if(ps_global->smime->privatetype == Directory){
361 if(our_copy(fpath, pathkey) == 0)
362 setup_dir++;
363 } else if(ps_global->smime->privatetype == Container) {
364 BIO *out;
365 if((out = BIO_new_file(fpath, "w")) != NULL){
366 if(PEM_write_bio_X509(out, pc->cert))
367 setup_dir++;
368 BIO_free(out);
369 }
370 } else if (ps_global->smime->privatetype == Keychain) {
371 /* add support for Mac OS X */
372 }
373 }
374
375 if(setup_dir){
376 *pwdcert = (void *) pc2;
377 was_here = 0;
378 return 0;
379 }
380 else if(pc2 != NULL)
381 free_personal_certs(&pc2);
382 } /* if (pathkey...) */
383 } /* if(ps_global->smime->personal_certs) */
384
385
386 if(setup_dir == 0){
387 /* PATHCERTDIR(Private) must be null, so create a path */
388 set_current_val(&ps_global->vars[V_PRIVATEKEY_DIR], TRUE, TRUE);
389 smime_path(ps_global->VAR_PRIVATEKEY_DIR, pathkey, sizeof(pathkey));
390
391 /* PATHCERTDIR(Public) must be null, so create a path */
392 set_current_val(&ps_global->vars[V_PUBLICCERT_DIR], TRUE, TRUE);
393 smime_path(ps_global->VAR_PUBLICCERT_DIR, pathcert, sizeof(pathcert));
394
395 /* BUG: this does not support local containers */
396 load_key_and_cert(pathkey, pathcert, &keyfile, &certfile, &pkey, &pcert);
397
398 if(certfile && keyfile){
399 build_path(fpath, pathdir, keyfile, sizeof(fpath));
400 strncat(fpath, ".key", 5);
401 fpath[sizeof(fpath)-1] = '\0';
402
403 build_path(fpath2, pathkey, keyfile, sizeof(fpath));
404 strncat(fpath2, ".key", 5);
405 fpath2[sizeof(fpath2)-1] = '\0';
406
407 if(our_copy(fpath, fpath2) == 0)
408 setup_dir++;
409
410 if(setup_dir){
411 setup_dir = 0;
412
413 build_path(fpath, pathdir, certfile, sizeof(fpath));
414 build_path(fpath2, pathcert, certfile, sizeof(fpath2));
415
416 if(our_copy(fpath, fpath2) == 0)
417 setup_dir++;
418 }
419 }
420 }
421
422 if(keyfile && certfile){
423 pc = (PERSONAL_CERT *) fs_get(sizeof(PERSONAL_CERT));
424 memset((void *)pc, 0, sizeof(PERSONAL_CERT));
425 pc->name = keyfile;
426 pc->key = pkey;
427 pc->cert = pcert;
428 *pwdcert = (void *) pc;
429 fs_give((void **)&certfile);
430 was_here = 0;
431 return 0;
432 }
433
434 was_here = 0;
435 if(we_inited)
436 smime_deinit();
437 return 0;
438 }
439 #endif /* PASSFILE */
440
441 /* smime_expunge_cert.
442 * Return values: < 0 there was an error.
443 * >=0 the number of messages expunged
444 */
445 int
smime_expunge_cert(WhichCerts ctype)446 smime_expunge_cert(WhichCerts ctype)
447 {
448 int count = 0, removed;
449 CertList *cl, *dummy, *data;
450 char *path, buf[MAXPATH+1];
451 char *contents;
452
453 if(DATACERT(ctype)== NULL)
454 return -1;
455
456 /* data cert is the way we unify certificate management across
457 * functions, but it is not where we really save the information in the
458 * case ctype is equal to Private. What we will do is to update the
459 * datacert, and in the case of ctype equal to Private use the updated
460 * certdata to update the personal_certs data.
461 */
462
463 path = PATHCERTDIR(ctype);
464
465 if(path){
466 /* add a fake certificate at the beginning of the list */
467 dummy = fs_get(sizeof(CertList));
468 memset((void *)dummy, 0, sizeof(CertList));
469 dummy->next = DATACERT(ctype);
470
471 for(cl = dummy, count = 0; cl && cl->next;){
472 if(cl->next->data.deleted == 0){
473 cl = cl->next;
474 continue;
475 }
476
477 removed = 1; /* assume success */
478 if(SMHOLDERTYPE(ctype) == Directory){
479 build_path(buf, path, cl->next->name, sizeof(buf));
480 if(ctype == Private && strlen(buf) + strlen(EXTCERT(Private)) < sizeof(buf)){
481 strncat(buf, EXTCERT(Private), 5);
482 buf[sizeof(buf)-1] = '\0';
483 }
484
485 if(our_unlink(buf) < 0){
486 q_status_message1(SM_ORDER, 3, 3, _("Error removing certificate %s"), cl->next->name);
487 cl = cl->next;
488 removed = 0;
489 }
490 }
491 else if(SMHOLDERTYPE(ctype) == Container){
492 char *prefix= ctype == CACert ? CACERTSTORELEADER : EMAILADDRLEADER;
493 char tmp[MAILTMPLEN], *s, *t;
494
495 contents = CONTENTCERTLIST(ctype);
496 snprintf(tmp, sizeof(tmp), "%s%s", prefix, cl->next->name);
497 tmp[sizeof(tmp) - 1] = '\0';
498 if((s = strstr(contents, tmp)) != NULL){
499 if((t = strstr(s+strlen(tmp), prefix)) == NULL)
500 *s = '\0';
501 else
502 memmove(s, t, strlen(t)+1);
503 fs_resize((void **)&contents, strlen(contents)+1);
504 switch(ctype){
505 case Private: ps_global->smime->privatecontent = contents; break;
506 case Public : ps_global->smime->publiccontent = contents; break;
507 case CACert : ps_global->smime->cacontent = contents; break;
508 default : break;
509 }
510 }
511 else
512 removed = 0;
513 } else { /* unhandled case */
514 }
515
516 if(removed > 0){
517 count++; /* count it! */
518 data = cl->next;
519 cl->next = data->next;
520 if(data->name) fs_give((void **)&data->name);
521 fs_give((void **)&data);
522 }
523 }
524 } else
525 q_status_message(SM_ORDER, 3, 3, _("Error expunging certificate"));
526
527 switch(ctype){
528 case Private: ps_global->smime->privatecertlist = dummy->next; break;
529 case Public : ps_global->smime->publiccertlist = dummy->next; break;
530 case CACert : ps_global->smime->cacertlist = dummy->next; break;
531 default : break;
532 }
533 fs_give((void **)&dummy);
534 if(SMHOLDERTYPE(ctype) == Container){
535 if(copy_dir_to_container(ctype, contents) < 0)
536 count = 0;
537 }
538 if(count > 0){
539 q_status_message2(SM_ORDER, 3, 3, _("Removed %s certificate%s"), comatose(count), plural(count));
540 }
541 else
542 q_status_message(SM_ORDER, 3, 3, _("Error: No certificates were removed"));
543 return count;
544 }
545
546 void
mark_cert_deleted(WhichCerts ctype,int num,unsigned state)547 mark_cert_deleted(WhichCerts ctype, int num, unsigned state)
548 {
549 CertList *cl;
550 int i;
551
552 for(cl = DATACERT(ctype), i = 0; cl != NULL && i < num; cl = cl->next, i++);
553 cl->data.deleted = state;
554 }
555
556 unsigned
get_cert_deleted(WhichCerts ctype,int num)557 get_cert_deleted(WhichCerts ctype, int num)
558 {
559 CertList *cl;
560 int i;
561
562 for(cl = DATACERT(ctype), i = 0; cl != NULL && i < num; cl = cl->next, i++);
563 return (cl && cl->data.deleted) ? 1 : 0;
564 }
565
566 EVP_PKEY *
load_pkey_with_prompt(char * fpath,char * text,char * prompt,int * ret)567 load_pkey_with_prompt(char *fpath, char *text, char *prompt, int *ret)
568 {
569 EVP_PKEY *pkey;
570 int rc = 0; /* rc == 1, cancel, rc == 0 success */
571 char pass[MAILTMPLEN+1];
572 BIO *in;
573
574 /* attempt to load with empty password */
575 in = text ? BIO_new_mem_buf(text, strlen(text)) : BIO_new_file(fpath, "r");
576 if(in != NULL){
577 pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, "");
578 if(pkey != NULL) return pkey;
579 } else return NULL;
580
581 if(pith_smime_enter_password)
582 while(pkey == NULL && rc != 1){
583 do {
584 rc = (*pith_smime_enter_password)(prompt, (char *)pass, sizeof(pass));
585 } while (rc!=0 && rc!=1 && rc>0);
586
587 (void) BIO_reset(in);
588 pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, (char *)pass);
589 }
590
591 BIO_free(in);
592
593 if(ret) *ret = rc == 1 ? -1 : pkey != NULL ? 0 : 1;
594 return pkey;
595 }
596
597 /* This is a tool for conf_screen, The return value must be zero when
598 * nothing changed, so if there is a failure in the import return 0
599 * and return 1 when we succeeded.\
600 * We call this function in two ways:
601 * either fname is null or not. If they fname is null, so is p_cert.
602 * if p_cert is not null, it is the PERSONAL_CERT structure of fname if this
603 * is available, otherwise we will fill it up here.
604 */
605 int
import_certificate(WhichCerts ctype,PERSONAL_CERT * p_cert,char * fname)606 import_certificate(WhichCerts ctype, PERSONAL_CERT *p_cert, char *fname)
607 {
608 int r = 1, rc;
609 char filename[MAXPATH+1], full_filename[MAXPATH+1], buf[MAXPATH+1];
610 char *what;
611
612 if(pith_smime_import_certificate == NULL
613 || pith_smime_enter_password == NULL){
614 q_status_message(SM_ORDER, 0, 2,
615 _("import of certificates not implemented yet!"));
616 return 0;
617 }
618
619 if(fname == NULL){
620 what = ctype == Public || ctype == CACert ? "certificate" : "key";
621 r = (*pith_smime_import_certificate)(filename, full_filename, what, sizeof(filename) - 20);
622
623 if(r < 0)
624 return 0;
625 } else {
626 char *s;
627 strncpy(full_filename, fname, sizeof(full_filename));
628 if((s = strrchr(full_filename, '/')) != NULL)
629 strncpy(filename, s+1, sizeof(filename));
630 }
631
632 /* we are trying to import a new key for the password file. First we ask for the
633 * private key. Once this is loaded, we make a reasonable attempt to find the
634 * public key in the same directory as the key was loaded from. We do this by
635 * looking for a file with the correct public certificate name, then we look
636 * in the same private key, and if not, we ask the user for its location. If all
637 * of this works, we import the key and public to the password directory.
638 */
639 #ifdef PASSFILE
640 if(ctype == Password){
641 char PrivateKeyPath[MAXPATH+1], PublicCertPath[MAXPATH+1], s[MAXPATH+1];
642 char full_name_key[MAXPATH+1], full_name_cert[MAXPATH+1];
643 char *use_this_file = NULL;
644 char prompt[500];
645 EVP_PKEY *key = p_cert ? p_cert->key : NULL;
646
647 rc = 1; /* assume success :) */
648 if(strlen(filename) > 4){
649 strncpy(s, filename, sizeof(s));
650 s[sizeof(s)-1] = '\0';
651 if(!strcmp(s + strlen(s) - strlen(EXTCERT(Private)), EXTCERT(Private)))
652 s[strlen(s) - strlen(EXTCERT(Private))] = '\0';
653 else
654 rc = 0;
655 } else rc = 0;
656
657 if(rc == 0){
658 q_status_message(SM_ORDER, 1, 3, _("Error in key name. Check file extension"));
659 return 0;
660 }
661
662 snprintf(prompt, sizeof(prompt), _("Enter passphrase to unlock new key <%s>: "), filename);
663 prompt[sizeof(prompt)-1] = '\0';
664 if(key != NULL
665 || (key = load_pkey_with_prompt(full_filename, NULL, prompt, NULL)) != NULL){
666 BIO *ins = NULL;
667 X509 *cert = p_cert ? p_cert->cert : NULL, *cert2;
668
669 strncpy(full_name_key, full_filename, sizeof(full_filename));
670 full_name_key[sizeof(full_name_key)-1] = '\0';
671
672 build_path(buf, PATHCERTDIR(ctype), s, sizeof(buf));
673
674 strncpy(PrivateKeyPath, buf, sizeof(PrivateKeyPath));
675 PrivateKeyPath[sizeof(PrivateKeyPath)-1] = '\0';
676 if(strlen(PrivateKeyPath) + 4 < sizeof(PrivateKeyPath)){
677 strncat(PrivateKeyPath, EXTCERT(Private), 5);
678 PrivateKeyPath[sizeof(PrivateKeyPath)-1] = '\0';
679 }
680
681 /* remove .key extension and replace it with .crt extension */
682 strncpy(full_name_cert, full_name_key, sizeof(full_name_key));
683 full_name_cert[sizeof(full_name_cert)-1] = '\0';
684 full_name_cert[strlen(full_name_cert) - strlen(EXTCERT(Private))] = '\0';
685 strncat(full_name_cert, EXTCERT(Public), 5);
686 full_name_cert[sizeof(full_name_cert)-1] = '\0';
687
688
689 /* set up path to location where we will save public cert */
690 strncpy(PublicCertPath, buf, sizeof(PublicCertPath));
691 PublicCertPath[sizeof(PublicCertPath)-1] = '\0';
692 if(strlen(PublicCertPath) + 4 < sizeof(PublicCertPath)){
693 strncat(PublicCertPath, EXTCERT(Public), 5);
694 PublicCertPath[sizeof(PublicCertPath)-1] = '\0';
695 }
696 /* attempt #1, use provided certificate,
697 * assumption is that full_name_cert is the file that this
698 * certificate derives from (which is obtained by substitution
699 * of .key extension in key by .crt extension)
700 */
701 if(cert != NULL) /* attempt #1 */
702 use_this_file = &full_name_cert[0];
703 else if((ins = BIO_new_file(full_name_cert, "r")) != NULL){
704 /* attempt #2 to guess public cert name, use .crt extension */
705 if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL){
706 use_this_file = &full_name_cert[0];
707 }
708 }
709 else{ /* attempt #3 to guess public cert name: use the original key */
710 if((ins = BIO_new_file(full_name_key, "r")) != NULL){
711 if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL){
712 use_this_file = &full_name_key[0];
713 }
714 }
715 else {
716 int done = 0;
717 /* attempt #4, ask the user */
718 do {
719 r = (*pith_smime_import_certificate)(filename, use_this_file, "certificate", sizeof(filename) - 20);
720 if(r < 0){
721 if(ins != NULL) BIO_free(ins);
722 if(cert != NULL) X509_free(cert);
723 return 0;
724 }
725 if((ins = BIO_new_file(use_this_file, "r")) != NULL){
726 if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL)
727 done++;
728 else
729 q_status_message(SM_ORDER, 1, 3, _("Error parsing certificate"));
730 }
731 else
732 q_status_message(SM_ORDER, 1, 3, _("Error reading certificate"));
733 } while (done == 0);
734 }
735 }
736 if(ins != NULL){
737 if(cert != NULL){ /* check that certificate matches key */
738 if(!X509_check_private_key(cert, key)){
739 rc = 0;
740 q_status_message(SM_ORDER, 1, 3, _("Certificate does not match key"));
741 }
742 else
743 rc = 1; /* Success! */
744 }
745 else
746 q_status_message(SM_ORDER, 1, 3, _("Error in certificate file (not a certificate?)"));
747 }
748 if(rc == 1){ /* if everything has been successful,
749 * copy the files to their final destination */
750 if(our_copy(PrivateKeyPath, full_filename) == 0){ /* <-- save the private key */
751 q_status_message(SM_ORDER, 1, 3, _("Private key saved"));
752 if(our_copy(PublicCertPath, use_this_file) == 0){
753 char tmp[MAILTMPLEN];
754 FILE *fp;
755
756 if(!passfile_name(ps_global->pinerc, tmp, sizeof(tmp))
757 || !(fp = our_fopen(tmp, "rb"))){
758 q_status_message(SM_ORDER, 1, 3, _("Error reading password file!"));
759 rc = 0;
760 }
761 else {
762 char tmp2[MAILTMPLEN];
763 int encrypted = 0;
764 char *text;
765 PERSONAL_CERT *pwdcert, *pc = p_cert;
766
767 pwdcert = (PERSONAL_CERT *) ps_global->pwdcert;
768 if(pwdcert == NULL)
769 setup_pwdcert((void **)&pwdcert);
770
771 tmp2[0] = '\0';
772 fgets(tmp2, sizeof(tmp2), fp);
773 fclose(fp);
774 if(strcmp(tmp2, "-----BEGIN PKCS7-----\n")){
775 if(encrypt_file((char *)tmp, NULL, pwdcert))
776 encrypted++;
777 }
778 else
779 encrypted++;
780
781 if(encrypted){
782 text = decrypt_file((char *)tmp, NULL, pwdcert);
783 if(text != NULL){
784 if(pc == NULL){
785 filename[strlen(filename)-strlen(EXTCERT(Private))] = '\0';
786 if(strlen(filename) + strlen(EXTCERT(Public)) < MAXPATH){
787 pc = fs_get(sizeof(PERSONAL_CERT));
788 memset((void *)pc, 0, sizeof(PERSONAL_CERT));
789 pc->name = cpystr(filename);
790 pc->cname = fs_get(strlen(filename) + strlen(EXTCERT(Public)) + 1);
791 sprintf(pc->cname, "%s%s", filename, EXTCERT(Public));
792 pc->key = key;
793 pc->cert = cert;
794 }
795 }
796
797 if(encrypt_file((char *)tmp, text, pc)){ /* we did it! */
798 build_path(buf, PATHCERTDIR(ctype), pwdcert->name, sizeof(buf));
799 strncat(buf, EXTCERT(Private), 5);
800 buf[sizeof(buf)-1] = '\0';
801 if(strcmp(PrivateKeyPath, buf)){
802 if (unlink(buf) < 0)
803 q_status_message(SM_ORDER, 1, 3, _("Failed to remove old key"));
804 }
805 build_path(buf, PATHCERTDIR(ctype), pwdcert->cname, sizeof(buf));
806 if(strcmp(PublicCertPath, buf)){
807 if(unlink(buf) < 0)
808 q_status_message(SM_ORDER, 1, 3, _("Failed to remove old certificate"));
809 }
810 free_personal_certs((PERSONAL_CERT **)&ps_global->pwdcert);
811 ps_global->pwdcert = pc;
812 rc = 1;
813 q_status_message(SM_ORDER, 1, 3, _("Password file reencrypted"));
814 } else {
815 q_status_message(SM_ORDER, 1, 3, _("Failed to reencrypt password file"));
816 rc = 0;
817 }
818 } else {
819 q_status_message(SM_ORDER, 1, 3, _("Error decrypting Password file"));
820 }
821 } else {
822 q_status_message(SM_ORDER, 1, 3, _("Password file not encrypted and could not encrypt"));
823 rc = 0;
824 }
825 }
826 }
827 else{
828 q_status_message(SM_ORDER, 1, 3, _("Error saving public certificate"));
829 if(our_unlink(PrivateKeyPath) < 0)
830 q_status_message(SM_ORDER, 1, 3, _("Error while cleaning private key"));
831 rc = 0;
832 }
833 }
834 else{
835 rc = 0;
836 q_status_message(SM_ORDER, 1, 3, _("Error saving private key"));
837 }
838 if(ins != NULL) BIO_free(ins);
839 if(rc == 0 && cert != NULL) X509_free(cert);
840 }
841 } else {
842 rc = 0;
843 q_status_message(SM_ORDER, 1, 3, _("Error unlocking private key"));
844 }
845
846 return rc;
847 }
848 #endif /* PASSFILE */
849
850 smime_init();
851 ps_global->mangled_screen = 1;
852
853 if (ctype == Private){
854 char prompt[500], *s, *t;
855 EVP_PKEY *key = NULL;
856
857 if(!ps_global->smime->privatecertlist){
858 ps_global->smime->privatecertlist = fs_get(sizeof(CertList));
859 memset((void *) ps_global->smime->privatecertlist, 0, sizeof(CertList));
860 }
861
862 for(s = t = filename; (t = strstr(s, ".key")) != NULL; s = t + 1);
863 if(s) *(s-1) = 0;
864
865 snprintf(prompt, sizeof(prompt), _("Enter passphrase for <%s>: "), filename);
866 prompt[sizeof(prompt)-1] = '\0';
867 if((key = load_pkey_with_prompt(full_filename, NULL, prompt, NULL)) != NULL){
868 if(SMHOLDERTYPE(ctype) == Directory){
869 build_path(buf, PATHCERTDIR(ctype), filename, sizeof(buf));
870 if(strcmp(buf + strlen(buf) - 4, EXTCERT(ctype)) != 0 && strlen(buf) + 4 < sizeof(buf)){
871 strncat(buf, EXTCERT(ctype), 5);
872 buf[sizeof(buf)-1] = '\0';
873 }
874 rc = our_copy(buf, full_filename);
875 }
876 else /* if(SMHOLDERTYPE(ctype) == Container){ */
877 rc = add_file_to_container(ctype, full_filename, NULL);
878 if(rc == 0)
879 q_status_message(SM_ORDER, 1, 3, _("Private key saved"));
880 else
881 q_status_message(SM_ORDER, 1, 3, _("Error saving private key"));
882 if(ps_global->smime->publiccertlist)
883 ps_global->smime->publiccertlist->data.renew = 1;
884 }
885 else
886 q_status_message(SM_ORDER, 1, 3, _("Problem unlocking key (not a certificate or wrong password)"));
887 } else if (ctype == CACert){
888 BIO *ins;
889 X509 *cert;
890
891 if((ins = BIO_new_file(full_filename, "r")) != NULL){
892 if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL){
893 if(SMHOLDERTYPE(ctype) == Directory){
894 build_path(buf, PATHCERTDIR(ctype), filename, sizeof(buf));
895 if(strcmp(buf + strlen(buf) - 4, ".crt") != 0 && strlen(buf) + 4 < sizeof(buf)){
896 strncat(buf, EXTCERT(ctype), 5);
897 buf[sizeof(buf)-1] = '\0';
898 }
899
900 rc = our_copy(buf, full_filename);
901 }
902 else /* if(SMHOLDERTYPE(ctype) == Container){ */
903 rc = add_file_to_container(ctype, full_filename, NULL);
904 if(rc == 0)
905 q_status_message(SM_ORDER, 1, 3, _("Certificate saved"));
906 else
907 q_status_message(SM_ORDER, 1, 3, _("Error saving certificate"));
908 X509_free(cert); /* not needed anymore */
909 }
910 else
911 q_status_message(SM_ORDER, 1, 3, _("Error in certificate file (not a certificate?)"));
912 BIO_free(ins);
913 }
914 renew_store();
915 } else { /* ctype == Public. save certificate, but first validate that it is one */
916 BIO *ins;
917 X509 *cert;
918
919 if((ins = BIO_new_file(full_filename, "r")) != NULL){
920 if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL){
921 if(SMHOLDERTYPE(ctype) == Directory){
922 char **email;
923
924 if((email = get_x509_subject_email(cert)) != NULL){
925 int i;
926 for(i = 0; email[i] != NULL; i++){
927 save_cert_for(email[i], cert, Public);
928 fs_give((void **)&email[i]);
929 }
930 fs_give((void **)email);
931 }
932 if(strcmp(filename + strlen(filename) - 4, ".crt") == 0)
933 filename[strlen(filename) - 4] = '\0';
934 save_cert_for(filename, cert, Public);
935 }
936 else /* if(SMHOLDERTYPE(ctype) == Container){ */
937 add_file_to_container(ctype, full_filename, NULL);
938 X509_free(cert);
939 if(ps_global->smime->publiccertlist)
940 ps_global->smime->publiccertlist->data.renew = 1;
941 }
942 else
943 q_status_message(SM_ORDER, 1, 3, _("Error in certificate file (not a certificate?)"));
944 BIO_free(ins);
945 }
946 }
947 if(DATACERT(ctype)) RENEWCERT(DATACERT(ctype)) = 1;
948 return 1;
949 }
950
951 /* itype: information type to add: 0 - public, 1 - private.
952 * Memory freed by caller
953 */
954 BIO *
print_private_key_information(char * email,int itype)955 print_private_key_information(char *email, int itype)
956 {
957 BIO *out;
958 PERSONAL_CERT *pc;
959
960 if(ps_global->smime == NULL
961 || ps_global->smime->personal_certs == NULL
962 || (itype != 0 && itype != 1))
963 return NULL;
964
965 for(pc = ps_global->smime->personal_certs;
966 pc != NULL && strcmp(pc->name, email) != 0; pc = pc->next);
967 if(pc->key == NULL
968 && !load_private_key(pc)
969 && ps_global->smime
970 && ps_global->smime->need_passphrase){
971 if (pith_opt_smime_get_passphrase)
972 (*pith_opt_smime_get_passphrase)();
973 load_private_key(pc);
974 }
975
976 if(pc->key == NULL)
977 return NULL;
978
979 out = BIO_new(BIO_s_mem());
980 if(itype == 0) /* 0 means public */
981 EVP_PKEY_print_public(out, pc->key, 0, NULL);
982 else if (itype == 1) /* 1 means private */
983 EVP_PKEY_print_private(out, pc->key, 0, NULL);
984
985 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE,ps_global))
986 forget_private_keys();
987
988 return out;
989 }
990
991 /*
992 * Forget any cached private keys
993 */
994 static void
forget_private_keys(void)995 forget_private_keys(void)
996 {
997 PERSONAL_CERT *pcert;
998 size_t len;
999 volatile char *p;
1000
1001 dprint((9, "forget_private_keys()"));
1002 if(ps_global->smime){
1003 ps_global->smime->already_auto_asked = 0;
1004 for(pcert=(PERSONAL_CERT *) ps_global->smime->personal_certs;
1005 pcert;
1006 pcert=pcert->next){
1007
1008 if(pcert->key){
1009 EVP_PKEY_free(pcert->key);
1010 pcert->key = NULL;
1011 }
1012 }
1013
1014 ps_global->smime->entered_passphrase = 0;
1015 len = sizeof(ps_global->smime->passphrase);
1016 p = ps_global->smime->passphrase;
1017
1018 while(len-- > 0)
1019 *p++ = '\0';
1020 }
1021 }
1022
1023 /* modelled after signature_path in reply.c, but uses home dir instead of the
1024 * directory where the .pinerc is located, since according to documentation,
1025 * the .alpine-smime directories are subdirectories of the home directory
1026 */
1027 int
smime_path(char * rpath,char * fpath,size_t len)1028 smime_path(char *rpath, char *fpath, size_t len)
1029 {
1030 *fpath = '\0';
1031 if(rpath && *rpath){
1032 size_t spl = strlen(rpath);
1033
1034 if(IS_REMOTE(rpath)){
1035 if(spl < len - 1)
1036 strncpy(fpath, rpath, len-1);
1037 fpath[len-1] = '\0';
1038 }
1039 else if(is_absolute_path(rpath)){
1040 strncpy(fpath, rpath, len-1);
1041 fpath[len-1] = '\0';
1042 fnexpand(fpath, len);
1043 }
1044 else if(ps_global->VAR_OPER_DIR){
1045 if(strlen(ps_global->VAR_OPER_DIR) + spl < len - 1)
1046 build_path(fpath, ps_global->VAR_OPER_DIR, rpath, len);
1047 }
1048 else if(ps_global->home_dir){
1049 if(strlen(ps_global->home_dir) + spl < len - 1)
1050 build_path(fpath, ps_global->home_dir, rpath, len);
1051 }
1052 }
1053 return fpath && *fpath ? 1 : 0;
1054 }
1055
1056
1057
1058 /*
1059 * taken from openssl/apps/app_rand.c
1060 */
1061 static int
app_RAND_load_file(const char * file)1062 app_RAND_load_file(const char *file)
1063 {
1064 #define RANDBUFLEN 200
1065 char buffer[RANDBUFLEN];
1066
1067 if(file == NULL)
1068 file = RAND_file_name(buffer, RANDBUFLEN);
1069
1070 if(file == NULL || !RAND_load_file(file, -1)){
1071 if(RAND_status() == 0){
1072 dprint((1, "unable to load 'random state'\n"));
1073 dprint((1, "This means that the random number generator has not been seeded\n"));
1074 dprint((1, "with much random data.\n"));
1075 }
1076
1077 return 0;
1078 }
1079
1080 seeded = 1;
1081 return 1;
1082 }
1083
1084
1085 /*
1086 * copied and fiddled from imap/src/osdep/unix/auth_ssl.c
1087 */
1088 static void
openssl_extra_randomness(void)1089 openssl_extra_randomness(void)
1090 {
1091 #if !defined(WIN32)
1092 int fd;
1093 unsigned long i;
1094 char *tf = NULL;
1095 char tmp[MAXPATH];
1096 struct stat sbuf;
1097 /* if system doesn't have /dev/urandom */
1098 if(stat ("/dev/urandom", &sbuf)){
1099 tmp[0] = '0';
1100 tf = temp_nam(NULL, NULL);
1101 if(tf){
1102 strncpy(tmp, tf, sizeof(tmp));
1103 tmp[sizeof(tmp)-1] = '\0';
1104 fs_give((void **) &tf);
1105 }
1106
1107 if((fd = open(tmp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0)
1108 i = (unsigned long) tmp;
1109 else{
1110 unlink(tmp); /* don't need the file */
1111 fstat(fd, &sbuf); /* get information about the file */
1112 i = sbuf.st_ino; /* remember its inode */
1113 close(fd); /* or its descriptor */
1114 }
1115 /* not great but it'll have to do */
1116 snprintf(tmp+strlen(tmp), sizeof(tmp)-strlen(tmp), "%.80s%lx%lx%lx",
1117 tcp_serverhost (),i,
1118 (unsigned long) (time (0) ^ gethostid ()),
1119 (unsigned long) getpid ());
1120 RAND_seed(tmp, strlen(tmp));
1121 }
1122 #endif
1123 }
1124
1125
1126 /* taken from openssl/apps/app_rand.c */
1127 static int
app_RAND_write_file(const char * file)1128 app_RAND_write_file(const char *file)
1129 {
1130 char buffer[200];
1131
1132 if(!seeded)
1133 /*
1134 * If we did not manage to read the seed file,
1135 * we should not write a low-entropy seed file back --
1136 * it would suppress a crucial warning the next time
1137 * we want to use it.
1138 */
1139 return 0;
1140
1141 if(file == NULL)
1142 file = RAND_file_name(buffer, sizeof buffer);
1143
1144 if(file == NULL || !RAND_write_file(file)){
1145 dprint((1, "unable to write 'random state'\n"));
1146 return 0;
1147 }
1148
1149 return 1;
1150 }
1151
1152 CertList *
certlist_from_personal_certs(PERSONAL_CERT * pc)1153 certlist_from_personal_certs(PERSONAL_CERT *pc)
1154 {
1155 CertList *cl = NULL;
1156 X509 *x;
1157
1158 if(pc == NULL)
1159 return NULL;
1160
1161 if((x = get_cert_for(pc->name, Public, 1)) != NULL){
1162 cl = smime_X509_to_cert_info(x, pc->name);
1163 cl->next = certlist_from_personal_certs(pc->next);
1164 }
1165
1166 return cl;
1167 }
1168
1169 void
renew_cert_data(CertList ** data,WhichCerts ctype)1170 renew_cert_data(CertList **data, WhichCerts ctype)
1171 {
1172 smime_init();
1173 if(ctype == Private){
1174 if(data){
1175 PERSONAL_CERT *pc = (PERSONAL_CERT *)ps_global->smime->personal_certs;
1176 if(*data)
1177 free_certlist(data);
1178 free_personal_certs(&pc);
1179 setup_privatekey_storage();
1180 *data = certlist_from_personal_certs((PERSONAL_CERT *)ps_global->smime->personal_certs);
1181 if(data && *data){
1182 resort_certificates(data, ctype);
1183 RENEWCERT(*data) = 0;
1184 }
1185 ps_global->smime->privatecertlist = *data;
1186 }
1187 if(ps_global->smime->privatecertlist)
1188 RENEWCERT(ps_global->smime->privatecertlist) = 0;
1189 } else {
1190 X509_LOOKUP *lookup = NULL;
1191 X509_STORE *store = NULL;
1192
1193 if((store = X509_STORE_new()) != NULL){
1194 if((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) != NULL){
1195 free_certlist(data);
1196 if(SMHOLDERTYPE(ctype) == Directory)
1197 add_certs_in_dir(lookup, PATHCERTDIR(ctype), EXTCERT(ctype), data);
1198 else /* if(SMHOLDERTYPE(ctype) == Container) */
1199 *data = mem_to_certlist(CONTENTCERTLIST(ctype), ctype);
1200 if(data && *data){
1201 resort_certificates(data, ctype);
1202 RENEWCERT(*data) = 0;
1203 }
1204 if(ctype == Public)
1205 ps_global->smime->publiccertlist = *data;
1206 else
1207 ps_global->smime->cacertlist = *data;
1208 }
1209 free_x509_store(&store);
1210 }
1211 }
1212 setup_certs_backup_by_type(ctype);
1213 }
1214
1215 void
smime_reinit(void)1216 smime_reinit(void)
1217 {
1218 smime_deinit();
1219 smime_init();
1220 }
1221
1222 /* Installed as an atexit() handler to save the random data */
1223 void
smime_deinit(void)1224 smime_deinit(void)
1225 {
1226 dprint((9, "smime_deinit()"));
1227 app_RAND_write_file(NULL);
1228 if (s_cert_store != NULL) free_x509_store(&s_cert_store);
1229 #ifdef ERR_free_strings
1230 ERR_free_strings();
1231 #endif /* ERR_free_strings */
1232 #ifdef EVP_cleanup
1233 EVP_cleanup();
1234 #endif /* EVP_cleanup */
1235 free_smime_struct(&ps_global->smime);
1236 }
1237
1238 /* we renew the store when it has changed */
1239 void
renew_store(void)1240 renew_store(void)
1241 {
1242 if(ps_global->smime->inited){
1243 if(s_cert_store != NULL)
1244 free_x509_store(&s_cert_store);
1245 s_cert_store = get_ca_store();
1246 }
1247 }
1248
1249 /* Initialise openssl stuff if needed */
1250 void
smime_init(void)1251 smime_init(void)
1252 {
1253 if(F_OFF(F_DONT_DO_SMIME, ps_global) && !(ps_global->smime && ps_global->smime->inited)){
1254
1255 dprint((9, "smime_init()"));
1256 if(!ps_global->smime)
1257 ps_global->smime = new_smime_struct();
1258
1259 setup_storage_locations();
1260
1261 s_cert_store = get_ca_store();
1262 setup_certs_backup_by_type(CACert);
1263
1264 #ifdef OPENSSL_1_1_0
1265 OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS|OPENSSL_INIT_ADD_ALL_DIGESTS|OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
1266 #else
1267 OpenSSL_add_all_algorithms();
1268 ERR_load_crypto_strings();
1269 #endif /* OPENSSL_1_1_0 */
1270
1271 app_RAND_load_file(NULL);
1272 openssl_extra_randomness();
1273 ps_global->smime->inited = 1;
1274 }
1275
1276 ERR_clear_error();
1277 }
1278
1279
1280 /* validate a certificate. Return value : 0 for no error, -1 for error.
1281 * In the latter case, set the openssl smime error in *error.
1282 */
1283 int
smime_validate_cert(X509 * cert,long * error)1284 smime_validate_cert(X509 *cert, long *error)
1285 {
1286 X509_STORE_CTX *csc;
1287
1288 ERR_clear_error();
1289 *error = 0;
1290 if((s_cert_store != NULL) && (csc = X509_STORE_CTX_new()) != NULL){
1291 X509_STORE_set_flags(s_cert_store, 0);
1292 if(X509_STORE_CTX_init(csc,s_cert_store,cert,NULL)
1293 && X509_verify_cert(csc) <= 0)
1294 *error = X509_STORE_CTX_get_error(csc);
1295 X509_STORE_CTX_free(csc);
1296 }
1297 return *error ? -1 : 0;
1298 }
1299
1300 PERSONAL_CERT *
get_personal_certs(char * path)1301 get_personal_certs(char *path)
1302 {
1303 PERSONAL_CERT *result = NULL;
1304 char buf2[MAXPATH], *fname;
1305 X509 *cert;
1306 size_t ll;
1307 #ifndef _WINDOWS
1308 struct dirent *d;
1309 DIR *dirp;
1310 #else /* _WINDOWS */
1311 struct _finddata_t dbuf;
1312 char buf[_MAX_PATH + 4];
1313 long findrv;
1314 #endif /* _WINDOWS */
1315
1316 ps_global->smime->privatepath = cpystr(path);
1317
1318 #ifndef _WINDOWS
1319 dirp = opendir(path);
1320 if(dirp){
1321 while((d=readdir(dirp)) != NULL){
1322 fname = d->d_name;
1323 #else /* _WINDOWS */
1324 snprintf(buf, sizeof(buf), "%s%s*.*", path, (path[strlen(path)-1] == '\\') ? "" : "\\");
1325 buf[sizeof(buf)-1] = '\0';
1326 if((findrv = _findfirst(buf, &dbuf)) < 0)
1327 return(NULL);
1328
1329 do {
1330 fname = fname_to_utf8(dbuf.name);
1331 #endif
1332 if((ll=strlen(fname)) && ll > 4 && !strcmp(fname+ll-4, ".key")){
1333
1334 /* copy file name to temp buffer */
1335 strncpy(buf2, fname, sizeof(buf2)-1);
1336 buf2[sizeof(buf2)-1] = '\0';
1337 /* chop off ".key" trailier */
1338 buf2[strlen(buf2)-4] = '\0';
1339 /* Look for certificate */
1340 cert = get_cert_for(buf2, Public, 1);
1341
1342 if(cert){
1343 PERSONAL_CERT *pc;
1344
1345 /* create a new PERSONAL_CERT, fill it in */
1346
1347 pc = (PERSONAL_CERT *) fs_get(sizeof(*pc));
1348 pc->cert = cert;
1349 pc->name = cpystr(buf2);
1350 strncat(buf2, EXTCERT(Public), 5);
1351 pc->cname = cpystr(buf2);
1352
1353 /* Try to load the key with an empty password */
1354 pc->key = load_key(pc, "", SM_NORMALCERT);
1355
1356 pc->next = result;
1357 result = pc;
1358 }
1359 }
1360 #ifndef _WINDOWS
1361 }
1362 closedir(dirp);
1363 }
1364 #else /* _WINDOWS */
1365 } while(_findnext(findrv, &dbuf) == 0);
1366 _findclose(findrv);
1367 #endif /* !_WINDOWS */
1368 return result;
1369 }
1370
1371
1372 void
setup_privatekey_storage(void)1373 setup_privatekey_storage(void)
1374 {
1375 char path[MAXPATH+1], *contents;
1376 int privatekeycontainer = 0;
1377
1378 /* private keys in a container */
1379 if(ps_global->VAR_PRIVATEKEY_CONTAINER && ps_global->VAR_PRIVATEKEY_CONTAINER[0]){
1380
1381 privatekeycontainer = 1;
1382 contents = NULL;
1383 path[0] = '\0';
1384 if(!smime_path(ps_global->VAR_PRIVATEKEY_CONTAINER, path, MAXPATH))
1385 privatekeycontainer = 0;
1386
1387 if(privatekeycontainer && !IS_REMOTE(path)
1388 && ps_global->VAR_OPER_DIR
1389 && !in_dir(ps_global->VAR_OPER_DIR, path)){
1390 q_status_message2(SM_ORDER | SM_DING, 3, 4,
1391 /* TRANSLATORS: First arg is the directory name, second is
1392 the file user wants to read but can't. */
1393 _("Can't read file outside %s: %s"),
1394 ps_global->VAR_OPER_DIR, path);
1395 privatekeycontainer = 0;
1396 }
1397
1398 if(privatekeycontainer
1399 && (IS_REMOTE(path) || can_access(path, ACCESS_EXISTS) == 0)){
1400 if(!(IS_REMOTE(path) && (contents = simple_read_remote_file(path, REMOTE_SMIME_SUBTYPE)))
1401 &&
1402 !(contents = read_file(path, READ_FROM_LOCALE)))
1403 privatekeycontainer = 0;
1404 }
1405
1406 if(privatekeycontainer && path[0]){
1407 ps_global->smime->privatetype = Container;
1408 ps_global->smime->privatepath = cpystr(path);
1409
1410 if(contents){
1411 ps_global->smime->privatecontent = contents;
1412 ps_global->smime->personal_certs = mem_to_personal_certs(contents);
1413 }
1414 }
1415 }
1416
1417 /* private keys in a directory of files */
1418 if(!privatekeycontainer){
1419 ps_global->smime->privatetype = Directory;
1420
1421 path[0] = '\0';
1422 if(!(smime_path(ps_global->VAR_PRIVATEKEY_DIR, path, MAXPATH)
1423 && !IS_REMOTE(path)))
1424 ps_global->smime->privatetype = Nada;
1425 else if(can_access(path, ACCESS_EXISTS)){
1426 if(our_mkpath(path, 0700)){
1427 q_status_message1(SM_ORDER, 3, 3, _("Can't create directory %s"), path);
1428 ps_global->smime->privatetype = Nada;
1429 }
1430 }
1431
1432 if(ps_global->smime->privatetype == Directory)
1433 ps_global->smime->personal_certs = get_personal_certs(path);
1434 }
1435 setup_certs_backup_by_type(Private);
1436 }
1437
1438 static void
setup_storage_locations(void)1439 setup_storage_locations(void)
1440 {
1441 int publiccertcontainer = 0, cacertcontainer = 0;
1442 char path[MAXPATH+1], *contents;
1443
1444 if(!ps_global->smime)
1445 return;
1446
1447 #ifdef APPLEKEYCHAIN
1448 if(F_ON(F_PUBLICCERTS_IN_KEYCHAIN, ps_global)){
1449 ps_global->smime->publictype = Keychain;
1450 }
1451 else{
1452 #endif /* APPLEKEYCHAIN */
1453 /* Public certificates in a container */
1454 if(ps_global->VAR_PUBLICCERT_CONTAINER && ps_global->VAR_PUBLICCERT_CONTAINER[0]){
1455
1456 publiccertcontainer = 1;
1457 contents = NULL;
1458 path[0] = '\0';
1459 if(!smime_path(ps_global->VAR_PUBLICCERT_CONTAINER, path, MAXPATH))
1460 publiccertcontainer = 0;
1461
1462 if(publiccertcontainer && !IS_REMOTE(path)
1463 && ps_global->VAR_OPER_DIR
1464 && !in_dir(ps_global->VAR_OPER_DIR, path)){
1465 q_status_message2(SM_ORDER | SM_DING, 3, 4,
1466 /* TRANSLATORS: First arg is the directory name, second is
1467 the file user wants to read but can't. */
1468 _("Can't read file outside %s: %s"),
1469 ps_global->VAR_OPER_DIR, path);
1470 publiccertcontainer = 0;
1471 }
1472
1473 if(publiccertcontainer
1474 && (IS_REMOTE(path) || can_access(path, ACCESS_EXISTS) == 0)){
1475 if(!(IS_REMOTE(path) && (contents = simple_read_remote_file(path, REMOTE_SMIME_SUBTYPE)))
1476 &&
1477 !(contents = read_file(path, READ_FROM_LOCALE)))
1478 publiccertcontainer = 0;
1479 }
1480
1481 if(publiccertcontainer && path[0]){
1482 ps_global->smime->publictype = Container;
1483 ps_global->smime->publicpath = cpystr(path);
1484
1485 if(contents){
1486 ps_global->smime->publiccontent = contents;
1487 ps_global->smime->publiccertlist = mem_to_certlist(contents, Public);
1488 }
1489 }
1490 }
1491
1492 /* Public certificates in a directory of files */
1493 if(!publiccertcontainer){
1494 ps_global->smime->publictype = Directory;
1495
1496 path[0] = '\0';
1497 if(!(smime_path(ps_global->VAR_PUBLICCERT_DIR, path, MAXPATH)
1498 && !IS_REMOTE(path)))
1499 ps_global->smime->publictype = Nada;
1500 else if(can_access(path, ACCESS_EXISTS)){
1501 if(our_mkpath(path, 0700)){
1502 q_status_message1(SM_ORDER, 3, 3, _("Can't create directory %s"), path);
1503 ps_global->smime->publictype = Nada;
1504 }
1505 }
1506
1507 if(ps_global->smime->publictype == Directory)
1508 ps_global->smime->publicpath = cpystr(path);
1509 }
1510
1511 #ifdef APPLEKEYCHAIN
1512 }
1513 #endif /* APPLEKEYCHAIN */
1514
1515 setup_privatekey_storage();
1516
1517 /* extra cacerts in a container */
1518 if(ps_global->VAR_CACERT_CONTAINER && ps_global->VAR_CACERT_CONTAINER[0]){
1519
1520 cacertcontainer = 1;
1521 contents = NULL;
1522 path[0] = '\0';
1523 if(!smime_path(ps_global->VAR_CACERT_CONTAINER, path, MAXPATH))
1524 cacertcontainer = 0;
1525
1526 if(cacertcontainer && !IS_REMOTE(path)
1527 && ps_global->VAR_OPER_DIR
1528 && !in_dir(ps_global->VAR_OPER_DIR, path)){
1529 q_status_message2(SM_ORDER | SM_DING, 3, 4,
1530 /* TRANSLATORS: First arg is the directory name, second is
1531 the file user wants to read but can't. */
1532 _("Can't read file outside %s: %s"),
1533 ps_global->VAR_OPER_DIR, path);
1534 cacertcontainer = 0;
1535 }
1536
1537 if(cacertcontainer
1538 && (IS_REMOTE(path) || can_access(path, ACCESS_EXISTS) == 0)){
1539 if(!(IS_REMOTE(path) && (contents = simple_read_remote_file(path, REMOTE_SMIME_SUBTYPE)))
1540 &&
1541 !(contents = read_file(path, READ_FROM_LOCALE)))
1542 cacertcontainer = 0;
1543 }
1544
1545 if(cacertcontainer && path[0]){
1546 ps_global->smime->catype = Container;
1547 ps_global->smime->capath = cpystr(path);
1548 ps_global->smime->cacontent = contents;
1549 if(contents)
1550 ps_global->smime->cacertlist = mem_to_certlist(contents, CACert);
1551 }
1552 }
1553
1554 if(!cacertcontainer){
1555 ps_global->smime->catype = Directory;
1556
1557 path[0] = '\0';
1558 if(!(smime_path(ps_global->VAR_CACERT_DIR, path, MAXPATH)
1559 && !IS_REMOTE(path)))
1560 ps_global->smime->catype = Nada;
1561 else if(can_access(path, ACCESS_EXISTS)){
1562 if(our_mkpath(path, 0700)){
1563 q_status_message1(SM_ORDER, 3, 3, _("Can't create directory %s"), path);
1564 ps_global->smime->catype = Nada;
1565 }
1566 }
1567
1568 if(ps_global->smime->catype == Directory)
1569 ps_global->smime->capath = cpystr(path);
1570 }
1571 }
1572
1573
1574 int
copy_publiccert_dir_to_container(void)1575 copy_publiccert_dir_to_container(void)
1576 {
1577 return(copy_dir_to_container(Public, NULL));
1578 }
1579
1580
1581 int
copy_publiccert_container_to_dir(void)1582 copy_publiccert_container_to_dir(void)
1583 {
1584 return(copy_container_to_dir(Public));
1585 }
1586
1587
1588 int
copy_privatecert_dir_to_container(void)1589 copy_privatecert_dir_to_container(void)
1590 {
1591 return(copy_dir_to_container(Private, NULL));
1592 }
1593
1594
1595 int
copy_privatecert_container_to_dir(void)1596 copy_privatecert_container_to_dir(void)
1597 {
1598 return(copy_container_to_dir(Private));
1599 }
1600
1601
1602 int
copy_cacert_dir_to_container(void)1603 copy_cacert_dir_to_container(void)
1604 {
1605 return(copy_dir_to_container(CACert, NULL));
1606 }
1607
1608
1609 int
copy_cacert_container_to_dir(void)1610 copy_cacert_container_to_dir(void)
1611 {
1612 return(copy_container_to_dir(CACert));
1613 }
1614
1615 /* Add the contents of a file to a container. Do not check the content
1616 * of the file, just add it using the format for that container. The
1617 * caller must check the format, so that there is no data corruption
1618 * in the future.
1619 * return value: 0 - success,
1620 * != 0 - failure.
1621 */
1622 int
add_file_to_container(WhichCerts ctype,char * fpath,char * altname)1623 add_file_to_container(WhichCerts ctype, char *fpath, char *altname)
1624 {
1625 char *sep = (ctype == Public || ctype == Private)
1626 ? EMAILADDRLEADER : CACERTSTORELEADER;
1627 char *content = ctype == Public ? ps_global->smime->publiccontent
1628 : (ctype == Private ? ps_global->smime->privatecontent
1629 : ps_global->smime->cacontent);
1630 char *name;
1631 char *s;
1632 unsigned char c;
1633 struct stat sbuf;
1634 STORE_S *in = NULL;
1635 int rv = -1; /* assume error */
1636 size_t clen; /* content buffer size */
1637
1638 if(our_stat(fpath, &sbuf) < 0
1639 || (in = so_get(FileStar, fpath, READ_ACCESS | READ_FROM_LOCALE)) == NULL)
1640 goto endadd;
1641
1642 if(altname != NULL)
1643 name = altname;
1644 else if((name = strrchr(fpath, '/')) != NULL){
1645 size_t ll;
1646 if((ll = strlen(++name)) > 4 && strucmp(name + ll - 4, EXTCERT(ctype)) == 0)
1647 name[ll-strlen(EXTCERT(ctype))] = '\0';
1648 }
1649 else
1650 goto endadd;
1651
1652 if(content){
1653 clen = strlen(content) + strlen(sep) + strlen(name) + sbuf.st_size + 2*strlen(NEWLINE) + 1;
1654 fs_resize((void **)&content, clen);
1655 s = content;
1656 content += strlen(content);
1657 }
1658 else{
1659 clen = strlen(sep) + strlen(name) + sbuf.st_size + strlen(NEWLINE) + 1;
1660 s = content = fs_get(clen);
1661 *content = '\0';
1662 }
1663 strncat(content, sep, clen - strlen(content));
1664 strncat(content, name, clen - strlen(content));
1665 content += strlen(content);
1666 #ifdef _WINDOWS
1667 *content++ = '\r';
1668 #endif /* _WINDOWS */
1669 *content++ = '\n';
1670
1671 while(so_readc(&c, in))
1672 *content++ = (char) c;
1673 *content = '\0';
1674
1675 switch(ctype){
1676 case Private: ps_global->smime->privatecontent = s; break;
1677 case Public : ps_global->smime->publiccontent = s; break;
1678 case CACert : ps_global->smime->cacontent = s; break;
1679 default : break;
1680 }
1681
1682 rv = copy_dir_to_container(ctype, s);
1683
1684 endadd:
1685 if(in) so_give(&in);
1686
1687 return rv;
1688 }
1689
1690
1691 /*
1692 * returns 0 on success, -1 on failure
1693 * contents is an argument which tells this function to write the value
1694 * of this variable instead of reading the contents of the directory.
1695 * If the var contents is not null use its value as the value of the
1696 * container.
1697 */
1698 int
copy_dir_to_container(WhichCerts which,char * contents)1699 copy_dir_to_container(WhichCerts which, char *contents)
1700 {
1701 int ret = 0, container = 0;
1702 BIO *bio_out = NULL, *bio_in = NULL;
1703 char srcpath[MAXPATH+1], dstpath[MAXPATH+1], emailaddr[MAXPATH], file[MAXPATH], line[4096];
1704 char *tempfile = NULL, fpath[MAXPATH+1], *fname;
1705 size_t ll;
1706 #ifndef _WINDOWS
1707 DIR *dirp;
1708 struct dirent *d;
1709 #else /* _WINDOWS */
1710 struct _finddata_t dbuf;
1711 char buf[_MAX_PATH + 4];
1712 long findrv;
1713 #endif /* _WINDOWS */
1714 REMDATA_S *rd = NULL;
1715 char *configdir = NULL;
1716 char *configpath = NULL;
1717 char *configcontainer = NULL;
1718 char *filesuffix = NULL;
1719 char *ret_dir = NULL;
1720
1721 dprint((9, "copy_dir_to_container(%s)", which==Public ? "Public" : which==Private ? "Private" : which==CACert ? "CACert" : "?"));
1722 smime_init();
1723
1724 srcpath[0] = '\0';
1725 dstpath[0] = '\0';
1726 file[0] = '\0';
1727 emailaddr[0] = '\0';
1728
1729 if(which == Public){
1730 configdir = ps_global->VAR_PUBLICCERT_DIR;
1731 configpath = ps_global->smime->publicpath;
1732 configcontainer = cpystr(DF_PUBLIC_CONTAINER);
1733 filesuffix = ".crt";
1734 }
1735 else if(which == Private){
1736 configdir = ps_global->VAR_PRIVATEKEY_DIR;
1737 configpath = ps_global->smime->privatepath;
1738 configcontainer = cpystr(DF_PRIVATE_CONTAINER);
1739 filesuffix = ".key";
1740 }
1741 else if(which == CACert){
1742 configdir = ps_global->VAR_CACERT_DIR;
1743 configpath = ps_global->smime->capath;
1744 configcontainer = cpystr(DF_CA_CONTAINER);
1745 filesuffix = ".crt";
1746 }
1747 container = SMHOLDERTYPE(which) == Container;
1748
1749 if(!(configdir && configdir[0])){
1750 q_status_message(SM_ORDER, 3, 3, _("Directory not defined"));
1751 return -1;
1752 }
1753
1754 if(!(configpath && configpath[0])){
1755 #ifdef APPLEKEYCHAIN
1756 if(which == Public && F_ON(F_PUBLICCERTS_IN_KEYCHAIN, ps_global)){
1757 q_status_message(SM_ORDER, 3, 3, _("Turn off the Keychain feature above first"));
1758 return -1;
1759 }
1760 #endif /* APPLEKEYCHAIN */
1761 q_status_message(SM_ORDER, 3, 3, _("Container path is not defined"));
1762 return -1;
1763 }
1764
1765 if(!(filesuffix && strlen(filesuffix) == 4)){
1766 return -1;
1767 }
1768
1769
1770 /*
1771 * If there is a legit directory to read from set up the
1772 * container file to write to.
1773 */
1774 if(smime_path(configdir, srcpath, MAXPATH) && !IS_REMOTE(srcpath)){
1775
1776 if(IS_REMOTE(configpath)){
1777 rd = rd_create_remote(RemImap, configpath, REMOTE_SMIME_SUBTYPE,
1778 NULL, "Error: ",
1779 _("Can't access remote smime configuration."));
1780 if(!rd)
1781 return -1;
1782
1783 (void) rd_read_metadata(rd);
1784
1785 if(rd->access == MaybeRorW){
1786 if(rd->read_status == 'R')
1787 rd->access = ReadOnly;
1788 else
1789 rd->access = ReadWrite;
1790 }
1791
1792 if(rd->access != NoExists){
1793
1794 rd_check_remvalid(rd, 1L);
1795
1796 /*
1797 * If the cached info says it is readonly but
1798 * it looks like it's been fixed now, change it to readwrite.
1799 */
1800 if(rd->read_status == 'R'){
1801 rd_check_readonly_access(rd);
1802 if(rd->read_status == 'W'){
1803 rd->access = ReadWrite;
1804 rd->flags |= REM_OUTOFDATE;
1805 }
1806 else
1807 rd->access = ReadOnly;
1808 }
1809 }
1810
1811 if(rd->flags & REM_OUTOFDATE){
1812 if(rd_update_local(rd) != 0){
1813
1814 dprint((1, "copy_dir_to_container: rd_update_local failed\n"));
1815 rd_close_remdata(&rd);
1816 return -1;
1817 }
1818 }
1819 else
1820 rd_open_remote(rd);
1821
1822 if(rd->access != ReadWrite || rd_remote_is_readonly(rd)){
1823 rd_close_remdata(&rd);
1824 return -1;
1825 }
1826
1827 rd->flags |= DO_REMTRIM;
1828
1829 strncpy(dstpath, rd->lf, sizeof(dstpath)-1);
1830 dstpath[sizeof(dstpath)-1] = '\0';
1831 }
1832 else{
1833 strncpy(dstpath, configpath, sizeof(dstpath)-1);
1834 dstpath[sizeof(dstpath)-1] = '\0';
1835 }
1836
1837 /*
1838 * dstpath is either the local Container file or the local cache file
1839 * for the remote Container file.
1840 */
1841 tempfile = tempfile_in_same_dir(dstpath, "az", &ret_dir);
1842 }
1843
1844 /*
1845 * If there is a legit directory to read from and a tempfile
1846 * to write to we continue.
1847 */
1848 if(tempfile && (bio_out=BIO_new_file(tempfile, "w")) != NULL){
1849
1850 if(contents != NULL){
1851 if(BIO_puts(bio_out, contents) < 0)
1852 ret = -1;
1853 }
1854 else {
1855 #ifndef _WINDOWS
1856 if((dirp = opendir(srcpath)) != NULL){
1857
1858 while((d=readdir(dirp)) && !ret){
1859 fname = d->d_name;
1860 #else /* _WINDOWS */
1861 snprintf(buf, sizeof(buf), "%s%s*.*", srcpath, (srcpath[strlen(srcpath)-1] == '\\') ? "" : "\\");
1862 buf[sizeof(buf)-1] = '\0';
1863 if((findrv = _findfirst(buf, &dbuf)) < 0)
1864 return -1;
1865
1866 do{
1867 fname = fname_to_utf8(dbuf.name);
1868 #endif /* ! _WINDOWS */
1869 if((ll=strlen(fname)) && ll > 4 && !strcmp(fname+ll-4, filesuffix)){
1870
1871 /* copy file name to temp buffer */
1872 strncpy(emailaddr, fname, sizeof(emailaddr)-1);
1873 emailaddr[sizeof(emailaddr)-1] = '\0';
1874 /* chop off suffix trailier */
1875 emailaddr[strlen(emailaddr)-4] = 0;
1876
1877 /*
1878 * This is the separator between the contents of
1879 * different files.
1880 */
1881 if(which == CACert){
1882 if(!((BIO_puts(bio_out, CACERTSTORELEADER) > 0)
1883 && (BIO_puts(bio_out, emailaddr) > 0)
1884 && (BIO_puts(bio_out, NEWLINE) > 0)))
1885 ret = -1;
1886 }
1887 else{
1888 if(!((BIO_puts(bio_out, EMAILADDRLEADER) > 0)
1889 && (BIO_puts(bio_out, emailaddr) > 0)
1890 && (BIO_puts(bio_out, NEWLINE) > 0)))
1891 ret = -1;
1892 }
1893
1894 /* read then write contents of file */
1895 build_path(file, srcpath, fname, sizeof(file));
1896 if(!(bio_in = BIO_new_file(file, "r")))
1897 ret = -1;
1898
1899 if(!ret){
1900 int good_stuff = 0;
1901
1902 while(BIO_gets(bio_in, line, sizeof(line)) > 0){
1903 if(strncmp("-----BEGIN", line, strlen("-----BEGIN")) == 0)
1904 good_stuff = 1;
1905
1906 if(good_stuff)
1907 BIO_puts(bio_out, line);
1908
1909 if(strncmp("-----END", line, strlen("-----END")) == 0)
1910 good_stuff = 0;
1911 }
1912 }
1913
1914 BIO_free(bio_in);
1915 }
1916 #ifndef _WINDOWS
1917 }
1918 closedir(dirp);
1919 }
1920 #else /* _WINDOWS */
1921 } while (_findnext(findrv, &dbuf) == 0);
1922 _findclose(findrv);
1923 #endif /* ! _WINDOWS */
1924 }
1925
1926 BIO_free(bio_out);
1927
1928 if(!ret){
1929 if(container && configpath && *configpath){
1930 strncpy(fpath, configpath, sizeof(fpath));
1931 fpath[sizeof(fpath) - 1] = '\0';
1932 }
1933 else if(ret_dir){
1934 if(strlen(dstpath) + strlen(configcontainer) + 2 < sizeof(dstpath))
1935 snprintf(fpath, sizeof(fpath), "%.*s%c%.*s",
1936 (int) strlen(dstpath), dstpath,
1937 tempfile[strlen(ret_dir)],
1938 (int) (sizeof(fpath) - strlen(dstpath) - 1), configcontainer);
1939 else
1940 ret = -1;
1941 }
1942 else ret = -1;
1943
1944 if(!ret){
1945 if(!IS_REMOTE(configpath)){
1946 if(rename_file(tempfile, fpath) < 0){
1947 q_status_message2(SM_ORDER, 3, 3,
1948 _("Can't rename %s to %s"), tempfile, fpath);
1949 ret = -1;
1950 } else q_status_message1(SM_ORDER, 3, 3,
1951 _("saved container to %s"), fpath);
1952 }
1953 else { /* if the container is remote, copy it */
1954 int e;
1955 char datebuf[200];
1956
1957 if(rd != NULL && rename_file(tempfile, rd->lf) < 0){
1958 q_status_message2(SM_ORDER, 3, 3,
1959 _("Can't rename %s to %s"), tempfile, rd->lf);
1960 ret = -1;
1961 }
1962
1963 datebuf[0] = '\0';
1964
1965 if((e = rd_update_remote(rd, datebuf)) != 0){
1966 if(e == -1){
1967 q_status_message2(SM_ORDER | SM_DING, 3, 5,
1968 _("Error opening temporary smime file %s: %s"),
1969 rd->lf, error_description(errno));
1970 dprint((1,
1971 "write_remote_smime: error opening temp file %s\n",
1972 rd->lf ? rd->lf : "?"));
1973 }
1974 else{
1975 q_status_message2(SM_ORDER | SM_DING, 3, 5,
1976 _("Error copying to %s: %s"),
1977 rd->rn, error_description(errno));
1978 dprint((1,
1979 "write_remote_smime: error copying from %s to %s\n",
1980 rd->lf ? rd->lf : "?", rd->rn ? rd->rn : "?"));
1981 }
1982
1983 q_status_message(SM_ORDER | SM_DING, 5, 5,
1984 _("Copy of smime key to remote folder failed, NOT saved remotely"));
1985 }
1986 else{
1987 rd_update_metadata(rd, datebuf);
1988 rd->read_status = 'W';
1989 }
1990
1991 rd_close_remdata(&rd);
1992 }
1993 }
1994 }
1995 }
1996
1997 if(tempfile)
1998 fs_give((void **) &tempfile);
1999
2000 if(ret_dir)
2001 fs_give((void **) &ret_dir);
2002
2003 if(configcontainer)
2004 fs_give((void **) &configcontainer);
2005
2006 return ret;
2007 }
2008
2009
2010 /*
2011 * returns 0 on success, -1 on failure
2012 */
2013 int
copy_container_to_dir(WhichCerts which)2014 copy_container_to_dir(WhichCerts which)
2015 {
2016 char path[MAXPATH+1], file[MAXPATH+1], buf[MAXPATH+1];
2017 char iobuf[4096];
2018 char *contents = NULL;
2019 char *leader = NULL;
2020 char *filesuffix = NULL;
2021 char *configdir = NULL;
2022 char *configpath = NULL;
2023 char *tempfile = NULL;
2024 char *p, *q, *line, *name, *certtext, *save_p;
2025 int len;
2026 BIO *in, *out;
2027
2028 dprint((9, "copy_container_to_dir(%s)", which==Public ? "Public" : which==Private ? "Private" : which==CACert ? "CACert" : "?"));
2029 smime_init();
2030
2031 path[0] = '\0';
2032
2033 if(which == Public){
2034 leader = EMAILADDRLEADER;
2035 contents = ps_global->smime->publiccontent;
2036 configdir = ps_global->VAR_PUBLICCERT_DIR;
2037 configpath = ps_global->smime->publicpath;
2038 filesuffix = ".crt";
2039 if(!(configpath && configpath[0])){
2040 #ifdef APPLEKEYCHAIN
2041 if(which == Public && F_ON(F_PUBLICCERTS_IN_KEYCHAIN, ps_global)){
2042 q_status_message(SM_ORDER, 3, 3, _("Turn off the Keychain feature above first"));
2043 return -1;
2044 }
2045 #endif /* APPLEKEYCHAIN */
2046 q_status_message(SM_ORDER, 3, 3, _("Container path is not defined"));
2047 return -1;
2048 }
2049
2050 fs_give((void **) &ps_global->smime->publicpath);
2051
2052 path[0] = '\0';
2053 if(!(smime_path(ps_global->VAR_PUBLICCERT_DIR, path, MAXPATH)
2054 && !IS_REMOTE(path))){
2055 q_status_message(SM_ORDER, 3, 3, _("Directory is not defined"));
2056 return -1;
2057 }
2058
2059 if(can_access(path, ACCESS_EXISTS)){
2060 if(our_mkpath(path, 0700)){
2061 q_status_message1(SM_ORDER, 3, 3, _("Can't create directory %s"), path);
2062 return -1;
2063 }
2064 }
2065
2066 ps_global->smime->publicpath = cpystr(path);
2067 configpath = ps_global->smime->publicpath;
2068 }
2069 else if(which == Private){
2070 leader = EMAILADDRLEADER;
2071 contents = ps_global->smime->privatecontent;
2072 configdir = ps_global->VAR_PRIVATEKEY_DIR;
2073 configpath = ps_global->smime->privatepath;
2074 filesuffix = ".key";
2075 if(!(configpath && configpath[0])){
2076 q_status_message(SM_ORDER, 3, 3, _("Container path is not defined"));
2077 return -1;
2078 }
2079
2080 fs_give((void **) &ps_global->smime->privatepath);
2081
2082 path[0] = '\0';
2083 if(!(smime_path(ps_global->VAR_PRIVATEKEY_DIR, path, MAXPATH)
2084 && !IS_REMOTE(path))){
2085 q_status_message(SM_ORDER, 3, 3, _("Directory is not defined"));
2086 return -1;
2087 }
2088
2089 if(can_access(path, ACCESS_EXISTS)){
2090 if(our_mkpath(path, 0700)){
2091 q_status_message1(SM_ORDER, 3, 3, _("Can't create directory %s"), path);
2092 return -1;
2093 }
2094 }
2095
2096 ps_global->smime->privatepath = cpystr(path);
2097 configpath = ps_global->smime->privatepath;
2098 }
2099 else if(which == CACert){
2100 leader = CACERTSTORELEADER;
2101 contents = ps_global->smime->cacontent;
2102 configdir = ps_global->VAR_CACERT_DIR;
2103 configpath = ps_global->smime->capath;
2104 filesuffix = ".crt";
2105 if(!(configpath && configpath[0])){
2106 q_status_message(SM_ORDER, 3, 3, _("Container path is not defined"));
2107 return -1;
2108 }
2109
2110 fs_give((void **) &ps_global->smime->capath);
2111
2112 path[0] = '\0';
2113 if(!(smime_path(ps_global->VAR_CACERT_DIR, path, MAXPATH)
2114 && !IS_REMOTE(path))){
2115 q_status_message(SM_ORDER, 3, 3, _("Directory is not defined"));
2116 return -1;
2117 }
2118
2119 if(can_access(path, ACCESS_EXISTS)){
2120 if(our_mkpath(path, 0700)){
2121 q_status_message1(SM_ORDER, 3, 3, _("Can't create directory %s"), path);
2122 return -1;
2123 }
2124 }
2125
2126 ps_global->smime->capath = cpystr(path);
2127 configpath = ps_global->smime->capath;
2128 }
2129
2130 if(!(configdir && configdir[0])){
2131 q_status_message(SM_ORDER, 3, 3, _("Directory not defined"));
2132 return -1;
2133 }
2134
2135 if(!(configpath && configpath[0])){
2136 q_status_message(SM_ORDER, 3, 3, _("Container path is not defined"));
2137 return -1;
2138 }
2139
2140 if(!(filesuffix && strlen(filesuffix) == 4)){
2141 return -1;
2142 }
2143
2144
2145 if(contents && *contents){
2146 for(p = contents; *p != '\0';){
2147 line = p;
2148
2149 while(*p && *p != '\n')
2150 p++;
2151
2152 save_p = NULL;
2153 if(*p == '\n'){
2154 save_p = p;
2155 *p++ = '\0';
2156 }
2157
2158 if(strncmp(leader, line, strlen(leader)) == 0){
2159 name = line + strlen(leader);
2160 certtext = p;
2161 if(strncmp("-----BEGIN", certtext, strlen("-----BEGIN")) == 0){
2162 if((q = strstr(certtext, leader)) != NULL){
2163 p = q;
2164 }
2165 else{ /* end of file */
2166 q = certtext + strlen(certtext);
2167 p = q;
2168 }
2169
2170 strncpy(buf, name, sizeof(buf)-5);
2171 buf[sizeof(buf)-5] = '\0';
2172 strncat(buf, filesuffix, 5);
2173 build_path(file, configpath, buf, sizeof(file));
2174
2175 in = BIO_new_mem_buf(certtext, q-certtext);
2176 if(in){
2177 tempfile = tempfile_in_same_dir(file, "az", NULL);
2178 out = NULL;
2179 if(tempfile)
2180 out = BIO_new_file(tempfile, "w");
2181
2182 if(out){
2183 while((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0)
2184 BIO_write(out, iobuf, len);
2185
2186 BIO_free(out);
2187
2188 if(rename_file(tempfile, file) < 0){
2189 q_status_message2(SM_ORDER, 3, 3,
2190 _("Can't rename %s to %s"),
2191 tempfile, file);
2192 return -1;
2193 }
2194
2195 fs_give((void **) &tempfile);
2196 }
2197
2198 BIO_free(in);
2199 }
2200 }
2201 }
2202
2203 if(save_p)
2204 *save_p = '\n';
2205 }
2206 }
2207
2208 return 0;
2209 }
2210
2211
2212 #ifdef APPLEKEYCHAIN
2213
2214 int
copy_publiccert_container_to_keychain(void)2215 copy_publiccert_container_to_keychain(void)
2216 {
2217 /* NOT IMPLEMNTED */
2218 return -1;
2219 }
2220
2221 int
copy_publiccert_keychain_to_container(void)2222 copy_publiccert_keychain_to_container(void)
2223 {
2224 /* NOT IMPLEMNTED */
2225 return -1;
2226 }
2227
2228 #endif /* APPLEKEYCHAIN */
2229
2230
2231 /*
2232 * Get a pointer to a string describing the most recent OpenSSL error.
2233 * It's statically allocated, so don't change or attempt to free it.
2234 */
2235 static const char *
openssl_error_string(void)2236 openssl_error_string(void)
2237 {
2238 char *errs;
2239 const char *data = NULL;
2240 long errn;
2241
2242 errn = ERR_peek_error_line_data(NULL, NULL, &data, NULL);
2243 errs = (char*) ERR_reason_error_string(errn);
2244
2245 if(errs)
2246 return errs;
2247 else if(data)
2248 return data;
2249
2250 return "unknown error";
2251 }
2252
2253
2254 /* Return true if the body looks like a PKCS7 object */
2255 int
is_pkcs7_body(BODY * body)2256 is_pkcs7_body(BODY *body)
2257 {
2258 int result;
2259
2260 result = body->type==TYPEAPPLICATION &&
2261 body->subtype &&
2262 (strucmp(body->subtype,"pkcs7-mime")==0 ||
2263 strucmp(body->subtype,"x-pkcs7-mime")==0 ||
2264 strucmp(body->subtype,"pkcs7-signature")==0 ||
2265 strucmp(body->subtype,"x-pkcs7-signature")==0);
2266
2267 return result;
2268 }
2269
2270
2271 /*
2272 * Recursively stash a pointer to the decrypted data in our
2273 * manufactured body.
2274 * parameters: type: call of type 1, save the base and header for multipart messages
2275 call of type 0, do not save the base and header for multipart messages
2276 */
2277 static void
create_local_cache(char * h,char * base,BODY * b,int type)2278 create_local_cache(char *h, char *base, BODY *b, int type)
2279 {
2280 if(b->type==TYPEMULTIPART){
2281 PART *p;
2282
2283 if(type == 1){
2284 cpytxt(&b->mime.text, h+b->mime.offset, b->mime.text.size);
2285 cpytxt(&b->contents.text, base + b->contents.offset, b->size.bytes);
2286 } else if(type == 0){
2287 /*
2288 * We don't really want to copy the real body contents. It shouldn't be
2289 * used, and in the case of a message with attachments, we'll be
2290 * duplicating the files multiple times.
2291 */
2292 cpytxt(&b->contents.text, "BODY UNAVAILABLE", 16);
2293
2294 for(p=b->nested.part; p; p=p->next)
2295 create_local_cache(h, base, (BODY *) p, type);
2296 }
2297 }
2298 else{
2299 cpytxt(&b->mime.text, h+b->mime.offset, b->mime.text.size);
2300 cpytxt(&b->contents.text, base + b->contents.offset, b->size.bytes);
2301 }
2302 }
2303
2304
2305 static long
rfc822_output_func(void * b,char * string)2306 rfc822_output_func(void *b, char *string)
2307 {
2308 BIO *bio = (BIO *) b;
2309
2310 return(string ? *string ? (BIO_puts(bio, string) > 0 ? 1L : 0L)
2311 : (BIO_puts(bio, string) >= 0 ? 1L : 0L)
2312 : 0L);
2313 }
2314
2315
2316 /*
2317 * Attempt to load the private key for the given PERSONAL_CERT.
2318 * This sets the appropriate passphrase globals in order to
2319 * interact with the user correctly.
2320 */
2321 static int
load_private_key(PERSONAL_CERT * pcert)2322 load_private_key(PERSONAL_CERT *pcert)
2323 {
2324 if(!pcert->key){
2325
2326 /* Try empty password by default */
2327 char *password = "";
2328
2329 if(ps_global->smime
2330 && (ps_global->smime->need_passphrase
2331 || ps_global->smime->entered_passphrase)){
2332 /* We've already been in here and discovered we need a different password */
2333
2334 if(ps_global->smime->entered_passphrase)
2335 password = (char *) ps_global->smime->passphrase; /* already entered */
2336 else
2337 return 0;
2338 }
2339
2340 ERR_clear_error();
2341
2342 if(!(pcert->key = load_key(pcert, password, SM_NORMALCERT))){
2343 long err = ERR_get_error();
2344
2345 /* Couldn't load key... */
2346
2347 if(ps_global->smime && ps_global->smime->entered_passphrase){
2348
2349 /* The user got the password wrong maybe? */
2350
2351 if((ERR_GET_LIB(err)==ERR_LIB_EVP && ERR_GET_REASON(err)==EVP_R_BAD_DECRYPT) ||
2352 (ERR_GET_LIB(err)==ERR_LIB_PEM && ERR_GET_REASON(err)==PEM_R_BAD_DECRYPT))
2353 q_status_message(SM_ORDER | SM_DING, 4, 4, _("Incorrect passphrase"));
2354 else
2355 q_status_message1(SM_ORDER, 4, 4, _("Couldn't read key: %s"),(char*)openssl_error_string());
2356
2357 /* This passphrase is no good; forget it */
2358 ps_global->smime->entered_passphrase = 0;
2359 }
2360
2361 if(ps_global->smime){
2362 /* Indicate to the UI that we need re-entry (see mailcmd.c:process_cmd())*/
2363 ps_global->smime->need_passphrase = 1;
2364 if(ps_global->smime->passphrase_emailaddr){
2365 int i;
2366 for(i = 0; ps_global->smime->passphrase_emailaddr[i] != NULL; i++)
2367 fs_give((void **)&ps_global->smime->passphrase_emailaddr[i]);
2368 fs_give((void **) ps_global->smime->passphrase_emailaddr);
2369 }
2370
2371 ps_global->smime->passphrase_emailaddr = get_x509_subject_email(pcert->cert);
2372 }
2373
2374 return 0;
2375 }
2376 else{
2377 /* This key will be cached, so we won't be called again */
2378 if(ps_global->smime){
2379 ps_global->smime->entered_passphrase = 0;
2380 ps_global->smime->need_passphrase = 0;
2381 }
2382 }
2383
2384 return 1;
2385 }
2386
2387 return 0;
2388 }
2389
2390
2391 static void
setup_pkcs7_body_for_signature(BODY * b,char * description,char * type,char * filename,char * smime_type)2392 setup_pkcs7_body_for_signature(BODY *b, char *description, char *type, char *filename, char *smime_type)
2393 {
2394 b->type = TYPEAPPLICATION;
2395 b->subtype = cpystr(type);
2396 b->encoding = ENCBINARY;
2397 b->description = cpystr(description);
2398
2399 b->disposition.type = cpystr("attachment");
2400 set_parameter(&b->disposition.parameter, "filename", filename);
2401
2402 set_parameter(&b->parameter, "name", filename);
2403 if(smime_type && *smime_type)
2404 set_parameter(&b->parameter, "smime-type", smime_type);
2405 }
2406
2407
2408 /*
2409 * Look for a personal certificate matching the
2410 * given address
2411 */
2412 PERSONAL_CERT *
match_personal_cert_to_email(ADDRESS * a)2413 match_personal_cert_to_email(ADDRESS *a)
2414 {
2415 PERSONAL_CERT *pcert = NULL;
2416 char buf[MAXPATH];
2417 char **email;
2418 int i, done;
2419
2420 if(!a || !a->mailbox || !a->host)
2421 return NULL;
2422
2423 snprintf(buf, sizeof(buf), "%s@%s", a->mailbox, a->host);
2424
2425 if(ps_global->smime){
2426 for(pcert=(PERSONAL_CERT *) ps_global->smime->personal_certs;
2427 pcert;
2428 pcert=pcert->next){
2429
2430 if(!pcert->cert)
2431 continue;
2432
2433 email = get_x509_subject_email(pcert->cert);
2434
2435 done = 0;
2436 if(email != NULL){
2437 for(i = 0; email[i] && strucmp(email[i], buf) != 0; i++);
2438 if(email[i] != NULL) done++;
2439 for(i = 0; email[i] != NULL; i++)
2440 fs_give((void **)&email[i]);
2441 fs_give((void **)email);
2442 }
2443
2444 if(done > 0)
2445 break;
2446 }
2447 }
2448
2449 return pcert;
2450 }
2451
2452
2453 /*
2454 * Look for a personal certificate matching the from
2455 * (or reply_to? in the given envelope)
2456 */
2457 PERSONAL_CERT *
match_personal_cert(ENVELOPE * env)2458 match_personal_cert(ENVELOPE *env)
2459 {
2460 PERSONAL_CERT *pcert;
2461
2462 pcert = match_personal_cert_to_email(env->reply_to);
2463 if(!pcert)
2464 pcert = match_personal_cert_to_email(env->from);
2465
2466 return pcert;
2467 }
2468
2469
2470 /*
2471 * Flatten the given body into its MIME representation.
2472 * Return the result in a BIO.
2473 */
2474 static BIO *
body_to_bio(BODY * body)2475 body_to_bio(BODY *body)
2476 {
2477 BIO *bio = NULL;
2478 int len;
2479
2480 bio = BIO_new(BIO_s_mem());
2481 if(!bio)
2482 return NULL;
2483
2484 pine_encode_body(body); /* this attaches random boundary strings to multiparts */
2485 pine_write_body_header(body, rfc822_output_func, bio);
2486 pine_rfc822_output_body(body, rfc822_output_func, bio);
2487
2488 /*
2489 * Now need to truncate by two characters since the above
2490 * appends CRLF.
2491 */
2492 if((len=BIO_ctrl_pending(bio)) > 1){
2493 BUF_MEM *biobuf = NULL;
2494
2495 /* this code used to truncate without closing the bio, and
2496 then resetting the memory, causing non validation in
2497 signatures. Fix contributed by Bernd Edlinger.
2498 */
2499 BIO_get_mem_ptr(bio, &biobuf);
2500 BIO_set_close(bio, BIO_NOCLOSE);
2501 BUF_MEM_grow(biobuf, len-2); /* remove CRLF */
2502 BIO_set_mem_buf(bio, biobuf, BIO_CLOSE);
2503 }
2504
2505 return bio;
2506 }
2507
2508
2509 static BIO *
bio_from_store(STORE_S * store)2510 bio_from_store(STORE_S *store)
2511 {
2512 BIO *ret = NULL;
2513
2514 if(store && store->src == BioType && store->txt){
2515 ret = (BIO *) store->txt;
2516 }
2517
2518 return(ret);
2519 }
2520
2521 /*
2522 * Encrypt file; given a path (char *) fp, replace the file
2523 * by an encrypted version of it. If (char *) text is not null, then
2524 * replace the text of (char *) fp by the encrypted version of (char *) text.
2525 * certpath is the FULL path to the file containing the certificate used for
2526 * encryption.
2527 * return value: 0 - failed to encrypt; 1 - success!
2528 */
2529 int
encrypt_file(char * fp,char * text,PERSONAL_CERT * pc)2530 encrypt_file(char *fp, char *text, PERSONAL_CERT *pc)
2531 {
2532 const EVP_CIPHER *cipher = NULL;
2533 STACK_OF(X509) *encerts = NULL;
2534 BIO *out = NULL;
2535 PKCS7 *p7 = NULL;
2536 int rv = 0;
2537
2538 if(pc == NULL)
2539 return 0;
2540
2541 cipher = EVP_aes_256_cbc();
2542 encerts = sk_X509_new_null();
2543
2544 sk_X509_push(encerts, X509_dup(pc->cert));
2545
2546 if(text){
2547 if((out = BIO_new(BIO_s_mem())) != NULL){
2548 (void) BIO_reset(out);
2549 BIO_puts(out, text);
2550 }
2551 }
2552 else if((out = BIO_new_file(fp, "rb")) != NULL)
2553 BIO_read_filename(out, fp);
2554
2555 if((p7 = PKCS7_encrypt(encerts, out, cipher, 0)) != NULL){
2556 BIO_set_close(out, BIO_CLOSE);
2557 BIO_free(out);
2558 if((out = BIO_new_file(fp, "w")) != NULL){
2559 BIO_reset(out);
2560 rv = PEM_write_bio_PKCS7(out, p7);
2561 BIO_flush(out);
2562 }
2563 }
2564
2565 if(out != NULL)
2566 BIO_free(out);
2567 PKCS7_free(p7);
2568 sk_X509_pop_free(encerts, X509_free);
2569
2570 return rv;
2571 }
2572
2573 /*
2574 * Encrypt a message on the way out. Called from call_mailer in send.c
2575 * The body may be reallocated.
2576 */
2577 int
encrypt_outgoing_message(METAENV * header,BODY ** bodyP)2578 encrypt_outgoing_message(METAENV *header, BODY **bodyP)
2579 {
2580 PKCS7 *p7 = NULL;
2581 BIO *in = NULL;
2582 BIO *out = NULL;
2583 const EVP_CIPHER *cipher = NULL;
2584 STACK_OF(X509) *encerts = NULL;
2585 STORE_S *outs = NULL;
2586 PINEFIELD *pf;
2587 ADDRESS *a;
2588 BODY *body = *bodyP;
2589 BODY *newBody = NULL;
2590 int result = 0;
2591 X509 *cert;
2592 char buf[MAXPATH];
2593
2594 dprint((9, "encrypt_outgoing_message()"));
2595 smime_init();
2596
2597 cipher = EVP_aes_256_cbc();
2598
2599 encerts = sk_X509_new_null();
2600
2601 /* Look for a certificate for each of the recipients */
2602 for(pf = header->local; pf && pf->name; pf = pf->next)
2603 if(pf->type == Address && pf->rcptto && pf->addr && *pf->addr){
2604 for(a=*pf->addr; a; a=a->next){
2605 snprintf(buf, sizeof(buf), "%s@%s", a->mailbox, a->host);
2606
2607 if((cert = get_cert_for(buf, Public, 1)) != NULL){
2608 sk_X509_push(encerts,cert);
2609 }else{
2610 q_status_message2(SM_ORDER, 1, 1,
2611 _("Unable to find certificate for <%s@%s>"),
2612 a->mailbox, a->host);
2613 goto end;
2614 }
2615 }
2616 }
2617
2618 /* add the sender's certificate so that they can decrypt the message too */
2619 for(a=header->env->from; a ; a = a->next){
2620 snprintf(buf, sizeof(buf), "%s@%s", a->mailbox, a->host);
2621
2622 if((cert = get_cert_for(buf, Public, 1)) != NULL
2623 && sk_X509_find(encerts, cert) == -1)
2624 sk_X509_push(encerts,cert);
2625 }
2626
2627 in = body_to_bio(body);
2628
2629 p7 = PKCS7_encrypt(encerts, in, cipher, 0);
2630
2631 outs = so_get(BioType, NULL, EDIT_ACCESS);
2632 out = bio_from_store(outs);
2633
2634 i2d_PKCS7_bio(out, p7);
2635 (void) BIO_flush(out);
2636
2637 so_seek(outs, 0, SEEK_SET);
2638
2639 newBody = mail_newbody();
2640
2641 newBody->type = TYPEAPPLICATION;
2642 newBody->subtype = cpystr("pkcs7-mime");
2643 newBody->encoding = ENCBINARY;
2644
2645 newBody->disposition.type = cpystr("attachment");
2646 set_parameter(&newBody->disposition.parameter, "filename", "smime.p7m");
2647
2648 newBody->description = cpystr("S/MIME Encrypted Message");
2649 set_parameter(&newBody->parameter, "smime-type", "enveloped-data");
2650 set_parameter(&newBody->parameter, "name", "smime.p7m");
2651
2652 newBody->contents.text.data = (unsigned char *) outs;
2653
2654 *bodyP = newBody;
2655
2656 result = 1;
2657
2658 end:
2659
2660 BIO_free(in);
2661 PKCS7_free(p7);
2662 sk_X509_pop_free(encerts, X509_free);
2663
2664 dprint((9, "encrypt_outgoing_message returns %d", result));
2665 return result;
2666 }
2667
2668
2669 /*
2670 Get (and decode) the body of the given section of msg
2671 */
2672 static STORE_S*
get_part_contents(long msgno,const char * section)2673 get_part_contents(long msgno, const char *section)
2674 {
2675 long len;
2676 gf_io_t pc;
2677 STORE_S *store = NULL;
2678 char *err;
2679
2680 store = so_get(CharStar, NULL, EDIT_ACCESS);
2681 if(store){
2682 gf_set_so_writec(&pc,store);
2683
2684 err = detach(ps_global->mail_stream, msgno, (char*) section, 0L, &len, pc, NULL, 0L);
2685
2686 gf_clear_so_writec(store);
2687
2688 so_seek(store, 0, SEEK_SET);
2689
2690 if(err)
2691 so_give(&store);
2692 }
2693
2694 return store;
2695 }
2696
2697
2698 static PKCS7 *
get_pkcs7_from_part(long msgno,const char * section)2699 get_pkcs7_from_part(long msgno,const char *section)
2700 {
2701 STORE_S *store = NULL;
2702 PKCS7 *p7 = NULL;
2703 BIO *in = NULL;
2704
2705 store = get_part_contents(msgno, section);
2706
2707 if(store){
2708 if(store->src == CharStar){
2709 int len;
2710
2711 /*
2712 * We're reaching inside the STORE_S structure. We should
2713 * probably have a way to get the length, instead.
2714 */
2715 len = (int) (store->eod - store->dp);
2716 in = BIO_new_mem_buf(store->txt, len);
2717 }
2718 else{ /* just copy it */
2719 unsigned char c;
2720
2721 in = BIO_new(BIO_s_mem());
2722 (void) BIO_reset(in);
2723
2724 so_seek(store, 0L, 0);
2725 while(so_readc(&c, store)){
2726 BIO_write(in, &c, 1);
2727 }
2728 }
2729
2730 if(in){
2731 /* dump_bio_to_file(in, "/tmp/decoded-signature"); */
2732 if((p7=d2i_PKCS7_bio(in,NULL)) == NULL){
2733 /* error */
2734 }
2735
2736 BIO_free(in);
2737 }
2738
2739 so_give(&store);
2740 }
2741
2742 return p7;
2743 }
2744
2745 int
same_cert(X509 * x,X509 * cert)2746 same_cert(X509 *x, X509 *cert)
2747 {
2748 char bufcert[256], bufx[256];
2749 int rv = 0;
2750
2751 get_fingerprint(cert, EVP_md5(), bufcert, sizeof(bufcert), ":");
2752 get_fingerprint(x, EVP_md5(), bufx, sizeof(bufx), ":");
2753 if(strcmp(bufx, bufcert) == 0)
2754 rv = 1;
2755
2756 return rv;
2757 }
2758
2759
2760 /* extract and save certificates from a PKCS7 package.
2761 * Return value:
2762 * 0 - no errors. Either the certificate was in public/
2763 * or we could save it there.
2764 * < 0 - the certificate was not in public/ and the user
2765 * did not save it there.
2766 */
2767
2768 int
smime_extract_and_save_cert(PKCS7 * p7)2769 smime_extract_and_save_cert(PKCS7 *p7)
2770 {
2771 STACK_OF(X509) *signers;
2772 X509 *x, *cert;
2773 char **email;
2774 int i, j, rv, already_saved;
2775
2776 /* any signers for this message? */
2777 if((signers = PKCS7_get0_signers(p7, NULL, 0)) == NULL)
2778 return -1;
2779
2780 rv = 0;
2781 for(i = 0; i < sk_X509_num(signers); i++){
2782 if((x = sk_X509_value(signers,i)) == NULL)
2783 continue;
2784
2785 if((email = get_x509_subject_email(x)) != NULL){
2786 for(j = 0; email[j] != NULL; j++){
2787 already_saved = 0;
2788 /* check if we have the certificate for this address */
2789 cert = get_cert_for(email[j], Public, 1);
2790 /* if we have one, check if it is the one packaged */
2791 if(cert != NULL){
2792 already_saved = same_cert(x, cert);
2793 X509_free(cert);
2794 }
2795
2796 /* if not saved, try to save it */
2797 if(already_saved == 0
2798 && (*pith_smime_confirm_save)(email[j]) == 1){
2799 save_cert_for(email[j], x, Public);
2800 if(ps_global->smime->publiccertlist) /* renew store */
2801 free_certlist(&ps_global->smime->publiccertlist);
2802 }
2803
2804 /* check if it got saved */
2805 cert = get_cert_for(email[j], Public, 1);
2806 /* if saved, all is good */
2807 if(cert != NULL)
2808 X509_free(cert);
2809 else /* else, we do not have this certificate saved */
2810 rv += -1;
2811
2812 fs_give((void **) &email[j]);
2813 }
2814 fs_give((void **) email);
2815 }
2816 }
2817 sk_X509_free(signers);
2818
2819 return rv;
2820 }
2821
2822 /*
2823 * Try to verify a signature.
2824 *
2825 * p7 - the pkcs7 object to verify
2826 * in - the plain data to verify (NULL if not detached)
2827 * out - BIO to which to write the opaque data
2828 * silent - if non zero, do not print errors, only print success.
2829 */
2830 static int
do_signature_verify(PKCS7 * p7,BIO * in,BIO * out,int silent)2831 do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent)
2832 {
2833 STACK_OF(X509) *otherCerts = NULL;
2834 CertList *cl;
2835 int result, flags;
2836 const char *data;
2837 long err;
2838
2839 if(!s_cert_store){
2840 if(!silent) q_status_message(SM_ORDER | SM_DING, 2, 2,
2841 _("Couldn't verify S/MIME signature: No CA Certs were loaded"));
2842
2843 return -1;
2844 }
2845
2846 flags = F_ON(F_USE_CERT_STORE_ONLY, ps_global) ? PKCS7_NOINTERN : 0;
2847
2848 if(ps_global->smime->publiccertlist == NULL){
2849 renew_cert_data(&ps_global->smime->publiccertlist, Public);
2850 for(cl = ps_global->smime->publiccertlist; cl ; cl = cl->next){
2851 if(cl->x509_cert == NULL){
2852 char *s = strrchr(cl->name, '.');
2853 *s = '\0';
2854 cl->x509_cert = get_cert_for(cl->name, Public, 1);
2855 *s = '.';
2856 }
2857 }
2858 }
2859
2860 if(ps_global->smime->publiccertlist){
2861 otherCerts = sk_X509_new_null();
2862 for(cl = ps_global->smime->publiccertlist; cl ; cl = cl->next)
2863 if(cl->x509_cert != NULL)
2864 sk_X509_push(otherCerts, X509_dup(cl->x509_cert));
2865 }
2866
2867 result = PKCS7_verify(p7, otherCerts, s_cert_store, in, out, flags);
2868
2869 if(result){
2870 q_status_message(SM_ORDER, 1, 1, _("S/MIME signature verified ok"));
2871 }
2872 else{
2873 err = ERR_peek_error_line_data(NULL, NULL, &data, NULL);
2874
2875 if(out && err==ERR_PACK(ERR_LIB_PKCS7,PKCS7_F_PKCS7_VERIFY,PKCS7_R_CERTIFICATE_VERIFY_ERROR)){
2876
2877 /*
2878 * verification failed due to an error in verifying a certificate.
2879 * Just write the "out" BIO, and leave. Of course let the user
2880 * know about this. Make two more attempts to get the data out. The
2881 * last one should succeed. In any case, let the user know why it
2882 * failed.
2883 */
2884 if(PKCS7_verify(p7, otherCerts, s_cert_store, in, out, PKCS7_NOVERIFY) == 0)
2885 PKCS7_verify(p7, otherCerts, s_cert_store, in, out, PKCS7_NOVERIFY|PKCS7_NOSIGS);
2886 }
2887 if (!silent) q_status_message1(SM_ORDER | SM_DING, 3, 3,
2888 _("Couldn't verify S/MIME signature: %s"), (char *) openssl_error_string());
2889 }
2890
2891 sk_X509_pop_free(otherCerts, X509_free);
2892
2893 return result;
2894 }
2895
2896 /* Big comment, explaining the mess that exists out there, and how we deal
2897 with it, and also how we solve the problems that are created this way.
2898
2899 When Alpine sends a message, it constructs that message, computes the
2900 signature, but then it forgets the message it signed and reconstructs it
2901 again. Since it signs a message containing a notice about "mime aware
2902 tools", but it does not send that we do not include that in the part
2903 that is signed, and that takes care of much of the problems.
2904
2905 Another problem is what is received from the servers. All servers tested
2906 seem to transmit the message that was signed intact and Alpine can check
2907 the signature correctly. That is not a problem. The problem arises when
2908 the message includes attachments. In this case different servers send
2909 different things, so it will be up to us to figure out what is the text
2910 that was actually signed. Confused? here is the story:
2911
2912 When a message containing and attachment is sent by Alpine, UW-IMAP,
2913 Panda-IMAP, Gmail, and local reading of folders send exactly the message
2914 that was sent by Alpine, but GMX.com, Exchange, and probably other
2915 servers add a trailing \r\n in the message, so when validating the
2916 signature, these messages will not validate. There are several things
2917 that can be done.
2918
2919 1. Add a trailing \r\n to any message that contains attachments, sign that
2920 and send that. In this way, all messages will validate with all
2921 servers.
2922
2923 2. Compatibility mode: If a message has an attachment, contains a trailing
2924 \r\n and does not validate (sent by an earlier version of Alpine),
2925 remove the trailing \r\n and try to revalidate again.
2926
2927 3. We do not add \r\n to validate a message that we sent, because that
2928 would only work in Alpine, and not in any other client. That would
2929 not be a good thing to do.
2930
2931 PART II
2932
2933 Now we have to deal with encrypted and signed messages. The problem is
2934 that c-client makes all its pointers point to "on disk" content, but
2935 since we decrypted the data earlier, we have to make sure of two things.
2936 One is that we saved that data (so we do not have to decrypt it again)
2937 and second that we can use it.
2938
2939 In order to save the data we use create_local_cache, so that we do not
2940 have to redecrypt the message. Once this is saved, c-client functions will
2941 find it and send it to us in mail_fetch_mime and mail_fetch_body.
2942
2943 PART III
2944
2945 When we are trying to verify messages with detached signatures, some
2946 imap servers send incorrect information in the mail_fetch_mime call. By
2947 incorrect I mean that this is not fetched directly from the message, but
2948 it is read from the message, processed, and then the processed part is
2949 sent to us, so this text might not agree with what is in the message,
2950 and so the validation of the signature might fail. However, the good
2951 news is that the message validates if saved to a local folder. This
2952 means that if normal validation does not work we can make it work by
2953 saving the message locally and validating that. This is implemented
2954 below, and causes delay in the display of the message. I am considering
2955 at this time not to do this automatically, but wait for the user to tell
2956 us to do it for them by means of a command available in the
2957 mail_view_screen. This might help in other situations, where a message
2958 is supposed to have an attachment, but it can not be seen in the
2959 processed text. Nevertheless, at this time, this is automatic, and is
2960 causing a delay in the processing of the message, but it is validating
2961 correctly all messages.
2962
2963 PART IV
2964
2965 When the user sends a message as encrypted and signed, this code used to
2966 encrypt first, and then sign the pkcs7 body, but it turns out that some
2967 other clients can not handle these messages. While we could argue that the
2968 other clients need to improve, we will support reading messages in both
2969 ways, and will send messages using this technique; that is, signed first,
2970 encrypted second. It seems that all tested clients support this way, so it
2971 should be safe to do so.
2972 */
2973
2974 typedef struct smime_filter_s {
2975 void (*filter)();
2976 } SMIME_FILTER_S;
2977
2978 SMIME_FILTER_S sig_filter[] = {
2979 {smime_remove_trailing_crlf},
2980 {smime_remove_folding_space}
2981 };
2982
2983 #define TOTAL_FILTERS (sizeof(sig_filter)/sizeof(sig_filter[0]))
2984 #define TOTAL_SIGFLTR (1 << TOTAL_FILTERS) /* not good, keep filters to a low number */
2985
2986 void
smime_remove_trailing_crlf(char ** mimetext,unsigned long * mimelen,char ** bodytext,unsigned long * bodylen)2987 smime_remove_trailing_crlf(char **mimetext, unsigned long *mimelen,
2988 char **bodytext, unsigned long *bodylen)
2989 {
2990 if(*bodylen > 2 && !strncmp(*bodytext+*bodylen-2, "\r\n", 2))
2991 *bodylen -= 2;
2992 }
2993
2994 void
smime_remove_folding_space(char ** mimetext,unsigned long * mimelen,char ** bodytext,unsigned long * bodylen)2995 smime_remove_folding_space(char **mimetext, unsigned long *mimelen,
2996 char **bodytext, unsigned long *bodylen)
2997 {
2998 char *s = NULL, *t;
2999 unsigned long mlen = *mimelen;
3000
3001 if(*mimetext){
3002 for (s = t = *mimetext; t - *mimetext < *mimelen; ){
3003 if(*t == '\r' && *(t+1) == '\n' && (*(t+2) == '\t' || *(t+2) == ' ')){
3004 *s++ = ' ';
3005 t += 3;
3006 mlen -= 2;
3007 }
3008 else
3009 *s++ = *t++;
3010 }
3011 *mimelen = mlen;
3012 }
3013 }
3014
3015 int
smime_validate_extra_test(char * mimetext,unsigned long mimelen,char * bodytext,unsigned long bodylen,PKCS7 * p7,int nflag)3016 smime_validate_extra_test(char *mimetext, unsigned long mimelen, char *bodytext, unsigned long bodylen, PKCS7 *p7, int nflag)
3017 {
3018 int result, i, j, flag;
3019 char *mtext, *btext;
3020 unsigned long mlen, blen;
3021 BIO *in;
3022
3023 mtext = mimelen ? fs_get(mimelen+1) : NULL;
3024 btext = fs_get(bodylen+1);
3025 result = 0;
3026
3027 flag = 1; /* silence all failures */
3028 for(i = 1; result == 0 && i < TOTAL_SIGFLTR; i++){
3029 if((in = BIO_new(BIO_s_mem())) == NULL)
3030 return -1;
3031
3032 (void) BIO_reset(in);
3033
3034 if(i+1 == TOTAL_SIGFLTR)
3035 flag = nflag;
3036
3037 if(mimelen)
3038 strncpy(mtext, mimetext, mlen = mimelen);
3039 strncpy(btext, bodytext, blen = bodylen);
3040 for(j = 0; j < TOTAL_FILTERS; j++)
3041 if((i >> j) & 1)
3042 (sig_filter[j].filter)(&mtext, &mlen, &btext, &blen);
3043 if(mtext != NULL)
3044 BIO_write(in, mtext, mlen);
3045 BIO_write(in, btext, blen);
3046 result = do_signature_verify(p7, in, NULL, flag);
3047 BIO_free(in);
3048 }
3049 if(mtext) fs_give((void **)&mtext);
3050 if(btext) fs_give((void **)&btext);
3051 return result;
3052 }
3053
3054 /*
3055 * Given a multipart body of type multipart/signed, attempt to verify it.
3056 * Returns non-zero if the body was changed.
3057 */
3058 static int
do_detached_signature_verify(BODY * b,long msgno,char * section)3059 do_detached_signature_verify(BODY *b, long msgno, char *section)
3060 {
3061 PKCS7 *p7 = NULL;
3062 BIO *in = NULL;
3063 PART *p;
3064 int result, modified_the_body = 0;
3065 int flag; /* 1 silent, 0 not silent */
3066 unsigned long mimelen, bodylen;
3067 char newSec[100], *mimetext, *bodytext;
3068 char *what_we_did;
3069 SIZEDTEXT *st;
3070
3071 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"));
3072
3073 smime_init();
3074 mimetext = bodytext = NULL;
3075
3076 /* if it was signed and then encrypted, use the decrypted text
3077 * to check the validity of the signature
3078 */
3079 if(b->sparep){
3080 if(get_body_sparep_type(b->sparep) == SizedText){
3081 /* bodytext includes mimetext */
3082 st = (SIZEDTEXT *) get_body_sparep_data(b->sparep);
3083 bodytext = (char *) st->data;
3084 bodylen = st->size;
3085 mimetext = NULL;
3086 mimelen = 0L;
3087 }
3088 }
3089 else{
3090 snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : "");
3091 mimetext = mail_fetch_mime(ps_global->mail_stream, msgno, (char*) newSec, &mimelen, 0);
3092 if(mimetext)
3093 bodytext = mail_fetch_body (ps_global->mail_stream, msgno, (char*) newSec, &bodylen, 0);
3094
3095 if(mimetext == NULL || bodytext == NULL)
3096 return modified_the_body;
3097 }
3098
3099 snprintf(newSec, sizeof(newSec), "%s%s2", section ? section : "", (section && *section) ? "." : "");
3100
3101 if((p7 = get_pkcs7_from_part(msgno, newSec)) == NULL
3102 || (in = BIO_new(BIO_s_mem())) == NULL)
3103 return modified_the_body;
3104
3105 (void) BIO_reset(in);
3106 if(mimetext != NULL)
3107 BIO_write(in, mimetext, mimelen);
3108 BIO_write(in, bodytext, bodylen);
3109
3110 smime_extract_and_save_cert(p7);
3111
3112 if((result = do_signature_verify(p7, in, NULL, 1)) == 0){
3113 flag = (mimelen == 0 || !IS_REMOTE(ps_global->mail_stream->mailbox))
3114 ? 0 : 1;
3115 result = smime_validate_extra_test(mimetext, mimelen, bodytext, bodylen, p7, flag);
3116 if(result < 0)
3117 return modified_the_body;
3118 if(result == 0
3119 && mimelen > 0 /* do not do this for encrypted messages */
3120 && IS_REMOTE(ps_global->mail_stream->mailbox)){
3121 char *fetch;
3122 unsigned long hlen, tlen;
3123 STORE_S *msg_so;
3124
3125 BIO_free(in);
3126 if((in = BIO_new(BIO_s_mem())) != NULL
3127 && (fetch = mail_fetch_header(ps_global->mail_stream, msgno, NULL,
3128 NULL, &hlen, FT_PEEK)) != NULL
3129 && (msg_so = so_get(CharStar, NULL, WRITE_ACCESS)) != NULL
3130 && so_nputs(msg_so, fetch, (long) hlen)
3131 && (fetch = pine_mail_fetch_text(ps_global->mail_stream, msgno, NULL,
3132 &tlen, FT_PEEK)) != NULL
3133 && so_nputs(msg_so, fetch, tlen)){
3134 STRING bs;
3135 char *h = (char *) so_text(msg_so);
3136 char *bstart = strstr(h, "\r\n\r\n");
3137 ENVELOPE *env;
3138 BODY *body, *tmpB;
3139
3140 bstart += 4;
3141 INIT(&bs, mail_string, bstart, tlen);
3142 rfc822_parse_msg_full(&env, &body, h, bstart-h-4, &bs, BADHOST, 0, 0);
3143 mail_free_envelope(&env);
3144
3145 mail_free_body_part(&b->nested.part);
3146 tmpB = mail_body_section(body, (unsigned char *) section);
3147 if(MIME_MSG(tmpB->type, tmpB->subtype))
3148 b->nested.part = tmpB->nested.msg->body->nested.part;
3149 else
3150 b->nested.part = tmpB->nested.part;
3151 create_local_cache(bstart, bstart, &b->nested.part->body, 1);
3152 modified_the_body = 1;
3153
3154 snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : "");
3155
3156 mimetext = mail_fetch_mime(ps_global->mail_stream, msgno, (char*) newSec, &mimelen, 0);
3157
3158 if(mimetext)
3159 bodytext = mail_fetch_body (ps_global->mail_stream, msgno, (char*) newSec, &bodylen, 0);
3160
3161 if (mimetext == NULL || bodytext == NULL)
3162 return modified_the_body;
3163
3164 snprintf(newSec, sizeof(newSec), "%s%s2", section ? section : "", (section && *section) ? "." : "");
3165
3166 if((p7 = get_pkcs7_from_part(msgno, newSec)) == NULL)
3167 return modified_the_body;
3168
3169 (void) BIO_reset(in);
3170 BIO_write(in, mimetext, mimelen);
3171 BIO_write(in, bodytext, bodylen);
3172 so_give(&msg_so);
3173
3174 if((result = do_signature_verify(p7, in, NULL, 1)) == 0){
3175 result = smime_validate_extra_test(mimetext, mimelen, bodytext, bodylen, p7, 0);
3176 if(result < 0)
3177 return modified_the_body;
3178 }
3179 }
3180 }
3181 }
3182
3183 BIO_free(in);
3184 if(b->subtype)
3185 fs_give((void**) &b->subtype);
3186
3187 b->subtype = cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE);
3188 b->encoding = ENC8BIT;
3189
3190 if(b->description)
3191 fs_give ((void**) &b->description);
3192
3193 what_we_did = result ? _("This message was cryptographically signed.") :
3194 _("This message was cryptographically signed but the signature could not be verified.");
3195
3196 b->description = cpystr(what_we_did);
3197
3198 b->sparep = create_body_sparep(P7Type, p7);
3199
3200 p = b->nested.part;
3201
3202 /* p is signed plaintext */
3203 if(p && p->next)
3204 mail_free_body_part(&p->next); /* hide the pkcs7 from the viewer */
3205
3206 modified_the_body = 1;
3207
3208 return modified_the_body;
3209 }
3210
3211
3212 PERSONAL_CERT *
find_certificate_matching_recip_info(PKCS7_RECIP_INFO * ri)3213 find_certificate_matching_recip_info(PKCS7_RECIP_INFO *ri)
3214 {
3215 PERSONAL_CERT *x = NULL;
3216
3217 if(ps_global->smime){
3218 for(x = (PERSONAL_CERT *) ps_global->smime->personal_certs; x; x=x->next){
3219 X509 *mine;
3220
3221 mine = x->cert;
3222
3223 if(!X509_NAME_cmp(ri->issuer_and_serial->issuer,X509_get_issuer_name(mine)) &&
3224 !ASN1_INTEGER_cmp(ri->issuer_and_serial->serial,X509_get_serialNumber(mine))){
3225 break;
3226 }
3227 }
3228 }
3229
3230 return x;
3231 }
3232
3233
3234 static PERSONAL_CERT *
find_certificate_matching_pkcs7(PKCS7 * p7)3235 find_certificate_matching_pkcs7(PKCS7 *p7)
3236 {
3237 int i;
3238 STACK_OF(PKCS7_RECIP_INFO) *recips;
3239 PERSONAL_CERT *x = NULL;
3240
3241 recips = p7->d.enveloped->recipientinfo;
3242
3243 for(i=0; i<sk_PKCS7_RECIP_INFO_num(recips); i++){
3244 PKCS7_RECIP_INFO *ri;
3245
3246 ri = sk_PKCS7_RECIP_INFO_value(recips, i);
3247
3248 if((x=find_certificate_matching_recip_info(ri))!=0){
3249 break;
3250 }
3251 }
3252
3253 return x;
3254 }
3255
3256 /* decrypt an encrypted file.
3257 Args: fp - the path to the encrypted file.
3258 rv - a code that tells the caller what happened inside the function
3259 pcert - a personal certificate that was used to encrypt this file
3260 Returns the decoded text allocated in a char *, whose memory must be
3261 freed by caller
3262 */
3263
3264 char *
decrypt_file(char * fp,int * rv,PERSONAL_CERT * pc)3265 decrypt_file(char *fp, int *rv, PERSONAL_CERT *pc)
3266 {
3267 PKCS7 *p7 = NULL;
3268 char *text, *tmp;
3269 BIO *in = NULL, *out = NULL;
3270 long unsigned int len;
3271 void *ret;
3272
3273 if(pc == NULL || (text = read_file(fp, 0)) == NULL || *text == '\0')
3274 return NULL;
3275
3276 tmp = strchr(text + strlen("-----BEGIN PKCS7-----") + strlen(NEWLINE), '-');
3277 if(tmp != NULL) *tmp = '\0';
3278 tmp = text + strlen("-----BEGIN PKCS7-----") + strlen(NEWLINE);
3279
3280 ret = rfc822_base64((unsigned char *)tmp, strlen(tmp), &len);
3281
3282 if((in = BIO_new_mem_buf((char *)ret, len)) != NULL){
3283 p7 = d2i_PKCS7_bio(in, NULL);
3284 BIO_free(in);
3285 }
3286
3287 if (text) fs_give((void **)&text);
3288 if (ret) fs_give((void **)&ret);
3289
3290 if (rv) *rv = pc->key == NULL ? -1 : 1;
3291
3292 out = BIO_new(BIO_s_mem());
3293 (void) BIO_reset(out);
3294
3295 if(PKCS7_decrypt(p7, pc->key, pc->cert, out, 0) != 0){
3296 len = BIO_get_mem_data(out, &tmp);
3297 text = fs_get((len+1)*sizeof(char));
3298 strncpy(text, tmp, len);
3299 text[len] = '\0';
3300 BIO_free(out);
3301 } else
3302 q_status_message1(SM_ORDER, 1, 1, _("Error decrypting: %s"),
3303 (char *) openssl_error_string());
3304 PKCS7_free(p7);
3305
3306 return text;
3307 }
3308
3309 /*
3310 * Try to decode (decrypt or verify a signature) a PKCS7 body
3311 * Returns non-zero if something was changed.
3312 */
3313 static int
do_decoding(BODY * b,long msgno,const char * section)3314 do_decoding(BODY *b, long msgno, const char *section)
3315 {
3316 int modified_the_body = 0;
3317 BIO *out = NULL;
3318 PKCS7 *p7 = NULL;
3319 X509 *recip = NULL;
3320 EVP_PKEY *key = NULL;
3321 PERSONAL_CERT *pcert = NULL;
3322 char *what_we_did = "";
3323 char null[1];
3324
3325 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"));
3326 null[0] = '\0';
3327 smime_init();
3328
3329 /*
3330 * Extract binary data from part to an in-memory store
3331 */
3332
3333 if(b->sparep){
3334 if(get_body_sparep_type(b->sparep) == P7Type)
3335 p7 = (PKCS7*) get_body_sparep_data(b->sparep);
3336 }
3337 else{
3338 p7 = get_pkcs7_from_part(msgno, section && *section ? section : "1");
3339 if(!p7){
3340 q_status_message1(SM_ORDER, 2, 2, "Couldn't load PKCS7 object: %s",
3341 (char*) openssl_error_string());
3342 goto end;
3343 }
3344
3345 /*
3346 * Save the PKCS7 object for later dealings by the user interface.
3347 * It will be cleaned up when the body is garbage collected.
3348 */
3349 b->sparep = create_body_sparep(P7Type, p7);
3350 }
3351
3352 dprint((1, "type_is_signed = %d, type_is_enveloped = %d", PKCS7_type_is_signed(p7), PKCS7_type_is_enveloped(p7)));
3353
3354 if(PKCS7_type_is_signed(p7)){
3355 int sigok;
3356
3357 out = BIO_new(BIO_s_mem());
3358 (void) BIO_reset(out);
3359 BIO_puts(out, "MIME-Version: 1.0\r\n"); /* needed so rfc822_parse_msg_full believes it's MIME */
3360
3361 sigok = do_signature_verify(p7, NULL, out, 0);
3362
3363 what_we_did = sigok ? _("This message was cryptographically signed.") :
3364 _("This message was cryptographically signed but the signature could not be verified.");
3365
3366 /* make sure it's null terminated */
3367 BIO_write(out, null, 1);
3368 }
3369 else if(!PKCS7_type_is_enveloped(p7)){
3370 q_status_message(SM_ORDER, 1, 1, "PKCS7 object not recognised.");
3371 goto end;
3372 }
3373 else{ /* It *is* enveloped */
3374 int decrypt_result;
3375
3376 what_we_did = _("This message was encrypted.");
3377
3378 /* now need to find a cert that can decrypt this */
3379 pcert = find_certificate_matching_pkcs7(p7);
3380
3381 if(!pcert){
3382 q_status_message(SM_ORDER, 3, 3, _("Couldn't find the certificate needed to decrypt."));
3383 goto end;
3384 }
3385
3386 recip = pcert->cert;
3387
3388 if(!load_private_key(pcert)
3389 && ps_global->smime
3390 && ps_global->smime->need_passphrase
3391 && !ps_global->smime->already_auto_asked){
3392 /* Couldn't load key with blank password, ask user */
3393 ps_global->smime->already_auto_asked = 1;
3394 if(pith_opt_smime_get_passphrase){
3395 (*pith_opt_smime_get_passphrase)();
3396 load_private_key(pcert);
3397 }
3398 }
3399
3400 key = pcert->key;
3401 if(!key)
3402 goto end;
3403
3404 out = BIO_new(BIO_s_mem());
3405 (void) BIO_reset(out);
3406 BIO_puts(out, "MIME-Version: 1.0\r\n");
3407
3408 decrypt_result = PKCS7_decrypt(p7, key, recip, out, 0);
3409
3410 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE,ps_global))
3411 forget_private_keys();
3412
3413 if(!decrypt_result){
3414 q_status_message1(SM_ORDER, 1, 1, _("Error decrypting: %s"),
3415 (char*) openssl_error_string());
3416 goto end; }
3417
3418 BIO_write(out, null, 1);
3419 }
3420
3421 /*
3422 * We've now produced a flattened MIME object in BIO out.
3423 * It needs to be turned back into a BODY.
3424 */
3425
3426 if(out){
3427 BODY *body;
3428 ENVELOPE *env;
3429 char *h = NULL;
3430 char *bstart;
3431 STRING s;
3432 BUF_MEM *bptr = NULL;
3433 int we_free = 0;
3434
3435 BIO_get_mem_ptr(out, &bptr);
3436 if(bptr)
3437 h = bptr->data;
3438
3439 /* look for start of body */
3440 bstart = strstr(h, "\r\n\r\n");
3441
3442 if(!bstart){
3443 /*
3444 * Some clients do not canonicalize before encrypting, so
3445 * look for "\n\n" instead.
3446 */
3447 bstart = strstr(h, "\n\n");
3448 if(bstart){
3449 int lines;
3450 char *s, *t;
3451 for(lines = 0, bstart = h; (bstart = strchr(bstart, '\n')) != NULL;
3452 bstart++, lines++);
3453 h = t = fs_get(strlen(bptr->data) + lines + 1);
3454 we_free++;
3455 for(s = bptr->data; *s != '\0'; s++)
3456 if(*s == '\n' && *(s-1) != '\r'){
3457 *t++ = '\r';
3458 *t++ = '\n';
3459 }
3460 else
3461 *t++ = *s;
3462 *t = '\0';
3463 bstart = strstr(h, "\r\n\r\n");
3464 }
3465 }
3466
3467 if(!bstart){
3468 q_status_message(SM_ORDER, 3, 3, _("Encrypted data couldn't be parsed."));
3469 }
3470 else{
3471 SIZEDTEXT *st;
3472 bstart += 4; /* skip over CRLF*2 */
3473
3474 INIT(&s, mail_string, bstart, strlen(bstart));
3475 rfc822_parse_msg_full(&env, &body, h, bstart-h-2, &s, BADHOST, 0, 0);
3476 mail_free_envelope(&env); /* Don't care about this */
3477
3478 if(body->type == TYPEMULTIPART
3479 && !strucmp(body->subtype, "SIGNED")){
3480 char *cookie = NULL;
3481 PARAMETER *param;
3482 for (param = body->parameter; param && !cookie; param = param->next)
3483 if (!strucmp (param->attribute,"BOUNDARY")) cookie = param->value;
3484 if(cookie != NULL){
3485 st = fs_get(sizeof(SIZEDTEXT));
3486 st->data = (void *) cpystr(bstart + strlen(cookie)+4); /* 4 = strlen("--\r\n") */
3487 st->size = body->nested.part->next->body.mime.offset - 2*(strlen(cookie) + 4);
3488 body->sparep = create_body_sparep(SizedText, (void *)st);
3489 }
3490 else
3491 q_status_message(SM_ORDER, 3, 3, _("Couldn't find cookie in attachment list."));
3492 }
3493 body->mime.offset = 0;
3494 body->mime.text.size = 0;
3495
3496 /*
3497 * Now convert original body (application/pkcs7-mime)
3498 * to a multipart body with one sub-part (the decrypted body).
3499 * Note that the sub-part may also be multipart!
3500 */
3501
3502 b->type = TYPEMULTIPART;
3503 if(b->subtype)
3504 fs_give((void **) &b->subtype);
3505
3506 /*
3507 * This subtype is used in mailview.c to annotate the display of
3508 * encrypted or signed messages. We know for sure then that it's a PKCS7
3509 * part because the sparep field is set to the PKCS7 object (see above).
3510 */
3511 b->subtype = cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE);
3512 b->encoding = ENC8BIT;
3513
3514 if(b->description)
3515 fs_give((void **) &b->description);
3516
3517 b->description = cpystr(what_we_did);
3518
3519 if(b->disposition.type)
3520 fs_give((void **) &b->disposition.type);
3521
3522 if(b->contents.text.data)
3523 fs_give((void **) &b->contents.text.data);
3524
3525 if(b->parameter)
3526 mail_free_body_parameter(&b->parameter);
3527
3528 /* Allocate mem for the sub-part, and copy over the contents of our parsed body */
3529 b->nested.part = fs_get(sizeof(PART));
3530 b->nested.part->body = *body;
3531 b->nested.part->next = NULL;
3532
3533 fs_give((void**) &body);
3534
3535 /*
3536 * IMPORTANT BIT: set the body->contents.text.data elements to contain
3537 * the decrypted data. Otherwise, it'll try to load it from the original
3538 * data. Eek.
3539 */
3540 create_local_cache(bstart-b->nested.part->body.mime.offset, bstart, &b->nested.part->body, 0);
3541
3542 modified_the_body = 1;
3543 }
3544 if(we_free)
3545 fs_give((void **) &h);
3546 }
3547
3548 end:
3549 if(out)
3550 BIO_free(out);
3551
3552 return modified_the_body;
3553 }
3554
3555
3556 /*
3557 * Recursively handle PKCS7 bodies in our message.
3558 *
3559 * Returns non-zero if some fiddling was done.
3560 */
3561 static int
do_fiddle_smime_message(BODY * b,long msgno,char * section)3562 do_fiddle_smime_message(BODY *b, long msgno, char *section)
3563 {
3564 int modified_the_body = 0;
3565
3566 if(!b)
3567 return 0;
3568
3569 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"));
3570
3571 if(is_pkcs7_body(b)){
3572
3573 if(do_decoding(b, msgno, section)){
3574 /*
3575 * b should now be a multipart message:
3576 * fiddle it too in case it's been multiply-encrypted!
3577 */
3578
3579 /* fallthru */
3580 modified_the_body = 1;
3581 }
3582 }
3583
3584 if(b->type==TYPEMULTIPART || MIME_MSG(b->type, b->subtype)){
3585
3586 PART *p;
3587 int partNum;
3588 char newSec[100];
3589
3590 if(MIME_MULT_SIGNED(b->type, b->subtype)){
3591
3592
3593 /*
3594 * Ahah. We have a multipart signed entity.
3595 *
3596 * Multipart/signed
3597 * part 1 (signed thing)
3598 * part 2 (the pkcs7 signature)
3599 *
3600 * We're going to convert that to
3601 *
3602 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
3603 * part 1 (signed thing)
3604 * part 2 has been freed
3605 *
3606 * We also extract the signature from part 2 and save it
3607 * in the multipart body->sparep, and we add a description
3608 * in the multipart body->description.
3609 *
3610 *
3611 * The results of a decrypted message will be similar. It
3612 * will be
3613 *
3614 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
3615 * part 1 (decrypted thing)
3616 */
3617
3618 modified_the_body += do_detached_signature_verify(b, msgno, section);
3619 }
3620 else if(MIME_MSG(b->type, b->subtype)){
3621 modified_the_body += do_fiddle_smime_message(b->nested.msg->body, msgno, section);
3622 }
3623 else{
3624
3625 for(p=b->nested.part,partNum=1; p; p=p->next,partNum++){
3626 /* Append part number to the section string */
3627
3628 snprintf(newSec, sizeof(newSec), "%s%s%d", section, *section ? "." : "", partNum);
3629
3630 modified_the_body += do_fiddle_smime_message(&p->body, msgno, newSec);
3631 }
3632 }
3633 }
3634
3635 return modified_the_body;
3636 }
3637
3638
3639 /*
3640 * Fiddle a message in-place by decrypting/verifying S/MIME entities.
3641 * Returns non-zero if something was changed.
3642 */
3643 int
fiddle_smime_message(BODY * b,long msgno)3644 fiddle_smime_message(BODY *b, long msgno)
3645 {
3646 return do_fiddle_smime_message(b, msgno, "");
3647 }
3648
3649
3650 /********************************************************************************/
3651
3652
3653 /*
3654 * Output a string in a distinctive style
3655 */
3656 void
gf_puts_uline(char * txt,gf_io_t pc)3657 gf_puts_uline(char *txt, gf_io_t pc)
3658 {
3659 pc(TAG_EMBED); pc(TAG_BOLDON);
3660 gf_puts(txt, pc);
3661 pc(TAG_EMBED); pc(TAG_BOLDOFF);
3662 }
3663
3664 /* get_chain_for_cert: error and level are mandatory arguments */
STACK_OF(X509)3665 STACK_OF(X509) *
3666 get_chain_for_cert(X509 *cert, int *error, int *level)
3667 {
3668 STACK_OF(X509) *chain = NULL;
3669 X509_STORE_CTX *ctx;
3670 X509 *x, *xtmp;
3671 int rc; /* return code */
3672
3673 *level = -1;
3674 *error = 0;
3675 ERR_clear_error();
3676 if((s_cert_store != NULL) && (ctx = X509_STORE_CTX_new()) != NULL){
3677 X509_STORE_set_flags(s_cert_store, 0);
3678 if(!X509_STORE_CTX_init(ctx, s_cert_store, cert, NULL))
3679 *error = X509_STORE_CTX_get_error(ctx);
3680 else if((chain = sk_X509_new_null()) != NULL){
3681 for(x = cert; ; x = xtmp){
3682 if(++*level > 0)
3683 sk_X509_push(chain, X509_dup(x));
3684 rc = X509_STORE_CTX_get1_issuer(&xtmp, ctx, x);
3685 if(rc < 0)
3686 *error = 1;
3687 if(rc <= 0)
3688 break;
3689 if(!X509_check_issued(xtmp, xtmp))
3690 break;
3691 }
3692 }
3693 X509_STORE_CTX_free(ctx);
3694 }
3695 return chain;
3696 }
3697
3698
3699 /*
3700 * Sign a message. Called from call_mailer in send.c.
3701 *
3702 * This takes the header for the outgoing message as well as a pointer
3703 * to the current body (which may be reallocated).
3704 * The last argument (BODY **bp) is an argument that tells Alpine
3705 * if the body has 8 bit. if *bp is not null we compute two signatures
3706 * one for the quoted-printable encoded message, and another for the
3707 * 8bit encoded message. We return the signature for the 8bit encoded
3708 * part in p2->body.mime.text.data.
3709 * The reason why we compute two signatures is so that we can decide
3710 * which one to use later, and we only do it in the case that *bp is
3711 * not null. If we did not do this, then we might not be able to sign
3712 * a message until we log in to the smtp server, so instead of doing
3713 * that, we get ready for any possible situation we might find.
3714 */
3715 int
sign_outgoing_message(METAENV * header,BODY ** bodyP,int dont_detach,BODY ** bp)3716 sign_outgoing_message(METAENV *header, BODY **bodyP, int dont_detach, BODY **bp)
3717 {
3718 STORE_S *outs = NULL;
3719 STORE_S *outs_2 = NULL;
3720 BODY *body = *bodyP;
3721 BODY *newBody = NULL;
3722 PART *p1 = NULL;
3723 PART *p2 = NULL;
3724 PERSONAL_CERT *pcert;
3725 BIO *in = NULL;
3726 BIO *in_2 = NULL;
3727 BIO *out = NULL;
3728 BIO *out_2 = NULL;
3729 PKCS7 *p7 = NULL;
3730 PKCS7 *p7_2 = NULL;
3731 STACK_OF(X509) *chain;
3732 const EVP_MD *md = EVP_sha256(); /* use this digest instead of sha1 */
3733 int result = 0, error;
3734 int flags = dont_detach ? 0 : PKCS7_DETACHED;
3735 int level;
3736
3737 dprint((9, "sign_outgoing_message()"));
3738
3739 smime_init();
3740
3741 /* Look for a private key matching the sender address... */
3742
3743 pcert = match_personal_cert(header->env);
3744
3745 if(!pcert){
3746 q_status_message(SM_ORDER, 3, 3, _("Couldn't find the certificate needed to sign."));
3747 goto end;
3748 }
3749
3750 if(!load_private_key(pcert) && ps_global->smime && ps_global->smime->need_passphrase){
3751 /* Couldn't load key with blank password, try again */
3752 if(pith_opt_smime_get_passphrase){
3753 (*pith_opt_smime_get_passphrase)();
3754 load_private_key(pcert);
3755 }
3756 }
3757
3758 if(!pcert->key)
3759 goto end;
3760
3761 if(((chain = get_chain_for_cert(pcert->cert, &error, &level)) != NULL && error)
3762 || level == 0){
3763 sk_X509_pop_free(chain, X509_free);
3764 chain = NULL;
3765 }
3766
3767 if(error)
3768 q_status_message(SM_ORDER, 1, 1,
3769 _("Not all certificates needed to verify signature included in signed message"));
3770
3771 in = body_to_bio(body);
3772
3773 flags |= PKCS7_PARTIAL;
3774 if((p7 = PKCS7_sign(NULL, NULL, chain, in, flags)) != NULL
3775 && PKCS7_sign_add_signer(p7, pcert->cert, pcert->key, md, flags))
3776 PKCS7_final(p7, in, flags);
3777
3778 if(bp && *bp){
3779 int i, save_encoding;
3780
3781 for(i = 0; (i <= ENCMAX) && body_encodings[i]; i++);
3782
3783 if(i > ENCMAX){ /* no empty encoding slots! */
3784 *bp = NULL;
3785 }
3786 else {
3787 save_encoding = (*bp)->encoding;
3788 body_encodings[(*bp)->encoding = i] = body_encodings[ENC8BIT];
3789
3790 in_2 = body_to_bio(body);
3791
3792 body_encodings[i] = NULL;
3793 (*bp)->encoding = save_encoding;
3794 }
3795 }
3796
3797 if(bp && *bp){
3798 if((p7_2 = PKCS7_sign(NULL, NULL, chain, in_2, flags)) != NULL
3799 && PKCS7_sign_add_signer(p7_2, pcert->cert, pcert->key, md, flags))
3800 PKCS7_final(p7_2, in_2, flags);
3801 }
3802
3803 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE,ps_global))
3804 forget_private_keys();
3805
3806 if(chain)
3807 sk_X509_pop_free(chain, X509_free);
3808
3809 if(!p7){
3810 q_status_message(SM_ORDER, 1, 1, _("Error creating signed object."));
3811 goto end;
3812 }
3813
3814 outs = so_get(BioType, NULL, EDIT_ACCESS);
3815 out = bio_from_store(outs);
3816
3817 i2d_PKCS7_bio(out, p7);
3818 (void) BIO_flush(out);
3819
3820 so_seek(outs, 0, SEEK_SET);
3821
3822 if(bp && *bp && p7_2){
3823 outs_2 = so_get(BioType, NULL, EDIT_ACCESS);
3824 out_2 = bio_from_store(outs_2);
3825
3826 i2d_PKCS7_bio(out_2, p7_2);
3827 (void) BIO_flush(out_2);
3828
3829 so_seek(outs_2, 0, SEEK_SET);
3830 }
3831
3832 if((flags&PKCS7_DETACHED)==0){
3833
3834 /* the simple case: the signed data is in the pkcs7 object */
3835
3836 newBody = mail_newbody();
3837
3838 setup_pkcs7_body_for_signature(newBody, "S/MIME Cryptographically Signed Message", "pkcs7-mime", "smime.p7m", "signed-data");
3839
3840 newBody->contents.text.data = (unsigned char *) outs;
3841 *bodyP = newBody;
3842
3843 result = 1;
3844 }
3845 else{
3846
3847 /*
3848 * OK.
3849 * We have to create a new body as follows:
3850 *
3851 * multipart/signed; blah blah blah
3852 * reference to existing body
3853 *
3854 * pkcs7 object
3855 */
3856
3857 newBody = mail_newbody();
3858
3859 newBody->type = TYPEMULTIPART;
3860 newBody->subtype = cpystr("signed");
3861 newBody->encoding = ENC7BIT;
3862
3863 set_parameter(&newBody->parameter, "protocol", "application/pkcs7-signature");
3864 set_parameter(&newBody->parameter, "micalg", "sha-256");
3865
3866 p1 = mail_newbody_part();
3867 p2 = mail_newbody_part();
3868
3869 /*
3870 * This is nasty. We're just copying the body in here,
3871 * but since our newBody is freed at the end of call_mailer,
3872 * we mustn't let this body (the original one) be freed twice.
3873 */
3874 p1->body = *body; /* ARRGH. This is special cased at the end of call_mailer */
3875
3876 p1->next = p2;
3877
3878 setup_pkcs7_body_for_signature(&p2->body, "S/MIME Cryptographic Signature", "pkcs7-signature", "smime.p7s", NULL);
3879 p2->body.mime.text.data = (unsigned char *) outs_2;
3880 p2->body.contents.text.data = (unsigned char *) outs;
3881
3882 newBody->nested.part = p1;
3883
3884 *bodyP = newBody;
3885
3886 result = 1;
3887 }
3888
3889 end:
3890
3891 PKCS7_free(p7);
3892 BIO_free(in);
3893
3894 if(bp && *bp){
3895 if(p7_2) PKCS7_free(p7_2);
3896 BIO_free(in_2);
3897 }
3898
3899 dprint((9, "sign_outgoing_message returns %d", result));
3900 return result;
3901 }
3902
3903
3904 SMIME_STUFF_S *
new_smime_struct(void)3905 new_smime_struct(void)
3906 {
3907 SMIME_STUFF_S *ret = NULL;
3908
3909 ret = (SMIME_STUFF_S *) fs_get(sizeof(*ret));
3910 memset((void *) ret, 0, sizeof(*ret));
3911 ret->publictype = Nada;
3912
3913 return ret;
3914 }
3915
3916
3917 static void
free_smime_struct(SMIME_STUFF_S ** smime)3918 free_smime_struct(SMIME_STUFF_S **smime)
3919 {
3920 if(smime && *smime){
3921 if((*smime)->passphrase_emailaddr){
3922 int i;
3923 for(i = 0; (*smime)->passphrase_emailaddr[i] != NULL; i++)
3924 fs_give((void **) &(*smime)->passphrase_emailaddr[i]);
3925 fs_give((void **) (*smime)->passphrase_emailaddr);
3926 }
3927
3928 if((*smime)->publicpath)
3929 fs_give((void **) &(*smime)->publicpath);
3930
3931 if((*smime)->publiccertlist)
3932 free_certlist(&(*smime)->publiccertlist);
3933
3934 if((*smime)->backuppubliccertlist)
3935 free_certlist(&(*smime)->backuppubliccertlist);
3936
3937 if((*smime)->cacertlist)
3938 free_certlist(&(*smime)->cacertlist);
3939
3940 if((*smime)->backupcacertlist)
3941 free_certlist(&(*smime)->backupcacertlist);
3942
3943 if((*smime)->privatecertlist)
3944 free_certlist(&(*smime)->privatecertlist);
3945
3946 if((*smime)->backupprivatecertlist)
3947 free_certlist(&(*smime)->backupprivatecertlist);
3948
3949 if((*smime)->publiccontent)
3950 fs_give((void **) &(*smime)->publiccontent);
3951
3952 if((*smime)->privatepath)
3953 fs_give((void **) &(*smime)->privatepath);
3954
3955 if((*smime)->personal_certs){
3956 PERSONAL_CERT *pc;
3957
3958 pc = (PERSONAL_CERT *) (*smime)->personal_certs;
3959 free_personal_certs(&pc);
3960 (*smime)->personal_certs = NULL;
3961 }
3962
3963 if((*smime)->privatecontent)
3964 fs_give((void **) &(*smime)->privatecontent);
3965
3966 if((*smime)->capath)
3967 fs_give((void **) &(*smime)->capath);
3968
3969 if((*smime)->cacontent)
3970 fs_give((void **) &(*smime)->cacontent);
3971
3972 fs_give((void **) smime);
3973 }
3974 }
3975
3976 #endif /* SMIME */
3977