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