Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / util / quickder.c
blob29a5821476f47d9dac70791d6902aca0aeec5577
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
12 * License.
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.
21 * Contributor(s):
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 ***** */
38 Optimized ASN.1 DER decoder
42 #include "secerr.h"
43 #include "secasn1.h" /* for SEC_ASN1GetSubtemplate */
44 #include "secitem.h"
47 * simple definite-length ASN.1 decoder
50 static unsigned char* definite_length_decoder(const unsigned char *buf,
51 const unsigned int length,
52 unsigned int *data_length,
53 PRBool includeTag)
55 unsigned char tag;
56 unsigned int used_length= 0;
57 unsigned int data_len;
59 if (used_length >= length)
61 return NULL;
63 tag = buf[used_length++];
65 /* blow out when we come to the end */
66 if (tag == 0)
68 return NULL;
71 if (used_length >= length)
73 return NULL;
75 data_len = buf[used_length++];
77 if (data_len&0x80)
79 int len_count = data_len & 0x7f;
81 data_len = 0;
83 while (len_count-- > 0)
85 if (used_length >= length)
87 return NULL;
89 data_len = (data_len << 8) | buf[used_length++];
93 if (data_len > (length-used_length) )
95 return NULL;
97 if (includeTag) data_len += used_length;
99 *data_length = data_len;
100 return ((unsigned char*)buf + (includeTag ? 0 : used_length));
103 static SECStatus GetItem(SECItem* src, SECItem* dest, PRBool includeTag)
105 if ( (!src) || (!dest) || (!src->data) )
107 PORT_SetError(SEC_ERROR_INVALID_ARGS);
108 return SECFailure;
111 if (!src->len)
113 /* reaching the end of the buffer is not an error */
114 dest->data = NULL;
115 dest->len = 0;
116 return SECSuccess;
119 dest->data = definite_length_decoder(src->data, src->len, &dest->len,
120 includeTag);
121 if (dest->data == NULL)
123 PORT_SetError(SEC_ERROR_BAD_DER);
124 return SECFailure;
126 src->len -= (dest->data - src->data) + dest->len;
127 src->data = dest->data + dest->len;
128 return SECSuccess;
131 /* check if the actual component's type matches the type in the template */
133 static SECStatus MatchComponentType(const SEC_ASN1Template* templateEntry,
134 SECItem* item, PRBool* match, void* dest)
136 unsigned long kind = 0;
137 unsigned char tag = 0;
139 if ( (!item) || (!templateEntry) || (!match) )
141 PORT_SetError(SEC_ERROR_INVALID_ARGS);
142 return SECFailure;
145 if (!item->len || !item->data)
147 *match = PR_FALSE;
148 return SECSuccess;
151 kind = templateEntry->kind;
152 tag = *(unsigned char*) item->data;
154 if ( ( (kind & SEC_ASN1_INLINE) ||
155 (kind & SEC_ASN1_POINTER) ) &&
156 (0 == (kind & SEC_ASN1_TAG_MASK) ) )
158 /* These cases are special because the template's "kind" does not
159 give us the information for the ASN.1 tag of the next item. It can
160 only be figured out from the subtemplate. */
161 if (!(kind & SEC_ASN1_OPTIONAL))
163 /* This is a required component. If there is a type mismatch,
164 the decoding of the subtemplate will fail, so assume this
165 is a match at the parent level and let it fail later. This
166 avoids a redundant check in matching cases */
167 *match = PR_TRUE;
168 return SECSuccess;
170 else
172 /* optional component. This is the hard case. Now we need to
173 look at the subtemplate to get the expected kind */
174 const SEC_ASN1Template* subTemplate =
175 SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
176 if (!subTemplate)
178 PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
179 return SECFailure;
181 if ( (subTemplate->kind & SEC_ASN1_INLINE) ||
182 (subTemplate->kind & SEC_ASN1_POINTER) )
184 /* disallow nesting SEC_ASN1_POINTER and SEC_ASN1_INLINE,
185 otherwise you may get a false positive due to the recursion
186 optimization above that always matches the type if the
187 component is required . Nesting these should never be
188 required, so that no one should miss this ability */
189 PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
190 return SECFailure;
192 return MatchComponentType(subTemplate, item, match,
193 (void*)((char*)dest + templateEntry->offset));
197 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 unsigned choiceIndex = 1;
206 const SEC_ASN1Template* choiceEntry;
207 while ( (choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind))
209 if ( (SECSuccess == MatchComponentType(choiceEntry, item, match,
210 (void*)((char*)dest + choiceEntry->offset))) &&
211 (PR_TRUE == *match) )
213 return SECSuccess;
216 /* no match, caller must decide if this is BAD DER, or not. */
217 *match = PR_FALSE;
218 return SECSuccess;
221 if (kind & SEC_ASN1_ANY)
223 /* SEC_ASN1_ANY always matches */
224 *match = PR_TRUE;
225 return SECSuccess;
228 if ( (0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) &&
229 (!(kind & SEC_ASN1_EXPLICIT)) &&
230 ( ( (kind & SEC_ASN1_SAVE) ||
231 (kind & SEC_ASN1_SKIP) ) &&
232 (!(kind & SEC_ASN1_OPTIONAL))
236 /* when saving or skipping a required component, a type is not
237 required in the template. This is for legacy support of
238 SEC_ASN1_SAVE and SEC_ASN1_SKIP only. XXX I would like to
239 deprecate these usages and always require a type, as this
240 disables type checking, and effectively forbids us from
241 transparently ignoring optional components we aren't aware of */
242 *match = PR_TRUE;
243 return SECSuccess;
246 /* first, do a class check */
247 if ( (tag & SEC_ASN1_CLASS_MASK) !=
248 (((unsigned char)kind) & SEC_ASN1_CLASS_MASK) )
250 #ifdef DEBUG
251 /* this is only to help debugging of the decoder in case of problems */
252 unsigned char tagclass = tag & SEC_ASN1_CLASS_MASK;
253 unsigned char expectedclass = (unsigned char)kind & SEC_ASN1_CLASS_MASK;
254 tagclass = tagclass;
255 expectedclass = expectedclass;
256 #endif
257 *match = PR_FALSE;
258 return SECSuccess;
261 /* now do a tag check */
262 if ( ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) !=
263 (tag & SEC_ASN1_TAGNUM_MASK))
265 *match = PR_FALSE;
266 return SECSuccess;
269 /* now, do a method check. This depends on the class */
270 switch (tag & SEC_ASN1_CLASS_MASK)
272 case SEC_ASN1_UNIVERSAL:
273 /* For types of the SEC_ASN1_UNIVERSAL class, we know which must be
274 primitive or constructed based on the tag */
275 switch (tag & SEC_ASN1_TAGNUM_MASK)
277 case SEC_ASN1_SEQUENCE:
278 case SEC_ASN1_SET:
279 case SEC_ASN1_EMBEDDED_PDV:
280 /* this component must be a constructed type */
281 /* XXX add any new universal constructed type here */
282 if (tag & SEC_ASN1_CONSTRUCTED)
284 *match = PR_TRUE;
285 return SECSuccess;
287 break;
289 default:
290 /* this component must be a primitive type */
291 if (! (tag & SEC_ASN1_CONSTRUCTED))
293 *match = PR_TRUE;
294 return SECSuccess;
296 break;
298 break;
300 default:
301 /* for all other classes, we check the method based on the template */
302 if ( (unsigned char)(kind & SEC_ASN1_METHOD_MASK) ==
303 (tag & SEC_ASN1_METHOD_MASK) )
305 *match = PR_TRUE;
306 return SECSuccess;
308 /* method does not match between template and component */
309 break;
312 *match = PR_FALSE;
313 return SECSuccess;
316 #ifdef DEBUG
318 static SECStatus CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate)
320 SECStatus rv = SECSuccess;
321 const SEC_ASN1Template* sequenceEntry = NULL;
322 unsigned long seqIndex = 0;
323 unsigned long lastEntryIndex = 0;
324 unsigned long ambiguityIndex = 0;
325 PRBool foundAmbiguity = PR_FALSE;
329 sequenceEntry = &sequenceTemplate[seqIndex++];
330 if (sequenceEntry->kind)
332 /* ensure that we don't have an optional component of SEC_ASN1_ANY
333 in the middle of the sequence, since we could not handle it */
334 /* XXX this function needs to dig into the subtemplates to find
335 the next tag */
336 if ( (PR_FALSE == foundAmbiguity) &&
337 (sequenceEntry->kind & SEC_ASN1_OPTIONAL) &&
338 (sequenceEntry->kind & SEC_ASN1_ANY) )
340 foundAmbiguity = PR_TRUE;
341 ambiguityIndex = seqIndex - 1;
344 } while (sequenceEntry->kind);
346 lastEntryIndex = seqIndex - 2;
348 if (PR_FALSE != foundAmbiguity)
350 if (ambiguityIndex < lastEntryIndex)
352 /* ambiguity can only be tolerated on the last entry */
353 PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
354 rv = SECFailure;
358 /* XXX also enforce ASN.1 requirement that tags be
359 distinct for consecutive optional components */
361 return rv;
364 #endif
366 static SECStatus DecodeItem(void* dest,
367 const SEC_ASN1Template* templateEntry,
368 SECItem* src, PRArenaPool* arena, PRBool checkTag);
370 static SECStatus DecodeSequence(void* dest,
371 const SEC_ASN1Template* templateEntry,
372 SECItem* src, PRArenaPool* arena)
374 SECStatus rv = SECSuccess;
375 SECItem source;
376 SECItem sequence;
377 const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]);
378 const SEC_ASN1Template* sequenceEntry = NULL;
379 unsigned long seqindex = 0;
381 #ifdef DEBUG
382 /* for a sequence, we need to validate the template. */
383 rv = CheckSequenceTemplate(sequenceTemplate);
384 #endif
386 source = *src;
388 /* get the sequence */
389 if (SECSuccess == rv)
391 rv = GetItem(&source, &sequence, PR_FALSE);
394 /* process it */
395 if (SECSuccess == rv)
398 sequenceEntry = &sequenceTemplate[seqindex++];
399 if ( (sequenceEntry && sequenceEntry->kind) &&
400 (sequenceEntry->kind != SEC_ASN1_SKIP_REST) )
402 rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE);
404 } while ( (SECSuccess == rv) &&
405 (sequenceEntry->kind &&
406 sequenceEntry->kind != SEC_ASN1_SKIP_REST) );
407 /* we should have consumed all the bytes in the sequence by now
408 unless the caller doesn't care about the rest of the sequence */
409 if (SECSuccess == rv && sequence.len &&
410 sequenceEntry && sequenceEntry->kind != SEC_ASN1_SKIP_REST)
412 /* it isn't 100% clear whether this is a bad DER or a bad template.
413 The problem is that logically, they don't match - there is extra
414 data in the DER that the template doesn't know about */
415 PORT_SetError(SEC_ERROR_BAD_DER);
416 rv = SECFailure;
419 return rv;
422 static SECStatus DecodeInline(void* dest,
423 const SEC_ASN1Template* templateEntry,
424 SECItem* src, PRArenaPool* arena, PRBool checkTag)
426 const SEC_ASN1Template* inlineTemplate =
427 SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
428 return DecodeItem((void*)((char*)dest + templateEntry->offset),
429 inlineTemplate, src, arena, checkTag);
432 static SECStatus DecodePointer(void* dest,
433 const SEC_ASN1Template* templateEntry,
434 SECItem* src, PRArenaPool* arena, PRBool checkTag)
436 const SEC_ASN1Template* ptrTemplate =
437 SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
438 void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size);
439 *(void**)((char*)dest + templateEntry->offset) = subdata;
440 if (subdata)
442 return DecodeItem(subdata, ptrTemplate, src, arena, checkTag);
444 else
446 PORT_SetError(SEC_ERROR_NO_MEMORY);
447 return SECFailure;
451 static SECStatus DecodeImplicit(void* dest,
452 const SEC_ASN1Template* templateEntry,
453 SECItem* src, PRArenaPool* arena)
455 if (templateEntry->kind & SEC_ASN1_POINTER)
457 return DecodePointer((void*)((char*)dest ),
458 templateEntry, src, arena, PR_FALSE);
460 else
462 return DecodeInline((void*)((char*)dest ),
463 templateEntry, src, arena, PR_FALSE);
467 static SECStatus DecodeChoice(void* dest,
468 const SEC_ASN1Template* templateEntry,
469 SECItem* src, PRArenaPool* arena)
471 SECStatus rv = SECSuccess;
472 SECItem choice;
473 const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]);
474 const SEC_ASN1Template* choiceEntry = NULL;
475 unsigned long choiceindex = 0;
477 /* XXX for a choice component, we should validate the template to make
478 sure the tags are distinct, in debug builds. This hasn't been
479 implemented yet */
480 /* rv = CheckChoiceTemplate(sequenceTemplate); */
482 /* process it */
485 choice = *src;
486 choiceEntry = &choiceTemplate[choiceindex++];
487 if (choiceEntry->kind)
489 rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE);
491 } while ( (SECFailure == rv) && (choiceEntry->kind));
493 if (SECFailure == rv)
495 /* the component didn't match any of the choices */
496 PORT_SetError(SEC_ERROR_BAD_DER);
498 else
500 /* set the type in the union here */
501 int *which = (int *)((char *)dest + templateEntry->offset);
502 *which = (int)choiceEntry->size;
505 /* we should have consumed all the bytes by now */
506 /* fail if we have not */
507 if (SECSuccess == rv && choice.len)
509 /* there is extra data that isn't listed in the template */
510 PORT_SetError(SEC_ERROR_BAD_DER);
511 rv = SECFailure;
513 return rv;
516 static SECStatus DecodeGroup(void* dest,
517 const SEC_ASN1Template* templateEntry,
518 SECItem* src, PRArenaPool* arena)
520 SECStatus rv = SECSuccess;
521 SECItem source;
522 SECItem group;
523 PRUint32 totalEntries = 0;
524 PRUint32 entryIndex = 0;
525 void** entries = NULL;
527 const SEC_ASN1Template* subTemplate =
528 SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
530 source = *src;
532 /* get the group */
533 if (SECSuccess == rv)
535 rv = GetItem(&source, &group, PR_FALSE);
538 /* XXX we should check the subtemplate in debug builds */
539 if (SECSuccess == rv)
541 /* first, count the number of entries. Benchmarking showed that this
542 counting pass is more efficient than trying to allocate entries as
543 we read the DER, even if allocating many entries at a time
545 SECItem counter = group;
548 SECItem anitem;
549 rv = GetItem(&counter, &anitem, PR_TRUE);
550 if (SECSuccess == rv && (anitem.len) )
552 totalEntries++;
554 } while ( (SECSuccess == rv) && (counter.len) );
556 if (SECSuccess == rv)
558 /* allocate room for pointer array and entries */
559 /* we want to allocate the array even if there is 0 entry */
560 entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*)*
561 (totalEntries + 1 ) + /* the extra one is for NULL termination */
562 subTemplate->size*totalEntries);
564 if (entries)
566 entries[totalEntries] = NULL; /* terminate the array */
568 else
570 PORT_SetError(SEC_ERROR_NO_MEMORY);
571 rv = SECFailure;
573 if (SECSuccess == rv)
575 void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*)*(totalEntries + 1 ));
576 /* and fix the pointers in the array */
577 PRUint32 entriesIndex = 0;
578 for (entriesIndex = 0;entriesIndex<totalEntries;entriesIndex++)
580 entries[entriesIndex] =
581 (char*)entriesData + (subTemplate->size*entriesIndex);
587 if (SECSuccess == rv && totalEntries)
590 if (!(entryIndex<totalEntries))
592 rv = SECFailure;
593 break;
595 rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE);
596 } while ( (SECSuccess == rv) && (group.len) );
597 /* we should be at the end of the set by now */
598 /* save the entries where requested */
599 memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**));
601 return rv;
604 static SECStatus DecodeExplicit(void* dest,
605 const SEC_ASN1Template* templateEntry,
606 SECItem* src, PRArenaPool* arena)
608 SECStatus rv = SECSuccess;
609 SECItem subItem;
610 SECItem constructed = *src;
612 rv = GetItem(&constructed, &subItem, PR_FALSE);
614 if (SECSuccess == rv)
616 if (templateEntry->kind & SEC_ASN1_POINTER)
618 rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE);
620 else
622 rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE);
626 return rv;
629 /* new decoder implementation. This is a recursive function */
631 static SECStatus DecodeItem(void* dest,
632 const SEC_ASN1Template* templateEntry,
633 SECItem* src, PRArenaPool* arena, PRBool checkTag)
635 SECStatus rv = SECSuccess;
636 SECItem temp;
637 SECItem mark;
638 PRBool pop = PR_FALSE;
639 PRBool decode = PR_TRUE;
640 PRBool save = PR_FALSE;
641 unsigned long kind;
642 PRBool match = PR_TRUE;
643 PRBool optional = PR_FALSE;
645 PR_ASSERT(src && dest && templateEntry && arena);
646 #if 0
647 if (!src || !dest || !templateEntry || !arena)
649 PORT_SetError(SEC_ERROR_INVALID_ARGS);
650 rv = SECFailure;
652 #endif
654 if (SECSuccess == rv)
656 /* do the template validation */
657 kind = templateEntry->kind;
658 optional = (0 != (kind & SEC_ASN1_OPTIONAL));
659 if (!kind)
661 PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
662 rv = SECFailure;
666 if (SECSuccess == rv)
668 #ifdef DEBUG
669 if (kind & SEC_ASN1_DEBUG_BREAK)
671 /* when debugging the decoder or a template that fails to
672 decode, put SEC_ASN1_DEBUG in the component that gives you
673 trouble. The decoder will then get to this block and assert.
674 If you want to debug the rest of the code, you can set a
675 breakpoint and set dontassert to PR_TRUE, which will let
676 you skip over the assert and continue the debugging session
677 past it. */
678 PRBool dontassert = PR_FALSE;
679 PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/
681 #endif
683 if ((kind & SEC_ASN1_SKIP) ||
684 (kind & SEC_ASN1_SAVE))
686 /* if skipping or saving this component, don't decode it */
687 decode = PR_FALSE;
690 if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL))
692 /* if saving this component, or if it is optional, we may not want to
693 move past it, so save the position in case we have to rewind */
694 mark = *src;
695 if (kind & SEC_ASN1_SAVE)
697 save = PR_TRUE;
698 if (0 == (kind & SEC_ASN1_SKIP))
700 /* we will for sure have to rewind when saving this
701 component and not skipping it. This is true for all
702 legacy uses of SEC_ASN1_SAVE where the following entry
703 in the template would causes the same component to be
704 processed again */
705 pop = PR_TRUE;
710 rv = GetItem(src, &temp, PR_TRUE);
713 if (SECSuccess == rv)
715 /* now check if the component matches what we expect in the template */
717 if (PR_TRUE == checkTag)
720 rv = MatchComponentType(templateEntry, &temp, &match, dest);
723 if ( (SECSuccess == rv) && (PR_TRUE != match) )
725 if (kind & SEC_ASN1_OPTIONAL)
728 /* the optional component is missing. This is not fatal. */
729 /* Rewind, don't decode, and don't save */
730 pop = PR_TRUE;
731 decode = PR_FALSE;
732 save = PR_FALSE;
734 else
736 /* a required component is missing. abort */
737 PORT_SetError(SEC_ERROR_BAD_DER);
738 rv = SECFailure;
743 if ((SECSuccess == rv) && (PR_TRUE == decode))
745 /* the order of processing here is is the tricky part */
746 /* we start with our special cases */
747 /* first, check the component class */
748 if (kind & SEC_ASN1_INLINE)
750 /* decode inline template */
751 rv = DecodeInline(dest, templateEntry, &temp , arena, PR_TRUE);
754 else
755 if (kind & SEC_ASN1_EXPLICIT)
757 rv = DecodeExplicit(dest, templateEntry, &temp, arena);
759 else
760 if ( (SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) &&
762 (!(kind & SEC_ASN1_EXPLICIT)))
765 /* decode implicitly tagged components */
766 rv = DecodeImplicit(dest, templateEntry, &temp , arena);
768 else
769 if (kind & SEC_ASN1_POINTER)
771 rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE);
773 else
774 if (kind & SEC_ASN1_CHOICE)
776 rv = DecodeChoice(dest, templateEntry, &temp, arena);
778 else
779 if (kind & SEC_ASN1_ANY)
781 /* catch-all ANY type, don't decode */
782 save = PR_TRUE;
783 if (kind & SEC_ASN1_INNER)
785 /* skip the tag and length */
786 SECItem newtemp = temp;
787 rv = GetItem(&newtemp, &temp, PR_FALSE);
790 else
791 if (kind & SEC_ASN1_GROUP)
793 if ( (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) ||
794 (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK)) )
796 rv = DecodeGroup(dest, templateEntry, &temp , arena);
798 else
800 /* a group can only be a SET OF or SEQUENCE OF */
801 PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
802 rv = SECFailure;
805 else
806 if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK))
808 /* plain SEQUENCE */
809 rv = DecodeSequence(dest, templateEntry, &temp , arena);
811 else
813 /* handle all other types as "save" */
814 /* we should only get here for primitive universal types */
815 SECItem newtemp = temp;
816 rv = GetItem(&newtemp, &temp, PR_FALSE);
817 save = PR_TRUE;
818 if ((SECSuccess == rv) && SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK))
819 switch (kind & SEC_ASN1_TAGNUM_MASK)
821 /* special cases of primitive types */
822 case SEC_ASN1_INTEGER:
824 /* remove leading zeroes if the caller requested siUnsignedInteger
825 This is to allow RSA key operations to work */
826 SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
827 if (destItem && (siUnsignedInteger == destItem->type))
829 while (temp.len > 1 && temp.data[0] == 0)
830 { /* leading 0 */
831 temp.data++;
832 temp.len--;
835 break;
838 case SEC_ASN1_BIT_STRING:
840 /* change the length in the SECItem to be the number of bits */
841 if (temp.len && temp.data)
843 temp.len = (temp.len-1)*8 - ((*(unsigned char*)temp.data) & 0x7);
844 temp.data = (unsigned char*)(temp.data+1);
846 break;
849 default:
851 break;
857 if ((SECSuccess == rv) && (PR_TRUE == save))
859 SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
860 if (destItem)
862 /* we leave the type alone in the destination SECItem.
863 If part of the destination was allocated by the decoder, in
864 cases of POINTER, SET OF and SEQUENCE OF, then type is set to
865 siBuffer due to the use of PORT_ArenaZAlloc*/
866 destItem->data = temp.data;
867 destItem->len = temp.len;
869 else
871 PORT_SetError(SEC_ERROR_INVALID_ARGS);
872 rv = SECFailure;
876 if (PR_TRUE == pop)
878 /* we don't want to move ahead, so restore the position */
879 *src = mark;
881 return rv;
884 /* the function below is the public one */
886 SECStatus SEC_QuickDERDecodeItem(PRArenaPool* arena, void* dest,
887 const SEC_ASN1Template* templateEntry,
888 const SECItem* src)
890 SECStatus rv = SECSuccess;
891 SECItem newsrc;
893 if (!arena || !templateEntry || !src)
895 PORT_SetError(SEC_ERROR_INVALID_ARGS);
896 rv = SECFailure;
899 if (SECSuccess == rv)
901 newsrc = *src;
902 rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE);
903 if (SECSuccess == rv && newsrc.len)
905 rv = SECFailure;
906 PORT_SetError(SEC_ERROR_EXTRA_INPUT);
910 return rv;