5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2005 - 2008 Pekka Riikonen
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.
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.
20 #include "silccrypto.h"
23 /************************** Types and definitions ***************************/
25 /* Search constraints */
27 SILC_SKR_FIND_PKCS_TYPE,
28 SILC_SKR_FIND_USERNAME,
30 SILC_SKR_FIND_REALNAME,
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 */
39 /* Hash table key context */
41 SilcSKRFindType type; /* Type of key */
42 void *data; /* Hash table key */
43 } *SilcSKREntry, SilcSKREntryStruct;
45 /* Foreach user context when finding entries from hash table */
49 SilcSKRKeyUsage usage;
52 #if defined(SILC_DEBUG)
53 static const char *find_name[] = {
66 #endif /* SILC_DEBUG */
68 /************************ Static utility functions **************************/
70 #if defined(SILC_DEBUG)
72 /* Returns search constraint string */
74 static void silc_skr_type_string(SilcSKRFindType type, void *data,
75 char *retbuf, SilcUInt32 retbuf_size)
78 case SILC_SKR_FIND_PKCS_TYPE:
79 case SILC_SKR_FIND_USAGE:
80 silc_snprintf(retbuf, retbuf_size, "[%s] [%d]", find_name[type],
81 (int)SILC_PTR_TO_32(data));
84 case SILC_SKR_FIND_PUBLIC_KEY:
85 case SILC_SKR_FIND_CONTEXT:
86 silc_snprintf(retbuf, retbuf_size, "[%s] [%p]", find_name[type], data);
90 silc_snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type],
94 #endif /* SILC_DEBUG */
96 /* Hash table destructor for search constraints */
98 static void silc_skr_find_destructor(void *key, void *context,
101 SilcSKRFindType type = SILC_PTR_TO_32(key);
102 SilcPKCSType pkcs_type = SILC_PTR_TO_32(user_context);
105 case SILC_SKR_FIND_PKCS_TYPE:
106 case SILC_SKR_FIND_USAGE:
107 case SILC_SKR_FIND_CONTEXT:
110 case SILC_SKR_FIND_PUBLIC_KEY:
111 silc_pkcs_public_key_free(context);
115 /* In SILC and SSH2 keys all entries are referenced from the public key
116 so don't free them. This test is valid only when removing key
117 from the repository. */
118 if (pkcs_type == SILC_PKCS_SILC || pkcs_type == SILC_PKCS_SSH2)
125 /* Hash table destructor for key entries */
127 static void silc_skr_destructor(void *key, void *context, void *user_context)
129 SilcSKREntry type = key;
130 SilcSKRKeyInternal entry = context;
131 SilcPKCSType pkcs_type = silc_pkcs_get_type(entry->key.key);
133 /* Destroy search data, except for SILC_SKR_FIND_PUBLIC_KEY because it
134 shares same context with the key entry. */
135 if (SILC_PTR_TO_32(type->type) != SILC_SKR_FIND_PUBLIC_KEY)
136 silc_skr_find_destructor(SILC_32_TO_PTR(type->type), type->data,
137 SILC_32_TO_PTR(pkcs_type));
142 if (entry->refcnt > 0)
145 SILC_LOG_DEBUG(("Freeing public key %p", entry->key.key));
147 silc_pkcs_public_key_free(entry->key.key);
151 /* Hash table hash function for key entries */
153 static SilcUInt32 silc_skr_hash(void *key, void *user_context)
155 SilcSKREntry type = key;
157 switch (type->type) {
158 case SILC_SKR_FIND_PKCS_TYPE:
159 case SILC_SKR_FIND_CONTEXT:
160 return type->type + (type->type ^ SILC_PTR_TO_32(type->data));
163 case SILC_SKR_FIND_PUBLIC_KEY:
164 return type->type + silc_hash_public_key(type->data, user_context);
171 return type->type + silc_hash_string_case(type->data, user_context);
174 /* Hash table comparison function for key entries */
176 static SilcBool silc_skr_compare(void *key1, void *key2, void *user_context)
178 SilcSKREntry type1 = key1;
179 SilcSKREntry type2 = key2;
181 if (type1->type != type2->type)
184 switch (type1->type) {
185 case SILC_SKR_FIND_PKCS_TYPE:
186 case SILC_SKR_FIND_CONTEXT:
187 return type1->data == type2->data;
190 case SILC_SKR_FIND_PUBLIC_KEY:
191 return silc_hash_public_key_compare(type1->data, type2->data,
199 return silc_utf8_strcasecmp((const char *)type1->data,
200 (const char *)type2->data);
203 /* Foreach function for finding entries in the repository */
205 static void silc_skr_find_foreach(void *key, void *context,
208 SilcSKRFindForeach *f = user_context;
209 SilcSKRKeyInternal k = context;
212 /* If key context is present, it must match the context in the key.
213 This is used only internally when adding keys, to check if the key
214 is added with same context. */
215 if (f->key_context && f->key_context != k->key.key_context)
218 /* Check for usage bits. At least one usage bit must be set. */
219 if (f->usage && k->key.usage && (f->usage & k->key.usage) == 0)
222 silc_dlist_add(f->list, k);
226 /* Finds entry from repository by search constraint type and data */
228 static SilcBool silc_skr_find_entry(SilcSKR skr,
230 SilcSKRFindType type,
234 SilcSKRKeyUsage usage)
236 SilcSKREntryStruct find;
237 SilcSKRFindForeach f;
239 f.list = silc_dlist_init();
241 *status |= SILC_SKR_NO_MEMORY;
244 f.key_context = key_context;
248 find.data = type_data;
250 silc_hash_table_find_foreach(skr->keys, (void *)&find,
251 silc_skr_find_foreach, &f);
253 if (!silc_dlist_count(f.list)) {
254 *status |= SILC_SKR_NOT_FOUND;
255 silc_dlist_uninit(f.list);
262 silc_dlist_uninit(f.list);
267 /* Add a key by search constraint type to repository */
269 static SilcBool silc_skr_add_entry(SilcSKR skr, SilcSKRFindType type,
270 void *type_data, SilcSKRKeyInternal key)
274 #if defined(SILC_DEBUG)
276 memset(tmp, 0, sizeof(tmp));
277 silc_skr_type_string(type, type_data, tmp, sizeof(tmp) - 1);
278 SILC_LOG_DEBUG(("Search constraint %s", tmp));
279 #endif /* SILC_DEBUG */
281 entry = silc_calloc(1, sizeof(*entry));
286 entry->data = type_data;
288 return silc_hash_table_add(skr->keys, entry, key);
291 /* Delete a key by search constraint type from repository */
293 static SilcBool silc_skr_del_entry(SilcSKR skr, SilcSKRFindType type,
294 void *type_data, SilcSKRKeyInternal key)
296 SilcSKREntryStruct entry;
302 entry.data = type_data;
304 return silc_hash_table_del_by_context(skr->keys, &entry, key);
307 /* This performs AND operation. Any entry already in `results' that is not
308 in `list' will be removed from `results'. */
310 static SilcBool silc_skr_results_and(SilcDList list, SilcResult *status,
313 SilcSKRKeyInternal entry, r;
315 if (*results == NULL) {
316 *results = silc_dlist_init();
317 if (*results == NULL) {
318 *status |= SILC_SKR_NO_MEMORY;
323 /* If results is empty, just add all entries from list to results */
324 if (!silc_dlist_count(*results)) {
325 silc_dlist_start(list);
326 while ((entry = silc_dlist_get(list)) != SILC_LIST_END)
327 silc_dlist_add(*results, entry);
332 silc_dlist_start(*results);
333 while ((entry = silc_dlist_get(*results)) != SILC_LIST_END) {
335 /* Check if this entry is in list */
336 silc_dlist_start(list);
337 while ((r = silc_dlist_get(list)) != SILC_LIST_END) {
341 if (r != SILC_LIST_END)
344 /* Remove from results */
345 silc_dlist_del(*results, entry);
348 /* If results became empty, we did not find any key */
349 if (!silc_dlist_count(*results)) {
350 SILC_LOG_DEBUG(("Not all search constraints found"));
351 *status |= SILC_SKR_NOT_FOUND;
359 /***************************** SILC Public Key ******************************/
361 /* Add SILC style public key to repository */
363 static SilcResult silc_skr_add_silc(SilcSKR skr,
364 SilcPublicKey public_key,
365 SilcSKRKeyUsage usage,
367 SilcSKRKey *return_key)
369 SilcSKRKeyInternal key;
370 SilcResult status = SILC_ERR;
371 SilcPublicKeyIdentifier ident;
372 SilcSILCPublicKey silc_pubkey;
373 #if defined(SILC_DEBUG)
375 #endif /* SILC_DEBUG */
377 /* Get the SILC public key */
378 silc_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SILC, public_key);
379 ident = &silc_pubkey->identifier;
381 SILC_LOG_DEBUG(("Adding SILC public key %p [%s], context %p",
382 public_key, ident->username, key_context));
384 silc_mutex_lock(skr->lock);
386 /* Check that this key hasn't been added already */
387 if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
388 public_key, NULL, key_context, 0)) {
389 silc_mutex_unlock(skr->lock);
390 SILC_LOG_DEBUG(("Key already added"));
391 return SILC_ERR_ALREADY_EXISTS;
394 /* Allocate key entry */
395 key = silc_calloc(1, sizeof(*key));
397 silc_mutex_unlock(skr->lock);
401 key->key.usage = usage;
402 key->key.key = public_key;
403 key->key.key_context = key_context;
405 #if defined(SILC_DEBUG)
406 silc_skr_type_string(SILC_SKR_FIND_USAGE, SILC_32_TO_PTR(usage),
407 tmp, sizeof(tmp) - 1);
408 SILC_LOG_DEBUG((" Search constraint %s", tmp));
409 #endif /* SILC_DEBUG */
411 /* Add key specifics */
413 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
418 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PKCS_TYPE,
419 SILC_32_TO_PTR(SILC_PKCS_SILC), key))
423 if (ident->username) {
424 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_USERNAME,
425 ident->username, key))
431 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_HOST,
437 if (ident->realname) {
438 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_REALNAME,
439 ident->realname, key))
445 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_EMAIL,
452 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_ORG,
458 if (ident->country) {
459 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_COUNTRY,
460 ident->country, key))
466 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT,
472 silc_mutex_unlock(skr->lock);
475 *return_key = (SilcSKRKey)key;
480 silc_mutex_unlock(skr->lock);
484 /* Add SILC style public key to repository, and only the public key, not
485 other details from the key. */
487 static SilcResult silc_skr_add_silc_simple(SilcSKR skr,
488 SilcPublicKey public_key,
489 SilcSKRKeyUsage usage,
491 SilcSKRKey *return_key)
493 SilcSKRKeyInternal key;
494 SilcResult status = SILC_ERR;
495 #if defined(SILC_DEBUG)
497 #endif /* SILC_DEBUG */
499 SILC_LOG_DEBUG(("Adding SILC public key"));
501 silc_mutex_lock(skr->lock);
503 /* Check that this key hasn't been added already */
504 if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
505 public_key, NULL, key_context, 0)) {
506 silc_mutex_unlock(skr->lock);
507 SILC_LOG_DEBUG(("Key already added"));
508 return SILC_ERR_ALREADY_EXISTS;
511 /* Allocate key entry */
512 key = silc_calloc(1, sizeof(*key));
514 silc_mutex_unlock(skr->lock);
518 key->key.usage = usage;
519 key->key.key = public_key;
520 key->key.key_context = key_context;
522 #if defined(SILC_DEBUG)
523 silc_skr_type_string(SILC_SKR_FIND_USAGE, SILC_32_TO_PTR(usage),
524 tmp, sizeof(tmp) - 1);
525 SILC_LOG_DEBUG(("Search cons %s", tmp));
526 #endif /* SILC_DEBUG */
528 /* Add key specifics */
530 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
536 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT,
542 silc_mutex_unlock(skr->lock);
545 *return_key = (SilcSKRKey)key;
550 silc_mutex_unlock(skr->lock);
554 /* Deletes SILC public key from repository */
556 static SilcResult silc_skr_del_silc_public_key(SilcSKR skr,
557 SilcPublicKey public_key,
560 SilcResult status = SILC_ERR;
561 SilcPublicKeyIdentifier ident;
562 SilcSILCPublicKey silc_pubkey;
563 SilcSKRKeyInternal key;
566 /* Get the SILC public key */
567 silc_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SILC, public_key);
568 ident = &silc_pubkey->identifier;
570 SILC_LOG_DEBUG(("Deleting SILC public key [%s]", ident->username));
572 silc_mutex_lock(skr->lock);
574 /* Check that this key exists */
575 if (!silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
576 public_key, &entry, key_context, 0)) {
577 silc_mutex_unlock(skr->lock);
578 SILC_LOG_DEBUG(("Key does not exist"));
579 return SILC_ERR_NOT_FOUND;
582 silc_dlist_start(entry);
583 key = silc_dlist_get(entry);
584 silc_dlist_uninit(entry);
586 silc_skr_del_entry(skr, SILC_SKR_FIND_PUBLIC_KEY, public_key, key);
587 silc_skr_del_entry(skr, SILC_SKR_FIND_PKCS_TYPE,
588 SILC_32_TO_PTR(SILC_PKCS_SILC), key);
589 silc_skr_del_entry(skr, SILC_SKR_FIND_USERNAME, ident->username, key);
590 silc_skr_del_entry(skr, SILC_SKR_FIND_HOST, ident->host, key);
591 silc_skr_del_entry(skr, SILC_SKR_FIND_REALNAME, ident->realname, key);
592 silc_skr_del_entry(skr, SILC_SKR_FIND_EMAIL, ident->email, key);
593 silc_skr_del_entry(skr, SILC_SKR_FIND_ORG, ident->org, key);
594 silc_skr_del_entry(skr, SILC_SKR_FIND_COUNTRY, ident->country, key);
595 silc_skr_del_entry(skr, SILC_SKR_FIND_CONTEXT, key_context, key);
597 silc_mutex_unlock(skr->lock);
603 /***************************** SSH2 Public Key ******************************/
605 /* Add SSH2 style public key to repository */
607 static SilcResult silc_skr_add_ssh(SilcSKR skr,
608 SilcPublicKey public_key,
609 SilcSKRKeyUsage usage,
611 SilcSKRKey *return_key)
613 SilcSKRKeyInternal key;
614 SilcResult status = SILC_ERR;
615 SilcSshPublicKey ssh_pubkey;
617 #if defined(SILC_DEBUG)
619 #endif /* SILC_DEBUG */
621 /* Get the SSH public key */
622 ssh_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SSH2, public_key);
625 subject = silc_ssh_public_key_get_field(ssh_pubkey, "Subject");
627 SILC_LOG_DEBUG(("Adding SSH public key %p [%s], context %p", public_key,
628 subject ? subject : "none", key_context));
630 silc_mutex_lock(skr->lock);
632 /* Check that this key hasn't been added already */
633 if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
634 public_key, NULL, key_context, 0)) {
635 silc_mutex_unlock(skr->lock);
636 SILC_LOG_DEBUG(("Key already added"));
637 return SILC_ERR_ALREADY_EXISTS;
640 /* Allocate key entry */
641 key = silc_calloc(1, sizeof(*key));
643 silc_mutex_unlock(skr->lock);
647 key->key.usage = usage;
648 key->key.key = public_key;
649 key->key.key_context = key_context;
651 #if defined(SILC_DEBUG)
652 silc_skr_type_string(SILC_SKR_FIND_USAGE, SILC_32_TO_PTR(usage),
653 tmp, sizeof(tmp) - 1);
654 SILC_LOG_DEBUG((" Search constraint %s", tmp));
655 #endif /* SILC_DEBUG */
657 /* Add key specifics */
659 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
664 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PKCS_TYPE,
665 SILC_32_TO_PTR(SILC_PKCS_SSH2), key))
670 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_USERNAME,
671 (void *)subject, key))
677 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT,
683 silc_mutex_unlock(skr->lock);
686 *return_key = (SilcSKRKey)key;
691 silc_mutex_unlock(skr->lock);
695 /* Add SSH2 style public key to repository. Only the public key is added,
696 not other information from the key. */
698 static SilcResult silc_skr_add_ssh_simple(SilcSKR skr,
699 SilcPublicKey public_key,
700 SilcSKRKeyUsage usage,
702 SilcSKRKey *return_key)
704 SilcSKRKeyInternal key;
705 SilcResult status = SILC_ERR;
706 SilcSshPublicKey ssh_pubkey;
707 #if defined(SILC_DEBUG)
709 #endif /* SILC_DEBUG */
711 /* Get the SSH public key */
712 ssh_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SSH2, public_key);
714 SILC_LOG_DEBUG(("Adding SSH public key %p, context %p", public_key,
717 silc_mutex_lock(skr->lock);
719 /* Check that this key hasn't been added already */
720 if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
721 public_key, NULL, key_context, 0)) {
722 silc_mutex_unlock(skr->lock);
723 SILC_LOG_DEBUG(("Key already added"));
724 return SILC_ERR_ALREADY_EXISTS;
727 /* Allocate key entry */
728 key = silc_calloc(1, sizeof(*key));
730 silc_mutex_unlock(skr->lock);
734 key->key.usage = usage;
735 key->key.key = public_key;
736 key->key.key_context = key_context;
738 #if defined(SILC_DEBUG)
739 silc_skr_type_string(SILC_SKR_FIND_USAGE, SILC_32_TO_PTR(usage),
740 tmp, sizeof(tmp) - 1);
741 SILC_LOG_DEBUG((" Search constraint %s", tmp));
742 #endif /* SILC_DEBUG */
744 /* Add key specifics */
746 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
752 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT,
758 silc_mutex_unlock(skr->lock);
761 *return_key = (SilcSKRKey)key;
766 silc_mutex_unlock(skr->lock);
770 /* Deletes SSH public key from repository */
772 static SilcResult silc_skr_del_ssh_public_key(SilcSKR skr,
773 SilcPublicKey public_key,
776 SilcResult status = SILC_ERR;
777 SilcSshPublicKey ssh_pubkey;
778 SilcSKRKeyInternal key;
782 /* Get the SSH public key */
783 ssh_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SSH2, public_key);
786 subject = silc_ssh_public_key_get_field(ssh_pubkey, "Subject");
788 SILC_LOG_DEBUG(("Deleting SSH public key %p [%s]", public_key,
789 subject ? subject : "none"));
791 silc_mutex_lock(skr->lock);
793 /* Check that this key exists */
794 if (!silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
795 public_key, &entry, key_context, 0)) {
796 silc_mutex_unlock(skr->lock);
797 SILC_LOG_DEBUG(("Key does not exist"));
798 return SILC_ERR_NOT_FOUND;
801 silc_dlist_start(entry);
802 key = silc_dlist_get(entry);
803 silc_dlist_uninit(entry);
805 silc_skr_del_entry(skr, SILC_SKR_FIND_PUBLIC_KEY, public_key, key);
806 silc_skr_del_entry(skr, SILC_SKR_FIND_PKCS_TYPE,
807 SILC_32_TO_PTR(SILC_PKCS_SSH2), key);
808 silc_skr_del_entry(skr, SILC_SKR_FIND_USERNAME, (void *)subject, key);
809 silc_skr_del_entry(skr, SILC_SKR_FIND_CONTEXT, key_context, key);
811 silc_mutex_unlock(skr->lock);
817 /**************************** Key Repository API ****************************/
819 /* Allocate key repository */
821 SilcSKR silc_skr_alloc(void)
825 skr = silc_calloc(1, sizeof(*skr));
829 if (!silc_skr_init(skr)) {
837 /* Free key repository */
839 void silc_skr_free(SilcSKR skr)
841 silc_skr_uninit(skr);
845 /* Initializes key repository */
847 SilcBool silc_skr_init(SilcSKR skr)
849 if (!silc_mutex_alloc(&skr->lock))
852 skr->keys = silc_hash_table_alloc(NULL, 0, silc_skr_hash, NULL,
853 silc_skr_compare, NULL,
854 silc_skr_destructor, NULL, TRUE);
861 /* Uninitializes key repository */
863 void silc_skr_uninit(SilcSKR skr)
866 silc_hash_table_free(skr->keys);
867 silc_mutex_free(skr->lock);
870 /* Adds public key to key repository */
872 SilcResult silc_skr_add_public_key(SilcSKR skr,
873 SilcPublicKey public_key,
874 SilcSKRKeyUsage usage,
876 SilcSKRKey *return_key)
881 return SILC_ERR_INVALID_ARGUMENT;
883 type = silc_pkcs_get_type(public_key);
885 SILC_LOG_DEBUG(("Adding public key %p to repository", public_key));
890 return silc_skr_add_silc(skr, public_key, usage, key_context, return_key);
894 return silc_skr_add_ssh(skr, public_key, usage, key_context, return_key);
901 return SILC_ERR_NOT_SUPPORTED;
904 /* Adds public key to repository. */
906 SilcResult silc_skr_add_public_key_simple(SilcSKR skr,
907 SilcPublicKey public_key,
908 SilcSKRKeyUsage usage,
910 SilcSKRKey *return_key)
915 return SILC_ERR_INVALID_ARGUMENT;
917 type = silc_pkcs_get_type(public_key);
919 SILC_LOG_DEBUG(("Adding public key %p to repository", public_key));
924 return silc_skr_add_silc_simple(skr, public_key, usage, key_context,
929 return silc_skr_add_ssh_simple(skr, public_key, usage, key_context,
937 return SILC_ERR_NOT_SUPPORTED;
940 /* Remove key from repository */
942 SilcResult silc_skr_del_public_key(SilcSKR skr,
943 SilcPublicKey public_key,
949 return SILC_ERR_INVALID_ARGUMENT;
951 type = silc_pkcs_get_type(public_key);
953 SILC_LOG_DEBUG(("Deleting public key %p from repository", public_key));
958 return silc_skr_del_silc_public_key(skr, public_key, key_context);
962 return silc_skr_del_ssh_public_key(skr, public_key, key_context);
969 return SILC_ERR_NOT_SUPPORTED;
974 void silc_skr_ref_public_key(SilcSKR skr, SilcSKRKey key)
976 SilcSKRKeyInternal k = (SilcSKRKeyInternal)key;
978 silc_mutex_lock(skr->lock);
979 SILC_LOG_DEBUG(("SKR key %p ref %d -> %d", k->refcnt, k->refcnt + 1));
981 silc_mutex_unlock(skr->lock);
984 /* Release key reference. */
986 void silc_skr_unref_public_key(SilcSKR skr, SilcSKRKey key)
988 SilcSKRKeyInternal k = (SilcSKRKeyInternal)key;
990 silc_mutex_lock(skr->lock);
992 SILC_LOG_DEBUG(("SKR key %p ref %d -> %d", k->refcnt, k->refcnt - 1));
995 if (k->refcnt == 0) {
996 /* If reference is zero, the key has been removed from the repository
997 already. Just destroy the public key. */
998 silc_pkcs_public_key_free(key->key);
1002 silc_mutex_unlock(skr->lock);
1006 /************************** Search Constraints API **************************/
1008 /* Allocate search constraints */
1010 SilcSKRFind silc_skr_find_alloc(void)
1014 find = silc_calloc(1, sizeof(*find));
1018 find->constr = silc_hash_table_alloc(NULL, 0, silc_hash_uint,
1020 silc_skr_find_destructor, NULL, TRUE);
1021 if (!find->constr) {
1022 silc_skr_find_free(find);
1029 /* Free search constraints */
1031 void silc_skr_find_free(SilcSKRFind find)
1034 silc_hash_table_free(find->constr);
1038 SilcBool silc_skr_find_set_pkcs_type(SilcSKRFind find, SilcPKCSType type)
1040 return silc_hash_table_add(find->constr,
1041 SILC_32_TO_PTR(SILC_SKR_FIND_PKCS_TYPE),
1042 SILC_32_TO_PTR(type));
1045 SilcBool silc_skr_find_set_username(SilcSKRFind find, const char *username)
1047 void *c = silc_memdup(username, strlen(username));
1050 return silc_hash_table_add(find->constr,
1051 SILC_32_TO_PTR(SILC_SKR_FIND_USERNAME), c);
1054 SilcBool silc_skr_find_set_host(SilcSKRFind find, const char *host)
1056 void *c = silc_memdup(host, strlen(host));
1059 return silc_hash_table_add(find->constr,
1060 SILC_32_TO_PTR(SILC_SKR_FIND_HOST), c);
1063 SilcBool silc_skr_find_set_realname(SilcSKRFind find, const char *realname)
1065 void *c = silc_memdup(realname, strlen(realname));
1068 return silc_hash_table_add(find->constr,
1069 SILC_32_TO_PTR(SILC_SKR_FIND_REALNAME), c);
1072 SilcBool silc_skr_find_set_email(SilcSKRFind find, const char *email)
1074 void *c = silc_memdup(email, strlen(email));
1077 return silc_hash_table_add(find->constr,
1078 SILC_32_TO_PTR(SILC_SKR_FIND_EMAIL), c);
1081 SilcBool silc_skr_find_set_org(SilcSKRFind find, const char *org)
1083 void *c = silc_memdup(org, strlen(org));
1086 return silc_hash_table_add(find->constr,
1087 SILC_32_TO_PTR(SILC_SKR_FIND_ORG), c);
1090 SilcBool silc_skr_find_set_country(SilcSKRFind find, const char *country)
1092 void *c = silc_memdup(country, strlen(country));
1095 return silc_hash_table_add(find->constr,
1096 SILC_32_TO_PTR(SILC_SKR_FIND_COUNTRY), c);
1099 SilcBool silc_skr_find_set_public_key(SilcSKRFind find,
1100 SilcPublicKey public_key)
1102 SilcPublicKey pk = silc_pkcs_public_key_copy(public_key);
1105 return silc_hash_table_add(find->constr,
1106 SILC_32_TO_PTR(SILC_SKR_FIND_PUBLIC_KEY), pk);
1109 SilcBool silc_skr_find_set_context(SilcSKRFind find, void *context)
1113 return silc_hash_table_add(find->constr,
1114 SILC_32_TO_PTR(SILC_SKR_FIND_CONTEXT), context);
1117 SilcBool silc_skr_find_set_usage(SilcSKRFind find, SilcSKRKeyUsage usage)
1121 return silc_hash_table_add(find->constr,
1122 SILC_32_TO_PTR(SILC_SKR_FIND_USAGE),
1123 SILC_32_TO_PTR(usage));
1126 /******************************** Search API ********************************/
1128 /* Finds key(s) by the set search constraints. The callback will be called
1129 once keys has been found. */
1130 /* This is now synchronous function but may later change async */
1132 SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSchedule schedule,
1134 SilcSKRFindCallback callback,
1135 void *callback_context)
1137 SilcResult status = SILC_ERR;
1138 SilcHashTableList htl;
1139 SilcDList list, results = NULL;
1140 void *type, *ctx, *usage = NULL;
1141 #if defined(SILC_DEBUG)
1143 #endif /* SILC_DEBUG */
1145 SILC_LOG_DEBUG(("Finding key from repository"));
1147 if (!find || !callback)
1150 silc_mutex_lock(skr->lock);
1152 /* Get usage bits, if searching by them */
1153 silc_hash_table_find(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_USAGE),
1156 #if defined(SILC_DEBUG)
1158 memset(tmp, 0, sizeof(tmp));
1159 silc_skr_type_string(SILC_SKR_FIND_USAGE, usage, tmp, sizeof(tmp) - 1);
1160 SILC_LOG_DEBUG(("Finding key by %s", tmp));
1162 #endif /* SILC_DEBUG */
1164 silc_hash_table_list(find->constr, &htl);
1165 while (silc_hash_table_get(&htl, &type, &ctx)) {
1167 /* SILC_SKR_FIND_USAGE is handled separately while searching the keys. */
1168 if ((SilcSKRFindType)SILC_32_TO_PTR(type) == SILC_SKR_FIND_USAGE)
1171 #if defined(SILC_DEBUG)
1172 memset(tmp, 0, sizeof(tmp));
1173 silc_skr_type_string((SilcSKRFindType)SILC_32_TO_PTR(type),
1174 ctx, tmp, sizeof(tmp) - 1);
1175 SILC_LOG_DEBUG(("Finding key by %s", tmp));
1176 #endif /* SILC_DEBUG */
1178 /* Find entries by this search constraint */
1179 if (!silc_skr_find_entry(skr, &status,
1180 (SilcSKRFindType)SILC_32_TO_PTR(type),
1181 ctx, &list, NULL, SILC_PTR_TO_32(usage))) {
1182 SILC_LOG_DEBUG(("Not found"));
1184 silc_dlist_uninit(results);
1190 /* For now, our logic rule is AND. All constraints must be found
1191 to find the key. Later OR might be added also. */
1192 if (!silc_skr_results_and(list, &status, &results)) {
1193 SILC_LOG_DEBUG(("Not found"));
1195 silc_dlist_uninit(results);
1198 silc_dlist_uninit(list);
1202 silc_dlist_uninit(list);
1204 silc_hash_table_list_reset(&htl);
1206 silc_mutex_unlock(skr->lock);
1208 /* Return results */
1210 callback(skr, find, status, NULL, callback_context);
1212 silc_dlist_start(results);
1213 callback(skr, find, SILC_OK, results, callback_context);