Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(653)

Side by Side Diff: nss/lib/util/quickder.c

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

Powered by Google App Engine
This is Rietveld 408576698