📄 pgpprsasc.c
字号:
size -= retlen;
ctx->armorlen += retlen;
/* Set EOB if we hit the end of the armorline buffer */
if (ctx->armorlen >= LINE_LEN-1)
ctx->eob = 1;
/*
* At this point we are either at EOL or not. If not, then we
* either ran out of input data or ran out of buffer space. If
* we are at EOL and eol==2 and we have more data, check if its a
* \n or something else. If so, copy that in and set eol=1.
*/
if (eol) {
ctx->crlf = (eol == 2 ? kPGPLineEnd_CR : kPGPLineEnd_LF);
if (eol == 2 && size) {
if (*buf == '\n') {
*ptr = *buf;
ctx->armorlen++;
ctx->crlf = kPGPLineEnd_CRLF;
size--;
}
eol = 1;
}
}
/* Save off the EOL and return the number of bytes used */
ctx->eol = eol;
ctx->bytesread += size0-size;
return size0-size;
}
/* memCmpPrefix works like memcmp except it allows certain material to
* prefix the 1st arg. The intention is to generalize the search for
* "-----BEGIN PGP MESSAGE-----" so that quoted versions can be matched.
* The rule presently is that material in angle brackets is ignored, like
* "<bigger>", because Eudora in richtext mode sometimes puts those in.
* Likewise non-alphabetic characters will be allowed, because people may
* be quoting a PGP message or key with "> " and similar conventions.
* Only the number of chars specified in testlen must match.
* In addition to returning the error code, this function returns the
* number of skipped chars in *skiplen.
*/
static int
memCmpPrefix(const char *orig, size_t origlen, const char *test,
size_t testlen, size_t *skiplen)
{
char ctest, corig;
size_t len = 0;
PGPBoolean inbracket = FALSE;
pgpAssert (IsntNull(skiplen));
pgpAssert (testlen > 0);
*skiplen = 0;
if (origlen == 0)
return 0;
ctest = test[0];
for ( ; ; ) {
if (origlen-len < testlen)
return 1; /* Failure, no match */
corig = orig[len];
if (!inbracket) {
if (corig == ctest && memcmp (orig+len, test, testlen) == 0) {
*skiplen = len;
return 0; /* Success */
}
if (isalnum((int) corig))
return 1; /* Failure, not a legal prefix */
if (corig == '<')
inbracket = TRUE;
} else {
if (corig == '>')
inbracket = FALSE;
}
++len;
}
}
/*
* Contained in buf (of length size) should be a Header-line. Parse
* it appropriately, and store it as necessary.
*
* A headerline must fit in the armorline buffer (I.e., it must be
* less that LINE_LEN-1 bytes long), it must start with an Alpha
* character and then have up to 64 AlphaNumeric characters or dashes,
* followed by a colon and then a space. A header that does not
* conform to this is an error.
*
* 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 ((int) (*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((int) 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -