pgpprsasc.c

来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 2,441 行 · 第 1/5 页

C
2,441
字号
/*
 * pgpPrsAsc.c -- ascii dearmor parser.  This is fairly complicated.  Read
 * 	the comment a page down for a description of how this system works.
 *	The nice part is that you can input multipart armor in any order
 *	and it will work.  In fact, you can intersperse armor parts from
 *	multiple messages and it will work.  Moreover, you can input binary
 *	PGP messages and it will still work!  My god, can this man think
 *	of everything or what?
 *
 * Copyright (C) 1995-1997 Pretty Good Privacy, Inc. All rights reserved.
 *
 * Written by:	Derek Atkins <warlord@MIT.EDU>
 *
 * $Id: pgpPrsAsc.c,v 1.13.2.3 1997/06/07 09:50:57 mhw Exp $
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

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

/* [Hal] I am working on adding PGP/MIME parsing to this. */
#ifndef MIMEPARSE
#define MIMEPARSE		0
#endif

#include "pgpDebug.h"
#include "pgpCharMap.h"		/* for charMapIdentity */
#include "pgpCopyMod.h"
#include "pgpCRC.h"
#include "pgpPrsAsc.h"
#include "pgpRadix64.h"
#include "pgpAnnotate.h"
#if MIMEPARSE
#include "pgpDeMimeMod.h"
#endif
#include "pgpFIFO.h"
#include "pgpFileType.h"
#include "pgpHash.h"
#include "pgpJoin.h"
#include "pgpMem.h"
#include "pgpPrsBin.h"
#include "pgpEnv.h"
#include "pgpErr.h"
#include "pgpPipeline.h"
#include "pgpSplit.h"
#include "pgpTextFilt.h"
#include "pgpUsuals.h"
#include "pgpVerifyRa.h"

/*
 * This is a complicated piece of code.  Less politely, this code is a
 * bitch.  It needs to be able to keep track of many different things
 * at the same time in order to combine pieces of armor into whole messages.
 *
 * There are three entities defined here. First is an armor part, which
 * is defined as the range from BEGIN PGP MESSAGE to the END. Second is
 * a message, which is PGP message made up of one or more parts.
 * And third, there are files, which can contain parts.
 *
 * Parts must be fully contained within a file, however there can be
 * multiple parts in a single file. On the other hand, messages can
 * cross file boundaries.
 *
 * This code will output PGP messages in a stream of input "files"
 * wherever the first part of the message came in the stream. In a
 * multipart message, this will require the least amount of buffering
 * since buffering is only required when pieces come out of order.
 * This can also handle the degenerate cases of interleaved messages,
 * although that requires possibly large amounts of buffering.
 * That case happens rarely enough that the resource requirement is
 * not onsidered a problem.
 *
 * A picture best describes this behavior:
 *
 *  W1          W2   X1     X2      X3   Y1      Y2      Y3   Z1    Z2
 * |  |   A2   |  | |  | B |  | A1 |  | |  | C2 |  | C1 |  | |  |A3|  |
 * |  +--------+  | |  +---+  +----+  | |  +----+  +----+  | |  +--+  |
 * +--------------+ +-----------------+ +------------------+ +--------+
 *     File 1              File 2              File 3          File 4
 *                                 ^                            ^
 *                                 |   Everything is buffered   |
 *                                 +----------------------------+
 *
 * W,X,Y,Z are file header and footer text which is outside the PGP armor.
 * The numbers are used to associate where in the data stream they occur.
 *
 * A,B,C are 3 PGP messages. The numbers are the actual multipart parts
 * which may occur out of order.
 *
 * If this input stream were given to this armor parser, the following
 * output would occur:
 *
 *  | W1 ~ W2 | X1 B X2 A X3 | Y1 ~ Y2 C Y3 | Z1 ~ Z2 |
 *
 * Where:	| == A file separation annotation (or multiple annotations)
 *			~ == An armor annotation (an armor part occured here)
 *			W,X,Y,Z == The exact unencrypted text that arrived in the
 *			           input.
 *			A,B,C == The full messages, wrapped in "PGP data" annotations,
 *			         which will be sent to a binary parser for decryption.
 *
 * As you can see, the messages are output in the order B, A, C, each
 * message occurring in the place in the unenecrpted text stream where
 * part 1 is located. Other parts are replaced with an annotation that just
 * notes the deletion.
 *
 * While decryting message A, all the data between A1 and A3 (including
 * annotations) needs to be buffered. In the usual case where the text
 * between parts is short (e-mail headers, mostly) and there aren't
 * multiple interleaved parts, not very much needs to be buffered.
 * Not much can be done to improve the worst case.
 */

#define kPGPPrsAscCmdBufSize	4096

#define DEARMORMAGIC	0xdea4304

/* List of commands */
#define CMD_WRITE	1
#define CMD_ANNOTATE	2

#define LINE_LEN	256	/* 256 bytes is MORE than Ascii armorsize! */

struct Message;			/* forward reference */

struct MsgPart {
	unsigned num;		/* Which part number is this? */
	struct PgpPipeline *mod; /* Pointer to the join module for this part */
	struct PgpPipeline *text; /* clearsigned: the text goes here */
	struct PgpPipeline *sig; /* clearsigned: the sig goes here */
	struct Message *msg;	/* What message does this belong to? */
	struct MsgPart *next;	/* Pointer to the next part */
	byte first;		/* Is this the first section left to do? */
	byte done;		/* Is this part complete? */
};

struct Message {
	char *name;		/* The name of this message */
	unsigned size;		/* How many parts does this have, if known */
	struct PgpPipeline **tail; /* Tail pointer for this message */
	struct MsgPart *parts;	/* The message parts */
	struct Message *next;	/* The next message */
	int msg_number;		/* What is this message number */
	byte writing;		/* Are we writing? */
	byte foundpart1;	/* Did we find part 1? */
};

struct Context {
	struct PgpFifoDesc const *fifod;	/* Fifo Descriptor */
	struct PgpFifoContext *ann; /* Fifo to hold the saved annotations */
	struct PgpFifoContext *data; /* Fifo to hold saved non-PGP data */
	struct Message *msgs;	/* List of current messages */
	struct MsgPart *part;	/* The current message part */
	struct PgpPipeline *myself; /* Pointer to this pipeline module */
	struct PgpPipeline *tail; /* Tail pointer for rest of the pipeline */
	struct PgpUICb const *ui;
	struct PgpEnv const *env;
	void *ui_arg;
	unsigned long written;	/* Fifo delta from last command */
	unsigned long left;	/* Bytes left in fifo until next command */
	unsigned thispart;	/* This part, obtained from the PGP header */
	unsigned maxparts;	/* Max parts, obtained from the PGP header */
	int state;		/* FSM state */
	int annotation;		/* Annotation State */
	int depth_at_ann;	/* Scope depth when we sent the annotation */
	int scope_depth;	/* Count of scopes we're inside */
	char messageid[LINE_LEN]; /* Message ID, obtained from the PGP header*/
	byte databuf[51];	/* Space to hold raw data 48+slush */
	byte *dataptr;		/* Pointer into the data buffer */
	unsigned datalen;	/* length of data buffer */
	byte armorline[LINE_LEN]; /* line of armor */
	byte *armorptr;		/* pointer into armorline */
	unsigned armorlen;	/* length of line */
	unsigned long crc;	/* CRC Checksum */
	byte hashlist[255];	/* List of hashes */
	byte hashlen;		/* Length of the list of hashes */
	byte cmdarg[kPGPPrsAscCmdBufSize];	/* buffered command */
	unsigned cmdlen;	/* length of buffered command */
	int msg_count;		/* A count of the number of messages */
	byte command;		/* the command that is buffered */
	byte buffering;		/* A flag -- are we buffering everything? */
	byte eol;		/* Our readLine EOL flag */
	byte eob;		/* End of Buffer flag (from readLine) */
	byte expectcrc;		/* Are we expecting the CRC line next? */
	byte crlf;		/* The type of crlf we have */
	byte saved_crlf;	/* Save it off... */
	byte firstheader;	/* True if looking for 1st header line */
	byte doublespace;	/* True if every other line is blank */
#if MIMEPARSE
	byte mime_signed;	/* Dealing with a PGP/MIME clearsigned message */
	byte no_mime_headers;		/* Don't have mime headers, look in body */
	byte mime_boundary[256];	/* MIME boundary with "--" */
	int mime_bound_len;	/* strlen(mime_boundary) */
#endif
};

static char dearmorTable[256];
static int inited = 0;

/* forward references */
static int writeMessage (struct Context *ctx, struct Message *msg);
static int sendAnnotate (struct Context *ctx, struct PgpPipeline *origin,
			int type, byte const *string, size_t size);
static int flushMessage (struct Context *ctx, struct Message *msg);

/*
 * Close this part.  This makes sure that this message is being written
 * before it does this.  It will call a sizeAdvise (0) on the join
 * module and then possibly a teardown, too.
 */
static int
closePart (struct MsgPart *part)
{
	int error;

	if (! part->msg->writing)
		return 0;

	if (part->sig) {
		error = part->sig->sizeAdvise (part->sig, 0);
		if (error)
			return error;
	}

	if (part->mod) {
		error = part->mod->sizeAdvise (part->mod, 0);
		if (error)
			return error;
	}

	if (part->text) {
		error = part->text->sizeAdvise (part->text, 0);
		if (error)
			return error;
	}

	part->done = 2;
	return 0;
}

/*
 * Free a message part; this tears down the join module, which must be
 * unhooked from the pipeline first.
 */
static void
freePart (struct MsgPart *part)
{
	struct MsgPart **partp = &part->msg->parts;

	if (part->mod)
		part->mod->teardown (part->mod);
	if (part->text)
		part->text->teardown (part->text);
	if (part->sig)
		part->sig->teardown (part->sig);

	while (*partp) {
		if (*partp == part) {
			*partp = part->next;
			memset (part, 0, sizeof (*part));
			pgpMemFree (part);
			return;
		}
	}
	/* no match found */
	return;
}

/*
 * We are done with the current part, so mark it as done.  We should
 * also close this part if we are writing this message and either
 * there is a next part or this is the last part.  Then try to flush
 * the message, in case we have anything buffered.  Finally, clear the
 * part from the context so we know we don't have a current part.
 */
static int
donePart (struct Context *ctx)
{
	struct MsgPart *part = ctx->part;
	int error;

	pgpAssert (part);

	part->done = 1;
	if (part->msg->writing) {
		if (part->next || part->num == part->msg->size) {
			error = closePart (part);
			if (error)
				return error;
		}
		error = flushMessage (ctx, part->msg);
		if (error)
			return error;
	}

	ctx->part = NULL;
	return 0;
}

/*
 * We're going to start a new part.  Therefore we need to pass in the
 * message that it is a part of, and then create the new part or
 * return the pre-created part.  If we ask for a part number in this
 * message that is beyond the highest number in the list, then we
 * create that many more parts up to the number passed in.
 *
 * Should we close old parts if we can?  I don't know, yet.  If we've
 * already written out part one and we just got part two, should I close
 * part one here?  I don't know, yet.
 */
static struct MsgPart *
getPart (struct Context *ctx, struct Message *msg, unsigned num)
{
	struct MsgPart *temp = NULL, **part = &msg->parts;
	struct PgpPipeline *last = NULL;
	unsigned highest = 0;

	/* Initialize the CRC counter! */
	ctx->crc = CRC_INIT;

	while (*part) {
		if (num == (*part)->num)
			return *part;
		highest = (*part)->num;
		last = (*part)->mod;
		part = &(*part)->next;
	}

	/* We need to allocate a bunch of parts */
	for (highest++; highest <= num; highest++) {
		temp = (struct MsgPart *)pgpMemAlloc (sizeof (*temp));
		if (!temp)
			return NULL;

		memset (temp, 0, sizeof (*temp));
		temp->num = highest;
		temp->msg = msg;

		if (last) {
			temp->mod = pgpJoinAppend (last);
		} else {
			msg->tail = pgpJoinCreate (&(temp->mod), ctx->fifod);
			temp->first = 1;
			msg->tail = pgpParseBinCreate (msg->tail, ctx->env);
			/*
			 * Binary parser may add modules after itself, and in some
			 * error recovery situations they are still there when we try
			 * to close things.  Create a copy module to act as a stable
			 * predecessor to context->tail.
			 */
			msg->tail = pgpCopyModCreate (msg->tail);

			/* connect the join module to the rest of the pipe */
			if (msg->tail)
				*(msg->tail) = ctx->tail;
		}

		if (!temp->mod) {
			pgpMemFree (temp);
			return NULL;
		}

		*part = temp;
		last = temp->mod;
		part = &temp->next;
	}

	return temp;
}

/*
 * We have a part of a message "name" of size "size" -- lets try to
 * find the message that this is a part of, and either return that
 * message pointer or create a new one and return that.  If name is
 * non-NULL, then it will compare the name passed in with older names
 * (i.e., a messageID).  If name is NULL, then it will compare sizes
 * for old-style multipart armor.  Do not return messages that have
 * only one part.
 *
 * This means that you can only have one old-style multipart message
 * going of any particular size (number of parts). I don't consider
 * this a big problem, since interleaved messages are rarely a
 * problem.  Out-of-order messages, on the other hand.....
 */
static struct Message *
getMessage (struct Context *ctx, char const *name, unsigned size)
{
	struct Message **msg = &ctx->msgs;
	char *newname;

	/* Just remove name if it is a NULL string */
	if (name && !*name)
		name = NULL;

	if (!name && !size)
		return NULL;

	while (*msg) {
		if (name && (*msg)->name && !memcmp (name, (*msg)->name,
			strlen (name))) {
			/* Update the message size if we know it */
			if (!(*msg)->size && size)
				(*msg)->size = size;
			return *msg;
		}
		if (!name && !(*msg)->name && size == (*msg)->size &&
			size != 1)
			return *msg;
		msg = &((*msg)->next);
	}

	*msg = (struct Message *)pgpMemAlloc (sizeof (**msg));
	if (! *msg)
		return NULL;

	memset (*msg, 0, sizeof (**msg));
	if (name) {
		newname = (char *)pgpMemAlloc (strlen (name) + 1);
		if (!newname) {
			pgpMemFree (*msg);
			*msg = NULL;
			return NULL;
		}
		memcpy (newname, name, strlen (name) + 1);
	} else
		newname = NULL;

	(*msg)->name = newname;
	(*msg)->size = size;
	(*msg)->msg_number = ++(ctx->msg_count);

	return *msg;
}

/*
 * We're done with this message so we can remove it from our queue
 * of pending messages.  Free any remaining message parts in the process.
 * We can also turn buffering off now.
 */
static void
freeMessage (struct Context *ctx, struct Message *msg)
{
	struct Message **msgp = &ctx->msgs;
	struct MsgPart *part, *temp;

	while (*msgp) {
		if (*msgp == msg) {
			*msgp = msg->next;
			part = msg->parts;
			if (msg->tail)
				/* Disconnect join module */
				*(msg->tail) = NULL;
			while (part) {
				temp = part;
				part = part->next;
				freePart (temp);
			}
			if (msg->name)
				pgpMemFree (msg->name);
			ctx->buffering = 0;
			memset (msg, 0, sizeof (*msg));
			pgpMemFree (msg);

			return;
		}
	}
	/* no match found */
	return;
}

/*
 * Buffer a command at the current spot in the data stream.  This is only
 * called when ctx->buffering is true.  What it does is find the delta
 * of this command in the data fifo from the last command in order to replay
 * the commands at the proper place.  It saves off context->written as
 * the offset and then resets the value to 0.
 *
 * The return value is 0 on success or an error code.
 *
 * Command Byte Syntax: <offset><cmd><arglen><arg>
 */
static int
bufferCommand (struct Context *ctx, byte cmd, const byte *arg, unsigned arglen)
{
	/* Make sure the command argument fits the buffer size */

⌨️ 快捷键说明

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