blob: 288e56cac318de8cf28636215d2154a403cfcbf2 [file] [log] [blame]
/* 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;
}