1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
39 tagDone
, lengthDone
, leafDone
, compositeDone
,
41 parseError
, parseComplete
44 typedef unsigned char Byte
;
45 typedef void (*ParseProc
)(BERParse
*h
, unsigned char **buf
, int *len
);
48 int pos
; /* length from global start to item start */
57 ParseStackElem
*stackPtr
;
58 ParseStackElem
*stack
;
59 int pending
; /* bytes remaining to complete this part */
60 int pos
; /* running length of consumed characters */
74 static unsigned char NextChar(BERParse
*h
, unsigned char **buf
, int *len
)
76 unsigned char c
= *(*buf
)++;
80 (*h
->filter
)(h
->filterArg
, &c
, 1);
84 static void ParseTag(BERParse
*h
, unsigned char **buf
, int *len
)
86 SECArb
* arb
= &(h
->stackPtr
->arb
);
87 arb
->tag
= NextChar(h
, buf
, len
);
89 PORT_Assert(h
->state
== notDone
);
92 * NOTE: This does not handle the high-tag-number form
94 if ((arb
->tag
& DER_HIGH_TAG_NUMBER
) == DER_HIGH_TAG_NUMBER
) {
95 PORT_SetError(SEC_ERROR_BAD_DER
);
96 h
->state
= parseError
;
100 h
->pending
= UNKNOWN
;
101 arb
->length
= UNKNOWN
;
102 if (arb
->tag
& DER_CONSTRUCTED
) {
103 arb
->body
.cons
.numSubs
= 0;
104 arb
->body
.cons
.subs
= NULL
;
106 arb
->body
.item
.len
= UNKNOWN
;
107 arb
->body
.item
.data
= NULL
;
113 static void ParseLength(BERParse
*h
, unsigned char **buf
, int *len
)
116 SECArb
*arb
= &(h
->stackPtr
->arb
);
118 PORT_Assert(h
->state
== notDone
);
120 if (h
->pending
== UNKNOWN
) {
121 b
= NextChar(h
, buf
, len
);
122 if ((b
& 0x80) == 0) { /* short form */
125 * if the tag and the length are both zero bytes, then this
126 * should be the marker showing end of list for the
127 * indefinite length composite
129 if (arb
->length
== 0 && arb
->tag
== 0)
130 h
->state
= compositeDone
;
132 h
->state
= lengthDone
;
136 h
->pending
= b
& 0x7f;
137 /* 0 implies this is an indefinite length */
138 if (h
->pending
> 4) {
139 PORT_SetError(SEC_ERROR_BAD_DER
);
140 h
->state
= parseError
;
146 while ((*len
> 0) && (h
->pending
> 0)) {
147 b
= NextChar(h
, buf
, len
);
148 arb
->length
= (arb
->length
<< 8) + b
;
151 if (h
->pending
== 0) {
152 if (h
->derOnly
&& (arb
->length
== 0))
153 h
->state
= parseError
;
155 h
->state
= lengthDone
;
160 static void ParseLeaf(BERParse
*h
, unsigned char **buf
, int *len
)
163 SECArb
*arb
= &(h
->stackPtr
->arb
);
165 PORT_Assert(h
->state
== notDone
);
166 PORT_Assert(h
->pending
>= 0);
168 if (*len
< h
->pending
)
174 memcpy(arb
->body
.item
.data
+ arb
->body
.item
.len
, *buf
, count
);
176 (*h
->filter
)(h
->filterArg
, *buf
, count
);
179 arb
->body
.item
.len
+= count
;
182 if (h
->pending
== 0) {
188 static void CreateArbNode(BERParse
*h
)
190 SECArb
*arb
= PORT_ArenaAlloc(h
->his
, sizeof(SECArb
));
192 *arb
= h
->stackPtr
->arb
;
195 * Special case closing the root
197 if (h
->stackPtr
== h
->stack
) {
198 PORT_Assert(arb
->tag
& DER_CONSTRUCTED
);
199 h
->state
= parseComplete
;
201 SECArb
*parent
= h
->stackPtr
->parent
;
202 parent
->body
.cons
.subs
= DS_ArenaGrow(
203 h
->his
, parent
->body
.cons
.subs
,
204 (parent
->body
.cons
.numSubs
) * sizeof(SECArb
*),
205 (parent
->body
.cons
.numSubs
+ 1) * sizeof(SECArb
*));
206 parent
->body
.cons
.subs
[parent
->body
.cons
.numSubs
] = arb
;
207 parent
->body
.cons
.numSubs
++;
210 h
->pending
= UNKNOWN
;
213 (*h
->after
)(h
->afterArg
, arb
, h
->stackPtr
- h
->stack
, PR_FALSE
);
216 SECStatus
BER_ParseSome(BERParse
*h
, unsigned char *buf
, int len
)
218 if (h
->state
== parseError
) return PR_TRUE
;
221 (*h
->proc
)(h
, &buf
, &len
);
222 if (h
->state
== parseComplete
) {
223 PORT_SetError(SEC_ERROR_BAD_DER
);
224 h
->state
= parseError
;
227 if (h
->state
== parseError
) return PR_TRUE
;
228 PORT_Assert(h
->state
!= parseComplete
);
230 if (h
->state
<= compositeDone
) {
231 if (h
->proc
== ParseTag
) {
232 PORT_Assert(h
->state
== tagDone
);
233 h
->proc
= ParseLength
;
235 } else if (h
->proc
== ParseLength
) {
236 SECArb
*arb
= &(h
->stackPtr
->arb
);
237 PORT_Assert(h
->state
== lengthDone
|| h
->state
== compositeDone
);
240 (*h
->before
)(h
->beforeArg
, arb
,
241 h
->stackPtr
- h
->stack
, PR_TRUE
);
244 * Check to see if this is the end of an indefinite
247 if (h
->state
== compositeDone
) {
248 SECArb
*parent
= h
->stackPtr
->parent
;
250 PORT_Assert(parent
->tag
& DER_CONSTRUCTED
);
251 if (parent
->length
!= 0) {
252 PORT_SetError(SEC_ERROR_BAD_DER
);
253 h
->state
= parseError
;
257 * NOTE: This does not check for an indefinite length
258 * composite being contained inside a definite length
259 * composite. It is not clear that is legal.
264 h
->stackPtr
->pos
= h
->pos
;
267 if (arb
->tag
& DER_CONSTRUCTED
) {
270 * Make sure there is room on the stack before we
271 * stick anything else there.
273 PORT_Assert(h
->stackPtr
- h
->stack
< h
->stackDepth
);
274 if (h
->stackPtr
- h
->stack
== h
->stackDepth
- 1) {
275 int newDepth
= h
->stackDepth
* 2;
276 h
->stack
= DS_ArenaGrow(h
->mine
, h
->stack
,
277 sizeof(ParseStackElem
) * h
->stackDepth
,
278 sizeof(ParseStackElem
) * newDepth
);
279 h
->stackPtr
= h
->stack
+ h
->stackDepth
+ 1;
280 h
->stackDepth
= newDepth
;
282 parent
= &(h
->stackPtr
->arb
);
284 h
->stackPtr
->parent
= parent
;
287 h
->pending
= UNKNOWN
;
289 if (arb
->length
< 0) {
290 PORT_SetError(SEC_ERROR_BAD_DER
);
291 h
->state
= parseError
;
294 arb
->body
.item
.len
= 0;
295 if (arb
->length
> 0 && h
->keepLeaves
) {
296 arb
->body
.item
.data
=
297 PORT_ArenaAlloc(h
->his
, arb
->length
);
299 arb
->body
.item
.data
= NULL
;
303 h
->pending
= arb
->length
;
307 ParseStackElem
*parent
;
308 PORT_Assert(h
->state
= leafDone
);
309 PORT_Assert(h
->proc
== ParseLeaf
);
313 if (h
->stackPtr
== h
->stack
)
315 parent
= (h
->stackPtr
- 1);
316 PORT_Assert(parent
->arb
.tag
& DER_CONSTRUCTED
);
317 if (parent
->arb
.length
== 0) /* need explicit end */
319 if (parent
->pos
+ parent
->arb
.length
> h
->pos
)
321 if (parent
->pos
+ parent
->arb
.length
< h
->pos
) {
322 PORT_SetError(SEC_ERROR_BAD_DER
);
323 h
->state
= parseError
;
326 h
->stackPtr
= parent
;
334 BERParse
*BER_ParseInit(PRArenaPool
*arena
, PRBool derOnly
)
337 PRArenaPool
*temp
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
339 PORT_SetError(SEC_ERROR_NO_MEMORY
);
342 h
= PORT_ArenaAlloc(temp
, sizeof(BERParse
));
344 PORT_FreeArena(temp
, PR_FALSE
);
345 PORT_SetError(SEC_ERROR_NO_MEMORY
);
352 h
->stack
= PORT_ArenaZAlloc(h
->mine
,
353 sizeof(ParseStackElem
) * h
->stackDepth
);
354 h
->stackPtr
= h
->stack
;
357 h
->keepLeaves
= PR_TRUE
;
361 h
->derOnly
= derOnly
;
365 SECArb
*BER_ParseFini(BERParse
*h
)
367 PRArenaPool
*myArena
= h
->mine
;
370 if (h
->state
!= parseComplete
) {
373 arb
= PORT_ArenaAlloc(h
->his
, sizeof(SECArb
));
374 *arb
= h
->stackPtr
->arb
;
377 PORT_FreeArena(myArena
, PR_FALSE
);
383 void BER_SetFilter(BERParse
*h
, BERFilterProc proc
, void *instance
)
386 h
->filterArg
= instance
;
389 void BER_SetLeafStorage(BERParse
*h
, PRBool keep
)
391 h
->keepLeaves
= keep
;
394 void BER_SetNotifyProc(BERParse
*h
, BERNotifyProc proc
, void *instance
,
399 h
->beforeArg
= instance
;
402 h
->afterArg
= instance
;