commit 3f7587f: [Feature] Support SMIME signed messages container

Vsevolod Stakhov vsevolod at highsecure.ru
Mon Dec 21 17:21:09 UTC 2020


Author: Vsevolod Stakhov
Date: 2020-12-21 17:16:50 +0000
URL: https://github.com/rspamd/rspamd/commit/3f7587fc5812c66f66bb1574507ba077e26e814c (HEAD -> master)

[Feature] Support SMIME signed messages container
Issue: #3568

---
 src/libmime/mime_parser.c | 81 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 4 deletions(-)

diff --git a/src/libmime/mime_parser.c b/src/libmime/mime_parser.c
index 213eb99d2..207bd4462 100644
--- a/src/libmime/mime_parser.c
+++ b/src/libmime/mime_parser.c
@@ -23,6 +23,8 @@
 #include "multipattern.h"
 #include "contrib/libottery/ottery.h"
 #include "contrib/uthash/utlist.h"
+#include <openssl/cms.h>
+#include <openssl/pkcs7.h>
 
 struct rspamd_mime_parser_lib_ctx {
 	struct rspamd_multipattern *mp_boundary;
@@ -77,8 +79,17 @@ static enum rspamd_mime_parse_error
 rspamd_mime_parse_normal_part (struct rspamd_task *task,
 		struct rspamd_mime_part *part,
 		struct rspamd_mime_parser_ctx *st,
+		struct rspamd_content_type *ct,
 		GError **err);
 
+static enum rspamd_mime_parse_error
+rspamd_mime_process_multipart_node (struct rspamd_task *task,
+									struct rspamd_mime_parser_ctx *st,
+									struct rspamd_mime_part *multipart,
+									const gchar *start, const gchar *end,
+									gboolean is_finished,
+									GError **err);
+
 
 #define RSPAMD_MIME_QUARK (rspamd_mime_parser_quark())
 static GQuark
@@ -575,6 +586,7 @@ static enum rspamd_mime_parse_error
 rspamd_mime_parse_normal_part (struct rspamd_task *task,
 		struct rspamd_mime_part *part,
 		struct rspamd_mime_parser_ctx *st,
+		struct rspamd_content_type *ct,
 		GError **err)
 {
 	rspamd_fstring_t *parsed;
@@ -690,6 +702,67 @@ rspamd_mime_parse_normal_part (struct rspamd_task *task,
 			part->raw_data.len, rspamd_cte_to_string (part->cte));
 	rspamd_mime_parser_calc_digest (part);
 
+	if (ct && (ct->flags & RSPAMD_CONTENT_TYPE_SMIME)) {
+		CMS_ContentInfo *cms;
+		const unsigned char *der_beg = part->parsed_data.begin;
+		cms = d2i_CMS_ContentInfo (NULL, &der_beg, part->parsed_data.len);
+
+		if (cms) {
+			const ASN1_OBJECT *asn_ct = CMS_get0_eContentType (cms);
+			int ct_nid = OBJ_obj2nid (asn_ct);
+
+			if (ct_nid == NID_pkcs7_data) {
+				BIO *bio = BIO_new_mem_buf (part->parsed_data.begin,
+						part->parsed_data.len);
+
+				PKCS7 *p7;
+				p7 = d2i_PKCS7_bio (bio, NULL);
+
+				if (p7) {
+					ct_nid = OBJ_obj2nid (p7->type);
+
+					if (ct_nid == NID_pkcs7_signed) {
+						PKCS7 *p7_signed_content = p7->d.sign->contents;
+
+						ct_nid =  OBJ_obj2nid (p7_signed_content->type);
+
+						if (ct_nid == NID_pkcs7_data) {
+							int ret;
+
+							msg_debug_mime ("found an additional part inside of "
+											"smime structure of type %T/%T; length=%d",
+									&ct->type, &ct->subtype, p7_signed_content->d.data->length);
+							/*
+							 * Since ASN.1 structures are freed, we need to copy
+							 * the content
+							 */
+							gchar *cpy = rspamd_mempool_alloc (task->task_pool,
+									p7_signed_content->d.data->length);
+							memcpy (cpy, p7_signed_content->d.data->data,
+									p7_signed_content->d.data->length);
+							ret = rspamd_mime_process_multipart_node (task,
+									st, NULL,
+									cpy,cpy + p7_signed_content->d.data->length,
+									TRUE, err);
+
+							PKCS7_free (p7);
+							BIO_free (bio);
+							CMS_ContentInfo_free (cms);
+
+							return ret;
+						}
+					}
+
+					PKCS7_free (p7);
+				}
+
+				BIO_free (bio);
+			}
+
+			CMS_ContentInfo_free (cms);
+		}
+	}
+
 	return RSPAMD_MIME_PARSE_OK;
 }
 
@@ -839,13 +912,13 @@ rspamd_mime_process_multipart_node (struct rspamd_task *task,
 		g_ptr_array_add (st->stack, npart);
 		npart->part_type = RSPAMD_MIME_PART_MESSAGE;
 
-		if ((ret = rspamd_mime_parse_normal_part (task, npart, st, err))
+		if ((ret = rspamd_mime_parse_normal_part (task, npart, st, sel, err))
 				== RSPAMD_MIME_PARSE_OK) {
 			ret = rspamd_mime_parse_message (task, npart, st, err);
 		}
 	}
 	else {
-		ret = rspamd_mime_parse_normal_part (task, npart, st, err);
+		ret = rspamd_mime_parse_normal_part (task, npart, st, sel, err);
 	}
 
 	return ret;
@@ -1478,14 +1551,14 @@ rspamd_mime_parse_message (struct rspamd_task *task,
 		ret = rspamd_mime_parse_multipart_part (task, npart, nst, err);
 	}
 	else if (sel->flags & RSPAMD_CONTENT_TYPE_MESSAGE) {
-		if ((ret = rspamd_mime_parse_normal_part (task, npart, nst, err))
+		if ((ret = rspamd_mime_parse_normal_part (task, npart, nst, sel, err))
 			== RSPAMD_MIME_PARSE_OK) {
 			npart->part_type = RSPAMD_MIME_PART_MESSAGE;
 			ret = rspamd_mime_parse_message (task, npart, nst, err);
 		}
 	}
 	else {
-		ret = rspamd_mime_parse_normal_part (task, npart, nst, err);
+		ret = rspamd_mime_parse_normal_part (task, npart, nst, sel, err);
 	}
 
 	if (ret != RSPAMD_MIME_PARSE_OK) {


More information about the Commits mailing list