PageRenderTime 48ms CodeModel.GetById 13ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

/security/nss/cmd/lib/berparse.c

http://github.com/zpao/v8monkey
C | 407 lines | 305 code | 42 blank | 60 comment | 83 complexity | 4a6892ffc7a8fc97d195f6bc7cf3cbbd MD5 | raw file
  1/* ***** BEGIN LICENSE BLOCK *****
  2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3 *
  4 * The contents of this file are subject to the Mozilla Public License Version
  5 * 1.1 (the "License"); you may not use this file except in compliance with
  6 * the License. You may obtain a copy of the License at
  7 * http://www.mozilla.org/MPL/
  8 *
  9 * Software distributed under the License is distributed on an "AS IS" basis,
 10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 11 * for the specific language governing rights and limitations under the
 12 * License.
 13 *
 14 * The Original Code is the Netscape security libraries.
 15 *
 16 * The Initial Developer of the Original Code is
 17 * Netscape Communications Corporation.
 18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
 19 * the Initial Developer. All Rights Reserved.
 20 *
 21 * Contributor(s):
 22 *
 23 * Alternatively, the contents of this file may be used under the terms of
 24 * either the GNU General Public License Version 2 or later (the "GPL"), or
 25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 26 * in which case the provisions of the GPL or the LGPL are applicable instead
 27 * of those above. If you wish to allow use of your version of this file only
 28 * under the terms of either the GPL or the LGPL, and not to allow others to
 29 * use your version of this file under the terms of the MPL, indicate your
 30 * decision by deleting the provisions above and replace them with the notice
 31 * and other provisions required by the GPL or the LGPL. If you do not delete
 32 * the provisions above, a recipient may use your version of this file under
 33 * the terms of any one of the MPL, the GPL or the LGPL.
 34 *
 35 * ***** END LICENSE BLOCK ***** */
 36#include "secutil.h"
 37
 38typedef enum {
 39    tagDone, lengthDone, leafDone, compositeDone,
 40    notDone,
 41    parseError, parseComplete
 42} ParseState;
 43
 44typedef unsigned char Byte;
 45typedef void (*ParseProc)(BERParse *h, unsigned char **buf, int *len);
 46typedef struct {
 47    SECArb arb;
 48    int pos;			/* length from global start to item start */
 49    SECArb *parent;
 50} ParseStackElem;
 51
 52struct BERParseStr {
 53    PRArenaPool *his;
 54    PRArenaPool *mine;
 55    ParseProc proc;
 56    int stackDepth;
 57    ParseStackElem *stackPtr;
 58    ParseStackElem *stack;
 59    int pending;		/* bytes remaining to complete this part */
 60    int pos;			/* running length of consumed characters */
 61    ParseState state;
 62    PRBool keepLeaves;
 63    PRBool derOnly;
 64    BERFilterProc filter;
 65    void *filterArg;
 66    BERNotifyProc before;
 67    void *beforeArg;
 68    BERNotifyProc after;
 69    void *afterArg;
 70};
 71
 72#define UNKNOWN -1
 73
 74static unsigned char NextChar(BERParse *h, unsigned char **buf, int *len)
 75{
 76    unsigned char c = *(*buf)++;
 77    (*len)--;
 78    h->pos++;
 79    if (h->filter)
 80	(*h->filter)(h->filterArg, &c, 1);
 81    return c;
 82}
 83
 84static void ParseTag(BERParse *h, unsigned char **buf, int *len)
 85{
 86    SECArb* arb = &(h->stackPtr->arb);
 87    arb->tag = NextChar(h, buf, len);
 88
 89    PORT_Assert(h->state == notDone);
 90
 91  /*
 92   * NOTE: This does not handle the high-tag-number form
 93   */
 94    if ((arb->tag & DER_HIGH_TAG_NUMBER) == DER_HIGH_TAG_NUMBER) {
 95        PORT_SetError(SEC_ERROR_BAD_DER);
 96	h->state = parseError;
 97	return;
 98    }
 99
100    h->pending = UNKNOWN;
101    arb->length = UNKNOWN;
102    if (arb->tag & DER_CONSTRUCTED) {
103	arb->body.cons.numSubs = 0;
104	arb->body.cons.subs = NULL;
105    } else {
106	arb->body.item.len = UNKNOWN;
107	arb->body.item.data = NULL;
108    }
109
110    h->state = tagDone;
111}
112
113static void ParseLength(BERParse *h, unsigned char **buf, int *len)
114{
115    Byte b;
116    SECArb *arb = &(h->stackPtr->arb);
117
118    PORT_Assert(h->state == notDone);
119
120    if (h->pending == UNKNOWN) {
121	b = NextChar(h, buf, len);
122	if ((b & 0x80) == 0) {	/* short form */
123	    arb->length = b;
124	    /*
125	     * if the tag and the length are both zero bytes, then this
126	     * should be the marker showing end of list for the
127	     * indefinite length composite
128	     */
129	    if (arb->length == 0 && arb->tag == 0)
130		h->state = compositeDone;
131	    else
132		h->state = lengthDone;
133	    return;
134	}
135
136	h->pending = b & 0x7f;
137	/* 0 implies this is an indefinite length */
138	if (h->pending > 4) {
139	    PORT_SetError(SEC_ERROR_BAD_DER);
140	    h->state = parseError;
141	    return;
142	}
143	arb->length = 0;
144    }
145
146    while ((*len > 0) && (h->pending > 0)) {
147	b = NextChar(h, buf, len);
148	arb->length = (arb->length << 8) + b;
149	h->pending--;
150    }
151    if (h->pending == 0) {
152	if (h->derOnly && (arb->length == 0))
153	    h->state = parseError;
154	else
155	    h->state = lengthDone;
156    }
157    return;
158}
159
160static void ParseLeaf(BERParse *h, unsigned char **buf, int *len)
161{
162    int count;
163    SECArb *arb = &(h->stackPtr->arb);
164
165    PORT_Assert(h->state == notDone);
166    PORT_Assert(h->pending >= 0);
167
168    if (*len < h->pending)
169	count = *len;
170    else
171	count = h->pending;
172
173    if (h->keepLeaves)
174	memcpy(arb->body.item.data + arb->body.item.len, *buf, count);
175    if (h->filter)
176	(*h->filter)(h->filterArg, *buf, count);
177    *buf += count;
178    *len -= count;
179    arb->body.item.len += count;
180    h->pending -= count;
181    h->pos += count;
182    if (h->pending == 0) {
183	h->state = leafDone;
184    }
185    return;
186}
187
188static void CreateArbNode(BERParse *h)
189{
190    SECArb *arb = PORT_ArenaAlloc(h->his, sizeof(SECArb));
191
192    *arb = h->stackPtr->arb;
193
194    /* 
195     * Special case closing the root
196     */	
197    if (h->stackPtr == h->stack) {
198	PORT_Assert(arb->tag & DER_CONSTRUCTED);
199	h->state = parseComplete;
200    } else {
201	SECArb *parent = h->stackPtr->parent;
202	parent->body.cons.subs = DS_ArenaGrow(
203	    h->his, parent->body.cons.subs,
204	    (parent->body.cons.numSubs) * sizeof(SECArb*),
205	    (parent->body.cons.numSubs + 1) * sizeof(SECArb*));
206	parent->body.cons.subs[parent->body.cons.numSubs] = arb;
207	parent->body.cons.numSubs++;
208	h->proc = ParseTag;
209	h->state = notDone;
210	h->pending = UNKNOWN;
211    }
212    if (h->after)
213	(*h->after)(h->afterArg, arb, h->stackPtr - h->stack, PR_FALSE);
214}
215
216SECStatus BER_ParseSome(BERParse *h, unsigned char *buf, int len)
217{
218    if (h->state == parseError) return PR_TRUE;
219
220    while (len) {
221        (*h->proc)(h, &buf, &len);
222	if (h->state == parseComplete) {
223	    PORT_SetError(SEC_ERROR_BAD_DER);
224	    h->state = parseError;
225	    return PR_TRUE;
226	}
227	if (h->state == parseError) return PR_TRUE;
228	PORT_Assert(h->state != parseComplete);
229
230        if (h->state <= compositeDone) {
231	    if (h->proc == ParseTag) {
232		PORT_Assert(h->state == tagDone);
233		h->proc = ParseLength;
234		h->state = notDone;
235	    } else if (h->proc == ParseLength) {
236		SECArb *arb = &(h->stackPtr->arb);
237		PORT_Assert(h->state == lengthDone || h->state == compositeDone);
238
239		if (h->before)
240		    (*h->before)(h->beforeArg, arb,
241				 h->stackPtr - h->stack, PR_TRUE);
242
243		/*
244		 * Check to see if this is the end of an indefinite
245		 * length composite
246		 */
247		if (h->state == compositeDone) {
248		    SECArb *parent = h->stackPtr->parent;
249		    PORT_Assert(parent);
250		    PORT_Assert(parent->tag & DER_CONSTRUCTED);
251		    if (parent->length != 0) {
252			PORT_SetError(SEC_ERROR_BAD_DER);
253			h->state = parseError;
254			return PR_TRUE;
255		    }
256		    /*
257		     * NOTE: This does not check for an indefinite length
258		     * composite being contained inside a definite length
259		     * composite. It is not clear that is legal.
260		     */
261		    h->stackPtr--;
262		    CreateArbNode(h);
263		} else {
264		    h->stackPtr->pos = h->pos;
265
266
267		    if (arb->tag & DER_CONSTRUCTED) {
268			SECArb *parent;
269			/*
270			 * Make sure there is room on the stack before we
271			 * stick anything else there.
272			 */
273			PORT_Assert(h->stackPtr - h->stack < h->stackDepth);
274			if (h->stackPtr - h->stack == h->stackDepth - 1) {
275			    int newDepth = h->stackDepth * 2;
276			    h->stack = DS_ArenaGrow(h->mine, h->stack,
277				sizeof(ParseStackElem) * h->stackDepth,
278				sizeof(ParseStackElem) * newDepth);
279			    h->stackPtr = h->stack + h->stackDepth + 1;
280			    h->stackDepth = newDepth;
281			}
282			parent = &(h->stackPtr->arb);
283			h->stackPtr++;
284			h->stackPtr->parent = parent;
285			h->proc = ParseTag;
286			h->state = notDone;
287			h->pending = UNKNOWN;
288		    } else {
289			if (arb->length < 0) {
290			    PORT_SetError(SEC_ERROR_BAD_DER);
291			    h->state = parseError;
292			    return PR_TRUE;
293			}
294			arb->body.item.len = 0;
295			if (arb->length > 0 && h->keepLeaves) {
296			    arb->body.item.data =
297				PORT_ArenaAlloc(h->his, arb->length);
298			} else {
299			    arb->body.item.data = NULL;
300			}
301			h->proc = ParseLeaf;
302			h->state = notDone;
303			h->pending = arb->length;
304		    }
305		}
306	    } else {
307		ParseStackElem *parent;
308		PORT_Assert(h->state = leafDone);
309		PORT_Assert(h->proc == ParseLeaf);
310
311		for (;;) {
312		    CreateArbNode(h);
313		    if (h->stackPtr == h->stack)
314			break;
315		    parent = (h->stackPtr - 1);
316		    PORT_Assert(parent->arb.tag & DER_CONSTRUCTED);
317		    if (parent->arb.length == 0) /* need explicit end */
318			break;
319		    if (parent->pos + parent->arb.length > h->pos)
320			break;
321		    if (parent->pos + parent->arb.length < h->pos) {
322			PORT_SetError(SEC_ERROR_BAD_DER);
323			h->state = parseError;
324			return PR_TRUE;
325		    }
326		    h->stackPtr = parent;
327		}
328	    }
329
330	}
331    }
332    return PR_FALSE;
333}
334BERParse *BER_ParseInit(PRArenaPool *arena, PRBool derOnly)
335{
336    BERParse *h;
337    PRArenaPool *temp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
338    if (temp == NULL) {
339	PORT_SetError(SEC_ERROR_NO_MEMORY);
340	return NULL;
341    }
342    h = PORT_ArenaAlloc(temp, sizeof(BERParse));
343    if (h == NULL) {
344	PORT_FreeArena(temp, PR_FALSE);
345	PORT_SetError(SEC_ERROR_NO_MEMORY);
346	return NULL;
347    }
348    h->his = arena;
349    h->mine = temp;
350    h->proc = ParseTag;
351    h->stackDepth = 20;
352    h->stack = PORT_ArenaZAlloc(h->mine,
353			      sizeof(ParseStackElem) * h->stackDepth);
354    h->stackPtr = h->stack;
355    h->state = notDone;
356    h->pos = 0;
357    h->keepLeaves = PR_TRUE;
358    h->before = NULL;
359    h->after = NULL;
360    h->filter = NULL;
361    h->derOnly = derOnly;
362    return h;
363}
364
365SECArb *BER_ParseFini(BERParse *h)
366{
367    PRArenaPool *myArena = h->mine;
368    SECArb *arb;
369
370    if (h->state != parseComplete) {
371	arb = NULL;
372    } else {
373	arb = PORT_ArenaAlloc(h->his, sizeof(SECArb));
374	*arb = h->stackPtr->arb;
375    }
376
377    PORT_FreeArena(myArena, PR_FALSE);
378
379    return arb;
380}
381
382
383void BER_SetFilter(BERParse *h, BERFilterProc proc, void *instance)
384{
385    h->filter = proc;
386    h->filterArg = instance;
387}
388
389void BER_SetLeafStorage(BERParse *h, PRBool keep)
390{
391    h->keepLeaves = keep;
392}
393
394void BER_SetNotifyProc(BERParse *h, BERNotifyProc proc, void *instance,
395			      PRBool beforeData)
396{
397    if (beforeData) {
398	h->before = proc;
399	h->beforeArg = instance;
400    } else {
401	h->after = proc;
402	h->afterArg = instance;
403    }
404}
405
406
407