security/nss/cmd/lib/berparse.c

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

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

mercurial