Coverage Report

Created: 2024-11-21 07:03

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