Coverage Report

Created: 2024-05-20 06:23

/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
26.3k
{
23
26.3k
    unsigned char tag;
24
26.3k
    unsigned int used_length = 0;
25
26.3k
    unsigned int data_length = 0;
26
26.3k
    unsigned char length_field_len = 0;
27
26.3k
    unsigned char byte;
28
26.3k
    unsigned int i;
29
30
26.3k
    if (used_length >= buf_length) {
31
        /* Tag field was not found! */
32
0
        return NULL;
33
0
    }
34
26.3k
    tag = buf[used_length++];
35
36
26.3k
    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
1
        return NULL;
40
1
    }
41
42
26.3k
    if ((tag & 0x1F) == 0x1F) {
43
        /* High tag number (a tag number > 30) is not supported */
44
0
        return NULL;
45
0
    }
46
47
26.3k
    if (used_length >= buf_length) {
48
        /* Length field was not found! */
49
0
        return NULL;
50
0
    }
51
26.3k
    byte = buf[used_length++];
52
53
26.3k
    if (!(byte & 0x80)) {
54
        /* Short form: The high bit is not set. */
55
23.5k
        data_length = byte; /* clarity; we're returning a 32-bit int. */
56
23.5k
    } else {
57
        /* Long form. Extract the field length */
58
2.76k
        length_field_len = byte & 0x7F;
59
2.76k
        if (length_field_len == 0) {
60
            /* DER doesn't use the indefinite length form. */
61
0
            return NULL;
62
0
        }
63
64
2.76k
        if (length_field_len > sizeof(data_length)) {
65
            /* We don't support an extended length field  longer than
66
               4 bytes (2^32) */
67
0
            return NULL;
68
0
        }
69
70
2.76k
        if (length_field_len > (buf_length - used_length)) {
71
            /* Extended length field was not found */
72
0
            return NULL;
73
0
        }
74
75
        /* Iterate across the extended length field */
76
5.75k
        for (i = 0; i < length_field_len; i++) {
77
2.98k
            byte = buf[used_length++];
78
2.98k
            data_length = (data_length << 8) | byte;
79
80
2.98k
            if (i == 0) {
81
2.76k
                PRBool too_long = PR_FALSE;
82
2.76k
                if (length_field_len == 1) {
83
2.54k
                    too_long = ((byte & 0x80) == 0); /* Short form suffices */
84
2.54k
                } else {
85
217
                    too_long = (byte == 0); /* This zero byte can be omitted */
86
217
                }
87
2.76k
                if (too_long) {
88
                    /* The length is longer than needed. */
89
0
                    return NULL;
90
0
                }
91
2.76k
            }
92
2.98k
        }
93
2.76k
    }
94
95
26.3k
    if ((tag & SEC_ASN1_TAGNUM_MASK) == SEC_ASN1_NULL && data_length != 0) {
96
        /* The DER encoding of NULL has no contents octets */
97
2
        return NULL;
98
2
    }
99
100
26.3k
    if (data_length > (buf_length - used_length)) {
101
        /* The decoded length exceeds the available buffer */
102
3
        return NULL;
103
3
    }
104
105
26.3k
    if (includeTag) {
106
13.4k
        data_length += used_length;
107
13.4k
    }
108
109
26.3k
    *out_data_length = data_length;
110
26.3k
    return ((unsigned char*)buf + (includeTag ? 0 : used_length));
111
26.3k
}
112
113
static SECStatus
114
GetItem(SECItem* src, SECItem* dest, PRBool includeTag)
115
26.3k
{
116
26.3k
    if ((!src) || (!dest) || (!src->data && src->len)) {
117
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
118
0
        return SECFailure;
119
0
    }
120
121
26.3k
    if (!src->len) {
122
        /* reaching the end of the buffer is not an error */
123
31
        dest->data = NULL;
124
31
        dest->len = 0;
125
31
        return SECSuccess;
126
31
    }
127
128
26.3k
    dest->data = definite_length_decoder(src->data, src->len, &dest->len,
129
26.3k
                                         includeTag);
130
26.3k
    if (dest->data == NULL) {
131
6
        PORT_SetError(SEC_ERROR_BAD_DER);
132
6
        return SECFailure;
133
6
    }
134
26.3k
    src->len -= (int)(dest->data - src->data) + dest->len;
135
26.3k
    src->data = dest->data + dest->len;
136
26.3k
    return SECSuccess;
137
26.3k
}
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
13.4k
{
145
13.4k
    unsigned long kind = 0;
146
13.4k
    unsigned char tag = 0;
147
148
13.4k
    if ((!item) || (!item->data && item->len) || (!templateEntry) || (!match)) {
149
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
150
0
        return SECFailure;
151
0
    }
152
153
13.4k
    if (!item->len) {
154
29
        *match = PR_FALSE;
155
29
        return SECSuccess;
156
29
    }
157
158
13.3k
    kind = templateEntry->kind;
159
13.3k
    tag = *(unsigned char*)item->data;
160
161
13.3k
    if (((kind & SEC_ASN1_INLINE) ||
162
13.3k
         (kind & SEC_ASN1_POINTER)) &&
163
13.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
129
        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
129
            *match = PR_TRUE;
173
129
            return SECSuccess;
174
129
        } 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
129
    }
197
198
13.2k
    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
18
        unsigned choiceIndex = 1;
206
18
        const SEC_ASN1Template* choiceEntry;
207
18
        while ((choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind)) {
208
18
            if ((SECSuccess == MatchComponentType(choiceEntry, item, match,
209
18
                                                  (void*)((char*)dest + choiceEntry->offset))) &&
210
18
                (PR_TRUE == *match)) {
211
18
                return SECSuccess;
212
18
            }
213
18
        }
214
        /* no match, caller must decide if this is BAD DER, or not. */
215
0
        *match = PR_FALSE;
216
0
        return SECSuccess;
217
18
    }
218
219
13.2k
    if (kind & SEC_ASN1_ANY) {
220
        /* SEC_ASN1_ANY always matches */
221
158
        *match = PR_TRUE;
222
158
        return SECSuccess;
223
158
    }
224
225
13.0k
    if ((0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) &&
226
13.0k
        (!(kind & SEC_ASN1_EXPLICIT)) &&
227
13.0k
        (((kind & SEC_ASN1_SAVE) ||
228
110
          (kind & SEC_ASN1_SKIP)) &&
229
110
         (!(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
108
        *match = PR_TRUE;
237
108
        return SECSuccess;
238
108
    }
239
240
    /* first, do a class check */
241
12.9k
    if ((tag & SEC_ASN1_CLASS_MASK) !=
242
12.9k
        (((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
0
        *match = PR_FALSE;
247
0
        return SECSuccess;
248
0
    }
249
250
    /* now do a tag check */
251
12.9k
    if (((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) !=
252
12.9k
        (tag & SEC_ASN1_TAGNUM_MASK)) {
253
35
        *match = PR_FALSE;
254
35
        return SECSuccess;
255
35
    }
256
257
    /* now, do a method check. This depends on the class */
258
12.9k
    switch (tag & SEC_ASN1_CLASS_MASK) {
259
12.8k
        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
12.8k
            switch (tag & SEC_ASN1_TAGNUM_MASK) {
263
271
                case SEC_ASN1_SEQUENCE:
264
300
                case SEC_ASN1_SET:
265
300
                case SEC_ASN1_EMBEDDED_PDV:
266
                    /* this component must be a constructed type */
267
                    /* XXX add any new universal constructed type here */
268
300
                    if (tag & SEC_ASN1_CONSTRUCTED) {
269
300
                        *match = PR_TRUE;
270
300
                        return SECSuccess;
271
300
                    }
272
0
                    break;
273
274
12.5k
                default:
275
                    /* this component must be a primitive type */
276
12.5k
                    if (!(tag & SEC_ASN1_CONSTRUCTED)) {
277
12.5k
                        *match = PR_TRUE;
278
12.5k
                        return SECSuccess;
279
12.5k
                    }
280
0
                    break;
281
12.8k
            }
282
0
            break;
283
284
63
        default:
285
            /* for all other classes, we check the method based on the template */
286
63
            if ((unsigned char)(kind & SEC_ASN1_METHOD_MASK) ==
287
63
                (tag & SEC_ASN1_METHOD_MASK)) {
288
63
                *match = PR_TRUE;
289
63
                return SECSuccess;
290
63
            }
291
            /* method does not match between template and component */
292
0
            break;
293
12.9k
    }
294
295
0
    *match = PR_FALSE;
296
0
    return SECSuccess;
297
12.9k
}
298
299
#ifdef DEBUG
300
301
static SECStatus
302
CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate)
303
244
{
304
244
    SECStatus rv = SECSuccess;
305
244
    const SEC_ASN1Template* sequenceEntry = NULL;
306
244
    unsigned long seqIndex = 0;
307
244
    unsigned long lastEntryIndex = 0;
308
244
    unsigned long ambiguityIndex = 0;
309
244
    PRBool foundAmbiguity = PR_FALSE;
310
311
988
    do {
312
988
        sequenceEntry = &sequenceTemplate[seqIndex++];
313
988
        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
744
            if ((PR_FALSE == foundAmbiguity) &&
319
744
                (sequenceEntry->kind & SEC_ASN1_OPTIONAL) &&
320
744
                (sequenceEntry->kind & SEC_ASN1_ANY)) {
321
66
                foundAmbiguity = PR_TRUE;
322
66
                ambiguityIndex = seqIndex - 1;
323
66
            }
324
744
        }
325
988
    } while (sequenceEntry->kind);
326
327
244
    lastEntryIndex = seqIndex - 2;
328
329
244
    if (PR_FALSE != foundAmbiguity) {
330
66
        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
66
    }
336
337
    /* XXX also enforce ASN.1 requirement that tags be
338
       distinct for consecutive optional components */
339
340
244
    return rv;
341
244
}
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
244
{
354
244
    SECStatus rv = SECSuccess;
355
244
    SECItem source;
356
244
    SECItem sequence;
357
244
    const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]);
358
244
    const SEC_ASN1Template* sequenceEntry = NULL;
359
244
    unsigned long seqindex = 0;
360
361
244
#ifdef DEBUG
362
    /* for a sequence, we need to validate the template. */
363
244
    rv = CheckSequenceTemplate(sequenceTemplate);
364
244
#endif
365
366
244
    source = *src;
367
368
    /* get the sequence */
369
244
    if (SECSuccess == rv) {
370
244
        rv = GetItem(&source, &sequence, PR_FALSE);
371
244
    }
372
373
    /* process it */
374
244
    if (SECSuccess == rv)
375
938
        do {
376
938
            sequenceEntry = &sequenceTemplate[seqindex++];
377
938
            if ((sequenceEntry && sequenceEntry->kind) &&
378
938
                (sequenceEntry->kind != SEC_ASN1_SKIP_REST)) {
379
698
                rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE);
380
698
            }
381
938
        } while ((SECSuccess == rv) &&
382
938
                 (sequenceEntry->kind &&
383
934
                  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
244
    if (SECSuccess == rv && sequence.len &&
387
244
        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
2
        PORT_SetError(SEC_ERROR_BAD_DER);
392
2
        rv = SECFailure;
393
2
    }
394
395
244
    return rv;
396
244
}
397
398
static SECStatus
399
DecodeInline(void* dest,
400
             const SEC_ASN1Template* templateEntry,
401
             SECItem* src, PLArenaPool* arena, PRBool checkTag)
402
192
{
403
192
    const SEC_ASN1Template* inlineTemplate =
404
192
        SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE);
405
192
    return DecodeItem((void*)((char*)dest + templateEntry->offset),
406
192
                      inlineTemplate, src, arena, checkTag);
407
192
}
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
4
{
435
4
    if (templateEntry->kind & SEC_ASN1_POINTER) {
436
0
        return DecodePointer((void*)((char*)dest),
437
0
                             templateEntry, src, arena, PR_FALSE);
438
4
    } else {
439
4
        return DecodeInline((void*)((char*)dest),
440
4
                            templateEntry, src, arena, PR_FALSE);
441
4
    }
442
4
}
443
444
static SECStatus
445
DecodeChoice(void* dest,
446
             const SEC_ASN1Template* templateEntry,
447
             SECItem* src, PLArenaPool* arena)
448
18
{
449
18
    SECStatus rv = SECSuccess;
450
18
    SECItem choice;
451
18
    const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]);
452
18
    const SEC_ASN1Template* choiceEntry = NULL;
453
18
    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
18
    do {
462
18
        choice = *src;
463
18
        choiceEntry = &choiceTemplate[choiceindex++];
464
18
        if (choiceEntry->kind) {
465
18
            rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE);
466
18
        }
467
18
    } while ((SECFailure == rv) && (choiceEntry->kind));
468
469
18
    if (SECFailure == rv) {
470
        /* the component didn't match any of the choices */
471
0
        PORT_SetError(SEC_ERROR_BAD_DER);
472
18
    } else {
473
        /* set the type in the union here */
474
18
        int* which = (int*)((char*)dest + templateEntry->offset);
475
18
        *which = (int)choiceEntry->size;
476
18
    }
477
478
    /* we should have consumed all the bytes by now */
479
    /* fail if we have not */
480
18
    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
18
    return rv;
486
18
}
487
488
static SECStatus
489
DecodeGroup(void* dest,
490
            const SEC_ASN1Template* templateEntry,
491
            SECItem* src, PLArenaPool* arena)
492
57
{
493
57
    SECStatus rv = SECSuccess;
494
57
    SECItem source;
495
57
    SECItem group;
496
57
    PRUint32 totalEntries = 0;
497
57
    PRUint32 entryIndex = 0;
498
57
    void** entries = NULL;
499
500
57
    const SEC_ASN1Template* subTemplate =
501
57
        SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE);
502
503
57
    source = *src;
504
505
    /* get the group */
506
57
    if (SECSuccess == rv) {
507
57
        rv = GetItem(&source, &group, PR_FALSE);
508
57
    }
509
510
    /* XXX we should check the subtemplate in debug builds */
511
57
    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
57
        SECItem counter = group;
517
75
        do {
518
75
            SECItem anitem;
519
75
            rv = GetItem(&counter, &anitem, PR_TRUE);
520
75
            if (SECSuccess == rv && (anitem.len)) {
521
73
                totalEntries++;
522
73
            }
523
75
        } while ((SECSuccess == rv) && (counter.len));
524
525
57
        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
57
            entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*) * (totalEntries + 1) + /* the extra one is for NULL termination */
529
57
                                                          subTemplate->size * totalEntries);
530
531
57
            if (entries) {
532
57
                entries[totalEntries] = NULL; /* terminate the array */
533
57
            } else {
534
0
                PORT_SetError(SEC_ERROR_NO_MEMORY);
535
0
                rv = SECFailure;
536
0
            }
537
57
            if (SECSuccess == rv) {
538
57
                void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*) * (totalEntries + 1));
539
                /* and fix the pointers in the array */
540
57
                PRUint32 entriesIndex = 0;
541
130
                for (entriesIndex = 0; entriesIndex < totalEntries; entriesIndex++) {
542
73
                    entries[entriesIndex] =
543
73
                        (char*)entriesData + (subTemplate->size * entriesIndex);
544
73
                }
545
57
            }
546
57
        }
547
57
    }
548
549
57
    if (SECSuccess == rv && totalEntries)
550
73
        do {
551
73
            if (!(entryIndex < totalEntries)) {
552
0
                rv = SECFailure;
553
0
                break;
554
0
            }
555
73
            rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE);
556
73
        } 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
57
    return rv;
562
57
}
563
564
static SECStatus
565
DecodeExplicit(void* dest,
566
               const SEC_ASN1Template* templateEntry,
567
               SECItem* src, PLArenaPool* arena)
568
59
{
569
59
    SECStatus rv = SECSuccess;
570
59
    SECItem subItem;
571
59
    SECItem constructed = *src;
572
573
59
    rv = GetItem(&constructed, &subItem, PR_FALSE);
574
575
59
    if (SECSuccess == rv) {
576
59
        if (templateEntry->kind & SEC_ASN1_POINTER) {
577
0
            rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE);
578
59
        } else {
579
59
            rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE);
580
59
        }
581
59
    }
582
583
59
    return rv;
584
59
}
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
13.3k
{
593
13.3k
    SECStatus rv = SECSuccess;
594
13.3k
    SECItem temp;
595
13.3k
    SECItem mark = { siBuffer, NULL, 0 };
596
13.3k
    PRBool pop = PR_FALSE;
597
13.3k
    PRBool decode = PR_TRUE;
598
13.3k
    PRBool save = PR_FALSE;
599
13.3k
    unsigned long kind;
600
13.3k
    PRBool match = PR_TRUE;
601
602
13.3k
    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
13.3k
    if (SECSuccess == rv) {
612
        /* do the template validation */
613
13.3k
        kind = templateEntry->kind;
614
13.3k
        if (!kind) {
615
0
            PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
616
0
            rv = SECFailure;
617
0
        }
618
13.3k
    }
619
620
13.3k
    if (SECSuccess == rv) {
621
13.3k
#ifdef DEBUG
622
13.3k
        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
13.3k
#endif
634
635
13.3k
        if ((kind & SEC_ASN1_SKIP) ||
636
13.3k
            (kind & SEC_ASN1_SAVE)) {
637
            /* if skipping or saving this component, don't decode it */
638
108
            decode = PR_FALSE;
639
108
        }
640
641
13.3k
        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
214
            mark = *src;
645
214
            if (kind & SEC_ASN1_SAVE) {
646
36
                save = PR_TRUE;
647
36
                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
36
                    pop = PR_TRUE;
654
36
                }
655
36
            }
656
214
        }
657
658
13.3k
        rv = GetItem(src, &temp, PR_TRUE);
659
13.3k
    }
660
661
13.3k
    if (SECSuccess == rv) {
662
        /* now check if the component matches what we expect in the template */
663
664
13.3k
        if (PR_TRUE == checkTag)
665
666
13.3k
        {
667
13.3k
            rv = MatchComponentType(templateEntry, &temp, &match, dest);
668
13.3k
        }
669
670
13.3k
        if ((SECSuccess == rv) && (PR_TRUE != match)) {
671
64
            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
64
                pop = PR_TRUE;
676
64
                decode = PR_FALSE;
677
64
                save = PR_FALSE;
678
64
            } else {
679
                /* a required component is missing. abort */
680
0
                PORT_SetError(SEC_ERROR_BAD_DER);
681
0
                rv = SECFailure;
682
0
            }
683
64
        }
684
13.3k
    }
685
686
13.3k
    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
13.2k
        if (kind & SEC_ASN1_INLINE) {
691
            /* decode inline template */
692
129
            rv = DecodeInline(dest, templateEntry, &temp, arena, PR_TRUE);
693
129
        }
694
695
13.0k
        else if (kind & SEC_ASN1_EXPLICIT) {
696
59
            rv = DecodeExplicit(dest, templateEntry, &temp, arena);
697
13.0k
        } else if ((SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) &&
698
699
13.0k
                   (!(kind & SEC_ASN1_EXPLICIT))) {
700
701
            /* decode implicitly tagged components */
702
4
            rv = DecodeImplicit(dest, templateEntry, &temp, arena);
703
13.0k
        } else if (kind & SEC_ASN1_POINTER) {
704
0
            rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE);
705
13.0k
        } else if (kind & SEC_ASN1_CHOICE) {
706
18
            rv = DecodeChoice(dest, templateEntry, &temp, arena);
707
13.0k
        } else if (kind & SEC_ASN1_ANY) {
708
            /* catch-all ANY type, don't decode */
709
158
            save = PR_TRUE;
710
158
            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
12.8k
        } else if (kind & SEC_ASN1_GROUP) {
716
57
            if ((SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) ||
717
57
                (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK))) {
718
57
                rv = DecodeGroup(dest, templateEntry, &temp, arena);
719
57
            } 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
12.7k
        } else if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) {
725
            /* plain SEQUENCE */
726
244
            rv = DecodeSequence(dest, templateEntry, &temp, arena);
727
12.5k
        } else {
728
            /* handle all other types as "save" */
729
            /* we should only get here for primitive universal types */
730
12.5k
            SECItem newtemp = temp;
731
12.5k
            rv = GetItem(&newtemp, &temp, PR_FALSE);
732
12.5k
            save = PR_TRUE;
733
12.5k
            if ((SECSuccess == rv) &&
734
12.5k
                SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK)) {
735
12.5k
                unsigned long tagnum = kind & SEC_ASN1_TAGNUM_MASK;
736
12.5k
                if (temp.len == 0 && (tagnum == SEC_ASN1_BOOLEAN ||
737
0
                                      tagnum == SEC_ASN1_INTEGER ||
738
0
                                      tagnum == SEC_ASN1_BIT_STRING ||
739
0
                                      tagnum == SEC_ASN1_OBJECT_ID ||
740
0
                                      tagnum == SEC_ASN1_ENUMERATED ||
741
0
                                      tagnum == SEC_ASN1_UTC_TIME ||
742
0
                                      tagnum == SEC_ASN1_GENERALIZED_TIME)) {
743
                    /* these types MUST have at least one content octet */
744
0
                    PORT_SetError(SEC_ERROR_BAD_DER);
745
0
                    rv = SECFailure;
746
0
                } else
747
12.5k
                    switch (tagnum) {
748
                        /* special cases of primitive types */
749
39
                        case SEC_ASN1_INTEGER: {
750
39
                            SECItem* destItem = (SECItem*)((char*)dest +
751
39
                                                           templateEntry->offset);
752
39
                            if (destItem && (siUnsignedInteger == destItem->type)) {
753
                                /* A leading 0 is only allowed when a value
754
                                 * would otherwise be interpreted as negative. */
755
19
                                if (temp.len > 1 && temp.data[0] == 0) {
756
8
                                    temp.data++;
757
8
                                    temp.len--;
758
8
                                    if (!(temp.data[0] & 0x80)) {
759
0
                                        PORT_SetError(SEC_ERROR_BAD_DER);
760
0
                                        rv = SECFailure;
761
0
                                    }
762
8
                                }
763
19
                            }
764
39
                            break;
765
0
                        }
766
767
59
                        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
59
                            if (temp.data[0] >= 8 || (temp.data[0] > 0 && temp.len == 1)) {
771
0
                                PORT_SetError(SEC_ERROR_BAD_DER);
772
0
                                rv = SECFailure;
773
0
                                break;
774
0
                            }
775
                            /* change the length in the SECItem to be the number
776
                               of bits */
777
59
                            temp.len = (temp.len - 1) * 8 - (temp.data[0] & 0x7);
778
59
                            temp.data++;
779
59
                            break;
780
59
                        }
781
782
12.4k
                        default: {
783
12.4k
                            break;
784
59
                        }
785
12.5k
                    }
786
12.5k
            }
787
12.5k
        }
788
13.2k
    }
789
790
13.3k
    if ((SECSuccess == rv) && (PR_TRUE == save)) {
791
12.7k
        SECItem* destItem = (SECItem*)((char*)dest + templateEntry->offset);
792
12.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
12.7k
            destItem->data = temp.len ? temp.data : NULL;
798
12.7k
            destItem->len = temp.len;
799
12.7k
        } else {
800
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
801
0
            rv = SECFailure;
802
0
        }
803
12.7k
    }
804
805
13.3k
    if (PR_TRUE == pop) {
806
        /* we don't want to move ahead, so restore the position */
807
100
        *src = mark;
808
100
    }
809
13.3k
    return rv;
810
13.3k
}
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
12.4k
{
819
12.4k
    SECStatus rv = SECSuccess;
820
12.4k
    SECItem newsrc;
821
822
12.4k
    if (!arena || !templateEntry || !src) {
823
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
824
0
        rv = SECFailure;
825
0
    }
826
827
12.4k
    if (SECSuccess == rv) {
828
12.4k
        newsrc = *src;
829
12.4k
        rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE);
830
12.4k
        if (SECSuccess == rv && newsrc.len) {
831
0
            rv = SECFailure;
832
0
            PORT_SetError(SEC_ERROR_EXTRA_INPUT);
833
0
        }
834
12.4k
    }
835
836
12.4k
    return rv;
837
12.4k
}