📄 pgpprsbin.c
字号:
PrsBinContext *ctx;
size_t len;
PGPByte const *p;
size_t size0 = size;
pgpAssert (myself);
pgpAssert (myself->magic == PARSERMAGIC);
ctx = (PrsBinContext *)myself->priv;
pgpAssert (ctx);
pgpAssert (ctx->tail);
pgpAssert (error);
pgpAssert (!size || !ctx->eof);
/* Make sure nothing confusing can happen here! */
pgpAssert(!ctx->needcallback);
/* Do NOT complain on truncation. */
ctx->input.silent_trunc = 1;
/* No error until told otherwise */
*error = kPGPError_NoErr;
switch (ctx->state) {
case 0: /* Get packet header byte */
if (!size)
return 0;
/* We know it's a literal packet, so no worries. */
(void)inputStart(&ctx->input, *buf);
buf++;
size--;
ctx->state++;
/* FALLTHROUGH */
case 1: /* Get internal header */
len = inputMerge(&ctx->input, buf, size, 2, error);
buf += len;
size -= len;
if (*error)
break;
p = inputPeek(&ctx->input, NULL, 0, &len);
if (len < 2) {
if (!inputFinished(&ctx->input.head))
break;
} else {
len = inputMerge(&ctx->input, buf, size, 6+p[1],
error);
buf += len;
size -= len;
if (*error)
break;
if (inputMerged(&ctx->input) < (size_t)6+p[1]) {
if (!inputFinished(&ctx->input.head))
break;
}
}
/* We've got as much as we need */
ctx->state++;
myself->write = DoWriteNext;
size -= DoWriteNext (myself, buf, size, error);
break;
default:
pgpAssert(0);
}
return size0-size;
}
/*
* This function just does a little bit of trivial initialization,
* including setting the state to 0, and then falls through to
* parseSignedLiteralMagic. The Do functions can be called from a
* variety of states, due to the way they are set up from callbacks
* that may be called from a variety of states, so they can't depend on
* the ctx->state. Thus, the need for this little wrapper function.
*/
static size_t
DoSignedLiteralMagic (PGPPipeline *myself, PGPByte const *buf, size_t size,
PGPError *error)
{
PrsBinContext *ctx;
pgpAssert (myself);
pgpAssert (myself->magic == PARSERMAGIC);
ctx = (PrsBinContext *)myself->priv;
pgpAssert (ctx);
pgpAssert (ctx->tail);
pgpAssert (error);
pgpAssert (!size || !ctx->eof);
/* Make sure nothing confusing can happen here! */
pgpAssert(!ctx->needcallback);
/* Do NOT complain on truncation. */
ctx->input.silent_trunc = 1;
/* Reset state for parseSignedLiteralMagic */
ctx->state = 0;
myself->write = parseSignedLiteralMagic;
return parseSignedLiteralMagic(myself, buf, size, error);
}
/*
* Pass through the full ciphertext of the current packet, headers and
* all, to the tail module
*/
static size_t
DoPassthrough (PGPPipeline *myself, PGPByte const *buf, size_t size,
PGPError *error)
{
PrsBinContext *ctx;
size_t size0 = size;
PGPByte const *p;
size_t len;
PGPPipeline *tail;
pgpAssert (myself);
pgpAssert (myself->magic == PARSERMAGIC);
ctx = (PrsBinContext *)myself->priv;
pgpAssert (ctx);
tail = ctx->tail;
pgpAssert (tail);
pgpAssert (error);
pgpAssert (!size || !ctx->eof);
*error = kPGPError_NoErr;
/* empty out the buffered data and then the packet */
for (;;) {
p = inputRawPeek(&ctx->input, buf, size, &len);
if (!len)
break;
len = tail->write (tail, p, len, error);
len = inputRawSeek (&ctx->input, buf, size, len);
buf += len;
size -= len;
if (*error)
return size0-size;
}
/* If that's the end of this packet, continue with the next. */
if (inputFinished (&ctx->input.head)) {
/* End of input */
myself->write = nextScope;
size -= nextScope (myself, buf, size, error);
}
return size0-size;
}
/*
* Tear down the pipeline connected to our tail for the processing of the
* current packet. This is the pipeline starting with ctx->tail and
* ending at *ctx->end. Note that myself may be zero length, i.e.
* ctx->end == &ctx->tail!
*/
static void
parsePipelineTeardown (PrsBinContext *ctx)
{
PGPPipeline *temp;
pgpAssert (ctx->end);
/*
* End the pipeline I created, tear it down, and re-attach the
* original pipeline
*/
temp = *(ctx->end);
*(ctx->end) = NULL;
/*
* Make sure this isn't a zero-length pipeline, since ctx->end
* can point to the address of ctx->tail!
*/
if (ctx->tail)
ctx->tail->teardown (ctx->tail);
ctx->tail = temp;
ctx->end = NULL;
}
/*
* Given a candidate encryption key, verify it against the IV that we have
* stored in the buffer. If it checks, return the PGPCFBContext
* set up to decrypt the rest of the packet. Otherwise, return NULL.
*/
static PGPCFBContext *
CheckKey (
PGPContextRef cdkContext,
PrsBinContext *ctx,
PGPByte const *string,
size_t size,
PGPError *error
)
{
PGPByte buf[MAXIVLEN+2];
PGPCFBContext *cfb;
PGPCipherVTBL const *cipher;
PGPSize ivlen;
unsigned char const *p;
size_t len;
if (!size) {
*error = kPGPError_BadKeyLength; /* Um, I guess? */
return (PGPCFBContext *)0;
}
cipher = pgpCipherGetVTBL ( (PGPCipherAlgorithm)string[0]);
if (!cipher) {
*error = kPGPError_BadCipherNumber;
return (PGPCFBContext *)0;
}
if (size != cipher->keysize+1) {
*error = kPGPError_BadKeyLength;
return (PGPCFBContext *)0;
}
cfb = pgpCFBCreate ( PGPGetContextMemoryMgr( cdkContext ), cipher);
if (!cfb) {
*error = kPGPError_OutOfMemory;
return (PGPCFBContext *)0;
}
ivlen = pgpCFBGetBlockSize( cfb );
p = inputPeek(&ctx->input, NULL, 0, &len);
if (len < ivlen+2) {
PGPFreeCFBContext (cfb);
*error = kPGPError_CantDecrypt;
return (PGPCFBContext *)0;
}
/* Set up with zero IV, decrypt first ivlen+2 bytes */
PGPInitCFB (cfb, string+1, NULL);
pgpCFBDecryptInternal (cfb, p, ivlen+2, buf);
if (buf[ivlen] != buf[ivlen-2] || buf[ivlen+1] != buf[ivlen-1]) {
PGPFreeCFBContext (cfb);
*error = kPGPError_CantDecrypt;
return (PGPCFBContext *)0;
}
/* Advance pointer to skip the bytes we've used */
ctx->input.bufptr += ivlen+2;
if (ctx->input.bufptr != ctx->input.bufend)
ctx->nopurge = TRUE;
#if 0
/* Only do sync with small block ciphers */
if (pgpCFBGetBlockSize( cfb ) <= 8)
#endif
PGPCFBSync (cfb);
*error = kPGPError_NoErr;
return cfb;
}
/*
* Process one of the incoming annotations that's expected in response to
* one of our own annotations. These can happen either during the
* ctx->tail->annotate() call, or after that call has returned an error
* to the top level, which makes the call in turn. Either way, we have
* to change state appropraitely.
*
* Currently, there are 4 things that can be done with any given packet:
* - Eat it silently. No data will be emitted before the end scope
* annotation.
* - Pass it through as ciphertext.
* - Decode it, and pass the body through as plaintext. The body is *not*
* parsed further.
* - Decode it and parse it recursively.
*
* The latter two options depend on the type of packet we're inside, as
* recorded in the ctx->end_scope variable. They do some special
* processing setting up a pipeline to do the decoding, then everyone
* appends another parser to the chain and sets things up to write the
* packet body to the decoding pipe.
*/
static PGPError
ProcessCallback (PGPPipeline *myself, int type,
PGPByte const *string, size_t size)
{
PrsBinContext *ctx = (PrsBinContext *)myself->priv;
PGPPipeline *oldhead;
PGPCFBContext *cfb;
PGPError error = kPGPError_NoErr;
PGPContextRef cdkContext;
PGPMemoryMgrRef memoryMgr = NULL;
pgpAssertAddrValid( myself, PGPPipeline );
cdkContext = myself->cdkContext;
memoryMgr = PGPGetContextMemoryMgr( cdkContext );
pgpAssert(ctx->needcallback); /* Maybe a less nasty failure? */
pgpAssert(!ctx->end); /* This will change in future, but for now */
if (!ctx->end)
ctx->end = &ctx->tail;
oldhead = *ctx->end;
*ctx->end = NULL;
/* The other option is to make this illegal... */
if (ctx->end_scope == PGPANN_NONPACKET_END &&
(type == PGPANN_PARSER_PROCESS || type == PGPANN_PARSER_RECURSE))
type = PGPANN_PARSER_PASSTHROUGH;
/* Type will ONLY be one of these! */
switch (type) {
case PGPANN_PARSER_EATIT:
myself->write = DoSkip;
break;
case PGPANN_PARSER_PASSTHROUGH:
if (ctx->end_scope == PGPANN_PGPKEY_END) {
/* Passthrough is unreasonable on keys */
type = PGPANN_PARSER_PROCESS;
break;
}
ctx->end = pgpHeaderCreate ( myself->cdkContext, ctx->end);
if (!ctx->end) {
error = kPGPError_OutOfMemory;
break;
}
myself->write = DoPassthrough;
break;
case PGPANN_PARSER_PROCESS:
case PGPANN_PARSER_RECURSE:
switch (ctx->end_scope) {
case PGPANN_LITERAL_END:
if (type == PGPANN_PARSER_PROCESS &&
ctx->subtype == PGP_LITERAL_RECURSE) {
/* Decided not to recurse, fixup subtype and type */
type = PGPANN_PARSER_RECURSE;
ctx->subtype = PGP_LITERAL_TEXT;
error = oldhead->annotate (oldhead, myself,
PGPANN_LITERAL_TYPE, &ctx->subtype, 1);
}
if (type == PGPANN_PARSER_RECURSE &&
ctx->subtype == PGP_LITERAL_TEXT) {
PGPByte const *charmap;
PGPLineEndType lineEnd = pgpGetDefaultLineEndType();
charmap = (PGPByte const *)
pgpenvGetPointer
(ctx->env, PGPENV_CHARMAPTOLOCAL, NULL);
/* Recurse means filter the text */
ctx->end = pgpTextFiltCreate ( myself->cdkContext,
ctx->end, charmap, 0, lineEnd );
if (!ctx->end) {
error = kPGPError_OutOfMemory;
break;
}
} else if (type == PGPANN_PARSER_RECURSE &&
ctx->subtype == PGP_LITERAL_RECURSE) {
/* Want to recurse inside literal packet */
PGPPipeline **temp = ctx->end;
PGPBoolean trueflag = TRUE;
ctx->end = pgpParseAscCreate ( myself->cdkContext,
ctx->end, ctx->env, &pgpByteFifoDesc,
ctx->ui, ctx->ui_arg );
ctx->nextparser = *temp;
if (!ctx->end) {
error = kPGPError_OutOfMemory;
break;
}
/* Chain end of pipeline so can do annotation */
*(ctx->end) = oldhead;
ctx->needcallback--;
/* Set ascii armor to passthroughclearsign mode */
ctx->nextparser->annotate( ctx->nextparser, NULL,
PGPANN_PASSTHROUGH_CLEARSIGN,
&trueflag, 1 );
if (!ctx->nopurge)
inputPurge(&ctx->input);
ctx->nopurge = FALSE;
myself->write = DoWrite;
return error;
}
type = PGPANN_PARSER_PROCESS;
break;
case PGPANN_CIPHER_END:
cfb = CheckKey (myself->cdkContext, ctx, string, size, &error);
if (!cfb)
break;
ctx->end = pgpCipherModDecryptCreate ( myself->cdkContext,
ctx->end, cfb, ctx->env, kPGPHashAlgorithm_Invalid, 0);
if (!ctx->end)
error = kPGPError_OutOfMemory;
break;
case PGPANN_COMPRESSED_END:
ctx->end = pgpDecompressModCreate ( cdkContext, ctx->end,
*inputMergedPtr(&ctx->input), &error);
break;
case PGPANN_COMMENT_END:
case PGPANN_UNKNOWN_END:
type = PGPANN_PARSER_PROCESS;
break;
case PGPANN_SIGNED_END:
{
PGPUInt32 numHashes =0;
if (ctx->nextparser)
type = PGPANN_PARSER_PROCESS;
/* Set up all requested hashes */
pgpAssert(!ctx->hashes);
if (!size)
return kPGPError_NoErr;
/* Get all the PgpHashContexts */
error = (PGPError)pgpHashListCreate ( memoryMgr,
string, &ctx->hashes, size);
if ( IsPGPError( error ) )
break;
numHashes = pgpHashListGetSize( ctx->hashes );
/* Make a pipeline out of them */
ctx->end = pgpHashModListCreate ( cdkContext,
ctx->end, ctx->hashes, numHashes);
if (!ctx->end) {
pgpHashListDestroy (ctx->hashes );
ctx->hashes = NULL;
error = kPGPError_OutOfMemory;
break;
}
pgpAssert(inputFinished(&ctx->input.head));
ctx->input.head.pktlen = (PGPUInt32)-1l; /* Write through rest */
ctx->input.silent_trunc = 1;
error = kPGPError_NoErr;
break;
}
case PGPANN_PGPKEY_END:
type = PGPANN_PARSER_PROCESS;
break;
default:
error = kPGPError_BadParams;
}
/*
* Processing for all packet types... set up parser if
* desired, then skip any header prifix in the buffer,
* then arrange to write out what we have.
*/
/* If we want to create a parser, do that */
if (!error && type == PGPANN_PARSER_RECURSE) {
PGPPipeline **temp = ctx->end;
ctx->end = pgpParseBinCreate ( myself->cdkContext,
ctx->end, ctx->env, ctx->ui, ctx->ui_arg);
if (!ctx->end)
error = kPGPError_OutOfMemory;
ctx->nextparser = *temp;
}
if (!error && type == PGPANN_PARSER_PROCESS) {
/* Add a header if appropriate */
switch (ctx->end_scope) {
case PGPANN_CIPHER_END:
case PGPANN_COMPRESSED_END:
case PGPANN_SIGNED_END:
ctx->end = pgpHeaderCreate ( myself->cdkContext, ctx->end);
if (!ctx->end)
error = kPGPError_OutOfMemory;
}
}
/* Success! Flush data and write through the rest */
if (!error) {
if (ctx->end_scope == PGPANN_SIGNED_END) {
if (ctx->state >= 10)
myself->write = DoSignedLiteralMagic;
else if (ctx->sig1pass)
myself->write = DoWriteSignedPackets;
else {
if( !ctx->nopurge )
inputPurge( &ctx->input );
ctx->nopurge = FALSE;
myself->write = DoWrite;
}
} else {
if (ctx->end_scope == PGPANN_PGPKEY_END)
myself->write = parseKey;
else {
if( !ctx->nopurge )
inputPurge( &ctx->input );
ctx->nopurge = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -