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
NextChar(BERParse * h,unsigned char ** buf,int * len)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
ParseTag(BERParse * h,unsigned char ** buf,int * len)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
ParseLength(BERParse * h,unsigned char ** buf,int * len)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
ParseLeaf(BERParse * h,unsigned char ** buf,int * len)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
CreateArbNode(BERParse * h)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
BER_ParseSome(BERParse * h,unsigned char * buf,int len)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 *
BER_ParseInit(PLArenaPool * arena,PRBool derOnly)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 *
BER_ParseFini(BERParse * h)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
BER_SetFilter(BERParse * h,BERFilterProc proc,void * instance)365 BER_SetFilter(BERParse *h, BERFilterProc proc, void *instance)
366 {
367 h->filter = proc;
368 h->filterArg = instance;
369 }
370
371 void
BER_SetLeafStorage(BERParse * h,PRBool keep)372 BER_SetLeafStorage(BERParse *h, PRBool keep)
373 {
374 h->keepLeaves = keep;
375 }
376
377 void
BER_SetNotifyProc(BERParse * h,BERNotifyProc proc,void * instance,PRBool beforeData)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 }
389