⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgpprsbin.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * pgpPrsBin.c -- Binary Parser
 *
 * Written by:	Colin Plumb and Derek Atkins <warlord@MIT.EDU>
 *
 * $Id: pgpPrsBin.c,v 1.65 1999/04/14 18:51:26 hal Exp $
 */
#include "pgpConfig.h"

#include <stdio.h>
#include <string.h>

#include "pgpDebug.h"
#include "pgpPktByte.h"
#include "pgpPrsAsc.h"
#include "pgpPrsBin.h"
#include "pgpAnnotate.h"
#include "pgpCFBPriv.h"
#include "pgpSymmetricCipherPriv.h"
#include "pgpCiphrMod.h"
#include "pgpCompress.h"
#include "pgpCompMod.h"
#include "pgpEncodePriv.h"
#include "pgpFIFO.h"
#include "pgpHashPriv.h"
#include "pgpHashMod.h"
#include "pgpHeader.h"
#include "pgpMem.h"
#include "pgpEnv.h"
#include "pgpErrors.h"
#include "pgpPipeline.h"
#include "pgpSig.h"
#include "pgpTextFilt.h"
#include "pgpUsuals.h"
#include "pgpContext.h"

#define PARSERMAGIC	0xfeedf00d

/* Only accept this much data per call to parsePacket */
#define PARSER_SIZE_LIMIT	512

/*
 * There are two formats for PGP packets.  Both are equivalent as far as
 * the rest of the code is concerned.
 * The original PGP packet format:
 * - Packet byte: 10ttttll, where tttt = packet type, and ll = length of length
 * - Length field, 1/2/4/0 bytes, big-endian, based on ll bits
 * - Body
 * This format is simple and small, but requires knowing the size of the
 * enclosed data before you can emit the length field.
 *
 * The one-pass PGP 3 format:
 * - Packet byte 11tttttt, where tttttt = packet type
 * - Zero or more non-final subpackets, starting with a byte of the form
 *   111sssss, followed by 2^s bytes of data
 * - A final subpacket, which starts with either 0sssssss, 10sssssss,
 *   or 110sssss ssssssss, holding up to 2^7 + 2^6 + 2^13 - 1 bytes.
 *   (The formats encode lengths of 0-127, 128-191, and 192-8383 bytes.)
 *
 * Generally, a PGP implementation will emit non-final subpackets in the
 * 1K to 8K range, followed by one final subpacket.  However, any size
 * may be used, down to one byte.  This flexibility allows data to be
 * flushed out and a stream to be brought up to date at any byte boundary
 * by emitting a combination of non-final subpackets which sum to the
 * desired boundary.
 *
 * To keep track of both of these formats, there is a Header,
 * which describes the parsing state of the current subpacket header on
 * an arbitrary byte boundary.  It has three members:
 * lenbytes - the count of the number of bytes remaining in the
 *            current big-endian subpacket size.  This may be as large
 *            as 4.  As additional bytes are read, lenbytes is decremented
 *            and "pktlen" is increased with the appropriately shifted
 *            byte.
 * more - a flag which is true if the current subpacket is non-terminal,
 *        so another subpacket is expected.
 * pktlen - the length of the current subpacket.  If lenbytes is non-zero,
 *          the value here is an underestimate.  When this is 0, a new
 *          packet or subpacket (depending on the more flag) is expected.
 * 
 * To keep track of the state of the input stream, a Header structure is
 * used, but data that has already been read from the Header structure
 * is kept around as well.  There are two data structures for this:
 * - The FIFO contains a copy of the raw input data up to the point
 *   marked by "passptr".
 * - The buffer, which also holds a prefix of the input data, but a
 *   parsed version.  A portion of the two overlap, and what can be
 *   kept in the buffer, is.  This always includes the tail of the last
 *   subpacket that has been read.  If this is also the first subpacket,
 *   nothing actually needs to get copied to the FIFO at all.
 *
 * The buffer ends up looking like this:
 *
 * /------------------------ passptr - First byte not passed through to FIFO.
 * |
 * v
 * +------------------------------------+
 * |                                    |
 * +------------------------------------+
 *     ^           ^
 *     |           |
 *     |           \--------- bufend - End of packet header/start of read-ahead
 *     \--------------------- bufptr - Beginning of intra-packet header
 * 
 * It works like this: The data from the FIFO, plus passptr through bufend,
 * is the raw data that's been processed.  Passptr is usually before
 * bufptr, with the gap filled by the packet's external header
 * (packet header byte plus length or first subpacket header), and
 * then bufptr through bufend is shared between the two.
 *
 * If the amount of header data needed exceeds the size of the first
 * subpacket, then the data up to and including the second subpacket
 * header is copied to the FIFO, and as much of the second subpacket as
 * is needed is read into the buffer immediately following the first
 * subpacket, with no intervening subpacket header, and "passptr" is
 * set to point to the beginning of the second subpacket data.
 *
 * The data between bufend and readptr is, however, raw input data
 * including subpacket headers that have not yet been parsed.
 */

/* Size of buffer - must hold a whole ESK or SIG packet */
/* 4096 bit ElGamal ESK's will be a bit over 1024 bytes */
/* Some X.509 sigs can be several times this */
/* However this is OK, they are only in keyring and get passed through */
#define MAXPKTSIZE		1100


static size_t nextScope (PGPPipeline *myself, PGPByte const *buf,
			 size_t size, PGPError *error);
static size_t nextESK (PGPPipeline *myself, PGPByte const *buf,
		       size_t size, PGPError *error);
static size_t parsePacket (PGPPipeline *myself, PGPByte const *buf,
			   size_t size, PGPError *error);
static size_t parseKey (PGPPipeline *myself, PGPByte const *buf,
			size_t size, PGPError *error);

/* Used to recognize the beginning of a recursive literal packet */
static char const pgp_message_begin[] = "-----BEGIN PGP ";


/* Information needed to parse a subpacket header */
typedef struct Header {
	PGPUInt32 pktlen;		/* Length of current subpacket */
	unsigned lenbytes;	/* Number of length bytes to come */
	PGPByte more;		/* More subpackets to come */
} Header;

/* Information needed to parse a data stream */
typedef struct Input {
	PGPByte buffer[MAXPKTSIZE];	/* Buffer of parsed data */
	PGPFifoContext *fifo;	/* FIFO of raw data */
	PGPByte const *passptr;	/* Pointer into buffer */
	PGPByte const *bufptr;	/* Pointer into buffer */
	PGPByte *bufend;		/* Pointer into buffer */
	Header head;	/* Current subpacket status */
	PGPByte silent_trunc;	/* Complain if out of input? */
} Input;

typedef struct PrsBinContext {
	PGPPipeline		pipe;
	
	Input input;
	PGPPipeline *tail;
	PGPPipeline *nextparser;
	PGPPipeline **end;
	PGPHashListRef hashes;
	PGPEnv const *env;
	int state;		/* Used my bumerous parse functions */
	int end_scope;		/* Annotation at end of this scope, or 0 */
	PGPByte subtype;		/* Type of literal packet (t vs. b) */
	int sig1pass;		/* Within 1-pass signature scope */
	int sig1nest;		/* Number of unpaired 1pass headers nested */
	/* Flags */
	PGPByte sepsig;		/* 1-pass separate signature */
	PGPByte findpkt;		/* Searching for a new packet */
	PGPByte eof;		/* No more input available, ever */
	PGPByte needcallback;
	PGPByte nopurge;	/* Suppress purge of input buffer */
	PGPUICb const *ui;
	void *ui_arg;
	DEBUG_STRUCT_CONSTRUCTOR( PrsBinContext )
} PrsBinContext;

/* Return true if the end of the current packet has been reached */
static int
inputFinished(Header const *head)
{
	return !head->pktlen && !head->lenbytes && !head->more;
}

/*
 * Return a pointer to, and then length of, the subpacket header at the
 * current position in the input buffer, using the context of "head".
 */
static PGPByte const *
inputHeadPeek(Header const *head, PGPByte const *buf, size_t size,
              size_t *len)
{
	pgpAssert(buf || !size);

	if (head->lenbytes) {
		*len = (size < head->lenbytes) ? size : (size_t)head->lenbytes;
		return buf;
	}
	if (head->pktlen) {
		*len = 0;
		return buf;
	}
	if (!head->more) {
		*len = 0;
		return (PGPByte const *)0;
	}
	if (!size) {
		*len = 0;
		return buf;
	}
	if (buf[0] == 0xff && size >= 5)
		*len = 5;
	else if (buf[0] == 0xff)
		*len = size;
	else if ((buf[0] & 0xe0) == 0xc0 && size > 1)
		*len = 2;
	else
		*len = 1;
	return buf;
}

/*
 * Skip the upcoming header, adjusting the state in "head" appropriately.
 * Return the number of bytes consumed (<= size).
 */
static size_t
inputHeadSeek(Header *head, PGPByte const *buf, size_t size)
{
	unsigned i;
	unsigned char b;

	/* No data, don't care */
	if (!size)
		return 0;
	pgpAssert(buf);

	/* If we're in the middle of a header, read the tail of it */
	if (head->lenbytes) {
		if (size > head->lenbytes)
			size = (size_t)head->lenbytes;
		i = (unsigned)size;
		do {
			head->pktlen += (PGPUInt32)*buf++ << (8*--head->lenbytes);
		} while (--i);
		return size;
	}

	/* Are we not at the end of a packet? */
	if (head->pktlen || !head->more)
		return 0;

	/* Otherwise, we're starting a new subpacket header */
	b = buf[0];
	if (b < 0xc0) {
		head->pktlen = (PGPUInt32)b;
		head->more = 0;
	} else if (b < 0xe0) {
		head->pktlen = ((PGPUInt32)b << 8) - (0xc000 - 0xc0);
		head->more = 0;
		if (size == 1) {
			head->lenbytes = 1;
		} else {
			head->pktlen += (PGPUInt32)buf[1];
			return 2;
		}
	} else if (b == 0xff) {
		if (size > 5)
			size = 5;
		i = (unsigned)size-1;
		head->more = 0;
		head->lenbytes = 4;
		head->pktlen = 0;
		do {
			head->pktlen += (PGPUInt32)*++buf << (8*--head->lenbytes);
		} while (--i);
		return size;
	} else if (b >= 0xe0) {
		head->pktlen = (PGPUInt32)1 << (b & 31);
	}
	return 1;
}
                
static void
inputReset(Input *input)
{
	input->passptr = input->bufptr = input->bufend = input->buffer;
	input->head.pktlen = 0;
	input->head.lenbytes = 0;
	input->head.more = 0;
}

/*
 * Start parsing a packet with the given header byte.
 * Returns 0 if it's a normal, good header byte, and -1
 * if it's a bogus header byte, in which case the rest of the
 * input is taken as the body.
 */
static int
inputStart(Input *input, PGPByte b)
{
	/* Store first byte in buffer */
	input->passptr = input->buffer;
	input->buffer[0] = b;
	input->bufend = input->buffer+1;
	input->head.pktlen = 0;

	if (IS_NEW_PKTBYTE(b)) {
		/* New style */
		input->head.lenbytes = 0;
		input->head.more = 1;
		input->silent_trunc = 0;
	} else if (IS_OLD_PKTBYTE(b)) {
		/* Old style */
		input->head.lenbytes = LLEN_TO_BYTES(PKTBYTE_LLEN(b));
		input->head.more = 0;
		input->silent_trunc = 0;
		if (PKTBYTE_LLEN(b) == 3) {
			input->silent_trunc = 1;
			input->head.pktlen = (PGPUInt32)-1;
		}
	} else {
		/* Erroneous! */
		input->bufptr = input->buffer;
		input->head.pktlen = (PGPUInt32)-1;
		input->head.lenbytes = 0;
		input->head.more = 0;
		input->silent_trunc = 1;
		return -1;
	}
	/* Usual case wrapup */
	input->bufptr = input->bufend;
	return 0;
}

/*
 * Return a pointer to, and the length of, the next available packet payload
 * bytes.  These bytes will come from either the read-ahead buffer or the
 * input buffer (buf, size), as appropriate.  Returns a NULL pointer when
 * there is no more data available in the packet.  If "size" is 0 and
 * this is not the end of the packet, this returns the "buf" pointer,
 * which may or may not be NULL, at the caller's discretion.
 *
 * This may, in some situations (like when "size" is 1 and sitting
 * on a subpacket header), return the "buf" pointer but a zero length
 * even when size is non-zero.
 * In that case, the current packet is not finished, but no data is available
 * in the current input buffer.   You need to call inputSeek(0) to give
 * it a chance to consume the current input buffer.
 */
static PGPByte const *
inputPeek(Input const *input, PGPByte const *buf, size_t size, size_t *len)
{
	/* If we have no buffer, then size must be 0 */
	pgpAssert(buf || !size);

	/* If we have data buffered, use that. */
	if (input->bufend != input->bufptr) {
		*len = (size_t)(input->bufend - input->bufptr);
		return input->bufptr;
	}
	/*
	 * If we are in the middle of a subpacket header, no data available,
	 * but more to come.
	 */
	if (input->head.lenbytes) {
		*len = 0;
		return buf;
	}
	/*
	 * If we're at the end of a subpacket, no data available, and
	 * there may or may not be more to come.
	 */
	if (!input->head.pktlen) {
		*len = 0;
		return input->head.more ? buf : 0;
	}

	/* Return the appropriate data from the input buffer */
	if (size > input->head.pktlen)
		size = (size_t)input->head.pktlen;

	*len = size;
	return buf;
}

/*
 * Skip over "len" bytes (where len <= the amount returned from the latest
 * call to inputPeek!) of input from the input stream (either the context
 * buffer or the supplied external buffer).
 */
static size_t
inputSeek(Input *input, PGPByte const *buf, size_t size, size_t len)
{
	pgpAssert(buf || !size);

	/* If we have data in the input buffer, skip that */
	if (input->bufend != input->bufptr) {
		pgpAssert(len <= (size_t)(input->bufend - input->bufptr));
		input->bufptr += len;
		return 0;
	}
	/* Make sure the skip is legal */
	pgpAssert(!len || !input->head.lenbytes);
	pgpAssert(len <= input->head.pktlen);
	pgpAssert(len <= size);

	/* Skip the data */
	input->head.pktlen -= len;

	/* Skip any additional header that follows */
	return len + inputHeadSeek(&input->head, buf+len, size-len);
}

/*
 * Copy the input buffer to the FIFO.
 */
static PGPError
inputToFifo(Input *input)
{
	size_t len, written;

	len = (size_t)(input->bufend - input->passptr);
	if (len) {
		written = pgpFifoWrite (&pgpByteFifoDesc, input->fifo,
					input->passptr, len);
		input->passptr += written;
		if (written != len)
			return kPGPError_OutOfMemory;
	}
	return( kPGPError_NoErr );
}

/*
 * Try to ensure that the next "desired" bytes of input are contiguous
 * and thus inputPeek will return them in one call.  This will copy
 * bytes from the external buffer to the input buffer.  If it does,
 * the number of bytes copied is returned.
 *
 * If this needs to squeeze subpacket header bytes out of the read-ahead
 * buffer to make the buffer contiguous, it copies the bytes to the FIFO
 * so they'll be available for raw reading.
 */
static size_t
inputMerge(Input *input, PGPByte const *buf, size_t size, unsigned desired,
           PGPError *error)
{
	size_t size0;
	size_t s, t;
	unsigned avail;

	pgpAssert(buf || !size);

	*error = kPGPError_NoErr;	/* No error */

	s = (size_t)(input->bufend - input->bufptr);
	if (s >= desired)
		return 0;
	desired -= (unsigned)s;

	size0 = size;
	
	while (desired && size) {
		/* Suck in the following header, if any */
		if (!inputHeadPeek(&input->head, buf, size, &s))
			break;	/* End of packet */
		/* If we have a header, deal with it. */
		if (s) {
			/*
			 * Do something with the header - put it in the buffer
			 * before bufptr if possible, or in the FIFO if not.
			 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -