1 /*
2
3 silcskr.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2005 - 2007 Pekka Riikonen
8
9 The contents of this file are subject to one of the Licenses specified
10 in the COPYING file; You may not use this file except in compliance
11 with the License.
12
13 The software distributed under the License is distributed on an "AS IS"
14 basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15 KIND, either expressed or implied. See the COPYING file for more
16 information.
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
silc_skr_type_string(SilcSKRFindType type,void * data,char * retbuf,SilcUInt32 retbuf_size)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 silc_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 case SILC_SKR_FIND_CONTEXT:
86 silc_snprintf(retbuf, retbuf_size, "[%s] [%p]", find_name[type], data);
87 break;
88
89 default:
90 silc_snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type],
91 (char *)data);
92 }
93 }
94 #endif /* SILC_DEBUG */
95
96 /* Hash table destructor for search constraints */
97
silc_skr_find_destructor(void * key,void * context,void * user_context)98 static void silc_skr_find_destructor(void *key, void *context,
99 void *user_context)
100 {
101 SilcSKRFindType type = SILC_PTR_TO_32(key);
102 SilcPKCSType pkcs_type = SILC_PTR_TO_32(user_context);
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 /* In SILC Public key 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)
119 break;
120
121 silc_free(context);
122 }
123 }
124
125 /* Hash table destructor for key entries */
126
silc_skr_destructor(void * key,void * context,void * user_context)127 static void silc_skr_destructor(void *key, void *context, void *user_context)
128 {
129 SilcSKREntry type = key;
130 SilcSKRKeyInternal entry = context;
131 SilcPKCSType pkcs_type = silc_pkcs_get_type(entry->key.key);
132
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));
138 silc_free(type);
139
140 /* Destroy key */
141 entry->refcnt--;
142 if (entry->refcnt > 0)
143 return;
144
145 SILC_LOG_DEBUG(("Freeing public key %p", entry->key.key));
146
147 silc_pkcs_public_key_free(entry->key.key);
148 silc_free(entry);
149 }
150
151 /* Hash table hash function for key entries */
152
silc_skr_hash(void * key,void * user_context)153 static SilcUInt32 silc_skr_hash(void *key, void *user_context)
154 {
155 SilcSKREntry type = key;
156
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));
161 break;
162
163 case SILC_SKR_FIND_PUBLIC_KEY:
164 return type->type + silc_hash_public_key(type->data, user_context);
165 break;
166
167 default:
168 break;
169 }
170
171 return type->type + silc_hash_string(type->data, user_context);
172 }
173
174 /* Hash table comparison function for key entries */
175
silc_skr_compare(void * key1,void * key2,void * user_context)176 static SilcBool silc_skr_compare(void *key1, void *key2, void *user_context)
177 {
178 SilcSKREntry type1 = key1;
179 SilcSKREntry type2 = key2;
180
181 if (type1->type != type2->type)
182 return FALSE;
183
184 switch (type1->type) {
185 case SILC_SKR_FIND_PKCS_TYPE:
186 case SILC_SKR_FIND_CONTEXT:
187 return type1->data == type2->data;
188 break;
189
190 case SILC_SKR_FIND_PUBLIC_KEY:
191 return silc_hash_public_key_compare(type1->data, type2->data,
192 user_context);
193 break;
194
195 default:
196 break;
197 }
198
199 return silc_utf8_strcasecmp((const char *)type1->data,
200 (const char *)type2->data);
201 }
202
203 /* Foreach function for finding entries in the repository */
204
silc_skr_find_foreach(void * key,void * context,void * user_context)205 static void silc_skr_find_foreach(void *key, void *context,
206 void *user_context)
207 {
208 SilcSKRFindForeach *f = user_context;
209 SilcSKRKeyInternal k = context;
210
211 if (k) {
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)
216 return;
217
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)
220 return;
221
222 silc_dlist_add(f->list, k);
223 }
224 }
225
226 /* Finds entry from repository by search constraint type and data */
227
silc_skr_find_entry(SilcSKR skr,SilcSKRStatus * status,SilcSKRFindType type,void * type_data,SilcDList * results,void * key_context,SilcSKRKeyUsage usage)228 static SilcBool silc_skr_find_entry(SilcSKR skr,
229 SilcSKRStatus *status,
230 SilcSKRFindType type,
231 void *type_data,
232 SilcDList *results,
233 void *key_context,
234 SilcSKRKeyUsage usage)
235 {
236 SilcSKREntryStruct find;
237 SilcSKRFindForeach f;
238
239 f.list = silc_dlist_init();
240 if (!f.list) {
241 *status |= SILC_SKR_NO_MEMORY;
242 return FALSE;
243 }
244 f.key_context = key_context;
245 f.usage = usage;
246
247 find.type = type;
248 find.data = type_data;
249
250 silc_hash_table_find_foreach(skr->keys, (void *)&find,
251 silc_skr_find_foreach, &f);
252
253 if (!silc_dlist_count(f.list)) {
254 *status |= SILC_SKR_NOT_FOUND;
255 silc_dlist_uninit(f.list);
256 return FALSE;
257 }
258
259 if (results)
260 *results = f.list;
261 else
262 silc_dlist_uninit(f.list);
263
264 return TRUE;
265 }
266
267 /* Add a key by search constraint type to repository */
268
silc_skr_add_entry(SilcSKR skr,SilcSKRFindType type,void * type_data,SilcSKRKeyInternal key)269 static SilcBool silc_skr_add_entry(SilcSKR skr, SilcSKRFindType type,
270 void *type_data, SilcSKRKeyInternal key)
271 {
272 SilcSKREntry entry;
273
274 #if defined(SILC_DEBUG)
275 char tmp[256];
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 */
280
281 entry = silc_calloc(1, sizeof(*entry));
282 if (!entry)
283 return FALSE;
284
285 entry->type = type;
286 entry->data = type_data;
287
288 return silc_hash_table_add(skr->keys, entry, key);
289 }
290
291 /* Delete a key by search constraint type from repository */
292
silc_skr_del_entry(SilcSKR skr,SilcSKRFindType type,void * type_data,SilcSKRKeyInternal key)293 static SilcBool silc_skr_del_entry(SilcSKR skr, SilcSKRFindType type,
294 void *type_data, SilcSKRKeyInternal key)
295 {
296 SilcSKREntryStruct entry;
297
298 if (!type_data)
299 return FALSE;
300
301 entry.type = type;
302 entry.data = type_data;
303
304 return silc_hash_table_del_by_context(skr->keys, &entry, key);
305 }
306
307 /* This performs AND operation. Any entry already in `results' that is not
308 in `list' will be removed from `results'. */
309
silc_skr_results_and(SilcDList list,SilcSKRStatus * status,SilcDList * results)310 static SilcBool silc_skr_results_and(SilcDList list, SilcSKRStatus *status,
311 SilcDList *results)
312 {
313 SilcSKRKeyInternal entry, r;
314
315 if (*results == NULL) {
316 *results = silc_dlist_init();
317 if (*results == NULL) {
318 *status |= SILC_SKR_NO_MEMORY;
319 return FALSE;
320 }
321 }
322
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);
328
329 return TRUE;
330 }
331
332 silc_dlist_start(*results);
333 while ((entry = silc_dlist_get(*results)) != SILC_LIST_END) {
334
335 /* Check if this entry is in list */
336 silc_dlist_start(list);
337 while ((r = silc_dlist_get(list)) != SILC_LIST_END) {
338 if (r == entry)
339 break;
340 }
341 if (r != SILC_LIST_END)
342 continue;
343
344 /* Remove from results */
345 silc_dlist_del(*results, entry);
346 }
347
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;
352 return FALSE;
353 }
354
355 return TRUE;
356 }
357
358
359 /***************************** SILC Public Key ******************************/
360
361 /* Add SILC style public key to repository */
362
silc_skr_add_silc(SilcSKR skr,SilcPublicKey public_key,SilcSKRKeyUsage usage,void * key_context,SilcSKRKey * return_key)363 static SilcSKRStatus silc_skr_add_silc(SilcSKR skr,
364 SilcPublicKey public_key,
365 SilcSKRKeyUsage usage,
366 void *key_context,
367 SilcSKRKey *return_key)
368 {
369 SilcSKRKeyInternal key;
370 SilcSKRStatus status = SILC_SKR_ERROR;
371 SilcPublicKeyIdentifier ident;
372 SilcSILCPublicKey silc_pubkey;
373 #if defined(SILC_DEBUG)
374 char tmp[256];
375 #endif /* SILC_DEBUG */
376
377 /* Get the SILC public key */
378 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
379 ident = &silc_pubkey->identifier;
380
381 SILC_LOG_DEBUG(("Adding SILC public key %p [%s], context %p",
382 public_key, ident->username, key_context));
383
384 silc_mutex_lock(skr->lock);
385
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 status | SILC_SKR_ALREADY_EXIST;
392 }
393
394 /* Allocate key entry */
395 key = silc_calloc(1, sizeof(*key));
396 if (!key) {
397 silc_mutex_unlock(skr->lock);
398 return status | SILC_SKR_NO_MEMORY;
399 }
400
401 key->key.usage = usage;
402 key->key.key = public_key;
403 key->key.key_context = key_context;
404
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 */
410
411 /* Add key specifics */
412
413 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
414 public_key, key))
415 goto err;
416 key->refcnt++;
417
418 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PKCS_TYPE,
419 SILC_32_TO_PTR(SILC_PKCS_SILC), key))
420 goto err;
421 key->refcnt++;
422
423 if (ident->username) {
424 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_USERNAME,
425 ident->username, key))
426 goto err;
427 key->refcnt++;
428 }
429
430 if (ident->host) {
431 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_HOST,
432 ident->host, key))
433 goto err;
434 key->refcnt++;
435 }
436
437 if (ident->realname) {
438 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_REALNAME,
439 ident->realname, key))
440 goto err;
441 key->refcnt++;
442 }
443
444 if (ident->email) {
445 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_EMAIL,
446 ident->email, key))
447 goto err;
448 key->refcnt++;
449 }
450
451 if (ident->org) {
452 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_ORG,
453 ident->org, key))
454 goto err;
455 key->refcnt++;
456 }
457
458 if (ident->country) {
459 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_COUNTRY,
460 ident->country, key))
461 goto err;
462 key->refcnt++;
463 }
464
465 if (key_context) {
466 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT,
467 key_context, key))
468 goto err;
469 key->refcnt++;
470 }
471
472 silc_mutex_unlock(skr->lock);
473
474 if (return_key)
475 *return_key = (SilcSKRKey)key;
476
477 return SILC_SKR_OK;
478
479 err:
480 silc_mutex_unlock(skr->lock);
481 return status;
482 }
483
484 /* Add SILC style public key to repository, and only the public key, not
485 other details from the key. */
486
silc_skr_add_silc_simple(SilcSKR skr,SilcPublicKey public_key,SilcSKRKeyUsage usage,void * key_context,SilcSKRKey * return_key)487 static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr,
488 SilcPublicKey public_key,
489 SilcSKRKeyUsage usage,
490 void *key_context,
491 SilcSKRKey *return_key)
492 {
493 SilcSKRKeyInternal key;
494 SilcSKRStatus status = SILC_SKR_ERROR;
495 #if defined(SILC_DEBUG)
496 char tmp[256];
497 #endif /* SILC_DEBUG */
498
499 SILC_LOG_DEBUG(("Adding SILC public key"));
500
501 silc_mutex_lock(skr->lock);
502
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 status | SILC_SKR_ALREADY_EXIST;
509 }
510
511 /* Allocate key entry */
512 key = silc_calloc(1, sizeof(*key));
513 if (!key) {
514 silc_mutex_unlock(skr->lock);
515 return status | SILC_SKR_NO_MEMORY;
516 }
517
518 key->key.usage = usage;
519 key->key.key = public_key;
520 key->key.key_context = key_context;
521
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 */
527
528 /* Add key specifics */
529
530 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
531 public_key, key))
532 goto err;
533 key->refcnt++;
534
535 if (key_context) {
536 if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT,
537 key_context, key))
538 goto err;
539 key->refcnt++;
540 }
541
542 silc_mutex_unlock(skr->lock);
543
544 if (return_key)
545 *return_key = (SilcSKRKey)key;
546
547 return SILC_SKR_OK;
548
549 err:
550 silc_mutex_unlock(skr->lock);
551 return status;
552 }
553
554 /* Deletes SILC public key from repository */
555
silc_skr_del_silc_public_key(SilcSKR skr,SilcPublicKey public_key,void * key_context)556 static SilcSKRStatus silc_skr_del_silc_public_key(SilcSKR skr,
557 SilcPublicKey public_key,
558 void *key_context)
559 {
560 SilcSKRStatus status = SILC_SKR_ERROR;
561 SilcPublicKeyIdentifier ident;
562 SilcSILCPublicKey silc_pubkey;
563 SilcSKRKeyInternal key;
564 SilcDList entry;
565
566 /* Get the SILC public key */
567 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
568 ident = &silc_pubkey->identifier;
569
570 SILC_LOG_DEBUG(("Deleting SILC public key [%s]", ident->username));
571
572 silc_mutex_lock(skr->lock);
573
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 status | SILC_SKR_NOT_FOUND;
580 }
581
582 silc_dlist_start(entry);
583 key = silc_dlist_get(entry);
584 silc_dlist_uninit(entry);
585
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);
596
597 silc_mutex_unlock(skr->lock);
598
599 return SILC_SKR_OK;
600 }
601
602
603 /**************************** Key Repository API ****************************/
604
605 /* Allocate key repository */
606
silc_skr_alloc(void)607 SilcSKR silc_skr_alloc(void)
608 {
609 SilcSKR skr;
610
611 skr = silc_calloc(1, sizeof(*skr));
612 if (!skr)
613 return NULL;
614
615 if (!silc_skr_init(skr)) {
616 silc_skr_free(skr);
617 return NULL;
618 }
619
620 return skr;
621 }
622
623 /* Free key repository */
624
silc_skr_free(SilcSKR skr)625 void silc_skr_free(SilcSKR skr)
626 {
627 silc_skr_uninit(skr);
628 silc_free(skr);
629 }
630
631 /* Initializes key repository */
632
silc_skr_init(SilcSKR skr)633 SilcBool silc_skr_init(SilcSKR skr)
634 {
635 silc_mutex_alloc(&skr->lock);
636
637 skr->keys = silc_hash_table_alloc(0, silc_skr_hash, NULL,
638 silc_skr_compare, NULL,
639 silc_skr_destructor, NULL, TRUE);
640 if (!skr->keys)
641 return FALSE;
642
643 return TRUE;
644 }
645
646 /* Uninitializes key repository */
647
silc_skr_uninit(SilcSKR skr)648 void silc_skr_uninit(SilcSKR skr)
649 {
650 if (skr->keys)
651 silc_hash_table_free(skr->keys);
652 silc_mutex_free(skr->lock);
653 }
654
655 /* Adds public key to key repository */
656
silc_skr_add_public_key(SilcSKR skr,SilcPublicKey public_key,SilcSKRKeyUsage usage,void * key_context,SilcSKRKey * return_key)657 SilcSKRStatus silc_skr_add_public_key(SilcSKR skr,
658 SilcPublicKey public_key,
659 SilcSKRKeyUsage usage,
660 void *key_context,
661 SilcSKRKey *return_key)
662 {
663 SilcPKCSType type;
664
665 if (!public_key)
666 return SILC_SKR_ERROR;
667
668 type = silc_pkcs_get_type(public_key);
669
670 SILC_LOG_DEBUG(("Adding public key %p to repository", public_key));
671
672 switch (type) {
673
674 case SILC_PKCS_SILC:
675 return silc_skr_add_silc(skr, public_key, usage, key_context, return_key);
676 break;
677
678 default:
679 break;
680 }
681
682 return SILC_SKR_ERROR;
683 }
684
685 /* Adds public key to repository. */
686
silc_skr_add_public_key_simple(SilcSKR skr,SilcPublicKey public_key,SilcSKRKeyUsage usage,void * key_context,SilcSKRKey * return_key)687 SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr,
688 SilcPublicKey public_key,
689 SilcSKRKeyUsage usage,
690 void *key_context,
691 SilcSKRKey *return_key)
692 {
693 SilcPKCSType type;
694
695 if (!public_key)
696 return SILC_SKR_ERROR;
697
698 type = silc_pkcs_get_type(public_key);
699
700 SILC_LOG_DEBUG(("Adding public key %p to repository", public_key));
701
702 switch (type) {
703
704 case SILC_PKCS_SILC:
705 return silc_skr_add_silc_simple(skr, public_key, usage, key_context,
706 return_key);
707 break;
708
709 default:
710 break;
711 }
712
713 return SILC_SKR_ERROR;
714 }
715
716 /* Remove key from repository */
717
silc_skr_del_public_key(SilcSKR skr,SilcPublicKey public_key,void * key_context)718 SilcSKRStatus silc_skr_del_public_key(SilcSKR skr,
719 SilcPublicKey public_key,
720 void *key_context)
721 {
722 SilcPKCSType type;
723
724 if (!public_key)
725 return SILC_SKR_ERROR;
726
727 type = silc_pkcs_get_type(public_key);
728
729 SILC_LOG_DEBUG(("Deleting public key %p from repository", public_key));
730
731 switch (type) {
732
733 case SILC_PKCS_SILC:
734 return silc_skr_del_silc_public_key(skr, public_key, key_context);
735 break;
736
737 default:
738 break;
739 }
740
741 return SILC_SKR_ERROR;
742 }
743
744 /* Reference key */
745
silc_skr_ref_public_key(SilcSKR skr,SilcSKRKey key)746 void silc_skr_ref_public_key(SilcSKR skr, SilcSKRKey key)
747 {
748 SilcSKRKeyInternal k = (SilcSKRKeyInternal)key;
749
750 silc_mutex_lock(skr->lock);
751 SILC_LOG_DEBUG(("SKR key %p ref %d -> %d", k, k->refcnt, k->refcnt + 1));
752 k->refcnt++;
753 silc_mutex_unlock(skr->lock);
754 }
755
756 /* Release key reference. */
757
silc_skr_unref_public_key(SilcSKR skr,SilcSKRKey key)758 void silc_skr_unref_public_key(SilcSKR skr, SilcSKRKey key)
759 {
760 SilcSKRKeyInternal k = (SilcSKRKeyInternal)key;
761
762 silc_mutex_lock(skr->lock);
763
764 SILC_LOG_DEBUG(("SKR key %p ref %d -> %d", k, k->refcnt, k->refcnt - 1));
765 k->refcnt--;
766
767 if (k->refcnt == 0) {
768 /* If reference is zero, the key has been removed from the repository
769 already. Just destroy the public key. */
770 silc_pkcs_public_key_free(key->key);
771 silc_free(key);
772 }
773
774 silc_mutex_unlock(skr->lock);
775 }
776
777
778 /************************** Search Constraints API **************************/
779
780 /* Allocate search constraints */
781
silc_skr_find_alloc(void)782 SilcSKRFind silc_skr_find_alloc(void)
783 {
784 SilcSKRFind find;
785
786 find = silc_calloc(1, sizeof(*find));
787 if (!find)
788 return NULL;
789
790 find->constr = silc_hash_table_alloc(0, silc_hash_uint, NULL, NULL, NULL,
791 silc_skr_find_destructor, NULL, TRUE);
792 if (!find->constr) {
793 silc_skr_find_free(find);
794 return NULL;
795 }
796
797 return find;
798 }
799
800 /* Free search constraints */
801
silc_skr_find_free(SilcSKRFind find)802 void silc_skr_find_free(SilcSKRFind find)
803 {
804 if (find->constr)
805 silc_hash_table_free(find->constr);
806 silc_free(find);
807 }
808
silc_skr_find_set_pkcs_type(SilcSKRFind find,SilcPKCSType type)809 SilcBool silc_skr_find_set_pkcs_type(SilcSKRFind find, SilcPKCSType type)
810 {
811 return silc_hash_table_add(find->constr,
812 SILC_32_TO_PTR(SILC_SKR_FIND_PKCS_TYPE),
813 SILC_32_TO_PTR(type));
814 }
815
silc_skr_find_set_username(SilcSKRFind find,const char * username)816 SilcBool silc_skr_find_set_username(SilcSKRFind find, const char *username)
817 {
818 void *c = silc_memdup(username, strlen(username));
819 if (!c)
820 return FALSE;
821 return silc_hash_table_add(find->constr,
822 SILC_32_TO_PTR(SILC_SKR_FIND_USERNAME), c);
823 }
824
silc_skr_find_set_host(SilcSKRFind find,const char * host)825 SilcBool silc_skr_find_set_host(SilcSKRFind find, const char *host)
826 {
827 void *c = silc_memdup(host, strlen(host));
828 if (!c)
829 return FALSE;
830 return silc_hash_table_add(find->constr,
831 SILC_32_TO_PTR(SILC_SKR_FIND_HOST), c);
832 }
833
silc_skr_find_set_realname(SilcSKRFind find,const char * realname)834 SilcBool silc_skr_find_set_realname(SilcSKRFind find, const char *realname)
835 {
836 void *c = silc_memdup(realname, strlen(realname));
837 if (!c)
838 return FALSE;
839 return silc_hash_table_add(find->constr,
840 SILC_32_TO_PTR(SILC_SKR_FIND_REALNAME), c);
841 }
842
silc_skr_find_set_email(SilcSKRFind find,const char * email)843 SilcBool silc_skr_find_set_email(SilcSKRFind find, const char *email)
844 {
845 void *c = silc_memdup(email, strlen(email));
846 if (!c)
847 return FALSE;
848 return silc_hash_table_add(find->constr,
849 SILC_32_TO_PTR(SILC_SKR_FIND_EMAIL), c);
850 }
851
silc_skr_find_set_org(SilcSKRFind find,const char * org)852 SilcBool silc_skr_find_set_org(SilcSKRFind find, const char *org)
853 {
854 void *c = silc_memdup(org, strlen(org));
855 if (!c)
856 return FALSE;
857 return silc_hash_table_add(find->constr,
858 SILC_32_TO_PTR(SILC_SKR_FIND_ORG), c);
859 }
860
silc_skr_find_set_country(SilcSKRFind find,const char * country)861 SilcBool silc_skr_find_set_country(SilcSKRFind find, const char *country)
862 {
863 void *c = silc_memdup(country, strlen(country));
864 if (!c)
865 return FALSE;
866 return silc_hash_table_add(find->constr,
867 SILC_32_TO_PTR(SILC_SKR_FIND_COUNTRY), c);
868 }
869
silc_skr_find_set_public_key(SilcSKRFind find,SilcPublicKey public_key)870 SilcBool silc_skr_find_set_public_key(SilcSKRFind find,
871 SilcPublicKey public_key)
872 {
873 SilcPublicKey pk = silc_pkcs_public_key_copy(public_key);
874 if (!pk)
875 return FALSE;
876 return silc_hash_table_add(find->constr,
877 SILC_32_TO_PTR(SILC_SKR_FIND_PUBLIC_KEY), pk);
878 }
879
silc_skr_find_set_context(SilcSKRFind find,void * context)880 SilcBool silc_skr_find_set_context(SilcSKRFind find, void *context)
881 {
882 if (!context)
883 return TRUE;
884 return silc_hash_table_add(find->constr,
885 SILC_32_TO_PTR(SILC_SKR_FIND_CONTEXT), context);
886 }
887
silc_skr_find_set_usage(SilcSKRFind find,SilcSKRKeyUsage usage)888 SilcBool silc_skr_find_set_usage(SilcSKRFind find, SilcSKRKeyUsage usage)
889 {
890 if (!usage)
891 return TRUE;
892 return silc_hash_table_add(find->constr,
893 SILC_32_TO_PTR(SILC_SKR_FIND_USAGE),
894 SILC_32_TO_PTR(usage));
895 }
896
897 /******************************** Search API ********************************/
898
899 /* Finds key(s) by the set search constraints. The callback will be called
900 once keys has been found. */
901 /* This is now synchronous function but may later change async */
902
silc_skr_find(SilcSKR skr,SilcSchedule schedule,SilcSKRFind find,SilcSKRFindCallback callback,void * callback_context)903 SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSchedule schedule,
904 SilcSKRFind find,
905 SilcSKRFindCallback callback,
906 void *callback_context)
907 {
908 SilcSKRStatus status = SILC_SKR_ERROR;
909 SilcHashTableList htl;
910 SilcDList list, results = NULL;
911 void *type, *ctx, *usage = NULL;
912 #if defined(SILC_DEBUG)
913 char tmp[256];
914 #endif /* SILC_DEBUG */
915
916 SILC_LOG_DEBUG(("Finding key from repository"));
917
918 if (!find || !callback)
919 return NULL;
920
921 silc_mutex_lock(skr->lock);
922
923 /* Get usage bits, if searching by them */
924 silc_hash_table_find(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_USAGE),
925 NULL, &usage);
926
927 #if defined(SILC_DEBUG)
928 if (usage) {
929 memset(tmp, 0, sizeof(tmp));
930 silc_skr_type_string(SILC_SKR_FIND_USAGE, usage, tmp, sizeof(tmp) - 1);
931 SILC_LOG_DEBUG(("Finding key by %s", tmp));
932 }
933 #endif /* SILC_DEBUG */
934
935 silc_hash_table_list(find->constr, &htl);
936 while (silc_hash_table_get(&htl, &type, &ctx)) {
937
938 /* SILC_SKR_FIND_USAGE is handled separately while searching the keys. */
939 if ((SilcSKRFindType)SILC_32_TO_PTR(type) == SILC_SKR_FIND_USAGE)
940 continue;
941
942 #if defined(SILC_DEBUG)
943 memset(tmp, 0, sizeof(tmp));
944 silc_skr_type_string((SilcSKRFindType)SILC_32_TO_PTR(type),
945 ctx, tmp, sizeof(tmp) - 1);
946 SILC_LOG_DEBUG(("Finding key by %s", tmp));
947 #endif /* SILC_DEBUG */
948
949 /* Find entries by this search constraint */
950 if (!silc_skr_find_entry(skr, &status,
951 (SilcSKRFindType)SILC_32_TO_PTR(type),
952 ctx, &list, NULL, SILC_PTR_TO_32(usage))) {
953 SILC_LOG_DEBUG(("Not found"));
954 if (results) {
955 silc_dlist_uninit(results);
956 results = NULL;
957 }
958 break;
959 }
960
961 /* For now, our logic rule is AND. All constraints must be found
962 to find the key. Later OR might be added also. */
963 if (!silc_skr_results_and(list, &status, &results)) {
964 SILC_LOG_DEBUG(("Not found"));
965 if (results) {
966 silc_dlist_uninit(results);
967 results = NULL;
968 }
969 silc_dlist_uninit(list);
970 break;
971 }
972
973 silc_dlist_uninit(list);
974 }
975 silc_hash_table_list_reset(&htl);
976
977 silc_mutex_unlock(skr->lock);
978
979 /* Return results */
980 if (!results) {
981 callback(skr, find, status, NULL, callback_context);
982 } else {
983 silc_dlist_start(results);
984 callback(skr, find, SILC_SKR_OK, results, callback_context);
985 }
986
987 return NULL;
988 }
989