tor-browser

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

berparse.c (11444B)


      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 #include "secutil.h"
      5 
      6 typedef enum {
      7    tagDone,
      8    lengthDone,
      9    leafDone,
     10    compositeDone,
     11    notDone,
     12    parseError,
     13    parseComplete
     14 } ParseState;
     15 
     16 typedef unsigned char Byte;
     17 typedef void (*ParseProc)(BERParse *h, unsigned char **buf, int *len);
     18 typedef struct {
     19    SECArb arb;
     20    int pos; /* length from global start to item start */
     21    SECArb *parent;
     22 } ParseStackElem;
     23 
     24 struct BERParseStr {
     25    PLArenaPool *his;
     26    PLArenaPool *mine;
     27    ParseProc proc;
     28    int stackDepth;
     29    ParseStackElem *stackPtr;
     30    ParseStackElem *stack;
     31    int pending; /* bytes remaining to complete this part */
     32    int pos;     /* running length of consumed characters */
     33    ParseState state;
     34    PRBool keepLeaves;
     35    PRBool derOnly;
     36    BERFilterProc filter;
     37    void *filterArg;
     38    BERNotifyProc before;
     39    void *beforeArg;
     40    BERNotifyProc after;
     41    void *afterArg;
     42 };
     43 
     44 #define UNKNOWN -1
     45 
     46 static unsigned char
     47 NextChar(BERParse *h, unsigned char **buf, int *len)
     48 {
     49    unsigned char c = *(*buf)++;
     50    (*len)--;
     51    h->pos++;
     52    if (h->filter)
     53        (*h->filter)(h->filterArg, &c, 1);
     54    return c;
     55 }
     56 
     57 static void
     58 ParseTag(BERParse *h, unsigned char **buf, int *len)
     59 {
     60    SECArb *arb = &(h->stackPtr->arb);
     61    arb->tag = NextChar(h, buf, len);
     62 
     63    PORT_Assert(h->state == notDone);
     64 
     65    /*
     66     * NOTE: This does not handle the high-tag-number form
     67     */
     68    if ((arb->tag & DER_HIGH_TAG_NUMBER) == DER_HIGH_TAG_NUMBER) {
     69        PORT_SetError(SEC_ERROR_BAD_DER);
     70        h->state = parseError;
     71        return;
     72    }
     73 
     74    h->pending = UNKNOWN;
     75    arb->length = UNKNOWN;
     76    if (arb->tag & DER_CONSTRUCTED) {
     77        arb->body.cons.numSubs = 0;
     78        arb->body.cons.subs = NULL;
     79    } else {
     80        arb->body.item.len = UNKNOWN;
     81        arb->body.item.data = NULL;
     82    }
     83 
     84    h->state = tagDone;
     85 }
     86 
     87 static void
     88 ParseLength(BERParse *h, unsigned char **buf, int *len)
     89 {
     90    Byte b;
     91    SECArb *arb = &(h->stackPtr->arb);
     92 
     93    PORT_Assert(h->state == notDone);
     94 
     95    if (h->pending == UNKNOWN) {
     96        b = NextChar(h, buf, len);
     97        if ((b & 0x80) == 0) { /* short form */
     98            arb->length = b;
     99            /*
    100             * if the tag and the length are both zero bytes, then this
    101             * should be the marker showing end of list for the
    102             * indefinite length composite
    103             */
    104            if (arb->length == 0 && arb->tag == 0)
    105                h->state = compositeDone;
    106            else
    107                h->state = lengthDone;
    108            return;
    109        }
    110 
    111        h->pending = b & 0x7f;
    112        /* 0 implies this is an indefinite length */
    113        if (h->pending > 4) {
    114            PORT_SetError(SEC_ERROR_BAD_DER);
    115            h->state = parseError;
    116            return;
    117        }
    118        arb->length = 0;
    119    }
    120 
    121    while ((*len > 0) && (h->pending > 0)) {
    122        b = NextChar(h, buf, len);
    123        arb->length = (arb->length << 8) + b;
    124        h->pending--;
    125    }
    126    if (h->pending == 0) {
    127        if (h->derOnly && (arb->length == 0))
    128            h->state = parseError;
    129        else
    130            h->state = lengthDone;
    131    }
    132    return;
    133 }
    134 
    135 static void
    136 ParseLeaf(BERParse *h, unsigned char **buf, int *len)
    137 {
    138    int count;
    139    SECArb *arb = &(h->stackPtr->arb);
    140 
    141    PORT_Assert(h->state == notDone);
    142    PORT_Assert(h->pending >= 0);
    143 
    144    if (*len < h->pending)
    145        count = *len;
    146    else
    147        count = h->pending;
    148 
    149    if (h->keepLeaves)
    150        memcpy(arb->body.item.data + arb->body.item.len, *buf, count);
    151    if (h->filter)
    152        (*h->filter)(h->filterArg, *buf, count);
    153    *buf += count;
    154    *len -= count;
    155    arb->body.item.len += count;
    156    h->pending -= count;
    157    h->pos += count;
    158    if (h->pending == 0) {
    159        h->state = leafDone;
    160    }
    161    return;
    162 }
    163 
    164 static void
    165 CreateArbNode(BERParse *h)
    166 {
    167    SECArb *arb = PORT_ArenaAlloc(h->his, sizeof(SECArb));
    168 
    169    *arb = h->stackPtr->arb;
    170 
    171    /*
    172     * Special case closing the root
    173     */
    174    if (h->stackPtr == h->stack) {
    175        PORT_Assert(arb->tag & DER_CONSTRUCTED);
    176        h->state = parseComplete;
    177    } else {
    178        SECArb *parent = h->stackPtr->parent;
    179        parent->body.cons.subs = DS_ArenaGrow(
    180            h->his, parent->body.cons.subs,
    181            (parent->body.cons.numSubs) * sizeof(SECArb *),
    182            (parent->body.cons.numSubs + 1) * sizeof(SECArb *));
    183        parent->body.cons.subs[parent->body.cons.numSubs] = arb;
    184        parent->body.cons.numSubs++;
    185        h->proc = ParseTag;
    186        h->state = notDone;
    187        h->pending = UNKNOWN;
    188    }
    189    if (h->after)
    190        (*h->after)(h->afterArg, arb, h->stackPtr - h->stack, PR_FALSE);
    191 }
    192 
    193 SECStatus
    194 BER_ParseSome(BERParse *h, unsigned char *buf, int len)
    195 {
    196    if (h->state == parseError)
    197        return PR_TRUE;
    198 
    199    while (len) {
    200        (*h->proc)(h, &buf, &len);
    201        if (h->state == parseComplete) {
    202            PORT_SetError(SEC_ERROR_BAD_DER);
    203            h->state = parseError;
    204            return PR_TRUE;
    205        }
    206        if (h->state == parseError)
    207            return PR_TRUE;
    208        PORT_Assert(h->state != parseComplete);
    209 
    210        if (h->state <= compositeDone) {
    211            if (h->proc == ParseTag) {
    212                PORT_Assert(h->state == tagDone);
    213                h->proc = ParseLength;
    214                h->state = notDone;
    215            } else if (h->proc == ParseLength) {
    216                SECArb *arb = &(h->stackPtr->arb);
    217                PORT_Assert(h->state == lengthDone || h->state == compositeDone);
    218 
    219                if (h->before)
    220                    (*h->before)(h->beforeArg, arb,
    221                                 h->stackPtr - h->stack, PR_TRUE);
    222 
    223                /*
    224                 * Check to see if this is the end of an indefinite
    225                 * length composite
    226                 */
    227                if (h->state == compositeDone) {
    228                    SECArb *parent = h->stackPtr->parent;
    229                    PORT_Assert(parent);
    230                    PORT_Assert(parent->tag & DER_CONSTRUCTED);
    231                    if (parent->length != 0) {
    232                        PORT_SetError(SEC_ERROR_BAD_DER);
    233                        h->state = parseError;
    234                        return PR_TRUE;
    235                    }
    236                    /*
    237                     * NOTE: This does not check for an indefinite length
    238                     * composite being contained inside a definite length
    239                     * composite. It is not clear that is legal.
    240                     */
    241                    h->stackPtr--;
    242                    CreateArbNode(h);
    243                } else {
    244                    h->stackPtr->pos = h->pos;
    245 
    246                    if (arb->tag & DER_CONSTRUCTED) {
    247                        SECArb *parent;
    248                        /*
    249                         * Make sure there is room on the stack before we
    250                         * stick anything else there.
    251                         */
    252                        PORT_Assert(h->stackPtr - h->stack < h->stackDepth);
    253                        if (h->stackPtr - h->stack == h->stackDepth - 1) {
    254                            int newDepth = h->stackDepth * 2;
    255                            h->stack = DS_ArenaGrow(h->mine, h->stack,
    256                                                    sizeof(ParseStackElem) *
    257                                                        h->stackDepth,
    258                                                    sizeof(ParseStackElem) *
    259                                                        newDepth);
    260                            h->stackPtr = h->stack + h->stackDepth + 1;
    261                            h->stackDepth = newDepth;
    262                        }
    263                        parent = &(h->stackPtr->arb);
    264                        h->stackPtr++;
    265                        h->stackPtr->parent = parent;
    266                        h->proc = ParseTag;
    267                        h->state = notDone;
    268                        h->pending = UNKNOWN;
    269                    } else {
    270                        if (arb->length < 0) {
    271                            PORT_SetError(SEC_ERROR_BAD_DER);
    272                            h->state = parseError;
    273                            return PR_TRUE;
    274                        }
    275                        arb->body.item.len = 0;
    276                        if (arb->length > 0 && h->keepLeaves) {
    277                            arb->body.item.data =
    278                                PORT_ArenaAlloc(h->his, arb->length);
    279                        } else {
    280                            arb->body.item.data = NULL;
    281                        }
    282                        h->proc = ParseLeaf;
    283                        h->state = notDone;
    284                        h->pending = arb->length;
    285                    }
    286                }
    287            } else {
    288                ParseStackElem *parent;
    289                PORT_Assert(h->state = leafDone);
    290                PORT_Assert(h->proc == ParseLeaf);
    291 
    292                for (;;) {
    293                    CreateArbNode(h);
    294                    if (h->stackPtr == h->stack)
    295                        break;
    296                    parent = (h->stackPtr - 1);
    297                    PORT_Assert(parent->arb.tag & DER_CONSTRUCTED);
    298                    if (parent->arb.length == 0) /* need explicit end */
    299                        break;
    300                    if (parent->pos + parent->arb.length > h->pos)
    301                        break;
    302                    if (parent->pos + parent->arb.length < h->pos) {
    303                        PORT_SetError(SEC_ERROR_BAD_DER);
    304                        h->state = parseError;
    305                        return PR_TRUE;
    306                    }
    307                    h->stackPtr = parent;
    308                }
    309            }
    310        }
    311    }
    312    return PR_FALSE;
    313 }
    314 BERParse *
    315 BER_ParseInit(PLArenaPool *arena, PRBool derOnly)
    316 {
    317    BERParse *h;
    318    PLArenaPool *temp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    319    if (temp == NULL) {
    320        PORT_SetError(SEC_ERROR_NO_MEMORY);
    321        return NULL;
    322    }
    323    h = PORT_ArenaAlloc(temp, sizeof(BERParse));
    324    if (h == NULL) {
    325        PORT_FreeArena(temp, PR_FALSE);
    326        PORT_SetError(SEC_ERROR_NO_MEMORY);
    327        return NULL;
    328    }
    329    h->his = arena;
    330    h->mine = temp;
    331    h->proc = ParseTag;
    332    h->stackDepth = 20;
    333    h->stack = PORT_ArenaZAlloc(h->mine,
    334                                sizeof(ParseStackElem) * h->stackDepth);
    335    h->stackPtr = h->stack;
    336    h->state = notDone;
    337    h->pos = 0;
    338    h->keepLeaves = PR_TRUE;
    339    h->before = NULL;
    340    h->after = NULL;
    341    h->filter = NULL;
    342    h->derOnly = derOnly;
    343    return h;
    344 }
    345 
    346 SECArb *
    347 BER_ParseFini(BERParse *h)
    348 {
    349    PLArenaPool *myArena = h->mine;
    350    SECArb *arb;
    351 
    352    if (h->state != parseComplete) {
    353        arb = NULL;
    354    } else {
    355        arb = PORT_ArenaAlloc(h->his, sizeof(SECArb));
    356        *arb = h->stackPtr->arb;
    357    }
    358 
    359    PORT_FreeArena(myArena, PR_FALSE);
    360 
    361    return arb;
    362 }
    363 
    364 void
    365 BER_SetFilter(BERParse *h, BERFilterProc proc, void *instance)
    366 {
    367    h->filter = proc;
    368    h->filterArg = instance;
    369 }
    370 
    371 void
    372 BER_SetLeafStorage(BERParse *h, PRBool keep)
    373 {
    374    h->keepLeaves = keep;
    375 }
    376 
    377 void
    378 BER_SetNotifyProc(BERParse *h, BERNotifyProc proc, void *instance,
    379                  PRBool beforeData)
    380 {
    381    if (beforeData) {
    382        h->before = proc;
    383        h->beforeArg = instance;
    384    } else {
    385        h->after = proc;
    386        h->afterArg = instance;
    387    }
    388 }