berparse.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:10k
- /*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
- #include "secutil.h"
- typedef enum {
- tagDone, lengthDone, leafDone, compositeDone,
- notDone,
- parseError, parseComplete
- } ParseState;
- typedef unsigned char Byte;
- typedef void (*ParseProc)(BERParse *h, unsigned char **buf, int *len);
- typedef struct {
- SECArb arb;
- int pos; /* length from global start to item start */
- SECArb *parent;
- } ParseStackElem;
- struct BERParseStr {
- PRArenaPool *his;
- PRArenaPool *mine;
- ParseProc proc;
- int stackDepth;
- ParseStackElem *stackPtr;
- ParseStackElem *stack;
- int pending; /* bytes remaining to complete this part */
- int pos; /* running length of consumed characters */
- ParseState state;
- PRBool keepLeaves;
- PRBool derOnly;
- BERFilterProc filter;
- void *filterArg;
- BERNotifyProc before;
- void *beforeArg;
- BERNotifyProc after;
- void *afterArg;
- };
- #define UNKNOWN -1
- static unsigned char NextChar(BERParse *h, unsigned char **buf, int *len)
- {
- unsigned char c = *(*buf)++;
- (*len)--;
- h->pos++;
- if (h->filter)
- (*h->filter)(h->filterArg, &c, 1);
- return c;
- }
- static void ParseTag(BERParse *h, unsigned char **buf, int *len)
- {
- SECArb* arb = &(h->stackPtr->arb);
- arb->tag = NextChar(h, buf, len);
- PORT_Assert(h->state == notDone);
- /*
- * NOTE: This does not handle the high-tag-number form
- */
- if ((arb->tag & DER_HIGH_TAG_NUMBER) == DER_HIGH_TAG_NUMBER) {
- PORT_SetError(SEC_ERROR_BAD_DER);
- h->state = parseError;
- return;
- }
- h->pending = UNKNOWN;
- arb->length = UNKNOWN;
- if (arb->tag & DER_CONSTRUCTED) {
- arb->body.cons.numSubs = 0;
- arb->body.cons.subs = NULL;
- } else {
- arb->body.item.len = UNKNOWN;
- arb->body.item.data = NULL;
- }
- h->state = tagDone;
- }
- static void ParseLength(BERParse *h, unsigned char **buf, int *len)
- {
- Byte b;
- SECArb *arb = &(h->stackPtr->arb);
- PORT_Assert(h->state == notDone);
- if (h->pending == UNKNOWN) {
- b = NextChar(h, buf, len);
- if ((b & 0x80) == 0) { /* short form */
- arb->length = b;
- /*
- * if the tag and the length are both zero bytes, then this
- * should be the marker showing end of list for the
- * indefinite length composite
- */
- if (arb->length == 0 && arb->tag == 0)
- h->state = compositeDone;
- else
- h->state = lengthDone;
- return;
- }
- h->pending = b & 0x7f;
- /* 0 implies this is an indefinite length */
- if (h->pending > 4) {
- PORT_SetError(SEC_ERROR_BAD_DER);
- h->state = parseError;
- return;
- }
- arb->length = 0;
- }
- while ((*len > 0) && (h->pending > 0)) {
- b = NextChar(h, buf, len);
- arb->length = (arb->length << 8) + b;
- h->pending--;
- }
- if (h->pending == 0) {
- if (h->derOnly && (arb->length == 0))
- h->state = parseError;
- else
- h->state = lengthDone;
- }
- return;
- }
- static void ParseLeaf(BERParse *h, unsigned char **buf, int *len)
- {
- int count;
- SECArb *arb = &(h->stackPtr->arb);
- PORT_Assert(h->state == notDone);
- PORT_Assert(h->pending >= 0);
- if (*len < h->pending)
- count = *len;
- else
- count = h->pending;
- if (h->keepLeaves)
- memcpy(arb->body.item.data + arb->body.item.len, *buf, count);
- if (h->filter)
- (*h->filter)(h->filterArg, *buf, count);
- *buf += count;
- *len -= count;
- arb->body.item.len += count;
- h->pending -= count;
- h->pos += count;
- if (h->pending == 0) {
- h->state = leafDone;
- }
- return;
- }
- static void CreateArbNode(BERParse *h)
- {
- SECArb *arb = PORT_ArenaAlloc(h->his, sizeof(SECArb));
- *arb = h->stackPtr->arb;
- /*
- * Special case closing the root
- */
- if (h->stackPtr == h->stack) {
- PORT_Assert(arb->tag & DER_CONSTRUCTED);
- h->state = parseComplete;
- } else {
- SECArb *parent = h->stackPtr->parent;
- parent->body.cons.subs = DS_ArenaGrow(
- h->his, parent->body.cons.subs,
- (parent->body.cons.numSubs) * sizeof(SECArb*),
- (parent->body.cons.numSubs + 1) * sizeof(SECArb*));
- parent->body.cons.subs[parent->body.cons.numSubs] = arb;
- parent->body.cons.numSubs++;
- h->proc = ParseTag;
- h->state = notDone;
- h->pending = UNKNOWN;
- }
- if (h->after)
- (*h->after)(h->afterArg, arb, h->stackPtr - h->stack, PR_FALSE);
- }
- SECStatus BER_ParseSome(BERParse *h, unsigned char *buf, int len)
- {
- if (h->state == parseError) return PR_TRUE;
- while (len) {
- (*h->proc)(h, &buf, &len);
- if (h->state == parseComplete) {
- PORT_SetError(SEC_ERROR_BAD_DER);
- h->state = parseError;
- return PR_TRUE;
- }
- if (h->state == parseError) return PR_TRUE;
- PORT_Assert(h->state != parseComplete);
- if (h->state <= compositeDone) {
- if (h->proc == ParseTag) {
- PORT_Assert(h->state == tagDone);
- h->proc = ParseLength;
- h->state = notDone;
- } else if (h->proc == ParseLength) {
- SECArb *arb = &(h->stackPtr->arb);
- PORT_Assert(h->state == lengthDone || h->state == compositeDone);
- if (h->before)
- (*h->before)(h->beforeArg, arb,
- h->stackPtr - h->stack, PR_TRUE);
- /*
- * Check to see if this is the end of an indefinite
- * length composite
- */
- if (h->state == compositeDone) {
- SECArb *parent = h->stackPtr->parent;
- PORT_Assert(parent);
- PORT_Assert(parent->tag & DER_CONSTRUCTED);
- if (parent->length != 0) {
- PORT_SetError(SEC_ERROR_BAD_DER);
- h->state = parseError;
- return PR_TRUE;
- }
- /*
- * NOTE: This does not check for an indefinite length
- * composite being contained inside a definite length
- * composite. It is not clear that is legal.
- */
- h->stackPtr--;
- CreateArbNode(h);
- } else {
- h->stackPtr->pos = h->pos;
- if (arb->tag & DER_CONSTRUCTED) {
- SECArb *parent;
- /*
- * Make sure there is room on the stack before we
- * stick anything else there.
- */
- PORT_Assert(h->stackPtr - h->stack < h->stackDepth);
- if (h->stackPtr - h->stack == h->stackDepth - 1) {
- int newDepth = h->stackDepth * 2;
- h->stack = DS_ArenaGrow(h->mine, h->stack,
- sizeof(ParseStackElem) * h->stackDepth,
- sizeof(ParseStackElem) * newDepth);
- h->stackPtr = h->stack + h->stackDepth + 1;
- h->stackDepth = newDepth;
- }
- parent = &(h->stackPtr->arb);
- h->stackPtr++;
- h->stackPtr->parent = parent;
- h->proc = ParseTag;
- h->state = notDone;
- h->pending = UNKNOWN;
- } else {
- if (arb->length < 0) {
- PORT_SetError(SEC_ERROR_BAD_DER);
- h->state = parseError;
- return PR_TRUE;
- }
- arb->body.item.len = 0;
- if (arb->length > 0 && h->keepLeaves) {
- arb->body.item.data =
- PORT_ArenaAlloc(h->his, arb->length);
- } else {
- arb->body.item.data = NULL;
- }
- h->proc = ParseLeaf;
- h->state = notDone;
- h->pending = arb->length;
- }
- }
- } else {
- ParseStackElem *parent;
- PORT_Assert(h->state = leafDone);
- PORT_Assert(h->proc == ParseLeaf);
- for (;;) {
- CreateArbNode(h);
- if (h->stackPtr == h->stack)
- break;
- parent = (h->stackPtr - 1);
- PORT_Assert(parent->arb.tag & DER_CONSTRUCTED);
- if (parent->arb.length == 0) /* need explicit end */
- break;
- if (parent->pos + parent->arb.length > h->pos)
- break;
- if (parent->pos + parent->arb.length < h->pos) {
- PORT_SetError(SEC_ERROR_BAD_DER);
- h->state = parseError;
- return PR_TRUE;
- }
- h->stackPtr = parent;
- }
- }
- }
- }
- return PR_FALSE;
- }
- BERParse *BER_ParseInit(PRArenaPool *arena, PRBool derOnly)
- {
- BERParse *h;
- PRArenaPool *temp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (temp == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return NULL;
- }
- h = PORT_ArenaAlloc(temp, sizeof(BERParse));
- if (h == NULL) {
- PORT_FreeArena(temp, PR_FALSE);
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return NULL;
- }
- h->his = arena;
- h->mine = temp;
- h->proc = ParseTag;
- h->stackDepth = 20;
- h->stack = PORT_ArenaZAlloc(h->mine,
- sizeof(ParseStackElem) * h->stackDepth);
- h->stackPtr = h->stack;
- h->state = notDone;
- h->pos = 0;
- h->keepLeaves = PR_TRUE;
- h->before = NULL;
- h->after = NULL;
- h->filter = NULL;
- h->derOnly = derOnly;
- return h;
- }
- SECArb *BER_ParseFini(BERParse *h)
- {
- PRArenaPool *myArena = h->mine;
- SECArb *arb;
- if (h->state != parseComplete) {
- arb = NULL;
- } else {
- arb = PORT_ArenaAlloc(h->his, sizeof(SECArb));
- *arb = h->stackPtr->arb;
- }
- PORT_FreeArena(myArena, PR_FALSE);
- return arb;
- }
- void BER_SetFilter(BERParse *h, BERFilterProc proc, void *instance)
- {
- h->filter = proc;
- h->filterArg = instance;
- }
- void BER_SetLeafStorage(BERParse *h, PRBool keep)
- {
- h->keepLeaves = keep;
- }
- void BER_SetNotifyProc(BERParse *h, BERNotifyProc proc, void *instance,
- PRBool beforeData)
- {
- if (beforeData) {
- h->before = proc;
- h->beforeArg = instance;
- } else {
- h->after = proc;
- h->afterArg = instance;
- }
- }