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 2013-2014 Eduardo Chappa
8 * Copyright 2008 University of Washington
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
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
20 * This is based on a contribution from Jonathan Paisley
23 * Author: paisleyj@dcs.gla.ac.uk
28 #include "../pith/headers.h"
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"
46 #include <openssl/buffer.h>
49 typedef enum {Public
, Private
, CACert
} WhichCerts
;
52 /* internal prototypes */
53 static void forget_private_keys(void);
54 static int app_RAND_load_file(const char *file
);
55 static void openssl_extra_randomness(void);
56 static int app_RAND_write_file(const char *file
);
57 static void smime_init(void);
58 static const char *openssl_error_string(void);
59 static void create_local_cache(char *h
, char *base
, BODY
*b
);
60 static long rfc822_output_func(void *b
, char *string
);
61 static int load_private_key(PERSONAL_CERT
*pcert
);
62 static void setup_pkcs7_body_for_signature(BODY
*b
, char *description
,
63 char *type
, char *filename
);
64 static BIO
*body_to_bio(BODY
*body
);
65 static BIO
*bio_from_store(STORE_S
*store
);
66 static STORE_S
*get_part_contents(long msgno
, const char *section
);
67 static PKCS7
*get_pkcs7_from_part(long msgno
, const char *section
);
68 static int do_signature_verify(PKCS7
*p7
, BIO
*in
, BIO
*out
, int silent
);
69 static int do_detached_signature_verify(BODY
*b
, long msgno
, char *section
);
70 static PERSONAL_CERT
*find_certificate_matching_pkcs7(PKCS7
*p7
);
71 static int do_decoding(BODY
*b
, long msgno
, const char *section
);
72 static void free_smime_struct(SMIME_STUFF_S
**smime
);
73 static void setup_storage_locations(void);
74 static int copy_dir_to_container(WhichCerts which
);
75 static int copy_container_to_dir(WhichCerts which
);
78 int (*pith_opt_smime_get_passphrase
)(void);
81 static X509_STORE
*s_cert_store
;
83 /* State management for randomness functions below */
84 static int seeded
= 0;
85 static int egdsocket
= 0;
89 * Forget any cached private keys
92 forget_private_keys(void)
98 dprint((9, "forget_private_keys()"));
100 for(pcert
=(PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
105 EVP_PKEY_free(pcert
->key
);
110 ps_global
->smime
->entered_passphrase
= 0;
111 len
= sizeof(ps_global
->smime
->passphrase
);
112 p
= ps_global
->smime
->passphrase
;
121 * taken from openssl/apps/app_rand.c
124 app_RAND_load_file(const char *file
)
129 file
= RAND_file_name(buffer
, sizeof buffer
);
130 else if(RAND_egd(file
) > 0){
131 /* we try if the given filename is an EGD socket.
132 if it is, we don't write anything back to the file. */
137 if(file
== NULL
|| !RAND_load_file(file
, -1)){
138 if(RAND_status() == 0){
139 dprint((1, "unable to load 'random state'\n"));
140 dprint((1, "This means that the random number generator has not been seeded\n"));
141 dprint((1, "with much random data.\n"));
153 * copied and fiddled from imap/src/osdep/unix/auth_ssl.c
156 openssl_extra_randomness(void)
164 /* if system doesn't have /dev/urandom */
165 if(stat ("/dev/urandom", &sbuf
)){
167 tf
= temp_nam(NULL
, NULL
);
169 strncpy(tmp
, tf
, sizeof(tmp
));
170 tmp
[sizeof(tmp
)-1] = '\0';
171 fs_give((void **) &tf
);
174 if((fd
= open(tmp
, O_WRONLY
|O_CREAT
|O_EXCL
, 0600)) < 0)
175 i
= (unsigned long) tmp
;
177 unlink(tmp
); /* don't need the file */
178 fstat(fd
, &sbuf
); /* get information about the file */
179 i
= sbuf
.st_ino
; /* remember its inode */
180 close(fd
); /* or its descriptor */
182 /* not great but it'll have to do */
183 snprintf(tmp
+strlen(tmp
), sizeof(tmp
)-strlen(tmp
), "%.80s%lx%lx%lx",
185 (unsigned long) (time (0) ^ gethostid ()),
186 (unsigned long) getpid ());
187 RAND_seed(tmp
, strlen(tmp
));
193 /* taken from openssl/apps/app_rand.c */
195 app_RAND_write_file(const char *file
)
199 if(egdsocket
|| !seeded
)
201 * If we did not manage to read the seed file,
202 * we should not write a low-entropy seed file back --
203 * it would suppress a crucial warning the next time
209 file
= RAND_file_name(buffer
, sizeof buffer
);
211 if(file
== NULL
|| !RAND_write_file(file
)){
212 dprint((1, "unable to write 'random state'\n"));
220 /* Installed as an atexit() handler to save the random data */
224 dprint((9, "smime_deinit()"));
225 app_RAND_write_file(NULL
);
226 free_smime_struct(&ps_global
->smime
);
230 /* Initialise openssl stuff if needed */
234 if(F_OFF(F_DONT_DO_SMIME
, ps_global
) && !(ps_global
->smime
&& ps_global
->smime
->inited
)){
236 dprint((9, "smime_init()"));
237 if(!ps_global
->smime
)
238 ps_global
->smime
= new_smime_struct();
240 setup_storage_locations();
242 s_cert_store
= get_ca_store();
244 OpenSSL_add_all_algorithms();
245 ERR_load_crypto_strings();
247 app_RAND_load_file(NULL
);
249 openssl_extra_randomness();
250 ps_global
->smime
->inited
= 1;
258 setup_storage_locations(void)
260 int publiccertcontainer
= 0, privatekeycontainer
= 0, cacertcontainer
= 0;
261 char path
[MAXPATH
+1], *contents
;
263 if(!ps_global
->smime
)
267 if(F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
268 ps_global
->smime
->publictype
= Keychain
;
271 #endif /* APPLEKEYCHAIN */
272 /* Public certificates in a container */
273 if(ps_global
->VAR_PUBLICCERT_CONTAINER
&& ps_global
->VAR_PUBLICCERT_CONTAINER
[0]){
275 publiccertcontainer
= 1;
278 if(!signature_path(ps_global
->VAR_PUBLICCERT_CONTAINER
, path
, MAXPATH
))
279 publiccertcontainer
= 0;
281 if(publiccertcontainer
&& !IS_REMOTE(path
)
282 && ps_global
->VAR_OPER_DIR
283 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
284 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
285 /* TRANSLATORS: First arg is the directory name, second is
286 the file user wants to read but can't. */
287 _("Can't read file outside %s: %s"),
288 ps_global
->VAR_OPER_DIR
, path
);
289 publiccertcontainer
= 0;
292 if(publiccertcontainer
293 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
294 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
296 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
297 publiccertcontainer
= 0;
300 if(publiccertcontainer
&& path
[0]){
301 ps_global
->smime
->publictype
= Container
;
302 ps_global
->smime
->publicpath
= cpystr(path
);
305 ps_global
->smime
->publiccontent
= contents
;
306 ps_global
->smime
->publiccertlist
= mem_to_certlist(contents
);
311 /* Public certificates in a directory of files */
312 if(!publiccertcontainer
){
313 ps_global
->smime
->publictype
= Directory
;
316 if(!(signature_path(ps_global
->VAR_PUBLICCERT_DIR
, path
, MAXPATH
)
317 && !IS_REMOTE(path
)))
318 ps_global
->smime
->publictype
= Nada
;
319 else if(can_access(path
, ACCESS_EXISTS
)){
320 if(our_mkpath(path
, 0700)){
321 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
322 ps_global
->smime
->publictype
= Nada
;
326 if(ps_global
->smime
->publictype
== Directory
)
327 ps_global
->smime
->publicpath
= cpystr(path
);
332 #endif /* APPLEKEYCHAIN */
334 /* private keys in a container */
335 if(ps_global
->VAR_PRIVATEKEY_CONTAINER
&& ps_global
->VAR_PRIVATEKEY_CONTAINER
[0]){
337 privatekeycontainer
= 1;
340 if(!signature_path(ps_global
->VAR_PRIVATEKEY_CONTAINER
, path
, MAXPATH
))
341 privatekeycontainer
= 0;
343 if(privatekeycontainer
&& !IS_REMOTE(path
)
344 && ps_global
->VAR_OPER_DIR
345 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
346 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
347 /* TRANSLATORS: First arg is the directory name, second is
348 the file user wants to read but can't. */
349 _("Can't read file outside %s: %s"),
350 ps_global
->VAR_OPER_DIR
, path
);
351 privatekeycontainer
= 0;
354 if(privatekeycontainer
355 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
356 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
358 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
359 privatekeycontainer
= 0;
362 if(privatekeycontainer
&& path
[0]){
363 ps_global
->smime
->privatetype
= Container
;
364 ps_global
->smime
->privatepath
= cpystr(path
);
367 ps_global
->smime
->privatecontent
= contents
;
368 ps_global
->smime
->personal_certs
= mem_to_personal_certs(contents
);
373 /* private keys in a directory of files */
374 if(!privatekeycontainer
){
375 PERSONAL_CERT
*result
= NULL
;
377 ps_global
->smime
->privatetype
= Directory
;
380 if(!(signature_path(ps_global
->VAR_PRIVATEKEY_DIR
, path
, MAXPATH
)
381 && !IS_REMOTE(path
)))
382 ps_global
->smime
->privatetype
= Nada
;
383 else if(can_access(path
, ACCESS_EXISTS
)){
384 if(our_mkpath(path
, 0700)){
385 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
386 ps_global
->smime
->privatetype
= Nada
;
390 if(ps_global
->smime
->privatetype
== Directory
){
395 ps_global
->smime
->privatepath
= cpystr(path
);
396 dirp
= opendir(path
);
399 while((d
=readdir(dirp
)) != NULL
){
403 if((ll
=strlen(d
->d_name
)) && ll
> 4 && !strcmp(d
->d_name
+ll
-4, ".key")){
405 /* copy file name to temp buffer */
406 strncpy(buf2
, d
->d_name
, sizeof(buf2
)-1);
407 buf2
[sizeof(buf2
)-1] = '\0';
408 /* chop off ".key" trailier */
409 buf2
[strlen(buf2
)-4] = 0;
410 /* Look for certificate */
411 cert
= get_cert_for(buf2
);
416 /* create a new PERSONAL_CERT, fill it in */
418 pc
= (PERSONAL_CERT
*) fs_get(sizeof(*pc
));
420 pc
->name
= cpystr(buf2
);
422 /* Try to load the key with an empty password */
423 pc
->key
= load_key(pc
, "");
435 ps_global
->smime
->personal_certs
= result
;
438 /* extra cacerts in a container */
439 if(ps_global
->VAR_CACERT_CONTAINER
&& ps_global
->VAR_CACERT_CONTAINER
[0]){
444 if(!signature_path(ps_global
->VAR_CACERT_CONTAINER
, path
, MAXPATH
))
447 if(cacertcontainer
&& !IS_REMOTE(path
)
448 && ps_global
->VAR_OPER_DIR
449 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
450 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
451 /* TRANSLATORS: First arg is the directory name, second is
452 the file user wants to read but can't. */
453 _("Can't read file outside %s: %s"),
454 ps_global
->VAR_OPER_DIR
, path
);
459 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
460 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
462 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
466 if(cacertcontainer
&& path
[0]){
467 ps_global
->smime
->catype
= Container
;
468 ps_global
->smime
->capath
= cpystr(path
);
469 ps_global
->smime
->cacontent
= contents
;
473 if(!cacertcontainer
){
474 ps_global
->smime
->catype
= Directory
;
477 if(!(signature_path(ps_global
->VAR_CACERT_DIR
, path
, MAXPATH
)
478 && !IS_REMOTE(path
)))
479 ps_global
->smime
->catype
= Nada
;
480 else if(can_access(path
, ACCESS_EXISTS
)){
481 if(our_mkpath(path
, 0700)){
482 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
483 ps_global
->smime
->catype
= Nada
;
487 if(ps_global
->smime
->catype
== Directory
)
488 ps_global
->smime
->capath
= cpystr(path
);
494 copy_publiccert_dir_to_container(void)
496 return(copy_dir_to_container(Public
));
501 copy_publiccert_container_to_dir(void)
503 return(copy_container_to_dir(Public
));
508 copy_privatecert_dir_to_container(void)
510 return(copy_dir_to_container(Private
));
515 copy_privatecert_container_to_dir(void)
517 return(copy_container_to_dir(Private
));
522 copy_cacert_dir_to_container(void)
524 return(copy_dir_to_container(CACert
));
529 copy_cacert_container_to_dir(void)
531 return(copy_container_to_dir(CACert
));
536 * returns 0 on success, -1 on failure
539 copy_dir_to_container(WhichCerts which
)
542 BIO
*bio_out
= NULL
, *bio_in
= NULL
;
543 char srcpath
[MAXPATH
+1], dstpath
[MAXPATH
+1], emailaddr
[MAXPATH
], file
[MAXPATH
], line
[4096];
544 char *tempfile
= NULL
;
547 REMDATA_S
*rd
= NULL
;
548 char *configdir
= NULL
;
549 char *configpath
= NULL
;
550 char *filesuffix
= NULL
;
552 dprint((9, "copy_dir_to_container(%s)", which
==Public
? "Public" : which
==Private
? "Private" : which
==CACert
? "CACert" : "?"));
561 configdir
= ps_global
->VAR_PUBLICCERT_DIR
;
562 configpath
= ps_global
->smime
->publicpath
;
565 else if(which
== Private
){
566 configdir
= ps_global
->VAR_PRIVATEKEY_DIR
;
567 configpath
= ps_global
->smime
->privatepath
;
570 else if(which
== CACert
){
571 configdir
= ps_global
->VAR_CACERT_DIR
;
572 configpath
= ps_global
->smime
->capath
;
576 if(!(configdir
&& configdir
[0])){
577 q_status_message(SM_ORDER
, 3, 3, _("Directory not defined"));
581 if(!(configpath
&& configpath
[0])){
583 if(which
== Public
&& F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
584 q_status_message(SM_ORDER
, 3, 3, _("Turn off the Keychain feature above first"));
587 #endif /* APPLEKEYCHAIN */
588 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
592 if(!(filesuffix
&& strlen(filesuffix
) == 4)){
598 * If there is a legit directory to read from set up the
599 * container file to write to.
601 if(signature_path(configdir
, srcpath
, MAXPATH
) && !IS_REMOTE(srcpath
)){
603 if(IS_REMOTE(configpath
)){
604 rd
= rd_create_remote(RemImap
, configpath
, REMOTE_SMIME_SUBTYPE
,
606 _("Can't access remote smime configuration."));
610 (void) rd_read_metadata(rd
);
612 if(rd
->access
== MaybeRorW
){
613 if(rd
->read_status
== 'R')
614 rd
->access
= ReadOnly
;
616 rd
->access
= ReadWrite
;
619 if(rd
->access
!= NoExists
){
621 rd_check_remvalid(rd
, 1L);
624 * If the cached info says it is readonly but
625 * it looks like it's been fixed now, change it to readwrite.
627 if(rd
->read_status
== 'R'){
628 rd_check_readonly_access(rd
);
629 if(rd
->read_status
== 'W'){
630 rd
->access
= ReadWrite
;
631 rd
->flags
|= REM_OUTOFDATE
;
634 rd
->access
= ReadOnly
;
638 if(rd
->flags
& REM_OUTOFDATE
){
639 if(rd_update_local(rd
) != 0){
641 dprint((1, "copy_dir_to_container: rd_update_local failed\n"));
642 rd_close_remdata(&rd
);
649 if(rd
->access
!= ReadWrite
|| rd_remote_is_readonly(rd
)){
650 rd_close_remdata(&rd
);
654 rd
->flags
|= DO_REMTRIM
;
656 strncpy(dstpath
, rd
->lf
, sizeof(dstpath
)-1);
657 dstpath
[sizeof(dstpath
)-1] = '\0';
660 strncpy(dstpath
, configpath
, sizeof(dstpath
)-1);
661 dstpath
[sizeof(dstpath
)-1] = '\0';
665 * dstpath is either the local Container file or the local cache file
666 * for the remote Container file.
668 tempfile
= tempfile_in_same_dir(dstpath
, "az", NULL
);
672 * If there is a legit directory to read from and a tempfile
673 * to write to we continue.
675 if(tempfile
&& (bio_out
=BIO_new_file(tempfile
, "w")) != NULL
){
677 dirp
= opendir(srcpath
);
680 while((d
=readdir(dirp
)) && !ret
){
683 if((ll
=strlen(d
->d_name
)) && ll
> 4 && !strcmp(d
->d_name
+ll
-4, filesuffix
)){
685 /* copy file name to temp buffer */
686 strncpy(emailaddr
, d
->d_name
, sizeof(emailaddr
)-1);
687 emailaddr
[sizeof(emailaddr
)-1] = '\0';
688 /* chop off suffix trailier */
689 emailaddr
[strlen(emailaddr
)-4] = 0;
692 * This is the separator between the contents of
696 if(!((BIO_puts(bio_out
, CACERTSTORELEADER
) > 0)
697 && (BIO_puts(bio_out
, emailaddr
) > 0)
698 && (BIO_puts(bio_out
, "\n") > 0)))
702 if(!((BIO_puts(bio_out
, EMAILADDRLEADER
) > 0)
703 && (BIO_puts(bio_out
, emailaddr
) > 0)
704 && (BIO_puts(bio_out
, "\n") > 0)))
708 /* read then write contents of file */
709 build_path(file
, srcpath
, d
->d_name
, sizeof(file
));
710 if(!(bio_in
= BIO_new_file(file
, "r")))
716 while(BIO_gets(bio_in
, line
, sizeof(line
)) > 0){
717 if(strncmp("-----BEGIN", line
, strlen("-----BEGIN")) == 0)
721 BIO_puts(bio_out
, line
);
723 if(strncmp("-----END", line
, strlen("-----END")) == 0)
738 if(rename_file(tempfile
, dstpath
) < 0){
739 q_status_message2(SM_ORDER
, 3, 3,
740 _("Can't rename %s to %s"), tempfile
, dstpath
);
744 /* if the container is remote, copy it */
745 if(!ret
&& IS_REMOTE(configpath
)){
751 if((e
= rd_update_remote(rd
, datebuf
)) != 0){
753 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
754 _("Error opening temporary smime file %s: %s"),
755 rd
->lf
, error_description(errno
));
757 "write_remote_smime: error opening temp file %s\n",
758 rd
->lf
? rd
->lf
: "?"));
761 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
762 _("Error copying to %s: %s"),
763 rd
->rn
, error_description(errno
));
765 "write_remote_smime: error copying from %s to %s\n",
766 rd
->lf
? rd
->lf
: "?", rd
->rn
? rd
->rn
: "?"));
769 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
770 _("Copy of smime key to remote folder failed, NOT saved remotely"));
773 rd_update_metadata(rd
, datebuf
);
774 rd
->read_status
= 'W';
777 rd_close_remdata(&rd
);
783 fs_give((void **) &tempfile
);
790 * returns 0 on success, -1 on failure
793 copy_container_to_dir(WhichCerts which
)
795 char path
[MAXPATH
+1], file
[MAXPATH
+1], buf
[MAXPATH
+1];
797 char *contents
= NULL
;
799 char *filesuffix
= NULL
;
800 char *configdir
= NULL
;
801 char *configpath
= NULL
;
802 char *tempfile
= NULL
;
803 char *p
, *q
, *line
, *name
, *certtext
, *save_p
;
807 dprint((9, "copy_container_to_dir(%s)", which
==Public
? "Public" : which
==Private
? "Private" : which
==CACert
? "CACert" : "?"));
813 leader
= EMAILADDRLEADER
;
814 contents
= ps_global
->smime
->publiccontent
;
815 configdir
= ps_global
->VAR_PUBLICCERT_DIR
;
816 configpath
= ps_global
->smime
->publicpath
;
818 if(!(configpath
&& configpath
[0])){
820 if(which
== Public
&& F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
821 q_status_message(SM_ORDER
, 3, 3, _("Turn off the Keychain feature above first"));
824 #endif /* APPLEKEYCHAIN */
825 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
829 fs_give((void **) &ps_global
->smime
->publicpath
);
832 if(!(signature_path(ps_global
->VAR_PUBLICCERT_DIR
, path
, MAXPATH
)
833 && !IS_REMOTE(path
))){
834 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
838 if(can_access(path
, ACCESS_EXISTS
)){
839 if(our_mkpath(path
, 0700)){
840 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
845 ps_global
->smime
->publicpath
= cpystr(path
);
846 configpath
= ps_global
->smime
->publicpath
;
848 else if(which
== Private
){
849 leader
= EMAILADDRLEADER
;
850 contents
= ps_global
->smime
->privatecontent
;
851 configdir
= ps_global
->VAR_PRIVATEKEY_DIR
;
852 configpath
= ps_global
->smime
->privatepath
;
854 if(!(configpath
&& configpath
[0])){
855 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
859 fs_give((void **) &ps_global
->smime
->privatepath
);
862 if(!(signature_path(ps_global
->VAR_PRIVATEKEY_DIR
, path
, MAXPATH
)
863 && !IS_REMOTE(path
))){
864 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
868 if(can_access(path
, ACCESS_EXISTS
)){
869 if(our_mkpath(path
, 0700)){
870 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
875 ps_global
->smime
->privatepath
= cpystr(path
);
876 configpath
= ps_global
->smime
->privatepath
;
878 else if(which
== CACert
){
879 leader
= CACERTSTORELEADER
;
880 contents
= ps_global
->smime
->cacontent
;
881 configdir
= ps_global
->VAR_CACERT_DIR
;
882 configpath
= ps_global
->smime
->capath
;
884 if(!(configpath
&& configpath
[0])){
885 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
889 fs_give((void **) &ps_global
->smime
->capath
);
892 if(!(signature_path(ps_global
->VAR_CACERT_DIR
, path
, MAXPATH
)
893 && !IS_REMOTE(path
))){
894 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
898 if(can_access(path
, ACCESS_EXISTS
)){
899 if(our_mkpath(path
, 0700)){
900 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
905 ps_global
->smime
->capath
= cpystr(path
);
906 configpath
= ps_global
->smime
->capath
;
909 if(!(configdir
&& configdir
[0])){
910 q_status_message(SM_ORDER
, 3, 3, _("Directory not defined"));
914 if(!(configpath
&& configpath
[0])){
915 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
919 if(!(filesuffix
&& strlen(filesuffix
) == 4)){
924 if(contents
&& *contents
){
925 for(p
= contents
; *p
!= '\0';){
928 while(*p
&& *p
!= '\n')
937 if(strncmp(leader
, line
, strlen(leader
)) == 0){
938 name
= line
+ strlen(leader
);
940 if(strncmp("-----BEGIN", certtext
, strlen("-----BEGIN")) == 0){
941 if((q
= strstr(certtext
, leader
)) != NULL
){
944 else{ /* end of file */
945 q
= certtext
+ strlen(certtext
);
949 strncpy(buf
, name
, sizeof(buf
)-5);
950 buf
[sizeof(buf
)-5] = '\0';
951 strncat(buf
, filesuffix
, 5);
952 build_path(file
, configpath
, buf
, sizeof(file
));
954 in
= BIO_new_mem_buf(certtext
, q
-certtext
);
956 tempfile
= tempfile_in_same_dir(file
, "az", NULL
);
959 out
= BIO_new_file(tempfile
, "w");
962 while((len
= BIO_read(in
, iobuf
, sizeof(iobuf
))) > 0)
963 BIO_write(out
, iobuf
, len
);
967 if(rename_file(tempfile
, file
) < 0){
968 q_status_message2(SM_ORDER
, 3, 3,
969 _("Can't rename %s to %s"),
974 fs_give((void **) &tempfile
);
994 copy_publiccert_container_to_keychain(void)
1001 copy_publiccert_keychain_to_container(void)
1003 /* NOT IMPLEMNTED */
1007 #endif /* APPLEKEYCHAIN */
1011 * Get a pointer to a string describing the most recent OpenSSL error.
1012 * It's statically allocated, so don't change or attempt to free it.
1015 openssl_error_string(void)
1018 const char *data
= NULL
;
1021 errn
= ERR_peek_error_line_data(NULL
, NULL
, &data
, NULL
);
1022 errs
= (char*) ERR_reason_error_string(errn
);
1029 return "unknown error";
1033 /* Return true if the body looks like a PKCS7 object */
1035 is_pkcs7_body(BODY
*body
)
1039 result
= body
->type
==TYPEAPPLICATION
&&
1041 (strucmp(body
->subtype
,"pkcs7-mime")==0 ||
1042 strucmp(body
->subtype
,"x-pkcs7-mime")==0 ||
1043 strucmp(body
->subtype
,"pkcs7-signature")==0 ||
1044 strucmp(body
->subtype
,"x-pkcs7-signature")==0);
1052 * Somewhat useful debug utility to dump the contents of a BIO to a file.
1053 * Note that a memory BIO will have its contents eliminated after they
1054 * are read so this will break the next step.
1057 dump_bio_to_file(BIO
*in
, char *filename
)
1063 out
= BIO_new_file(filename
, "w");
1066 if(BIO_method_type(in
) != BIO_TYPE_MEM
)
1069 while((len
= BIO_read(in
, iobuf
, sizeof(iobuf
))) > 0)
1070 BIO_write(out
, iobuf
, len
);
1081 * Recursively stash a pointer to the decrypted data in our
1082 * manufactured body.
1085 create_local_cache(char *h
, char *base
, BODY
*b
)
1087 if(b
->type
==TYPEMULTIPART
){
1091 cpytxt(&b
->contents
.text
, base
+ b
->contents
.offset
, b
->size
.bytes
);
1094 * We don't really want to copy the real body contents. It shouldn't be
1095 * used, and in the case of a message with attachments, we'll be
1096 * duplicating the files multiple times.
1098 cpytxt(&b
->contents
.text
, "BODY UNAVAILABLE", 16);
1101 for(p
=b
->nested
.part
; p
; p
=p
->next
)
1102 create_local_cache(h
, base
, (BODY
*) p
);
1105 cpytxt(&b
->mime
.text
, h
+b
->mime
.offset
, b
->mime
.text
.size
);
1106 cpytxt(&b
->contents
.text
, base
+ b
->contents
.offset
, b
->size
.bytes
);
1112 rfc822_output_func(void *b
, char *string
)
1114 BIO
*bio
= (BIO
*) b
;
1116 return(string
? *string
? (BIO_puts(bio
, string
) > 0 ? 1L : 0L)
1117 : (BIO_puts(bio
, string
) >= 0 ? 1L : 0L)
1123 * Attempt to load the private key for the given PERSONAL_CERT.
1124 * This sets the appropriate passphrase globals in order to
1125 * interact with the user correctly.
1128 load_private_key(PERSONAL_CERT
*pcert
)
1132 /* Try empty password by default */
1133 char *password
= "";
1136 && (ps_global
->smime
->need_passphrase
1137 || ps_global
->smime
->entered_passphrase
)){
1138 /* We've already been in here and discovered we need a different password */
1140 if(ps_global
->smime
->entered_passphrase
)
1141 password
= (char *) ps_global
->smime
->passphrase
; /* already entered */
1148 if(!(pcert
->key
= load_key(pcert
, password
))){
1149 long err
= ERR_get_error();
1151 /* Couldn't load key... */
1153 if(ps_global
->smime
&& ps_global
->smime
->entered_passphrase
){
1155 /* The user got the password wrong maybe? */
1157 if((ERR_GET_LIB(err
)==ERR_LIB_EVP
&& ERR_GET_REASON(err
)==EVP_R_BAD_DECRYPT
) ||
1158 (ERR_GET_LIB(err
)==ERR_LIB_PEM
&& ERR_GET_REASON(err
)==PEM_R_BAD_DECRYPT
))
1159 q_status_message(SM_ORDER
| SM_DING
, 4, 4, _("Incorrect passphrase"));
1161 q_status_message1(SM_ORDER
, 4, 4, _("Couldn't read key: %s"),(char*)openssl_error_string());
1163 /* This passphrase is no good; forget it */
1164 ps_global
->smime
->entered_passphrase
= 0;
1167 if(ps_global
->smime
){
1168 /* Indicate to the UI that we need re-entry (see mailcmd.c:process_cmd())*/
1169 ps_global
->smime
->need_passphrase
= 1;
1170 if(ps_global
->smime
->passphrase_emailaddr
){
1172 for(i
= 0; ps_global
->smime
->passphrase_emailaddr
[i
] != NULL
; i
++)
1173 fs_give((void **)&ps_global
->smime
->passphrase_emailaddr
[i
]);
1174 fs_give((void **) ps_global
->smime
->passphrase_emailaddr
);
1177 ps_global
->smime
->passphrase_emailaddr
= get_x509_subject_email(pcert
->cert
);
1183 /* This key will be cached, so we won't be called again */
1184 if(ps_global
->smime
){
1185 ps_global
->smime
->entered_passphrase
= 0;
1186 ps_global
->smime
->need_passphrase
= 0;
1198 setup_pkcs7_body_for_signature(BODY
*b
, char *description
, char *type
, char *filename
)
1200 b
->type
= TYPEAPPLICATION
;
1201 b
->subtype
= cpystr(type
);
1202 b
->encoding
= ENCBINARY
;
1203 b
->description
= cpystr(description
);
1205 b
->disposition
.type
= cpystr("attachment");
1206 set_parameter(&b
->disposition
.parameter
, "filename", filename
);
1208 set_parameter(&b
->parameter
, "name", filename
);
1213 * Look for a personal certificate matching the
1217 match_personal_cert_to_email(ADDRESS
*a
)
1219 PERSONAL_CERT
*pcert
= NULL
;
1224 if(!a
|| !a
->mailbox
|| !a
->host
)
1227 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
1229 if(ps_global
->smime
){
1230 for(pcert
=(PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
1237 email
= get_x509_subject_email(pcert
->cert
);
1241 for(i
= 0; email
[i
] && strucmp(email
[i
], buf
) != 0; i
++);
1242 if(email
[i
] != NULL
) done
++;
1243 for(i
= 0; email
[i
] != NULL
; i
++)
1244 fs_give((void **)&email
[i
]);
1245 fs_give((void **)email
);
1258 * Look for a personal certificate matching the from
1259 * (or reply_to? in the given envelope)
1262 match_personal_cert(ENVELOPE
*env
)
1264 PERSONAL_CERT
*pcert
;
1266 pcert
= match_personal_cert_to_email(env
->reply_to
);
1268 pcert
= match_personal_cert_to_email(env
->from
);
1275 * Flatten the given body into its MIME representation.
1276 * Return the result in a BIO.
1279 body_to_bio(BODY
*body
)
1284 bio
= BIO_new(BIO_s_mem());
1288 pine_encode_body(body
); /* this attaches random boundary strings to multiparts */
1289 pine_write_body_header(body
, rfc822_output_func
, bio
);
1290 pine_rfc822_output_body(body
, rfc822_output_func
, bio
);
1293 * Now need to truncate by two characters since the above
1296 if((len
=BIO_ctrl_pending(bio
)) > 1){
1297 BUF_MEM
*biobuf
= NULL
;
1299 BIO_get_mem_ptr(bio
, &biobuf
);
1301 BUF_MEM_grow(biobuf
, len
-2); /* remove CRLF */
1310 bio_from_store(STORE_S
*store
)
1314 if(store
&& store
->src
== BioType
&& store
->txt
){
1315 ret
= (BIO
*) store
->txt
;
1322 * Encrypt file; given a path (char *) fp, replace the file
1323 * by an encrypted version of it. If (char *) text is not null, then
1324 * replace the text of (char *) fp by the encrypted version of (char *) text.
1327 encrypt_file(char *fp
, char *text
)
1329 const EVP_CIPHER
*cipher
= NULL
;
1330 STACK_OF(X509
) *encerts
= NULL
;
1332 PERSONAL_CERT
*pcert
;
1339 if((pcert
= ps_global
->smime
->personal_certs
) == NULL
)
1342 cipher
= EVP_aes_256_cbc();
1343 encerts
= sk_X509_new_null();
1345 if((cert
= get_cert_for(pcert
->name
)) != NULL
)
1346 sk_X509_push(encerts
, cert
);
1351 in
= BIO_new(BIO_s_mem());
1354 (void) BIO_reset(in
);
1358 if(!(in
= BIO_new_file(fp
, "rb")))
1361 BIO_read_filename(in
, fp
);
1364 if((p7
= PKCS7_encrypt(encerts
, in
, cipher
, 0)) == NULL
)
1366 BIO_set_close(in
, BIO_CLOSE
);
1368 if(!(in
= BIO_new_file(fp
, "w")))
1371 rv
= PEM_write_bio_PKCS7(in
, p7
);
1377 sk_X509_pop_free(encerts
, X509_free
);
1383 * Encrypt a message on the way out. Called from call_mailer in send.c
1384 * The body may be reallocated.
1387 encrypt_outgoing_message(METAENV
*header
, BODY
**bodyP
)
1392 const EVP_CIPHER
*cipher
= NULL
;
1393 STACK_OF(X509
) *encerts
= NULL
;
1394 STORE_S
*outs
= NULL
;
1397 BODY
*body
= *bodyP
;
1398 BODY
*newBody
= NULL
;
1401 dprint((9, "encrypt_outgoing_message()"));
1404 cipher
= EVP_aes_256_cbc();
1406 encerts
= sk_X509_new_null();
1408 /* Look for a certificate for each of the recipients */
1409 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
1410 if(pf
->type
== Address
&& pf
->rcptto
&& pf
->addr
&& *pf
->addr
){
1411 for(a
=*pf
->addr
; a
; a
=a
->next
){
1415 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
1417 cert
= get_cert_for(buf
);
1419 sk_X509_push(encerts
,cert
);
1421 q_status_message2(SM_ORDER
, 1, 1,
1422 _("Unable to find certificate for <%s@%s>"),
1423 a
->mailbox
, a
->host
);
1430 in
= body_to_bio(body
);
1432 p7
= PKCS7_encrypt(encerts
, in
, cipher
, 0);
1434 outs
= so_get(BioType
, NULL
, EDIT_ACCESS
);
1435 out
= bio_from_store(outs
);
1437 i2d_PKCS7_bio(out
, p7
);
1438 (void) BIO_flush(out
);
1440 so_seek(outs
, 0, SEEK_SET
);
1442 newBody
= mail_newbody();
1444 newBody
->type
= TYPEAPPLICATION
;
1445 newBody
->subtype
= cpystr("pkcs7-mime");
1446 newBody
->encoding
= ENCBINARY
;
1448 newBody
->disposition
.type
= cpystr("attachment");
1449 set_parameter(&newBody
->disposition
.parameter
, "filename", "smime.p7m");
1451 newBody
->description
= cpystr("S/MIME Encrypted Message");
1452 set_parameter(&newBody
->parameter
, "smime-type", "enveloped-data");
1453 set_parameter(&newBody
->parameter
, "name", "smime.p7m");
1455 newBody
->contents
.text
.data
= (unsigned char *) outs
;
1465 sk_X509_pop_free(encerts
, X509_free
);
1467 dprint((9, "encrypt_outgoing_message returns %d", result
));
1473 Get (and decode) the body of the given section of msg
1476 get_part_contents(long msgno
, const char *section
)
1480 STORE_S
*store
= NULL
;
1483 store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
1485 gf_set_so_writec(&pc
,store
);
1487 err
= detach(ps_global
->mail_stream
, msgno
, (char*) section
, 0L, &len
, pc
, NULL
, 0L);
1489 gf_clear_so_writec(store
);
1491 so_seek(store
, 0, SEEK_SET
);
1502 get_pkcs7_from_part(long msgno
,const char *section
)
1504 STORE_S
*store
= NULL
;
1508 store
= get_part_contents(msgno
, section
);
1511 if(store
->src
== CharStar
){
1515 * We're reaching inside the STORE_S structure. We should
1516 * probably have a way to get the length, instead.
1518 len
= (int) (store
->eod
- store
->dp
);
1519 in
= BIO_new_mem_buf(store
->txt
, len
);
1521 else{ /* just copy it */
1524 in
= BIO_new(BIO_s_mem());
1525 (void) BIO_reset(in
);
1527 so_seek(store
, 0L, 0);
1528 while(so_readc(&c
, store
)){
1529 BIO_write(in
, &c
, 1);
1534 /* dump_bio_to_file(in, "/tmp/decoded-signature"); */
1535 if((p7
=d2i_PKCS7_bio(in
,NULL
)) == NULL
){
1550 * Try to verify a signature.
1552 * p7 - the pkcs7 object to verify
1553 * in - the plain data to verify (NULL if not detached)
1554 * out - BIO to which to write the opaque data
1555 * silent - if non zero, do not print errors, only print success.
1558 do_signature_verify(PKCS7
*p7
, BIO
*in
, BIO
*out
, int silent
)
1560 STACK_OF(X509
) *otherCerts
= NULL
;
1567 dump_bio_to_file(in
,"/tmp/verified-data");
1571 if(!silent
) q_status_message(SM_ORDER
| SM_DING
, 2, 2,
1572 _("Couldn't verify S/MIME signature: No CA Certs were loaded"));
1577 result
= PKCS7_verify(p7
, otherCerts
, s_cert_store
, in
, out
, 0);
1580 q_status_message(SM_ORDER
, 1, 1, _("S/MIME signature verified ok"));
1583 err
= ERR_peek_error_line_data(NULL
, NULL
, &data
, NULL
);
1585 if(out
&& err
==ERR_PACK(ERR_LIB_PKCS7
,PKCS7_F_PKCS7_VERIFY
,PKCS7_R_CERTIFICATE_VERIFY_ERROR
)){
1587 /* Retry verification so we can get the plain text */
1588 /* Might be better to reimplement PKCS7_verify here? */
1590 PKCS7_verify(p7
, otherCerts
, s_cert_store
, in
, out
, PKCS7_NOVERIFY
);
1592 if (!silent
) q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
1593 _("Couldn't verify S/MIME signature: %s"), (char*) openssl_error_string());
1596 /* now try to extract the certificates of any signers */
1598 STACK_OF(X509
) *signers
;
1601 if((signers
= PKCS7_get0_signers(p7
, NULL
, 0)) != NULL
)
1602 for(i
=0; i
<sk_X509_num(signers
); i
++){
1606 if((x
= sk_X509_value(signers
,i
)) == NULL
)
1609 if((email
= get_x509_subject_email(x
)) != NULL
){
1611 for(i
= 0; email
[i
] != NULL
; i
++){
1612 if((cert
= get_cert_for(email
[i
])) != NULL
)
1615 save_cert_for(email
[i
], x
);
1616 fs_give((void **) &email
[i
]);
1618 fs_give((void **) email
);
1621 sk_X509_free(signers
);
1629 free_smime_body_sparep(void **sparep
)
1631 if(sparep
&& *sparep
){
1632 PKCS7_free((PKCS7
*) (*sparep
));
1637 /* Big comment, explaining the mess that exists out there, and how we deal
1638 with it, and also how we solve the problems that are created this way.
1640 When Alpine sends a message, it constructs that message, computes the
1641 signature, but then it forgets the message it signed and reconstructs it
1642 again. Since it signs a message containing a notice about "mime aware
1643 tools", but it does not send that we do not include that in the part that
1644 is signed, and that takes care of much of the problems.
1646 Another problem is what is received from the servers. All servers tested
1647 seem to transmit the message that was signed intact and Alpine can check
1648 the signature correctly. That is not a problem. The problem arises when
1649 the message includes attachments. In this case different servers send
1650 different things, so it will be up to us to figure out what is the text
1651 that was actually signed. Confused? here is the story:
1653 When a message containing and attachment is sent by Alpine, UW-IMAP,
1654 Panda-IMAP, Gmail, and local reading of folders send exactly the message
1655 that was sent by Alpine, but GMX.com, Exchange, and probably other servers
1656 add a trailing \r\n in the message, so when validating the signature,
1657 these messages will not validate. There are several things that can be
1660 1. Add a trailing \r\n to any message that contains attachments, sign that
1661 and send that. In this way, all messages will validate with all
1664 2. Compatibility mode: If a message has an attachment, contains a trailing
1665 \r\n and does not validate (sent by an earlier version of Alpine),
1666 remove the trailing \r\n and try to revalidate again.
1668 3. We do not add \r\n to validate a message that we sent, because that
1669 would only work in Alpine, and not in any other client. That would not
1670 be a good thing to do.
1674 Now we have to deal with encrypted and signed messages. The problem is that
1675 c-client makes all its pointers point to "on disk" content, but since we
1676 decrypted the data earlier, we have to make sure of two things. One is that we
1677 saved that data (so we do not have to decrypt it again) and second that we can
1680 In order to save the data we use create_local_cache, so that we do not
1681 have to redecrypt the message. Once this is saved, c-client functions will
1682 find it and send it to us in mail_fetch_mime and mail_fetch_body.
1687 * Given a multipart body of type multipart/signed, attempt to verify it.
1688 * Returns non-zero if the body was changed.
1691 do_detached_signature_verify(BODY
*b
, long msgno
, char *section
)
1696 int result
, modified_the_body
= 0;
1697 unsigned long mimelen
, bodylen
;
1698 char newSec
[100], *mimetext
, *bodytext
;
1701 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"));
1704 snprintf(newSec
, sizeof(newSec
), "%s%s1", section
? section
: "", (section
&& *section
) ? "." : "");
1706 mimetext
= mail_fetch_mime(ps_global
->mail_stream
, msgno
, (char*) newSec
, &mimelen
, 0);
1709 bodytext
= mail_fetch_body (ps_global
->mail_stream
, msgno
, (char*) newSec
, &bodylen
, 0);
1711 if (mimetext
== NULL
|| bodytext
== NULL
)
1712 return modified_the_body
;
1714 snprintf(newSec
, sizeof(newSec
), "%s%s2", section
? section
: "", (section
&& *section
) ? "." : "");
1716 if((p7
= get_pkcs7_from_part(msgno
, newSec
)) == NULL
1717 || (in
= BIO_new(BIO_s_mem())) == NULL
)
1718 return modified_the_body
;
1720 (void) BIO_reset(in
);
1721 BIO_write(in
, mimetext
, mimelen
);
1722 BIO_write(in
, bodytext
, bodylen
);
1724 /* Try compatibility with the past and check if this message
1725 * validates when we remove the last two characters. Silence
1726 * any failures first.
1728 if(((result
= do_signature_verify(p7
, in
, NULL
, 1)) == 0)
1730 && (strncmp(bodytext
+bodylen
-2,"\r\n", 2) == 0)){
1731 BUF_MEM
*biobuf
= NULL
;
1733 BIO_get_mem_ptr(in
, &biobuf
);
1735 BUF_MEM_grow(biobuf
, mimelen
+ bodylen
- 2);
1736 result
= do_signature_verify(p7
, in
, NULL
, 0);
1741 fs_give((void**) &b
->subtype
);
1743 b
->subtype
= cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE
);
1744 b
->encoding
= ENC8BIT
;
1747 fs_give ((void**) &b
->description
);
1749 what_we_did
= result
? _("This message was cryptographically signed.") :
1750 _("This message was cryptographically signed but the signature could not be verified.");
1752 b
->description
= cpystr(what_we_did
);
1758 /* p is signed plaintext */
1760 mail_free_body_part(&p
->next
); /* hide the pkcs7 from the viewer */
1762 modified_the_body
= 1;
1764 return modified_the_body
;
1769 find_certificate_matching_recip_info(PKCS7_RECIP_INFO
*ri
)
1771 PERSONAL_CERT
*x
= NULL
;
1773 if(ps_global
->smime
){
1774 for(x
= (PERSONAL_CERT
*) ps_global
->smime
->personal_certs
; x
; x
=x
->next
){
1779 if(!X509_NAME_cmp(ri
->issuer_and_serial
->issuer
,mine
->cert_info
->issuer
) &&
1780 !ASN1_INTEGER_cmp(ri
->issuer_and_serial
->serial
,mine
->cert_info
->serialNumber
)){
1790 static PERSONAL_CERT
*
1791 find_certificate_matching_pkcs7(PKCS7
*p7
)
1794 STACK_OF(PKCS7_RECIP_INFO
) *recips
;
1795 PERSONAL_CERT
*x
= NULL
;
1797 recips
= p7
->d
.enveloped
->recipientinfo
;
1799 for(i
=0; i
<sk_PKCS7_RECIP_INFO_num(recips
); i
++){
1800 PKCS7_RECIP_INFO
*ri
;
1802 ri
= sk_PKCS7_RECIP_INFO_value(recips
, i
);
1804 if((x
=find_certificate_matching_recip_info(ri
))!=0){
1812 /* decrypt an encrypted file.
1813 Args: fp - the path to the encrypted file.
1814 rv - a code that thells the caller what happened inside the function
1815 Returns the decoded text allocated in a char *, whose memory must be
1820 decrypt_file(char *fp
, int *rv
)
1824 BIO
*in
= NULL
, *out
= NULL
;
1825 EVP_PKEY
*pkey
= NULL
, *key
= NULL
;
1826 PERSONAL_CERT
*pcert
= NULL
;
1828 STORE_S
*outs
= NULL
, *store
, *ins
;
1830 long unsigned int len
;
1835 if((text
= read_file(fp
, 0)) == NULL
)
1838 tmp
= fs_get(strlen(text
) + (strlen(text
) << 6) + 1);
1839 for(j
= 0, i
= strlen("-----BEGIN PKCS7-----") + 1; text
[i
] != '\0'
1840 && text
[i
] != '-'; j
++, i
++)
1844 ret
= rfc822_base64(tmp
, strlen(tmp
), &len
);
1846 if((in
= BIO_new_mem_buf((char *)ret
, len
)) != NULL
){
1847 p7
= d2i_PKCS7_bio(in
, NULL
);
1851 if(text
) fs_give((void **)&text
);
1852 if(ret
) fs_give((void **)&ret
);
1854 if((pcert
= ps_global
->smime
->personal_certs
) == NULL
)
1857 if((i
= load_private_key(pcert
)) == 0
1859 && ps_global
->smime
->need_passphrase
1860 && !ps_global
->smime
->already_auto_asked
)
1862 ps_global
->smime
->already_auto_asked
= 1;
1863 if(pith_opt_smime_get_passphrase
){
1864 switch((*pith_opt_smime_get_passphrase
)()){
1865 case 0 : i
= load_private_key(pcert
);
1871 default: break; /* repeat until we cancel */
1880 if((key
= pcert
->key
) == NULL
)
1883 recip
= get_cert_for(pcert
->name
);
1884 out
= BIO_new(BIO_s_mem());
1885 (void) BIO_reset(out
);
1887 i
= PKCS7_decrypt(p7
, key
, recip
, out
, 0);
1889 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
1890 forget_private_keys();
1893 q_status_message1(SM_ORDER
, 1, 1, _("Error decrypting: %s"),
1894 (char*) openssl_error_string());
1898 BIO_get_mem_data(out
, &tmp
);
1910 * Try to decode (decrypt or verify a signature) a PKCS7 body
1911 * Returns non-zero if something was changed.
1914 do_decoding(BODY
*b
, long msgno
, const char *section
)
1916 int modified_the_body
= 0;
1920 EVP_PKEY
*key
= NULL
;
1921 PERSONAL_CERT
*pcert
= NULL
;
1922 char *what_we_did
= "";
1925 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"));
1930 * Extract binary data from part to an in-memory store
1933 if(b
->sparep
){ /* already done */
1934 p7
= (PKCS7
*) b
->sparep
;
1938 p7
= get_pkcs7_from_part(msgno
, section
&& *section
? section
: "1");
1940 q_status_message1(SM_ORDER
, 2, 2, "Couldn't load PKCS7 object: %s",
1941 (char*) openssl_error_string());
1946 * Save the PKCS7 object for later dealings by the user interface.
1947 * It will be cleaned up when the body is garbage collected.
1952 dprint((1, "type_is_signed = %d, type_is_enveloped = %d", PKCS7_type_is_signed(p7
), PKCS7_type_is_enveloped(p7
)));
1954 if(PKCS7_type_is_signed(p7
)){
1957 out
= BIO_new(BIO_s_mem());
1958 (void) BIO_reset(out
);
1959 BIO_puts(out
, "MIME-Version: 1.0\r\n"); /* needed so rfc822_parse_msg_full believes it's MIME */
1961 sigok
= do_signature_verify(p7
, NULL
, out
, 0);
1963 what_we_did
= sigok
? _("This message was cryptographically signed.") :
1964 _("This message was cryptographically signed but the signature could not be verified.");
1966 /* make sure it's null terminated */
1967 BIO_write(out
, null
, 1);
1969 else if(!PKCS7_type_is_enveloped(p7
)){
1970 q_status_message(SM_ORDER
, 1, 1, "PKCS7 object not recognised.");
1973 else{ /* It *is* enveloped */
1976 what_we_did
= _("This message was encrypted.");
1978 /* now need to find a cert that can decrypt this */
1979 pcert
= find_certificate_matching_pkcs7(p7
);
1982 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find the certificate needed to decrypt."));
1986 recip
= pcert
->cert
;
1988 if(!load_private_key(pcert
)
1990 && ps_global
->smime
->need_passphrase
1991 && !ps_global
->smime
->already_auto_asked
){
1992 /* Couldn't load key with blank password, ask user */
1993 ps_global
->smime
->already_auto_asked
= 1;
1994 if(pith_opt_smime_get_passphrase
){
1995 (*pith_opt_smime_get_passphrase
)();
1996 load_private_key(pcert
);
2004 out
= BIO_new(BIO_s_mem());
2005 (void) BIO_reset(out
);
2006 BIO_puts(out
, "MIME-Version: 1.0\r\n");
2008 decrypt_result
= PKCS7_decrypt(p7
, key
, recip
, out
, 0);
2010 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
2011 forget_private_keys();
2013 if(!decrypt_result
){
2014 q_status_message1(SM_ORDER
, 1, 1, _("Error decrypting: %s"),
2015 (char*) openssl_error_string());
2019 BIO_write(out
, null
, 1);
2023 * We've now produced a flattened MIME object in BIO out.
2024 * It needs to be turned back into a BODY.
2033 BUF_MEM
*bptr
= NULL
;
2035 BIO_get_mem_ptr(out
, &bptr
);
2039 /* look for start of body */
2040 bstart
= strstr(h
, "\r\n\r\n");
2043 q_status_message(SM_ORDER
, 3, 3, _("Encrypted data couldn't be parsed."));
2046 bstart
+= 4; /* skip over CRLF*2 */
2048 INIT(&s
, mail_string
, bstart
, strlen(bstart
));
2049 rfc822_parse_msg_full(&env
, &body
, h
, (bstart
-h
)-2, &s
, BADHOST
, 0, 0);
2050 mail_free_envelope(&env
); /* Don't care about this */
2052 body
->mime
.offset
= 0;
2053 body
->mime
.text
.size
= 0;
2055 * Now convert original body (application/pkcs7-mime)
2056 * to a multipart body with one sub-part (the decrypted body).
2057 * Note that the sub-part may also be multipart!
2060 b
->type
= TYPEMULTIPART
;
2062 fs_give((void**) &b
->subtype
);
2065 * This subtype is used in mailview.c to annotate the display of
2066 * encrypted or signed messages. We know for sure then that it's a PKCS7
2067 * part because the sparep field is set to the PKCS7 object (see above).
2069 b
->subtype
= cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE
);
2070 b
->encoding
= ENC8BIT
;
2073 fs_give((void**) &b
->description
);
2075 b
->description
= cpystr(what_we_did
);
2077 if(b
->disposition
.type
)
2078 fs_give((void **) &b
->disposition
.type
);
2080 if(b
->contents
.text
.data
)
2081 fs_give((void **) &b
->contents
.text
.data
);
2084 mail_free_body_parameter(&b
->parameter
);
2086 /* Allocate mem for the sub-part, and copy over the contents of our parsed body */
2087 b
->nested
.part
= fs_get(sizeof(PART
));
2088 b
->nested
.part
->body
= *body
;
2089 b
->nested
.part
->next
= NULL
;
2091 fs_give((void**) &body
);
2094 * IMPORTANT BIT: set the body->contents.text.data elements to contain the decrypted
2095 * data. Otherwise, it'll try to load it from the original data. Eek.
2097 create_local_cache(bstart
-b
->nested
.part
->body
.mime
.offset
, bstart
, &b
->nested
.part
->body
);
2099 modified_the_body
= 1;
2107 return modified_the_body
;
2112 * Recursively handle PKCS7 bodies in our message.
2114 * Returns non-zero if some fiddling was done.
2117 do_fiddle_smime_message(BODY
*b
, long msgno
, char *section
)
2119 int modified_the_body
= 0;
2124 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"));
2126 if(is_pkcs7_body(b
)){
2128 if(do_decoding(b
, msgno
, section
)){
2130 * b should now be a multipart message:
2131 * fiddle it too in case it's been multiply-encrypted!
2135 modified_the_body
= 1;
2139 if(b
->type
==TYPEMULTIPART
|| MIME_MSG(b
->type
, b
->subtype
)){
2145 if(MIME_MULT_SIGNED(b
->type
, b
->subtype
)){
2149 * Ahah. We have a multipart signed entity.
2152 * part 1 (signed thing)
2153 * part 2 (the pkcs7 signature)
2155 * We're going to convert that to
2157 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
2158 * part 1 (signed thing)
2159 * part 2 has been freed
2161 * We also extract the signature from part 2 and save it
2162 * in the multipart body->sparep, and we add a description
2163 * in the multipart body->description.
2166 * The results of a decrypted message will be similar. It
2169 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
2170 * part 1 (decrypted thing)
2173 modified_the_body
+= do_detached_signature_verify(b
, msgno
, section
);
2175 else if(MIME_MSG(b
->type
, b
->subtype
)){
2176 modified_the_body
+= do_fiddle_smime_message(b
->nested
.msg
->body
, msgno
, section
);
2180 for(p
=b
->nested
.part
,partNum
=1; p
; p
=p
->next
,partNum
++){
2182 /* Append part number to the section string */
2184 snprintf(newSec
, sizeof(newSec
), "%s%s%d", section
, *section
? "." : "", partNum
);
2186 modified_the_body
+= do_fiddle_smime_message(&p
->body
, msgno
, newSec
);
2191 return modified_the_body
;
2196 * Fiddle a message in-place by decrypting/verifying S/MIME entities.
2197 * Returns non-zero if something was changed.
2200 fiddle_smime_message(BODY
*b
, long msgno
)
2202 return do_fiddle_smime_message(b
, msgno
, "");
2206 /********************************************************************************/
2210 * Output a string in a distinctive style
2213 gf_puts_uline(char *txt
, gf_io_t pc
)
2215 pc(TAG_EMBED
); pc(TAG_BOLDON
);
2217 pc(TAG_EMBED
); pc(TAG_BOLDOFF
);
2222 * Sign a message. Called from call_mailer in send.c.
2224 * This takes the header for the outgoing message as well as a pointer
2225 * to the current body (which may be reallocated).
2228 sign_outgoing_message(METAENV
*header
, BODY
**bodyP
, int dont_detach
)
2230 STORE_S
*outs
= NULL
;
2231 BODY
*body
= *bodyP
;
2232 BODY
*newBody
= NULL
;
2235 PERSONAL_CERT
*pcert
;
2240 int flags
= dont_detach
? 0 : PKCS7_DETACHED
;
2242 dprint((9, "sign_outgoing_message()"));
2246 /* Look for a private key matching the sender address... */
2248 pcert
= match_personal_cert(header
->env
);
2251 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find the certificate needed to sign."));
2255 if(!load_private_key(pcert
) && ps_global
->smime
&& ps_global
->smime
->need_passphrase
){
2256 /* Couldn't load key with blank password, try again */
2257 if(pith_opt_smime_get_passphrase
){
2258 (*pith_opt_smime_get_passphrase
)();
2259 load_private_key(pcert
);
2266 in
= body_to_bio(body
);
2269 dump_bio_to_file(in
,"/tmp/signed-data");
2272 p7
= PKCS7_sign(pcert
->cert
, pcert
->key
, NULL
, in
, flags
);
2274 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
2275 forget_private_keys();
2278 q_status_message(SM_ORDER
, 1, 1, _("Error creating signed object."));
2282 outs
= so_get(BioType
, NULL
, EDIT_ACCESS
);
2283 out
= bio_from_store(outs
);
2285 i2d_PKCS7_bio(out
, p7
);
2286 (void) BIO_flush(out
);
2288 so_seek(outs
, 0, SEEK_SET
);
2290 if((flags
&PKCS7_DETACHED
)==0){
2292 /* the simple case: the signed data is in the pkcs7 object */
2294 newBody
= mail_newbody();
2296 setup_pkcs7_body_for_signature(newBody
, "S/MIME Cryptographically Signed Message", "pkcs7-mime", "smime.p7m");
2298 newBody
->contents
.text
.data
= (unsigned char *) outs
;
2307 * We have to create a new body as follows:
2309 * multipart/signed; blah blah blah
2310 * reference to existing body
2315 newBody
= mail_newbody();
2317 newBody
->type
= TYPEMULTIPART
;
2318 newBody
->subtype
= cpystr("signed");
2319 newBody
->encoding
= ENC7BIT
;
2321 set_parameter(&newBody
->parameter
, "protocol", "application/pkcs7-signature");
2322 set_parameter(&newBody
->parameter
, "micalg", "sha1");
2324 p1
= mail_newbody_part();
2325 p2
= mail_newbody_part();
2328 * This is nasty. We're just copying the body in here,
2329 * but since our newBody is freed at the end of call_mailer,
2330 * we mustn't let this body (the original one) be freed twice.
2332 p1
->body
= *body
; /* ARRGH. This is special cased at the end of call_mailer */
2336 setup_pkcs7_body_for_signature(&p2
->body
, "S/MIME Cryptographic Signature", "pkcs7-signature", "smime.p7s");
2337 p2
->body
.contents
.text
.data
= (unsigned char *) outs
;
2339 newBody
->nested
.part
= p1
;
2351 dprint((9, "sign_outgoing_message returns %d", result
));
2357 new_smime_struct(void)
2359 SMIME_STUFF_S
*ret
= NULL
;
2361 ret
= (SMIME_STUFF_S
*) fs_get(sizeof(*ret
));
2362 memset((void *) ret
, 0, sizeof(*ret
));
2363 ret
->publictype
= Nada
;
2370 free_smime_struct(SMIME_STUFF_S
**smime
)
2372 if(smime
&& *smime
){
2373 if((*smime
)->passphrase_emailaddr
){
2375 for(i
= 0; (*smime
)->passphrase_emailaddr
[i
] != NULL
; i
++)
2376 fs_give((void **) &(*smime
)->passphrase_emailaddr
[i
]);
2377 fs_give((void **) (*smime
)->passphrase_emailaddr
);
2380 if((*smime
)->publicpath
)
2381 fs_give((void **) &(*smime
)->publicpath
);
2383 if((*smime
)->publiccertlist
)
2384 free_certlist(&(*smime
)->publiccertlist
);
2386 if((*smime
)->publiccontent
)
2387 fs_give((void **) &(*smime
)->publiccontent
);
2389 if((*smime
)->privatepath
)
2390 fs_give((void **) &(*smime
)->privatepath
);
2392 if((*smime
)->personal_certs
){
2395 pc
= (PERSONAL_CERT
*) (*smime
)->personal_certs
;
2396 free_personal_certs(&pc
);
2397 (*smime
)->personal_certs
= NULL
;
2400 if((*smime
)->privatecontent
)
2401 fs_give((void **) &(*smime
)->privatecontent
);
2403 if((*smime
)->capath
)
2404 fs_give((void **) &(*smime
)->capath
);
2406 if((*smime
)->cacontent
)
2407 fs_give((void **) &(*smime
)->cacontent
);
2409 fs_give((void **) smime
);