diff nss/lib/softoken/legacydb/lgfind.c @ 3:150b72113545

Add DBM and legacydb support
author Andre Heinecke <andre.heinecke@intevation.de>
date Tue, 05 Aug 2014 18:32:02 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/softoken/legacydb/lgfind.c	Tue Aug 05 18:32:02 2014 +0200
@@ -0,0 +1,915 @@
+/* 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;
+}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)