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/. */
6
Optimized ASN.1 DER decoder
11
#include "secasn1.h" /* for SEC_ASN1GetSubtemplate */
15
* simple definite-length ASN.1 decoder
18
static unsigned char* definite_length_decoder(const unsigned char *buf,
19
const unsigned int length,
20
unsigned int *data_length,
24
unsigned int used_length= 0;
25
unsigned int data_len;
27
if (used_length >= length)
31
tag = buf[used_length++];
33
/* blow out when we come to the end */
39
if (used_length >= length)
43
data_len = buf[used_length++];
47
int len_count = data_len & 0x7f;
51
while (len_count-- > 0)
53
if (used_length >= length)
57
data_len = (data_len << 8) | buf[used_length++];
61
if (data_len > (length-used_length) )
65
if (includeTag) data_len += used_length;
67
*data_length = data_len;
68
return ((unsigned char*)buf + (includeTag ? 0 : used_length));
71
static SECStatus GetItem(SECItem* src, SECItem* dest, PRBool includeTag)
73
if ( (!src) || (!dest) || (!src->data && src->len) )
75
PORT_SetError(SEC_ERROR_INVALID_ARGS);
81
/* reaching the end of the buffer is not an error */
87
dest->data = definite_length_decoder(src->data, src->len, &dest->len,
89
if (dest->data == NULL)
91
PORT_SetError(SEC_ERROR_BAD_DER);
94
src->len -= (dest->data - src->data) + dest->len;
95
src->data = dest->data + dest->len;
99
/* check if the actual component's type matches the type in the template */
101
static SECStatus MatchComponentType(const SEC_ASN1Template* templateEntry,
102
SECItem* item, PRBool* match, void* dest)
104
unsigned long kind = 0;
105
unsigned char tag = 0;
107
if ( (!item) || (!item->data && item->len) || (!templateEntry) || (!match) )
109
PORT_SetError(SEC_ERROR_INVALID_ARGS);
119
kind = templateEntry->kind;
120
tag = *(unsigned char*) item->data;
122
if ( ( (kind & SEC_ASN1_INLINE) ||
123
(kind & SEC_ASN1_POINTER) ) &&
124
(0 == (kind & SEC_ASN1_TAG_MASK) ) )
126
/* These cases are special because the template's "kind" does not
127
give us the information for the ASN.1 tag of the next item. It can
128
only be figured out from the subtemplate. */
129
if (!(kind & SEC_ASN1_OPTIONAL))
131
/* This is a required component. If there is a type mismatch,
132
the decoding of the subtemplate will fail, so assume this
133
is a match at the parent level and let it fail later. This
134
avoids a redundant check in matching cases */
140
/* optional component. This is the hard case. Now we need to
141
look at the subtemplate to get the expected kind */
142
const SEC_ASN1Template* subTemplate =
143
SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
146
PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
149
if ( (subTemplate->kind & SEC_ASN1_INLINE) ||
150
(subTemplate->kind & SEC_ASN1_POINTER) )
152
/* disallow nesting SEC_ASN1_POINTER and SEC_ASN1_INLINE,
153
otherwise you may get a false positive due to the recursion
154
optimization above that always matches the type if the
155
component is required . Nesting these should never be
156
required, so that no one should miss this ability */
157
PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
160
return MatchComponentType(subTemplate, item, match,
161
(void*)((char*)dest + templateEntry->offset));
165
if (kind & SEC_ASN1_CHOICE)
167
/* we need to check the component's tag against each choice's tag */
168
/* XXX it would be nice to save the index of the choice here so that
169
DecodeChoice wouldn't have to do this again. However, due to the
170
recursivity of MatchComponentType, we don't know if we are in a
171
required or optional component, so we can't write anywhere in
172
the destination within this function */
173
unsigned choiceIndex = 1;
174
const SEC_ASN1Template* choiceEntry;
175
while ( (choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind))
177
if ( (SECSuccess == MatchComponentType(choiceEntry, item, match,
178
(void*)((char*)dest + choiceEntry->offset))) &&
179
(PR_TRUE == *match) )
184
/* no match, caller must decide if this is BAD DER, or not. */
189
if (kind & SEC_ASN1_ANY)
191
/* SEC_ASN1_ANY always matches */
196
if ( (0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) &&
197
(!(kind & SEC_ASN1_EXPLICIT)) &&
198
( ( (kind & SEC_ASN1_SAVE) ||
199
(kind & SEC_ASN1_SKIP) ) &&
200
(!(kind & SEC_ASN1_OPTIONAL))
204
/* when saving or skipping a required component, a type is not
205
required in the template. This is for legacy support of
206
SEC_ASN1_SAVE and SEC_ASN1_SKIP only. XXX I would like to
207
deprecate these usages and always require a type, as this
208
disables type checking, and effectively forbids us from
209
transparently ignoring optional components we aren't aware of */
214
/* first, do a class check */
215
if ( (tag & SEC_ASN1_CLASS_MASK) !=
216
(((unsigned char)kind) & SEC_ASN1_CLASS_MASK) )
219
/* this is only to help debugging of the decoder in case of problems */
220
unsigned char tagclass = tag & SEC_ASN1_CLASS_MASK;
221
unsigned char expectedclass = (unsigned char)kind & SEC_ASN1_CLASS_MASK;
223
expectedclass = expectedclass;
229
/* now do a tag check */
230
if ( ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) !=
231
(tag & SEC_ASN1_TAGNUM_MASK))
237
/* now, do a method check. This depends on the class */
238
switch (tag & SEC_ASN1_CLASS_MASK)
240
case SEC_ASN1_UNIVERSAL:
241
/* For types of the SEC_ASN1_UNIVERSAL class, we know which must be
242
primitive or constructed based on the tag */
243
switch (tag & SEC_ASN1_TAGNUM_MASK)
245
case SEC_ASN1_SEQUENCE:
247
case SEC_ASN1_EMBEDDED_PDV:
248
/* this component must be a constructed type */
249
/* XXX add any new universal constructed type here */
250
if (tag & SEC_ASN1_CONSTRUCTED)
258
/* this component must be a primitive type */
259
if (! (tag & SEC_ASN1_CONSTRUCTED))
269
/* for all other classes, we check the method based on the template */
270
if ( (unsigned char)(kind & SEC_ASN1_METHOD_MASK) ==
271
(tag & SEC_ASN1_METHOD_MASK) )
276
/* method does not match between template and component */
286
static SECStatus CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate)
288
SECStatus rv = SECSuccess;
289
const SEC_ASN1Template* sequenceEntry = NULL;
290
unsigned long seqIndex = 0;
291
unsigned long lastEntryIndex = 0;
292
unsigned long ambiguityIndex = 0;
293
PRBool foundAmbiguity = PR_FALSE;
297
sequenceEntry = &sequenceTemplate[seqIndex++];
298
if (sequenceEntry->kind)
300
/* ensure that we don't have an optional component of SEC_ASN1_ANY
301
in the middle of the sequence, since we could not handle it */
302
/* XXX this function needs to dig into the subtemplates to find
304
if ( (PR_FALSE == foundAmbiguity) &&
305
(sequenceEntry->kind & SEC_ASN1_OPTIONAL) &&
306
(sequenceEntry->kind & SEC_ASN1_ANY) )
308
foundAmbiguity = PR_TRUE;
309
ambiguityIndex = seqIndex - 1;
312
} while (sequenceEntry->kind);
314
lastEntryIndex = seqIndex - 2;
316
if (PR_FALSE != foundAmbiguity)
318
if (ambiguityIndex < lastEntryIndex)
320
/* ambiguity can only be tolerated on the last entry */
321
PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
326
/* XXX also enforce ASN.1 requirement that tags be
327
distinct for consecutive optional components */
334
static SECStatus DecodeItem(void* dest,
335
const SEC_ASN1Template* templateEntry,
336
SECItem* src, PLArenaPool* arena, PRBool checkTag);
338
static SECStatus DecodeSequence(void* dest,
339
const SEC_ASN1Template* templateEntry,
340
SECItem* src, PLArenaPool* arena)
342
SECStatus rv = SECSuccess;
345
const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]);
346
const SEC_ASN1Template* sequenceEntry = NULL;
347
unsigned long seqindex = 0;
350
/* for a sequence, we need to validate the template. */
351
rv = CheckSequenceTemplate(sequenceTemplate);
356
/* get the sequence */
357
if (SECSuccess == rv)
359
rv = GetItem(&source, &sequence, PR_FALSE);
363
if (SECSuccess == rv)
366
sequenceEntry = &sequenceTemplate[seqindex++];
367
if ( (sequenceEntry && sequenceEntry->kind) &&
368
(sequenceEntry->kind != SEC_ASN1_SKIP_REST) )
370
rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE);
372
} while ( (SECSuccess == rv) &&
373
(sequenceEntry->kind &&
374
sequenceEntry->kind != SEC_ASN1_SKIP_REST) );
375
/* we should have consumed all the bytes in the sequence by now
376
unless the caller doesn't care about the rest of the sequence */
377
if (SECSuccess == rv && sequence.len &&
378
sequenceEntry && sequenceEntry->kind != SEC_ASN1_SKIP_REST)
380
/* it isn't 100% clear whether this is a bad DER or a bad template.
381
The problem is that logically, they don't match - there is extra
382
data in the DER that the template doesn't know about */
383
PORT_SetError(SEC_ERROR_BAD_DER);
390
static SECStatus DecodeInline(void* dest,
391
const SEC_ASN1Template* templateEntry,
392
SECItem* src, PLArenaPool* arena, PRBool checkTag)
394
const SEC_ASN1Template* inlineTemplate =
395
SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
396
return DecodeItem((void*)((char*)dest + templateEntry->offset),
397
inlineTemplate, src, arena, checkTag);
400
static SECStatus DecodePointer(void* dest,
401
const SEC_ASN1Template* templateEntry,
402
SECItem* src, PLArenaPool* arena, PRBool checkTag)
404
const SEC_ASN1Template* ptrTemplate =
405
SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
406
void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size);
407
*(void**)((char*)dest + templateEntry->offset) = subdata;
410
return DecodeItem(subdata, ptrTemplate, src, arena, checkTag);
414
PORT_SetError(SEC_ERROR_NO_MEMORY);
419
static SECStatus DecodeImplicit(void* dest,
420
const SEC_ASN1Template* templateEntry,
421
SECItem* src, PLArenaPool* arena)
423
if (templateEntry->kind & SEC_ASN1_POINTER)
425
return DecodePointer((void*)((char*)dest ),
426
templateEntry, src, arena, PR_FALSE);
430
return DecodeInline((void*)((char*)dest ),
431
templateEntry, src, arena, PR_FALSE);
435
static SECStatus DecodeChoice(void* dest,
436
const SEC_ASN1Template* templateEntry,
437
SECItem* src, PLArenaPool* arena)
439
SECStatus rv = SECSuccess;
441
const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]);
442
const SEC_ASN1Template* choiceEntry = NULL;
443
unsigned long choiceindex = 0;
445
/* XXX for a choice component, we should validate the template to make
446
sure the tags are distinct, in debug builds. This hasn't been
448
/* rv = CheckChoiceTemplate(sequenceTemplate); */
454
choiceEntry = &choiceTemplate[choiceindex++];
455
if (choiceEntry->kind)
457
rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE);
459
} while ( (SECFailure == rv) && (choiceEntry->kind));
461
if (SECFailure == rv)
463
/* the component didn't match any of the choices */
464
PORT_SetError(SEC_ERROR_BAD_DER);
468
/* set the type in the union here */
469
int *which = (int *)((char *)dest + templateEntry->offset);
470
*which = (int)choiceEntry->size;
473
/* we should have consumed all the bytes by now */
474
/* fail if we have not */
475
if (SECSuccess == rv && choice.len)
477
/* there is extra data that isn't listed in the template */
478
PORT_SetError(SEC_ERROR_BAD_DER);
484
static SECStatus DecodeGroup(void* dest,
485
const SEC_ASN1Template* templateEntry,
486
SECItem* src, PLArenaPool* arena)
488
SECStatus rv = SECSuccess;
491
PRUint32 totalEntries = 0;
492
PRUint32 entryIndex = 0;
493
void** entries = NULL;
495
const SEC_ASN1Template* subTemplate =
496
SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
501
if (SECSuccess == rv)
503
rv = GetItem(&source, &group, PR_FALSE);
506
/* XXX we should check the subtemplate in debug builds */
507
if (SECSuccess == rv)
509
/* first, count the number of entries. Benchmarking showed that this
510
counting pass is more efficient than trying to allocate entries as
511
we read the DER, even if allocating many entries at a time
513
SECItem counter = group;
517
rv = GetItem(&counter, &anitem, PR_TRUE);
518
if (SECSuccess == rv && (anitem.len) )
522
} while ( (SECSuccess == rv) && (counter.len) );
524
if (SECSuccess == rv)
526
/* allocate room for pointer array and entries */
527
/* we want to allocate the array even if there is 0 entry */
528
entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*)*
529
(totalEntries + 1 ) + /* the extra one is for NULL termination */
530
subTemplate->size*totalEntries);
534
entries[totalEntries] = NULL; /* terminate the array */
538
PORT_SetError(SEC_ERROR_NO_MEMORY);
541
if (SECSuccess == rv)
543
void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*)*(totalEntries + 1 ));
544
/* and fix the pointers in the array */
545
PRUint32 entriesIndex = 0;
546
for (entriesIndex = 0;entriesIndex<totalEntries;entriesIndex++)
548
entries[entriesIndex] =
549
(char*)entriesData + (subTemplate->size*entriesIndex);
555
if (SECSuccess == rv && totalEntries)
558
if (!(entryIndex<totalEntries))
563
rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE);
564
} while ( (SECSuccess == rv) && (group.len) );
565
/* we should be at the end of the set by now */
566
/* save the entries where requested */
567
memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**));
572
static SECStatus DecodeExplicit(void* dest,
573
const SEC_ASN1Template* templateEntry,
574
SECItem* src, PLArenaPool* arena)
576
SECStatus rv = SECSuccess;
578
SECItem constructed = *src;
580
rv = GetItem(&constructed, &subItem, PR_FALSE);
582
if (SECSuccess == rv)
584
if (templateEntry->kind & SEC_ASN1_POINTER)
586
rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE);
590
rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE);
597
/* new decoder implementation. This is a recursive function */
599
static SECStatus DecodeItem(void* dest,
600
const SEC_ASN1Template* templateEntry,
601
SECItem* src, PLArenaPool* arena, PRBool checkTag)
603
SECStatus rv = SECSuccess;
606
PRBool pop = PR_FALSE;
607
PRBool decode = PR_TRUE;
608
PRBool save = PR_FALSE;
610
PRBool match = PR_TRUE;
611
PRBool optional = PR_FALSE;
613
PR_ASSERT(src && dest && templateEntry && arena);
615
if (!src || !dest || !templateEntry || !arena)
617
PORT_SetError(SEC_ERROR_INVALID_ARGS);
622
if (SECSuccess == rv)
624
/* do the template validation */
625
kind = templateEntry->kind;
626
optional = (0 != (kind & SEC_ASN1_OPTIONAL));
629
PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
634
if (SECSuccess == rv)
637
if (kind & SEC_ASN1_DEBUG_BREAK)
639
/* when debugging the decoder or a template that fails to
640
decode, put SEC_ASN1_DEBUG in the component that gives you
641
trouble. The decoder will then get to this block and assert.
642
If you want to debug the rest of the code, you can set a
643
breakpoint and set dontassert to PR_TRUE, which will let
644
you skip over the assert and continue the debugging session
646
PRBool dontassert = PR_FALSE;
647
PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/
651
if ((kind & SEC_ASN1_SKIP) ||
652
(kind & SEC_ASN1_SAVE))
654
/* if skipping or saving this component, don't decode it */
658
if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL))
660
/* if saving this component, or if it is optional, we may not want to
661
move past it, so save the position in case we have to rewind */
663
if (kind & SEC_ASN1_SAVE)
666
if (0 == (kind & SEC_ASN1_SKIP))
668
/* we will for sure have to rewind when saving this
669
component and not skipping it. This is true for all
670
legacy uses of SEC_ASN1_SAVE where the following entry
671
in the template would causes the same component to be
678
rv = GetItem(src, &temp, PR_TRUE);
681
if (SECSuccess == rv)
683
/* now check if the component matches what we expect in the template */
685
if (PR_TRUE == checkTag)
688
rv = MatchComponentType(templateEntry, &temp, &match, dest);
691
if ( (SECSuccess == rv) && (PR_TRUE != match) )
693
if (kind & SEC_ASN1_OPTIONAL)
696
/* the optional component is missing. This is not fatal. */
697
/* Rewind, don't decode, and don't save */
704
/* a required component is missing. abort */
705
PORT_SetError(SEC_ERROR_BAD_DER);
711
if ((SECSuccess == rv) && (PR_TRUE == decode))
713
/* the order of processing here is is the tricky part */
714
/* we start with our special cases */
715
/* first, check the component class */
716
if (kind & SEC_ASN1_INLINE)
718
/* decode inline template */
719
rv = DecodeInline(dest, templateEntry, &temp , arena, PR_TRUE);
723
if (kind & SEC_ASN1_EXPLICIT)
725
rv = DecodeExplicit(dest, templateEntry, &temp, arena);
728
if ( (SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) &&
730
(!(kind & SEC_ASN1_EXPLICIT)))
733
/* decode implicitly tagged components */
734
rv = DecodeImplicit(dest, templateEntry, &temp , arena);
737
if (kind & SEC_ASN1_POINTER)
739
rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE);
742
if (kind & SEC_ASN1_CHOICE)
744
rv = DecodeChoice(dest, templateEntry, &temp, arena);
747
if (kind & SEC_ASN1_ANY)
749
/* catch-all ANY type, don't decode */
751
if (kind & SEC_ASN1_INNER)
753
/* skip the tag and length */
754
SECItem newtemp = temp;
755
rv = GetItem(&newtemp, &temp, PR_FALSE);
759
if (kind & SEC_ASN1_GROUP)
761
if ( (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) ||
762
(SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK)) )
764
rv = DecodeGroup(dest, templateEntry, &temp , arena);
768
/* a group can only be a SET OF or SEQUENCE OF */
769
PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
774
if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK))
777
rv = DecodeSequence(dest, templateEntry, &temp , arena);
781
/* handle all other types as "save" */
782
/* we should only get here for primitive universal types */
783
SECItem newtemp = temp;
784
rv = GetItem(&newtemp, &temp, PR_FALSE);
786
if ((SECSuccess == rv) &&
787
SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK))
789
unsigned long tagnum = kind & SEC_ASN1_TAGNUM_MASK;
790
if ( temp.len == 0 && (tagnum == SEC_ASN1_BOOLEAN ||
791
tagnum == SEC_ASN1_INTEGER ||
792
tagnum == SEC_ASN1_BIT_STRING ||
793
tagnum == SEC_ASN1_OBJECT_ID ||
794
tagnum == SEC_ASN1_ENUMERATED ||
795
tagnum == SEC_ASN1_UTC_TIME ||
796
tagnum == SEC_ASN1_GENERALIZED_TIME) )
798
/* these types MUST have at least one content octet */
799
PORT_SetError(SEC_ERROR_BAD_DER);
805
/* special cases of primitive types */
806
case SEC_ASN1_INTEGER:
808
/* remove leading zeroes if the caller requested
810
This is to allow RSA key operations to work */
811
SECItem* destItem = (SECItem*) ((char*)dest +
812
templateEntry->offset);
813
if (destItem && (siUnsignedInteger == destItem->type))
815
while (temp.len > 1 && temp.data[0] == 0)
824
case SEC_ASN1_BIT_STRING:
826
/* change the length in the SECItem to be the number
828
temp.len = (temp.len-1)*8 - (temp.data[0] & 0x7);
842
if ((SECSuccess == rv) && (PR_TRUE == save))
844
SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
847
/* we leave the type alone in the destination SECItem.
848
If part of the destination was allocated by the decoder, in
849
cases of POINTER, SET OF and SEQUENCE OF, then type is set to
850
siBuffer due to the use of PORT_ArenaZAlloc*/
851
destItem->data = temp.len ? temp.data : NULL;
852
destItem->len = temp.len;
856
PORT_SetError(SEC_ERROR_INVALID_ARGS);
863
/* we don't want to move ahead, so restore the position */
869
/* the function below is the public one */
871
SECStatus SEC_QuickDERDecodeItem(PLArenaPool* arena, void* dest,
872
const SEC_ASN1Template* templateEntry,
875
SECStatus rv = SECSuccess;
878
if (!arena || !templateEntry || !src)
880
PORT_SetError(SEC_ERROR_INVALID_ARGS);
884
if (SECSuccess == rv)
887
rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE);
888
if (SECSuccess == rv && newsrc.len)
891
PORT_SetError(SEC_ERROR_EXTRA_INPUT);