mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
941 lines
25 KiB
C
941 lines
25 KiB
C
|
/* ***** BEGIN LICENSE BLOCK *****
|
||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||
|
*
|
||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||
|
* the License. You may obtain a copy of the License at
|
||
|
* http://www.mozilla.org/MPL/
|
||
|
*
|
||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||
|
* for the specific language governing rights and limitations under the
|
||
|
* License.
|
||
|
*
|
||
|
* The Original Code is the Netscape security libraries.
|
||
|
*
|
||
|
* The Initial Developer of the Original Code is
|
||
|
* Netscape Communications Corporation.
|
||
|
* Portions created by the Initial Developer are Copyright (C) 1994-2000
|
||
|
* the Initial Developer. All Rights Reserved.
|
||
|
*
|
||
|
*
|
||
|
* Alternatively, the contents of this file may be used under the terms of
|
||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||
|
* of those above. If you wish to allow use of your version of this file only
|
||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||
|
* use your version of this file under the terms of the MPL, indicate your
|
||
|
* decision by deleting the provisions above and replace them with the notice
|
||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||
|
* the provisions above, a recipient may use your version of this file under
|
||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||
|
*
|
||
|
* ***** END LICENSE BLOCK ***** */
|
||
|
#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);
|
||
|
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 ) {
|
||
|
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;
|
||
|
}
|
||
|
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;
|
||
|
}
|
||
|
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;
|
||
|
}
|
||
|
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;
|
||
|
}
|
||
|
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_CLASS,&pTemplate[i],1,&certType);
|
||
|
if (crv != CKR_OK) {
|
||
|
classFlags = 0;
|
||
|
}
|
||
|
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;
|
||
|
}
|
||
|
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;
|
||
|
}
|