summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mailnews/compose/src/nsMsgAttachmentHandler.cpp1
-rw-r--r--mailnews/compose/src/nsMsgAttachmentHandler.h10
-rw-r--r--mailnews/mime/src/mimecms.cpp148
-rw-r--r--mailnews/mime/src/mimecryp.cpp13
-rw-r--r--mailnews/mime/src/mimeeobj.cpp10
-rw-r--r--mailnews/mime/src/mimeeobj.h16
-rw-r--r--mailnews/mime/src/mimei.cpp26
-rw-r--r--mailnews/mime/src/mimei.h14
-rw-r--r--mailnews/mime/src/mimemcms.cpp177
-rw-r--r--mailnews/mime/src/mimemsg.cpp42
-rw-r--r--mailnews/mime/src/mimemsg.h6
-rw-r--r--mailnews/mime/src/mimemsig.cpp23
-rw-r--r--mailnews/mime/src/mimemsig.h2
-rw-r--r--mailnews/mime/src/mimemult.cpp9
14 files changed, 282 insertions, 215 deletions
diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.cpp b/mailnews/compose/src/nsMsgAttachmentHandler.cpp
index 9555de37fc..4994c3fe69 100644
--- a/mailnews/compose/src/nsMsgAttachmentHandler.cpp
+++ b/mailnews/compose/src/nsMsgAttachmentHandler.cpp
@@ -116,7 +116,6 @@ nsMsgAttachmentHandler::nsMsgAttachmentHandler() :
m_bogus_attachment(false),
m_done(false),
m_already_encoded_p(false),
- m_decrypted_p(false),
mDeleteFile(false),
mMHTMLPart(false),
mPartUserOmissionOverride(false),
diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.h b/mailnews/compose/src/nsMsgAttachmentHandler.h
index 79e526627d..2034cba032 100644
--- a/mailnews/compose/src/nsMsgAttachmentHandler.h
+++ b/mailnews/compose/src/nsMsgAttachmentHandler.h
@@ -140,16 +140,6 @@ public:
bool m_already_encoded_p; // If we attach a document that is already
// encoded, we just pass it through.
- bool m_decrypted_p; /* S/MIME -- when attaching a message that was
- encrypted, it's necessary to decrypt it first
- (since nobody but the original recipient can
- read it -- if you forward it to someone in the
- raw, it will be useless to them.) This flag
- indicates whether decryption occurred, so that
- libmsg can issue appropriate warnings about
- doing a cleartext forward of a message that was
- originally encrypted. */
-
bool mDeleteFile; // If this is true, Delete the file...its
// NOT the original file!
diff --git a/mailnews/mime/src/mimecms.cpp b/mailnews/mime/src/mimecms.cpp
index 9289c0c33d..6f7455c0a0 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)
diff --git a/mailnews/mime/src/mimecryp.cpp b/mailnews/mime/src/mimecryp.cpp
index 9f6e3630f5..fd4f8f8ae7 100644
--- a/mailnews/mime/src/mimecryp.cpp
+++ b/mailnews/mime/src/mimecryp.cpp
@@ -418,18 +418,8 @@ MimeEncrypted_emit_buffered_child(MimeObject *obj)
obj->options->headers != MimeHeadersCitation &&
obj->options->write_html_p &&
obj->options->output_fn)
- // && !mime_crypto_object_p(enc->hdrs, true, obj->options)) // XXX fix later XXX //
{
char *html;
-#if 0 // XXX Fix this later XXX //
- char *html = (((MimeEncryptedClass *) obj->clazz)->crypto_generate_html
- (enc->crypto_closure));
- if (!html) return -1; /* MK_OUT_OF_MEMORY? */
-
- status = MimeObject_write(obj, html, strlen(html), false);
- PR_FREEIF(html);
- if (status < 0) return status;
-#endif
/* Now that we have written out the crypto stamp, the outermost header
block is well and truly closed. If this is in fact the outermost
@@ -445,7 +435,8 @@ MimeEncrypted_emit_buffered_child(MimeObject *obj)
for (p = obj; p->parent; p = p->parent)
outer_headers = p->headers;
NS_ASSERTION(obj->options->state->first_data_written_p, "1.2 <mscott@netscape.com> 01 Nov 2001 17:59");
- html = obj->options->generate_post_header_html_fn(NULL,
+ char *html = obj->options->generate_post_header_html_fn(
+ NULL,
obj->options->html_closure,
outer_headers);
obj->options->state->post_header_html_run_p = true;
diff --git a/mailnews/mime/src/mimeeobj.cpp b/mailnews/mime/src/mimeeobj.cpp
index da59a9d623..7d8b2f8a66 100644
--- a/mailnews/mime/src/mimeeobj.cpp
+++ b/mailnews/mime/src/mimeeobj.cpp
@@ -234,3 +234,13 @@ MimeExternalObject_displayable_inline_p (MimeObjectClass *clazz,
{
return false;
}
+
+#undef MIME_SUPERCLASS
+#define MIME_SUPERCLASS mimeExternalObjectClass
+MimeDefClass(MimeSuppressedCrypto, MimeSuppressedCryptoClass,
+ mimeSuppressedCryptoClass, &MIME_SUPERCLASS);
+
+static int MimeSuppressedCryptoClassInitialize(MimeSuppressedCryptoClass *clazz) {
+ MimeExternalObjectClass *lclass = (MimeExternalObjectClass *)clazz;
+ return MimeExternalObjectClassInitialize(lclass);
+}
diff --git a/mailnews/mime/src/mimeeobj.h b/mailnews/mime/src/mimeeobj.h
index 2b8ade5d54..076f8f9bf6 100644
--- a/mailnews/mime/src/mimeeobj.h
+++ b/mailnews/mime/src/mimeeobj.h
@@ -31,4 +31,20 @@ struct MimeExternalObject {
#define MimeExternalObjectClassInitializer(ITYPE,CSUPER) \
{ MimeLeafClassInitializer(ITYPE,CSUPER) }
+typedef struct MimeSuppressedCryptoClass MimeSuppressedCryptoClass;
+typedef struct MimeSuppressedCrypto MimeSuppressedCrypto;
+
+struct MimeSuppressedCryptoClass {
+ MimeExternalObjectClass eobj;
+};
+
+extern "C" MimeSuppressedCryptoClass mimeSuppressedCryptoClass;
+
+struct MimeSuppressedCrypto {
+ MimeExternalObject eobj;
+};
+
+#define MimeSuppressedCryptoClassInitializer(ITYPE, CSUPER) \
+ { MimeExternalObjectClassInitializer(ITYPE, CSUPER) }
+
#endif /* _MIMEEOBJ_H_ */
diff --git a/mailnews/mime/src/mimei.cpp b/mailnews/mime/src/mimei.cpp
index c0a134a627..015830a80a 100644
--- a/mailnews/mime/src/mimei.cpp
+++ b/mailnews/mime/src/mimei.cpp
@@ -731,7 +731,7 @@ mime_find_class (const char *content_type, MimeHeaders *hdrs,
// Allowing them would leak the plain text in case the part is
// cleverly hidden and the decrypted content gets included in
// replies and forwards.
- clazz = (MimeObjectClass *)&mimeExternalObjectClass;
+ clazz = (MimeObjectClass *)&mimeSuppressedCryptoClass;
return clazz;
}
@@ -951,9 +951,14 @@ mime_create (const char *content_type, MimeHeaders *hdrs,
(clazz != (MimeObjectClass *)&mimeInlineTextRichtextClass) &&
(clazz != (MimeObjectClass *)&mimeInlineTextEnrichedClass) &&
(clazz != (MimeObjectClass *)&mimeMessageClass) &&
- (clazz != (MimeObjectClass *)&mimeInlineImageClass) )
+ (clazz != (MimeObjectClass *)&mimeInlineImageClass) ) {
// not a special inline type, so show as attachment
- clazz = (MimeObjectClass *)&mimeExternalObjectClass;
+ // However, mimeSuppressedCryptoClass is treated identically as
+ // mimeExternalObjectClass, let's not lose that type information.
+ if (clazz != (MimeObjectClass *)&mimeSuppressedCryptoClass) {
+ clazz = (MimeObjectClass *)&mimeExternalObjectClass;
+ }
+ }
}
/* If the option `Show Attachments Inline' is off, now would be the time to change our mind... */
@@ -1221,21 +1226,6 @@ mime_crypto_object_p(MimeHeaders *hdrs, bool clearsigned_counts, MimeDisplayOpti
return false;
}
-/* Whether the given object has written out the HTML version of its headers
- in such a way that it will have a "crypto stamp" next to the headers. If
- this is true, then the child must write out its HTML slightly differently
- to take this into account...
- */
-bool
-mime_crypto_stamped_p(MimeObject *obj)
-{
- if (!obj) return false;
- if (mime_typep (obj, (MimeObjectClass *) &mimeMessageClass))
- return ((MimeMessage *) obj)->crypto_stamped_p;
- else
- return false;
-}
-
#endif // ENABLE_SMIME
/* Puts a part-number into a URL. If append_p is true, then the part number
diff --git a/mailnews/mime/src/mimei.h b/mailnews/mime/src/mimei.h
index a2d8332cdf..a024c45237 100644
--- a/mailnews/mime/src/mimei.h
+++ b/mailnews/mime/src/mimei.h
@@ -332,14 +332,6 @@ extern void mime_get_crypto_state (MimeObject *obj,
bool *signed_p, bool *encrypted_p,
bool *signed_ok, bool *encrypted_ok);
-
-/* Whether the given object has written out the HTML version of its headers
- in such a way that it will have a "crypto stamp" next to the headers. If
- this is true, then the child must write out its HTML slightly differently
- to take this into account...
- */
-extern bool mime_crypto_stamped_p(MimeObject *obj);
-
/* How the crypto code tells the MimeMessage object what the crypto stamp
on it says. */
extern void mime_set_crypto_stamp(MimeObject *obj,
@@ -352,7 +344,7 @@ public:
MimeParseStateObject()
{root = 0; separator_queued_p = false; separator_suppressed_p = false;
first_part_written_p = false; post_header_html_run_p = false; first_data_written_p = false;
- decrypted_p = false; strippingPart = false;
+ strippingPart = false;
}
MimeObject *root; /* The outermost parser object. */
@@ -376,10 +368,6 @@ public:
bool first_data_written_p; /* State used for Mozilla lazy-stream-
creation evilness. */
- bool decrypted_p; /* If options->dexlate_p is true, then this
- will be set to indicate whether any
- dexlateion did in fact occur.
- */
nsTArray<nsCString> partsToStrip; /* if we're stripping parts, what parts to strip */
nsTArray<nsCString> detachToFiles; /* if we're detaching parts, where each part was detached to */
bool strippingPart;
diff --git a/mailnews/mime/src/mimemcms.cpp b/mailnews/mime/src/mimemcms.cpp
index 1a281b1620..96aa5481f2 100644
--- a/mailnews/mime/src/mimemcms.cpp
+++ b/mailnews/mime/src/mimemcms.cpp
@@ -38,6 +38,7 @@ static int MimeMultCMS_sig_eof (void *, bool);
static int MimeMultCMS_sig_init (void *, MimeObject *, MimeHeaders *);
static char * MimeMultCMS_generate (void *);
static void MimeMultCMS_free (void *);
+static void MimeMultCMS_suppressed_child(void *crypto_closure);
extern int SEC_ERROR_CERT_ADDR_MISMATCH;
@@ -56,6 +57,7 @@ MimeMultipartSignedCMSClassInitialize(MimeMultipartSignedCMSClass *clazz)
sclass->crypto_signature_hash = MimeMultCMS_sig_hash;
sclass->crypto_signature_eof = MimeMultCMS_sig_eof;
sclass->crypto_generate_html = MimeMultCMS_generate;
+ sclass->crypto_notify_suppressed_child = MimeMultCMS_suppressed_child;
sclass->crypto_free = MimeMultCMS_free;
PR_ASSERT(!oclass->class_initialized);
@@ -80,8 +82,6 @@ typedef struct MimeMultCMSdata
unsigned char* item_data;
uint32_t item_len;
MimeObject *self;
- bool parent_is_encrypted_p;
- bool parent_holds_stamp_p;
nsCOMPtr<nsIMsgSMIMEHeaderSink> smimeHeaderSink;
nsCString url;
@@ -90,11 +90,7 @@ typedef struct MimeMultCMSdata
sender_addr(nullptr),
decoding_failed(false),
item_data(nullptr),
- self(nullptr),
- parent_is_encrypted_p(false),
- parent_holds_stamp_p(false)
- {
- }
+ self(nullptr) {}
~MimeMultCMSdata()
{
@@ -113,7 +109,7 @@ typedef struct MimeMultCMSdata
/* #### MimeEncryptedCMS and MimeMultipartSignedCMS have a sleazy,
incestuous, dysfunctional relationship. */
-extern bool MimeEncryptedCMS_encrypted_p (MimeObject *obj);
+extern bool MimeAnyParentCMSSigned(MimeObject *obj);
extern void MimeCMSGetFromSender(MimeObject *obj,
nsCString &from_addr,
nsCString &from_name,
@@ -142,82 +138,11 @@ MimeMultCMS_init (MimeObject *obj)
int16_t hash_type;
nsresult rv;
- ct = MimeHeaders_get (hdrs, HEADER_CONTENT_TYPE, false, false);
- if (!ct) return 0; /* #### bogus message? out of memory? */
- micalg = MimeHeaders_get_parameter (ct, PARAM_MICALG, NULL, NULL);
- PR_Free(ct);
- ct = 0;
- if (!micalg) return 0; /* #### bogus message? out of memory? */
-
- if (!PL_strcasecmp(micalg, PARAM_MICALG_MD5) ||
- !PL_strcasecmp(micalg, PARAM_MICALG_MD5_2))
- hash_type = nsICryptoHash::MD5;
- else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA1) ||
- !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_2) ||
- !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_3) ||
- !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_4) ||
- !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_5))
- hash_type = nsICryptoHash::SHA1;
- else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA256) ||
- !PL_strcasecmp(micalg, PARAM_MICALG_SHA256_2) ||
- !PL_strcasecmp(micalg, PARAM_MICALG_SHA256_3))
- hash_type = nsICryptoHash::SHA256;
- else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA384) ||
- !PL_strcasecmp(micalg, PARAM_MICALG_SHA384_2) ||
- !PL_strcasecmp(micalg, PARAM_MICALG_SHA384_3))
- hash_type = nsICryptoHash::SHA384;
- else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA512) ||
- !PL_strcasecmp(micalg, PARAM_MICALG_SHA512_2) ||
- !PL_strcasecmp(micalg, PARAM_MICALG_SHA512_3))
- hash_type = nsICryptoHash::SHA512;
- else if (!PL_strcasecmp(micalg, PARAM_MICALG_MD2))
- hash_type = nsICryptoHash::MD2;
- else
- hash_type = -1;
-
- PR_Free(micalg);
- micalg = 0;
-
- if (hash_type == -1) return 0; /* #### bogus message? */
-
data = new MimeMultCMSdata;
if (!data)
return 0;
data->self = obj;
- data->hash_type = hash_type;
-
- data->data_hash_context = do_CreateInstance("@mozilla.org/security/hash;1", &rv);
- if (NS_FAILED(rv))
- {
- delete data;
- return 0;
- }
-
- rv = data->data_hash_context->Init(data->hash_type);
- if (NS_FAILED(rv))
- {
- delete data;
- return 0;
- }
-
- PR_SetError(0,0);
-
- data->parent_holds_stamp_p =
- (obj->parent && mime_crypto_stamped_p(obj->parent));
-
- data->parent_is_encrypted_p =
- (obj->parent && MimeEncryptedCMS_encrypted_p (obj->parent));
-
- /* 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 s##t s$%#s.)
- */
- 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);
mime_stream_data *msd = (mime_stream_data *) (data->self->options->stream_closure);
if (msd)
@@ -266,6 +191,89 @@ MimeMultCMS_init (MimeObject *obj)
} // if channel
} // if msd
+ if (obj->parent && MimeAnyParentCMSSigned(obj)) {
+ // Parent is signed. We know this part is a signature, too, because
+ // multipart doesn't allow encryption.
+ // We don't support "inner sign" 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).
+ // Also we don't want to support sign-then-sign, that's misleading,
+ // which part would be shown as having a signature?
+ // TODO: should we show all contents, without any signature info?
+
+ if (data->smimeHeaderSink) {
+ data->smimeHeaderSink->SignedStatus(
+ MIMEGetRelativeCryptoNestLevel(data->self),
+ nsICMSMessageErrors::GENERAL_ERROR, nullptr, data->url);
+ }
+ delete data;
+ PR_SetError(-1, 0);
+ return 0;
+ }
+
+ ct = MimeHeaders_get(hdrs, HEADER_CONTENT_TYPE, false, false);
+ if (!ct) {
+ delete data;
+ return 0; /* #### bogus message? out of memory? */
+ }
+ micalg = MimeHeaders_get_parameter(ct, PARAM_MICALG, NULL, NULL);
+ PR_Free(ct);
+ ct = 0;
+ if (!micalg) {
+ delete data;
+ return 0; /* #### bogus message? out of memory? */
+ }
+
+ if (!PL_strcasecmp(micalg, PARAM_MICALG_MD5) ||
+ !PL_strcasecmp(micalg, PARAM_MICALG_MD5_2))
+ hash_type = nsICryptoHash::MD5;
+ else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA1) ||
+ !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_2) ||
+ !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_3) ||
+ !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_4) ||
+ !PL_strcasecmp(micalg, PARAM_MICALG_SHA1_5))
+ hash_type = nsICryptoHash::SHA1;
+ else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA256) ||
+ !PL_strcasecmp(micalg, PARAM_MICALG_SHA256_2) ||
+ !PL_strcasecmp(micalg, PARAM_MICALG_SHA256_3))
+ hash_type = nsICryptoHash::SHA256;
+ else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA384) ||
+ !PL_strcasecmp(micalg, PARAM_MICALG_SHA384_2) ||
+ !PL_strcasecmp(micalg, PARAM_MICALG_SHA384_3))
+ hash_type = nsICryptoHash::SHA384;
+ else if (!PL_strcasecmp(micalg, PARAM_MICALG_SHA512) ||
+ !PL_strcasecmp(micalg, PARAM_MICALG_SHA512_2) ||
+ !PL_strcasecmp(micalg, PARAM_MICALG_SHA512_3))
+ hash_type = nsICryptoHash::SHA512;
+ else
+ hash_type = -1;
+
+ PR_Free(micalg);
+ micalg = 0;
+
+ if (hash_type == -1) {
+ delete data;
+ return 0; /* #### bogus message? */
+ }
+
+ data->hash_type = hash_type;
+
+ data->data_hash_context =
+ do_CreateInstance("@mozilla.org/security/hash;1", &rv);
+ if (NS_FAILED(rv)) {
+ delete data;
+ return 0;
+ }
+
+ rv = data->data_hash_context->Init(data->hash_type);
+ if (NS_FAILED(rv)) {
+ delete data;
+ return 0;
+ }
+
+ PR_SetError(0, 0);
+
return data;
}
@@ -400,6 +408,17 @@ MimeMultCMS_free (void *crypto_closure)
delete data;
}
+static void MimeMultCMS_suppressed_child(void *crypto_closure) {
+ // I'm a multipart/signed. If one of my cryptographic child elements
+ // was suppressed, then I want my signature to be shown as invalid.
+ MimeMultCMSdata *data = (MimeMultCMSdata *)crypto_closure;
+ if (data && data->smimeHeaderSink) {
+ data->smimeHeaderSink->SignedStatus(
+ MIMEGetRelativeCryptoNestLevel(data->self),
+ nsICMSMessageErrors::GENERAL_ERROR, nullptr, data->url);
+ }
+}
+
static char *
MimeMultCMS_generate (void *crypto_closure)
{
diff --git a/mailnews/mime/src/mimemsg.cpp b/mailnews/mime/src/mimemsg.cpp
index 2d69570690..d024a77258 100644
--- a/mailnews/mime/src/mimemsg.cpp
+++ b/mailnews/mime/src/mimemsg.cpp
@@ -786,34 +786,22 @@ MimeMessage_write_headers_html (MimeObject *obj)
return status;
}
- if (!msg->crypto_stamped_p)
- {
- /* If we're not writing a xlation stamp, and this is the outermost
- message, then now is the time to run the post_header_html_fn.
- (Otherwise, it will be run when the xlation-stamp is finally
- closed off, in MimeXlateed_emit_buffered_child() or
- MimeMultipartSigned_emit_child().)
- */
- if (obj->options &&
- obj->options->state &&
+ // If this is the outermost message, then now is the time to run the
+ // post_header_html_fn.
+ if (obj->options && obj->options->state &&
obj->options->generate_post_header_html_fn &&
- !obj->options->state->post_header_html_run_p)
- {
- char *html = 0;
- PR_ASSERT(obj->options->state->first_data_written_p);
- html = obj->options->generate_post_header_html_fn(NULL,
- obj->options->html_closure,
- msg->hdrs);
- obj->options->state->post_header_html_run_p = true;
- if (html)
- {
- status = MimeObject_write(obj, html, strlen(html), false);
- PR_Free(html);
- if (status < 0)
- {
- mimeEmitterEndHeader(obj->options, obj);
- return status;
- }
+ !obj->options->state->post_header_html_run_p) {
+ char *html = 0;
+ PR_ASSERT(obj->options->state->first_data_written_p);
+ html = obj->options->generate_post_header_html_fn(
+ NULL, obj->options->html_closure, msg->hdrs);
+ obj->options->state->post_header_html_run_p = true;
+ if (html) {
+ status = MimeObject_write(obj, html, strlen(html), false);
+ PR_Free(html);
+ if (status < 0) {
+ mimeEmitterEndHeader(obj->options, obj);
+ return status;
}
}
}
diff --git a/mailnews/mime/src/mimemsg.h b/mailnews/mime/src/mimemsg.h
index c4023ccf09..9a38a6e719 100644
--- a/mailnews/mime/src/mimemsg.h
+++ b/mailnews/mime/src/mimemsg.h
@@ -25,12 +25,6 @@ struct MimeMessage {
MimeContainer container; /* superclass variables */
MimeHeaders *hdrs; /* headers of this message */
bool newline_p; /* whether the last line ended in a newline */
- bool crypto_stamped_p; /* whether the header of this message has been
- emitted expecting its child to emit HTML
- which says that it is xlated. */
-
- bool crypto_msg_signed_p; /* What the emitted xlation-stamp *says*. */
- bool crypto_msg_encrypted_p;
bool grabSubject; /* Should we try to grab the subject of this message */
int32_t bodyLength; /* Used for determining if the body has been truncated */
int32_t sizeSoFar; /* The total size of the MIME message, once parsing is
diff --git a/mailnews/mime/src/mimemsig.cpp b/mailnews/mime/src/mimemsig.cpp
index d74cfb09ae..bb34607cba 100644
--- a/mailnews/mime/src/mimemsig.cpp
+++ b/mailnews/mime/src/mimemsig.cpp
@@ -14,6 +14,7 @@
#include "msgCore.h"
#include "nsMimeStringResources.h"
#include "mimemoz2.h"
+#include "mimeeobj.h"
#include "nsIMimeConverter.h" // for MimeConverterOutputCallback
#include "mozilla/Attributes.h"
@@ -32,6 +33,8 @@ static void MimeMultipartSigned_finalize (MimeObject *);
static int MimeMultipartSigned_emit_child (MimeObject *obj);
+extern "C" MimeSuppressedCryptoClass mimeSuppressedCryptoClass;
+
static int
MimeMultipartSignedClassInitialize(MimeMultipartSignedClass *clazz)
{
@@ -582,6 +585,11 @@ MimeMultipartSigned_emit_child (MimeObject *obj)
int status = 0;
MimeObject *body;
+ if (!sig->crypto_closure) {
+ // We might have decided to skip processing this part.
+ return 0;
+ }
+
NS_ASSERTION(sig->crypto_closure, "no crypto closure");
/* Emit some HTML saying whether the signature was cool.
@@ -594,15 +602,11 @@ MimeMultipartSigned_emit_child (MimeObject *obj)
obj->options->headers != MimeHeadersCitation &&
sig->crypto_closure)
{
+ // Calling crypto_generate_html may trigger wanted side effects,
+ // but we're no longer using its results.
char *html = (((MimeMultipartSignedClass *) obj->clazz)
->crypto_generate_html (sig->crypto_closure));
-#if 0 // XXX For the moment, no HTML output. Fix this XXX //
- if (!html) return -1; /* MIME_OUT_OF_MEMORY? */
-
- status = MimeObject_write(obj, html, strlen(html), false);
- PR_Free(html);
- if (status < 0) return status;
-#endif
+ PR_FREEIF(html);
/* Now that we have written out the crypto stamp, the outermost header
block is well and truly closed. If this is in fact the outermost
@@ -719,6 +723,11 @@ MimeMultipartSigned_emit_child (MimeObject *obj)
if (!body)
return -1;
+ if (mime_typep(body, (MimeObjectClass *)&mimeSuppressedCryptoClass)) {
+ ((MimeMultipartSignedClass *)obj->clazz)
+ ->crypto_notify_suppressed_child(sig->crypto_closure);
+ }
+
#ifdef MIME_DRAFTS
if (body->options->decompose_file_p) {
body->options->signed_p = true;
diff --git a/mailnews/mime/src/mimemsig.h b/mailnews/mime/src/mimemsig.h
index f8581c3a36..2ec9d314d0 100644
--- a/mailnews/mime/src/mimemsig.h
+++ b/mailnews/mime/src/mimemsig.h
@@ -105,6 +105,8 @@ struct MimeMultipartSignedClass {
char * (*crypto_generate_html) (void *crypto_closure);
+ void (*crypto_notify_suppressed_child)(void *crypto_closure);
+
void (*crypto_free) (void *crypto_closure);
};
diff --git a/mailnews/mime/src/mimemult.cpp b/mailnews/mime/src/mimemult.cpp
index 64f292ec0c..4695ba9910 100644
--- a/mailnews/mime/src/mimemult.cpp
+++ b/mailnews/mime/src/mimemult.cpp
@@ -43,6 +43,7 @@ extern "C" MimeObjectClass mimeMultipartRelatedClass;
extern "C" MimeObjectClass mimeMultipartSignedClass;
extern "C" MimeObjectClass mimeInlineTextVCardClass;
extern "C" MimeExternalObjectClass mimeExternalObjectClass;
+extern "C" MimeSuppressedCryptoClass mimeSuppressedCryptoClass;
#if defined(DEBUG) && defined(XP_UNIX)
static int MimeMultipart_debug_print (MimeObject *, PRFileDesc *, int32_t);
@@ -471,7 +472,9 @@ MimeMultipart_create_child(MimeObject *obj)
part functions set correctly */
!mime_typep(body, (MimeObjectClass*) &mimeMultipartClass)
#endif
- && ! (mime_typep(body, (MimeObjectClass*)&mimeExternalObjectClass) && !strcmp(body->content_type, "text/x-vcard"))
+ && !((mime_typep(body, (MimeObjectClass *)&mimeExternalObjectClass) ||
+ mime_typep(body, (MimeObjectClass *)&mimeSuppressedCryptoClass)) &&
+ !strcmp(body->content_type, "text/x-vcard"))
)
{
status = obj->options->decompose_file_init_fn ( obj->options->stream_closure, mult->hdrs );
@@ -575,7 +578,9 @@ MimeMultipart_close_child(MimeObject *object)
part functions set correctly */
!mime_typep(kid,(MimeObjectClass*) &mimeMultipartClass)
#endif
- && !(mime_typep(kid, (MimeObjectClass*)&mimeExternalObjectClass) && !strcmp(kid->content_type, "text/x-vcard"))
+ && !((mime_typep(kid, (MimeObjectClass *)&mimeExternalObjectClass) ||
+ mime_typep(kid, (MimeObjectClass *)&mimeSuppressedCryptoClass)) &&
+ !strcmp(kid->content_type, "text/x-vcard"))
)
{
status = object->options->decompose_file_close_fn ( object->options->stream_closure );