Coverage Report

Created: 2025-04-22 06:15

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