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