tor-browser

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

secitem.c (11328B)


      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 * Support routines for SECItem data structure.
      7 */
      8 
      9 #include "seccomon.h"
     10 #include "secitem.h"
     11 #include "secerr.h"
     12 #include "secport.h"
     13 
     14 SECItem *
     15 SECITEM_AllocItem(PLArenaPool *arena, SECItem *item, unsigned int len)
     16 {
     17    SECItem *result = NULL;
     18    void *mark = NULL;
     19 
     20    if (arena != NULL) {
     21        mark = PORT_ArenaMark(arena);
     22    }
     23 
     24    if (item == NULL) {
     25        if (arena != NULL) {
     26            result = PORT_ArenaZAlloc(arena, sizeof(SECItem));
     27        } else {
     28            result = PORT_ZAlloc(sizeof(SECItem));
     29        }
     30        if (result == NULL) {
     31            goto loser;
     32        }
     33    } else {
     34        PORT_Assert(item->data == NULL);
     35        result = item;
     36    }
     37 
     38    result->len = len;
     39    if (len) {
     40        if (arena != NULL) {
     41            result->data = PORT_ArenaAlloc(arena, len);
     42        } else {
     43            result->data = PORT_Alloc(len);
     44        }
     45        if (result->data == NULL) {
     46            goto loser;
     47        }
     48    } else {
     49        result->data = NULL;
     50    }
     51 
     52    if (mark) {
     53        PORT_ArenaUnmark(arena, mark);
     54    }
     55    return (result);
     56 
     57 loser:
     58    if (arena != NULL) {
     59        if (mark) {
     60            PORT_ArenaRelease(arena, mark);
     61        }
     62        if (item != NULL) {
     63            item->data = NULL;
     64            item->len = 0;
     65        }
     66    } else {
     67        if (result != NULL) {
     68            SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE);
     69        }
     70        /*
     71         * If item is not NULL, the above has set item->data and
     72         * item->len to 0.
     73         */
     74    }
     75    return (NULL);
     76 }
     77 
     78 SECStatus
     79 SECITEM_MakeItem(PLArenaPool *arena, SECItem *dest, const unsigned char *data,
     80                 unsigned int len)
     81 {
     82    SECItem it = { siBuffer, (unsigned char *)data, len };
     83 
     84    return SECITEM_CopyItem(arena, dest, &it);
     85 }
     86 
     87 SECStatus
     88 SECITEM_ReallocItem(PLArenaPool *arena, SECItem *item, unsigned int oldlen,
     89                    unsigned int newlen)
     90 {
     91    PORT_Assert(item != NULL);
     92    if (item == NULL) {
     93        /* XXX Set error.  But to what? */
     94        return SECFailure;
     95    }
     96 
     97    /*
     98     * If no old length, degenerate to just plain alloc.
     99     */
    100    if (oldlen == 0) {
    101        PORT_Assert(item->data == NULL || item->len == 0);
    102        if (newlen == 0) {
    103            /* Nothing to do.  Weird, but not a failure.  */
    104            return SECSuccess;
    105        }
    106        item->len = newlen;
    107        if (arena != NULL) {
    108            item->data = PORT_ArenaAlloc(arena, newlen);
    109        } else {
    110            item->data = PORT_Alloc(newlen);
    111        }
    112    } else {
    113        if (arena != NULL) {
    114            item->data = PORT_ArenaGrow(arena, item->data, oldlen, newlen);
    115        } else {
    116            item->data = PORT_Realloc(item->data, newlen);
    117        }
    118    }
    119 
    120    if (item->data == NULL) {
    121        return SECFailure;
    122    }
    123 
    124    return SECSuccess;
    125 }
    126 
    127 SECStatus
    128 SECITEM_ReallocItemV2(PLArenaPool *arena, SECItem *item, unsigned int newlen)
    129 {
    130    unsigned char *newdata = NULL;
    131 
    132    PORT_Assert(item);
    133    if (!item) {
    134        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    135        return SECFailure;
    136    }
    137 
    138    if (item->len == newlen) {
    139        return SECSuccess;
    140    }
    141 
    142    if (!newlen) {
    143        if (!arena) {
    144            PORT_Free(item->data);
    145        }
    146        item->data = NULL;
    147        item->len = 0;
    148        return SECSuccess;
    149    }
    150 
    151    if (!item->data) {
    152        /* allocate fresh block of memory */
    153        PORT_Assert(!item->len);
    154        if (arena) {
    155            newdata = PORT_ArenaAlloc(arena, newlen);
    156        } else {
    157            newdata = PORT_Alloc(newlen);
    158        }
    159    } else {
    160        /* reallocate or adjust existing block of memory */
    161        if (arena) {
    162            if (item->len > newlen) {
    163                /* There's no need to realloc a shorter block from the arena,
    164                 * because it would result in using even more memory!
    165                 * Therefore we'll continue to use the old block and
    166                 * set the item to the shorter size.
    167                 */
    168                item->len = newlen;
    169                return SECSuccess;
    170            }
    171            newdata = PORT_ArenaGrow(arena, item->data, item->len, newlen);
    172        } else {
    173            newdata = PORT_Realloc(item->data, newlen);
    174        }
    175    }
    176 
    177    if (!newdata) {
    178        PORT_SetError(SEC_ERROR_NO_MEMORY);
    179        return SECFailure;
    180    }
    181 
    182    item->len = newlen;
    183    item->data = newdata;
    184    return SECSuccess;
    185 }
    186 
    187 SECComparison
    188 SECITEM_CompareItem(const SECItem *a, const SECItem *b)
    189 {
    190    unsigned m;
    191    int rv;
    192 
    193    if (a == b)
    194        return SECEqual;
    195    if (!a || !a->len || !a->data)
    196        return (!b || !b->len || !b->data) ? SECEqual : SECLessThan;
    197    if (!b || !b->len || !b->data)
    198        return SECGreaterThan;
    199 
    200    m = ((a->len < b->len) ? a->len : b->len);
    201 
    202    rv = PORT_Memcmp(a->data, b->data, m);
    203    if (rv) {
    204        return rv < 0 ? SECLessThan : SECGreaterThan;
    205    }
    206    if (a->len < b->len) {
    207        return SECLessThan;
    208    }
    209    if (a->len == b->len) {
    210        return SECEqual;
    211    }
    212    return SECGreaterThan;
    213 }
    214 
    215 PRBool
    216 SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b)
    217 {
    218    if (a->len != b->len)
    219        return PR_FALSE;
    220    if (!a->len)
    221        return PR_TRUE;
    222    if (!a->data || !b->data) {
    223        /* avoid null pointer crash. */
    224        return (PRBool)(a->data == b->data);
    225    }
    226    return (PRBool)!PORT_Memcmp(a->data, b->data, a->len);
    227 }
    228 
    229 SECItem *
    230 SECITEM_DupItem(const SECItem *from)
    231 {
    232    return SECITEM_ArenaDupItem(NULL, from);
    233 }
    234 
    235 SECItem *
    236 SECITEM_ArenaDupItem(PLArenaPool *arena, const SECItem *from)
    237 {
    238    SECItem *to;
    239 
    240    if (from == NULL) {
    241        return NULL;
    242    }
    243 
    244    to = SECITEM_AllocItem(arena, NULL, from->len);
    245    if (to == NULL) {
    246        return NULL;
    247    }
    248 
    249    to->type = from->type;
    250    if (to->len) {
    251        PORT_Memcpy(to->data, from->data, to->len);
    252    }
    253 
    254    return to;
    255 }
    256 
    257 SECStatus
    258 SECITEM_CopyItem(PLArenaPool *arena, SECItem *to, const SECItem *from)
    259 {
    260    to->type = from->type;
    261    if (from->data && from->len) {
    262        if (arena) {
    263            to->data = (unsigned char *)PORT_ArenaAlloc(arena, from->len);
    264        } else {
    265            to->data = (unsigned char *)PORT_Alloc(from->len);
    266        }
    267 
    268        if (!to->data) {
    269            return SECFailure;
    270        }
    271        PORT_Memcpy(to->data, from->data, from->len);
    272        to->len = from->len;
    273    } else {
    274        /*
    275         * If from->data is NULL but from->len is nonzero, this function
    276         * will succeed.  Is this right?
    277         */
    278        to->data = 0;
    279        to->len = 0;
    280    }
    281    return SECSuccess;
    282 }
    283 
    284 void
    285 SECITEM_FreeItem(SECItem *zap, PRBool freeit)
    286 {
    287    if (zap) {
    288        PORT_Free(zap->data);
    289        zap->data = 0;
    290        zap->len = 0;
    291        if (freeit) {
    292            PORT_Free(zap);
    293        }
    294    }
    295 }
    296 
    297 void
    298 SECITEM_ZfreeItem(SECItem *zap, PRBool freeit)
    299 {
    300    if (zap) {
    301        PORT_ZFree(zap->data, zap->len);
    302        zap->data = 0;
    303        zap->len = 0;
    304        if (freeit) {
    305            PORT_ZFree(zap, sizeof(SECItem));
    306        }
    307    }
    308 }
    309 /* these reroutines were taken from pkix oid.c, which is supposed to
    310 * replace this file some day */
    311 /*
    312 * This is the hash function.  We simply XOR the encoded form with
    313 * itself in sizeof(PLHashNumber)-byte chunks.  Improving this
    314 * routine is left as an excercise for the more mathematically
    315 * inclined student.
    316 */
    317 PLHashNumber PR_CALLBACK
    318 SECITEM_Hash(const void *key)
    319 {
    320    const SECItem *item = (const SECItem *)key;
    321    PLHashNumber rv = 0;
    322 
    323    PRUint8 *data = (PRUint8 *)item->data;
    324    PRUint32 i;
    325    PRUint8 *rvc = (PRUint8 *)&rv;
    326 
    327    for (i = 0; i < item->len; i++) {
    328        rvc[i % sizeof(rv)] ^= *data;
    329        data++;
    330    }
    331 
    332    return rv;
    333 }
    334 
    335 /*
    336 * This is the key-compare function.  It simply does a lexical
    337 * comparison on the item data.  This does not result in
    338 * quite the same ordering as the "sequence of numbers" order,
    339 * but heck it's only used internally by the hash table anyway.
    340 */
    341 PRIntn PR_CALLBACK
    342 SECITEM_HashCompare(const void *k1, const void *k2)
    343 {
    344    const SECItem *i1 = (const SECItem *)k1;
    345    const SECItem *i2 = (const SECItem *)k2;
    346 
    347    return SECITEM_ItemsAreEqual(i1, i2);
    348 }
    349 
    350 SECItemArray *
    351 SECITEM_AllocArray(PLArenaPool *arena, SECItemArray *array, unsigned int len)
    352 {
    353    SECItemArray *result = NULL;
    354    void *mark = NULL;
    355 
    356    if (array != NULL && array->items != NULL) {
    357        PORT_Assert(0);
    358        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    359        return NULL;
    360    }
    361 
    362    if (arena != NULL) {
    363        mark = PORT_ArenaMark(arena);
    364    }
    365 
    366    if (array == NULL) {
    367        if (arena != NULL) {
    368            result = PORT_ArenaZAlloc(arena, sizeof(SECItemArray));
    369        } else {
    370            result = PORT_ZAlloc(sizeof(SECItemArray));
    371        }
    372        if (result == NULL) {
    373            goto loser;
    374        }
    375    } else {
    376        result = array;
    377    }
    378 
    379    result->len = len;
    380    if (len) {
    381        if (arena != NULL) {
    382            result->items = PORT_ArenaZNewArray(arena, SECItem, len);
    383        } else {
    384            result->items = PORT_ZNewArray(SECItem, len);
    385        }
    386        if (result->items == NULL) {
    387            goto loser;
    388        }
    389    } else {
    390        result->items = NULL;
    391    }
    392 
    393    if (mark) {
    394        PORT_ArenaUnmark(arena, mark);
    395    }
    396    return result;
    397 
    398 loser:
    399    if (arena != NULL) {
    400        if (mark) {
    401            PORT_ArenaRelease(arena, mark);
    402        }
    403    } else {
    404        if (result != NULL && array == NULL) {
    405            PORT_Free(result);
    406        }
    407    }
    408    if (array != NULL) {
    409        array->items = NULL;
    410        array->len = 0;
    411    }
    412    return NULL;
    413 }
    414 
    415 static void
    416 secitem_FreeArray(SECItemArray *array, PRBool zero_items, PRBool freeit)
    417 {
    418    unsigned int i;
    419 
    420    if (!array || !array->len || !array->items)
    421        return;
    422 
    423    for (i = 0; i < array->len; ++i) {
    424        SECItem *item = &array->items[i];
    425 
    426        if (item->data) {
    427            if (zero_items) {
    428                SECITEM_ZfreeItem(item, PR_FALSE);
    429            } else {
    430                SECITEM_FreeItem(item, PR_FALSE);
    431            }
    432        }
    433    }
    434    PORT_Free(array->items);
    435    array->items = NULL;
    436    array->len = 0;
    437 
    438    if (freeit)
    439        PORT_Free(array);
    440 }
    441 
    442 void
    443 SECITEM_FreeArray(SECItemArray *array, PRBool freeit)
    444 {
    445    secitem_FreeArray(array, PR_FALSE, freeit);
    446 }
    447 
    448 void
    449 SECITEM_ZfreeArray(SECItemArray *array, PRBool freeit)
    450 {
    451    secitem_FreeArray(array, PR_TRUE, freeit);
    452 }
    453 
    454 SECItemArray *
    455 SECITEM_DupArray(PLArenaPool *arena, const SECItemArray *from)
    456 {
    457    SECItemArray *result;
    458    unsigned int i;
    459 
    460    /* Require a "from" array.
    461     * Reject an inconsistent "from" array with NULL data and nonzero length.
    462     * However, allow a "from" array of zero length.
    463     */
    464    if (!from || (!from->items && from->len))
    465        return NULL;
    466 
    467    result = SECITEM_AllocArray(arena, NULL, from->len);
    468    if (!result)
    469        return NULL;
    470 
    471    for (i = 0; i < from->len; ++i) {
    472        SECStatus rv = SECITEM_CopyItem(arena,
    473                                        &result->items[i], &from->items[i]);
    474        if (rv != SECSuccess) {
    475            SECITEM_ZfreeArray(result, PR_TRUE);
    476            return NULL;
    477        }
    478    }
    479 
    480    return result;
    481 }