📄 pgpprsasc.c
字号:
*
* Returns 0 on success, or a HEADER_ error code.
*/
#define HEADER_TOOLONG -1
#define HEADER_INVALID -2
static int
parseHeader (PrsAscContext *ctx, PGPByte const *buf, size_t size)
{
int i;
char const *ptr = (char const *)buf;
static char const messageid[] = "MessageID:";
char c;
(void)size; /* So, why do I have this arg? */
/* Make sure this is the WHOLE line -- if not, it is an error */
if (!ctx->eol)
return HEADER_TOOLONG;
/* The first character must be an Alpha character */
if (!isalpha (*ptr++))
return HEADER_INVALID;
i = 1;
for (;;) {
c = *ptr++;
/* header ends in a colon */
if (c == ':')
break;
/* Arbitrary label length restriction */
if (++i > 64)
return HEADER_TOOLONG; /* Error */
/* Following chars much be alphanumeric or '-' */
if (!isalnum(c) && c != '-')
return HEADER_INVALID; /* Error */
}
/* Must be a space after the ':' */
if (*ptr++ != ' ')
return HEADER_INVALID;
/*
* Now process the header
*
* ptr points to the value; buf points to the key (of length
* (ptr - buf - 2), plus a colon)
*/
i = ptr - (char const *)buf - 1;
/* Process message ID header */
if (i == sizeof (messageid) - 1 && !memcmp (buf, messageid, i))
memcpy (ctx->messageid, ptr,
pgpMin ((strlen (ptr) + 1), sizeof (ctx->messageid)));
/* XXX: signal an unknown header? */
return 0;
}
/* Write data to be dearmored.
*
* The main FSM to control dearmoring. The actual FSM is kind of
* complicated so I'll try to explain it by comments in the code.
* Suffice it to say that there are two main parts of the machine.
* The first part deals with armor'ed data, and the second part deals
* with out-of-armored text. There is a little glue between them, and
* there you have it...
*
* Here are the states, categorized into general phases of activity:
*
* 0 Start state, outside PGP data
*
* 10 - 50 Waiting for start of PGP data
*
* 90 - 100 Process -----BEGIN PGP line
*
* 110 - 130 Process headers after -----BEGIN PGP
*
* 140 - 160 Setup to begin processing armored data
*
* 170 - 200 Process PGP armored data
*
* 210 - 230 Process CRC at end of armored data
*
* 240 - 270 Process -----END PGP line, finish up, back to 0
*
* 300 - 330 Clearsigned message, process Hash: lines if any
*
* 340 - 360 Setup to begin processing clearsigned message
*
* 390 - 430 Process clearsigned message body, then to 90 for sig
*
* 500 - 530 Process binary message, to 260 to finish up when done
*
* 600 - 630 Scan MIME headers, get boundary string
*
* 650 - 680 Look for initial MIME boundary string, to 340 when found
*
* 700 - 720 Check apparent initial MIME separator, to 340 if looks OK
*
* 750 - 770 Look for start of PGP sig in MIME clearsig sig part, to 90
*
* 800 - 830 Look for final MIME clearsign boundary after PGP sig
*
*/
static size_t
Write (PGPPipeline *myself, PGPByte const *buf, size_t size, PGPError *error)
{
PrsAscContext *ctx;
Message *msg;
MsgPart *part;
PGPByte *ptr, *num;
static char const prefix1[] = "-----BEGIN PGP ";
static char const prefix2[] = ", PART ";
static char const prefix3[] = "-----END PGP ";
static char const suffix[] = "-----"; /* With trailing nul */
static char const signedmsg[] = "SIGNED MESSAGE";
static char const pubkey[] = "PUBLIC KEY";
static char const privkey[] = "PRIVATE KEY";
static char const sigprefix[] = "-----BEGIN PGP SIGNATURE-----";
static char const signedprefix[] = "-----BEGIN PGP SIGNED MESSAGE-----";
#if MIMEPARSE
PGPByte *ptr2;
static char prefix_mimesig2[] = "-----BEGIN PGP MESSAGE-----";
static char prefix_mime1[] = "content-type: multipart/signed;";
static char prefix_mime2[] = "protocol=\"application/pgp-signature\"";
static char prefix_mime3[] = "boundary=";
#if 0
static char prefix_mime4[] = "micalg=";
static char prefix_mime5[] = "pgp-";
#endif /* 0 */
#endif /* MIMEPARSE */
int i, thispart, maxparts, lineused;
size_t retval, written = 0;
unsigned inlen;
long crc;
char temp_c;
PGPContextRef cdkContext;
pgpAssertAddrValid( myself, PGPPipeline );
cdkContext = myself->cdkContext;
pgpAssert (myself);
pgpAssert (myself->magic == DEARMORMAGIC);
pgpAssert (error);
ctx = (PrsAscContext *)myself->priv;
pgpAssert (ctx);
pgpAssert (ctx->tail);
switch (ctx->state) {
case 0:
state_start:
ctx->state = 0;
/*
* This is the "start" position. Check if we are
* buffering and flush buffers if we are not. Then go
* to the next state.
*/
if (!ctx->buffering) {
*error = flushBuffers (ctx);
if (*error)
break;
}
/* FALLTHROUGH */
case 10:
state_wait_for_pgp:
ctx->state = 10;
/* call readline until we have EOB or EOL */
retval = readLine (ctx, buf, size);
size -= retval;
buf += retval;
written += retval;
if (ctx->eol || ctx->eob)
;
else
break;
/* FALLTHROUGH */
case 20:
ctx->state = 20;
/*
* check the line for BEGIN. If it is not a begin
* then we should output this line. If it is a begin,
* then we need to parse it as an armor beginning.
* Use special compare routine which skips some prefixes of the
* test line so we can recognize "- -----BEGIN PGP" and such.
*/
if (ctx->armorlen > sizeof (prefix1) - 1 &&
!memCmpPrefix ((char *)ctx->armorline, ctx->armorlen,
prefix1, sizeof (prefix1) - 1,
&ctx->skipPrefixLength)) {
/*
* Don't allow a prefix on BEGIN PGP SIGNATURE or BEGIN PGP
* SIGNED MESSAGE. People often quote signed messages in replies
* and we don't want to trigger on those. And the SIGNATURE
* is the last part of the signed message.
*/
if (ctx->skipPrefixLength == 0 ||
(memcmp(ctx->armorline+ctx->skipPrefixLength, sigprefix,
sizeof(sigprefix)-1)!=0 &&
memcmp(ctx->armorline+ctx->skipPrefixLength, signedprefix,
sizeof(signedprefix)-1)!=0 )) {
if (ctx->skipPrefixLength > 0) {
pgpAssert (ctx->skipPrefixLength <
sizeof(ctx->skipPrefix));
pgpCopyMemory (ctx->armorline, ctx->skipPrefix,
ctx->skipPrefixLength);
ctx->skipPrefix[ctx->skipPrefixLength] = '\0';
}
goto state_pgp_begin;
}
}
/*
* check the line to see if it is the beginning of a
* PGP binary message. This check is only done the
* first time through this loop, using ctx->annotation
* as the loop detector. If this is a PGP message,
* then treat it as such and buffer the data for
* processing through a parser.
*/
if (! ctx->annotation) {
if (pgpFileTypePGP (ctx->armorline, ctx->armorlen))
{
/*
* ooh, a binary PGP message fed into the
* ascii armor parser!
*/
goto state_pgp_binary;
}
}
#if MIMEPARSE
/*
* Look for either the MIME content-type message, or what looks
* like a MIME message boundary (in case we don't have headers).
*/
if (ctx->armorlen > sizeof (prefix_mime1) - 1 &&
!strncmp_ignorecase ((char *)ctx->armorline, prefix_mime1,
sizeof (prefix_mime1) - 1)) {
/* MIME header */
goto state_pgpmime;
}
/*
* If no_mime_headers, we have only a body, so assume that a line
* starting with -- is a pgp/mime signed part. This is not a very
* good assumption in general, so we will assume that we had some
* reason to think so.
*/
if (ctx->no_mime_headers && ctx->eol &&
ctx->armorlen > 2 && !memcmp (ctx->armorline, "--", 2) &&
ctx->eol) {
/* Potential MIME initial body indicator */
goto state_pgpmime_body_noheaders;
}
#endif
/* FALLTHROUGH */
case 30:
state_nonpgp:
ctx->state = 30;
/* send annotation if we need to */
/* Get here with armorlen==0 only on flush call, don't annotate then */
ctx->sectoff = ctx->prevlineoff;
if (!ctx->annotation && ctx->armorlen!=0) {
*error = sendAnnotate (ctx, myself, PGPANN_NONPGP_BEGIN,
(PGPByte *)&ctx->sectoff, sizeof(ctx->sectoff));
if (*error)
break;
ctx->annotation = PGPANN_NONPGP_END;
ctx->depth_at_ann = ctx->scope_depth;
}
/* FALLTHROUGH */
case 40:
state_nonpgp_output:
ctx->state = 40;
/* output armorline buffer */
while (ctx->armorlen) {
retval = writeExtraData (ctx, ctx->armorptr,
ctx->armorlen, error);
ctx->armorptr += retval;
ctx->armorlen -= retval;
if (*error)
return written;
}
ctx->armorptr = ctx->armorline;
/* FALLTHROUGH */
case 50:
ctx->state = 50;
/*
* if EOL == 1, clear state and goto state wait_for_pgp, otherwise
* read data and return to state nonpgp_output to output the line.
*/
if (ctx->eol == 1) {
ctx->eol = 0;
ctx->eob = 0;
goto state_wait_for_pgp;
}
if (!size)
break;
retval = readLine (ctx, buf, size);
size -= retval;
buf += retval;
written += retval;
goto state_nonpgp_output;
case 90:
state_pgp_begin:
ctx->state = 90;
/*
* parse begin line. If this is not a valid begin
* line, assume that it is not and output it as
* non-PGP text (in state nonpgp).
* skipPrefixLength holds extra chars to skip at beginning
*/
ctx->sectoff = ctx->prevlineoff;
ptr = ctx->armorline + sizeof (prefix1) - 1 + ctx->skipPrefixLength;
lineused = ctx->armorlen - (sizeof (prefix1) - 1)
- ctx->skipPrefixLength;
thispart = maxparts = 0;
do {
if (lineused == 0) {
/* not a valid BEGIN line */
goto state_nonpgp;
}
} while (isspace (ptr[--lineused]));
/* temporarily null-terminate this string */
temp_c = ptr[++lineused];
ptr[lineused] = '\0';
if (!memcmp (ptr, signedmsg, sizeof (signedmsg)-1)) {
/* This is a clearsigned message */
if (ctx->eol) {
/*
* This looks like a clearsigned
* message. jump into the clearsigned
* parser and parse it.
*/
ptr[lineused] = temp_c; /* restore terminator */
goto state_cleartext;
}
/*
* Someone is playing with us.. This is an
* error.
*/
goto err_state_pgp_begin;
}
if (ctx->passthroughkey &&
(memcmp (ptr, pubkey, sizeof(pubkey)-1) == 0 ||
memcmp (ptr, privkey, sizeof(privkey)-1) == 0)) {
/* Go into passthrough mode on key block */
ctx->passthrough = TRUE;
ptr[lineused] = temp_c;
*error = sendAnnotate (ctx, myself, PGPANN_CLEARDATA,
ctx->armorline, ctx->armorlen);
if (*error)
break;
ptr[lineused] = '\0';
}
/* skip the "whatever" in "-----BEGIN PGP whatever" */
while (isalnum (*ptr) || *ptr == ' ') {
ptr++;
lineused--;
}
/* check for multipart */
if (*ptr == ',') {
/* "-----BEGIN PGP whatever, PART x[/y]-----" */
if (memcmp (ptr, prefix2, sizeof (prefix2) - 1))
goto err_state_pgp_begin;
ptr += sizeof (prefix2) - 1;
lineused -= sizeof (prefix2) - 1;
thispart = strtoul ((char *)ptr, (char **)&num, 10);
if (num == NULL || thispart < 0 || thispart > 999)
goto err_state_pgp_begin;
lineused -= (num - ptr);
ptr = num;
/*
* now check for "/y", if it exists. It is
* legal for it not to exist, but it must have
* either a 'y' here or a messageID.
*/
if (*ptr == '/') {
maxparts = strtoul ((char *)ptr+1,
(char **)&num, 10);
if (!num || maxparts < 2 || maxparts > 999)
goto err_state_pgp_begin;
lineused -= (num - ptr);
ptr = num;
}
} else {
thispart = maxparts = 1;
}
if (memcmp (ptr, suffix, sizeof (suffix)))
goto err_state_pgp_begin;
ctx->thispart = thispart;
ctx->maxparts = maxparts;
goto state_pgp_end_anno;
err_state_pgp_begin:
ptr[lineused] = temp_c;
goto state_nonpgp;
case 100:
state_pgp_end_anno:
ctx->state = 100;
/* Send end-annotation (if we sent a begin annotation) */
if (ctx->annotation) {
pgpAssert (ctx->depth_at_ann == ctx->scope_depth);
*error = sendAnnotate (ctx, myself, ctx->annotation,
NULL, 0);
if (*error)
break;
ctx->annotation = 0;
}
/* FALLTHROUGH */
case 110:
state_pgp_armor_header:
ctx->state = 110;
/* read until EOL to get to end of the last line */
ctx->armorptr = ctx->armorline;
ctx->armorlen = 0;
while (ctx->eol != 1) {
ctx->armorlen = 0;
retval = readLine (ctx, buf, size);
written += retval;
buf += retval;
size -= retval;
if (!size)
return written;
}
ctx->eol = 0;
ctx->eob = 0;
ctx->armorlen = 0;
/* FALLTHROUGH */
case 120:
ctx->state = 120;
/* call readline until we have EOB or EOL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -