]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] Support SMIME signed messages container
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 21 Dec 2020 17:16:50 +0000 (17:16 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 21 Dec 2020 17:17:31 +0000 (17:17 +0000)
Issue: #3568

src/libmime/mime_parser.c

index 213eb99d2f8c9d823ad7b9798e1b4634f0e76b33..207bd4462820585879f0c1bc2d54beb38c147fc1 100644 (file)
@@ -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) {