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