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