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