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