From c23d791bbbb1e9192bca8fd133f537d3fe45ef44 Mon Sep 17 00:00:00 2001 From: "kaie%kuix.de" Date: Tue, 4 Apr 2006 13:15:49 +0000 Subject: [PATCH] bug 329990, Unwind S/Mime signature verification from UI thread bug 332212, Incorrect calls to update chrome UI with sign/encrypt status r/sr=mscott second checkin attempt --- mailnews/mime/src/mimecms.cpp | 492 +++++++++++++-------------------- mailnews/mime/src/mimecms.h | 8 - mailnews/mime/src/mimei.cpp | 195 ------------- mailnews/mime/src/mimei.h | 14 - mailnews/mime/src/mimemcms.cpp | 227 +++++---------- mailnews/mime/src/mimemcms.h | 8 - 6 files changed, 256 insertions(+), 688 deletions(-) diff --git a/mailnews/mime/src/mimecms.cpp b/mailnews/mime/src/mimecms.cpp index 5ba5dad8ffb..97a6a1ff1bd 100644 --- a/mailnews/mime/src/mimecms.cpp +++ b/mailnews/mime/src/mimecms.cpp @@ -20,6 +20,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Kai Engert * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -36,6 +37,7 @@ * ***** END LICENSE BLOCK ***** */ #include "nsICMSMessage.h" +#include "nsICMSMessage2.h" #include "nsICMSMessageErrors.h" #include "nsICMSDecoder.h" #include "mimecms.h" @@ -53,6 +55,7 @@ #include "nsCOMPtr.h" #include "nsIX509Cert.h" #include "nsIMsgHeaderParser.h" +#include "nsIProxyObjectManager.h" #define MIME_SUPERCLASS mimeEncryptedClass @@ -64,7 +67,6 @@ static int MimeCMS_write (const char *, PRInt32, void *); static int MimeCMS_eof (void *, PRBool); static char * MimeCMS_generate (void *); static void MimeCMS_free (void *); -static void MimeCMS_get_content_info (MimeObject *, nsICMSMessage **, char **, PRInt32 *, PRInt32 *, PRBool *); extern int SEC_ERROR_CERT_ADDR_MISMATCH; @@ -82,8 +84,6 @@ static int MimeEncryptedCMSClassInitialize(MimeEncryptedCMSClass *clazz) eclass->crypto_generate_html = MimeCMS_generate; eclass->crypto_free = MimeCMS_free; - clazz->get_content_info = MimeCMS_get_content_info; - return 0; } @@ -96,8 +96,7 @@ typedef struct MimeCMSdata nsCOMPtr content_info; PRBool ci_is_encrypted; char *sender_addr; - PRInt32 decode_error; - PRInt32 verify_error; + PRBool decoding_failed; MimeObject *self; PRBool parent_is_encrypted_p; PRBool parent_holds_stamp_p; @@ -108,8 +107,7 @@ typedef struct MimeCMSdata output_closure(nsnull), ci_is_encrypted(PR_FALSE), sender_addr(nsnull), - decode_error(PR_FALSE), - verify_error(PR_FALSE), + decoding_failed(PR_FALSE), self(nsnull), parent_is_encrypted_p(PR_FALSE), parent_holds_stamp_p(PR_FALSE) @@ -130,30 +128,6 @@ typedef struct MimeCMSdata } } MimeCMSdata; - -static void MimeCMS_get_content_info(MimeObject *obj, - nsICMSMessage **content_info_ret, - char **sender_email_addr_return, - PRInt32 *decode_error_ret, - PRInt32 *verify_error_ret, - PRBool *ci_is_encrypted) -{ - MimeEncrypted *enc = (MimeEncrypted *) obj; - if (enc && enc->crypto_closure) - { - MimeCMSdata *data = (MimeCMSdata *) enc->crypto_closure; - - *decode_error_ret = data->decode_error; - *verify_error_ret = data->verify_error; - *content_info_ret = data->content_info; - *ci_is_encrypted = data->ci_is_encrypted; - - if (sender_email_addr_return) - *sender_email_addr_return = (data->sender_addr ? nsCRT::strdup(data->sender_addr) : 0); - } -} - - /* SEC_PKCS7DecoderContentCallback for SEC_PKCS7DecoderStart() */ static void MimeCMS_content_callback (void *arg, const char *buf, unsigned long length) { @@ -204,19 +178,14 @@ static void ParseRFC822Addresses (const char *line, nsXPIDLCString &names, nsXPI } } -extern char *IMAP_CreateReloadAllPartsUrl(const char *url); - - -PRBool MimeCMSHeadersAndCertsMatch(MimeObject *obj, - nsICMSMessage *content_info, - PRBool *signing_cert_without_email_address, - char **sender_email_addr_return) +PRBool MimeCMSHeadersAndCertsMatch(nsICMSMessage *content_info, + nsIX509Cert *signerCert, + const char *from_addr, + const char *from_name, + const char *sender_addr, + const char *sender_name, + PRBool *signing_cert_without_email_address) { - MimeHeaders *msg_headers = 0; - nsXPIDLCString from_addr; - nsXPIDLCString from_name; - nsXPIDLCString sender_addr; - nsXPIDLCString sender_name; nsXPIDLCString cert_addr; PRBool match = PR_TRUE; PRBool foundFrom = PR_FALSE; @@ -236,52 +205,6 @@ PRBool MimeCMSHeadersAndCertsMatch(MimeObject *obj, *signing_cert_without_email_address = (!cert_addr); } - if (!cert_addr) { - // no address, no match - return PR_FALSE; - } - - /* Find the headers of the MimeMessage which is the parent (or grandparent) - of this object (remember, crypto objects nest.) */ - { - MimeObject *o2 = obj; - msg_headers = o2->headers; - while (o2 && - o2->parent && - !mime_typep(o2->parent, (MimeObjectClass *) &mimeMessageClass)) - { - o2 = o2->parent; - msg_headers = o2->headers; - } - } - - if (!msg_headers) { - // no headers, no match - return PR_FALSE; - } - - /* Find the names and addresses in the From and/or Sender fields. - */ - { - char *s; - - /* Extract the name and address of the "From:" field. */ - s = MimeHeaders_get(msg_headers, HEADER_FROM, PR_FALSE, PR_FALSE); - if (s) - { - ParseRFC822Addresses(s, from_name, from_addr); - PR_FREEIF(s); - } - - /* Extract the name and address of the "Sender:" field. */ - s = MimeHeaders_get(msg_headers, HEADER_SENDER, PR_FALSE, PR_FALSE); - if (s) - { - ParseRFC822Addresses(s, sender_name, sender_addr); - PR_FREEIF(s); - } - } - /* Now compare them -- consider it a match if the address in the cert matches either the address in the From or Sender field @@ -294,9 +217,6 @@ PRBool MimeCMSHeadersAndCertsMatch(MimeObject *obj, } else { - nsCOMPtr signerCert; - content_info->GetSignerCert(getter_AddRefs(signerCert)); - if (signerCert) { if (from_addr && *from_addr) @@ -324,20 +244,100 @@ PRBool MimeCMSHeadersAndCertsMatch(MimeObject *obj, } } - if (sender_email_addr_return) { - if (match && foundFrom) - *sender_email_addr_return = nsCRT::strdup(from_addr); - if (match && foundSender) - *sender_email_addr_return = nsCRT::strdup(sender_addr); - else if (from_addr && *from_addr) - *sender_email_addr_return = nsCRT::strdup(from_addr); - else if (sender_addr && *sender_addr) - *sender_email_addr_return = nsCRT::strdup(sender_addr); - else - *sender_email_addr_return = 0; + return match; +} + +class nsSMimeVerificationListener : public nsISMimeVerificationListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISMIMEVERIFICATIONLISTENER + + nsSMimeVerificationListener(const char *aFromAddr, const char *aFromName, + const char *aSenderAddr, const char *aSenderName, + nsIMsgSMIMEHeaderSink *aHeaderSink, PRInt32 aMimeNestingLevel); + + virtual ~nsSMimeVerificationListener() {} + +protected: + nsCOMPtr mHeaderSink; + PRInt32 mMimeNestingLevel; + + nsXPIDLCString mFromAddr; + nsXPIDLCString mFromName; + nsXPIDLCString mSenderAddr; + nsXPIDLCString mSenderName; +}; + +NS_IMPL_ISUPPORTS1(nsSMimeVerificationListener, nsISMimeVerificationListener) + +nsSMimeVerificationListener::nsSMimeVerificationListener(const char *aFromAddr, const char *aFromName, + const char *aSenderAddr, const char *aSenderName, + nsIMsgSMIMEHeaderSink *aHeaderSink, PRInt32 aMimeNestingLevel) +{ + mHeaderSink = aHeaderSink; + mMimeNestingLevel = aMimeNestingLevel; + + mFromAddr = aFromAddr; + mFromName = aFromName; + mSenderAddr = aSenderAddr; + mSenderName = aSenderName; +} + +NS_IMETHODIMP nsSMimeVerificationListener::Notify(nsICMSMessage2 *aVerifiedMessage, + nsresult aVerificationResultCode) +{ + // Only continue if we have a valid pointer to the UI + NS_ENSURE_TRUE(mHeaderSink, NS_OK); + + NS_ENSURE_TRUE(aVerifiedMessage, NS_ERROR_FAILURE); + + nsCOMPtr msg = do_QueryInterface(aVerifiedMessage); + NS_ENSURE_TRUE(msg, NS_ERROR_FAILURE); + + nsCOMPtr signerCert; + msg->GetSignerCert(getter_AddRefs(signerCert)); + + PRInt32 signature_status = nsICMSMessageErrors::GENERAL_ERROR; + + if (NS_FAILED(aVerificationResultCode)) + { + if (NS_ERROR_MODULE_SECURITY == NS_ERROR_GET_MODULE(aVerificationResultCode)) + signature_status = NS_ERROR_GET_CODE(aVerificationResultCode); + else if (NS_ERROR_NOT_IMPLEMENTED == aVerificationResultCode) + signature_status = nsICMSMessageErrors::VERIFY_ERROR_PROCESSING; + } + else + { + PRBool signing_cert_without_email_address; + + PRBool good_p = MimeCMSHeadersAndCertsMatch(msg, signerCert, + mFromAddr.get(), mFromName.get(), + mSenderAddr.get(), mSenderName.get(), + &signing_cert_without_email_address); + if (!good_p) + { + if (signing_cert_without_email_address) + signature_status = nsICMSMessageErrors::VERIFY_CERT_WITHOUT_ADDRESS; + else + signature_status = nsICMSMessageErrors::VERIFY_HEADER_MISMATCH; + } + else + signature_status = nsICMSMessageErrors::SUCCESS; } - return match; + + nsCOMPtr proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID)); + if (proxyman) + { + nsCOMPtr proxySink; + proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIMsgSMIMEHeaderSink), + mHeaderSink, PROXY_SYNC, getter_AddRefs(proxySink)); + if (proxySink) + proxySink->SignedStatus(mMimeNestingLevel, signature_status, signerCert); + } + + return NS_OK; } int MIMEGetRelativeCryptoNestLevel(MimeObject *obj) @@ -371,7 +371,10 @@ int MIMEGetRelativeCryptoNestLevel(MimeObject *obj) aTopShownObject = walker; } if (!aAlreadyFoundTop && !walker->parent) { - aTopShownObject = walker; + // The mime part part_to_load is not a parent of the + // the crypto mime part passed in to this function as parameter obj. + // That means the crypto part belongs to another branch of the mime tree. + return -1; } } } @@ -509,18 +512,83 @@ MimeCMS_write (const char *buf, PRInt32 buf_size, void *closure) PR_SetError(0, 0); rv = data->decoder_context->Update(buf, buf_size); - if (NS_FAILED(rv)) { - data->verify_error = -1; - } + data->decoding_failed = NS_FAILED(rv); return 0; } +void MimeCMSGetFromSender(MimeObject *obj, + nsXPIDLCString &from_addr, + nsXPIDLCString &from_name, + nsXPIDLCString &sender_addr, + nsXPIDLCString &sender_name) +{ + MimeHeaders *msg_headers = 0; + + /* Find the headers of the MimeMessage which is the parent (or grandparent) + of this object (remember, crypto objects nest.) */ + MimeObject *o2 = obj; + msg_headers = o2->headers; + while (o2 && + o2->parent && + !mime_typep(o2->parent, (MimeObjectClass *) &mimeMessageClass)) + { + o2 = o2->parent; + msg_headers = o2->headers; + } + + if (!msg_headers) + return; + + /* Find the names and addresses in the From and/or Sender fields. + */ + char *s; + + /* Extract the name and address of the "From:" field. */ + s = MimeHeaders_get(msg_headers, HEADER_FROM, PR_FALSE, PR_FALSE); + if (s) + { + ParseRFC822Addresses(s, from_name, from_addr); + PR_FREEIF(s); + } + + /* Extract the name and address of the "Sender:" field. */ + s = MimeHeaders_get(msg_headers, HEADER_SENDER, PR_FALSE, PR_FALSE); + if (s) + { + ParseRFC822Addresses(s, sender_name, sender_addr); + PR_FREEIF(s); + } +} + +void MimeCMSRequestAsyncSignatureVerification(nsICMSMessage *aCMSMsg, + const char *aFromAddr, const char *aFromName, + const char *aSenderAddr, const char *aSenderName, + nsIMsgSMIMEHeaderSink *aHeaderSink, PRInt32 aMimeNestingLevel, + unsigned char* item_data, PRUint32 item_len) +{ + nsCOMPtr msg2 = do_QueryInterface(aCMSMsg); + if (!msg2) + return; + + nsRefPtr listener = + new nsSMimeVerificationListener(aFromAddr, aFromName, aSenderAddr, aSenderName, + aHeaderSink, aMimeNestingLevel); + if (!listener) + return; + + if (item_data) + msg2->AsyncVerifyDetachedSignature(listener, item_data, item_len); + else + msg2->AsyncVerifySignature(listener); +} + static int MimeCMS_eof (void *crypto_closure, PRBool abort_p) { MimeCMSdata *data = (MimeCMSdata *) crypto_closure; nsresult rv; + PRInt32 status = nsICMSMessageErrors::SUCCESS; if (!data || !data->output_fn || !data->decoder_context) { return -1; @@ -538,9 +606,8 @@ MimeCMS_eof (void *crypto_closure, PRBool abort_p) PR_SetError(0, 0); rv = data->decoder_context->Finish(getter_AddRefs(data->content_info)); - if (NS_FAILED(rv)) - data->verify_error = PR_GetError(); + status = nsICMSMessageErrors::GENERAL_ERROR; data->decoder_context = 0; @@ -549,9 +616,8 @@ MimeCMS_eof (void *crypto_closure, PRBool abort_p) if (!data->smimeHeaderSink) return 0; - if (aRelativeNestLevel < 0) { + if (aRelativeNestLevel < 0) return 0; - } PRInt32 maxNestLevel = 0; data->smimeHeaderSink->MaxWantedNesting(&maxNestLevel); @@ -559,14 +625,8 @@ MimeCMS_eof (void *crypto_closure, PRBool abort_p) if (aRelativeNestLevel > maxNestLevel) return 0; - PRInt32 status = nsICMSMessageErrors::SUCCESS; - - if (data->verify_error - || data->decode_error - || NS_FAILED(rv)) - { + if (data->decoding_failed) status = nsICMSMessageErrors::GENERAL_ERROR; - } if (!data->content_info) { @@ -598,34 +658,20 @@ MimeCMS_eof (void *crypto_closure, PRBool abort_p) return 0; } - rv = data->content_info->VerifySignature(); + nsXPIDLCString from_addr; + nsXPIDLCString from_name; + nsXPIDLCString sender_addr; + nsXPIDLCString sender_name; - if (NS_FAILED(rv)) { - if (NS_ERROR_MODULE_SECURITY == NS_ERROR_GET_MODULE(rv)) { - status = NS_ERROR_GET_CODE(rv); - } - else if (NS_ERROR_NOT_IMPLEMENTED == rv) { - status = nsICMSMessageErrors::VERIFY_ERROR_PROCESSING; - } - } - else { - PRBool signing_cert_without_email_address; - if (MimeCMSHeadersAndCertsMatch(data->self, data->content_info, &signing_cert_without_email_address, &data->sender_addr)) - { - status = nsICMSMessageErrors::SUCCESS; - } - else - { - if (signing_cert_without_email_address) { - status = nsICMSMessageErrors::VERIFY_CERT_WITHOUT_ADDRESS; - } - else { - status = nsICMSMessageErrors::VERIFY_HEADER_MISMATCH; - } - } - } + MimeCMSGetFromSender(data->self, + from_addr, from_name, + sender_addr, sender_name); - data->content_info->GetSignerCert(getter_AddRefs(certOfInterest)); + MimeCMSRequestAsyncSignatureVerification(data->content_info, + from_addr, from_name, + sender_addr, sender_name, + data->smimeHeaderSink, aRelativeNestLevel, + nsnull, 0); } } @@ -637,14 +683,6 @@ MimeCMS_eof (void *crypto_closure, PRBool abort_p) certOfInterest ); } - else - { - data->smimeHeaderSink->SignedStatus( - aRelativeNestLevel, - status, - certOfInterest - ); - } return 0; } @@ -658,153 +696,9 @@ MimeCMS_free (void *crypto_closure) delete data; } -char * -MimeCMS_MakeSAURL(MimeObject *obj) -{ - char *stamp_url = 0; - - /* Skip over any crypto objects which lie between us and a message/rfc822. - But if we reach an object that isn't a crypto object or a message/rfc822 - then stop on the crypto object *before* it. That is, leave `obj' set to - either a crypto object, or a message/rfc822, but leave it set to the - innermost message/rfc822 above a consecutive run of crypto objects. - */ - while (1) - { - if (!obj->parent) - break; - else if (mime_typep (obj->parent, (MimeObjectClass *) &mimeMessageClass)) - { - obj = obj->parent; - break; - } -#if 0 // XXX Fix later XXX // - else if (!mime_typep (obj->parent, (MimeObjectClass *) &mimeEncryptedClass) && !mime_typep (obj->parent, - (MimeObjectClass *) &mimeMultipartSignedClass)) -#endif - else if (!mime_typep (obj->parent, (MimeObjectClass *) &mimeEncryptedClass)) - { - break; - } - obj = obj->parent; - NS_ASSERTION(obj, "1.2 01 Nov 2001 17:59"); - } - - - if (obj->options) - { - const char *base_url = obj->options->url; - char *id = (base_url ? mime_part_address (obj) : 0); - char *url = (id && base_url - ? mime_set_url_part(base_url, id, PR_TRUE) - : 0); - char *url2 = (url ? nsEscape(url, url_XAlphas) : 0); - PR_FREEIF(id); - PR_FREEIF(url); - - stamp_url = (char *) PR_MALLOC(strlen(url2) + 50); - if (stamp_url) - { - PL_strcpy(stamp_url, "about:security?advisor="); - PL_strcat(stamp_url, url2); - } - PR_FREEIF(url2); - } - return stamp_url; -} - static char * MimeCMS_generate (void *crypto_closure) { - MimeCMSdata *data = (MimeCMSdata *) crypto_closure; - PRBool self_signed_p = PR_FALSE; - PRBool self_encrypted_p = PR_FALSE; - PRBool union_encrypted_p = PR_FALSE; - PRBool good_p = PR_FALSE; - PRBool unverified_p = PR_FALSE; - - if (!data || !data->output_fn) return 0; - - if (data->content_info) - { - data->content_info->ContentIsSigned(&self_signed_p); - data->content_info->ContentIsEncrypted(&self_encrypted_p); - union_encrypted_p = (self_encrypted_p || data->parent_is_encrypted_p); - - if (self_signed_p) - { - PR_SetError(0, 0); - good_p = data->content_info->VerifySignature(); - if (!good_p) - { - if (!data->verify_error) - data->verify_error = PR_GetError(); - if (data->verify_error >= 0) - data->verify_error = -1; - } - else - { - PRBool signing_cert_without_email_address; - good_p = MimeCMSHeadersAndCertsMatch(data->self, data->content_info, &signing_cert_without_email_address, - &data->sender_addr); - if (!good_p && !data->verify_error) { - // data->verify_error = SEC_ERROR_CERT_ADDR_MISMATCH; XXX Fix later XXX // - data->verify_error = -1; - } - } - } - -#if 0 - if (SEC_PKCS7ContainsCertsOrCrls(data->content_info)) - { - /* #### call libsec telling it to import the certs */ - } -#endif - - /* Don't free these yet -- keep them around for the lifetime of the - MIME object, so that we can get at the security info of sub-parts - of the currently-displayed message. */ -#if 0 - SEC_PKCS7DestroyContentInfo(data->content_info); - data->content_info = 0; -#endif /* 0 */ - } - else - { - /* No content info? Something's horked. Guess. */ - self_encrypted_p = PR_TRUE; - union_encrypted_p = PR_TRUE; - if (!data->decode_error && !data->verify_error) - data->decode_error = -1; - } - - unverified_p = data->self->options->missing_parts; - - if (data->self && data->self->parent) { - mime_set_crypto_stamp(data->self->parent, self_signed_p, self_encrypted_p); - } - - { - char *stamp_url = 0, *result = nsnull; - if (data->self) - { - if (unverified_p && data->self->options) { - // stamp_url = IMAP_CreateReloadAllPartsUrl(data->self->options->url); XXX Fix later XXX // - stamp_url = nsnull; - } - else { - stamp_url = MimeCMS_MakeSAURL(data->self); - } - } - - result = - MimeHeaders_make_crypto_stamp (union_encrypted_p, - self_signed_p, - good_p, - unverified_p, - data->parent_holds_stamp_p, - stamp_url); - PR_FREEIF(stamp_url); - return result; - } + return nsnull; } + diff --git a/mailnews/mime/src/mimecms.h b/mailnews/mime/src/mimecms.h index ba4261810f5..1df36cb3de7 100644 --- a/mailnews/mime/src/mimecms.h +++ b/mailnews/mime/src/mimecms.h @@ -54,14 +54,6 @@ typedef struct MimeEncryptedCMS MimeEncryptedCMS; struct MimeEncryptedCMSClass { MimeEncryptedClass encrypted; - - /* Callback used to access the SEC_PKCS7ContentInfo of this object. */ - void (*get_content_info) (MimeObject *self, - nsICMSMessage **content_info_ret, - char **sender_email_addr_return, - PRInt32 *decode_error_ret, - PRInt32 *verify_error_ret, - PRBool * ci_is_encrypted); }; extern MimeEncryptedCMSClass mimeEncryptedCMSClass; diff --git a/mailnews/mime/src/mimei.cpp b/mailnews/mime/src/mimei.cpp index 0cb274f0536..fb779eee758 100644 --- a/mailnews/mime/src/mimei.cpp +++ b/mailnews/mime/src/mimei.cpp @@ -1160,201 +1160,6 @@ mime_crypto_stamped_p(MimeObject *obj) return PR_FALSE; } - -/* Tells whether the given MimeObject is a message which has been encrypted - or signed. (Helper for MIME_GetMessageCryptoState()). - */ -void -mime_get_crypto_state (MimeObject *obj, - PRBool *signed_ret, - PRBool *encrypted_ret, - PRBool *signed_ok_ret, - PRBool *encrypted_ok_ret) -{ - PRBool signed_p, encrypted_p; - - if (signed_ret) *signed_ret = PR_FALSE; - if (encrypted_ret) *encrypted_ret = PR_FALSE; - if (signed_ok_ret) *signed_ok_ret = PR_FALSE; - if (encrypted_ok_ret) *encrypted_ok_ret = PR_FALSE; - - NS_ASSERTION(obj, "1.1 19 Mar 1999 12:00"); - if (!obj) return; - - if (!mime_typep (obj, (MimeObjectClass *) &mimeMessageClass)) - return; - - signed_p = ((MimeMessage *) obj)->crypto_msg_signed_p; - encrypted_p = ((MimeMessage *) obj)->crypto_msg_encrypted_p; - - if (signed_ret) - *signed_ret = signed_p; - if (encrypted_ret) - *encrypted_ret = encrypted_p; - - if ((signed_p || encrypted_p) && - (signed_ok_ret || encrypted_ok_ret)) - { - nsICMSMessage *encrypted_ci = 0; - nsICMSMessage *signed_ci = 0; - PRInt32 decode_error = 0, verify_error = 0; - char *addr = mime_part_address(obj); - - mime_find_security_info_of_part(addr, obj, - &encrypted_ci, - &signed_ci, - 0, /* email_addr */ - &decode_error, &verify_error); - - if (encrypted_p && encrypted_ok_ret) - *encrypted_ok_ret = (encrypted_ci && decode_error >= 0); - - if (signed_p && signed_ok_ret) - *signed_ok_ret = (verify_error >= 0 && decode_error >= 0); - - PR_FREEIF(addr); - } -} - - -/* How the crypto code tells the MimeMessage object what the crypto stamp - on it says. */ -void -mime_set_crypto_stamp(MimeObject *obj, PRBool signed_p, PRBool encrypted_p) -{ - if (!obj) return; - if (mime_typep (obj, (MimeObjectClass *) &mimeMessageClass)) - { - MimeMessage *msg = (MimeMessage *) obj; - if (!msg->crypto_msg_signed_p) - msg->crypto_msg_signed_p = signed_p; - if (!msg->crypto_msg_encrypted_p) - msg->crypto_msg_encrypted_p = encrypted_p; - - /* If the `decrypt_p' option is on, record whether any decryption has - actually occurred. */ - if (encrypted_p && - obj->options && - obj->options->decrypt_p && - obj->options->state) - { - /* decrypt_p and write_html_p are incompatible. */ - NS_ASSERTION(!obj->options->write_html_p, "1.1 19 Mar 1999 12:00"); - obj->options->state->decrypted_p = PR_TRUE; - } - - return; /* continue up the tree? I think that's not a good idea. */ - } - - if (obj->parent) - mime_set_crypto_stamp(obj->parent, signed_p, encrypted_p); -} - -/* Given a part ID, looks through the MimeObject tree for a sub-part whose ID - number matches; if one is found, and if it represents a PKCS7-encrypted - object, returns information about the security status of that object. - - `part' is not a URL -- it's of the form "1.3.5" and is interpreted relative - to the `obj' argument. - - Returned values: - - void **pkcs7_content_info_return - this is the SEC_PKCS7ContentInfo* of the object. - - int32 *decode_error_return - this is the error code, if any, that the security library returned - while trying to parse the PKCS7 data (if this is negative, then it - probably means the message was corrupt in some way.) - - int32 *verify_error_return - this is the error code, if any, that the security library returned - while trying to decrypt or verify or otherwise validate the data - (if this is negative, it might mean the message was corrupt, or might - mean the signature didn't match, or the cert was expired, or...) - */ -void -mime_find_security_info_of_part(const char *part, MimeObject *obj, - nsICMSMessage **pkcs7_encrypted_content_info_return, - nsICMSMessage **pkcs7_signed_content_info_return, - char **sender_email_addr_return, - PRInt32 *decode_error_return, - PRInt32 *verify_error_return) -{ - obj = mime_address_to_part(part, obj); - - *pkcs7_encrypted_content_info_return = 0; - *pkcs7_signed_content_info_return = 0; - *decode_error_return = 0; - *verify_error_return = 0; - if (sender_email_addr_return) - *sender_email_addr_return = 0; - - if (!obj) - return; - - /* If someone asks for the security info of a message/rfc822 object, - instead give them the security info of its child (the body of the - message.) - */ - if (mime_typep (obj, (MimeObjectClass *) &mimeMessageClass)) - { - MimeContainer *cont = (MimeContainer *) obj; - if (cont->nchildren >= 1) - { - NS_ASSERTION(cont->nchildren == 1, "1.1 19 Mar 1999 12:00"); - obj = cont->children[0]; - } - } - - - while (obj && - (mime_typep(obj, (MimeObjectClass *) &mimeEncryptedCMSClass) || - mime_typep(obj, (MimeObjectClass *) &mimeMultipartSignedCMSClass))) - { - nsICMSMessage *ci = 0; - PRInt32 decode_error = 0, verify_error = 0; - PRBool ci_is_encrypted = PR_FALSE; - char *sender = 0; - - if (mime_typep(obj, (MimeObjectClass *) &mimeEncryptedCMSClass)) { - (((MimeEncryptedCMSClass *) (obj->clazz)) - ->get_content_info) (obj, &ci, &sender, &decode_error, &verify_error, &ci_is_encrypted); - } else if (mime_typep(obj, - (MimeObjectClass *) &mimeMultipartSignedCMSClass)) { - (((MimeMultipartSignedCMSClass *) (obj->clazz)) - ->get_content_info) (obj, &ci, &sender, &decode_error, &verify_error, &ci_is_encrypted); - } - - if (ci) { - if (ci_is_encrypted) { - *pkcs7_encrypted_content_info_return = ci; - } else { - *pkcs7_signed_content_info_return = ci; - } - } - - if (sender_email_addr_return) - *sender_email_addr_return = sender; - else - PR_FREEIF(sender); - - if (*decode_error_return >= 0) - *decode_error_return = decode_error; - - if (*verify_error_return >= 0) - *verify_error_return = verify_error; - - - NS_ASSERTION(mime_typep(obj, (MimeObjectClass *) &mimeContainerClass) && - ((MimeContainer *) obj)->nchildren <= 1, "1.1 19 Mar 1999 12:00"); - - obj = ((((MimeContainer *) obj)->nchildren > 0) - ? ((MimeContainer *) obj)->children[0] - : 0); - } -} - #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 17172035d18..f124e6c2924 100644 --- a/mailnews/mime/src/mimei.h +++ b/mailnews/mime/src/mimei.h @@ -342,20 +342,6 @@ extern char *mime_find_content_type_of_part(const char *part, MimeObject *obj); extern int mime_parse_url_options(const char *url, MimeDisplayOptions *); #ifdef ENABLE_SMIME -/* Given a part ID, looks through the MimeObject tree for a sub-part whose ID - number matches; if one is found, and if it represents a PKCS7-encrypted - object, returns information about the security status of that object. - - `part' is not a URL -- it's of the form "1.3.5" and is interpreted relative - to the `obj' argument. - */ -extern void mime_find_security_info_of_part(const char *part, MimeObject *obj, - nsICMSMessage **cms_encrypt_content_info_return, - nsICMSMessage **cms_sign_content_info_return, - char **sender_email_addr_return, - PRInt32 *decode_error_return, - PRInt32 *verify_error_return); - /* Asks whether the given object is one of the cryptographically signed or encrypted objects that we know about. (MimeMessageClass uses this diff --git a/mailnews/mime/src/mimemcms.cpp b/mailnews/mime/src/mimemcms.cpp index dfcf2159b62..d562fcc6399 100644 --- a/mailnews/mime/src/mimemcms.cpp +++ b/mailnews/mime/src/mimemcms.cpp @@ -20,6 +20,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Kai Engert * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -68,9 +69,6 @@ static int MimeMultCMS_sig_eof (void *, PRBool); static int MimeMultCMS_sig_init (void *, MimeObject *, MimeHeaders *); static char * MimeMultCMS_generate (void *); static void MimeMultCMS_free (void *); -static void MimeMultCMS_get_content_info (MimeObject *, - nsICMSMessage **, - char **, PRInt32 *, PRInt32 *, PRBool *); extern int SEC_ERROR_CERT_ADDR_MISMATCH; @@ -91,8 +89,6 @@ MimeMultipartSignedCMSClassInitialize(MimeMultipartSignedCMSClass *clazz) sclass->crypto_generate_html = MimeMultCMS_generate; sclass->crypto_free = MimeMultCMS_free; - clazz->get_content_info = MimeMultCMS_get_content_info; - PR_ASSERT(!oclass->class_initialized); return 0; } @@ -111,8 +107,7 @@ typedef struct MimeMultCMSdata nsCOMPtr sig_decoder_context; nsCOMPtr content_info; char *sender_addr; - PRInt32 decode_error; - PRInt32 verify_error; + PRBool decoding_failed; unsigned char* item_data; PRUint32 item_len; MimeObject *self; @@ -123,8 +118,7 @@ typedef struct MimeMultCMSdata MimeMultCMSdata() :hash_type(0), sender_addr(nsnull), - decode_error(0), - verify_error(0), + decoding_failed(PR_FALSE), item_data(nsnull), self(nsnull), parent_is_encrypted_p(PR_FALSE), @@ -147,38 +141,22 @@ typedef struct MimeMultCMSdata } } MimeMultCMSdata; -static void -MimeMultCMS_get_content_info(MimeObject *obj, - nsICMSMessage **content_info_ret, - char **sender_email_addr_return, - PRInt32 *decode_error_ret, - PRInt32 *verify_error_ret, - PRBool *ci_is_encrypted) -{ - MimeMultipartSigned *msig = (MimeMultipartSigned *) obj; - if (msig && msig->crypto_closure) - { - MimeMultCMSdata *data = (MimeMultCMSdata *) msig->crypto_closure; - - *decode_error_ret = data->decode_error; - *verify_error_ret = data->verify_error; - *content_info_ret = data->content_info; - *ci_is_encrypted = PR_FALSE; - - if (sender_email_addr_return) - *sender_email_addr_return = (data->sender_addr - ? nsCRT::strdup(data->sender_addr) - : 0); - } -} - /* #### MimeEncryptedCMS and MimeMultipartSignedCMS have a sleazy, incestuous, dysfunctional relationship. */ extern PRBool MimeEncryptedCMS_encrypted_p (MimeObject *obj); +extern void MimeCMSGetFromSender(MimeObject *obj, + nsXPIDLCString &from_addr, + nsXPIDLCString &from_name, + nsXPIDLCString &sender_addr, + nsXPIDLCString &sender_name); extern PRBool MimeCMSHeadersAndCertsMatch(MimeObject *obj, - nsICMSMessage *, - PRBool *signing_cert_without_email_address, - char **); + nsICMSMessage *, + PRBool *signing_cert_without_email_address); +extern void MimeCMSRequestAsyncSignatureVerification(nsICMSMessage *aCMSMsg, + const char *aFromAddr, const char *aFromName, + const char *aSenderAddr, const char *aSenderName, + nsIMsgSMIMEHeaderSink *aHeaderSink, PRInt32 aMimeNestingLevel, + unsigned char* item_data, PRUint32 item_len); extern char *MimeCMS_MakeSAURL(MimeObject *obj); extern char *IMAP_CreateReloadAllPartsUrl(const char *url); extern int MIMEGetRelativeCryptoNestLevel(MimeObject *obj); @@ -233,16 +211,6 @@ MimeMultCMS_init (MimeObject *obj) PR_SetError(0,0); - if (!data->decode_error) - { - data->decode_error = PR_GetError(); - if (data->decode_error) - { - delete data; - return 0; - } - } - data->parent_holds_stamp_p = (obj->parent && mime_crypto_stamped_p(obj->parent)); @@ -319,10 +287,8 @@ MimeMultCMS_data_hash (char *buf, PRInt32 size, void *crypto_closure) } PR_SetError(0, 0); - data->data_hash_context->Update((unsigned char *) buf, size); - if (!data->verify_error) { - data->verify_error = PR_GetError(); - } + nsresult rv = data->data_hash_context->Update((unsigned char *) buf, size); + data->decoding_failed = NS_FAILED(rv); return 0; } @@ -345,10 +311,6 @@ MimeMultCMS_data_eof (void *crypto_closure, PRBool abort_p) memcpy(data->item_data, hashString.get(), data->item_len); - if (!data->verify_error) { - data->verify_error = PR_GetError(); - } - // Release our reference to nsICryptoHash // data->data_hash_context = 0; @@ -408,12 +370,7 @@ MimeMultCMS_sig_hash (char *buf, PRInt32 size, void *crypto_closure) } rv = data->sig_decoder_context->Update(buf, size); - if (NS_FAILED(rv)) { - if (!data->verify_error) - data->verify_error = PR_GetError(); - if (data->verify_error >= 0) - data->verify_error = -1; - } + data->decoding_failed = NS_FAILED(rv); return 0; } @@ -438,10 +395,6 @@ MimeMultCMS_sig_eof (void *crypto_closure, PRBool abort_p) // Release our reference to nsICMSDecoder // data->sig_decoder_context = 0; - - if (!data->content_info && !data->verify_error) { - data->verify_error = PR_GetError(); - } } return 0; @@ -460,125 +413,71 @@ static char * MimeMultCMS_generate (void *crypto_closure) { MimeMultCMSdata *data = (MimeMultCMSdata *) crypto_closure; - PRBool signed_p = PR_TRUE; - PRBool good_p = PR_FALSE; PRBool encrypted_p; - PRBool unverified_p = PR_FALSE; - nsresult rv; if (!data) return 0; encrypted_p = data->parent_is_encrypted_p; - PRInt32 signature_status = nsICMSMessageErrors::GENERAL_ERROR; nsCOMPtr signerCert; int aRelativeNestLevel = MIMEGetRelativeCryptoNestLevel(data->self); - unverified_p = data->self->options->missing_parts; + if (aRelativeNestLevel < 0) + return nsnull; - if (unverified_p) + PRInt32 maxNestLevel = 0; + if (data->smimeHeaderSink && aRelativeNestLevel >= 0) + { + data->smimeHeaderSink->MaxWantedNesting(&maxNestLevel); + + if (aRelativeNestLevel > maxNestLevel) + return nsnull; + } + + if (data->self->options->missing_parts) { // We were not given all parts of the message. // We are therefore unable to verify correctness of the signature. - signature_status = nsICMSMessageErrors::VERIFY_NOT_YET_ATTEMPTED; + + if (data->smimeHeaderSink) + data->smimeHeaderSink->SignedStatus(aRelativeNestLevel, + nsICMSMessageErrors::VERIFY_NOT_YET_ATTEMPTED, + nsnull); + return nsnull; } - else + + if (!data->content_info) + { + /* No content_info at all -- since we're inside a multipart/signed, + that means that we've either gotten a message that was truncated + before the signature part, or we ran out of memory, or something + awful has happened. + */ + return nsnull; + } + + nsXPIDLCString from_addr; + nsXPIDLCString from_name; + nsXPIDLCString sender_addr; + nsXPIDLCString sender_name; + + MimeCMSGetFromSender(data->self, + from_addr, from_name, + sender_addr, sender_name); + + MimeCMSRequestAsyncSignatureVerification(data->content_info, + from_addr, from_name, + sender_addr, sender_name, + data->smimeHeaderSink, aRelativeNestLevel, + data->item_data, data->item_len); + if (data->content_info) { - rv = data->content_info->VerifyDetachedSignature(data->item_data, data->item_len); - data->content_info->GetSignerCert(getter_AddRefs(signerCert)); - - if (NS_FAILED(rv)) { - if (NS_ERROR_MODULE_SECURITY == NS_ERROR_GET_MODULE(rv)) { - signature_status = NS_ERROR_GET_CODE(rv); - } - - if (!data->verify_error) { - data->verify_error = PR_GetError(); - } - if (data->verify_error >= 0) { - data->verify_error = -1; - } - } else { - PRBool signing_cert_without_email_address; - - good_p = MimeCMSHeadersAndCertsMatch(data->self, - data->content_info, - &signing_cert_without_email_address, - &data->sender_addr); - if (!good_p) { - if (signing_cert_without_email_address) { - signature_status = nsICMSMessageErrors::VERIFY_CERT_WITHOUT_ADDRESS; - } - else { - signature_status = nsICMSMessageErrors::VERIFY_HEADER_MISMATCH; - } - if (!data->verify_error) { - data->verify_error = -1; - // XXX Fix this data->verify_error = SEC_ERROR_CERT_ADDR_MISMATCH; XXX // - } - } - else - { - signature_status = nsICMSMessageErrors::SUCCESS; - } - } - #if 0 // XXX Fix this. What do we do here? // if (SEC_CMSContainsCertsOrCrls(data->content_info)) { /* #### call libsec telling it to import the certs */ } #endif - - /* Don't free these yet -- keep them around for the lifetime of the - MIME object, so that we can get at the security info of sub-parts - of the currently-displayed message. */ -#if 0 - SEC_CMSDestroyContentInfo(data->content_info); - data->content_info = 0; -#endif /* 0 */ - } - else - { - /* No content_info at all -- since we're inside a multipart/signed, - that means that we've either gotten a message that was truncated - before the signature part, or we ran out of memory, or something - awful has happened. Anyway, it sure ain't good_p. - */ } - PRInt32 maxNestLevel = 0; - if (data->smimeHeaderSink) { - if (aRelativeNestLevel >= 0) { - data->smimeHeaderSink->MaxWantedNesting(&maxNestLevel); - - if (aRelativeNestLevel <= maxNestLevel) - { - data->smimeHeaderSink->SignedStatus(aRelativeNestLevel, signature_status, signerCert); - } - } - } - - if (data->self && data->self->parent) { - mime_set_crypto_stamp(data->self->parent, signed_p, encrypted_p); - } - - { - char *stamp_url = 0, *result; - if (data->self) - { - if (unverified_p && data->self->options) { - // XXX Fix this stamp_url = IMAP_CreateReloadAllPartsUrl(data->self->options->url); XXX // - } else { - stamp_url = MimeCMS_MakeSAURL(data->self); - } - } - - result = - MimeHeaders_make_crypto_stamp (encrypted_p, signed_p, good_p, - unverified_p, - data->parent_holds_stamp_p, - stamp_url); - PR_FREEIF(stamp_url); - return result; - } + return nsnull; } diff --git a/mailnews/mime/src/mimemcms.h b/mailnews/mime/src/mimemcms.h index 0685c4dd11d..d3438c0373d 100644 --- a/mailnews/mime/src/mimemcms.h +++ b/mailnews/mime/src/mimemcms.h @@ -53,14 +53,6 @@ typedef struct MimeMultipartSignedCMS MimeMultipartSignedCMS; struct MimeMultipartSignedCMSClass { MimeMultipartSignedClass msigned; - - /* Callback used to access the SEC_CMSContentInfo of this object. */ - void (*get_content_info) (MimeObject *self, - nsICMSMessage **content_info_ret, - char **sender_email_addr_return, - PRInt32 *decode_error_ret, - PRInt32 *verify_error_ret, - PRBool * ci_is_encrypted); }; extern MimeMultipartSignedCMSClass mimeMultipartSignedCMSClass;