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