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>
48 /* internal prototypes */
49 static void forget_private_keys(void);
50 static int app_RAND_load_file(const char *file
);
51 static void openssl_extra_randomness(void);
52 static int app_RAND_write_file(const char *file
);
53 static const char *openssl_error_string(void);
54 static int load_private_key(PERSONAL_CERT
*pcert
);
55 static void create_local_cache(char *h
, char *base
, BODY
*b
);
56 static long rfc822_output_func(void *b
, char *string
);
57 static void setup_pkcs7_body_for_signature(BODY
*b
, char *description
,
58 char *type
, char *filename
);
59 static BIO
*body_to_bio(BODY
*body
);
60 static BIO
*bio_from_store(STORE_S
*store
);
61 static STORE_S
*get_part_contents(long msgno
, const char *section
);
62 static PKCS7
*get_pkcs7_from_part(long msgno
, const char *section
);
63 static int do_signature_verify(PKCS7
*p7
, BIO
*in
, BIO
*out
, int silent
);
64 static int do_detached_signature_verify(BODY
*b
, long msgno
, char *section
);
65 static PERSONAL_CERT
*find_certificate_matching_pkcs7(PKCS7
*p7
);
66 static int do_decoding(BODY
*b
, long msgno
, const char *section
);
67 static void free_smime_struct(SMIME_STUFF_S
**smime
);
68 static void setup_storage_locations(void);
69 static int copy_dir_to_container(WhichCerts which
);
70 static int copy_container_to_dir(WhichCerts which
);
71 int smime_path(char *rpath
, char *fpath
, size_t len
);
72 int smime_extract_and_save_cert(PKCS7
*p7
);
73 int same_cert(X509
*, X509
*);
74 CertList
* certlist_from_personal_certs(PERSONAL_CERT
*pc
);
76 int (*pith_opt_smime_get_passphrase
)(void);
77 int (*pith_smime_import_certificate
)(char *, char *, size_t);
78 char *(*pith_enter_password
)(char *prompt
, char *, size_t);
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 import_certificate(WhichCerts ctype
)
91 char filename
[MAXPATH
+1], full_filename
[MAXPATH
+1], buf
[MAXPATH
+1];
93 if(pith_smime_import_certificate
== NULL
)
94 q_status_message(SM_ORDER
, 0, 2,
95 _("import of certificates not implemented yet!"));
99 r
= (*pith_smime_import_certificate
)(filename
, full_filename
, sizeof(filename
) - 20);
104 cmd_cancelled("Import certificate");
108 q_status_message1(SM_ORDER
, 0, 2,
109 _("Can't import certificate outside of %s"),
110 ps_global
->VAR_OPER_DIR
);
113 } else if (ctype
== Private
){
114 char prompt
[500], *s
, *t
;
115 char pass
[MAILTMPLEN
+1];
117 EVP_PKEY
*key
= NULL
;
120 if(!ps_global
->smime
->privatecertdata
){
121 ps_global
->smime
->privatecertdata
= fs_get(sizeof(CertList
));
122 memset((void *)DATACERT(ctype
), 0, sizeof(CertList
));
125 if(!(in
= BIO_new_file(full_filename
, "r")))
128 for(s
= t
= filename
; (t
= strstr(s
, ".key")) != NULL
; s
= t
+ 1);
131 snprintf(prompt
, sizeof(prompt
),
132 _("Enter passphrase for <%s>: "), s
? s
: filename
);
135 if(pith_enter_password
)
136 (*pith_enter_password
)(prompt
, (char *)pass
, sizeof(pass
));
138 if((key
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, pass
)) != NULL
){
139 if(SMHOLDERTYPE(ctype
) == Directory
){
140 STORE_S
*in_cert
, *out_cert
;
143 build_path(buf
, PATHCERTDIR(ctype
), filename
, sizeof(buf
));
144 if(strcmp(buf
+ strlen(buf
) - 4, EXTCERT(ctype
)) != 0 && strlen(buf
) + 4 < sizeof(buf
))
145 strcat(buf
, EXTCERT(ctype
));
147 in_cert
= so_get(FileStar
, full_filename
, READ_ACCESS
| READ_FROM_LOCALE
);
148 out_cert
= so_get(FileStar
, buf
, WRITE_ACCESS
| WRITE_TO_LOCALE
);
150 if(in_cert
!= NULL
&& out_cert
!= NULL
){
151 while(so_readc(&c
, in_cert
) > 0)
152 so_writec(c
, out_cert
);
153 q_status_message(SM_ORDER
, 1, 3, _("Certificate saved"));
156 q_status_message(SM_ORDER
, 1, 3, _("Error saving certificate"));
161 if(ps_global
->smime
->publiccertdata
)
162 ps_global
->smime
->publiccertdata
->data
.renew
= 1;
165 q_status_message(SM_ORDER
, 1, 3, _("Problem unlocking key (not a certificate and/or wrong password)"));
167 } else if (ctype
== CACert
){
171 if((ins
= BIO_new_file(full_filename
, "r")) != NULL
){
172 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
){
173 if(SMHOLDERTYPE(ctype
) == Directory
){
174 STORE_S
*in_cert
, *out_cert
;
177 build_path(buf
, PATHCERTDIR(ctype
), filename
, sizeof(buf
));
178 if(strcmp(buf
+ strlen(buf
) - 4, ".crt") != 0 && strlen(buf
) + 4 < sizeof(buf
))
179 strcat(buf
, EXTCERT(ctype
));
181 in_cert
= so_get(FileStar
, full_filename
, READ_ACCESS
| READ_FROM_LOCALE
);
182 out_cert
= so_get(FileStar
, buf
, WRITE_ACCESS
| WRITE_TO_LOCALE
);
184 if(in_cert
!= NULL
&& out_cert
!= NULL
){
185 while(so_readc(&c
, in_cert
) > 0)
186 so_writec(c
, out_cert
);
187 q_status_message(SM_ORDER
, 1, 3, _("Certificate saved"));
190 q_status_message(SM_ORDER
, 1, 3, _("Error saving certificate"));
195 X509_free(cert
); /* not needed anymore */
198 q_status_message(SM_ORDER
, 1, 3, _("Error in certificate file (not a certificate?)"));
202 } else { /* ctype == Public. save certificate, but first validate that it is one */
206 if((ins
= BIO_new_file(full_filename
, "r")) != NULL
){
207 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
){
208 char **email
= get_x509_subject_email(cert
);
211 for(i
= 0; email
[i
] != NULL
; i
++){
212 save_cert_for(email
[i
], cert
, Public
);
213 fs_give((void **)&email
[i
]);
215 fs_give((void **)email
);
217 if(ps_global
->smime
->publiccertdata
)
218 ps_global
->smime
->publiccertdata
->data
.renew
= 1;
221 q_status_message(SM_ORDER
, 1, 3, _("Error in certificate file (not a certificate?)"));
225 if(DATACERT(ctype
)) RENEWCERT(DATACERT(ctype
)) = 1;
226 ps_global
->mangled_screen
= 1;
230 /* itype: information type to add: 0 - public, 1 - private.
231 * Memory freed by caller
234 print_private_key_information(char *email
, int itype
)
239 if(ps_global
->smime
== NULL
240 || ps_global
->smime
->personal_certs
== NULL
241 || (itype
!= 0 && itype
!= 1))
244 for(pc
= ps_global
->smime
->personal_certs
;
245 pc
!= NULL
&& strcmp(pc
->name
, email
) != 0; pc
= pc
->next
);
247 && !load_private_key(pc
)
249 && ps_global
->smime
->need_passphrase
){
250 if (*pith_opt_smime_get_passphrase
)
251 (*pith_opt_smime_get_passphrase
)();
252 load_private_key(pc
);
258 out
= BIO_new(BIO_s_mem());
259 if(itype
== 0) /* 0 means public */
260 EVP_PKEY_print_public(out
, pc
->key
, 0, NULL
);
261 else if (itype
== 1) /* 1 means private */
262 EVP_PKEY_print_private(out
, pc
->key
, 0, NULL
);
264 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
265 forget_private_keys();
271 * Forget any cached private keys
274 forget_private_keys(void)
276 PERSONAL_CERT
*pcert
;
280 dprint((9, "forget_private_keys()"));
281 if(ps_global
->smime
){
282 for(pcert
=(PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
287 EVP_PKEY_free(pcert
->key
);
292 ps_global
->smime
->entered_passphrase
= 0;
293 len
= sizeof(ps_global
->smime
->passphrase
);
294 p
= ps_global
->smime
->passphrase
;
301 /* modelled after signature_path in reply.c, but uses home dir instead of the
302 * directory where the .pinerc is located, since according to documentation,
303 * the .alpine-smime directories are subdirectories of the home directory
306 int smime_path(char *rpath
, char *fpath
, size_t len
)
310 size_t spl
= strlen(rpath
);
313 if(IS_REMOTE(rpath
)){
315 strncpy(fpath
, rpath
, len
-1);
318 else if(is_absolute_path(rpath
)){
319 strncpy(fpath
, rpath
, len
-1);
321 fnexpand(fpath
, len
);
323 else if(ps_global
->VAR_OPER_DIR
){
324 if(strlen(ps_global
->VAR_OPER_DIR
) + spl
< len
- 1)
325 build_path(fpath
, ps_global
->VAR_OPER_DIR
, rpath
, len
);
327 else if(ps_global
->home_dir
){
328 if(strlen(ps_global
->home_dir
) + spl
< len
- 1)
329 build_path(fpath
, ps_global
->home_dir
, rpath
, len
);
332 return fpath
&& *fpath
? 1 : 0;
338 * taken from openssl/apps/app_rand.c
341 app_RAND_load_file(const char *file
)
346 file
= RAND_file_name(buffer
, sizeof buffer
);
347 else if(RAND_egd(file
) > 0){
348 /* we try if the given filename is an EGD socket.
349 if it is, we don't write anything back to the file. */
354 if(file
== NULL
|| !RAND_load_file(file
, -1)){
355 if(RAND_status() == 0){
356 dprint((1, "unable to load 'random state'\n"));
357 dprint((1, "This means that the random number generator has not been seeded\n"));
358 dprint((1, "with much random data.\n"));
370 * copied and fiddled from imap/src/osdep/unix/auth_ssl.c
373 openssl_extra_randomness(void)
381 /* if system doesn't have /dev/urandom */
382 if(stat ("/dev/urandom", &sbuf
)){
384 tf
= temp_nam(NULL
, NULL
);
386 strncpy(tmp
, tf
, sizeof(tmp
));
387 tmp
[sizeof(tmp
)-1] = '\0';
388 fs_give((void **) &tf
);
391 if((fd
= open(tmp
, O_WRONLY
|O_CREAT
|O_EXCL
, 0600)) < 0)
392 i
= (unsigned long) tmp
;
394 unlink(tmp
); /* don't need the file */
395 fstat(fd
, &sbuf
); /* get information about the file */
396 i
= sbuf
.st_ino
; /* remember its inode */
397 close(fd
); /* or its descriptor */
399 /* not great but it'll have to do */
400 snprintf(tmp
+strlen(tmp
), sizeof(tmp
)-strlen(tmp
), "%.80s%lx%lx%lx",
402 (unsigned long) (time (0) ^ gethostid ()),
403 (unsigned long) getpid ());
404 RAND_seed(tmp
, strlen(tmp
));
410 /* taken from openssl/apps/app_rand.c */
412 app_RAND_write_file(const char *file
)
416 if(egdsocket
|| !seeded
)
418 * If we did not manage to read the seed file,
419 * we should not write a low-entropy seed file back --
420 * it would suppress a crucial warning the next time
426 file
= RAND_file_name(buffer
, sizeof buffer
);
428 if(file
== NULL
|| !RAND_write_file(file
)){
429 dprint((1, "unable to write 'random state'\n"));
437 certlist_from_personal_certs(PERSONAL_CERT
*pc
)
444 cl
= fs_get(sizeof(CertList
));
445 memset((void *)cl
, 0, sizeof(CertList
));
446 cl
->name
= cpystr(pc
->name
);
447 cl
->next
= certlist_from_personal_certs(pc
->next
);
454 renew_cert_data(CertList
**data
, WhichCerts ctype
)
457 if(ctype
== Private
){
459 PERSONAL_CERT
*pc
= (PERSONAL_CERT
*)ps_global
->smime
->personal_certs
;
462 free_personal_certs(&pc
);
463 ps_global
->smime
->personal_certs
= (void *) get_personal_certs(ps_global
->smime
->privatepath
);
464 *data
= certlist_from_personal_certs((PERSONAL_CERT
*)ps_global
->smime
->personal_certs
);
466 RENEWCERT(*data
) = 0;
467 ps_global
->smime
->privatecertdata
= (CertList
*) *data
;
469 if(ps_global
->smime
->privatecertdata
)
470 RENEWCERT(ps_global
->smime
->privatecertdata
) = 0;
472 X509_LOOKUP
*lookup
= NULL
;
473 X509_STORE
*store
= NULL
;
475 if((store
= X509_STORE_new()) != NULL
)
476 if ((lookup
= X509_STORE_add_lookup(store
, X509_LOOKUP_file())) == NULL
){
477 X509_STORE_free(store
);
481 if(PATHCERTDIR(ctype
)){
483 add_certs_in_dir(lookup
, PATHCERTDIR(ctype
), EXTCERT(ctype
), data
);
485 RENEWCERT(*data
) = 0;
487 ps_global
->smime
->publiccertdata
= *data
;
489 ps_global
->smime
->cacertdata
= *data
;
497 /* Installed as an atexit() handler to save the random data */
501 dprint((9, "smime_deinit()"));
502 app_RAND_write_file(NULL
);
503 free_smime_struct(&ps_global
->smime
);
506 /* we renew the store when it has changed */
507 void renew_store(void)
509 if(ps_global
->smime
->inited
){
510 if(s_cert_store
!= NULL
)
511 X509_STORE_free(s_cert_store
);
512 s_cert_store
= get_ca_store();
516 /* Initialise openssl stuff if needed */
520 if(F_OFF(F_DONT_DO_SMIME
, ps_global
) && !(ps_global
->smime
&& ps_global
->smime
->inited
)){
522 dprint((9, "smime_init()"));
523 if(!ps_global
->smime
)
524 ps_global
->smime
= new_smime_struct();
526 setup_storage_locations();
528 s_cert_store
= get_ca_store();
530 OpenSSL_add_all_algorithms();
531 ERR_load_crypto_strings();
533 app_RAND_load_file(NULL
);
535 openssl_extra_randomness();
536 ps_global
->smime
->inited
= 1;
543 /* validate a certificate. Return value : 0 for no error, -1 for error.
544 * In the latter case, set the openssl smime error in *error.
546 int smime_validate_cert(X509
*cert
, long *error
)
552 if((csc
= X509_STORE_CTX_new()) != NULL
){
553 X509_STORE_set_flags(s_cert_store
, 0);
554 if(X509_STORE_CTX_init(csc
,s_cert_store
,cert
,NULL
)
555 && X509_verify_cert(csc
) <= 0)
556 *error
= X509_STORE_CTX_get_error(csc
);
557 X509_STORE_CTX_free(csc
);
559 return *error
? -1 : 0;
563 get_personal_certs(char *path
)
565 PERSONAL_CERT
*result
= NULL
;
570 ps_global
->smime
->privatepath
= cpystr(path
);
571 dirp
= opendir(path
);
573 while((d
=readdir(dirp
)) != NULL
){
577 if((ll
=strlen(d
->d_name
)) && ll
> 4 && !strcmp(d
->d_name
+ll
-4, ".key")){
579 /* copy file name to temp buffer */
580 strncpy(buf2
, d
->d_name
, sizeof(buf2
)-1);
581 buf2
[sizeof(buf2
)-1] = '\0';
582 /* chop off ".key" trailier */
583 buf2
[strlen(buf2
)-4] = 0;
584 /* Look for certificate */
585 cert
= get_cert_for(buf2
, Public
);
590 /* create a new PERSONAL_CERT, fill it in */
592 pc
= (PERSONAL_CERT
*) fs_get(sizeof(*pc
));
594 pc
->name
= cpystr(buf2
);
596 /* Try to load the key with an empty password */
597 pc
->key
= load_key(pc
, "");
611 setup_storage_locations(void)
613 int publiccertcontainer
= 0, privatekeycontainer
= 0, cacertcontainer
= 0;
614 char path
[MAXPATH
+1], *contents
;
616 if(!ps_global
->smime
)
620 if(F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
621 ps_global
->smime
->publictype
= Keychain
;
624 #endif /* APPLEKEYCHAIN */
625 /* Public certificates in a container */
626 if(ps_global
->VAR_PUBLICCERT_CONTAINER
&& ps_global
->VAR_PUBLICCERT_CONTAINER
[0]){
628 publiccertcontainer
= 1;
631 if(!smime_path(ps_global
->VAR_PUBLICCERT_CONTAINER
, path
, MAXPATH
))
632 publiccertcontainer
= 0;
634 if(publiccertcontainer
&& !IS_REMOTE(path
)
635 && ps_global
->VAR_OPER_DIR
636 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
637 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
638 /* TRANSLATORS: First arg is the directory name, second is
639 the file user wants to read but can't. */
640 _("Can't read file outside %s: %s"),
641 ps_global
->VAR_OPER_DIR
, path
);
642 publiccertcontainer
= 0;
645 if(publiccertcontainer
646 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
647 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
649 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
650 publiccertcontainer
= 0;
653 if(publiccertcontainer
&& path
[0]){
654 ps_global
->smime
->publictype
= Container
;
655 ps_global
->smime
->publicpath
= cpystr(path
);
658 ps_global
->smime
->publiccontent
= contents
;
659 ps_global
->smime
->publiccertlist
= mem_to_certlist(contents
);
664 /* Public certificates in a directory of files */
665 if(!publiccertcontainer
){
666 ps_global
->smime
->publictype
= Directory
;
669 if(!(smime_path(ps_global
->VAR_PUBLICCERT_DIR
, path
, MAXPATH
)
670 && !IS_REMOTE(path
)))
671 ps_global
->smime
->publictype
= Nada
;
672 else if(can_access(path
, ACCESS_EXISTS
)){
673 if(our_mkpath(path
, 0700)){
674 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
675 ps_global
->smime
->publictype
= Nada
;
679 if(ps_global
->smime
->publictype
== Directory
)
680 ps_global
->smime
->publicpath
= cpystr(path
);
685 #endif /* APPLEKEYCHAIN */
687 /* private keys in a container */
688 if(ps_global
->VAR_PRIVATEKEY_CONTAINER
&& ps_global
->VAR_PRIVATEKEY_CONTAINER
[0]){
690 privatekeycontainer
= 1;
693 if(!smime_path(ps_global
->VAR_PRIVATEKEY_CONTAINER
, path
, MAXPATH
))
694 privatekeycontainer
= 0;
696 if(privatekeycontainer
&& !IS_REMOTE(path
)
697 && ps_global
->VAR_OPER_DIR
698 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
699 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
700 /* TRANSLATORS: First arg is the directory name, second is
701 the file user wants to read but can't. */
702 _("Can't read file outside %s: %s"),
703 ps_global
->VAR_OPER_DIR
, path
);
704 privatekeycontainer
= 0;
707 if(privatekeycontainer
708 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
709 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
711 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
712 privatekeycontainer
= 0;
715 if(privatekeycontainer
&& path
[0]){
716 ps_global
->smime
->privatetype
= Container
;
717 ps_global
->smime
->privatepath
= cpystr(path
);
720 ps_global
->smime
->privatecontent
= contents
;
721 ps_global
->smime
->personal_certs
= mem_to_personal_certs(contents
);
726 /* private keys in a directory of files */
727 if(!privatekeycontainer
){
728 PERSONAL_CERT
*result
= NULL
;
730 ps_global
->smime
->privatetype
= Directory
;
733 if(!(smime_path(ps_global
->VAR_PRIVATEKEY_DIR
, path
, MAXPATH
)
734 && !IS_REMOTE(path
)))
735 ps_global
->smime
->privatetype
= Nada
;
736 else if(can_access(path
, ACCESS_EXISTS
)){
737 if(our_mkpath(path
, 0700)){
738 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
739 ps_global
->smime
->privatetype
= Nada
;
743 if(ps_global
->smime
->privatetype
== Directory
)
744 ps_global
->smime
->personal_certs
= get_personal_certs(path
);
747 /* extra cacerts in a container */
748 if(ps_global
->VAR_CACERT_CONTAINER
&& ps_global
->VAR_CACERT_CONTAINER
[0]){
753 if(!smime_path(ps_global
->VAR_CACERT_CONTAINER
, path
, MAXPATH
))
756 if(cacertcontainer
&& !IS_REMOTE(path
)
757 && ps_global
->VAR_OPER_DIR
758 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
759 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
760 /* TRANSLATORS: First arg is the directory name, second is
761 the file user wants to read but can't. */
762 _("Can't read file outside %s: %s"),
763 ps_global
->VAR_OPER_DIR
, path
);
768 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
769 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
771 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
775 if(cacertcontainer
&& path
[0]){
776 ps_global
->smime
->catype
= Container
;
777 ps_global
->smime
->capath
= cpystr(path
);
778 ps_global
->smime
->cacontent
= contents
;
782 if(!cacertcontainer
){
783 ps_global
->smime
->catype
= Directory
;
786 if(!(smime_path(ps_global
->VAR_CACERT_DIR
, path
, MAXPATH
)
787 && !IS_REMOTE(path
)))
788 ps_global
->smime
->catype
= Nada
;
789 else if(can_access(path
, ACCESS_EXISTS
)){
790 if(our_mkpath(path
, 0700)){
791 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
792 ps_global
->smime
->catype
= Nada
;
796 if(ps_global
->smime
->catype
== Directory
)
797 ps_global
->smime
->capath
= cpystr(path
);
803 copy_publiccert_dir_to_container(void)
805 return(copy_dir_to_container(Public
));
810 copy_publiccert_container_to_dir(void)
812 return(copy_container_to_dir(Public
));
817 copy_privatecert_dir_to_container(void)
819 return(copy_dir_to_container(Private
));
824 copy_privatecert_container_to_dir(void)
826 return(copy_container_to_dir(Private
));
831 copy_cacert_dir_to_container(void)
833 return(copy_dir_to_container(CACert
));
838 copy_cacert_container_to_dir(void)
840 return(copy_container_to_dir(CACert
));
845 * returns 0 on success, -1 on failure
848 copy_dir_to_container(WhichCerts which
)
851 BIO
*bio_out
= NULL
, *bio_in
= NULL
;
852 char srcpath
[MAXPATH
+1], dstpath
[MAXPATH
+1], emailaddr
[MAXPATH
], file
[MAXPATH
], line
[4096];
853 char *tempfile
= NULL
;
856 REMDATA_S
*rd
= NULL
;
857 char *configdir
= NULL
;
858 char *configpath
= NULL
;
859 char *filesuffix
= NULL
;
861 dprint((9, "copy_dir_to_container(%s)", which
==Public
? "Public" : which
==Private
? "Private" : which
==CACert
? "CACert" : "?"));
870 configdir
= ps_global
->VAR_PUBLICCERT_DIR
;
871 configpath
= ps_global
->smime
->publicpath
;
874 else if(which
== Private
){
875 configdir
= ps_global
->VAR_PRIVATEKEY_DIR
;
876 configpath
= ps_global
->smime
->privatepath
;
879 else if(which
== CACert
){
880 configdir
= ps_global
->VAR_CACERT_DIR
;
881 configpath
= ps_global
->smime
->capath
;
885 if(!(configdir
&& configdir
[0])){
886 q_status_message(SM_ORDER
, 3, 3, _("Directory not defined"));
890 if(!(configpath
&& configpath
[0])){
892 if(which
== Public
&& F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
893 q_status_message(SM_ORDER
, 3, 3, _("Turn off the Keychain feature above first"));
896 #endif /* APPLEKEYCHAIN */
897 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
901 if(!(filesuffix
&& strlen(filesuffix
) == 4)){
907 * If there is a legit directory to read from set up the
908 * container file to write to.
910 if(smime_path(configdir
, srcpath
, MAXPATH
) && !IS_REMOTE(srcpath
)){
912 if(IS_REMOTE(configpath
)){
913 rd
= rd_create_remote(RemImap
, configpath
, REMOTE_SMIME_SUBTYPE
,
915 _("Can't access remote smime configuration."));
919 (void) rd_read_metadata(rd
);
921 if(rd
->access
== MaybeRorW
){
922 if(rd
->read_status
== 'R')
923 rd
->access
= ReadOnly
;
925 rd
->access
= ReadWrite
;
928 if(rd
->access
!= NoExists
){
930 rd_check_remvalid(rd
, 1L);
933 * If the cached info says it is readonly but
934 * it looks like it's been fixed now, change it to readwrite.
936 if(rd
->read_status
== 'R'){
937 rd_check_readonly_access(rd
);
938 if(rd
->read_status
== 'W'){
939 rd
->access
= ReadWrite
;
940 rd
->flags
|= REM_OUTOFDATE
;
943 rd
->access
= ReadOnly
;
947 if(rd
->flags
& REM_OUTOFDATE
){
948 if(rd_update_local(rd
) != 0){
950 dprint((1, "copy_dir_to_container: rd_update_local failed\n"));
951 rd_close_remdata(&rd
);
958 if(rd
->access
!= ReadWrite
|| rd_remote_is_readonly(rd
)){
959 rd_close_remdata(&rd
);
963 rd
->flags
|= DO_REMTRIM
;
965 strncpy(dstpath
, rd
->lf
, sizeof(dstpath
)-1);
966 dstpath
[sizeof(dstpath
)-1] = '\0';
969 strncpy(dstpath
, configpath
, sizeof(dstpath
)-1);
970 dstpath
[sizeof(dstpath
)-1] = '\0';
974 * dstpath is either the local Container file or the local cache file
975 * for the remote Container file.
977 tempfile
= tempfile_in_same_dir(dstpath
, "az", NULL
);
981 * If there is a legit directory to read from and a tempfile
982 * to write to we continue.
984 if(tempfile
&& (bio_out
=BIO_new_file(tempfile
, "w")) != NULL
){
986 dirp
= opendir(srcpath
);
989 while((d
=readdir(dirp
)) && !ret
){
992 if((ll
=strlen(d
->d_name
)) && ll
> 4 && !strcmp(d
->d_name
+ll
-4, filesuffix
)){
994 /* copy file name to temp buffer */
995 strncpy(emailaddr
, d
->d_name
, sizeof(emailaddr
)-1);
996 emailaddr
[sizeof(emailaddr
)-1] = '\0';
997 /* chop off suffix trailier */
998 emailaddr
[strlen(emailaddr
)-4] = 0;
1001 * This is the separator between the contents of
1004 if(which
== CACert
){
1005 if(!((BIO_puts(bio_out
, CACERTSTORELEADER
) > 0)
1006 && (BIO_puts(bio_out
, emailaddr
) > 0)
1007 && (BIO_puts(bio_out
, "\n") > 0)))
1011 if(!((BIO_puts(bio_out
, EMAILADDRLEADER
) > 0)
1012 && (BIO_puts(bio_out
, emailaddr
) > 0)
1013 && (BIO_puts(bio_out
, "\n") > 0)))
1017 /* read then write contents of file */
1018 build_path(file
, srcpath
, d
->d_name
, sizeof(file
));
1019 if(!(bio_in
= BIO_new_file(file
, "r")))
1025 while(BIO_gets(bio_in
, line
, sizeof(line
)) > 0){
1026 if(strncmp("-----BEGIN", line
, strlen("-----BEGIN")) == 0)
1030 BIO_puts(bio_out
, line
);
1032 if(strncmp("-----END", line
, strlen("-----END")) == 0)
1047 if(rename_file(tempfile
, dstpath
) < 0){
1048 q_status_message2(SM_ORDER
, 3, 3,
1049 _("Can't rename %s to %s"), tempfile
, dstpath
);
1053 /* if the container is remote, copy it */
1054 if(!ret
&& IS_REMOTE(configpath
)){
1060 if((e
= rd_update_remote(rd
, datebuf
)) != 0){
1062 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1063 _("Error opening temporary smime file %s: %s"),
1064 rd
->lf
, error_description(errno
));
1066 "write_remote_smime: error opening temp file %s\n",
1067 rd
->lf
? rd
->lf
: "?"));
1070 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1071 _("Error copying to %s: %s"),
1072 rd
->rn
, error_description(errno
));
1074 "write_remote_smime: error copying from %s to %s\n",
1075 rd
->lf
? rd
->lf
: "?", rd
->rn
? rd
->rn
: "?"));
1078 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
1079 _("Copy of smime key to remote folder failed, NOT saved remotely"));
1082 rd_update_metadata(rd
, datebuf
);
1083 rd
->read_status
= 'W';
1086 rd_close_remdata(&rd
);
1092 fs_give((void **) &tempfile
);
1099 * returns 0 on success, -1 on failure
1102 copy_container_to_dir(WhichCerts which
)
1104 char path
[MAXPATH
+1], file
[MAXPATH
+1], buf
[MAXPATH
+1];
1106 char *contents
= NULL
;
1107 char *leader
= NULL
;
1108 char *filesuffix
= NULL
;
1109 char *configdir
= NULL
;
1110 char *configpath
= NULL
;
1111 char *tempfile
= NULL
;
1112 char *p
, *q
, *line
, *name
, *certtext
, *save_p
;
1116 dprint((9, "copy_container_to_dir(%s)", which
==Public
? "Public" : which
==Private
? "Private" : which
==CACert
? "CACert" : "?"));
1121 if(which
== Public
){
1122 leader
= EMAILADDRLEADER
;
1123 contents
= ps_global
->smime
->publiccontent
;
1124 configdir
= ps_global
->VAR_PUBLICCERT_DIR
;
1125 configpath
= ps_global
->smime
->publicpath
;
1126 filesuffix
= ".crt";
1127 if(!(configpath
&& configpath
[0])){
1128 #ifdef APPLEKEYCHAIN
1129 if(which
== Public
&& F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
1130 q_status_message(SM_ORDER
, 3, 3, _("Turn off the Keychain feature above first"));
1133 #endif /* APPLEKEYCHAIN */
1134 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1138 fs_give((void **) &ps_global
->smime
->publicpath
);
1141 if(!(smime_path(ps_global
->VAR_PUBLICCERT_DIR
, path
, MAXPATH
)
1142 && !IS_REMOTE(path
))){
1143 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
1147 if(can_access(path
, ACCESS_EXISTS
)){
1148 if(our_mkpath(path
, 0700)){
1149 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1154 ps_global
->smime
->publicpath
= cpystr(path
);
1155 configpath
= ps_global
->smime
->publicpath
;
1157 else if(which
== Private
){
1158 leader
= EMAILADDRLEADER
;
1159 contents
= ps_global
->smime
->privatecontent
;
1160 configdir
= ps_global
->VAR_PRIVATEKEY_DIR
;
1161 configpath
= ps_global
->smime
->privatepath
;
1162 filesuffix
= ".key";
1163 if(!(configpath
&& configpath
[0])){
1164 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1168 fs_give((void **) &ps_global
->smime
->privatepath
);
1171 if(!(smime_path(ps_global
->VAR_PRIVATEKEY_DIR
, path
, MAXPATH
)
1172 && !IS_REMOTE(path
))){
1173 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
1177 if(can_access(path
, ACCESS_EXISTS
)){
1178 if(our_mkpath(path
, 0700)){
1179 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1184 ps_global
->smime
->privatepath
= cpystr(path
);
1185 configpath
= ps_global
->smime
->privatepath
;
1187 else if(which
== CACert
){
1188 leader
= CACERTSTORELEADER
;
1189 contents
= ps_global
->smime
->cacontent
;
1190 configdir
= ps_global
->VAR_CACERT_DIR
;
1191 configpath
= ps_global
->smime
->capath
;
1192 filesuffix
= ".crt";
1193 if(!(configpath
&& configpath
[0])){
1194 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1198 fs_give((void **) &ps_global
->smime
->capath
);
1201 if(!(smime_path(ps_global
->VAR_CACERT_DIR
, path
, MAXPATH
)
1202 && !IS_REMOTE(path
))){
1203 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
1207 if(can_access(path
, ACCESS_EXISTS
)){
1208 if(our_mkpath(path
, 0700)){
1209 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1214 ps_global
->smime
->capath
= cpystr(path
);
1215 configpath
= ps_global
->smime
->capath
;
1218 if(!(configdir
&& configdir
[0])){
1219 q_status_message(SM_ORDER
, 3, 3, _("Directory not defined"));
1223 if(!(configpath
&& configpath
[0])){
1224 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1228 if(!(filesuffix
&& strlen(filesuffix
) == 4)){
1233 if(contents
&& *contents
){
1234 for(p
= contents
; *p
!= '\0';){
1237 while(*p
&& *p
!= '\n')
1246 if(strncmp(leader
, line
, strlen(leader
)) == 0){
1247 name
= line
+ strlen(leader
);
1249 if(strncmp("-----BEGIN", certtext
, strlen("-----BEGIN")) == 0){
1250 if((q
= strstr(certtext
, leader
)) != NULL
){
1253 else{ /* end of file */
1254 q
= certtext
+ strlen(certtext
);
1258 strncpy(buf
, name
, sizeof(buf
)-5);
1259 buf
[sizeof(buf
)-5] = '\0';
1260 strncat(buf
, filesuffix
, 5);
1261 build_path(file
, configpath
, buf
, sizeof(file
));
1263 in
= BIO_new_mem_buf(certtext
, q
-certtext
);
1265 tempfile
= tempfile_in_same_dir(file
, "az", NULL
);
1268 out
= BIO_new_file(tempfile
, "w");
1271 while((len
= BIO_read(in
, iobuf
, sizeof(iobuf
))) > 0)
1272 BIO_write(out
, iobuf
, len
);
1276 if(rename_file(tempfile
, file
) < 0){
1277 q_status_message2(SM_ORDER
, 3, 3,
1278 _("Can't rename %s to %s"),
1283 fs_give((void **) &tempfile
);
1300 #ifdef APPLEKEYCHAIN
1303 copy_publiccert_container_to_keychain(void)
1305 /* NOT IMPLEMNTED */
1310 copy_publiccert_keychain_to_container(void)
1312 /* NOT IMPLEMNTED */
1316 #endif /* APPLEKEYCHAIN */
1320 * Get a pointer to a string describing the most recent OpenSSL error.
1321 * It's statically allocated, so don't change or attempt to free it.
1324 openssl_error_string(void)
1327 const char *data
= NULL
;
1330 errn
= ERR_peek_error_line_data(NULL
, NULL
, &data
, NULL
);
1331 errs
= (char*) ERR_reason_error_string(errn
);
1338 return "unknown error";
1342 /* Return true if the body looks like a PKCS7 object */
1344 is_pkcs7_body(BODY
*body
)
1348 result
= body
->type
==TYPEAPPLICATION
&&
1350 (strucmp(body
->subtype
,"pkcs7-mime")==0 ||
1351 strucmp(body
->subtype
,"x-pkcs7-mime")==0 ||
1352 strucmp(body
->subtype
,"pkcs7-signature")==0 ||
1353 strucmp(body
->subtype
,"x-pkcs7-signature")==0);
1361 * Somewhat useful debug utility to dump the contents of a BIO to a file.
1362 * Note that a memory BIO will have its contents eliminated after they
1363 * are read so this will break the next step.
1366 dump_bio_to_file(BIO
*in
, char *filename
)
1372 out
= BIO_new_file(filename
, "w");
1375 if(BIO_method_type(in
) != BIO_TYPE_MEM
)
1378 while((len
= BIO_read(in
, iobuf
, sizeof(iobuf
))) > 0)
1379 BIO_write(out
, iobuf
, len
);
1390 * Recursively stash a pointer to the decrypted data in our
1391 * manufactured body.
1394 create_local_cache(char *h
, char *base
, BODY
*b
)
1396 if(b
->type
==TYPEMULTIPART
){
1400 cpytxt(&b
->contents
.text
, base
+ b
->contents
.offset
, b
->size
.bytes
);
1403 * We don't really want to copy the real body contents. It shouldn't be
1404 * used, and in the case of a message with attachments, we'll be
1405 * duplicating the files multiple times.
1407 cpytxt(&b
->contents
.text
, "BODY UNAVAILABLE", 16);
1410 for(p
=b
->nested
.part
; p
; p
=p
->next
)
1411 create_local_cache(h
, base
, (BODY
*) p
);
1414 cpytxt(&b
->mime
.text
, h
+b
->mime
.offset
, b
->mime
.text
.size
);
1415 cpytxt(&b
->contents
.text
, base
+ b
->contents
.offset
, b
->size
.bytes
);
1421 rfc822_output_func(void *b
, char *string
)
1423 BIO
*bio
= (BIO
*) b
;
1425 return(string
? *string
? (BIO_puts(bio
, string
) > 0 ? 1L : 0L)
1426 : (BIO_puts(bio
, string
) >= 0 ? 1L : 0L)
1432 * Attempt to load the private key for the given PERSONAL_CERT.
1433 * This sets the appropriate passphrase globals in order to
1434 * interact with the user correctly.
1437 load_private_key(PERSONAL_CERT
*pcert
)
1441 /* Try empty password by default */
1442 char *password
= "";
1445 && (ps_global
->smime
->need_passphrase
1446 || ps_global
->smime
->entered_passphrase
)){
1447 /* We've already been in here and discovered we need a different password */
1449 if(ps_global
->smime
->entered_passphrase
)
1450 password
= (char *) ps_global
->smime
->passphrase
; /* already entered */
1457 if(!(pcert
->key
= load_key(pcert
, password
))){
1458 long err
= ERR_get_error();
1460 /* Couldn't load key... */
1462 if(ps_global
->smime
&& ps_global
->smime
->entered_passphrase
){
1464 /* The user got the password wrong maybe? */
1466 if((ERR_GET_LIB(err
)==ERR_LIB_EVP
&& ERR_GET_REASON(err
)==EVP_R_BAD_DECRYPT
) ||
1467 (ERR_GET_LIB(err
)==ERR_LIB_PEM
&& ERR_GET_REASON(err
)==PEM_R_BAD_DECRYPT
))
1468 q_status_message(SM_ORDER
| SM_DING
, 4, 4, _("Incorrect passphrase"));
1470 q_status_message1(SM_ORDER
, 4, 4, _("Couldn't read key: %s"),(char*)openssl_error_string());
1472 /* This passphrase is no good; forget it */
1473 ps_global
->smime
->entered_passphrase
= 0;
1476 if(ps_global
->smime
){
1477 /* Indicate to the UI that we need re-entry (see mailcmd.c:process_cmd())*/
1478 ps_global
->smime
->need_passphrase
= 1;
1479 if(ps_global
->smime
->passphrase_emailaddr
){
1481 for(i
= 0; ps_global
->smime
->passphrase_emailaddr
[i
] != NULL
; i
++)
1482 fs_give((void **)&ps_global
->smime
->passphrase_emailaddr
[i
]);
1483 fs_give((void **) ps_global
->smime
->passphrase_emailaddr
);
1486 ps_global
->smime
->passphrase_emailaddr
= get_x509_subject_email(pcert
->cert
);
1492 /* This key will be cached, so we won't be called again */
1493 if(ps_global
->smime
){
1494 ps_global
->smime
->entered_passphrase
= 0;
1495 ps_global
->smime
->need_passphrase
= 0;
1507 setup_pkcs7_body_for_signature(BODY
*b
, char *description
, char *type
, char *filename
)
1509 b
->type
= TYPEAPPLICATION
;
1510 b
->subtype
= cpystr(type
);
1511 b
->encoding
= ENCBINARY
;
1512 b
->description
= cpystr(description
);
1514 b
->disposition
.type
= cpystr("attachment");
1515 set_parameter(&b
->disposition
.parameter
, "filename", filename
);
1517 set_parameter(&b
->parameter
, "name", filename
);
1522 * Look for a personal certificate matching the
1526 match_personal_cert_to_email(ADDRESS
*a
)
1528 PERSONAL_CERT
*pcert
= NULL
;
1533 if(!a
|| !a
->mailbox
|| !a
->host
)
1536 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
1538 if(ps_global
->smime
){
1539 for(pcert
=(PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
1546 email
= get_x509_subject_email(pcert
->cert
);
1550 for(i
= 0; email
[i
] && strucmp(email
[i
], buf
) != 0; i
++);
1551 if(email
[i
] != NULL
) done
++;
1552 for(i
= 0; email
[i
] != NULL
; i
++)
1553 fs_give((void **)&email
[i
]);
1554 fs_give((void **)email
);
1567 * Look for a personal certificate matching the from
1568 * (or reply_to? in the given envelope)
1571 match_personal_cert(ENVELOPE
*env
)
1573 PERSONAL_CERT
*pcert
;
1575 pcert
= match_personal_cert_to_email(env
->reply_to
);
1577 pcert
= match_personal_cert_to_email(env
->from
);
1584 * Flatten the given body into its MIME representation.
1585 * Return the result in a BIO.
1588 body_to_bio(BODY
*body
)
1593 bio
= BIO_new(BIO_s_mem());
1597 pine_encode_body(body
); /* this attaches random boundary strings to multiparts */
1598 pine_write_body_header(body
, rfc822_output_func
, bio
);
1599 pine_rfc822_output_body(body
, rfc822_output_func
, bio
);
1602 * Now need to truncate by two characters since the above
1605 if((len
=BIO_ctrl_pending(bio
)) > 1){
1606 BUF_MEM
*biobuf
= NULL
;
1608 BIO_get_mem_ptr(bio
, &biobuf
);
1610 BUF_MEM_grow(biobuf
, len
-2); /* remove CRLF */
1619 bio_from_store(STORE_S
*store
)
1623 if(store
&& store
->src
== BioType
&& store
->txt
){
1624 ret
= (BIO
*) store
->txt
;
1631 * Encrypt file; given a path (char *) fp, replace the file
1632 * by an encrypted version of it. If (char *) text is not null, then
1633 * replace the text of (char *) fp by the encrypted version of (char *) text.
1636 encrypt_file(char *fp
, char *text
)
1638 const EVP_CIPHER
*cipher
= NULL
;
1639 STACK_OF(X509
) *encerts
= NULL
;
1641 PERSONAL_CERT
*pcert
;
1648 if((pcert
= ps_global
->smime
->personal_certs
) == NULL
)
1651 cipher
= EVP_aes_256_cbc();
1652 encerts
= sk_X509_new_null();
1654 if((cert
= get_cert_for(pcert
->name
, Public
)) != NULL
)
1655 sk_X509_push(encerts
, cert
);
1660 in
= BIO_new(BIO_s_mem());
1663 (void) BIO_reset(in
);
1667 if(!(in
= BIO_new_file(fp
, "rb")))
1670 BIO_read_filename(in
, fp
);
1673 if((p7
= PKCS7_encrypt(encerts
, in
, cipher
, 0)) == NULL
)
1675 BIO_set_close(in
, BIO_CLOSE
);
1677 if(!(in
= BIO_new_file(fp
, "w")))
1680 rv
= PEM_write_bio_PKCS7(in
, p7
);
1686 sk_X509_pop_free(encerts
, X509_free
);
1692 * Encrypt a message on the way out. Called from call_mailer in send.c
1693 * The body may be reallocated.
1696 encrypt_outgoing_message(METAENV
*header
, BODY
**bodyP
)
1701 const EVP_CIPHER
*cipher
= NULL
;
1702 STACK_OF(X509
) *encerts
= NULL
;
1703 STORE_S
*outs
= NULL
;
1706 BODY
*body
= *bodyP
;
1707 BODY
*newBody
= NULL
;
1710 dprint((9, "encrypt_outgoing_message()"));
1713 cipher
= EVP_aes_256_cbc();
1715 encerts
= sk_X509_new_null();
1717 /* Look for a certificate for each of the recipients */
1718 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
1719 if(pf
->type
== Address
&& pf
->rcptto
&& pf
->addr
&& *pf
->addr
){
1720 for(a
=*pf
->addr
; a
; a
=a
->next
){
1724 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
1726 cert
= get_cert_for(buf
, Public
);
1728 sk_X509_push(encerts
,cert
);
1730 q_status_message2(SM_ORDER
, 1, 1,
1731 _("Unable to find certificate for <%s@%s>"),
1732 a
->mailbox
, a
->host
);
1739 in
= body_to_bio(body
);
1741 p7
= PKCS7_encrypt(encerts
, in
, cipher
, 0);
1743 outs
= so_get(BioType
, NULL
, EDIT_ACCESS
);
1744 out
= bio_from_store(outs
);
1746 i2d_PKCS7_bio(out
, p7
);
1747 (void) BIO_flush(out
);
1749 so_seek(outs
, 0, SEEK_SET
);
1751 newBody
= mail_newbody();
1753 newBody
->type
= TYPEAPPLICATION
;
1754 newBody
->subtype
= cpystr("pkcs7-mime");
1755 newBody
->encoding
= ENCBINARY
;
1757 newBody
->disposition
.type
= cpystr("attachment");
1758 set_parameter(&newBody
->disposition
.parameter
, "filename", "smime.p7m");
1760 newBody
->description
= cpystr("S/MIME Encrypted Message");
1761 set_parameter(&newBody
->parameter
, "smime-type", "enveloped-data");
1762 set_parameter(&newBody
->parameter
, "name", "smime.p7m");
1764 newBody
->contents
.text
.data
= (unsigned char *) outs
;
1774 sk_X509_pop_free(encerts
, X509_free
);
1776 dprint((9, "encrypt_outgoing_message returns %d", result
));
1782 Get (and decode) the body of the given section of msg
1785 get_part_contents(long msgno
, const char *section
)
1789 STORE_S
*store
= NULL
;
1792 store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
1794 gf_set_so_writec(&pc
,store
);
1796 err
= detach(ps_global
->mail_stream
, msgno
, (char*) section
, 0L, &len
, pc
, NULL
, 0L);
1798 gf_clear_so_writec(store
);
1800 so_seek(store
, 0, SEEK_SET
);
1811 get_pkcs7_from_part(long msgno
,const char *section
)
1813 STORE_S
*store
= NULL
;
1817 store
= get_part_contents(msgno
, section
);
1820 if(store
->src
== CharStar
){
1824 * We're reaching inside the STORE_S structure. We should
1825 * probably have a way to get the length, instead.
1827 len
= (int) (store
->eod
- store
->dp
);
1828 in
= BIO_new_mem_buf(store
->txt
, len
);
1830 else{ /* just copy it */
1833 in
= BIO_new(BIO_s_mem());
1834 (void) BIO_reset(in
);
1836 so_seek(store
, 0L, 0);
1837 while(so_readc(&c
, store
)){
1838 BIO_write(in
, &c
, 1);
1843 /* dump_bio_to_file(in, "/tmp/decoded-signature"); */
1844 if((p7
=d2i_PKCS7_bio(in
,NULL
)) == NULL
){
1857 int same_cert(X509
*x
, X509
*cert
)
1859 char bufcert
[256], bufx
[256];
1862 get_fingerprint(cert
, EVP_md5(), bufcert
, sizeof(bufcert
));
1863 get_fingerprint(x
, EVP_md5(), bufx
, sizeof(bufx
));
1864 if(strcmp(bufx
, bufcert
) == 0)
1871 /* extract and save certificates from a PKCS7 package. The ctype variable
1872 * tells us if we want to extract it to a public/ or a ca/ directory. The
1873 * later makes sense only for recoverable errors (errors that can be fixed
1874 * by saving to the ca/ directory before we verify the signature).
1876 * 0 - no errors (in public/) no need to try again,
1877 * or validated self signed certificate (in ca/)
1878 * 1 - self signed certificate was saved in public/, try again to validate it
1879 * 2 - user was prompted about self-signed certificate, but certificate was not saved
1880 * < 0 - certificate error is not recoverable, don't even think about it.
1883 int smime_extract_and_save_cert(PKCS7
*p7
)
1885 STACK_OF(X509
) *signers
;
1891 if((signers
= PKCS7_get0_signers(p7
, NULL
, 0)) == NULL
)
1894 rv
= 0; /* assume no error */
1895 for(i
= 0; i
< sk_X509_num(signers
); i
++){
1896 if((x
= sk_X509_value(signers
,i
)) == NULL
)
1899 if((email
= get_x509_subject_email(x
)) != NULL
){
1900 for(j
= 0; email
[j
] != NULL
; j
++){
1901 if((cert
= get_cert_for(email
[j
], Public
)) == NULL
|| same_cert(x
, cert
) == 0)
1902 save_cert_for(email
[j
], x
, Public
);
1904 if(smime_validate_cert(cert
, &error
) < 0){
1905 const char *error_string
= X509_verify_cert_error_string(error
);
1906 dprint((1, "Certificate verify error code %lu for <%s>", error
, email
[j
]));
1908 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
:
1909 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
:
1910 rv
= 2; /* recoverable error */
1912 default : rv
= -1; /* not recoverable error */
1915 sprintf(tmp_20k_buf
, "%s <%s>: %s", _("Error in certificate for "), email
[j
], error_string
);
1916 q_status_message(SM_ORDER
| SM_DING
, 2, 2, tmp_20k_buf
);
1918 if(pith_opt_action_certificate_error
)
1919 switch((*pith_opt_action_certificate_error
)(cert_error
)){
1920 case 1 : save_cert_for(email
[j
], x
, CACert
);
1931 fs_give((void **) &email
[i
]);
1933 fs_give((void **) email
);
1935 sk_X509_free(signers
);
1941 * Try to verify a signature.
1943 * p7 - the pkcs7 object to verify
1944 * in - the plain data to verify (NULL if not detached)
1945 * out - BIO to which to write the opaque data
1946 * silent - if non zero, do not print errors, only print success.
1949 do_signature_verify(PKCS7
*p7
, BIO
*in
, BIO
*out
, int silent
)
1951 STACK_OF(X509
) *otherCerts
= NULL
;
1957 if(!silent
) q_status_message(SM_ORDER
| SM_DING
, 2, 2,
1958 _("Couldn't verify S/MIME signature: No CA Certs were loaded"));
1963 smime_extract_and_save_cert(p7
);
1965 result
= PKCS7_verify(p7
, otherCerts
, s_cert_store
, in
, out
, 0);
1968 q_status_message(SM_ORDER
, 1, 1, _("S/MIME signature verified ok"));
1971 err
= ERR_peek_error_line_data(NULL
, NULL
, &data
, NULL
);
1973 if(out
&& err
==ERR_PACK(ERR_LIB_PKCS7
,PKCS7_F_PKCS7_VERIFY
,PKCS7_R_CERTIFICATE_VERIFY_ERROR
)){
1975 /* Retry verification so we can get the plain text */
1976 /* Might be better to reimplement PKCS7_verify here? */
1978 PKCS7_verify(p7
, otherCerts
, s_cert_store
, in
, out
, PKCS7_NOVERIFY
);
1980 if (!silent
) q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
1981 _("Couldn't verify S/MIME signature: %s"), (char*) openssl_error_string());
1989 free_smime_body_sparep(void **sparep
)
1991 if(sparep
&& *sparep
){
1992 PKCS7_free((PKCS7
*) (*sparep
));
1997 /* Big comment, explaining the mess that exists out there, and how we deal
1998 with it, and also how we solve the problems that are created this way.
2000 When Alpine sends a message, it constructs that message, computes the
2001 signature, but then it forgets the message it signed and reconstructs it
2002 again. Since it signs a message containing a notice about "mime aware
2003 tools", but it does not send that we do not include that in the part that
2004 is signed, and that takes care of much of the problems.
2006 Another problem is what is received from the servers. All servers tested
2007 seem to transmit the message that was signed intact and Alpine can check
2008 the signature correctly. That is not a problem. The problem arises when
2009 the message includes attachments. In this case different servers send
2010 different things, so it will be up to us to figure out what is the text
2011 that was actually signed. Confused? here is the story:
2013 When a message containing and attachment is sent by Alpine, UW-IMAP,
2014 Panda-IMAP, Gmail, and local reading of folders send exactly the message
2015 that was sent by Alpine, but GMX.com, Exchange, and probably other servers
2016 add a trailing \r\n in the message, so when validating the signature,
2017 these messages will not validate. There are several things that can be
2020 1. Add a trailing \r\n to any message that contains attachments, sign that
2021 and send that. In this way, all messages will validate with all
2024 2. Compatibility mode: If a message has an attachment, contains a trailing
2025 \r\n and does not validate (sent by an earlier version of Alpine),
2026 remove the trailing \r\n and try to revalidate again.
2028 3. We do not add \r\n to validate a message that we sent, because that
2029 would only work in Alpine, and not in any other client. That would not
2030 be a good thing to do.
2034 Now we have to deal with encrypted and signed messages. The problem is that
2035 c-client makes all its pointers point to "on disk" content, but since we
2036 decrypted the data earlier, we have to make sure of two things. One is that we
2037 saved that data (so we do not have to decrypt it again) and second that we can
2040 In order to save the data we use create_local_cache, so that we do not
2041 have to redecrypt the message. Once this is saved, c-client functions will
2042 find it and send it to us in mail_fetch_mime and mail_fetch_body.
2047 * Given a multipart body of type multipart/signed, attempt to verify it.
2048 * Returns non-zero if the body was changed.
2051 do_detached_signature_verify(BODY
*b
, long msgno
, char *section
)
2056 int result
, modified_the_body
= 0;
2057 unsigned long mimelen
, bodylen
;
2058 char newSec
[100], *mimetext
, *bodytext
;
2061 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"));
2064 snprintf(newSec
, sizeof(newSec
), "%s%s1", section
? section
: "", (section
&& *section
) ? "." : "");
2066 mimetext
= mail_fetch_mime(ps_global
->mail_stream
, msgno
, (char*) newSec
, &mimelen
, 0);
2069 bodytext
= mail_fetch_body (ps_global
->mail_stream
, msgno
, (char*) newSec
, &bodylen
, 0);
2071 if (mimetext
== NULL
|| bodytext
== NULL
)
2072 return modified_the_body
;
2074 snprintf(newSec
, sizeof(newSec
), "%s%s2", section
? section
: "", (section
&& *section
) ? "." : "");
2076 if((p7
= get_pkcs7_from_part(msgno
, newSec
)) == NULL
2077 || (in
= BIO_new(BIO_s_mem())) == NULL
)
2078 return modified_the_body
;
2080 (void) BIO_reset(in
);
2081 BIO_write(in
, mimetext
, mimelen
);
2082 BIO_write(in
, bodytext
, bodylen
);
2084 /* Try compatibility with the past and check if this message
2085 * validates when we remove the last two characters. Silence
2086 * any failures first.
2088 if(((result
= do_signature_verify(p7
, in
, NULL
, 1)) == 0)
2090 && (strncmp(bodytext
+bodylen
-2,"\r\n", 2) == 0)){
2091 BUF_MEM
*biobuf
= NULL
;
2093 BIO_get_mem_ptr(in
, &biobuf
);
2095 BUF_MEM_grow(biobuf
, mimelen
+ bodylen
- 2);
2096 result
= do_signature_verify(p7
, in
, NULL
, 0);
2101 fs_give((void**) &b
->subtype
);
2103 b
->subtype
= cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE
);
2104 b
->encoding
= ENC8BIT
;
2107 fs_give ((void**) &b
->description
);
2109 what_we_did
= result
? _("This message was cryptographically signed.") :
2110 _("This message was cryptographically signed but the signature could not be verified.");
2112 b
->description
= cpystr(what_we_did
);
2118 /* p is signed plaintext */
2120 mail_free_body_part(&p
->next
); /* hide the pkcs7 from the viewer */
2122 modified_the_body
= 1;
2124 return modified_the_body
;
2129 find_certificate_matching_recip_info(PKCS7_RECIP_INFO
*ri
)
2131 PERSONAL_CERT
*x
= NULL
;
2133 if(ps_global
->smime
){
2134 for(x
= (PERSONAL_CERT
*) ps_global
->smime
->personal_certs
; x
; x
=x
->next
){
2139 if(!X509_NAME_cmp(ri
->issuer_and_serial
->issuer
,mine
->cert_info
->issuer
) &&
2140 !ASN1_INTEGER_cmp(ri
->issuer_and_serial
->serial
,mine
->cert_info
->serialNumber
)){
2150 static PERSONAL_CERT
*
2151 find_certificate_matching_pkcs7(PKCS7
*p7
)
2154 STACK_OF(PKCS7_RECIP_INFO
) *recips
;
2155 PERSONAL_CERT
*x
= NULL
;
2157 recips
= p7
->d
.enveloped
->recipientinfo
;
2159 for(i
=0; i
<sk_PKCS7_RECIP_INFO_num(recips
); i
++){
2160 PKCS7_RECIP_INFO
*ri
;
2162 ri
= sk_PKCS7_RECIP_INFO_value(recips
, i
);
2164 if((x
=find_certificate_matching_recip_info(ri
))!=0){
2172 /* decrypt an encrypted file.
2173 Args: fp - the path to the encrypted file.
2174 rv - a code that thells the caller what happened inside the function
2175 Returns the decoded text allocated in a char *, whose memory must be
2180 decrypt_file(char *fp
, int *rv
)
2184 BIO
*in
= NULL
, *out
= NULL
;
2185 EVP_PKEY
*pkey
= NULL
, *key
= NULL
;
2186 PERSONAL_CERT
*pcert
= NULL
;
2188 STORE_S
*outs
= NULL
, *store
, *ins
;
2190 long unsigned int len
;
2195 if((text
= read_file(fp
, 0)) == NULL
)
2198 tmp
= fs_get(strlen(text
) + (strlen(text
) << 6) + 1);
2199 for(j
= 0, i
= strlen("-----BEGIN PKCS7-----") + 1; text
[i
] != '\0'
2200 && text
[i
] != '-'; j
++, i
++)
2204 ret
= rfc822_base64(tmp
, strlen(tmp
), &len
);
2206 if((in
= BIO_new_mem_buf((char *)ret
, len
)) != NULL
){
2207 p7
= d2i_PKCS7_bio(in
, NULL
);
2211 if(text
) fs_give((void **)&text
);
2212 if(ret
) fs_give((void **)&ret
);
2214 if((pcert
= ps_global
->smime
->personal_certs
) == NULL
)
2217 if((i
= load_private_key(pcert
)) == 0
2219 && ps_global
->smime
->need_passphrase
2220 && !ps_global
->smime
->already_auto_asked
)
2222 ps_global
->smime
->already_auto_asked
= 1;
2223 if(pith_opt_smime_get_passphrase
){
2224 switch((*pith_opt_smime_get_passphrase
)()){
2225 case 0 : i
= load_private_key(pcert
);
2231 default: break; /* repeat until we cancel */
2240 if((key
= pcert
->key
) == NULL
)
2243 recip
= get_cert_for(pcert
->name
, Public
);
2244 out
= BIO_new(BIO_s_mem());
2245 (void) BIO_reset(out
);
2247 i
= PKCS7_decrypt(p7
, key
, recip
, out
, 0);
2249 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
2250 forget_private_keys();
2253 q_status_message1(SM_ORDER
, 1, 1, _("Error decrypting: %s"),
2254 (char*) openssl_error_string());
2258 BIO_get_mem_data(out
, &tmp
);
2270 * Try to decode (decrypt or verify a signature) a PKCS7 body
2271 * Returns non-zero if something was changed.
2274 do_decoding(BODY
*b
, long msgno
, const char *section
)
2276 int modified_the_body
= 0;
2280 EVP_PKEY
*key
= NULL
;
2281 PERSONAL_CERT
*pcert
= NULL
;
2282 char *what_we_did
= "";
2285 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"));
2290 * Extract binary data from part to an in-memory store
2293 if(b
->sparep
){ /* already done */
2294 p7
= (PKCS7
*) b
->sparep
;
2298 p7
= get_pkcs7_from_part(msgno
, section
&& *section
? section
: "1");
2300 q_status_message1(SM_ORDER
, 2, 2, "Couldn't load PKCS7 object: %s",
2301 (char*) openssl_error_string());
2306 * Save the PKCS7 object for later dealings by the user interface.
2307 * It will be cleaned up when the body is garbage collected.
2312 dprint((1, "type_is_signed = %d, type_is_enveloped = %d", PKCS7_type_is_signed(p7
), PKCS7_type_is_enveloped(p7
)));
2314 if(PKCS7_type_is_signed(p7
)){
2317 out
= BIO_new(BIO_s_mem());
2318 (void) BIO_reset(out
);
2319 BIO_puts(out
, "MIME-Version: 1.0\r\n"); /* needed so rfc822_parse_msg_full believes it's MIME */
2321 sigok
= do_signature_verify(p7
, NULL
, out
, 0);
2323 what_we_did
= sigok
? _("This message was cryptographically signed.") :
2324 _("This message was cryptographically signed but the signature could not be verified.");
2326 /* make sure it's null terminated */
2327 BIO_write(out
, null
, 1);
2329 else if(!PKCS7_type_is_enveloped(p7
)){
2330 q_status_message(SM_ORDER
, 1, 1, "PKCS7 object not recognised.");
2333 else{ /* It *is* enveloped */
2336 what_we_did
= _("This message was encrypted.");
2338 /* now need to find a cert that can decrypt this */
2339 pcert
= find_certificate_matching_pkcs7(p7
);
2342 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find the certificate needed to decrypt."));
2346 recip
= pcert
->cert
;
2348 if(!load_private_key(pcert
)
2350 && ps_global
->smime
->need_passphrase
2351 && !ps_global
->smime
->already_auto_asked
){
2352 /* Couldn't load key with blank password, ask user */
2353 ps_global
->smime
->already_auto_asked
= 1;
2354 if(pith_opt_smime_get_passphrase
){
2355 (*pith_opt_smime_get_passphrase
)();
2356 load_private_key(pcert
);
2364 out
= BIO_new(BIO_s_mem());
2365 (void) BIO_reset(out
);
2366 BIO_puts(out
, "MIME-Version: 1.0\r\n");
2368 decrypt_result
= PKCS7_decrypt(p7
, key
, recip
, out
, 0);
2370 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
2371 forget_private_keys();
2373 if(!decrypt_result
){
2374 q_status_message1(SM_ORDER
, 1, 1, _("Error decrypting: %s"),
2375 (char*) openssl_error_string());
2379 BIO_write(out
, null
, 1);
2383 * We've now produced a flattened MIME object in BIO out.
2384 * It needs to be turned back into a BODY.
2393 BUF_MEM
*bptr
= NULL
;
2395 BIO_get_mem_ptr(out
, &bptr
);
2399 /* look for start of body */
2400 bstart
= strstr(h
, "\r\n\r\n");
2403 q_status_message(SM_ORDER
, 3, 3, _("Encrypted data couldn't be parsed."));
2406 bstart
+= 4; /* skip over CRLF*2 */
2408 INIT(&s
, mail_string
, bstart
, strlen(bstart
));
2409 rfc822_parse_msg_full(&env
, &body
, h
, (bstart
-h
)-2, &s
, BADHOST
, 0, 0);
2410 mail_free_envelope(&env
); /* Don't care about this */
2412 body
->mime
.offset
= 0;
2413 body
->mime
.text
.size
= 0;
2415 * Now convert original body (application/pkcs7-mime)
2416 * to a multipart body with one sub-part (the decrypted body).
2417 * Note that the sub-part may also be multipart!
2420 b
->type
= TYPEMULTIPART
;
2422 fs_give((void**) &b
->subtype
);
2425 * This subtype is used in mailview.c to annotate the display of
2426 * encrypted or signed messages. We know for sure then that it's a PKCS7
2427 * part because the sparep field is set to the PKCS7 object (see above).
2429 b
->subtype
= cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE
);
2430 b
->encoding
= ENC8BIT
;
2433 fs_give((void**) &b
->description
);
2435 b
->description
= cpystr(what_we_did
);
2437 if(b
->disposition
.type
)
2438 fs_give((void **) &b
->disposition
.type
);
2440 if(b
->contents
.text
.data
)
2441 fs_give((void **) &b
->contents
.text
.data
);
2444 mail_free_body_parameter(&b
->parameter
);
2446 /* Allocate mem for the sub-part, and copy over the contents of our parsed body */
2447 b
->nested
.part
= fs_get(sizeof(PART
));
2448 b
->nested
.part
->body
= *body
;
2449 b
->nested
.part
->next
= NULL
;
2451 fs_give((void**) &body
);
2454 * IMPORTANT BIT: set the body->contents.text.data elements to contain the decrypted
2455 * data. Otherwise, it'll try to load it from the original data. Eek.
2457 create_local_cache(bstart
-b
->nested
.part
->body
.mime
.offset
, bstart
, &b
->nested
.part
->body
);
2459 modified_the_body
= 1;
2467 return modified_the_body
;
2472 * Recursively handle PKCS7 bodies in our message.
2474 * Returns non-zero if some fiddling was done.
2477 do_fiddle_smime_message(BODY
*b
, long msgno
, char *section
)
2479 int modified_the_body
= 0;
2484 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"));
2486 if(is_pkcs7_body(b
)){
2488 if(do_decoding(b
, msgno
, section
)){
2490 * b should now be a multipart message:
2491 * fiddle it too in case it's been multiply-encrypted!
2495 modified_the_body
= 1;
2499 if(b
->type
==TYPEMULTIPART
|| MIME_MSG(b
->type
, b
->subtype
)){
2505 if(MIME_MULT_SIGNED(b
->type
, b
->subtype
)){
2509 * Ahah. We have a multipart signed entity.
2512 * part 1 (signed thing)
2513 * part 2 (the pkcs7 signature)
2515 * We're going to convert that to
2517 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
2518 * part 1 (signed thing)
2519 * part 2 has been freed
2521 * We also extract the signature from part 2 and save it
2522 * in the multipart body->sparep, and we add a description
2523 * in the multipart body->description.
2526 * The results of a decrypted message will be similar. It
2529 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
2530 * part 1 (decrypted thing)
2533 modified_the_body
+= do_detached_signature_verify(b
, msgno
, section
);
2535 else if(MIME_MSG(b
->type
, b
->subtype
)){
2536 modified_the_body
+= do_fiddle_smime_message(b
->nested
.msg
->body
, msgno
, section
);
2540 for(p
=b
->nested
.part
,partNum
=1; p
; p
=p
->next
,partNum
++){
2542 /* Append part number to the section string */
2544 snprintf(newSec
, sizeof(newSec
), "%s%s%d", section
, *section
? "." : "", partNum
);
2546 modified_the_body
+= do_fiddle_smime_message(&p
->body
, msgno
, newSec
);
2551 return modified_the_body
;
2556 * Fiddle a message in-place by decrypting/verifying S/MIME entities.
2557 * Returns non-zero if something was changed.
2560 fiddle_smime_message(BODY
*b
, long msgno
)
2562 return do_fiddle_smime_message(b
, msgno
, "");
2566 /********************************************************************************/
2570 * Output a string in a distinctive style
2573 gf_puts_uline(char *txt
, gf_io_t pc
)
2575 pc(TAG_EMBED
); pc(TAG_BOLDON
);
2577 pc(TAG_EMBED
); pc(TAG_BOLDOFF
);
2582 * Sign a message. Called from call_mailer in send.c.
2584 * This takes the header for the outgoing message as well as a pointer
2585 * to the current body (which may be reallocated).
2588 sign_outgoing_message(METAENV
*header
, BODY
**bodyP
, int dont_detach
)
2590 STORE_S
*outs
= NULL
;
2591 BODY
*body
= *bodyP
;
2592 BODY
*newBody
= NULL
;
2595 PERSONAL_CERT
*pcert
;
2600 int flags
= dont_detach
? 0 : PKCS7_DETACHED
;
2602 dprint((9, "sign_outgoing_message()"));
2606 /* Look for a private key matching the sender address... */
2608 pcert
= match_personal_cert(header
->env
);
2611 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find the certificate needed to sign."));
2615 if(!load_private_key(pcert
) && ps_global
->smime
&& ps_global
->smime
->need_passphrase
){
2616 /* Couldn't load key with blank password, try again */
2617 if(pith_opt_smime_get_passphrase
){
2618 (*pith_opt_smime_get_passphrase
)();
2619 load_private_key(pcert
);
2626 in
= body_to_bio(body
);
2629 dump_bio_to_file(in
,"/tmp/signed-data");
2632 p7
= PKCS7_sign(pcert
->cert
, pcert
->key
, NULL
, in
, flags
);
2634 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
2635 forget_private_keys();
2638 q_status_message(SM_ORDER
, 1, 1, _("Error creating signed object."));
2642 outs
= so_get(BioType
, NULL
, EDIT_ACCESS
);
2643 out
= bio_from_store(outs
);
2645 i2d_PKCS7_bio(out
, p7
);
2646 (void) BIO_flush(out
);
2648 so_seek(outs
, 0, SEEK_SET
);
2650 if((flags
&PKCS7_DETACHED
)==0){
2652 /* the simple case: the signed data is in the pkcs7 object */
2654 newBody
= mail_newbody();
2656 setup_pkcs7_body_for_signature(newBody
, "S/MIME Cryptographically Signed Message", "pkcs7-mime", "smime.p7m");
2658 newBody
->contents
.text
.data
= (unsigned char *) outs
;
2667 * We have to create a new body as follows:
2669 * multipart/signed; blah blah blah
2670 * reference to existing body
2675 newBody
= mail_newbody();
2677 newBody
->type
= TYPEMULTIPART
;
2678 newBody
->subtype
= cpystr("signed");
2679 newBody
->encoding
= ENC7BIT
;
2681 set_parameter(&newBody
->parameter
, "protocol", "application/pkcs7-signature");
2682 set_parameter(&newBody
->parameter
, "micalg", "sha1");
2684 p1
= mail_newbody_part();
2685 p2
= mail_newbody_part();
2688 * This is nasty. We're just copying the body in here,
2689 * but since our newBody is freed at the end of call_mailer,
2690 * we mustn't let this body (the original one) be freed twice.
2692 p1
->body
= *body
; /* ARRGH. This is special cased at the end of call_mailer */
2696 setup_pkcs7_body_for_signature(&p2
->body
, "S/MIME Cryptographic Signature", "pkcs7-signature", "smime.p7s");
2697 p2
->body
.contents
.text
.data
= (unsigned char *) outs
;
2699 newBody
->nested
.part
= p1
;
2711 dprint((9, "sign_outgoing_message returns %d", result
));
2717 new_smime_struct(void)
2719 SMIME_STUFF_S
*ret
= NULL
;
2721 ret
= (SMIME_STUFF_S
*) fs_get(sizeof(*ret
));
2722 memset((void *) ret
, 0, sizeof(*ret
));
2723 ret
->publictype
= Nada
;
2730 free_smime_struct(SMIME_STUFF_S
**smime
)
2732 if(smime
&& *smime
){
2733 if((*smime
)->passphrase_emailaddr
){
2735 for(i
= 0; (*smime
)->passphrase_emailaddr
[i
] != NULL
; i
++)
2736 fs_give((void **) &(*smime
)->passphrase_emailaddr
[i
]);
2737 fs_give((void **) (*smime
)->passphrase_emailaddr
);
2740 if((*smime
)->publicpath
)
2741 fs_give((void **) &(*smime
)->publicpath
);
2743 if((*smime
)->publiccertlist
)
2744 free_certlist(&(*smime
)->publiccertlist
);
2746 if((*smime
)->publiccertdata
)
2747 free_certlist(&(*smime
)->publiccertdata
);
2749 if((*smime
)->privatecertdata
)
2750 free_certlist(&(*smime
)->privatecertdata
);
2752 if((*smime
)->cacertdata
)
2753 free_certlist(&(*smime
)->cacertdata
);
2755 if((*smime
)->publiccontent
)
2756 fs_give((void **) &(*smime
)->publiccontent
);
2758 if((*smime
)->privatepath
)
2759 fs_give((void **) &(*smime
)->privatepath
);
2761 if((*smime
)->personal_certs
){
2764 pc
= (PERSONAL_CERT
*) (*smime
)->personal_certs
;
2765 free_personal_certs(&pc
);
2766 (*smime
)->personal_certs
= NULL
;
2769 if((*smime
)->privatecontent
)
2770 fs_give((void **) &(*smime
)->privatecontent
);
2772 if((*smime
)->capath
)
2773 fs_give((void **) &(*smime
)->capath
);
2775 if((*smime
)->cacontent
)
2776 fs_give((void **) &(*smime
)->cacontent
);
2778 fs_give((void **) smime
);