Exemple #1
0
static int
MimeEncrypted_parse_begin (MimeObject *obj)
{
  MimeEncrypted *enc = (MimeEncrypted *) obj;
  MimeDecoderData *(*fn) (nsresult (*) (const char*, PRInt32, void*), void*) = 0;

  if (enc->crypto_closure)
	return -1;

  enc->crypto_closure = (((MimeEncryptedClass *) obj->clazz)->crypto_init) (obj, MimeHandleDecryptedOutput, obj);
  if (!enc->crypto_closure)
	return -1;


  /* (Mostly duplicated from MimeLeaf, see comments in mimecryp.h.)
     Initialize a decoder if necessary.
   */
  if (!obj->encoding)
	;
  else if (!nsCRT::strcasecmp(obj->encoding, ENCODING_BASE64))
	fn = &MimeB64DecoderInit;
  else if (!nsCRT::strcasecmp(obj->encoding, ENCODING_QUOTED_PRINTABLE))
  {
    enc->decoder_data =
	  MimeQPDecoderInit (/* The (int (*) ...) cast is to turn the `void' argument
		     into `MimeObject'. */
		  ((nsresult (*) (const char *, PRInt32, void *))
		   ((MimeEncryptedClass *)obj->clazz)->parse_decoded_buffer),
		  obj);

    if (!enc->decoder_data)
	  return MIME_OUT_OF_MEMORY;
  }
  else if (!nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE) ||
		   !nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE2) ||
		   !nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE3) ||
		   !nsCRT::strcasecmp(obj->encoding, ENCODING_UUENCODE4))
	fn = &MimeUUDecoderInit;
  else if (!nsCRT::strcasecmp(obj->encoding, ENCODING_YENCODE))
    fn = &MimeYDecoderInit;
  if (fn)
	{
	  enc->decoder_data =
		fn (/* The (int (*) ...) cast is to turn the `void' argument
			   into `MimeObject'. */
			((nsresult (*) (const char *, PRInt32, void *))
			 ((MimeEncryptedClass *)obj->clazz)->parse_decoded_buffer),
			obj);

	  if (!enc->decoder_data)
		return MIME_OUT_OF_MEMORY;
	}

  return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
}
Exemple #2
0
static int
MimeLeaf_parse_begin (MimeObject *obj)
{
  MimeLeaf *leaf = (MimeLeaf *) obj;
  MimeDecoderData *(*fn) (nsresult (*) (const char*, PRInt32, void*), void*) = 0;

  /* Initialize a decoder if necessary.
   */
  if (!obj->encoding)
  ;
  else if (!PL_strcasecmp(obj->encoding, ENCODING_BASE64))
  fn = &MimeB64DecoderInit;
  else if (!PL_strcasecmp(obj->encoding, ENCODING_QUOTED_PRINTABLE))
  leaf->decoder_data = 
          MimeQPDecoderInit(((nsresult (*) (const char *, PRInt32, void *))
                        ((MimeLeafClass *)obj->clazz)->parse_decoded_buffer),
                        obj, obj);
  else if (!PL_strcasecmp(obj->encoding, ENCODING_UUENCODE) ||
       !PL_strcasecmp(obj->encoding, ENCODING_UUENCODE2) ||
       !PL_strcasecmp(obj->encoding, ENCODING_UUENCODE3) ||
       !PL_strcasecmp(obj->encoding, ENCODING_UUENCODE4))
  fn = &MimeUUDecoderInit;
  else if (!PL_strcasecmp(obj->encoding, ENCODING_YENCODE))
    fn = &MimeYDecoderInit;

  if (fn)
  {
    leaf->decoder_data =
    fn (/* The (nsresult (*) ...) cast is to turn the `void' argument
         into `MimeObject'. */
      ((nsresult (*) (const char *, PRInt32, void *))
       ((MimeLeafClass *)obj->clazz)->parse_decoded_buffer),
      obj);

    if (!leaf->decoder_data)
    return MIME_OUT_OF_MEMORY;
  }

  return ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
}
Exemple #3
0
static int
MimeMultipartSigned_parse_line (const char *line, PRInt32 length, MimeObject *obj)
{
  MimeMultipart *mult = (MimeMultipart *) obj;
  MimeMultipartSigned *sig = (MimeMultipartSigned *) obj;
  MimeMultipartParseState old_state = mult->state;
  bool hash_line_p = true;
  bool no_headers_p = false;
  int status = 0;

  /* First do the parsing for normal multipart/ objects by handing it off to
   the superclass method.  This includes calling the create_child and
   close_child methods.
   */
  status = (((MimeObjectClass *)(&MIME_SUPERCLASS))
      ->parse_line (line, length, obj));
  if (status < 0) return status;

  /* The instance variable MimeMultipartClass->state tracks motion through
   the various stages of multipart/ parsing.  The instance variable
   MimeMultipartSigned->state tracks the difference between the first
   part (the body) and the second part (the signature.)  This second,
   more specific state variable is updated by noticing the transitions
   of the first, more general state variable.
   */
  if (old_state != mult->state)  /* there has been a state change */
  {
    switch (mult->state)
    {
    case MimeMultipartPreamble:
      PR_ASSERT(0);  /* can't move *in* to preamble state. */
      sig->state = MimeMultipartSignedPreamble;
      break;

    case MimeMultipartHeaders:
      /* If we're moving in to the Headers state, then that means
       that this line is the preceeding boundary string (and we
       should ignore it.)
       */
      hash_line_p = false;

      if (sig->state == MimeMultipartSignedPreamble)
      sig->state = MimeMultipartSignedBodyFirstHeader;
      else if (sig->state == MimeMultipartSignedBodyFirstLine ||
           sig->state == MimeMultipartSignedBodyLine)
      sig->state = MimeMultipartSignedSignatureHeaders;
      else if (sig->state == MimeMultipartSignedSignatureFirstLine ||
           sig->state == MimeMultipartSignedSignatureLine)
      sig->state = MimeMultipartSignedEpilogue;
      break;

    case MimeMultipartPartFirstLine:
      if (sig->state == MimeMultipartSignedBodyFirstHeader)
      {      
        sig->state = MimeMultipartSignedBodyFirstLine;
        no_headers_p = true;
      }
      else if (sig->state == MimeMultipartSignedBodyHeaders)
      sig->state = MimeMultipartSignedBodyFirstLine;
      else if (sig->state == MimeMultipartSignedSignatureHeaders)
      sig->state = MimeMultipartSignedSignatureFirstLine;
      else
      sig->state = MimeMultipartSignedEpilogue;
      break;

    case MimeMultipartPartLine:

      PR_ASSERT(sig->state == MimeMultipartSignedBodyFirstLine ||
          sig->state == MimeMultipartSignedBodyLine ||
          sig->state == MimeMultipartSignedSignatureFirstLine ||
          sig->state == MimeMultipartSignedSignatureLine);

      if (sig->state == MimeMultipartSignedBodyFirstLine)
      sig->state = MimeMultipartSignedBodyLine;
      else if (sig->state == MimeMultipartSignedSignatureFirstLine)
      sig->state = MimeMultipartSignedSignatureLine;
      break;

    case MimeMultipartEpilogue:
      sig->state = MimeMultipartSignedEpilogue;
      break;

    default:  /* bad state */
      NS_ERROR("bad state in MultipartSigned parse line");
      return -1;
      break;
    }
  }


  /* Perform multipart/signed-related actions on this line based on the state
   of the parser.
   */
  switch (sig->state)
  {
  case MimeMultipartSignedPreamble:
    /* Do nothing. */
    break;

  case MimeMultipartSignedBodyFirstLine:
    /* We have just moved out of the MimeMultipartSignedBodyHeaders
     state, so cache away the headers that apply only to the body part.
     */
    NS_ASSERTION(mult->hdrs, "null multipart hdrs");
    NS_ASSERTION(!sig->body_hdrs, "signed part shouldn't have already have body_hdrs");
    sig->body_hdrs = mult->hdrs;
    mult->hdrs = 0;

    /* fall through. */

  case MimeMultipartSignedBodyFirstHeader:
  case MimeMultipartSignedBodyHeaders:
  case MimeMultipartSignedBodyLine:

    if (!sig->crypto_closure)
    {
      /* Set error change */
      PR_SetError(0, 0);
      /* Initialize the signature verification library. */
      sig->crypto_closure = (((MimeMultipartSignedClass *) obj->clazz)
                 ->crypto_init) (obj);
      if (!sig->crypto_closure)
      {
        status = PR_GetError();
        NS_ASSERTION(status < 0, "got non-negative status");
        if (status >= 0)
          status = -1;
        return status;
      }
    }

    if (hash_line_p)
    {
      /* this is the first hashed line if this is the first header
       (that is, if it's the first line in the header state after
       a state change.)
       */
      bool first_line_p
      = (no_headers_p ||
         sig->state == MimeMultipartSignedBodyFirstHeader);

      if (sig->state == MimeMultipartSignedBodyFirstHeader)
      sig->state = MimeMultipartSignedBodyHeaders;

      /* The newline issues here are tricky, since both the newlines
       before and after the boundary string are to be considered part
       of the boundary: this is so that a part can be specified such
       that it does not end in a trailing newline.

       To implement this, we send a newline *before* each line instead
       of after, except for the first line, which is not preceeded by a
       newline.

       For purposes of cryptographic hashing, we always hash line
       breaks as CRLF -- the canonical, on-the-wire linebreaks, since
       we have no idea of knowing what line breaks were used on the
       originating system (SMTP rightly destroys that information.)
       */

      /* Remove the trailing newline... */
      if (length > 0 && line[length-1] == '\n') length--;
      if (length > 0 && line[length-1] == '\r') length--;

      PR_ASSERT(sig->crypto_closure);

      if (!first_line_p)
      {
        /* Push out a preceeding newline... */
        char nl[] = CRLF;
        status = (((MimeMultipartSignedClass *) obj->clazz)
            ->crypto_data_hash (nl, 2, sig->crypto_closure));
        if (status < 0) return status;
      }

      /* Now push out the line sans trailing newline. */
      if (length > 0)
      status = (((MimeMultipartSignedClass *) obj->clazz)
            ->crypto_data_hash (line,length, sig->crypto_closure));
      if (status < 0) return status;
    }
    break;

  case MimeMultipartSignedSignatureHeaders:

    if (sig->crypto_closure &&
      old_state != mult->state)
    {
      /* We have just moved out of the MimeMultipartSignedBodyLine
       state, so tell the signature verification library that we've
       reached the end of the signed data.
       */
      status = (((MimeMultipartSignedClass *) obj->clazz)
          ->crypto_data_eof) (sig->crypto_closure, false);
      if (status < 0) return status;
    }
    break;

  case MimeMultipartSignedSignatureFirstLine:
    /* We have just moved out of the MimeMultipartSignedSignatureHeaders
     state, so cache away the headers that apply only to the sig part.
     */
    PR_ASSERT(mult->hdrs);
    PR_ASSERT(!sig->sig_hdrs);
    sig->sig_hdrs = mult->hdrs;
    mult->hdrs = 0;


    /* If the signature block has an encoding, set up a decoder for it.
     (Similar logic is in MimeLeafClass->parse_begin.)
     */
    {
    MimeDecoderData *(*fn) (nsresult (*) (const char*, PRInt32,void*), void*) = 0;
    nsCString encoding;
    encoding.Adopt(MimeHeaders_get (sig->sig_hdrs,
                   HEADER_CONTENT_TRANSFER_ENCODING,
                   true, false));
    if (encoding.IsEmpty())
      ;
    else if (!PL_strcasecmp(encoding.get(), ENCODING_BASE64))
      fn = &MimeB64DecoderInit;
    else if (!PL_strcasecmp(encoding.get(), ENCODING_QUOTED_PRINTABLE))
    {
      sig->sig_decoder_data =
  MimeQPDecoderInit (((nsresult (*) (const char *, PRInt32, void *))
     (((MimeMultipartSignedClass *) obj->clazz)
          ->crypto_signature_hash)),
    sig->crypto_closure);
      if (!sig->sig_decoder_data)
  return MIME_OUT_OF_MEMORY;
    }
    else if (!PL_strcasecmp(encoding.get(), ENCODING_UUENCODE) ||
             !PL_strcasecmp(encoding.get(), ENCODING_UUENCODE2) ||
             !PL_strcasecmp(encoding.get(), ENCODING_UUENCODE3) ||
             !PL_strcasecmp(encoding.get(), ENCODING_UUENCODE4))
      fn = &MimeUUDecoderInit;
    else if (!PL_strcasecmp(encoding.get(), ENCODING_YENCODE))
      fn = &MimeYDecoderInit;
    if (fn)
      {
      sig->sig_decoder_data =
        fn (((nsresult (*) (const char *, PRInt32, void *))
           (((MimeMultipartSignedClass *) obj->clazz)
          ->crypto_signature_hash)),
          sig->crypto_closure);
      if (!sig->sig_decoder_data)
        return MIME_OUT_OF_MEMORY;
      }
    }

    /* Show these headers to the crypto module. */
    if (hash_line_p)
    {
      status = (((MimeMultipartSignedClass *) obj->clazz)
          ->crypto_signature_init) (sig->crypto_closure,
                        obj, sig->sig_hdrs);
      if (status < 0) return status;
    }

    /* fall through. */

  case MimeMultipartSignedSignatureLine:
    if (hash_line_p)
    {
      /* Feed this line into the signature verification routines. */

      if (sig->sig_decoder_data)
      status = MimeDecoderWrite (sig->sig_decoder_data, line, length, nsnull);
      else
      status = (((MimeMultipartSignedClass *) obj->clazz)
            ->crypto_signature_hash (line, length,
                         sig->crypto_closure));
      if (status < 0) return status;
    }
    break;

  case MimeMultipartSignedEpilogue:
    /* Nothing special to do here. */
    break;

  default:  /* bad state */
    PR_ASSERT(0);
    return -1;
  }

  return status;
}
void
nsEnigMimeListener::ParseMimeHeaders(const char* mimeHeaders, PRUint32 count)
{
  DEBUG_LOG(("nsEnigMimeListener::ParseMimeHeaders, count=%d\n", count));

  // Copy headers string
  nsCAutoString headers(mimeHeaders, count);

  // Replace CRLF with just LF
  __ReplaceCSubstring(headers, "\r\n", "\n");

  // Replace CR with LF (for MAC-style line endings)
  __ReplaceCChar(headers, '\r', '\n');

  // Eliminate all leading whitespace (including linefeeds)
  headers.Trim(" \t\n", PR_TRUE, PR_FALSE);

  if (headers.Length() <= 3) {
    // No headers to parse
    return;
  }

  // Handle continuation of MIME headers, i.e., newline followed by whitespace
  __ReplaceCSubstring(headers, "\n ",  " ");
  __ReplaceCSubstring(headers, "\n\t", "\t");

  //DEBUG_LOG(("nsEnigMimeListener::ParseMimeHeaders: headers='%s'\n", headers.get()));

  PRUint32 offset = 0;
  while (offset < headers.Length()) {
    PRInt32 lineEnd = headers.FindChar('\n', offset);

    if (lineEnd < 0) {
      // Header line terminator not found
      NS_NOTREACHED("lineEnd == kNotFound");
      return;
    }

    // Normal exit if empty header line
    if (lineEnd == (int)offset)
      break;

    // Parse header line
    ParseHeader((headers.get())+offset, lineEnd - offset);

    offset = lineEnd+1;
  }

  if (mDecodeContent) {
    // Decode data
    if (mContentEncoding.Equals("base64", CaseInsensitiveCompare)) {

      mDecoderData = MimeB64DecoderInit(EnigMimeListener_write, (void*) this);

    } else if (mContentEncoding.Equals("quoted-printable", CaseInsensitiveCompare)) {

      mDecoderData = MimeQPDecoderInit(EnigMimeListener_write, (void*) this);
    }
  }
  return;
}