Coverage Report

Created: 2026-06-07 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/util/quickder.c
Line
Count
Source
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
55.4M
{
23
55.4M
    unsigned char tag;
24
55.4M
    unsigned int used_length = 0;
25
55.4M
    unsigned int data_length = 0;
26
55.4M
    unsigned char length_field_len = 0;
27
55.4M
    unsigned char byte;
28
55.4M
    unsigned int i;
29
30
55.4M
    if (used_length >= buf_length) {
31
        /* Tag field was not found! */
32
0
        return NULL;
33
0
    }
34
55.4M
    tag = buf[used_length++];
35
36
55.4M
    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.65k
        return NULL;
40
1.65k
    }
41
42
55.4M
    if ((tag & 0x1F) == 0x1F) {
43
        /* High tag number (a tag number > 30) is not supported */
44
1.07k
        return NULL;
45
1.07k
    }
46
47
55.4M
    if (used_length >= buf_length) {
48
        /* Length field was not found! */
49
3.16k
        return NULL;
50
3.16k
    }
51
55.4M
    byte = buf[used_length++];
52
53
55.4M
    if (!(byte & 0x80)) {
54
        /* Short form: The high bit is not set. */
55
51.3M
        data_length = byte; /* clarity; we're returning a 32-bit int. */
56
51.3M
    } else {
57
        /* Long form. Extract the field length */
58
4.12M
        length_field_len = byte & 0x7F;
59
4.12M
        if (length_field_len == 0) {
60
            /* DER doesn't use the indefinite length form. */
61
817
            return NULL;
62
817
        }
63
64
4.12M
        if (length_field_len > sizeof(data_length)) {
65
            /* We don't support an extended length field  longer than
66
               4 bytes (2^32) */
67
3.77k
            return NULL;
68
3.77k
        }
69
70
4.11M
        if (length_field_len > (buf_length - used_length)) {
71
            /* Extended length field was not found */
72
671
            return NULL;
73
671
        }
74
75
        /* Iterate across the extended length field */
76
10.5M
        for (i = 0; i < length_field_len; i++) {
77
6.47M
            byte = buf[used_length++];
78
6.47M
            data_length = (data_length << 8) | byte;
79
80
6.47M
            if (i == 0) {
81
4.11M
                PRBool too_long = PR_FALSE;
82
4.11M
                if (length_field_len == 1) {
83
1.77M
                    too_long = ((byte & 0x80) == 0); /* Short form suffices */
84
2.34M
                } else {
85
2.34M
                    too_long = (byte == 0); /* This zero byte can be omitted */
86
2.34M
                }
87
4.11M
                if (too_long) {
88
                    /* The length is longer than needed. */
89
1.21k
                    return NULL;
90
1.21k
                }
91
4.11M
            }
92
6.47M
        }
93
4.11M
    }
94
95
55.4M
    if ((tag & SEC_ASN1_TAGNUM_MASK) == SEC_ASN1_NULL && data_length != 0) {
96
        /* The DER encoding of NULL has no contents octets */
97
4.41k
        return NULL;
98
4.41k
    }
99
100
55.4M
    if (data_length > (buf_length - used_length)) {
101
        /* The decoded length exceeds the available buffer */
102
21.0k
        return NULL;
103
21.0k
    }
104
105
55.4M
    if (includeTag) {
106
48.3M
        data_length += used_length;
107
48.3M
    }
108
109
55.4M
    *out_data_length = data_length;
110
55.4M
    return ((unsigned char*)buf + (includeTag ? 0 : used_length));
111
55.4M
}
112
113
static SECStatus
114
GetItem(SECItem* src, SECItem* dest, PRBool includeTag)
115
56.0M
{
116
56.0M
    if ((!src) || (!dest) || (!src->data && src->len)) {
117
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
118
0
        return SECFailure;
119
0
    }
120
121
56.0M
    if (!src->len) {
122
        /* reaching the end of the buffer is not an error */
123
578k
        dest->data = NULL;
124
578k
        dest->len = 0;
125
578k
        return SECSuccess;
126
578k
    }
127
128
55.4M
    dest->data = definite_length_decoder(src->data, src->len, &dest->len,
129
55.4M
                                         includeTag);
130
55.4M
    if (dest->data == NULL) {
131
37.8k
        PORT_SetError(SEC_ERROR_BAD_DER);
132
37.8k
        return SECFailure;
133
37.8k
    }
134
55.4M
    src->len -= (int)(dest->data - src->data) + dest->len;
135
55.4M
    src->data = dest->data + dest->len;
136
55.4M
    return SECSuccess;
137
55.4M
}
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
19.1M
{
145
19.1M
    unsigned long kind = 0;
146
19.1M
    unsigned char tag = 0;
147
148
19.1M
    if ((!item) || (!item->data && item->len) || (!templateEntry) || (!match)) {
149
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
150
0
        return SECFailure;
151
0
    }
152
153
19.1M
    if (!item->len) {
154
520k
        *match = PR_FALSE;
155
520k
        return SECSuccess;
156
520k
    }
157
158
18.5M
    kind = templateEntry->kind;
159
18.5M
    tag = *(unsigned char*)item->data;
160
161
18.5M
    if (((kind & SEC_ASN1_INLINE) ||
162
17.1M
         (kind & SEC_ASN1_POINTER)) &&
163
1.42M
        (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
1.42M
        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
1.42M
            *match = PR_TRUE;
173
1.42M
            return SECSuccess;
174
1.42M
        } else {
175
            /* optional component. This is the hard case. Now we need to
176
               look at the subtemplate to get the expected kind */
177
5.03k
            const SEC_ASN1Template* subTemplate =
178
5.03k
                SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE);
179
5.03k
            if (!subTemplate) {
180
0
                PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
181
0
                return SECFailure;
182
0
            }
183
5.03k
            if ((subTemplate->kind & SEC_ASN1_INLINE) ||
184
5.03k
                (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
5.03k
            return MatchComponentType(subTemplate, item, match,
194
5.03k
                                      (void*)((char*)dest + templateEntry->offset));
195
5.03k
        }
196
1.42M
    }
197
198
17.1M
    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
196k
        unsigned choiceIndex = 1;
206
196k
        const SEC_ASN1Template* choiceEntry;
207
217k
        while ((choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind)) {
208
211k
            if ((SECSuccess == MatchComponentType(choiceEntry, item, match,
209
211k
                                                  (void*)((char*)dest + choiceEntry->offset))) &&
210
211k
                (PR_TRUE == *match)) {
211
190k
                return SECSuccess;
212
190k
            }
213
211k
        }
214
        /* no match, caller must decide if this is BAD DER, or not. */
215
6.28k
        *match = PR_FALSE;
216
6.28k
        return SECSuccess;
217
196k
    }
218
219
16.9M
    if (kind & SEC_ASN1_ANY) {
220
        /* SEC_ASN1_ANY always matches */
221
7.97M
        *match = PR_TRUE;
222
7.97M
        return SECSuccess;
223
7.97M
    }
224
225
8.99M
    if ((0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) &&
226
1.76M
        (!(kind & SEC_ASN1_EXPLICIT)) &&
227
1.21M
        (((kind & SEC_ASN1_SAVE) ||
228
830k
          (kind & SEC_ASN1_SKIP)) &&
229
1.20M
         (!(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
1.20M
        *match = PR_TRUE;
237
1.20M
        return SECSuccess;
238
1.20M
    }
239
240
    /* first, do a class check */
241
7.78M
    if ((tag & SEC_ASN1_CLASS_MASK) !=
242
7.78M
        (((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
9.66k
        *match = PR_FALSE;
247
9.66k
        return SECSuccess;
248
9.66k
    }
249
250
    /* now do a tag check */
251
7.77M
    if (((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) !=
252
7.77M
        (tag & SEC_ASN1_TAGNUM_MASK)) {
253
504k
        *match = PR_FALSE;
254
504k
        return SECSuccess;
255
504k
    }
256
257
    /* now, do a method check. This depends on the class */
258
7.27M
    switch (tag & SEC_ASN1_CLASS_MASK) {
259
6.58M
        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
6.58M
            switch (tag & SEC_ASN1_TAGNUM_MASK) {
263
2.93M
                case SEC_ASN1_SEQUENCE:
264
3.20M
                case SEC_ASN1_SET:
265
3.20M
                case SEC_ASN1_EMBEDDED_PDV:
266
                    /* this component must be a constructed type */
267
                    /* XXX add any new universal constructed type here */
268
3.20M
                    if (tag & SEC_ASN1_CONSTRUCTED) {
269
3.20M
                        *match = PR_TRUE;
270
3.20M
                        return SECSuccess;
271
3.20M
                    }
272
609
                    break;
273
274
3.38M
                default:
275
                    /* this component must be a primitive type */
276
3.38M
                    if (!(tag & SEC_ASN1_CONSTRUCTED)) {
277
3.38M
                        *match = PR_TRUE;
278
3.38M
                        return SECSuccess;
279
3.38M
                    }
280
346
                    break;
281
6.58M
            }
282
955
            break;
283
284
685k
        default:
285
            /* for all other classes, we check the method based on the template */
286
685k
            if ((unsigned char)(kind & SEC_ASN1_METHOD_MASK) ==
287
685k
                (tag & SEC_ASN1_METHOD_MASK)) {
288
685k
                *match = PR_TRUE;
289
685k
                return SECSuccess;
290
685k
            }
291
            /* method does not match between template and component */
292
215
            break;
293
7.27M
    }
294
295
1.17k
    *match = PR_FALSE;
296
1.17k
    return SECSuccess;
297
7.27M
}
298
299
#ifdef DEBUG
300
301
static SECStatus
302
CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate)
303
2.64M
{
304
2.64M
    SECStatus rv = SECSuccess;
305
2.64M
    const SEC_ASN1Template* sequenceEntry = NULL;
306
2.64M
    unsigned long seqIndex = 0;
307
2.64M
    unsigned long lastEntryIndex = 0;
308
2.64M
    unsigned long ambiguityIndex = 0;
309
2.64M
    PRBool foundAmbiguity = PR_FALSE;
310
311
10.6M
    do {
312
10.6M
        sequenceEntry = &sequenceTemplate[seqIndex++];
313
10.6M
        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
8.04M
            if ((PR_FALSE == foundAmbiguity) &&
319
8.04M
                (sequenceEntry->kind & SEC_ASN1_OPTIONAL) &&
320
1.98M
                (sequenceEntry->kind & SEC_ASN1_ANY)) {
321
754k
                foundAmbiguity = PR_TRUE;
322
754k
                ambiguityIndex = seqIndex - 1;
323
754k
            }
324
8.04M
        }
325
10.6M
    } while (sequenceEntry->kind);
326
327
2.64M
    lastEntryIndex = seqIndex - 2;
328
329
2.64M
    if (PR_FALSE != foundAmbiguity) {
330
754k
        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
754k
    }
336
337
    /* XXX also enforce ASN.1 requirement that tags be
338
       distinct for consecutive optional components */
339
340
2.64M
    return rv;
341
2.64M
}
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
2.64M
{
354
2.64M
    SECStatus rv = SECSuccess;
355
2.64M
    SECItem source;
356
2.64M
    SECItem sequence;
357
2.64M
    const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]);
358
2.64M
    const SEC_ASN1Template* sequenceEntry = NULL;
359
2.64M
    unsigned long seqindex = 0;
360
361
2.64M
#ifdef DEBUG
362
    /* for a sequence, we need to validate the template. */
363
2.64M
    rv = CheckSequenceTemplate(sequenceTemplate);
364
2.64M
#endif
365
366
2.64M
    source = *src;
367
368
    /* get the sequence */
369
2.64M
    if (SECSuccess == rv) {
370
2.64M
        rv = GetItem(&source, &sequence, PR_FALSE);
371
2.64M
    }
372
373
    /* process it */
374
2.64M
    if (SECSuccess == rv)
375
10.1M
        do {
376
10.1M
            sequenceEntry = &sequenceTemplate[seqindex++];
377
10.1M
            if ((sequenceEntry && sequenceEntry->kind) &&
378
8.01M
                (sequenceEntry->kind != SEC_ASN1_SKIP_REST)) {
379
7.55M
                rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE);
380
7.55M
            }
381
10.1M
        } while ((SECSuccess == rv) &&
382
10.1M
                 (sequenceEntry->kind &&
383
7.99M
                  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
2.64M
    if (SECSuccess == rv && sequence.len &&
387
461k
        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
1.08k
        PORT_SetError(SEC_ERROR_BAD_DER);
392
1.08k
        rv = SECFailure;
393
1.08k
    }
394
395
2.64M
    return rv;
396
2.64M
}
397
398
static SECStatus
399
DecodeInline(void* dest,
400
             const SEC_ASN1Template* templateEntry,
401
             SECItem* src, PLArenaPool* arena, PRBool checkTag)
402
2.09M
{
403
2.09M
    const SEC_ASN1Template* inlineTemplate =
404
2.09M
        SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE);
405
2.09M
    return DecodeItem((void*)((char*)dest + templateEntry->offset),
406
2.09M
                      inlineTemplate, src, arena, checkTag);
407
2.09M
}
408
409
static SECStatus
410
DecodePointer(void* dest,
411
              const SEC_ASN1Template* templateEntry,
412
              SECItem* src, PLArenaPool* arena, PRBool checkTag)
413
7.48k
{
414
7.48k
    const SEC_ASN1Template* ptrTemplate =
415
7.48k
        SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE);
416
7.48k
    if (!ptrTemplate) {
417
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
418
0
        return SECFailure;
419
0
    }
420
7.48k
    void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size);
421
7.48k
    *(void**)((char*)dest + templateEntry->offset) = subdata;
422
7.48k
    if (subdata) {
423
7.48k
        return DecodeItem(subdata, ptrTemplate, src, arena, checkTag);
424
7.48k
    } else {
425
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
426
0
        return SECFailure;
427
0
    }
428
7.48k
}
429
430
static SECStatus
431
DecodeImplicit(void* dest,
432
               const SEC_ASN1Template* templateEntry,
433
               SECItem* src, PLArenaPool* arena)
434
37.6k
{
435
37.6k
    if (templateEntry->kind & SEC_ASN1_POINTER) {
436
0
        return DecodePointer((void*)((char*)dest),
437
0
                             templateEntry, src, arena, PR_FALSE);
438
37.6k
    } else {
439
37.6k
        return DecodeInline((void*)((char*)dest),
440
37.6k
                            templateEntry, src, arena, PR_FALSE);
441
37.6k
    }
442
37.6k
}
443
444
static SECStatus
445
DecodeChoice(void* dest,
446
             const SEC_ASN1Template* templateEntry,
447
             SECItem* src, PLArenaPool* arena)
448
190k
{
449
190k
    SECStatus rv = SECSuccess;
450
190k
    SECItem choice;
451
190k
    const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]);
452
190k
    const SEC_ASN1Template* choiceEntry = NULL;
453
190k
    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
198k
    do {
462
198k
        choice = *src;
463
198k
        choiceEntry = &choiceTemplate[choiceindex++];
464
198k
        if (choiceEntry->kind) {
465
198k
            rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE);
466
198k
        }
467
198k
    } while ((SECFailure == rv) && (choiceEntry->kind));
468
469
190k
    if (SECFailure == rv) {
470
        /* the component didn't match any of the choices */
471
63
        PORT_SetError(SEC_ERROR_BAD_DER);
472
190k
    } else {
473
        /* set the type in the union here */
474
190k
        int* which = (int*)((char*)dest + templateEntry->offset);
475
190k
        *which = (int)choiceEntry->size;
476
190k
    }
477
478
    /* we should have consumed all the bytes by now */
479
    /* fail if we have not */
480
190k
    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
190k
    return rv;
486
190k
}
487
488
static SECStatus
489
DecodeGroup(void* dest,
490
            const SEC_ASN1Template* templateEntry,
491
            SECItem* src, PLArenaPool* arena)
492
560k
{
493
560k
    SECStatus rv = SECSuccess;
494
560k
    SECItem source;
495
560k
    SECItem group;
496
560k
    PRUint32 totalEntries = 0;
497
560k
    PRUint32 entryIndex = 0;
498
560k
    void** entries = NULL;
499
500
560k
    const SEC_ASN1Template* subTemplate =
501
560k
        SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE);
502
503
560k
    source = *src;
504
505
    /* get the group */
506
560k
    if (SECSuccess == rv) {
507
560k
        rv = GetItem(&source, &group, PR_FALSE);
508
560k
    }
509
510
    /* XXX we should check the subtemplate in debug builds */
511
560k
    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
560k
        SECItem counter = group;
517
29.9M
        do {
518
29.9M
            SECItem anitem;
519
29.9M
            rv = GetItem(&counter, &anitem, PR_TRUE);
520
29.9M
            if (SECSuccess == rv && (anitem.len)) {
521
29.9M
                totalEntries++;
522
29.9M
            }
523
29.9M
        } while ((SECSuccess == rv) && (counter.len));
524
525
        /* Limit entry data to 1 GiB. */
526
560k
        if (SECSuccess == rv && subTemplate->size &&
527
558k
            totalEntries > ((size_t)1 << 30) / subTemplate->size) {
528
0
            PORT_SetError(SEC_ERROR_BAD_DER);
529
0
            rv = SECFailure;
530
0
        }
531
532
560k
        if (SECSuccess == rv) {
533
            /* allocate room for pointer array and entries */
534
            /* we want to allocate the array even if there is 0 entry */
535
558k
            entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*) * (totalEntries + 1) + /* the extra one is for NULL termination */
536
558k
                                                          (size_t)subTemplate->size * totalEntries);
537
538
558k
            if (entries) {
539
558k
                entries[totalEntries] = NULL; /* terminate the array */
540
558k
            } else {
541
0
                PORT_SetError(SEC_ERROR_NO_MEMORY);
542
0
                rv = SECFailure;
543
0
            }
544
558k
            if (SECSuccess == rv) {
545
558k
                void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*) * (totalEntries + 1));
546
                /* and fix the pointers in the array */
547
558k
                PRUint32 entriesIndex = 0;
548
30.3M
                for (entriesIndex = 0; entriesIndex < totalEntries; entriesIndex++) {
549
29.8M
                    entries[entriesIndex] =
550
29.8M
                        (char*)entriesData + ((size_t)subTemplate->size * entriesIndex);
551
29.8M
                }
552
558k
            }
553
558k
        }
554
560k
    }
555
556
560k
    if (SECSuccess == rv && totalEntries)
557
7.10M
        do {
558
7.10M
            if (!(entryIndex < totalEntries)) {
559
0
                rv = SECFailure;
560
0
                break;
561
0
            }
562
7.10M
            rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE);
563
7.10M
        } while ((SECSuccess == rv) && (group.len));
564
    /* we should be at the end of the set by now */
565
    /* save the entries where requested */
566
560k
    memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**));
567
568
560k
    return rv;
569
560k
}
570
571
static SECStatus
572
DecodeExplicit(void* dest,
573
               const SEC_ASN1Template* templateEntry,
574
               SECItem* src, PLArenaPool* arena)
575
647k
{
576
647k
    SECStatus rv = SECSuccess;
577
647k
    SECItem subItem;
578
647k
    SECItem constructed = *src;
579
580
647k
    rv = GetItem(&constructed, &subItem, PR_FALSE);
581
582
647k
    if (SECSuccess == rv) {
583
647k
        if (templateEntry->kind & SEC_ASN1_POINTER) {
584
0
            rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE);
585
647k
        } else {
586
647k
            rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE);
587
647k
        }
588
647k
    }
589
590
647k
    return rv;
591
647k
}
592
593
/* new decoder implementation. This is a recursive function */
594
595
static SECStatus
596
DecodeItem(void* dest,
597
           const SEC_ASN1Template* templateEntry,
598
           SECItem* src, PLArenaPool* arena, PRBool checkTag)
599
18.9M
{
600
18.9M
    SECStatus rv = SECSuccess;
601
18.9M
    SECItem temp;
602
18.9M
    SECItem mark = { siBuffer, NULL, 0 };
603
18.9M
    PRBool pop = PR_FALSE;
604
18.9M
    PRBool decode = PR_TRUE;
605
18.9M
    PRBool save = PR_FALSE;
606
18.9M
    unsigned long kind;
607
18.9M
    PRBool match = PR_TRUE;
608
609
18.9M
    PR_ASSERT(src && dest && templateEntry && arena);
610
#if 0
611
    if (!src || !dest || !templateEntry || !arena)
612
    {
613
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
614
        rv = SECFailure;
615
    }
616
#endif
617
618
18.9M
    if (SECSuccess == rv) {
619
        /* do the template validation */
620
18.9M
        kind = templateEntry->kind;
621
18.9M
        if (!kind) {
622
0
            PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
623
0
            rv = SECFailure;
624
0
        }
625
18.9M
    }
626
627
18.9M
    if (SECSuccess == rv) {
628
18.9M
#ifdef DEBUG
629
18.9M
        if (kind & SEC_ASN1_DEBUG_BREAK) {
630
            /* when debugging the decoder or a template that fails to
631
            decode, put SEC_ASN1_DEBUG in the component that gives you
632
            trouble. The decoder will then get to this block and assert.
633
            If you want to debug the rest of the code, you can set a
634
            breakpoint and set dontassert to PR_TRUE, which will let
635
            you skip over the assert and continue the debugging session
636
            past it. */
637
0
            PRBool dontassert = PR_FALSE;
638
0
            PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/
639
0
        }
640
18.9M
#endif
641
642
18.9M
        if ((kind & SEC_ASN1_SKIP) ||
643
18.1M
            (kind & SEC_ASN1_SAVE)) {
644
            /* if skipping or saving this component, don't decode it */
645
1.20M
            decode = PR_FALSE;
646
1.20M
        }
647
648
18.9M
        if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL)) {
649
            /* if saving this component, or if it is optional, we may not want to
650
               move past it, so save the position in case we have to rewind */
651
2.35M
            mark = *src;
652
2.35M
            if (kind & SEC_ASN1_SAVE) {
653
382k
                save = PR_TRUE;
654
382k
                if (0 == (kind & SEC_ASN1_SKIP)) {
655
                    /* we will for sure have to rewind when saving this
656
                       component and not skipping it. This is true for all
657
                       legacy uses of SEC_ASN1_SAVE where the following entry
658
                       in the template would causes the same component to be
659
                       processed again */
660
382k
                    pop = PR_TRUE;
661
382k
                }
662
382k
            }
663
2.35M
        }
664
665
18.9M
        rv = GetItem(src, &temp, PR_TRUE);
666
18.9M
    }
667
668
18.9M
    if (SECSuccess == rv) {
669
        /* now check if the component matches what we expect in the template */
670
671
18.9M
        if (PR_TRUE == checkTag)
672
673
18.8M
        {
674
18.8M
            rv = MatchComponentType(templateEntry, &temp, &match, dest);
675
18.8M
        }
676
677
18.9M
        if ((SECSuccess == rv) && (PR_TRUE != match)) {
678
1.02M
            if (kind & SEC_ASN1_OPTIONAL) {
679
680
                /* the optional component is missing. This is not fatal. */
681
                /* Rewind, don't decode, and don't save */
682
900k
                pop = PR_TRUE;
683
900k
                decode = PR_FALSE;
684
900k
                save = PR_FALSE;
685
900k
            } else {
686
                /* a required component is missing. abort */
687
120k
                PORT_SetError(SEC_ERROR_BAD_DER);
688
120k
                rv = SECFailure;
689
120k
            }
690
1.02M
        }
691
18.9M
    }
692
693
18.9M
    if ((SECSuccess == rv) && (PR_TRUE == decode)) {
694
        /* the order of processing here is is the tricky part */
695
        /* we start with our special cases */
696
        /* first, check the component class */
697
16.7M
        if (kind & SEC_ASN1_INLINE) {
698
            /* decode inline template */
699
1.41M
            rv = DecodeInline(dest, templateEntry, &temp, arena, PR_TRUE);
700
1.41M
        }
701
702
15.2M
        else if (kind & SEC_ASN1_EXPLICIT) {
703
647k
            rv = DecodeExplicit(dest, templateEntry, &temp, arena);
704
14.6M
        } else if ((SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) &&
705
706
37.6k
                   (!(kind & SEC_ASN1_EXPLICIT))) {
707
708
            /* decode implicitly tagged components */
709
37.6k
            rv = DecodeImplicit(dest, templateEntry, &temp, arena);
710
14.6M
        } else if (kind & SEC_ASN1_POINTER) {
711
7.48k
            rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE);
712
14.5M
        } else if (kind & SEC_ASN1_CHOICE) {
713
190k
            rv = DecodeChoice(dest, templateEntry, &temp, arena);
714
14.4M
        } else if (kind & SEC_ASN1_ANY) {
715
            /* catch-all ANY type, don't decode */
716
7.97M
            save = PR_TRUE;
717
7.97M
            if (kind & SEC_ASN1_INNER) {
718
                /* skip the tag and length */
719
0
                SECItem newtemp = temp;
720
0
                rv = GetItem(&newtemp, &temp, PR_FALSE);
721
0
            }
722
7.97M
        } else if (kind & SEC_ASN1_GROUP) {
723
560k
            if ((SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) ||
724
560k
                (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK))) {
725
560k
                rv = DecodeGroup(dest, templateEntry, &temp, arena);
726
560k
            } else {
727
                /* a group can only be a SET OF or SEQUENCE OF */
728
0
                PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
729
0
                rv = SECFailure;
730
0
            }
731
5.87M
        } else if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) {
732
            /* plain SEQUENCE */
733
2.64M
            rv = DecodeSequence(dest, templateEntry, &temp, arena);
734
3.23M
        } else {
735
            /* handle all other types as "save" */
736
            /* we should only get here for primitive universal types */
737
3.23M
            SECItem newtemp = temp;
738
3.23M
            rv = GetItem(&newtemp, &temp, PR_FALSE);
739
3.23M
            save = PR_TRUE;
740
3.23M
            if ((SECSuccess == rv) &&
741
3.23M
                SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK)) {
742
3.23M
                unsigned long tagnum = kind & SEC_ASN1_TAGNUM_MASK;
743
3.23M
                if (temp.len == 0 && (tagnum == SEC_ASN1_BOOLEAN ||
744
8.39k
                                      tagnum == SEC_ASN1_INTEGER ||
745
8.19k
                                      tagnum == SEC_ASN1_BIT_STRING ||
746
7.76k
                                      tagnum == SEC_ASN1_OBJECT_ID ||
747
7.48k
                                      tagnum == SEC_ASN1_ENUMERATED ||
748
7.46k
                                      tagnum == SEC_ASN1_UTC_TIME ||
749
7.43k
                                      tagnum == SEC_ASN1_GENERALIZED_TIME)) {
750
                    /* these types MUST have at least one content octet */
751
1.16k
                    PORT_SetError(SEC_ERROR_BAD_DER);
752
1.16k
                    rv = SECFailure;
753
1.16k
                } else
754
3.22M
                    switch (tagnum) {
755
                        /* special cases of primitive types */
756
356k
                        case SEC_ASN1_INTEGER: {
757
356k
                            SECItem* destItem = (SECItem*)((char*)dest +
758
356k
                                                           templateEntry->offset);
759
356k
                            if (destItem && (siUnsignedInteger == destItem->type)) {
760
                                /* A leading 0 is only allowed when a value
761
                                 * would otherwise be interpreted as negative. */
762
166k
                                if (temp.len > 1 && temp.data[0] == 0) {
763
45.6k
                                    temp.data++;
764
45.6k
                                    temp.len--;
765
45.6k
                                    if (!(temp.data[0] & 0x80)) {
766
47
                                        PORT_SetError(SEC_ERROR_BAD_DER);
767
47
                                        rv = SECFailure;
768
47
                                    }
769
45.6k
                                }
770
166k
                            }
771
356k
                            break;
772
0
                        }
773
774
670k
                        case SEC_ASN1_BIT_STRING: {
775
                            /* Can't be 8 or more spare bits, or any spare bits
776
                             * if there are no octets. */
777
670k
                            if (temp.data[0] >= 8 || (temp.data[0] > 0 && temp.len == 1)) {
778
1.04k
                                PORT_SetError(SEC_ERROR_BAD_DER);
779
1.04k
                                rv = SECFailure;
780
1.04k
                                break;
781
1.04k
                            }
782
                            /* change the length in the SECItem to be the number
783
                               of bits */
784
669k
                            temp.len = (temp.len - 1) * 8 - (temp.data[0] & 0x7);
785
669k
                            temp.data++;
786
669k
                            break;
787
670k
                        }
788
789
2.20M
                        default: {
790
2.20M
                            break;
791
670k
                        }
792
3.22M
                    }
793
3.23M
            }
794
3.23M
        }
795
16.7M
    }
796
797
18.9M
    if ((SECSuccess == rv) && (PR_TRUE == save)) {
798
11.5M
        SECItem* destItem = (SECItem*)((char*)dest + templateEntry->offset);
799
11.5M
        if (destItem) {
800
            /* we leave the type alone in the destination SECItem.
801
               If part of the destination was allocated by the decoder, in
802
               cases of POINTER, SET OF and SEQUENCE OF, then type is set to
803
               siBuffer due to the use of PORT_ArenaZAlloc*/
804
11.5M
            destItem->data = temp.len ? temp.data : NULL;
805
11.5M
            destItem->len = temp.len;
806
11.5M
        } else {
807
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
808
0
            rv = SECFailure;
809
0
        }
810
11.5M
    }
811
812
18.9M
    if (PR_TRUE == pop) {
813
        /* we don't want to move ahead, so restore the position */
814
1.28M
        *src = mark;
815
1.28M
    }
816
18.9M
    return rv;
817
18.9M
}
818
819
/* the function below is the public one */
820
821
SECStatus
822
SEC_QuickDERDecodeItem(PLArenaPool* arena, void* dest,
823
                       const SEC_ASN1Template* templateEntry,
824
                       const SECItem* src)
825
2.00M
{
826
2.00M
    SECStatus rv = SECSuccess;
827
2.00M
    SECItem newsrc;
828
829
2.00M
    if (!arena || !templateEntry || !src) {
830
11
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
831
11
        rv = SECFailure;
832
11
    }
833
834
2.00M
    if (SECSuccess == rv) {
835
2.00M
        newsrc = *src;
836
2.00M
        rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE);
837
2.00M
        if (SECSuccess == rv && newsrc.len) {
838
1.97k
            rv = SECFailure;
839
1.97k
            PORT_SetError(SEC_ERROR_EXTRA_INPUT);
840
1.97k
        }
841
2.00M
    }
842
843
2.00M
    return rv;
844
2.00M
}