summaryrefslogtreecommitdiffstats
path: root/mailnews/mime/src/mimecms.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/mime/src/mimecms.cpp')
-rw-r--r--mailnews/mime/src/mimecms.cpp148
1 files changed, 107 insertions, 41 deletions
diff --git a/mailnews/mime/src/mimecms.cpp b/mailnews/mime/src/mimecms.cpp
index 9289c0c33..6f7455c0a 100644
--- a/mailnews/mime/src/mimecms.cpp
+++ b/mailnews/mime/src/mimecms.cpp
@@ -8,6 +8,7 @@
#include "nsICMSMessageErrors.h"
#include "nsICMSDecoder.h"
#include "mimecms.h"
+#include "mimemcms.h"
#include "mimemsig.h"
#include "nspr.h"
#include "mimemsg.h"
@@ -28,6 +29,9 @@
using namespace mozilla::mailnews;
+// The name "mime encrypted" is misleading, because this code is used
+// both for CMS messages that are encrypted, and also for messages that
+// aren't encrypted, but only contain a signature.
#define MIME_SUPERCLASS mimeEncryptedClass
MimeDefClass(MimeEncryptedCMS, MimeEncryptedCMSClass,
@@ -68,10 +72,11 @@ typedef struct MimeCMSdata
bool ci_is_encrypted;
char *sender_addr;
bool decoding_failed;
+ bool skip_content;
uint32_t decoded_bytes;
MimeObject *self;
- bool parent_is_encrypted_p;
- bool parent_holds_stamp_p;
+ bool any_parent_is_encrypted_p;
+ bool any_parent_is_signed_p;
nsCOMPtr<nsIMsgSMIMEHeaderSink> smimeHeaderSink;
nsCString url;
@@ -81,12 +86,11 @@ typedef struct MimeCMSdata
ci_is_encrypted(false),
sender_addr(nullptr),
decoding_failed(false),
+ skip_content(false),
decoded_bytes(0),
self(nullptr),
- parent_is_encrypted_p(false),
- parent_holds_stamp_p(false)
- {
- }
+ any_parent_is_encrypted_p(false),
+ any_parent_is_signed_p(false) {}
~MimeCMSdata()
{
@@ -140,6 +144,46 @@ bool MimeEncryptedCMS_encrypted_p (MimeObject *obj)
return false;
}
+bool MimeEncOrMP_CMS_signed_p(MimeObject *obj) {
+ bool is_signed;
+
+ if (!obj) return false;
+ if (mime_typep(obj, (MimeObjectClass *)&mimeMultipartSignedCMSClass)) {
+ return true;
+ }
+ if (mime_typep(obj, (MimeObjectClass *)&mimeEncryptedCMSClass)) {
+ MimeEncrypted *enc = (MimeEncrypted *)obj;
+ MimeCMSdata *data = (MimeCMSdata *)enc->crypto_closure;
+ if (!data || !data->content_info) return false;
+ data->content_info->ContentIsSigned(&is_signed);
+ return is_signed;
+ }
+ return false;
+}
+
+bool MimeAnyParentCMSEncrypted(MimeObject *obj)
+{
+ MimeObject *o2 = obj;
+ while (o2 && o2->parent) {
+ if (MimeEncryptedCMS_encrypted_p(o2->parent)) {
+ return true;
+ }
+ o2 = o2->parent;
+ }
+ return false;
+}
+
+bool MimeAnyParentCMSSigned(MimeObject *obj)
+{
+ MimeObject *o2 = obj;
+ while (o2 && o2->parent) {
+ if (MimeEncOrMP_CMS_signed_p(o2->parent)) {
+ return true;
+ }
+ o2 = o2->parent;
+ }
+ return false;
+}
bool MimeCMSHeadersAndCertsMatch(nsICMSMessage *content_info,
nsIX509Cert *signerCert,
@@ -439,38 +483,37 @@ static void *MimeCMS_init(MimeObject *obj,
data->output_fn = output_fn;
data->output_closure = output_closure;
PR_SetError(0, 0);
- data->decoder_context = do_CreateInstance(NS_CMSDECODER_CONTRACTID, &rv);
- if (NS_FAILED(rv))
- {
- delete data;
- return 0;
- }
- rv = data->decoder_context->Start(MimeCMS_content_callback, data);
- if (NS_FAILED(rv))
- {
- delete data;
- return 0;
+ data->any_parent_is_signed_p = MimeAnyParentCMSSigned(obj);
+
+ if (data->any_parent_is_signed_p) {
+ // Parent is signed.
+ // We don't know yet if this child is signed or encrypted.
+ // (We'll know after decoding has completed and EOF is called.)
+ // We don't support "inner encrypt" with outer sign, because the
+ // inner encrypted part could have been produced by an attacker who
+ // stripped away a part containing the signature (S/MIME doesn't
+ // have integrity protection).
+ // A sign-then-sign encoding is confusing, too, because it could be
+ // an attempt to influence which signature is shown.
+ data->skip_content = true;
}
- // XXX Fix later XXX //
- data->parent_holds_stamp_p =
- (obj->parent &&
- (mime_crypto_stamped_p(obj->parent) ||
- mime_typep(obj->parent, (MimeObjectClass *) &mimeEncryptedClass)));
+ if (!data->skip_content) {
+ data->decoder_context = do_CreateInstance(NS_CMSDECODER_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) {
+ delete data;
+ return 0;
+ }
- data->parent_is_encrypted_p =
- (obj->parent && MimeEncryptedCMS_encrypted_p (obj->parent));
+ rv = data->decoder_context->Start(MimeCMS_content_callback, data);
+ if (NS_FAILED(rv)) {
+ delete data;
+ return 0;
+ }
+ }
- /* If the parent of this object is a crypto-blob, then it's the grandparent
- who would have written out the headers and prepared for a stamp...
- (This shit sucks.)
- */
- if (data->parent_is_encrypted_p &&
- !data->parent_holds_stamp_p &&
- obj->parent && obj->parent->parent)
- data->parent_holds_stamp_p =
- mime_crypto_stamped_p (obj->parent->parent);
+ data->any_parent_is_encrypted_p = MimeAnyParentCMSEncrypted(obj);
mime_stream_data *msd = (mime_stream_data *) (data->self->options->stream_closure);
if (msd)
@@ -530,9 +573,11 @@ MimeCMS_write (const char *buf, int32_t buf_size, void *closure)
if (!data || !data->output_fn || !data->decoder_context) return -1;
- PR_SetError(0, 0);
- rv = data->decoder_context->Update(buf, buf_size);
- data->decoding_failed = NS_FAILED(rv);
+ if (!data->decoding_failed && !data->skip_content) {
+ PR_SetError(0, 0);
+ rv = data->decoder_context->Update(buf, buf_size);
+ data->decoding_failed = NS_FAILED(rv);
+ }
return 0;
}
@@ -606,7 +651,12 @@ MimeCMS_eof (void *crypto_closure, bool abort_p)
nsresult rv;
int32_t status = nsICMSMessageErrors::SUCCESS;
- if (!data || !data->output_fn || !data->decoder_context) {
+ if (!data || !data->output_fn) {
+ return -1;
+ }
+
+ if (!data->skip_content && !data->decoder_context) {
+ // If we don't skip, we should have a context.
return -1;
}
@@ -621,11 +671,12 @@ MimeCMS_eof (void *crypto_closure, bool abort_p)
*/
PR_SetError(0, 0);
- rv = data->decoder_context->Finish(getter_AddRefs(data->content_info));
- if (NS_FAILED(rv))
- status = nsICMSMessageErrors::GENERAL_ERROR;
+ if (!data->skip_content) {
+ rv = data->decoder_context->Finish(getter_AddRefs(data->content_info));
+ if (NS_FAILED(rv)) status = nsICMSMessageErrors::GENERAL_ERROR;
- data->decoder_context = nullptr;
+ data->decoder_context = nullptr;
+ }
nsCOMPtr<nsIX509Cert> certOfInterest;
@@ -644,6 +695,21 @@ MimeCMS_eof (void *crypto_closure, bool abort_p)
if (data->decoding_failed)
status = nsICMSMessageErrors::GENERAL_ERROR;
+ if (data->skip_content) {
+ // Skipping content means, we detected a forbidden combination
+ // of CMS objects, so let's make sure we replace the parent status
+ // with a bad status.
+ if (data->any_parent_is_signed_p) {
+ data->smimeHeaderSink->SignedStatus(aRelativeNestLevel,
+ nsICMSMessageErrors::GENERAL_ERROR, nullptr, data->url);
+ }
+ if (data->any_parent_is_encrypted_p) {
+ data->smimeHeaderSink->EncryptionStatus(aRelativeNestLevel,
+ nsICMSMessageErrors::GENERAL_ERROR, nullptr, data->url);
+ }
+ return 0;
+ }
+
if (!data->content_info)
{
if (!data->decoded_bytes)