tor-browser

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

devutil.c (30731B)


      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 #ifndef DEVM_H
      6 #include "devm.h"
      7 #endif /* DEVM_H */
      8 
      9 #ifndef CKHELPER_H
     10 #include "ckhelper.h"
     11 #endif /* CKHELPER_H */
     12 
     13 #include "pk11pub.h"
     14 #include "dev3hack.h"
     15 #include "secerr.h"
     16 
     17 NSS_IMPLEMENT nssCryptokiObject *
     18 nssCryptokiObject_Create(
     19    NSSToken *t,
     20    nssSession *session,
     21    CK_OBJECT_HANDLE h)
     22 {
     23    PRStatus status;
     24    NSSSlot *slot;
     25    nssCryptokiObject *object;
     26    CK_BBOOL *isTokenObject;
     27    CK_ATTRIBUTE cert_template[] = {
     28        { CKA_TOKEN, NULL, 0 },
     29        { CKA_LABEL, NULL, 0 }
     30    };
     31    slot = nssToken_GetSlot(t);
     32    status = nssCKObject_GetAttributes(h, cert_template, 2,
     33                                       NULL, session, slot);
     34    nssSlot_Destroy(slot);
     35    if (status != PR_SUCCESS) {
     36        /* a failure here indicates a device error */
     37        return (nssCryptokiObject *)NULL;
     38    }
     39    if (cert_template[0].ulValueLen == 0 || !cert_template[0].pValue) {
     40        nss_ZFreeIf(cert_template[1].pValue);
     41        return (nssCryptokiObject *)NULL;
     42    }
     43    object = nss_ZNEW(NULL, nssCryptokiObject);
     44    if (!object) {
     45        nss_ZFreeIf(cert_template[0].pValue);
     46        nss_ZFreeIf(cert_template[1].pValue);
     47        return (nssCryptokiObject *)NULL;
     48    }
     49    object->handle = h;
     50    object->token = nssToken_AddRef(t);
     51    isTokenObject = (CK_BBOOL *)cert_template[0].pValue;
     52    object->isTokenObject = *isTokenObject;
     53    object->trustType = CKM_INVALID_MECHANISM;
     54    nss_ZFreeIf(cert_template[0].pValue);
     55    NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label);
     56    return object;
     57 }
     58 
     59 NSS_IMPLEMENT void
     60 nssCryptokiObject_Destroy(
     61    nssCryptokiObject *object)
     62 {
     63    if (object) {
     64        (void)nssToken_Destroy(object->token);
     65        nss_ZFreeIf(object->label);
     66        nss_ZFreeIf(object);
     67    }
     68 }
     69 
     70 NSS_IMPLEMENT nssCryptokiObject *
     71 nssCryptokiObject_Clone(
     72    nssCryptokiObject *object)
     73 {
     74    nssCryptokiObject *rvObject;
     75    rvObject = nss_ZNEW(NULL, nssCryptokiObject);
     76    if (rvObject) {
     77        rvObject->handle = object->handle;
     78        rvObject->token = nssToken_AddRef(object->token);
     79        rvObject->isTokenObject = object->isTokenObject;
     80        if (object->label) {
     81            rvObject->label = nssUTF8_Duplicate(object->label, NULL);
     82        }
     83    }
     84    return rvObject;
     85 }
     86 
     87 NSS_EXTERN PRBool
     88 nssCryptokiObject_Equal(
     89    nssCryptokiObject *o1,
     90    nssCryptokiObject *o2)
     91 {
     92    return (o1->token == o2->token && o1->handle == o2->handle);
     93 }
     94 
     95 NSS_IMPLEMENT PRUint32
     96 nssPKCS11String_Length(CK_CHAR *pkcs11Str, PRUint32 bufLen)
     97 {
     98    PRInt32 i;
     99    for (i = bufLen - 1; i >= 0;) {
    100        if (pkcs11Str[i] != ' ' && pkcs11Str[i] != '\0')
    101            break;
    102        --i;
    103    }
    104    return (PRUint32)(i + 1);
    105 }
    106 
    107 /*
    108 * Slot arrays
    109 */
    110 
    111 NSS_IMPLEMENT NSSSlot **
    112 nssSlotArray_Clone(
    113    NSSSlot **slots)
    114 {
    115    NSSSlot **rvSlots = NULL;
    116    NSSSlot **sp = slots;
    117    PRUint32 count = 0;
    118    while (sp && *sp)
    119        count++;
    120    if (count > 0) {
    121        rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1);
    122        if (rvSlots) {
    123            for (sp = slots, count = 0; *sp; sp++) {
    124                rvSlots[count++] = nssSlot_AddRef(*sp);
    125            }
    126        }
    127    }
    128    return rvSlots;
    129 }
    130 
    131 NSS_IMPLEMENT void
    132 nssSlotArray_Destroy(
    133    NSSSlot **slots)
    134 {
    135    if (slots) {
    136        NSSSlot **slotp;
    137        for (slotp = slots; *slotp; slotp++) {
    138            nssSlot_Destroy(*slotp);
    139        }
    140        nss_ZFreeIf(slots);
    141    }
    142 }
    143 
    144 NSS_IMPLEMENT void
    145 NSSSlotArray_Destroy(
    146    NSSSlot **slots)
    147 {
    148    nssSlotArray_Destroy(slots);
    149 }
    150 
    151 NSS_IMPLEMENT void
    152 nssTokenArray_Destroy(
    153    NSSToken **tokens)
    154 {
    155    if (tokens) {
    156        NSSToken **tokenp;
    157        for (tokenp = tokens; *tokenp; tokenp++) {
    158            (void)nssToken_Destroy(*tokenp);
    159        }
    160        nss_ZFreeIf(tokens);
    161    }
    162 }
    163 
    164 NSS_IMPLEMENT void
    165 nssCryptokiObjectArray_Destroy(
    166    nssCryptokiObject **objects)
    167 {
    168    if (objects) {
    169        nssCryptokiObject **op;
    170        for (op = objects; *op; op++) {
    171            nssCryptokiObject_Destroy(*op);
    172        }
    173        nss_ZFreeIf(objects);
    174    }
    175 }
    176 
    177 /* object cache for token */
    178 
    179 typedef struct
    180 {
    181    NSSArena *arena;
    182    nssCryptokiObject *object;
    183    CK_ATTRIBUTE_PTR attributes;
    184    CK_ULONG numAttributes;
    185 } nssCryptokiObjectAndAttributes;
    186 
    187 enum {
    188    cachedCerts = 0,
    189    cachedTrust = 1,
    190    cachedCRLs = 2
    191 } cachedObjectType;
    192 
    193 struct nssTokenObjectCacheStr {
    194    NSSToken *token;
    195    PZLock *lock;
    196    PRBool loggedIn;
    197    PRBool doObjectType[3];
    198    PRBool searchedObjectType[3];
    199    nssCryptokiObjectAndAttributes **objects[3];
    200 };
    201 
    202 NSS_IMPLEMENT nssTokenObjectCache *
    203 nssTokenObjectCache_Create(
    204    NSSToken *token,
    205    PRBool cacheCerts,
    206    PRBool cacheTrust,
    207    PRBool cacheCRLs)
    208 {
    209    nssTokenObjectCache *rvCache;
    210    rvCache = nss_ZNEW(NULL, nssTokenObjectCache);
    211    if (!rvCache) {
    212        goto loser;
    213    }
    214    rvCache->lock = PZ_NewLock(nssILockOther); /* XXX */
    215    if (!rvCache->lock) {
    216        goto loser;
    217    }
    218    rvCache->doObjectType[cachedCerts] = cacheCerts;
    219    rvCache->doObjectType[cachedTrust] = cacheTrust;
    220    rvCache->doObjectType[cachedCRLs] = cacheCRLs;
    221    rvCache->token = token; /* cache goes away with token */
    222    return rvCache;
    223 loser:
    224    nssTokenObjectCache_Destroy(rvCache);
    225    return (nssTokenObjectCache *)NULL;
    226 }
    227 
    228 static void
    229 clear_cache(
    230    nssTokenObjectCache *cache)
    231 {
    232    nssCryptokiObjectAndAttributes **oa;
    233    PRUint32 objectType;
    234    for (objectType = cachedCerts; objectType <= cachedCRLs; objectType++) {
    235        cache->searchedObjectType[objectType] = PR_FALSE;
    236        if (!cache->objects[objectType]) {
    237            continue;
    238        }
    239        for (oa = cache->objects[objectType]; *oa; oa++) {
    240            /* prevent the token from being destroyed */
    241            (*oa)->object->token = NULL;
    242            nssCryptokiObject_Destroy((*oa)->object);
    243            nssArena_Destroy((*oa)->arena);
    244        }
    245        nss_ZFreeIf(cache->objects[objectType]);
    246        cache->objects[objectType] = NULL;
    247    }
    248 }
    249 
    250 NSS_IMPLEMENT void
    251 nssTokenObjectCache_Clear(
    252    nssTokenObjectCache *cache)
    253 {
    254    if (cache) {
    255        PZ_Lock(cache->lock);
    256        clear_cache(cache);
    257        PZ_Unlock(cache->lock);
    258    }
    259 }
    260 
    261 NSS_IMPLEMENT void
    262 nssTokenObjectCache_Destroy(
    263    nssTokenObjectCache *cache)
    264 {
    265    if (cache) {
    266        clear_cache(cache);
    267        if (cache->lock) {
    268            PZ_DestroyLock(cache->lock);
    269        }
    270        nss_ZFreeIf(cache);
    271    }
    272 }
    273 
    274 NSS_IMPLEMENT PRBool
    275 nssTokenObjectCache_HaveObjectClass(
    276    nssTokenObjectCache *cache,
    277    CK_OBJECT_CLASS objclass)
    278 {
    279    PRBool haveIt;
    280    PZ_Lock(cache->lock);
    281    switch (objclass) {
    282        case CKO_CERTIFICATE:
    283            haveIt = cache->doObjectType[cachedCerts];
    284            break;
    285        case CKO_NSS_TRUST:
    286        case CKO_TRUST:
    287            haveIt = cache->doObjectType[cachedTrust];
    288            break;
    289        case CKO_NSS_CRL:
    290            haveIt = cache->doObjectType[cachedCRLs];
    291            break;
    292        default:
    293            haveIt = PR_FALSE;
    294    }
    295    PZ_Unlock(cache->lock);
    296    return haveIt;
    297 }
    298 
    299 static nssCryptokiObjectAndAttributes **
    300 create_object_array(
    301    nssCryptokiObject **objects,
    302    PRBool *doObjects,
    303    PRUint32 *numObjects,
    304    PRStatus *status)
    305 {
    306    nssCryptokiObjectAndAttributes **rvOandA = NULL;
    307    *numObjects = 0;
    308    /* There are no objects for this type */
    309    if (!objects || !*objects) {
    310        *status = PR_SUCCESS;
    311        return rvOandA;
    312    }
    313    while (*objects++)
    314        (*numObjects)++;
    315    if (*numObjects >= MAX_LOCAL_CACHE_OBJECTS) {
    316        /* Hit the maximum allowed, so don't use a cache (there are
    317         * too many objects to make caching worthwhile, presumably, if
    318         * the token can handle that many objects, it can handle searching.
    319         */
    320        *doObjects = PR_FALSE;
    321        *status = PR_FAILURE;
    322        *numObjects = 0;
    323    } else {
    324        rvOandA = nss_ZNEWARRAY(NULL,
    325                                nssCryptokiObjectAndAttributes *,
    326                                *numObjects + 1);
    327        *status = rvOandA ? PR_SUCCESS : PR_FAILURE;
    328    }
    329    return rvOandA;
    330 }
    331 
    332 static nssCryptokiObjectAndAttributes *
    333 create_object(
    334    nssCryptokiObject *object,
    335    const CK_ATTRIBUTE_TYPE *types,
    336    PRUint32 numTypes,
    337    PRStatus *status)
    338 {
    339    PRUint32 j;
    340    NSSArena *arena = NULL;
    341    NSSSlot *slot = NULL;
    342    nssSession *session = NULL;
    343    nssCryptokiObjectAndAttributes *rvCachedObject = NULL;
    344 
    345    slot = nssToken_GetSlot(object->token);
    346    if (!slot) {
    347        nss_SetError(NSS_ERROR_INVALID_POINTER);
    348        goto loser;
    349    }
    350    session = nssToken_GetDefaultSession(object->token);
    351    if (!session) {
    352        nss_SetError(NSS_ERROR_INVALID_POINTER);
    353        goto loser;
    354    }
    355    arena = nssArena_Create();
    356    if (!arena) {
    357        goto loser;
    358    }
    359    rvCachedObject = nss_ZNEW(arena, nssCryptokiObjectAndAttributes);
    360    if (!rvCachedObject) {
    361        goto loser;
    362    }
    363    rvCachedObject->arena = arena;
    364    /* The cache is tied to the token, and therefore the objects
    365     * in it should not hold references to the token.
    366     */
    367    (void)nssToken_Destroy(object->token);
    368    rvCachedObject->object = object;
    369    rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes);
    370    if (!rvCachedObject->attributes) {
    371        goto loser;
    372    }
    373    for (j = 0; j < numTypes; j++) {
    374        rvCachedObject->attributes[j].type = types[j];
    375    }
    376    *status = nssCKObject_GetAttributes(object->handle,
    377                                        rvCachedObject->attributes,
    378                                        numTypes,
    379                                        arena,
    380                                        session,
    381                                        slot);
    382    if (*status != PR_SUCCESS) {
    383        goto loser;
    384    }
    385    rvCachedObject->numAttributes = numTypes;
    386    *status = PR_SUCCESS;
    387    nssSlot_Destroy(slot);
    388 
    389    return rvCachedObject;
    390 loser:
    391    *status = PR_FAILURE;
    392    if (slot) {
    393        nssSlot_Destroy(slot);
    394    }
    395    if (arena)
    396        nssArena_Destroy(arena);
    397    return (nssCryptokiObjectAndAttributes *)NULL;
    398 }
    399 
    400 /*
    401 *
    402 * State diagram for cache:
    403 *
    404 *            token !present            token removed
    405 *        +-------------------------+<----------------------+
    406 *        |                         ^                       |
    407 *        v                         |                       |
    408 *  +----------+   slot friendly    |  token present   +----------+
    409 *  |   cache  | -----------------> % ---------------> |   cache  |
    410 *  | unloaded |                                       |  loaded  |
    411 *  +----------+                                       +----------+
    412 *    ^   |                                                 ^   |
    413 *    |   |   slot !friendly           slot logged in       |   |
    414 *    |   +-----------------------> % ----------------------+   |
    415 *    |                             |                           |
    416 *    | slot logged out             v  slot !friendly           |
    417 *    +-----------------------------+<--------------------------+
    418 *
    419 */
    420 
    421 /* This function must not be called with cache->lock locked. */
    422 static PRBool
    423 token_is_present(
    424    nssTokenObjectCache *cache)
    425 {
    426    NSSSlot *slot = nssToken_GetSlot(cache->token);
    427    PRBool tokenPresent = nssSlot_IsTokenPresent(slot);
    428    nssSlot_Destroy(slot);
    429    return tokenPresent;
    430 }
    431 
    432 static PRBool
    433 search_for_objects(
    434    nssTokenObjectCache *cache)
    435 {
    436    PRBool doSearch = PR_FALSE;
    437    NSSSlot *slot = nssToken_GetSlot(cache->token);
    438    /* Handle non-friendly slots (slots which require login for objects) */
    439    if (!nssSlot_IsFriendly(slot)) {
    440        if (nssSlot_IsLoggedIn(slot)) {
    441            /* Either no state change, or went from !logged in -> logged in */
    442            cache->loggedIn = PR_TRUE;
    443            doSearch = PR_TRUE;
    444        } else {
    445            if (cache->loggedIn) {
    446                /* went from logged in -> !logged in, destroy cached objects */
    447                clear_cache(cache);
    448                cache->loggedIn = PR_FALSE;
    449            } /* else no state change, still not logged in, so exit */
    450        }
    451    } else {
    452        /* slot is friendly, thus always available for search */
    453        doSearch = PR_TRUE;
    454    }
    455    nssSlot_Destroy(slot);
    456    return doSearch;
    457 }
    458 
    459 static nssCryptokiObjectAndAttributes *
    460 create_cert(
    461    nssCryptokiObject *object,
    462    PRStatus *status)
    463 {
    464    static const CK_ATTRIBUTE_TYPE certAttr[] = {
    465        CKA_CLASS,
    466        CKA_TOKEN,
    467        CKA_LABEL,
    468        CKA_CERTIFICATE_TYPE,
    469        CKA_ID,
    470        CKA_VALUE,
    471        CKA_ISSUER,
    472        CKA_SERIAL_NUMBER,
    473        CKA_SUBJECT,
    474        CKA_NSS_EMAIL
    475    };
    476    static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]);
    477    return create_object(object, certAttr, numCertAttr, status);
    478 }
    479 
    480 static nssCryptokiObjectAndAttributes *
    481 create_trust(
    482    nssCryptokiObject *object,
    483    PRStatus *status)
    484 {
    485    static const CK_ATTRIBUTE_TYPE nssTrustAttr[] = {
    486        CKA_CLASS,
    487        CKA_TOKEN,
    488        CKA_LABEL,
    489        CKA_NSS_CERT_SHA1_HASH,
    490        CKA_NSS_CERT_MD5_HASH,
    491        CKA_ISSUER,
    492        CKA_SUBJECT,
    493        CKA_NSS_TRUST_SERVER_AUTH,
    494        CKA_NSS_TRUST_CLIENT_AUTH,
    495        CKA_NSS_TRUST_EMAIL_PROTECTION,
    496        CKA_NSS_TRUST_CODE_SIGNING
    497    };
    498    static const CK_ATTRIBUTE_TYPE pkcsTrustAttr[] = {
    499        CKA_CLASS,
    500        CKA_TOKEN,
    501        CKA_LABEL,
    502        CKA_HASH_OF_CERTIFICATE,
    503        CKA_NAME_HASH_ALGORITHM,
    504        CKA_ISSUER,
    505        CKA_SUBJECT,
    506        CKA_PKCS_TRUST_SERVER_AUTH,
    507        CKA_PKCS_TRUST_CLIENT_AUTH,
    508        CKA_PKCS_TRUST_EMAIL_PROTECTION,
    509        CKA_PKCS_TRUST_CODE_SIGNING
    510    };
    511    static const PRUint32 numNSSTrustAttr = PR_ARRAY_SIZE(nssTrustAttr);
    512    static const PRUint32 numPKCSTrustAttr = PR_ARRAY_SIZE(pkcsTrustAttr);
    513    const CK_ATTRIBUTE_TYPE *trustAttr;
    514    PRUint32 numTrustAttr;
    515 
    516    trustAttr = (object->trustType == CKO_TRUST) ? pkcsTrustAttr
    517                                                 : nssTrustAttr;
    518    numTrustAttr = (object->trustType == CKO_TRUST) ? numPKCSTrustAttr
    519                                                    : numNSSTrustAttr;
    520    return create_object(object, trustAttr, numTrustAttr, status);
    521 }
    522 
    523 static nssCryptokiObjectAndAttributes *
    524 create_crl(
    525    nssCryptokiObject *object,
    526    PRStatus *status)
    527 {
    528    static const CK_ATTRIBUTE_TYPE crlAttr[] = {
    529        CKA_CLASS,
    530        CKA_TOKEN,
    531        CKA_LABEL,
    532        CKA_VALUE,
    533        CKA_SUBJECT,
    534        CKA_NSS_KRL,
    535        CKA_NSS_URL
    536    };
    537    static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]);
    538    return create_object(object, crlAttr, numCRLAttr, status);
    539 }
    540 
    541 /* Dispatch to the create function for the object type */
    542 static nssCryptokiObjectAndAttributes *
    543 create_object_of_type(
    544    nssCryptokiObject *object,
    545    PRUint32 objectType,
    546    PRStatus *status)
    547 {
    548    if (objectType == cachedCerts) {
    549        return create_cert(object, status);
    550    }
    551    if (objectType == cachedTrust) {
    552        return create_trust(object, status);
    553    }
    554    if (objectType == cachedCRLs) {
    555        return create_crl(object, status);
    556    }
    557    return (nssCryptokiObjectAndAttributes *)NULL;
    558 }
    559 
    560 static PRStatus
    561 get_token_objects_for_cache(
    562    nssTokenObjectCache *cache,
    563    PRUint32 objectType,
    564    CK_OBJECT_CLASS objclass)
    565 {
    566    PRStatus status;
    567    nssCryptokiObject **objects;
    568    PRBool *doIt = &cache->doObjectType[objectType];
    569    PRUint32 i, numObjects;
    570 
    571    if (!search_for_objects(cache) ||
    572        cache->searchedObjectType[objectType] ||
    573        !cache->doObjectType[objectType]) {
    574        /* Either there was a state change that prevents a search
    575         * (token logged out), or the search was already done,
    576         * or objects of this type are not being cached.
    577         */
    578        return PR_SUCCESS;
    579    }
    580    objects = nssToken_FindObjects(cache->token, NULL, objclass,
    581                                   nssTokenSearchType_TokenForced,
    582                                   MAX_LOCAL_CACHE_OBJECTS, &status);
    583    if (status != PR_SUCCESS) {
    584        return status;
    585    }
    586    cache->objects[objectType] = create_object_array(objects,
    587                                                     doIt,
    588                                                     &numObjects,
    589                                                     &status);
    590    if (status != PR_SUCCESS) {
    591        nssCryptokiObjectArray_Destroy(objects);
    592        return status;
    593    }
    594    for (i = 0; i < numObjects; i++) {
    595        cache->objects[objectType][i] = create_object_of_type(objects[i],
    596                                                              objectType,
    597                                                              &status);
    598        if (status != PR_SUCCESS) {
    599            break;
    600        }
    601    }
    602    if (status == PR_SUCCESS) {
    603        nss_ZFreeIf(objects);
    604    } else {
    605        PRUint32 j;
    606        for (j = 0; j < i; j++) {
    607            /* Objects that were successfully added to the cache do not own a
    608             * token reference (they share a reference with the cache itself).
    609             * Nulling out the pointer here prevents the token's refcount
    610             * from being decremented in nssCryptokiObject_Destroy */
    611            cache->objects[objectType][j]->object->token = NULL;
    612            nssArena_Destroy(cache->objects[objectType][j]->arena);
    613        }
    614        nss_ZFreeIf(cache->objects[objectType]);
    615        cache->objects[objectType] = NULL;
    616        nssCryptokiObjectArray_Destroy(objects);
    617    }
    618    cache->searchedObjectType[objectType] = PR_TRUE;
    619    return status;
    620 }
    621 
    622 static CK_ATTRIBUTE_PTR
    623 find_attribute_in_object(
    624    nssCryptokiObjectAndAttributes *obj,
    625    CK_ATTRIBUTE_TYPE attrType)
    626 {
    627    PRUint32 j;
    628    for (j = 0; j < obj->numAttributes; j++) {
    629        if (attrType == obj->attributes[j].type) {
    630            return &obj->attributes[j];
    631        }
    632    }
    633    return (CK_ATTRIBUTE_PTR)NULL;
    634 }
    635 
    636 /* Find all objects in the array that match the supplied template */
    637 static nssCryptokiObject **
    638 find_objects_in_array(
    639    nssCryptokiObjectAndAttributes **objArray,
    640    CK_ATTRIBUTE_PTR ot,
    641    CK_ULONG otlen,
    642    PRUint32 maximumOpt)
    643 {
    644    PRIntn oi = 0;
    645    PRUint32 i;
    646    NSSArena *arena;
    647    PRUint32 size = 8;
    648    PRUint32 numMatches = 0;
    649    nssCryptokiObject **objects = NULL;
    650    nssCryptokiObjectAndAttributes **matches = NULL;
    651    CK_ATTRIBUTE_PTR attr;
    652 
    653    if (!objArray) {
    654        return (nssCryptokiObject **)NULL;
    655    }
    656    arena = nssArena_Create();
    657    if (!arena) {
    658        return (nssCryptokiObject **)NULL;
    659    }
    660    matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size);
    661    if (!matches) {
    662        goto loser;
    663    }
    664    if (maximumOpt == 0)
    665        maximumOpt = ~0;
    666    /* loop over the cached objects */
    667    for (; *objArray && numMatches < maximumOpt; objArray++) {
    668        nssCryptokiObjectAndAttributes *obj = *objArray;
    669        /* loop over the test template */
    670        for (i = 0; i < otlen; i++) {
    671            /* see if the object has the attribute */
    672            attr = find_attribute_in_object(obj, ot[i].type);
    673            if (!attr) {
    674                /* nope, match failed */
    675                break;
    676            }
    677            /* compare the attribute against the test value */
    678            if (ot[i].ulValueLen != attr->ulValueLen ||
    679                !nsslibc_memequal(ot[i].pValue,
    680                                  attr->pValue,
    681                                  attr->ulValueLen, NULL)) {
    682                /* nope, match failed */
    683                break;
    684            }
    685        }
    686        if (i == otlen) {
    687            /* all of the attributes in the test template were found
    688             * in the object's template, and they all matched
    689             */
    690            matches[numMatches++] = obj;
    691            if (numMatches == size) {
    692                size *= 2;
    693                matches = nss_ZREALLOCARRAY(matches,
    694                                            nssCryptokiObjectAndAttributes *,
    695                                            size);
    696                if (!matches) {
    697                    goto loser;
    698                }
    699            }
    700        }
    701    }
    702    if (numMatches > 0) {
    703        objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1);
    704        if (!objects) {
    705            goto loser;
    706        }
    707        for (oi = 0; oi < (PRIntn)numMatches; oi++) {
    708            objects[oi] = nssCryptokiObject_Clone(matches[oi]->object);
    709            if (!objects[oi]) {
    710                goto loser;
    711            }
    712        }
    713    }
    714    nssArena_Destroy(arena);
    715    return objects;
    716 loser:
    717    nssCryptokiObjectArray_Destroy(objects);
    718    nssArena_Destroy(arena);
    719    return (nssCryptokiObject **)NULL;
    720 }
    721 
    722 NSS_IMPLEMENT nssCryptokiObject **
    723 nssTokenObjectCache_FindObjectsByTemplate(
    724    nssTokenObjectCache *cache,
    725    CK_OBJECT_CLASS objclass,
    726    CK_ATTRIBUTE_PTR otemplate,
    727    CK_ULONG otlen,
    728    PRUint32 maximumOpt,
    729    PRStatus *statusOpt)
    730 {
    731    PRStatus status = PR_FAILURE;
    732    nssCryptokiObject **rvObjects = NULL;
    733    PRUint32 objectType;
    734    if (!token_is_present(cache)) {
    735        status = PR_SUCCESS;
    736        goto finish;
    737    }
    738    switch (objclass) {
    739        case CKO_CERTIFICATE:
    740            objectType = cachedCerts;
    741            break;
    742        case CKO_NSS_TRUST:
    743        case CKO_TRUST:
    744            objectType = cachedTrust;
    745            break;
    746        case CKO_NSS_CRL:
    747            objectType = cachedCRLs;
    748            break;
    749        default:
    750            goto finish;
    751    }
    752    PZ_Lock(cache->lock);
    753    if (cache->doObjectType[objectType]) {
    754        status = get_token_objects_for_cache(cache, objectType, objclass);
    755        if (status == PR_SUCCESS) {
    756            rvObjects = find_objects_in_array(cache->objects[objectType],
    757                                              otemplate, otlen, maximumOpt);
    758        }
    759    }
    760    PZ_Unlock(cache->lock);
    761 finish:
    762    if (statusOpt) {
    763        *statusOpt = status;
    764    }
    765    return rvObjects;
    766 }
    767 
    768 static PRBool
    769 cache_available_for_object_type(
    770    nssTokenObjectCache *cache,
    771    PRUint32 objectType)
    772 {
    773    if (!cache->doObjectType[objectType]) {
    774        /* not caching this object kind */
    775        return PR_FALSE;
    776    }
    777    if (!cache->searchedObjectType[objectType]) {
    778        /* objects are not cached yet */
    779        return PR_FALSE;
    780    }
    781    if (!search_for_objects(cache)) {
    782        /* not logged in */
    783        return PR_FALSE;
    784    }
    785    return PR_TRUE;
    786 }
    787 
    788 NSS_IMPLEMENT PRStatus
    789 nssTokenObjectCache_GetObjectAttributes(
    790    nssTokenObjectCache *cache,
    791    NSSArena *arenaOpt,
    792    nssCryptokiObject *object,
    793    CK_OBJECT_CLASS objclass,
    794    CK_ATTRIBUTE_PTR atemplate,
    795    CK_ULONG atlen)
    796 {
    797    PRUint32 i, j;
    798    NSSArena *arena = NULL;
    799    nssArenaMark *mark = NULL;
    800    nssCryptokiObjectAndAttributes *cachedOA = NULL;
    801    nssCryptokiObjectAndAttributes **oa = NULL;
    802    PRUint32 objectType;
    803    if (!token_is_present(cache)) {
    804        return PR_FAILURE;
    805    }
    806    PZ_Lock(cache->lock);
    807    switch (objclass) {
    808        case CKO_CERTIFICATE:
    809            objectType = cachedCerts;
    810            break;
    811        case CKO_NSS_TRUST:
    812        case CKO_TRUST:
    813            objectType = cachedTrust;
    814            break;
    815        case CKO_NSS_CRL:
    816            objectType = cachedCRLs;
    817            break;
    818        default:
    819            goto loser;
    820    }
    821    if (!cache_available_for_object_type(cache, objectType)) {
    822        goto loser;
    823    }
    824    oa = cache->objects[objectType];
    825    if (!oa) {
    826        goto loser;
    827    }
    828    for (; *oa; oa++) {
    829        if (nssCryptokiObject_Equal((*oa)->object, object)) {
    830            cachedOA = *oa;
    831            break;
    832        }
    833    }
    834    if (!cachedOA) {
    835        goto loser; /* don't have this object */
    836    }
    837    if (arenaOpt) {
    838        arena = arenaOpt;
    839        mark = nssArena_Mark(arena);
    840    }
    841    for (i = 0; i < atlen; i++) {
    842        for (j = 0; j < cachedOA->numAttributes; j++) {
    843            if (atemplate[i].type == cachedOA->attributes[j].type) {
    844                CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j];
    845                if (cachedOA->attributes[j].ulValueLen == 0 ||
    846                    cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) {
    847                    break; /* invalid attribute */
    848                }
    849                if (atemplate[i].ulValueLen > 0) {
    850                    if (atemplate[i].pValue == NULL ||
    851                        atemplate[i].ulValueLen < attr->ulValueLen) {
    852                        goto loser;
    853                    }
    854                } else {
    855                    atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen);
    856                    if (!atemplate[i].pValue) {
    857                        goto loser;
    858                    }
    859                }
    860                nsslibc_memcpy(atemplate[i].pValue,
    861                               attr->pValue, attr->ulValueLen);
    862                atemplate[i].ulValueLen = attr->ulValueLen;
    863                break;
    864            }
    865        }
    866        if (j == cachedOA->numAttributes) {
    867            atemplate[i].ulValueLen = (CK_ULONG)-1;
    868        }
    869    }
    870    PZ_Unlock(cache->lock);
    871    if (mark) {
    872        nssArena_Unmark(arena, mark);
    873    }
    874    return PR_SUCCESS;
    875 loser:
    876    PZ_Unlock(cache->lock);
    877    if (mark) {
    878        nssArena_Release(arena, mark);
    879    }
    880    return PR_FAILURE;
    881 }
    882 
    883 NSS_IMPLEMENT PRStatus
    884 nssTokenObjectCache_ImportObject(
    885    nssTokenObjectCache *cache,
    886    nssCryptokiObject *object,
    887    CK_OBJECT_CLASS objclass,
    888    CK_ATTRIBUTE_PTR ot,
    889    CK_ULONG otlen)
    890 {
    891    PRStatus status = PR_SUCCESS;
    892    PRUint32 count;
    893    nssCryptokiObjectAndAttributes **oa, ***otype;
    894    PRUint32 objectType;
    895    PRBool haveIt = PR_FALSE;
    896 
    897    if (!token_is_present(cache)) {
    898        return PR_SUCCESS; /* cache not active, ignored */
    899    }
    900    PZ_Lock(cache->lock);
    901    switch (objclass) {
    902        case CKO_CERTIFICATE:
    903            objectType = cachedCerts;
    904            break;
    905        case CKO_NSS_TRUST:
    906        case CKO_TRUST:
    907            objectType = cachedTrust;
    908            object->trustType = objclass;
    909            break;
    910        case CKO_NSS_CRL:
    911            objectType = cachedCRLs;
    912            break;
    913        default:
    914            PZ_Unlock(cache->lock);
    915            return PR_SUCCESS; /* don't need to import it here */
    916    }
    917    if (!cache_available_for_object_type(cache, objectType)) {
    918        PZ_Unlock(cache->lock);
    919        return PR_SUCCESS; /* cache not active, ignored */
    920    }
    921    count = 0;
    922    otype = &cache->objects[objectType]; /* index into array of types */
    923    oa = *otype;                         /* the array of objects for this type */
    924    while (oa && *oa) {
    925        if (nssCryptokiObject_Equal((*oa)->object, object)) {
    926            haveIt = PR_TRUE;
    927            break;
    928        }
    929        count++;
    930        oa++;
    931    }
    932    if (haveIt) {
    933        /* Destroy the old entry */
    934        (*oa)->object->token = NULL;
    935        nssCryptokiObject_Destroy((*oa)->object);
    936        nssArena_Destroy((*oa)->arena);
    937    } else {
    938        /* Create space for a new entry */
    939        if (count > 0) {
    940            *otype = nss_ZREALLOCARRAY(*otype,
    941                                       nssCryptokiObjectAndAttributes *,
    942                                       count + 2);
    943        } else {
    944            *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2);
    945        }
    946    }
    947    if (*otype) {
    948        nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object);
    949        (*otype)[count] = create_object_of_type(copyObject, objectType,
    950                                                &status);
    951    } else {
    952        status = PR_FAILURE;
    953    }
    954    PZ_Unlock(cache->lock);
    955    return status;
    956 }
    957 
    958 NSS_IMPLEMENT void
    959 nssTokenObjectCache_RemoveObject(
    960    nssTokenObjectCache *cache,
    961    nssCryptokiObject *object)
    962 {
    963    PRUint32 oType;
    964    nssCryptokiObjectAndAttributes **oa, **swp = NULL;
    965    if (!token_is_present(cache)) {
    966        return;
    967    }
    968    PZ_Lock(cache->lock);
    969    for (oType = 0; oType < 3; oType++) {
    970        if (!cache_available_for_object_type(cache, oType) ||
    971            !cache->objects[oType]) {
    972            continue;
    973        }
    974        for (oa = cache->objects[oType]; *oa; oa++) {
    975            if (nssCryptokiObject_Equal((*oa)->object, object)) {
    976                swp = oa; /* the entry to remove */
    977                while (oa[1])
    978                    oa++; /* go to the tail */
    979                (*swp)->object->token = NULL;
    980                nssCryptokiObject_Destroy((*swp)->object);
    981                nssArena_Destroy((*swp)->arena); /* destroy it */
    982                *swp = *oa;                      /* swap the last with the removed */
    983                *oa = NULL;                      /* null-terminate the array */
    984                break;
    985            }
    986        }
    987        if (swp) {
    988            break;
    989        }
    990    }
    991    if ((oType < 3) &&
    992        cache->objects[oType] && cache->objects[oType][0] == NULL) {
    993        nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */
    994        cache->objects[oType] = NULL;
    995    }
    996    PZ_Unlock(cache->lock);
    997 }
    998 
    999 /* We need a general hash to support CKO_TRUST
   1000 ** Replace the algorithm specific version used for
   1001 ** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes.
   1002 ** CKA_HASH_OF_CERTIFICATE uses the mechanism specified
   1003 ** in CKA_NAME_HASH_ALGORITHM, with can be passed to this
   1004 ** function.
   1005 */
   1006 /* XXX of course this doesn't belong here */
   1007 NSS_IMPLEMENT NSSAlgorithmAndParameters *
   1008 NSSAlgorithmAndParameters_CreateDigest(
   1009    NSSArena *arenaOpt, CK_MECHANISM_TYPE hashMech)
   1010 {
   1011    NSSAlgorithmAndParameters *rvAP = NULL;
   1012    rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
   1013    if (rvAP) {
   1014        rvAP->mechanism.mechanism = hashMech;
   1015        rvAP->mechanism.pParameter = NULL;
   1016        rvAP->mechanism.ulParameterLen = 0;
   1017    }
   1018    return rvAP;
   1019 }
   1020 
   1021 /*
   1022 * we need a DigestBuf for both create and verify trust objects.
   1023 * So put it here for now. We don't have any Stan based crypto operations
   1024 * yet.
   1025 */
   1026 NSS_IMPLEMENT PRStatus
   1027 NSSAlgorithm_DigestBuf(CK_MECHANISM_TYPE type, NSSItem *input, NSSItem *output)
   1028 {
   1029    PRStatus ret = PR_FAILURE;
   1030    NSSAlgorithmAndParameters *ap = NULL;
   1031    PK11SlotInfo *internal = NULL;
   1032    NSSToken *token = NULL;
   1033    NSSItem *dummy = NULL;
   1034 
   1035    internal = PK11_GetInternalSlot();
   1036    if (!internal) {
   1037        goto done;
   1038    }
   1039    token = PK11Slot_GetNSSToken(internal);
   1040    if (!token) {
   1041        goto done;
   1042    }
   1043    ap = NSSAlgorithmAndParameters_CreateDigest(NULL, type);
   1044    if (!token) {
   1045        goto done;
   1046    }
   1047 
   1048    dummy = nssToken_Digest(token, NULL, ap, input, output, NULL);
   1049    if (dummy) {
   1050        ret = PR_SUCCESS;
   1051    }
   1052 
   1053 done:
   1054    nss_ZFreeIf(ap);
   1055    if (token) {
   1056        (void)nssToken_Destroy(token);
   1057    }
   1058    if (internal) {
   1059        PK11_FreeSlot(internal);
   1060    }
   1061    return ret;
   1062 }