/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "secitem.h" #include "pkcs11.h" #include "lgdb.h" #include "lowkeyi.h" #include "pcert.h" #include "blapi.h" #include "keydbi.h" /* * This code maps PKCS #11 Finds to legacy database searches. This code * was orginally in pkcs11.c in previous versions of NSS. */ struct SDBFindStr { CK_OBJECT_HANDLE *handles; int size; int index; int array_size; }; /* * free a search structure */ void lg_FreeSearch(SDBFind *search) { if (search->handles) { PORT_Free(search->handles); } PORT_Free(search); } void lg_addHandle(SDBFind *search, CK_OBJECT_HANDLE handle) { if (search->handles == NULL) { return; } if (search->size >= search->array_size) { search->array_size += LG_SEARCH_BLOCK_SIZE; search->handles = (CK_OBJECT_HANDLE *)PORT_Realloc(search->handles, sizeof(CK_OBJECT_HANDLE) * search->array_size); if (search->handles == NULL) { return; } } search->handles[search->size] = handle; search->size++; } /* * find any certs that may match the template and load them. */ #define LG_CERT 0x00000001 #define LG_TRUST 0x00000002 #define LG_CRL 0x00000004 #define LG_SMIME 0x00000008 #define LG_PRIVATE 0x00000010 #define LG_PUBLIC 0x00000020 #define LG_KEY 0x00000040 /* * structure to collect key handles. */ typedef struct lgEntryDataStr { SDB *sdb; SDBFind *searchHandles; const CK_ATTRIBUTE *template; CK_ULONG templ_count; } lgEntryData; static SECStatus lg_crl_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg) { lgEntryData *crlData; CK_OBJECT_HANDLE class_handle; SDB *sdb; crlData = (lgEntryData *)arg; sdb = crlData->sdb; class_handle = (type == certDBEntryTypeRevocation) ? LG_TOKEN_TYPE_CRL : LG_TOKEN_KRL_HANDLE; if (lg_tokenMatch(sdb, key, class_handle, crlData->template, crlData->templ_count)) { lg_addHandle(crlData->searchHandles, lg_mkHandle(sdb, key, class_handle)); } return (SECSuccess); } static void lg_searchCrls(SDB *sdb, SECItem *derSubject, PRBool isKrl, unsigned long classFlags, SDBFind *search, const CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount) { NSSLOWCERTCertDBHandle *certHandle = NULL; certHandle = lg_getCertDB(sdb); if (certHandle == NULL) { return; } if (derSubject->data != NULL) { certDBEntryRevocation *crl = nsslowcert_FindCrlByKey(certHandle, derSubject, isKrl); if (crl != NULL) { lg_addHandle(search, lg_mkHandle(sdb, derSubject, isKrl ? LG_TOKEN_KRL_HANDLE : LG_TOKEN_TYPE_CRL)); nsslowcert_DestroyDBEntry((certDBEntry *)crl); } } else { lgEntryData crlData; /* traverse */ crlData.sdb = sdb; crlData.searchHandles = search; crlData.template = pTemplate; crlData.templ_count = ulCount; nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeRevocation, lg_crl_collect, (void *)&crlData); nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeKeyRevocation, lg_crl_collect, (void *)&crlData); } } /* * structure to collect key handles. */ typedef struct lgKeyDataStr { SDB *sdb; NSSLOWKEYDBHandle *keyHandle; SDBFind *searchHandles; SECItem *id; const CK_ATTRIBUTE *template; CK_ULONG templ_count; unsigned long classFlags; PRBool strict; } lgKeyData; static PRBool isSecretKey(NSSLOWKEYPrivateKey *privKey) { if (privKey->keyType == NSSLOWKEYRSAKey && privKey->u.rsa.publicExponent.len == 1 && privKey->u.rsa.publicExponent.data[0] == 0) return PR_TRUE; return PR_FALSE; } static SECStatus lg_key_collect(DBT *key, DBT *data, void *arg) { lgKeyData *keyData; NSSLOWKEYPrivateKey *privKey = NULL; SECItem tmpDBKey; SDB *sdb; unsigned long classFlags; keyData = (lgKeyData *)arg; sdb = keyData->sdb; classFlags = keyData->classFlags; tmpDBKey.data = key->data; tmpDBKey.len = key->size; tmpDBKey.type = siBuffer; PORT_Assert(keyData->keyHandle); if (!keyData->strict && keyData->id && keyData->id->data) { SECItem result; PRBool haveMatch = PR_FALSE; unsigned char hashKey[SHA1_LENGTH]; result.data = hashKey; result.len = sizeof(hashKey); if (keyData->id->len == 0) { /* Make sure this isn't a LG_KEY */ privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, &tmpDBKey, keyData->sdb /*->password*/); if (privKey) { /* turn off the unneeded class flags */ classFlags &= isSecretKey(privKey) ? ~(LG_PRIVATE | LG_PUBLIC) : ~LG_KEY; haveMatch = (PRBool)((classFlags & (LG_KEY | LG_PRIVATE | LG_PUBLIC)) != 0); lg_nsslowkey_DestroyPrivateKey(privKey); } } else { SHA1_HashBuf(hashKey, key->data, key->size); /* match id */ haveMatch = SECITEM_ItemsAreEqual(keyData->id, &result); if (!haveMatch && ((unsigned char *)key->data)[0] == 0) { /* This is a fix for backwards compatibility. The key * database indexes private keys by the public key, and * versions of NSS prior to 3.4 stored the public key as * a signed integer. The public key is now treated as an * unsigned integer, with no leading zero. In order to * correctly compute the hash of an old key, it is necessary * to fallback and detect the leading zero. */ SHA1_HashBuf(hashKey, (unsigned char *)key->data + 1, key->size - 1); haveMatch = SECITEM_ItemsAreEqual(keyData->id, &result); } } if (haveMatch) { if (classFlags & LG_PRIVATE) { lg_addHandle(keyData->searchHandles, lg_mkHandle(sdb, &tmpDBKey, LG_TOKEN_TYPE_PRIV)); } if (classFlags & LG_PUBLIC) { lg_addHandle(keyData->searchHandles, lg_mkHandle(sdb, &tmpDBKey, LG_TOKEN_TYPE_PUB)); } if (classFlags & LG_KEY) { lg_addHandle(keyData->searchHandles, lg_mkHandle(sdb, &tmpDBKey, LG_TOKEN_TYPE_KEY)); } } return SECSuccess; } privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, &tmpDBKey, keyData->sdb /*->password*/); if (privKey == NULL) { goto loser; } if (isSecretKey(privKey)) { if ((classFlags & LG_KEY) && lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_KEY, keyData->template, keyData->templ_count)) { lg_addHandle(keyData->searchHandles, lg_mkHandle(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_KEY)); } } else { if ((classFlags & LG_PRIVATE) && lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PRIV, keyData->template, keyData->templ_count)) { lg_addHandle(keyData->searchHandles, lg_mkHandle(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PRIV)); } if ((classFlags & LG_PUBLIC) && lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PUB, keyData->template, keyData->templ_count)) { lg_addHandle(keyData->searchHandles, lg_mkHandle(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PUB)); } } loser: if (privKey) { lg_nsslowkey_DestroyPrivateKey(privKey); } return (SECSuccess); } static void lg_searchKeys(SDB *sdb, SECItem *key_id, unsigned long classFlags, SDBFind *search, PRBool mustStrict, const CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount) { NSSLOWKEYDBHandle *keyHandle = NULL; NSSLOWKEYPrivateKey *privKey; lgKeyData keyData; PRBool found = PR_FALSE; keyHandle = lg_getKeyDB(sdb); if (keyHandle == NULL) { return; } if (key_id->data) { privKey = nsslowkey_FindKeyByPublicKey(keyHandle, key_id, sdb); if (privKey) { if ((classFlags & LG_KEY) && isSecretKey(privKey)) { lg_addHandle(search, lg_mkHandle(sdb, key_id, LG_TOKEN_TYPE_KEY)); found = PR_TRUE; } if ((classFlags & LG_PRIVATE) && !isSecretKey(privKey)) { lg_addHandle(search, lg_mkHandle(sdb, key_id, LG_TOKEN_TYPE_PRIV)); found = PR_TRUE; } if ((classFlags & LG_PUBLIC) && !isSecretKey(privKey)) { lg_addHandle(search, lg_mkHandle(sdb, key_id, LG_TOKEN_TYPE_PUB)); found = PR_TRUE; } lg_nsslowkey_DestroyPrivateKey(privKey); } /* don't do the traversal if we have an up to date db */ if (keyHandle->version != 3) { goto loser; } /* don't do the traversal if it can't possibly be the correct id */ /* all soft token id's are SHA1_HASH_LEN's */ if (key_id->len != SHA1_LENGTH) { goto loser; } if (found) { /* if we already found some keys, don't do the traversal */ goto loser; } } keyData.sdb = sdb; keyData.keyHandle = keyHandle; keyData.searchHandles = search; keyData.id = key_id; keyData.template = pTemplate; keyData.templ_count = ulCount; keyData.classFlags = classFlags; keyData.strict = mustStrict ? mustStrict : LG_STRICT; nsslowkey_TraverseKeys(keyHandle, lg_key_collect, &keyData); loser: return; } /* * structure to collect certs into */ typedef struct lgCertDataStr { SDB *sdb; int cert_count; int max_cert_count; NSSLOWCERTCertificate **certs; const CK_ATTRIBUTE *template; CK_ULONG templ_count; unsigned long classFlags; PRBool strict; } lgCertData; /* * collect all the certs from the traverse call. */ static SECStatus lg_cert_collect(NSSLOWCERTCertificate *cert, void *arg) { lgCertData *cd = (lgCertData *)arg; if (cert == NULL) { return SECSuccess; } if (cd->certs == NULL) { return SECFailure; } if (cd->strict) { if ((cd->classFlags & LG_CERT) && !lg_tokenMatch(cd->sdb, &cert->certKey, LG_TOKEN_TYPE_CERT, cd->template, cd->templ_count)) { return SECSuccess; } if ((cd->classFlags & LG_TRUST) && !lg_tokenMatch(cd->sdb, &cert->certKey, LG_TOKEN_TYPE_TRUST, cd->template, cd->templ_count)) { return SECSuccess; } } /* allocate more space if we need it. This should only happen in * the general traversal case */ if (cd->cert_count >= cd->max_cert_count) { int size; cd->max_cert_count += LG_SEARCH_BLOCK_SIZE; size = cd->max_cert_count * sizeof(NSSLOWCERTCertificate *); cd->certs = (NSSLOWCERTCertificate **)PORT_Realloc(cd->certs, size); if (cd->certs == NULL) { return SECFailure; } } cd->certs[cd->cert_count++] = nsslowcert_DupCertificate(cert); return SECSuccess; } /* provide impedence matching ... */ static SECStatus lg_cert_collect2(NSSLOWCERTCertificate *cert, SECItem *dymmy, void *arg) { return lg_cert_collect(cert, arg); } static void lg_searchSingleCert(lgCertData *certData, NSSLOWCERTCertificate *cert) { if (cert == NULL) { return; } if (certData->strict && !lg_tokenMatch(certData->sdb, &cert->certKey, LG_TOKEN_TYPE_CERT, certData->template, certData->templ_count)) { nsslowcert_DestroyCertificate(cert); return; } certData->certs = (NSSLOWCERTCertificate **) PORT_Alloc(sizeof(NSSLOWCERTCertificate *)); if (certData->certs == NULL) { nsslowcert_DestroyCertificate(cert); return; } certData->certs[0] = cert; certData->cert_count = 1; } static void lg_CertSetupData(lgCertData *certData, int count) { certData->max_cert_count = count; if (certData->max_cert_count <= 0) { return; } certData->certs = (NSSLOWCERTCertificate **) PORT_Alloc(count * sizeof(NSSLOWCERTCertificate *)); return; } static void lg_searchCertsAndTrust(SDB *sdb, SECItem *derCert, SECItem *name, SECItem *derSubject, NSSLOWCERTIssuerAndSN *issuerSN, SECItem *email, unsigned long classFlags, SDBFind *handles, const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount) { NSSLOWCERTCertDBHandle *certHandle = NULL; lgCertData certData; int i; certHandle = lg_getCertDB(sdb); if (certHandle == NULL) return; certData.sdb = sdb; certData.max_cert_count = 0; certData.certs = NULL; certData.cert_count = 0; certData.template = pTemplate; certData.templ_count = ulCount; certData.classFlags = classFlags; certData.strict = LG_STRICT; /* * Find the Cert. */ if (derCert->data != NULL) { NSSLOWCERTCertificate *cert = nsslowcert_FindCertByDERCert(certHandle, derCert); lg_searchSingleCert(&certData, cert); } else if (name->data != NULL) { char *tmp_name = (char *)PORT_Alloc(name->len + 1); int count; if (tmp_name == NULL) { return; } PORT_Memcpy(tmp_name, name->data, name->len); tmp_name[name->len] = 0; count = nsslowcert_NumPermCertsForNickname(certHandle, tmp_name); lg_CertSetupData(&certData, count); nsslowcert_TraversePermCertsForNickname(certHandle, tmp_name, lg_cert_collect, &certData); PORT_Free(tmp_name); } else if (derSubject->data != NULL) { int count; count = nsslowcert_NumPermCertsForSubject(certHandle, derSubject); lg_CertSetupData(&certData, count); nsslowcert_TraversePermCertsForSubject(certHandle, derSubject, lg_cert_collect, &certData); } else if ((issuerSN->derIssuer.data != NULL) && (issuerSN->serialNumber.data != NULL)) { if (classFlags & LG_CERT) { NSSLOWCERTCertificate *cert = nsslowcert_FindCertByIssuerAndSN(certHandle, issuerSN); lg_searchSingleCert(&certData, cert); } if (classFlags & LG_TRUST) { NSSLOWCERTTrust *trust = nsslowcert_FindTrustByIssuerAndSN(certHandle, issuerSN); if (trust) { lg_addHandle(handles, lg_mkHandle(sdb, &trust->dbKey, LG_TOKEN_TYPE_TRUST)); nsslowcert_DestroyTrust(trust); } } } else if (email->data != NULL) { char *tmp_name = (char *)PORT_Alloc(email->len + 1); certDBEntrySMime *entry = NULL; if (tmp_name == NULL) { return; } PORT_Memcpy(tmp_name, email->data, email->len); tmp_name[email->len] = 0; entry = nsslowcert_ReadDBSMimeEntry(certHandle, tmp_name); if (entry) { int count; SECItem *subjectName = &entry->subjectName; count = nsslowcert_NumPermCertsForSubject(certHandle, subjectName); lg_CertSetupData(&certData, count); nsslowcert_TraversePermCertsForSubject(certHandle, subjectName, lg_cert_collect, &certData); nsslowcert_DestroyDBEntry((certDBEntry *)entry); } PORT_Free(tmp_name); } else { /* we aren't filtering the certs, we are working on all, so turn * on the strict filters. */ certData.strict = PR_TRUE; lg_CertSetupData(&certData, LG_SEARCH_BLOCK_SIZE); nsslowcert_TraversePermCerts(certHandle, lg_cert_collect2, &certData); } /* * build the handles */ for (i = 0; i < certData.cert_count; i++) { NSSLOWCERTCertificate *cert = certData.certs[i]; /* if we filtered it would have been on the stuff above */ if (classFlags & LG_CERT) { lg_addHandle(handles, lg_mkHandle(sdb, &cert->certKey, LG_TOKEN_TYPE_CERT)); } if ((classFlags & LG_TRUST) && nsslowcert_hasTrust(cert->trust)) { lg_addHandle(handles, lg_mkHandle(sdb, &cert->certKey, LG_TOKEN_TYPE_TRUST)); } nsslowcert_DestroyCertificate(cert); } if (certData.certs) PORT_Free(certData.certs); return; } static SECStatus lg_smime_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg) { lgEntryData *smimeData; SDB *sdb; smimeData = (lgEntryData *)arg; sdb = smimeData->sdb; if (lg_tokenMatch(sdb, key, LG_TOKEN_TYPE_SMIME, smimeData->template, smimeData->templ_count)) { lg_addHandle(smimeData->searchHandles, lg_mkHandle(sdb, key, LG_TOKEN_TYPE_SMIME)); } return (SECSuccess); } static void lg_searchSMime(SDB *sdb, SECItem *email, SDBFind *handles, const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount) { NSSLOWCERTCertDBHandle *certHandle = NULL; certDBEntrySMime *entry; certHandle = lg_getCertDB(sdb); if (certHandle == NULL) return; if (email->data != NULL) { char *tmp_name = (char *)PORT_Alloc(email->len + 1); if (tmp_name == NULL) { return; } PORT_Memcpy(tmp_name, email->data, email->len); tmp_name[email->len] = 0; entry = nsslowcert_ReadDBSMimeEntry(certHandle, tmp_name); if (entry) { SECItem emailKey; emailKey.data = (unsigned char *)tmp_name; emailKey.len = PORT_Strlen(tmp_name) + 1; emailKey.type = 0; lg_addHandle(handles, lg_mkHandle(sdb, &emailKey, LG_TOKEN_TYPE_SMIME)); nsslowcert_DestroyDBEntry((certDBEntry *)entry); } PORT_Free(tmp_name); } else { /* traverse */ lgEntryData smimeData; /* traverse */ smimeData.sdb = sdb; smimeData.searchHandles = handles; smimeData.template = pTemplate; smimeData.templ_count = ulCount; nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeSMimeProfile, lg_smime_collect, (void *)&smimeData); } return; } static CK_RV lg_searchTokenList(SDB *sdb, SDBFind *search, const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount) { int i; PRBool isKrl = PR_FALSE; SECItem derCert = { siBuffer, NULL, 0 }; SECItem derSubject = { siBuffer, NULL, 0 }; SECItem name = { siBuffer, NULL, 0 }; SECItem email = { siBuffer, NULL, 0 }; SECItem key_id = { siBuffer, NULL, 0 }; SECItem cert_sha1_hash = { siBuffer, NULL, 0 }; SECItem cert_md5_hash = { siBuffer, NULL, 0 }; NSSLOWCERTIssuerAndSN issuerSN = { { siBuffer, NULL, 0 }, { siBuffer, NULL, 0 } }; SECItem *copy = NULL; CK_CERTIFICATE_TYPE certType; CK_OBJECT_CLASS objectClass; CK_RV crv; unsigned long classFlags; if (lg_getCertDB(sdb) == NULL) { classFlags = LG_PRIVATE | LG_KEY; } else { classFlags = LG_CERT | LG_TRUST | LG_PUBLIC | LG_SMIME | LG_CRL; } /* * look for things to search on token objects for. If the right options * are specified, we can use them as direct indeces into the database * (rather than using linear searches. We can also use the attributes to * limit the kinds of objects we are searching for. Later we can use this * array to filter the remaining objects more finely. */ for (i = 0; classFlags && i < (int)ulCount; i++) { switch (pTemplate[i].type) { case CKA_SUBJECT: copy = &derSubject; classFlags &= (LG_CERT | LG_PRIVATE | LG_PUBLIC | LG_SMIME | LG_CRL); break; case CKA_ISSUER: copy = &issuerSN.derIssuer; classFlags &= (LG_CERT | LG_TRUST); break; case CKA_SERIAL_NUMBER: copy = &issuerSN.serialNumber; classFlags &= (LG_CERT | LG_TRUST); break; case CKA_VALUE: copy = &derCert; classFlags &= (LG_CERT | LG_CRL | LG_SMIME); break; case CKA_LABEL: copy = &name; break; case CKA_NETSCAPE_EMAIL: copy = &email; classFlags &= LG_SMIME | LG_CERT; break; case CKA_NETSCAPE_SMIME_TIMESTAMP: classFlags &= LG_SMIME; break; case CKA_CLASS: crv = lg_GetULongAttribute(CKA_CLASS, &pTemplate[i], 1, &objectClass); if (crv != CKR_OK) { classFlags = 0; break; } switch (objectClass) { case CKO_CERTIFICATE: classFlags &= LG_CERT; break; case CKO_NETSCAPE_TRUST: classFlags &= LG_TRUST; break; case CKO_NETSCAPE_CRL: classFlags &= LG_CRL; break; case CKO_NETSCAPE_SMIME: classFlags &= LG_SMIME; break; case CKO_PRIVATE_KEY: classFlags &= LG_PRIVATE; break; case CKO_PUBLIC_KEY: classFlags &= LG_PUBLIC; break; case CKO_SECRET_KEY: classFlags &= LG_KEY; break; default: classFlags = 0; break; } break; case CKA_PRIVATE: if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) { classFlags = 0; break; } if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) { classFlags &= (LG_PRIVATE | LG_KEY); } else { classFlags &= ~(LG_PRIVATE | LG_KEY); } break; case CKA_SENSITIVE: if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) { classFlags = 0; break; } if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) { classFlags &= (LG_PRIVATE | LG_KEY); } else { classFlags = 0; } break; case CKA_TOKEN: if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) { classFlags = 0; break; } if (*((CK_BBOOL *)pTemplate[i].pValue) != CK_TRUE) { classFlags = 0; } break; case CKA_CERT_SHA1_HASH: classFlags &= LG_TRUST; copy = &cert_sha1_hash; break; case CKA_CERT_MD5_HASH: classFlags &= LG_TRUST; copy = &cert_md5_hash; break; case CKA_CERTIFICATE_TYPE: crv = lg_GetULongAttribute(CKA_CERTIFICATE_TYPE, &pTemplate[i], 1, &certType); if (crv != CKR_OK) { classFlags = 0; break; } classFlags &= LG_CERT; if (certType != CKC_X_509) { classFlags = 0; } break; case CKA_ID: copy = &key_id; classFlags &= (LG_CERT | LG_PRIVATE | LG_KEY | LG_PUBLIC); break; case CKA_NETSCAPE_KRL: if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) { classFlags = 0; break; } classFlags &= LG_CRL; isKrl = (PRBool)(*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE); break; case CKA_MODIFIABLE: break; case CKA_KEY_TYPE: case CKA_DERIVE: classFlags &= LG_PUBLIC | LG_PRIVATE | LG_KEY; break; case CKA_VERIFY_RECOVER: classFlags &= LG_PUBLIC; break; case CKA_SIGN_RECOVER: classFlags &= LG_PRIVATE; break; case CKA_ENCRYPT: case CKA_VERIFY: case CKA_WRAP: classFlags &= LG_PUBLIC | LG_KEY; break; case CKA_DECRYPT: case CKA_SIGN: case CKA_UNWRAP: case CKA_ALWAYS_SENSITIVE: case CKA_EXTRACTABLE: case CKA_NEVER_EXTRACTABLE: classFlags &= LG_PRIVATE | LG_KEY; break; /* can't be a certificate if it doesn't match one of the above * attributes */ default: classFlags = 0; break; } if (copy) { copy->data = (unsigned char *)pTemplate[i].pValue; copy->len = pTemplate[i].ulValueLen; } copy = NULL; } /* certs */ if (classFlags & (LG_CERT | LG_TRUST)) { lg_searchCertsAndTrust(sdb, &derCert, &name, &derSubject, &issuerSN, &email, classFlags, search, pTemplate, ulCount); } /* keys */ if (classFlags & (LG_PRIVATE | LG_PUBLIC | LG_KEY)) { PRBool mustStrict = (name.len != 0); lg_searchKeys(sdb, &key_id, classFlags, search, mustStrict, pTemplate, ulCount); } /* crl's */ if (classFlags & LG_CRL) { lg_searchCrls(sdb, &derSubject, isKrl, classFlags, search, pTemplate, ulCount); } /* Add S/MIME entry stuff */ if (classFlags & LG_SMIME) { lg_searchSMime(sdb, &email, search, pTemplate, ulCount); } return CKR_OK; } /* lg_FindObjectsInit initializes a search for token and session objects * that match a template. */ CK_RV lg_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount, SDBFind **retSearch) { SDBFind *search; CK_RV crv = CKR_OK; *retSearch = NULL; search = (SDBFind *)PORT_Alloc(sizeof(SDBFind)); if (search == NULL) { crv = CKR_HOST_MEMORY; goto loser; } search->handles = (CK_OBJECT_HANDLE *) PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * LG_SEARCH_BLOCK_SIZE); if (search->handles == NULL) { crv = CKR_HOST_MEMORY; goto loser; } search->index = 0; search->size = 0; search->array_size = LG_SEARCH_BLOCK_SIZE; /* FIXME - do we still need to get Login state? */ crv = lg_searchTokenList(sdb, search, pTemplate, ulCount); if (crv != CKR_OK) { goto loser; } *retSearch = search; return CKR_OK; loser: if (search) { lg_FreeSearch(search); } return crv; } /* lg_FindObjects continues a search for token and session objects * that match a template, obtaining additional object handles. */ CK_RV lg_FindObjects(SDB *sdb, SDBFind *search, CK_OBJECT_HANDLE *phObject, CK_ULONG ulMaxObjectCount, CK_ULONG *pulObjectCount) { int transfer; int left; *pulObjectCount = 0; left = search->size - search->index; transfer = ((int)ulMaxObjectCount > left) ? left : ulMaxObjectCount; if (transfer > 0) { PORT_Memcpy(phObject, &search->handles[search->index], transfer * sizeof(CK_OBJECT_HANDLE)); } else { *phObject = CK_INVALID_HANDLE; } search->index += transfer; *pulObjectCount = transfer; return CKR_OK; } /* lg_FindObjectsFinal finishes a search for token and session objects. */ CK_RV lg_FindObjectsFinal(SDB *lgdb, SDBFind *search) { if (search != NULL) { lg_FreeSearch(search); } return CKR_OK; }