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-2017 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 "../pith/imap.h"
49 #include <openssl/buffer.h>
50 #include <openssl/x509v3.h>
51 #include <openssl/evp.h>
53 /* internal prototypes */
54 static void forget_private_keys(void);
55 static int app_RAND_load_file(const char *file
);
56 static void openssl_extra_randomness(void);
57 static int app_RAND_write_file(const char *file
);
58 static const char *openssl_error_string(void);
59 static int load_private_key(PERSONAL_CERT
*pcert
);
60 static void create_local_cache(char *h
, char *base
, BODY
*b
, int type
);
61 static long rfc822_output_func(void *b
, char *string
);
62 static void setup_pkcs7_body_for_signature(BODY
*b
, char *description
,
63 char *type
, char *filename
, char *smime_type
);
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_container_to_dir(WhichCerts which
);
75 static int do_fiddle_smime_message(BODY
*b
, long msgno
, char *section
);
76 void setup_privatekey_storage(void);
77 int smime_extract_and_save_cert(PKCS7
*p7
, int check_cert
);
78 int same_cert(X509
*, X509
*);
80 int load_key_and_cert(char *pathkeydir
, char *pathcertdir
, char **keyfile
, char **certfile
, EVP_PKEY
**pkey
, X509
**pcert
);
82 EVP_PKEY
*load_pkey_with_prompt(char *fpath
, char *text
, char *prompt
, int *);
83 void smime_remove_trailing_crlf(char **mimetext
, unsigned long *mimelen
, char **bodytext
, unsigned long *bodylen
);
84 void smime_remove_folding_space(char **mimetext
, unsigned long *mimelen
, char **bodytext
, unsigned long *bodylen
);
85 int smime_validate_extra_test(char *mimetext
, unsigned long mimelen
, char *bodytext
, unsigned long bodylen
, PKCS7
*p7
, int nflag
);
87 int (*pith_opt_smime_get_passphrase
)(void);
88 int (*pith_smime_import_certificate
)(char *, char *, char *, size_t);
89 int (*pith_smime_enter_password
)(char *, char *, size_t);
90 int (*pith_smime_confirm_save
)(char *);
92 static X509_STORE
*s_cert_store
;
94 /* State management for randomness functions below */
95 static int seeded
= 0;
98 create_smime_sparep(SpareType stype
, void *s
)
102 rv
= fs_get(sizeof(SMIME_SPARE_S
));
109 get_smime_sparep_type(void *s
)
111 return ((SMIME_SPARE_S
*)s
)->sptype
;
115 get_smime_sparep_data(void *s
)
117 return ((SMIME_SPARE_S
*)s
)->data
;
123 * load key from pathkeydir and cert from pathcertdir. It chooses the first
124 * key/certificate pair that matches. Delete pairs that you do not want used,
125 * if you do not want them selected. All parameters must be non-null.
126 * Memory freed by caller.
128 * -1 : user cancelled load
129 * 0 : load was successful
130 * 1 : there was an error in the loading.
133 load_key_and_cert(char *pathkeydir
, char *pathcertdir
, char **keyfile
,
134 char **certfile
, EVP_PKEY
**pkey
, X509
**pcert
)
136 char buf
[MAXPATH
+1], pathkey
[MAXPATH
+1], prompt
[MAILTMPLEN
];
139 int b
= 0, ret
= 1; /* assume error */
141 if(pathkeydir
== NULL
|| pathcertdir
== NULL
|| keyfile
== NULL
142 || pkey
== NULL
|| certfile
== NULL
|| pcert
== NULL
)
150 if((dirp
= opendir(pathkeydir
)) != NULL
){
151 while(b
== 0 && (d
=readdir(dirp
)) != NULL
){
154 if((ll
=strlen(d
->d_name
)) && ll
> 4){
155 if(!strcmp(d
->d_name
+ll
-4, ".key")){
156 strncpy(buf
, d
->d_name
, sizeof(buf
));
157 buf
[sizeof(buf
)-1] = '\0';
158 build_path(pathkey
, pathkeydir
, buf
, sizeof(pathkey
));
159 buf
[strlen(buf
)-4] = '\0';
160 snprintf(prompt
, sizeof(prompt
),
161 _("Enter password of key <%s> to unlock password file: "), buf
);
162 if((*pkey
= load_pkey_with_prompt(pathkey
, NULL
, prompt
, &ret
)) != NULL
){
163 if(load_cert_for_key(pathcertdir
, *pkey
, certfile
, pcert
)){
165 *keyfile
= cpystr(buf
);
167 EVP_PKEY_free(*pkey
);
169 q_status_message1(SM_ORDER
, 0, 2,
170 _("Cannot find certificate that matches key <%s>. Continuing..."), buf
);
182 /* setup a key and certificate to encrypt and decrypt a password file.
183 * These files will be saved in the .alpine-smime/.pwd directory, but its
184 * location can be setup in the command line with the -pwdcertdir option.
185 * Here are the rules:
187 * Check if the .alpine-smime/.pwd (or -pwdcertdir directory) exists,
188 * if not create it. If we are successful, move to the next step
190 * - If the user has a key/cert pair, in the .alpine-smime/.pwd dir
191 * setup is successful;
192 * - if the user does not have a key/cert pair, look to see if
193 * ps_global->smime->personal_certs is already setup, if so, use it.
194 * - if ps_global->smime->personal_certs is not set up, see if we can
195 * find a certificate/cert pair in the default locations at compilation
196 * time. (~/.alpine-smime/private and ~/.alpine-smime/public
197 * - if none of this is successful, create a key/certificate pair
198 * (TODO: implement this)
199 * - in any other case, setup is not successful.
201 * If setup is successful, setup ps_global->pwdcert.
202 * If any of this fails, ps_global->pwdcert will be null.
203 * Ok, that should do it.
205 * return values: 0 - everything is normal
206 * 1 - User could not unlock key or no key in directory.
207 * 2 - User cancelled to create self signed certificate
208 * -1 - we do not know which directory to use
209 * -2 - "-pwdcertdir" was given by user, but directory does not exist
210 * -3 - "DF_PASSWORD_DIR" exists but it is not a directory!!??
211 * -4 - we tried to create DF_PASSWORD_DIR but failed.
212 * -5 - password directory exists, but it is empty
216 setup_pwdcert(void **pwdcert
)
220 int setup_dir
= 0; /* make it non zero if we know which dir to use */
222 char pathdir
[MAXPATH
+1], pathkey
[MAXPATH
+1], fpath
[MAXPATH
+1], pathcert
[MAXPATH
+1];
223 char fpath2
[MAXPATH
+1], prompt
[MAILTMPLEN
];
224 char *keyfile
, *certfile
, *text
;
225 EVP_PKEY
*pkey
= NULL
;
227 PERSONAL_CERT
*pc
, *pc2
= NULL
;
228 static int was_here
= 0;
230 if(pwdcert
== NULL
|| was_here
== 1)
234 if(ps_global
->pwdcertdir
){
235 if(our_stat(ps_global
->pwdcertdir
, &sbuf
) == 0
236 && ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
)){
238 strncpy(pathdir
, ps_global
->pwdcertdir
, sizeof(pathdir
));
239 pathdir
[sizeof(pathdir
)-1] = '\0';
243 smime_path(DF_PASSWORD_DIR
, pathdir
, sizeof(pathdir
));
244 if(our_stat(pathdir
, &sbuf
) == 0){
245 if((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
)
248 } else if(can_access(pathdir
, ACCESS_EXISTS
) != 0
249 && our_mkpath(pathdir
, 0700) == 0)
259 if(load_key_and_cert(pathdir
, pathdir
, &keyfile
, &certfile
, &pkey
, &pcert
) < 0){
264 if(ps_global
->pwdcertdir
== NULL
){ /* save the result of pwdcertdir */
265 ps_global
->pwdcertdir
= cpystr(pathdir
);
266 /* if the user gave a pwdcertdir and there is nothing there, do not
267 * continue. Let the user initialize on their own this directory.
269 if(certfile
== NULL
|| keyfile
== NULL
){
275 if(certfile
&& keyfile
){
276 pc
= (PERSONAL_CERT
*) fs_get(sizeof(PERSONAL_CERT
));
277 memset((void *)pc
, 0, sizeof(PERSONAL_CERT
));
281 pc
->cname
= certfile
;
282 *pwdcert
= (void *) pc
;
287 /* look to see if there are any certificates lying around, first
288 * we try to load ps_global->smime to see if that has information
289 * we can use. If we are the process filling the smime structure
290 * we deinit at the end, since this might not do a full init.
292 if(ps_global
&& ps_global
->smime
&& !ps_global
->smime
->inited
){
297 /* at this point ps_global->smime->inited == 1 */
298 if(ps_global
->smime
&& ps_global
->smime
->personal_certs
!= NULL
){
299 pc
= (PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
300 if(ps_global
->smime
->privatetype
== Directory
){
301 build_path(pathkey
, ps_global
->smime
->privatepath
, pc
->name
, sizeof(pathkey
));
302 strncat(pathkey
, ".key", 4);
303 pathkey
[sizeof(pathkey
)-1] = '\0';
305 } else if (ps_global
->smime
->privatetype
== Container
){
306 if(pc
->keytext
== NULL
){ /* we should *never* be here, but just in case */
307 if(ps_global
->smime
->privatecontent
!= NULL
){
308 char tmp
[MAILTMPLEN
], *s
, *t
, c
;
309 snprintf(tmp
, sizeof(tmp
), "%s%s", EMAILADDRLEADER
, pc
->name
);
310 tmp
[sizeof(tmp
)-1] = '\0';
311 if((s
= strstr(ps_global
->smime
->privatecontent
, tmp
)) != NULL
){
312 if((t
= strstr(s
+strlen(tmp
), EMAILADDRLEADER
)) != NULL
){
315 pc
->keytext
= cpystr(s
+ strlen(tmp
) + 1); /* 1 = strlen("\n") */
319 pc
->keytext
= cpystr(s
+ strlen(tmp
) + 1); /* 1 = strlen("\n") */
323 if(pc
->keytext
!= NULL
) /* we should go straigth here */
325 } else if (ps_global
->smime
->privatetype
== Keychain
){
326 pathkey
[0] = '\0'; /* no apple key chain support yet */
329 if((pathkey
&& *pathkey
) || text
){
330 snprintf(prompt
, sizeof(prompt
),
331 _("Enter password of key <%s> to unlock password file: "), pc
->name
);
333 if((pkey
= load_pkey_with_prompt(pathkey
, text
, prompt
, NULL
)) != NULL
){
334 pc2
= (PERSONAL_CERT
*) fs_get(sizeof(PERSONAL_CERT
));
335 memset((void *)pc2
, 0, sizeof(PERSONAL_CERT
));
336 pc2
->name
= cpystr(pc
->name
);
338 pc2
->cert
= X509_dup(pc
->cert
);
340 /* now copy the keys and certs, starting by the key... */
341 build_path(fpath
, pathdir
, pc
->name
, sizeof(fpath
));
342 strncat(fpath
, ".key", 4);
343 fpath
[sizeof(fpath
)-1] = '\0';
344 if(our_stat(fpath
, &sbuf
) == 0){ /* if fpath exists */
345 if((sbuf
.st_mode
& S_IFMT
) == S_IFREG
) /* and is a regular file */
346 setup_dir
++; /* we are done */
347 } else if(ps_global
->smime
->privatetype
== Directory
){
348 if(our_copy(fpath
, pathkey
) == 0)
350 } else if(ps_global
->smime
->privatetype
== Container
){
352 if((out
= BIO_new_file(fpath
, "w")) != NULL
){
353 if(BIO_puts(out
, pc
->keytext
) > 0)
357 } else if(ps_global
->smime
->privatetype
== Keychain
){
358 /* add support for Apple Mac OS X */
362 /* successful copy of key, now continue with certificate */
366 build_path(pathkey
, ps_global
->smime
->publicpath
, pc
->name
, sizeof(pathkey
));
367 strncat(pathkey
, ".crt", 4);
368 pathkey
[sizeof(pathkey
)-1] = '\0';
370 build_path(fpath
, pathdir
, pc
->name
, sizeof(fpath
));
371 strncat(fpath
, ".crt", 4);
372 fpath
[sizeof(fpath
)-1] = '\0';
374 if(our_stat(fpath
, &sbuf
) == 0){
375 if((sbuf
.st_mode
& S_IFMT
) == S_IFREG
)
378 else if(ps_global
->smime
->privatetype
== Directory
){
379 if(our_copy(fpath
, pathkey
) == 0)
381 } else if(ps_global
->smime
->privatetype
== Container
) {
383 if((out
= BIO_new_file(fpath
, "w")) != NULL
){
384 if(PEM_write_bio_X509(out
, pc
->cert
))
388 } else if (ps_global
->smime
->privatetype
== Keychain
) {
389 /* add support for Mac OS X */
394 *pwdcert
= (void *) pc2
;
399 free_personal_certs(&pc2
);
400 } /* if (pathkey...) */
401 } /* if(ps_global->smime->personal_certs) */
405 /* PATHCERTDIR(Private) must be null, so create a path */
406 set_current_val(&ps_global
->vars
[V_PRIVATEKEY_DIR
], TRUE
, TRUE
);
407 smime_path(ps_global
->VAR_PRIVATEKEY_DIR
, pathkey
, sizeof(pathkey
));
409 /* PATHCERTDIR(Public) must be null, so create a path */
410 set_current_val(&ps_global
->vars
[V_PUBLICCERT_DIR
], TRUE
, TRUE
);
411 smime_path(ps_global
->VAR_PUBLICCERT_DIR
, pathcert
, sizeof(pathcert
));
413 /* BUG: this does not support local containers */
414 load_key_and_cert(pathkey
, pathcert
, &keyfile
, &certfile
, &pkey
, &pcert
);
416 if(certfile
&& keyfile
){
417 build_path(fpath
, pathdir
, keyfile
, sizeof(fpath
));
418 strncat(fpath
, ".key", 4);
419 fpath
[sizeof(fpath
)-1] = '\0';
421 build_path(fpath2
, pathkey
, keyfile
, sizeof(fpath
));
422 strncat(fpath2
, ".key", 4);
423 fpath2
[sizeof(fpath2
)-1] = '\0';
425 if(our_copy(fpath
, fpath2
) == 0)
431 build_path(fpath
, pathdir
, certfile
, sizeof(fpath
));
432 build_path(fpath2
, pathcert
, certfile
, sizeof(fpath2
));
434 if(our_copy(fpath
, fpath2
) == 0)
440 if(keyfile
&& certfile
){
441 pc
= (PERSONAL_CERT
*) fs_get(sizeof(PERSONAL_CERT
));
442 memset((void *)pc
, 0, sizeof(PERSONAL_CERT
));
446 *pwdcert
= (void *) pc
;
447 fs_give((void **)&certfile
);
457 #endif /* PASSFILE */
459 /* smime_expunge_cert.
460 * Return values: < 0 there was an error.
461 * >=0 the number of messages expunged
464 smime_expunge_cert(WhichCerts ctype
)
467 CertList
*cl
, *dummy
, *data
;
468 char *path
, buf
[MAXPATH
+1];
471 if(DATACERT(ctype
)== NULL
)
474 /* data cert is the way we unify certificate management across
475 * functions, but it is not where we really save the information in the
476 * case ctype is equal to Private. What we will do is to update the
477 * datacert, and in the case of ctype equal to Private use the updated
478 * certdata to update the personal_certs data.
481 path
= PATHCERTDIR(ctype
);
484 /* add a fake certificate at the beginning of the list */
485 dummy
= fs_get(sizeof(CertList
));
486 memset((void *)dummy
, 0, sizeof(CertList
));
487 dummy
->next
= DATACERT(ctype
);
489 for(cl
= dummy
, count
= 0; cl
&& cl
->next
;){
490 if(cl
->next
->data
.deleted
== 0){
495 removed
= 1; /* assume success */
496 if(SMHOLDERTYPE(ctype
) == Directory
){
497 build_path(buf
, path
, cl
->next
->name
, sizeof(buf
));
498 if(ctype
== Private
&& strlen(buf
) + strlen(EXTCERT(Private
)) < sizeof(buf
)){
499 strncat(buf
, EXTCERT(Private
), 4);
500 buf
[sizeof(buf
)-1] = '\0';
503 if(our_unlink(buf
) < 0){
504 q_status_message1(SM_ORDER
, 3, 3, _("Error removing certificate %s"), cl
->next
->name
);
509 else if(SMHOLDERTYPE(ctype
) == Container
){
510 char *prefix
= ctype
== CACert
? CACERTSTORELEADER
: EMAILADDRLEADER
;
511 char tmp
[MAILTMPLEN
], *s
, *t
;
513 contents
= CONTENTCERTLIST(ctype
);
514 snprintf(tmp
, sizeof(tmp
), "%s%s", prefix
, cl
->next
->name
);
515 tmp
[sizeof(tmp
) - 1] = '\0';
516 if((s
= strstr(contents
, tmp
)) != NULL
){
517 if((t
= strstr(s
+strlen(tmp
), prefix
)) == NULL
)
520 memmove(s
, t
, strlen(t
)+1);
521 fs_resize((void **)&contents
, strlen(contents
)+1);
523 case Private
: ps_global
->smime
->privatecontent
= contents
; break;
524 case Public
: ps_global
->smime
->publiccontent
= contents
; break;
525 case CACert
: ps_global
->smime
->cacontent
= contents
; break;
531 } else { /* unhandled case */
535 count
++; /* count it! */
537 cl
->next
= data
->next
;
538 if(data
->name
) fs_give((void **)&data
->name
);
539 fs_give((void **)&data
);
543 q_status_message(SM_ORDER
, 3, 3, _("Error expunging certificate"));
546 case Private
: ps_global
->smime
->privatecertlist
= dummy
->next
; break;
547 case Public
: ps_global
->smime
->publiccertlist
= dummy
->next
; break;
548 case CACert
: ps_global
->smime
->cacertlist
= dummy
->next
; break;
551 fs_give((void **)&dummy
);
552 if(SMHOLDERTYPE(ctype
) == Container
){
553 if(copy_dir_to_container(ctype
, contents
) < 0)
557 q_status_message2(SM_ORDER
, 3, 3, _("Removed %s certificate%s"), comatose(count
), plural(count
));
560 q_status_message(SM_ORDER
, 3, 3, _("Error: No certificates were removed"));
565 mark_cert_deleted(WhichCerts ctype
, int num
, unsigned state
)
570 for(cl
= DATACERT(ctype
), i
= 0; cl
!= NULL
&& i
< num
; cl
= cl
->next
, i
++);
571 cl
->data
.deleted
= state
;
575 get_cert_deleted(WhichCerts ctype
, int num
)
580 for(cl
= DATACERT(ctype
), i
= 0; cl
!= NULL
&& i
< num
; cl
= cl
->next
, i
++);
581 return (cl
&& cl
->data
.deleted
) ? 1 : 0;
585 load_pkey_with_prompt(char *fpath
, char *text
, char *prompt
, int *ret
)
588 int rc
= 0; /* rc == 1, cancel, rc == 0 success */
589 char pass
[MAILTMPLEN
+1];
592 /* attempt to load with empty password */
593 in
= text
? BIO_new_mem_buf(text
, strlen(text
)) : BIO_new_file(fpath
, "r");
595 pkey
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, "");
596 if(pkey
!= NULL
) return pkey
;
599 if(pith_smime_enter_password
)
600 while(pkey
== NULL
&& rc
!= 1){
602 rc
= (*pith_smime_enter_password
)(prompt
, (char *)pass
, sizeof(pass
));
603 } while (rc
!=0 && rc
!=1 && rc
>0);
605 (void) BIO_reset(in
);
606 pkey
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, (char *)pass
);
611 if(ret
) *ret
= rc
== 1 ? -1 : pkey
!= NULL
? 0 : 1;
615 /* This is a tool for conf_screen, The return value must be zero when
616 * nothing changed, so if there is a failure in the import return 0
617 * and return 1 when we succeeded.\
618 * We call this function in two ways:
619 * either fname is null or not. If they fname is null, so is p_cert.
620 * if p_cert is not null, it is the PERSONAL_CERT structure of fname if this
621 * is available, otherwise we will fill it up here.
624 import_certificate(WhichCerts ctype
, PERSONAL_CERT
*p_cert
, char *fname
)
627 char filename
[MAXPATH
+1], full_filename
[MAXPATH
+1], buf
[MAXPATH
+1];
630 if(pith_smime_import_certificate
== NULL
631 || pith_smime_enter_password
== NULL
){
632 q_status_message(SM_ORDER
, 0, 2,
633 _("import of certificates not implemented yet!"));
638 what
= ctype
== Public
|| ctype
== CACert
? "certificate" : "key";
639 r
= (*pith_smime_import_certificate
)(filename
, full_filename
, what
, sizeof(filename
) - 20);
645 strncpy(full_filename
, fname
, sizeof(full_filename
));
646 if((s
= strrchr(full_filename
, '/')) != NULL
)
647 strncpy(filename
, s
+1, sizeof(filename
));
650 /* we are trying to import a new key for the password file. First we ask for the
651 * private key. Once this is loaded, we make a reasonable attempt to find the
652 * public key in the same directory as the key was loaded from. We do this by
653 * looking for a file with the correct public certificate name, then we look
654 * in the same private key, and if not, we ask the user for its location. If all
655 * of this works, we import the key and public to the password directory.
658 if(ctype
== Password
){
659 char PrivateKeyPath
[MAXPATH
+1], PublicCertPath
[MAXPATH
+1], s
[MAXPATH
+1];
660 char full_name_key
[MAXPATH
+1], full_name_cert
[MAXPATH
+1];
663 EVP_PKEY
*key
= p_cert
? p_cert
->key
: NULL
;
665 rc
= 1; /* assume success :) */
666 if(strlen(filename
) > 4){
667 strncpy(s
, filename
, sizeof(s
));
668 s
[sizeof(s
)-1] = '\0';
669 if(!strcmp(s
+ strlen(s
) - strlen(EXTCERT(Private
)), EXTCERT(Private
)))
670 s
[strlen(s
) - strlen(EXTCERT(Private
))] = '\0';
676 q_status_message(SM_ORDER
, 1, 3, _("Error in key name. Check file extension"));
680 snprintf(prompt
, sizeof(prompt
), _("Enter passphrase to unlock new key <%s>: "), filename
);
681 prompt
[sizeof(prompt
)-1] = '\0';
683 || (key
= load_pkey_with_prompt(full_filename
, NULL
, prompt
, NULL
)) != NULL
){
685 X509
*cert
= p_cert
? p_cert
->cert
: NULL
, *cert2
;
687 strncpy(full_name_key
, full_filename
, sizeof(full_filename
));
688 full_name_key
[sizeof(full_name_key
)-1] = '\0';
690 build_path(buf
, PATHCERTDIR(ctype
), s
, sizeof(buf
));
692 strncpy(PrivateKeyPath
, buf
, sizeof(PrivateKeyPath
));
693 PrivateKeyPath
[sizeof(PrivateKeyPath
)-1] = '\0';
694 if(strlen(PrivateKeyPath
) + 4 < sizeof(PrivateKeyPath
)){
695 strncat(PrivateKeyPath
, EXTCERT(Private
), 4);
696 PrivateKeyPath
[sizeof(PrivateKeyPath
)-1] = '\0';
699 /* remove .key extension and replace it with .crt extension */
700 strncpy(full_name_cert
, full_name_key
, sizeof(full_name_key
));
701 full_name_cert
[sizeof(full_name_cert
)-1] = '\0';
702 full_name_cert
[strlen(full_name_cert
) - strlen(EXTCERT(Private
))] = '\0';
703 strncat(full_name_cert
, EXTCERT(Public
), 4);
704 full_name_cert
[sizeof(full_name_cert
)-1] = '\0';
707 /* set up path to location where we will save public cert */
708 strncpy(PublicCertPath
, buf
, sizeof(PublicCertPath
));
709 PublicCertPath
[sizeof(PublicCertPath
)-1] = '\0';
710 if(strlen(PublicCertPath
) + 4 < sizeof(PublicCertPath
)){
711 strncat(PublicCertPath
, EXTCERT(Public
), 4);
712 PublicCertPath
[sizeof(PublicCertPath
)-1] = '\0';
714 /* attempt #1, use provided certificate,
715 * assumption is that full_name_cert is the file that this
716 * certificate derives from (which is obtained by substitution
717 * of .key extension in key by .crt extension)
719 if(cert
!= NULL
) /* attempt #1 */
720 use_this_file
= &full_name_cert
[0];
721 else if((ins
= BIO_new_file(full_name_cert
, "r")) != NULL
){
722 /* attempt #2 to guess public cert name, use .crt extension */
723 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
){
724 use_this_file
= &full_name_cert
[0];
727 else{ /* attempt #3 to guess public cert name: use the original key */
728 if((ins
= BIO_new_file(full_name_key
, "r")) != NULL
){
729 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
){
730 use_this_file
= &full_name_key
[0];
735 /* attempt #4, ask the user */
737 r
= (*pith_smime_import_certificate
)(filename
, use_this_file
, "certificate", sizeof(filename
) - 20);
739 if(ins
!= NULL
) BIO_free(ins
);
740 if(cert
!= NULL
) X509_free(cert
);
743 if((ins
= BIO_new_file(use_this_file
, "r")) != NULL
){
744 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
)
747 q_status_message(SM_ORDER
, 1, 3, _("Error parsing certificate"));
750 q_status_message(SM_ORDER
, 1, 3, _("Error reading certificate"));
755 if(cert
!= NULL
){ /* check that certificate matches key */
756 if(!X509_check_private_key(cert
, key
)){
758 q_status_message(SM_ORDER
, 1, 3, _("Certificate does not match key"));
761 rc
= 1; /* Success! */
764 q_status_message(SM_ORDER
, 1, 3, _("Error in certificate file (not a certificate?)"));
766 if(rc
== 1){ /* if everything has been successful,
767 * copy the files to their final destination */
768 if(our_copy(PrivateKeyPath
, full_filename
) == 0){ /* <-- save the private key */
769 q_status_message(SM_ORDER
, 1, 3, _("Private key saved"));
770 if(our_copy(PublicCertPath
, use_this_file
) == 0){
771 char tmp
[MAILTMPLEN
];
774 if(!passfile_name(ps_global
->pinerc
, tmp
, sizeof(tmp
))
775 || !(fp
= our_fopen(tmp
, "rb"))){
776 q_status_message(SM_ORDER
, 1, 3, _("Error reading password file!"));
780 char tmp2
[MAILTMPLEN
];
783 PERSONAL_CERT
*pwdcert
, *pc
= p_cert
;
785 pwdcert
= (PERSONAL_CERT
*) ps_global
->pwdcert
;
787 setup_pwdcert((void **)&pwdcert
);
790 fgets(tmp2
, sizeof(tmp2
), fp
);
792 if(strcmp(tmp2
, "-----BEGIN PKCS7-----\n")){
793 if(encrypt_file((char *)tmp
, NULL
, pwdcert
))
800 text
= decrypt_file((char *)tmp
, NULL
, pwdcert
);
803 pc
= fs_get(sizeof(PERSONAL_CERT
));
804 memset((void *)pc
, 0, sizeof(PERSONAL_CERT
));
805 filename
[strlen(filename
)-strlen(EXTCERT(Private
))] = '\0';
806 pc
->name
= cpystr(filename
);
807 snprintf(buf
, sizeof(buf
), "%s%s", filename
, EXTCERT(Public
));
808 buf
[sizeof(buf
)-1] = '\0';
809 pc
->cname
= cpystr(buf
);
814 if(encrypt_file((char *)tmp
, text
, pc
)){ /* we did it! */
815 build_path(buf
, PATHCERTDIR(ctype
), pwdcert
->name
, sizeof(buf
));
816 strncat(buf
, EXTCERT(Private
), 4);
817 buf
[sizeof(buf
)-1] = '\0';
818 if(strcmp(PrivateKeyPath
, buf
)){
820 q_status_message(SM_ORDER
, 1, 3, _("Failed to remove old key"));
822 build_path(buf
, PATHCERTDIR(ctype
), pwdcert
->cname
, sizeof(buf
));
823 if(strcmp(PublicCertPath
, buf
)){
825 q_status_message(SM_ORDER
, 1, 3, _("Failed to remove old certificate"));
827 free_personal_certs((PERSONAL_CERT
**)&ps_global
->pwdcert
);
828 ps_global
->pwdcert
= pc
;
830 q_status_message(SM_ORDER
, 1, 3, _("Password file reencrypted"));
832 q_status_message(SM_ORDER
, 1, 3, _("Failed to reencrypt password file"));
836 q_status_message(SM_ORDER
, 1, 3, _("Error decrypting Password file"));
839 q_status_message(SM_ORDER
, 1, 3, _("Password file not encrypted and coulr not encrypt"));
845 q_status_message(SM_ORDER
, 1, 3, _("Error saving public certificate"));
846 if(our_unlink(PrivateKeyPath
) < 0)
847 q_status_message(SM_ORDER
, 1, 3, _("Error while cleaning private key"));
853 q_status_message(SM_ORDER
, 1, 3, _("Error saving private key"));
855 if(ins
!= NULL
) BIO_free(ins
);
856 if(rc
== 0 && cert
!= NULL
) X509_free(cert
);
860 q_status_message(SM_ORDER
, 1, 3, _("Error unlocking private key"));
865 #endif /* PASSFILE */
868 ps_global
->mangled_screen
= 1;
870 if (ctype
== Private
){
871 char prompt
[500], *s
, *t
;
872 EVP_PKEY
*key
= NULL
;
874 if(!ps_global
->smime
->privatecertlist
){
875 ps_global
->smime
->privatecertlist
= fs_get(sizeof(CertList
));
876 memset((void *)DATACERT(ctype
), 0, sizeof(CertList
));
879 for(s
= t
= filename
; (t
= strstr(s
, ".key")) != NULL
; s
= t
+ 1);
882 snprintf(prompt
, sizeof(prompt
), _("Enter passphrase for <%s>: "), filename
);
883 prompt
[sizeof(prompt
)-1] = '\0';
884 if((key
= load_pkey_with_prompt(full_filename
, NULL
, prompt
, NULL
)) != NULL
){
885 if(SMHOLDERTYPE(ctype
) == Directory
){
886 build_path(buf
, PATHCERTDIR(ctype
), filename
, sizeof(buf
));
887 if(strcmp(buf
+ strlen(buf
) - 4, EXTCERT(ctype
)) != 0 && strlen(buf
) + 4 < sizeof(buf
)){
888 strncat(buf
, EXTCERT(ctype
), 4);
889 buf
[sizeof(buf
)-1] = '\0';
891 rc
= our_copy(buf
, full_filename
);
893 else /* if(SMHOLDERTYPE(ctype) == Container){ */
894 rc
= add_file_to_container(ctype
, full_filename
, NULL
);
896 q_status_message(SM_ORDER
, 1, 3, _("Private key saved"));
898 q_status_message(SM_ORDER
, 1, 3, _("Error saving private key"));
899 if(ps_global
->smime
->publiccertlist
)
900 ps_global
->smime
->publiccertlist
->data
.renew
= 1;
903 q_status_message(SM_ORDER
, 1, 3, _("Problem unlocking key (not a certificate or wrong password)"));
904 } else if (ctype
== CACert
){
908 if((ins
= BIO_new_file(full_filename
, "r")) != NULL
){
909 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
){
910 if(SMHOLDERTYPE(ctype
) == Directory
){
911 build_path(buf
, PATHCERTDIR(ctype
), filename
, sizeof(buf
));
912 if(strcmp(buf
+ strlen(buf
) - 4, ".crt") != 0 && strlen(buf
) + 4 < sizeof(buf
)){
913 strncat(buf
, EXTCERT(ctype
), 4);
914 buf
[sizeof(buf
)-1] = '\0';
917 rc
= our_copy(buf
, full_filename
);
919 else /* if(SMHOLDERTYPE(ctype) == Container){ */
920 rc
= add_file_to_container(ctype
, full_filename
, NULL
);
922 q_status_message(SM_ORDER
, 1, 3, _("Certificate saved"));
924 q_status_message(SM_ORDER
, 1, 3, _("Error saving certificate"));
925 X509_free(cert
); /* not needed anymore */
928 q_status_message(SM_ORDER
, 1, 3, _("Error in certificate file (not a certificate?)"));
932 } else { /* ctype == Public. save certificate, but first validate that it is one */
936 if((ins
= BIO_new_file(full_filename
, "r")) != NULL
){
937 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
){
938 if(SMHOLDERTYPE(ctype
) == Directory
){
941 if((email
= get_x509_subject_email(cert
)) != NULL
){
943 for(i
= 0; email
[i
] != NULL
; i
++){
944 save_cert_for(email
[i
], cert
, Public
);
945 fs_give((void **)&email
[i
]);
947 fs_give((void **)email
);
949 if(strcmp(filename
+ strlen(filename
) - 4, ".crt") == 0)
950 filename
[strlen(filename
) - 4] = '\0';
951 save_cert_for(filename
, cert
, Public
);
953 else /* if(SMHOLDERTYPE(ctype) == Container){ */
954 add_file_to_container(ctype
, full_filename
, NULL
);
956 if(ps_global
->smime
->publiccertlist
)
957 ps_global
->smime
->publiccertlist
->data
.renew
= 1;
960 q_status_message(SM_ORDER
, 1, 3, _("Error in certificate file (not a certificate?)"));
964 if(DATACERT(ctype
)) RENEWCERT(DATACERT(ctype
)) = 1;
968 /* itype: information type to add: 0 - public, 1 - private.
969 * Memory freed by caller
972 print_private_key_information(char *email
, int itype
)
977 if(ps_global
->smime
== NULL
978 || ps_global
->smime
->personal_certs
== NULL
979 || (itype
!= 0 && itype
!= 1))
982 for(pc
= ps_global
->smime
->personal_certs
;
983 pc
!= NULL
&& strcmp(pc
->name
, email
) != 0; pc
= pc
->next
);
985 && !load_private_key(pc
)
987 && ps_global
->smime
->need_passphrase
){
988 if (*pith_opt_smime_get_passphrase
)
989 (*pith_opt_smime_get_passphrase
)();
990 load_private_key(pc
);
996 out
= BIO_new(BIO_s_mem());
997 if(itype
== 0) /* 0 means public */
998 EVP_PKEY_print_public(out
, pc
->key
, 0, NULL
);
999 else if (itype
== 1) /* 1 means private */
1000 EVP_PKEY_print_private(out
, pc
->key
, 0, NULL
);
1002 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
1003 forget_private_keys();
1009 * Forget any cached private keys
1012 forget_private_keys(void)
1014 PERSONAL_CERT
*pcert
;
1018 dprint((9, "forget_private_keys()"));
1019 if(ps_global
->smime
){
1020 ps_global
->smime
->already_auto_asked
= 0;
1021 for(pcert
=(PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
1026 EVP_PKEY_free(pcert
->key
);
1031 ps_global
->smime
->entered_passphrase
= 0;
1032 len
= sizeof(ps_global
->smime
->passphrase
);
1033 p
= ps_global
->smime
->passphrase
;
1040 /* modelled after signature_path in reply.c, but uses home dir instead of the
1041 * directory where the .pinerc is located, since according to documentation,
1042 * the .alpine-smime directories are subdirectories of the home directory
1044 int smime_path(char *rpath
, char *fpath
, size_t len
)
1047 if(rpath
&& *rpath
){
1048 size_t spl
= strlen(rpath
);
1050 if(IS_REMOTE(rpath
)){
1052 strncpy(fpath
, rpath
, len
-1);
1053 fpath
[len
-1] = '\0';
1055 else if(is_absolute_path(rpath
)){
1056 strncpy(fpath
, rpath
, len
-1);
1057 fpath
[len
-1] = '\0';
1058 fnexpand(fpath
, len
);
1060 else if(ps_global
->VAR_OPER_DIR
){
1061 if(strlen(ps_global
->VAR_OPER_DIR
) + spl
< len
- 1)
1062 build_path(fpath
, ps_global
->VAR_OPER_DIR
, rpath
, len
);
1064 else if(ps_global
->home_dir
){
1065 if(strlen(ps_global
->home_dir
) + spl
< len
- 1)
1066 build_path(fpath
, ps_global
->home_dir
, rpath
, len
);
1069 return fpath
&& *fpath
? 1 : 0;
1075 * taken from openssl/apps/app_rand.c
1078 app_RAND_load_file(const char *file
)
1080 #define RANDBUFLEN 200
1081 char buffer
[RANDBUFLEN
];
1084 file
= RAND_file_name(buffer
, RANDBUFLEN
);
1086 if(file
== NULL
|| !RAND_load_file(file
, -1)){
1087 if(RAND_status() == 0){
1088 dprint((1, "unable to load 'random state'\n"));
1089 dprint((1, "This means that the random number generator has not been seeded\n"));
1090 dprint((1, "with much random data.\n"));
1102 * copied and fiddled from imap/src/osdep/unix/auth_ssl.c
1105 openssl_extra_randomness(void)
1113 /* if system doesn't have /dev/urandom */
1114 if(stat ("/dev/urandom", &sbuf
)){
1116 tf
= temp_nam(NULL
, NULL
);
1118 strncpy(tmp
, tf
, sizeof(tmp
));
1119 tmp
[sizeof(tmp
)-1] = '\0';
1120 fs_give((void **) &tf
);
1123 if((fd
= open(tmp
, O_WRONLY
|O_CREAT
|O_EXCL
, 0600)) < 0)
1124 i
= (unsigned long) tmp
;
1126 unlink(tmp
); /* don't need the file */
1127 fstat(fd
, &sbuf
); /* get information about the file */
1128 i
= sbuf
.st_ino
; /* remember its inode */
1129 close(fd
); /* or its descriptor */
1131 /* not great but it'll have to do */
1132 snprintf(tmp
+strlen(tmp
), sizeof(tmp
)-strlen(tmp
), "%.80s%lx%lx%lx",
1133 tcp_serverhost (),i
,
1134 (unsigned long) (time (0) ^ gethostid ()),
1135 (unsigned long) getpid ());
1136 RAND_seed(tmp
, strlen(tmp
));
1142 /* taken from openssl/apps/app_rand.c */
1144 app_RAND_write_file(const char *file
)
1150 * If we did not manage to read the seed file,
1151 * we should not write a low-entropy seed file back --
1152 * it would suppress a crucial warning the next time
1153 * we want to use it.
1158 file
= RAND_file_name(buffer
, sizeof buffer
);
1160 if(file
== NULL
|| !RAND_write_file(file
)){
1161 dprint((1, "unable to write 'random state'\n"));
1169 certlist_from_personal_certs(PERSONAL_CERT
*pc
)
1177 if((x
= get_cert_for(pc
->name
, Public
, 1)) != NULL
)
1178 cl
= smime_X509_to_cert_info(x
, pc
->name
);
1179 cl
->next
= certlist_from_personal_certs(pc
->next
);
1185 renew_cert_data(CertList
**data
, WhichCerts ctype
)
1188 if(ctype
== Private
){
1190 PERSONAL_CERT
*pc
= (PERSONAL_CERT
*)ps_global
->smime
->personal_certs
;
1192 free_certlist(data
);
1193 free_personal_certs(&pc
);
1194 setup_privatekey_storage();
1195 *data
= certlist_from_personal_certs((PERSONAL_CERT
*)ps_global
->smime
->personal_certs
);
1197 resort_certificates(data
, ctype
);
1198 RENEWCERT(*data
) = 0;
1200 ps_global
->smime
->privatecertlist
= *data
;
1202 if(ps_global
->smime
->privatecertlist
)
1203 RENEWCERT(ps_global
->smime
->privatecertlist
) = 0;
1205 X509_LOOKUP
*lookup
= NULL
;
1206 X509_STORE
*store
= NULL
;
1208 if((store
= X509_STORE_new()) != NULL
){
1209 if((lookup
= X509_STORE_add_lookup(store
, X509_LOOKUP_file())) == NULL
){
1210 X509_STORE_free(store
);
1213 free_certlist(data
);
1214 if(SMHOLDERTYPE(ctype
) == Directory
)
1215 add_certs_in_dir(lookup
, PATHCERTDIR(ctype
), EXTCERT(ctype
), data
);
1216 else /* if(SMHOLDERTYPE(ctype) == Container) */
1217 *data
= mem_to_certlist(CONTENTCERTLIST(ctype
), ctype
);
1219 resort_certificates(data
, ctype
);
1220 RENEWCERT(*data
) = 0;
1223 ps_global
->smime
->publiccertlist
= *data
;
1225 ps_global
->smime
->cacertlist
= *data
;
1229 setup_certs_backup_by_type(ctype
);
1239 /* Installed as an atexit() handler to save the random data */
1243 dprint((9, "smime_deinit()"));
1244 app_RAND_write_file(NULL
);
1245 free_smime_struct(&ps_global
->smime
);
1248 /* we renew the store when it has changed */
1249 void renew_store(void)
1251 if(ps_global
->smime
->inited
){
1252 if(s_cert_store
!= NULL
)
1253 X509_STORE_free(s_cert_store
);
1254 s_cert_store
= get_ca_store();
1258 /* Initialise openssl stuff if needed */
1262 if(F_OFF(F_DONT_DO_SMIME
, ps_global
) && !(ps_global
->smime
&& ps_global
->smime
->inited
)){
1264 dprint((9, "smime_init()"));
1265 if(!ps_global
->smime
)
1266 ps_global
->smime
= new_smime_struct();
1268 setup_storage_locations();
1270 s_cert_store
= get_ca_store();
1271 setup_certs_backup_by_type(CACert
);
1273 #ifdef OPENSSL_1_1_0
1274 OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|OPENSSL_INIT_ADD_ALL_DIGESTS
|OPENSSL_INIT_LOAD_CRYPTO_STRINGS
, NULL
);
1276 OpenSSL_add_all_algorithms();
1277 ERR_load_crypto_strings();
1278 #endif /* OPENSSL_1_1_0 */
1280 app_RAND_load_file(NULL
);
1281 openssl_extra_randomness();
1282 ps_global
->smime
->inited
= 1;
1289 /* validate a certificate. Return value : 0 for no error, -1 for error.
1290 * In the latter case, set the openssl smime error in *error.
1292 int smime_validate_cert(X509
*cert
, long *error
)
1294 X509_STORE_CTX
*csc
;
1298 if((s_cert_store
!= NULL
) && (csc
= X509_STORE_CTX_new()) != NULL
){
1299 X509_STORE_set_flags(s_cert_store
, 0);
1300 if(X509_STORE_CTX_init(csc
,s_cert_store
,cert
,NULL
)
1301 && X509_verify_cert(csc
) <= 0)
1302 *error
= X509_STORE_CTX_get_error(csc
);
1303 X509_STORE_CTX_free(csc
);
1305 return *error
? -1 : 0;
1309 get_personal_certs(char *path
)
1311 PERSONAL_CERT
*result
= NULL
;
1316 ps_global
->smime
->privatepath
= cpystr(path
);
1317 dirp
= opendir(path
);
1319 while((d
=readdir(dirp
)) != NULL
){
1323 if((ll
=strlen(d
->d_name
)) && ll
> 4 && !strcmp(d
->d_name
+ll
-4, ".key")){
1325 /* copy file name to temp buffer */
1326 strncpy(buf2
, d
->d_name
, sizeof(buf2
)-1);
1327 buf2
[sizeof(buf2
)-1] = '\0';
1328 /* chop off ".key" trailier */
1329 buf2
[strlen(buf2
)-4] = '\0';
1330 /* Look for certificate */
1331 cert
= get_cert_for(buf2
, Public
, 1);
1336 /* create a new PERSONAL_CERT, fill it in */
1338 pc
= (PERSONAL_CERT
*) fs_get(sizeof(*pc
));
1340 pc
->name
= cpystr(buf2
);
1341 strncat(buf2
, EXTCERT(Public
), 4);
1342 pc
->cname
= cpystr(buf2
);
1344 /* Try to load the key with an empty password */
1345 pc
->key
= load_key(pc
, "", SM_NORMALCERT
);
1359 setup_privatekey_storage(void)
1361 char path
[MAXPATH
+1], *contents
;
1362 int privatekeycontainer
= 0;
1364 /* private keys in a container */
1365 if(ps_global
->VAR_PRIVATEKEY_CONTAINER
&& ps_global
->VAR_PRIVATEKEY_CONTAINER
[0]){
1367 privatekeycontainer
= 1;
1370 if(!smime_path(ps_global
->VAR_PRIVATEKEY_CONTAINER
, path
, MAXPATH
))
1371 privatekeycontainer
= 0;
1373 if(privatekeycontainer
&& !IS_REMOTE(path
)
1374 && ps_global
->VAR_OPER_DIR
1375 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
1376 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1377 /* TRANSLATORS: First arg is the directory name, second is
1378 the file user wants to read but can't. */
1379 _("Can't read file outside %s: %s"),
1380 ps_global
->VAR_OPER_DIR
, path
);
1381 privatekeycontainer
= 0;
1384 if(privatekeycontainer
1385 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
1386 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
1388 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
1389 privatekeycontainer
= 0;
1392 if(privatekeycontainer
&& path
[0]){
1393 ps_global
->smime
->privatetype
= Container
;
1394 ps_global
->smime
->privatepath
= cpystr(path
);
1397 ps_global
->smime
->privatecontent
= contents
;
1398 ps_global
->smime
->personal_certs
= mem_to_personal_certs(contents
);
1403 /* private keys in a directory of files */
1404 if(!privatekeycontainer
){
1405 ps_global
->smime
->privatetype
= Directory
;
1408 if(!(smime_path(ps_global
->VAR_PRIVATEKEY_DIR
, path
, MAXPATH
)
1409 && !IS_REMOTE(path
)))
1410 ps_global
->smime
->privatetype
= Nada
;
1411 else if(can_access(path
, ACCESS_EXISTS
)){
1412 if(our_mkpath(path
, 0700)){
1413 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1414 ps_global
->smime
->privatetype
= Nada
;
1418 if(ps_global
->smime
->privatetype
== Directory
)
1419 ps_global
->smime
->personal_certs
= get_personal_certs(path
);
1421 setup_certs_backup_by_type(Private
);
1427 setup_storage_locations(void)
1429 int publiccertcontainer
= 0, cacertcontainer
= 0;
1430 char path
[MAXPATH
+1], *contents
;
1432 if(!ps_global
->smime
)
1435 #ifdef APPLEKEYCHAIN
1436 if(F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
1437 ps_global
->smime
->publictype
= Keychain
;
1440 #endif /* APPLEKEYCHAIN */
1441 /* Public certificates in a container */
1442 if(ps_global
->VAR_PUBLICCERT_CONTAINER
&& ps_global
->VAR_PUBLICCERT_CONTAINER
[0]){
1444 publiccertcontainer
= 1;
1447 if(!smime_path(ps_global
->VAR_PUBLICCERT_CONTAINER
, path
, MAXPATH
))
1448 publiccertcontainer
= 0;
1450 if(publiccertcontainer
&& !IS_REMOTE(path
)
1451 && ps_global
->VAR_OPER_DIR
1452 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
1453 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1454 /* TRANSLATORS: First arg is the directory name, second is
1455 the file user wants to read but can't. */
1456 _("Can't read file outside %s: %s"),
1457 ps_global
->VAR_OPER_DIR
, path
);
1458 publiccertcontainer
= 0;
1461 if(publiccertcontainer
1462 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
1463 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
1465 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
1466 publiccertcontainer
= 0;
1469 if(publiccertcontainer
&& path
[0]){
1470 ps_global
->smime
->publictype
= Container
;
1471 ps_global
->smime
->publicpath
= cpystr(path
);
1474 ps_global
->smime
->publiccontent
= contents
;
1475 ps_global
->smime
->publiccertlist
= mem_to_certlist(contents
, Public
);
1480 /* Public certificates in a directory of files */
1481 if(!publiccertcontainer
){
1482 ps_global
->smime
->publictype
= Directory
;
1485 if(!(smime_path(ps_global
->VAR_PUBLICCERT_DIR
, path
, MAXPATH
)
1486 && !IS_REMOTE(path
)))
1487 ps_global
->smime
->publictype
= Nada
;
1488 else if(can_access(path
, ACCESS_EXISTS
)){
1489 if(our_mkpath(path
, 0700)){
1490 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1491 ps_global
->smime
->publictype
= Nada
;
1495 if(ps_global
->smime
->publictype
== Directory
)
1496 ps_global
->smime
->publicpath
= cpystr(path
);
1499 #ifdef APPLEKEYCHAIN
1501 #endif /* APPLEKEYCHAIN */
1503 setup_privatekey_storage();
1505 /* extra cacerts in a container */
1506 if(ps_global
->VAR_CACERT_CONTAINER
&& ps_global
->VAR_CACERT_CONTAINER
[0]){
1508 cacertcontainer
= 1;
1511 if(!smime_path(ps_global
->VAR_CACERT_CONTAINER
, path
, MAXPATH
))
1512 cacertcontainer
= 0;
1514 if(cacertcontainer
&& !IS_REMOTE(path
)
1515 && ps_global
->VAR_OPER_DIR
1516 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
1517 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1518 /* TRANSLATORS: First arg is the directory name, second is
1519 the file user wants to read but can't. */
1520 _("Can't read file outside %s: %s"),
1521 ps_global
->VAR_OPER_DIR
, path
);
1522 cacertcontainer
= 0;
1526 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
1527 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
1529 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
1530 cacertcontainer
= 0;
1533 if(cacertcontainer
&& path
[0]){
1534 ps_global
->smime
->catype
= Container
;
1535 ps_global
->smime
->capath
= cpystr(path
);
1536 ps_global
->smime
->cacontent
= contents
;
1538 ps_global
->smime
->cacertlist
= mem_to_certlist(contents
, CACert
);
1542 if(!cacertcontainer
){
1543 ps_global
->smime
->catype
= Directory
;
1546 if(!(smime_path(ps_global
->VAR_CACERT_DIR
, path
, MAXPATH
)
1547 && !IS_REMOTE(path
)))
1548 ps_global
->smime
->catype
= Nada
;
1549 else if(can_access(path
, ACCESS_EXISTS
)){
1550 if(our_mkpath(path
, 0700)){
1551 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1552 ps_global
->smime
->catype
= Nada
;
1556 if(ps_global
->smime
->catype
== Directory
)
1557 ps_global
->smime
->capath
= cpystr(path
);
1563 copy_publiccert_dir_to_container(void)
1565 return(copy_dir_to_container(Public
, NULL
));
1570 copy_publiccert_container_to_dir(void)
1572 return(copy_container_to_dir(Public
));
1577 copy_privatecert_dir_to_container(void)
1579 return(copy_dir_to_container(Private
, NULL
));
1584 copy_privatecert_container_to_dir(void)
1586 return(copy_container_to_dir(Private
));
1591 copy_cacert_dir_to_container(void)
1593 return(copy_dir_to_container(CACert
, NULL
));
1598 copy_cacert_container_to_dir(void)
1600 return(copy_container_to_dir(CACert
));
1603 /* Add the contents of a file to a container. Do not check the content
1604 * of the file, just add it using the format for that container. The
1605 * caller must check the format, so that there is no data corruption
1607 * return value: 0 - success,
1611 add_file_to_container(WhichCerts ctype
, char *fpath
, char *altname
)
1613 char *sep
= (ctype
== Public
|| ctype
== Private
)
1614 ? EMAILADDRLEADER
: CACERTSTORELEADER
;
1615 char *content
= ctype
== Public
? ps_global
->smime
->publiccontent
1616 : (ctype
== Private
? ps_global
->smime
->privatecontent
1617 : ps_global
->smime
->cacontent
);
1623 int rv
= -1; /* assume error */
1625 if(our_stat(fpath
, &sbuf
) < 0
1626 || (in
= so_get(FileStar
, fpath
, READ_ACCESS
| READ_FROM_LOCALE
)) == NULL
)
1631 else if((name
= strrchr(fpath
, '/')) != NULL
){
1633 if((ll
= strlen(++name
)) > 4 && strucmp(name
+ ll
- 4, EXTCERT(ctype
)) == 0)
1634 name
[ll
-strlen(EXTCERT(ctype
))] = '\0';
1640 fs_resize((void **)&content
, strlen(content
) + strlen(sep
) + strlen(name
) + sbuf
.st_size
+ 3); /* 2 = \n + \n + \0*/
1642 content
+= strlen(content
);
1645 s
= content
= fs_get(strlen(sep
) + strlen(name
) + sbuf
.st_size
+ 1); /* 2 = \n + \0 */
1648 strncat(content
, sep
, strlen(sep
));
1649 strncat(content
, name
, strlen(name
));
1650 content
+= strlen(content
);
1653 while(so_readc(&c
, in
))
1654 *content
++ = (char) c
;
1658 case Private
: ps_global
->smime
->privatecontent
= s
; break;
1659 case Public
: ps_global
->smime
->publiccontent
= s
; break;
1660 case CACert
: ps_global
->smime
->cacontent
= s
; break;
1664 rv
= copy_dir_to_container(ctype
, s
);
1667 if(in
) so_give(&in
);
1674 * returns 0 on success, -1 on failure
1675 * contents is an argument which tells this function to write the value
1676 * of this variable instead of reading the contents of the directory.
1677 * If the var contents is not null use its value as the value of the
1681 copy_dir_to_container(WhichCerts which
, char *contents
)
1683 int ret
= 0, container
= 0;
1684 BIO
*bio_out
= NULL
, *bio_in
= NULL
;
1685 char srcpath
[MAXPATH
+1], dstpath
[MAXPATH
+1], emailaddr
[MAXPATH
], file
[MAXPATH
], line
[4096];
1686 char *tempfile
= NULL
, fpath
[MAXPATH
+1];
1689 REMDATA_S
*rd
= NULL
;
1690 char *configdir
= NULL
;
1691 char *configpath
= NULL
;
1692 char *configcontainer
= NULL
;
1693 char *filesuffix
= NULL
;
1694 char *ret_dir
= NULL
;
1696 dprint((9, "copy_dir_to_container(%s)", which
==Public
? "Public" : which
==Private
? "Private" : which
==CACert
? "CACert" : "?"));
1702 emailaddr
[0] = '\0';
1704 if(which
== Public
){
1705 configdir
= ps_global
->VAR_PUBLICCERT_DIR
;
1706 configpath
= ps_global
->smime
->publicpath
;
1707 configcontainer
= cpystr(DF_PUBLIC_CONTAINER
);
1708 filesuffix
= ".crt";
1710 else if(which
== Private
){
1711 configdir
= ps_global
->VAR_PRIVATEKEY_DIR
;
1712 configpath
= ps_global
->smime
->privatepath
;
1713 configcontainer
= cpystr(DF_PRIVATE_CONTAINER
);
1714 filesuffix
= ".key";
1716 else if(which
== CACert
){
1717 configdir
= ps_global
->VAR_CACERT_DIR
;
1718 configpath
= ps_global
->smime
->capath
;
1719 configcontainer
= cpystr(DF_CA_CONTAINER
);
1720 filesuffix
= ".crt";
1722 container
= SMHOLDERTYPE(which
) == Container
;
1724 if(!(configdir
&& configdir
[0])){
1725 q_status_message(SM_ORDER
, 3, 3, _("Directory not defined"));
1729 if(!(configpath
&& configpath
[0])){
1730 #ifdef APPLEKEYCHAIN
1731 if(which
== Public
&& F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
1732 q_status_message(SM_ORDER
, 3, 3, _("Turn off the Keychain feature above first"));
1735 #endif /* APPLEKEYCHAIN */
1736 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1740 if(!(filesuffix
&& strlen(filesuffix
) == 4)){
1746 * If there is a legit directory to read from set up the
1747 * container file to write to.
1749 if(smime_path(configdir
, srcpath
, MAXPATH
) && !IS_REMOTE(srcpath
)){
1751 if(IS_REMOTE(configpath
)){
1752 rd
= rd_create_remote(RemImap
, configpath
, REMOTE_SMIME_SUBTYPE
,
1754 _("Can't access remote smime configuration."));
1758 (void) rd_read_metadata(rd
);
1760 if(rd
->access
== MaybeRorW
){
1761 if(rd
->read_status
== 'R')
1762 rd
->access
= ReadOnly
;
1764 rd
->access
= ReadWrite
;
1767 if(rd
->access
!= NoExists
){
1769 rd_check_remvalid(rd
, 1L);
1772 * If the cached info says it is readonly but
1773 * it looks like it's been fixed now, change it to readwrite.
1775 if(rd
->read_status
== 'R'){
1776 rd_check_readonly_access(rd
);
1777 if(rd
->read_status
== 'W'){
1778 rd
->access
= ReadWrite
;
1779 rd
->flags
|= REM_OUTOFDATE
;
1782 rd
->access
= ReadOnly
;
1786 if(rd
->flags
& REM_OUTOFDATE
){
1787 if(rd_update_local(rd
) != 0){
1789 dprint((1, "copy_dir_to_container: rd_update_local failed\n"));
1790 rd_close_remdata(&rd
);
1797 if(rd
->access
!= ReadWrite
|| rd_remote_is_readonly(rd
)){
1798 rd_close_remdata(&rd
);
1802 rd
->flags
|= DO_REMTRIM
;
1804 strncpy(dstpath
, rd
->lf
, sizeof(dstpath
)-1);
1805 dstpath
[sizeof(dstpath
)-1] = '\0';
1808 strncpy(dstpath
, configpath
, sizeof(dstpath
)-1);
1809 dstpath
[sizeof(dstpath
)-1] = '\0';
1813 * dstpath is either the local Container file or the local cache file
1814 * for the remote Container file.
1816 tempfile
= tempfile_in_same_dir(dstpath
, "az", &ret_dir
);
1820 * If there is a legit directory to read from and a tempfile
1821 * to write to we continue.
1823 if(tempfile
&& (bio_out
=BIO_new_file(tempfile
, "w")) != NULL
){
1825 if(contents
!= NULL
){
1826 if(BIO_puts(bio_out
, contents
) < 0)
1830 if((dirp
= opendir(srcpath
)) != NULL
){
1832 while((d
=readdir(dirp
)) && !ret
){
1835 if((ll
=strlen(d
->d_name
)) && ll
> 4 && !strcmp(d
->d_name
+ll
-4, filesuffix
)){
1837 /* copy file name to temp buffer */
1838 strncpy(emailaddr
, d
->d_name
, sizeof(emailaddr
)-1);
1839 emailaddr
[sizeof(emailaddr
)-1] = '\0';
1840 /* chop off suffix trailier */
1841 emailaddr
[strlen(emailaddr
)-4] = 0;
1844 * This is the separator between the contents of
1847 if(which
== CACert
){
1848 if(!((BIO_puts(bio_out
, CACERTSTORELEADER
) > 0)
1849 && (BIO_puts(bio_out
, emailaddr
) > 0)
1850 && (BIO_puts(bio_out
, "\n") > 0)))
1854 if(!((BIO_puts(bio_out
, EMAILADDRLEADER
) > 0)
1855 && (BIO_puts(bio_out
, emailaddr
) > 0)
1856 && (BIO_puts(bio_out
, "\n") > 0)))
1860 /* read then write contents of file */
1861 build_path(file
, srcpath
, d
->d_name
, sizeof(file
));
1862 if(!(bio_in
= BIO_new_file(file
, "r")))
1868 while(BIO_gets(bio_in
, line
, sizeof(line
)) > 0){
1869 if(strncmp("-----BEGIN", line
, strlen("-----BEGIN")) == 0)
1873 BIO_puts(bio_out
, line
);
1875 if(strncmp("-----END", line
, strlen("-----END")) == 0)
1891 if(container
&& configpath
&& *configpath
){
1892 strncpy(fpath
, configpath
, sizeof(fpath
));
1893 fpath
[sizeof(fpath
) - 1] = '\0';
1896 if(strlen(dstpath
) + strlen(configcontainer
) - strlen(ret_dir
) + 1 < sizeof(dstpath
))
1897 snprintf(fpath
, sizeof(fpath
), "%s%c%s",
1898 dstpath
, tempfile
[strlen(ret_dir
)], configcontainer
);
1905 if(!IS_REMOTE(configpath
)){
1906 if(rename_file(tempfile
, fpath
) < 0){
1907 q_status_message2(SM_ORDER
, 3, 3,
1908 _("Can't rename %s to %s"), tempfile
, fpath
);
1910 } else q_status_message1(SM_ORDER
, 3, 3,
1911 _("saved container to %s"), fpath
);
1913 else { /* if the container is remote, copy it */
1917 if(rd
!= NULL
&& rename_file(tempfile
, rd
->lf
) < 0){
1918 q_status_message2(SM_ORDER
, 3, 3,
1919 _("Can't rename %s to %s"), tempfile
, rd
->lf
);
1925 if((e
= rd_update_remote(rd
, datebuf
)) != 0){
1927 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1928 _("Error opening temporary smime file %s: %s"),
1929 rd
->lf
, error_description(errno
));
1931 "write_remote_smime: error opening temp file %s\n",
1932 rd
->lf
? rd
->lf
: "?"));
1935 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1936 _("Error copying to %s: %s"),
1937 rd
->rn
, error_description(errno
));
1939 "write_remote_smime: error copying from %s to %s\n",
1940 rd
->lf
? rd
->lf
: "?", rd
->rn
? rd
->rn
: "?"));
1943 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
1944 _("Copy of smime key to remote folder failed, NOT saved remotely"));
1947 rd_update_metadata(rd
, datebuf
);
1948 rd
->read_status
= 'W';
1951 rd_close_remdata(&rd
);
1958 fs_give((void **) &tempfile
);
1961 fs_give((void **) &ret_dir
);
1964 fs_give((void **) &configcontainer
);
1971 * returns 0 on success, -1 on failure
1974 copy_container_to_dir(WhichCerts which
)
1976 char path
[MAXPATH
+1], file
[MAXPATH
+1], buf
[MAXPATH
+1];
1978 char *contents
= NULL
;
1979 char *leader
= NULL
;
1980 char *filesuffix
= NULL
;
1981 char *configdir
= NULL
;
1982 char *configpath
= NULL
;
1983 char *tempfile
= NULL
;
1984 char *p
, *q
, *line
, *name
, *certtext
, *save_p
;
1988 dprint((9, "copy_container_to_dir(%s)", which
==Public
? "Public" : which
==Private
? "Private" : which
==CACert
? "CACert" : "?"));
1993 if(which
== Public
){
1994 leader
= EMAILADDRLEADER
;
1995 contents
= ps_global
->smime
->publiccontent
;
1996 configdir
= ps_global
->VAR_PUBLICCERT_DIR
;
1997 configpath
= ps_global
->smime
->publicpath
;
1998 filesuffix
= ".crt";
1999 if(!(configpath
&& configpath
[0])){
2000 #ifdef APPLEKEYCHAIN
2001 if(which
== Public
&& F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
2002 q_status_message(SM_ORDER
, 3, 3, _("Turn off the Keychain feature above first"));
2005 #endif /* APPLEKEYCHAIN */
2006 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
2010 fs_give((void **) &ps_global
->smime
->publicpath
);
2013 if(!(smime_path(ps_global
->VAR_PUBLICCERT_DIR
, path
, MAXPATH
)
2014 && !IS_REMOTE(path
))){
2015 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
2019 if(can_access(path
, ACCESS_EXISTS
)){
2020 if(our_mkpath(path
, 0700)){
2021 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
2026 ps_global
->smime
->publicpath
= cpystr(path
);
2027 configpath
= ps_global
->smime
->publicpath
;
2029 else if(which
== Private
){
2030 leader
= EMAILADDRLEADER
;
2031 contents
= ps_global
->smime
->privatecontent
;
2032 configdir
= ps_global
->VAR_PRIVATEKEY_DIR
;
2033 configpath
= ps_global
->smime
->privatepath
;
2034 filesuffix
= ".key";
2035 if(!(configpath
&& configpath
[0])){
2036 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
2040 fs_give((void **) &ps_global
->smime
->privatepath
);
2043 if(!(smime_path(ps_global
->VAR_PRIVATEKEY_DIR
, path
, MAXPATH
)
2044 && !IS_REMOTE(path
))){
2045 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
2049 if(can_access(path
, ACCESS_EXISTS
)){
2050 if(our_mkpath(path
, 0700)){
2051 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
2056 ps_global
->smime
->privatepath
= cpystr(path
);
2057 configpath
= ps_global
->smime
->privatepath
;
2059 else if(which
== CACert
){
2060 leader
= CACERTSTORELEADER
;
2061 contents
= ps_global
->smime
->cacontent
;
2062 configdir
= ps_global
->VAR_CACERT_DIR
;
2063 configpath
= ps_global
->smime
->capath
;
2064 filesuffix
= ".crt";
2065 if(!(configpath
&& configpath
[0])){
2066 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
2070 fs_give((void **) &ps_global
->smime
->capath
);
2073 if(!(smime_path(ps_global
->VAR_CACERT_DIR
, path
, MAXPATH
)
2074 && !IS_REMOTE(path
))){
2075 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
2079 if(can_access(path
, ACCESS_EXISTS
)){
2080 if(our_mkpath(path
, 0700)){
2081 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
2086 ps_global
->smime
->capath
= cpystr(path
);
2087 configpath
= ps_global
->smime
->capath
;
2090 if(!(configdir
&& configdir
[0])){
2091 q_status_message(SM_ORDER
, 3, 3, _("Directory not defined"));
2095 if(!(configpath
&& configpath
[0])){
2096 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
2100 if(!(filesuffix
&& strlen(filesuffix
) == 4)){
2105 if(contents
&& *contents
){
2106 for(p
= contents
; *p
!= '\0';){
2109 while(*p
&& *p
!= '\n')
2118 if(strncmp(leader
, line
, strlen(leader
)) == 0){
2119 name
= line
+ strlen(leader
);
2121 if(strncmp("-----BEGIN", certtext
, strlen("-----BEGIN")) == 0){
2122 if((q
= strstr(certtext
, leader
)) != NULL
){
2125 else{ /* end of file */
2126 q
= certtext
+ strlen(certtext
);
2130 strncpy(buf
, name
, sizeof(buf
)-5);
2131 buf
[sizeof(buf
)-5] = '\0';
2132 strncat(buf
, filesuffix
, 5);
2133 build_path(file
, configpath
, buf
, sizeof(file
));
2135 in
= BIO_new_mem_buf(certtext
, q
-certtext
);
2137 tempfile
= tempfile_in_same_dir(file
, "az", NULL
);
2140 out
= BIO_new_file(tempfile
, "w");
2143 while((len
= BIO_read(in
, iobuf
, sizeof(iobuf
))) > 0)
2144 BIO_write(out
, iobuf
, len
);
2148 if(rename_file(tempfile
, file
) < 0){
2149 q_status_message2(SM_ORDER
, 3, 3,
2150 _("Can't rename %s to %s"),
2155 fs_give((void **) &tempfile
);
2172 #ifdef APPLEKEYCHAIN
2175 copy_publiccert_container_to_keychain(void)
2177 /* NOT IMPLEMNTED */
2182 copy_publiccert_keychain_to_container(void)
2184 /* NOT IMPLEMNTED */
2188 #endif /* APPLEKEYCHAIN */
2192 * Get a pointer to a string describing the most recent OpenSSL error.
2193 * It's statically allocated, so don't change or attempt to free it.
2196 openssl_error_string(void)
2199 const char *data
= NULL
;
2202 errn
= ERR_peek_error_line_data(NULL
, NULL
, &data
, NULL
);
2203 errs
= (char*) ERR_reason_error_string(errn
);
2210 return "unknown error";
2214 /* Return true if the body looks like a PKCS7 object */
2216 is_pkcs7_body(BODY
*body
)
2220 result
= body
->type
==TYPEAPPLICATION
&&
2222 (strucmp(body
->subtype
,"pkcs7-mime")==0 ||
2223 strucmp(body
->subtype
,"x-pkcs7-mime")==0 ||
2224 strucmp(body
->subtype
,"pkcs7-signature")==0 ||
2225 strucmp(body
->subtype
,"x-pkcs7-signature")==0);
2232 * Recursively stash a pointer to the decrypted data in our
2233 * manufactured body.
2234 * parameters: type: call of type 1, save the base and header for multipart messages
2235 call of type 0, do not save the base and header for multipart messages
2238 create_local_cache(char *h
, char *base
, BODY
*b
, int type
)
2240 if(b
->type
==TYPEMULTIPART
){
2244 cpytxt(&b
->mime
.text
, h
+b
->mime
.offset
, b
->mime
.text
.size
);
2245 cpytxt(&b
->contents
.text
, base
+ b
->contents
.offset
, b
->size
.bytes
);
2246 } else if(type
== 0){
2248 * We don't really want to copy the real body contents. It shouldn't be
2249 * used, and in the case of a message with attachments, we'll be
2250 * duplicating the files multiple times.
2252 cpytxt(&b
->contents
.text
, "BODY UNAVAILABLE", 16);
2254 for(p
=b
->nested
.part
; p
; p
=p
->next
)
2255 create_local_cache(h
, base
, (BODY
*) p
, type
);
2259 cpytxt(&b
->mime
.text
, h
+b
->mime
.offset
, b
->mime
.text
.size
);
2260 cpytxt(&b
->contents
.text
, base
+ b
->contents
.offset
, b
->size
.bytes
);
2266 rfc822_output_func(void *b
, char *string
)
2268 BIO
*bio
= (BIO
*) b
;
2270 return(string
? *string
? (BIO_puts(bio
, string
) > 0 ? 1L : 0L)
2271 : (BIO_puts(bio
, string
) >= 0 ? 1L : 0L)
2277 * Attempt to load the private key for the given PERSONAL_CERT.
2278 * This sets the appropriate passphrase globals in order to
2279 * interact with the user correctly.
2282 load_private_key(PERSONAL_CERT
*pcert
)
2286 /* Try empty password by default */
2287 char *password
= "";
2290 && (ps_global
->smime
->need_passphrase
2291 || ps_global
->smime
->entered_passphrase
)){
2292 /* We've already been in here and discovered we need a different password */
2294 if(ps_global
->smime
->entered_passphrase
)
2295 password
= (char *) ps_global
->smime
->passphrase
; /* already entered */
2302 if(!(pcert
->key
= load_key(pcert
, password
, SM_NORMALCERT
))){
2303 long err
= ERR_get_error();
2305 /* Couldn't load key... */
2307 if(ps_global
->smime
&& ps_global
->smime
->entered_passphrase
){
2309 /* The user got the password wrong maybe? */
2311 if((ERR_GET_LIB(err
)==ERR_LIB_EVP
&& ERR_GET_REASON(err
)==EVP_R_BAD_DECRYPT
) ||
2312 (ERR_GET_LIB(err
)==ERR_LIB_PEM
&& ERR_GET_REASON(err
)==PEM_R_BAD_DECRYPT
))
2313 q_status_message(SM_ORDER
| SM_DING
, 4, 4, _("Incorrect passphrase"));
2315 q_status_message1(SM_ORDER
, 4, 4, _("Couldn't read key: %s"),(char*)openssl_error_string());
2317 /* This passphrase is no good; forget it */
2318 ps_global
->smime
->entered_passphrase
= 0;
2321 if(ps_global
->smime
){
2322 /* Indicate to the UI that we need re-entry (see mailcmd.c:process_cmd())*/
2323 ps_global
->smime
->need_passphrase
= 1;
2324 if(ps_global
->smime
->passphrase_emailaddr
){
2326 for(i
= 0; ps_global
->smime
->passphrase_emailaddr
[i
] != NULL
; i
++)
2327 fs_give((void **)&ps_global
->smime
->passphrase_emailaddr
[i
]);
2328 fs_give((void **) ps_global
->smime
->passphrase_emailaddr
);
2331 ps_global
->smime
->passphrase_emailaddr
= get_x509_subject_email(pcert
->cert
);
2337 /* This key will be cached, so we won't be called again */
2338 if(ps_global
->smime
){
2339 ps_global
->smime
->entered_passphrase
= 0;
2340 ps_global
->smime
->need_passphrase
= 0;
2352 setup_pkcs7_body_for_signature(BODY
*b
, char *description
, char *type
, char *filename
, char *smime_type
)
2354 b
->type
= TYPEAPPLICATION
;
2355 b
->subtype
= cpystr(type
);
2356 b
->encoding
= ENCBINARY
;
2357 b
->description
= cpystr(description
);
2359 b
->disposition
.type
= cpystr("attachment");
2360 set_parameter(&b
->disposition
.parameter
, "filename", filename
);
2362 set_parameter(&b
->parameter
, "name", filename
);
2363 if(smime_type
&& *smime_type
)
2364 set_parameter(&b
->parameter
, "smime-type", smime_type
);
2369 * Look for a personal certificate matching the
2373 match_personal_cert_to_email(ADDRESS
*a
)
2375 PERSONAL_CERT
*pcert
= NULL
;
2380 if(!a
|| !a
->mailbox
|| !a
->host
)
2383 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
2385 if(ps_global
->smime
){
2386 for(pcert
=(PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
2393 email
= get_x509_subject_email(pcert
->cert
);
2397 for(i
= 0; email
[i
] && strucmp(email
[i
], buf
) != 0; i
++);
2398 if(email
[i
] != NULL
) done
++;
2399 for(i
= 0; email
[i
] != NULL
; i
++)
2400 fs_give((void **)&email
[i
]);
2401 fs_give((void **)email
);
2414 * Look for a personal certificate matching the from
2415 * (or reply_to? in the given envelope)
2418 match_personal_cert(ENVELOPE
*env
)
2420 PERSONAL_CERT
*pcert
;
2422 pcert
= match_personal_cert_to_email(env
->reply_to
);
2424 pcert
= match_personal_cert_to_email(env
->from
);
2431 * Flatten the given body into its MIME representation.
2432 * Return the result in a BIO.
2435 body_to_bio(BODY
*body
)
2440 bio
= BIO_new(BIO_s_mem());
2444 pine_encode_body(body
); /* this attaches random boundary strings to multiparts */
2445 pine_write_body_header(body
, rfc822_output_func
, bio
);
2446 pine_rfc822_output_body(body
, rfc822_output_func
, bio
);
2449 * Now need to truncate by two characters since the above
2452 if((len
=BIO_ctrl_pending(bio
)) > 1){
2453 BUF_MEM
*biobuf
= NULL
;
2455 BIO_get_mem_ptr(bio
, &biobuf
);
2457 BUF_MEM_grow(biobuf
, len
-2); /* remove CRLF */
2466 bio_from_store(STORE_S
*store
)
2470 if(store
&& store
->src
== BioType
&& store
->txt
){
2471 ret
= (BIO
*) store
->txt
;
2478 * Encrypt file; given a path (char *) fp, replace the file
2479 * by an encrypted version of it. If (char *) text is not null, then
2480 * replace the text of (char *) fp by the encrypted version of (char *) text.
2481 * certpath is the FULL path to the file containing the certificate used for
2483 * return value: 0 - failed to encrypt; 1 - success!
2486 encrypt_file(char *fp
, char *text
, PERSONAL_CERT
*pc
)
2488 const EVP_CIPHER
*cipher
= NULL
;
2489 STACK_OF(X509
) *encerts
= NULL
;
2497 cipher
= EVP_aes_256_cbc();
2498 encerts
= sk_X509_new_null();
2500 sk_X509_push(encerts
, X509_dup(pc
->cert
));
2503 if((out
= BIO_new(BIO_s_mem())) != NULL
){
2504 (void) BIO_reset(out
);
2505 BIO_puts(out
, text
);
2508 else if((out
= BIO_new_file(fp
, "rb")) != NULL
)
2509 BIO_read_filename(out
, fp
);
2511 if((p7
= PKCS7_encrypt(encerts
, out
, cipher
, 0)) != NULL
){
2512 BIO_set_close(out
, BIO_CLOSE
);
2514 if((out
= BIO_new_file(fp
, "w")) != NULL
){
2516 rv
= PEM_write_bio_PKCS7(out
, p7
);
2524 sk_X509_pop_free(encerts
, X509_free
);
2530 * Encrypt a message on the way out. Called from call_mailer in send.c
2531 * The body may be reallocated.
2534 encrypt_outgoing_message(METAENV
*header
, BODY
**bodyP
)
2539 const EVP_CIPHER
*cipher
= NULL
;
2540 STACK_OF(X509
) *encerts
= NULL
;
2541 STORE_S
*outs
= NULL
;
2544 BODY
*body
= *bodyP
;
2545 BODY
*newBody
= NULL
;
2550 dprint((9, "encrypt_outgoing_message()"));
2553 cipher
= EVP_aes_256_cbc();
2555 encerts
= sk_X509_new_null();
2557 /* Look for a certificate for each of the recipients */
2558 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
2559 if(pf
->type
== Address
&& pf
->rcptto
&& pf
->addr
&& *pf
->addr
){
2560 for(a
=*pf
->addr
; a
; a
=a
->next
){
2561 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
2563 if((cert
= get_cert_for(buf
, Public
, 1)) != NULL
){
2564 sk_X509_push(encerts
,cert
);
2566 q_status_message2(SM_ORDER
, 1, 1,
2567 _("Unable to find certificate for <%s@%s>"),
2568 a
->mailbox
, a
->host
);
2574 /* add the sender's certificate so that they can decrypt the message too */
2575 for(a
=header
->env
->from
; a
; a
= a
->next
){
2576 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
2578 if((cert
= get_cert_for(buf
, Public
, 1)) != NULL
2579 && sk_X509_find(encerts
, cert
) == -1)
2580 sk_X509_push(encerts
,cert
);
2583 in
= body_to_bio(body
);
2585 p7
= PKCS7_encrypt(encerts
, in
, cipher
, 0);
2587 outs
= so_get(BioType
, NULL
, EDIT_ACCESS
);
2588 out
= bio_from_store(outs
);
2590 i2d_PKCS7_bio(out
, p7
);
2591 (void) BIO_flush(out
);
2593 so_seek(outs
, 0, SEEK_SET
);
2595 newBody
= mail_newbody();
2597 newBody
->type
= TYPEAPPLICATION
;
2598 newBody
->subtype
= cpystr("pkcs7-mime");
2599 newBody
->encoding
= ENCBINARY
;
2601 newBody
->disposition
.type
= cpystr("attachment");
2602 set_parameter(&newBody
->disposition
.parameter
, "filename", "smime.p7m");
2604 newBody
->description
= cpystr("S/MIME Encrypted Message");
2605 set_parameter(&newBody
->parameter
, "smime-type", "enveloped-data");
2606 set_parameter(&newBody
->parameter
, "name", "smime.p7m");
2608 newBody
->contents
.text
.data
= (unsigned char *) outs
;
2618 sk_X509_pop_free(encerts
, X509_free
);
2620 dprint((9, "encrypt_outgoing_message returns %d", result
));
2626 Get (and decode) the body of the given section of msg
2629 get_part_contents(long msgno
, const char *section
)
2633 STORE_S
*store
= NULL
;
2636 store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
2638 gf_set_so_writec(&pc
,store
);
2640 err
= detach(ps_global
->mail_stream
, msgno
, (char*) section
, 0L, &len
, pc
, NULL
, 0L);
2642 gf_clear_so_writec(store
);
2644 so_seek(store
, 0, SEEK_SET
);
2655 get_pkcs7_from_part(long msgno
,const char *section
)
2657 STORE_S
*store
= NULL
;
2661 store
= get_part_contents(msgno
, section
);
2664 if(store
->src
== CharStar
){
2668 * We're reaching inside the STORE_S structure. We should
2669 * probably have a way to get the length, instead.
2671 len
= (int) (store
->eod
- store
->dp
);
2672 in
= BIO_new_mem_buf(store
->txt
, len
);
2674 else{ /* just copy it */
2677 in
= BIO_new(BIO_s_mem());
2678 (void) BIO_reset(in
);
2680 so_seek(store
, 0L, 0);
2681 while(so_readc(&c
, store
)){
2682 BIO_write(in
, &c
, 1);
2687 /* dump_bio_to_file(in, "/tmp/decoded-signature"); */
2688 if((p7
=d2i_PKCS7_bio(in
,NULL
)) == NULL
){
2701 int same_cert(X509
*x
, X509
*cert
)
2703 char bufcert
[256], bufx
[256];
2706 get_fingerprint(cert
, EVP_md5(), bufcert
, sizeof(bufcert
), ":");
2707 get_fingerprint(x
, EVP_md5(), bufx
, sizeof(bufx
), ":");
2708 if(strcmp(bufx
, bufcert
) == 0)
2715 /* extract and save certificates from a PKCS7 package. The ctype variable
2716 * tells us if we want to extract it to a public/ or a ca/ directory. The
2717 * later makes sense only for recoverable errors (errors that can be fixed
2718 * by saving to the ca/ directory before we verify the signature).
2720 * 0 - no errors (in public/) no need to try again,
2721 * or validated self signed certificate (in ca/)
2722 * < 0 - certificate error is not recoverable, don't even think about it.
2725 int smime_extract_and_save_cert(PKCS7
*p7
, int check_cert
)
2727 STACK_OF(X509
) *signers
;
2733 if((signers
= PKCS7_get0_signers(p7
, NULL
, 0)) == NULL
)
2736 for(i
= 0; i
< sk_X509_num(signers
); i
++){
2737 if((x
= sk_X509_value(signers
,i
)) == NULL
)
2740 if((email
= get_x509_subject_email(x
)) != NULL
){
2741 for(j
= 0; email
[j
] != NULL
; j
++){
2742 if((cert
= get_cert_for(email
[j
], Public
, 1)) == NULL
2743 || same_cert(x
, cert
) == 0){
2745 || smime_validate_cert(x
, &error
) == 0
2746 || (*pith_smime_confirm_save
)(email
[j
]) == 1)
2747 save_cert_for(email
[j
], x
, Public
);
2751 fs_give((void **) &email
[j
]);
2753 fs_give((void **) email
);
2756 sk_X509_free(signers
);
2762 * Try to verify a signature.
2764 * p7 - the pkcs7 object to verify
2765 * in - the plain data to verify (NULL if not detached)
2766 * out - BIO to which to write the opaque data
2767 * silent - if non zero, do not print errors, only print success.
2770 do_signature_verify(PKCS7
*p7
, BIO
*in
, BIO
*out
, int silent
)
2772 STACK_OF(X509
) *otherCerts
= NULL
;
2779 if(!silent
) q_status_message(SM_ORDER
| SM_DING
, 2, 2,
2780 _("Couldn't verify S/MIME signature: No CA Certs were loaded"));
2785 flags
= F_ON(F_USE_CERT_STORE_ONLY
, ps_global
) ? PKCS7_NOINTERN
: 0;
2787 if(ps_global
->smime
->publiccertlist
== NULL
){
2788 renew_cert_data(&ps_global
->smime
->publiccertlist
, Public
);
2789 for(cl
= ps_global
->smime
->publiccertlist
; cl
; cl
= cl
->next
){
2790 if(cl
->x509_cert
== NULL
){
2791 char *s
= strrchr(cl
->name
, '.');
2793 cl
->x509_cert
= get_cert_for(cl
->name
, Public
, 1);
2799 if(ps_global
->smime
->publiccertlist
){
2800 otherCerts
= sk_X509_new_null();
2801 for(cl
= ps_global
->smime
->publiccertlist
; cl
; cl
= cl
->next
)
2802 if(cl
->x509_cert
!= NULL
)
2803 sk_X509_push(otherCerts
, X509_dup(cl
->x509_cert
));
2806 result
= PKCS7_verify(p7
, otherCerts
, s_cert_store
, in
, out
, flags
);
2808 sk_X509_pop_free(otherCerts
, X509_free
);
2811 q_status_message(SM_ORDER
, 1, 1, _("S/MIME signature verified ok"));
2814 err
= ERR_peek_error_line_data(NULL
, NULL
, &data
, NULL
);
2816 if(out
&& err
==ERR_PACK(ERR_LIB_PKCS7
,PKCS7_F_PKCS7_VERIFY
,PKCS7_R_CERTIFICATE_VERIFY_ERROR
)){
2818 /* Retry verification so we can get the plain text */
2819 /* Might be better to reimplement PKCS7_verify here? */
2821 PKCS7_verify(p7
, otherCerts
, s_cert_store
, in
, out
, PKCS7_NOVERIFY
);
2823 if (!silent
) q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
2824 _("Couldn't verify S/MIME signature: %s"), (char*) openssl_error_string());
2832 free_smime_body_sparep(void **sparep
)
2836 if(sparep
&& *sparep
){
2837 switch(get_smime_sparep_type(*sparep
)){
2838 case P7Type
: PKCS7_free((PKCS7
*) get_smime_sparep_data(*sparep
));
2840 case CharType
: s
= (char *)get_smime_sparep_data(*sparep
);
2841 fs_give((void **) &s
);
2843 case SizedText
: st
= (SIZEDTEXT
*)get_smime_sparep_data(*sparep
);
2844 fs_give((void **) &st
->data
);
2845 fs_give((void **) &st
);
2849 ((SMIME_SPARE_S
*)(*sparep
))->data
= NULL
;
2854 /* Big comment, explaining the mess that exists out there, and how we deal
2855 with it, and also how we solve the problems that are created this way.
2857 When Alpine sends a message, it constructs that message, computes the
2858 signature, but then it forgets the message it signed and reconstructs it
2859 again. Since it signs a message containing a notice about "mime aware
2860 tools", but it does not send that we do not include that in the part
2861 that is signed, and that takes care of much of the problems.
2863 Another problem is what is received from the servers. All servers tested
2864 seem to transmit the message that was signed intact and Alpine can check
2865 the signature correctly. That is not a problem. The problem arises when
2866 the message includes attachments. In this case different servers send
2867 different things, so it will be up to us to figure out what is the text
2868 that was actually signed. Confused? here is the story:
2870 When a message containing and attachment is sent by Alpine, UW-IMAP,
2871 Panda-IMAP, Gmail, and local reading of folders send exactly the message
2872 that was sent by Alpine, but GMX.com, Exchange, and probably other
2873 servers add a trailing \r\n in the message, so when validating the
2874 signature, these messages will not validate. There are several things
2877 1. Add a trailing \r\n to any message that contains attachments, sign that
2878 and send that. In this way, all messages will validate with all
2881 2. Compatibility mode: If a message has an attachment, contains a trailing
2882 \r\n and does not validate (sent by an earlier version of Alpine),
2883 remove the trailing \r\n and try to revalidate again.
2885 3. We do not add \r\n to validate a message that we sent, because that
2886 would only work in Alpine, and not in any other client. That would
2887 not be a good thing to do.
2891 Now we have to deal with encrypted and signed messages. The problem is
2892 that c-client makes all its pointers point to "on disk" content, but
2893 since we decrypted the data earlier, we have to make sure of two things.
2894 One is that we saved that data (so we do not have to decrypt it again)
2895 and second that we can use it.
2897 In order to save the data we use create_local_cache, so that we do not
2898 have to redecrypt the message. Once this is saved, c-client functions will
2899 find it and send it to us in mail_fetch_mime and mail_fetch_body.
2903 When we are trying to verify messages with detached signatures, some
2904 imap servers send incorrect information in the mail_fetch_mime call. By
2905 incorrect I mean that this is not fetched directly from the message, but
2906 it is read from the message, processed, and then the processed part is
2907 sent to us, so this text might not agree with what is in the message,
2908 and so the validation of the signature might fail. However, the good
2909 news is that the message validates if saved to a local folder. This
2910 means that if normal validation does not work we can make it work by
2911 saving the message locally and validating that. This is implemented
2912 below, and causes delay in the display of the message. I am considering
2913 at this time not to do this automatically, but wait for the user to tell
2914 us to do it for them by means of a command available in the
2915 mail_view_screen. This might help in other situations, where a message
2916 is supposed to have an attachment, but it can not be seen in the
2917 processed text. Nevertheless, at this time, this is automatic, and is
2918 causing a delay in the processing of the message, but it is validating
2919 correctly all messages.
2923 When the user sends a message as encrypted and signed, this code used to
2924 encrypt first, and then sign the pkcs7 body, but it turns out that some
2925 other clients can not handle these messages. While we could argue that the
2926 other clients need to improve, we will support reading messages in both
2927 ways, and will send messages using this technique; that is, signed first,
2928 encrypted second. It seems that all tested clients support this way, so it
2929 should be safe to do so.
2932 typedef struct smime_filter_s
{
2936 SMIME_FILTER_S sig_filter
[] = {
2937 {smime_remove_trailing_crlf
},
2938 {smime_remove_folding_space
}
2941 #define TOTAL_FILTERS (sizeof(sig_filter)/sizeof(sig_filter[0]))
2942 #define TOTAL_SIGFLTR (1 << TOTAL_FILTERS) /* not good, keep filters to a low number */
2945 smime_remove_trailing_crlf(char **mimetext
, unsigned long *mimelen
,
2946 char **bodytext
, unsigned long *bodylen
)
2948 if(*bodylen
> 2 && !strncmp(*bodytext
+*bodylen
-2, "\r\n", 2))
2953 smime_remove_folding_space(char **mimetext
, unsigned long *mimelen
,
2954 char **bodytext
, unsigned long *bodylen
)
2957 unsigned long mlen
= *mimelen
;
2960 for (s
= t
= *mimetext
; t
- *mimetext
< *mimelen
; ){
2961 if(*t
== '\r' && *(t
+1) == '\n' && (*(t
+2) == '\t' || *(t
+2) == ' ')){
2974 smime_validate_extra_test(char *mimetext
, unsigned long mimelen
, char *bodytext
, unsigned long bodylen
, PKCS7
*p7
, int nflag
)
2976 int result
, i
, j
, flag
;
2977 char *mtext
, *btext
;
2978 unsigned long mlen
, blen
;
2981 mtext
= mimelen
? fs_get(mimelen
+1) : NULL
;
2982 btext
= fs_get(bodylen
+1);
2984 flag
= 1; /* silence all failures */
2985 for(i
= 1; result
== 0 && i
< TOTAL_SIGFLTR
; i
++){
2986 if((in
= BIO_new(BIO_s_mem())) == NULL
)
2989 (void) BIO_reset(in
);
2991 if(i
+1 == TOTAL_SIGFLTR
)
2995 strncpy(mtext
, mimetext
, mlen
= mimelen
);
2996 strncpy(btext
, bodytext
, blen
= bodylen
);
2997 for(j
= 0; j
< TOTAL_FILTERS
; j
++)
2999 (sig_filter
[j
].filter
)(&mtext
, &mlen
, &btext
, &blen
);
3001 BIO_write(in
, mtext
, mlen
);
3002 BIO_write(in
, btext
, blen
);
3003 result
= do_signature_verify(p7
, in
, NULL
, flag
);
3006 if(mtext
) fs_give((void **)&mtext
);
3007 if(btext
) fs_give((void **)&btext
);
3012 * Given a multipart body of type multipart/signed, attempt to verify it.
3013 * Returns non-zero if the body was changed.
3016 do_detached_signature_verify(BODY
*b
, long msgno
, char *section
)
3021 int result
, modified_the_body
= 0;
3022 int flag
; /* 1 silent, 0 not silent */
3024 unsigned long mimelen
, bodylen
;
3025 char newSec
[100], *mimetext
, *bodytext
;
3029 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"));
3033 /* if it was signed and then encrypted, use the decrypted text
3034 * to check the validity of the signature
3037 if(get_smime_sparep_type(b
->sparep
) == SizedText
){
3038 /* bodytext includes mimetext */
3039 st
= (SIZEDTEXT
*) get_smime_sparep_data(b
->sparep
);
3040 bodytext
= (char *) st
->data
;
3047 snprintf(newSec
, sizeof(newSec
), "%s%s1", section
? section
: "", (section
&& *section
) ? "." : "");
3048 mimetext
= mail_fetch_mime(ps_global
->mail_stream
, msgno
, (char*) newSec
, &mimelen
, 0);
3050 bodytext
= mail_fetch_body (ps_global
->mail_stream
, msgno
, (char*) newSec
, &bodylen
, 0);
3052 if(mimetext
== NULL
|| bodytext
== NULL
)
3053 return modified_the_body
;
3056 snprintf(newSec
, sizeof(newSec
), "%s%s2", section
? section
: "", (section
&& *section
) ? "." : "");
3058 if((p7
= get_pkcs7_from_part(msgno
, newSec
)) == NULL
3059 || (in
= BIO_new(BIO_s_mem())) == NULL
)
3060 return modified_the_body
;
3062 (void) BIO_reset(in
);
3063 if(mimetext
!= NULL
)
3064 BIO_write(in
, mimetext
, mimelen
);
3065 BIO_write(in
, bodytext
, bodylen
);
3067 saved
= smime_extract_and_save_cert(p7
, F_ON(F_USE_CERT_STORE_ONLY
, ps_global
));
3068 if(saved
< 0 && F_ON(F_USE_CERT_STORE_ONLY
, ps_global
))
3069 return modified_the_body
;
3071 if((result
= do_signature_verify(p7
, in
, NULL
, 1)) == 0){
3072 flag
= (mimelen
== 0 || !IS_REMOTE(ps_global
->mail_stream
->mailbox
))
3074 result
= smime_validate_extra_test(mimetext
, mimelen
, bodytext
, bodylen
, p7
, flag
);
3076 return modified_the_body
;
3078 && mimelen
> 0 /* do not do this for encrypted messages */
3079 && IS_REMOTE(ps_global
->mail_stream
->mailbox
)){
3081 unsigned long hlen
, tlen
;
3085 if((in
= BIO_new(BIO_s_mem())) != NULL
3086 && (fetch
= mail_fetch_header(ps_global
->mail_stream
, msgno
, NULL
,
3087 NULL
, &hlen
, FT_PEEK
)) != NULL
3088 && (msg_so
= so_get(CharStar
, NULL
, WRITE_ACCESS
)) != NULL
3089 && so_nputs(msg_so
, fetch
, (long) hlen
)
3090 && (fetch
= pine_mail_fetch_text(ps_global
->mail_stream
, msgno
, NULL
,
3091 &tlen
, FT_PEEK
)) != NULL
3092 && so_nputs(msg_so
, fetch
, tlen
)){
3094 char *h
= (char *) so_text(msg_so
);
3095 char *bstart
= strstr(h
, "\r\n\r\n");
3100 INIT(&bs
, mail_string
, bstart
, tlen
);
3101 rfc822_parse_msg_full(&env
, &body
, h
, bstart
-h
-4, &bs
, BADHOST
, 0, 0);
3102 mail_free_envelope(&env
);
3104 mail_free_body_part(&b
->nested
.part
);
3105 tmpB
= mail_body_section(body
, (unsigned char *) section
);
3106 if(MIME_MSG(tmpB
->type
, tmpB
->subtype
))
3107 b
->nested
.part
= tmpB
->nested
.msg
->body
->nested
.part
;
3109 b
->nested
.part
= tmpB
->nested
.part
;
3110 create_local_cache(bstart
, bstart
, &b
->nested
.part
->body
, 1);
3111 modified_the_body
= 1;
3113 snprintf(newSec
, sizeof(newSec
), "%s%s1", section
? section
: "", (section
&& *section
) ? "." : "");
3115 mimetext
= mail_fetch_mime(ps_global
->mail_stream
, msgno
, (char*) newSec
, &mimelen
, 0);
3118 bodytext
= mail_fetch_body (ps_global
->mail_stream
, msgno
, (char*) newSec
, &bodylen
, 0);
3120 if (mimetext
== NULL
|| bodytext
== NULL
)
3121 return modified_the_body
;
3123 snprintf(newSec
, sizeof(newSec
), "%s%s2", section
? section
: "", (section
&& *section
) ? "." : "");
3125 if((p7
= get_pkcs7_from_part(msgno
, newSec
)) == NULL
)
3126 return modified_the_body
;
3128 (void) BIO_reset(in
);
3129 BIO_write(in
, mimetext
, mimelen
);
3130 BIO_write(in
, bodytext
, bodylen
);
3133 if((result
= do_signature_verify(p7
, in
, NULL
, 1)) == 0){
3134 result
= smime_validate_extra_test(mimetext
, mimelen
, bodytext
, bodylen
, p7
, 0);
3136 return modified_the_body
;
3144 fs_give((void**) &b
->subtype
);
3146 b
->subtype
= cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE
);
3147 b
->encoding
= ENC8BIT
;
3150 fs_give ((void**) &b
->description
);
3152 what_we_did
= result
? _("This message was cryptographically signed.") :
3153 _("This message was cryptographically signed but the signature could not be verified.");
3155 b
->description
= cpystr(what_we_did
);
3157 b
->sparep
= create_smime_sparep(P7Type
, p7
);
3161 /* p is signed plaintext */
3163 mail_free_body_part(&p
->next
); /* hide the pkcs7 from the viewer */
3165 modified_the_body
= 1;
3167 return modified_the_body
;
3172 find_certificate_matching_recip_info(PKCS7_RECIP_INFO
*ri
)
3174 PERSONAL_CERT
*x
= NULL
;
3176 if(ps_global
->smime
){
3177 for(x
= (PERSONAL_CERT
*) ps_global
->smime
->personal_certs
; x
; x
=x
->next
){
3182 if(!X509_NAME_cmp(ri
->issuer_and_serial
->issuer
,X509_get_issuer_name(mine
)) &&
3183 !ASN1_INTEGER_cmp(ri
->issuer_and_serial
->serial
,X509_get_serialNumber(mine
))){
3193 static PERSONAL_CERT
*
3194 find_certificate_matching_pkcs7(PKCS7
*p7
)
3197 STACK_OF(PKCS7_RECIP_INFO
) *recips
;
3198 PERSONAL_CERT
*x
= NULL
;
3200 recips
= p7
->d
.enveloped
->recipientinfo
;
3202 for(i
=0; i
<sk_PKCS7_RECIP_INFO_num(recips
); i
++){
3203 PKCS7_RECIP_INFO
*ri
;
3205 ri
= sk_PKCS7_RECIP_INFO_value(recips
, i
);
3207 if((x
=find_certificate_matching_recip_info(ri
))!=0){
3215 /* decrypt an encrypted file.
3216 Args: fp - the path to the encrypted file.
3217 rv - a code that tells the caller what happened inside the function
3218 pcert - a personal certificate that was used to encrypt this file
3219 Returns the decoded text allocated in a char *, whose memory must be
3224 decrypt_file(char *fp
, int *rv
, PERSONAL_CERT
*pc
)
3228 BIO
*in
= NULL
, *out
= NULL
;
3230 long unsigned int len
;
3233 if(pc
== NULL
|| (text
= read_file(fp
, 0)) == NULL
|| *text
== '\0')
3236 tmp
= fs_get(strlen(text
) + (strlen(text
) << 6) + 1);
3237 for(j
= 0, i
= strlen("-----BEGIN PKCS7-----") + 1; text
[i
] != '\0'
3238 && text
[i
] != '-'; j
++, i
++)
3242 ret
= rfc822_base64((unsigned char *)tmp
, strlen(tmp
), &len
);
3244 if((in
= BIO_new_mem_buf((char *)ret
, len
)) != NULL
){
3245 p7
= d2i_PKCS7_bio(in
, NULL
);
3249 if (text
) fs_give((void **)&text
);
3250 if (ret
) fs_give((void **)&ret
);
3252 if (rv
) *rv
= pc
->key
== NULL
? -1 : 1;
3254 out
= BIO_new(BIO_s_mem());
3255 (void) BIO_reset(out
);
3257 if(PKCS7_decrypt(p7
, pc
->key
, pc
->cert
, out
, 0) != 0){
3258 BIO_get_mem_data(out
, &tmp
);
3262 q_status_message1(SM_ORDER
, 1, 1, _("Error decrypting: %s"),
3263 (char *) openssl_error_string());
3270 * Try to decode (decrypt or verify a signature) a PKCS7 body
3271 * Returns non-zero if something was changed.
3274 do_decoding(BODY
*b
, long msgno
, const char *section
)
3276 int modified_the_body
= 0;
3280 EVP_PKEY
*key
= NULL
;
3281 PERSONAL_CERT
*pcert
= NULL
;
3282 char *what_we_did
= "";
3285 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"));
3290 * Extract binary data from part to an in-memory store
3294 if(get_smime_sparep_type(b
->sparep
) == P7Type
)
3295 p7
= (PKCS7
*) get_smime_sparep_data(b
->sparep
);
3298 p7
= get_pkcs7_from_part(msgno
, section
&& *section
? section
: "1");
3300 q_status_message1(SM_ORDER
, 2, 2, "Couldn't load PKCS7 object: %s",
3301 (char*) openssl_error_string());
3306 * Save the PKCS7 object for later dealings by the user interface.
3307 * It will be cleaned up when the body is garbage collected.
3309 b
->sparep
= create_smime_sparep(P7Type
, p7
);
3312 dprint((1, "type_is_signed = %d, type_is_enveloped = %d", PKCS7_type_is_signed(p7
), PKCS7_type_is_enveloped(p7
)));
3314 if(PKCS7_type_is_signed(p7
)){
3317 out
= BIO_new(BIO_s_mem());
3318 (void) BIO_reset(out
);
3319 BIO_puts(out
, "MIME-Version: 1.0\r\n"); /* needed so rfc822_parse_msg_full believes it's MIME */
3321 sigok
= do_signature_verify(p7
, NULL
, out
, 0);
3323 what_we_did
= sigok
? _("This message was cryptographically signed.") :
3324 _("This message was cryptographically signed but the signature could not be verified.");
3326 /* make sure it's null terminated */
3327 BIO_write(out
, null
, 1);
3329 else if(!PKCS7_type_is_enveloped(p7
)){
3330 q_status_message(SM_ORDER
, 1, 1, "PKCS7 object not recognised.");
3333 else{ /* It *is* enveloped */
3336 what_we_did
= _("This message was encrypted.");
3338 /* now need to find a cert that can decrypt this */
3339 pcert
= find_certificate_matching_pkcs7(p7
);
3342 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find the certificate needed to decrypt."));
3346 recip
= pcert
->cert
;
3348 if(!load_private_key(pcert
)
3350 && ps_global
->smime
->need_passphrase
3351 && !ps_global
->smime
->already_auto_asked
){
3352 /* Couldn't load key with blank password, ask user */
3353 ps_global
->smime
->already_auto_asked
= 1;
3354 if(pith_opt_smime_get_passphrase
){
3355 (*pith_opt_smime_get_passphrase
)();
3356 load_private_key(pcert
);
3364 out
= BIO_new(BIO_s_mem());
3365 (void) BIO_reset(out
);
3366 BIO_puts(out
, "MIME-Version: 1.0\r\n");
3368 decrypt_result
= PKCS7_decrypt(p7
, key
, recip
, out
, 0);
3370 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
3371 forget_private_keys();
3373 if(!decrypt_result
){
3374 q_status_message1(SM_ORDER
, 1, 1, _("Error decrypting: %s"),
3375 (char*) openssl_error_string());
3378 BIO_write(out
, null
, 1);
3382 * We've now produced a flattened MIME object in BIO out.
3383 * It needs to be turned back into a BODY.
3392 BUF_MEM
*bptr
= NULL
;
3394 BIO_get_mem_ptr(out
, &bptr
);
3398 /* look for start of body */
3399 bstart
= strstr(h
, "\r\n\r\n");
3402 q_status_message(SM_ORDER
, 3, 3, _("Encrypted data couldn't be parsed."));
3406 bstart
+= 4; /* skip over CRLF*2 */
3408 INIT(&s
, mail_string
, bstart
, strlen(bstart
));
3409 rfc822_parse_msg_full(&env
, &body
, h
, bstart
-h
-2, &s
, BADHOST
, 0, 0);
3410 mail_free_envelope(&env
); /* Don't care about this */
3412 if(body
->type
== TYPEMULTIPART
3413 && !strucmp(body
->subtype
, "SIGNED")){
3414 char *cookie
= NULL
;
3416 for (param
= body
->parameter
; param
&& !cookie
; param
= param
->next
)
3417 if (!strucmp (param
->attribute
,"BOUNDARY")) cookie
= param
->value
;
3419 st
= fs_get(sizeof(SIZEDTEXT
));
3420 st
->data
= (void *) cpystr(bstart
+ strlen(cookie
)+4); /* 4 = strlen("--\r\n") */
3421 st
->size
= body
->nested
.part
->next
->body
.mime
.offset
- 2*(strlen(cookie
) + 4);
3422 body
->sparep
= create_smime_sparep(SizedText
, (void *)st
);
3425 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find cookie in attachment list."));
3427 body
->mime
.offset
= 0;
3428 body
->mime
.text
.size
= 0;
3431 * Now convert original body (application/pkcs7-mime)
3432 * to a multipart body with one sub-part (the decrypted body).
3433 * Note that the sub-part may also be multipart!
3436 b
->type
= TYPEMULTIPART
;
3438 fs_give((void**) &b
->subtype
);
3441 * This subtype is used in mailview.c to annotate the display of
3442 * encrypted or signed messages. We know for sure then that it's a PKCS7
3443 * part because the sparep field is set to the PKCS7 object (see above).
3445 b
->subtype
= cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE
);
3446 b
->encoding
= ENC8BIT
;
3449 fs_give((void**) &b
->description
);
3451 b
->description
= cpystr(what_we_did
);
3453 if(b
->disposition
.type
)
3454 fs_give((void **) &b
->disposition
.type
);
3456 if(b
->contents
.text
.data
)
3457 fs_give((void **) &b
->contents
.text
.data
);
3460 mail_free_body_parameter(&b
->parameter
);
3462 /* Allocate mem for the sub-part, and copy over the contents of our parsed body */
3463 b
->nested
.part
= fs_get(sizeof(PART
));
3464 b
->nested
.part
->body
= *body
;
3465 b
->nested
.part
->next
= NULL
;
3467 fs_give((void**) &body
);
3470 * IMPORTANT BIT: set the body->contents.text.data elements to contain
3471 * the decrypted data. Otherwise, it'll try to load it from the original
3474 create_local_cache(bstart
-b
->nested
.part
->body
.mime
.offset
, bstart
, &b
->nested
.part
->body
, 0);
3476 modified_the_body
= 1;
3484 return modified_the_body
;
3489 * Recursively handle PKCS7 bodies in our message.
3491 * Returns non-zero if some fiddling was done.
3494 do_fiddle_smime_message(BODY
*b
, long msgno
, char *section
)
3496 int modified_the_body
= 0;
3501 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"));
3503 if(is_pkcs7_body(b
)){
3505 if(do_decoding(b
, msgno
, section
)){
3507 * b should now be a multipart message:
3508 * fiddle it too in case it's been multiply-encrypted!
3512 modified_the_body
= 1;
3516 if(b
->type
==TYPEMULTIPART
|| MIME_MSG(b
->type
, b
->subtype
)){
3522 if(MIME_MULT_SIGNED(b
->type
, b
->subtype
)){
3526 * Ahah. We have a multipart signed entity.
3529 * part 1 (signed thing)
3530 * part 2 (the pkcs7 signature)
3532 * We're going to convert that to
3534 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
3535 * part 1 (signed thing)
3536 * part 2 has been freed
3538 * We also extract the signature from part 2 and save it
3539 * in the multipart body->sparep, and we add a description
3540 * in the multipart body->description.
3543 * The results of a decrypted message will be similar. It
3546 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
3547 * part 1 (decrypted thing)
3550 modified_the_body
+= do_detached_signature_verify(b
, msgno
, section
);
3552 else if(MIME_MSG(b
->type
, b
->subtype
)){
3553 modified_the_body
+= do_fiddle_smime_message(b
->nested
.msg
->body
, msgno
, section
);
3557 for(p
=b
->nested
.part
,partNum
=1; p
; p
=p
->next
,partNum
++){
3558 /* Append part number to the section string */
3560 snprintf(newSec
, sizeof(newSec
), "%s%s%d", section
, *section
? "." : "", partNum
);
3562 modified_the_body
+= do_fiddle_smime_message(&p
->body
, msgno
, newSec
);
3567 return modified_the_body
;
3572 * Fiddle a message in-place by decrypting/verifying S/MIME entities.
3573 * Returns non-zero if something was changed.
3576 fiddle_smime_message(BODY
*b
, long msgno
)
3578 return do_fiddle_smime_message(b
, msgno
, "");
3582 /********************************************************************************/
3586 * Output a string in a distinctive style
3589 gf_puts_uline(char *txt
, gf_io_t pc
)
3591 pc(TAG_EMBED
); pc(TAG_BOLDON
);
3593 pc(TAG_EMBED
); pc(TAG_BOLDOFF
);
3596 /* get_chain_for_cert: error and level are mandatory arguments */
3598 get_chain_for_cert(X509
*cert
, int *error
, int *level
)
3600 STACK_OF(X509
) *chain
= NULL
;
3601 X509_STORE_CTX
*ctx
;
3603 int rc
; /* return code */
3608 if((s_cert_store
!= NULL
) && (ctx
= X509_STORE_CTX_new()) != NULL
){
3609 X509_STORE_set_flags(s_cert_store
, 0);
3610 if(!X509_STORE_CTX_init(ctx
, s_cert_store
, cert
, NULL
))
3611 *error
= X509_STORE_CTX_get_error(ctx
);
3612 else if((chain
= sk_X509_new_null()) != NULL
){
3613 for(x
= cert
; ; x
= xtmp
){
3615 sk_X509_push(chain
, X509_dup(x
));
3616 rc
= X509_STORE_CTX_get1_issuer(&xtmp
, ctx
, x
);
3621 if(!X509_check_issued(xtmp
, xtmp
))
3625 X509_STORE_CTX_free(ctx
);
3632 * Sign a message. Called from call_mailer in send.c.
3634 * This takes the header for the outgoing message as well as a pointer
3635 * to the current body (which may be reallocated).
3636 * The last argument (BODY **bp) is an argument that tells Alpine
3637 * if the body has 8 bit. if *bp is not null we compute two signatures
3638 * one for the quoted-printable encoded message, and another for the
3639 * 8bit encoded message. We return the signature for the 8bit encoded
3640 * part in p2->body.mime.text.data.
3641 * The reason why we compute two signatures is so that we can decide
3642 * which one to use later, and we only do it in the case that *bp is
3643 * not null. If we did not do this, then we might not be able to sign
3644 * a message until we log in to the smtp server, so instead of doing
3645 * that, we get ready for any possible situation we might find.
3648 sign_outgoing_message(METAENV
*header
, BODY
**bodyP
, int dont_detach
, BODY
**bp
)
3650 STORE_S
*outs
= NULL
;
3651 STORE_S
*outs_2
= NULL
;
3652 BODY
*body
= *bodyP
;
3653 BODY
*newBody
= NULL
;
3656 PERSONAL_CERT
*pcert
;
3663 STACK_OF(X509
) *chain
;
3664 const EVP_MD
*md
= EVP_sha256(); /* use this digest instead of sha1 */
3665 int result
= 0, error
;
3666 int flags
= dont_detach
? 0 : PKCS7_DETACHED
;
3669 dprint((9, "sign_outgoing_message()"));
3673 /* Look for a private key matching the sender address... */
3675 pcert
= match_personal_cert(header
->env
);
3678 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find the certificate needed to sign."));
3682 if(!load_private_key(pcert
) && ps_global
->smime
&& ps_global
->smime
->need_passphrase
){
3683 /* Couldn't load key with blank password, try again */
3684 if(pith_opt_smime_get_passphrase
){
3685 (*pith_opt_smime_get_passphrase
)();
3686 load_private_key(pcert
);
3693 if(((chain
= get_chain_for_cert(pcert
->cert
, &error
, &level
)) != NULL
&& error
)
3695 sk_X509_pop_free(chain
, X509_free
);
3700 q_status_message(SM_ORDER
, 1, 1,
3701 _("Not all certificates needed to verify signature included in signed message"));
3703 in
= body_to_bio(body
);
3705 flags
|= PKCS7_PARTIAL
;
3706 if((p7
= PKCS7_sign(NULL
, NULL
, chain
, in
, flags
)) != NULL
3707 && PKCS7_sign_add_signer(p7
, pcert
->cert
, pcert
->key
, md
, flags
))
3708 PKCS7_final(p7
, in
, flags
);
3711 int i
, save_encoding
;
3713 for(i
= 0; (i
<= ENCMAX
) && body_encodings
[i
]; i
++);
3715 if(i
> ENCMAX
){ /* no empty encoding slots! */
3719 save_encoding
= (*bp
)->encoding
;
3720 body_encodings
[(*bp
)->encoding
= i
] = body_encodings
[ENC8BIT
];
3722 in_2
= body_to_bio(body
);
3724 body_encodings
[i
] = NULL
;
3725 (*bp
)->encoding
= save_encoding
;
3730 if((p7_2
= PKCS7_sign(NULL
, NULL
, chain
, in_2
, flags
)) != NULL
3731 && PKCS7_sign_add_signer(p7_2
, pcert
->cert
, pcert
->key
, md
, flags
))
3732 PKCS7_final(p7_2
, in_2
, flags
);
3735 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
3736 forget_private_keys();
3739 sk_X509_pop_free(chain
, X509_free
);
3742 q_status_message(SM_ORDER
, 1, 1, _("Error creating signed object."));
3746 outs
= so_get(BioType
, NULL
, EDIT_ACCESS
);
3747 out
= bio_from_store(outs
);
3749 i2d_PKCS7_bio(out
, p7
);
3750 (void) BIO_flush(out
);
3752 so_seek(outs
, 0, SEEK_SET
);
3754 if(bp
&& *bp
&& p7_2
){
3755 outs_2
= so_get(BioType
, NULL
, EDIT_ACCESS
);
3756 out_2
= bio_from_store(outs_2
);
3758 i2d_PKCS7_bio(out_2
, p7_2
);
3759 (void) BIO_flush(out_2
);
3761 so_seek(outs_2
, 0, SEEK_SET
);
3764 if((flags
&PKCS7_DETACHED
)==0){
3766 /* the simple case: the signed data is in the pkcs7 object */
3768 newBody
= mail_newbody();
3770 setup_pkcs7_body_for_signature(newBody
, "S/MIME Cryptographically Signed Message", "pkcs7-mime", "smime.p7m", "signed-data");
3772 newBody
->contents
.text
.data
= (unsigned char *) outs
;
3781 * We have to create a new body as follows:
3783 * multipart/signed; blah blah blah
3784 * reference to existing body
3789 newBody
= mail_newbody();
3791 newBody
->type
= TYPEMULTIPART
;
3792 newBody
->subtype
= cpystr("signed");
3793 newBody
->encoding
= ENC7BIT
;
3795 set_parameter(&newBody
->parameter
, "protocol", "application/pkcs7-signature");
3796 set_parameter(&newBody
->parameter
, "micalg", "sha-256");
3798 p1
= mail_newbody_part();
3799 p2
= mail_newbody_part();
3802 * This is nasty. We're just copying the body in here,
3803 * but since our newBody is freed at the end of call_mailer,
3804 * we mustn't let this body (the original one) be freed twice.
3806 p1
->body
= *body
; /* ARRGH. This is special cased at the end of call_mailer */
3810 setup_pkcs7_body_for_signature(&p2
->body
, "S/MIME Cryptographic Signature", "pkcs7-signature", "smime.p7s", NULL
);
3811 p2
->body
.mime
.text
.data
= (unsigned char *) outs_2
;
3812 p2
->body
.contents
.text
.data
= (unsigned char *) outs
;
3814 newBody
->nested
.part
= p1
;
3827 if(p7_2
) PKCS7_free(p7_2
);
3831 dprint((9, "sign_outgoing_message returns %d", result
));
3837 new_smime_struct(void)
3839 SMIME_STUFF_S
*ret
= NULL
;
3841 ret
= (SMIME_STUFF_S
*) fs_get(sizeof(*ret
));
3842 memset((void *) ret
, 0, sizeof(*ret
));
3843 ret
->publictype
= Nada
;
3850 free_smime_struct(SMIME_STUFF_S
**smime
)
3852 if(smime
&& *smime
){
3853 if((*smime
)->passphrase_emailaddr
){
3855 for(i
= 0; (*smime
)->passphrase_emailaddr
[i
] != NULL
; i
++)
3856 fs_give((void **) &(*smime
)->passphrase_emailaddr
[i
]);
3857 fs_give((void **) (*smime
)->passphrase_emailaddr
);
3860 if((*smime
)->publicpath
)
3861 fs_give((void **) &(*smime
)->publicpath
);
3863 if((*smime
)->publiccertlist
)
3864 free_certlist(&(*smime
)->publiccertlist
);
3866 if((*smime
)->backuppubliccertlist
)
3867 free_certlist(&(*smime
)->backuppubliccertlist
);
3869 if((*smime
)->cacertlist
)
3870 free_certlist(&(*smime
)->cacertlist
);
3872 if((*smime
)->backupcacertlist
)
3873 free_certlist(&(*smime
)->backupcacertlist
);
3875 if((*smime
)->privatecertlist
)
3876 free_certlist(&(*smime
)->privatecertlist
);
3878 if((*smime
)->backupprivatecertlist
)
3879 free_certlist(&(*smime
)->backupprivatecertlist
);
3881 if((*smime
)->publiccontent
)
3882 fs_give((void **) &(*smime
)->publiccontent
);
3884 if((*smime
)->privatepath
)
3885 fs_give((void **) &(*smime
)->privatepath
);
3887 if((*smime
)->personal_certs
){
3890 pc
= (PERSONAL_CERT
*) (*smime
)->personal_certs
;
3891 free_personal_certs(&pc
);
3892 (*smime
)->personal_certs
= NULL
;
3895 if((*smime
)->privatecontent
)
3896 fs_give((void **) &(*smime
)->privatecontent
);
3898 if((*smime
)->capath
)
3899 fs_give((void **) &(*smime
)->capath
);
3901 if((*smime
)->cacontent
)
3902 fs_give((void **) &(*smime
)->cacontent
);
3904 fs_give((void **) smime
);