pgparmor.c

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

C
1,332
字号
	if (context->scope_depth)
		return 0;

	/* Then compute maxparts */
	if (!context->maxparts) {
		pgpAssert(context->armorlines);

		/* Add buffered bytes */
		total = bytes + pgpFifoSize (context->fd, context->fifo);
		/* Convert to lines */
		total = (total + ARMOR_LINE_INPUT-1) / ARMOR_LINE_INPUT;

		/* Add already-output lines (> PGPVERSION_2_6) */
		total += context->lineno;

		/* Convert to parts */
		total = (total + context->armorlines-1) / context->armorlines;

		/* Add already-emitted parts */
		total += context->thispart - (context->thispart != 0);

		context->maxparts = (unsigned)total;
	}
	if (bytes)
		return 0;	/* Stop futzing with non-zero sizeAdvises */

	/* The real end - this is it */
	context->at_eof = 1;

	/* Flush out any buffered data */
	error = armorFlushFifo (myself, (size_t)-1);
	if (error)
		return error;

	/* Force a write out of last partial line. */
	error = armorWritePartial (myself);
	if (error)
		return error;

	if (context->clearsign) {
		/* Clear out the clearsign buffer, if we have it. */
		if (context->linebuf) {
			pgpFifoWrite (context->fd, context->header,
			              context->input, context->linebuf);
			context->linebuf = 0;
		}
		/*
		 * If clearsign input ended with '\r', will be hashed with
		 * '\r\n' but the output file will be missing the '\n'.
		 * Add it here.
		 */
		if (context->state == 2) {
			pgpFifoWrite (context->fd, context->header,
				      (const unsigned char *) "\n", 1);
			context->state = 0;
		}
	} else {
		if (!context->didfooter)
			armorMakeFooter (context);

		error = armorFlushPending (myself);
		if (error)
			return error;
	}

	/* Finally, the downstream SizeAdvise */
	return context->tail->sizeAdvise (context->tail, 0);
}

/* Push anything available through */
static int
Flush (struct PgpPipeline *myself)
{
	struct Context *context = (struct Context *)myself->priv;
	int error;

	error = armorFlushPending (myself);
	if (error)
		return error;
	return context->tail->flush (context->tail);
}

/* Straightforward deallocate & destroy */
static void
Teardown (struct PgpPipeline *myself)
{
	struct Context *context;

	pgpAssert (myself);
	pgpAssert (myself->magic == ARMORMAGIC);

	context = (struct Context *)myself->priv;
	pgpAssert (context);

	if (context->tail)
		context->tail->teardown (context->tail);

	pgpFifoDestroy (context->fd, context->fifo);
	pgpFifoDestroy (context->fd, context->header);
	if (context->messageid)
		pgpMemFree (context->messageid);
	memset (context, 0, sizeof (*context));
	pgpMemFree (context);
	memset (myself, 0, sizeof (*myself));
	pgpMemFree (myself);
}

/*
 * Add a "Hash: foo, bar, baz" header to the given FIFO if needed.
 * it is not needed if there are no hashes, or there is only MD5.
 */
static void
armorWriteHashHeader (struct PgpFifoDesc const *fd,
                      struct PgpFifoContext *header,
                      byte const *hashlist, unsigned hashlen)
{
	int dohash = 0;
	struct PgpHash const *hash;

	if (!hashlen || (hashlen == 1 && *hashlist == PGP_HASH_MD5))
		return;
	pgpFifoWrite (fd, header, (byte const *)"\nHash: ", 7);
	while (hashlen--) {
		hash = pgpHashByNumber (*hashlist++);
		if (!hash)
			continue;
		if (dohash)
			pgpFifoWrite (fd, header, (byte const *)", ", 2);
		pgpFifoWrite (fd, header,
			      (byte const *)hash->name, strlen (hash->name));
		dohash = 1;
	}
}

/*
 * The slightly different types of ASCII armoring that we do.
 */
#define ATYPE_NORMAL	0
#define ATYPE_CLEARSIG	10
#define ATYPE_SEPSIG	20
#define ATYPE_SEPSIGMSG	21
#define ATYPE_MIMESIG	30
#define ATYPE_MIMEENC	40
#define ATYPE_MIMESEPSIG 50

/*
 * The all-purpose ASCII armor pipeline module creator.
 */
static struct PgpPipeline **
armorDoCreate (struct PgpPipeline **head, struct PgpEnv const *env,
	       PgpVersion version, struct PgpFifoDesc const *fd,
	       struct PgpRandomContext const *rc, unsigned long armorlines,
	       int armortype, byte const *hashlist, unsigned hashlen)
{
	struct PgpPipeline *mod;
	struct Context *context;
	struct PgpFifoContext *fifo;
	struct PgpFifoContext *header;
	char *mid;
	byte message[24];	/* Messageid (binary) */
	int len;

	if (!head)
		return NULL;

	pgpAssert (fd);

	context = (struct Context *)pgpMemAlloc (sizeof (*context));
	if (!context)
		return NULL;
	mod = (struct PgpPipeline *)pgpMemAlloc (sizeof (*mod));
	if (!mod) {
		pgpMemFree (context);
		return NULL;
	}
	fifo = pgpFifoCreate (fd);
	if (!fifo) {
		pgpMemFree (context);
		pgpMemFree (mod);
		return NULL;
	}
	header = pgpFifoCreate (fd);
	if (!header) {
		pgpFifoDestroy (fd, fifo);
		pgpMemFree (context);
		pgpMemFree (mod);
		return NULL;
	}
	if (rc) {
		mid = (char *)pgpMemAlloc ((sizeof(message)+3)*4/3 + 1);
		if (!mid) {
			pgpFifoDestroy (fd, fifo);
			pgpFifoDestroy (fd, header);
			pgpMemFree (context);
			pgpMemFree (mod);
			return NULL;
		}
		/* Create a random message id */
		pgpRandomGetBytes (rc, message, sizeof (message));
		len = armorLine (message, sizeof(message), mid);
		mid[len] = '\0';
	} else {
		mid = NULL;
	}

	mod->magic = ARMORMAGIC;
	mod->write = Write;
	mod->flush = Flush;
	mod->sizeAdvise = SizeAdvise;
	mod->annotate = Annotate;
	mod->teardown = Teardown;
	mod->name = "ASCII Armor Write Module";
	mod->priv = context;

	memset (context, 0, sizeof (*context));
	context->outptr = context->output;
	context->armorlines = armorlines;
	context->maxparts = armorlines ? 0 : 1;	/* 0 = unknown */
	context->crc = CRC_INIT;
	context->fd = fd;
	context->fifo = fifo;
	context->header = header;
	context->messageid = mid;
	context->comment = pgpenvGetString (env, PGPENV_COMMENT, NULL, NULL);
	context->version = version;

	/* The armortype-dependent whatnot */
	if (armortype == ATYPE_CLEARSIG) {
		static char const CLRSIGN[] =
			"-----BEGIN PGP SIGNED MESSAGE-----";

		pgpFifoWrite (fd, header, (byte const *)CLRSIGN,
			      sizeof(CLRSIGN)-1);
		context->clearsign = 1;
		context->armorlines = 0;

		armorWriteHashHeader (fd, header, hashlist, hashlen);
		pgpFifoWrite (fd, header, (byte const *)"\n\n", 2);
	} else if (armortype == ATYPE_MIMESIG) {
		pgpFifoWrite (fd, header, (byte const *)MIMETOPHDR,
			      strlen(MIMETOPHDR));
		context->clearsign = 1;
		context->armorlines = 0;
		context->pgpmime = PGPMIMESIG;
	} else if (armortype == ATYPE_SEPSIG) {
		context->blocktype = "SIGNATURE";
	} else if (armortype == ATYPE_SEPSIGMSG) {
		context->blocktype = "MESSAGE";
	} else if (armortype == ATYPE_MIMESEPSIG) {
		context->blocktype = "MESSAGE";
		context->pgpmime = PGPMIMESIG;
		context->armorlines = 0;
	} else if (armortype == ATYPE_MIMEENC) {
		context->pgpmime = PGPMIMEENC;
		context->armorlines = 0;
	}

	context->tail = *head;
	*head = mod;
	return &context->tail;
}

/*
 * Create a generic ASCII armor output filter.
 */
struct PgpPipeline **
pgpArmorWriteCreate (struct PgpPipeline **head, struct PgpEnv const *env,
		     struct PgpFifoDesc const *fd,
		     struct PgpRandomContext const *rc, PgpVersion version,
		     byte armortype)
{
	int type = 0;
	unsigned long armorlines;
	int error;

	if (!head)
		return NULL;

	if (armortype == PGP_ARMOR_NORMAL) {
		if (pgpenvGetInt (env, PGPENV_PGPMIME, NULL, &error)) {
			type = ATYPE_MIMEENC;
			rc = NULL; /* prevents messageid appearing */
		} else {
			type = ATYPE_NORMAL;
		}
	} else if (armortype == PGP_ARMOR_SEPSIG) {
		type = ATYPE_SEPSIG;
	} else if (armortype == PGP_ARMOR_SEPSIGMSG) {
		type = ATYPE_SEPSIGMSG;
	} else {
		return NULL;
	}

	armorlines = pgpenvGetInt (env, PGPENV_ARMORLINES, NULL, NULL);


	return (armorDoCreate (head, env, version, fd, rc, armorlines,
			       type, NULL, 0));
}

/*
 * Create a clearsigned armored output.  This takes two tail pointers,
 * the text being signed (which will be lightly quoted on output) and
 * the signature (which will be ASCII-armored).  We build an ASCII armor
 * pipeline module for each (with different settings), and join them together.
 */
struct PgpPipeline **
pgpArmorWriteCreateClearsig (struct PgpPipeline **texthead,
			     struct PgpPipeline **signhead,
			     struct PgpEnv const *env,
			     struct PgpFifoDesc const *fd,
			     PgpVersion version, byte *hashlist,
			     unsigned hashlen)
{
	struct PgpPipeline *txthead = NULL, *sighead = NULL;
	struct PgpPipeline **joinhead, **sigtail, **tail;
	struct Context *context;

	if (!texthead || !signhead)
		return NULL;

	joinhead = armorDoCreate (&txthead, env, version, fd, NULL, 0,
				  ATYPE_CLEARSIG, hashlist, hashlen);
	if (!joinhead)
		return NULL;

	tail = pgpJoinCreate (joinhead, fd);
	if (!tail) {
		txthead->teardown (txthead);
		return NULL;
	}

	sigtail = armorDoCreate (&sighead, env, version, fd, NULL, 0,
				 ATYPE_SEPSIG, NULL, 0);
	if (!sigtail) {
		txthead->teardown (txthead);
		return NULL;
	}

	/* Add the charset used when generating the clearsigned message */
	context = (struct Context *)sighead->priv;
	pgpAssert (context);
	context->charset = pgpenvGetString (env, PGPENV_CHARSET, NULL, NULL);

	*sigtail = pgpJoinAppend (*joinhead);
	if (!*sigtail) {
		txthead->teardown (txthead);
		sighead->teardown (sighead);
		return NULL;
	}

	pgpJoinBuffer (*sigtail, (byte *)"\n", 1);

	*texthead = txthead;
	*signhead = sighead;
	return tail;
}

/*
 * Create a multipart/signed output.  This takes two tail pointers,
 * the text being signed (which will be lightly quoted on output) and
 * the signature (which will be ASCII-armored).  We build an ASCII armor
 * pipeline module for each (with different settings), and join them together.
 */
struct PgpPipeline **
pgpArmorWriteCreatePgpMimesig (struct PgpPipeline **texttail,
			     struct PgpPipeline **signtail,
			     struct PgpEnv const *env,
			     struct PgpFifoDesc const *fd,
			     PgpVersion version, byte *hashlist,
			     unsigned hashlen)
{
	struct PgpPipeline *txthead = NULL, *sighead = NULL;
	struct PgpPipeline **joinhead, **sigtail, **tail;
	struct PgpPipeline **splithead, **splittail;

	if (!texttail || !signtail)
		return NULL;

	splithead = armorDoCreate (&txthead, env, version, fd, NULL, 0,
				  ATYPE_MIMESIG, hashlist, hashlen);
	if (!splithead)
		return NULL;

	/* Create split to take output from clearmime armor module */
	joinhead = pgpSplitCreate(splithead);

	/* Set second split output to go to signing pipeline */
	splittail = pgpSplitAdd (*splithead);
	*splittail = *texttail;

	tail = pgpJoinCreate (joinhead, fd);
	if (!tail) {
		txthead->teardown (txthead);
		return NULL;
	}

	sigtail = armorDoCreate (&sighead, env, version, fd, NULL, 0,
				 ATYPE_MIMESEPSIG, NULL, 0);
	if (!sigtail) {
		txthead->teardown (txthead);
		return NULL;
	}

	*sigtail = pgpJoinAppend (*joinhead);
	if (!*sigtail) {
		txthead->teardown (txthead);
		sighead->teardown (sighead);
		return NULL;
	}

	pgpJoinBuffer (*joinhead, (byte *)MIMESIGHDR, strlen(MIMESIGHDR));
	if (!hashlen) {
		pgpJoinBuffer (*joinhead, (byte *)MIMEMIC, strlen(MIMEMIC));
		pgpJoinBuffer (*joinhead, (byte *)MIMEDFLTMIC,
				strlen(MIMEDFLTMIC));
	} else {
		while (hashlen--) {
			struct PgpHash const *hash = NULL;
			unsigned i, len;
			char hashname[30]; /* lower case name */

			hash = pgpHashByNumber (*hashlist++);
			pgpAssert(hash);
			len = strlen(hash->name);
			pgpAssert (len < sizeof(hashname));
			pgpJoinBuffer (*joinhead, (byte *)MIMEMIC,
				       strlen(MIMEMIC));
			for (i=0; i<len; ++i)
				hashname[i] = tolower(hash->name[i]);
			pgpJoinBuffer (*joinhead, (byte *)hashname,
				       len);
			pgpJoinBuffer (*joinhead, (byte *)";", 1);
		}
	}
	pgpJoinBuffer (*joinhead, (byte *)MIMETOPBOUND, strlen(MIMETOPBOUND));

	pgpJoinBuffer (*sigtail, (byte *)MIMEMIDBOUND, strlen(MIMEMIDBOUND));

	*texttail = txthead;
	*signtail = sighead;
	return tail;
}

⌨️ 快捷键说明

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