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