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