Coverage Report

Created: 2024-11-21 07:03

/src/nss-nspr/nss/lib/util/derenc.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
#include "secder.h"
6
#include "secerr.h"
7
8
#if 0
9
/*
10
 * Generic templates for individual/simple items.
11
 */
12
13
DERTemplate SECAnyTemplate[] = {
14
    { DER_ANY,
15
    0, NULL, sizeof(SECItem) }
16
};
17
18
DERTemplate SECBitStringTemplate[] = {
19
    { DER_BIT_STRING,
20
    0, NULL, sizeof(SECItem) }
21
};
22
23
DERTemplate SECBooleanTemplate[] = {
24
    { DER_BOOLEAN,
25
    0, NULL, sizeof(SECItem) }
26
};
27
28
DERTemplate SECIA5StringTemplate[] = {
29
    { DER_IA5_STRING,
30
    0, NULL, sizeof(SECItem) }
31
};
32
33
DERTemplate SECIntegerTemplate[] = {
34
    { DER_INTEGER,
35
    0, NULL, sizeof(SECItem) }
36
};
37
38
DERTemplate SECNullTemplate[] = {
39
    { DER_NULL,
40
    0, NULL, sizeof(SECItem) }
41
};
42
43
DERTemplate SECObjectIDTemplate[] = {
44
    { DER_OBJECT_ID,
45
    0, NULL, sizeof(SECItem) }
46
};
47
48
DERTemplate SECOctetStringTemplate[] = {
49
    { DER_OCTET_STRING,
50
    0, NULL, sizeof(SECItem) }
51
};
52
53
DERTemplate SECPrintableStringTemplate[] = {
54
    { DER_PRINTABLE_STRING,
55
    0, NULL, sizeof(SECItem) }
56
};
57
58
DERTemplate SECT61StringTemplate[] = {
59
    { DER_T61_STRING,
60
    0, NULL, sizeof(SECItem) }
61
};
62
63
DERTemplate SECUTCTimeTemplate[] = {
64
    { DER_UTC_TIME,
65
    0, NULL, sizeof(SECItem) }
66
};
67
68
#endif
69
70
static int
71
header_length(DERTemplate *dtemplate, PRUint32 contents_len)
72
96
{
73
96
    PRUint32 len;
74
96
    unsigned long encode_kind, under_kind;
75
96
    PRBool explicit, optional, universal;
76
77
96
    encode_kind = dtemplate->kind;
78
79
96
    explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
80
96
    optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
81
96
    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
82
96
                    ? PR_TRUE
83
96
                    : PR_FALSE;
84
85
96
    PORT_Assert(!(explicit && universal)); /* bad templates */
86
87
96
    if (encode_kind & DER_POINTER) {
88
0
        if (dtemplate->sub != NULL) {
89
0
            under_kind = dtemplate->sub->kind;
90
0
            if (universal) {
91
0
                encode_kind = under_kind;
92
0
            }
93
0
        } else if (universal) {
94
0
            under_kind = encode_kind & ~DER_POINTER;
95
0
        } else {
96
0
            under_kind = dtemplate->arg;
97
0
        }
98
96
    } else if (encode_kind & DER_INLINE) {
99
18
        PORT_Assert(dtemplate->sub != NULL);
100
18
        under_kind = dtemplate->sub->kind;
101
18
        if (universal) {
102
18
            encode_kind = under_kind;
103
18
        }
104
78
    } else if (universal) {
105
78
        under_kind = encode_kind;
106
78
    } else {
107
0
        under_kind = dtemplate->arg;
108
0
    }
109
110
    /* This is only used in decoding; it plays no part in encoding.  */
111
96
    if (under_kind & DER_DERPTR)
112
0
        return 0;
113
114
    /* No header at all for an "empty" optional.  */
115
96
    if ((contents_len == 0) && optional)
116
0
        return 0;
117
118
    /* And no header for a full DER_ANY.  */
119
96
    if (encode_kind & DER_ANY)
120
24
        return 0;
121
122
    /*
123
     * The common case: one octet for identifier and as many octets
124
     * as necessary to hold the content length.
125
     */
126
72
    len = 1 + DER_LengthLength(contents_len);
127
128
    /* Account for the explicit wrapper, if necessary.  */
129
72
    if (explicit) {
130
#if 0 /*                                                         \
131
       * Well, I was trying to do something useful, but these    \
132
       * assertions are too restrictive on valid templates.      \
133
       * I wanted to make sure that the top-level "kind" of      \
134
       * a template does not also specify DER_EXPLICIT, which    \
135
       * should only modify a component field.  Maybe later      \
136
       * I can figure out a better way to detect such a problem, \
137
       * but for now I must remove these checks altogether.      \
138
       */
139
  /*
140
   * This modifier applies only to components of a set or sequence;
141
   * it should never be used on a set/sequence itself -- confirm.
142
   */
143
  PORT_Assert (under_kind != DER_SEQUENCE);
144
  PORT_Assert (under_kind != DER_SET);
145
#endif
146
147
0
        len += 1 + DER_LengthLength(len + contents_len);
148
0
    }
149
150
72
    return len;
151
96
}
152
153
static PRUint32
154
contents_length(DERTemplate *dtemplate, void *src)
155
96
{
156
96
    PRUint32 len;
157
96
    unsigned long encode_kind, under_kind;
158
96
    PRBool universal;
159
160
96
    PORT_Assert(src != NULL);
161
162
96
    encode_kind = dtemplate->kind;
163
164
96
    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
165
96
                    ? PR_TRUE
166
96
                    : PR_FALSE;
167
96
    encode_kind &= ~DER_OPTIONAL;
168
169
96
    if (encode_kind & DER_POINTER) {
170
0
        src = *(void **)src;
171
0
        if (src == NULL) {
172
0
            return 0;
173
0
        }
174
0
        if (dtemplate->sub != NULL) {
175
0
            dtemplate = dtemplate->sub;
176
0
            under_kind = dtemplate->kind;
177
0
            src = (void *)((char *)src + dtemplate->offset);
178
0
        } else if (universal) {
179
0
            under_kind = encode_kind & ~DER_POINTER;
180
0
        } else {
181
0
            under_kind = dtemplate->arg;
182
0
        }
183
96
    } else if (encode_kind & DER_INLINE) {
184
18
        PORT_Assert(dtemplate->sub != NULL);
185
18
        dtemplate = dtemplate->sub;
186
18
        under_kind = dtemplate->kind;
187
18
        src = (void *)((char *)src + dtemplate->offset);
188
78
    } else if (universal) {
189
78
        under_kind = encode_kind;
190
78
    } else {
191
0
        under_kind = dtemplate->arg;
192
0
    }
193
194
    /* Having any of these bits is not expected here...  */
195
96
    PORT_Assert((under_kind & (DER_EXPLICIT | DER_INLINE | DER_OPTIONAL | DER_POINTER | DER_SKIP)) == 0);
196
197
    /* This is only used in decoding; it plays no part in encoding.  */
198
96
    if (under_kind & DER_DERPTR)
199
0
        return 0;
200
201
96
    if (under_kind & DER_INDEFINITE) {
202
0
        PRUint32 sub_len;
203
0
        void **indp = *(void ***)src;
204
205
0
        if (indp == NULL)
206
0
            return 0;
207
208
0
        len = 0;
209
0
        under_kind &= ~DER_INDEFINITE;
210
211
0
        if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
212
0
            DERTemplate *tmpt = dtemplate->sub;
213
0
            PORT_Assert(tmpt != NULL);
214
215
0
            for (; *indp != NULL; indp++) {
216
0
                void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
217
0
                sub_len = contents_length(tmpt, sub_src);
218
0
                len += sub_len + header_length(tmpt, sub_len);
219
0
            }
220
0
        } else {
221
            /*
222
             * XXX Lisa is not sure this code (for handling, for example,
223
             * DER_INDEFINITE | DER_OCTET_STRING) is right.
224
             */
225
0
            for (; *indp != NULL; indp++) {
226
0
                SECItem *item = (SECItem *)(*indp);
227
0
                sub_len = item->len;
228
0
                if (under_kind == DER_BIT_STRING) {
229
0
                    sub_len = (sub_len + 7) >> 3;
230
                    /* bit string contents involve an extra octet */
231
0
                    if (sub_len)
232
0
                        sub_len++;
233
0
                }
234
0
                if (under_kind != DER_ANY)
235
0
                    len += 1 + DER_LengthLength(sub_len);
236
0
            }
237
0
        }
238
239
0
        return len;
240
0
    }
241
242
96
    switch (under_kind) {
243
30
        case DER_SEQUENCE:
244
30
        case DER_SET: {
245
30
            DERTemplate *tmpt;
246
30
            void *sub_src;
247
30
            PRUint32 sub_len;
248
249
30
            len = 0;
250
90
            for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
251
60
                sub_src = (void *)((char *)src + tmpt->offset);
252
60
                sub_len = contents_length(tmpt, sub_src);
253
60
                len += sub_len + header_length(tmpt, sub_len);
254
60
            }
255
30
        } break;
256
257
0
        case DER_BIT_STRING:
258
0
            len = (((SECItem *)src)->len + 7) >> 3;
259
            /* bit string contents involve an extra octet */
260
0
            if (len)
261
0
                len++;
262
0
            break;
263
264
66
        default:
265
66
            len = ((SECItem *)src)->len;
266
66
            break;
267
96
    }
268
269
96
    return len;
270
96
}
271
272
static unsigned char *
273
der_encode(unsigned char *buf, DERTemplate *dtemplate, void *src)
274
30
{
275
30
    int header_len;
276
30
    PRUint32 contents_len;
277
30
    unsigned long encode_kind, under_kind;
278
30
    PRBool explicit, universal;
279
280
    /*
281
     * First figure out how long the encoding will be.  Do this by
282
     * traversing the template from top to bottom and accumulating
283
     * the length of each leaf item.
284
     */
285
30
    contents_len = contents_length(dtemplate, src);
286
30
    header_len = header_length(dtemplate, contents_len);
287
288
    /*
289
     * Enough smarts was involved already, so that if both the
290
     * header and the contents have a length of zero, then we
291
     * are not doing any encoding for this element.
292
     */
293
30
    if (header_len == 0 && contents_len == 0)
294
0
        return buf;
295
296
30
    encode_kind = dtemplate->kind;
297
298
30
    explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
299
30
    encode_kind &= ~DER_OPTIONAL;
300
30
    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
301
30
                    ? PR_TRUE
302
30
                    : PR_FALSE;
303
304
30
    if (encode_kind & DER_POINTER) {
305
0
        if (contents_len) {
306
0
            src = *(void **)src;
307
0
            PORT_Assert(src != NULL);
308
0
        }
309
0
        if (dtemplate->sub != NULL) {
310
0
            dtemplate = dtemplate->sub;
311
0
            under_kind = dtemplate->kind;
312
0
            if (universal) {
313
0
                encode_kind = under_kind;
314
0
            }
315
0
            src = (void *)((char *)src + dtemplate->offset);
316
0
        } else if (universal) {
317
0
            under_kind = encode_kind & ~DER_POINTER;
318
0
        } else {
319
0
            under_kind = dtemplate->arg;
320
0
        }
321
30
    } else if (encode_kind & DER_INLINE) {
322
6
        dtemplate = dtemplate->sub;
323
6
        under_kind = dtemplate->kind;
324
6
        if (universal) {
325
6
            encode_kind = under_kind;
326
6
        }
327
6
        src = (void *)((char *)src + dtemplate->offset);
328
24
    } else if (universal) {
329
24
        under_kind = encode_kind;
330
24
    } else {
331
0
        under_kind = dtemplate->arg;
332
0
    }
333
334
30
    if (explicit) {
335
0
        buf = DER_StoreHeader(buf, encode_kind,
336
0
                              (1 + DER_LengthLength(contents_len) + contents_len));
337
0
        encode_kind = under_kind;
338
0
    }
339
340
30
    if ((encode_kind & DER_ANY) == 0) { /* DER_ANY already contains header */
341
24
        buf = DER_StoreHeader(buf, encode_kind, contents_len);
342
24
    }
343
344
    /* If no real contents to encode, then we are done.  */
345
30
    if (contents_len == 0)
346
0
        return buf;
347
348
30
    if (under_kind & DER_INDEFINITE) {
349
0
        void **indp;
350
351
0
        indp = *(void ***)src;
352
0
        PORT_Assert(indp != NULL);
353
354
0
        under_kind &= ~DER_INDEFINITE;
355
0
        if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
356
0
            DERTemplate *tmpt = dtemplate->sub;
357
0
            PORT_Assert(tmpt != NULL);
358
0
            for (; *indp != NULL; indp++) {
359
0
                void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
360
0
                buf = der_encode(buf, tmpt, sub_src);
361
0
            }
362
0
        } else {
363
0
            for (; *indp != NULL; indp++) {
364
0
                SECItem *item;
365
0
                int sub_len;
366
367
0
                item = (SECItem *)(*indp);
368
0
                sub_len = item->len;
369
0
                if (under_kind == DER_BIT_STRING) {
370
0
                    if (sub_len) {
371
0
                        int rem;
372
373
0
                        sub_len = (sub_len + 7) >> 3;
374
0
                        buf = DER_StoreHeader(buf, under_kind, sub_len + 1);
375
0
                        rem = (sub_len << 3) - item->len;
376
0
                        *buf++ = rem; /* remaining bits */
377
0
                    } else {
378
0
                        buf = DER_StoreHeader(buf, under_kind, 0);
379
0
                    }
380
0
                } else if (under_kind != DER_ANY) {
381
0
                    buf = DER_StoreHeader(buf, under_kind, sub_len);
382
0
                }
383
0
                PORT_Memcpy(buf, item->data, sub_len);
384
0
                buf += sub_len;
385
0
            }
386
0
        }
387
0
        return buf;
388
0
    }
389
390
30
    switch (under_kind) {
391
12
        case DER_SEQUENCE:
392
12
        case DER_SET: {
393
12
            DERTemplate *tmpt;
394
12
            void *sub_src;
395
396
36
            for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
397
24
                sub_src = (void *)((char *)src + tmpt->offset);
398
24
                buf = der_encode(buf, tmpt, sub_src);
399
24
            }
400
12
        } break;
401
402
0
        case DER_BIT_STRING: {
403
0
            SECItem *item;
404
0
            int rem;
405
406
            /*
407
             * The contents length includes our extra octet; subtract
408
             * it off so we just have the real string length there.
409
             */
410
0
            contents_len--;
411
0
            item = (SECItem *)src;
412
0
            PORT_Assert(contents_len == ((item->len + 7) >> 3));
413
0
            rem = (contents_len << 3) - item->len;
414
0
            *buf++ = rem; /* remaining bits */
415
0
            PORT_Memcpy(buf, item->data, contents_len);
416
0
            buf += contents_len;
417
0
        } break;
418
419
18
        default: {
420
18
            SECItem *item;
421
422
18
            item = (SECItem *)src;
423
18
            PORT_Assert(contents_len == item->len);
424
18
            PORT_Memcpy(buf, item->data, contents_len);
425
18
            buf += contents_len;
426
18
        } break;
427
30
    }
428
429
30
    return buf;
430
30
}
431
432
SECStatus
433
DER_Encode(PLArenaPool *arena, SECItem *dest, DERTemplate *dtemplate, void *src)
434
6
{
435
6
    unsigned int contents_len, header_len;
436
437
6
    src = (void **)((char *)src + dtemplate->offset);
438
439
    /*
440
     * First figure out how long the encoding will be. Do this by
441
     * traversing the template from top to bottom and accumulating
442
     * the length of each leaf item.
443
     */
444
6
    contents_len = contents_length(dtemplate, src);
445
6
    header_len = header_length(dtemplate, contents_len);
446
447
6
    dest->len = contents_len + header_len;
448
449
    /* Allocate storage to hold the encoding */
450
6
    dest->data = (unsigned char *)PORT_ArenaAlloc(arena, dest->len);
451
6
    if (dest->data == NULL) {
452
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
453
0
        return SECFailure;
454
0
    }
455
456
    /* Now encode into the buffer */
457
6
    (void)der_encode(dest->data, dtemplate, src);
458
459
6
    return SECSuccess;
460
6
}