📄 pgpprsasc.c
字号:
/*
* 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?
*
* Written by: Derek Atkins <warlord@MIT.EDU>
*
* $Id: pgpPrsAsc.c,v 1.50.6.1 1999/06/03 23:26:00 heller Exp $
*/
#include "pgpConfig.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#ifndef MIMEPARSE
#define MIMEPARSE 1
#endif
#include "pgpDebug.h"
#include "pgpCharMap.h" /* for charMapIdentity */
#include "pgpCopyMod.h"
#include "pgpCRC.h"
#include "pgpPrsAsc.h"
#include "pgpRadix64.h"
#include "pgpAnnotate.h"
#include "pgpFIFO.h"
#include "pgpFileType.h"
#include "pgpHashPriv.h"
#include "pgpJoin.h"
#include "pgpMem.h"
#include "pgpPrsBin.h"
#include "pgpEnv.h"
#include "pgpErrors.h"
#include "pgpPipeline.h"
#include "pgpSplit.h"
#include "pgpTextFilt.h"
#include "pgpUsuals.h"
#include "pgpVerifyRa.h"
#include "pgpContext.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 decrypting 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! */
/* Some explanations of the various pipeline pointers (as usual, the
* "tail" pointers are PGPPipeline **, that is, pointers to the "next"
* pointer in the relevant object):
*
* context->tail Points at next stage set up by our caller, usually
* an annotation reader. Downstream of msg->tail.
* context->myself Points at this very pipeline module.
* msg->tail Points at a copy module which precedes context->tail.
* Part of downstream pipeline of part->mod.
* part->mod Points at the 1st-nth stage of a join input, which leads
* to a binary parser, 1 stage for each part. Now NULL for
* clearsigned messages.
* part->text Used for clearsigned text, points at a split which
* feeds into both the sig verifier (via a textfilt) and
* into the main msg->tail output (anno reader). (Used to
* point to 2nd stage of join input, where part->mod pointed
* at first stage. This caused unnecessary buffering.)
* and we pass the raw data to context->tail.
* part->sig Used for clearsigned signatures, points at a binary
* parser that feeds into a sig verifier.
*/
typedef struct Message Message;
typedef struct MsgPart MsgPart;
struct MsgPart {
PGPContextRef cdkContext;
unsigned num; /* Which part number is this? */
PGPPipeline *mod; /* Pointer to the join module for this part */
PGPPipeline *text; /* clearsigned: the text goes here */
PGPPipeline *sig; /* clearsigned: the sig goes here */
Message *msg; /* What message does this belong to? */
MsgPart *next; /* Pointer to the next part */
PGPByte first; /* Is this the first section left to do? */
PGPByte done; /* Is this part complete? */
DEBUG_STRUCT_CONSTRUCTOR( MsgPart )
};
struct Message {
PGPContextRef cdkContext;
char *name; /* The name of this message */
unsigned size; /* How many parts does this have, if known */
PGPPipeline **tail; /* Tail pointer for this message */
MsgPart *parts; /* The message parts */
Message *next; /* The next message */
int msg_number; /* What is this message number */
PGPByte writing; /* Are we writing? */
PGPByte foundpart1; /* Did we find part 1? */
DEBUG_STRUCT_CONSTRUCTOR( Message )
} ;
typedef struct PrsAscContext {
PGPPipeline pipe;
PGPFifoDesc const *fifod; /* Fifo Descriptor */
PGPFifoContext *ann; /* Fifo to hold the saved annotations */
PGPFifoContext *data; /* Fifo to hold saved non-PGP data */
Message *msgs; /* List of current messages */
MsgPart *part; /* The current message part */
PGPPipeline *myself; /* Pointer to this pipeline module */
PGPPipeline *tail; /* Tail pointer for rest of the pipeline */
PGPUICb const *ui;
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*/
PGPByte databuf[65]; /* Space to hold raw data 60+slush */
PGPByte *dataptr; /* Pointer into the data buffer */
unsigned datalen; /* length of data buffer */
PGPByte armorline[LINE_LEN]; /* line of armor */
PGPByte *armorptr; /* pointer into armorline */
unsigned armorlen; /* length of line */
unsigned long crc; /* CRC Checksum */
PGPByte hashlist[255]; /* List of hashes */
PGPByte hashlen; /* Length of the list of hashes */
PGPByte cmdarg[kPGPPrsAscCmdBufSize]; /* buffered command */
unsigned cmdlen; /* length of buffered command */
int msg_count; /* A count of the number of messages */
PGPByte command; /* the command that is buffered */
PGPByte buffering; /* A flag -- are we buffering everything? */
PGPByte eol; /* Our readLine EOL flag */
PGPByte eob; /* End of Buffer flag (from readLine) */
PGPByte expectcrc; /* Are we expecting the CRC line next? */
PGPByte noarmorblanks; /* Armor data starts on next line after BEGIN */
PGPLineEndType crlf; /* The type of crlf we have */
PGPByte saved_crlf; /* Save it off... */
PGPSize bytesread; /* Number of bytes read, total */
PGPSize prevlineoff; /* bytesread value at start of last line */
PGPSize sectoff; /* bytesread value at start of last section */
size_t skipPrefixLength; /* Number of chars preceding -----BEGIN PGP... */
PGPByte skipPrefix[LINE_LEN]; /* Chars preceding -----BEGIN PGP... */
PGPByte crcendline; /* CRC at end of last armor line */
PGPByte passthrough; /* Passing armor or cleartext data unchanged */
PGPByte passthroughcleartext; /* Request passthrough on cleartext */
PGPByte passthroughkey; /* Request passthrough on key blocks */
#if MIMEPARSE
PGPByte mime_signed; /* Dealing with a PGP/MIME clearsigned message */
PGPByte no_mime_headers; /* Don't have mime headers, look in body */
PGPByte mime_boundary[256]; /* MIME boundary with "--" */
int mime_bound_len; /* strlen(mime_boundary) */
#endif
DEBUG_STRUCT_CONSTRUCTOR( PrsAscContext )
} PrsAscContext;
static char const * sDearmorTable = NULL; /* enforce 'const' access */
/* forward references */
static PGPError writeMessage (PrsAscContext *ctx, Message *msg);
static PGPError sendAnnotate (PrsAscContext *ctx, PGPPipeline *origin,
int type, PGPByte const *string, size_t size);
static PGPError flushMessage (PrsAscContext *ctx, Message *msg);
/* Case-insensitive compare routine */
static int
strncmp_ignorecase (const char *str1, const char *str2, int len)
{
while (len--) {
char c1 = tolower(*str1++);
char c2 = tolower(*str2++);
if (c1 != c2) {
return (int)c1 - (int)c2;
}
}
return 0;
}
/*
* 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 PGPError
closePart (MsgPart *part)
{
PGPError error;
if (! part->msg->writing)
return kPGPError_NoErr;
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 kPGPError_NoErr;
}
/*
* Free a message part; this tears down the join module, which must be
* unhooked from the pipeline first.
*/
static void
freePart (MsgPart *part)
{
MsgPart **partp = &part->msg->parts;
PGPContextRef cdkContext;
pgpAssertAddrValid( *partp, MsgPart );
cdkContext = (*partp)->cdkContext;
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;
pgpClearMemory( part, sizeof (*part));
pgpContextMemFree( cdkContext, 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 PGPError
donePart (PrsAscContext *ctx)
{
MsgPart *part = ctx->part;
PGPError 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( kPGPError_NoErr );
}
/*
* 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 MsgPart *
getPart (PrsAscContext *ctx, Message *msg, unsigned num)
{
MsgPart *temp = NULL, **part = &msg->parts;
PGPPipeline *last = NULL;
unsigned highest = 0;
PGPContextRef cdkContext;
pgpAssert( IsntNull( ctx ) && IsntNull( ctx->myself ) );
cdkContext = ctx->myself->cdkContext;
/* 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 = (MsgPart *)pgpContextMemAlloc( cdkContext,
sizeof (*temp), kPGPMemoryMgrFlags_Clear);
if (!temp)
return NULL;
temp->num = highest;
temp->msg = msg;
temp->cdkContext = cdkContext;
if (last) {
temp->mod = pgpJoinAppend (last);
} else {
msg->tail = pgpJoinCreate ( cdkContext, &(temp->mod), ctx->fifod);
temp->first = 1;
msg->tail = pgpParseBinCreate ( cdkContext, msg->tail, ctx->env,
ctx->ui, ctx->ui_arg );
/*
* 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 ( cdkContext, msg->tail);
/* connect the join module to the rest of the pipe */
if (msg->tail)
*(msg->tail) = ctx->tail;
}
if (!temp->mod) {
pgpContextMemFree( cdkContext, 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 Message *
getMessage (PrsAscContext *ctx, char const *name, unsigned size)
{
Message **msg = &ctx->msgs;
char *newname;
PGPContextRef cdkContext = ctx->pipe.cdkContext;
/* Just remove name if it is a NULL string */
if (name && !*name)
name = NULL;
if (!name && !size)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -