1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/lib/berparse.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,375 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +#include "secutil.h" 1.8 + 1.9 +typedef enum { 1.10 + tagDone, lengthDone, leafDone, compositeDone, 1.11 + notDone, 1.12 + parseError, parseComplete 1.13 +} ParseState; 1.14 + 1.15 +typedef unsigned char Byte; 1.16 +typedef void (*ParseProc)(BERParse *h, unsigned char **buf, int *len); 1.17 +typedef struct { 1.18 + SECArb arb; 1.19 + int pos; /* length from global start to item start */ 1.20 + SECArb *parent; 1.21 +} ParseStackElem; 1.22 + 1.23 +struct BERParseStr { 1.24 + PLArenaPool *his; 1.25 + PLArenaPool *mine; 1.26 + ParseProc proc; 1.27 + int stackDepth; 1.28 + ParseStackElem *stackPtr; 1.29 + ParseStackElem *stack; 1.30 + int pending; /* bytes remaining to complete this part */ 1.31 + int pos; /* running length of consumed characters */ 1.32 + ParseState state; 1.33 + PRBool keepLeaves; 1.34 + PRBool derOnly; 1.35 + BERFilterProc filter; 1.36 + void *filterArg; 1.37 + BERNotifyProc before; 1.38 + void *beforeArg; 1.39 + BERNotifyProc after; 1.40 + void *afterArg; 1.41 +}; 1.42 + 1.43 +#define UNKNOWN -1 1.44 + 1.45 +static unsigned char NextChar(BERParse *h, unsigned char **buf, int *len) 1.46 +{ 1.47 + unsigned char c = *(*buf)++; 1.48 + (*len)--; 1.49 + h->pos++; 1.50 + if (h->filter) 1.51 + (*h->filter)(h->filterArg, &c, 1); 1.52 + return c; 1.53 +} 1.54 + 1.55 +static void ParseTag(BERParse *h, unsigned char **buf, int *len) 1.56 +{ 1.57 + SECArb* arb = &(h->stackPtr->arb); 1.58 + arb->tag = NextChar(h, buf, len); 1.59 + 1.60 + PORT_Assert(h->state == notDone); 1.61 + 1.62 + /* 1.63 + * NOTE: This does not handle the high-tag-number form 1.64 + */ 1.65 + if ((arb->tag & DER_HIGH_TAG_NUMBER) == DER_HIGH_TAG_NUMBER) { 1.66 + PORT_SetError(SEC_ERROR_BAD_DER); 1.67 + h->state = parseError; 1.68 + return; 1.69 + } 1.70 + 1.71 + h->pending = UNKNOWN; 1.72 + arb->length = UNKNOWN; 1.73 + if (arb->tag & DER_CONSTRUCTED) { 1.74 + arb->body.cons.numSubs = 0; 1.75 + arb->body.cons.subs = NULL; 1.76 + } else { 1.77 + arb->body.item.len = UNKNOWN; 1.78 + arb->body.item.data = NULL; 1.79 + } 1.80 + 1.81 + h->state = tagDone; 1.82 +} 1.83 + 1.84 +static void ParseLength(BERParse *h, unsigned char **buf, int *len) 1.85 +{ 1.86 + Byte b; 1.87 + SECArb *arb = &(h->stackPtr->arb); 1.88 + 1.89 + PORT_Assert(h->state == notDone); 1.90 + 1.91 + if (h->pending == UNKNOWN) { 1.92 + b = NextChar(h, buf, len); 1.93 + if ((b & 0x80) == 0) { /* short form */ 1.94 + arb->length = b; 1.95 + /* 1.96 + * if the tag and the length are both zero bytes, then this 1.97 + * should be the marker showing end of list for the 1.98 + * indefinite length composite 1.99 + */ 1.100 + if (arb->length == 0 && arb->tag == 0) 1.101 + h->state = compositeDone; 1.102 + else 1.103 + h->state = lengthDone; 1.104 + return; 1.105 + } 1.106 + 1.107 + h->pending = b & 0x7f; 1.108 + /* 0 implies this is an indefinite length */ 1.109 + if (h->pending > 4) { 1.110 + PORT_SetError(SEC_ERROR_BAD_DER); 1.111 + h->state = parseError; 1.112 + return; 1.113 + } 1.114 + arb->length = 0; 1.115 + } 1.116 + 1.117 + while ((*len > 0) && (h->pending > 0)) { 1.118 + b = NextChar(h, buf, len); 1.119 + arb->length = (arb->length << 8) + b; 1.120 + h->pending--; 1.121 + } 1.122 + if (h->pending == 0) { 1.123 + if (h->derOnly && (arb->length == 0)) 1.124 + h->state = parseError; 1.125 + else 1.126 + h->state = lengthDone; 1.127 + } 1.128 + return; 1.129 +} 1.130 + 1.131 +static void ParseLeaf(BERParse *h, unsigned char **buf, int *len) 1.132 +{ 1.133 + int count; 1.134 + SECArb *arb = &(h->stackPtr->arb); 1.135 + 1.136 + PORT_Assert(h->state == notDone); 1.137 + PORT_Assert(h->pending >= 0); 1.138 + 1.139 + if (*len < h->pending) 1.140 + count = *len; 1.141 + else 1.142 + count = h->pending; 1.143 + 1.144 + if (h->keepLeaves) 1.145 + memcpy(arb->body.item.data + arb->body.item.len, *buf, count); 1.146 + if (h->filter) 1.147 + (*h->filter)(h->filterArg, *buf, count); 1.148 + *buf += count; 1.149 + *len -= count; 1.150 + arb->body.item.len += count; 1.151 + h->pending -= count; 1.152 + h->pos += count; 1.153 + if (h->pending == 0) { 1.154 + h->state = leafDone; 1.155 + } 1.156 + return; 1.157 +} 1.158 + 1.159 +static void CreateArbNode(BERParse *h) 1.160 +{ 1.161 + SECArb *arb = PORT_ArenaAlloc(h->his, sizeof(SECArb)); 1.162 + 1.163 + *arb = h->stackPtr->arb; 1.164 + 1.165 + /* 1.166 + * Special case closing the root 1.167 + */ 1.168 + if (h->stackPtr == h->stack) { 1.169 + PORT_Assert(arb->tag & DER_CONSTRUCTED); 1.170 + h->state = parseComplete; 1.171 + } else { 1.172 + SECArb *parent = h->stackPtr->parent; 1.173 + parent->body.cons.subs = DS_ArenaGrow( 1.174 + h->his, parent->body.cons.subs, 1.175 + (parent->body.cons.numSubs) * sizeof(SECArb*), 1.176 + (parent->body.cons.numSubs + 1) * sizeof(SECArb*)); 1.177 + parent->body.cons.subs[parent->body.cons.numSubs] = arb; 1.178 + parent->body.cons.numSubs++; 1.179 + h->proc = ParseTag; 1.180 + h->state = notDone; 1.181 + h->pending = UNKNOWN; 1.182 + } 1.183 + if (h->after) 1.184 + (*h->after)(h->afterArg, arb, h->stackPtr - h->stack, PR_FALSE); 1.185 +} 1.186 + 1.187 +SECStatus BER_ParseSome(BERParse *h, unsigned char *buf, int len) 1.188 +{ 1.189 + if (h->state == parseError) return PR_TRUE; 1.190 + 1.191 + while (len) { 1.192 + (*h->proc)(h, &buf, &len); 1.193 + if (h->state == parseComplete) { 1.194 + PORT_SetError(SEC_ERROR_BAD_DER); 1.195 + h->state = parseError; 1.196 + return PR_TRUE; 1.197 + } 1.198 + if (h->state == parseError) return PR_TRUE; 1.199 + PORT_Assert(h->state != parseComplete); 1.200 + 1.201 + if (h->state <= compositeDone) { 1.202 + if (h->proc == ParseTag) { 1.203 + PORT_Assert(h->state == tagDone); 1.204 + h->proc = ParseLength; 1.205 + h->state = notDone; 1.206 + } else if (h->proc == ParseLength) { 1.207 + SECArb *arb = &(h->stackPtr->arb); 1.208 + PORT_Assert(h->state == lengthDone || h->state == compositeDone); 1.209 + 1.210 + if (h->before) 1.211 + (*h->before)(h->beforeArg, arb, 1.212 + h->stackPtr - h->stack, PR_TRUE); 1.213 + 1.214 + /* 1.215 + * Check to see if this is the end of an indefinite 1.216 + * length composite 1.217 + */ 1.218 + if (h->state == compositeDone) { 1.219 + SECArb *parent = h->stackPtr->parent; 1.220 + PORT_Assert(parent); 1.221 + PORT_Assert(parent->tag & DER_CONSTRUCTED); 1.222 + if (parent->length != 0) { 1.223 + PORT_SetError(SEC_ERROR_BAD_DER); 1.224 + h->state = parseError; 1.225 + return PR_TRUE; 1.226 + } 1.227 + /* 1.228 + * NOTE: This does not check for an indefinite length 1.229 + * composite being contained inside a definite length 1.230 + * composite. It is not clear that is legal. 1.231 + */ 1.232 + h->stackPtr--; 1.233 + CreateArbNode(h); 1.234 + } else { 1.235 + h->stackPtr->pos = h->pos; 1.236 + 1.237 + 1.238 + if (arb->tag & DER_CONSTRUCTED) { 1.239 + SECArb *parent; 1.240 + /* 1.241 + * Make sure there is room on the stack before we 1.242 + * stick anything else there. 1.243 + */ 1.244 + PORT_Assert(h->stackPtr - h->stack < h->stackDepth); 1.245 + if (h->stackPtr - h->stack == h->stackDepth - 1) { 1.246 + int newDepth = h->stackDepth * 2; 1.247 + h->stack = DS_ArenaGrow(h->mine, h->stack, 1.248 + sizeof(ParseStackElem) * h->stackDepth, 1.249 + sizeof(ParseStackElem) * newDepth); 1.250 + h->stackPtr = h->stack + h->stackDepth + 1; 1.251 + h->stackDepth = newDepth; 1.252 + } 1.253 + parent = &(h->stackPtr->arb); 1.254 + h->stackPtr++; 1.255 + h->stackPtr->parent = parent; 1.256 + h->proc = ParseTag; 1.257 + h->state = notDone; 1.258 + h->pending = UNKNOWN; 1.259 + } else { 1.260 + if (arb->length < 0) { 1.261 + PORT_SetError(SEC_ERROR_BAD_DER); 1.262 + h->state = parseError; 1.263 + return PR_TRUE; 1.264 + } 1.265 + arb->body.item.len = 0; 1.266 + if (arb->length > 0 && h->keepLeaves) { 1.267 + arb->body.item.data = 1.268 + PORT_ArenaAlloc(h->his, arb->length); 1.269 + } else { 1.270 + arb->body.item.data = NULL; 1.271 + } 1.272 + h->proc = ParseLeaf; 1.273 + h->state = notDone; 1.274 + h->pending = arb->length; 1.275 + } 1.276 + } 1.277 + } else { 1.278 + ParseStackElem *parent; 1.279 + PORT_Assert(h->state = leafDone); 1.280 + PORT_Assert(h->proc == ParseLeaf); 1.281 + 1.282 + for (;;) { 1.283 + CreateArbNode(h); 1.284 + if (h->stackPtr == h->stack) 1.285 + break; 1.286 + parent = (h->stackPtr - 1); 1.287 + PORT_Assert(parent->arb.tag & DER_CONSTRUCTED); 1.288 + if (parent->arb.length == 0) /* need explicit end */ 1.289 + break; 1.290 + if (parent->pos + parent->arb.length > h->pos) 1.291 + break; 1.292 + if (parent->pos + parent->arb.length < h->pos) { 1.293 + PORT_SetError(SEC_ERROR_BAD_DER); 1.294 + h->state = parseError; 1.295 + return PR_TRUE; 1.296 + } 1.297 + h->stackPtr = parent; 1.298 + } 1.299 + } 1.300 + 1.301 + } 1.302 + } 1.303 + return PR_FALSE; 1.304 +} 1.305 +BERParse *BER_ParseInit(PLArenaPool *arena, PRBool derOnly) 1.306 +{ 1.307 + BERParse *h; 1.308 + PLArenaPool *temp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.309 + if (temp == NULL) { 1.310 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.311 + return NULL; 1.312 + } 1.313 + h = PORT_ArenaAlloc(temp, sizeof(BERParse)); 1.314 + if (h == NULL) { 1.315 + PORT_FreeArena(temp, PR_FALSE); 1.316 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.317 + return NULL; 1.318 + } 1.319 + h->his = arena; 1.320 + h->mine = temp; 1.321 + h->proc = ParseTag; 1.322 + h->stackDepth = 20; 1.323 + h->stack = PORT_ArenaZAlloc(h->mine, 1.324 + sizeof(ParseStackElem) * h->stackDepth); 1.325 + h->stackPtr = h->stack; 1.326 + h->state = notDone; 1.327 + h->pos = 0; 1.328 + h->keepLeaves = PR_TRUE; 1.329 + h->before = NULL; 1.330 + h->after = NULL; 1.331 + h->filter = NULL; 1.332 + h->derOnly = derOnly; 1.333 + return h; 1.334 +} 1.335 + 1.336 +SECArb *BER_ParseFini(BERParse *h) 1.337 +{ 1.338 + PLArenaPool *myArena = h->mine; 1.339 + SECArb *arb; 1.340 + 1.341 + if (h->state != parseComplete) { 1.342 + arb = NULL; 1.343 + } else { 1.344 + arb = PORT_ArenaAlloc(h->his, sizeof(SECArb)); 1.345 + *arb = h->stackPtr->arb; 1.346 + } 1.347 + 1.348 + PORT_FreeArena(myArena, PR_FALSE); 1.349 + 1.350 + return arb; 1.351 +} 1.352 + 1.353 + 1.354 +void BER_SetFilter(BERParse *h, BERFilterProc proc, void *instance) 1.355 +{ 1.356 + h->filter = proc; 1.357 + h->filterArg = instance; 1.358 +} 1.359 + 1.360 +void BER_SetLeafStorage(BERParse *h, PRBool keep) 1.361 +{ 1.362 + h->keepLeaves = keep; 1.363 +} 1.364 + 1.365 +void BER_SetNotifyProc(BERParse *h, BERNotifyProc proc, void *instance, 1.366 + PRBool beforeData) 1.367 +{ 1.368 + if (beforeData) { 1.369 + h->before = proc; 1.370 + h->beforeArg = instance; 1.371 + } else { 1.372 + h->after = proc; 1.373 + h->afterArg = instance; 1.374 + } 1.375 +} 1.376 + 1.377 + 1.378 +