summaryrefslogtreecommitdiff
path: root/pith/smime.c
diff options
context:
space:
mode:
Diffstat (limited to 'pith/smime.c')
-rw-r--r--pith/smime.c196
1 files changed, 89 insertions, 107 deletions
diff --git a/pith/smime.c b/pith/smime.c
index ce7b6a70..6c49fdcc 100644
--- a/pith/smime.c
+++ b/pith/smime.c
@@ -62,7 +62,7 @@ static BIO *bio_from_store(STORE_S *store);
static STORE_S *get_part_contents(long msgno, const char *section);
static PKCS7 *get_pkcs7_from_part(long msgno, const char *section);
static int do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent);
-int do_detached_signature_verify(BODY *b, long msgno, char *section);
+static int do_detached_signature_verify(BODY *b, long msgno, char *section);
static PERSONAL_CERT *find_certificate_matching_pkcs7(PKCS7 *p7);
static int do_decoding(BODY *b, long msgno, const char *section);
static void free_smime_struct(SMIME_STUFF_S **smime);
@@ -90,13 +90,6 @@ static X509_STORE *s_cert_store;
static int seeded = 0;
static int egdsocket = 0;
-typedef enum {P7Type, CharType, SizedText} SpareType;
-
-typedef struct smime_sparep_t {
- SpareType sptype;
- void *data;
-} SMIME_SPARE_S;
-
void *
create_smime_sparep(SpareType stype, void *s)
{
@@ -1410,13 +1403,15 @@ copy_dir_to_container(WhichCerts which, char *contents)
int ret = 0;
BIO *bio_out = NULL, *bio_in = NULL;
char srcpath[MAXPATH+1], dstpath[MAXPATH+1], emailaddr[MAXPATH], file[MAXPATH], line[4096];
- char *tempfile = NULL;
+ char *tempfile = NULL, fpath[MAXPATH+1];
DIR *dirp;
struct dirent *d;
REMDATA_S *rd = NULL;
char *configdir = NULL;
char *configpath = NULL;
+ char *configcontainer = NULL;
char *filesuffix = NULL;
+ char *ret_dir = NULL;
dprint((9, "copy_dir_to_container(%s)", which==Public ? "Public" : which==Private ? "Private" : which==CACert ? "CACert" : "?"));
smime_init();
@@ -1429,16 +1424,19 @@ copy_dir_to_container(WhichCerts which, char *contents)
if(which == Public){
configdir = ps_global->VAR_PUBLICCERT_DIR;
configpath = ps_global->smime->publicpath;
+ configcontainer = cpystr(DF_PUBLIC_CONTAINER);
filesuffix = ".crt";
}
else if(which == Private){
configdir = ps_global->VAR_PRIVATEKEY_DIR;
configpath = ps_global->smime->privatepath;
+ configcontainer = cpystr(DF_PRIVATE_CONTAINER);
filesuffix = ".key";
}
else if(which == CACert){
configdir = ps_global->VAR_CACERT_DIR;
configpath = ps_global->smime->capath;
+ configcontainer = cpystr(DF_CA_CONTAINER);
filesuffix = ".crt";
}
@@ -1534,7 +1532,7 @@ copy_dir_to_container(WhichCerts which, char *contents)
* dstpath is either the local Container file or the local cache file
* for the remote Container file.
*/
- tempfile = tempfile_in_same_dir(dstpath, "az", NULL);
+ tempfile = tempfile_in_same_dir(dstpath, "az", &ret_dir);
}
/*
@@ -1609,12 +1607,24 @@ copy_dir_to_container(WhichCerts which, char *contents)
BIO_free(bio_out);
if(!ret){
- if(rename_file(tempfile, dstpath) < 0){
+ if(ret_dir){
+ if(strlen(dstpath) + strlen(configcontainer) - strlen(ret_dir) + 1 < sizeof(dstpath))
+ snprintf(fpath, sizeof(fpath), "%s%c%s",
+ dstpath, tempfile[strlen(ret_dir)], configcontainer);
+ else
+ ret = -1;
+ }
+ else ret = -1;
+
+ if(!ret){
+ if(rename_file(tempfile, fpath) < 0){
q_status_message2(SM_ORDER, 3, 3,
- _("Can't rename %s to %s"), tempfile, dstpath);
+ _("Can't rename %s to %s"), tempfile, fpath);
ret = -1;
+ } else q_status_message1(SM_ORDER, 3, 3,
+ _("saved container to %s"), fpath);
}
-
+
/* if the container is remote, copy it */
if(!ret && IS_REMOTE(configpath)){
int e;
@@ -1656,6 +1666,12 @@ copy_dir_to_container(WhichCerts which, char *contents)
if(tempfile)
fs_give((void **) &tempfile);
+ if(ret_dir)
+ fs_give((void **) &ret_dir);
+
+ if(configcontainer)
+ fs_give((void **) &configcontainer);
+
return ret;
}
@@ -1921,36 +1937,6 @@ is_pkcs7_body(BODY *body)
}
-#ifdef notdef
-/*
- * Somewhat useful debug utility to dump the contents of a BIO to a file.
- * Note that a memory BIO will have its contents eliminated after they
- * are read so this will break the next step.
- */
-static void
-dump_bio_to_file(BIO *in, char *filename)
-{
- char iobuf[4096];
- int len;
- BIO *out;
-
- out = BIO_new_file(filename, "w");
-
- if(out){
- if(BIO_method_type(in) != BIO_TYPE_MEM)
- BIO_reset(in);
-
- while((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0)
- BIO_write(out, iobuf, len);
-
- BIO_free(out);
- }
-
- BIO_reset(in);
-}
-#endif
-
-
/*
* Recursively stash a pointer to the decrypted data in our
* manufactured body.
@@ -2255,7 +2241,7 @@ end:
/*
* Encrypt a message on the way out. Called from call_mailer in send.c
- * The body may be reallocated.
+ * The body may be reallocated.
*/
int
encrypt_outgoing_message(METAENV *header, BODY **bodyP)
@@ -2287,9 +2273,9 @@ encrypt_outgoing_message(METAENV *header, BODY **bodyP)
for(a=*pf->addr; a; a=a->next){
snprintf(buf, sizeof(buf), "%s@%s", a->mailbox, a->host);
- if((cert = get_cert_for(buf, Public)) != NULL)
+ if((cert = get_cert_for(buf, Public)) != NULL){
sk_X509_push(encerts,cert);
- else{
+ }else{
q_status_message2(SM_ORDER, 1, 1,
_("Unable to find certificate for <%s@%s>"),
a->mailbox, a->host);
@@ -2491,10 +2477,12 @@ static int
do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent)
{
STACK_OF(X509) *otherCerts = NULL;
+ CertList *cl;
int result;
+ int flags;
const char *data;
long err;
-
+
if(!s_cert_store){
if(!silent) q_status_message(SM_ORDER | SM_DING, 2, 2,
_("Couldn't verify S/MIME signature: No CA Certs were loaded"));
@@ -2504,8 +2492,31 @@ do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent)
smime_extract_and_save_cert(p7);
- result = PKCS7_verify(p7, otherCerts, s_cert_store, in, out, 0);
-
+ flags = F_ON(F_USE_CERT_STORE_ONLY, ps_global) ? PKCS7_NOINTERN : 0;
+
+ if(ps_global->smime->publiccertlist == NULL){
+ renew_cert_data(&ps_global->smime->publiccertlist, Public);
+ for(cl = ps_global->smime->publiccertlist; cl ; cl = cl->next){
+ if(cl->x509_cert == NULL){
+ char *s = strrchr(cl->name, '.');
+ *s = '\0';
+ cl->x509_cert = get_cert_for(cl->name, Public);
+ *s = '.';
+ }
+ }
+ }
+
+ if(ps_global->smime->publiccertlist){
+ otherCerts = sk_X509_new_null();
+ for(cl = ps_global->smime->publiccertlist; cl ; cl = cl->next)
+ if(cl->x509_cert != NULL)
+ sk_X509_push(otherCerts, X509_dup(cl->x509_cert));
+ }
+
+ result = PKCS7_verify(p7, otherCerts, s_cert_store, in, out, flags);
+
+ sk_X509_pop_free(otherCerts, X509_free);
+
if(result){
q_status_message(SM_ORDER, 1, 1, _("S/MIME signature verified ok"));
}
@@ -2550,54 +2561,6 @@ free_smime_body_sparep(void **sparep)
}
}
-/* return the mime header for this body part. Memory freed by caller */
-char *
-smime_fetch_mime(BODY *b, MAILSTREAM *stream, long msgno, char * section,
- unsigned long *mimelen)
-{
- char *rv;
- char newSec[100];
-
- if(b->type == TYPEMULTIPART)
- snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : "");
- else
- strncpy(newSec, section, sizeof(newSec));
- newSec[sizeof(newSec)-1] = '\0';
- rv = mail_fetch_mime(stream, msgno, newSec, mimelen, 0);
- return rv ? cpystr(rv) : NULL;
-}
-
-
-void
-smime_write_body_header(BODY *b, MAILSTREAM *stream, long msgno, char *section, soutr_t f, void *s)
-{
- char *rv;
- char newSec[100];
-
- if(b->nested.part == NULL)
- return;
-
- if(b->nested.part->body.type == TYPEMULTIPART)
- snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : "");
- else
- strncpy(newSec, section, sizeof(newSec));
- newSec[sizeof(newSec)-1] = '\0';
- rv = mail_fetch_mime(stream, msgno, newSec, NULL, 0);
- if(f && rv != NULL)
- (*f)(s, rv);
-}
-
-int
-write_signed_body(BODY *b, MAILSTREAM *stream, long msgno, char *section, BIO *in)
-{
-
- smime_write_body_header(b, stream, msgno, section, rfc822_output_func, in);
-
-
-}
-
-
-
/* Big comment, explaining the mess that exists out there, and how we deal
with it, and also how we solve the problems that are created this way.
@@ -2664,19 +2627,30 @@ write_signed_body(BODY *b, MAILSTREAM *stream, long msgno, char *section, BIO *i
processed text. Nevertheless, at this time, this is automatic, and is
causing a delay in the processing of the message, but it is validating
correctly all messages.
+
+ PART IV
+
+ When the user sends a message as encrypted and signed, this code used to
+ encrypt first, and then sign the pkcs7 body, but it turns out that some
+ other clients can not handle these messages. While we could argue that the
+ other clients need to improve, we will support reading messages in both
+ ways, and will send messages using this technique; that is, signed first,
+ encrypted second. It seems that all tested clients support this way, so it
+ should be safe to do so.
*/
/*
* Given a multipart body of type multipart/signed, attempt to verify it.
* Returns non-zero if the body was changed.
*/
-int
+static int
do_detached_signature_verify(BODY *b, long msgno, char *section)
{
PKCS7 *p7 = NULL;
BIO *in = NULL;
PART *p;
int result, modified_the_body = 0;
+ int flag; /* 1 silent, 0 not silent */
unsigned long mimelen, bodylen;
char newSec[100], *mimetext, *bodytext;
char *what_we_did;
@@ -2693,7 +2667,7 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
if(get_smime_sparep_type(b->sparep) == SizedText){
/* bodytext includes mimetext */
st = (SIZEDTEXT *) get_smime_sparep_data(b->sparep);
- bodytext = st->data;
+ bodytext = (char *) st->data;
bodylen = st->size;
mimetext = NULL;
mimelen = 0L;
@@ -2724,7 +2698,9 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
* validates when we remove the last two characters. Silence
* any failures first.
*/
- if(((result = do_signature_verify(p7, in, NULL, 1)) == 0)
+ flag = (bodylen <= 2 || strncmp(bodytext+bodylen-2, "\r\n", 2))
+ ? 0 : 1;
+ if(((result = do_signature_verify(p7, in, NULL, flag)) == 0)
&& bodylen > 2
&& (strncmp(bodytext+bodylen-2,"\r\n", 2) == 0)){
BUF_MEM *biobuf = NULL;
@@ -2738,7 +2714,9 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
* information. In this case, we fetch the message and we process
* it by hand.
*/
- if((result = do_signature_verify(p7, in, NULL, 1)) == 0
+ flag = (mimelen == 0 || !IS_REMOTE(ps_global->mail_stream->mailbox))
+ ? 0 : 1;
+ if((result = do_signature_verify(p7, in, NULL, flag)) == 0
&& mimelen > 0 /* do not do this for encrypted messages */
&& IS_REMOTE(ps_global->mail_stream->mailbox)){
char *fetch;
@@ -2766,7 +2744,7 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
mail_free_envelope(&env);
mail_free_body_part(&b->nested.part);
- b->nested.part = body->nested.part;
+ b->nested.part = mail_body_section(body, section)->nested.part;
create_local_cache(bstart, bstart, &b->nested.part->body, 1);
modified_the_body = 1;
@@ -3086,11 +3064,15 @@ do_decoding(BODY *b, long msgno, const char *section)
char *cookie = NULL;
PARAMETER *param;
for (param = body->parameter; param && !cookie; param = param->next)
- if (!strucmp (param->attribute,"BOUNDARY")) cookie = param->value;
- st = fs_get(sizeof(SIZEDTEXT));
- st->data = (void *) cpystr(bstart + strlen(cookie)+4); /* 4 = strlen("--\r\n") */
- st->size = body->nested.part->next->body.mime.offset - 2*(strlen(cookie) + 4);
- body->sparep = create_smime_sparep(SizedText, (void *)st);
+ if (!strucmp (param->attribute,"BOUNDARY")) cookie = param->value;
+ if(cookie != NULL){
+ st = fs_get(sizeof(SIZEDTEXT));
+ st->data = (void *) cpystr(bstart + strlen(cookie)+4); /* 4 = strlen("--\r\n") */
+ st->size = body->nested.part->next->body.mime.offset - 2*(strlen(cookie) + 4);
+ body->sparep = create_smime_sparep(SizedText, (void *)st);
+ }
+ else
+ q_status_message(SM_ORDER, 3, 3, _("Couldn't find cookie in attachment list."));
}
body->mime.offset = 0;
body->mime.text.size = 0;