Пример #1
0
Файл: filetype.c Проект: gpg/gpa
static int
detect_cms (const char *data, size_t datalen)
{
  tlvinfo_t ti;
  const char *s;
  size_t n;

  if (datalen < 24) /* Object is probably too short for CMS.  */
    return 0;

  s = data;
  n = datalen;
  if (parse_tlv (&s, &n, &ti))
    goto try_pgp; /* Not properly BER encoded.  */
  if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_SEQUENCE
        && ti.is_cons))
    goto try_pgp; /* A CMS object always starts witn a sequence.  */
  if (parse_tlv (&s, &n, &ti))
    goto try_pgp; /* Not properly BER encoded.  */
  if (!(ti.cls == ASN1_CLASS_UNIVERSAL && ti.tag == ASN1_TAG_OBJECT_ID
        && !ti.is_cons && ti.length) || ti.length > n)
    goto try_pgp; /* This is not an OID as expected.  */
  if (ti.length == 9)
    {
      if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x03", 9))
        return 1; /* Encrypted (aka Enveloped Data).  */
      if (!memcmp (s, "\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02", 9))
        return 1; /* Signed.  */
    }

 try_pgp:
  /* Check whether this might be a non-armored PGP message.  We need
     to do this before checking for armor lines, so that we don't get
     fooled by armored messages inside a signed binary PGP message.  */
  if ((data[0] & 0x80))
    {
      /* That might be a binary PGP message.  At least it is not plain
         ASCII.  Of course this might be certain lead-in text of
         armored CMS messages.  However, I am not sure whether this is
         at all defined and in any case it is uncommon.  Thus we don't
         do any further plausibility checks but stupidly assume no CMS
         armored data will follow.  */
      return 0;
    }

  /* Now check whether there are armor lines.  */
  for (s = data; s && *s; s = (*s=='\n')?(s+1):((s=strchr (s,'\n'))?(s+1):s))
    {
      if (!strncmp (s, "-----BEGIN ", 11))
        {
          if (!strncmp (s+11, "PGP ", 4))
            return 0; /* This is PGP */
          return 1; /* Not PGP, thus we assume CMS.  */
        }
    }

  return 0;
}
Пример #2
0
static void parse_tlv_buffer(const char *block, long size)
{
	co_debug_tlv_t *tlv;

	while (size > 0) {
		tlv = (co_debug_tlv_t *)block;
		if (size < sizeof(*tlv))
		    return;

		parse_tlv(tlv, tlv->value); 

		block += sizeof(*tlv) + tlv->length;
		size -= sizeof(*tlv) + tlv->length;
	}
}
Пример #3
0
static void co_debug_parse(int fd)
{
	xml_start();
	for (;;) {
		co_debug_tlv_t tlv;
		int nread;

		nread = read(fd, &tlv, sizeof(tlv));
		if (nread != sizeof(tlv) || tlv.length == 0)
			break;

		char block[tlv.length];
		nread = read_helper(fd, (void*)&block, tlv.length);
		if (nread != tlv.length)
			break;

		parse_tlv(&tlv, block);

		/* Flush every block, if stdout not redirected */
		if (output_file != stdout)
			fflush (output_file);
	}
	xml_end();
}
Пример #4
0
static void 
parse_aim_snac(struct TCPRECORD *sess, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	enum {
		SNAC_START,
		SNAC_FAMILY_HI, SNAC_FAMILY_LO, 
		SNAC_SUBTYPE_HI, SNAC_SUBTYPE_LO, 
		SNAC_FLAGS_HI, SNAC_FLAGS_LO, 
		SNAC_REQUESTID_0, SNAC_REQUESTID_1, SNAC_REQUESTID_2, SNAC_REQUESTID_3, 
		SNAC_REQUEST_DONE,
		SNAC_REQUEST_DATA,
		SNAC_TLV_START,
		SNAC_TLV_TAG_HI, SNAC_TLV_TAG_LO, SNAC_TLV_LEN_HI, SNAC_TLV_LEN_LO,
		SNAC_TLV_DATA,
		SNAC_TLV_DONE,
		SNAC_IGNORE,

		SNAC_ONCOMING_PRE_BUDDY1,
		SNAC_ONCOMING_PRE_BUDDY2,
		SNAC_ONCOMING_PRE_BUDDY3,
		SNAC_ONCOMING_BUDDY, SNAC_ONCOMING_BUDDY_NAME,

		SNAC_SSI_UNKNOWN_HI, SNAC_SSI_UNKNOWN_LO,
		SNAC_SSI_VERSION, SNAC_SSI_OBJ_COUNT_HI, SNAC_SSI_OBJ_COUNT_LO,
		SNAC_SSI_ENTRY,


		SNAC_SKIP_TO_BUDDY,SNAC_SKIP_TO_TLV,
	};
	struct AIMPARSER *aim = &sess->layer7.aim;
	unsigned offset = 0;

	/* Do the 'close' fucntion that indicates we we've reached the end
	 * of the encapsulating FLAP packet, telling us that anything left undone
	 * parsing the inside SNAC data needs to finish */
	if (px == NULL) {
		if (aim->tlv_len) {
			/* Check to see if the PDU was truncated in the middle
			 * of a TLV */
			FRAMERR(frame, "%s: truncated\n", "AIM");
		}
		return;
	}


	/* Run through the state machine */
	while (offset<length)
	switch (aim->snac_state) {
	case SNAC_START:
		aim->snac_state++;
		break;
	case SNAC_FAMILY_HI:
	case SNAC_FAMILY_LO:
		aim->pdu.family <<= 8;
		aim->pdu.family |= px[offset++];
		aim->snac_state++;
		break;

	case SNAC_SUBTYPE_HI:
	case SNAC_SUBTYPE_LO:
		aim->pdu.subtype <<= 8;
		aim->pdu.subtype |= px[offset++];
		aim->snac_state++;
		break;

	case SNAC_FLAGS_HI:
	case SNAC_FLAGS_LO:
		aim->pdu.flags <<= 8;
		aim->pdu.flags |= px[offset++];
		aim->snac_state++;
		break;

	case SNAC_REQUESTID_0:
	case SNAC_REQUESTID_1:
	case SNAC_REQUESTID_2:
	case SNAC_REQUESTID_3:
		aim->pdu.request_id <<= 8;
		aim->pdu.request_id |= px[offset++];
		aim->snac_state++;
		break;
	case SNAC_REQUEST_DONE:
		if (aim->pdu.channel == 2) {
			switch (aim->pdu.family<<16 | aim->pdu.subtype) {
			case 0x00040006: /* Outgoing Message */
			case 0x00040007: /* Incoming Message */
			case 0x00040014: /* typin to buddy */
				aim->skip_len = 10;
				aim->snac_state = SNAC_SKIP_TO_BUDDY;
				break;
			case 0x0003000b:
			case 0x00020015:
			case 0x00020006:
				aim->snac_state = SNAC_ONCOMING_BUDDY;
				break;
			case 0x00130006: /* family=Server Side Info, subtype=List */
				/* This is a special structure, but it starts with
				 * a 2-byte number followed by a TLV */
				aim->snac_state = SNAC_SSI_UNKNOWN_HI;
				break;
			case 0x00170007: /* signon reply*/
				/* It's just LEN-VALUE encoded, so pretend there is a tag in 
				 * front */
				aim->tlv_tag = 0;
				aim->snac_state = SNAC_TLV_LEN_HI;
				break;
			case 0x00010017: /* family=Generic, subtype=Capabilities */
			case 0x00010018: /* family=Generic, subtype=Capabilities ACK*/
			case 0x00010006: /* family=Generic, subtype=Rate Info request*/
			case 0x00010007: /* family=Generic, subtype=Rate Info responset*/
			case 0x00010008: /* family=Generic, subtype=Rate Info ACK*/
			case 0x00010003:
			case 0x00010002:
			case 0x00040002: /* family=messaging, subtype= Set ICBM Parameter*/
			case 0x00040005: /* family=messaging, subtype=parameter info */
			case 0x0013000e: /* family=aim SSI, subtype=server ack*/
			case 0x00130009: /* family=aim SSI, subtype=modify buffy*/
			case 0x000d0009: /* family=ChatNav , subtype=Info*/
				/* These don't have TLV, but some other data inside */
				aim->snac_state = SNAC_IGNORE;
				break;
			case 0x00010013: /* family=Generic, subtype=message-of-the-day*/
				/* This has some TLVs later in the packet, but starts with
				 * some non-TLV info */
				aim->snac_state = SNAC_IGNORE;
				break;
			case 0x00170002:
			case 0x00170003:
			case 0x00170006:
			case 0x0001001e: /* family=generic, subtype=0x1e*/
				aim->snac_state = SNAC_TLV_START;
				break;
			default:
				switch (aim->pdu.family) {
				case 1:
				case 0x13: /* AIM SSI */
				case 0x18: /* e-mail */
					/* These (probably) don't have TLV stuff */
					aim->snac_state = SNAC_IGNORE;
					break;
				default:
					/* These (probably) have TLV stuff */
					aim->snac_state = SNAC_TLV_START;
				}
				break;

			}
		} else
			aim->snac_state = SNAC_IGNORE;
		break;
	case SNAC_TLV_START:
		strfrag_init(sess->str);
		aim->snac_state++;
		break;
	case SNAC_TLV_TAG_HI:
		aim->tlv_tag = px[offset++];
		aim->snac_state++;
		break;
	case SNAC_TLV_TAG_LO:
		aim->tlv_tag <<= 8;
		aim->tlv_tag |= px[offset++];
		aim->snac_state++;
		break;
	case SNAC_TLV_LEN_HI:
		aim->tlv_len = px[offset++];
		aim->snac_state++;
		break;
	case SNAC_TLV_LEN_LO:
		aim->tlv_len <<= 8;
		aim->tlv_len |= px[offset++];
		aim->snac_state++;
		break;
	case SNAC_TLV_DATA:
		if (aim->tlv_len) {
			unsigned sublen;

			if (aim->tlv_len < length-offset)
				sublen = aim->tlv_len;
			else
				sublen = length-offset;

			parse_tlv(sess, frame, px+offset, sublen);

			offset += sublen;
			aim->tlv_len -= sublen;
		}

		/* We can get here 3 ways.
		 * #1 - the TLV len could have started at zero, in
		 *      which case there is no real data to process.
		 * #2 - the TLV len had a value that crossed packets,
		 *      and we slowly decremented it by bits
		 # #3 - we got here right after processing a chunk
		 */
		if (aim->tlv_len == 0) {
			/* If done parsing the TLV, then do a 'close' operation by
			 * sending a NULL data pointer */
			parse_tlv(sess, frame, 0, 0);
			aim->snac_state = SNAC_TLV_DONE;
		}
		break;
	case SNAC_TLV_DONE:
		switch (aim->pdu.family<<16 | aim->pdu.subtype) {
		case 0x00130006: /* family=Server Side Info, subtype=List */
			/* This has non-TLV data following the TLV */
			aim->snac_state = SNAC_SSI_VERSION;
			break;
		default:
			aim->snac_state = SNAC_TLV_START;
		}
		break;
	case SNAC_IGNORE:
		/* Just ignore the remainder of the data from this point on */
		offset = length;
		break;


	case SNAC_ONCOMING_PRE_BUDDY1:
	case SNAC_ONCOMING_PRE_BUDDY2:
	case SNAC_ONCOMING_PRE_BUDDY3:
		offset++;
		aim->snac_state++;
		break;
	case SNAC_ONCOMING_BUDDY:
		/* The buddy stuff doesn't have a TLV header, so we need
		 * to parse it separately */
		aim->tlv_tag = 0x0000; /* pseudo tag */
		aim->tlv_len = px[offset++];
		if (aim->tlv_len == 0) {
			aim->snac_state = SNAC_ONCOMING_PRE_BUDDY1; 
		} else {
			strfrag_init(sess->str);
			aim->snac_state++;
		}
		break;
	case SNAC_ONCOMING_BUDDY_NAME:
		if (aim->tlv_len) {
			unsigned sublen;
			if (aim->tlv_len < length-offset)
				sublen = aim->tlv_len;
			else
				sublen = length-offset;
			strfrag_append(sess->str, px+offset, sublen);
			offset += sublen;
			aim->tlv_len -= sublen;
		}
		if (aim->tlv_len == 0) {
			/* Save the buddy name */
			strfrag_copy(&sess->str[1], &sess->str[0]);

			/* If done parsing the TLV, then do a 'close' operation by
			 * sending a NULL data pointer */
			parse_tlv(sess, frame, 0, 0);


			switch (aim->pdu.family<<16 | aim->pdu.subtype) {
			case 0x00040006: /* Outgoing Message */
				aim->skip_len = 0;
				aim->snac_state = SNAC_SKIP_TO_TLV;
				break;
			case 0x00040007: /* Incoming Message */
			case 0x00020006: /* Incoming Buddy User Info */
				aim->skip_len = 4;
				aim->snac_state = SNAC_SKIP_TO_TLV;
				break;
			case 0x00040015: /* User Info Query */
				break;
			default:
				aim->snac_state = SNAC_IGNORE;
				break;
			}
		}
		break;
	case SNAC_SSI_UNKNOWN_HI:
		offset++;
		aim->snac_state++;
		break;
	case SNAC_SSI_UNKNOWN_LO:
		offset++;
		aim->snac_state = SNAC_TLV_START;
		break;
	case SNAC_SSI_VERSION:
		if (px[offset++] != 0)
			aim->snac_state = SNAC_IGNORE; /* don't understand this version */
		else
			aim->snac_state = SNAC_SSI_OBJ_COUNT_HI;
		break;
	case SNAC_SSI_OBJ_COUNT_HI:
		aim->ssi_obj_count = px[offset++];
		aim->snac_state++;
		break;
	case SNAC_SSI_OBJ_COUNT_LO:
		aim->ssi_obj_count <<= 8;
		aim->ssi_obj_count |= px[offset++];
		aim->snac_state++;
		break;
	case SNAC_SSI_ENTRY:
		/* Loop through a number of entries */
		while (offset<length && aim->ssi_obj_count) {
			unsigned sublen;

			/* Parse a fragment of data. This function only parses a SINGLE
			 * fragment. Therefore, the returned 'sublen' may be smaller than
			 * the one passed into it */
			aim->ssi_state = 0;
			sublen = parse_ssi_entry(sess, frame, px+offset, length-offset);

			offset += sublen;

			aim->ssi_obj_count--;
		}

		/* there is some more info past the entries, but just ingore it */
		if (aim->ssi_obj_count == 0) {
			aim->snac_state = SNAC_IGNORE;
			strfrag_finish(sess->str+0);
			strfrag_finish(sess->str+1);
		}
		break;
	case SNAC_SKIP_TO_BUDDY:
		{
			unsigned sublen = aim->skip_len;
			if (sublen > length-offset)
				sublen = length-offset;
			aim->skip_len -= sublen;
			offset += sublen;

			if (aim->skip_len == 0)
				aim->snac_state = SNAC_ONCOMING_BUDDY;
		}
		break;
	case SNAC_SKIP_TO_TLV:
		{
			unsigned sublen = aim->skip_len;
			if (sublen > length-offset)
				sublen = length-offset;
			aim->skip_len -= sublen;
			offset += sublen;

			if (aim->skip_len == 0)
				aim->snac_state = SNAC_TLV_START;
		}
		break;
	}
}
Пример #5
0
static unsigned
parse_ssi_entry(struct TCPRECORD *sess, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	enum {
		SSI_BUDDYLEN_HI, SSI_BUDDYLEN_LOW, SSI_BUDDY, SSI_BUDDY_DONE,
		SSI_GROUPID_HI, SSI_GROUPID_LO,
		SSI_BUDDYID_HI, SSI_BUDDYID_LO,
		SSI_TYPE_HI, SSI_TYPE_LOW,
		SSI_TLVLEN_HI, SSI_TLVLEN_LO,

		SNAC_TLV_START,
		SNAC_TLV_TAG_HI, SNAC_TLV_TAG_LO, SNAC_TLV_LEN_HI, SNAC_TLV_LEN_LO,
		SNAC_TLV_DATA,
		SNAC_TLV_DONE,
		SNAC_IGNORE,
	};
	struct AIMPARSER *aim = &sess->layer7.aim;
	unsigned offset = 0;
	
	
	while (offset<length)
	switch (aim->ssi_state) {
	case SSI_BUDDYLEN_HI:
		aim->tlv_len = px[offset++];
		aim->ssi_state++;
		break;
	case SSI_BUDDYLEN_LOW: 
		aim->tlv_len <<= 8;
		aim->tlv_len |= px[offset++];
		aim->ssi_state++;
		strfrag_init(sess->str);
		strfrag_init(sess->str+1);
		break;
	case SSI_BUDDY:
		if (aim->tlv_len) {
			unsigned sublen;
			if (aim->tlv_len < length-offset)
				sublen = aim->tlv_len;
			else
				sublen = length-offset;
			strfrag_append(sess->str+1, px+offset, sublen);
			offset += sublen;
			aim->tlv_len -= sublen;
		}
		if (aim->tlv_len == 0) {
			aim->ssi_state = SSI_BUDDY_DONE;
		}
		break;
	case SSI_BUDDY_DONE:
		aim->ssi_state++;
		break;
	case SSI_GROUPID_HI: 
	case SSI_GROUPID_LO:
		/* just ignore these fields */
		aim->ssi_state++;
		offset++;
		break;
	case SSI_BUDDYID_HI: 
	case SSI_BUDDYID_LO:
		/* just ignore these fields */
		aim->ssi_state++;
		offset++;
		break;
	case SSI_TYPE_HI:
		aim->ssi_buddy_type = px[offset++];
		aim->ssi_state++;
		break;
	case SSI_TYPE_LOW:
		aim->ssi_buddy_type <<= 8;
		aim->ssi_buddy_type |= px[offset++];
		aim->ssi_state++;
		if (sess->str[1].length)
		switch (aim->ssi_buddy_type) {
		case 0x0000: /* individual */
			/* TODO: I should also remember what group it is in */
			if (aim->ssi_group)
				JOTDOWN(sess->eng->ferret, 
					JOT_DST("ID-IP",frame),
					JOT_PRINT("AIM-Buddy", sess->str[1].the_string, sess->str[1].length),
					JOT_PRINT("AIM-Group", aim->ssi_group->str, aim->ssi_group->length),
					0);
			else
				JOTDOWN(sess->eng->ferret, 
					JOT_DST("ID-IP",frame),
					JOT_PRINT("AIM-Buddy", sess->str[1].the_string, sess->str[1].length),
					0);
			break;
		case 0x0001: /* group */
			aim->ssi_group = stringtab_lookup(sess->eng->stringtab, sess->str[1].the_string, sess->str[1].length);
			strfrag_finish(&sess->str[1]);
			break;
		default:
			/*TODO: add SAMPLE */
			break;
		}
		break;
	case SSI_TLVLEN_HI:
		aim->ssi_len = px[offset++];
		aim->ssi_state++;
		break;
	case SSI_TLVLEN_LO:
		aim->ssi_len <<= 8;
		aim->ssi_len |= px[offset++];
		aim->ssi_state++;
		break;
	case SNAC_TLV_START:
	case SNAC_TLV_TAG_HI:
	case SNAC_TLV_TAG_LO:
	case SNAC_TLV_LEN_HI:
	case SNAC_TLV_LEN_LO:
	case SNAC_TLV_DATA:
	case SNAC_TLV_DONE:
		while (offset<length && aim->ssi_len > 0)
		switch (aim->ssi_state) {
		case SNAC_TLV_START:
			strfrag_init(sess->str);
			aim->ssi_state++;
			break;
		case SNAC_TLV_TAG_HI:
			aim->tlv_tag = px[offset++];
			aim->ssi_len--;
			aim->ssi_state++;
			break;
		case SNAC_TLV_TAG_LO:
			aim->tlv_tag <<= 8;
			aim->tlv_tag |= px[offset++];
			aim->ssi_len--;
			aim->ssi_state++;
			break;
		case SNAC_TLV_LEN_HI:
			aim->tlv_len = px[offset++];
			aim->ssi_len--;
			aim->ssi_state++;
			break;
		case SNAC_TLV_LEN_LO:
			aim->tlv_len <<= 8;
			aim->tlv_len |= px[offset++];
			aim->ssi_len--;
			aim->ssi_state++;
			break;
		case SNAC_TLV_DATA:
			if (aim->tlv_len && aim->ssi_len) {
				unsigned sublen;

				if (aim->tlv_len < length-offset)
					sublen = aim->tlv_len;
				else
					sublen = length-offset;
				if (sublen > aim->ssi_len)
					sublen = aim->ssi_len;

				parse_tlv(sess, frame, px+offset, sublen);

				offset += sublen;
				aim->tlv_len -= sublen;
				aim->ssi_len -= sublen;
			}

			/* We can get here 3 ways.
			 * #1 - the TLV len could have started at zero, in
			 *      which case there is no real data to process.
			 * #2 - the TLV len had a value that crossed packets,
			 *      and we slowly decremented it by bits
			 # #3 - we got here right after processing a chunk
			 */
			if (aim->tlv_len == 0 || aim->ssi_len == 0) {
				/* If done parsing the TLV, then do a 'close' operation by
				 * sending a NULL data pointer */
				parse_tlv(sess, frame, 0, 0);
				aim->ssi_state = SNAC_TLV_DONE;
			}
			break;
		case SNAC_TLV_DONE:
			aim->ssi_state = SNAC_TLV_START;
			break;
		}
		if (aim->ssi_len == 0)
			return offset; /* return the number of bytes we analyzed */
		break;
	case SNAC_IGNORE:
		/* Just ignore the remainder of the data from this point on */
		offset = length;
		break;
	}

	return offset;
}