summaryrefslogtreecommitdiff
path: root/pith/smime.c
diff options
context:
space:
mode:
Diffstat (limited to 'pith/smime.c')
-rw-r--r--pith/smime.c206
1 files changed, 169 insertions, 37 deletions
diff --git a/pith/smime.c b/pith/smime.c
index 566e2be5..ce7b6a70 100644
--- a/pith/smime.c
+++ b/pith/smime.c
@@ -56,18 +56,19 @@ static int load_private_key(PERSONAL_CERT *pcert);
static void create_local_cache(char *h, char *base, BODY *b, int type);
static long rfc822_output_func(void *b, char *string);
static void setup_pkcs7_body_for_signature(BODY *b, char *description,
- char *type, char *filename);
+ char *type, char *filename, char *smime_type);
static BIO *body_to_bio(BODY *body);
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);
-static int do_detached_signature_verify(BODY *b, long msgno, char *section);
+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);
static void setup_storage_locations(void);
static int copy_container_to_dir(WhichCerts which);
+static int do_fiddle_smime_message(BODY *b, long msgno, char *section);
void setup_privatekey_storage(void);
int smime_path(char *rpath, char *fpath, size_t len);
int smime_extract_and_save_cert(PKCS7 *p7);
@@ -89,6 +90,36 @@ 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)
+{
+ SMIME_SPARE_S *rv;
+
+ rv = fs_get(sizeof(SMIME_SPARE_S));
+ rv->sptype = stype;
+ rv->data = s;
+ return (void *) rv;
+}
+
+SpareType
+get_smime_sparep_type(void *s)
+{
+ return ((SMIME_SPARE_S *)s)->sptype;
+}
+
+void *
+get_smime_sparep_data(void *s)
+{
+ return ((SMIME_SPARE_S *)s)->data;
+}
+
#ifdef PASSFILE
/*
@@ -2041,7 +2072,7 @@ load_private_key(PERSONAL_CERT *pcert)
static void
-setup_pkcs7_body_for_signature(BODY *b, char *description, char *type, char *filename)
+setup_pkcs7_body_for_signature(BODY *b, char *description, char *type, char *filename, char *smime_type)
{
b->type = TYPEAPPLICATION;
b->subtype = cpystr(type);
@@ -2052,6 +2083,8 @@ setup_pkcs7_body_for_signature(BODY *b, char *description, char *type, char *fil
set_parameter(&b->disposition.parameter, "filename", filename);
set_parameter(&b->parameter, "name", filename);
+ if(smime_type && *smime_type)
+ set_parameter(&b->parameter, "smime-type", smime_type);
}
@@ -2238,6 +2271,8 @@ encrypt_outgoing_message(METAENV *header, BODY **bodyP)
BODY *body = *bodyP;
BODY *newBody = NULL;
int result = 0;
+ X509 *cert;
+ char buf[MAXPATH];
dprint((9, "encrypt_outgoing_message()"));
smime_init();
@@ -2250,13 +2285,9 @@ encrypt_outgoing_message(METAENV *header, BODY **bodyP)
for(pf = header->local; pf && pf->name; pf = pf->next)
if(pf->type == Address && pf->rcptto && pf->addr && *pf->addr){
for(a=*pf->addr; a; a=a->next){
- X509 *cert;
- char buf[MAXPATH];
-
snprintf(buf, sizeof(buf), "%s@%s", a->mailbox, a->host);
- cert = get_cert_for(buf, Public);
- if(cert)
+ if((cert = get_cert_for(buf, Public)) != NULL)
sk_X509_push(encerts,cert);
else{
q_status_message2(SM_ORDER, 1, 1,
@@ -2267,6 +2298,14 @@ encrypt_outgoing_message(METAENV *header, BODY **bodyP)
}
}
+ /* add the sender's certificate so that they can decrypt the message too */
+ for(a=header->env->from; a ; a = a->next){
+ snprintf(buf, sizeof(buf), "%s@%s", a->mailbox, a->host);
+
+ if((cert = get_cert_for(buf, Public)) != NULL
+ && sk_X509_find(encerts, cert) == -1)
+ sk_X509_push(encerts,cert);
+ }
in = body_to_bio(body);
@@ -2491,12 +2530,74 @@ do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent)
void
free_smime_body_sparep(void **sparep)
{
+ char *s;
+ SIZEDTEXT *st;
if(sparep && *sparep){
- PKCS7_free((PKCS7 *) (*sparep));
- *sparep = NULL;
+ switch(get_smime_sparep_type(*sparep)){
+ case P7Type: PKCS7_free((PKCS7 *) get_smime_sparep_data(*sparep));
+ break;
+ case CharType: s = (char *)get_smime_sparep_data(*sparep);
+ fs_give((void **) &s);
+ break;
+ case SizedText : st = (SIZEDTEXT *)get_smime_sparep_data(*sparep);
+ fs_give((void **) &st->data);
+ fs_give((void **) &st);
+ break;
+ default : break;
+ }
+ ((SMIME_SPARE_S *)(*sparep))->data = NULL;
+ fs_give(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.
@@ -2569,7 +2670,7 @@ free_smime_body_sparep(void **sparep)
* Given a multipart body of type multipart/signed, attempt to verify it.
* Returns non-zero if the body was changed.
*/
-static int
+int
do_detached_signature_verify(BODY *b, long msgno, char *section)
{
PKCS7 *p7 = NULL;
@@ -2579,29 +2680,44 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
unsigned long mimelen, bodylen;
char newSec[100], *mimetext, *bodytext;
char *what_we_did;
+ SIZEDTEXT *st;
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"));
smime_init();
- snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : "");
-
- mimetext = mail_fetch_mime(ps_global->mail_stream, msgno, (char*) newSec, &mimelen, 0);
-
- if(mimetext)
- bodytext = mail_fetch_body (ps_global->mail_stream, msgno, (char*) newSec, &bodylen, 0);
+ /* if it was signed and then encrypted, use the decrypted text
+ * to check the validity of the signature
+ */
+ if(b->sparep){
+ if(get_smime_sparep_type(b->sparep) == SizedText){
+ /* bodytext includes mimetext */
+ st = (SIZEDTEXT *) get_smime_sparep_data(b->sparep);
+ bodytext = st->data;
+ bodylen = st->size;
+ mimetext = NULL;
+ mimelen = 0L;
+ }
+ }
+ else{
+ snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : "");
+ mimetext = mail_fetch_mime(ps_global->mail_stream, msgno, (char*) newSec, &mimelen, 0);
+ if(mimetext)
+ bodytext = mail_fetch_body (ps_global->mail_stream, msgno, (char*) newSec, &bodylen, 0);
- if (mimetext == NULL || bodytext == NULL)
- return modified_the_body;
+ if(mimetext == NULL || bodytext == NULL)
+ return modified_the_body;
+ }
snprintf(newSec, sizeof(newSec), "%s%s2", section ? section : "", (section && *section) ? "." : "");
- if((p7 = get_pkcs7_from_part(msgno, newSec)) == NULL
- || (in = BIO_new(BIO_s_mem())) == NULL)
- return modified_the_body;
+ if((p7 = get_pkcs7_from_part(msgno, newSec)) == NULL
+ || (in = BIO_new(BIO_s_mem())) == NULL)
+ return modified_the_body;
(void) BIO_reset(in);
- BIO_write(in, mimetext, mimelen);
+ if(mimetext != NULL)
+ BIO_write(in, mimetext, mimelen);
BIO_write(in, bodytext, bodylen);
/* Try compatibility with the past and check if this message
@@ -2623,6 +2739,7 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
* it by hand.
*/
if((result = do_signature_verify(p7, in, NULL, 1)) == 0
+ && mimelen > 0 /* do not do this for encrypted messages */
&& IS_REMOTE(ps_global->mail_stream->mailbox)){
char *fetch;
unsigned long hlen, tlen;
@@ -2645,7 +2762,7 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
bstart += 4;
INIT(&bs, mail_string, bstart, tlen);
- rfc822_parse_msg_full(&env, &body, h, (bstart-h), &bs, BADHOST, 0, 0);
+ rfc822_parse_msg_full(&env, &body, h, bstart-h, &bs, BADHOST, 0, 0);
mail_free_envelope(&env);
mail_free_body_part(&b->nested.part);
@@ -2654,6 +2771,7 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
modified_the_body = 1;
snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : "");
+
mimetext = mail_fetch_mime(ps_global->mail_stream, msgno, (char*) newSec, &mimelen, 0);
if(mimetext)
@@ -2701,7 +2819,7 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
b->description = cpystr(what_we_did);
- b->sparep = p7;
+ b->sparep = create_smime_sparep(P7Type, p7);
p = b->nested.part;
@@ -2844,11 +2962,11 @@ do_decoding(BODY *b, long msgno, const char *section)
* Extract binary data from part to an in-memory store
*/
- if(b->sparep){ /* already done */
- p7 = (PKCS7*) b->sparep;
+ if(b->sparep){
+ if(get_smime_sparep_type(b->sparep) == P7Type)
+ p7 = (PKCS7*) get_smime_sparep_data(b->sparep);
}
else{
-
p7 = get_pkcs7_from_part(msgno, section && *section ? section : "1");
if(!p7){
q_status_message1(SM_ORDER, 2, 2, "Couldn't load PKCS7 object: %s",
@@ -2860,7 +2978,7 @@ do_decoding(BODY *b, long msgno, const char *section)
* Save the PKCS7 object for later dealings by the user interface.
* It will be cleaned up when the body is garbage collected.
*/
- b->sparep = p7;
+ b->sparep = create_smime_sparep(P7Type, p7);
}
dprint((1, "type_is_signed = %d, type_is_enveloped = %d", PKCS7_type_is_signed(p7), PKCS7_type_is_enveloped(p7)));
@@ -2927,8 +3045,7 @@ do_decoding(BODY *b, long msgno, const char *section)
if(!decrypt_result){
q_status_message1(SM_ORDER, 1, 1, _("Error decrypting: %s"),
(char*) openssl_error_string());
- goto end;
- }
+ goto end; }
BIO_write(out, null, 1);
}
@@ -2957,12 +3074,24 @@ do_decoding(BODY *b, long msgno, const char *section)
q_status_message(SM_ORDER, 3, 3, _("Encrypted data couldn't be parsed."));
}
else{
+ SIZEDTEXT *st;
bstart += 4; /* skip over CRLF*2 */
INIT(&s, mail_string, bstart, strlen(bstart));
- rfc822_parse_msg_full(&env, &body, h, (bstart-h)-2, &s, BADHOST, 0, 0);
+ rfc822_parse_msg_full(&env, &body, h, bstart-h-2, &s, BADHOST, 0, 0);
mail_free_envelope(&env); /* Don't care about this */
+ if(body->type == TYPEMULTIPART
+ && !strucmp(body->subtype, "SIGNED")){
+ 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);
+ }
body->mime.offset = 0;
body->mime.text.size = 0;
@@ -3094,7 +3223,6 @@ do_fiddle_smime_message(BODY *b, long msgno, char *section)
else{
for(p=b->nested.part,partNum=1; p; p=p->next,partNum++){
-
/* Append part number to the section string */
snprintf(newSec, sizeof(newSec), "%s%s%d", section, *section ? "." : "", partNum);
@@ -3141,6 +3269,7 @@ get_chain_for_cert(X509 *cert, int *error)
X509_STORE_CTX *ctx;
X509 *x, *xtmp;
int rc; /* return code */
+ int level = -1;
*error = 0;
ERR_clear_error();
@@ -3150,7 +3279,8 @@ get_chain_for_cert(X509 *cert, int *error)
*error = X509_STORE_CTX_get_error(ctx);
else if((chain = sk_X509_new_null()) != NULL){
for(x = cert; ; x = xtmp){
- sk_X509_push(chain, X509_dup(x));
+ if(++level > 0)
+ sk_X509_push(chain, X509_dup(x));
rc = X509_STORE_CTX_get1_issuer(&xtmp, ctx, x);
if(rc < 0)
*error = 1;
@@ -3160,8 +3290,10 @@ get_chain_for_cert(X509 *cert, int *error)
break;
}
}
- if(*error && chain != NULL)
+ if((*error && chain != NULL) || level == 0){
sk_X509_pop_free(chain, X509_free);
+ chain = NULL;
+ }
X509_STORE_CTX_free(ctx);
}
return chain;
@@ -3248,7 +3380,7 @@ sign_outgoing_message(METAENV *header, BODY **bodyP, int dont_detach)
newBody = mail_newbody();
- setup_pkcs7_body_for_signature(newBody, "S/MIME Cryptographically Signed Message", "pkcs7-mime", "smime.p7m");
+ setup_pkcs7_body_for_signature(newBody, "S/MIME Cryptographically Signed Message", "pkcs7-mime", "smime.p7m", "signed-data");
newBody->contents.text.data = (unsigned char *) outs;
*bodyP = newBody;
@@ -3288,7 +3420,7 @@ sign_outgoing_message(METAENV *header, BODY **bodyP, int dont_detach)
p1->next = p2;
- setup_pkcs7_body_for_signature(&p2->body, "S/MIME Cryptographic Signature", "pkcs7-signature", "smime.p7s");
+ setup_pkcs7_body_for_signature(&p2->body, "S/MIME Cryptographic Signature", "pkcs7-signature", "smime.p7s", NULL);
p2->body.contents.text.data = (unsigned char *) outs;
newBody->nested.part = p1;