/src/nss-nspr/nss/lib/util/quickder.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
5 | | /* |
6 | | Optimized ASN.1 DER decoder |
7 | | */ |
8 | | |
9 | | #include "secerr.h" |
10 | | #include "secasn1.h" /* for SEC_ASN1GetSubtemplate */ |
11 | | #include "secitem.h" |
12 | | |
13 | | /* |
14 | | * simple definite-length ASN.1 decoder |
15 | | */ |
16 | | |
17 | | static unsigned char* |
18 | | definite_length_decoder(const unsigned char* buf, |
19 | | const unsigned int buf_length, |
20 | | unsigned int* out_data_length, |
21 | | PRBool includeTag) |
22 | 0 | { |
23 | 0 | unsigned char tag; |
24 | 0 | unsigned int used_length = 0; |
25 | 0 | unsigned int data_length = 0; |
26 | 0 | unsigned char length_field_len = 0; |
27 | 0 | unsigned char byte; |
28 | 0 | unsigned int i; |
29 | |
|
30 | 0 | if (used_length >= buf_length) { |
31 | | /* Tag field was not found! */ |
32 | 0 | return NULL; |
33 | 0 | } |
34 | 0 | tag = buf[used_length++]; |
35 | |
|
36 | 0 | if (tag == 0) { |
37 | | /* End-of-contents octects should not be present in DER because |
38 | | DER doesn't use the indefinite length form. */ |
39 | 0 | return NULL; |
40 | 0 | } |
41 | | |
42 | 0 | if ((tag & 0x1F) == 0x1F) { |
43 | | /* High tag number (a tag number > 30) is not supported */ |
44 | 0 | return NULL; |
45 | 0 | } |
46 | | |
47 | 0 | if (used_length >= buf_length) { |
48 | | /* Length field was not found! */ |
49 | 0 | return NULL; |
50 | 0 | } |
51 | 0 | byte = buf[used_length++]; |
52 | |
|
53 | 0 | if (!(byte & 0x80)) { |
54 | | /* Short form: The high bit is not set. */ |
55 | 0 | data_length = byte; /* clarity; we're returning a 32-bit int. */ |
56 | 0 | } else { |
57 | | /* Long form. Extract the field length */ |
58 | 0 | length_field_len = byte & 0x7F; |
59 | 0 | if (length_field_len == 0) { |
60 | | /* DER doesn't use the indefinite length form. */ |
61 | 0 | return NULL; |
62 | 0 | } |
63 | | |
64 | 0 | if (length_field_len > sizeof(data_length)) { |
65 | | /* We don't support an extended length field longer than |
66 | | 4 bytes (2^32) */ |
67 | 0 | return NULL; |
68 | 0 | } |
69 | | |
70 | 0 | if (length_field_len > (buf_length - used_length)) { |
71 | | /* Extended length field was not found */ |
72 | 0 | return NULL; |
73 | 0 | } |
74 | | |
75 | | /* Iterate across the extended length field */ |
76 | 0 | for (i = 0; i < length_field_len; i++) { |
77 | 0 | byte = buf[used_length++]; |
78 | 0 | data_length = (data_length << 8) | byte; |
79 | |
|
80 | 0 | if (i == 0) { |
81 | 0 | PRBool too_long = PR_FALSE; |
82 | 0 | if (length_field_len == 1) { |
83 | 0 | too_long = ((byte & 0x80) == 0); /* Short form suffices */ |
84 | 0 | } else { |
85 | 0 | too_long = (byte == 0); /* This zero byte can be omitted */ |
86 | 0 | } |
87 | 0 | if (too_long) { |
88 | | /* The length is longer than needed. */ |
89 | 0 | return NULL; |
90 | 0 | } |
91 | 0 | } |
92 | 0 | } |
93 | 0 | } |
94 | | |
95 | 0 | if ((tag & SEC_ASN1_TAGNUM_MASK) == SEC_ASN1_NULL && data_length != 0) { |
96 | | /* The DER encoding of NULL has no contents octets */ |
97 | 0 | return NULL; |
98 | 0 | } |
99 | | |
100 | 0 | if (data_length > (buf_length - used_length)) { |
101 | | /* The decoded length exceeds the available buffer */ |
102 | 0 | return NULL; |
103 | 0 | } |
104 | | |
105 | 0 | if (includeTag) { |
106 | 0 | data_length += used_length; |
107 | 0 | } |
108 | |
|
109 | 0 | *out_data_length = data_length; |
110 | 0 | return ((unsigned char*)buf + (includeTag ? 0 : used_length)); |
111 | 0 | } |
112 | | |
113 | | static SECStatus |
114 | | GetItem(SECItem* src, SECItem* dest, PRBool includeTag) |
115 | 0 | { |
116 | 0 | if ((!src) || (!dest) || (!src->data && src->len)) { |
117 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
118 | 0 | return SECFailure; |
119 | 0 | } |
120 | | |
121 | 0 | if (!src->len) { |
122 | | /* reaching the end of the buffer is not an error */ |
123 | 0 | dest->data = NULL; |
124 | 0 | dest->len = 0; |
125 | 0 | return SECSuccess; |
126 | 0 | } |
127 | | |
128 | 0 | dest->data = definite_length_decoder(src->data, src->len, &dest->len, |
129 | 0 | includeTag); |
130 | 0 | if (dest->data == NULL) { |
131 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
132 | 0 | return SECFailure; |
133 | 0 | } |
134 | 0 | src->len -= (int)(dest->data - src->data) + dest->len; |
135 | 0 | src->data = dest->data + dest->len; |
136 | 0 | return SECSuccess; |
137 | 0 | } |
138 | | |
139 | | /* check if the actual component's type matches the type in the template */ |
140 | | |
141 | | static SECStatus |
142 | | MatchComponentType(const SEC_ASN1Template* templateEntry, |
143 | | SECItem* item, PRBool* match, void* dest) |
144 | 0 | { |
145 | 0 | unsigned long kind = 0; |
146 | 0 | unsigned char tag = 0; |
147 | |
|
148 | 0 | if ((!item) || (!item->data && item->len) || (!templateEntry) || (!match)) { |
149 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
150 | 0 | return SECFailure; |
151 | 0 | } |
152 | | |
153 | 0 | if (!item->len) { |
154 | 0 | *match = PR_FALSE; |
155 | 0 | return SECSuccess; |
156 | 0 | } |
157 | | |
158 | 0 | kind = templateEntry->kind; |
159 | 0 | tag = *(unsigned char*)item->data; |
160 | |
|
161 | 0 | if (((kind & SEC_ASN1_INLINE) || |
162 | 0 | (kind & SEC_ASN1_POINTER)) && |
163 | 0 | (0 == (kind & SEC_ASN1_TAG_MASK))) { |
164 | | /* These cases are special because the template's "kind" does not |
165 | | give us the information for the ASN.1 tag of the next item. It can |
166 | | only be figured out from the subtemplate. */ |
167 | 0 | if (!(kind & SEC_ASN1_OPTIONAL)) { |
168 | | /* This is a required component. If there is a type mismatch, |
169 | | the decoding of the subtemplate will fail, so assume this |
170 | | is a match at the parent level and let it fail later. This |
171 | | avoids a redundant check in matching cases */ |
172 | 0 | *match = PR_TRUE; |
173 | 0 | return SECSuccess; |
174 | 0 | } else { |
175 | | /* optional component. This is the hard case. Now we need to |
176 | | look at the subtemplate to get the expected kind */ |
177 | 0 | const SEC_ASN1Template* subTemplate = |
178 | 0 | SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE); |
179 | 0 | if (!subTemplate) { |
180 | 0 | PORT_SetError(SEC_ERROR_BAD_TEMPLATE); |
181 | 0 | return SECFailure; |
182 | 0 | } |
183 | 0 | if ((subTemplate->kind & SEC_ASN1_INLINE) || |
184 | 0 | (subTemplate->kind & SEC_ASN1_POINTER)) { |
185 | | /* disallow nesting SEC_ASN1_POINTER and SEC_ASN1_INLINE, |
186 | | otherwise you may get a false positive due to the recursion |
187 | | optimization above that always matches the type if the |
188 | | component is required . Nesting these should never be |
189 | | required, so that no one should miss this ability */ |
190 | 0 | PORT_SetError(SEC_ERROR_BAD_TEMPLATE); |
191 | 0 | return SECFailure; |
192 | 0 | } |
193 | 0 | return MatchComponentType(subTemplate, item, match, |
194 | 0 | (void*)((char*)dest + templateEntry->offset)); |
195 | 0 | } |
196 | 0 | } |
197 | | |
198 | 0 | if (kind & SEC_ASN1_CHOICE) { |
199 | | /* we need to check the component's tag against each choice's tag */ |
200 | | /* XXX it would be nice to save the index of the choice here so that |
201 | | DecodeChoice wouldn't have to do this again. However, due to the |
202 | | recursivity of MatchComponentType, we don't know if we are in a |
203 | | required or optional component, so we can't write anywhere in |
204 | | the destination within this function */ |
205 | 0 | unsigned choiceIndex = 1; |
206 | 0 | const SEC_ASN1Template* choiceEntry; |
207 | 0 | while ((choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind)) { |
208 | 0 | if ((SECSuccess == MatchComponentType(choiceEntry, item, match, |
209 | 0 | (void*)((char*)dest + choiceEntry->offset))) && |
210 | 0 | (PR_TRUE == *match)) { |
211 | 0 | return SECSuccess; |
212 | 0 | } |
213 | 0 | } |
214 | | /* no match, caller must decide if this is BAD DER, or not. */ |
215 | 0 | *match = PR_FALSE; |
216 | 0 | return SECSuccess; |
217 | 0 | } |
218 | | |
219 | 0 | if (kind & SEC_ASN1_ANY) { |
220 | | /* SEC_ASN1_ANY always matches */ |
221 | 0 | *match = PR_TRUE; |
222 | 0 | return SECSuccess; |
223 | 0 | } |
224 | | |
225 | 0 | if ((0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) && |
226 | 0 | (!(kind & SEC_ASN1_EXPLICIT)) && |
227 | 0 | (((kind & SEC_ASN1_SAVE) || |
228 | 0 | (kind & SEC_ASN1_SKIP)) && |
229 | 0 | (!(kind & SEC_ASN1_OPTIONAL)))) { |
230 | | /* when saving or skipping a required component, a type is not |
231 | | required in the template. This is for legacy support of |
232 | | SEC_ASN1_SAVE and SEC_ASN1_SKIP only. XXX I would like to |
233 | | deprecate these usages and always require a type, as this |
234 | | disables type checking, and effectively forbids us from |
235 | | transparently ignoring optional components we aren't aware of */ |
236 | 0 | *match = PR_TRUE; |
237 | 0 | return SECSuccess; |
238 | 0 | } |
239 | | |
240 | | /* first, do a class check */ |
241 | 0 | if ((tag & SEC_ASN1_CLASS_MASK) != |
242 | 0 | (((unsigned char)kind) & SEC_ASN1_CLASS_MASK)) { |
243 | | /* this is only to help debugging of the decoder in case of problems */ |
244 | | /* unsigned char tagclass = tag & SEC_ASN1_CLASS_MASK; */ |
245 | | /* unsigned char expectedclass = (unsigned char)kind & SEC_ASN1_CLASS_MASK; */ |
246 | 0 | *match = PR_FALSE; |
247 | 0 | return SECSuccess; |
248 | 0 | } |
249 | | |
250 | | /* now do a tag check */ |
251 | 0 | if (((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) != |
252 | 0 | (tag & SEC_ASN1_TAGNUM_MASK)) { |
253 | 0 | *match = PR_FALSE; |
254 | 0 | return SECSuccess; |
255 | 0 | } |
256 | | |
257 | | /* now, do a method check. This depends on the class */ |
258 | 0 | switch (tag & SEC_ASN1_CLASS_MASK) { |
259 | 0 | case SEC_ASN1_UNIVERSAL: |
260 | | /* For types of the SEC_ASN1_UNIVERSAL class, we know which must be |
261 | | primitive or constructed based on the tag */ |
262 | 0 | switch (tag & SEC_ASN1_TAGNUM_MASK) { |
263 | 0 | case SEC_ASN1_SEQUENCE: |
264 | 0 | case SEC_ASN1_SET: |
265 | 0 | case SEC_ASN1_EMBEDDED_PDV: |
266 | | /* this component must be a constructed type */ |
267 | | /* XXX add any new universal constructed type here */ |
268 | 0 | if (tag & SEC_ASN1_CONSTRUCTED) { |
269 | 0 | *match = PR_TRUE; |
270 | 0 | return SECSuccess; |
271 | 0 | } |
272 | 0 | break; |
273 | | |
274 | 0 | default: |
275 | | /* this component must be a primitive type */ |
276 | 0 | if (!(tag & SEC_ASN1_CONSTRUCTED)) { |
277 | 0 | *match = PR_TRUE; |
278 | 0 | return SECSuccess; |
279 | 0 | } |
280 | 0 | break; |
281 | 0 | } |
282 | 0 | break; |
283 | | |
284 | 0 | default: |
285 | | /* for all other classes, we check the method based on the template */ |
286 | 0 | if ((unsigned char)(kind & SEC_ASN1_METHOD_MASK) == |
287 | 0 | (tag & SEC_ASN1_METHOD_MASK)) { |
288 | 0 | *match = PR_TRUE; |
289 | 0 | return SECSuccess; |
290 | 0 | } |
291 | | /* method does not match between template and component */ |
292 | 0 | break; |
293 | 0 | } |
294 | | |
295 | 0 | *match = PR_FALSE; |
296 | 0 | return SECSuccess; |
297 | 0 | } |
298 | | |
299 | | #ifdef DEBUG |
300 | | |
301 | | static SECStatus |
302 | | CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate) |
303 | 0 | { |
304 | 0 | SECStatus rv = SECSuccess; |
305 | 0 | const SEC_ASN1Template* sequenceEntry = NULL; |
306 | 0 | unsigned long seqIndex = 0; |
307 | 0 | unsigned long lastEntryIndex = 0; |
308 | 0 | unsigned long ambiguityIndex = 0; |
309 | 0 | PRBool foundAmbiguity = PR_FALSE; |
310 | |
|
311 | 0 | do { |
312 | 0 | sequenceEntry = &sequenceTemplate[seqIndex++]; |
313 | 0 | if (sequenceEntry->kind) { |
314 | | /* ensure that we don't have an optional component of SEC_ASN1_ANY |
315 | | in the middle of the sequence, since we could not handle it */ |
316 | | /* XXX this function needs to dig into the subtemplates to find |
317 | | the next tag */ |
318 | 0 | if ((PR_FALSE == foundAmbiguity) && |
319 | 0 | (sequenceEntry->kind & SEC_ASN1_OPTIONAL) && |
320 | 0 | (sequenceEntry->kind & SEC_ASN1_ANY)) { |
321 | 0 | foundAmbiguity = PR_TRUE; |
322 | 0 | ambiguityIndex = seqIndex - 1; |
323 | 0 | } |
324 | 0 | } |
325 | 0 | } while (sequenceEntry->kind); |
326 | |
|
327 | 0 | lastEntryIndex = seqIndex - 2; |
328 | |
|
329 | 0 | if (PR_FALSE != foundAmbiguity) { |
330 | 0 | if (ambiguityIndex < lastEntryIndex) { |
331 | | /* ambiguity can only be tolerated on the last entry */ |
332 | 0 | PORT_SetError(SEC_ERROR_BAD_TEMPLATE); |
333 | 0 | rv = SECFailure; |
334 | 0 | } |
335 | 0 | } |
336 | | |
337 | | /* XXX also enforce ASN.1 requirement that tags be |
338 | | distinct for consecutive optional components */ |
339 | |
|
340 | 0 | return rv; |
341 | 0 | } |
342 | | |
343 | | #endif |
344 | | |
345 | | static SECStatus DecodeItem(void* dest, |
346 | | const SEC_ASN1Template* templateEntry, |
347 | | SECItem* src, PLArenaPool* arena, PRBool checkTag); |
348 | | |
349 | | static SECStatus |
350 | | DecodeSequence(void* dest, |
351 | | const SEC_ASN1Template* templateEntry, |
352 | | SECItem* src, PLArenaPool* arena) |
353 | 0 | { |
354 | 0 | SECStatus rv = SECSuccess; |
355 | 0 | SECItem source; |
356 | 0 | SECItem sequence; |
357 | 0 | const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]); |
358 | 0 | const SEC_ASN1Template* sequenceEntry = NULL; |
359 | 0 | unsigned long seqindex = 0; |
360 | |
|
361 | 0 | #ifdef DEBUG |
362 | | /* for a sequence, we need to validate the template. */ |
363 | 0 | rv = CheckSequenceTemplate(sequenceTemplate); |
364 | 0 | #endif |
365 | |
|
366 | 0 | source = *src; |
367 | | |
368 | | /* get the sequence */ |
369 | 0 | if (SECSuccess == rv) { |
370 | 0 | rv = GetItem(&source, &sequence, PR_FALSE); |
371 | 0 | } |
372 | | |
373 | | /* process it */ |
374 | 0 | if (SECSuccess == rv) |
375 | 0 | do { |
376 | 0 | sequenceEntry = &sequenceTemplate[seqindex++]; |
377 | 0 | if ((sequenceEntry && sequenceEntry->kind) && |
378 | 0 | (sequenceEntry->kind != SEC_ASN1_SKIP_REST)) { |
379 | 0 | rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE); |
380 | 0 | } |
381 | 0 | } while ((SECSuccess == rv) && |
382 | 0 | (sequenceEntry->kind && |
383 | 0 | sequenceEntry->kind != SEC_ASN1_SKIP_REST)); |
384 | | /* we should have consumed all the bytes in the sequence by now |
385 | | unless the caller doesn't care about the rest of the sequence */ |
386 | 0 | if (SECSuccess == rv && sequence.len && |
387 | 0 | sequenceEntry && sequenceEntry->kind != SEC_ASN1_SKIP_REST) { |
388 | | /* it isn't 100% clear whether this is a bad DER or a bad template. |
389 | | The problem is that logically, they don't match - there is extra |
390 | | data in the DER that the template doesn't know about */ |
391 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
392 | 0 | rv = SECFailure; |
393 | 0 | } |
394 | |
|
395 | 0 | return rv; |
396 | 0 | } |
397 | | |
398 | | static SECStatus |
399 | | DecodeInline(void* dest, |
400 | | const SEC_ASN1Template* templateEntry, |
401 | | SECItem* src, PLArenaPool* arena, PRBool checkTag) |
402 | 0 | { |
403 | 0 | const SEC_ASN1Template* inlineTemplate = |
404 | 0 | SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE); |
405 | 0 | return DecodeItem((void*)((char*)dest + templateEntry->offset), |
406 | 0 | inlineTemplate, src, arena, checkTag); |
407 | 0 | } |
408 | | |
409 | | static SECStatus |
410 | | DecodePointer(void* dest, |
411 | | const SEC_ASN1Template* templateEntry, |
412 | | SECItem* src, PLArenaPool* arena, PRBool checkTag) |
413 | 0 | { |
414 | 0 | const SEC_ASN1Template* ptrTemplate = |
415 | 0 | SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE); |
416 | 0 | if (!ptrTemplate) { |
417 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
418 | 0 | return SECFailure; |
419 | 0 | } |
420 | 0 | void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size); |
421 | 0 | *(void**)((char*)dest + templateEntry->offset) = subdata; |
422 | 0 | if (subdata) { |
423 | 0 | return DecodeItem(subdata, ptrTemplate, src, arena, checkTag); |
424 | 0 | } else { |
425 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
426 | 0 | return SECFailure; |
427 | 0 | } |
428 | 0 | } |
429 | | |
430 | | static SECStatus |
431 | | DecodeImplicit(void* dest, |
432 | | const SEC_ASN1Template* templateEntry, |
433 | | SECItem* src, PLArenaPool* arena) |
434 | 0 | { |
435 | 0 | if (templateEntry->kind & SEC_ASN1_POINTER) { |
436 | 0 | return DecodePointer((void*)((char*)dest), |
437 | 0 | templateEntry, src, arena, PR_FALSE); |
438 | 0 | } else { |
439 | 0 | return DecodeInline((void*)((char*)dest), |
440 | 0 | templateEntry, src, arena, PR_FALSE); |
441 | 0 | } |
442 | 0 | } |
443 | | |
444 | | static SECStatus |
445 | | DecodeChoice(void* dest, |
446 | | const SEC_ASN1Template* templateEntry, |
447 | | SECItem* src, PLArenaPool* arena) |
448 | 0 | { |
449 | 0 | SECStatus rv = SECSuccess; |
450 | 0 | SECItem choice; |
451 | 0 | const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]); |
452 | 0 | const SEC_ASN1Template* choiceEntry = NULL; |
453 | 0 | unsigned long choiceindex = 0; |
454 | | |
455 | | /* XXX for a choice component, we should validate the template to make |
456 | | sure the tags are distinct, in debug builds. This hasn't been |
457 | | implemented yet */ |
458 | | /* rv = CheckChoiceTemplate(sequenceTemplate); */ |
459 | | |
460 | | /* process it */ |
461 | 0 | do { |
462 | 0 | choice = *src; |
463 | 0 | choiceEntry = &choiceTemplate[choiceindex++]; |
464 | 0 | if (choiceEntry->kind) { |
465 | 0 | rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE); |
466 | 0 | } |
467 | 0 | } while ((SECFailure == rv) && (choiceEntry->kind)); |
468 | |
|
469 | 0 | if (SECFailure == rv) { |
470 | | /* the component didn't match any of the choices */ |
471 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
472 | 0 | } else { |
473 | | /* set the type in the union here */ |
474 | 0 | int* which = (int*)((char*)dest + templateEntry->offset); |
475 | 0 | *which = (int)choiceEntry->size; |
476 | 0 | } |
477 | | |
478 | | /* we should have consumed all the bytes by now */ |
479 | | /* fail if we have not */ |
480 | 0 | if (SECSuccess == rv && choice.len) { |
481 | | /* there is extra data that isn't listed in the template */ |
482 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
483 | 0 | rv = SECFailure; |
484 | 0 | } |
485 | 0 | return rv; |
486 | 0 | } |
487 | | |
488 | | static SECStatus |
489 | | DecodeGroup(void* dest, |
490 | | const SEC_ASN1Template* templateEntry, |
491 | | SECItem* src, PLArenaPool* arena) |
492 | 0 | { |
493 | 0 | SECStatus rv = SECSuccess; |
494 | 0 | SECItem source; |
495 | 0 | SECItem group; |
496 | 0 | PRUint32 totalEntries = 0; |
497 | 0 | PRUint32 entryIndex = 0; |
498 | 0 | void** entries = NULL; |
499 | |
|
500 | 0 | const SEC_ASN1Template* subTemplate = |
501 | 0 | SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE); |
502 | |
|
503 | 0 | source = *src; |
504 | | |
505 | | /* get the group */ |
506 | 0 | if (SECSuccess == rv) { |
507 | 0 | rv = GetItem(&source, &group, PR_FALSE); |
508 | 0 | } |
509 | | |
510 | | /* XXX we should check the subtemplate in debug builds */ |
511 | 0 | if (SECSuccess == rv) { |
512 | | /* first, count the number of entries. Benchmarking showed that this |
513 | | counting pass is more efficient than trying to allocate entries as |
514 | | we read the DER, even if allocating many entries at a time |
515 | | */ |
516 | 0 | SECItem counter = group; |
517 | 0 | do { |
518 | 0 | SECItem anitem; |
519 | 0 | rv = GetItem(&counter, &anitem, PR_TRUE); |
520 | 0 | if (SECSuccess == rv && (anitem.len)) { |
521 | 0 | totalEntries++; |
522 | 0 | } |
523 | 0 | } while ((SECSuccess == rv) && (counter.len)); |
524 | |
|
525 | 0 | if (SECSuccess == rv) { |
526 | | /* allocate room for pointer array and entries */ |
527 | | /* we want to allocate the array even if there is 0 entry */ |
528 | 0 | entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*) * (totalEntries + 1) + /* the extra one is for NULL termination */ |
529 | 0 | subTemplate->size * totalEntries); |
530 | |
|
531 | 0 | if (entries) { |
532 | 0 | entries[totalEntries] = NULL; /* terminate the array */ |
533 | 0 | } else { |
534 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
535 | 0 | rv = SECFailure; |
536 | 0 | } |
537 | 0 | if (SECSuccess == rv) { |
538 | 0 | void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*) * (totalEntries + 1)); |
539 | | /* and fix the pointers in the array */ |
540 | 0 | PRUint32 entriesIndex = 0; |
541 | 0 | for (entriesIndex = 0; entriesIndex < totalEntries; entriesIndex++) { |
542 | 0 | entries[entriesIndex] = |
543 | 0 | (char*)entriesData + (subTemplate->size * entriesIndex); |
544 | 0 | } |
545 | 0 | } |
546 | 0 | } |
547 | 0 | } |
548 | |
|
549 | 0 | if (SECSuccess == rv && totalEntries) |
550 | 0 | do { |
551 | 0 | if (!(entryIndex < totalEntries)) { |
552 | 0 | rv = SECFailure; |
553 | 0 | break; |
554 | 0 | } |
555 | 0 | rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE); |
556 | 0 | } while ((SECSuccess == rv) && (group.len)); |
557 | | /* we should be at the end of the set by now */ |
558 | | /* save the entries where requested */ |
559 | 0 | memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**)); |
560 | |
|
561 | 0 | return rv; |
562 | 0 | } |
563 | | |
564 | | static SECStatus |
565 | | DecodeExplicit(void* dest, |
566 | | const SEC_ASN1Template* templateEntry, |
567 | | SECItem* src, PLArenaPool* arena) |
568 | 0 | { |
569 | 0 | SECStatus rv = SECSuccess; |
570 | 0 | SECItem subItem; |
571 | 0 | SECItem constructed = *src; |
572 | |
|
573 | 0 | rv = GetItem(&constructed, &subItem, PR_FALSE); |
574 | |
|
575 | 0 | if (SECSuccess == rv) { |
576 | 0 | if (templateEntry->kind & SEC_ASN1_POINTER) { |
577 | 0 | rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE); |
578 | 0 | } else { |
579 | 0 | rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE); |
580 | 0 | } |
581 | 0 | } |
582 | |
|
583 | 0 | return rv; |
584 | 0 | } |
585 | | |
586 | | /* new decoder implementation. This is a recursive function */ |
587 | | |
588 | | static SECStatus |
589 | | DecodeItem(void* dest, |
590 | | const SEC_ASN1Template* templateEntry, |
591 | | SECItem* src, PLArenaPool* arena, PRBool checkTag) |
592 | 0 | { |
593 | 0 | SECStatus rv = SECSuccess; |
594 | 0 | SECItem temp; |
595 | 0 | SECItem mark = { siBuffer, NULL, 0 }; |
596 | 0 | PRBool pop = PR_FALSE; |
597 | 0 | PRBool decode = PR_TRUE; |
598 | 0 | PRBool save = PR_FALSE; |
599 | 0 | unsigned long kind; |
600 | 0 | PRBool match = PR_TRUE; |
601 | |
|
602 | 0 | PR_ASSERT(src && dest && templateEntry && arena); |
603 | | #if 0 |
604 | | if (!src || !dest || !templateEntry || !arena) |
605 | | { |
606 | | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
607 | | rv = SECFailure; |
608 | | } |
609 | | #endif |
610 | |
|
611 | 0 | if (SECSuccess == rv) { |
612 | | /* do the template validation */ |
613 | 0 | kind = templateEntry->kind; |
614 | 0 | if (!kind) { |
615 | 0 | PORT_SetError(SEC_ERROR_BAD_TEMPLATE); |
616 | 0 | rv = SECFailure; |
617 | 0 | } |
618 | 0 | } |
619 | |
|
620 | 0 | if (SECSuccess == rv) { |
621 | 0 | #ifdef DEBUG |
622 | 0 | if (kind & SEC_ASN1_DEBUG_BREAK) { |
623 | | /* when debugging the decoder or a template that fails to |
624 | | decode, put SEC_ASN1_DEBUG in the component that gives you |
625 | | trouble. The decoder will then get to this block and assert. |
626 | | If you want to debug the rest of the code, you can set a |
627 | | breakpoint and set dontassert to PR_TRUE, which will let |
628 | | you skip over the assert and continue the debugging session |
629 | | past it. */ |
630 | 0 | PRBool dontassert = PR_FALSE; |
631 | 0 | PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/ |
632 | 0 | } |
633 | 0 | #endif |
634 | |
|
635 | 0 | if ((kind & SEC_ASN1_SKIP) || |
636 | 0 | (kind & SEC_ASN1_SAVE)) { |
637 | | /* if skipping or saving this component, don't decode it */ |
638 | 0 | decode = PR_FALSE; |
639 | 0 | } |
640 | |
|
641 | 0 | if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL)) { |
642 | | /* if saving this component, or if it is optional, we may not want to |
643 | | move past it, so save the position in case we have to rewind */ |
644 | 0 | mark = *src; |
645 | 0 | if (kind & SEC_ASN1_SAVE) { |
646 | 0 | save = PR_TRUE; |
647 | 0 | if (0 == (kind & SEC_ASN1_SKIP)) { |
648 | | /* we will for sure have to rewind when saving this |
649 | | component and not skipping it. This is true for all |
650 | | legacy uses of SEC_ASN1_SAVE where the following entry |
651 | | in the template would causes the same component to be |
652 | | processed again */ |
653 | 0 | pop = PR_TRUE; |
654 | 0 | } |
655 | 0 | } |
656 | 0 | } |
657 | |
|
658 | 0 | rv = GetItem(src, &temp, PR_TRUE); |
659 | 0 | } |
660 | |
|
661 | 0 | if (SECSuccess == rv) { |
662 | | /* now check if the component matches what we expect in the template */ |
663 | |
|
664 | 0 | if (PR_TRUE == checkTag) |
665 | | |
666 | 0 | { |
667 | 0 | rv = MatchComponentType(templateEntry, &temp, &match, dest); |
668 | 0 | } |
669 | |
|
670 | 0 | if ((SECSuccess == rv) && (PR_TRUE != match)) { |
671 | 0 | if (kind & SEC_ASN1_OPTIONAL) { |
672 | | |
673 | | /* the optional component is missing. This is not fatal. */ |
674 | | /* Rewind, don't decode, and don't save */ |
675 | 0 | pop = PR_TRUE; |
676 | 0 | decode = PR_FALSE; |
677 | 0 | save = PR_FALSE; |
678 | 0 | } else { |
679 | | /* a required component is missing. abort */ |
680 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
681 | 0 | rv = SECFailure; |
682 | 0 | } |
683 | 0 | } |
684 | 0 | } |
685 | |
|
686 | 0 | if ((SECSuccess == rv) && (PR_TRUE == decode)) { |
687 | | /* the order of processing here is is the tricky part */ |
688 | | /* we start with our special cases */ |
689 | | /* first, check the component class */ |
690 | 0 | if (kind & SEC_ASN1_INLINE) { |
691 | | /* decode inline template */ |
692 | 0 | rv = DecodeInline(dest, templateEntry, &temp, arena, PR_TRUE); |
693 | 0 | } |
694 | | |
695 | 0 | else if (kind & SEC_ASN1_EXPLICIT) { |
696 | 0 | rv = DecodeExplicit(dest, templateEntry, &temp, arena); |
697 | 0 | } else if ((SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) && |
698 | |
|
699 | 0 | (!(kind & SEC_ASN1_EXPLICIT))) { |
700 | | |
701 | | /* decode implicitly tagged components */ |
702 | 0 | rv = DecodeImplicit(dest, templateEntry, &temp, arena); |
703 | 0 | } else if (kind & SEC_ASN1_POINTER) { |
704 | 0 | rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE); |
705 | 0 | } else if (kind & SEC_ASN1_CHOICE) { |
706 | 0 | rv = DecodeChoice(dest, templateEntry, &temp, arena); |
707 | 0 | } else if (kind & SEC_ASN1_ANY) { |
708 | | /* catch-all ANY type, don't decode */ |
709 | 0 | save = PR_TRUE; |
710 | 0 | if (kind & SEC_ASN1_INNER) { |
711 | | /* skip the tag and length */ |
712 | 0 | SECItem newtemp = temp; |
713 | 0 | rv = GetItem(&newtemp, &temp, PR_FALSE); |
714 | 0 | } |
715 | 0 | } else if (kind & SEC_ASN1_GROUP) { |
716 | 0 | if ((SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) || |
717 | 0 | (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK))) { |
718 | 0 | rv = DecodeGroup(dest, templateEntry, &temp, arena); |
719 | 0 | } else { |
720 | | /* a group can only be a SET OF or SEQUENCE OF */ |
721 | 0 | PORT_SetError(SEC_ERROR_BAD_TEMPLATE); |
722 | 0 | rv = SECFailure; |
723 | 0 | } |
724 | 0 | } else if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) { |
725 | | /* plain SEQUENCE */ |
726 | 0 | rv = DecodeSequence(dest, templateEntry, &temp, arena); |
727 | 0 | } else { |
728 | | /* handle all other types as "save" */ |
729 | | /* we should only get here for primitive universal types */ |
730 | 0 | SECItem newtemp = temp; |
731 | 0 | rv = GetItem(&newtemp, &temp, PR_FALSE); |
732 | 0 | save = PR_TRUE; |
733 | 0 | if ((SECSuccess == rv) && |
734 | 0 | SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK)) { |
735 | 0 | unsigned long tagnum = kind & SEC_ASN1_TAGNUM_MASK; |
736 | 0 | if (temp.len == 0 && (tagnum == SEC_ASN1_BOOLEAN || |
737 | 0 | tagnum == SEC_ASN1_INTEGER || |
738 | 0 | tagnum == SEC_ASN1_BIT_STRING || |
739 | 0 | tagnum == SEC_ASN1_OBJECT_ID || |
740 | 0 | tagnum == SEC_ASN1_ENUMERATED || |
741 | 0 | tagnum == SEC_ASN1_UTC_TIME || |
742 | 0 | tagnum == SEC_ASN1_GENERALIZED_TIME)) { |
743 | | /* these types MUST have at least one content octet */ |
744 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
745 | 0 | rv = SECFailure; |
746 | 0 | } else |
747 | 0 | switch (tagnum) { |
748 | | /* special cases of primitive types */ |
749 | 0 | case SEC_ASN1_INTEGER: { |
750 | 0 | SECItem* destItem = (SECItem*)((char*)dest + |
751 | 0 | templateEntry->offset); |
752 | 0 | if (destItem && (siUnsignedInteger == destItem->type)) { |
753 | | /* A leading 0 is only allowed when a value |
754 | | * would otherwise be interpreted as negative. */ |
755 | 0 | if (temp.len > 1 && temp.data[0] == 0) { |
756 | 0 | temp.data++; |
757 | 0 | temp.len--; |
758 | 0 | if (!(temp.data[0] & 0x80)) { |
759 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
760 | 0 | rv = SECFailure; |
761 | 0 | } |
762 | 0 | } |
763 | 0 | } |
764 | 0 | break; |
765 | 0 | } |
766 | | |
767 | 0 | case SEC_ASN1_BIT_STRING: { |
768 | | /* Can't be 8 or more spare bits, or any spare bits |
769 | | * if there are no octets. */ |
770 | 0 | if (temp.data[0] >= 8 || (temp.data[0] > 0 && temp.len == 1)) { |
771 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
772 | 0 | rv = SECFailure; |
773 | 0 | break; |
774 | 0 | } |
775 | | /* change the length in the SECItem to be the number |
776 | | of bits */ |
777 | 0 | temp.len = (temp.len - 1) * 8 - (temp.data[0] & 0x7); |
778 | 0 | temp.data++; |
779 | 0 | break; |
780 | 0 | } |
781 | | |
782 | 0 | default: { |
783 | 0 | break; |
784 | 0 | } |
785 | 0 | } |
786 | 0 | } |
787 | 0 | } |
788 | 0 | } |
789 | | |
790 | 0 | if ((SECSuccess == rv) && (PR_TRUE == save)) { |
791 | 0 | SECItem* destItem = (SECItem*)((char*)dest + templateEntry->offset); |
792 | 0 | if (destItem) { |
793 | | /* we leave the type alone in the destination SECItem. |
794 | | If part of the destination was allocated by the decoder, in |
795 | | cases of POINTER, SET OF and SEQUENCE OF, then type is set to |
796 | | siBuffer due to the use of PORT_ArenaZAlloc*/ |
797 | 0 | destItem->data = temp.len ? temp.data : NULL; |
798 | 0 | destItem->len = temp.len; |
799 | 0 | } else { |
800 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
801 | 0 | rv = SECFailure; |
802 | 0 | } |
803 | 0 | } |
804 | |
|
805 | 0 | if (PR_TRUE == pop) { |
806 | | /* we don't want to move ahead, so restore the position */ |
807 | 0 | *src = mark; |
808 | 0 | } |
809 | 0 | return rv; |
810 | 0 | } |
811 | | |
812 | | /* the function below is the public one */ |
813 | | |
814 | | SECStatus |
815 | | SEC_QuickDERDecodeItem(PLArenaPool* arena, void* dest, |
816 | | const SEC_ASN1Template* templateEntry, |
817 | | const SECItem* src) |
818 | 0 | { |
819 | 0 | SECStatus rv = SECSuccess; |
820 | 0 | SECItem newsrc; |
821 | |
|
822 | 0 | if (!arena || !templateEntry || !src) { |
823 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
824 | 0 | rv = SECFailure; |
825 | 0 | } |
826 | |
|
827 | 0 | if (SECSuccess == rv) { |
828 | 0 | newsrc = *src; |
829 | 0 | rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE); |
830 | 0 | if (SECSuccess == rv && newsrc.len) { |
831 | 0 | rv = SECFailure; |
832 | 0 | PORT_SetError(SEC_ERROR_EXTRA_INPUT); |
833 | 0 | } |
834 | 0 | } |
835 | |
|
836 | 0 | return rv; |
837 | 0 | } |