security/nss/cmd/lib/berparse.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     4 #include "secutil.h"
     6 typedef enum {
     7     tagDone, lengthDone, leafDone, compositeDone,
     8     notDone,
     9     parseError, parseComplete
    10 } ParseState;
    12 typedef unsigned char Byte;
    13 typedef void (*ParseProc)(BERParse *h, unsigned char **buf, int *len);
    14 typedef struct {
    15     SECArb arb;
    16     int pos;			/* length from global start to item start */
    17     SECArb *parent;
    18 } ParseStackElem;
    20 struct BERParseStr {
    21     PLArenaPool *his;
    22     PLArenaPool *mine;
    23     ParseProc proc;
    24     int stackDepth;
    25     ParseStackElem *stackPtr;
    26     ParseStackElem *stack;
    27     int pending;		/* bytes remaining to complete this part */
    28     int pos;			/* running length of consumed characters */
    29     ParseState state;
    30     PRBool keepLeaves;
    31     PRBool derOnly;
    32     BERFilterProc filter;
    33     void *filterArg;
    34     BERNotifyProc before;
    35     void *beforeArg;
    36     BERNotifyProc after;
    37     void *afterArg;
    38 };
    40 #define UNKNOWN -1
    42 static unsigned char NextChar(BERParse *h, unsigned char **buf, int *len)
    43 {
    44     unsigned char c = *(*buf)++;
    45     (*len)--;
    46     h->pos++;
    47     if (h->filter)
    48 	(*h->filter)(h->filterArg, &c, 1);
    49     return c;
    50 }
    52 static void ParseTag(BERParse *h, unsigned char **buf, int *len)
    53 {
    54     SECArb* arb = &(h->stackPtr->arb);
    55     arb->tag = NextChar(h, buf, len);
    57     PORT_Assert(h->state == notDone);
    59   /*
    60    * NOTE: This does not handle the high-tag-number form
    61    */
    62     if ((arb->tag & DER_HIGH_TAG_NUMBER) == DER_HIGH_TAG_NUMBER) {
    63         PORT_SetError(SEC_ERROR_BAD_DER);
    64 	h->state = parseError;
    65 	return;
    66     }
    68     h->pending = UNKNOWN;
    69     arb->length = UNKNOWN;
    70     if (arb->tag & DER_CONSTRUCTED) {
    71 	arb->body.cons.numSubs = 0;
    72 	arb->body.cons.subs = NULL;
    73     } else {
    74 	arb->body.item.len = UNKNOWN;
    75 	arb->body.item.data = NULL;
    76     }
    78     h->state = tagDone;
    79 }
    81 static void ParseLength(BERParse *h, unsigned char **buf, int *len)
    82 {
    83     Byte b;
    84     SECArb *arb = &(h->stackPtr->arb);
    86     PORT_Assert(h->state == notDone);
    88     if (h->pending == UNKNOWN) {
    89 	b = NextChar(h, buf, len);
    90 	if ((b & 0x80) == 0) {	/* short form */
    91 	    arb->length = b;
    92 	    /*
    93 	     * if the tag and the length are both zero bytes, then this
    94 	     * should be the marker showing end of list for the
    95 	     * indefinite length composite
    96 	     */
    97 	    if (arb->length == 0 && arb->tag == 0)
    98 		h->state = compositeDone;
    99 	    else
   100 		h->state = lengthDone;
   101 	    return;
   102 	}
   104 	h->pending = b & 0x7f;
   105 	/* 0 implies this is an indefinite length */
   106 	if (h->pending > 4) {
   107 	    PORT_SetError(SEC_ERROR_BAD_DER);
   108 	    h->state = parseError;
   109 	    return;
   110 	}
   111 	arb->length = 0;
   112     }
   114     while ((*len > 0) && (h->pending > 0)) {
   115 	b = NextChar(h, buf, len);
   116 	arb->length = (arb->length << 8) + b;
   117 	h->pending--;
   118     }
   119     if (h->pending == 0) {
   120 	if (h->derOnly && (arb->length == 0))
   121 	    h->state = parseError;
   122 	else
   123 	    h->state = lengthDone;
   124     }
   125     return;
   126 }
   128 static void ParseLeaf(BERParse *h, unsigned char **buf, int *len)
   129 {
   130     int count;
   131     SECArb *arb = &(h->stackPtr->arb);
   133     PORT_Assert(h->state == notDone);
   134     PORT_Assert(h->pending >= 0);
   136     if (*len < h->pending)
   137 	count = *len;
   138     else
   139 	count = h->pending;
   141     if (h->keepLeaves)
   142 	memcpy(arb->body.item.data + arb->body.item.len, *buf, count);
   143     if (h->filter)
   144 	(*h->filter)(h->filterArg, *buf, count);
   145     *buf += count;
   146     *len -= count;
   147     arb->body.item.len += count;
   148     h->pending -= count;
   149     h->pos += count;
   150     if (h->pending == 0) {
   151 	h->state = leafDone;
   152     }
   153     return;
   154 }
   156 static void CreateArbNode(BERParse *h)
   157 {
   158     SECArb *arb = PORT_ArenaAlloc(h->his, sizeof(SECArb));
   160     *arb = h->stackPtr->arb;
   162     /* 
   163      * Special case closing the root
   164      */	
   165     if (h->stackPtr == h->stack) {
   166 	PORT_Assert(arb->tag & DER_CONSTRUCTED);
   167 	h->state = parseComplete;
   168     } else {
   169 	SECArb *parent = h->stackPtr->parent;
   170 	parent->body.cons.subs = DS_ArenaGrow(
   171 	    h->his, parent->body.cons.subs,
   172 	    (parent->body.cons.numSubs) * sizeof(SECArb*),
   173 	    (parent->body.cons.numSubs + 1) * sizeof(SECArb*));
   174 	parent->body.cons.subs[parent->body.cons.numSubs] = arb;
   175 	parent->body.cons.numSubs++;
   176 	h->proc = ParseTag;
   177 	h->state = notDone;
   178 	h->pending = UNKNOWN;
   179     }
   180     if (h->after)
   181 	(*h->after)(h->afterArg, arb, h->stackPtr - h->stack, PR_FALSE);
   182 }
   184 SECStatus BER_ParseSome(BERParse *h, unsigned char *buf, int len)
   185 {
   186     if (h->state == parseError) return PR_TRUE;
   188     while (len) {
   189         (*h->proc)(h, &buf, &len);
   190 	if (h->state == parseComplete) {
   191 	    PORT_SetError(SEC_ERROR_BAD_DER);
   192 	    h->state = parseError;
   193 	    return PR_TRUE;
   194 	}
   195 	if (h->state == parseError) return PR_TRUE;
   196 	PORT_Assert(h->state != parseComplete);
   198         if (h->state <= compositeDone) {
   199 	    if (h->proc == ParseTag) {
   200 		PORT_Assert(h->state == tagDone);
   201 		h->proc = ParseLength;
   202 		h->state = notDone;
   203 	    } else if (h->proc == ParseLength) {
   204 		SECArb *arb = &(h->stackPtr->arb);
   205 		PORT_Assert(h->state == lengthDone || h->state == compositeDone);
   207 		if (h->before)
   208 		    (*h->before)(h->beforeArg, arb,
   209 				 h->stackPtr - h->stack, PR_TRUE);
   211 		/*
   212 		 * Check to see if this is the end of an indefinite
   213 		 * length composite
   214 		 */
   215 		if (h->state == compositeDone) {
   216 		    SECArb *parent = h->stackPtr->parent;
   217 		    PORT_Assert(parent);
   218 		    PORT_Assert(parent->tag & DER_CONSTRUCTED);
   219 		    if (parent->length != 0) {
   220 			PORT_SetError(SEC_ERROR_BAD_DER);
   221 			h->state = parseError;
   222 			return PR_TRUE;
   223 		    }
   224 		    /*
   225 		     * NOTE: This does not check for an indefinite length
   226 		     * composite being contained inside a definite length
   227 		     * composite. It is not clear that is legal.
   228 		     */
   229 		    h->stackPtr--;
   230 		    CreateArbNode(h);
   231 		} else {
   232 		    h->stackPtr->pos = h->pos;
   235 		    if (arb->tag & DER_CONSTRUCTED) {
   236 			SECArb *parent;
   237 			/*
   238 			 * Make sure there is room on the stack before we
   239 			 * stick anything else there.
   240 			 */
   241 			PORT_Assert(h->stackPtr - h->stack < h->stackDepth);
   242 			if (h->stackPtr - h->stack == h->stackDepth - 1) {
   243 			    int newDepth = h->stackDepth * 2;
   244 			    h->stack = DS_ArenaGrow(h->mine, h->stack,
   245 				sizeof(ParseStackElem) * h->stackDepth,
   246 				sizeof(ParseStackElem) * newDepth);
   247 			    h->stackPtr = h->stack + h->stackDepth + 1;
   248 			    h->stackDepth = newDepth;
   249 			}
   250 			parent = &(h->stackPtr->arb);
   251 			h->stackPtr++;
   252 			h->stackPtr->parent = parent;
   253 			h->proc = ParseTag;
   254 			h->state = notDone;
   255 			h->pending = UNKNOWN;
   256 		    } else {
   257 			if (arb->length < 0) {
   258 			    PORT_SetError(SEC_ERROR_BAD_DER);
   259 			    h->state = parseError;
   260 			    return PR_TRUE;
   261 			}
   262 			arb->body.item.len = 0;
   263 			if (arb->length > 0 && h->keepLeaves) {
   264 			    arb->body.item.data =
   265 				PORT_ArenaAlloc(h->his, arb->length);
   266 			} else {
   267 			    arb->body.item.data = NULL;
   268 			}
   269 			h->proc = ParseLeaf;
   270 			h->state = notDone;
   271 			h->pending = arb->length;
   272 		    }
   273 		}
   274 	    } else {
   275 		ParseStackElem *parent;
   276 		PORT_Assert(h->state = leafDone);
   277 		PORT_Assert(h->proc == ParseLeaf);
   279 		for (;;) {
   280 		    CreateArbNode(h);
   281 		    if (h->stackPtr == h->stack)
   282 			break;
   283 		    parent = (h->stackPtr - 1);
   284 		    PORT_Assert(parent->arb.tag & DER_CONSTRUCTED);
   285 		    if (parent->arb.length == 0) /* need explicit end */
   286 			break;
   287 		    if (parent->pos + parent->arb.length > h->pos)
   288 			break;
   289 		    if (parent->pos + parent->arb.length < h->pos) {
   290 			PORT_SetError(SEC_ERROR_BAD_DER);
   291 			h->state = parseError;
   292 			return PR_TRUE;
   293 		    }
   294 		    h->stackPtr = parent;
   295 		}
   296 	    }
   298 	}
   299     }
   300     return PR_FALSE;
   301 }
   302 BERParse *BER_ParseInit(PLArenaPool *arena, PRBool derOnly)
   303 {
   304     BERParse *h;
   305     PLArenaPool *temp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   306     if (temp == NULL) {
   307 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   308 	return NULL;
   309     }
   310     h = PORT_ArenaAlloc(temp, sizeof(BERParse));
   311     if (h == NULL) {
   312 	PORT_FreeArena(temp, PR_FALSE);
   313 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   314 	return NULL;
   315     }
   316     h->his = arena;
   317     h->mine = temp;
   318     h->proc = ParseTag;
   319     h->stackDepth = 20;
   320     h->stack = PORT_ArenaZAlloc(h->mine,
   321 			      sizeof(ParseStackElem) * h->stackDepth);
   322     h->stackPtr = h->stack;
   323     h->state = notDone;
   324     h->pos = 0;
   325     h->keepLeaves = PR_TRUE;
   326     h->before = NULL;
   327     h->after = NULL;
   328     h->filter = NULL;
   329     h->derOnly = derOnly;
   330     return h;
   331 }
   333 SECArb *BER_ParseFini(BERParse *h)
   334 {
   335     PLArenaPool *myArena = h->mine;
   336     SECArb *arb;
   338     if (h->state != parseComplete) {
   339 	arb = NULL;
   340     } else {
   341 	arb = PORT_ArenaAlloc(h->his, sizeof(SECArb));
   342 	*arb = h->stackPtr->arb;
   343     }
   345     PORT_FreeArena(myArena, PR_FALSE);
   347     return arb;
   348 }
   351 void BER_SetFilter(BERParse *h, BERFilterProc proc, void *instance)
   352 {
   353     h->filter = proc;
   354     h->filterArg = instance;
   355 }
   357 void BER_SetLeafStorage(BERParse *h, PRBool keep)
   358 {
   359     h->keepLeaves = keep;
   360 }
   362 void BER_SetNotifyProc(BERParse *h, BERNotifyProc proc, void *instance,
   363 			      PRBool beforeData)
   364 {
   365     if (beforeData) {
   366 	h->before = proc;
   367 	h->beforeArg = instance;
   368     } else {
   369 	h->after = proc;
   370 	h->afterArg = instance;
   371     }
   372 }

mercurial