tor-browser

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

lgfind.c (30448B)


      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 "secitem.h"
      5 #include "pkcs11.h"
      6 #include "lgdb.h"
      7 #include "lowkeyi.h"
      8 #include "pcert.h"
      9 #include "blapi.h"
     10 
     11 #include "keydbi.h"
     12 
     13 /*
     14 * This code maps PKCS #11 Finds to legacy database searches. This code
     15 * was orginally in pkcs11.c in previous versions of NSS.
     16 */
     17 
     18 struct SDBFindStr {
     19    CK_OBJECT_HANDLE *handles;
     20    int size;
     21    int index;
     22    int array_size;
     23 };
     24 
     25 /*
     26 * free a search structure
     27 */
     28 void
     29 lg_FreeSearch(SDBFind *search)
     30 {
     31    if (search->handles) {
     32        PORT_Free(search->handles);
     33    }
     34    PORT_Free(search);
     35 }
     36 
     37 void
     38 lg_addHandle(SDBFind *search, CK_OBJECT_HANDLE handle)
     39 {
     40    if (search->handles == NULL) {
     41        return;
     42    }
     43    if (search->size >= search->array_size) {
     44        search->array_size += LG_SEARCH_BLOCK_SIZE;
     45        search->handles = (CK_OBJECT_HANDLE *)PORT_Realloc(search->handles,
     46                                                           sizeof(CK_OBJECT_HANDLE) * search->array_size);
     47        if (search->handles == NULL) {
     48            return;
     49        }
     50    }
     51    search->handles[search->size] = handle;
     52    search->size++;
     53 }
     54 
     55 /*
     56 * find any certs that may match the template and load them.
     57 */
     58 #define LG_CERT 0x00000001
     59 #define LG_TRUST 0x00000002
     60 #define LG_CRL 0x00000004
     61 #define LG_SMIME 0x00000008
     62 #define LG_PRIVATE 0x00000010
     63 #define LG_PUBLIC 0x00000020
     64 #define LG_KEY 0x00000040
     65 #define LG_NSS_TRUST 0x00000080
     66 
     67 /*
     68 * structure to collect key handles.
     69 */
     70 typedef struct lgEntryDataStr {
     71    SDB *sdb;
     72    SDBFind *searchHandles;
     73    const CK_ATTRIBUTE *template;
     74    CK_ULONG templ_count;
     75 } lgEntryData;
     76 
     77 static SECStatus
     78 lg_crl_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg)
     79 {
     80    lgEntryData *crlData;
     81    CK_OBJECT_HANDLE class_handle;
     82    SDB *sdb;
     83 
     84    crlData = (lgEntryData *)arg;
     85    sdb = crlData->sdb;
     86 
     87    class_handle = (type == certDBEntryTypeRevocation) ? LG_TOKEN_TYPE_CRL : LG_TOKEN_KRL_HANDLE;
     88    if (lg_tokenMatch(sdb, key, class_handle,
     89                      crlData->template, crlData->templ_count)) {
     90        lg_addHandle(crlData->searchHandles,
     91                     lg_mkHandle(sdb, key, class_handle));
     92    }
     93    return (SECSuccess);
     94 }
     95 
     96 static void
     97 lg_searchCrls(SDB *sdb, SECItem *derSubject, PRBool isKrl,
     98              unsigned long classFlags, SDBFind *search,
     99              const CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
    100 {
    101    NSSLOWCERTCertDBHandle *certHandle = NULL;
    102 
    103    certHandle = lg_getCertDB(sdb);
    104    if (certHandle == NULL) {
    105        return;
    106    }
    107    if (derSubject->data != NULL) {
    108        certDBEntryRevocation *crl =
    109            nsslowcert_FindCrlByKey(certHandle, derSubject, isKrl);
    110 
    111        if (crl != NULL) {
    112            lg_addHandle(search, lg_mkHandle(sdb, derSubject,
    113                                             isKrl ? LG_TOKEN_KRL_HANDLE : LG_TOKEN_TYPE_CRL));
    114            nsslowcert_DestroyDBEntry((certDBEntry *)crl);
    115        }
    116    } else {
    117        lgEntryData crlData;
    118 
    119        /* traverse */
    120        crlData.sdb = sdb;
    121        crlData.searchHandles = search;
    122        crlData.template = pTemplate;
    123        crlData.templ_count = ulCount;
    124        nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeRevocation,
    125                                     lg_crl_collect, (void *)&crlData);
    126        nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeKeyRevocation,
    127                                     lg_crl_collect, (void *)&crlData);
    128    }
    129 }
    130 
    131 /*
    132 * structure to collect key handles.
    133 */
    134 typedef struct lgKeyDataStr {
    135    SDB *sdb;
    136    NSSLOWKEYDBHandle *keyHandle;
    137    SDBFind *searchHandles;
    138    SECItem *id;
    139    const CK_ATTRIBUTE *template;
    140    CK_ULONG templ_count;
    141    unsigned long classFlags;
    142    PRBool strict;
    143 } lgKeyData;
    144 
    145 static PRBool
    146 isSecretKey(NSSLOWKEYPrivateKey *privKey)
    147 {
    148    if (privKey->keyType == NSSLOWKEYRSAKey &&
    149        privKey->u.rsa.publicExponent.len == 1 &&
    150        privKey->u.rsa.publicExponent.data[0] == 0)
    151        return PR_TRUE;
    152 
    153    return PR_FALSE;
    154 }
    155 
    156 static SECStatus
    157 lg_key_collect(DBT *key, DBT *data, void *arg)
    158 {
    159    lgKeyData *keyData;
    160    NSSLOWKEYPrivateKey *privKey = NULL;
    161    SECItem tmpDBKey;
    162    SDB *sdb;
    163    unsigned long classFlags;
    164 
    165    keyData = (lgKeyData *)arg;
    166    sdb = keyData->sdb;
    167    classFlags = keyData->classFlags;
    168 
    169    tmpDBKey.data = key->data;
    170    tmpDBKey.len = key->size;
    171    tmpDBKey.type = siBuffer;
    172 
    173    PORT_Assert(keyData->keyHandle);
    174    if (!keyData->strict && keyData->id && keyData->id->data) {
    175        SECItem result;
    176        PRBool haveMatch = PR_FALSE;
    177        unsigned char hashKey[SHA1_LENGTH];
    178        result.data = hashKey;
    179        result.len = sizeof(hashKey);
    180 
    181        if (keyData->id->len == 0) {
    182            /* Make sure this isn't a LG_KEY */
    183            privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle,
    184                                                   &tmpDBKey, keyData->sdb /*->password*/);
    185            if (privKey) {
    186                /* turn off the unneeded class flags */
    187                classFlags &= isSecretKey(privKey) ? ~(LG_PRIVATE | LG_PUBLIC) : ~LG_KEY;
    188                haveMatch = (PRBool)((classFlags & (LG_KEY | LG_PRIVATE | LG_PUBLIC)) != 0);
    189                lg_nsslowkey_DestroyPrivateKey(privKey);
    190            }
    191        } else {
    192            SHA1_HashBuf(hashKey, key->data, key->size); /* match id */
    193            haveMatch = SECITEM_ItemsAreEqual(keyData->id, &result);
    194            if (!haveMatch && ((unsigned char *)key->data)[0] == 0) {
    195                /* This is a fix for backwards compatibility.  The key
    196                 * database indexes private keys by the public key, and
    197                 * versions of NSS prior to 3.4 stored the public key as
    198                 * a signed integer.  The public key is now treated as an
    199                 * unsigned integer, with no leading zero.  In order to
    200                 * correctly compute the hash of an old key, it is necessary
    201                 * to fallback and detect the leading zero.
    202                 */
    203                SHA1_HashBuf(hashKey,
    204                             (unsigned char *)key->data + 1, key->size - 1);
    205                haveMatch = SECITEM_ItemsAreEqual(keyData->id, &result);
    206            }
    207        }
    208        if (haveMatch) {
    209            if (classFlags & LG_PRIVATE) {
    210                lg_addHandle(keyData->searchHandles,
    211                             lg_mkHandle(sdb, &tmpDBKey, LG_TOKEN_TYPE_PRIV));
    212            }
    213            if (classFlags & LG_PUBLIC) {
    214                lg_addHandle(keyData->searchHandles,
    215                             lg_mkHandle(sdb, &tmpDBKey, LG_TOKEN_TYPE_PUB));
    216            }
    217            if (classFlags & LG_KEY) {
    218                lg_addHandle(keyData->searchHandles,
    219                             lg_mkHandle(sdb, &tmpDBKey, LG_TOKEN_TYPE_KEY));
    220            }
    221        }
    222        return SECSuccess;
    223    }
    224 
    225    privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, &tmpDBKey,
    226                                           keyData->sdb /*->password*/);
    227    if (privKey == NULL) {
    228        goto loser;
    229    }
    230 
    231    if (isSecretKey(privKey)) {
    232        if ((classFlags & LG_KEY) &&
    233            lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_KEY,
    234                          keyData->template, keyData->templ_count)) {
    235            lg_addHandle(keyData->searchHandles,
    236                         lg_mkHandle(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_KEY));
    237        }
    238    } else {
    239        if ((classFlags & LG_PRIVATE) &&
    240            lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PRIV,
    241                          keyData->template, keyData->templ_count)) {
    242            lg_addHandle(keyData->searchHandles,
    243                         lg_mkHandle(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PRIV));
    244        }
    245        if ((classFlags & LG_PUBLIC) &&
    246            lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PUB,
    247                          keyData->template, keyData->templ_count)) {
    248            lg_addHandle(keyData->searchHandles,
    249                         lg_mkHandle(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PUB));
    250        }
    251    }
    252 
    253 loser:
    254    if (privKey) {
    255        lg_nsslowkey_DestroyPrivateKey(privKey);
    256    }
    257    return (SECSuccess);
    258 }
    259 
    260 static void
    261 lg_searchKeys(SDB *sdb, SECItem *key_id,
    262              unsigned long classFlags, SDBFind *search, PRBool mustStrict,
    263              const CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
    264 {
    265    NSSLOWKEYDBHandle *keyHandle = NULL;
    266    NSSLOWKEYPrivateKey *privKey;
    267    lgKeyData keyData;
    268    PRBool found = PR_FALSE;
    269 
    270    keyHandle = lg_getKeyDB(sdb);
    271    if (keyHandle == NULL) {
    272        return;
    273    }
    274 
    275    if (key_id->data) {
    276        privKey = nsslowkey_FindKeyByPublicKey(keyHandle, key_id, sdb);
    277        if (privKey) {
    278            if ((classFlags & LG_KEY) && isSecretKey(privKey)) {
    279                lg_addHandle(search,
    280                             lg_mkHandle(sdb, key_id, LG_TOKEN_TYPE_KEY));
    281                found = PR_TRUE;
    282            }
    283            if ((classFlags & LG_PRIVATE) && !isSecretKey(privKey)) {
    284                lg_addHandle(search,
    285                             lg_mkHandle(sdb, key_id, LG_TOKEN_TYPE_PRIV));
    286                found = PR_TRUE;
    287            }
    288            if ((classFlags & LG_PUBLIC) && !isSecretKey(privKey)) {
    289                lg_addHandle(search,
    290                             lg_mkHandle(sdb, key_id, LG_TOKEN_TYPE_PUB));
    291                found = PR_TRUE;
    292            }
    293            lg_nsslowkey_DestroyPrivateKey(privKey);
    294        }
    295        /* don't do the traversal if we have an up to date db */
    296        if (keyHandle->version != 3) {
    297            goto loser;
    298        }
    299        /* don't do the traversal if it can't possibly be the correct id */
    300        /* all soft token id's are SHA1_HASH_LEN's */
    301        if (key_id->len != SHA1_LENGTH) {
    302            goto loser;
    303        }
    304        if (found) {
    305            /* if we already found some keys, don't do the traversal */
    306            goto loser;
    307        }
    308    }
    309    keyData.sdb = sdb;
    310    keyData.keyHandle = keyHandle;
    311    keyData.searchHandles = search;
    312    keyData.id = key_id;
    313    keyData.template = pTemplate;
    314    keyData.templ_count = ulCount;
    315    keyData.classFlags = classFlags;
    316    keyData.strict = mustStrict ? mustStrict : LG_STRICT;
    317 
    318    nsslowkey_TraverseKeys(keyHandle, lg_key_collect, &keyData);
    319 
    320 loser:
    321    return;
    322 }
    323 
    324 /*
    325 * structure to collect certs into
    326 */
    327 typedef struct lgCertDataStr {
    328    SDB *sdb;
    329    int cert_count;
    330    int max_cert_count;
    331    NSSLOWCERTCertificate **certs;
    332    const CK_ATTRIBUTE *template;
    333    CK_ULONG templ_count;
    334    unsigned long classFlags;
    335    PRBool strict;
    336 } lgCertData;
    337 
    338 /*
    339 * collect all the certs from the traverse call.
    340 */
    341 static SECStatus
    342 lg_cert_collect(NSSLOWCERTCertificate *cert, void *arg)
    343 {
    344    lgCertData *cd = (lgCertData *)arg;
    345 
    346    if (cert == NULL) {
    347        return SECSuccess;
    348    }
    349 
    350    if (cd->certs == NULL) {
    351        return SECFailure;
    352    }
    353 
    354    if (cd->strict) {
    355        if ((cd->classFlags & LG_CERT) &&
    356            !lg_tokenMatch(cd->sdb, &cert->certKey, LG_TOKEN_TYPE_CERT, cd->template, cd->templ_count)) {
    357            return SECSuccess;
    358        }
    359        if ((cd->classFlags & LG_TRUST) &&
    360            !lg_tokenMatch(cd->sdb, &cert->certKey, LG_TOKEN_TYPE_TRUST, cd->template, cd->templ_count)) {
    361            return SECSuccess;
    362        }
    363        if ((cd->classFlags & LG_NSS_TRUST) &&
    364            !lg_tokenMatch(cd->sdb, &cert->certKey, LG_TOKEN_TYPE_NSS_TRUST, cd->template, cd->templ_count)) {
    365            return SECSuccess;
    366        }
    367    }
    368 
    369    /* allocate more space if we need it. This should only happen in
    370     * the general traversal case */
    371    if (cd->cert_count >= cd->max_cert_count) {
    372        int size;
    373        cd->max_cert_count += LG_SEARCH_BLOCK_SIZE;
    374        size = cd->max_cert_count * sizeof(NSSLOWCERTCertificate *);
    375        cd->certs = (NSSLOWCERTCertificate **)PORT_Realloc(cd->certs, size);
    376        if (cd->certs == NULL) {
    377            return SECFailure;
    378        }
    379    }
    380 
    381    cd->certs[cd->cert_count++] = nsslowcert_DupCertificate(cert);
    382    return SECSuccess;
    383 }
    384 
    385 /* provide impedence matching ... */
    386 static SECStatus
    387 lg_cert_collect2(NSSLOWCERTCertificate *cert, SECItem *dymmy, void *arg)
    388 {
    389    return lg_cert_collect(cert, arg);
    390 }
    391 
    392 static void
    393 lg_searchSingleCert(lgCertData *certData, NSSLOWCERTCertificate *cert)
    394 {
    395    if (cert == NULL) {
    396        return;
    397    }
    398    if (certData->strict &&
    399        !lg_tokenMatch(certData->sdb, &cert->certKey, LG_TOKEN_TYPE_CERT,
    400                       certData->template, certData->templ_count)) {
    401        nsslowcert_DestroyCertificate(cert);
    402        return;
    403    }
    404    certData->certs = (NSSLOWCERTCertificate **)
    405        PORT_Alloc(sizeof(NSSLOWCERTCertificate *));
    406    if (certData->certs == NULL) {
    407        nsslowcert_DestroyCertificate(cert);
    408        return;
    409    }
    410    certData->certs[0] = cert;
    411    certData->cert_count = 1;
    412 }
    413 
    414 static void
    415 lg_CertSetupData(lgCertData *certData, int count)
    416 {
    417    certData->max_cert_count = count;
    418 
    419    if (certData->max_cert_count <= 0) {
    420        return;
    421    }
    422    certData->certs = (NSSLOWCERTCertificate **)
    423        PORT_Alloc(count * sizeof(NSSLOWCERTCertificate *));
    424    return;
    425 }
    426 
    427 static void
    428 lg_searchCertsAndTrust(SDB *sdb, SECItem *derCert, SECItem *name,
    429                       SECItem *derSubject, NSSLOWCERTIssuerAndSN *issuerSN,
    430                       SECItem *email,
    431                       unsigned long classFlags, SDBFind *handles,
    432                       const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount)
    433 {
    434    NSSLOWCERTCertDBHandle *certHandle = NULL;
    435    lgCertData certData;
    436    int i;
    437 
    438    certHandle = lg_getCertDB(sdb);
    439    if (certHandle == NULL)
    440        return;
    441 
    442    certData.sdb = sdb;
    443    certData.max_cert_count = 0;
    444    certData.certs = NULL;
    445    certData.cert_count = 0;
    446    certData.template = pTemplate;
    447    certData.templ_count = ulCount;
    448    certData.classFlags = classFlags;
    449    certData.strict = LG_STRICT;
    450 
    451    /*
    452     * Find the Cert.
    453     */
    454    if (derCert->data != NULL) {
    455        NSSLOWCERTCertificate *cert =
    456            nsslowcert_FindCertByDERCert(certHandle, derCert);
    457        lg_searchSingleCert(&certData, cert);
    458    } else if (name->data != NULL) {
    459        char *tmp_name = (char *)PORT_Alloc(name->len + 1);
    460        int count;
    461 
    462        if (tmp_name == NULL) {
    463            return;
    464        }
    465        PORT_Memcpy(tmp_name, name->data, name->len);
    466        tmp_name[name->len] = 0;
    467 
    468        count = nsslowcert_NumPermCertsForNickname(certHandle, tmp_name);
    469        lg_CertSetupData(&certData, count);
    470        nsslowcert_TraversePermCertsForNickname(certHandle, tmp_name,
    471                                                lg_cert_collect, &certData);
    472        PORT_Free(tmp_name);
    473    } else if (derSubject->data != NULL) {
    474        int count;
    475 
    476        count = nsslowcert_NumPermCertsForSubject(certHandle, derSubject);
    477        lg_CertSetupData(&certData, count);
    478        nsslowcert_TraversePermCertsForSubject(certHandle, derSubject,
    479                                               lg_cert_collect, &certData);
    480    } else if ((issuerSN->derIssuer.data != NULL) &&
    481               (issuerSN->serialNumber.data != NULL)) {
    482        if (classFlags & LG_CERT) {
    483            NSSLOWCERTCertificate *cert =
    484                nsslowcert_FindCertByIssuerAndSN(certHandle, issuerSN);
    485 
    486            lg_searchSingleCert(&certData, cert);
    487        }
    488        if (classFlags & LG_TRUST) {
    489            NSSLOWCERTTrust *trust =
    490                nsslowcert_FindTrustByIssuerAndSN(certHandle, issuerSN);
    491 
    492            if (trust) {
    493                lg_addHandle(handles,
    494                             lg_mkHandle(sdb, &trust->dbKey, LG_TOKEN_TYPE_TRUST));
    495                nsslowcert_DestroyTrust(trust);
    496            }
    497        }
    498        if (classFlags & LG_NSS_TRUST) {
    499            NSSLOWCERTTrust *trust =
    500                nsslowcert_FindTrustByIssuerAndSN(certHandle, issuerSN);
    501 
    502            if (trust) {
    503                lg_addHandle(handles,
    504                             lg_mkHandle(sdb, &trust->dbKey, LG_TOKEN_TYPE_NSS_TRUST));
    505                nsslowcert_DestroyTrust(trust);
    506            }
    507        }
    508    } else if (email->data != NULL) {
    509        char *tmp_name = (char *)PORT_Alloc(email->len + 1);
    510        certDBEntrySMime *entry = NULL;
    511 
    512        if (tmp_name == NULL) {
    513            return;
    514        }
    515        PORT_Memcpy(tmp_name, email->data, email->len);
    516        tmp_name[email->len] = 0;
    517 
    518        entry = nsslowcert_ReadDBSMimeEntry(certHandle, tmp_name);
    519        if (entry) {
    520            int count;
    521            SECItem *subjectName = &entry->subjectName;
    522 
    523            count = nsslowcert_NumPermCertsForSubject(certHandle, subjectName);
    524            lg_CertSetupData(&certData, count);
    525            nsslowcert_TraversePermCertsForSubject(certHandle, subjectName,
    526                                                   lg_cert_collect, &certData);
    527 
    528            nsslowcert_DestroyDBEntry((certDBEntry *)entry);
    529        }
    530        PORT_Free(tmp_name);
    531    } else {
    532        /* we aren't filtering the certs, we are working on all, so turn
    533         * on the strict filters. */
    534        certData.strict = PR_TRUE;
    535        lg_CertSetupData(&certData, LG_SEARCH_BLOCK_SIZE);
    536        nsslowcert_TraversePermCerts(certHandle, lg_cert_collect2, &certData);
    537    }
    538 
    539    /*
    540     * build the handles
    541     */
    542    for (i = 0; i < certData.cert_count; i++) {
    543        NSSLOWCERTCertificate *cert = certData.certs[i];
    544 
    545        /* if we filtered it would have been on the stuff above */
    546        if (classFlags & LG_CERT) {
    547            lg_addHandle(handles,
    548                         lg_mkHandle(sdb, &cert->certKey, LG_TOKEN_TYPE_CERT));
    549        }
    550        if ((classFlags & LG_TRUST) && nsslowcert_hasTrust(cert->trust)) {
    551            lg_addHandle(handles,
    552                         lg_mkHandle(sdb, &cert->certKey, LG_TOKEN_TYPE_TRUST));
    553        }
    554        if ((classFlags & LG_NSS_TRUST) && nsslowcert_hasTrust(cert->trust)) {
    555            lg_addHandle(handles,
    556                         lg_mkHandle(sdb, &cert->certKey, LG_TOKEN_TYPE_NSS_TRUST));
    557        }
    558        nsslowcert_DestroyCertificate(cert);
    559    }
    560 
    561    if (certData.certs)
    562        PORT_Free(certData.certs);
    563    return;
    564 }
    565 
    566 static SECStatus
    567 lg_smime_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg)
    568 {
    569    lgEntryData *smimeData;
    570    SDB *sdb;
    571 
    572    smimeData = (lgEntryData *)arg;
    573    sdb = smimeData->sdb;
    574 
    575    if (lg_tokenMatch(sdb, key, LG_TOKEN_TYPE_SMIME,
    576                      smimeData->template, smimeData->templ_count)) {
    577        lg_addHandle(smimeData->searchHandles,
    578                     lg_mkHandle(sdb, key, LG_TOKEN_TYPE_SMIME));
    579    }
    580    return (SECSuccess);
    581 }
    582 
    583 static void
    584 lg_searchSMime(SDB *sdb, SECItem *email, SDBFind *handles,
    585               const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount)
    586 {
    587    NSSLOWCERTCertDBHandle *certHandle = NULL;
    588    certDBEntrySMime *entry;
    589 
    590    certHandle = lg_getCertDB(sdb);
    591    if (certHandle == NULL)
    592        return;
    593 
    594    if (email->data != NULL) {
    595        char *tmp_name = (char *)PORT_Alloc(email->len + 1);
    596 
    597        if (tmp_name == NULL) {
    598            return;
    599        }
    600        PORT_Memcpy(tmp_name, email->data, email->len);
    601        tmp_name[email->len] = 0;
    602 
    603        entry = nsslowcert_ReadDBSMimeEntry(certHandle, tmp_name);
    604        if (entry) {
    605            SECItem emailKey;
    606 
    607            emailKey.data = (unsigned char *)tmp_name;
    608            emailKey.len = PORT_Strlen(tmp_name) + 1;
    609            emailKey.type = 0;
    610            lg_addHandle(handles,
    611                         lg_mkHandle(sdb, &emailKey, LG_TOKEN_TYPE_SMIME));
    612            nsslowcert_DestroyDBEntry((certDBEntry *)entry);
    613        }
    614        PORT_Free(tmp_name);
    615    } else {
    616        /* traverse */
    617        lgEntryData smimeData;
    618 
    619        /* traverse */
    620        smimeData.sdb = sdb;
    621        smimeData.searchHandles = handles;
    622        smimeData.template = pTemplate;
    623        smimeData.templ_count = ulCount;
    624        nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeSMimeProfile,
    625                                     lg_smime_collect, (void *)&smimeData);
    626    }
    627    return;
    628 }
    629 
    630 static CK_RV
    631 lg_searchTokenList(SDB *sdb, SDBFind *search,
    632                   const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount)
    633 {
    634    int i;
    635    PRBool isKrl = PR_FALSE;
    636    SECItem derCert = { siBuffer, NULL, 0 };
    637    SECItem derSubject = { siBuffer, NULL, 0 };
    638    SECItem name = { siBuffer, NULL, 0 };
    639    SECItem email = { siBuffer, NULL, 0 };
    640    SECItem key_id = { siBuffer, NULL, 0 };
    641    SECItem cert_sha1_hash = { siBuffer, NULL, 0 };
    642    SECItem cert_md5_hash = { siBuffer, NULL, 0 };
    643    NSSLOWCERTIssuerAndSN issuerSN = {
    644        { siBuffer, NULL, 0 },
    645        { siBuffer, NULL, 0 }
    646    };
    647    SECItem *copy = NULL;
    648    CK_CERTIFICATE_TYPE certType;
    649    CK_OBJECT_CLASS objectClass;
    650    CK_RV crv;
    651    unsigned long classFlags;
    652 
    653    if (lg_getCertDB(sdb) == NULL) {
    654        classFlags = LG_PRIVATE | LG_KEY;
    655    } else {
    656        classFlags = LG_CERT | LG_TRUST | LG_NSS_TRUST | LG_PUBLIC | LG_SMIME | LG_CRL;
    657    }
    658 
    659    /*
    660     * look for things to search on token objects for. If the right options
    661     * are specified, we can use them as direct indeces into the database
    662     * (rather than using linear searches. We can also use the attributes to
    663     * limit the kinds of objects we are searching for. Later we can use this
    664     * array to filter the remaining objects more finely.
    665     */
    666    for (i = 0; classFlags && i < (int)ulCount; i++) {
    667 
    668        switch (pTemplate[i].type) {
    669            case CKA_SUBJECT:
    670                copy = &derSubject;
    671                classFlags &= (LG_CERT | LG_PRIVATE | LG_PUBLIC | LG_SMIME | LG_CRL);
    672                break;
    673            case CKA_ISSUER:
    674                copy = &issuerSN.derIssuer;
    675                classFlags &= (LG_CERT | LG_NSS_TRUST | LG_TRUST);
    676                break;
    677            case CKA_SERIAL_NUMBER:
    678                copy = &issuerSN.serialNumber;
    679                classFlags &= (LG_CERT | LG_NSS_TRUST | LG_TRUST);
    680                break;
    681            case CKA_VALUE:
    682                copy = &derCert;
    683                classFlags &= (LG_CERT | LG_CRL | LG_SMIME);
    684                break;
    685            case CKA_LABEL:
    686                copy = &name;
    687                break;
    688            case CKA_NSS_EMAIL:
    689                copy = &email;
    690                classFlags &= LG_SMIME | LG_CERT;
    691                break;
    692            case CKA_NSS_SMIME_TIMESTAMP:
    693                classFlags &= LG_SMIME;
    694                break;
    695            case CKA_CLASS:
    696                crv = lg_GetULongAttribute(CKA_CLASS, &pTemplate[i], 1, &objectClass);
    697                if (crv != CKR_OK) {
    698                    classFlags = 0;
    699                    break;
    700                }
    701                switch (objectClass) {
    702                    case CKO_CERTIFICATE:
    703                        classFlags &= LG_CERT;
    704                        break;
    705                    case CKO_NSS_TRUST:
    706                        classFlags &= LG_NSS_TRUST;
    707                        break;
    708                    case CKO_TRUST:
    709                        classFlags &= LG_TRUST;
    710                        break;
    711                    case CKO_NSS_CRL:
    712                        classFlags &= LG_CRL;
    713                        break;
    714                    case CKO_NSS_SMIME:
    715                        classFlags &= LG_SMIME;
    716                        break;
    717                    case CKO_PRIVATE_KEY:
    718                        classFlags &= LG_PRIVATE;
    719                        break;
    720                    case CKO_PUBLIC_KEY:
    721                        classFlags &= LG_PUBLIC;
    722                        break;
    723                    case CKO_SECRET_KEY:
    724                        classFlags &= LG_KEY;
    725                        break;
    726                    default:
    727                        classFlags = 0;
    728                        break;
    729                }
    730                break;
    731            case CKA_PRIVATE:
    732                if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
    733                    classFlags = 0;
    734                    break;
    735                }
    736                if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) {
    737                    classFlags &= (LG_PRIVATE | LG_KEY);
    738                } else {
    739                    classFlags &= ~(LG_PRIVATE | LG_KEY);
    740                }
    741                break;
    742            case CKA_SENSITIVE:
    743                if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
    744                    classFlags = 0;
    745                    break;
    746                }
    747                if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) {
    748                    classFlags &= (LG_PRIVATE | LG_KEY);
    749                } else {
    750                    classFlags = 0;
    751                }
    752                break;
    753            case CKA_TOKEN:
    754                if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
    755                    classFlags = 0;
    756                    break;
    757                }
    758                if (*((CK_BBOOL *)pTemplate[i].pValue) != CK_TRUE) {
    759                    classFlags = 0;
    760                }
    761                break;
    762            case CKA_NSS_CERT_SHA1_HASH:
    763                classFlags &= LG_NSS_TRUST;
    764                copy = &cert_sha1_hash;
    765                break;
    766            case CKA_HASH_OF_CERTIFICATE:
    767                classFlags &= LG_NSS_TRUST;
    768                copy = &cert_sha1_hash;
    769                break;
    770            case CKA_NSS_CERT_MD5_HASH:
    771                classFlags &= LG_NSS_TRUST;
    772                copy = &cert_md5_hash;
    773                break;
    774            case CKA_CERTIFICATE_TYPE:
    775                crv = lg_GetULongAttribute(CKA_CERTIFICATE_TYPE, &pTemplate[i],
    776                                           1, &certType);
    777                if (crv != CKR_OK) {
    778                    classFlags = 0;
    779                    break;
    780                }
    781                classFlags &= LG_CERT;
    782                if (certType != CKC_X_509) {
    783                    classFlags = 0;
    784                }
    785                break;
    786            case CKA_ID:
    787                copy = &key_id;
    788                classFlags &= (LG_CERT | LG_PRIVATE | LG_KEY | LG_PUBLIC);
    789                break;
    790            case CKA_NSS_KRL:
    791                if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
    792                    classFlags = 0;
    793                    break;
    794                }
    795                classFlags &= LG_CRL;
    796                isKrl = (PRBool)(*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE);
    797                break;
    798            case CKA_MODIFIABLE:
    799                break;
    800            case CKA_KEY_TYPE:
    801            case CKA_DERIVE:
    802                classFlags &= LG_PUBLIC | LG_PRIVATE | LG_KEY;
    803                break;
    804            case CKA_VERIFY_RECOVER:
    805                classFlags &= LG_PUBLIC;
    806                break;
    807            case CKA_SIGN_RECOVER:
    808                classFlags &= LG_PRIVATE;
    809                break;
    810            case CKA_ENCRYPT:
    811            case CKA_VERIFY:
    812            case CKA_WRAP:
    813                classFlags &= LG_PUBLIC | LG_KEY;
    814                break;
    815            case CKA_DECRYPT:
    816            case CKA_SIGN:
    817            case CKA_UNWRAP:
    818            case CKA_ALWAYS_SENSITIVE:
    819            case CKA_EXTRACTABLE:
    820            case CKA_NEVER_EXTRACTABLE:
    821                classFlags &= LG_PRIVATE | LG_KEY;
    822                break;
    823            /* can't be a certificate if it doesn't match one of the above
    824             * attributes */
    825            default:
    826                classFlags = 0;
    827                break;
    828        }
    829        if (copy) {
    830            copy->data = (unsigned char *)pTemplate[i].pValue;
    831            copy->len = pTemplate[i].ulValueLen;
    832        }
    833        copy = NULL;
    834    }
    835 
    836    /* certs */
    837    if (classFlags & (LG_CERT | LG_TRUST | LG_NSS_TRUST)) {
    838        lg_searchCertsAndTrust(sdb, &derCert, &name, &derSubject,
    839                               &issuerSN, &email, classFlags, search,
    840                               pTemplate, ulCount);
    841    }
    842 
    843    /* keys */
    844    if (classFlags & (LG_PRIVATE | LG_PUBLIC | LG_KEY)) {
    845        PRBool mustStrict = (name.len != 0);
    846        lg_searchKeys(sdb, &key_id, classFlags, search,
    847                      mustStrict, pTemplate, ulCount);
    848    }
    849 
    850    /* crl's */
    851    if (classFlags & LG_CRL) {
    852        lg_searchCrls(sdb, &derSubject, isKrl, classFlags, search,
    853                      pTemplate, ulCount);
    854    }
    855    /* Add S/MIME entry stuff */
    856    if (classFlags & LG_SMIME) {
    857        lg_searchSMime(sdb, &email, search, pTemplate, ulCount);
    858    }
    859    return CKR_OK;
    860 }
    861 
    862 /* lg_FindObjectsInit initializes a search for token and session objects
    863 * that match a template. */
    864 CK_RV
    865 lg_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *pTemplate,
    866                   CK_ULONG ulCount, SDBFind **retSearch)
    867 {
    868    SDBFind *search;
    869    CK_RV crv = CKR_OK;
    870 
    871    *retSearch = NULL;
    872 
    873    search = (SDBFind *)PORT_Alloc(sizeof(SDBFind));
    874    if (search == NULL) {
    875        crv = CKR_HOST_MEMORY;
    876        goto loser;
    877    }
    878    search->handles = (CK_OBJECT_HANDLE *)
    879        PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * LG_SEARCH_BLOCK_SIZE);
    880    if (search->handles == NULL) {
    881        crv = CKR_HOST_MEMORY;
    882        goto loser;
    883    }
    884    search->index = 0;
    885    search->size = 0;
    886    search->array_size = LG_SEARCH_BLOCK_SIZE;
    887    /* FIXME - do we still need to get Login state? */
    888 
    889    crv = lg_searchTokenList(sdb, search, pTemplate, ulCount);
    890    if (crv != CKR_OK) {
    891        goto loser;
    892    }
    893 
    894    *retSearch = search;
    895    return CKR_OK;
    896 
    897 loser:
    898    if (search) {
    899        lg_FreeSearch(search);
    900    }
    901    return crv;
    902 }
    903 
    904 /* lg_FindObjects continues a search for token and session objects
    905 * that match a template, obtaining additional object handles. */
    906 CK_RV
    907 lg_FindObjects(SDB *sdb, SDBFind *search,
    908               CK_OBJECT_HANDLE *phObject, CK_ULONG ulMaxObjectCount,
    909               CK_ULONG *pulObjectCount)
    910 {
    911    int transfer;
    912    int left;
    913 
    914    *pulObjectCount = 0;
    915    left = search->size - search->index;
    916    transfer = ((int)ulMaxObjectCount > left) ? left : ulMaxObjectCount;
    917    if (transfer > 0) {
    918        PORT_Memcpy(phObject, &search->handles[search->index],
    919                    transfer * sizeof(CK_OBJECT_HANDLE));
    920    } else {
    921        *phObject = CK_INVALID_HANDLE;
    922    }
    923 
    924    search->index += transfer;
    925    *pulObjectCount = transfer;
    926    return CKR_OK;
    927 }
    928 
    929 /* lg_FindObjectsFinal finishes a search for token and session objects. */
    930 CK_RV
    931 lg_FindObjectsFinal(SDB *lgdb, SDBFind *search)
    932 {
    933 
    934    if (search != NULL) {
    935        lg_FreeSearch(search);
    936    }
    937    return CKR_OK;
    938 }