Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Typedefs | Functions | Variables
mimecms.cpp File Reference
#include "nsICMSMessage.h"
#include "nsICMSMessage2.h"
#include "nsICMSMessageErrors.h"
#include "nsICMSDecoder.h"
#include "mimecms.h"
#include "mimemsig.h"
#include "nsCRT.h"
#include "nspr.h"
#include "nsEscape.h"
#include "mimemsg.h"
#include "mimemoz2.h"
#include "nsIURI.h"
#include "nsIMsgWindow.h"
#include "nsIMsgMailNewsUrl.h"
#include "nsIMimeMiscStatus.h"
#include "nsIMsgSMIMEHeaderSink.h"
#include "nsCOMPtr.h"
#include "nsIX509Cert.h"
#include "nsIMsgHeaderParser.h"
#include "nsIProxyObjectManager.h"

Go to the source code of this file.

Classes

struct  MimeCMSdata
class  nsSMimeVerificationListener

Defines

#define MIME_SUPERCLASS   mimeEncryptedClass

Typedefs

typedef struct MimeCMSdata MimeCMSdata

Functions

 MimeDefClass (MimeEncryptedCMS, MimeEncryptedCMSClass, mimeEncryptedCMSClass,&MIME_SUPERCLASS)
static voidMimeCMS_init (MimeObject *, int(*output_fn)(const char *, PRInt32, void *), void *)
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 int MimeEncryptedCMSClassInitialize (MimeEncryptedCMSClass *clazz)
static void MimeCMS_content_callback (void *arg, const char *buf, unsigned long length)
PRBool MimeEncryptedCMS_encrypted_p (MimeObject *obj)
static void ParseRFC822Addresses (const char *line, nsXPIDLCString &names, nsXPIDLCString &addresses)
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)
int MIMEGetRelativeCryptoNestLevel (MimeObject *obj)
static voidMimeCMS_init (MimeObject *obj, int(*output_fn)(const char *buf, PRInt32 buf_size, void *output_closure), void *output_closure)
void MimeCMSGetFromSender (MimeObject *obj, nsXPIDLCString &from_addr, nsXPIDLCString &from_name, nsXPIDLCString &sender_addr, nsXPIDLCString &sender_name)
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)

Variables

int SEC_ERROR_CERT_ADDR_MISMATCH

Define Documentation

Definition at line 61 of file mimecms.cpp.


Typedef Documentation

typedef struct MimeCMSdata MimeCMSdata

Function Documentation

static void MimeCMS_content_callback ( void arg,
const char *  buf,
unsigned long  length 
) [static]

Definition at line 134 of file mimecms.cpp.

{
  int status;
  MimeCMSdata *data = (MimeCMSdata *) arg;
  if (!data) return;

  if (!data->output_fn)
    return;

  PR_SetError(0,0);
  status = data->output_fn (buf, length, data->output_closure);
  if (status < 0)
  {
    PR_SetError(status, 0);
    data->output_fn = 0;
    return;
  }

  data->decoded_bytes += length;
}

Here is the caller graph for this function:

static int MimeCMS_eof ( void crypto_closure,
PRBool  abort_p 
) [static]

Definition at line 591 of file mimecms.cpp.

{
  MimeCMSdata *data = (MimeCMSdata *) crypto_closure;
  nsresult rv;
  PRInt32 status = nsICMSMessageErrors::SUCCESS;

  if (!data || !data->output_fn || !data->decoder_context) {
    return -1;
  }

  int aRelativeNestLevel = MIMEGetRelativeCryptoNestLevel(data->self);

  /* Hand an EOF to the crypto library.  It may call data->output_fn.
   (Today, the crypto library has no flushing to do, but maybe there
   will be someday.)

   We save away the value returned and will use it later to emit a
   blurb about whether the signature validation was cool.
   */

  PR_SetError(0, 0);
  rv = data->decoder_context->Finish(getter_AddRefs(data->content_info));
  if (NS_FAILED(rv))
    status = nsICMSMessageErrors::GENERAL_ERROR;

  data->decoder_context = 0;

  nsCOMPtr<nsIX509Cert> certOfInterest;

  if (!data->smimeHeaderSink)
    return 0;

  if (aRelativeNestLevel < 0)
    return 0;

  PRInt32 maxNestLevel = 0;
  data->smimeHeaderSink->MaxWantedNesting(&maxNestLevel);

  if (aRelativeNestLevel > maxNestLevel)
    return 0;

  if (data->decoding_failed)
    status = nsICMSMessageErrors::GENERAL_ERROR;

  if (!data->content_info)
  {
    if (!data->decoded_bytes)
    {
      // We were unable to decode any data.
      status = nsICMSMessageErrors::GENERAL_ERROR;
    }
    else
    {
      // Some content got decoded, but we failed to decode
      // the final summary, probably we got truncated data.
      status = nsICMSMessageErrors::ENCRYPT_INCOMPLETE;
    }

    // Although a CMS message could be either encrypted or opaquely signed,
    // what we see is most likely encrypted, because if it were
    // signed only, we probably would have been able to decode it.

    data->ci_is_encrypted = PR_TRUE;
  }
  else
  {
    rv = data->content_info->ContentIsEncrypted(&data->ci_is_encrypted);

    if (NS_SUCCEEDED(rv) && data->ci_is_encrypted) {
      data->content_info->GetEncryptionCert(getter_AddRefs(certOfInterest));
    }
    else {
      // Existing logic in mimei assumes, if !ci_is_encrypted, then it is signed.
      // Make sure it indeed is signed.

      PRBool testIsSigned;
      rv = data->content_info->ContentIsSigned(&testIsSigned);

      if (NS_FAILED(rv) || !testIsSigned) {
        // Neither signed nor encrypted?
        // We are unable to understand what we got, do not try to indicate S/Mime status.
        return 0;
      }

      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, 
                                               nsnull, 0);
    }
  }

  if (data->ci_is_encrypted)
  {
    data->smimeHeaderSink->EncryptionStatus(
      aRelativeNestLevel,
      status,
      certOfInterest
    );
  }

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void MimeCMS_free ( void crypto_closure) [static]

Definition at line 705 of file mimecms.cpp.

{
  MimeCMSdata *data = (MimeCMSdata *) crypto_closure;
  if (!data) return;
  
  delete data;
}

Here is the caller graph for this function:

static char * MimeCMS_generate ( void crypto_closure) [static]

Definition at line 714 of file mimecms.cpp.

{
  return nsnull;
}

Here is the caller graph for this function:

static void* MimeCMS_init ( MimeObject ,
int(*)(const char *, PRInt32, void *)  output_fn,
void  
) [static]

Here is the caller graph for this function:

static void* MimeCMS_init ( MimeObject obj,
int(*)(const char *buf, PRInt32 buf_size, void *output_closure)  output_fn,
void output_closure 
) [static]

Definition at line 415 of file mimecms.cpp.

{
  MimeCMSdata *data;
  MimeDisplayOptions *opts;
  nsresult rv;

  if (!(obj && obj->options && output_fn)) return 0;

  opts = obj->options;
  data = new MimeCMSdata;
  if (!data) return 0;

  data->self = 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)) return 0;

  rv = data->decoder_context->Start(MimeCMS_content_callback, data);
  if (NS_FAILED(rv)) return 0;

  // XXX Fix later XXX //
  data->parent_holds_stamp_p =
  (obj->parent &&
   (mime_crypto_stamped_p(obj->parent) ||
    mime_typep(obj->parent, (MimeObjectClass *) &mimeEncryptedClass)));

  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 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);

  mime_stream_data *msd = (mime_stream_data *) (data->self->options->stream_closure);
  if (msd)
  {
    nsIChannel *channel = msd->channel;  // note the lack of ref counting...
    if (channel)
    {
      nsCOMPtr<nsIURI> uri;
      nsCOMPtr<nsIMsgWindow> msgWindow;
      nsCOMPtr<nsIMsgHeaderSink> headerSink;
      nsCOMPtr<nsIMsgMailNewsUrl> msgurl;
      nsCOMPtr<nsISupports> securityInfo;
      channel->GetURI(getter_AddRefs(uri));
      if (uri)
      {
        nsCAutoString urlSpec;
        rv = uri->GetSpec(urlSpec);

        // We only want to update the UI if the current mime transaction
        // is intended for display.
        // If the current transaction is intended for background processing,
        // we can learn that by looking at the additional header=filter
        // string contained in the URI.
        //
        // If we find something, we do not set smimeHeaderSink,
        // which will prevent us from giving UI feedback.
        //
        // If we do not find header=filter, we assume the result of the
        // processing will be shown in the UI.

        if (!strstr(urlSpec.get(), "?header=filter") &&
            !strstr(urlSpec.get(), "&header=filter") &&
            !strstr(urlSpec.get(), "?header=attach") &&
            !strstr(urlSpec.get(), "&header=attach"))
        {
          msgurl = do_QueryInterface(uri);
          if (msgurl)
            msgurl->GetMsgWindow(getter_AddRefs(msgWindow));
          if (msgWindow)
            msgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
          if (headerSink)
            headerSink->GetSecurityInfo(getter_AddRefs(securityInfo));
          if (securityInfo)
            data->smimeHeaderSink = do_QueryInterface(securityInfo);
        }
      }
    } // if channel
  } // if msd

  return data;
}

Here is the call graph for this function:

static int MimeCMS_write ( const char *  buf,
PRInt32  buf_size,
void closure 
) [static]

Definition at line 510 of file mimecms.cpp.

{
  MimeCMSdata *data = (MimeCMSdata *) closure;
  nsresult rv;

  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);

  return 0;
}

Here is the caller graph for this function:

void MimeCMSGetFromSender ( MimeObject obj,
nsXPIDLCString from_addr,
nsXPIDLCString from_name,
nsXPIDLCString sender_addr,
nsXPIDLCString sender_name 
)

Definition at line 524 of file mimecms.cpp.

{
  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);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

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 
)

Definition at line 185 of file mimecms.cpp.

{
  nsXPIDLCString cert_addr;
  PRBool match = PR_TRUE;
  PRBool foundFrom = PR_FALSE;
  PRBool foundSender = PR_FALSE;

  /* Find the name and address in the cert.
   */
  if (content_info)
  {
    // Extract any address contained in the cert.
    // This will be used for testing, whether the cert contains no addresses at all.
    content_info->GetSignerEmailAddress (getter_Copies(cert_addr));
  }

  if (signing_cert_without_email_address)
  {
    *signing_cert_without_email_address = (!cert_addr);
  }

  /* Now compare them --
   consider it a match if the address in the cert matches either the
   address in the From or Sender field
   */

  /* If there is no addr in the cert at all, it can not match and we fail. */
  if (!cert_addr)
  {
    match = PR_FALSE;
  }
  else
  {
    if (signerCert)
    {
      if (from_addr && *from_addr)
      {
        NS_ConvertASCIItoUCS2 ucs2From(from_addr);
        if (NS_FAILED(signerCert->ContainsEmailAddress(ucs2From, &foundFrom)))
        {
          foundFrom = PR_FALSE;
        }
      }

      if (sender_addr && *sender_addr)
      {
        NS_ConvertASCIItoUCS2 ucs2Sender(sender_addr);
        if (NS_FAILED(signerCert->ContainsEmailAddress(ucs2Sender, &foundSender)))
        {
          foundSender = PR_FALSE;
        }
      }
    }

    if (!foundSender && !foundFrom)
    {
      match = PR_FALSE;
    }
  }

  return match;
}

Here is the call graph for this function:

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 
)

Definition at line 568 of file mimecms.cpp.

{
  nsCOMPtr<nsICMSMessage2> msg2 = do_QueryInterface(aCMSMsg);
  if (!msg2)
    return;
  
  nsRefPtr<nsSMimeVerificationListener> 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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 155 of file mimecms.cpp.

{
  PRBool encrypted;

  if (!obj) return PR_FALSE;
  if (mime_typep(obj, (MimeObjectClass *) &mimeEncryptedCMSClass))
  {
    MimeEncrypted *enc = (MimeEncrypted *) obj;
    MimeCMSdata *data = (MimeCMSdata *) enc->crypto_closure;
    if (!data || !data->content_info) return PR_FALSE;
                data->content_info->ContentIsEncrypted(&encrypted);
          return encrypted;
  }
  return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 73 of file mimecms.cpp.

{
#ifdef DEBUG
  MimeObjectClass    *oclass = (MimeObjectClass *)    clazz;
  NS_ASSERTION(!oclass->class_initialized, "1.2 <mscott@netscape.com> 01 Nov 2001 17:59");
#endif

  MimeEncryptedClass *eclass = (MimeEncryptedClass *) clazz;
  eclass->crypto_init          = MimeCMS_init;
  eclass->crypto_write         = MimeCMS_write;
  eclass->crypto_eof           = MimeCMS_eof;
  eclass->crypto_generate_html = MimeCMS_generate;
  eclass->crypto_free          = MimeCMS_free;

  return 0;
}

Here is the call graph for this function:

Definition at line 347 of file mimecms.cpp.

{
  /*
    the part id of any mimeobj is mime_part_address(obj)
    our currently displayed crypto part is obj
    the part shown as the toplevel object in the current window is
        obj->options->part_to_load
        possibly stored in the toplevel object only ???
        but hopefully all nested mimeobject point to the same displayooptions

    we need to find out the nesting level of our currently displayed crypto object
    wrt the shown part in the toplevel window
  */

  // if we are showing the toplevel message, aTopMessageNestLevel == 0
  int aTopMessageNestLevel = 0;
  MimeObject *aTopShownObject = nsnull;
  if (obj && obj->options->part_to_load) {
    PRBool aAlreadyFoundTop = PR_FALSE;
    for (MimeObject *walker = obj; walker; walker = walker->parent) {
      if (aAlreadyFoundTop) {
        if (!mime_typep(walker, (MimeObjectClass *) &mimeEncryptedClass)
            && !mime_typep(walker, (MimeObjectClass *) &mimeMultipartSignedClass)) {
          ++aTopMessageNestLevel;
        }
      }
      if (!aAlreadyFoundTop && !strcmp(mime_part_address(walker), walker->options->part_to_load)) {
        aAlreadyFoundTop = PR_TRUE;
        aTopShownObject = walker;
      }
      if (!aAlreadyFoundTop && !walker->parent) {
        // 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;
      }
    }
  }

  PRBool CryptoObjectIsChildOfTopShownObject = PR_FALSE;
  if (!aTopShownObject) {
    // no sub part specified, top message is displayed, and
    // our crypto object is definitively a child of it
    CryptoObjectIsChildOfTopShownObject = PR_TRUE;
  }

  // if we are the child of the topmost message, aCryptoPartNestLevel == 1
  int aCryptoPartNestLevel = 0;
  if (obj) {
    for (MimeObject *walker = obj; walker; walker = walker->parent) {
      // Crypto mime objects are transparent wrt nesting.
      if (!mime_typep(walker, (MimeObjectClass *) &mimeEncryptedClass)
          && !mime_typep(walker, (MimeObjectClass *) &mimeMultipartSignedClass)) {
        ++aCryptoPartNestLevel;
      }
      if (aTopShownObject && walker->parent == aTopShownObject) {
        CryptoObjectIsChildOfTopShownObject = PR_TRUE;
      }
    }
  }

  if (!CryptoObjectIsChildOfTopShownObject) {
    return -1;
  }

  return aCryptoPartNestLevel - aTopMessageNestLevel;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void ParseRFC822Addresses ( const char *  line,
nsXPIDLCString names,
nsXPIDLCString addresses 
) [static]

Definition at line 173 of file mimecms.cpp.

{
  PRUint32 numAddresses;
  nsresult res;
  nsCOMPtr<nsIMsgHeaderParser> pHeader = do_GetService(NS_MAILNEWS_MIME_HEADER_PARSER_CONTRACTID, &res);

  if (NS_SUCCEEDED(res))
  {
    pHeader->ParseHeaderAddresses(nsnull, line, getter_Copies(names), getter_Copies(addresses), &numAddresses);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation