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