tor-browser

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

lgutil.c (10600B)


      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 "lgdb.h"
      5 #include "secerr.h"
      6 #include "lgglue.h"
      7 
      8 /*
      9 * ******************** Attribute Utilities *******************************
     10 */
     11 
     12 /*
     13 * look up and attribute structure from a type and Object structure.
     14 * The returned attribute is referenced and needs to be freed when
     15 * it is no longer needed.
     16 */
     17 const CK_ATTRIBUTE *
     18 lg_FindAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ,
     19                 CK_ULONG count)
     20 {
     21    unsigned int i;
     22 
     23    for (i = 0; i < count; i++) {
     24        if (templ[i].type == type) {
     25            return &templ[i];
     26        }
     27    }
     28    return NULL;
     29 }
     30 
     31 /*
     32 * return true if object has attribute
     33 */
     34 PRBool
     35 lg_hasAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ,
     36                CK_ULONG count)
     37 {
     38    if (lg_FindAttribute(type, templ, count) == NULL) {
     39        return PR_FALSE;
     40    }
     41    return PR_TRUE;
     42 }
     43 
     44 /*
     45 * copy an attribute into a SECItem. Secitem is allocated in the specified
     46 * arena.
     47 */
     48 CK_RV
     49 lg_Attribute2SecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type,
     50                     const CK_ATTRIBUTE *templ, CK_ULONG count,
     51                     SECItem *item)
     52 {
     53    int len;
     54    const CK_ATTRIBUTE *attribute;
     55 
     56    attribute = lg_FindAttribute(type, templ, count);
     57    if (attribute == NULL)
     58        return CKR_TEMPLATE_INCOMPLETE;
     59    len = attribute->ulValueLen;
     60 
     61    if (arena) {
     62        item->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
     63    } else {
     64        item->data = (unsigned char *)PORT_Alloc(len);
     65    }
     66    if (item->data == NULL) {
     67        return CKR_HOST_MEMORY;
     68    }
     69    item->len = len;
     70    if (item->len) {
     71        PORT_Memcpy(item->data, attribute->pValue, len);
     72    }
     73    return CKR_OK;
     74 }
     75 
     76 /*
     77 * copy an unsigned attribute into a SECItem. Secitem is allocated in
     78 * the specified arena.
     79 */
     80 CK_RV
     81 lg_Attribute2SSecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type,
     82                      const CK_ATTRIBUTE *templ, CK_ULONG count,
     83                      SECItem *item)
     84 {
     85    const CK_ATTRIBUTE *attribute;
     86    item->data = NULL;
     87 
     88    attribute = lg_FindAttribute(type, templ, count);
     89    if (attribute == NULL)
     90        return CKR_TEMPLATE_INCOMPLETE;
     91 
     92    (void)SECITEM_AllocItem(arena, item, attribute->ulValueLen);
     93    if (item->data == NULL) {
     94        return CKR_HOST_MEMORY;
     95    }
     96    PORT_Memcpy(item->data, attribute->pValue, item->len);
     97    return CKR_OK;
     98 }
     99 
    100 /*
    101 * copy an unsigned attribute into a SECItem. Secitem is allocated in
    102 * the specified arena.
    103 */
    104 CK_RV
    105 lg_PrivAttr2SSecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type,
    106                     const CK_ATTRIBUTE *templ, CK_ULONG count,
    107                     SECItem *item, SDB *sdbpw)
    108 {
    109    const CK_ATTRIBUTE *attribute;
    110    SECItem epki, *dest = NULL;
    111    SECStatus rv;
    112 
    113    item->data = NULL;
    114 
    115    attribute = lg_FindAttribute(type, templ, count);
    116    if (attribute == NULL)
    117        return CKR_TEMPLATE_INCOMPLETE;
    118 
    119    epki.data = attribute->pValue;
    120    epki.len = attribute->ulValueLen;
    121 
    122    rv = lg_util_decrypt(sdbpw, &epki, &dest);
    123    if (rv != SECSuccess) {
    124        return CKR_USER_NOT_LOGGED_IN;
    125    }
    126    (void)SECITEM_AllocItem(arena, item, dest->len);
    127    if (item->data == NULL) {
    128        SECITEM_FreeItem(dest, PR_TRUE);
    129        return CKR_HOST_MEMORY;
    130    }
    131 
    132    PORT_Memcpy(item->data, dest->data, item->len);
    133    SECITEM_FreeItem(dest, PR_TRUE);
    134    return CKR_OK;
    135 }
    136 
    137 CK_RV
    138 lg_PrivAttr2SecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type,
    139                    const CK_ATTRIBUTE *templ, CK_ULONG count,
    140                    SECItem *item, SDB *sdbpw)
    141 {
    142    return lg_PrivAttr2SSecItem(arena, type, templ, count, item, sdbpw);
    143 }
    144 
    145 /*
    146 * this is only valid for CK_BBOOL type attributes. Return the state
    147 * of that attribute.
    148 */
    149 PRBool
    150 lg_isTrue(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, CK_ULONG count)
    151 {
    152    const CK_ATTRIBUTE *attribute;
    153    PRBool tok = PR_FALSE;
    154 
    155    attribute = lg_FindAttribute(type, templ, count);
    156    if (attribute == NULL) {
    157        return PR_FALSE;
    158    }
    159    tok = (PRBool)(*(CK_BBOOL *)attribute->pValue);
    160 
    161    return tok;
    162 }
    163 
    164 /*
    165 * return a null terminated string from attribute 'type'. This string
    166 * is allocated and needs to be freed with PORT_Free() When complete.
    167 */
    168 char *
    169 lg_getString(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, CK_ULONG count)
    170 {
    171    const CK_ATTRIBUTE *attribute;
    172    char *label = NULL;
    173 
    174    attribute = lg_FindAttribute(type, templ, count);
    175    if (attribute == NULL)
    176        return NULL;
    177 
    178    if (attribute->pValue != NULL) {
    179        label = (char *)PORT_Alloc(attribute->ulValueLen + 1);
    180        if (label == NULL) {
    181            return NULL;
    182        }
    183 
    184        PORT_Memcpy(label, attribute->pValue, attribute->ulValueLen);
    185        label[attribute->ulValueLen] = 0;
    186    }
    187    return label;
    188 }
    189 
    190 CK_RV
    191 lg_GetULongAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ,
    192                     CK_ULONG count, CK_ULONG *longData)
    193 {
    194    const CK_ATTRIBUTE *attribute;
    195    CK_ULONG value = 0;
    196    const unsigned char *data;
    197    int i;
    198 
    199    attribute = lg_FindAttribute(type, templ, count);
    200    if (attribute == NULL)
    201        return CKR_TEMPLATE_INCOMPLETE;
    202 
    203    if (attribute->ulValueLen != 4) {
    204        return CKR_ATTRIBUTE_VALUE_INVALID;
    205    }
    206    data = (const unsigned char *)attribute->pValue;
    207    for (i = 0; i < 4; i++) {
    208        value |= (CK_ULONG)(data[i]) << ((3 - i) * 8);
    209    }
    210 
    211    *longData = value;
    212    return CKR_OK;
    213 }
    214 
    215 /*
    216 * ******************** Object Utilities *******************************
    217 */
    218 
    219 SECStatus
    220 lg_deleteTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle)
    221 {
    222    SECItem *item;
    223    PRBool rem;
    224    PLHashTable *hashTable = lg_GetHashTable(sdb);
    225 
    226    item = (SECItem *)PL_HashTableLookup(hashTable, (void *)handle);
    227    rem = PL_HashTableRemove(hashTable, (void *)handle);
    228    if (rem && item) {
    229        SECITEM_FreeItem(item, PR_TRUE);
    230    }
    231    return rem ? SECSuccess : SECFailure;
    232 }
    233 
    234 /* must be called holding lg_DBLock(sdb) */
    235 static SECStatus
    236 lg_addTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle, SECItem *key)
    237 {
    238    PLHashEntry *entry;
    239    SECItem *item;
    240    PLHashTable *hashTable = lg_GetHashTable(sdb);
    241 
    242    item = SECITEM_DupItem(key);
    243    if (item == NULL) {
    244        return SECFailure;
    245    }
    246    entry = PL_HashTableAdd(hashTable, (void *)handle, item);
    247    if (entry == NULL) {
    248        SECITEM_FreeItem(item, PR_TRUE);
    249        return SECFailure;
    250    }
    251    return SECSuccess;
    252 }
    253 
    254 /* must be called holding lg_DBLock(sdb) */
    255 const SECItem *
    256 lg_lookupTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle)
    257 {
    258    PLHashTable *hashTable = lg_GetHashTable(sdb);
    259    return (const SECItem *)PL_HashTableLookup(hashTable, (void *)handle);
    260 }
    261 
    262 static PRIntn
    263 lg_freeHashItem(PLHashEntry *entry, PRIntn index, void *arg)
    264 {
    265    SECItem *item = (SECItem *)entry->value;
    266 
    267    SECITEM_FreeItem(item, PR_TRUE);
    268    return HT_ENUMERATE_NEXT;
    269 }
    270 
    271 CK_RV
    272 lg_ClearTokenKeyHashTable(SDB *sdb)
    273 {
    274    PLHashTable *hashTable;
    275    lg_DBLock(sdb);
    276    hashTable = lg_GetHashTable(sdb);
    277    PL_HashTableEnumerateEntries(hashTable, lg_freeHashItem, NULL);
    278    lg_DBUnlock(sdb);
    279    return CKR_OK;
    280 }
    281 
    282 /*
    283 * handle Token Object stuff
    284 */
    285 static void
    286 lg_XORHash(unsigned char *key, unsigned char *dbkey, int len)
    287 {
    288    int i;
    289 
    290    PORT_Memset(key, 0, 4);
    291 
    292    for (i = 0; i < len - 4; i += 4) {
    293        key[0] ^= dbkey[i];
    294        key[1] ^= dbkey[i + 1];
    295        key[2] ^= dbkey[i + 2];
    296        key[3] ^= dbkey[i + 3];
    297    }
    298 }
    299 
    300 /* Make a token handle for an object and record it so we can find it again */
    301 CK_OBJECT_HANDLE
    302 lg_mkHandle(SDB *sdb, SECItem *dbKey, CK_OBJECT_HANDLE class)
    303 {
    304    unsigned char hashBuf[4];
    305    CK_OBJECT_HANDLE handle;
    306    const SECItem *key;
    307 
    308    handle = class;
    309    /* there is only one KRL, use a fixed handle for it */
    310    if (handle != LG_TOKEN_KRL_HANDLE) {
    311        lg_XORHash(hashBuf, dbKey->data, dbKey->len);
    312        handle = ((CK_OBJECT_HANDLE)hashBuf[0] << 24) |
    313                 ((CK_OBJECT_HANDLE)hashBuf[1] << 16) |
    314                 ((CK_OBJECT_HANDLE)hashBuf[2] << 8) |
    315                 (CK_OBJECT_HANDLE)hashBuf[3];
    316        handle = class | (handle & ~(LG_TOKEN_TYPE_MASK | LG_TOKEN_MASK));
    317        /* we have a CRL who's handle has randomly matched the reserved KRL
    318         * handle, increment it */
    319        if (handle == LG_TOKEN_KRL_HANDLE) {
    320            handle++;
    321        }
    322    }
    323 
    324    lg_DBLock(sdb);
    325    while ((key = lg_lookupTokenKeyByHandle(sdb, handle)) != NULL) {
    326        if (SECITEM_ItemsAreEqual(key, dbKey)) {
    327            lg_DBUnlock(sdb);
    328            return handle;
    329        }
    330        handle++;
    331    }
    332    lg_addTokenKeyByHandle(sdb, handle, dbKey);
    333    lg_DBUnlock(sdb);
    334    return handle;
    335 }
    336 
    337 PRBool
    338 lg_poisonHandle(SDB *sdb, SECItem *dbKey, CK_OBJECT_HANDLE class)
    339 {
    340    unsigned char hashBuf[4];
    341    CK_OBJECT_HANDLE handle;
    342    const SECItem *key;
    343 
    344    handle = class;
    345    /* there is only one KRL, use a fixed handle for it */
    346    if (handle != LG_TOKEN_KRL_HANDLE) {
    347        lg_XORHash(hashBuf, dbKey->data, dbKey->len);
    348        handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) |
    349                 (hashBuf[2] << 8) | hashBuf[3];
    350        handle = class | (handle & ~(LG_TOKEN_TYPE_MASK | LG_TOKEN_MASK));
    351        /* we have a CRL who's handle has randomly matched the reserved KRL
    352         * handle, increment it */
    353        if (handle == LG_TOKEN_KRL_HANDLE) {
    354            handle++;
    355        }
    356    }
    357    lg_DBLock(sdb);
    358    while ((key = lg_lookupTokenKeyByHandle(sdb, handle)) != NULL) {
    359        if (SECITEM_ItemsAreEqual(key, dbKey)) {
    360            key->data[0] ^= 0x80;
    361            lg_DBUnlock(sdb);
    362            return PR_TRUE;
    363        }
    364        handle++;
    365    }
    366    lg_DBUnlock(sdb);
    367    return PR_FALSE;
    368 }
    369 
    370 static LGEncryptFunc lg_encrypt_stub = NULL;
    371 static LGDecryptFunc lg_decrypt_stub = NULL;
    372 
    373 void
    374 legacy_SetCryptFunctions(LGEncryptFunc enc, LGDecryptFunc dec)
    375 {
    376    lg_encrypt_stub = enc;
    377    lg_decrypt_stub = dec;
    378 }
    379 
    380 SECStatus
    381 lg_util_encrypt(PLArenaPool *arena, SDB *sdb,
    382                SECItem *plainText, SECItem **cipherText)
    383 {
    384    if (lg_encrypt_stub == NULL) {
    385        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    386        return SECFailure;
    387    }
    388    return (*lg_encrypt_stub)(arena, sdb, plainText, cipherText);
    389 }
    390 
    391 SECStatus
    392 lg_util_decrypt(SDB *sdb, SECItem *cipherText, SECItem **plainText)
    393 {
    394    if (lg_decrypt_stub == NULL) {
    395        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    396        return SECFailure;
    397    }
    398    return (*lg_decrypt_stub)(sdb, cipherText, plainText);
    399 }