Coverage Report

Created: 2025-08-18 06:34

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