📄 pgpprsasc.c
字号:
return kPGPError_FIFOReadError;
cmdlen -= sizeof (ctx->cmdlen);
if (pgpFifoRead (ctx->fifod, ctx->ann, ctx->cmdarg,
ctx->cmdlen) != ctx->cmdlen)
return kPGPError_FIFOReadError;
cmdlen -= ctx->cmdlen;
} else {
/*
* If this can happen then we need to do this
* and keep track of the amount of data left in
* the fifo.
*/
ctx->left = datalen;
ctx->written = datalen;
}
} while (datalen || cmdlen || ctx->cmdlen);
/* If we get here then everything has been written out. */
ctx->written = 0;
return( kPGPError_NoErr );
}
/*
* TBD for MIME support:
* Add a filter to remove some MIME transforms. To wit:
* First read headers, looking for blank line. If see any header other
* than Content-Type: text/plain... or Content-Transfer-Encoding
* other than quoted-printable (or whatever the plain one is), we can't
* handle it, and we should just pass the whole thing through. Otherwise
* we delete the header and trailing blank line. We then run through the
* filter which undoes the content-transfer-encoding transformation if
* necessary, or else just passes data through.
* This filter should be added just before the copymod, below. It might
* even replace the copymod, but I don't remember what it is for. Something
* to do with some error recovery state, where we needed to know we were
* pointing at the last thing in the pipeline before context->tail?
*/
/*
* This is a clearsigned message. We need to setup the verification
* pipeline to get this to work. First we have a join module. It is a
* placeholder for the message. The clearsigned text goes into the
* second input of the join module. The output of the join module goes
* to a split. The first output of the split goes to the annotation
* reader. The second output of the split goes into a textfilt module
* to strip the spaces and then into a signature verification module.
*/
static PGPError
createClearsig (
PGPContextRef cdkContext,
PrsAscContext *ctx,
Message *msg,
MsgPart *part)
{
/*
* We don't need a join module for clearsigning. That causes the
* entire clearsigned part to be buffered in the join module until
* we get to the cleanup phase! Redo that.
*/
#if 0
PGPPipeline *join = NULL, *split = NULL, *text = NULL;
PGPPipeline **tail, **temp;
PGPPipeline *sighead = NULL, **sigtail;
/* First, build up a replacement "join/split" module */
tail = pgpJoinCreate (cdkContext, &join, ctx->fifod);
if (!tail)
return kPGPError_OutOfMemory;
temp = tail;
tail = pgpSplitCreate (cdkContext, temp);
if (!tail) {
return kPGPError_OutOfMemory;
}
split = *temp;
/* Splice in the join/split in place of the old join/parser */
*(msg->tail) = NULL;
part->mod->teardown (part->mod);
part->mod = join;
msg->tail = tail;
/*
* 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);
/* And connect the tail */
if (msg->tail)
*(msg->tail) = ctx->tail;
/* Create the text input */
text = pgpJoinAppend (join);
if (! text) {
return kPGPError_OutOfMemory;
}
/* add a textfilt module */
tail = pgpSplitAdd (split);
if (!tail) {
text->teardown (text);
return kPGPError_OutOfMemory;
}
#if MIMEPARSE
tail = pgpTextFiltCreate (cdkContext, tail, charMapIdentity, 1,
(ctx->mime_signed ? kPGPLineEnd_CRLF : kPGPLineEnd_Default));
#else
tail = pgpTextFiltCreate ( cdkContext,
tail, charMapIdentity, 1, kPGPLineEnd_Default);
#endif
if (!tail) {
text->teardown (text);
return kPGPError_OutOfMemory;
}
/* Create the signature parser... */
sigtail = pgpParseBinCreate ( cdkContext, &sighead, ctx->env,
ctx->ui, ctx->ui_arg );
if (!sigtail) {
text->teardown (text);
return kPGPError_OutOfMemory;
}
/* ...and the signature verifier */
if (!pgpVerifyReaderCreate ( cdkContext,
tail, sigtail, ctx->env, ctx->fifod,
(ctx->hashlen ? ctx->hashlist : NULL),
ctx->hashlen, (ctx->hashlen ? 1 : 0),
ctx->ui, ctx->ui_arg)) {
text->teardown (text);
sighead->teardown (sighead);
return kPGPError_OutOfMemory;
}
/* Now put it all together in this message */
part->text = text;
part->sig = sighead;
#else
PGPPipeline *text = NULL;
PGPPipeline **tail;
PGPPipeline *sighead = NULL, **sigtail;
tail = pgpSplitCreate (cdkContext, &text);
/* Splice in the split in place of the old join/parser */
*(msg->tail) = NULL;
part->mod->teardown (part->mod);
part->mod = NULL; /* No join module */
msg->tail = tail;
/*
* 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);
/* And connect the tail */
if (msg->tail)
*(msg->tail) = ctx->tail;
/* add a textfilt module */
tail = pgpSplitAdd (text);
if (!tail) {
return kPGPError_OutOfMemory;
}
/* Not clear about using Default on non-MIME here */
tail = pgpTextFiltCreate (cdkContext, tail, charMapIdentity, 1,
(ctx->mime_signed ? kPGPLineEnd_CRLF : kPGPLineEnd_Default));
if (!tail) {
return kPGPError_OutOfMemory;
}
/* Create the signature parser... */
sigtail = pgpParseBinCreate ( cdkContext, &sighead, ctx->env,
ctx->ui, ctx->ui_arg);
if (!sigtail) {
return kPGPError_OutOfMemory;
}
/* ...and the signature verifier */
if (!pgpVerifyReaderCreate ( cdkContext,
tail, sigtail, ctx->env, ctx->fifod,
(ctx->hashlen ? ctx->hashlist : NULL),
ctx->hashlen, (ctx->hashlen ? 1 : 0),
ctx->ui, ctx->ui_arg)) {
sighead->teardown (sighead);
return kPGPError_OutOfMemory;
}
/* Now put it all together in this message */
part->text = text;
part->sig = sighead;
#endif
return( kPGPError_NoErr );
}
/*
* Build up the Ascii Parser Table in order to dearmor data. For all
* values, set it to -1 if it is not a valid armor character and then
* set the valid characters out of the armorTable.
*
* To make it thread-safe, init using local table, then copy table
* to global.
*/
void
pgpParseAscInit (void)
{
#define kDearmorTableSize ( (PGPSize)256 )
static char sDearmorTableStorage[ kDearmorTableSize ];
static PGPBoolean sInited = FALSE;
int i;
char tempTable[ kDearmorTableSize ];
if ( sInited )
return;
for (i = 0; i < (int)kDearmorTableSize; i++)
tempTable[i] = -1;
for (i = 0; i < (int)(sizeof(armorTable) - 1); i++)
tempTable[armorTable[i] & 0xff] = (char)i;
pgpCopyMemory( tempTable, sDearmorTableStorage, sizeof(tempTable) );
sDearmorTable = &sDearmorTableStorage[ 0 ];
/* set 'sInited' only after everything has been setup above */
sInited = 1;
return;
}
/*
* Convert input bytes to output bytes. Returns the number of
* input bytes successfully converted. The number of output
* bytes available is one less than this number.
*/
static int
dearmorMorsel (PGPByte const in[4], PGPByte out[3])
{
signed char c0, c1;
c0 = sDearmorTable[in[0] & 255];
if (c0 < 0)
return 0;
c1 = sDearmorTable[in[1] & 255];
if (c1 < 0)
return 1;
out[0] = (c0 & 63u) << 2 | (c1 & 63u) >> 4;
c0 = sDearmorTable[in[2] & 255];
if (c0 < 0)
return 2;
out[1] = (c1 & 63u) << 4 | (c0 & 63u) >> 2;
c1 = sDearmorTable[in[3] & 255];
if (c1 < 0)
return 3;
out[2] = (c0 & 63u) << 6 | (c1 & 63u);
return 4;
}
/*
* Given a line of a certain length, convert to binary and
* return the number of binary bytes that result, or -1 on error.
*
* This is very fussy about trailing junk and whatnot.
* There is some complexity due to accepting "=3D" in place
* of a normal "=". This is to allow MIME-encapsulated messages
* to be input directly, without having MIME unencapsulate them
* first.
*
* This will ignore trailing white space and give an error if there
* is too much data on the line.
*/
int
pgpDearmorLine (PGPByte const *in, PGPByte *out, unsigned inlen)
{
int outlen = 0;
int t;
while ((t = dearmorMorsel (in, out)) == 4) {
in += 4;
out += 3;
inlen -= 4;
outlen += 3;
if (inlen < 4)
return inlen ? -1 : outlen;
}
switch (t) {
case 2:
if (inlen == 4) {
if (in[2] == '=' && in[3] == '=')
return outlen + 1;
} else if (inlen == 8) {
if (in[2] == '=' && in[3] == '3' && in[4] == 'D' &&
in[5] == '=' && in[6] == '3' && in[7] == 'D')
return outlen + 1;
}
break;
case 3:
if (inlen == 4) {
if (in[3] == '=')
return outlen + 2;
} else if (inlen == 6) {
if (in[3] == '=' && in[4] == '3' && in[5] == 'D')
return outlen + 2;
}
break;
}
/* None of the above - we have an error */
return -1;
}
/*
* Return true if the line is a valid candidate as an armor line,
* one with no bad characters. This will allow us to have ascii armor
* with no headers and no blanks before the armor data.
* A better check would look for mults of 4 or trailing '=', but we don't
* do that yet.
*/
static int
validArmorLine (PGPByte const *in, unsigned inlen)
{
while (inlen--) {
/* Fail if bad character */
if( sDearmorTable[in[0] & 255] < 0 && in[0] != '=')
return FALSE;
++in;
}
return TRUE;
}
/*
* Given a line thought to contain a CRC, this returns the 24-bit
* CRC, or -1 on error. Handles possible MIME expansion
* of "=" to "=3D".
*/
static long
dearmorCrc (PGPByte const *in, unsigned inlen)
{
PGPByte buf[3];
/* skip trailing white space */
while (inlen && isspace (in[inlen - 1]))
inlen--;
if (*in != '=')
return -1;
if (inlen == 5)
{
if (dearmorMorsel (in + 1, buf) != 4)
{
return -1;
}
else if (inlen == 7)
{
if (in[1] != '3' || in[2] != 'D' ||
dearmorMorsel (in + 3, buf) != 4)
{
return -1;
}
else
{
return -1;
}
}
}
/*
* Welcome to the famous ANSI C glitch. ANSI C
* promotes to signed values where possible when preserving
* the value. Thus, buf[1]<<8 is promoted to signed, then
* shifted, then promoted to long (on a 16-bit int machine,
* this causes sign-extension!), and merged with the other
* values. Not Good.
* I'm beginning to see why people preferred the K&R unsigned-
* preserving rules. Sigh.
*/
return (long)buf[0] << 16 | (unsigned)(buf[1] << 8 | buf[2]);
}
/*
* try to fill up ctx->armorline up to LINE_LEN-1 bytes or a newline,
* whichever comes first.
*
* This will set ctx->eol when an EOL condition occurs. eol == 1
* means armorline is ready for processing. eol == 2 means that
* readLine needs to be called with more data (looking for \n).
*
* The return value is the number of bytes used. If all the bytes are
* used and EOL is not set, then more data is required and readLine
* should be called with more data.
*/
static size_t
readLine (PrsAscContext *ctx, PGPByte const *buf, size_t size)
{
size_t size0 = size;
unsigned t, retlen;
PGPByte eol = ctx->eol;
PGPByte *ptr = ctx->armorline + ctx->armorlen;
if (!size)
return 0;
/* If start of new line, remember total byte offset */
if (eol == 0) {
ctx->prevlineoff = ctx->bytesread;
}
/*
* This test is needed in case the '\r' and \'n' come in
* different write calls.
*/
if (eol == 2) {
/* Must have hit a '\r' as last char in previous input buffer */
if (*buf == '\n') {
*ptr = *buf;
ctx->armorlen++;
ctx->eol = 1;
ctx->crlf = kPGPLineEnd_CRLF;
ctx->bytesread++;
return 1;
}
/*
* Bug fix here - wasn't doing this. This happens when we have CR
* terminated lines and a CR right before end of buffer. Should just
* reset our state on start of next buffer.
*/
ctx->eol = 1;
return 0;
}
/* try to fill the input buffer with a line */
t = (unsigned)pgpMin (LINE_LEN-1 - ctx->armorlen, size);
for (eol = 0, retlen = 0; retlen < t && !eol; retlen++) {
*ptr++ = *buf;
if (*buf == '\r' || *buf == '\n')
eol = (*buf == '\r' ? 2 : 1);
buf++;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -