security/nss/lib/softoken/legacydb/lgfind.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 #include "secitem.h"
michael@0 5 #include "pkcs11.h"
michael@0 6 #include "lgdb.h"
michael@0 7 #include "lowkeyi.h"
michael@0 8 #include "pcert.h"
michael@0 9 #include "blapi.h"
michael@0 10
michael@0 11 #include "keydbi.h"
michael@0 12
michael@0 13 /*
michael@0 14 * This code maps PKCS #11 Finds to legacy database searches. This code
michael@0 15 * was orginally in pkcs11.c in previous versions of NSS.
michael@0 16 */
michael@0 17
michael@0 18 struct SDBFindStr {
michael@0 19 CK_OBJECT_HANDLE *handles;
michael@0 20 int size;
michael@0 21 int index;
michael@0 22 int array_size;
michael@0 23 };
michael@0 24
michael@0 25
michael@0 26 /*
michael@0 27 * free a search structure
michael@0 28 */
michael@0 29 void
michael@0 30 lg_FreeSearch(SDBFind *search)
michael@0 31 {
michael@0 32 if (search->handles) {
michael@0 33 PORT_Free(search->handles);
michael@0 34 }
michael@0 35 PORT_Free(search);
michael@0 36 }
michael@0 37
michael@0 38 void
michael@0 39 lg_addHandle(SDBFind *search, CK_OBJECT_HANDLE handle)
michael@0 40 {
michael@0 41 if (search->handles == NULL) {
michael@0 42 return;
michael@0 43 }
michael@0 44 if (search->size >= search->array_size) {
michael@0 45 search->array_size += LG_SEARCH_BLOCK_SIZE;
michael@0 46 search->handles = (CK_OBJECT_HANDLE *) PORT_Realloc(search->handles,
michael@0 47 sizeof(CK_OBJECT_HANDLE)* search->array_size);
michael@0 48 if (search->handles == NULL) {
michael@0 49 return;
michael@0 50 }
michael@0 51 }
michael@0 52 search->handles[search->size] = handle;
michael@0 53 search->size++;
michael@0 54 }
michael@0 55
michael@0 56 /*
michael@0 57 * find any certs that may match the template and load them.
michael@0 58 */
michael@0 59 #define LG_CERT 0x00000001
michael@0 60 #define LG_TRUST 0x00000002
michael@0 61 #define LG_CRL 0x00000004
michael@0 62 #define LG_SMIME 0x00000008
michael@0 63 #define LG_PRIVATE 0x00000010
michael@0 64 #define LG_PUBLIC 0x00000020
michael@0 65 #define LG_KEY 0x00000040
michael@0 66
michael@0 67 /*
michael@0 68 * structure to collect key handles.
michael@0 69 */
michael@0 70 typedef struct lgEntryDataStr {
michael@0 71 SDB *sdb;
michael@0 72 SDBFind *searchHandles;
michael@0 73 const CK_ATTRIBUTE *template;
michael@0 74 CK_ULONG templ_count;
michael@0 75 } lgEntryData;
michael@0 76
michael@0 77
michael@0 78 static SECStatus
michael@0 79 lg_crl_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg)
michael@0 80 {
michael@0 81 lgEntryData *crlData;
michael@0 82 CK_OBJECT_HANDLE class_handle;
michael@0 83 SDB *sdb;
michael@0 84
michael@0 85 crlData = (lgEntryData *)arg;
michael@0 86 sdb = crlData->sdb;
michael@0 87
michael@0 88 class_handle = (type == certDBEntryTypeRevocation) ? LG_TOKEN_TYPE_CRL :
michael@0 89 LG_TOKEN_KRL_HANDLE;
michael@0 90 if (lg_tokenMatch(sdb, key, class_handle,
michael@0 91 crlData->template, crlData->templ_count)) {
michael@0 92 lg_addHandle(crlData->searchHandles,
michael@0 93 lg_mkHandle(sdb,key,class_handle));
michael@0 94 }
michael@0 95 return(SECSuccess);
michael@0 96 }
michael@0 97
michael@0 98 static void
michael@0 99 lg_searchCrls(SDB *sdb, SECItem *derSubject, PRBool isKrl,
michael@0 100 unsigned long classFlags, SDBFind *search,
michael@0 101 const CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
michael@0 102 {
michael@0 103 NSSLOWCERTCertDBHandle *certHandle = NULL;
michael@0 104
michael@0 105 certHandle = lg_getCertDB(sdb);
michael@0 106 if (certHandle == NULL) {
michael@0 107 return;
michael@0 108 }
michael@0 109 if (derSubject->data != NULL) {
michael@0 110 certDBEntryRevocation *crl =
michael@0 111 nsslowcert_FindCrlByKey(certHandle, derSubject, isKrl);
michael@0 112
michael@0 113 if (crl != NULL) {
michael@0 114 lg_addHandle(search, lg_mkHandle(sdb, derSubject,
michael@0 115 isKrl ? LG_TOKEN_KRL_HANDLE : LG_TOKEN_TYPE_CRL));
michael@0 116 nsslowcert_DestroyDBEntry((certDBEntry *)crl);
michael@0 117 }
michael@0 118 } else {
michael@0 119 lgEntryData crlData;
michael@0 120
michael@0 121 /* traverse */
michael@0 122 crlData.sdb = sdb;
michael@0 123 crlData.searchHandles = search;
michael@0 124 crlData.template = pTemplate;
michael@0 125 crlData.templ_count = ulCount;
michael@0 126 nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeRevocation,
michael@0 127 lg_crl_collect, (void *)&crlData);
michael@0 128 nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeKeyRevocation,
michael@0 129 lg_crl_collect, (void *)&crlData);
michael@0 130 }
michael@0 131 }
michael@0 132
michael@0 133 /*
michael@0 134 * structure to collect key handles.
michael@0 135 */
michael@0 136 typedef struct lgKeyDataStr {
michael@0 137 SDB *sdb;
michael@0 138 NSSLOWKEYDBHandle *keyHandle;
michael@0 139 SDBFind *searchHandles;
michael@0 140 SECItem *id;
michael@0 141 const CK_ATTRIBUTE *template;
michael@0 142 CK_ULONG templ_count;
michael@0 143 unsigned long classFlags;
michael@0 144 PRBool strict;
michael@0 145 } lgKeyData;
michael@0 146
michael@0 147 static PRBool
michael@0 148 isSecretKey(NSSLOWKEYPrivateKey *privKey)
michael@0 149 {
michael@0 150 if (privKey->keyType == NSSLOWKEYRSAKey &&
michael@0 151 privKey->u.rsa.publicExponent.len == 1 &&
michael@0 152 privKey->u.rsa.publicExponent.data[0] == 0)
michael@0 153 return PR_TRUE;
michael@0 154
michael@0 155 return PR_FALSE;
michael@0 156 }
michael@0 157
michael@0 158
michael@0 159
michael@0 160 static SECStatus
michael@0 161 lg_key_collect(DBT *key, DBT *data, void *arg)
michael@0 162 {
michael@0 163 lgKeyData *keyData;
michael@0 164 NSSLOWKEYPrivateKey *privKey = NULL;
michael@0 165 SECItem tmpDBKey;
michael@0 166 SDB *sdb;
michael@0 167 unsigned long classFlags;
michael@0 168
michael@0 169 keyData = (lgKeyData *)arg;
michael@0 170 sdb = keyData->sdb;
michael@0 171 classFlags = keyData->classFlags;
michael@0 172
michael@0 173 tmpDBKey.data = key->data;
michael@0 174 tmpDBKey.len = key->size;
michael@0 175 tmpDBKey.type = siBuffer;
michael@0 176
michael@0 177 PORT_Assert(keyData->keyHandle);
michael@0 178 if (!keyData->strict && keyData->id && keyData->id->data) {
michael@0 179 SECItem result;
michael@0 180 PRBool haveMatch= PR_FALSE;
michael@0 181 unsigned char hashKey[SHA1_LENGTH];
michael@0 182 result.data = hashKey;
michael@0 183 result.len = sizeof(hashKey);
michael@0 184
michael@0 185 if (keyData->id->len == 0) {
michael@0 186 /* Make sure this isn't a LG_KEY */
michael@0 187 privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle,
michael@0 188 &tmpDBKey, keyData->sdb/*->password*/);
michael@0 189 if (privKey) {
michael@0 190 /* turn off the unneeded class flags */
michael@0 191 classFlags &= isSecretKey(privKey) ? ~(LG_PRIVATE|LG_PUBLIC) :
michael@0 192 ~LG_KEY;
michael@0 193 haveMatch = (PRBool)
michael@0 194 ((classFlags & (LG_KEY|LG_PRIVATE|LG_PUBLIC)) != 0);
michael@0 195 lg_nsslowkey_DestroyPrivateKey(privKey);
michael@0 196 }
michael@0 197 } else {
michael@0 198 SHA1_HashBuf( hashKey, key->data, key->size ); /* match id */
michael@0 199 haveMatch = SECITEM_ItemsAreEqual(keyData->id,&result);
michael@0 200 if (!haveMatch && ((unsigned char *)key->data)[0] == 0) {
michael@0 201 /* This is a fix for backwards compatibility. The key
michael@0 202 * database indexes private keys by the public key, and
michael@0 203 * versions of NSS prior to 3.4 stored the public key as
michael@0 204 * a signed integer. The public key is now treated as an
michael@0 205 * unsigned integer, with no leading zero. In order to
michael@0 206 * correctly compute the hash of an old key, it is necessary
michael@0 207 * to fallback and detect the leading zero.
michael@0 208 */
michael@0 209 SHA1_HashBuf(hashKey,
michael@0 210 (unsigned char *)key->data + 1, key->size - 1);
michael@0 211 haveMatch = SECITEM_ItemsAreEqual(keyData->id,&result);
michael@0 212 }
michael@0 213 }
michael@0 214 if (haveMatch) {
michael@0 215 if (classFlags & LG_PRIVATE) {
michael@0 216 lg_addHandle(keyData->searchHandles,
michael@0 217 lg_mkHandle(sdb,&tmpDBKey,LG_TOKEN_TYPE_PRIV));
michael@0 218 }
michael@0 219 if (classFlags & LG_PUBLIC) {
michael@0 220 lg_addHandle(keyData->searchHandles,
michael@0 221 lg_mkHandle(sdb,&tmpDBKey,LG_TOKEN_TYPE_PUB));
michael@0 222 }
michael@0 223 if (classFlags & LG_KEY) {
michael@0 224 lg_addHandle(keyData->searchHandles,
michael@0 225 lg_mkHandle(sdb,&tmpDBKey,LG_TOKEN_TYPE_KEY));
michael@0 226 }
michael@0 227 }
michael@0 228 return SECSuccess;
michael@0 229 }
michael@0 230
michael@0 231 privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, &tmpDBKey,
michael@0 232 keyData->sdb/*->password*/);
michael@0 233 if ( privKey == NULL ) {
michael@0 234 goto loser;
michael@0 235 }
michael@0 236
michael@0 237 if (isSecretKey(privKey)) {
michael@0 238 if ((classFlags & LG_KEY) &&
michael@0 239 lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_KEY,
michael@0 240 keyData->template, keyData->templ_count)) {
michael@0 241 lg_addHandle(keyData->searchHandles,
michael@0 242 lg_mkHandle(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_KEY));
michael@0 243 }
michael@0 244 } else {
michael@0 245 if ((classFlags & LG_PRIVATE) &&
michael@0 246 lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PRIV,
michael@0 247 keyData->template, keyData->templ_count)) {
michael@0 248 lg_addHandle(keyData->searchHandles,
michael@0 249 lg_mkHandle(keyData->sdb,&tmpDBKey,LG_TOKEN_TYPE_PRIV));
michael@0 250 }
michael@0 251 if ((classFlags & LG_PUBLIC) &&
michael@0 252 lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PUB,
michael@0 253 keyData->template, keyData->templ_count)) {
michael@0 254 lg_addHandle(keyData->searchHandles,
michael@0 255 lg_mkHandle(keyData->sdb, &tmpDBKey,LG_TOKEN_TYPE_PUB));
michael@0 256 }
michael@0 257 }
michael@0 258
michael@0 259 loser:
michael@0 260 if ( privKey ) {
michael@0 261 lg_nsslowkey_DestroyPrivateKey(privKey);
michael@0 262 }
michael@0 263 return(SECSuccess);
michael@0 264 }
michael@0 265
michael@0 266 static void
michael@0 267 lg_searchKeys(SDB *sdb, SECItem *key_id,
michael@0 268 unsigned long classFlags, SDBFind *search, PRBool mustStrict,
michael@0 269 const CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
michael@0 270 {
michael@0 271 NSSLOWKEYDBHandle *keyHandle = NULL;
michael@0 272 NSSLOWKEYPrivateKey *privKey;
michael@0 273 lgKeyData keyData;
michael@0 274 PRBool found = PR_FALSE;
michael@0 275
michael@0 276 keyHandle = lg_getKeyDB(sdb);
michael@0 277 if (keyHandle == NULL) {
michael@0 278 return;
michael@0 279 }
michael@0 280
michael@0 281 if (key_id->data) {
michael@0 282 privKey = nsslowkey_FindKeyByPublicKey(keyHandle, key_id, sdb);
michael@0 283 if (privKey) {
michael@0 284 if ((classFlags & LG_KEY) && isSecretKey(privKey)) {
michael@0 285 lg_addHandle(search,
michael@0 286 lg_mkHandle(sdb,key_id,LG_TOKEN_TYPE_KEY));
michael@0 287 found = PR_TRUE;
michael@0 288 }
michael@0 289 if ((classFlags & LG_PRIVATE) && !isSecretKey(privKey)) {
michael@0 290 lg_addHandle(search,
michael@0 291 lg_mkHandle(sdb,key_id,LG_TOKEN_TYPE_PRIV));
michael@0 292 found = PR_TRUE;
michael@0 293 }
michael@0 294 if ((classFlags & LG_PUBLIC) && !isSecretKey(privKey)) {
michael@0 295 lg_addHandle(search,
michael@0 296 lg_mkHandle(sdb,key_id,LG_TOKEN_TYPE_PUB));
michael@0 297 found = PR_TRUE;
michael@0 298 }
michael@0 299 lg_nsslowkey_DestroyPrivateKey(privKey);
michael@0 300 }
michael@0 301 /* don't do the traversal if we have an up to date db */
michael@0 302 if (keyHandle->version != 3) {
michael@0 303 goto loser;
michael@0 304 }
michael@0 305 /* don't do the traversal if it can't possibly be the correct id */
michael@0 306 /* all soft token id's are SHA1_HASH_LEN's */
michael@0 307 if (key_id->len != SHA1_LENGTH) {
michael@0 308 goto loser;
michael@0 309 }
michael@0 310 if (found) {
michael@0 311 /* if we already found some keys, don't do the traversal */
michael@0 312 goto loser;
michael@0 313 }
michael@0 314 }
michael@0 315 keyData.sdb = sdb;
michael@0 316 keyData.keyHandle = keyHandle;
michael@0 317 keyData.searchHandles = search;
michael@0 318 keyData.id = key_id;
michael@0 319 keyData.template = pTemplate;
michael@0 320 keyData.templ_count = ulCount;
michael@0 321 keyData.classFlags = classFlags;
michael@0 322 keyData.strict = mustStrict ? mustStrict : LG_STRICT;
michael@0 323
michael@0 324 nsslowkey_TraverseKeys(keyHandle, lg_key_collect, &keyData);
michael@0 325
michael@0 326 loser:
michael@0 327 return;
michael@0 328 }
michael@0 329
michael@0 330 /*
michael@0 331 * structure to collect certs into
michael@0 332 */
michael@0 333 typedef struct lgCertDataStr {
michael@0 334 SDB *sdb;
michael@0 335 int cert_count;
michael@0 336 int max_cert_count;
michael@0 337 NSSLOWCERTCertificate **certs;
michael@0 338 const CK_ATTRIBUTE *template;
michael@0 339 CK_ULONG templ_count;
michael@0 340 unsigned long classFlags;
michael@0 341 PRBool strict;
michael@0 342 } lgCertData;
michael@0 343
michael@0 344 /*
michael@0 345 * collect all the certs from the traverse call.
michael@0 346 */
michael@0 347 static SECStatus
michael@0 348 lg_cert_collect(NSSLOWCERTCertificate *cert,void *arg)
michael@0 349 {
michael@0 350 lgCertData *cd = (lgCertData *)arg;
michael@0 351
michael@0 352 if (cert == NULL) {
michael@0 353 return SECSuccess;
michael@0 354 }
michael@0 355
michael@0 356 if (cd->certs == NULL) {
michael@0 357 return SECFailure;
michael@0 358 }
michael@0 359
michael@0 360 if (cd->strict) {
michael@0 361 if ((cd->classFlags & LG_CERT) && !lg_tokenMatch(cd->sdb,
michael@0 362 &cert->certKey, LG_TOKEN_TYPE_CERT, cd->template,cd->templ_count)) {
michael@0 363 return SECSuccess;
michael@0 364 }
michael@0 365 if ((cd->classFlags & LG_TRUST) && !lg_tokenMatch(cd->sdb,
michael@0 366 &cert->certKey, LG_TOKEN_TYPE_TRUST,
michael@0 367 cd->template, cd->templ_count)) {
michael@0 368 return SECSuccess;
michael@0 369 }
michael@0 370 }
michael@0 371
michael@0 372 /* allocate more space if we need it. This should only happen in
michael@0 373 * the general traversal case */
michael@0 374 if (cd->cert_count >= cd->max_cert_count) {
michael@0 375 int size;
michael@0 376 cd->max_cert_count += LG_SEARCH_BLOCK_SIZE;
michael@0 377 size = cd->max_cert_count * sizeof (NSSLOWCERTCertificate *);
michael@0 378 cd->certs = (NSSLOWCERTCertificate **)PORT_Realloc(cd->certs,size);
michael@0 379 if (cd->certs == NULL) {
michael@0 380 return SECFailure;
michael@0 381 }
michael@0 382 }
michael@0 383
michael@0 384 cd->certs[cd->cert_count++] = nsslowcert_DupCertificate(cert);
michael@0 385 return SECSuccess;
michael@0 386 }
michael@0 387
michael@0 388 /* provide impedence matching ... */
michael@0 389 static SECStatus
michael@0 390 lg_cert_collect2(NSSLOWCERTCertificate *cert, SECItem *dymmy, void *arg)
michael@0 391 {
michael@0 392 return lg_cert_collect(cert, arg);
michael@0 393 }
michael@0 394
michael@0 395 static void
michael@0 396 lg_searchSingleCert(lgCertData *certData,NSSLOWCERTCertificate *cert)
michael@0 397 {
michael@0 398 if (cert == NULL) {
michael@0 399 return;
michael@0 400 }
michael@0 401 if (certData->strict &&
michael@0 402 !lg_tokenMatch(certData->sdb, &cert->certKey, LG_TOKEN_TYPE_CERT,
michael@0 403 certData->template,certData->templ_count)) {
michael@0 404 nsslowcert_DestroyCertificate(cert);
michael@0 405 return;
michael@0 406 }
michael@0 407 certData->certs = (NSSLOWCERTCertificate **)
michael@0 408 PORT_Alloc(sizeof (NSSLOWCERTCertificate *));
michael@0 409 if (certData->certs == NULL) {
michael@0 410 nsslowcert_DestroyCertificate(cert);
michael@0 411 return;
michael@0 412 }
michael@0 413 certData->certs[0] = cert;
michael@0 414 certData->cert_count = 1;
michael@0 415 }
michael@0 416
michael@0 417 static void
michael@0 418 lg_CertSetupData(lgCertData *certData,int count)
michael@0 419 {
michael@0 420 certData->max_cert_count = count;
michael@0 421
michael@0 422 if (certData->max_cert_count <= 0) {
michael@0 423 return;
michael@0 424 }
michael@0 425 certData->certs = (NSSLOWCERTCertificate **)
michael@0 426 PORT_Alloc( count * sizeof(NSSLOWCERTCertificate *));
michael@0 427 return;
michael@0 428 }
michael@0 429
michael@0 430 static void
michael@0 431 lg_searchCertsAndTrust(SDB *sdb, SECItem *derCert, SECItem *name,
michael@0 432 SECItem *derSubject, NSSLOWCERTIssuerAndSN *issuerSN,
michael@0 433 SECItem *email,
michael@0 434 unsigned long classFlags, SDBFind *handles,
michael@0 435 const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount)
michael@0 436 {
michael@0 437 NSSLOWCERTCertDBHandle *certHandle = NULL;
michael@0 438 lgCertData certData;
michael@0 439 int i;
michael@0 440
michael@0 441 certHandle = lg_getCertDB(sdb);
michael@0 442 if (certHandle == NULL) return;
michael@0 443
michael@0 444 certData.sdb = sdb;
michael@0 445 certData.max_cert_count = 0;
michael@0 446 certData.certs = NULL;
michael@0 447 certData.cert_count = 0;
michael@0 448 certData.template = pTemplate;
michael@0 449 certData.templ_count = ulCount;
michael@0 450 certData.classFlags = classFlags;
michael@0 451 certData.strict = LG_STRICT;
michael@0 452
michael@0 453
michael@0 454 /*
michael@0 455 * Find the Cert.
michael@0 456 */
michael@0 457 if (derCert->data != NULL) {
michael@0 458 NSSLOWCERTCertificate *cert =
michael@0 459 nsslowcert_FindCertByDERCert(certHandle,derCert);
michael@0 460 lg_searchSingleCert(&certData,cert);
michael@0 461 } else if (name->data != NULL) {
michael@0 462 char *tmp_name = (char*)PORT_Alloc(name->len+1);
michael@0 463 int count;
michael@0 464
michael@0 465 if (tmp_name == NULL) {
michael@0 466 return;
michael@0 467 }
michael@0 468 PORT_Memcpy(tmp_name,name->data,name->len);
michael@0 469 tmp_name[name->len] = 0;
michael@0 470
michael@0 471 count= nsslowcert_NumPermCertsForNickname(certHandle,tmp_name);
michael@0 472 lg_CertSetupData(&certData,count);
michael@0 473 nsslowcert_TraversePermCertsForNickname(certHandle,tmp_name,
michael@0 474 lg_cert_collect, &certData);
michael@0 475 PORT_Free(tmp_name);
michael@0 476 } else if (derSubject->data != NULL) {
michael@0 477 int count;
michael@0 478
michael@0 479 count = nsslowcert_NumPermCertsForSubject(certHandle,derSubject);
michael@0 480 lg_CertSetupData(&certData,count);
michael@0 481 nsslowcert_TraversePermCertsForSubject(certHandle,derSubject,
michael@0 482 lg_cert_collect, &certData);
michael@0 483 } else if ((issuerSN->derIssuer.data != NULL) &&
michael@0 484 (issuerSN->serialNumber.data != NULL)) {
michael@0 485 if (classFlags & LG_CERT) {
michael@0 486 NSSLOWCERTCertificate *cert =
michael@0 487 nsslowcert_FindCertByIssuerAndSN(certHandle,issuerSN);
michael@0 488
michael@0 489 lg_searchSingleCert(&certData,cert);
michael@0 490 }
michael@0 491 if (classFlags & LG_TRUST) {
michael@0 492 NSSLOWCERTTrust *trust =
michael@0 493 nsslowcert_FindTrustByIssuerAndSN(certHandle, issuerSN);
michael@0 494
michael@0 495 if (trust) {
michael@0 496 lg_addHandle(handles,
michael@0 497 lg_mkHandle(sdb,&trust->dbKey,LG_TOKEN_TYPE_TRUST));
michael@0 498 nsslowcert_DestroyTrust(trust);
michael@0 499 }
michael@0 500 }
michael@0 501 } else if (email->data != NULL) {
michael@0 502 char *tmp_name = (char*)PORT_Alloc(email->len+1);
michael@0 503 certDBEntrySMime *entry = NULL;
michael@0 504
michael@0 505 if (tmp_name == NULL) {
michael@0 506 return;
michael@0 507 }
michael@0 508 PORT_Memcpy(tmp_name,email->data,email->len);
michael@0 509 tmp_name[email->len] = 0;
michael@0 510
michael@0 511 entry = nsslowcert_ReadDBSMimeEntry(certHandle,tmp_name);
michael@0 512 if (entry) {
michael@0 513 int count;
michael@0 514 SECItem *subjectName = &entry->subjectName;
michael@0 515
michael@0 516 count = nsslowcert_NumPermCertsForSubject(certHandle, subjectName);
michael@0 517 lg_CertSetupData(&certData,count);
michael@0 518 nsslowcert_TraversePermCertsForSubject(certHandle, subjectName,
michael@0 519 lg_cert_collect, &certData);
michael@0 520
michael@0 521 nsslowcert_DestroyDBEntry((certDBEntry *)entry);
michael@0 522 }
michael@0 523 PORT_Free(tmp_name);
michael@0 524 } else {
michael@0 525 /* we aren't filtering the certs, we are working on all, so turn
michael@0 526 * on the strict filters. */
michael@0 527 certData.strict = PR_TRUE;
michael@0 528 lg_CertSetupData(&certData,LG_SEARCH_BLOCK_SIZE);
michael@0 529 nsslowcert_TraversePermCerts(certHandle, lg_cert_collect2, &certData);
michael@0 530 }
michael@0 531
michael@0 532 /*
michael@0 533 * build the handles
michael@0 534 */
michael@0 535 for (i=0 ; i < certData.cert_count ; i++) {
michael@0 536 NSSLOWCERTCertificate *cert = certData.certs[i];
michael@0 537
michael@0 538 /* if we filtered it would have been on the stuff above */
michael@0 539 if (classFlags & LG_CERT) {
michael@0 540 lg_addHandle(handles,
michael@0 541 lg_mkHandle(sdb,&cert->certKey,LG_TOKEN_TYPE_CERT));
michael@0 542 }
michael@0 543 if ((classFlags & LG_TRUST) && nsslowcert_hasTrust(cert->trust)) {
michael@0 544 lg_addHandle(handles,
michael@0 545 lg_mkHandle(sdb,&cert->certKey,LG_TOKEN_TYPE_TRUST));
michael@0 546 }
michael@0 547 nsslowcert_DestroyCertificate(cert);
michael@0 548 }
michael@0 549
michael@0 550 if (certData.certs) PORT_Free(certData.certs);
michael@0 551 return;
michael@0 552 }
michael@0 553
michael@0 554 static SECStatus
michael@0 555 lg_smime_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg)
michael@0 556 {
michael@0 557 lgEntryData *smimeData;
michael@0 558 SDB *sdb;
michael@0 559
michael@0 560 smimeData = (lgEntryData *)arg;
michael@0 561 sdb = smimeData->sdb;
michael@0 562
michael@0 563 if (lg_tokenMatch(sdb, key, LG_TOKEN_TYPE_SMIME,
michael@0 564 smimeData->template, smimeData->templ_count)) {
michael@0 565 lg_addHandle(smimeData->searchHandles,
michael@0 566 lg_mkHandle(sdb,key,LG_TOKEN_TYPE_SMIME));
michael@0 567 }
michael@0 568 return(SECSuccess);
michael@0 569 }
michael@0 570
michael@0 571 static void
michael@0 572 lg_searchSMime(SDB *sdb, SECItem *email, SDBFind *handles,
michael@0 573 const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount)
michael@0 574 {
michael@0 575 NSSLOWCERTCertDBHandle *certHandle = NULL;
michael@0 576 certDBEntrySMime *entry;
michael@0 577
michael@0 578 certHandle = lg_getCertDB(sdb);
michael@0 579 if (certHandle == NULL) return;
michael@0 580
michael@0 581 if (email->data != NULL) {
michael@0 582 char *tmp_name = (char*)PORT_Alloc(email->len+1);
michael@0 583
michael@0 584 if (tmp_name == NULL) {
michael@0 585 return;
michael@0 586 }
michael@0 587 PORT_Memcpy(tmp_name,email->data,email->len);
michael@0 588 tmp_name[email->len] = 0;
michael@0 589
michael@0 590 entry = nsslowcert_ReadDBSMimeEntry(certHandle,tmp_name);
michael@0 591 if (entry) {
michael@0 592 SECItem emailKey;
michael@0 593
michael@0 594 emailKey.data = (unsigned char *)tmp_name;
michael@0 595 emailKey.len = PORT_Strlen(tmp_name)+1;
michael@0 596 emailKey.type = 0;
michael@0 597 lg_addHandle(handles,
michael@0 598 lg_mkHandle(sdb,&emailKey,LG_TOKEN_TYPE_SMIME));
michael@0 599 nsslowcert_DestroyDBEntry((certDBEntry *)entry);
michael@0 600 }
michael@0 601 PORT_Free(tmp_name);
michael@0 602 } else {
michael@0 603 /* traverse */
michael@0 604 lgEntryData smimeData;
michael@0 605
michael@0 606 /* traverse */
michael@0 607 smimeData.sdb = sdb;
michael@0 608 smimeData.searchHandles = handles;
michael@0 609 smimeData.template = pTemplate;
michael@0 610 smimeData.templ_count = ulCount;
michael@0 611 nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeSMimeProfile,
michael@0 612 lg_smime_collect, (void *)&smimeData);
michael@0 613 }
michael@0 614 return;
michael@0 615 }
michael@0 616
michael@0 617 static CK_RV
michael@0 618 lg_searchTokenList(SDB *sdb, SDBFind *search,
michael@0 619 const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount)
michael@0 620 {
michael@0 621 int i;
michael@0 622 PRBool isKrl = PR_FALSE;
michael@0 623 SECItem derCert = { siBuffer, NULL, 0 };
michael@0 624 SECItem derSubject = { siBuffer, NULL, 0 };
michael@0 625 SECItem name = { siBuffer, NULL, 0 };
michael@0 626 SECItem email = { siBuffer, NULL, 0 };
michael@0 627 SECItem key_id = { siBuffer, NULL, 0 };
michael@0 628 SECItem cert_sha1_hash = { siBuffer, NULL, 0 };
michael@0 629 SECItem cert_md5_hash = { siBuffer, NULL, 0 };
michael@0 630 NSSLOWCERTIssuerAndSN issuerSN = {
michael@0 631 { siBuffer, NULL, 0 },
michael@0 632 { siBuffer, NULL, 0 }
michael@0 633 };
michael@0 634 SECItem *copy = NULL;
michael@0 635 CK_CERTIFICATE_TYPE certType;
michael@0 636 CK_OBJECT_CLASS objectClass;
michael@0 637 CK_RV crv;
michael@0 638 unsigned long classFlags;
michael@0 639
michael@0 640 if (lg_getCertDB(sdb) == NULL) {
michael@0 641 classFlags = LG_PRIVATE|LG_KEY;
michael@0 642 } else {
michael@0 643 classFlags = LG_CERT|LG_TRUST|LG_PUBLIC|LG_SMIME|LG_CRL;
michael@0 644 }
michael@0 645
michael@0 646 /*
michael@0 647 * look for things to search on token objects for. If the right options
michael@0 648 * are specified, we can use them as direct indeces into the database
michael@0 649 * (rather than using linear searches. We can also use the attributes to
michael@0 650 * limit the kinds of objects we are searching for. Later we can use this
michael@0 651 * array to filter the remaining objects more finely.
michael@0 652 */
michael@0 653 for (i=0 ;classFlags && i < (int)ulCount; i++) {
michael@0 654
michael@0 655 switch (pTemplate[i].type) {
michael@0 656 case CKA_SUBJECT:
michael@0 657 copy = &derSubject;
michael@0 658 classFlags &= (LG_CERT|LG_PRIVATE|LG_PUBLIC|LG_SMIME|LG_CRL);
michael@0 659 break;
michael@0 660 case CKA_ISSUER:
michael@0 661 copy = &issuerSN.derIssuer;
michael@0 662 classFlags &= (LG_CERT|LG_TRUST);
michael@0 663 break;
michael@0 664 case CKA_SERIAL_NUMBER:
michael@0 665 copy = &issuerSN.serialNumber;
michael@0 666 classFlags &= (LG_CERT|LG_TRUST);
michael@0 667 break;
michael@0 668 case CKA_VALUE:
michael@0 669 copy = &derCert;
michael@0 670 classFlags &= (LG_CERT|LG_CRL|LG_SMIME);
michael@0 671 break;
michael@0 672 case CKA_LABEL:
michael@0 673 copy = &name;
michael@0 674 break;
michael@0 675 case CKA_NETSCAPE_EMAIL:
michael@0 676 copy = &email;
michael@0 677 classFlags &= LG_SMIME|LG_CERT;
michael@0 678 break;
michael@0 679 case CKA_NETSCAPE_SMIME_TIMESTAMP:
michael@0 680 classFlags &= LG_SMIME;
michael@0 681 break;
michael@0 682 case CKA_CLASS:
michael@0 683 crv = lg_GetULongAttribute(CKA_CLASS,&pTemplate[i],1, &objectClass);
michael@0 684 if (crv != CKR_OK) {
michael@0 685 classFlags = 0;
michael@0 686 break;
michael@0 687 }
michael@0 688 switch (objectClass) {
michael@0 689 case CKO_CERTIFICATE:
michael@0 690 classFlags &= LG_CERT;
michael@0 691 break;
michael@0 692 case CKO_NETSCAPE_TRUST:
michael@0 693 classFlags &= LG_TRUST;
michael@0 694 break;
michael@0 695 case CKO_NETSCAPE_CRL:
michael@0 696 classFlags &= LG_CRL;
michael@0 697 break;
michael@0 698 case CKO_NETSCAPE_SMIME:
michael@0 699 classFlags &= LG_SMIME;
michael@0 700 break;
michael@0 701 case CKO_PRIVATE_KEY:
michael@0 702 classFlags &= LG_PRIVATE;
michael@0 703 break;
michael@0 704 case CKO_PUBLIC_KEY:
michael@0 705 classFlags &= LG_PUBLIC;
michael@0 706 break;
michael@0 707 case CKO_SECRET_KEY:
michael@0 708 classFlags &= LG_KEY;
michael@0 709 break;
michael@0 710 default:
michael@0 711 classFlags = 0;
michael@0 712 break;
michael@0 713 }
michael@0 714 break;
michael@0 715 case CKA_PRIVATE:
michael@0 716 if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
michael@0 717 classFlags = 0;
michael@0 718 break;
michael@0 719 }
michael@0 720 if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) {
michael@0 721 classFlags &= (LG_PRIVATE|LG_KEY);
michael@0 722 } else {
michael@0 723 classFlags &= ~(LG_PRIVATE|LG_KEY);
michael@0 724 }
michael@0 725 break;
michael@0 726 case CKA_SENSITIVE:
michael@0 727 if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
michael@0 728 classFlags = 0;
michael@0 729 break;
michael@0 730 }
michael@0 731 if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) {
michael@0 732 classFlags &= (LG_PRIVATE|LG_KEY);
michael@0 733 } else {
michael@0 734 classFlags = 0;
michael@0 735 }
michael@0 736 break;
michael@0 737 case CKA_TOKEN:
michael@0 738 if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
michael@0 739 classFlags = 0;
michael@0 740 break;
michael@0 741 }
michael@0 742 if (*((CK_BBOOL *)pTemplate[i].pValue) != CK_TRUE) {
michael@0 743 classFlags = 0;
michael@0 744 }
michael@0 745 break;
michael@0 746 case CKA_CERT_SHA1_HASH:
michael@0 747 classFlags &= LG_TRUST;
michael@0 748 copy = &cert_sha1_hash; break;
michael@0 749 case CKA_CERT_MD5_HASH:
michael@0 750 classFlags &= LG_TRUST;
michael@0 751 copy = &cert_md5_hash; break;
michael@0 752 case CKA_CERTIFICATE_TYPE:
michael@0 753 crv = lg_GetULongAttribute(CKA_CERTIFICATE_TYPE,&pTemplate[i],
michael@0 754 1,&certType);
michael@0 755 if (crv != CKR_OK) {
michael@0 756 classFlags = 0;
michael@0 757 break;
michael@0 758 }
michael@0 759 classFlags &= LG_CERT;
michael@0 760 if (certType != CKC_X_509) {
michael@0 761 classFlags = 0;
michael@0 762 }
michael@0 763 break;
michael@0 764 case CKA_ID:
michael@0 765 copy = &key_id;
michael@0 766 classFlags &= (LG_CERT|LG_PRIVATE|LG_KEY|LG_PUBLIC);
michael@0 767 break;
michael@0 768 case CKA_NETSCAPE_KRL:
michael@0 769 if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) {
michael@0 770 classFlags = 0;
michael@0 771 break;
michael@0 772 }
michael@0 773 classFlags &= LG_CRL;
michael@0 774 isKrl = (PRBool)(*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE);
michael@0 775 break;
michael@0 776 case CKA_MODIFIABLE:
michael@0 777 break;
michael@0 778 case CKA_KEY_TYPE:
michael@0 779 case CKA_DERIVE:
michael@0 780 classFlags &= LG_PUBLIC|LG_PRIVATE|LG_KEY;
michael@0 781 break;
michael@0 782 case CKA_VERIFY_RECOVER:
michael@0 783 classFlags &= LG_PUBLIC;
michael@0 784 break;
michael@0 785 case CKA_SIGN_RECOVER:
michael@0 786 classFlags &= LG_PRIVATE;
michael@0 787 break;
michael@0 788 case CKA_ENCRYPT:
michael@0 789 case CKA_VERIFY:
michael@0 790 case CKA_WRAP:
michael@0 791 classFlags &= LG_PUBLIC|LG_KEY;
michael@0 792 break;
michael@0 793 case CKA_DECRYPT:
michael@0 794 case CKA_SIGN:
michael@0 795 case CKA_UNWRAP:
michael@0 796 case CKA_ALWAYS_SENSITIVE:
michael@0 797 case CKA_EXTRACTABLE:
michael@0 798 case CKA_NEVER_EXTRACTABLE:
michael@0 799 classFlags &= LG_PRIVATE|LG_KEY;
michael@0 800 break;
michael@0 801 /* can't be a certificate if it doesn't match one of the above
michael@0 802 * attributes */
michael@0 803 default:
michael@0 804 classFlags = 0;
michael@0 805 break;
michael@0 806 }
michael@0 807 if (copy) {
michael@0 808 copy->data = (unsigned char*)pTemplate[i].pValue;
michael@0 809 copy->len = pTemplate[i].ulValueLen;
michael@0 810 }
michael@0 811 copy = NULL;
michael@0 812 }
michael@0 813
michael@0 814 /* certs */
michael@0 815 if (classFlags & (LG_CERT|LG_TRUST)) {
michael@0 816 lg_searchCertsAndTrust(sdb,&derCert,&name,&derSubject,
michael@0 817 &issuerSN, &email,classFlags,search,
michael@0 818 pTemplate, ulCount);
michael@0 819 }
michael@0 820
michael@0 821 /* keys */
michael@0 822 if (classFlags & (LG_PRIVATE|LG_PUBLIC|LG_KEY)) {
michael@0 823 PRBool mustStrict = (name.len != 0);
michael@0 824 lg_searchKeys(sdb, &key_id, classFlags, search,
michael@0 825 mustStrict, pTemplate, ulCount);
michael@0 826 }
michael@0 827
michael@0 828 /* crl's */
michael@0 829 if (classFlags & LG_CRL) {
michael@0 830 lg_searchCrls(sdb, &derSubject, isKrl, classFlags, search,
michael@0 831 pTemplate, ulCount);
michael@0 832 }
michael@0 833 /* Add S/MIME entry stuff */
michael@0 834 if (classFlags & LG_SMIME) {
michael@0 835 lg_searchSMime(sdb, &email, search, pTemplate, ulCount);
michael@0 836 }
michael@0 837 return CKR_OK;
michael@0 838 }
michael@0 839
michael@0 840
michael@0 841 /* lg_FindObjectsInit initializes a search for token and session objects
michael@0 842 * that match a template. */
michael@0 843 CK_RV lg_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *pTemplate,
michael@0 844 CK_ULONG ulCount, SDBFind **retSearch)
michael@0 845 {
michael@0 846 SDBFind *search;
michael@0 847 CK_RV crv = CKR_OK;
michael@0 848
michael@0 849 *retSearch = NULL;
michael@0 850
michael@0 851 search = (SDBFind *)PORT_Alloc(sizeof(SDBFind));
michael@0 852 if (search == NULL) {
michael@0 853 crv = CKR_HOST_MEMORY;
michael@0 854 goto loser;
michael@0 855 }
michael@0 856 search->handles = (CK_OBJECT_HANDLE *)
michael@0 857 PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * LG_SEARCH_BLOCK_SIZE);
michael@0 858 if (search->handles == NULL) {
michael@0 859 crv = CKR_HOST_MEMORY;
michael@0 860 goto loser;
michael@0 861 }
michael@0 862 search->index = 0;
michael@0 863 search->size = 0;
michael@0 864 search->array_size = LG_SEARCH_BLOCK_SIZE;
michael@0 865 /* FIXME - do we still need to get Login state? */
michael@0 866
michael@0 867 crv = lg_searchTokenList(sdb, search, pTemplate, ulCount);
michael@0 868 if (crv != CKR_OK) {
michael@0 869 goto loser;
michael@0 870 }
michael@0 871
michael@0 872 *retSearch = search;
michael@0 873 return CKR_OK;
michael@0 874
michael@0 875 loser:
michael@0 876 if (search) {
michael@0 877 lg_FreeSearch(search);
michael@0 878 }
michael@0 879 return crv;
michael@0 880 }
michael@0 881
michael@0 882
michael@0 883 /* lg_FindObjects continues a search for token and session objects
michael@0 884 * that match a template, obtaining additional object handles. */
michael@0 885 CK_RV lg_FindObjects(SDB *sdb, SDBFind *search,
michael@0 886 CK_OBJECT_HANDLE *phObject,CK_ULONG ulMaxObjectCount,
michael@0 887 CK_ULONG *pulObjectCount)
michael@0 888 {
michael@0 889 int transfer;
michael@0 890 int left;
michael@0 891
michael@0 892 *pulObjectCount = 0;
michael@0 893 left = search->size - search->index;
michael@0 894 transfer = ((int)ulMaxObjectCount > left) ? left : ulMaxObjectCount;
michael@0 895 if (transfer > 0) {
michael@0 896 PORT_Memcpy(phObject,&search->handles[search->index],
michael@0 897 transfer*sizeof(CK_OBJECT_HANDLE));
michael@0 898 } else {
michael@0 899 *phObject = CK_INVALID_HANDLE;
michael@0 900 }
michael@0 901
michael@0 902 search->index += transfer;
michael@0 903 *pulObjectCount = transfer;
michael@0 904 return CKR_OK;
michael@0 905 }
michael@0 906
michael@0 907 /* lg_FindObjectsFinal finishes a search for token and session objects. */
michael@0 908 CK_RV lg_FindObjectsFinal(SDB* lgdb, SDBFind *search)
michael@0 909 {
michael@0 910
michael@0 911 if (search != NULL) {
michael@0 912 lg_FreeSearch(search);
michael@0 913 }
michael@0 914 return CKR_OK;
michael@0 915 }

mercurial