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-2016 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>
52 /* internal prototypes */
53 static void forget_private_keys(void);
54 static int app_RAND_load_file(const char *file
);
55 static void openssl_extra_randomness(void);
56 static int app_RAND_write_file(const char *file
);
57 static const char *openssl_error_string(void);
58 static int load_private_key(PERSONAL_CERT
*pcert
);
59 static void create_local_cache(char *h
, char *base
, BODY
*b
, int type
);
60 static long rfc822_output_func(void *b
, char *string
);
61 static void setup_pkcs7_body_for_signature(BODY
*b
, char *description
,
62 char *type
, char *filename
, char *smime_type
);
63 static BIO
*body_to_bio(BODY
*body
);
64 static BIO
*bio_from_store(STORE_S
*store
);
65 static STORE_S
*get_part_contents(long msgno
, const char *section
);
66 static PKCS7
*get_pkcs7_from_part(long msgno
, const char *section
);
67 static int do_signature_verify(PKCS7
*p7
, BIO
*in
, BIO
*out
, int silent
);
68 static int do_detached_signature_verify(BODY
*b
, long msgno
, char *section
);
69 static PERSONAL_CERT
*find_certificate_matching_pkcs7(PKCS7
*p7
);
70 static int do_decoding(BODY
*b
, long msgno
, const char *section
);
71 static void free_smime_struct(SMIME_STUFF_S
**smime
);
72 static void setup_storage_locations(void);
73 static int copy_container_to_dir(WhichCerts which
);
74 static int do_fiddle_smime_message(BODY
*b
, long msgno
, char *section
);
75 void setup_privatekey_storage(void);
76 int smime_extract_and_save_cert(PKCS7
*p7
, int check_cert
);
77 int same_cert(X509
*, X509
*);
79 int load_key_and_cert(char *pathkeydir
, char *pathcertdir
, char **keyfile
, char **certfile
, EVP_PKEY
**pkey
, X509
**pcert
);
81 EVP_PKEY
*load_pkey_with_prompt(char *fpath
, char *text
, char *prompt
, int *);
82 void smime_remove_trailing_crlf(char **mimetext
, unsigned long *mimelen
, char **bodytext
, unsigned long *bodylen
);
83 void smime_remove_folding_space(char **mimetext
, unsigned long *mimelen
, char **bodytext
, unsigned long *bodylen
);
84 int smime_validate_extra_test(char *mimetext
, unsigned long mimelen
, char *bodytext
, unsigned long bodylen
, PKCS7
*p7
, int nflag
);
86 int (*pith_opt_smime_get_passphrase
)(void);
87 int (*pith_smime_import_certificate
)(char *, char *, size_t);
88 int (*pith_smime_enter_password
)(char *prompt
, char *, size_t);
89 int (*pith_smime_confirm_save
)(char *email
);
91 static X509_STORE
*s_cert_store
;
93 /* State management for randomness functions below */
94 static int seeded
= 0;
97 create_smime_sparep(SpareType stype
, void *s
)
101 rv
= fs_get(sizeof(SMIME_SPARE_S
));
108 get_smime_sparep_type(void *s
)
110 return ((SMIME_SPARE_S
*)s
)->sptype
;
114 get_smime_sparep_data(void *s
)
116 return ((SMIME_SPARE_S
*)s
)->data
;
122 * load key from pathkeydir and cert from pathcertdir. It chooses the first
123 * key/certificate pair that matches. Delete pairs that you do not want used,
124 * if you do not want them selected. All parameters must be non-null.
125 * Memory freed by caller.
127 * -1 : user cancelled load
128 * 0 : load was successful
129 * 1 : there was an error in the loading.
132 load_key_and_cert(char *pathkeydir
, char *pathcertdir
, char **keyfile
,
133 char **certfile
, EVP_PKEY
**pkey
, X509
**pcert
)
135 char buf
[MAXPATH
+1], pathkey
[MAXPATH
+1], prompt
[MAILTMPLEN
];
138 int b
= 0, ret
= 1; /* assume error */
140 if(pathkeydir
== NULL
|| pathcertdir
== NULL
|| keyfile
== NULL
141 || pkey
== NULL
|| certfile
== NULL
|| pcert
== NULL
)
149 if((dirp
= opendir(pathkeydir
)) != NULL
){
150 while(b
== 0 && (d
=readdir(dirp
)) != NULL
){
153 if((ll
=strlen(d
->d_name
)) && ll
> 4){
154 if(!strcmp(d
->d_name
+ll
-4, ".key")){
155 strncpy(buf
, d
->d_name
, sizeof(buf
));
156 buf
[sizeof(buf
)-1] = '\0';
157 build_path(pathkey
, pathkeydir
, buf
, sizeof(pathkey
));
158 buf
[strlen(buf
)-4] = '\0';
159 snprintf(prompt
, sizeof(prompt
),
160 _("Enter password of key <%s> to unlock password file: "), buf
);
161 if((*pkey
= load_pkey_with_prompt(pathkey
, NULL
, prompt
, &ret
)) != NULL
){
162 if(load_cert_for_key(pathcertdir
, *pkey
, certfile
, pcert
)){
164 *keyfile
= cpystr(buf
);
166 EVP_PKEY_free(*pkey
);
168 q_status_message1(SM_ORDER
, 0, 2,
169 _("Cannot find certificate that matches key <%s>. Continuing..."), buf
);
181 /* setup a key and certificate to encrypt and decrypt a password file.
182 * These files will be saved in the .alpine-smime/.pwd directory, but its
183 * location can be setup in the command line with the -pwdcertdir option.
184 * Here are the rules:
186 * Check if the .alpine-smime/.pwd (or -pwdcertdir directory) exists,
187 * if not create it. If we are successful, move to the next step
189 * - If the user has a key/cert pair, in the .alpine-smime/.pwd dir
190 * setup is successful;
191 * - if the user does not have a key/cert pair, look to see if
192 * ps_global->smime->personal_certs is already setup, if so, use it.
193 * - if ps_global->smime->personal_certs is not set up, see if we can
194 * find a certificate/cert pair in the default locations at compilation
195 * time. (~/.alpine-smime/private and ~/.alpine-smime/public
196 * - if none of this is successful, create a key/certificate pair
197 * (TODO: implement this)
198 * - in any other case, setup is not successful.
200 * If setup is successful, setup ps_global->pwdcert.
201 * If any of this fails, ps_global->pwdcert will be null.
202 * Ok, that should do it.
205 setup_pwdcert(void **pwdcert
)
208 int setup_dir
= 0; /* make it non zero if we know which dir to use */
210 char pathdir
[MAXPATH
+1], pathkey
[MAXPATH
+1], fpath
[MAXPATH
+1], pathcert
[MAXPATH
+1];
211 char fpath2
[MAXPATH
+1], prompt
[MAILTMPLEN
];
212 char *keyfile
, *certfile
, *text
;
213 EVP_PKEY
*pkey
= NULL
;
215 PERSONAL_CERT
*pc
, *pc2
= NULL
;
216 static int was_here
= 0;
218 if(pwdcert
== NULL
|| was_here
== 1)
222 if(ps_global
->pwdcertdir
){
223 if(our_stat(ps_global
->pwdcertdir
, &sbuf
) == 0
224 && ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
)){
226 strncpy(pathdir
, ps_global
->pwdcertdir
, sizeof(pathdir
));
227 pathdir
[sizeof(pathdir
)-1] = '\0';
230 smime_path(DF_PASSWORD_DIR
, pathdir
, sizeof(pathdir
));
231 if(our_stat(pathdir
, &sbuf
) == 0){
232 if((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
)
234 } else if(can_access(pathdir
, ACCESS_EXISTS
) != 0
235 && our_mkpath(pathdir
, 0700) == 0)
244 if(load_key_and_cert(pathdir
, pathdir
, &keyfile
, &certfile
, &pkey
, &pcert
) < 0){
250 if(ps_global
->pwdcertdir
== NULL
) /* save the result of pwdcertdir */
251 ps_global
->pwdcertdir
= cpystr(pathdir
);
253 if(certfile
&& keyfile
){
254 pc
= (PERSONAL_CERT
*) fs_get(sizeof(PERSONAL_CERT
));
255 memset((void *)pc
, 0, sizeof(PERSONAL_CERT
));
259 pc
->cname
= certfile
;
260 *pwdcert
= (void *) pc
;
265 /* if the user gave a pwdcertdir and there is nothing there, do not
266 * continue. Let the user initialize on their own this directory.
268 if(ps_global
->pwdcertdir
!= NULL
){
273 /* look to see if there are any certificates lying around, first
274 * we try to load ps_global->smime to see if that has information
275 * we can use. If we are the process filling the smime structure
276 * we deinit at the end, since this might not do a full init.
278 if(ps_global
&& ps_global
->smime
&& !ps_global
->smime
->inited
){
283 /* at this point ps_global->smime->inited == 1 */
284 if(ps_global
->smime
&& ps_global
->smime
->personal_certs
!= NULL
){
285 pc
= (PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
286 if(ps_global
->smime
->privatetype
== Directory
){
287 build_path(pathkey
, ps_global
->smime
->privatepath
, pc
->name
, sizeof(pathkey
));
288 strncat(pathkey
, ".key", 4);
289 pathkey
[sizeof(pathkey
)-1] = '\0';
291 } else if (ps_global
->smime
->privatetype
== Container
){
292 if(pc
->keytext
== NULL
){ /* we should *never* be here, but just in case */
293 if(ps_global
->smime
->privatecontent
!= NULL
){
294 char tmp
[MAILTMPLEN
], *s
, *t
, c
;
295 snprintf(tmp
, sizeof(tmp
), "%s%s", EMAILADDRLEADER
, pc
->name
);
296 tmp
[sizeof(tmp
)-1] = '\0';
297 if((s
= strstr(ps_global
->smime
->privatecontent
, tmp
)) != NULL
){
298 if((t
= strstr(s
+strlen(tmp
), EMAILADDRLEADER
)) != NULL
){
301 pc
->keytext
= cpystr(s
+ strlen(tmp
) + 1); /* 1 = strlen("\n") */
305 pc
->keytext
= cpystr(s
+ strlen(tmp
) + 1); /* 1 = strlen("\n") */
309 if(pc
->keytext
!= NULL
) /* we should go straigth here */
311 } else if (ps_global
->smime
->privatetype
== Keychain
){
312 pathkey
[0] = '\0'; /* no apple key chain support yet */
315 if((pathkey
&& *pathkey
) || text
){
316 snprintf(prompt
, sizeof(prompt
),
317 _("Enter password of key <%s> to unlock password file: "), pc
->name
);
319 if((pkey
= load_pkey_with_prompt(pathkey
, text
, prompt
, NULL
)) != NULL
){
320 pc2
= (PERSONAL_CERT
*) fs_get(sizeof(PERSONAL_CERT
));
321 memset((void *)pc2
, 0, sizeof(PERSONAL_CERT
));
322 pc2
->name
= cpystr(pc
->name
);
324 pc2
->cert
= X509_dup(pc
->cert
);
326 /* now copy the keys and certs, starting by the key... */
327 build_path(fpath
, pathdir
, pc
->name
, sizeof(fpath
));
328 strncat(fpath
, ".key", 4);
329 fpath
[sizeof(fpath
)-1] = '\0';
330 if(our_stat(fpath
, &sbuf
) == 0){ /* if fpath exists */
331 if((sbuf
.st_mode
& S_IFMT
) == S_IFREG
) /* and is a regular file */
332 setup_dir
++; /* we are done */
333 } else if(ps_global
->smime
->privatetype
== Directory
){
334 if(our_copy(fpath
, pathkey
) == 0)
336 } else if(ps_global
->smime
->privatetype
== Container
){
338 if((out
= BIO_new_file(fpath
, "w")) != NULL
){
339 if(BIO_puts(out
, pc
->keytext
) > 0)
343 } else if(ps_global
->smime
->privatetype
== Keychain
){
344 /* add support for Apple Mac OS X */
348 /* successful copy of key, now continue with certificate */
352 build_path(pathkey
, ps_global
->smime
->publicpath
, pc
->name
, sizeof(pathkey
));
353 strncat(pathkey
, ".crt", 4);
354 pathkey
[sizeof(pathkey
)-1] = '\0';
356 build_path(fpath
, pathdir
, pc
->name
, sizeof(fpath
));
357 strncat(fpath
, ".crt", 4);
358 fpath
[sizeof(fpath
)-1] = '\0';
360 if(our_stat(fpath
, &sbuf
) == 0){
361 if((sbuf
.st_mode
& S_IFMT
) == S_IFREG
)
364 else if(ps_global
->smime
->privatetype
== Directory
){
365 if(our_copy(fpath
, pathkey
) == 0)
367 } else if(ps_global
->smime
->privatetype
== Container
) {
369 if((out
= BIO_new_file(fpath
, "w")) != NULL
){
370 if(PEM_write_bio_X509(out
, pc
->cert
))
374 } else if (ps_global
->smime
->privatetype
== Keychain
) {
375 /* add support for Mac OS X */
380 *pwdcert
= (void *) pc2
;
385 free_personal_certs(&pc2
);
386 } /* if (pathkey...) */
387 } /* if(ps_global->smime->personal_certs) */
391 /* PATHCERTDIR(Private) must be null, so create a path */
392 set_current_val(&ps_global
->vars
[V_PRIVATEKEY_DIR
], TRUE
, TRUE
);
393 smime_path(ps_global
->VAR_PRIVATEKEY_DIR
, pathkey
, sizeof(pathkey
));
395 /* PATHCERTDIR(Public) must be null, so create a path */
396 set_current_val(&ps_global
->vars
[V_PUBLICCERT_DIR
], TRUE
, TRUE
);
397 smime_path(ps_global
->VAR_PUBLICCERT_DIR
, pathcert
, sizeof(pathcert
));
399 /* BUG: this does not support local containers */
400 load_key_and_cert(pathkey
, pathcert
, &keyfile
, &certfile
, &pkey
, &pcert
);
402 if(certfile
&& keyfile
){
403 build_path(fpath
, pathdir
, keyfile
, sizeof(fpath
));
404 strncat(fpath
, ".key", 4);
405 fpath
[sizeof(fpath
)-1] = '\0';
407 build_path(fpath2
, pathkey
, keyfile
, sizeof(fpath
));
408 strncat(fpath2
, ".key", 4);
409 fpath2
[sizeof(fpath2
)-1] = '\0';
411 if(our_copy(fpath
, fpath2
) == 0)
417 build_path(fpath
, pathdir
, certfile
, sizeof(fpath
));
418 build_path(fpath2
, pathcert
, certfile
, sizeof(fpath2
));
420 if(our_copy(fpath
, fpath2
) == 0)
426 if(keyfile
&& certfile
){
427 pc
= (PERSONAL_CERT
*) fs_get(sizeof(PERSONAL_CERT
));
428 memset((void *)pc
, 0, sizeof(PERSONAL_CERT
));
432 *pwdcert
= (void *) pc
;
433 fs_give((void **)&certfile
);
438 /* TODO: create self signed certificate
439 q_status_message(SM_ORDER, 2, 2,
440 _("No key/certificate pair found for password file encryption support"));
446 #endif /* PASSFILE */
448 /* smime_expunge_cert.
449 * Return values: < 0 there was an error.
450 * >=0 the number of messages expunged
453 smime_expunge_cert(WhichCerts ctype
)
456 CertList
*cl
, *dummy
, *data
;
457 char *path
, buf
[MAXPATH
+1];
460 if(DATACERT(ctype
)== NULL
)
463 /* data cert is the way we unify certificate management across
464 * functions, but it is not where we really save the information in the
465 * case ctype is equal to Private. What we will do is to update the
466 * datacert, and in the case of ctype equal to Private use the updated
467 * certdata to update the personal_certs data.
470 path
= PATHCERTDIR(ctype
);
473 /* add a fake certificate at the beginning of the list */
474 dummy
= fs_get(sizeof(CertList
));
475 memset((void *)dummy
, 0, sizeof(CertList
));
476 dummy
->next
= DATACERT(ctype
);
478 for(cl
= dummy
, count
= 0; cl
&& cl
->next
;){
479 if(cl
->next
->data
.deleted
== 0){
484 removed
= 1; /* assume success */
485 if(SMHOLDERTYPE(ctype
) == Directory
){
486 build_path(buf
, path
, cl
->next
->name
, sizeof(buf
));
487 if(ctype
== Private
&& strlen(buf
) + strlen(EXTCERT(Private
)) < sizeof(buf
)){
488 strncat(buf
, EXTCERT(Private
), 4);
489 buf
[sizeof(buf
)-1] = '\0';
492 if(our_unlink(buf
) < 0){
493 q_status_message1(SM_ORDER
, 3, 3, _("Error removing certificate %s"), cl
->next
->name
);
498 else if(SMHOLDERTYPE(ctype
) == Container
){
499 char *prefix
= ctype
== CACert
? CACERTSTORELEADER
: EMAILADDRLEADER
;
500 char tmp
[MAILTMPLEN
], *s
, *t
;
502 contents
= CONTENTCERTLIST(ctype
);
503 snprintf(tmp
, sizeof(tmp
), "%s%s", prefix
, cl
->next
->name
);
504 tmp
[sizeof(tmp
) - 1] = '\0';
505 if((s
= strstr(contents
, tmp
)) != NULL
){
506 if((t
= strstr(s
+strlen(tmp
), prefix
)) == NULL
)
509 memmove(s
, t
, strlen(t
)+1);
510 fs_resize((void **)&contents
, strlen(contents
)+1);
512 case Private
: ps_global
->smime
->privatecontent
= contents
; break;
513 case Public
: ps_global
->smime
->publiccontent
= contents
; break;
514 case CACert
: ps_global
->smime
->cacontent
= contents
; break;
520 } else { /* unhandled case */
524 count
++; /* count it! */
526 cl
->next
= data
->next
;
527 if(data
->name
) fs_give((void **)&data
->name
);
528 fs_give((void **)&data
);
532 q_status_message(SM_ORDER
, 3, 3, _("Error expunging certificate"));
535 case Private
: ps_global
->smime
->privatecertlist
= dummy
->next
; break;
536 case Public
: ps_global
->smime
->publiccertlist
= dummy
->next
; break;
537 case CACert
: ps_global
->smime
->cacertlist
= dummy
->next
; break;
540 fs_give((void **)&dummy
);
541 if(SMHOLDERTYPE(ctype
) == Container
){
542 if(copy_dir_to_container(ctype
, contents
) < 0)
546 q_status_message2(SM_ORDER
, 3, 3, _("Removed %s certificate%s"), comatose(count
), plural(count
));
549 q_status_message(SM_ORDER
, 3, 3, _("Error: No certificates were removed"));
554 mark_cert_deleted(WhichCerts ctype
, int num
, unsigned state
)
559 for(cl
= DATACERT(ctype
), i
= 0; cl
!= NULL
&& i
< num
; cl
= cl
->next
, i
++);
560 cl
->data
.deleted
= state
;
564 get_cert_deleted(WhichCerts ctype
, int num
)
569 for(cl
= DATACERT(ctype
), i
= 0; cl
!= NULL
&& i
< num
; cl
= cl
->next
, i
++);
570 return (cl
&& cl
->data
.deleted
) ? 1 : 0;
574 load_pkey_with_prompt(char *fpath
, char *text
, char *prompt
, int *ret
)
577 int rc
= 0; /* rc == 1, cancel, rc == 0 success */
578 char pass
[MAILTMPLEN
+1];
581 /* attempt to load with empty password */
582 in
= text
? BIO_new_mem_buf(text
, strlen(text
)) : BIO_new_file(fpath
, "r");
584 pkey
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, "");
585 if(pkey
!= NULL
) return pkey
;
588 if(pith_smime_enter_password
)
589 while(pkey
== NULL
&& rc
!= 1){
591 rc
= (*pith_smime_enter_password
)(prompt
, (char *)pass
, sizeof(pass
));
592 } while (rc
!=0 && rc
!=1 && rc
>0);
594 (void) BIO_reset(in
);
595 pkey
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, (char *)pass
);
600 if(ret
) *ret
= rc
== 1 ? -1 : pkey
!= NULL
? 0 : 1;
604 /* This is a tool for conf_screen, The return value must be zero when
605 * nothing changed, so if there is a failure in the import return 0
606 * and return 1 when we succeeded
609 import_certificate(WhichCerts ctype
)
612 char filename
[MAXPATH
+1], full_filename
[MAXPATH
+1], buf
[MAXPATH
+1];
614 if(pith_smime_import_certificate
== NULL
){
615 q_status_message(SM_ORDER
, 0, 2,
616 _("import of certificates not implemented yet!"));
620 r
= (*pith_smime_import_certificate
)(filename
, full_filename
, sizeof(filename
) - 20);
625 /* we are trying to import a new key for the password file. First we ask for the
626 * private key. Once this is loaded, we make a reasonable attempt to find the
627 * public key in the same directory as the key was loaded from. We do this by
628 * looking for a file with the correct public certificate name, then we look
629 * in the same private key, and if not, we ask the user for its location. If all
630 * of this works, we import the key and public to the password directory.
632 if(ctype
== Password
){
633 char PrivateKeyPath
[MAXPATH
+1], PublicCertPath
[MAXPATH
+1], s
[MAXPATH
+1];
634 char full_name_key
[MAXPATH
+1], full_name_cert
[MAXPATH
+1];
637 EVP_PKEY
*key
= NULL
;
639 rc
= 1; /* assume success :) */
640 if(strlen(filename
) > 4){
641 strncpy(s
, filename
, sizeof(s
));
642 s
[sizeof(s
)-1] = '\0';
643 if(!strcmp(s
+ strlen(s
) - strlen(EXTCERT(Private
)), EXTCERT(Private
)))
644 s
[strlen(s
) - strlen(EXTCERT(Private
))] = '\0';
650 q_status_message(SM_ORDER
, 1, 3, _("Error in key name. Check file extension"));
654 snprintf(prompt
, sizeof(prompt
), _("Enter passphrase for <%s>: "), filename
);
655 prompt
[sizeof(prompt
)-1] = '\0';
656 if((key
= load_pkey_with_prompt(full_filename
, NULL
, prompt
, NULL
)) != NULL
){
660 strncpy(full_name_key
, full_filename
, sizeof(full_filename
));
661 full_name_key
[sizeof(full_name_key
)-1] = '\0';
663 build_path(buf
, PATHCERTDIR(ctype
), s
, sizeof(buf
));
665 strncpy(PrivateKeyPath
, buf
, sizeof(PrivateKeyPath
));
666 PrivateKeyPath
[sizeof(PrivateKeyPath
)-1] = '\0';
667 if(strlen(PrivateKeyPath
) + 4 < sizeof(PrivateKeyPath
)){
668 strncat(PrivateKeyPath
, EXTCERT(Private
), 4);
669 PrivateKeyPath
[sizeof(PrivateKeyPath
)-1] = '\0';
672 /* remove .key extension and replace it with .crt extension */
673 strncpy(full_name_cert
, full_name_key
, sizeof(full_name_key
));
674 full_name_cert
[sizeof(full_name_cert
)-1] = '\0';
675 full_name_cert
[strlen(full_name_cert
) - strlen(EXTCERT(Private
))] = '\0';
676 strncat(full_name_cert
, EXTCERT(Public
), 4);
677 full_name_cert
[sizeof(full_name_cert
)-1] = '\0';
680 /* set up path to location where we will save public cert */
681 strncpy(PublicCertPath
, buf
, sizeof(PublicCertPath
));
682 PublicCertPath
[sizeof(PublicCertPath
)-1] = '\0';
683 if(strlen(PublicCertPath
) + 4 < sizeof(PublicCertPath
)){
684 strncat(PublicCertPath
, EXTCERT(Public
), 4);
685 PublicCertPath
[sizeof(PublicCertPath
)-1] = '\0';
688 /* attempt #1 to guess public cert name, use .crt extension */
689 if((ins
= BIO_new_file(full_name_cert
, "r")) != NULL
){
690 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
){
691 use_this_file
= &full_name_cert
[0];
695 /* attempt #2 to guess public cert name: user the original key */
696 if((ins
= BIO_new_file(full_name_key
, "r")) != NULL
){
697 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
){
698 use_this_file
= &full_name_key
[0];
703 /* attempt #3, ask the user */
705 r
= (*pith_smime_import_certificate
)(filename
, use_this_file
, sizeof(filename
) - 20);
707 if(ins
!= NULL
) BIO_free(ins
);
708 if(cert
!= NULL
) X509_free(cert
);
711 if((ins
= BIO_new_file(use_this_file
, "r")) != NULL
){
712 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
)
715 q_status_message(SM_ORDER
, 1, 3, _("Error parsing certificate"));
718 q_status_message(SM_ORDER
, 1, 3, _("Error reading certificate"));
723 if(cert
!= NULL
){ /* check that certificate matches key */
724 if(!X509_check_private_key(cert
, key
)){
726 q_status_message(SM_ORDER
, 1, 3, _("Certificate does not match key"));
729 rc
= 1; /* Success! */
732 q_status_message(SM_ORDER
, 1, 3, _("Error in certificate file (not a certificate?)"));
734 if(rc
== 1){ /* if everything has been successful,
735 * copy the files to their final destination */
736 if(our_copy(PrivateKeyPath
, full_filename
) == 0){ /* <-- save the private key */
737 q_status_message(SM_ORDER
, 1, 3, _("Private key saved"));
738 if(our_copy(PublicCertPath
, use_this_file
) == 0){
739 char tmp
[MAILTMPLEN
];
742 if(!passfile_name(ps_global
->pinerc
, tmp
, sizeof(tmp
))
743 || !(fp
= our_fopen(tmp
, "rb"))){
744 q_status_message(SM_ORDER
, 1, 3, _("Error reading password file!"));
748 char tmp2
[MAILTMPLEN
];
751 PERSONAL_CERT
*pwdcert
, *pc
;
753 pwdcert
= (PERSONAL_CERT
*) ps_global
->pwdcert
;
755 setup_pwdcert((void **)&pwdcert
);
758 fgets(tmp2
, sizeof(tmp2
), fp
);
760 if(strcmp(tmp2
, "-----BEGIN PKCS7-----\n")){
761 if(encrypt_file((char *)tmp
, NULL
, pwdcert
))
768 text
= decrypt_file((char *)tmp
, NULL
, pwdcert
);
770 pc
= fs_get(sizeof(PERSONAL_CERT
));
771 memset((void *)pc
, 0, sizeof(PERSONAL_CERT
));
772 filename
[strlen(filename
)-strlen(EXTCERT(Private
))] = '\0';
773 pc
->name
= cpystr(filename
);
774 snprintf(buf
, sizeof(buf
), "%s%s", filename
, EXTCERT(Public
));
775 buf
[sizeof(buf
)-1] = '\0';
776 pc
->cname
= cpystr(buf
);
780 if(encrypt_file((char *)tmp
, text
, pc
)){ /* we did it! */
781 build_path(buf
, PATHCERTDIR(ctype
), pwdcert
->name
, sizeof(buf
));
782 strncat(buf
, EXTCERT(Private
), 4);
783 buf
[sizeof(buf
)-1] = '\0';
785 q_status_message(SM_ORDER
, 1, 3, _("Failed to remove old key"));
786 build_path(buf
, PATHCERTDIR(ctype
), pwdcert
->cname
, sizeof(buf
));
788 q_status_message(SM_ORDER
, 1, 3, _("Failed to remove old certificate"));
789 free_personal_certs((PERSONAL_CERT
**)&ps_global
->pwdcert
);
790 ps_global
->pwdcert
= pc
;
792 q_status_message(SM_ORDER
, 1, 3, _("Password file reencrypted"));
794 q_status_message(SM_ORDER
, 1, 3, _("Failed to reencrypt password file"));
798 q_status_message(SM_ORDER
, 1, 3, _("Error decrypting Password file"));
801 q_status_message(SM_ORDER
, 1, 3, _("Password file not encrypted and coulr not encrypt"));
807 q_status_message(SM_ORDER
, 1, 3, _("Error saving public certificate"));
808 if(our_unlink(PrivateKeyPath
) < 0)
809 q_status_message(SM_ORDER
, 1, 3, _("Error while cleaning private key"));
815 q_status_message(SM_ORDER
, 1, 3, _("Error saving private key"));
817 if(ins
!= NULL
) BIO_free(ins
);
818 if(rc
== 0 && cert
!= NULL
) X509_free(cert
);
822 q_status_message(SM_ORDER
, 1, 3, _("Error unlocking private key"));
829 ps_global
->mangled_screen
= 1;
831 if (ctype
== Private
){
832 char prompt
[500], *s
, *t
;
833 EVP_PKEY
*key
= NULL
;
835 if(!ps_global
->smime
->privatecertlist
){
836 ps_global
->smime
->privatecertlist
= fs_get(sizeof(CertList
));
837 memset((void *)DATACERT(ctype
), 0, sizeof(CertList
));
840 for(s
= t
= filename
; (t
= strstr(s
, ".key")) != NULL
; s
= t
+ 1);
843 snprintf(prompt
, sizeof(prompt
), _("Enter passphrase for <%s>: "), filename
);
844 prompt
[sizeof(prompt
)-1] = '\0';
845 if((key
= load_pkey_with_prompt(full_filename
, NULL
, prompt
, NULL
)) != NULL
){
846 if(SMHOLDERTYPE(ctype
) == Directory
){
847 build_path(buf
, PATHCERTDIR(ctype
), filename
, sizeof(buf
));
848 if(strcmp(buf
+ strlen(buf
) - 4, EXTCERT(ctype
)) != 0 && strlen(buf
) + 4 < sizeof(buf
)){
849 strncat(buf
, EXTCERT(ctype
), 4);
850 buf
[sizeof(buf
)-1] = '\0';
852 rc
= our_copy(buf
, full_filename
);
854 else /* if(SMHOLDERTYPE(ctype) == Container){ */
855 rc
= add_file_to_container(ctype
, full_filename
, NULL
);
857 q_status_message(SM_ORDER
, 1, 3, _("Private key saved"));
859 q_status_message(SM_ORDER
, 1, 3, _("Error saving private key"));
860 if(ps_global
->smime
->publiccertlist
)
861 ps_global
->smime
->publiccertlist
->data
.renew
= 1;
864 q_status_message(SM_ORDER
, 1, 3, _("Problem unlocking key (not a certificate or wrong password)"));
865 } else if (ctype
== CACert
){
869 if((ins
= BIO_new_file(full_filename
, "r")) != NULL
){
870 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
){
871 if(SMHOLDERTYPE(ctype
) == Directory
){
872 build_path(buf
, PATHCERTDIR(ctype
), filename
, sizeof(buf
));
873 if(strcmp(buf
+ strlen(buf
) - 4, ".crt") != 0 && strlen(buf
) + 4 < sizeof(buf
)){
874 strncat(buf
, EXTCERT(ctype
), 4);
875 buf
[sizeof(buf
)-1] = '\0';
878 rc
= our_copy(buf
, full_filename
);
880 else /* if(SMHOLDERTYPE(ctype) == Container){ */
881 rc
= add_file_to_container(ctype
, full_filename
, NULL
);
883 q_status_message(SM_ORDER
, 1, 3, _("Certificate saved"));
885 q_status_message(SM_ORDER
, 1, 3, _("Error saving certificate"));
886 X509_free(cert
); /* not needed anymore */
889 q_status_message(SM_ORDER
, 1, 3, _("Error in certificate file (not a certificate?)"));
893 } else { /* ctype == Public. save certificate, but first validate that it is one */
897 if((ins
= BIO_new_file(full_filename
, "r")) != NULL
){
898 if((cert
= PEM_read_bio_X509(ins
, NULL
, NULL
, NULL
)) != NULL
){
899 if(SMHOLDERTYPE(ctype
) == Directory
){
902 if((email
= get_x509_subject_email(cert
)) != NULL
){
904 for(i
= 0; email
[i
] != NULL
; i
++){
905 save_cert_for(email
[i
], cert
, Public
);
906 fs_give((void **)&email
[i
]);
908 fs_give((void **)email
);
910 if(strcmp(filename
+ strlen(filename
) - 4, ".crt") == 0)
911 filename
[strlen(filename
) - 4] = '\0';
912 save_cert_for(filename
, cert
, Public
);
914 else /* if(SMHOLDERTYPE(ctype) == Container){ */
915 add_file_to_container(ctype
, full_filename
, NULL
);
917 if(ps_global
->smime
->publiccertlist
)
918 ps_global
->smime
->publiccertlist
->data
.renew
= 1;
921 q_status_message(SM_ORDER
, 1, 3, _("Error in certificate file (not a certificate?)"));
925 if(DATACERT(ctype
)) RENEWCERT(DATACERT(ctype
)) = 1;
929 /* itype: information type to add: 0 - public, 1 - private.
930 * Memory freed by caller
933 print_private_key_information(char *email
, int itype
)
938 if(ps_global
->smime
== NULL
939 || ps_global
->smime
->personal_certs
== NULL
940 || (itype
!= 0 && itype
!= 1))
943 for(pc
= ps_global
->smime
->personal_certs
;
944 pc
!= NULL
&& strcmp(pc
->name
, email
) != 0; pc
= pc
->next
);
946 && !load_private_key(pc
)
948 && ps_global
->smime
->need_passphrase
){
949 if (*pith_opt_smime_get_passphrase
)
950 (*pith_opt_smime_get_passphrase
)();
951 load_private_key(pc
);
957 out
= BIO_new(BIO_s_mem());
958 if(itype
== 0) /* 0 means public */
959 EVP_PKEY_print_public(out
, pc
->key
, 0, NULL
);
960 else if (itype
== 1) /* 1 means private */
961 EVP_PKEY_print_private(out
, pc
->key
, 0, NULL
);
963 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
964 forget_private_keys();
970 * Forget any cached private keys
973 forget_private_keys(void)
975 PERSONAL_CERT
*pcert
;
979 dprint((9, "forget_private_keys()"));
980 if(ps_global
->smime
){
981 for(pcert
=(PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
986 EVP_PKEY_free(pcert
->key
);
991 ps_global
->smime
->entered_passphrase
= 0;
992 len
= sizeof(ps_global
->smime
->passphrase
);
993 p
= ps_global
->smime
->passphrase
;
1000 /* modelled after signature_path in reply.c, but uses home dir instead of the
1001 * directory where the .pinerc is located, since according to documentation,
1002 * the .alpine-smime directories are subdirectories of the home directory
1004 int smime_path(char *rpath
, char *fpath
, size_t len
)
1007 if(rpath
&& *rpath
){
1008 size_t spl
= strlen(rpath
);
1010 if(IS_REMOTE(rpath
)){
1012 strncpy(fpath
, rpath
, len
-1);
1013 fpath
[len
-1] = '\0';
1015 else if(is_absolute_path(rpath
)){
1016 strncpy(fpath
, rpath
, len
-1);
1017 fpath
[len
-1] = '\0';
1018 fnexpand(fpath
, len
);
1020 else if(ps_global
->VAR_OPER_DIR
){
1021 if(strlen(ps_global
->VAR_OPER_DIR
) + spl
< len
- 1)
1022 build_path(fpath
, ps_global
->VAR_OPER_DIR
, rpath
, len
);
1024 else if(ps_global
->home_dir
){
1025 if(strlen(ps_global
->home_dir
) + spl
< len
- 1)
1026 build_path(fpath
, ps_global
->home_dir
, rpath
, len
);
1029 return fpath
&& *fpath
? 1 : 0;
1035 * taken from openssl/apps/app_rand.c
1038 app_RAND_load_file(const char *file
)
1040 #define RANDBUFLEN 200
1041 char buffer
[RANDBUFLEN
];
1044 file
= RAND_file_name(buffer
, RANDBUFLEN
);
1046 if(file
== NULL
|| !RAND_load_file(file
, -1)){
1047 if(RAND_status() == 0){
1048 dprint((1, "unable to load 'random state'\n"));
1049 dprint((1, "This means that the random number generator has not been seeded\n"));
1050 dprint((1, "with much random data.\n"));
1062 * copied and fiddled from imap/src/osdep/unix/auth_ssl.c
1065 openssl_extra_randomness(void)
1073 /* if system doesn't have /dev/urandom */
1074 if(stat ("/dev/urandom", &sbuf
)){
1076 tf
= temp_nam(NULL
, NULL
);
1078 strncpy(tmp
, tf
, sizeof(tmp
));
1079 tmp
[sizeof(tmp
)-1] = '\0';
1080 fs_give((void **) &tf
);
1083 if((fd
= open(tmp
, O_WRONLY
|O_CREAT
|O_EXCL
, 0600)) < 0)
1084 i
= (unsigned long) tmp
;
1086 unlink(tmp
); /* don't need the file */
1087 fstat(fd
, &sbuf
); /* get information about the file */
1088 i
= sbuf
.st_ino
; /* remember its inode */
1089 close(fd
); /* or its descriptor */
1091 /* not great but it'll have to do */
1092 snprintf(tmp
+strlen(tmp
), sizeof(tmp
)-strlen(tmp
), "%.80s%lx%lx%lx",
1093 tcp_serverhost (),i
,
1094 (unsigned long) (time (0) ^ gethostid ()),
1095 (unsigned long) getpid ());
1096 RAND_seed(tmp
, strlen(tmp
));
1102 /* taken from openssl/apps/app_rand.c */
1104 app_RAND_write_file(const char *file
)
1110 * If we did not manage to read the seed file,
1111 * we should not write a low-entropy seed file back --
1112 * it would suppress a crucial warning the next time
1113 * we want to use it.
1118 file
= RAND_file_name(buffer
, sizeof buffer
);
1120 if(file
== NULL
|| !RAND_write_file(file
)){
1121 dprint((1, "unable to write 'random state'\n"));
1129 certlist_from_personal_certs(PERSONAL_CERT
*pc
)
1137 if((x
= get_cert_for(pc
->name
, Public
, 1)) != NULL
){
1138 cl
= smime_X509_to_cert_info(x
, pc
->name
);
1141 cl
->next
= certlist_from_personal_certs(pc
->next
);
1147 renew_cert_data(CertList
**data
, WhichCerts ctype
)
1150 if(ctype
== Private
){
1152 PERSONAL_CERT
*pc
= (PERSONAL_CERT
*)ps_global
->smime
->personal_certs
;
1154 free_certlist(data
);
1155 free_personal_certs(&pc
);
1156 setup_privatekey_storage();
1157 *data
= certlist_from_personal_certs((PERSONAL_CERT
*)ps_global
->smime
->personal_certs
);
1159 resort_certificates(data
, ctype
);
1160 RENEWCERT(*data
) = 0;
1162 ps_global
->smime
->privatecertlist
= *data
;
1164 if(ps_global
->smime
->privatecertlist
)
1165 RENEWCERT(ps_global
->smime
->privatecertlist
) = 0;
1167 X509_LOOKUP
*lookup
= NULL
;
1168 X509_STORE
*store
= NULL
;
1170 if((store
= X509_STORE_new()) != NULL
){
1171 if((lookup
= X509_STORE_add_lookup(store
, X509_LOOKUP_file())) == NULL
){
1172 X509_STORE_free(store
);
1175 free_certlist(data
);
1176 if(SMHOLDERTYPE(ctype
) == Directory
)
1177 add_certs_in_dir(lookup
, PATHCERTDIR(ctype
), EXTCERT(ctype
), data
);
1178 else /* if(SMHOLDERTYPE(ctype) == Container) */
1179 *data
= mem_to_certlist(CONTENTCERTLIST(ctype
), ctype
);
1181 resort_certificates(data
, ctype
);
1182 RENEWCERT(*data
) = 0;
1185 ps_global
->smime
->publiccertlist
= *data
;
1187 ps_global
->smime
->cacertlist
= *data
;
1191 setup_certs_backup_by_type(ctype
);
1201 /* Installed as an atexit() handler to save the random data */
1205 dprint((9, "smime_deinit()"));
1206 app_RAND_write_file(NULL
);
1207 free_smime_struct(&ps_global
->smime
);
1210 /* we renew the store when it has changed */
1211 void renew_store(void)
1213 if(ps_global
->smime
->inited
){
1214 if(s_cert_store
!= NULL
)
1215 X509_STORE_free(s_cert_store
);
1216 s_cert_store
= get_ca_store();
1220 /* Initialise openssl stuff if needed */
1224 if(F_OFF(F_DONT_DO_SMIME
, ps_global
) && !(ps_global
->smime
&& ps_global
->smime
->inited
)){
1226 dprint((9, "smime_init()"));
1227 if(!ps_global
->smime
)
1228 ps_global
->smime
= new_smime_struct();
1230 setup_storage_locations();
1232 s_cert_store
= get_ca_store();
1233 setup_certs_backup_by_type(CACert
);
1235 OpenSSL_add_all_algorithms();
1236 ERR_load_crypto_strings();
1238 app_RAND_load_file(NULL
);
1239 openssl_extra_randomness();
1240 ps_global
->smime
->inited
= 1;
1247 /* validate a certificate. Return value : 0 for no error, -1 for error.
1248 * In the latter case, set the openssl smime error in *error.
1250 int smime_validate_cert(X509
*cert
, long *error
)
1252 X509_STORE_CTX
*csc
;
1256 if((csc
= X509_STORE_CTX_new()) != NULL
){
1257 X509_STORE_set_flags(s_cert_store
, 0);
1258 if(X509_STORE_CTX_init(csc
,s_cert_store
,cert
,NULL
)
1259 && X509_verify_cert(csc
) <= 0)
1260 *error
= X509_STORE_CTX_get_error(csc
);
1261 X509_STORE_CTX_free(csc
);
1263 return *error
? -1 : 0;
1267 get_personal_certs(char *path
)
1269 PERSONAL_CERT
*result
= NULL
;
1274 ps_global
->smime
->privatepath
= cpystr(path
);
1275 dirp
= opendir(path
);
1277 while((d
=readdir(dirp
)) != NULL
){
1281 if((ll
=strlen(d
->d_name
)) && ll
> 4 && !strcmp(d
->d_name
+ll
-4, ".key")){
1283 /* copy file name to temp buffer */
1284 strncpy(buf2
, d
->d_name
, sizeof(buf2
)-1);
1285 buf2
[sizeof(buf2
)-1] = '\0';
1286 /* chop off ".key" trailier */
1287 buf2
[strlen(buf2
)-4] = 0;
1288 /* Look for certificate */
1289 cert
= get_cert_for(buf2
, Public
, 1);
1294 /* create a new PERSONAL_CERT, fill it in */
1296 pc
= (PERSONAL_CERT
*) fs_get(sizeof(*pc
));
1298 pc
->name
= cpystr(buf2
);
1300 /* Try to load the key with an empty password */
1301 pc
->key
= load_key(pc
, "", SM_NORMALCERT
);
1315 setup_privatekey_storage(void)
1317 char path
[MAXPATH
+1], *contents
;
1318 int privatekeycontainer
= 0;
1320 /* private keys in a container */
1321 if(ps_global
->VAR_PRIVATEKEY_CONTAINER
&& ps_global
->VAR_PRIVATEKEY_CONTAINER
[0]){
1323 privatekeycontainer
= 1;
1326 if(!smime_path(ps_global
->VAR_PRIVATEKEY_CONTAINER
, path
, MAXPATH
))
1327 privatekeycontainer
= 0;
1329 if(privatekeycontainer
&& !IS_REMOTE(path
)
1330 && ps_global
->VAR_OPER_DIR
1331 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
1332 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1333 /* TRANSLATORS: First arg is the directory name, second is
1334 the file user wants to read but can't. */
1335 _("Can't read file outside %s: %s"),
1336 ps_global
->VAR_OPER_DIR
, path
);
1337 privatekeycontainer
= 0;
1340 if(privatekeycontainer
1341 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
1342 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
1344 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
1345 privatekeycontainer
= 0;
1348 if(privatekeycontainer
&& path
[0]){
1349 ps_global
->smime
->privatetype
= Container
;
1350 ps_global
->smime
->privatepath
= cpystr(path
);
1353 ps_global
->smime
->privatecontent
= contents
;
1354 ps_global
->smime
->personal_certs
= mem_to_personal_certs(contents
);
1359 /* private keys in a directory of files */
1360 if(!privatekeycontainer
){
1361 ps_global
->smime
->privatetype
= Directory
;
1364 if(!(smime_path(ps_global
->VAR_PRIVATEKEY_DIR
, path
, MAXPATH
)
1365 && !IS_REMOTE(path
)))
1366 ps_global
->smime
->privatetype
= Nada
;
1367 else if(can_access(path
, ACCESS_EXISTS
)){
1368 if(our_mkpath(path
, 0700)){
1369 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1370 ps_global
->smime
->privatetype
= Nada
;
1374 if(ps_global
->smime
->privatetype
== Directory
)
1375 ps_global
->smime
->personal_certs
= get_personal_certs(path
);
1377 setup_certs_backup_by_type(Private
);
1383 setup_storage_locations(void)
1385 int publiccertcontainer
= 0, cacertcontainer
= 0;
1386 char path
[MAXPATH
+1], *contents
;
1388 if(!ps_global
->smime
)
1391 #ifdef APPLEKEYCHAIN
1392 if(F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
1393 ps_global
->smime
->publictype
= Keychain
;
1396 #endif /* APPLEKEYCHAIN */
1397 /* Public certificates in a container */
1398 if(ps_global
->VAR_PUBLICCERT_CONTAINER
&& ps_global
->VAR_PUBLICCERT_CONTAINER
[0]){
1400 publiccertcontainer
= 1;
1403 if(!smime_path(ps_global
->VAR_PUBLICCERT_CONTAINER
, path
, MAXPATH
))
1404 publiccertcontainer
= 0;
1406 if(publiccertcontainer
&& !IS_REMOTE(path
)
1407 && ps_global
->VAR_OPER_DIR
1408 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
1409 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1410 /* TRANSLATORS: First arg is the directory name, second is
1411 the file user wants to read but can't. */
1412 _("Can't read file outside %s: %s"),
1413 ps_global
->VAR_OPER_DIR
, path
);
1414 publiccertcontainer
= 0;
1417 if(publiccertcontainer
1418 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
1419 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
1421 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
1422 publiccertcontainer
= 0;
1425 if(publiccertcontainer
&& path
[0]){
1426 ps_global
->smime
->publictype
= Container
;
1427 ps_global
->smime
->publicpath
= cpystr(path
);
1430 ps_global
->smime
->publiccontent
= contents
;
1431 ps_global
->smime
->publiccertlist
= mem_to_certlist(contents
, Public
);
1436 /* Public certificates in a directory of files */
1437 if(!publiccertcontainer
){
1438 ps_global
->smime
->publictype
= Directory
;
1441 if(!(smime_path(ps_global
->VAR_PUBLICCERT_DIR
, path
, MAXPATH
)
1442 && !IS_REMOTE(path
)))
1443 ps_global
->smime
->publictype
= Nada
;
1444 else if(can_access(path
, ACCESS_EXISTS
)){
1445 if(our_mkpath(path
, 0700)){
1446 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1447 ps_global
->smime
->publictype
= Nada
;
1451 if(ps_global
->smime
->publictype
== Directory
)
1452 ps_global
->smime
->publicpath
= cpystr(path
);
1455 #ifdef APPLEKEYCHAIN
1457 #endif /* APPLEKEYCHAIN */
1459 setup_privatekey_storage();
1461 /* extra cacerts in a container */
1462 if(ps_global
->VAR_CACERT_CONTAINER
&& ps_global
->VAR_CACERT_CONTAINER
[0]){
1464 cacertcontainer
= 1;
1467 if(!smime_path(ps_global
->VAR_CACERT_CONTAINER
, path
, MAXPATH
))
1468 cacertcontainer
= 0;
1470 if(cacertcontainer
&& !IS_REMOTE(path
)
1471 && ps_global
->VAR_OPER_DIR
1472 && !in_dir(ps_global
->VAR_OPER_DIR
, path
)){
1473 q_status_message2(SM_ORDER
| SM_DING
, 3, 4,
1474 /* TRANSLATORS: First arg is the directory name, second is
1475 the file user wants to read but can't. */
1476 _("Can't read file outside %s: %s"),
1477 ps_global
->VAR_OPER_DIR
, path
);
1478 cacertcontainer
= 0;
1482 && (IS_REMOTE(path
) || can_access(path
, ACCESS_EXISTS
) == 0)){
1483 if(!(IS_REMOTE(path
) && (contents
= simple_read_remote_file(path
, REMOTE_SMIME_SUBTYPE
)))
1485 !(contents
= read_file(path
, READ_FROM_LOCALE
)))
1486 cacertcontainer
= 0;
1489 if(cacertcontainer
&& path
[0]){
1490 ps_global
->smime
->catype
= Container
;
1491 ps_global
->smime
->capath
= cpystr(path
);
1492 ps_global
->smime
->cacontent
= contents
;
1494 ps_global
->smime
->cacertlist
= mem_to_certlist(contents
, CACert
);
1498 if(!cacertcontainer
){
1499 ps_global
->smime
->catype
= Directory
;
1502 if(!(smime_path(ps_global
->VAR_CACERT_DIR
, path
, MAXPATH
)
1503 && !IS_REMOTE(path
)))
1504 ps_global
->smime
->catype
= Nada
;
1505 else if(can_access(path
, ACCESS_EXISTS
)){
1506 if(our_mkpath(path
, 0700)){
1507 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1508 ps_global
->smime
->catype
= Nada
;
1512 if(ps_global
->smime
->catype
== Directory
)
1513 ps_global
->smime
->capath
= cpystr(path
);
1519 copy_publiccert_dir_to_container(void)
1521 return(copy_dir_to_container(Public
, NULL
));
1526 copy_publiccert_container_to_dir(void)
1528 return(copy_container_to_dir(Public
));
1533 copy_privatecert_dir_to_container(void)
1535 return(copy_dir_to_container(Private
, NULL
));
1540 copy_privatecert_container_to_dir(void)
1542 return(copy_container_to_dir(Private
));
1547 copy_cacert_dir_to_container(void)
1549 return(copy_dir_to_container(CACert
, NULL
));
1554 copy_cacert_container_to_dir(void)
1556 return(copy_container_to_dir(CACert
));
1559 /* Add the contents of a file to a container. Do not check the content
1560 * of the file, just add it using the format for that container. The
1561 * caller must check the format, so that there is no data corruption
1563 * return value: 0 - success,
1567 add_file_to_container(WhichCerts ctype
, char *fpath
, char *altname
)
1569 char *sep
= (ctype
== Public
|| ctype
== Private
)
1570 ? EMAILADDRLEADER
: CACERTSTORELEADER
;
1571 char *content
= ctype
== Public
? ps_global
->smime
->publiccontent
1572 : (ctype
== Private
? ps_global
->smime
->privatecontent
1573 : ps_global
->smime
->cacontent
);
1579 int rv
= -1; /* assume error */
1581 if(our_stat(fpath
, &sbuf
) < 0
1582 || (in
= so_get(FileStar
, fpath
, READ_ACCESS
| READ_FROM_LOCALE
)) == NULL
)
1587 else if((name
= strrchr(fpath
, '/')) != NULL
){
1589 if((ll
= strlen(++name
)) > 4 && strucmp(name
+ ll
- 4, EXTCERT(ctype
)) == 0)
1590 name
[ll
-strlen(EXTCERT(ctype
))] = '\0';
1596 fs_resize((void **)&content
, strlen(content
) + strlen(sep
) + strlen(name
) + sbuf
.st_size
+ 3); /* 2 = \n + \n + \0*/
1598 content
+= strlen(content
);
1601 s
= content
= fs_get(strlen(sep
) + strlen(name
) + sbuf
.st_size
+ 1); /* 2 = \n + \0 */
1604 strncat(content
, sep
, strlen(sep
));
1605 strncat(content
, name
, strlen(name
));
1606 content
+= strlen(content
);
1609 while(so_readc(&c
, in
))
1610 *content
++ = (char) c
;
1614 case Private
: ps_global
->smime
->privatecontent
= s
; break;
1615 case Public
: ps_global
->smime
->publiccontent
= s
; break;
1616 case CACert
: ps_global
->smime
->cacontent
= s
; break;
1620 rv
= copy_dir_to_container(ctype
, s
);
1623 if(in
) so_give(&in
);
1630 * returns 0 on success, -1 on failure
1631 * contents is an argument which tells this function to write the value
1632 * of this variable instead of reading the contents of the directory.
1633 * If the var contents is not null use its value as the value of the
1637 copy_dir_to_container(WhichCerts which
, char *contents
)
1639 int ret
= 0, container
= 0;
1640 BIO
*bio_out
= NULL
, *bio_in
= NULL
;
1641 char srcpath
[MAXPATH
+1], dstpath
[MAXPATH
+1], emailaddr
[MAXPATH
], file
[MAXPATH
], line
[4096];
1642 char *tempfile
= NULL
, fpath
[MAXPATH
+1];
1645 REMDATA_S
*rd
= NULL
;
1646 char *configdir
= NULL
;
1647 char *configpath
= NULL
;
1648 char *configcontainer
= NULL
;
1649 char *filesuffix
= NULL
;
1650 char *ret_dir
= NULL
;
1652 dprint((9, "copy_dir_to_container(%s)", which
==Public
? "Public" : which
==Private
? "Private" : which
==CACert
? "CACert" : "?"));
1658 emailaddr
[0] = '\0';
1660 if(which
== Public
){
1661 configdir
= ps_global
->VAR_PUBLICCERT_DIR
;
1662 configpath
= ps_global
->smime
->publicpath
;
1663 configcontainer
= cpystr(DF_PUBLIC_CONTAINER
);
1664 filesuffix
= ".crt";
1666 else if(which
== Private
){
1667 configdir
= ps_global
->VAR_PRIVATEKEY_DIR
;
1668 configpath
= ps_global
->smime
->privatepath
;
1669 configcontainer
= cpystr(DF_PRIVATE_CONTAINER
);
1670 filesuffix
= ".key";
1672 else if(which
== CACert
){
1673 configdir
= ps_global
->VAR_CACERT_DIR
;
1674 configpath
= ps_global
->smime
->capath
;
1675 configcontainer
= cpystr(DF_CA_CONTAINER
);
1676 filesuffix
= ".crt";
1678 container
= SMHOLDERTYPE(which
) == Container
;
1680 if(!(configdir
&& configdir
[0])){
1681 q_status_message(SM_ORDER
, 3, 3, _("Directory not defined"));
1685 if(!(configpath
&& configpath
[0])){
1686 #ifdef APPLEKEYCHAIN
1687 if(which
== Public
&& F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
1688 q_status_message(SM_ORDER
, 3, 3, _("Turn off the Keychain feature above first"));
1691 #endif /* APPLEKEYCHAIN */
1692 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1696 if(!(filesuffix
&& strlen(filesuffix
) == 4)){
1702 * If there is a legit directory to read from set up the
1703 * container file to write to.
1705 if(smime_path(configdir
, srcpath
, MAXPATH
) && !IS_REMOTE(srcpath
)){
1707 if(IS_REMOTE(configpath
)){
1708 rd
= rd_create_remote(RemImap
, configpath
, REMOTE_SMIME_SUBTYPE
,
1710 _("Can't access remote smime configuration."));
1714 (void) rd_read_metadata(rd
);
1716 if(rd
->access
== MaybeRorW
){
1717 if(rd
->read_status
== 'R')
1718 rd
->access
= ReadOnly
;
1720 rd
->access
= ReadWrite
;
1723 if(rd
->access
!= NoExists
){
1725 rd_check_remvalid(rd
, 1L);
1728 * If the cached info says it is readonly but
1729 * it looks like it's been fixed now, change it to readwrite.
1731 if(rd
->read_status
== 'R'){
1732 rd_check_readonly_access(rd
);
1733 if(rd
->read_status
== 'W'){
1734 rd
->access
= ReadWrite
;
1735 rd
->flags
|= REM_OUTOFDATE
;
1738 rd
->access
= ReadOnly
;
1742 if(rd
->flags
& REM_OUTOFDATE
){
1743 if(rd_update_local(rd
) != 0){
1745 dprint((1, "copy_dir_to_container: rd_update_local failed\n"));
1746 rd_close_remdata(&rd
);
1753 if(rd
->access
!= ReadWrite
|| rd_remote_is_readonly(rd
)){
1754 rd_close_remdata(&rd
);
1758 rd
->flags
|= DO_REMTRIM
;
1760 strncpy(dstpath
, rd
->lf
, sizeof(dstpath
)-1);
1761 dstpath
[sizeof(dstpath
)-1] = '\0';
1764 strncpy(dstpath
, configpath
, sizeof(dstpath
)-1);
1765 dstpath
[sizeof(dstpath
)-1] = '\0';
1769 * dstpath is either the local Container file or the local cache file
1770 * for the remote Container file.
1772 tempfile
= tempfile_in_same_dir(dstpath
, "az", &ret_dir
);
1776 * If there is a legit directory to read from and a tempfile
1777 * to write to we continue.
1779 if(tempfile
&& (bio_out
=BIO_new_file(tempfile
, "w")) != NULL
){
1781 if(contents
!= NULL
){
1782 if(BIO_puts(bio_out
, contents
) < 0)
1786 if((dirp
= opendir(srcpath
)) != NULL
){
1788 while((d
=readdir(dirp
)) && !ret
){
1791 if((ll
=strlen(d
->d_name
)) && ll
> 4 && !strcmp(d
->d_name
+ll
-4, filesuffix
)){
1793 /* copy file name to temp buffer */
1794 strncpy(emailaddr
, d
->d_name
, sizeof(emailaddr
)-1);
1795 emailaddr
[sizeof(emailaddr
)-1] = '\0';
1796 /* chop off suffix trailier */
1797 emailaddr
[strlen(emailaddr
)-4] = 0;
1800 * This is the separator between the contents of
1803 if(which
== CACert
){
1804 if(!((BIO_puts(bio_out
, CACERTSTORELEADER
) > 0)
1805 && (BIO_puts(bio_out
, emailaddr
) > 0)
1806 && (BIO_puts(bio_out
, "\n") > 0)))
1810 if(!((BIO_puts(bio_out
, EMAILADDRLEADER
) > 0)
1811 && (BIO_puts(bio_out
, emailaddr
) > 0)
1812 && (BIO_puts(bio_out
, "\n") > 0)))
1816 /* read then write contents of file */
1817 build_path(file
, srcpath
, d
->d_name
, sizeof(file
));
1818 if(!(bio_in
= BIO_new_file(file
, "r")))
1824 while(BIO_gets(bio_in
, line
, sizeof(line
)) > 0){
1825 if(strncmp("-----BEGIN", line
, strlen("-----BEGIN")) == 0)
1829 BIO_puts(bio_out
, line
);
1831 if(strncmp("-----END", line
, strlen("-----END")) == 0)
1847 if(container
&& configpath
&& *configpath
){
1848 strncpy(fpath
, configpath
, sizeof(fpath
));
1849 fpath
[sizeof(fpath
) - 1] = '\0';
1852 if(strlen(dstpath
) + strlen(configcontainer
) - strlen(ret_dir
) + 1 < sizeof(dstpath
))
1853 snprintf(fpath
, sizeof(fpath
), "%s%c%s",
1854 dstpath
, tempfile
[strlen(ret_dir
)], configcontainer
);
1861 if(!IS_REMOTE(configpath
)){
1862 if(rename_file(tempfile
, fpath
) < 0){
1863 q_status_message2(SM_ORDER
, 3, 3,
1864 _("Can't rename %s to %s"), tempfile
, fpath
);
1866 } else q_status_message1(SM_ORDER
, 3, 3,
1867 _("saved container to %s"), fpath
);
1869 else { /* if the container is remote, copy it */
1873 if(rd
!= NULL
&& rename_file(tempfile
, rd
->lf
) < 0){
1874 q_status_message2(SM_ORDER
, 3, 3,
1875 _("Can't rename %s to %s"), tempfile
, rd
->lf
);
1881 if((e
= rd_update_remote(rd
, datebuf
)) != 0){
1883 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1884 _("Error opening temporary smime file %s: %s"),
1885 rd
->lf
, error_description(errno
));
1887 "write_remote_smime: error opening temp file %s\n",
1888 rd
->lf
? rd
->lf
: "?"));
1891 q_status_message2(SM_ORDER
| SM_DING
, 3, 5,
1892 _("Error copying to %s: %s"),
1893 rd
->rn
, error_description(errno
));
1895 "write_remote_smime: error copying from %s to %s\n",
1896 rd
->lf
? rd
->lf
: "?", rd
->rn
? rd
->rn
: "?"));
1899 q_status_message(SM_ORDER
| SM_DING
, 5, 5,
1900 _("Copy of smime key to remote folder failed, NOT saved remotely"));
1903 rd_update_metadata(rd
, datebuf
);
1904 rd
->read_status
= 'W';
1907 rd_close_remdata(&rd
);
1914 fs_give((void **) &tempfile
);
1917 fs_give((void **) &ret_dir
);
1920 fs_give((void **) &configcontainer
);
1927 * returns 0 on success, -1 on failure
1930 copy_container_to_dir(WhichCerts which
)
1932 char path
[MAXPATH
+1], file
[MAXPATH
+1], buf
[MAXPATH
+1];
1934 char *contents
= NULL
;
1935 char *leader
= NULL
;
1936 char *filesuffix
= NULL
;
1937 char *configdir
= NULL
;
1938 char *configpath
= NULL
;
1939 char *tempfile
= NULL
;
1940 char *p
, *q
, *line
, *name
, *certtext
, *save_p
;
1944 dprint((9, "copy_container_to_dir(%s)", which
==Public
? "Public" : which
==Private
? "Private" : which
==CACert
? "CACert" : "?"));
1949 if(which
== Public
){
1950 leader
= EMAILADDRLEADER
;
1951 contents
= ps_global
->smime
->publiccontent
;
1952 configdir
= ps_global
->VAR_PUBLICCERT_DIR
;
1953 configpath
= ps_global
->smime
->publicpath
;
1954 filesuffix
= ".crt";
1955 if(!(configpath
&& configpath
[0])){
1956 #ifdef APPLEKEYCHAIN
1957 if(which
== Public
&& F_ON(F_PUBLICCERTS_IN_KEYCHAIN
, ps_global
)){
1958 q_status_message(SM_ORDER
, 3, 3, _("Turn off the Keychain feature above first"));
1961 #endif /* APPLEKEYCHAIN */
1962 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1966 fs_give((void **) &ps_global
->smime
->publicpath
);
1969 if(!(smime_path(ps_global
->VAR_PUBLICCERT_DIR
, path
, MAXPATH
)
1970 && !IS_REMOTE(path
))){
1971 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
1975 if(can_access(path
, ACCESS_EXISTS
)){
1976 if(our_mkpath(path
, 0700)){
1977 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
1982 ps_global
->smime
->publicpath
= cpystr(path
);
1983 configpath
= ps_global
->smime
->publicpath
;
1985 else if(which
== Private
){
1986 leader
= EMAILADDRLEADER
;
1987 contents
= ps_global
->smime
->privatecontent
;
1988 configdir
= ps_global
->VAR_PRIVATEKEY_DIR
;
1989 configpath
= ps_global
->smime
->privatepath
;
1990 filesuffix
= ".key";
1991 if(!(configpath
&& configpath
[0])){
1992 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
1996 fs_give((void **) &ps_global
->smime
->privatepath
);
1999 if(!(smime_path(ps_global
->VAR_PRIVATEKEY_DIR
, path
, MAXPATH
)
2000 && !IS_REMOTE(path
))){
2001 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
2005 if(can_access(path
, ACCESS_EXISTS
)){
2006 if(our_mkpath(path
, 0700)){
2007 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
2012 ps_global
->smime
->privatepath
= cpystr(path
);
2013 configpath
= ps_global
->smime
->privatepath
;
2015 else if(which
== CACert
){
2016 leader
= CACERTSTORELEADER
;
2017 contents
= ps_global
->smime
->cacontent
;
2018 configdir
= ps_global
->VAR_CACERT_DIR
;
2019 configpath
= ps_global
->smime
->capath
;
2020 filesuffix
= ".crt";
2021 if(!(configpath
&& configpath
[0])){
2022 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
2026 fs_give((void **) &ps_global
->smime
->capath
);
2029 if(!(smime_path(ps_global
->VAR_CACERT_DIR
, path
, MAXPATH
)
2030 && !IS_REMOTE(path
))){
2031 q_status_message(SM_ORDER
, 3, 3, _("Directory is not defined"));
2035 if(can_access(path
, ACCESS_EXISTS
)){
2036 if(our_mkpath(path
, 0700)){
2037 q_status_message1(SM_ORDER
, 3, 3, _("Can't create directory %s"), path
);
2042 ps_global
->smime
->capath
= cpystr(path
);
2043 configpath
= ps_global
->smime
->capath
;
2046 if(!(configdir
&& configdir
[0])){
2047 q_status_message(SM_ORDER
, 3, 3, _("Directory not defined"));
2051 if(!(configpath
&& configpath
[0])){
2052 q_status_message(SM_ORDER
, 3, 3, _("Container path is not defined"));
2056 if(!(filesuffix
&& strlen(filesuffix
) == 4)){
2061 if(contents
&& *contents
){
2062 for(p
= contents
; *p
!= '\0';){
2065 while(*p
&& *p
!= '\n')
2074 if(strncmp(leader
, line
, strlen(leader
)) == 0){
2075 name
= line
+ strlen(leader
);
2077 if(strncmp("-----BEGIN", certtext
, strlen("-----BEGIN")) == 0){
2078 if((q
= strstr(certtext
, leader
)) != NULL
){
2081 else{ /* end of file */
2082 q
= certtext
+ strlen(certtext
);
2086 strncpy(buf
, name
, sizeof(buf
)-5);
2087 buf
[sizeof(buf
)-5] = '\0';
2088 strncat(buf
, filesuffix
, 5);
2089 build_path(file
, configpath
, buf
, sizeof(file
));
2091 in
= BIO_new_mem_buf(certtext
, q
-certtext
);
2093 tempfile
= tempfile_in_same_dir(file
, "az", NULL
);
2096 out
= BIO_new_file(tempfile
, "w");
2099 while((len
= BIO_read(in
, iobuf
, sizeof(iobuf
))) > 0)
2100 BIO_write(out
, iobuf
, len
);
2104 if(rename_file(tempfile
, file
) < 0){
2105 q_status_message2(SM_ORDER
, 3, 3,
2106 _("Can't rename %s to %s"),
2111 fs_give((void **) &tempfile
);
2128 #ifdef APPLEKEYCHAIN
2131 copy_publiccert_container_to_keychain(void)
2133 /* NOT IMPLEMNTED */
2138 copy_publiccert_keychain_to_container(void)
2140 /* NOT IMPLEMNTED */
2144 #endif /* APPLEKEYCHAIN */
2148 * Get a pointer to a string describing the most recent OpenSSL error.
2149 * It's statically allocated, so don't change or attempt to free it.
2152 openssl_error_string(void)
2155 const char *data
= NULL
;
2158 errn
= ERR_peek_error_line_data(NULL
, NULL
, &data
, NULL
);
2159 errs
= (char*) ERR_reason_error_string(errn
);
2166 return "unknown error";
2170 /* Return true if the body looks like a PKCS7 object */
2172 is_pkcs7_body(BODY
*body
)
2176 result
= body
->type
==TYPEAPPLICATION
&&
2178 (strucmp(body
->subtype
,"pkcs7-mime")==0 ||
2179 strucmp(body
->subtype
,"x-pkcs7-mime")==0 ||
2180 strucmp(body
->subtype
,"pkcs7-signature")==0 ||
2181 strucmp(body
->subtype
,"x-pkcs7-signature")==0);
2188 * Recursively stash a pointer to the decrypted data in our
2189 * manufactured body.
2190 * parameters: type: call of type 1, save the base and header for multipart messages
2191 call of type 0, do not save the base and header for multipart messages
2194 create_local_cache(char *h
, char *base
, BODY
*b
, int type
)
2196 if(b
->type
==TYPEMULTIPART
){
2200 cpytxt(&b
->mime
.text
, h
+b
->mime
.offset
, b
->mime
.text
.size
);
2201 cpytxt(&b
->contents
.text
, base
+ b
->contents
.offset
, b
->size
.bytes
);
2202 } else if(type
== 0){
2204 * We don't really want to copy the real body contents. It shouldn't be
2205 * used, and in the case of a message with attachments, we'll be
2206 * duplicating the files multiple times.
2208 cpytxt(&b
->contents
.text
, "BODY UNAVAILABLE", 16);
2210 for(p
=b
->nested
.part
; p
; p
=p
->next
)
2211 create_local_cache(h
, base
, (BODY
*) p
, type
);
2215 cpytxt(&b
->mime
.text
, h
+b
->mime
.offset
, b
->mime
.text
.size
);
2216 cpytxt(&b
->contents
.text
, base
+ b
->contents
.offset
, b
->size
.bytes
);
2222 rfc822_output_func(void *b
, char *string
)
2224 BIO
*bio
= (BIO
*) b
;
2226 return(string
? *string
? (BIO_puts(bio
, string
) > 0 ? 1L : 0L)
2227 : (BIO_puts(bio
, string
) >= 0 ? 1L : 0L)
2233 * Attempt to load the private key for the given PERSONAL_CERT.
2234 * This sets the appropriate passphrase globals in order to
2235 * interact with the user correctly.
2238 load_private_key(PERSONAL_CERT
*pcert
)
2242 /* Try empty password by default */
2243 char *password
= "";
2246 && (ps_global
->smime
->need_passphrase
2247 || ps_global
->smime
->entered_passphrase
)){
2248 /* We've already been in here and discovered we need a different password */
2250 if(ps_global
->smime
->entered_passphrase
)
2251 password
= (char *) ps_global
->smime
->passphrase
; /* already entered */
2258 if(!(pcert
->key
= load_key(pcert
, password
, SM_NORMALCERT
))){
2259 long err
= ERR_get_error();
2261 /* Couldn't load key... */
2263 if(ps_global
->smime
&& ps_global
->smime
->entered_passphrase
){
2265 /* The user got the password wrong maybe? */
2267 if((ERR_GET_LIB(err
)==ERR_LIB_EVP
&& ERR_GET_REASON(err
)==EVP_R_BAD_DECRYPT
) ||
2268 (ERR_GET_LIB(err
)==ERR_LIB_PEM
&& ERR_GET_REASON(err
)==PEM_R_BAD_DECRYPT
))
2269 q_status_message(SM_ORDER
| SM_DING
, 4, 4, _("Incorrect passphrase"));
2271 q_status_message1(SM_ORDER
, 4, 4, _("Couldn't read key: %s"),(char*)openssl_error_string());
2273 /* This passphrase is no good; forget it */
2274 ps_global
->smime
->entered_passphrase
= 0;
2277 if(ps_global
->smime
){
2278 /* Indicate to the UI that we need re-entry (see mailcmd.c:process_cmd())*/
2279 ps_global
->smime
->need_passphrase
= 1;
2280 if(ps_global
->smime
->passphrase_emailaddr
){
2282 for(i
= 0; ps_global
->smime
->passphrase_emailaddr
[i
] != NULL
; i
++)
2283 fs_give((void **)&ps_global
->smime
->passphrase_emailaddr
[i
]);
2284 fs_give((void **) ps_global
->smime
->passphrase_emailaddr
);
2287 ps_global
->smime
->passphrase_emailaddr
= get_x509_subject_email(pcert
->cert
);
2293 /* This key will be cached, so we won't be called again */
2294 if(ps_global
->smime
){
2295 ps_global
->smime
->entered_passphrase
= 0;
2296 ps_global
->smime
->need_passphrase
= 0;
2308 setup_pkcs7_body_for_signature(BODY
*b
, char *description
, char *type
, char *filename
, char *smime_type
)
2310 b
->type
= TYPEAPPLICATION
;
2311 b
->subtype
= cpystr(type
);
2312 b
->encoding
= ENCBINARY
;
2313 b
->description
= cpystr(description
);
2315 b
->disposition
.type
= cpystr("attachment");
2316 set_parameter(&b
->disposition
.parameter
, "filename", filename
);
2318 set_parameter(&b
->parameter
, "name", filename
);
2319 if(smime_type
&& *smime_type
)
2320 set_parameter(&b
->parameter
, "smime-type", smime_type
);
2325 * Look for a personal certificate matching the
2329 match_personal_cert_to_email(ADDRESS
*a
)
2331 PERSONAL_CERT
*pcert
= NULL
;
2336 if(!a
|| !a
->mailbox
|| !a
->host
)
2339 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
2341 if(ps_global
->smime
){
2342 for(pcert
=(PERSONAL_CERT
*) ps_global
->smime
->personal_certs
;
2349 email
= get_x509_subject_email(pcert
->cert
);
2353 for(i
= 0; email
[i
] && strucmp(email
[i
], buf
) != 0; i
++);
2354 if(email
[i
] != NULL
) done
++;
2355 for(i
= 0; email
[i
] != NULL
; i
++)
2356 fs_give((void **)&email
[i
]);
2357 fs_give((void **)email
);
2370 * Look for a personal certificate matching the from
2371 * (or reply_to? in the given envelope)
2374 match_personal_cert(ENVELOPE
*env
)
2376 PERSONAL_CERT
*pcert
;
2378 pcert
= match_personal_cert_to_email(env
->reply_to
);
2380 pcert
= match_personal_cert_to_email(env
->from
);
2387 * Flatten the given body into its MIME representation.
2388 * Return the result in a BIO.
2391 body_to_bio(BODY
*body
)
2396 bio
= BIO_new(BIO_s_mem());
2400 pine_encode_body(body
); /* this attaches random boundary strings to multiparts */
2401 pine_write_body_header(body
, rfc822_output_func
, bio
);
2402 pine_rfc822_output_body(body
, rfc822_output_func
, bio
);
2405 * Now need to truncate by two characters since the above
2408 if((len
=BIO_ctrl_pending(bio
)) > 1){
2409 BUF_MEM
*biobuf
= NULL
;
2411 BIO_get_mem_ptr(bio
, &biobuf
);
2413 BUF_MEM_grow(biobuf
, len
-2); /* remove CRLF */
2422 bio_from_store(STORE_S
*store
)
2426 if(store
&& store
->src
== BioType
&& store
->txt
){
2427 ret
= (BIO
*) store
->txt
;
2434 * Encrypt file; given a path (char *) fp, replace the file
2435 * by an encrypted version of it. If (char *) text is not null, then
2436 * replace the text of (char *) fp by the encrypted version of (char *) text.
2437 * certpath is the FULL path to the file containing the certificate used for
2441 encrypt_file(char *fp
, char *text
, PERSONAL_CERT
*pc
)
2443 const EVP_CIPHER
*cipher
= NULL
;
2444 STACK_OF(X509
) *encerts
= NULL
;
2452 cipher
= EVP_aes_256_cbc();
2453 encerts
= sk_X509_new_null();
2455 sk_X509_push(encerts
, X509_dup(pc
->cert
));
2458 if((out
= BIO_new(BIO_s_mem())) != NULL
){
2459 (void) BIO_reset(out
);
2460 BIO_puts(out
, text
);
2463 else if((out
= BIO_new_file(fp
, "rb")) != NULL
)
2464 BIO_read_filename(out
, fp
);
2466 if((p7
= PKCS7_encrypt(encerts
, out
, cipher
, 0)) != NULL
){
2467 BIO_set_close(out
, BIO_CLOSE
);
2469 if((out
= BIO_new_file(fp
, "w")) != NULL
){
2471 rv
= PEM_write_bio_PKCS7(out
, p7
);
2479 sk_X509_pop_free(encerts
, X509_free
);
2485 * Encrypt a message on the way out. Called from call_mailer in send.c
2486 * The body may be reallocated.
2489 encrypt_outgoing_message(METAENV
*header
, BODY
**bodyP
)
2494 const EVP_CIPHER
*cipher
= NULL
;
2495 STACK_OF(X509
) *encerts
= NULL
;
2496 STORE_S
*outs
= NULL
;
2499 BODY
*body
= *bodyP
;
2500 BODY
*newBody
= NULL
;
2505 dprint((9, "encrypt_outgoing_message()"));
2508 cipher
= EVP_aes_256_cbc();
2510 encerts
= sk_X509_new_null();
2512 /* Look for a certificate for each of the recipients */
2513 for(pf
= header
->local
; pf
&& pf
->name
; pf
= pf
->next
)
2514 if(pf
->type
== Address
&& pf
->rcptto
&& pf
->addr
&& *pf
->addr
){
2515 for(a
=*pf
->addr
; a
; a
=a
->next
){
2516 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
2518 if((cert
= get_cert_for(buf
, Public
, 1)) != NULL
){
2519 sk_X509_push(encerts
,cert
);
2521 q_status_message2(SM_ORDER
, 1, 1,
2522 _("Unable to find certificate for <%s@%s>"),
2523 a
->mailbox
, a
->host
);
2529 /* add the sender's certificate so that they can decrypt the message too */
2530 for(a
=header
->env
->from
; a
; a
= a
->next
){
2531 snprintf(buf
, sizeof(buf
), "%s@%s", a
->mailbox
, a
->host
);
2533 if((cert
= get_cert_for(buf
, Public
, 1)) != NULL
2534 && sk_X509_find(encerts
, cert
) == -1)
2535 sk_X509_push(encerts
,cert
);
2538 in
= body_to_bio(body
);
2540 p7
= PKCS7_encrypt(encerts
, in
, cipher
, 0);
2542 outs
= so_get(BioType
, NULL
, EDIT_ACCESS
);
2543 out
= bio_from_store(outs
);
2545 i2d_PKCS7_bio(out
, p7
);
2546 (void) BIO_flush(out
);
2548 so_seek(outs
, 0, SEEK_SET
);
2550 newBody
= mail_newbody();
2552 newBody
->type
= TYPEAPPLICATION
;
2553 newBody
->subtype
= cpystr("pkcs7-mime");
2554 newBody
->encoding
= ENCBINARY
;
2556 newBody
->disposition
.type
= cpystr("attachment");
2557 set_parameter(&newBody
->disposition
.parameter
, "filename", "smime.p7m");
2559 newBody
->description
= cpystr("S/MIME Encrypted Message");
2560 set_parameter(&newBody
->parameter
, "smime-type", "enveloped-data");
2561 set_parameter(&newBody
->parameter
, "name", "smime.p7m");
2563 newBody
->contents
.text
.data
= (unsigned char *) outs
;
2573 sk_X509_pop_free(encerts
, X509_free
);
2575 dprint((9, "encrypt_outgoing_message returns %d", result
));
2581 Get (and decode) the body of the given section of msg
2584 get_part_contents(long msgno
, const char *section
)
2588 STORE_S
*store
= NULL
;
2591 store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
2593 gf_set_so_writec(&pc
,store
);
2595 err
= detach(ps_global
->mail_stream
, msgno
, (char*) section
, 0L, &len
, pc
, NULL
, 0L);
2597 gf_clear_so_writec(store
);
2599 so_seek(store
, 0, SEEK_SET
);
2610 get_pkcs7_from_part(long msgno
,const char *section
)
2612 STORE_S
*store
= NULL
;
2616 store
= get_part_contents(msgno
, section
);
2619 if(store
->src
== CharStar
){
2623 * We're reaching inside the STORE_S structure. We should
2624 * probably have a way to get the length, instead.
2626 len
= (int) (store
->eod
- store
->dp
);
2627 in
= BIO_new_mem_buf(store
->txt
, len
);
2629 else{ /* just copy it */
2632 in
= BIO_new(BIO_s_mem());
2633 (void) BIO_reset(in
);
2635 so_seek(store
, 0L, 0);
2636 while(so_readc(&c
, store
)){
2637 BIO_write(in
, &c
, 1);
2642 /* dump_bio_to_file(in, "/tmp/decoded-signature"); */
2643 if((p7
=d2i_PKCS7_bio(in
,NULL
)) == NULL
){
2656 int same_cert(X509
*x
, X509
*cert
)
2658 char bufcert
[256], bufx
[256];
2661 get_fingerprint(cert
, EVP_md5(), bufcert
, sizeof(bufcert
), ":");
2662 get_fingerprint(x
, EVP_md5(), bufx
, sizeof(bufx
), ":");
2663 if(strcmp(bufx
, bufcert
) == 0)
2670 /* extract and save certificates from a PKCS7 package. The ctype variable
2671 * tells us if we want to extract it to a public/ or a ca/ directory. The
2672 * later makes sense only for recoverable errors (errors that can be fixed
2673 * by saving to the ca/ directory before we verify the signature).
2675 * 0 - no errors (in public/) no need to try again,
2676 * or validated self signed certificate (in ca/)
2677 * < 0 - certificate error is not recoverable, don't even think about it.
2680 int smime_extract_and_save_cert(PKCS7
*p7
, int check_cert
)
2682 STACK_OF(X509
) *signers
;
2688 if((signers
= PKCS7_get0_signers(p7
, NULL
, 0)) == NULL
)
2691 for(i
= 0; i
< sk_X509_num(signers
); i
++){
2692 if((x
= sk_X509_value(signers
,i
)) == NULL
)
2695 if((email
= get_x509_subject_email(x
)) != NULL
){
2696 for(j
= 0; email
[j
] != NULL
; j
++){
2697 if((cert
= get_cert_for(email
[j
], Public
, 1)) == NULL
2698 || same_cert(x
, cert
) == 0){
2700 || smime_validate_cert(x
, &error
) == 0
2701 || (*pith_smime_confirm_save
)(email
[j
]) == 1)
2702 save_cert_for(email
[j
], x
, Public
);
2706 fs_give((void **) &email
[j
]);
2708 fs_give((void **) email
);
2711 sk_X509_free(signers
);
2717 * Try to verify a signature.
2719 * p7 - the pkcs7 object to verify
2720 * in - the plain data to verify (NULL if not detached)
2721 * out - BIO to which to write the opaque data
2722 * silent - if non zero, do not print errors, only print success.
2725 do_signature_verify(PKCS7
*p7
, BIO
*in
, BIO
*out
, int silent
)
2727 STACK_OF(X509
) *otherCerts
= NULL
;
2734 if(!silent
) q_status_message(SM_ORDER
| SM_DING
, 2, 2,
2735 _("Couldn't verify S/MIME signature: No CA Certs were loaded"));
2740 flags
= F_ON(F_USE_CERT_STORE_ONLY
, ps_global
) ? PKCS7_NOINTERN
: 0;
2742 if(ps_global
->smime
->publiccertlist
== NULL
){
2743 renew_cert_data(&ps_global
->smime
->publiccertlist
, Public
);
2744 for(cl
= ps_global
->smime
->publiccertlist
; cl
; cl
= cl
->next
){
2745 if(cl
->x509_cert
== NULL
){
2746 char *s
= strrchr(cl
->name
, '.');
2748 cl
->x509_cert
= get_cert_for(cl
->name
, Public
, 1);
2754 if(ps_global
->smime
->publiccertlist
){
2755 otherCerts
= sk_X509_new_null();
2756 for(cl
= ps_global
->smime
->publiccertlist
; cl
; cl
= cl
->next
)
2757 if(cl
->x509_cert
!= NULL
)
2758 sk_X509_push(otherCerts
, X509_dup(cl
->x509_cert
));
2761 result
= PKCS7_verify(p7
, otherCerts
, s_cert_store
, in
, out
, flags
);
2763 sk_X509_pop_free(otherCerts
, X509_free
);
2766 q_status_message(SM_ORDER
, 1, 1, _("S/MIME signature verified ok"));
2769 err
= ERR_peek_error_line_data(NULL
, NULL
, &data
, NULL
);
2771 if(out
&& err
==ERR_PACK(ERR_LIB_PKCS7
,PKCS7_F_PKCS7_VERIFY
,PKCS7_R_CERTIFICATE_VERIFY_ERROR
)){
2773 /* Retry verification so we can get the plain text */
2774 /* Might be better to reimplement PKCS7_verify here? */
2776 PKCS7_verify(p7
, otherCerts
, s_cert_store
, in
, out
, PKCS7_NOVERIFY
);
2778 if (!silent
) q_status_message1(SM_ORDER
| SM_DING
, 3, 3,
2779 _("Couldn't verify S/MIME signature: %s"), (char*) openssl_error_string());
2787 free_smime_body_sparep(void **sparep
)
2791 if(sparep
&& *sparep
){
2792 switch(get_smime_sparep_type(*sparep
)){
2793 case P7Type
: PKCS7_free((PKCS7
*) get_smime_sparep_data(*sparep
));
2795 case CharType
: s
= (char *)get_smime_sparep_data(*sparep
);
2796 fs_give((void **) &s
);
2798 case SizedText
: st
= (SIZEDTEXT
*)get_smime_sparep_data(*sparep
);
2799 fs_give((void **) &st
->data
);
2800 fs_give((void **) &st
);
2804 ((SMIME_SPARE_S
*)(*sparep
))->data
= NULL
;
2809 /* Big comment, explaining the mess that exists out there, and how we deal
2810 with it, and also how we solve the problems that are created this way.
2812 When Alpine sends a message, it constructs that message, computes the
2813 signature, but then it forgets the message it signed and reconstructs it
2814 again. Since it signs a message containing a notice about "mime aware
2815 tools", but it does not send that we do not include that in the part
2816 that is signed, and that takes care of much of the problems.
2818 Another problem is what is received from the servers. All servers tested
2819 seem to transmit the message that was signed intact and Alpine can check
2820 the signature correctly. That is not a problem. The problem arises when
2821 the message includes attachments. In this case different servers send
2822 different things, so it will be up to us to figure out what is the text
2823 that was actually signed. Confused? here is the story:
2825 When a message containing and attachment is sent by Alpine, UW-IMAP,
2826 Panda-IMAP, Gmail, and local reading of folders send exactly the message
2827 that was sent by Alpine, but GMX.com, Exchange, and probably other
2828 servers add a trailing \r\n in the message, so when validating the
2829 signature, these messages will not validate. There are several things
2832 1. Add a trailing \r\n to any message that contains attachments, sign that
2833 and send that. In this way, all messages will validate with all
2836 2. Compatibility mode: If a message has an attachment, contains a trailing
2837 \r\n and does not validate (sent by an earlier version of Alpine),
2838 remove the trailing \r\n and try to revalidate again.
2840 3. We do not add \r\n to validate a message that we sent, because that
2841 would only work in Alpine, and not in any other client. That would
2842 not be a good thing to do.
2846 Now we have to deal with encrypted and signed messages. The problem is
2847 that c-client makes all its pointers point to "on disk" content, but
2848 since we decrypted the data earlier, we have to make sure of two things.
2849 One is that we saved that data (so we do not have to decrypt it again)
2850 and second that we can use it.
2852 In order to save the data we use create_local_cache, so that we do not
2853 have to redecrypt the message. Once this is saved, c-client functions will
2854 find it and send it to us in mail_fetch_mime and mail_fetch_body.
2858 When we are trying to verify messages with detached signatures, some
2859 imap servers send incorrect information in the mail_fetch_mime call. By
2860 incorrect I mean that this is not fetched directly from the message, but
2861 it is read from the message, processed, and then the processed part is
2862 sent to us, so this text might not agree with what is in the message,
2863 and so the validation of the signature might fail. However, the good
2864 news is that the message validates if saved to a local folder. This
2865 means that if normal validation does not work we can make it work by
2866 saving the message locally and validating that. This is implemented
2867 below, and causes delay in the display of the message. I am considering
2868 at this time not to do this automatically, but wait for the user to tell
2869 us to do it for them by means of a command available in the
2870 mail_view_screen. This might help in other situations, where a message
2871 is supposed to have an attachment, but it can not be seen in the
2872 processed text. Nevertheless, at this time, this is automatic, and is
2873 causing a delay in the processing of the message, but it is validating
2874 correctly all messages.
2878 When the user sends a message as encrypted and signed, this code used to
2879 encrypt first, and then sign the pkcs7 body, but it turns out that some
2880 other clients can not handle these messages. While we could argue that the
2881 other clients need to improve, we will support reading messages in both
2882 ways, and will send messages using this technique; that is, signed first,
2883 encrypted second. It seems that all tested clients support this way, so it
2884 should be safe to do so.
2887 typedef struct smime_filter_s
{
2891 SMIME_FILTER_S sig_filter
[] = {
2892 {smime_remove_trailing_crlf
},
2893 {smime_remove_folding_space
}
2896 #define TOTAL_FILTERS (sizeof(sig_filter)/sizeof(sig_filter[0]))
2897 #define TOTAL_SIGFLTR (1 << TOTAL_FILTERS) /* not good, keep filters to a low number */
2900 smime_remove_trailing_crlf(char **mimetext
, unsigned long *mimelen
,
2901 char **bodytext
, unsigned long *bodylen
)
2903 if(*bodylen
> 2 && !strncmp(*bodytext
+*bodylen
-2, "\r\n", 2))
2908 smime_remove_folding_space(char **mimetext
, unsigned long *mimelen
,
2909 char **bodytext
, unsigned long *bodylen
)
2912 unsigned long mlen
= *mimelen
;
2915 for (s
= t
= *mimetext
; t
- *mimetext
< *mimelen
; ){
2916 if(*t
== '\r' && *(t
+1) == '\n' && (*(t
+2) == '\t' || *(t
+2) == ' ')){
2929 smime_validate_extra_test(char *mimetext
, unsigned long mimelen
, char *bodytext
, unsigned long bodylen
, PKCS7
*p7
, int nflag
)
2931 int result
, i
, j
, flag
;
2932 char *mtext
, *btext
;
2933 unsigned long mlen
, blen
;
2936 mtext
= mimelen
? fs_get(mimelen
+1) : NULL
;
2937 btext
= fs_get(bodylen
+1);
2939 flag
= 1; /* silence all failures */
2940 for(i
= 1; result
== 0 && i
< TOTAL_SIGFLTR
; i
++){
2941 if((in
= BIO_new(BIO_s_mem())) == NULL
)
2944 (void) BIO_reset(in
);
2946 if(i
+1 == TOTAL_SIGFLTR
)
2950 strncpy(mtext
, mimetext
, mlen
= mimelen
);
2951 strncpy(btext
, bodytext
, blen
= bodylen
);
2952 for(j
= 0; j
< TOTAL_FILTERS
; j
++)
2954 (sig_filter
[j
].filter
)(&mtext
, &mlen
, &btext
, &blen
);
2956 BIO_write(in
, mtext
, mlen
);
2957 BIO_write(in
, btext
, blen
);
2958 result
= do_signature_verify(p7
, in
, NULL
, flag
);
2961 if(mtext
) fs_give((void **)&mtext
);
2962 if(btext
) fs_give((void **)&btext
);
2967 * Given a multipart body of type multipart/signed, attempt to verify it.
2968 * Returns non-zero if the body was changed.
2971 do_detached_signature_verify(BODY
*b
, long msgno
, char *section
)
2976 int result
, modified_the_body
= 0;
2977 int flag
; /* 1 silent, 0 not silent */
2979 unsigned long mimelen
, bodylen
;
2980 char newSec
[100], *mimetext
, *bodytext
;
2984 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"));
2988 /* if it was signed and then encrypted, use the decrypted text
2989 * to check the validity of the signature
2992 if(get_smime_sparep_type(b
->sparep
) == SizedText
){
2993 /* bodytext includes mimetext */
2994 st
= (SIZEDTEXT
*) get_smime_sparep_data(b
->sparep
);
2995 bodytext
= (char *) st
->data
;
3002 snprintf(newSec
, sizeof(newSec
), "%s%s1", section
? section
: "", (section
&& *section
) ? "." : "");
3003 mimetext
= mail_fetch_mime(ps_global
->mail_stream
, msgno
, (char*) newSec
, &mimelen
, 0);
3005 bodytext
= mail_fetch_body (ps_global
->mail_stream
, msgno
, (char*) newSec
, &bodylen
, 0);
3007 if(mimetext
== NULL
|| bodytext
== NULL
)
3008 return modified_the_body
;
3011 snprintf(newSec
, sizeof(newSec
), "%s%s2", section
? section
: "", (section
&& *section
) ? "." : "");
3013 if((p7
= get_pkcs7_from_part(msgno
, newSec
)) == NULL
3014 || (in
= BIO_new(BIO_s_mem())) == NULL
)
3015 return modified_the_body
;
3017 (void) BIO_reset(in
);
3018 if(mimetext
!= NULL
)
3019 BIO_write(in
, mimetext
, mimelen
);
3020 BIO_write(in
, bodytext
, bodylen
);
3022 saved
= smime_extract_and_save_cert(p7
, F_ON(F_USE_CERT_STORE_ONLY
, ps_global
));
3023 if(saved
< 0 && F_ON(F_USE_CERT_STORE_ONLY
, ps_global
))
3024 return modified_the_body
;
3026 if((result
= do_signature_verify(p7
, in
, NULL
, 1)) == 0){
3027 flag
= (mimelen
== 0 || !IS_REMOTE(ps_global
->mail_stream
->mailbox
))
3029 result
= smime_validate_extra_test(mimetext
, mimelen
, bodytext
, bodylen
, p7
, flag
);
3031 return modified_the_body
;
3033 && mimelen
> 0 /* do not do this for encrypted messages */
3034 && IS_REMOTE(ps_global
->mail_stream
->mailbox
)){
3036 unsigned long hlen
, tlen
;
3040 if((in
= BIO_new(BIO_s_mem())) != NULL
3041 && (fetch
= mail_fetch_header(ps_global
->mail_stream
, msgno
, NULL
,
3042 NULL
, &hlen
, FT_PEEK
)) != NULL
3043 && (msg_so
= so_get(CharStar
, NULL
, WRITE_ACCESS
)) != NULL
3044 && so_nputs(msg_so
, fetch
, (long) hlen
)
3045 && (fetch
= pine_mail_fetch_text(ps_global
->mail_stream
, msgno
, NULL
,
3046 &tlen
, FT_PEEK
)) != NULL
3047 && so_nputs(msg_so
, fetch
, tlen
)){
3049 char *h
= (char *) so_text(msg_so
);
3050 char *bstart
= strstr(h
, "\r\n\r\n");
3055 INIT(&bs
, mail_string
, bstart
, tlen
);
3056 rfc822_parse_msg_full(&env
, &body
, h
, bstart
-h
-4, &bs
, BADHOST
, 0, 0);
3057 mail_free_envelope(&env
);
3059 mail_free_body_part(&b
->nested
.part
);
3060 tmpB
= mail_body_section(body
, (unsigned char *) section
);
3061 if(MIME_MSG(tmpB
->type
, tmpB
->subtype
))
3062 b
->nested
.part
= tmpB
->nested
.msg
->body
->nested
.part
;
3064 b
->nested
.part
= tmpB
->nested
.part
;
3065 create_local_cache(bstart
, bstart
, &b
->nested
.part
->body
, 1);
3066 modified_the_body
= 1;
3068 snprintf(newSec
, sizeof(newSec
), "%s%s1", section
? section
: "", (section
&& *section
) ? "." : "");
3070 mimetext
= mail_fetch_mime(ps_global
->mail_stream
, msgno
, (char*) newSec
, &mimelen
, 0);
3073 bodytext
= mail_fetch_body (ps_global
->mail_stream
, msgno
, (char*) newSec
, &bodylen
, 0);
3075 if (mimetext
== NULL
|| bodytext
== NULL
)
3076 return modified_the_body
;
3078 snprintf(newSec
, sizeof(newSec
), "%s%s2", section
? section
: "", (section
&& *section
) ? "." : "");
3080 if((p7
= get_pkcs7_from_part(msgno
, newSec
)) == NULL
)
3081 return modified_the_body
;
3083 (void) BIO_reset(in
);
3084 BIO_write(in
, mimetext
, mimelen
);
3085 BIO_write(in
, bodytext
, bodylen
);
3088 if((result
= do_signature_verify(p7
, in
, NULL
, 1)) == 0){
3089 result
= smime_validate_extra_test(mimetext
, mimelen
, bodytext
, bodylen
, p7
, 0);
3091 return modified_the_body
;
3099 fs_give((void**) &b
->subtype
);
3101 b
->subtype
= cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE
);
3102 b
->encoding
= ENC8BIT
;
3105 fs_give ((void**) &b
->description
);
3107 what_we_did
= result
? _("This message was cryptographically signed.") :
3108 _("This message was cryptographically signed but the signature could not be verified.");
3110 b
->description
= cpystr(what_we_did
);
3112 b
->sparep
= create_smime_sparep(P7Type
, p7
);
3116 /* p is signed plaintext */
3118 mail_free_body_part(&p
->next
); /* hide the pkcs7 from the viewer */
3120 modified_the_body
= 1;
3122 return modified_the_body
;
3127 find_certificate_matching_recip_info(PKCS7_RECIP_INFO
*ri
)
3129 PERSONAL_CERT
*x
= NULL
;
3131 if(ps_global
->smime
){
3132 for(x
= (PERSONAL_CERT
*) ps_global
->smime
->personal_certs
; x
; x
=x
->next
){
3137 if(!X509_NAME_cmp(ri
->issuer_and_serial
->issuer
,mine
->cert_info
->issuer
) &&
3138 !ASN1_INTEGER_cmp(ri
->issuer_and_serial
->serial
,mine
->cert_info
->serialNumber
)){
3148 static PERSONAL_CERT
*
3149 find_certificate_matching_pkcs7(PKCS7
*p7
)
3152 STACK_OF(PKCS7_RECIP_INFO
) *recips
;
3153 PERSONAL_CERT
*x
= NULL
;
3155 recips
= p7
->d
.enveloped
->recipientinfo
;
3157 for(i
=0; i
<sk_PKCS7_RECIP_INFO_num(recips
); i
++){
3158 PKCS7_RECIP_INFO
*ri
;
3160 ri
= sk_PKCS7_RECIP_INFO_value(recips
, i
);
3162 if((x
=find_certificate_matching_recip_info(ri
))!=0){
3170 /* decrypt an encrypted file.
3171 Args: fp - the path to the encrypted file.
3172 rv - a code that tells the caller what happened inside the function
3173 pcert - a personal certificate that was used to encrypt this file
3174 Returns the decoded text allocated in a char *, whose memory must be
3179 decrypt_file(char *fp
, int *rv
, PERSONAL_CERT
*pc
)
3183 BIO
*in
= NULL
, *out
= NULL
;
3185 long unsigned int len
;
3188 if(pc
== NULL
|| (text
= read_file(fp
, 0)) == NULL
|| *text
== '\0')
3191 tmp
= fs_get(strlen(text
) + (strlen(text
) << 6) + 1);
3192 for(j
= 0, i
= strlen("-----BEGIN PKCS7-----") + 1; text
[i
] != '\0'
3193 && text
[i
] != '-'; j
++, i
++)
3197 ret
= rfc822_base64((unsigned char *)tmp
, strlen(tmp
), &len
);
3199 if((in
= BIO_new_mem_buf((char *)ret
, len
)) != NULL
){
3200 p7
= d2i_PKCS7_bio(in
, NULL
);
3204 if (text
) fs_give((void **)&text
);
3205 if (ret
) fs_give((void **)&ret
);
3207 if (rv
) *rv
= pc
->key
== NULL
? -1 : 1;
3209 out
= BIO_new(BIO_s_mem());
3210 (void) BIO_reset(out
);
3212 if(PKCS7_decrypt(p7
, pc
->key
, pc
->cert
, out
, 0) != 0){
3213 BIO_get_mem_data(out
, &tmp
);
3217 q_status_message1(SM_ORDER
, 1, 1, _("Error decrypting: %s"),
3218 (char *) openssl_error_string());
3225 * Try to decode (decrypt or verify a signature) a PKCS7 body
3226 * Returns non-zero if something was changed.
3229 do_decoding(BODY
*b
, long msgno
, const char *section
)
3231 int modified_the_body
= 0;
3235 EVP_PKEY
*key
= NULL
;
3236 PERSONAL_CERT
*pcert
= NULL
;
3237 char *what_we_did
= "";
3240 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"));
3245 * Extract binary data from part to an in-memory store
3249 if(get_smime_sparep_type(b
->sparep
) == P7Type
)
3250 p7
= (PKCS7
*) get_smime_sparep_data(b
->sparep
);
3253 p7
= get_pkcs7_from_part(msgno
, section
&& *section
? section
: "1");
3255 q_status_message1(SM_ORDER
, 2, 2, "Couldn't load PKCS7 object: %s",
3256 (char*) openssl_error_string());
3261 * Save the PKCS7 object for later dealings by the user interface.
3262 * It will be cleaned up when the body is garbage collected.
3264 b
->sparep
= create_smime_sparep(P7Type
, p7
);
3267 dprint((1, "type_is_signed = %d, type_is_enveloped = %d", PKCS7_type_is_signed(p7
), PKCS7_type_is_enveloped(p7
)));
3269 if(PKCS7_type_is_signed(p7
)){
3272 out
= BIO_new(BIO_s_mem());
3273 (void) BIO_reset(out
);
3274 BIO_puts(out
, "MIME-Version: 1.0\r\n"); /* needed so rfc822_parse_msg_full believes it's MIME */
3276 sigok
= do_signature_verify(p7
, NULL
, out
, 0);
3278 what_we_did
= sigok
? _("This message was cryptographically signed.") :
3279 _("This message was cryptographically signed but the signature could not be verified.");
3281 /* make sure it's null terminated */
3282 BIO_write(out
, null
, 1);
3284 else if(!PKCS7_type_is_enveloped(p7
)){
3285 q_status_message(SM_ORDER
, 1, 1, "PKCS7 object not recognised.");
3288 else{ /* It *is* enveloped */
3291 what_we_did
= _("This message was encrypted.");
3293 /* now need to find a cert that can decrypt this */
3294 pcert
= find_certificate_matching_pkcs7(p7
);
3297 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find the certificate needed to decrypt."));
3301 recip
= pcert
->cert
;
3303 if(!load_private_key(pcert
)
3305 && ps_global
->smime
->need_passphrase
3306 && !ps_global
->smime
->already_auto_asked
){
3307 /* Couldn't load key with blank password, ask user */
3308 ps_global
->smime
->already_auto_asked
= 1;
3309 if(pith_opt_smime_get_passphrase
){
3310 (*pith_opt_smime_get_passphrase
)();
3311 load_private_key(pcert
);
3319 out
= BIO_new(BIO_s_mem());
3320 (void) BIO_reset(out
);
3321 BIO_puts(out
, "MIME-Version: 1.0\r\n");
3323 decrypt_result
= PKCS7_decrypt(p7
, key
, recip
, out
, 0);
3325 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
3326 forget_private_keys();
3328 if(!decrypt_result
){
3329 q_status_message1(SM_ORDER
, 1, 1, _("Error decrypting: %s"),
3330 (char*) openssl_error_string());
3333 BIO_write(out
, null
, 1);
3337 * We've now produced a flattened MIME object in BIO out.
3338 * It needs to be turned back into a BODY.
3347 BUF_MEM
*bptr
= NULL
;
3349 BIO_get_mem_ptr(out
, &bptr
);
3353 /* look for start of body */
3354 bstart
= strstr(h
, "\r\n\r\n");
3357 q_status_message(SM_ORDER
, 3, 3, _("Encrypted data couldn't be parsed."));
3361 bstart
+= 4; /* skip over CRLF*2 */
3363 INIT(&s
, mail_string
, bstart
, strlen(bstart
));
3364 rfc822_parse_msg_full(&env
, &body
, h
, bstart
-h
-2, &s
, BADHOST
, 0, 0);
3365 mail_free_envelope(&env
); /* Don't care about this */
3367 if(body
->type
== TYPEMULTIPART
3368 && !strucmp(body
->subtype
, "SIGNED")){
3369 char *cookie
= NULL
;
3371 for (param
= body
->parameter
; param
&& !cookie
; param
= param
->next
)
3372 if (!strucmp (param
->attribute
,"BOUNDARY")) cookie
= param
->value
;
3374 st
= fs_get(sizeof(SIZEDTEXT
));
3375 st
->data
= (void *) cpystr(bstart
+ strlen(cookie
)+4); /* 4 = strlen("--\r\n") */
3376 st
->size
= body
->nested
.part
->next
->body
.mime
.offset
- 2*(strlen(cookie
) + 4);
3377 body
->sparep
= create_smime_sparep(SizedText
, (void *)st
);
3380 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find cookie in attachment list."));
3382 body
->mime
.offset
= 0;
3383 body
->mime
.text
.size
= 0;
3386 * Now convert original body (application/pkcs7-mime)
3387 * to a multipart body with one sub-part (the decrypted body).
3388 * Note that the sub-part may also be multipart!
3391 b
->type
= TYPEMULTIPART
;
3393 fs_give((void**) &b
->subtype
);
3396 * This subtype is used in mailview.c to annotate the display of
3397 * encrypted or signed messages. We know for sure then that it's a PKCS7
3398 * part because the sparep field is set to the PKCS7 object (see above).
3400 b
->subtype
= cpystr(OUR_PKCS7_ENCLOSURE_SUBTYPE
);
3401 b
->encoding
= ENC8BIT
;
3404 fs_give((void**) &b
->description
);
3406 b
->description
= cpystr(what_we_did
);
3408 if(b
->disposition
.type
)
3409 fs_give((void **) &b
->disposition
.type
);
3411 if(b
->contents
.text
.data
)
3412 fs_give((void **) &b
->contents
.text
.data
);
3415 mail_free_body_parameter(&b
->parameter
);
3417 /* Allocate mem for the sub-part, and copy over the contents of our parsed body */
3418 b
->nested
.part
= fs_get(sizeof(PART
));
3419 b
->nested
.part
->body
= *body
;
3420 b
->nested
.part
->next
= NULL
;
3422 fs_give((void**) &body
);
3425 * IMPORTANT BIT: set the body->contents.text.data elements to contain
3426 * the decrypted data. Otherwise, it'll try to load it from the original
3429 create_local_cache(bstart
-b
->nested
.part
->body
.mime
.offset
, bstart
, &b
->nested
.part
->body
, 0);
3431 modified_the_body
= 1;
3439 return modified_the_body
;
3444 * Recursively handle PKCS7 bodies in our message.
3446 * Returns non-zero if some fiddling was done.
3449 do_fiddle_smime_message(BODY
*b
, long msgno
, char *section
)
3451 int modified_the_body
= 0;
3456 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"));
3458 if(is_pkcs7_body(b
)){
3460 if(do_decoding(b
, msgno
, section
)){
3462 * b should now be a multipart message:
3463 * fiddle it too in case it's been multiply-encrypted!
3467 modified_the_body
= 1;
3471 if(b
->type
==TYPEMULTIPART
|| MIME_MSG(b
->type
, b
->subtype
)){
3477 if(MIME_MULT_SIGNED(b
->type
, b
->subtype
)){
3481 * Ahah. We have a multipart signed entity.
3484 * part 1 (signed thing)
3485 * part 2 (the pkcs7 signature)
3487 * We're going to convert that to
3489 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
3490 * part 1 (signed thing)
3491 * part 2 has been freed
3493 * We also extract the signature from part 2 and save it
3494 * in the multipart body->sparep, and we add a description
3495 * in the multipart body->description.
3498 * The results of a decrypted message will be similar. It
3501 * Multipart/OUR_PKCS7_ENCLOSURE_SUBTYPE
3502 * part 1 (decrypted thing)
3505 modified_the_body
+= do_detached_signature_verify(b
, msgno
, section
);
3507 else if(MIME_MSG(b
->type
, b
->subtype
)){
3508 modified_the_body
+= do_fiddle_smime_message(b
->nested
.msg
->body
, msgno
, section
);
3512 for(p
=b
->nested
.part
,partNum
=1; p
; p
=p
->next
,partNum
++){
3513 /* Append part number to the section string */
3515 snprintf(newSec
, sizeof(newSec
), "%s%s%d", section
, *section
? "." : "", partNum
);
3517 modified_the_body
+= do_fiddle_smime_message(&p
->body
, msgno
, newSec
);
3522 return modified_the_body
;
3527 * Fiddle a message in-place by decrypting/verifying S/MIME entities.
3528 * Returns non-zero if something was changed.
3531 fiddle_smime_message(BODY
*b
, long msgno
)
3533 return do_fiddle_smime_message(b
, msgno
, "");
3537 /********************************************************************************/
3541 * Output a string in a distinctive style
3544 gf_puts_uline(char *txt
, gf_io_t pc
)
3546 pc(TAG_EMBED
); pc(TAG_BOLDON
);
3548 pc(TAG_EMBED
); pc(TAG_BOLDOFF
);
3551 /* get_chain_for_cert: error and level are mandatory arguments */
3553 get_chain_for_cert(X509
*cert
, int *error
, int *level
)
3555 STACK_OF(X509
) *chain
= NULL
;
3556 X509_STORE_CTX
*ctx
;
3558 int rc
; /* return code */
3563 if((ctx
= X509_STORE_CTX_new()) != NULL
){
3564 X509_STORE_set_flags(s_cert_store
, 0);
3565 if(!X509_STORE_CTX_init(ctx
, s_cert_store
, cert
, NULL
))
3566 *error
= X509_STORE_CTX_get_error(ctx
);
3567 else if((chain
= sk_X509_new_null()) != NULL
){
3568 for(x
= cert
; ; x
= xtmp
){
3570 sk_X509_push(chain
, X509_dup(x
));
3571 rc
= X509_STORE_CTX_get1_issuer(&xtmp
, ctx
, x
);
3576 if(!X509_check_issued(xtmp
, xtmp
))
3580 X509_STORE_CTX_free(ctx
);
3587 * Sign a message. Called from call_mailer in send.c.
3589 * This takes the header for the outgoing message as well as a pointer
3590 * to the current body (which may be reallocated).
3591 * The last argument (BODY **bp) is an argument that tells Alpine
3592 * if the body has 8 bit. if *bp is not null we compute two signatures
3593 * one for the quoted-printable encoded message, and another for the
3594 * 8bit encoded message. We return the signature for the 8bit encoded
3595 * part in p2->body.mime.text.data.
3596 * The reason why we compute two signatures is so that we can decide
3597 * which one to use later, and we only do it in the case that *bp is
3598 * not null. If we did not do this, then we might not be able to sign
3599 * a message until we log in to the smtp server, so instead of doing
3600 * that, we get ready for any possible situation we might find.
3603 sign_outgoing_message(METAENV
*header
, BODY
**bodyP
, int dont_detach
, BODY
**bp
)
3605 STORE_S
*outs
= NULL
;
3606 STORE_S
*outs_2
= NULL
;
3607 BODY
*body
= *bodyP
;
3608 BODY
*newBody
= NULL
;
3611 PERSONAL_CERT
*pcert
;
3618 STACK_OF(X509
) *chain
;
3619 int result
= 0, error
;
3620 int flags
= dont_detach
? 0 : PKCS7_DETACHED
;
3623 dprint((9, "sign_outgoing_message()"));
3627 /* Look for a private key matching the sender address... */
3629 pcert
= match_personal_cert(header
->env
);
3632 q_status_message(SM_ORDER
, 3, 3, _("Couldn't find the certificate needed to sign."));
3636 if(!load_private_key(pcert
) && ps_global
->smime
&& ps_global
->smime
->need_passphrase
){
3637 /* Couldn't load key with blank password, try again */
3638 if(pith_opt_smime_get_passphrase
){
3639 (*pith_opt_smime_get_passphrase
)();
3640 load_private_key(pcert
);
3647 if(((chain
= get_chain_for_cert(pcert
->cert
, &error
, &level
)) != NULL
&& error
)
3649 sk_X509_pop_free(chain
, X509_free
);
3654 q_status_message(SM_ORDER
, 1, 1,
3655 _("Not all certificates needed to verify signature included in signed message"));
3657 in
= body_to_bio(body
);
3659 p7
= PKCS7_sign(pcert
->cert
, pcert
->key
, chain
, in
, flags
);
3662 int i
, save_encoding
;
3664 for(i
= 0; (i
<= ENCMAX
) && body_encodings
[i
]; i
++);
3666 if(i
> ENCMAX
){ /* no empty encoding slots! */
3670 save_encoding
= (*bp
)->encoding
;
3671 body_encodings
[(*bp
)->encoding
= i
] = body_encodings
[ENC8BIT
];
3673 in_2
= body_to_bio(body
);
3675 body_encodings
[i
] = NULL
;
3676 (*bp
)->encoding
= save_encoding
;
3681 p7_2
= PKCS7_sign(pcert
->cert
, pcert
->key
, chain
, in_2
, flags
);
3683 if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE
,ps_global
))
3684 forget_private_keys();
3687 sk_X509_pop_free(chain
, X509_free
);
3690 q_status_message(SM_ORDER
, 1, 1, _("Error creating signed object."));
3694 outs
= so_get(BioType
, NULL
, EDIT_ACCESS
);
3695 out
= bio_from_store(outs
);
3697 i2d_PKCS7_bio(out
, p7
);
3698 (void) BIO_flush(out
);
3700 so_seek(outs
, 0, SEEK_SET
);
3702 if(bp
&& *bp
&& p7_2
){
3703 outs_2
= so_get(BioType
, NULL
, EDIT_ACCESS
);
3704 out_2
= bio_from_store(outs_2
);
3706 i2d_PKCS7_bio(out_2
, p7_2
);
3707 (void) BIO_flush(out_2
);
3709 so_seek(outs_2
, 0, SEEK_SET
);
3712 if((flags
&PKCS7_DETACHED
)==0){
3714 /* the simple case: the signed data is in the pkcs7 object */
3716 newBody
= mail_newbody();
3718 setup_pkcs7_body_for_signature(newBody
, "S/MIME Cryptographically Signed Message", "pkcs7-mime", "smime.p7m", "signed-data");
3720 newBody
->contents
.text
.data
= (unsigned char *) outs
;
3729 * We have to create a new body as follows:
3731 * multipart/signed; blah blah blah
3732 * reference to existing body
3737 newBody
= mail_newbody();
3739 newBody
->type
= TYPEMULTIPART
;
3740 newBody
->subtype
= cpystr("signed");
3741 newBody
->encoding
= ENC7BIT
;
3743 set_parameter(&newBody
->parameter
, "protocol", "application/pkcs7-signature");
3744 set_parameter(&newBody
->parameter
, "micalg", "sha1");
3746 p1
= mail_newbody_part();
3747 p2
= mail_newbody_part();
3750 * This is nasty. We're just copying the body in here,
3751 * but since our newBody is freed at the end of call_mailer,
3752 * we mustn't let this body (the original one) be freed twice.
3754 p1
->body
= *body
; /* ARRGH. This is special cased at the end of call_mailer */
3758 setup_pkcs7_body_for_signature(&p2
->body
, "S/MIME Cryptographic Signature", "pkcs7-signature", "smime.p7s", NULL
);
3759 p2
->body
.mime
.text
.data
= (unsigned char *) outs_2
;
3760 p2
->body
.contents
.text
.data
= (unsigned char *) outs
;
3762 newBody
->nested
.part
= p1
;
3775 if(p7_2
) PKCS7_free(p7_2
);
3779 dprint((9, "sign_outgoing_message returns %d", result
));
3785 new_smime_struct(void)
3787 SMIME_STUFF_S
*ret
= NULL
;
3789 ret
= (SMIME_STUFF_S
*) fs_get(sizeof(*ret
));
3790 memset((void *) ret
, 0, sizeof(*ret
));
3791 ret
->publictype
= Nada
;
3798 free_smime_struct(SMIME_STUFF_S
**smime
)
3800 if(smime
&& *smime
){
3801 if((*smime
)->passphrase_emailaddr
){
3803 for(i
= 0; (*smime
)->passphrase_emailaddr
[i
] != NULL
; i
++)
3804 fs_give((void **) &(*smime
)->passphrase_emailaddr
[i
]);
3805 fs_give((void **) (*smime
)->passphrase_emailaddr
);
3808 if((*smime
)->publicpath
)
3809 fs_give((void **) &(*smime
)->publicpath
);
3811 if((*smime
)->publiccertlist
)
3812 free_certlist(&(*smime
)->publiccertlist
);
3814 if((*smime
)->backuppubliccertlist
)
3815 free_certlist(&(*smime
)->backuppubliccertlist
);
3817 if((*smime
)->cacertlist
)
3818 free_certlist(&(*smime
)->cacertlist
);
3820 if((*smime
)->backupcacertlist
)
3821 free_certlist(&(*smime
)->backupcacertlist
);
3823 if((*smime
)->privatecertlist
)
3824 free_certlist(&(*smime
)->privatecertlist
);
3826 if((*smime
)->backupprivatecertlist
)
3827 free_certlist(&(*smime
)->backupprivatecertlist
);
3829 if((*smime
)->publiccontent
)
3830 fs_give((void **) &(*smime
)->publiccontent
);
3832 if((*smime
)->privatepath
)
3833 fs_give((void **) &(*smime
)->privatepath
);
3835 if((*smime
)->personal_certs
){
3838 pc
= (PERSONAL_CERT
*) (*smime
)->personal_certs
;
3839 free_personal_certs(&pc
);
3840 (*smime
)->personal_certs
= NULL
;
3843 if((*smime
)->privatecontent
)
3844 fs_give((void **) &(*smime
)->privatecontent
);
3846 if((*smime
)->capath
)
3847 fs_give((void **) &(*smime
)->capath
);
3849 if((*smime
)->cacontent
)
3850 fs_give((void **) &(*smime
)->cacontent
);
3852 fs_give((void **) smime
);