diff options
Diffstat (limited to 'security/nss/lib/softoken/legacydb/lgfind.c')
-rw-r--r-- | security/nss/lib/softoken/legacydb/lgfind.c | 912 |
1 files changed, 912 insertions, 0 deletions
diff --git a/security/nss/lib/softoken/legacydb/lgfind.c b/security/nss/lib/softoken/legacydb/lgfind.c new file mode 100644 index 000000000..288e56cac --- /dev/null +++ b/security/nss/lib/softoken/legacydb/lgfind.c @@ -0,0 +1,912 @@ +/* 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; +} |