OLD | NEW |
| (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 | |
OLD | NEW |