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