From 73e14fb7049306439a5637ff261f1370a94518e5 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Mon, 11 Nov 2019 01:56:34 -0500 Subject: Bug 1240290 Tag #1273 --- mailnews/compose/src/nsMsgAttachmentHandler.cpp | 1 - mailnews/compose/src/nsMsgAttachmentHandler.h | 10 -- mailnews/mime/src/mimecms.cpp | 148 ++++++++++++++------ mailnews/mime/src/mimecryp.cpp | 13 +- mailnews/mime/src/mimeeobj.cpp | 10 ++ mailnews/mime/src/mimeeobj.h | 16 +++ mailnews/mime/src/mimei.cpp | 26 ++-- mailnews/mime/src/mimei.h | 14 +- mailnews/mime/src/mimemcms.cpp | 177 +++++++++++++----------- mailnews/mime/src/mimemsg.cpp | 42 ++---- mailnews/mime/src/mimemsg.h | 6 - mailnews/mime/src/mimemsig.cpp | 23 ++- mailnews/mime/src/mimemsig.h | 2 + mailnews/mime/src/mimemult.cpp | 9 +- 14 files changed, 282 insertions(+), 215 deletions(-) (limited to 'mailnews') diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.cpp b/mailnews/compose/src/nsMsgAttachmentHandler.cpp index 9555de37f..4994c3fe6 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 79e526627..2034cba03 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 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 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 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 9f6e3630f..fd4f8f8ae 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 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 da59a9d62..7d8b2f8a6 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 2b8ade5d5..076f8f9bf 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 c0a134a62..015830a80 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 a2d8332cd..a024c4523 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 partsToStrip; /* if we're stripping parts, what parts to strip */ nsTArray 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 1a281b162..96aa5481f 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 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 2d6957069..d024a7725 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 c4023ccf0..9a38a6e71 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 d74cfb09a..bb34607cb 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 f8581c3a3..2ec9d314d 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 64f292ec0..4695ba991 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 ); -- cgit v1.2.3