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-2015 Eduardo Chappa
8 * Copyright 2008 University of Washington
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
20 * This is based on a contribution from Jonathan Paisley
23 * Author: paisleyj@dcs.gla.ac.uk
28 #include "../pith/headers.h"
32 #include "../pith/osdep/canaccess.h"
33 #include "../pith/helptext.h"
34 #include "../pith/store.h"
35 #include "../pith/status.h"
36 #include "../pith/detach.h"
37 #include "../pith/conf.h"
38 #include "../pith/smkeys.h"
39 #include "../pith/smime.h"
40 #include "../pith/mailpart.h"
41 #include "../pith/reply.h"
42 #include "../pith/tempfile.h"
43 #include "../pith/readfile.h"
44 #include "../pith/remote.h"
46 #include <openssl/buffer.h>
47 #include <openssl/x509v3.h>
49 /* internal prototypes */
50 static void forget_private_keys(void);
51 static int app_RAND_load_file(const char *file
);
52 static void openssl_extra_randomness(void);
53 static int app_RAND_write_file(const char *file
);
54 static const char *openssl_error_string(void);
55 static int load_private_key(PERSONAL_CERT
*pcert
);
56 static void create_local_cache(char *h
, char *base
, BODY
*b
, int type
);
57 static long rfc822_output_func(void *b
, char *string
);
58 static void setup_pkcs7_body_for_signature(BODY
*b
, char *description
,
59 char *type
, char *filename
, char *smime_type
);
60 static BIO
*body_to_bio(BODY
*body
);
61 static BIO
*bio_from_store(STORE_S
*store
);
62 static STORE_S
*get_part_contents(long msgno
, const char *section
);
63 static PKCS7
*get_pkcs7_from_part(long msgno
, const char *section
);
64 static int do_signature_verify(PKCS7
*p7
, BIO
*in
, BIO
*out
, int silent
);
65 static int do_detached_signature_verify(BODY
*b
, long msgno
, char *section
);
66 static PERSONAL_CERT
*find_certificate_matching_pkcs7(PKCS7
*p7
);
67 static int do_decoding(BODY
*b
, long msgno
, const char *section
);
68 static void free_smime_struct(SMIME_STUFF_S
**smime
);
69 static void setup_storage_locations(void);
70 static int copy_container_to_dir(WhichCerts which
);
71 static int do_fiddle_smime_message(BODY
*b
, long msgno
, char *section
);
72 void setup_privatekey_storage(void);
73 int smime_path(char *rpath
, char *fpath
, size_t len
);
74 int smime_extract_and_save_cert(PKCS7
*p7
);
75 int same_cert(X509
*, X509
*);
76 CertList
* certlist_from_personal_certs(PERSONAL_CERT
*pc
);
78 int load_key_and_cert(char *pathkeydir
, char *pathcertdir
, char **keyfile
, char **certfile
, EVP_PKEY
**pkey
, X509
**pcert
);
80 EVP_PKEY
*load_pkey_with_prompt(char *fpath
, char *text
, char *prompt
, int *);
81 void smime_remove_trailing_crlf(char **mimetext
, unsigned long *mimelen
, char **bodytext
, unsigned long *bodylen
);
82 void smime_remove_folding_space(char **mimetext
, unsigned long *mimelen
, char **bodytext
, unsigned long *bodylen
);
83 int smime_validate_extra_test(char *mimetext
, unsigned long mimelen
, char *bodytext
, unsigned long bodylen
, PKCS7
*p7
, int nflag
);
85 int (*pith_opt_smime_get_passphrase
)(void);
86 int (*pith_smime_import_certificate
)(char *, char *, size_t);
87 int (*pith_smime_enter_password
)(char *prompt
, char *, size_t);
89 static X509_STORE
*s_cert_store
;
91 /* State management for randomness functions below */
92 static int seeded
= 0;
95 create_smime_sparep(SpareType stype
, void *s
)
99 rv
= fs_get(sizeof(SMIME_SPARE_S
));
106 get_smime_sparep_type(void *s
)
108 return ((SMIME_SPARE_S
*)s
)->sptype
;
112 get_smime_sparep_data(void *s
)
114 return ((SMIME_SPARE_S
*)s
)->data
;
120 * load key from pathkeydir and cert from pathcertdir. It chooses the first
121 * key/certificate pair that matches. Delete pairs that you do not want used,
122 * if you do not want them selected. All parameters must be non-null.
123 * Memory freed by caller.
125 * -1 : user cancelled load
126 * 0 : load was successful
127 * 1 : there was an error in the loading.
130 load_key_and_cert(char *pathkeydir
, char *pathcertdir
, char **keyfile
,
131 char **certfile
, EVP_PKEY
**pkey
, X509
**pcert
)
133 char buf
[MAXPATH
+1], pathkey
[MAXPATH
+1], prompt
[MAILTMPLEN
];
136 int b
= 0, ret
= 1; /* assume error */
138 if(pathkeydir
== NULL
|| pathcertdir
== NULL
|| keyfile
== NULL
139 || pkey
== NULL
|| certfile
== NULL
|| pcert
== NULL
)
147 if((dirp
= opendir(pathkeydir
)) != NULL
){
148 while(b
== 0 && (d
=readdir(dirp
)) != NULL
){
151 if((ll
=strlen(d
->d_name
)) && ll
> 4){
152 if(!strcmp(d
->d_name
+ll
-4, ".key")){
153 strncpy(buf
, d
->d_name
, sizeof(buf
));
154 buf
[sizeof(buf
)-1] = '\0';
155 build_path(pathkey
, pathkeydir
, buf
, sizeof(pathkey
));
156 buf
[strlen(buf
)-4] = '\0';
157 snprintf(prompt
, sizeof(prompt
),
158 _("Enter password of key <%s> to unlock password file: "), buf
);
159 if((*pkey
= load_pkey_with_prompt(pathkey
, NULL
, prompt
, &ret
)) != NULL
){
160 if(load_cert_for_key(pathcertdir
, *pkey
, certfile
, pcert
)){
162 *keyfile
= cpystr(buf
);
164 EVP_PKEY_free(*pkey
);
166 q_status_message1(SM_ORDER
, 0, 2,
167 _("Cannot find certificate that matches key <%s>. Continuing..."), buf
);
179 /* setup a key and certificate to encrypt and decrypt a password file.
180 * These files will be saved in the .alpine-smime/.pwd directory, but its
181 * location can be setup in the command line with the -pwdcertdir option.
182 * Here are the rules:
184 * Check if the .alpine-smime/.pwd (or -pwdcertdir directory) exists,
185 * if not create it. If we are successful, move to the next step
187 * - If the user has a key/cert pair, in the .alpine-smime/.pwd dir
188 * setup is successful;
189 * - if the user does not have a key/cert pair, look to see if
190 * ps_global->smime->personal_certs is already setup, if so, use it.
191 * - if ps_global->smime->personal_certs is not set up, see if we can
192 * find a certificate/cert pair in the default locations at compilation
193 * time. (~/.alpine-smime/private and ~/.alpine-smime/public
194 * - if none of this is successful, create a key/certificate pair
195 * (TODO: implement this)
196 * - in any other case, setup is not successful.
198 * If setup is successful, setup ps_global->pwdcert.
199 * If any of this fails, ps_global->pwdcert will be null.
200 * Ok, that should do it.
203 setup_pwdcert(void **pwdcert
)
206 int setup_dir
= 0; /* make it non zero if we know which dir to use */
208 char pathdir
[MAXPATH
+1], pathkey
[MAXPATH
+1], fpath
[MAXPATH
+1], pathcert
[MAXPATH
+1];
209 char fpath2
[MAXPATH
+1], prompt
[MAILTMPLEN
];
210 char *keyfile
, *certfile
, *text
;
211 EVP_PKEY
*pkey
= NULL
;
213 PERSONAL_CERT
*pc
, *pc2
= NULL
;
218 if(ps_global
->pwdcertdir
){
219 if(our_stat(ps_global
->pwdcertdir
, &sbuf
) == 0
220 && ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
)){
222 strncpy(pathdir
, ps_global
->pwdcertdir
, sizeof(pathdir
));
223 pathdir
[sizeof(pathdir
)-1] = '\0';
226 smime_path(DF_PASSWORD_DIR
, pathdir
, sizeof(pathdir
));
227 if(our_stat(pathdir
, &sbuf
) == 0){
228 if((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
)
230 } else if(can_access(pathdir
, ACCESS_EXISTS
) != 0
231 && our_mkpath(pathdir
, 0700) == 0)
238 if(load_key_and_cert(pathdir
, pathdir
, &keyfile
, &certfile
, &pkey
, &pcert
) < 0)
241 if(certfile
&& keyfile
){
242 pc
= (PERSONAL_CERT
*) fs_get(sizeof(PERSONAL_CERT
));
243 memset((void *)pc
, 0, sizeof(PERSONAL_CERT
));
247 *pwdcert
= (void *) pc
;
248 fs_give((void **)&certfile
);
252 /* if the user gave a pwdcertdir and there is nothing there, do not
253 * continue. Let the user initialize on their own this directory.
255 if(ps_global
->pwdcertdir
!= NULL
)
258 /* look to see if there are any certificates lying around, first
259 * we try to load ps_global->smime to see if that has information
260 * we can use. If we are the process filling the smime structure
261 * we deinit at the end, since this might not do a full init.
263 if(ps_global
&& ps_global
->smime
&& !ps_global
->smime
->inited
){
268 /* at this point ps_global->smime->inited == 1 */
269 if(ps_global
->smime
&& ps_global
->smime
->personal_certs
!= NULL
){
270 pc
= (PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
271 if(ps_global
->smime
->privatetype
== Directory
){
272 build_path(pathkey
, ps_global
->smime
->privatepath
, pc
->name
, sizeof(pathkey
));
273 strncat(pathkey
, ".key", 4);
274 pathkey
[sizeof(pathkey
)-1] = '\0';
276 } else if (ps_global
->smime
->privatetype
== Container
){
277 if(pc
->keytext
== NULL
){ /* we should *never* be here, but just in case */
278 if(ps_global
->smime
->privatecontent
!= NULL
){
279 char tmp
[MAILTMPLEN
], *s
, *t
, c
;
280 snprintf(tmp
, sizeof(tmp
), "%s%s", EMAILADDRLEADER
, pc
->name
);
281 tmp
[sizeof(tmp
)-1] = '\0';
282 if((s
= strstr(ps_global
->smime
->privatecontent
, tmp
)) != NULL
){
283 if((t
= strstr(s
+strlen(tmp
), EMAILADDRLEADER
)) != NULL
){
286 pc
->keytext
= cpystr(s
+ strlen(tmp
) + 1); /* 1 = strlen("\n") */
290 pc
->keytext
= cpystr(s
+ strlen(tmp
) + 1); /* 1 = strlen("\n") */
294 if(pc
->keytext
!= NULL
) /* we should go straigth here */
296 } else if (ps_global
->smime
->privatetype
== Keychain
){
297 pathkey
[0] = '\0'; /* no apple key chain support yet */
300 if((pathkey
&& *pathkey
) || text
){
301 snprintf(prompt
, sizeof(prompt
),
302 _("Enter password of key <%s> to unlock password file: "), pc
->name
);
304 if((pkey
= load_pkey_with_prompt(pathkey
, text
, prompt
, NULL
)) != NULL
){
305 pc2
= (PERSONAL_CERT
*) fs_get(sizeof(PERSONAL_CERT
));
306 memset((void *)pc2
, 0, sizeof(PERSONAL_CERT
));
307 pc2
->name
= cpystr(pc
->name
);
309 pc2
->cert
= X509_dup(pc
->cert
);
311 /* now copy the keys and certs, starting by the key... */
312 build_path(fpath
, pathdir
, pc
->name
, sizeof(fpath
));
313 strncat(fpath
, ".key", 4);
314 fpath
[sizeof(fpath
)-1] = '\0';
315 if(our_stat(fpath
, &sbuf
) == 0){ /* if fpath exists */
316 if((sbuf
.st_mode
& S_IFMT
) == S_IFREG
) /* and is a regular file */
317 setup_dir
++; /* we are done */
318 } else if(ps_global
->smime
->privatetype
== Directory
){
319 if(our_copy(fpath
, pathkey
) == 0)
321 } else if(ps_global
->smime
->privatetype
== Container
){
323 if((out
= BIO_new_file(fpath
, "w")) != NULL
){
324 if(BIO_puts(out
, pc
->keytext
) > 0)
328 } else if(ps_global
->smime
->privatetype
== Keychain
){
329 /* add support for Apple Mac OS X */
333 /* successful copy of key, now continue with certificate */
337 build_path(pathkey
, ps_global
->smime
->publicpath
, pc
->name
, sizeof(pathkey
));
338 strncat(pathkey
, ".crt", 4);
339 pathkey
[sizeof(pathkey
)-1] = '\0';
341 build_path(fpath
, pathdir
, pc
->name
, sizeof(fpath
));
342 strncat(fpath
, ".crt", 4);
343 fpath
[sizeof(fpath
)-1] = '\0';
345 if(our_stat(fpath
, &sbuf
) == 0){
346 if((sbuf
.st_mode
& S_IFMT
) == S_IFREG
)
349 else if(ps_global
->smime
->privatetype
== Directory
){
350 if(our_copy(fpath
, pathkey
) == 0)
352 } else if(ps_global
->smime
->privatetype
== Container
) {
354 if((out
= BIO_new_file(fpath
, "w")) != NULL
){
355 if(PEM_write_bio_X509(out
, pc
->cert
))
359 } else if (ps_global
->smime
->privatetype
== Keychain
) {
360 /* add support for Mac OS X */
365 *pwdcert
= (void *) pc2
;
369 free_personal_certs(&pc2
);
370 } /* if (pathkey...) */
371 } /* if(ps_global->smime->personal_certs) */
375 /* PATHCERTDIR(Private) must be null, so create a path */
376 set_current_val(&ps_global
->vars
[V_PRIVATEKEY_DIR
], TRUE
, TRUE
);
377 smime_path(ps_global
->VAR_PRIVATEKEY_DIR
, pathkey
, sizeof(pathkey
));
379 /* PATHCERTDIR(Public) must be null, so create a path */
380 set_current_val(&ps_global
->vars
[V_PUBLICCERT_DIR
], TRUE
, TRUE
);
381 smime_path(ps_global
->VAR_PUBLICCERT_DIR
, pathcert
, sizeof(pathcert
));
383 /* BUG: this does not support local containers */
384 load_key_and_cert(pathkey
, pathcert
, &keyfile
, &certfile
, &pkey
, &pcert
);
386 if(certfile
&& keyfile
){
387 build_path(fpath
, pathdir
, keyfile
, sizeof(fpath
));
388 strncat(fpath
, ".key", 4);
389 fpath
[sizeof(fpath
)-1] = '\0';
391 build_path(fpath2
, pathkey
, keyfile
, sizeof(fpath
));
392 strncat(fpath2
, ".key", 4);
393 fpath2
[sizeof(fpath2
)-1] = '\0';
395 if(our_copy(fpath
, fpath2
) == 0)
401 build_path(fpath
, pathdir
, certfile
, sizeof(fpath
));
402 build_path(fpath2
, pathcert
, certfile
, sizeof(fpath2
));
404 if(our_copy(fpath
, fpath2
) == 0)
410 if(keyfile
&& certfile
){
411 pc
= (PERSONAL_CERT
*) fs_get(sizeof(PERSONAL_CERT
));
412 memset((void *)pc
, 0, sizeof(PERSONAL_CERT
));
416 *pwdcert
= (void *) pc
;
417 fs_give((void **)&certfile
);
421 /* TODO: create self signed certificate
422 q_status_message(SM_ORDER, 2, 2,
423 _("No key/certificate pair found for password file encryption support"));
429 #endif /* PASSFILE */
431 /* smime_expunge_cert.
432 * Return values: < 0 there was an error.
433 * >=0 the number of messages expunged
436 smime_expunge_cert(WhichCerts ctype
)
439 CertList
*cl
, *dummy
, *data
;
440 char *path
, buf
[MAXPATH
+1];
443 if(DATACERT(ctype
)== NULL
)
446 /* data cert is the way we unify certificate management across
447 * functions, but it is not where we really save the information in the
448 * case ctype is equal to Private. What we will do is to update the
449 * datacert, and in the case of ctype equal to Private use the updated
450 * certdata to update the personal_certs data.
453 path
= PATHCERTDIR(ctype
);
456 /* add a fake certificate at the beginning of the list */
457 dummy
= fs_get(sizeof(CertList
));
458 memset((void *)dummy
, 0, sizeof(CertList
));
459 dummy
->next
= DATACERT(ctype
);
461 for(cl
= dummy
, count
= 0; cl
&& cl
->next
;){
462 if(cl
->next
->data
.deleted
== 0){
467 removed
= 1; /* assume success */
468 if(SMHOLDERTYPE(ctype
) == Directory
){
469 build_path(buf
, path
, cl
->next
->name
, sizeof(buf
));
470 if(ctype
== Private
&& strlen(buf
) + strlen(EXTCERT(Private
)) < sizeof(buf
)){
471 strncat(buf
, EXTCERT(Private
), 4);
472 buf
[sizeof(buf
)-1] = '\0';
475 if(our_unlink(buf
) < 0){
476 q_status_message1(SM_ORDER
, 3, 3, _("Error removing certificate %s"), cl
->next
->name
);
481 else if(SMHOLDERTYPE(ctype
) == Container
){
482 char *prefix
= ctype
== CACert
? CACERTSTORELEADER
: EMAILADDRLEADER
;
483 char tmp
[MAILTMPLEN
], *s
, *t
;
485 contents
= CONTENTCERTLIST(ctype
);
486 snprintf(tmp
, sizeof(tmp
), "%s%s", prefix
, cl
->next
->name
);
487 tmp
[sizeof(tmp
) - 1] = '\0';
488 if((s
= strstr(contents
, tmp
)) != NULL
){
489 if((t
= strstr(s
+strlen(tmp
), prefix
)) == NULL
)
492 memmove(s
, t
, strlen(t
)+1);
493 fs_resize((void **)&contents
, strlen(contents
)+1);
495 case Private
: ps_global
->smime
->privatecontent
= contents
; break;
496 case Public
: ps_global
->smime
->publiccontent
= contents
; break;
497 case CACert
: ps_global
->smime
->cacontent
= contents
; break;
503 } else { /* unhandled case */
507 count
++; /* count it! */
509 cl
->next
= data
->next
;
510 if(data
->name
) fs_give((void **)&data
->name
);
511 fs_give((void **)&data
);
515 q_status_message(SM_ORDER
, 3, 3, _("Error expunging certificate"));
518 case Private
: ps_global
->smime
->privatecertlist
= dummy
->next
; break;
519 case Public
: ps_global
->smime
->publiccertlist
= dummy
->next
; break;
520 case CACert
: ps_global
->smime
->cacertlist
= dummy
->next
; break;
523 fs_give((void **)&dummy
);
524 if(SMHOLDERTYPE(ctype
) == Container
){
525 if(copy_dir_to_container(ctype
, contents
) < 0)
529 q_status_message2(SM_ORDER
, 3, 3, _("Removed %s certificate%s"), comatose(count
), plural(count
));
532 q_status_message(SM_ORDER
, 3, 3, _("Error: No certificates were removed"));
537 mark_cert_deleted(WhichCerts ctype
, int num
, unsigned state
)
542 for(cl
= DATACERT(ctype
), i
= 0; cl
!= NULL
&& i
< num
; cl
= cl
->next
, i
++);
543 cl
->data
.deleted
= state
;
547 get_cert_deleted(WhichCerts ctype
, int num
)
552 for(cl
= DATACERT(ctype
), i
= 0; cl
!= NULL
&& i
< num
; cl
= cl
->next
, i
++);
553 return (cl
&& cl
->data
.deleted
) ? 1 : 0;
557 load_pkey_with_prompt(char *fpath
, char *text
, char *prompt
, int *ret
)
560 int rc
= 0; /* rc == 1, cancel, rc == 0 success */
561 char pass
[MAILTMPLEN
+1];
564 /* attempt to load with empty password */
565 in
= text
? BIO_new_mem_buf(text
, strlen(text
)) : BIO_new_file(fpath
, "r");
567 pkey
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, "");
568 if(pkey
!= NULL
) return pkey
;
571 if(pith_smime_enter_password
)
572 while(pkey
== NULL
&& rc
!= 1){
574 rc
= (*pith_smime_enter_password
)(prompt
, (char *)pass
, sizeof(pass
));
575 } while (rc
!=0 && rc
!=1 && rc
>0);
577 (void) BIO_reset(in
);
578 pkey
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, (char *)pass
);
583 if(ret
) *ret
= rc
== 1 ? -1 : pkey
!= NULL
? 0 : 1;
590 import_certificate(WhichCerts ctype
)
593 char filename
[MAXPATH
+1], full_filename
[MAXPATH
+1], buf
[MAXPATH
+1];
595 if(pith_smime_import_certificate
== NULL
){
596 q_status_message(SM_ORDER
, 0, 2,
597 _("import of certificates not implemented yet!"));
603 r
= (*pith_smime_import_certificate
)(filename
, full_filename
, sizeof(filename
) - 20);
605 ps_global
->mangled_screen
= 1;
609 else if (ctype
== Private
){
610 char prompt
[500], *s
, *t
;
611 EVP_PKEY
*key
= NULL
;
613 if(!ps_global
->smime
->privatecertlist
){
614 ps_global
->smime
->privatecertlist
= fs_get(sizeof(CertList
));
615 memset((void *)DATACERT(ctype
), 0, sizeof(CertList
));
618 for(s
= t
= filename
; (t
= strstr(s
, ".key")) != NULL
; s
= t
+ 1);
621 snprintf(prompt
, sizeof(prompt
), _("Enter passphrase for <%s>: "), filename
);
622 prompt
[sizeof(prompt
)-1] = '\0';
623 if((key
= load_pkey_with_prompt(full_filename
, NULL
, prompt
, NULL
)) != NULL
){
624 if(SMHOLDERTYPE(ctype
) == Directory
){
625 build_path(buf
, PATHCERTDIR(ctype
), filename
, sizeof(buf
));
626 if(strcmp(buf
+ strlen(buf
) - 4, EXTCERT(ctype
)) != 0 && strlen(buf
) + 4 < sizeof(buf
)){
627 strncat(buf
, EXTCERT(ctype
), 4);
628 buf
[sizeof(buf
)-1] = '\0';
630 rc
= our_copy(buf
, full_filename
);
632 else /* if(SMHOLDERTYPE(ctype) == Container){ */
633 rc
= add_file_to_container(ctype
, full_filename
, NULL
);
635 q_status_message(SM_ORDER
, 1, 3, _("Private key saved"));
637 q_status_message(SM_ORDER
, 1, 3, _("Error saving private key"));
638 if(ps_global
->smime
->publiccertlist
)
639 ps_global
->smime
->publiccertlist
->data
.renew
= 1;
642 q_status_message(SM_ORDER
, 1, 3, _("Problem unlocking key (not a certificate and/or wrong password)"));
643 } else if (ctype
== CACert
){
647 if((ins
= BIO_new_file(full_filename
, "r")) != NULL
){
648 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
){
649 if(SMHOLDERTYPE(ctype
) == Directory
){
650 build_path(buf
, PATHCERTDIR(ctype
), filename
, sizeof(buf
));
651 if(strcmp(buf
+ strlen(buf
) - 4, ".crt") != 0 && strlen(buf
) + 4 < sizeof(buf
)){
652 strncat(buf
, EXTCERT(ctype
), 4);
653 buf
[sizeof(buf
)-1] = '\0';
656 rc
= our_copy(buf
, full_filename
);
658 else /* if(SMHOLDERTYPE(ctype) == Container){ */
659 rc
= add_file_to_container(ctype
, full_filename
, NULL
);
661 q_status_message(SM_ORDER
, 1, 3, _("Certificate saved"));
663 q_status_message(SM_ORDER
, 1, 3, _("Error saving certificate"));
664 X509_free(cert
); /* not needed anymore */
667 q_status_message(SM_ORDER
, 1, 3, _("Error in certificate file (not a certificate?)"));
671 } else { /* ctype == Public. save certificate, but first validate that it is one */
675 if((ins
= BIO_new_file(full_filename
, "r")) != NULL
){
676 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
){
677 if(SMHOLDERTYPE(ctype
) == Directory
){
680 if((email
= get_x509_subject_email(cert
)) != NULL
){
682 for(i
= 0; email
[i
] != NULL
; i
++){
683 save_cert_for(email
[i
], cert
, Public
);
684 fs_give((void **)&email
[i
]);
686 fs_give((void **)email
);
689 save_cert_for(filename
, cert
, Public
);
691 else /* if(SMHOLDERTYPE(ctype) == Container){ */
692 add_file_to_container(ctype
, full_filename
, NULL
);
694 if(ps_global
->smime
->publiccertlist
)
695 ps_global
->smime
->publiccertlist
->data
.renew
= 1;
698 q_status_message(SM_ORDER
, 1, 3, _("Error in certificate file (not a certificate?)"));
702 if(DATACERT(ctype
)) RENEWCERT(DATACERT(ctype
)) = 1;
706 /* itype: information type to add: 0 - public, 1 - private.
707 * Memory freed by caller
710 print_private_key_information(char *email
, int itype
)
715 if(ps_global
->smime
== NULL
716 || ps_global
->smime
->personal_certs
== NULL
717 || (itype
!= 0 && itype
!= 1))
720 for(pc
= ps_global
->smime
->personal_certs
;
721 pc
!= NULL
&& strcmp(pc
->name
, email
) != 0; pc
= pc
->next
);
723 && !load_private_key(pc
)
725 && ps_global
->smime
->need_passphrase
){
726 if (*pith_opt_smime_get_passphrase
)
727 (*pith_opt_smime_get_passphrase
)();
728 load_private_key(pc
);
734 out
= BIO_new(BIO_s_mem());
735 if(itype
== 0) /* 0 means public */
736 EVP_PKEY_print_public(out
, pc
->key
, 0, NULL
);
737 else if (itype
== 1) /* 1 means private */
738 EVP_PKEY_print_private(out
, pc
->key
, 0, NULL
);
740 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
741 forget_private_keys();
747 * Forget any cached private keys
750 forget_private_keys(void)
752 PERSONAL_CERT
*pcert
;
756 dprint((9, "forget_private_keys()"));
757 if(ps_global
->smime
){
758 for(pcert
=(PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
763 EVP_PKEY_free(pcert
->key
);
768 ps_global
->smime
->entered_passphrase
= 0;
769 len
= sizeof(ps_global
->smime
->passphrase
);
770 p
= ps_global
->smime
->passphrase
;
777 /* modelled after signature_path in reply.c, but uses home dir instead of the
778 * directory where the .pinerc is located, since according to documentation,
779 * the .alpine-smime directories are subdirectories of the home directory
781 int smime_path(char *rpath
, char *fpath
, size_t len
)
785 size_t spl
= strlen(rpath
);
787 if(IS_REMOTE(rpath
)){
789 strncpy(fpath
, rpath
, len
-1);
792 else if(is_absolute_path(rpath
)){
793 strncpy(fpath
, rpath
, len
-1);
795 fnexpand(fpath
, len
);
797 else if(ps_global
->VAR_OPER_DIR
){
798 if(strlen(ps_global
->VAR_OPER_DIR
) + spl
< len
- 1)
799 build_path(fpath
, ps_global
->VAR_OPER_DIR
, rpath
, len
);
801 else if(ps_global
->home_dir
){
802 if(strlen(ps_global
->home_dir
) + spl
< len
- 1)
803 build_path(fpath
, ps_global
->home_dir
, rpath
, len
);
806 return fpath
&& *fpath
? 1 : 0;
812 * taken from openssl/apps/app_rand.c
815 app_RAND_load_file(const char *file
)
817 #define RANDBUFLEN 200
818 char buffer
[RANDBUFLEN
];
821 file
= RAND_file_name(buffer
, RANDBUFLEN
);
823 if(file
== NULL
|| !RAND_load_file(file
, -1)){
824 if(RAND_status() == 0){
825 dprint((1, "unable to load 'random state'\n"));
826 dprint((1, "This means that the random number generator has not been seeded\n"));
827 dprint((1, "with much random data.\n"));
839 * copied and fiddled from imap/src/osdep/unix/auth_ssl.c
842 openssl_extra_randomness(void)
850 /* if system doesn't have /dev/urandom */
851 if(stat ("/dev/urandom", &sbuf
)){
853 tf
= temp_nam(NULL
, NULL
);
855 strncpy(tmp
, tf
, sizeof(tmp
));
856 tmp
[sizeof(tmp
)-1] = '\0';
857 fs_give((void **) &tf
);
860 if((fd
= open(tmp
, O_WRONLY
|O_CREAT
|O_EXCL
, 0600)) < 0)
861 i
= (unsigned long) tmp
;
863 unlink(tmp
); /* don't need the file */
864 fstat(fd
, &sbuf
); /* get information about the file */
865 i
= sbuf
.st_ino
; /* remember its inode */
866 close(fd
); /* or its descriptor */
868 /* not great but it'll have to do */
869 snprintf(tmp
+strlen(tmp
), sizeof(tmp
)-strlen(tmp
), "%.80s%lx%lx%lx",
871 (unsigned long) (time (0) ^ gethostid ()),
872 (unsigned long) getpid ());
873 RAND_seed(tmp
, strlen(tmp
));
879 /* taken from openssl/apps/app_rand.c */
881 app_RAND_write_file(const char *file
)
887 * If we did not manage to read the seed file,
888 * we should not write a low-entropy seed file back --
889 * it would suppress a crucial warning the next time
895 file
= RAND_file_name(buffer
, sizeof buffer
);
897 if(file
== NULL
|| !RAND_write_file(file
)){
898 dprint((1, "unable to write 'random state'\n"));
906 certlist_from_personal_certs(PERSONAL_CERT
*pc
)
915 cl
= fs_get(sizeof(CertList
));
916 memset((void *)cl
, 0, sizeof(CertList
));
917 cl
->name
= cpystr(pc
->name
);
918 x
= get_cert_for(pc
->name
, Public
);
921 cl
->data
.date_from
= smime_get_date(x
->cert_info
->validity
->notBefore
);
922 cl
->data
.date_to
= smime_get_date(x
->cert_info
->validity
->notAfter
);
923 get_fingerprint(x
, EVP_md5(), buf
, sizeof(buf
), NULL
);
924 cl
->data
.md5
= cpystr(buf
);
928 cl
->next
= certlist_from_personal_certs(pc
->next
);
934 renew_cert_data(CertList
**data
, WhichCerts ctype
)
937 if(ctype
== Private
){
939 PERSONAL_CERT
*pc
= (PERSONAL_CERT
*)ps_global
->smime
->personal_certs
;
942 free_personal_certs(&pc
);
943 setup_privatekey_storage();
944 *data
= certlist_from_personal_certs((PERSONAL_CERT
*)ps_global
->smime
->personal_certs
);
946 resort_certificates(data
, ctype
);
947 RENEWCERT(*data
) = 0;
949 ps_global
->smime
->privatecertlist
= *data
;
951 if(ps_global
->smime
->privatecertlist
)
952 RENEWCERT(ps_global
->smime
->privatecertlist
) = 0;
954 X509_LOOKUP
*lookup
= NULL
;
955 X509_STORE
*store
= NULL
;
957 if((store
= X509_STORE_new()) != NULL
){
958 if((lookup
= X509_STORE_add_lookup(store
, X509_LOOKUP_file())) == NULL
){
959 X509_STORE_free(store
);
963 if(SMHOLDERTYPE(ctype
) == Directory
)
964 add_certs_in_dir(lookup
, PATHCERTDIR(ctype
), EXTCERT(ctype
), data
);
965 else /* if(SMHOLDERTYPE(ctype) == Container) */
966 *data
= mem_to_certlist(CONTENTCERTLIST(ctype
), ctype
);
968 resort_certificates(data
, ctype
);
969 RENEWCERT(*data
) = 0;
972 ps_global
->smime
->publiccertlist
= *data
;
974 ps_global
->smime
->cacertlist
= *data
;
978 setup_certs_backup_by_type(ctype
);
988 /* Installed as an atexit() handler to save the random data */
992 dprint((9, "smime_deinit()"));
993 app_RAND_write_file(NULL
);
994 free_smime_struct(&ps_global
->smime
);
997 /* we renew the store when it has changed */
998 void renew_store(void)
1000 if(ps_global
->smime
->inited
){
1001 if(s_cert_store
!= NULL
)
1002 X509_STORE_free(s_cert_store
);
1003 s_cert_store
= get_ca_store();
1007 /* Initialise openssl stuff if needed */
1011 if(F_OFF(F_DONT_DO_SMIME
, ps_global
) && !(ps_global
->smime
&& ps_global
->smime
->inited
)){
1013 dprint((9, "smime_init()"));
1014 if(!ps_global
->smime
)
1015 ps_global
->smime
= new_smime_struct();
1017 setup_storage_locations();
1019 s_cert_store
= get_ca_store();
1020 setup_certs_backup_by_type(CACert
);
1022 OpenSSL_add_all_algorithms();
1023 ERR_load_crypto_strings();
1025 app_RAND_load_file(NULL
);
1026 openssl_extra_randomness();
1027 ps_global
->smime
->inited
= 1;
1034 /* validate a certificate. Return value : 0 for no error, -1 for error.
1035 * In the latter case, set the openssl smime error in *error.
1037 int smime_validate_cert(X509
*cert
, long *error
)
1039 X509_STORE_CTX
*csc
;
1043 if((csc
= X509_STORE_CTX_new()) != NULL
){
1044 X509_STORE_set_flags(s_cert_store
, 0);
1045 if(X509_STORE_CTX_init(csc
,s_cert_store
,cert
,NULL
)
1046 && X509_verify_cert(csc
) <= 0)
1047 *error
= X509_STORE_CTX_get_error(csc
);
1048 X509_STORE_CTX_free(csc
);
1050 return *error
? -1 : 0;
1054 get_personal_certs(char *path
)
1056 PERSONAL_CERT
*result
= NULL
;
1061 ps_global
->smime
->privatepath
= cpystr(path
);
1062 dirp
= opendir(path
);
1064 while((d
=readdir(dirp
)) != NULL
){
1068 if((ll
=strlen(d
->d_name
)) && ll
> 4 && !strcmp(d
->d_name
+ll
-4, ".key")){
1070 /* copy file name to temp buffer */
1071 strncpy(buf2
, d
->d_name
, sizeof(buf2
)-1);
1072 buf2
[sizeof(buf2
)-1] = '\0';
1073 /* chop off ".key" trailier */
1074 buf2
[strlen(buf2
)-4] = 0;
1075 /* Look for certificate */
1076 cert
= get_cert_for(buf2
, Public
);
1081 /* create a new PERSONAL_CERT, fill it in */
1083 pc
= (PERSONAL_CERT
*) fs_get(sizeof(*pc
));
1085 pc
->name
= cpystr(buf2
);
1087 /* Try to load the key with an empty password */
1088 pc
->key
= load_key(pc
, "", SM_NORMALCERT
);
1102 setup_privatekey_storage(void)
1104 char path
[MAXPATH
+1], *contents
;
1105 int privatekeycontainer
= 0;
1107 /* private keys in a container */
1108 if(ps_global
->VAR_PRIVATEKEY_CONTAINER
&& ps_global
->VAR_PRIVATEKEY_CONTAINER
[0]){
1110 privatekeycontainer
= 1;
1113 if(!smime_path(ps_global
->VAR_PRIVATEKEY_CONTAINER
, path
, MAXPATH
))
1114 privatekeycontainer
= 0;
1116 if(privatekeycontainer
&& !IS_REMOTE(path
)
1117 && ps_global
->VAR_OPER_DIR
1118 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
1119 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1120 /* TRANSLATORS: First arg is the directory name, second is
1121 the file user wants to read but can't. */
1122 _("Can't read file outside %s: %s"),
1123 ps_global
->VAR_OPER_DIR
, path
);
1124 privatekeycontainer
= 0;
1127 if(privatekeycontainer
1128 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
1129 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
1131 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
1132 privatekeycontainer
= 0;
1135 if(privatekeycontainer
&& path
[0]){
1136 ps_global
->smime
->privatetype
= Container
;
1137 ps_global
->smime
->privatepath
= cpystr(path
);
1140 ps_global
->smime
->privatecontent
= contents
;
1141 ps_global
->smime
->personal_certs
= mem_to_personal_certs(contents
);
1146 /* private keys in a directory of files */
1147 if(!privatekeycontainer
){
1148 ps_global
->smime
->privatetype
= Directory
;
1151 if(!(smime_path(ps_global
->VAR_PRIVATEKEY_DIR
, path
, MAXPATH
)
1152 && !IS_REMOTE(path
)))
1153 ps_global
->smime
->privatetype
= Nada
;
1154 else if(can_access(path
, ACCESS_EXISTS
)){
1155 if(our_mkpath(path
, 0700)){
1156 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1157 ps_global
->smime
->privatetype
= Nada
;
1161 if(ps_global
->smime
->privatetype
== Directory
)
1162 ps_global
->smime
->personal_certs
= get_personal_certs(path
);
1164 setup_certs_backup_by_type(Private
);
1170 setup_storage_locations(void)
1172 int publiccertcontainer
= 0, cacertcontainer
= 0;
1173 char path
[MAXPATH
+1], *contents
;
1175 if(!ps_global
->smime
)
1178 #ifdef APPLEKEYCHAIN
1179 if(F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
1180 ps_global
->smime
->publictype
= Keychain
;
1183 #endif /* APPLEKEYCHAIN */
1184 /* Public certificates in a container */
1185 if(ps_global
->VAR_PUBLICCERT_CONTAINER
&& ps_global
->VAR_PUBLICCERT_CONTAINER
[0]){
1187 publiccertcontainer
= 1;
1190 if(!smime_path(ps_global
->VAR_PUBLICCERT_CONTAINER
, path
, MAXPATH
))
1191 publiccertcontainer
= 0;
1193 if(publiccertcontainer
&& !IS_REMOTE(path
)
1194 && ps_global
->VAR_OPER_DIR
1195 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
1196 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1197 /* TRANSLATORS: First arg is the directory name, second is
1198 the file user wants to read but can't. */
1199 _("Can't read file outside %s: %s"),
1200 ps_global
->VAR_OPER_DIR
, path
);
1201 publiccertcontainer
= 0;
1204 if(publiccertcontainer
1205 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
1206 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
1208 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
1209 publiccertcontainer
= 0;
1212 if(publiccertcontainer
&& path
[0]){
1213 ps_global
->smime
->publictype
= Container
;
1214 ps_global
->smime
->publicpath
= cpystr(path
);
1217 ps_global
->smime
->publiccontent
= contents
;
1218 ps_global
->smime
->publiccertlist
= mem_to_certlist(contents
, Public
);
1223 /* Public certificates in a directory of files */
1224 if(!publiccertcontainer
){
1225 ps_global
->smime
->publictype
= Directory
;
1228 if(!(smime_path(ps_global
->VAR_PUBLICCERT_DIR
, path
, MAXPATH
)
1229 && !IS_REMOTE(path
)))
1230 ps_global
->smime
->publictype
= Nada
;
1231 else if(can_access(path
, ACCESS_EXISTS
)){
1232 if(our_mkpath(path
, 0700)){
1233 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1234 ps_global
->smime
->publictype
= Nada
;
1238 if(ps_global
->smime
->publictype
== Directory
)
1239 ps_global
->smime
->publicpath
= cpystr(path
);
1242 #ifdef APPLEKEYCHAIN
1244 #endif /* APPLEKEYCHAIN */
1246 setup_privatekey_storage();
1248 /* extra cacerts in a container */
1249 if(ps_global
->VAR_CACERT_CONTAINER
&& ps_global
->VAR_CACERT_CONTAINER
[0]){
1251 cacertcontainer
= 1;
1254 if(!smime_path(ps_global
->VAR_CACERT_CONTAINER
, path
, MAXPATH
))
1255 cacertcontainer
= 0;
1257 if(cacertcontainer
&& !IS_REMOTE(path
)
1258 && ps_global
->VAR_OPER_DIR
1259 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
1260 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1261 /* TRANSLATORS: First arg is the directory name, second is
1262 the file user wants to read but can't. */
1263 _("Can't read file outside %s: %s"),
1264 ps_global
->VAR_OPER_DIR
, path
);
1265 cacertcontainer
= 0;
1269 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
1270 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
1272 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
1273 cacertcontainer
= 0;
1276 if(cacertcontainer
&& path
[0]){
1277 ps_global
->smime
->catype
= Container
;
1278 ps_global
->smime
->capath
= cpystr(path
);
1279 ps_global
->smime
->cacontent
= contents
;
1281 ps_global
->smime
->cacertlist
= mem_to_certlist(contents
, CACert
);
1285 if(!cacertcontainer
){
1286 ps_global
->smime
->catype
= Directory
;
1289 if(!(smime_path(ps_global
->VAR_CACERT_DIR
, path
, MAXPATH
)
1290 && !IS_REMOTE(path
)))
1291 ps_global
->smime
->catype
= Nada
;
1292 else if(can_access(path
, ACCESS_EXISTS
)){
1293 if(our_mkpath(path
, 0700)){
1294 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1295 ps_global
->smime
->catype
= Nada
;
1299 if(ps_global
->smime
->catype
== Directory
)
1300 ps_global
->smime
->capath
= cpystr(path
);
1306 copy_publiccert_dir_to_container(void)
1308 return(copy_dir_to_container(Public
, NULL
));
1313 copy_publiccert_container_to_dir(void)
1315 return(copy_container_to_dir(Public
));
1320 copy_privatecert_dir_to_container(void)
1322 return(copy_dir_to_container(Private
, NULL
));
1327 copy_privatecert_container_to_dir(void)
1329 return(copy_container_to_dir(Private
));
1334 copy_cacert_dir_to_container(void)
1336 return(copy_dir_to_container(CACert
, NULL
));
1341 copy_cacert_container_to_dir(void)
1343 return(copy_container_to_dir(CACert
));
1346 /* Add the contents of a file to a container. Do not check the content
1347 * of the file, just add it using the format for that container. The
1348 * caller must check the format, so that there is no data corruption
1350 * return value: 0 - success,
1354 add_file_to_container(WhichCerts ctype
, char *fpath
, char *altname
)
1356 char *sep
= (ctype
== Public
|| ctype
== Private
)
1357 ? EMAILADDRLEADER
: CACERTSTORELEADER
;
1358 char *content
= ctype
== Public
? ps_global
->smime
->publiccontent
1359 : (ctype
== Private
? ps_global
->smime
->privatecontent
1360 : ps_global
->smime
->cacontent
);
1366 int rv
= -1; /* assume error */
1368 if(our_stat(fpath
, &sbuf
) < 0
1369 || (in
= so_get(FileStar
, fpath
, READ_ACCESS
| READ_FROM_LOCALE
)) == NULL
)
1374 else if((name
= strrchr(fpath
, '/')) != NULL
){
1376 if((ll
= strlen(++name
)) > 4 && strucmp(name
+ ll
- 4, EXTCERT(ctype
)) == 0)
1377 name
[ll
-strlen(EXTCERT(ctype
))] = '\0';
1383 fs_resize((void **)&content
, strlen(content
) + strlen(sep
) + strlen(name
) + sbuf
.st_size
+ 3); /* 2 = \n + \n + \0*/
1385 content
+= strlen(content
);
1388 s
= content
= fs_get(strlen(sep
) + strlen(name
) + sbuf
.st_size
+ 1); /* 2 = \n + \0 */
1391 strncat(content
, sep
, strlen(sep
));
1392 strncat(content
, name
, strlen(name
));
1393 content
+= strlen(content
);
1396 while(so_readc(&c
, in
))
1397 *content
++ = (char) c
;
1401 case Private
: ps_global
->smime
->privatecontent
= s
; break;
1402 case Public
: ps_global
->smime
->publiccontent
= s
; break;
1403 case CACert
: ps_global
->smime
->cacontent
= s
; break;
1407 rv
= copy_dir_to_container(ctype
, s
);
1410 if(in
) so_give(&in
);
1417 * returns 0 on success, -1 on failure
1418 * contents is an argument which tells this function to write the value
1419 * of this variable instead of reading the contents of the directory.
1420 * If the var contents is not null use its value as the value of the
1424 copy_dir_to_container(WhichCerts which
, char *contents
)
1426 int ret
= 0, container
= 0;
1427 BIO
*bio_out
= NULL
, *bio_in
= NULL
;
1428 char srcpath
[MAXPATH
+1], dstpath
[MAXPATH
+1], emailaddr
[MAXPATH
], file
[MAXPATH
], line
[4096];
1429 char *tempfile
= NULL
, fpath
[MAXPATH
+1];
1432 REMDATA_S
*rd
= NULL
;
1433 char *configdir
= NULL
;
1434 char *configpath
= NULL
;
1435 char *configcontainer
= NULL
;
1436 char *filesuffix
= NULL
;
1437 char *ret_dir
= NULL
;
1439 dprint((9, "copy_dir_to_container(%s)", which
==Public
? "Public" : which
==Private
? "Private" : which
==CACert
? "CACert" : "?"));
1445 emailaddr
[0] = '\0';
1447 if(which
== Public
){
1448 configdir
= ps_global
->VAR_PUBLICCERT_DIR
;
1449 configpath
= ps_global
->smime
->publicpath
;
1450 configcontainer
= cpystr(DF_PUBLIC_CONTAINER
);
1451 filesuffix
= ".crt";
1453 else if(which
== Private
){
1454 configdir
= ps_global
->VAR_PRIVATEKEY_DIR
;
1455 configpath
= ps_global
->smime
->privatepath
;
1456 configcontainer
= cpystr(DF_PRIVATE_CONTAINER
);
1457 filesuffix
= ".key";
1459 else if(which
== CACert
){
1460 configdir
= ps_global
->VAR_CACERT_DIR
;
1461 configpath
= ps_global
->smime
->capath
;
1462 configcontainer
= cpystr(DF_CA_CONTAINER
);
1463 filesuffix
= ".crt";
1465 container
= SMHOLDERTYPE(which
) == Container
;
1467 if(!(configdir
&& configdir
[0])){
1468 q_status_message(SM_ORDER
, 3, 3, _("Directory not defined"));
1472 if(!(configpath
&& configpath
[0])){
1473 #ifdef APPLEKEYCHAIN
1474 if(which
== Public
&& F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
1475 q_status_message(SM_ORDER
, 3, 3, _("Turn off the Keychain feature above first"));
1478 #endif /* APPLEKEYCHAIN */
1479 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1483 if(!(filesuffix
&& strlen(filesuffix
) == 4)){
1489 * If there is a legit directory to read from set up the
1490 * container file to write to.
1492 if(smime_path(configdir
, srcpath
, MAXPATH
) && !IS_REMOTE(srcpath
)){
1494 if(IS_REMOTE(configpath
)){
1495 rd
= rd_create_remote(RemImap
, configpath
, REMOTE_SMIME_SUBTYPE
,
1497 _("Can't access remote smime configuration."));
1501 (void) rd_read_metadata(rd
);
1503 if(rd
->access
== MaybeRorW
){
1504 if(rd
->read_status
== 'R')
1505 rd
->access
= ReadOnly
;
1507 rd
->access
= ReadWrite
;
1510 if(rd
->access
!= NoExists
){
1512 rd_check_remvalid(rd
, 1L);
1515 * If the cached info says it is readonly but
1516 * it looks like it's been fixed now, change it to readwrite.
1518 if(rd
->read_status
== 'R'){
1519 rd_check_readonly_access(rd
);
1520 if(rd
->read_status
== 'W'){
1521 rd
->access
= ReadWrite
;
1522 rd
->flags
|= REM_OUTOFDATE
;
1525 rd
->access
= ReadOnly
;
1529 if(rd
->flags
& REM_OUTOFDATE
){
1530 if(rd_update_local(rd
) != 0){
1532 dprint((1, "copy_dir_to_container: rd_update_local failed\n"));
1533 rd_close_remdata(&rd
);
1540 if(rd
->access
!= ReadWrite
|| rd_remote_is_readonly(rd
)){
1541 rd_close_remdata(&rd
);
1545 rd
->flags
|= DO_REMTRIM
;
1547 strncpy(dstpath
, rd
->lf
, sizeof(dstpath
)-1);
1548 dstpath
[sizeof(dstpath
)-1] = '\0';
1551 strncpy(dstpath
, configpath
, sizeof(dstpath
)-1);
1552 dstpath
[sizeof(dstpath
)-1] = '\0';
1556 * dstpath is either the local Container file or the local cache file
1557 * for the remote Container file.
1559 tempfile
= tempfile_in_same_dir(dstpath
, "az", &ret_dir
);
1563 * If there is a legit directory to read from and a tempfile
1564 * to write to we continue.
1566 if(tempfile
&& (bio_out
=BIO_new_file(tempfile
, "w")) != NULL
){
1568 if(contents
!= NULL
){
1569 if(BIO_puts(bio_out
, contents
) < 0)
1573 if((dirp
= opendir(srcpath
)) != NULL
){
1575 while((d
=readdir(dirp
)) && !ret
){
1578 if((ll
=strlen(d
->d_name
)) && ll
> 4 && !strcmp(d
->d_name
+ll
-4, filesuffix
)){
1580 /* copy file name to temp buffer */
1581 strncpy(emailaddr
, d
->d_name
, sizeof(emailaddr
)-1);
1582 emailaddr
[sizeof(emailaddr
)-1] = '\0';
1583 /* chop off suffix trailier */
1584 emailaddr
[strlen(emailaddr
)-4] = 0;
1587 * This is the separator between the contents of
1590 if(which
== CACert
){
1591 if(!((BIO_puts(bio_out
, CACERTSTORELEADER
) > 0)
1592 && (BIO_puts(bio_out
, emailaddr
) > 0)
1593 && (BIO_puts(bio_out
, "\n") > 0)))
1597 if(!((BIO_puts(bio_out
, EMAILADDRLEADER
) > 0)
1598 && (BIO_puts(bio_out
, emailaddr
) > 0)
1599 && (BIO_puts(bio_out
, "\n") > 0)))
1603 /* read then write contents of file */
1604 build_path(file
, srcpath
, d
->d_name
, sizeof(file
));
1605 if(!(bio_in
= BIO_new_file(file
, "r")))
1611 while(BIO_gets(bio_in
, line
, sizeof(line
)) > 0){
1612 if(strncmp("-----BEGIN", line
, strlen("-----BEGIN")) == 0)
1616 BIO_puts(bio_out
, line
);
1618 if(strncmp("-----END", line
, strlen("-----END")) == 0)
1634 if(container
&& configpath
&& *configpath
){
1635 strncpy(fpath
, configpath
, sizeof(fpath
));
1636 fpath
[sizeof(fpath
) - 1] = '\0';
1639 if(strlen(dstpath
) + strlen(configcontainer
) - strlen(ret_dir
) + 1 < sizeof(dstpath
))
1640 snprintf(fpath
, sizeof(fpath
), "%s%c%s",
1641 dstpath
, tempfile
[strlen(ret_dir
)], configcontainer
);
1648 if(rename_file(tempfile
, fpath
) < 0){
1649 q_status_message2(SM_ORDER
, 3, 3,
1650 _("Can't rename %s to %s"), tempfile
, fpath
);
1652 } else q_status_message1(SM_ORDER
, 3, 3,
1653 _("saved container to %s"), fpath
);
1656 /* if the container is remote, copy it */
1657 if(!ret
&& IS_REMOTE(configpath
)){
1663 if((e
= rd_update_remote(rd
, datebuf
)) != 0){
1665 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1666 _("Error opening temporary smime file %s: %s"),
1667 rd
->lf
, error_description(errno
));
1669 "write_remote_smime: error opening temp file %s\n",
1670 rd
->lf
? rd
->lf
: "?"));
1673 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1674 _("Error copying to %s: %s"),
1675 rd
->rn
, error_description(errno
));
1677 "write_remote_smime: error copying from %s to %s\n",
1678 rd
->lf
? rd
->lf
: "?", rd
->rn
? rd
->rn
: "?"));
1681 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
1682 _("Copy of smime key to remote folder failed, NOT saved remotely"));
1685 rd_update_metadata(rd
, datebuf
);
1686 rd
->read_status
= 'W';
1689 rd_close_remdata(&rd
);
1695 fs_give((void **) &tempfile
);
1698 fs_give((void **) &ret_dir
);
1701 fs_give((void **) &configcontainer
);
1708 * returns 0 on success, -1 on failure
1711 copy_container_to_dir(WhichCerts which
)
1713 char path
[MAXPATH
+1], file
[MAXPATH
+1], buf
[MAXPATH
+1];
1715 char *contents
= NULL
;
1716 char *leader
= NULL
;
1717 char *filesuffix
= NULL
;
1718 char *configdir
= NULL
;
1719 char *configpath
= NULL
;
1720 char *tempfile
= NULL
;
1721 char *p
, *q
, *line
, *name
, *certtext
, *save_p
;
1725 dprint((9, "copy_container_to_dir(%s)", which
==Public
? "Public" : which
==Private
? "Private" : which
==CACert
? "CACert" : "?"));
1730 if(which
== Public
){
1731 leader
= EMAILADDRLEADER
;
1732 contents
= ps_global
->smime
->publiccontent
;
1733 configdir
= ps_global
->VAR_PUBLICCERT_DIR
;
1734 configpath
= ps_global
->smime
->publicpath
;
1735 filesuffix
= ".crt";
1736 if(!(configpath
&& configpath
[0])){
1737 #ifdef APPLEKEYCHAIN
1738 if(which
== Public
&& F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
1739 q_status_message(SM_ORDER
, 3, 3, _("Turn off the Keychain feature above first"));
1742 #endif /* APPLEKEYCHAIN */
1743 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1747 fs_give((void **) &ps_global
->smime
->publicpath
);
1750 if(!(smime_path(ps_global
->VAR_PUBLICCERT_DIR
, path
, MAXPATH
)
1751 && !IS_REMOTE(path
))){
1752 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
1756 if(can_access(path
, ACCESS_EXISTS
)){
1757 if(our_mkpath(path
, 0700)){
1758 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1763 ps_global
->smime
->publicpath
= cpystr(path
);
1764 configpath
= ps_global
->smime
->publicpath
;
1766 else if(which
== Private
){
1767 leader
= EMAILADDRLEADER
;
1768 contents
= ps_global
->smime
->privatecontent
;
1769 configdir
= ps_global
->VAR_PRIVATEKEY_DIR
;
1770 configpath
= ps_global
->smime
->privatepath
;
1771 filesuffix
= ".key";
1772 if(!(configpath
&& configpath
[0])){
1773 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1777 fs_give((void **) &ps_global
->smime
->privatepath
);
1780 if(!(smime_path(ps_global
->VAR_PRIVATEKEY_DIR
, path
, MAXPATH
)
1781 && !IS_REMOTE(path
))){
1782 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
1786 if(can_access(path
, ACCESS_EXISTS
)){
1787 if(our_mkpath(path
, 0700)){
1788 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1793 ps_global
->smime
->privatepath
= cpystr(path
);
1794 configpath
= ps_global
->smime
->privatepath
;
1796 else if(which
== CACert
){
1797 leader
= CACERTSTORELEADER
;
1798 contents
= ps_global
->smime
->cacontent
;
1799 configdir
= ps_global
->VAR_CACERT_DIR
;
1800 configpath
= ps_global
->smime
->capath
;
1801 filesuffix
= ".crt";
1802 if(!(configpath
&& configpath
[0])){
1803 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1807 fs_give((void **) &ps_global
->smime
->capath
);
1810 if(!(smime_path(ps_global
->VAR_CACERT_DIR
, path
, MAXPATH
)
1811 && !IS_REMOTE(path
))){
1812 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
1816 if(can_access(path
, ACCESS_EXISTS
)){
1817 if(our_mkpath(path
, 0700)){
1818 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1823 ps_global
->smime
->capath
= cpystr(path
);
1824 configpath
= ps_global
->smime
->capath
;
1827 if(!(configdir
&& configdir
[0])){
1828 q_status_message(SM_ORDER
, 3, 3, _("Directory not defined"));
1832 if(!(configpath
&& configpath
[0])){
1833 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1837 if(!(filesuffix
&& strlen(filesuffix
) == 4)){
1842 if(contents
&& *contents
){
1843 for(p
= contents
; *p
!= '\0';){
1846 while(*p
&& *p
!= '\n')
1855 if(strncmp(leader
, line
, strlen(leader
)) == 0){
1856 name
= line
+ strlen(leader
);
1858 if(strncmp("-----BEGIN", certtext
, strlen("-----BEGIN")) == 0){
1859 if((q
= strstr(certtext
, leader
)) != NULL
){
1862 else{ /* end of file */
1863 q
= certtext
+ strlen(certtext
);
1867 strncpy(buf
, name
, sizeof(buf
)-5);
1868 buf
[sizeof(buf
)-5] = '\0';
1869 strncat(buf
, filesuffix
, 5);
1870 build_path(file
, configpath
, buf
, sizeof(file
));
1872 in
= BIO_new_mem_buf(certtext
, q
-certtext
);
1874 tempfile
= tempfile_in_same_dir(file
, "az", NULL
);
1877 out
= BIO_new_file(tempfile
, "w");
1880 while((len
= BIO_read(in
, iobuf
, sizeof(iobuf
))) > 0)
1881 BIO_write(out
, iobuf
, len
);
1885 if(rename_file(tempfile
, file
) < 0){
1886 q_status_message2(SM_ORDER
, 3, 3,
1887 _("Can't rename %s to %s"),
1892 fs_give((void **) &tempfile
);
1909 #ifdef APPLEKEYCHAIN
1912 copy_publiccert_container_to_keychain(void)
1914 /* NOT IMPLEMNTED */
1919 copy_publiccert_keychain_to_container(void)
1921 /* NOT IMPLEMNTED */
1925 #endif /* APPLEKEYCHAIN */
1929 * Get a pointer to a string describing the most recent OpenSSL error.
1930 * It's statically allocated, so don't change or attempt to free it.
1933 openssl_error_string(void)
1936 const char *data
= NULL
;
1939 errn
= ERR_peek_error_line_data(NULL
, NULL
, &data
, NULL
);
1940 errs
= (char*) ERR_reason_error_string(errn
);
1947 return "unknown error";
1951 /* Return true if the body looks like a PKCS7 object */
1953 is_pkcs7_body(BODY
*body
)
1957 result
= body
->type
==TYPEAPPLICATION
&&
1959 (strucmp(body
->subtype
,"pkcs7-mime")==0 ||
1960 strucmp(body
->subtype
,"x-pkcs7-mime")==0 ||
1961 strucmp(body
->subtype
,"pkcs7-signature")==0 ||
1962 strucmp(body
->subtype
,"x-pkcs7-signature")==0);
1969 * Recursively stash a pointer to the decrypted data in our
1970 * manufactured body.
1971 * parameters: type: call of type 1, save the base and header for multipart messages
1972 call of type 0, do not save the base and header for multipart messages
1975 create_local_cache(char *h
, char *base
, BODY
*b
, int type
)
1977 if(b
->type
==TYPEMULTIPART
){
1981 cpytxt(&b
->mime
.text
, h
+b
->mime
.offset
, b
->mime
.text
.size
);
1982 cpytxt(&b
->contents
.text
, base
+ b
->contents
.offset
, b
->size
.bytes
);
1983 } else if(type
== 0){
1985 * We don't really want to copy the real body contents. It shouldn't be
1986 * used, and in the case of a message with attachments, we'll be
1987 * duplicating the files multiple times.
1989 cpytxt(&b
->contents
.text
, "BODY UNAVAILABLE", 16);
1991 for(p
=b
->nested
.part
; p
; p
=p
->next
)
1992 create_local_cache(h
, base
, (BODY
*) p
, type
);
1996 cpytxt(&b
->mime
.text
, h
+b
->mime
.offset
, b
->mime
.text
.size
);
1997 cpytxt(&b
->contents
.text
, base
+ b
->contents
.offset
, b
->size
.bytes
);
2003 rfc822_output_func(void *b
, char *string
)
2005 BIO
*bio
= (BIO
*) b
;
2007 return(string
? *string
? (BIO_puts(bio
, string
) > 0 ? 1L : 0L)
2008 : (BIO_puts(bio
, string
) >= 0 ? 1L : 0L)
2014 * Attempt to load the private key for the given PERSONAL_CERT.
2015 * This sets the appropriate passphrase globals in order to
2016 * interact with the user correctly.
2019 load_private_key(PERSONAL_CERT
*pcert
)
2023 /* Try empty password by default */
2024 char *password
= "";
2027 && (ps_global
->smime
->need_passphrase
2028 || ps_global
->smime
->entered_passphrase
)){
2029 /* We've already been in here and discovered we need a different password */
2031 if(ps_global
->smime
->entered_passphrase
)
2032 password
= (char *) ps_global
->smime
->passphrase
; /* already entered */
2039 if(!(pcert
->key
= load_key(pcert
, password
, SM_NORMALCERT
))){
2040 long err
= ERR_get_error();
2042 /* Couldn't load key... */
2044 if(ps_global
->smime
&& ps_global
->smime
->entered_passphrase
){
2046 /* The user got the password wrong maybe? */
2048 if((ERR_GET_LIB(err
)==ERR_LIB_EVP
&& ERR_GET_REASON(err
)==EVP_R_BAD_DECRYPT
) ||
2049 (ERR_GET_LIB(err
)==ERR_LIB_PEM
&& ERR_GET_REASON(err
)==PEM_R_BAD_DECRYPT
))
2050 q_status_message(SM_ORDER
| SM_DING
, 4, 4, _("Incorrect passphrase"));
2052 q_status_message1(SM_ORDER
, 4, 4, _("Couldn't read key: %s"),(char*)openssl_error_string());
2054 /* This passphrase is no good; forget it */
2055 ps_global
->smime
->entered_passphrase
= 0;
2058 if(ps_global
->smime
){
2059 /* Indicate to the UI that we need re-entry (see mailcmd.c:process_cmd())*/
2060 ps_global
->smime
->need_passphrase
= 1;
2061 if(ps_global
->smime
->passphrase_emailaddr
){
2063 for(i
= 0; ps_global
->smime
->passphrase_emailaddr
[i
] != NULL
; i
++)
2064 fs_give((void **)&ps_global
->smime
->passphrase_emailaddr
[i
]);
2065 fs_give((void **) ps_global
->smime
->passphrase_emailaddr
);
2068 ps_global
->smime
->passphrase_emailaddr
= get_x509_subject_email(pcert
->cert
);
2074 /* This key will be cached, so we won't be called again */
2075 if(ps_global
->smime
){
2076 ps_global
->smime
->entered_passphrase
= 0;
2077 ps_global
->smime
->need_passphrase
= 0;
2089 setup_pkcs7_body_for_signature(BODY
*b
, char *description
, char *type
, char *filename
, char *smime_type
)
2091 b
->type
= TYPEAPPLICATION
;
2092 b
->subtype
= cpystr(type
);
2093 b
->encoding
= ENCBINARY
;
2094 b
->description
= cpystr(description
);
2096 b
->disposition
.type
= cpystr("attachment");
2097 set_parameter(&b
->disposition
.parameter
, "filename", filename
);
2099 set_parameter(&b
->parameter
, "name", filename
);
2100 if(smime_type
&& *smime_type
)
2101 set_parameter(&b
->parameter
, "smime-type", smime_type
);
2106 * Look for a personal certificate matching the
2110 match_personal_cert_to_email(ADDRESS
*a
)
2112 PERSONAL_CERT
*pcert
= NULL
;
2117 if(!a
|| !a
->mailbox
|| !a
->host
)
2120 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
2122 if(ps_global
->smime
){
2123 for(pcert
=(PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
2130 email
= get_x509_subject_email(pcert
->cert
);
2134 for(i
= 0; email
[i
] && strucmp(email
[i
], buf
) != 0; i
++);
2135 if(email
[i
] != NULL
) done
++;
2136 for(i
= 0; email
[i
] != NULL
; i
++)
2137 fs_give((void **)&email
[i
]);
2138 fs_give((void **)email
);
2151 * Look for a personal certificate matching the from
2152 * (or reply_to? in the given envelope)
2155 match_personal_cert(ENVELOPE
*env
)
2157 PERSONAL_CERT
*pcert
;
2159 pcert
= match_personal_cert_to_email(env
->reply_to
);
2161 pcert
= match_personal_cert_to_email(env
->from
);
2168 * Flatten the given body into its MIME representation.
2169 * Return the result in a BIO.
2172 body_to_bio(BODY
*body
)
2177 bio
= BIO_new(BIO_s_mem());
2181 pine_encode_body(body
); /* this attaches random boundary strings to multiparts */
2182 pine_write_body_header(body
, rfc822_output_func
, bio
);
2183 pine_rfc822_output_body(body
, rfc822_output_func
, bio
);
2186 * Now need to truncate by two characters since the above
2189 if((len
=BIO_ctrl_pending(bio
)) > 1){
2190 BUF_MEM
*biobuf
= NULL
;
2192 BIO_get_mem_ptr(bio
, &biobuf
);
2194 BUF_MEM_grow(biobuf
, len
-2); /* remove CRLF */
2203 bio_from_store(STORE_S
*store
)
2207 if(store
&& store
->src
== BioType
&& store
->txt
){
2208 ret
= (BIO
*) store
->txt
;
2215 * Encrypt file; given a path (char *) fp, replace the file
2216 * by an encrypted version of it. If (char *) text is not null, then
2217 * replace the text of (char *) fp by the encrypted version of (char *) text.
2218 * certpath is the FULL path to the file containing the certificate used for
2222 encrypt_file(char *fp
, char *text
, PERSONAL_CERT
*pc
)
2224 const EVP_CIPHER
*cipher
= NULL
;
2225 STACK_OF(X509
) *encerts
= NULL
;
2233 cipher
= EVP_aes_256_cbc();
2234 encerts
= sk_X509_new_null();
2236 sk_X509_push(encerts
, X509_dup(pc
->cert
));
2239 if((out
= BIO_new(BIO_s_mem())) == NULL
)
2241 (void) BIO_reset(out
);
2242 BIO_puts(out
, text
);
2245 if(!(out
= BIO_new_file(fp
, "rb")))
2248 BIO_read_filename(out
, fp
);
2251 if((p7
= PKCS7_encrypt(encerts
, out
, cipher
, 0)) == NULL
)
2253 BIO_set_close(out
, BIO_CLOSE
);
2255 if(!(out
= BIO_new_file(fp
, "w")))
2258 rv
= PEM_write_bio_PKCS7(out
, p7
);
2265 sk_X509_pop_free(encerts
, X509_free
);
2271 * Encrypt a message on the way out. Called from call_mailer in send.c
2272 * The body may be reallocated.
2275 encrypt_outgoing_message(METAENV
*header
, BODY
**bodyP
)
2280 const EVP_CIPHER
*cipher
= NULL
;
2281 STACK_OF(X509
) *encerts
= NULL
;
2282 STORE_S
*outs
= NULL
;
2285 BODY
*body
= *bodyP
;
2286 BODY
*newBody
= NULL
;
2291 dprint((9, "encrypt_outgoing_message()"));
2294 cipher
= EVP_aes_256_cbc();
2296 encerts
= sk_X509_new_null();
2298 /* Look for a certificate for each of the recipients */
2299 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
2300 if(pf
->type
== Address
&& pf
->rcptto
&& pf
->addr
&& *pf
->addr
){
2301 for(a
=*pf
->addr
; a
; a
=a
->next
){
2302 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
2304 if((cert
= get_cert_for(buf
, Public
)) != NULL
){
2305 sk_X509_push(encerts
,cert
);
2307 q_status_message2(SM_ORDER
, 1, 1,
2308 _("Unable to find certificate for <%s@%s>"),
2309 a
->mailbox
, a
->host
);
2315 /* add the sender's certificate so that they can decrypt the message too */
2316 for(a
=header
->env
->from
; a
; a
= a
->next
){
2317 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
2319 if((cert
= get_cert_for(buf
, Public
)) != NULL
2320 && sk_X509_find(encerts
, cert
) == -1)
2321 sk_X509_push(encerts
,cert
);
2324 in
= body_to_bio(body
);
2326 p7
= PKCS7_encrypt(encerts
, in
, cipher
, 0);
2328 outs
= so_get(BioType
, NULL
, EDIT_ACCESS
);
2329 out
= bio_from_store(outs
);
2331 i2d_PKCS7_bio(out
, p7
);
2332 (void) BIO_flush(out
);
2334 so_seek(outs
, 0, SEEK_SET
);
2336 newBody
= mail_newbody();
2338 newBody
->type
= TYPEAPPLICATION
;
2339 newBody
->subtype
= cpystr("pkcs7-mime");
2340 newBody
->encoding
= ENCBINARY
;
2342 newBody
->disposition
.type
= cpystr("attachment");
2343 set_parameter(&newBody
->disposition
.parameter
, "filename", "smime.p7m");
2345 newBody
->description
= cpystr("S/MIME Encrypted Message");
2346 set_parameter(&newBody
->parameter
, "smime-type", "enveloped-data");
2347 set_parameter(&newBody
->parameter
, "name", "smime.p7m");
2349 newBody
->contents
.text
.data
= (unsigned char *) outs
;
2359 sk_X509_pop_free(encerts
, X509_free
);
2361 dprint((9, "encrypt_outgoing_message returns %d", result
));
2367 Get (and decode) the body of the given section of msg
2370 get_part_contents(long msgno
, const char *section
)
2374 STORE_S
*store
= NULL
;
2377 store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
2379 gf_set_so_writec(&pc
,store
);
2381 err
= detach(ps_global
->mail_stream
, msgno
, (char*) section
, 0L, &len
, pc
, NULL
, 0L);
2383 gf_clear_so_writec(store
);
2385 so_seek(store
, 0, SEEK_SET
);
2396 get_pkcs7_from_part(long msgno
,const char *section
)
2398 STORE_S
*store
= NULL
;
2402 store
= get_part_contents(msgno
, section
);
2405 if(store
->src
== CharStar
){
2409 * We're reaching inside the STORE_S structure. We should
2410 * probably have a way to get the length, instead.
2412 len
= (int) (store
->eod
- store
->dp
);
2413 in
= BIO_new_mem_buf(store
->txt
, len
);
2415 else{ /* just copy it */
2418 in
= BIO_new(BIO_s_mem());
2419 (void) BIO_reset(in
);
2421 so_seek(store
, 0L, 0);
2422 while(so_readc(&c
, store
)){
2423 BIO_write(in
, &c
, 1);
2428 /* dump_bio_to_file(in, "/tmp/decoded-signature"); */
2429 if((p7
=d2i_PKCS7_bio(in
,NULL
)) == NULL
){
2442 int same_cert(X509
*x
, X509
*cert
)
2444 char bufcert
[256], bufx
[256];
2447 get_fingerprint(cert
, EVP_md5(), bufcert
, sizeof(bufcert
), ":");
2448 get_fingerprint(x
, EVP_md5(), bufx
, sizeof(bufx
), ":");
2449 if(strcmp(bufx
, bufcert
) == 0)
2456 /* extract and save certificates from a PKCS7 package. The ctype variable
2457 * tells us if we want to extract it to a public/ or a ca/ directory. The
2458 * later makes sense only for recoverable errors (errors that can be fixed
2459 * by saving to the ca/ directory before we verify the signature).
2461 * 0 - no errors (in public/) no need to try again,
2462 * or validated self signed certificate (in ca/)
2463 * < 0 - certificate error is not recoverable, don't even think about it.
2466 int smime_extract_and_save_cert(PKCS7
*p7
)
2468 STACK_OF(X509
) *signers
;
2473 if((signers
= PKCS7_get0_signers(p7
, NULL
, 0)) == NULL
)
2476 for(i
= 0; i
< sk_X509_num(signers
); i
++){
2477 if((x
= sk_X509_value(signers
,i
)) == NULL
)
2480 if((email
= get_x509_subject_email(x
)) != NULL
){
2481 for(j
= 0; email
[j
] != NULL
; j
++){
2482 if((cert
= get_cert_for(email
[j
], Public
)) == NULL
2483 || same_cert(x
, cert
) == 0)
2484 save_cert_for(email
[j
], x
, Public
);
2486 fs_give((void **) &email
[i
]);
2488 fs_give((void **) email
);
2491 sk_X509_free(signers
);
2497 * Try to verify a signature.
2499 * p7 - the pkcs7 object to verify
2500 * in - the plain data to verify (NULL if not detached)
2501 * out - BIO to which to write the opaque data
2502 * silent - if non zero, do not print errors, only print success.
2505 do_signature_verify(PKCS7
*p7
, BIO
*in
, BIO
*out
, int silent
)
2507 STACK_OF(X509
) *otherCerts
= NULL
;
2515 if(!silent
) q_status_message(SM_ORDER
| SM_DING
, 2, 2,
2516 _("Couldn't verify S/MIME signature: No CA Certs were loaded"));
2521 smime_extract_and_save_cert(p7
);
2523 flags
= F_ON(F_USE_CERT_STORE_ONLY
, ps_global
) ? PKCS7_NOINTERN
: 0;
2525 if(ps_global
->smime
->publiccertlist
== NULL
){
2526 renew_cert_data(&ps_global
->smime
->publiccertlist
, Public
);
2527 for(cl
= ps_global
->smime
->publiccertlist
; cl
; cl
= cl
->next
){
2528 if(cl
->x509_cert
== NULL
){
2529 char *s
= strrchr(cl
->name
, '.');
2531 cl
->x509_cert
= get_cert_for(cl
->name
, Public
);
2537 if(ps_global
->smime
->publiccertlist
){
2538 otherCerts
= sk_X509_new_null();
2539 for(cl
= ps_global
->smime
->publiccertlist
; cl
; cl
= cl
->next
)
2540 if(cl
->x509_cert
!= NULL
)
2541 sk_X509_push(otherCerts
, X509_dup(cl
->x509_cert
));
2544 result
= PKCS7_verify(p7
, otherCerts
, s_cert_store
, in
, out
, flags
);
2546 sk_X509_pop_free(otherCerts
, X509_free
);
2549 q_status_message(SM_ORDER
, 1, 1, _("S/MIME signature verified ok"));
2552 err
= ERR_peek_error_line_data(NULL
, NULL
, &data
, NULL
);
2554 if(out
&& err
==ERR_PACK(ERR_LIB_PKCS7
,PKCS7_F_PKCS7_VERIFY
,PKCS7_R_CERTIFICATE_VERIFY_ERROR
)){
2556 /* Retry verification so we can get the plain text */
2557 /* Might be better to reimplement PKCS7_verify here? */
2559 PKCS7_verify(p7
, otherCerts
, s_cert_store
, in
, out
, PKCS7_NOVERIFY
);
2561 if (!silent
) q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
2562 _("Couldn't verify S/MIME signature: %s"), (char*) openssl_error_string());
2570 free_smime_body_sparep(void **sparep
)
2574 if(sparep
&& *sparep
){
2575 switch(get_smime_sparep_type(*sparep
)){
2576 case P7Type
: PKCS7_free((PKCS7
*) get_smime_sparep_data(*sparep
));
2578 case CharType
: s
= (char *)get_smime_sparep_data(*sparep
);
2579 fs_give((void **) &s
);
2581 case SizedText
: st
= (SIZEDTEXT
*)get_smime_sparep_data(*sparep
);
2582 fs_give((void **) &st
->data
);
2583 fs_give((void **) &st
);
2587 ((SMIME_SPARE_S
*)(*sparep
))->data
= NULL
;
2592 /* Big comment, explaining the mess that exists out there, and how we deal
2593 with it, and also how we solve the problems that are created this way.
2595 When Alpine sends a message, it constructs that message, computes the
2596 signature, but then it forgets the message it signed and reconstructs it
2597 again. Since it signs a message containing a notice about "mime aware
2598 tools", but it does not send that we do not include that in the part
2599 that is signed, and that takes care of much of the problems.
2601 Another problem is what is received from the servers. All servers tested
2602 seem to transmit the message that was signed intact and Alpine can check
2603 the signature correctly. That is not a problem. The problem arises when
2604 the message includes attachments. In this case different servers send
2605 different things, so it will be up to us to figure out what is the text
2606 that was actually signed. Confused? here is the story:
2608 When a message containing and attachment is sent by Alpine, UW-IMAP,
2609 Panda-IMAP, Gmail, and local reading of folders send exactly the message
2610 that was sent by Alpine, but GMX.com, Exchange, and probably other
2611 servers add a trailing \r\n in the message, so when validating the
2612 signature, these messages will not validate. There are several things
2615 1. Add a trailing \r\n to any message that contains attachments, sign that
2616 and send that. In this way, all messages will validate with all
2619 2. Compatibility mode: If a message has an attachment, contains a trailing
2620 \r\n and does not validate (sent by an earlier version of Alpine),
2621 remove the trailing \r\n and try to revalidate again.
2623 3. We do not add \r\n to validate a message that we sent, because that
2624 would only work in Alpine, and not in any other client. That would
2625 not be a good thing to do.
2629 Now we have to deal with encrypted and signed messages. The problem is
2630 that c-client makes all its pointers point to "on disk" content, but
2631 since we decrypted the data earlier, we have to make sure of two things.
2632 One is that we saved that data (so we do not have to decrypt it again)
2633 and second that we can use it.
2635 In order to save the data we use create_local_cache, so that we do not
2636 have to redecrypt the message. Once this is saved, c-client functions will
2637 find it and send it to us in mail_fetch_mime and mail_fetch_body.
2641 When we are trying to verify messages with detached signatures, some
2642 imap servers send incorrect information in the mail_fetch_mime call. By
2643 incorrect I mean that this is not fetched directly from the message, but
2644 it is read from the message, processed, and then the processed part is
2645 sent to us, so this text might not agree with what is in the message,
2646 and so the validation of the signature might fail. However, the good
2647 news is that the message validates if saved to a local folder. This
2648 means that if normal validation does not work we can make it work by
2649 saving the message locally and validating that. This is implemented
2650 below, and causes delay in the display of the message. I am considering
2651 at this time not to do this automatically, but wait for the user to tell
2652 us to do it for them by means of a command available in the
2653 mail_view_screen. This might help in other situations, where a message
2654 is supposed to have an attachment, but it can not be seen in the
2655 processed text. Nevertheless, at this time, this is automatic, and is
2656 causing a delay in the processing of the message, but it is validating
2657 correctly all messages.
2661 When the user sends a message as encrypted and signed, this code used to
2662 encrypt first, and then sign the pkcs7 body, but it turns out that some
2663 other clients can not handle these messages. While we could argue that the
2664 other clients need to improve, we will support reading messages in both
2665 ways, and will send messages using this technique; that is, signed first,
2666 encrypted second. It seems that all tested clients support this way, so it
2667 should be safe to do so.
2670 typedef struct smime_filter_s
{
2674 SMIME_FILTER_S sig_filter
[] = {
2675 {smime_remove_trailing_crlf
},
2676 {smime_remove_folding_space
}
2679 #define TOTAL_FILTERS (sizeof(sig_filter)/sizeof(sig_filter[0]))
2680 #define TOTAL_SIGFLTR (1 << TOTAL_FILTERS) /* not good, keep filters to a low number */
2683 smime_remove_trailing_crlf(char **mimetext
, unsigned long *mimelen
,
2684 char **bodytext
, unsigned long *bodylen
)
2686 if(*bodylen
> 2 && !strncmp(*bodytext
+*bodylen
-2, "\r\n", 2))
2691 smime_remove_folding_space(char **mimetext
, unsigned long *mimelen
,
2692 char **bodytext
, unsigned long *bodylen
)
2695 unsigned long mlen
= *mimelen
;
2698 for (s
= t
= *mimetext
; t
- *mimetext
< *mimelen
; ){
2699 if(*t
== '\r' && *(t
+1) == '\n' && (*(t
+2) == '\t' || *(t
+2) == ' ')){
2712 smime_validate_extra_test(char *mimetext
, unsigned long mimelen
, char *bodytext
, unsigned long bodylen
, PKCS7
*p7
, int nflag
)
2714 int result
, i
, j
, flag
;
2715 char *mtext
, *btext
;
2716 unsigned long mlen
, blen
;
2719 mtext
= mimelen
? fs_get(mimelen
+1) : NULL
;
2720 btext
= fs_get(bodylen
+1);
2722 flag
= 1; /* silence all failures */
2723 for(i
= 1; result
== 0 && i
< TOTAL_SIGFLTR
; i
++){
2724 if((in
= BIO_new(BIO_s_mem())) == NULL
)
2727 (void) BIO_reset(in
);
2729 if(i
+1 == TOTAL_SIGFLTR
)
2733 strncpy(mtext
, mimetext
, mlen
= mimelen
);
2734 strncpy(btext
, bodytext
, blen
= bodylen
);
2735 for(j
= 0; j
< TOTAL_FILTERS
; j
++)
2737 (sig_filter
[j
].filter
)(&mtext
, &mlen
, &btext
, &blen
);
2739 BIO_write(in
, mtext
, mlen
);
2740 BIO_write(in
, btext
, blen
);
2741 result
= do_signature_verify(p7
, in
, NULL
, flag
);
2744 if(mtext
) fs_give((void **)&mtext
);
2745 if(btext
) fs_give((void **)&btext
);
2750 * Given a multipart body of type multipart/signed, attempt to verify it.
2751 * Returns non-zero if the body was changed.
2754 do_detached_signature_verify(BODY
*b
, long msgno
, char *section
)
2759 int result
, modified_the_body
= 0;
2760 int flag
; /* 1 silent, 0 not silent */
2761 unsigned long mimelen
, bodylen
;
2762 char newSec
[100], *mimetext
, *bodytext
;
2766 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"));
2770 /* if it was signed and then encrypted, use the decrypted text
2771 * to check the validity of the signature
2774 if(get_smime_sparep_type(b
->sparep
) == SizedText
){
2775 /* bodytext includes mimetext */
2776 st
= (SIZEDTEXT
*) get_smime_sparep_data(b
->sparep
);
2777 bodytext
= (char *) st
->data
;
2784 snprintf(newSec
, sizeof(newSec
), "%s%s1", section
? section
: "", (section
&& *section
) ? "." : "");
2785 mimetext
= mail_fetch_mime(ps_global
->mail_stream
, msgno
, (char*) newSec
, &mimelen
, 0);
2787 bodytext
= mail_fetch_body (ps_global
->mail_stream
, msgno
, (char*) newSec
, &bodylen
, 0);
2789 if(mimetext
== NULL
|| bodytext
== NULL
)
2790 return modified_the_body
;
2793 snprintf(newSec
, sizeof(newSec
), "%s%s2", section
? section
: "", (section
&& *section
) ? "." : "");
2795 if((p7
= get_pkcs7_from_part(msgno
, newSec
)) == NULL
2796 || (in
= BIO_new(BIO_s_mem())) == NULL
)
2797 return modified_the_body
;
2799 (void) BIO_reset(in
);
2800 if(mimetext
!= NULL
)
2801 BIO_write(in
, mimetext
, mimelen
);
2802 BIO_write(in
, bodytext
, bodylen
);
2804 if((result
= do_signature_verify(p7
, in
, NULL
, 1)) == 0){
2805 flag
= (mimelen
== 0 || !IS_REMOTE(ps_global
->mail_stream
->mailbox
))
2807 result
= smime_validate_extra_test(mimetext
, mimelen
, bodytext
, bodylen
, p7
, flag
);
2809 return modified_the_body
;
2811 && mimelen
> 0 /* do not do this for encrypted messages */
2812 && IS_REMOTE(ps_global
->mail_stream
->mailbox
)){
2814 unsigned long hlen
, tlen
;
2818 if((in
= BIO_new(BIO_s_mem())) != NULL
2819 && (fetch
= mail_fetch_header(ps_global
->mail_stream
, msgno
, NULL
,
2820 NULL
, &hlen
, FT_PEEK
)) != NULL
2821 && (msg_so
= so_get(CharStar
, NULL
, WRITE_ACCESS
)) != NULL
2822 && so_nputs(msg_so
, fetch
, (long) hlen
)
2823 && (fetch
= pine_mail_fetch_text(ps_global
->mail_stream
, msgno
, NULL
,
2824 &tlen
, FT_PEEK
)) != NULL
2825 && so_nputs(msg_so
, fetch
, tlen
)){
2827 char *h
= (char *) so_text(msg_so
);
2828 char *bstart
= strstr(h
, "\r\n\r\n");
2833 INIT(&bs
, mail_string
, bstart
, tlen
);
2834 rfc822_parse_msg_full(&env
, &body
, h
, bstart
-h
-4, &bs
, BADHOST
, 0, 0);
2835 mail_free_envelope(&env
);
2837 mail_free_body_part(&b
->nested
.part
);
2838 tmpB
= mail_body_section(body
, (unsigned char *) section
);
2839 if(MIME_MSG(tmpB
->type
, tmpB
->subtype
))
2840 b
->nested
.part
= tmpB
->nested
.msg
->body
->nested
.part
;
2842 b
->nested
.part
= tmpB
->nested
.part
;
2843 create_local_cache(bstart
, bstart
, &b
->nested
.part
->body
, 1);
2844 modified_the_body
= 1;
2846 snprintf(newSec
, sizeof(newSec
), "%s%s1", section
? section
: "", (section
&& *section
) ? "." : "");
2848 mimetext
= mail_fetch_mime(ps_global
->mail_stream
, msgno
, (char*) newSec
, &mimelen
, 0);
2851 bodytext
= mail_fetch_body (ps_global
->mail_stream
, msgno
, (char*) newSec
, &bodylen
, 0);
2853 if (mimetext
== NULL
|| bodytext
== NULL
)
2854 return modified_the_body
;
2856 snprintf(newSec
, sizeof(newSec
), "%s%s2", section
? section
: "", (section
&& *section
) ? "." : "");
2858 if((p7
= get_pkcs7_from_part(msgno
, newSec
)) == NULL
)
2859 return modified_the_body
;
2861 (void) BIO_reset(in
);
2862 BIO_write(in
, mimetext
, mimelen
);
2863 BIO_write(in
, bodytext
, bodylen
);
2866 if((result
= do_signature_verify(p7
, in
, NULL
, 1)) == 0){
2867 result
= smime_validate_extra_test(mimetext
, mimelen
, bodytext
, bodylen
, p7
, 0);
2869 return modified_the_body
;
2877 fs_give((void**) &b
->subtype
);
2879 b
->subtype
= cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE
);
2880 b
->encoding
= ENC8BIT
;
2883 fs_give ((void**) &b
->description
);
2885 what_we_did
= result
? _("This message was cryptographically signed.") :
2886 _("This message was cryptographically signed but the signature could not be verified.");
2888 b
->description
= cpystr(what_we_did
);
2890 b
->sparep
= create_smime_sparep(P7Type
, p7
);
2894 /* p is signed plaintext */
2896 mail_free_body_part(&p
->next
); /* hide the pkcs7 from the viewer */
2898 modified_the_body
= 1;
2900 return modified_the_body
;
2905 find_certificate_matching_recip_info(PKCS7_RECIP_INFO
*ri
)
2907 PERSONAL_CERT
*x
= NULL
;
2909 if(ps_global
->smime
){
2910 for(x
= (PERSONAL_CERT
*) ps_global
->smime
->personal_certs
; x
; x
=x
->next
){
2915 if(!X509_NAME_cmp(ri
->issuer_and_serial
->issuer
,mine
->cert_info
->issuer
) &&
2916 !ASN1_INTEGER_cmp(ri
->issuer_and_serial
->serial
,mine
->cert_info
->serialNumber
)){
2926 static PERSONAL_CERT
*
2927 find_certificate_matching_pkcs7(PKCS7
*p7
)
2930 STACK_OF(PKCS7_RECIP_INFO
) *recips
;
2931 PERSONAL_CERT
*x
= NULL
;
2933 recips
= p7
->d
.enveloped
->recipientinfo
;
2935 for(i
=0; i
<sk_PKCS7_RECIP_INFO_num(recips
); i
++){
2936 PKCS7_RECIP_INFO
*ri
;
2938 ri
= sk_PKCS7_RECIP_INFO_value(recips
, i
);
2940 if((x
=find_certificate_matching_recip_info(ri
))!=0){
2948 /* decrypt an encrypted file.
2949 Args: fp - the path to the encrypted file.
2950 rv - a code that tells the caller what happened inside the function
2951 pcert - a personal certificate that was used to encrypt this file
2952 Returns the decoded text allocated in a char *, whose memory must be
2957 decrypt_file(char *fp
, int *rv
, PERSONAL_CERT
*pc
)
2961 BIO
*in
= NULL
, *out
= NULL
;
2963 long unsigned int len
;
2966 if(pc
== NULL
|| (text
= read_file(fp
, 0)) == NULL
|| *text
== '\0')
2969 tmp
= fs_get(strlen(text
) + (strlen(text
) << 6) + 1);
2970 for(j
= 0, i
= strlen("-----BEGIN PKCS7-----") + 1; text
[i
] != '\0'
2971 && text
[i
] != '-'; j
++, i
++)
2975 ret
= rfc822_base64((unsigned char *)tmp
, strlen(tmp
), &len
);
2977 if((in
= BIO_new_mem_buf((char *)ret
, len
)) != NULL
){
2978 p7
= d2i_PKCS7_bio(in
, NULL
);
2982 if (text
) fs_give((void **)&text
);
2983 if (ret
) fs_give((void **)&ret
);
2985 if (rv
) *rv
= pc
->key
== NULL
? -1 : 1;
2987 out
= BIO_new(BIO_s_mem());
2988 (void) BIO_reset(out
);
2990 i
= PKCS7_decrypt(p7
, pc
->key
, pc
->cert
, out
, 0);
2993 q_status_message1(SM_ORDER
, 1, 1, _("Error decrypting: %s"),
2994 (char*) openssl_error_string());
2998 BIO_get_mem_data(out
, &tmp
);
3010 * Try to decode (decrypt or verify a signature) a PKCS7 body
3011 * Returns non-zero if something was changed.
3014 do_decoding(BODY
*b
, long msgno
, const char *section
)
3016 int modified_the_body
= 0;
3020 EVP_PKEY
*key
= NULL
;
3021 PERSONAL_CERT
*pcert
= NULL
;
3022 char *what_we_did
= "";
3025 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"));
3030 * Extract binary data from part to an in-memory store
3034 if(get_smime_sparep_type(b
->sparep
) == P7Type
)
3035 p7
= (PKCS7
*) get_smime_sparep_data(b
->sparep
);
3038 p7
= get_pkcs7_from_part(msgno
, section
&& *section
? section
: "1");
3040 q_status_message1(SM_ORDER
, 2, 2, "Couldn't load PKCS7 object: %s",
3041 (char*) openssl_error_string());
3046 * Save the PKCS7 object for later dealings by the user interface.
3047 * It will be cleaned up when the body is garbage collected.
3049 b
->sparep
= create_smime_sparep(P7Type
, p7
);
3052 dprint((1, "type_is_signed = %d, type_is_enveloped = %d", PKCS7_type_is_signed(p7
), PKCS7_type_is_enveloped(p7
)));
3054 if(PKCS7_type_is_signed(p7
)){
3057 out
= BIO_new(BIO_s_mem());
3058 (void) BIO_reset(out
);
3059 BIO_puts(out
, "MIME-Version: 1.0\r\n"); /* needed so rfc822_parse_msg_full believes it's MIME */
3061 sigok
= do_signature_verify(p7
, NULL
, out
, 0);
3063 what_we_did
= sigok
? _("This message was cryptographically signed.") :
3064 _("This message was cryptographically signed but the signature could not be verified.");
3066 /* make sure it's null terminated */
3067 BIO_write(out
, null
, 1);
3069 else if(!PKCS7_type_is_enveloped(p7
)){
3070 q_status_message(SM_ORDER
, 1, 1, "PKCS7 object not recognised.");
3073 else{ /* It *is* enveloped */
3076 what_we_did
= _("This message was encrypted.");
3078 /* now need to find a cert that can decrypt this */
3079 pcert
= find_certificate_matching_pkcs7(p7
);
3082 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find the certificate needed to decrypt."));
3086 recip
= pcert
->cert
;
3088 if(!load_private_key(pcert
)
3090 && ps_global
->smime
->need_passphrase
3091 && !ps_global
->smime
->already_auto_asked
){
3092 /* Couldn't load key with blank password, ask user */
3093 ps_global
->smime
->already_auto_asked
= 1;
3094 if(pith_opt_smime_get_passphrase
){
3095 (*pith_opt_smime_get_passphrase
)();
3096 load_private_key(pcert
);
3104 out
= BIO_new(BIO_s_mem());
3105 (void) BIO_reset(out
);
3106 BIO_puts(out
, "MIME-Version: 1.0\r\n");
3108 decrypt_result
= PKCS7_decrypt(p7
, key
, recip
, out
, 0);
3110 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
3111 forget_private_keys();
3113 if(!decrypt_result
){
3114 q_status_message1(SM_ORDER
, 1, 1, _("Error decrypting: %s"),
3115 (char*) openssl_error_string());
3118 BIO_write(out
, null
, 1);
3122 * We've now produced a flattened MIME object in BIO out.
3123 * It needs to be turned back into a BODY.
3132 BUF_MEM
*bptr
= NULL
;
3134 BIO_get_mem_ptr(out
, &bptr
);
3138 /* look for start of body */
3139 bstart
= strstr(h
, "\r\n\r\n");
3142 q_status_message(SM_ORDER
, 3, 3, _("Encrypted data couldn't be parsed."));
3146 bstart
+= 4; /* skip over CRLF*2 */
3148 INIT(&s
, mail_string
, bstart
, strlen(bstart
));
3149 rfc822_parse_msg_full(&env
, &body
, h
, bstart
-h
-2, &s
, BADHOST
, 0, 0);
3150 mail_free_envelope(&env
); /* Don't care about this */
3152 if(body
->type
== TYPEMULTIPART
3153 && !strucmp(body
->subtype
, "SIGNED")){
3154 char *cookie
= NULL
;
3156 for (param
= body
->parameter
; param
&& !cookie
; param
= param
->next
)
3157 if (!strucmp (param
->attribute
,"BOUNDARY")) cookie
= param
->value
;
3159 st
= fs_get(sizeof(SIZEDTEXT
));
3160 st
->data
= (void *) cpystr(bstart
+ strlen(cookie
)+4); /* 4 = strlen("--\r\n") */
3161 st
->size
= body
->nested
.part
->next
->body
.mime
.offset
- 2*(strlen(cookie
) + 4);
3162 body
->sparep
= create_smime_sparep(SizedText
, (void *)st
);
3165 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find cookie in attachment list."));
3167 body
->mime
.offset
= 0;
3168 body
->mime
.text
.size
= 0;
3171 * Now convert original body (application/pkcs7-mime)
3172 * to a multipart body with one sub-part (the decrypted body).
3173 * Note that the sub-part may also be multipart!
3176 b
->type
= TYPEMULTIPART
;
3178 fs_give((void**) &b
->subtype
);
3181 * This subtype is used in mailview.c to annotate the display of
3182 * encrypted or signed messages. We know for sure then that it's a PKCS7
3183 * part because the sparep field is set to the PKCS7 object (see above).
3185 b
->subtype
= cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE
);
3186 b
->encoding
= ENC8BIT
;
3189 fs_give((void**) &b
->description
);
3191 b
->description
= cpystr(what_we_did
);
3193 if(b
->disposition
.type
)
3194 fs_give((void **) &b
->disposition
.type
);
3196 if(b
->contents
.text
.data
)
3197 fs_give((void **) &b
->contents
.text
.data
);
3200 mail_free_body_parameter(&b
->parameter
);
3202 /* Allocate mem for the sub-part, and copy over the contents of our parsed body */
3203 b
->nested
.part
= fs_get(sizeof(PART
));
3204 b
->nested
.part
->body
= *body
;
3205 b
->nested
.part
->next
= NULL
;
3207 fs_give((void**) &body
);
3210 * IMPORTANT BIT: set the body->contents.text.data elements to contain
3211 * the decrypted data. Otherwise, it'll try to load it from the original
3214 create_local_cache(bstart
-b
->nested
.part
->body
.mime
.offset
, bstart
, &b
->nested
.part
->body
, 0);
3216 modified_the_body
= 1;
3224 return modified_the_body
;
3229 * Recursively handle PKCS7 bodies in our message.
3231 * Returns non-zero if some fiddling was done.
3234 do_fiddle_smime_message(BODY
*b
, long msgno
, char *section
)
3236 int modified_the_body
= 0;
3241 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"));
3243 if(is_pkcs7_body(b
)){
3245 if(do_decoding(b
, msgno
, section
)){
3247 * b should now be a multipart message:
3248 * fiddle it too in case it's been multiply-encrypted!
3252 modified_the_body
= 1;
3256 if(b
->type
==TYPEMULTIPART
|| MIME_MSG(b
->type
, b
->subtype
)){
3262 if(MIME_MULT_SIGNED(b
->type
, b
->subtype
)){
3266 * Ahah. We have a multipart signed entity.
3269 * part 1 (signed thing)
3270 * part 2 (the pkcs7 signature)
3272 * We're going to convert that to
3274 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
3275 * part 1 (signed thing)
3276 * part 2 has been freed
3278 * We also extract the signature from part 2 and save it
3279 * in the multipart body->sparep, and we add a description
3280 * in the multipart body->description.
3283 * The results of a decrypted message will be similar. It
3286 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
3287 * part 1 (decrypted thing)
3290 modified_the_body
+= do_detached_signature_verify(b
, msgno
, section
);
3292 else if(MIME_MSG(b
->type
, b
->subtype
)){
3293 modified_the_body
+= do_fiddle_smime_message(b
->nested
.msg
->body
, msgno
, section
);
3297 for(p
=b
->nested
.part
,partNum
=1; p
; p
=p
->next
,partNum
++){
3298 /* Append part number to the section string */
3300 snprintf(newSec
, sizeof(newSec
), "%s%s%d", section
, *section
? "." : "", partNum
);
3302 modified_the_body
+= do_fiddle_smime_message(&p
->body
, msgno
, newSec
);
3307 return modified_the_body
;
3312 * Fiddle a message in-place by decrypting/verifying S/MIME entities.
3313 * Returns non-zero if something was changed.
3316 fiddle_smime_message(BODY
*b
, long msgno
)
3318 return do_fiddle_smime_message(b
, msgno
, "");
3322 /********************************************************************************/
3326 * Output a string in a distinctive style
3329 gf_puts_uline(char *txt
, gf_io_t pc
)
3331 pc(TAG_EMBED
); pc(TAG_BOLDON
);
3333 pc(TAG_EMBED
); pc(TAG_BOLDOFF
);
3336 /* get_chain_for_cert: error and level are mandatory arguments */
3338 get_chain_for_cert(X509
*cert
, int *error
, int *level
)
3340 STACK_OF(X509
) *chain
= NULL
;
3341 X509_STORE_CTX
*ctx
;
3343 int rc
; /* return code */
3348 if((ctx
= X509_STORE_CTX_new()) != NULL
){
3349 X509_STORE_set_flags(s_cert_store
, 0);
3350 if(!X509_STORE_CTX_init(ctx
, s_cert_store
, cert
, NULL
))
3351 *error
= X509_STORE_CTX_get_error(ctx
);
3352 else if((chain
= sk_X509_new_null()) != NULL
){
3353 for(x
= cert
; ; x
= xtmp
){
3355 sk_X509_push(chain
, X509_dup(x
));
3356 rc
= X509_STORE_CTX_get1_issuer(&xtmp
, ctx
, x
);
3361 if(!X509_check_issued(xtmp
, xtmp
))
3365 X509_STORE_CTX_free(ctx
);
3372 * Sign a message. Called from call_mailer in send.c.
3374 * This takes the header for the outgoing message as well as a pointer
3375 * to the current body (which may be reallocated).
3376 * The last argument (BODY **bp) is an argument that tells Alpine
3377 * if the body has 8 bit. if *bp is not null we compute two signatures
3378 * one for the quoted-printable encoded message, and another for the
3379 * 8bit encoded message. We return the signature for the 8bit encoded
3380 * part in p2->body.mime.text.data.
3381 * The reason why we compute two signatures is so that we can decide
3382 * which one to use later, and we only do it in the case that *bp is
3383 * not null. If we did not do this, then we might not be able to sign
3384 * a message until we log in to the smtp server, so instead of doing
3385 * that, we get ready for any possible situation we might find.
3388 sign_outgoing_message(METAENV
*header
, BODY
**bodyP
, int dont_detach
, BODY
**bp
)
3390 STORE_S
*outs
= NULL
;
3391 STORE_S
*outs_2
= NULL
;
3392 BODY
*body
= *bodyP
;
3393 BODY
*newBody
= NULL
;
3396 PERSONAL_CERT
*pcert
;
3403 STACK_OF(X509
) *chain
;
3404 int result
= 0, error
;
3405 int flags
= dont_detach
? 0 : PKCS7_DETACHED
;
3408 dprint((9, "sign_outgoing_message()"));
3412 /* Look for a private key matching the sender address... */
3414 pcert
= match_personal_cert(header
->env
);
3417 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find the certificate needed to sign."));
3421 if(!load_private_key(pcert
) && ps_global
->smime
&& ps_global
->smime
->need_passphrase
){
3422 /* Couldn't load key with blank password, try again */
3423 if(pith_opt_smime_get_passphrase
){
3424 (*pith_opt_smime_get_passphrase
)();
3425 load_private_key(pcert
);
3432 if(((chain
= get_chain_for_cert(pcert
->cert
, &error
, &level
)) != NULL
&& error
)
3434 sk_X509_pop_free(chain
, X509_free
);
3439 q_status_message(SM_ORDER
, 1, 1,
3440 _("Not all certificates needed to verify signature included in signed message"));
3442 in
= body_to_bio(body
);
3444 p7
= PKCS7_sign(pcert
->cert
, pcert
->key
, chain
, in
, flags
);
3447 int i
, save_encoding
;
3449 for(i
= 0; (i
<= ENCMAX
) && body_encodings
[i
]; i
++);
3451 if(i
> ENCMAX
){ /* no empty encoding slots! */
3455 save_encoding
= (*bp
)->encoding
;
3456 body_encodings
[(*bp
)->encoding
= i
] = body_encodings
[ENC8BIT
];
3458 in_2
= body_to_bio(body
);
3460 body_encodings
[i
] = NULL
;
3461 (*bp
)->encoding
= save_encoding
;
3466 p7_2
= PKCS7_sign(pcert
->cert
, pcert
->key
, chain
, in_2
, flags
);
3468 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
3469 forget_private_keys();
3472 sk_X509_pop_free(chain
, X509_free
);
3475 q_status_message(SM_ORDER
, 1, 1, _("Error creating signed object."));
3479 outs
= so_get(BioType
, NULL
, EDIT_ACCESS
);
3480 out
= bio_from_store(outs
);
3482 i2d_PKCS7_bio(out
, p7
);
3483 (void) BIO_flush(out
);
3485 so_seek(outs
, 0, SEEK_SET
);
3487 if(bp
&& *bp
&& p7_2
){
3488 outs_2
= so_get(BioType
, NULL
, EDIT_ACCESS
);
3489 out_2
= bio_from_store(outs_2
);
3491 i2d_PKCS7_bio(out_2
, p7_2
);
3492 (void) BIO_flush(out_2
);
3494 so_seek(outs_2
, 0, SEEK_SET
);
3497 if((flags
&PKCS7_DETACHED
)==0){
3499 /* the simple case: the signed data is in the pkcs7 object */
3501 newBody
= mail_newbody();
3503 setup_pkcs7_body_for_signature(newBody
, "S/MIME Cryptographically Signed Message", "pkcs7-mime", "smime.p7m", "signed-data");
3505 newBody
->contents
.text
.data
= (unsigned char *) outs
;
3514 * We have to create a new body as follows:
3516 * multipart/signed; blah blah blah
3517 * reference to existing body
3522 newBody
= mail_newbody();
3524 newBody
->type
= TYPEMULTIPART
;
3525 newBody
->subtype
= cpystr("signed");
3526 newBody
->encoding
= ENC7BIT
;
3528 set_parameter(&newBody
->parameter
, "protocol", "application/pkcs7-signature");
3529 set_parameter(&newBody
->parameter
, "micalg", "sha1");
3531 p1
= mail_newbody_part();
3532 p2
= mail_newbody_part();
3535 * This is nasty. We're just copying the body in here,
3536 * but since our newBody is freed at the end of call_mailer,
3537 * we mustn't let this body (the original one) be freed twice.
3539 p1
->body
= *body
; /* ARRGH. This is special cased at the end of call_mailer */
3543 setup_pkcs7_body_for_signature(&p2
->body
, "S/MIME Cryptographic Signature", "pkcs7-signature", "smime.p7s", NULL
);
3544 p2
->body
.mime
.text
.data
= (unsigned char *) outs_2
;
3545 p2
->body
.contents
.text
.data
= (unsigned char *) outs
;
3547 newBody
->nested
.part
= p1
;
3560 if(p7_2
) PKCS7_free(p7_2
);
3564 dprint((9, "sign_outgoing_message returns %d", result
));
3570 new_smime_struct(void)
3572 SMIME_STUFF_S
*ret
= NULL
;
3574 ret
= (SMIME_STUFF_S
*) fs_get(sizeof(*ret
));
3575 memset((void *) ret
, 0, sizeof(*ret
));
3576 ret
->publictype
= Nada
;
3583 free_smime_struct(SMIME_STUFF_S
**smime
)
3585 if(smime
&& *smime
){
3586 if((*smime
)->passphrase_emailaddr
){
3588 for(i
= 0; (*smime
)->passphrase_emailaddr
[i
] != NULL
; i
++)
3589 fs_give((void **) &(*smime
)->passphrase_emailaddr
[i
]);
3590 fs_give((void **) (*smime
)->passphrase_emailaddr
);
3593 if((*smime
)->publicpath
)
3594 fs_give((void **) &(*smime
)->publicpath
);
3596 if((*smime
)->publiccertlist
)
3597 free_certlist(&(*smime
)->publiccertlist
);
3599 if((*smime
)->backuppubliccertlist
)
3600 free_certlist(&(*smime
)->backuppubliccertlist
);
3602 if((*smime
)->cacertlist
)
3603 free_certlist(&(*smime
)->cacertlist
);
3605 if((*smime
)->backupcacertlist
)
3606 free_certlist(&(*smime
)->backupcacertlist
);
3608 if((*smime
)->privatecertlist
)
3609 free_certlist(&(*smime
)->privatecertlist
);
3611 if((*smime
)->backupprivatecertlist
)
3612 free_certlist(&(*smime
)->backupprivatecertlist
);
3614 if((*smime
)->publiccontent
)
3615 fs_give((void **) &(*smime
)->publiccontent
);
3617 if((*smime
)->privatepath
)
3618 fs_give((void **) &(*smime
)->privatepath
);
3620 if((*smime
)->personal_certs
){
3623 pc
= (PERSONAL_CERT
*) (*smime
)->personal_certs
;
3624 free_personal_certs(&pc
);
3625 (*smime
)->personal_certs
= NULL
;
3628 if((*smime
)->backuppersonal_certs
){
3631 pc
= (PERSONAL_CERT
*) (*smime
)->backuppersonal_certs
;
3632 free_personal_certs(&pc
);
3633 (*smime
)->backuppersonal_certs
= NULL
;
3636 if((*smime
)->privatecontent
)
3637 fs_give((void **) &(*smime
)->privatecontent
);
3639 if((*smime
)->capath
)
3640 fs_give((void **) &(*smime
)->capath
);
3642 if((*smime
)->cacontent
)
3643 fs_give((void **) &(*smime
)->cacontent
);
3645 fs_give((void **) smime
);