Added SILC Server library.
[silc.git] / lib / silcskr / silcskr.c
1 /*
2
3   silcskr.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2005 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silc.h"
21 #include "silcskr.h"
22
23 /************************** Types and definitions ***************************/
24
25 /* Search constraints */
26 typedef enum {
27   SILC_SKR_FIND_PKCS_TYPE,
28   SILC_SKR_FIND_USERNAME,
29   SILC_SKR_FIND_HOST,
30   SILC_SKR_FIND_REALNAME,
31   SILC_SKR_FIND_EMAIL,
32   SILC_SKR_FIND_ORG,
33   SILC_SKR_FIND_COUNTRY,
34   SILC_SKR_FIND_PUBLIC_KEY,
35   SILC_SKR_FIND_CONTEXT,
36   SILC_SKR_FIND_USAGE,          /* Never added as key specific */
37 } SilcSKRFindType;
38
39 /* Hash table key context */
40 typedef struct {
41   SilcSKRFindType type;         /* Type of key */
42   void *data;                   /* Hash table key */
43 } *SilcSKREntry, SilcSKREntryStruct;
44
45 /* Foreach user context when finding entries from hash table */
46 typedef struct {
47   SilcDList list;
48   void *key_context;
49   SilcSKRKeyUsage usage;
50 } SilcSKRFindForeach;
51
52 #if defined(SILC_DEBUG)
53 static const char *find_name[] = {
54   "PKCS TYPE",
55   "USERNAME",
56   "HOST",
57   "REALNAME",
58   "EMAIL",
59   "ORG",
60   "COUNTRY",
61   "PUBLIC KEY",
62   "CONTEXT",
63   "USAGE",
64   NULL
65 };
66 #endif /* SILC_DEBUG */
67
68 /************************ Static utility functions **************************/
69
70 #if defined(SILC_DEBUG)
71
72 /* Returns search constraint string */
73
74 static void silc_skr_type_string(SilcSKRFindType type, void *data,
75                                  char *retbuf, SilcUInt32 retbuf_size)
76 {
77   switch (type) {
78   case SILC_SKR_FIND_PKCS_TYPE:
79   case SILC_SKR_FIND_USAGE:
80     snprintf(retbuf, retbuf_size, "[%s] [%d]", find_name[type],
81              (int)SILC_PTR_TO_32(data));
82     break;
83
84   case SILC_SKR_FIND_PUBLIC_KEY:
85     snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type],
86              ((SilcPublicKey)data)->identifier);
87     break;
88
89   default:
90     snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type],
91              (char *)data);
92   }
93 }
94
95 #endif /* SILC_DEBUG */
96
97 /* Hash table destructor for search constraints */
98
99 static void silc_skr_find_destructor(void *key, void *context,
100                                      void *user_context)
101 {
102   SilcSKRFindType type = SILC_PTR_TO_32(key);
103
104   switch (type) {
105   case SILC_SKR_FIND_PKCS_TYPE:
106   case SILC_SKR_FIND_USAGE:
107   case SILC_SKR_FIND_CONTEXT:
108     break;
109
110   case SILC_SKR_FIND_PUBLIC_KEY:
111     silc_pkcs_public_key_free(context);
112     break;
113
114   default:
115     silc_free(context);
116   }
117 }
118
119 /* Hash table destructor for key entries */
120
121 static void silc_skr_destructor(void *key, void *context, void *user_context)
122 {
123   SilcSKREntry type = key;
124   SilcSKRKeyInternal entry = context;
125
126   /* Destroy search data, except for SILC_SKR_FIND_PUBLIC_KEY because it
127      shares same context with the key entry. */
128   if (SILC_PTR_TO_32(type->type) != SILC_SKR_FIND_PUBLIC_KEY)
129     silc_skr_find_destructor(SILC_32_TO_PTR(type->type), type->data, NULL);
130   silc_free(type);
131
132   /* Destroy key */
133   entry->refcnt--;
134   if (entry->refcnt == 0) {
135     switch (entry->key.pk_type) {
136     case SILC_PKCS_SILC:
137       silc_pkcs_public_key_free(entry->key.key);
138       break;
139
140     default:
141       break;
142     }
143
144     silc_free(entry);
145   }
146 }
147
148 /* Hash table hash function for key entries */
149
150 static SilcUInt32 silc_skr_hash(void *key, void *user_context)
151 {
152   SilcSKREntry type = key;
153
154   switch (type->type) {
155   case SILC_SKR_FIND_PKCS_TYPE:
156   case SILC_SKR_FIND_CONTEXT:
157     return type->type + (type->type ^ SILC_PTR_TO_32(type->data));
158     break;
159
160   case SILC_SKR_FIND_PUBLIC_KEY:
161     return type->type + silc_hash_public_key(type->data, user_context);
162     break;
163
164   default:
165     break;
166   }
167
168   return type->type + silc_hash_string(type->data, user_context);
169 }
170
171 /* Hash table comparison function for key entries */
172
173 static SilcBool silc_skr_compare(void *key1, void *key2, void *user_context)
174 {
175   SilcSKREntry type1 = key1;
176   SilcSKREntry type2 = key2;
177
178   if (type1->type != type2->type)
179     return FALSE;
180
181   switch (type1->type) {
182   case SILC_SKR_FIND_PKCS_TYPE:
183   case SILC_SKR_FIND_CONTEXT:
184     return type1->data == type2->data;
185     break;
186
187   case SILC_SKR_FIND_PUBLIC_KEY:
188     return silc_hash_public_key_compare(type1->data, type2->data,
189                                         user_context);
190     break;
191
192   default:
193     break;
194   }
195
196   return silc_utf8_strcasecmp((const char *)type1->data,
197                               (const char *)type2->data);
198 }
199
200 /* Foreach function for finding entries in the repository */
201
202 static void silc_skr_find_foreach(void *key, void *context,
203                                   void *user_context)
204 {
205   SilcSKRFindForeach *f = user_context;
206   SilcSKRKeyInternal k = context;
207
208   if (k) {
209     /* If key context is present, it must match the context in the key.
210        This is used only internally when adding keys, to check if the key
211        is added with same context. */
212     if (f->key_context && f->key_context != k->key.key_context)
213       return;
214
215     /* Check for usage bits.  At least one usage bit must be set. */
216     if (f->usage && k->key.usage && (f->usage & k->key.usage) == 0)
217       return;
218
219     silc_dlist_add(f->list, k);
220   }
221 }
222
223 /* Finds entry from repository by search constraint type and data */
224
225 static SilcBool silc_skr_find_entry(SilcSKR skr,
226                                     SilcSKRStatus *status,
227                                     SilcSKRFindType type,
228                                     void *type_data,
229                                     SilcDList *results,
230                                     void *key_context,
231                                     SilcSKRKeyUsage usage)
232 {
233   SilcSKREntryStruct find;
234   SilcSKRFindForeach f;
235
236   f.list = silc_dlist_init();
237   if (!f.list) {
238     *status |= SILC_SKR_NO_MEMORY;
239     return FALSE;
240   }
241   f.key_context = key_context;
242   f.usage = usage;
243
244   find.type = type;
245   find.data = type_data;
246
247   silc_hash_table_find_foreach(skr->keys, (void *)&find,
248                                silc_skr_find_foreach, &f);
249
250   if (!silc_dlist_count(f.list)) {
251     *status |= SILC_SKR_NOT_FOUND;
252     silc_dlist_uninit(f.list);
253     return FALSE;
254   }
255
256   if (results)
257     *results = f.list;
258   else
259     silc_dlist_uninit(f.list);
260
261   return TRUE;
262 }
263
264 /* Add a key by search constraint type to repository */
265
266 static SilcBool silc_skr_add_entry(SilcSKR skr, SilcSKRFindType type,
267                                    void *type_data, SilcSKRKeyInternal key)
268 {
269   SilcSKREntry entry;
270
271   entry = silc_calloc(1, sizeof(*entry));
272   if (!entry)
273     return FALSE;
274
275   entry->type = type;
276   entry->data = type_data;
277
278   return silc_hash_table_add(skr->keys, entry, key);
279 }
280
281 /* Add SILC style public key to repository */
282
283 static SilcSKRStatus silc_skr_add_silc(SilcSKR skr,
284                                        SilcPublicKey public_key,
285                                        SilcSKRKeyUsage usage,
286                                        void *key_context)
287 {
288   SilcPublicKeyIdentifier ident = NULL;
289   SilcSKRKeyInternal key;
290   SilcSKRStatus status = SILC_SKR_ERROR;
291
292   SILC_LOG_DEBUG(("Adding SILC public key [%s]", public_key->identifier));
293
294   silc_mutex_lock(skr->lock);
295
296   /* Check that this key hasn't been added already */
297   if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
298                           public_key, NULL, key_context, 0)) {
299     silc_mutex_unlock(skr->lock);
300     SILC_LOG_DEBUG(("Key already added"));
301     return status;
302   }
303
304   /* Allocate key entry */
305   key = silc_calloc(1, sizeof(*key));
306   if (!key) {
307     silc_mutex_unlock(skr->lock);
308     return status | SILC_SKR_NO_MEMORY;
309   }
310
311   key->key.usage = usage;
312   key->key.pk_type = public_key->pk_type;
313   key->key.key = public_key;
314   key->key.key_context = key_context;
315
316   ident = silc_pkcs_decode_identifier(public_key->identifier);
317   if (!ident) {
318     silc_mutex_unlock(skr->lock);
319     silc_pkcs_free_identifier(ident);
320     return status | SILC_SKR_NO_MEMORY;
321   }
322
323   /* Add key specifics */
324
325   if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
326                           public_key, key))
327     goto err;
328   key->refcnt++;
329
330   if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PKCS_TYPE,
331                           SILC_32_TO_PTR(public_key->pk_type), key))
332     goto err;
333   key->refcnt++;
334
335   if (ident->username) {
336     if (!silc_skr_add_entry(skr, SILC_SKR_FIND_USERNAME,
337                             ident->username, key))
338       goto err;
339     key->refcnt++;
340   }
341
342   if (ident->host) {
343     if (!silc_skr_add_entry(skr, SILC_SKR_FIND_HOST,
344                             ident->host, key))
345       goto err;
346     key->refcnt++;
347   }
348
349   if (ident->realname) {
350     if (!silc_skr_add_entry(skr, SILC_SKR_FIND_REALNAME,
351                             ident->realname, key))
352       goto err;
353     key->refcnt++;
354   }
355
356   if (ident->email) {
357     if (!silc_skr_add_entry(skr, SILC_SKR_FIND_EMAIL,
358                             ident->email, key))
359       goto err;
360     key->refcnt++;
361   }
362
363   if (ident->org) {
364     if (!silc_skr_add_entry(skr, SILC_SKR_FIND_ORG,
365                             ident->org, key))
366       goto err;
367     key->refcnt++;
368   }
369
370   if (ident->country) {
371     if (!silc_skr_add_entry(skr, SILC_SKR_FIND_COUNTRY,
372                             ident->country, key))
373       goto err;
374     key->refcnt++;
375   }
376
377   if (key_context) {
378     if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT,
379                             key_context, key))
380       goto err;
381     key->refcnt++;
382   }
383
384   silc_mutex_unlock(skr->lock);
385
386   silc_free(ident);
387   return SILC_SKR_OK;
388
389  err:
390   silc_mutex_unlock(skr->lock);
391   silc_free(ident);
392   return status;
393 }
394
395 /* Add SILC style public key to repository, and only the public key, not
396    other details from the key. */
397
398 static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr,
399                                               SilcPublicKey public_key,
400                                               SilcSKRKeyUsage usage,
401                                               void *key_context)
402 {
403   SilcSKRKeyInternal key;
404   SilcSKRStatus status = SILC_SKR_ERROR;
405
406   SILC_LOG_DEBUG(("Adding SILC public key [%s]", public_key->identifier));
407
408   silc_mutex_lock(skr->lock);
409
410   /* Check that this key hasn't been added already */
411   if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
412                           public_key, NULL, key_context, 0)) {
413     silc_mutex_unlock(skr->lock);
414     SILC_LOG_DEBUG(("Key already added"));
415     return status;
416   }
417
418   /* Allocate key entry */
419   key = silc_calloc(1, sizeof(*key));
420   if (!key) {
421     silc_mutex_unlock(skr->lock);
422     return status | SILC_SKR_NO_MEMORY;
423   }
424
425   key->key.usage = usage;
426   key->key.pk_type = public_key->pk_type;
427   key->key.key = public_key;
428   key->key.key_context = key_context;
429
430   /* Add key specifics */
431
432   if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
433                           public_key, key))
434     goto err;
435   key->refcnt++;
436
437   if (key_context) {
438     if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT,
439                             key_context, key))
440       goto err;
441     key->refcnt++;
442   }
443
444   silc_mutex_unlock(skr->lock);
445
446   return SILC_SKR_OK;
447
448  err:
449   silc_mutex_unlock(skr->lock);
450   return status;
451 }
452
453 /* This performs AND operation.  Any entry already in `results' that is not
454    in `list' will be removed from `results'. */
455
456 static SilcBool silc_skr_results_and(SilcDList list, SilcSKRStatus *status,
457                                      SilcDList *results)
458 {
459   SilcSKRKeyInternal entry, r;
460
461   if (*results == NULL) {
462     *results = silc_dlist_init();
463     if (*results == NULL) {
464       *status |= SILC_SKR_NO_MEMORY;
465       return FALSE;
466     }
467   }
468
469   /* If results is empty, just add all entries from list to results */
470   if (!silc_dlist_count(*results)) {
471     silc_dlist_start(list);
472     while ((entry = silc_dlist_get(list)) != SILC_LIST_END)
473       silc_dlist_add(*results, entry);
474
475     return TRUE;
476   }
477
478   silc_dlist_start(*results);
479   while ((entry = silc_dlist_get(*results)) != SILC_LIST_END) {
480
481     /* Check if this entry is in list  */
482     silc_dlist_start(list);
483     while ((r = silc_dlist_get(list)) != SILC_LIST_END) {
484       if (r == entry)
485         break;
486     }
487     if (r != SILC_LIST_END)
488       continue;
489
490     /* Remove from results */
491     silc_dlist_del(*results, entry);
492   }
493
494   /* If results became empty, we did not find any key */
495   if (!silc_dlist_count(*results)) {
496     SILC_LOG_DEBUG(("Not all search constraints found"));
497     *status |= SILC_SKR_NOT_FOUND;
498     return FALSE;
499   }
500
501   return TRUE;
502 }
503
504
505 /**************************** Key Repository API ****************************/
506
507 /* Allocate key repository */
508
509 SilcSKR silc_skr_alloc(SilcSchedule scheduler)
510 {
511   SilcSKR skr;
512
513   skr = silc_calloc(1, sizeof(*skr));
514   if (!skr)
515     return NULL;
516
517   if (!silc_skr_init(skr, scheduler)) {
518     silc_skr_free(skr);
519     return NULL;
520   }
521
522   return skr;
523 }
524
525 /* Free key repository */
526
527 void silc_skr_free(SilcSKR skr)
528 {
529   silc_skr_uninit(skr);
530   silc_free(skr);
531 }
532
533 /* Initializes key repository */
534
535 SilcBool silc_skr_init(SilcSKR skr, SilcSchedule scheduler)
536 {
537   if (!scheduler)
538     return FALSE;
539
540   skr->scheduler = scheduler;
541
542   if (!silc_mutex_alloc(&skr->lock))
543     return FALSE;
544
545   skr->keys = silc_hash_table_alloc(0, silc_skr_hash, NULL,
546                                     silc_skr_compare, NULL,
547                                     silc_skr_destructor, NULL, TRUE);
548   if (!skr->keys)
549     return FALSE;
550
551   return TRUE;
552 }
553
554 /* Uninitializes key repository */
555
556 void silc_skr_uninit(SilcSKR skr)
557 {
558   if (skr->keys)
559     silc_hash_table_free(skr->keys);
560   silc_mutex_free(skr->lock);
561 }
562
563 /* Adds public key to key repository */
564
565 SilcSKRStatus silc_skr_add_public_key(SilcSKR skr,
566                                       SilcPublicKey public_key,
567                                       SilcSKRKeyUsage usage,
568                                       void *key_context)
569 {
570   if (!public_key)
571     return SILC_SKR_ERROR;
572
573   SILC_LOG_DEBUG(("Adding public key to repository"));
574
575   switch (public_key->pk_type) {
576
577   case SILC_PKCS_SILC:
578     return silc_skr_add_silc(skr, public_key, usage, key_context);
579     break;
580
581   default:
582     break;
583   }
584
585   return SILC_SKR_ERROR;
586 }
587
588 /* Adds public key to repository. */
589
590 SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr,
591                                              SilcPublicKey public_key,
592                                              SilcSKRKeyUsage usage,
593                                              void *key_context)
594 {
595   if (!public_key)
596     return SILC_SKR_ERROR;
597
598   SILC_LOG_DEBUG(("Adding public key to repository"));
599
600   switch (public_key->pk_type) {
601
602   case SILC_PKCS_SILC:
603     return silc_skr_add_silc_simple(skr, public_key, usage, key_context);
604     break;
605
606   default:
607     break;
608   }
609
610   return SILC_SKR_ERROR;
611 }
612
613
614 /************************** Search Constraints API **************************/
615
616 /* Allocate search constraints */
617
618 SilcSKRFind silc_skr_find_alloc(void)
619 {
620   SilcSKRFind find;
621
622   find = silc_calloc(1, sizeof(*find));
623   if (!find)
624     return NULL;
625
626   find->constr = silc_hash_table_alloc(0, silc_hash_uint, NULL, NULL, NULL,
627                                        silc_skr_find_destructor, NULL, TRUE);
628   if (!find->constr) {
629     silc_skr_find_free(find);
630     return NULL;
631   }
632
633   return find;
634 }
635
636 /* Free search constraints */
637
638 void silc_skr_find_free(SilcSKRFind find)
639 {
640   if (find->constr)
641     silc_hash_table_free(find->constr);
642   silc_free(find);
643 }
644
645 SilcBool silc_skr_find_set_pkcs_type(SilcSKRFind find, SilcPKCSType type)
646 {
647   return silc_hash_table_add(find->constr,
648                              SILC_32_TO_PTR(SILC_SKR_FIND_PKCS_TYPE),
649                              SILC_32_TO_PTR(type));
650 }
651
652 SilcBool silc_skr_find_set_username(SilcSKRFind find, const char *username)
653 {
654   void *c = silc_memdup(username, strlen(username));
655   if (!c)
656     return FALSE;
657   return silc_hash_table_add(find->constr,
658                              SILC_32_TO_PTR(SILC_SKR_FIND_USERNAME), c);
659 }
660
661 SilcBool silc_skr_find_set_host(SilcSKRFind find, const char *host)
662 {
663   void *c = silc_memdup(host, strlen(host));
664   if (!c)
665     return FALSE;
666   return silc_hash_table_add(find->constr,
667                              SILC_32_TO_PTR(SILC_SKR_FIND_HOST), c);
668 }
669
670 SilcBool silc_skr_find_set_realname(SilcSKRFind find, const char *realname)
671 {
672   void *c = silc_memdup(realname, strlen(realname));
673   if (!c)
674     return FALSE;
675   return silc_hash_table_add(find->constr,
676                              SILC_32_TO_PTR(SILC_SKR_FIND_REALNAME), c);
677 }
678
679 SilcBool silc_skr_find_set_email(SilcSKRFind find, const char *email)
680 {
681   void *c = silc_memdup(email, strlen(email));
682   if (!c)
683     return FALSE;
684   return silc_hash_table_add(find->constr,
685                              SILC_32_TO_PTR(SILC_SKR_FIND_EMAIL), c);
686 }
687
688 SilcBool silc_skr_find_set_org(SilcSKRFind find, const char *org)
689 {
690   void *c = silc_memdup(org, strlen(org));
691   if (!c)
692     return FALSE;
693   return silc_hash_table_add(find->constr,
694                              SILC_32_TO_PTR(SILC_SKR_FIND_ORG), c);
695 }
696
697 SilcBool silc_skr_find_set_country(SilcSKRFind find, const char *country)
698 {
699   void *c = silc_memdup(country, strlen(country));
700   if (!c)
701     return FALSE;
702   return silc_hash_table_add(find->constr,
703                              SILC_32_TO_PTR(SILC_SKR_FIND_COUNTRY), c);
704 }
705
706 SilcBool silc_skr_find_set_public_key(SilcSKRFind find,
707                                       SilcPublicKey public_key)
708 {
709   SilcPublicKey pk = silc_pkcs_public_key_copy(public_key);
710   if (!pk)
711     return FALSE;
712   return silc_hash_table_add(find->constr,
713                              SILC_32_TO_PTR(SILC_SKR_FIND_PUBLIC_KEY), pk);
714 }
715
716 SilcBool silc_skr_find_set_context(SilcSKRFind find, void *context)
717 {
718   return silc_hash_table_add(find->constr,
719                              SILC_32_TO_PTR(SILC_SKR_FIND_CONTEXT), context);
720 }
721
722 SilcBool silc_skr_find_set_usage(SilcSKRFind find, SilcSKRKeyUsage usage)
723 {
724   if (!usage)
725     return TRUE;
726   return silc_hash_table_add(find->constr,
727                              SILC_32_TO_PTR(SILC_SKR_FIND_USAGE),
728                              SILC_32_TO_PTR(usage));
729 }
730
731 /******************************** Search API ********************************/
732
733 /* Finds key(s) by the set search constraints.  The callback will be called
734    once keys has been found. */
735 /* This is now synchronous function but may later change async */
736
737 SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find,
738                                  SilcSKRFindCallback callback,
739                                  void *callback_context)
740 {
741   SilcSKRStatus status = SILC_SKR_ERROR;
742   SilcHashTableList htl;
743   SilcDList list, results = NULL;
744   void *type, *ctx, *usage = NULL;
745
746   SILC_LOG_DEBUG(("Finding key from repository"));
747
748   if (!find || !callback)
749     return NULL;
750
751   silc_mutex_lock(skr->lock);
752
753   /* Get usage bits, if searching by them */
754   silc_hash_table_find(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_USAGE),
755                        NULL, &usage);
756
757   silc_hash_table_list(find->constr, &htl);
758   while (silc_hash_table_get(&htl, &type, &ctx)) {
759
760 #if defined(SILC_DEBUG)
761     char tmp[256];
762     memset(tmp, 0, sizeof(tmp));
763     silc_skr_type_string((SilcSKRFindType)SILC_32_TO_PTR(type),
764                          ctx, tmp, sizeof(tmp) - 1);
765     SILC_LOG_DEBUG(("Finding key by %s", tmp));
766 #endif /* SILC_DEBUG */
767
768     /* SILC_SKR_FIND_USAGE is handled separately while searching the keys. */
769     if ((SilcSKRFindType)SILC_32_TO_PTR(type) == SILC_SKR_FIND_USAGE)
770       continue;
771
772     /* Find entries by this search constraint */
773     if (!silc_skr_find_entry(skr, &status,
774                              (SilcSKRFindType)SILC_32_TO_PTR(type),
775                              ctx, &list, NULL, SILC_PTR_TO_32(usage))) {
776       SILC_LOG_DEBUG(("Not found"));
777       if (results) {
778         silc_dlist_uninit(results);
779         results = NULL;
780       }
781       break;
782     }
783
784     /* For now, our logic rule is AND.  All constraints must be found
785        to find the key.  Later OR might be added also. */
786     if (!silc_skr_results_and(list, &status, &results)) {
787       SILC_LOG_DEBUG(("Not found"));
788       if (results) {
789         silc_dlist_uninit(results);
790         results = NULL;
791       }
792       silc_dlist_uninit(list);
793       break;
794     }
795
796     silc_dlist_uninit(list);
797   }
798   silc_hash_table_list_reset(&htl);
799
800   silc_mutex_unlock(skr->lock);
801
802   /* Return results */
803   if (!results) {
804     callback(skr, find, status, NULL, callback_context);
805   } else {
806     silc_dlist_start(results);
807     callback(skr, find, SILC_SKR_OK, results, callback_context);
808   }
809
810   return NULL;
811 }
812
813 /* Helper function to find specificly SILC style public keys */
814
815 SilcAsyncOperation silc_skr_find_silc(SilcSKR skr,
816                                       SilcPublicKey public_key,
817                                       SilcSKRFindCallback callback,
818                                       void *callback_context)
819 {
820   SilcSKRFind find = NULL;
821   SilcAsyncOperation op;
822
823   SILC_LOG_DEBUG(("Finding SILC public key"));
824
825   if (!public_key || public_key->pk_type != SILC_PKCS_SILC)
826     goto err;
827
828   find = silc_skr_find_alloc();
829   if (!find)
830     goto err;
831
832   if (!silc_skr_find_set_public_key(find, public_key))
833     goto err;
834
835   op = silc_skr_find(skr, find, callback, callback_context);
836
837   return op;
838
839  err:
840   if (find)
841     silc_skr_find_free(find);
842   callback(skr, NULL, SILC_SKR_ERROR, NULL, callback_context);
843   return NULL;
844 }