tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

derdec.c (5408B)


      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 static PRUint32
      9 der_indefinite_length(unsigned char *buf, unsigned char *end)
     10 {
     11    PRUint32 len, ret, dataLen;
     12    unsigned char tag, lenCode;
     13    int dataLenLen;
     14 
     15    len = 0;
     16    while (1) {
     17        if ((buf + 2) > end) {
     18            return (0);
     19        }
     20 
     21        tag = *buf++;
     22        lenCode = *buf++;
     23        len += 2;
     24 
     25        if ((tag == 0) && (lenCode == 0)) {
     26            return (len);
     27        }
     28 
     29        if (lenCode == 0x80) {                     /* indefinite length */
     30            ret = der_indefinite_length(buf, end); /* recurse to find length */
     31            if (ret == 0)
     32                return 0;
     33            len += ret;
     34            buf += ret;
     35        } else { /* definite length */
     36            if (lenCode & 0x80) {
     37                /* Length of data is in multibyte format */
     38                dataLenLen = lenCode & 0x7f;
     39                switch (dataLenLen) {
     40                    case 1:
     41                        dataLen = buf[0];
     42                        break;
     43                    case 2:
     44                        dataLen = (buf[0] << 8) | buf[1];
     45                        break;
     46                    case 3:
     47                        dataLen = ((unsigned long)buf[0] << 16) | (buf[1] << 8) | buf[2];
     48                        break;
     49                    case 4:
     50                        dataLen = ((unsigned long)buf[0] << 24) |
     51                                  ((unsigned long)buf[1] << 16) | (buf[2] << 8) | buf[3];
     52                        break;
     53                    default:
     54                        PORT_SetError(SEC_ERROR_BAD_DER);
     55                        return SECFailure;
     56                }
     57            } else {
     58                /* Length of data is in single byte */
     59                dataLen = lenCode;
     60                dataLenLen = 0;
     61            }
     62 
     63            /* skip this item */
     64            buf = buf + dataLenLen + dataLen;
     65            len = len + dataLenLen + dataLen;
     66        }
     67    }
     68 }
     69 
     70 /*
     71 ** Capture the next thing in the buffer.
     72 ** Returns the length of the header and the length of the contents.
     73 */
     74 static SECStatus
     75 der_capture(unsigned char *buf, unsigned char *end,
     76            int *header_len_p, PRUint32 *contents_len_p)
     77 {
     78    unsigned char *bp;
     79    unsigned char whole_tag;
     80    PRUint32 contents_len;
     81    int tag_number;
     82 
     83    if ((buf + 2) > end) {
     84        *header_len_p = 0;
     85        *contents_len_p = 0;
     86        if (buf == end)
     87            return SECSuccess;
     88        return SECFailure;
     89    }
     90 
     91    bp = buf;
     92 
     93    /* Get tag and verify that it is ok. */
     94    whole_tag = *bp++;
     95    tag_number = whole_tag & DER_TAGNUM_MASK;
     96 
     97    /*
     98     * XXX This code does not (yet) handle the high-tag-number form!
     99     */
    100    if (tag_number == DER_HIGH_TAG_NUMBER) {
    101        PORT_SetError(SEC_ERROR_BAD_DER);
    102        return SECFailure;
    103    }
    104 
    105    if ((whole_tag & DER_CLASS_MASK) == DER_UNIVERSAL) {
    106        /* Check that the universal tag number is one we implement.  */
    107        switch (tag_number) {
    108            case DER_BOOLEAN:
    109            case DER_INTEGER:
    110            case DER_BIT_STRING:
    111            case DER_OCTET_STRING:
    112            case DER_NULL:
    113            case DER_OBJECT_ID:
    114            case DER_SEQUENCE:
    115            case DER_SET:
    116            case DER_PRINTABLE_STRING:
    117            case DER_T61_STRING:
    118            case DER_IA5_STRING:
    119            case DER_VISIBLE_STRING:
    120            case DER_UTC_TIME:
    121            case 0: /* end-of-contents tag */
    122                break;
    123            default:
    124                PORT_SetError(SEC_ERROR_BAD_DER);
    125                return SECFailure;
    126        }
    127    }
    128 
    129    /*
    130     * Get first byte of length code (might contain entire length, might not).
    131     */
    132    contents_len = *bp++;
    133 
    134    /*
    135     * If the high bit is set, then the length is in multibyte format,
    136     * or the thing has an indefinite-length.
    137     */
    138    if (contents_len & 0x80) {
    139        int bytes_of_encoded_len;
    140 
    141        bytes_of_encoded_len = contents_len & 0x7f;
    142        contents_len = 0;
    143 
    144        switch (bytes_of_encoded_len) {
    145            case 4:
    146                contents_len |= *bp++;
    147                contents_len <<= 8;
    148            /* fallthru */
    149            case 3:
    150                contents_len |= *bp++;
    151                contents_len <<= 8;
    152            /* fallthru */
    153            case 2:
    154                contents_len |= *bp++;
    155                contents_len <<= 8;
    156            /* fallthru */
    157            case 1:
    158                contents_len |= *bp++;
    159                break;
    160 
    161            case 0:
    162                contents_len = der_indefinite_length(bp, end);
    163                if (contents_len)
    164                    break;
    165            /* fallthru */
    166            default:
    167                PORT_SetError(SEC_ERROR_BAD_DER);
    168                return SECFailure;
    169        }
    170    }
    171 
    172    if ((bp + contents_len) > end) {
    173        /* Ran past end of buffer */
    174        PORT_SetError(SEC_ERROR_BAD_DER);
    175        return SECFailure;
    176    }
    177 
    178    *header_len_p = (int)(bp - buf);
    179    *contents_len_p = contents_len;
    180 
    181    return SECSuccess;
    182 }
    183 
    184 SECStatus
    185 DER_Lengths(SECItem *item, int *header_len_p, PRUint32 *contents_len_p)
    186 {
    187    return (der_capture(item->data, &item->data[item->len], header_len_p,
    188                        contents_len_p));
    189 }