~ubuntu-branches/ubuntu/lucid/seamonkey/lucid-security

« back to all changes in this revision

Viewing changes to security/nss-fips/lib/util/derdec.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabien Tassin
  • Date: 2008-07-29 21:29:02 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080729212902-spm9kpvchp9udwbw
Tags: 1.1.11+nobinonly-0ubuntu1
* New security upstream release: 1.1.11 (LP: #218534)
  Fixes USN-602-1, USN-619-1, USN-623-1 and USN-629-1
* Refresh diverged patch:
  - update debian/patches/80_security_build.patch
* Fix FTBFS with missing -lfontconfig
  - add debian/patches/11_fix_ftbfs_with_fontconfig.patch
  - update debian/patches/series
* Build with default gcc (hardy: 4.2, intrepid: 4.3)
  - update debian/rules
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ***** BEGIN LICENSE BLOCK *****
 
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
3
 *
 
4
 * The contents of this file are subject to the Mozilla Public License Version
 
5
 * 1.1 (the "License"); you may not use this file except in compliance with
 
6
 * the License. You may obtain a copy of the License at
 
7
 * http://www.mozilla.org/MPL/
 
8
 *
 
9
 * Software distributed under the License is distributed on an "AS IS" basis,
 
10
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
11
 * for the specific language governing rights and limitations under the
 
12
 * License.
 
13
 *
 
14
 * The Original Code is the Netscape security libraries.
 
15
 *
 
16
 * The Initial Developer of the Original Code is
 
17
 * Netscape Communications Corporation.
 
18
 * Portions created by the Initial Developer are Copyright (C) 1994-2000
 
19
 * the Initial Developer. All Rights Reserved.
 
20
 *
 
21
 * Contributor(s):
 
22
 *
 
23
 * Alternatively, the contents of this file may be used under the terms of
 
24
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
25
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
26
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
27
 * of those above. If you wish to allow use of your version of this file only
 
28
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
29
 * use your version of this file under the terms of the MPL, indicate your
 
30
 * decision by deleting the provisions above and replace them with the notice
 
31
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
32
 * the provisions above, a recipient may use your version of this file under
 
33
 * the terms of any one of the MPL, the GPL or the LGPL.
 
34
 *
 
35
 * ***** END LICENSE BLOCK ***** */
 
36
 
 
37
#include "secder.h"
 
38
#include "secerr.h"
 
39
 
 
40
static uint32
 
41
der_indefinite_length(unsigned char *buf, unsigned char *end)
 
42
{
 
43
    uint32 len, ret, dataLen;
 
44
    unsigned char tag, lenCode;
 
45
    int dataLenLen;
 
46
 
 
47
    len = 0;
 
48
    while ( 1 ) {
 
49
        if ((buf + 2) > end) {
 
50
            return(0);
 
51
        }
 
52
        
 
53
        tag = *buf++;
 
54
        lenCode = *buf++;
 
55
        len += 2;
 
56
        
 
57
        if ( ( tag == 0 ) && ( lenCode == 0 ) ) {
 
58
            return(len);
 
59
        }
 
60
        
 
61
        if ( lenCode == 0x80 ) {        /* indefinite length */
 
62
            ret = der_indefinite_length(buf, end); /* recurse to find length */
 
63
            if (ret == 0)
 
64
                return 0;
 
65
            len += ret;
 
66
            buf += ret;
 
67
        } else {                        /* definite length */
 
68
            if (lenCode & 0x80) {
 
69
                /* Length of data is in multibyte format */
 
70
                dataLenLen = lenCode & 0x7f;
 
71
                switch (dataLenLen) {
 
72
                  case 1:
 
73
                    dataLen = buf[0];
 
74
                    break;
 
75
                  case 2:
 
76
                    dataLen = (buf[0]<<8)|buf[1];
 
77
                    break;
 
78
                  case 3:
 
79
                    dataLen = ((unsigned long)buf[0]<<16)|(buf[1]<<8)|buf[2];
 
80
                    break;
 
81
                  case 4:
 
82
                    dataLen = ((unsigned long)buf[0]<<24)|
 
83
                        ((unsigned long)buf[1]<<16)|(buf[2]<<8)|buf[3];
 
84
                    break;
 
85
                  default:
 
86
                    PORT_SetError(SEC_ERROR_BAD_DER);
 
87
                    return SECFailure;
 
88
                }
 
89
            } else {
 
90
                /* Length of data is in single byte */
 
91
                dataLen = lenCode;
 
92
                dataLenLen = 0;
 
93
            }
 
94
 
 
95
            /* skip this item */
 
96
            buf = buf + dataLenLen + dataLen;
 
97
            len = len + dataLenLen + dataLen;
 
98
        }
 
99
    }
 
100
}
 
101
 
 
102
/*
 
103
** Capture the next thing in the buffer.
 
104
** Returns the length of the header and the length of the contents.
 
105
*/
 
106
static SECStatus
 
107
der_capture(unsigned char *buf, unsigned char *end,
 
108
            int *header_len_p, uint32 *contents_len_p)
 
109
{
 
110
    unsigned char *bp;
 
111
    unsigned char whole_tag;
 
112
    uint32 contents_len;
 
113
    int tag_number;
 
114
 
 
115
    if ((buf + 2) > end) {
 
116
        *header_len_p = 0;
 
117
        *contents_len_p = 0;
 
118
        if (buf == end)
 
119
            return SECSuccess;
 
120
        return SECFailure;
 
121
    }
 
122
 
 
123
    bp = buf;
 
124
 
 
125
    /* Get tag and verify that it is ok. */
 
126
    whole_tag = *bp++;
 
127
    tag_number = whole_tag & DER_TAGNUM_MASK;
 
128
 
 
129
    /*
 
130
     * XXX This code does not (yet) handle the high-tag-number form!
 
131
     */
 
132
    if (tag_number == DER_HIGH_TAG_NUMBER) {
 
133
        PORT_SetError(SEC_ERROR_BAD_DER);
 
134
        return SECFailure;
 
135
    }
 
136
 
 
137
    if ((whole_tag & DER_CLASS_MASK) == DER_UNIVERSAL) {
 
138
        /* Check that the universal tag number is one we implement.  */
 
139
        switch (tag_number) {
 
140
          case DER_BOOLEAN:
 
141
          case DER_INTEGER:
 
142
          case DER_BIT_STRING:
 
143
          case DER_OCTET_STRING:
 
144
          case DER_NULL:
 
145
          case DER_OBJECT_ID:
 
146
          case DER_SEQUENCE:
 
147
          case DER_SET:
 
148
          case DER_PRINTABLE_STRING:
 
149
          case DER_T61_STRING:
 
150
          case DER_IA5_STRING:
 
151
          case DER_VISIBLE_STRING:
 
152
          case DER_UTC_TIME:
 
153
          case 0:                       /* end-of-contents tag */
 
154
            break;
 
155
          default:
 
156
            PORT_SetError(SEC_ERROR_BAD_DER);
 
157
            return SECFailure;
 
158
        }
 
159
    }
 
160
 
 
161
    /*
 
162
     * Get first byte of length code (might contain entire length, might not).
 
163
     */
 
164
    contents_len = *bp++;
 
165
 
 
166
    /*
 
167
     * If the high bit is set, then the length is in multibyte format,
 
168
     * or the thing has an indefinite-length.
 
169
     */
 
170
    if (contents_len & 0x80) {
 
171
        int bytes_of_encoded_len;
 
172
 
 
173
        bytes_of_encoded_len = contents_len & 0x7f;
 
174
        contents_len = 0;
 
175
 
 
176
        switch (bytes_of_encoded_len) {
 
177
          case 4:
 
178
            contents_len |= *bp++;
 
179
            contents_len <<= 8;
 
180
            /* fallthru */
 
181
          case 3:
 
182
            contents_len |= *bp++;
 
183
            contents_len <<= 8;
 
184
            /* fallthru */
 
185
          case 2:
 
186
            contents_len |= *bp++;
 
187
            contents_len <<= 8;
 
188
            /* fallthru */
 
189
          case 1:
 
190
            contents_len |= *bp++;
 
191
            break;
 
192
 
 
193
          case 0:
 
194
            contents_len = der_indefinite_length (bp, end);
 
195
            if (contents_len)
 
196
                break;
 
197
            /* fallthru */
 
198
          default:
 
199
            PORT_SetError(SEC_ERROR_BAD_DER);
 
200
            return SECFailure;
 
201
        }
 
202
    }
 
203
 
 
204
    if ((bp + contents_len) > end) {
 
205
        /* Ran past end of buffer */
 
206
        PORT_SetError(SEC_ERROR_BAD_DER);
 
207
        return SECFailure;
 
208
    }
 
209
 
 
210
    *header_len_p = bp - buf;
 
211
    *contents_len_p = contents_len;
 
212
 
 
213
    return SECSuccess;
 
214
}
 
215
 
 
216
static unsigned char *
 
217
der_decode(PRArenaPool *arena, void *dest, DERTemplate *dtemplate,
 
218
           unsigned char *buf, int header_len, uint32 contents_len)
 
219
{
 
220
    unsigned char *orig_buf, *end;
 
221
    unsigned long encode_kind, under_kind;
 
222
    PRBool explicit, optional, universal, check_tag;
 
223
    SECItem *item;
 
224
    SECStatus rv;
 
225
    PRBool indefinite_length, explicit_indefinite_length;
 
226
 
 
227
    encode_kind = dtemplate->kind;
 
228
    explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
 
229
    optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
 
230
    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
 
231
                ? PR_TRUE : PR_FALSE;
 
232
 
 
233
    PORT_Assert (!(explicit && universal));     /* bad templates */
 
234
 
 
235
    if (header_len == 0) {
 
236
        if (optional || (encode_kind & DER_ANY))
 
237
            return buf;
 
238
        PORT_SetError(SEC_ERROR_BAD_DER);
 
239
        return NULL;
 
240
    }
 
241
 
 
242
    if (encode_kind & DER_POINTER) {
 
243
        void *place, **placep;
 
244
        int offset;
 
245
 
 
246
        if (dtemplate->sub != NULL) {
 
247
            dtemplate = dtemplate->sub;
 
248
            under_kind = dtemplate->kind;
 
249
            if (universal) {
 
250
                encode_kind = under_kind;
 
251
            }
 
252
            place = PORT_ArenaZAlloc(arena, dtemplate->arg);
 
253
            offset = dtemplate->offset;
 
254
        } else {
 
255
            if (universal) {
 
256
                under_kind = encode_kind & ~DER_POINTER;
 
257
            } else {
 
258
                under_kind = dtemplate->arg;
 
259
            }
 
260
            place = PORT_ArenaZAlloc(arena, sizeof(SECItem));
 
261
            offset = 0;
 
262
        }
 
263
        if (place == NULL) {
 
264
            PORT_SetError(SEC_ERROR_NO_MEMORY);
 
265
            return NULL;                /* Out of memory */
 
266
        }
 
267
        placep = (void **)dest;
 
268
        *placep = place;
 
269
        dest = (void *)((char *)place + offset);
 
270
    } else if (encode_kind & DER_INLINE) {
 
271
        PORT_Assert (dtemplate->sub != NULL);
 
272
        dtemplate = dtemplate->sub;
 
273
        under_kind = dtemplate->kind;
 
274
        if (universal) {
 
275
            encode_kind = under_kind;
 
276
        }
 
277
        dest = (void *)((char *)dest + dtemplate->offset);
 
278
    } else if (universal) {
 
279
        under_kind = encode_kind;
 
280
    } else {
 
281
        under_kind = dtemplate->arg;
 
282
    }
 
283
 
 
284
    orig_buf = buf;
 
285
    end = buf + header_len + contents_len;
 
286
 
 
287
    explicit_indefinite_length = PR_FALSE;
 
288
 
 
289
    if (explicit) {
 
290
        /*
 
291
         * This tag is expected to match exactly.
 
292
         * (The template has all of the bits specified.)
 
293
         */
 
294
        if (*buf != (encode_kind & DER_TAG_MASK)) {
 
295
            if (optional)
 
296
                return buf;
 
297
            PORT_SetError(SEC_ERROR_BAD_DER);
 
298
            return NULL;
 
299
        }
 
300
        if ((header_len == 2) && (*(buf + 1) == 0x80))
 
301
            explicit_indefinite_length = PR_TRUE;
 
302
        buf += header_len;
 
303
        rv = der_capture (buf, end, &header_len, &contents_len);
 
304
        if (rv != SECSuccess)
 
305
            return NULL;
 
306
        if (header_len == 0) {          /* XXX is this right? */
 
307
            PORT_SetError(SEC_ERROR_BAD_DER);
 
308
            return NULL;
 
309
        }
 
310
        optional = PR_FALSE;            /* can no longer be optional */
 
311
        encode_kind = under_kind;
 
312
    }
 
313
 
 
314
    check_tag = PR_TRUE;
 
315
    if (encode_kind & (DER_DERPTR | DER_ANY | DER_FORCE | DER_SKIP)) {
 
316
        PORT_Assert ((encode_kind & DER_ANY) || !optional);
 
317
        encode_kind = encode_kind & (~DER_FORCE);
 
318
        under_kind = under_kind & (~DER_FORCE);
 
319
        check_tag = PR_FALSE;
 
320
    }
 
321
 
 
322
    if (check_tag) {
 
323
        PRBool wrong;
 
324
        unsigned char expect_tag, expect_num;
 
325
 
 
326
        /*
 
327
         * This tag is expected to match, but the simple types
 
328
         * may or may not have the constructed bit set, so we
 
329
         * have to have all this extra logic.
 
330
         */
 
331
        wrong = PR_TRUE;
 
332
        expect_tag = (unsigned char)encode_kind & DER_TAG_MASK;
 
333
        expect_num = expect_tag & DER_TAGNUM_MASK;
 
334
        if (expect_num == DER_SET || expect_num == DER_SEQUENCE) {
 
335
            if (*buf == (expect_tag | DER_CONSTRUCTED))
 
336
                wrong = PR_FALSE;
 
337
        } else {
 
338
            if (*buf == expect_tag)
 
339
                wrong = PR_FALSE;
 
340
            else if (*buf == (expect_tag | DER_CONSTRUCTED))
 
341
                wrong = PR_FALSE;
 
342
        }
 
343
        if (wrong) {
 
344
            if (optional)
 
345
                return buf;
 
346
            PORT_SetError(SEC_ERROR_BAD_DER);
 
347
            return NULL;
 
348
        }
 
349
    }
 
350
 
 
351
    if (under_kind & DER_DERPTR) {
 
352
        item = (SECItem *)dest;
 
353
        if (under_kind & DER_OUTER) {
 
354
            item->data = buf;
 
355
            item->len = header_len + contents_len;
 
356
        } else {
 
357
            item->data = buf + header_len;
 
358
            item->len = contents_len;
 
359
        }
 
360
        return orig_buf;
 
361
    }
 
362
 
 
363
    if (encode_kind & DER_ANY) {
 
364
        contents_len += header_len;
 
365
        header_len = 0;
 
366
    }
 
367
 
 
368
    if ((header_len == 2) && (*(buf + 1) == 0x80))
 
369
        indefinite_length = PR_TRUE;
 
370
    else
 
371
        indefinite_length = PR_FALSE;
 
372
 
 
373
    buf += header_len;
 
374
 
 
375
    if (contents_len == 0)
 
376
        return buf;
 
377
 
 
378
    under_kind &= ~DER_OPTIONAL;
 
379
 
 
380
    if (under_kind & DER_INDEFINITE) {
 
381
        int count, thing_size;
 
382
        unsigned char *sub_buf;
 
383
        DERTemplate *tmpt;
 
384
        void *things, **indp, ***placep;
 
385
 
 
386
        under_kind &= ~DER_INDEFINITE;
 
387
 
 
388
        /*
 
389
         * Count items.
 
390
         */
 
391
        count = 0;
 
392
        sub_buf = buf;
 
393
        while (sub_buf < end) {
 
394
            if (indefinite_length && sub_buf[0] == 0 && sub_buf[1] == 0) {
 
395
                break; 
 
396
            }
 
397
            rv = der_capture (sub_buf, end, &header_len, &contents_len);
 
398
            if (rv != SECSuccess)
 
399
                return NULL;
 
400
            count++;
 
401
            sub_buf += header_len + contents_len;
 
402
        }
 
403
 
 
404
        /*
 
405
         * Allocate an array of pointers to items; extra one is for a NULL.
 
406
         */
 
407
        indp = (void**)PORT_ArenaZAlloc(arena, (count + 1) * sizeof(void *));
 
408
        if (indp == NULL) {
 
409
            PORT_SetError(SEC_ERROR_NO_MEMORY);
 
410
            return NULL;
 
411
        }
 
412
 
 
413
        /*
 
414
         * Prepare.
 
415
         */
 
416
        if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
 
417
            tmpt = dtemplate->sub;
 
418
            PORT_Assert (tmpt != NULL);
 
419
            thing_size = tmpt->arg;
 
420
            PORT_Assert (thing_size != 0);
 
421
        } else {
 
422
            tmpt = NULL;
 
423
            thing_size = sizeof(SECItem);
 
424
        }
 
425
 
 
426
        /*
 
427
         * Allocate the items themselves.
 
428
         */
 
429
        things = PORT_ArenaZAlloc(arena, count * thing_size);
 
430
        if (things == NULL) {
 
431
            PORT_SetError(SEC_ERROR_NO_MEMORY);
 
432
            return NULL;
 
433
        }
 
434
 
 
435
        placep = (void ***)dest;
 
436
        *placep = indp;
 
437
 
 
438
        while (count) {
 
439
            /* ignore return value because we already did whole thing above */
 
440
            (void) der_capture (buf, end, &header_len, &contents_len);
 
441
            if (tmpt != NULL) {
 
442
                void *sub_thing;
 
443
 
 
444
                sub_thing = (void *)((char *)things + tmpt->offset);
 
445
                buf = der_decode (arena, sub_thing, tmpt,
 
446
                                  buf, header_len, contents_len);
 
447
                if (buf == NULL)
 
448
                    return NULL;
 
449
            } else {
 
450
                item = (SECItem *)things;
 
451
                if (under_kind == DER_ANY) {
 
452
                    contents_len += header_len;
 
453
                    header_len = 0;
 
454
                }
 
455
                buf += header_len;
 
456
                if (under_kind == DER_BIT_STRING) {
 
457
                    item->data = buf + 1;
 
458
                    item->len = ((contents_len - 1) << 3) - *buf;
 
459
                } else {
 
460
                    item->data = buf;
 
461
                    item->len = contents_len;
 
462
                }
 
463
                buf += contents_len;
 
464
            }
 
465
            *indp++ = things;
 
466
            things = (void *)((char *)things + thing_size);
 
467
            count--;
 
468
        }
 
469
 
 
470
        *indp = NULL;
 
471
 
 
472
        goto der_decode_done;
 
473
    }
 
474
 
 
475
    switch (under_kind) {
 
476
      case DER_SEQUENCE:
 
477
      case DER_SET:
 
478
        {
 
479
            DERTemplate *tmpt;
 
480
            void *sub_dest;
 
481
 
 
482
            for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
 
483
                sub_dest = (void *)((char *)dest + tmpt->offset);
 
484
                rv = der_capture (buf, end, &header_len, &contents_len);
 
485
                if (rv != SECSuccess)
 
486
                    return NULL;
 
487
                buf = der_decode (arena, sub_dest, tmpt,
 
488
                                  buf, header_len, contents_len);
 
489
                if (buf == NULL)
 
490
                    return NULL;
 
491
            }
 
492
        }
 
493
        break;
 
494
 
 
495
      case DER_BIT_STRING:
 
496
        item = (SECItem *)dest;
 
497
        item->data = buf + 1;
 
498
        item->len = ((contents_len - 1) << 3) - *buf;
 
499
        buf += contents_len;
 
500
        break;
 
501
 
 
502
      case DER_SKIP:
 
503
        buf += contents_len;
 
504
        break;
 
505
 
 
506
      default:
 
507
        item = (SECItem *)dest;
 
508
        item->data = buf;
 
509
        item->len = contents_len;
 
510
        buf += contents_len;
 
511
        break;
 
512
    }
 
513
 
 
514
der_decode_done:
 
515
 
 
516
    if (indefinite_length && buf[0] == 0 && buf[1] == 0) {
 
517
        buf += 2;
 
518
    }
 
519
 
 
520
    if (explicit_indefinite_length && buf[0] == 0 && buf[1] == 0) {
 
521
        buf += 2;
 
522
    }
 
523
 
 
524
    return buf;
 
525
}
 
526
 
 
527
SECStatus
 
528
DER_Decode(PRArenaPool *arena, void *dest, DERTemplate *dtemplate, SECItem *src)
 
529
{
 
530
    unsigned char *buf;
 
531
    uint32 buf_len, contents_len;
 
532
    int header_len;
 
533
    SECStatus rv;
 
534
 
 
535
    buf = src->data;
 
536
    buf_len = src->len;
 
537
 
 
538
    rv = der_capture (buf, buf + buf_len, &header_len, &contents_len);
 
539
    if (rv != SECSuccess)
 
540
        return rv;
 
541
 
 
542
    dest = (void *)((char *)dest + dtemplate->offset);
 
543
    buf = der_decode (arena, dest, dtemplate, buf, header_len, contents_len);
 
544
    if (buf == NULL)
 
545
        return SECFailure;
 
546
 
 
547
    return SECSuccess;
 
548
}
 
549
 
 
550
SECStatus
 
551
DER_Lengths(SECItem *item, int *header_len_p, uint32 *contents_len_p)
 
552
{
 
553
    return(der_capture(item->data, &item->data[item->len], header_len_p,
 
554
                       contents_len_p));
 
555
}