1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: smime.c 1176 2008-09-29 21:16:42Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2008 University of Washington
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * ========================================================================
19 * This is based on a contribution from Jonathan Paisley
22 * Author: paisleyj@dcs.gla.ac.uk
27 #include "../pith/headers.h"
31 #include "../pith/osdep/canaccess.h"
32 #include "../pith/helptext.h"
33 #include "../pith/store.h"
34 #include "../pith/status.h"
35 #include "../pith/detach.h"
36 #include "../pith/conf.h"
37 #include "../pith/smkeys.h"
38 #include "../pith/smime.h"
39 #include "../pith/mailpart.h"
40 #include "../pith/reply.h"
41 #include "../pith/tempfile.h"
42 #include "../pith/readfile.h"
43 #include "../pith/remote.h"
45 #include <openssl/buffer.h>
48 typedef enum {Public
, Private
, CACert
} WhichCerts
;
51 /* internal prototypes */
52 static void forget_private_keys(void);
53 static int app_RAND_load_file(const char *file
);
54 static void openssl_extra_randomness(void);
55 static int app_RAND_write_file(const char *file
);
56 static void smime_init(void);
57 static const char *openssl_error_string(void);
58 static void create_local_cache(char *base
, BODY
*b
);
59 static long rfc822_output_func(void *b
, char *string
);
60 static int load_private_key(PERSONAL_CERT
*pcert
);
61 static void setup_pkcs7_body_for_signature(BODY
*b
, char *description
,
62 char *type
, char *filename
);
63 static BIO
*body_to_bio(BODY
*body
);
64 static BIO
*bio_from_store(STORE_S
*store
);
65 static STORE_S
*get_part_contents(long msgno
, const char *section
);
66 static PKCS7
*get_pkcs7_from_part(long msgno
, const char *section
);
67 static int do_signature_verify(PKCS7
*p7
, BIO
*in
, BIO
*out
);
68 static int do_detached_signature_verify(BODY
*b
, long msgno
, char *section
);
69 static PERSONAL_CERT
*find_certificate_matching_pkcs7(PKCS7
*p7
);
70 static int do_decoding(BODY
*b
, long msgno
, const char *section
);
71 static void free_smime_struct(SMIME_STUFF_S
**smime
);
72 static void setup_storage_locations(void);
73 static int copy_dir_to_container(WhichCerts which
);
74 static int copy_container_to_dir(WhichCerts which
);
77 int (*pith_opt_smime_get_passphrase
)(void);
80 static X509_STORE
*s_cert_store
;
82 /* State management for randomness functions below */
83 static int seeded
= 0;
84 static int egdsocket
= 0;
88 * Forget any cached private keys
91 forget_private_keys(void)
97 dprint((9, "forget_private_keys()"));
99 for(pcert
=(PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
104 EVP_PKEY_free(pcert
->key
);
109 ps_global
->smime
->entered_passphrase
= 0;
110 len
= sizeof(ps_global
->smime
->passphrase
);
111 p
= ps_global
->smime
->passphrase
;
120 * taken from openssl/apps/app_rand.c
123 app_RAND_load_file(const char *file
)
128 file
= RAND_file_name(buffer
, sizeof buffer
);
129 else if(RAND_egd(file
) > 0){
130 /* we try if the given filename is an EGD socket.
131 if it is, we don't write anything back to the file. */
136 if(file
== NULL
|| !RAND_load_file(file
, -1)){
137 if(RAND_status() == 0){
138 dprint((1, "unable to load 'random state'\n"));
139 dprint((1, "This means that the random number generator has not been seeded\n"));
140 dprint((1, "with much random data.\n"));
152 * copied and fiddled from imap/src/osdep/unix/auth_ssl.c
155 openssl_extra_randomness(void)
163 /* if system doesn't have /dev/urandom */
164 if(stat ("/dev/urandom", &sbuf
)){
166 tf
= temp_nam(NULL
, NULL
);
168 strncpy(tmp
, tf
, sizeof(tmp
));
169 tmp
[sizeof(tmp
)-1] = '\0';
170 fs_give((void **) &tf
);
173 if((fd
= open(tmp
, O_WRONLY
|O_CREAT
|O_EXCL
, 0600)) < 0)
174 i
= (unsigned long) tmp
;
176 unlink(tmp
); /* don't need the file */
177 fstat(fd
, &sbuf
); /* get information about the file */
178 i
= sbuf
.st_ino
; /* remember its inode */
179 close(fd
); /* or its descriptor */
181 /* not great but it'll have to do */
182 snprintf(tmp
+strlen(tmp
), sizeof(tmp
)-strlen(tmp
), "%.80s%lx%lx%lx",
184 (unsigned long) (time (0) ^ gethostid ()),
185 (unsigned long) getpid ());
186 RAND_seed(tmp
, strlen(tmp
));
192 /* taken from openssl/apps/app_rand.c */
194 app_RAND_write_file(const char *file
)
198 if(egdsocket
|| !seeded
)
200 * If we did not manage to read the seed file,
201 * we should not write a low-entropy seed file back --
202 * it would suppress a crucial warning the next time
208 file
= RAND_file_name(buffer
, sizeof buffer
);
210 if(file
== NULL
|| !RAND_write_file(file
)){
211 dprint((1, "unable to write 'random state'\n"));
219 /* Installed as an atexit() handler to save the random data */
223 dprint((9, "smime_deinit()"));
224 app_RAND_write_file(NULL
);
225 free_smime_struct(&ps_global
->smime
);
229 /* Initialise openssl stuff if needed */
233 if(F_OFF(F_DONT_DO_SMIME
, ps_global
) && !(ps_global
->smime
&& ps_global
->smime
->inited
)){
235 dprint((9, "smime_init()"));
236 if(!ps_global
->smime
)
237 ps_global
->smime
= new_smime_struct();
239 setup_storage_locations();
241 s_cert_store
= get_ca_store();
243 OpenSSL_add_all_algorithms();
244 ERR_load_crypto_strings();
246 app_RAND_load_file(NULL
);
248 openssl_extra_randomness();
249 ps_global
->smime
->inited
= 1;
257 setup_storage_locations(void)
259 int publiccertcontainer
= 0, privatekeycontainer
= 0, cacertcontainer
= 0;
260 char path
[MAXPATH
+1], *contents
;
262 if(!ps_global
->smime
)
266 if(F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
267 ps_global
->smime
->publictype
= Keychain
;
270 #endif /* APPLEKEYCHAIN */
271 /* Public certificates in a container */
272 if(ps_global
->VAR_PUBLICCERT_CONTAINER
&& ps_global
->VAR_PUBLICCERT_CONTAINER
[0]){
274 publiccertcontainer
= 1;
277 if(!signature_path(ps_global
->VAR_PUBLICCERT_CONTAINER
, path
, MAXPATH
))
278 publiccertcontainer
= 0;
280 if(publiccertcontainer
&& !IS_REMOTE(path
)
281 && ps_global
->VAR_OPER_DIR
282 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
283 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
284 /* TRANSLATORS: First arg is the directory name, second is
285 the file user wants to read but can't. */
286 _("Can't read file outside %s: %s"),
287 ps_global
->VAR_OPER_DIR
, path
);
288 publiccertcontainer
= 0;
291 if(publiccertcontainer
292 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
293 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
295 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
296 publiccertcontainer
= 0;
299 if(publiccertcontainer
&& path
[0]){
300 ps_global
->smime
->publictype
= Container
;
301 ps_global
->smime
->publicpath
= cpystr(path
);
304 ps_global
->smime
->publiccontent
= contents
;
305 ps_global
->smime
->publiccertlist
= mem_to_certlist(contents
);
310 /* Public certificates in a directory of files */
311 if(!publiccertcontainer
){
312 ps_global
->smime
->publictype
= Directory
;
315 if(!(signature_path(ps_global
->VAR_PUBLICCERT_DIR
, path
, MAXPATH
)
316 && !IS_REMOTE(path
)))
317 ps_global
->smime
->publictype
= Nada
;
318 else if(can_access(path
, ACCESS_EXISTS
)){
319 if(our_mkpath(path
, 0700)){
320 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
321 ps_global
->smime
->publictype
= Nada
;
325 if(ps_global
->smime
->publictype
== Directory
)
326 ps_global
->smime
->publicpath
= cpystr(path
);
331 #endif /* APPLEKEYCHAIN */
333 /* private keys in a container */
334 if(ps_global
->VAR_PRIVATEKEY_CONTAINER
&& ps_global
->VAR_PRIVATEKEY_CONTAINER
[0]){
336 privatekeycontainer
= 1;
339 if(!signature_path(ps_global
->VAR_PRIVATEKEY_CONTAINER
, path
, MAXPATH
))
340 privatekeycontainer
= 0;
342 if(privatekeycontainer
&& !IS_REMOTE(path
)
343 && ps_global
->VAR_OPER_DIR
344 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
345 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
346 /* TRANSLATORS: First arg is the directory name, second is
347 the file user wants to read but can't. */
348 _("Can't read file outside %s: %s"),
349 ps_global
->VAR_OPER_DIR
, path
);
350 privatekeycontainer
= 0;
353 if(privatekeycontainer
354 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
355 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
357 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
358 privatekeycontainer
= 0;
361 if(privatekeycontainer
&& path
[0]){
362 ps_global
->smime
->privatetype
= Container
;
363 ps_global
->smime
->privatepath
= cpystr(path
);
366 ps_global
->smime
->privatecontent
= contents
;
367 ps_global
->smime
->personal_certs
= mem_to_personal_certs(contents
);
372 /* private keys in a directory of files */
373 if(!privatekeycontainer
){
374 PERSONAL_CERT
*result
= NULL
;
376 ps_global
->smime
->privatetype
= Directory
;
379 if(!(signature_path(ps_global
->VAR_PRIVATEKEY_DIR
, path
, MAXPATH
)
380 && !IS_REMOTE(path
)))
381 ps_global
->smime
->privatetype
= Nada
;
382 else if(can_access(path
, ACCESS_EXISTS
)){
383 if(our_mkpath(path
, 0700)){
384 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
385 ps_global
->smime
->privatetype
= Nada
;
389 if(ps_global
->smime
->privatetype
== Directory
){
394 ps_global
->smime
->privatepath
= cpystr(path
);
395 dirp
= opendir(path
);
398 while((d
=readdir(dirp
)) != NULL
){
402 if((ll
=strlen(d
->d_name
)) && ll
> 4 && !strcmp(d
->d_name
+ll
-4, ".key")){
404 /* copy file name to temp buffer */
405 strncpy(buf2
, d
->d_name
, sizeof(buf2
)-1);
406 buf2
[sizeof(buf2
)-1] = '\0';
407 /* chop off ".key" trailier */
408 buf2
[strlen(buf2
)-4] = 0;
409 /* Look for certificate */
410 cert
= get_cert_for(buf2
);
415 /* create a new PERSONAL_CERT, fill it in */
417 pc
= (PERSONAL_CERT
*) fs_get(sizeof(*pc
));
419 pc
->name
= cpystr(buf2
);
421 /* Try to load the key with an empty password */
422 pc
->key
= load_key(pc
, "");
434 ps_global
->smime
->personal_certs
= result
;
437 /* extra cacerts in a container */
438 if(ps_global
->VAR_CACERT_CONTAINER
&& ps_global
->VAR_CACERT_CONTAINER
[0]){
443 if(!signature_path(ps_global
->VAR_CACERT_CONTAINER
, path
, MAXPATH
))
446 if(cacertcontainer
&& !IS_REMOTE(path
)
447 && ps_global
->VAR_OPER_DIR
448 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
449 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
450 /* TRANSLATORS: First arg is the directory name, second is
451 the file user wants to read but can't. */
452 _("Can't read file outside %s: %s"),
453 ps_global
->VAR_OPER_DIR
, path
);
458 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
459 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
461 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
465 if(cacertcontainer
&& path
[0]){
466 ps_global
->smime
->catype
= Container
;
467 ps_global
->smime
->capath
= cpystr(path
);
468 ps_global
->smime
->cacontent
= contents
;
472 if(!cacertcontainer
){
473 ps_global
->smime
->catype
= Directory
;
476 if(!(signature_path(ps_global
->VAR_CACERT_DIR
, path
, MAXPATH
)
477 && !IS_REMOTE(path
)))
478 ps_global
->smime
->catype
= Nada
;
479 else if(can_access(path
, ACCESS_EXISTS
)){
480 if(our_mkpath(path
, 0700)){
481 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
482 ps_global
->smime
->catype
= Nada
;
486 if(ps_global
->smime
->catype
== Directory
)
487 ps_global
->smime
->capath
= cpystr(path
);
493 copy_publiccert_dir_to_container(void)
495 return(copy_dir_to_container(Public
));
500 copy_publiccert_container_to_dir(void)
502 return(copy_container_to_dir(Public
));
507 copy_privatecert_dir_to_container(void)
509 return(copy_dir_to_container(Private
));
514 copy_privatecert_container_to_dir(void)
516 return(copy_container_to_dir(Private
));
521 copy_cacert_dir_to_container(void)
523 return(copy_dir_to_container(CACert
));
528 copy_cacert_container_to_dir(void)
530 return(copy_container_to_dir(CACert
));
535 * returns 0 on success, -1 on failure
538 copy_dir_to_container(WhichCerts which
)
541 BIO
*bio_out
= NULL
, *bio_in
= NULL
;
542 char srcpath
[MAXPATH
+1], dstpath
[MAXPATH
+1], emailaddr
[MAXPATH
], file
[MAXPATH
], line
[4096];
543 char *tempfile
= NULL
;
546 REMDATA_S
*rd
= NULL
;
547 char *configdir
= NULL
;
548 char *configpath
= NULL
;
549 char *filesuffix
= NULL
;
551 dprint((9, "copy_dir_to_container(%s)", which
==Public
? "Public" : which
==Private
? "Private" : which
==CACert
? "CACert" : "?"));
560 configdir
= ps_global
->VAR_PUBLICCERT_DIR
;
561 configpath
= ps_global
->smime
->publicpath
;
564 else if(which
== Private
){
565 configdir
= ps_global
->VAR_PRIVATEKEY_DIR
;
566 configpath
= ps_global
->smime
->privatepath
;
569 else if(which
== CACert
){
570 configdir
= ps_global
->VAR_CACERT_DIR
;
571 configpath
= ps_global
->smime
->capath
;
575 if(!(configdir
&& configdir
[0])){
576 q_status_message(SM_ORDER
, 3, 3, _("Directory not defined"));
580 if(!(configpath
&& configpath
[0])){
582 if(which
== Public
&& F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
583 q_status_message(SM_ORDER
, 3, 3, _("Turn off the Keychain feature above first"));
586 #endif /* APPLEKEYCHAIN */
587 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
591 if(!(filesuffix
&& strlen(filesuffix
) == 4)){
597 * If there is a legit directory to read from set up the
598 * container file to write to.
600 if(signature_path(configdir
, srcpath
, MAXPATH
) && !IS_REMOTE(srcpath
)){
602 if(IS_REMOTE(configpath
)){
603 rd
= rd_create_remote(RemImap
, configpath
, REMOTE_SMIME_SUBTYPE
,
605 _("Can't access remote smime configuration."));
609 (void) rd_read_metadata(rd
);
611 if(rd
->access
== MaybeRorW
){
612 if(rd
->read_status
== 'R')
613 rd
->access
= ReadOnly
;
615 rd
->access
= ReadWrite
;
618 if(rd
->access
!= NoExists
){
620 rd_check_remvalid(rd
, 1L);
623 * If the cached info says it is readonly but
624 * it looks like it's been fixed now, change it to readwrite.
626 if(rd
->read_status
== 'R'){
627 rd_check_readonly_access(rd
);
628 if(rd
->read_status
== 'W'){
629 rd
->access
= ReadWrite
;
630 rd
->flags
|= REM_OUTOFDATE
;
633 rd
->access
= ReadOnly
;
637 if(rd
->flags
& REM_OUTOFDATE
){
638 if(rd_update_local(rd
) != 0){
640 dprint((1, "copy_dir_to_container: rd_update_local failed\n"));
641 rd_close_remdata(&rd
);
648 if(rd
->access
!= ReadWrite
|| rd_remote_is_readonly(rd
)){
649 rd_close_remdata(&rd
);
653 rd
->flags
|= DO_REMTRIM
;
655 strncpy(dstpath
, rd
->lf
, sizeof(dstpath
)-1);
656 dstpath
[sizeof(dstpath
)-1] = '\0';
659 strncpy(dstpath
, configpath
, sizeof(dstpath
)-1);
660 dstpath
[sizeof(dstpath
)-1] = '\0';
664 * dstpath is either the local Container file or the local cache file
665 * for the remote Container file.
667 tempfile
= tempfile_in_same_dir(dstpath
, "az", NULL
);
671 * If there is a legit directory to read from and a tempfile
672 * to write to we continue.
674 if(tempfile
&& (bio_out
=BIO_new_file(tempfile
, "w")) != NULL
){
676 dirp
= opendir(srcpath
);
679 while((d
=readdir(dirp
)) && !ret
){
682 if((ll
=strlen(d
->d_name
)) && ll
> 4 && !strcmp(d
->d_name
+ll
-4, filesuffix
)){
684 /* copy file name to temp buffer */
685 strncpy(emailaddr
, d
->d_name
, sizeof(emailaddr
)-1);
686 emailaddr
[sizeof(emailaddr
)-1] = '\0';
687 /* chop off suffix trailier */
688 emailaddr
[strlen(emailaddr
)-4] = 0;
691 * This is the separator between the contents of
695 if(!((BIO_puts(bio_out
, CACERTSTORELEADER
) > 0)
696 && (BIO_puts(bio_out
, emailaddr
) > 0)
697 && (BIO_puts(bio_out
, "\n") > 0)))
701 if(!((BIO_puts(bio_out
, EMAILADDRLEADER
) > 0)
702 && (BIO_puts(bio_out
, emailaddr
) > 0)
703 && (BIO_puts(bio_out
, "\n") > 0)))
707 /* read then write contents of file */
708 build_path(file
, srcpath
, d
->d_name
, sizeof(file
));
709 if(!(bio_in
= BIO_new_file(file
, "r")))
715 while(BIO_gets(bio_in
, line
, sizeof(line
)) > 0){
716 if(strncmp("-----BEGIN", line
, strlen("-----BEGIN")) == 0)
720 BIO_puts(bio_out
, line
);
722 if(strncmp("-----END", line
, strlen("-----END")) == 0)
737 if(rename_file(tempfile
, dstpath
) < 0){
738 q_status_message2(SM_ORDER
, 3, 3,
739 _("Can't rename %s to %s"), tempfile
, dstpath
);
743 /* if the container is remote, copy it */
744 if(!ret
&& IS_REMOTE(configpath
)){
750 if((e
= rd_update_remote(rd
, datebuf
)) != 0){
752 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
753 _("Error opening temporary smime file %s: %s"),
754 rd
->lf
, error_description(errno
));
756 "write_remote_smime: error opening temp file %s\n",
757 rd
->lf
? rd
->lf
: "?"));
760 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
761 _("Error copying to %s: %s"),
762 rd
->rn
, error_description(errno
));
764 "write_remote_smime: error copying from %s to %s\n",
765 rd
->lf
? rd
->lf
: "?", rd
->rn
? rd
->rn
: "?"));
768 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
769 _("Copy of smime key to remote folder failed, NOT saved remotely"));
772 rd_update_metadata(rd
, datebuf
);
773 rd
->read_status
= 'W';
776 rd_close_remdata(&rd
);
782 fs_give((void **) &tempfile
);
789 * returns 0 on success, -1 on failure
792 copy_container_to_dir(WhichCerts which
)
794 char path
[MAXPATH
+1], file
[MAXPATH
+1], buf
[MAXPATH
+1];
796 char *contents
= NULL
;
798 char *filesuffix
= NULL
;
799 char *configdir
= NULL
;
800 char *configpath
= NULL
;
801 char *tempfile
= NULL
;
802 char *p
, *q
, *line
, *name
, *certtext
, *save_p
;
806 dprint((9, "copy_container_to_dir(%s)", which
==Public
? "Public" : which
==Private
? "Private" : which
==CACert
? "CACert" : "?"));
812 leader
= EMAILADDRLEADER
;
813 contents
= ps_global
->smime
->publiccontent
;
814 configdir
= ps_global
->VAR_PUBLICCERT_DIR
;
815 configpath
= ps_global
->smime
->publicpath
;
817 if(!(configpath
&& configpath
[0])){
819 if(which
== Public
&& F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
820 q_status_message(SM_ORDER
, 3, 3, _("Turn off the Keychain feature above first"));
823 #endif /* APPLEKEYCHAIN */
824 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
828 fs_give((void **) &ps_global
->smime
->publicpath
);
831 if(!(signature_path(ps_global
->VAR_PUBLICCERT_DIR
, path
, MAXPATH
)
832 && !IS_REMOTE(path
))){
833 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
837 if(can_access(path
, ACCESS_EXISTS
)){
838 if(our_mkpath(path
, 0700)){
839 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
844 ps_global
->smime
->publicpath
= cpystr(path
);
845 configpath
= ps_global
->smime
->publicpath
;
847 else if(which
== Private
){
848 leader
= EMAILADDRLEADER
;
849 contents
= ps_global
->smime
->privatecontent
;
850 configdir
= ps_global
->VAR_PRIVATEKEY_DIR
;
851 configpath
= ps_global
->smime
->privatepath
;
853 if(!(configpath
&& configpath
[0])){
854 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
858 fs_give((void **) &ps_global
->smime
->privatepath
);
861 if(!(signature_path(ps_global
->VAR_PRIVATEKEY_DIR
, path
, MAXPATH
)
862 && !IS_REMOTE(path
))){
863 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
867 if(can_access(path
, ACCESS_EXISTS
)){
868 if(our_mkpath(path
, 0700)){
869 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
874 ps_global
->smime
->privatepath
= cpystr(path
);
875 configpath
= ps_global
->smime
->privatepath
;
877 else if(which
== CACert
){
878 leader
= CACERTSTORELEADER
;
879 contents
= ps_global
->smime
->cacontent
;
880 configdir
= ps_global
->VAR_CACERT_DIR
;
881 configpath
= ps_global
->smime
->capath
;
883 if(!(configpath
&& configpath
[0])){
884 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
888 fs_give((void **) &ps_global
->smime
->capath
);
891 if(!(signature_path(ps_global
->VAR_CACERT_DIR
, path
, MAXPATH
)
892 && !IS_REMOTE(path
))){
893 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
897 if(can_access(path
, ACCESS_EXISTS
)){
898 if(our_mkpath(path
, 0700)){
899 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
904 ps_global
->smime
->capath
= cpystr(path
);
905 configpath
= ps_global
->smime
->capath
;
908 if(!(configdir
&& configdir
[0])){
909 q_status_message(SM_ORDER
, 3, 3, _("Directory not defined"));
913 if(!(configpath
&& configpath
[0])){
914 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
918 if(!(filesuffix
&& strlen(filesuffix
) == 4)){
923 if(contents
&& *contents
){
924 for(p
= contents
; *p
!= '\0';){
927 while(*p
&& *p
!= '\n')
936 if(strncmp(leader
, line
, strlen(leader
)) == 0){
937 name
= line
+ strlen(leader
);
939 if(strncmp("-----BEGIN", certtext
, strlen("-----BEGIN")) == 0){
940 if((q
= strstr(certtext
, leader
)) != NULL
){
943 else{ /* end of file */
944 q
= certtext
+ strlen(certtext
);
948 strncpy(buf
, name
, sizeof(buf
)-5);
949 buf
[sizeof(buf
)-5] = '\0';
950 strncat(buf
, filesuffix
, 5);
951 build_path(file
, configpath
, buf
, sizeof(file
));
953 in
= BIO_new_mem_buf(certtext
, q
-certtext
);
955 tempfile
= tempfile_in_same_dir(file
, "az", NULL
);
958 out
= BIO_new_file(tempfile
, "w");
961 while((len
= BIO_read(in
, iobuf
, sizeof(iobuf
))) > 0)
962 BIO_write(out
, iobuf
, len
);
966 if(rename_file(tempfile
, file
) < 0){
967 q_status_message2(SM_ORDER
, 3, 3,
968 _("Can't rename %s to %s"),
973 fs_give((void **) &tempfile
);
993 copy_publiccert_container_to_keychain(void)
1000 copy_publiccert_keychain_to_container(void)
1002 /* NOT IMPLEMNTED */
1006 #endif /* APPLEKEYCHAIN */
1010 * Get a pointer to a string describing the most recent OpenSSL error.
1011 * It's statically allocated, so don't change or attempt to free it.
1014 openssl_error_string(void)
1017 const char *data
= NULL
;
1020 errn
= ERR_peek_error_line_data(NULL
, NULL
, &data
, NULL
);
1021 errs
= (char*) ERR_reason_error_string(errn
);
1028 return "unknown error";
1032 /* Return true if the body looks like a PKCS7 object */
1034 is_pkcs7_body(BODY
*body
)
1038 result
= body
->type
==TYPEAPPLICATION
&&
1040 (strucmp(body
->subtype
,"pkcs7-mime")==0 ||
1041 strucmp(body
->subtype
,"x-pkcs7-mime")==0 ||
1042 strucmp(body
->subtype
,"pkcs7-signature")==0 ||
1043 strucmp(body
->subtype
,"x-pkcs7-signature")==0);
1051 * Somewhat useful debug utility to dump the contents of a BIO to a file.
1052 * Note that a memory BIO will have its contents eliminated after they
1053 * are read so this will break the next step.
1056 dump_bio_to_file(BIO
*in
, char *filename
)
1062 out
= BIO_new_file(filename
, "w");
1065 if(BIO_method_type(in
) != BIO_TYPE_MEM
)
1068 while((len
= BIO_read(in
, iobuf
, sizeof(iobuf
))) > 0)
1069 BIO_write(out
, iobuf
, len
);
1080 * Recursively stash a pointer to the decrypted data in our
1081 * manufactured body.
1084 create_local_cache(char *base
, BODY
*b
)
1086 if(b
->type
==TYPEMULTIPART
){
1090 cpytxt(&b
->contents
.text
, base
+ b
->contents
.offset
, b
->size
.bytes
);
1093 * We don't really want to copy the real body contents. It shouldn't be
1094 * used, and in the case of a message with attachments, we'll be
1095 * duplicating the files multiple times.
1097 cpytxt(&b
->contents
.text
, "BODY UNAVAILABLE", 16);
1100 for(p
=b
->nested
.part
; p
; p
=p
->next
)
1101 create_local_cache(base
, (BODY
*) p
);
1104 cpytxt(&b
->contents
.text
, base
+ b
->contents
.offset
, b
->size
.bytes
);
1110 rfc822_output_func(void *b
, char *string
)
1112 BIO
*bio
= (BIO
*) b
;
1114 return((BIO_puts(bio
, string
) > 0) ? 1L : 0L);
1119 * Attempt to load the private key for the given PERSONAL_CERT.
1120 * This sets the appropriate passphrase globals in order to
1121 * interact with the user correctly.
1124 load_private_key(PERSONAL_CERT
*pcert
)
1128 /* Try empty password by default */
1129 char *password
= "";
1132 && (ps_global
->smime
->need_passphrase
1133 || ps_global
->smime
->entered_passphrase
)){
1134 /* We've already been in here and discovered we need a different password */
1136 if(ps_global
->smime
->entered_passphrase
)
1137 password
= (char *) ps_global
->smime
->passphrase
; /* already entered */
1144 if(!(pcert
->key
= load_key(pcert
, password
))){
1145 long err
= ERR_get_error();
1147 /* Couldn't load key... */
1149 if(ps_global
->smime
&& ps_global
->smime
->entered_passphrase
){
1151 /* The user got the password wrong maybe? */
1153 if((ERR_GET_LIB(err
)==ERR_LIB_EVP
&& ERR_GET_REASON(err
)==EVP_R_BAD_DECRYPT
) ||
1154 (ERR_GET_LIB(err
)==ERR_LIB_PEM
&& ERR_GET_REASON(err
)==PEM_R_BAD_DECRYPT
))
1155 q_status_message(SM_ORDER
| SM_DING
, 4, 4, _("Incorrect passphrase"));
1157 q_status_message1(SM_ORDER
, 4, 4, _("Couldn't read key: %s"),(char*)openssl_error_string());
1159 /* This passphrase is no good; forget it */
1160 ps_global
->smime
->entered_passphrase
= 0;
1163 /* Indicate to the UI that we need re-entry (see mailcmd.c:process_cmd())*/
1164 if(ps_global
->smime
)
1165 ps_global
->smime
->need_passphrase
= 1;
1167 if(ps_global
->smime
){
1168 if(ps_global
->smime
->passphrase_emailaddr
){
1170 for(i
= 0; ps_global
->smime
->passphrase_emailaddr
[i
] != NULL
; i
++)
1171 fs_give((void **)&ps_global
->smime
->passphrase_emailaddr
[i
]);
1172 fs_give((void **) ps_global
->smime
->passphrase_emailaddr
);
1175 ps_global
->smime
->passphrase_emailaddr
= get_x509_subject_email(pcert
->cert
);
1181 /* This key will be cached, so we won't be called again */
1182 if(ps_global
->smime
){
1183 ps_global
->smime
->entered_passphrase
= 0;
1184 ps_global
->smime
->need_passphrase
= 0;
1196 setup_pkcs7_body_for_signature(BODY
*b
, char *description
, char *type
, char *filename
)
1198 b
->type
= TYPEAPPLICATION
;
1199 b
->subtype
= cpystr(type
);
1200 b
->encoding
= ENCBINARY
;
1201 b
->description
= cpystr(description
);
1203 b
->disposition
.type
= cpystr("attachment");
1204 set_parameter(&b
->disposition
.parameter
, "filename", filename
);
1206 set_parameter(&b
->parameter
, "name", filename
);
1211 * Look for a personal certificate matching the
1215 match_personal_cert_to_email(ADDRESS
*a
)
1217 PERSONAL_CERT
*pcert
= NULL
;
1222 if(!a
|| !a
->mailbox
|| !a
->host
)
1225 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
1227 if(ps_global
->smime
){
1228 for(pcert
=(PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
1235 email
= get_x509_subject_email(pcert
->cert
);
1239 for(i
= 0; email
[i
] && strucmp(email
[i
], buf
) != 0; i
++);
1240 if(email
[i
] != NULL
) done
++;
1241 for(i
= 0; email
[i
] != NULL
; i
++)
1242 fs_give((void **)&email
[i
]);
1243 fs_give((void **)email
);
1256 * Look for a personal certificate matching the from
1257 * (or reply_to? in the given envelope)
1260 match_personal_cert(ENVELOPE
*env
)
1262 PERSONAL_CERT
*pcert
;
1264 pcert
= match_personal_cert_to_email(env
->reply_to
);
1266 pcert
= match_personal_cert_to_email(env
->from
);
1273 * Flatten the given body into its MIME representation.
1274 * Return the result in a BIO.
1277 body_to_bio(BODY
*body
)
1282 bio
= BIO_new(BIO_s_mem());
1286 pine_encode_body(body
); /* this attaches random boundary strings to multiparts */
1287 pine_write_body_header(body
, rfc822_output_func
, bio
);
1288 pine_rfc822_output_body(body
, rfc822_output_func
, bio
);
1291 * Now need to truncate by two characters since the above
1294 if((len
=BIO_ctrl_pending(bio
)) > 1){
1295 BUF_MEM
*biobuf
= NULL
;
1297 BIO_get_mem_ptr(bio
, &biobuf
);
1299 BUF_MEM_grow(biobuf
, len
-2); /* remove CRLF */
1308 bio_from_store(STORE_S
*store
)
1312 if(store
&& store
->src
== BioType
&& store
->txt
){
1313 ret
= (BIO
*) store
->txt
;
1320 * Encrypt file; given a path (char *) fp, replace the file
1321 * by an encrypted version of it. If (char *) text is not null, then
1322 * replace the text of (char *) fp by the encrypted version of (char *) text.
1325 encrypt_file(char *fp
, char *text
)
1327 const EVP_CIPHER
*cipher
= NULL
;
1328 STACK_OF(X509
) *encerts
= NULL
;
1330 PERSONAL_CERT
*pcert
;
1337 if((pcert
= ps_global
->smime
->personal_certs
) == NULL
)
1340 cipher
= EVP_aes_256_cbc();
1341 encerts
= sk_X509_new_null();
1343 if((cert
= get_cert_for(pcert
->name
)) != NULL
)
1344 sk_X509_push(encerts
, cert
);
1349 in
= BIO_new(BIO_s_mem());
1352 (void) BIO_reset(in
);
1356 if(!(in
= BIO_new_file(fp
, "rb")))
1359 BIO_read_filename(in
, fp
);
1362 if((p7
= PKCS7_encrypt(encerts
, in
, cipher
, 0)) == NULL
)
1364 BIO_set_close(in
, BIO_CLOSE
);
1366 if(!(in
= BIO_new_file(fp
, "w")))
1369 rv
= PEM_write_bio_PKCS7(in
, p7
);
1375 sk_X509_pop_free(encerts
, X509_free
);
1381 * Encrypt a message on the way out. Called from call_mailer in send.c
1382 * The body may be reallocated.
1385 encrypt_outgoing_message(METAENV
*header
, BODY
**bodyP
)
1390 const EVP_CIPHER
*cipher
= NULL
;
1391 STACK_OF(X509
) *encerts
= NULL
;
1392 STORE_S
*outs
= NULL
;
1395 BODY
*body
= *bodyP
;
1396 BODY
*newBody
= NULL
;
1399 dprint((9, "encrypt_outgoing_message()"));
1402 cipher
= EVP_aes_256_cbc();
1404 encerts
= sk_X509_new_null();
1406 /* Look for a certificate for each of the recipients */
1407 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
1408 if(pf
->type
== Address
&& pf
->rcptto
&& pf
->addr
&& *pf
->addr
){
1409 for(a
=*pf
->addr
; a
; a
=a
->next
){
1413 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
1415 cert
= get_cert_for(buf
);
1417 sk_X509_push(encerts
,cert
);
1419 q_status_message2(SM_ORDER
, 1, 1,
1420 _("Unable to find certificate for <%s@%s>"),
1421 a
->mailbox
, a
->host
);
1428 in
= body_to_bio(body
);
1430 p7
= PKCS7_encrypt(encerts
, in
, cipher
, 0);
1432 outs
= so_get(BioType
, NULL
, EDIT_ACCESS
);
1433 out
= bio_from_store(outs
);
1435 i2d_PKCS7_bio(out
, p7
);
1436 (void) BIO_flush(out
);
1438 so_seek(outs
, 0, SEEK_SET
);
1440 newBody
= mail_newbody();
1442 newBody
->type
= TYPEAPPLICATION
;
1443 newBody
->subtype
= cpystr("pkcs7-mime");
1444 newBody
->encoding
= ENCBINARY
;
1446 newBody
->disposition
.type
= cpystr("attachment");
1447 set_parameter(&newBody
->disposition
.parameter
, "filename", "smime.p7m");
1449 newBody
->description
= cpystr("S/MIME Encrypted Message");
1450 set_parameter(&newBody
->parameter
, "smime-type", "enveloped-data");
1451 set_parameter(&newBody
->parameter
, "name", "smime.p7m");
1453 newBody
->contents
.text
.data
= (unsigned char *) outs
;
1463 sk_X509_pop_free(encerts
, X509_free
);
1465 dprint((9, "encrypt_outgoing_message returns %d", result
));
1471 Get (and decode) the body of the given section of msg
1474 get_part_contents(long msgno
, const char *section
)
1478 STORE_S
*store
= NULL
;
1481 store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
1483 gf_set_so_writec(&pc
,store
);
1485 err
= detach(ps_global
->mail_stream
, msgno
, (char*) section
, 0L, &len
, pc
, NULL
, 0L);
1487 gf_clear_so_writec(store
);
1489 so_seek(store
, 0, SEEK_SET
);
1500 get_pkcs7_from_part(long msgno
,const char *section
)
1502 STORE_S
*store
= NULL
;
1506 store
= get_part_contents(msgno
, section
);
1509 if(store
->src
== CharStar
){
1513 * We're reaching inside the STORE_S structure. We should
1514 * probably have a way to get the length, instead.
1516 len
= (int) (store
->eod
- store
->dp
);
1517 in
= BIO_new_mem_buf(store
->txt
, len
);
1519 else{ /* just copy it */
1522 in
= BIO_new(BIO_s_mem());
1523 (void) BIO_reset(in
);
1525 so_seek(store
, 0L, 0);
1526 while(so_readc(&c
, store
)){
1527 BIO_write(in
, &c
, 1);
1532 /* dump_bio_to_file(in, "/tmp/decoded-signature"); */
1533 if((p7
=d2i_PKCS7_bio(in
,NULL
)) == NULL
){
1548 * Try to verify a signature.
1550 * p7 - the pkcs7 object to verify
1551 * in - the plain data to verify (NULL if not detached)
1552 * out - BIO to which to write the opaque data
1555 do_signature_verify(PKCS7
*p7
, BIO
*in
, BIO
*out
)
1557 STACK_OF(X509
) *otherCerts
= NULL
;
1564 dump_bio_to_file(in
,"/tmp/verified-data");
1568 q_status_message(SM_ORDER
| SM_DING
, 2, 2,
1569 _("Couldn't verify S/MIME signature: No CA Certs were loaded"));
1574 result
= PKCS7_verify(p7
, otherCerts
, s_cert_store
, in
, out
, 0);
1577 q_status_message(SM_ORDER
, 1, 1, _("S/MIME signature verified ok"));
1580 err
= ERR_peek_error_line_data(NULL
, NULL
, &data
, NULL
);
1582 if(out
&& err
==ERR_PACK(ERR_LIB_PKCS7
,PKCS7_F_PKCS7_VERIFY
,PKCS7_R_CERTIFICATE_VERIFY_ERROR
)){
1584 /* Retry verification so we can get the plain text */
1585 /* Might be better to reimplement PKCS7_verify here? */
1587 PKCS7_verify(p7
, otherCerts
, s_cert_store
, in
, out
, PKCS7_NOVERIFY
);
1590 q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
1591 _("Couldn't verify S/MIME signature: %s"), (char*) openssl_error_string());
1594 /* now try to extract the certificates of any signers */
1596 STACK_OF(X509
) *signers
;
1599 signers
= PKCS7_get0_signers(p7
, NULL
, 0);
1602 for(i
=0; i
<sk_X509_num(signers
); i
++){
1604 X509
*x
= sk_X509_value(signers
,i
);
1610 email
= get_x509_subject_email(x
);
1614 for(i
= 0; email
[i
] != NULL
; i
++){
1615 cert
= get_cert_for(email
[i
]);
1619 save_cert_for(email
[i
], x
);
1620 fs_give((void **) &email
[i
]);
1622 fs_give((void **) email
);
1626 sk_X509_free(signers
);
1634 free_smime_body_sparep(void **sparep
)
1636 if(sparep
&& *sparep
){
1637 PKCS7_free((PKCS7
*) (*sparep
));
1642 /* Big comment, explaining the mess that exists out there
1644 When Alpine sends a message, it constructs that message, computes the
1645 signature, but then it forgets the message it signed and reconstructs it
1646 again. Since it signs a message containing a notice about "mime aware
1647 tools", but it does not send that we do not include that in the part that
1648 is signed, and that takes care of much of the problems.
1650 Another problem is what is received from the servers. All servers tested
1651 seem to transmit the message that was signed intact and Alpine can check
1652 the signature correctly. That is not a problem. The problem arises when
1653 the message includes attachments. In this case different servers send
1654 different things, so it will be up to us to figure out what is the text
1655 that was actually signed. Confused? here is the story:
1657 When a message containing and attachment is sent by Alpine, UW-IMAP,
1658 Panda-IMAP, Gmail, and local reading of folders send exactly the message
1659 that was sent by Alpine, but GMX.com, Exchange, and probably other servers
1660 add a trailing \r\n in the message, so when validating the signature,
1661 these messages will not validate. There are several things that can be
1664 1. Add a trailing \r\n to any message that contains attachments, sign that
1665 and send that. In this way, all messages will validate with all
1668 2. Compatibility mode: If a message has an attachment, contains a trailing
1669 \r\n and does not validate (sent by an earlier version of Alpine),
1670 remove the trailing \r\n and try to revalidate again.
1672 3. We do not add \r\n to validate a message that we sent, because that
1673 would only work in Alpine, and not in any other client. That would not
1674 be a good thing to do.
1678 * Given a multipart body of type multipart/signed, attempt to verify it.
1679 * Returns non-zero if the body was changed.
1682 do_detached_signature_verify(BODY
*b
, long msgno
, char *section
)
1687 int result
, modified_the_body
= 0;
1688 unsigned long mimelen
, bodylen
;
1689 char newSec
[100], *mimetext
, *bodytext
;
1692 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"));
1695 snprintf(newSec
, sizeof(newSec
), "%s%s1", section
? section
: "", (section
&& *section
) ? "." : "");
1697 mimetext
= mail_fetch_mime(ps_global
->mail_stream
, msgno
, (char*) newSec
, &mimelen
, 0);
1700 bodytext
= mail_fetch_body (ps_global
->mail_stream
, msgno
, (char*) newSec
, &bodylen
, 0);
1702 if (mimetext
== NULL
|| bodytext
== NULL
)
1703 return modified_the_body
;
1705 snprintf(newSec
, sizeof(newSec
), "%s%s2", section
? section
: "", (section
&& *section
) ? "." : "");
1707 if((p7
= get_pkcs7_from_part(msgno
, newSec
)) == NULL
)
1708 return modified_the_body
;
1710 /* first try with what get got */
1711 if((in
= BIO_new(BIO_s_mem())) == NULL
)
1712 return modified_the_body
;
1714 (void) BIO_reset(in
);
1715 BIO_write(in
, mimetext
, mimelen
);
1716 BIO_write(in
, bodytext
, bodylen
);
1718 /* Try compatibility with the past and check if this message
1719 validates when we remove the last two characters
1721 if(((result
= do_signature_verify(p7
, in
, NULL
)) == 0)
1723 && (strncmp(bodytext
+bodylen
-2,"\r\n", 2) == 0)){
1725 if((in
= BIO_new(BIO_s_mem())) == NULL
)
1726 return modified_the_body
;
1728 (void) BIO_reset(in
);
1729 BIO_write(in
, mimetext
, mimelen
);
1730 BIO_write(in
, bodytext
, bodylen
-2);
1732 result
= do_signature_verify(p7
, in
, NULL
);
1737 fs_give((void**) &b
->subtype
);
1739 b
->subtype
= cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE
);
1740 b
->encoding
= ENC8BIT
;
1743 fs_give ((void**) &b
->description
);
1745 what_we_did
= result
? _("This message was cryptographically signed.") :
1746 _("This message was cryptographically signed but the signature could not be verified.");
1748 b
->description
= cpystr(what_we_did
);
1754 /* p is signed plaintext */
1756 mail_free_body_part(&p
->next
); /* hide the pkcs7 from the viewer */
1758 modified_the_body
= 1;
1760 return modified_the_body
;
1765 find_certificate_matching_recip_info(PKCS7_RECIP_INFO
*ri
)
1767 PERSONAL_CERT
*x
= NULL
;
1769 if(ps_global
->smime
){
1770 for(x
= (PERSONAL_CERT
*) ps_global
->smime
->personal_certs
; x
; x
=x
->next
){
1775 if(!X509_NAME_cmp(ri
->issuer_and_serial
->issuer
,mine
->cert_info
->issuer
) &&
1776 !ASN1_INTEGER_cmp(ri
->issuer_and_serial
->serial
,mine
->cert_info
->serialNumber
)){
1786 static PERSONAL_CERT
*
1787 find_certificate_matching_pkcs7(PKCS7
*p7
)
1790 STACK_OF(PKCS7_RECIP_INFO
) *recips
;
1791 PERSONAL_CERT
*x
= NULL
;
1793 recips
= p7
->d
.enveloped
->recipientinfo
;
1795 for(i
=0; i
<sk_PKCS7_RECIP_INFO_num(recips
); i
++){
1796 PKCS7_RECIP_INFO
*ri
;
1798 ri
= sk_PKCS7_RECIP_INFO_value(recips
, i
);
1800 if((x
=find_certificate_matching_recip_info(ri
))!=0){
1808 /* decrypt an encrypted file.
1809 Args: fp - the path to the encrypted file.
1810 rv - a code that thells the caller what happened inside the function
1811 Returns the decoded text allocated in a char *, whose memory must be
1816 decrypt_file(char *fp
, int *rv
)
1820 BIO
*in
= NULL
, *out
= NULL
;
1821 EVP_PKEY
*pkey
= NULL
, *key
= NULL
;
1822 PERSONAL_CERT
*pcert
= NULL
;
1824 STORE_S
*outs
= NULL
, *store
, *ins
;
1826 long unsigned int len
;
1831 if((text
= read_file(fp
, 0)) == NULL
)
1834 tmp
= fs_get(strlen(text
) + (strlen(text
) << 6) + 1);
1835 for(j
= 0, i
= strlen("-----BEGIN PKCS7-----") + 1; text
[i
] != '\0'
1836 && text
[i
] != '-'; j
++, i
++)
1840 ret
= rfc822_base64(tmp
, strlen(tmp
), &len
);
1842 if((in
= BIO_new_mem_buf((char *)ret
, len
)) != NULL
){
1843 p7
= d2i_PKCS7_bio(in
, NULL
);
1847 if(text
) fs_give((void **)&text
);
1848 if(ret
) fs_give((void **)&ret
);
1850 if((pcert
= ps_global
->smime
->personal_certs
) == NULL
)
1853 if((i
= load_private_key(pcert
)) == 0
1855 && ps_global
->smime
->need_passphrase
1856 && !ps_global
->smime
->already_auto_asked
)
1858 ps_global
->smime
->already_auto_asked
= 1;
1859 if(pith_opt_smime_get_passphrase
){
1860 switch((*pith_opt_smime_get_passphrase
)()){
1861 case 0 : i
= load_private_key(pcert
);
1867 default: break; /* repeat until we cancel */
1876 if((key
= pcert
->key
) == NULL
)
1879 recip
= get_cert_for(pcert
->name
);
1880 out
= BIO_new(BIO_s_mem());
1881 (void) BIO_reset(out
);
1883 i
= PKCS7_decrypt(p7
, key
, recip
, out
, 0);
1885 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
1886 forget_private_keys();
1889 q_status_message1(SM_ORDER
, 1, 1, _("Error decrypting: %s"),
1890 (char*) openssl_error_string());
1894 BIO_get_mem_data(out
, &tmp
);
1906 * Try to decode (decrypt or verify a signature) a PKCS7 body
1907 * Returns non-zero if something was changed.
1910 do_decoding(BODY
*b
, long msgno
, const char *section
)
1912 int modified_the_body
= 0;
1916 EVP_PKEY
*key
= NULL
;
1917 PERSONAL_CERT
*pcert
= NULL
;
1918 char *what_we_did
= "";
1921 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"));
1926 * Extract binary data from part to an in-memory store
1929 if(b
->sparep
){ /* already done */
1930 p7
= (PKCS7
*) b
->sparep
;
1934 p7
= get_pkcs7_from_part(msgno
, section
&& *section
? section
: "1");
1936 q_status_message1(SM_ORDER
, 2, 2, "Couldn't load PKCS7 object: %s",
1937 (char*) openssl_error_string());
1942 * Save the PKCS7 object for later dealings by the user interface.
1943 * It will be cleaned up when the body is garbage collected.
1948 if(PKCS7_type_is_signed(p7
)){
1951 out
= BIO_new(BIO_s_mem());
1952 (void) BIO_reset(out
);
1953 BIO_puts(out
, "MIME-Version: 1.0\r\n"); /* needed so rfc822_parse_msg_full believes it's MIME */
1955 sigok
= do_signature_verify(p7
, NULL
, out
);
1957 /* shouldn't really duplicate these messages */
1958 what_we_did
= sigok
? _("This message was cryptographically signed.") :
1959 _("This message was cryptographically signed but the signature could not be verified.");
1961 /* make sure it's null terminated */
1962 BIO_write(out
, null
, 1);
1964 else if(!PKCS7_type_is_enveloped(p7
)){
1965 q_status_message(SM_ORDER
, 1, 1, "PKCS7 object not recognised.");
1968 else{ /* It *is* enveloped */
1971 what_we_did
= _("This message was encrypted.");
1973 /* now need to find a cert that can decrypt this */
1974 pcert
= find_certificate_matching_pkcs7(p7
);
1977 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find the certificate needed to decrypt."));
1981 recip
= pcert
->cert
;
1983 if(!load_private_key(pcert
)
1985 && ps_global
->smime
->need_passphrase
1986 && !ps_global
->smime
->already_auto_asked
){
1987 /* Couldn't load key with blank password, ask user */
1988 ps_global
->smime
->already_auto_asked
= 1;
1989 if(pith_opt_smime_get_passphrase
){
1990 (*pith_opt_smime_get_passphrase
)();
1991 load_private_key(pcert
);
1999 out
= BIO_new(BIO_s_mem());
2000 (void) BIO_reset(out
);
2001 BIO_puts(out
, "MIME-Version: 1.0\r\n");
2003 decrypt_result
= PKCS7_decrypt(p7
, key
, recip
, out
, 0);
2005 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
2006 forget_private_keys();
2008 if(!decrypt_result
){
2009 q_status_message1(SM_ORDER
, 1, 1, _("Error decrypting: %s"),
2010 (char*) openssl_error_string());
2014 BIO_write(out
, null
, 1);
2018 * We've now produced a flattened MIME object in BIO out.
2019 * It needs to be turned back into a BODY.
2028 BUF_MEM
*bptr
= NULL
;
2030 BIO_get_mem_ptr(out
, &bptr
);
2034 /* look for start of body */
2035 bstart
= strstr(h
, "\r\n\r\n");
2038 q_status_message(SM_ORDER
, 3, 3, _("Encrypted data couldn't be parsed."));
2041 bstart
+= 4; /* skip over CRLF*2 */
2043 INIT(&s
, mail_string
, bstart
, strlen(bstart
));
2044 rfc822_parse_msg_full(&env
, &body
, h
, bstart
-h
-2, &s
, BADHOST
, 0, 0);
2045 mail_free_envelope(&env
); /* Don't care about this */
2048 * Now convert original body (application/pkcs7-mime)
2049 * to a multipart body with one sub-part (the decrypted body).
2050 * Note that the sub-part may also be multipart!
2053 b
->type
= TYPEMULTIPART
;
2055 fs_give((void**) &b
->subtype
);
2058 * This subtype is used in mailview.c to annotate the display of
2059 * encrypted or signed messages. We know for sure then that it's a PKCS7
2060 * part because the sparep field is set to the PKCS7 object (see above).
2062 b
->subtype
= cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE
);
2063 b
->encoding
= ENC8BIT
;
2066 fs_give((void**) &b
->description
);
2068 b
->description
= cpystr(what_we_did
);
2070 if(b
->disposition
.type
)
2071 fs_give((void **) &b
->disposition
.type
);
2073 if(b
->contents
.text
.data
)
2074 fs_give((void **) &b
->contents
.text
.data
);
2077 mail_free_body_parameter(&b
->parameter
);
2079 /* Allocate mem for the sub-part, and copy over the contents of our parsed body */
2080 b
->nested
.part
= fs_get(sizeof(PART
));
2081 b
->nested
.part
->body
= *body
;
2082 b
->nested
.part
->next
= NULL
;
2084 fs_give((void**) &body
);
2087 * IMPORTANT BIT: set the body->contents.text.data elements to contain the decrypted
2088 * data. Otherwise, it'll try to load it from the original data. Eek.
2090 create_local_cache(bstart
, &b
->nested
.part
->body
);
2092 modified_the_body
= 1;
2100 return modified_the_body
;
2105 * Recursively handle PKCS7 bodies in our message.
2107 * Returns non-zero if some fiddling was done.
2110 do_fiddle_smime_message(BODY
*b
, long msgno
, char *section
)
2112 int modified_the_body
= 0;
2117 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"));
2119 if(is_pkcs7_body(b
)){
2121 if(do_decoding(b
, msgno
, section
)){
2123 * b should now be a multipart message:
2124 * fiddle it too in case it's been multiply-encrypted!
2128 modified_the_body
= 1;
2132 if(b
->type
==TYPEMULTIPART
|| MIME_MSG(b
->type
, b
->subtype
)){
2138 if(MIME_MULT_SIGNED(b
->type
, b
->subtype
)){
2142 * Ahah. We have a multipart signed entity.
2145 * part 1 (signed thing)
2146 * part 2 (the pkcs7 signature)
2148 * We're going to convert that to
2150 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
2151 * part 1 (signed thing)
2152 * part 2 has been freed
2154 * We also extract the signature from part 2 and save it
2155 * in the multipart body->sparep, and we add a description
2156 * in the multipart body->description.
2159 * The results of a decrypted message will be similar. It
2162 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
2163 * part 1 (decrypted thing)
2166 modified_the_body
+= do_detached_signature_verify(b
, msgno
, section
);
2168 else if(MIME_MSG(b
->type
, b
->subtype
)){
2169 modified_the_body
+= do_fiddle_smime_message(b
->nested
.msg
->body
, msgno
, section
);
2173 for(p
=b
->nested
.part
,partNum
=1; p
; p
=p
->next
,partNum
++){
2175 /* Append part number to the section string */
2177 snprintf(newSec
, sizeof(newSec
), "%s%s%d", section
, *section
? "." : "", partNum
);
2179 modified_the_body
+= do_fiddle_smime_message(&p
->body
, msgno
, newSec
);
2184 return modified_the_body
;
2189 * Fiddle a message in-place by decrypting/verifying S/MIME entities.
2190 * Returns non-zero if something was changed.
2193 fiddle_smime_message(BODY
*b
, long msgno
)
2195 return do_fiddle_smime_message(b
, msgno
, "");
2199 /********************************************************************************/
2203 * Output a string in a distinctive style
2206 gf_puts_uline(char *txt
, gf_io_t pc
)
2208 pc(TAG_EMBED
); pc(TAG_BOLDON
);
2210 pc(TAG_EMBED
); pc(TAG_BOLDOFF
);
2215 * Sign a message. Called from call_mailer in send.c.
2217 * This takes the header for the outgoing message as well as a pointer
2218 * to the current body (which may be reallocated).
2221 sign_outgoing_message(METAENV
*header
, BODY
**bodyP
, int dont_detach
)
2223 STORE_S
*outs
= NULL
;
2224 BODY
*body
= *bodyP
;
2225 BODY
*newBody
= NULL
;
2228 PERSONAL_CERT
*pcert
;
2233 int flags
= dont_detach
? 0 : PKCS7_DETACHED
;
2235 dprint((9, "sign_outgoing_message()"));
2239 /* Look for a private key matching the sender address... */
2241 pcert
= match_personal_cert(header
->env
);
2244 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find the certificate needed to sign."));
2248 if(!load_private_key(pcert
) && ps_global
->smime
&& ps_global
->smime
->need_passphrase
){
2249 /* Couldn't load key with blank password, try again */
2250 if(pith_opt_smime_get_passphrase
){
2251 (*pith_opt_smime_get_passphrase
)();
2252 load_private_key(pcert
);
2259 in
= body_to_bio(body
);
2262 dump_bio_to_file(in
,"/tmp/signed-data");
2265 p7
= PKCS7_sign(pcert
->cert
, pcert
->key
, NULL
, in
, flags
);
2267 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
2268 forget_private_keys();
2271 q_status_message(SM_ORDER
, 1, 1, _("Error creating signed object."));
2275 outs
= so_get(BioType
, NULL
, EDIT_ACCESS
);
2276 out
= bio_from_store(outs
);
2278 i2d_PKCS7_bio(out
, p7
);
2279 (void) BIO_flush(out
);
2281 so_seek(outs
, 0, SEEK_SET
);
2283 if((flags
&PKCS7_DETACHED
)==0){
2285 /* the simple case: the signed data is in the pkcs7 object */
2287 newBody
= mail_newbody();
2289 setup_pkcs7_body_for_signature(newBody
, "S/MIME Cryptographically Signed Message", "pkcs7-mime", "smime.p7m");
2291 newBody
->contents
.text
.data
= (unsigned char *) outs
;
2300 * We have to create a new body as follows:
2302 * multipart/signed; blah blah blah
2303 * reference to existing body
2308 newBody
= mail_newbody();
2310 newBody
->type
= TYPEMULTIPART
;
2311 newBody
->subtype
= cpystr("signed");
2312 newBody
->encoding
= ENC7BIT
;
2314 set_parameter(&newBody
->parameter
, "protocol", "application/pkcs7-signature");
2315 set_parameter(&newBody
->parameter
, "micalg", "sha1");
2317 p1
= mail_newbody_part();
2318 p2
= mail_newbody_part();
2321 * This is nasty. We're just copying the body in here,
2322 * but since our newBody is freed at the end of call_mailer,
2323 * we mustn't let this body (the original one) be freed twice.
2325 p1
->body
= *body
; /* ARRGH. This is special cased at the end of call_mailer */
2329 setup_pkcs7_body_for_signature(&p2
->body
, "S/MIME Cryptographic Signature", "pkcs7-signature", "smime.p7s");
2330 p2
->body
.contents
.text
.data
= (unsigned char *) outs
;
2332 newBody
->nested
.part
= p1
;
2344 dprint((9, "sign_outgoing_message returns %d", result
));
2350 new_smime_struct(void)
2352 SMIME_STUFF_S
*ret
= NULL
;
2354 ret
= (SMIME_STUFF_S
*) fs_get(sizeof(*ret
));
2355 memset((void *) ret
, 0, sizeof(*ret
));
2356 ret
->publictype
= Nada
;
2363 free_smime_struct(SMIME_STUFF_S
**smime
)
2365 if(smime
&& *smime
){
2366 if((*smime
)->passphrase_emailaddr
){
2368 for(i
= 0; (*smime
)->passphrase_emailaddr
[i
] != NULL
; i
++)
2369 fs_give((void **) &(*smime
)->passphrase_emailaddr
[i
]);
2370 fs_give((void **) (*smime
)->passphrase_emailaddr
);
2373 if((*smime
)->publicpath
)
2374 fs_give((void **) &(*smime
)->publicpath
);
2376 if((*smime
)->publiccertlist
)
2377 free_certlist(&(*smime
)->publiccertlist
);
2379 if((*smime
)->publiccontent
)
2380 fs_give((void **) &(*smime
)->publiccontent
);
2382 if((*smime
)->privatepath
)
2383 fs_give((void **) &(*smime
)->privatepath
);
2385 if((*smime
)->personal_certs
){
2388 pc
= (PERSONAL_CERT
*) (*smime
)->personal_certs
;
2389 free_personal_certs(&pc
);
2390 (*smime
)->personal_certs
= NULL
;
2393 if((*smime
)->privatecontent
)
2394 fs_give((void **) &(*smime
)->privatecontent
);
2396 if((*smime
)->capath
)
2397 fs_give((void **) &(*smime
)->capath
);
2399 if((*smime
)->cacontent
)
2400 fs_give((void **) &(*smime
)->cacontent
);
2402 fs_give((void **) smime
);