X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcskr%2Fsilcskr.c;h=f720d34584d7b7157f7c6d8f876311f5a05ee25b;hb=7d4fb45c07b67b027b549f46c3689e44e81b3586;hp=f2317c9e13d34db64ed88f0d95be13b05763b8e9;hpb=99e0d5ed5639b1e1a37b51f0bf8bbaf87d1f6a28;p=crypto.git diff --git a/lib/silcskr/silcskr.c b/lib/silcskr/silcskr.c index f2317c9e..f720d345 100644 --- a/lib/silcskr/silcskr.c +++ b/lib/silcskr/silcskr.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2005 - 2006 Pekka Riikonen + Copyright (C) 2005 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ */ -#include "silc.h" +#include "silccrypto.h" #include "silcskr.h" /************************** Types and definitions ***************************/ @@ -51,16 +51,16 @@ typedef struct { #if defined(SILC_DEBUG) static const char *find_name[] = { - "PKCS TYPE", - "USERNAME", - "HOST", - "REALNAME", - "EMAIL", - "ORG", - "COUNTRY", + "PKCS TYPE ", + "USERNAME ", + "HOST ", + "REALNAME ", + "EMAIL ", + "ORG ", + "COUNTRY ", "PUBLIC KEY", - "CONTEXT", - "USAGE", + "CONTEXT ", + "USAGE ", NULL }; #endif /* SILC_DEBUG */ @@ -77,20 +77,20 @@ static void silc_skr_type_string(SilcSKRFindType type, void *data, switch (type) { case SILC_SKR_FIND_PKCS_TYPE: case SILC_SKR_FIND_USAGE: - snprintf(retbuf, retbuf_size, "[%s] [%d]", find_name[type], - (int)SILC_PTR_TO_32(data)); + silc_snprintf(retbuf, retbuf_size, "[%s] [%d]", find_name[type], + (int)SILC_PTR_TO_32(data)); break; case SILC_SKR_FIND_PUBLIC_KEY: - snprintf(retbuf, retbuf_size, "[%s] [%p]", find_name[type], data); + case SILC_SKR_FIND_CONTEXT: + silc_snprintf(retbuf, retbuf_size, "[%s] [%p]", find_name[type], data); break; default: - snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type], - (char *)data); + silc_snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type], + (char *)data); } } - #endif /* SILC_DEBUG */ /* Hash table destructor for search constraints */ @@ -99,6 +99,7 @@ static void silc_skr_find_destructor(void *key, void *context, void *user_context) { SilcSKRFindType type = SILC_PTR_TO_32(key); + SilcPKCSType pkcs_type = SILC_PTR_TO_32(user_context); switch (type) { case SILC_SKR_FIND_PKCS_TYPE: @@ -111,6 +112,12 @@ static void silc_skr_find_destructor(void *key, void *context, break; default: + /* In SILC and SSH2 keys all entries are referenced from the public key + so don't free them. This test is valid only when removing key + from the repository. */ + if (pkcs_type == SILC_PKCS_SILC || pkcs_type == SILC_PKCS_SSH2) + break; + silc_free(context); } } @@ -121,11 +128,13 @@ static void silc_skr_destructor(void *key, void *context, void *user_context) { SilcSKREntry type = key; SilcSKRKeyInternal entry = context; + SilcPKCSType pkcs_type = silc_pkcs_get_type(entry->key.key); /* Destroy search data, except for SILC_SKR_FIND_PUBLIC_KEY because it shares same context with the key entry. */ if (SILC_PTR_TO_32(type->type) != SILC_SKR_FIND_PUBLIC_KEY) - silc_skr_find_destructor(SILC_32_TO_PTR(type->type), type->data, NULL); + silc_skr_find_destructor(SILC_32_TO_PTR(type->type), type->data, + SILC_32_TO_PTR(pkcs_type)); silc_free(type); /* Destroy key */ @@ -133,6 +142,8 @@ static void silc_skr_destructor(void *key, void *context, void *user_context) if (entry->refcnt > 0) return; + SILC_LOG_DEBUG(("Freeing public key %p", entry->key.key)); + silc_pkcs_public_key_free(entry->key.key); silc_free(entry); } @@ -157,7 +168,7 @@ static SilcUInt32 silc_skr_hash(void *key, void *user_context) break; } - return type->type + silc_hash_string(type->data, user_context); + return type->type + silc_hash_string_case(type->data, user_context); } /* Hash table comparison function for key entries */ @@ -215,7 +226,7 @@ static void silc_skr_find_foreach(void *key, void *context, /* Finds entry from repository by search constraint type and data */ static SilcBool silc_skr_find_entry(SilcSKR skr, - SilcSKRStatus *status, + SilcResult *status, SilcSKRFindType type, void *type_data, SilcDList *results, @@ -260,6 +271,13 @@ static SilcBool silc_skr_add_entry(SilcSKR skr, SilcSKRFindType type, { SilcSKREntry entry; +#if defined(SILC_DEBUG) + char tmp[256]; + memset(tmp, 0, sizeof(tmp)); + silc_skr_type_string(type, type_data, tmp, sizeof(tmp) - 1); + SILC_LOG_DEBUG(("Search constraint %s", tmp)); +#endif /* SILC_DEBUG */ + entry = silc_calloc(1, sizeof(*entry)); if (!entry) return FALSE; @@ -270,23 +288,98 @@ static SilcBool silc_skr_add_entry(SilcSKR skr, SilcSKRFindType type, return silc_hash_table_add(skr->keys, entry, key); } +/* Delete a key by search constraint type from repository */ + +static SilcBool silc_skr_del_entry(SilcSKR skr, SilcSKRFindType type, + void *type_data, SilcSKRKeyInternal key) +{ + SilcSKREntryStruct entry; + + if (!type_data) + return FALSE; + + entry.type = type; + entry.data = type_data; + + return silc_hash_table_del_by_context(skr->keys, &entry, key); +} + +/* This performs AND operation. Any entry already in `results' that is not + in `list' will be removed from `results'. */ + +static SilcBool silc_skr_results_and(SilcDList list, SilcResult *status, + SilcDList *results) +{ + SilcSKRKeyInternal entry, r; + + if (*results == NULL) { + *results = silc_dlist_init(); + if (*results == NULL) { + *status |= SILC_SKR_NO_MEMORY; + return FALSE; + } + } + + /* If results is empty, just add all entries from list to results */ + if (!silc_dlist_count(*results)) { + silc_dlist_start(list); + while ((entry = silc_dlist_get(list)) != SILC_LIST_END) + silc_dlist_add(*results, entry); + + return TRUE; + } + + silc_dlist_start(*results); + while ((entry = silc_dlist_get(*results)) != SILC_LIST_END) { + + /* Check if this entry is in list */ + silc_dlist_start(list); + while ((r = silc_dlist_get(list)) != SILC_LIST_END) { + if (r == entry) + break; + } + if (r != SILC_LIST_END) + continue; + + /* Remove from results */ + silc_dlist_del(*results, entry); + } + + /* If results became empty, we did not find any key */ + if (!silc_dlist_count(*results)) { + SILC_LOG_DEBUG(("Not all search constraints found")); + *status |= SILC_SKR_NOT_FOUND; + return FALSE; + } + + return TRUE; +} + + +/***************************** SILC Public Key ******************************/ + /* Add SILC style public key to repository */ -static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, - SilcPublicKey public_key, - SilcSKRKeyUsage usage, - void *key_context) +static SilcResult silc_skr_add_silc(SilcSKR skr, + SilcPublicKey public_key, + SilcSKRKeyUsage usage, + void *key_context, + SilcSKRKey *return_key) { SilcSKRKeyInternal key; - SilcSKRStatus status = SILC_SKR_ERROR; + SilcResult status = SILC_ERR; SilcPublicKeyIdentifier ident; SilcSILCPublicKey silc_pubkey; +#if defined(SILC_DEBUG) + char tmp[256]; +#endif /* SILC_DEBUG */ /* Get the SILC public key */ - silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key); + silc_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SILC, public_key); ident = &silc_pubkey->identifier; - SILC_LOG_DEBUG(("Adding SILC public key [%s]", ident->username)); + SILC_LOG_DEBUG(("Adding SILC public key %p [%s], context %p", + public_key, ident->username, key_context)); silc_mutex_lock(skr->lock); @@ -295,20 +388,26 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, public_key, NULL, key_context, 0)) { silc_mutex_unlock(skr->lock); SILC_LOG_DEBUG(("Key already added")); - return status | SILC_SKR_ALREADY_EXIST; + return SILC_ERR_ALREADY_EXISTS; } /* Allocate key entry */ key = silc_calloc(1, sizeof(*key)); if (!key) { silc_mutex_unlock(skr->lock); - return status | SILC_SKR_NO_MEMORY; + return silc_errno; } key->key.usage = usage; key->key.key = public_key; key->key.key_context = key_context; +#if defined(SILC_DEBUG) + silc_skr_type_string(SILC_SKR_FIND_USAGE, SILC_32_TO_PTR(usage), + tmp, sizeof(tmp) - 1); + SILC_LOG_DEBUG((" Search constraint %s", tmp)); +#endif /* SILC_DEBUG */ + /* Add key specifics */ if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY, @@ -372,7 +471,10 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, silc_mutex_unlock(skr->lock); - return SILC_SKR_OK; + if (return_key) + *return_key = (SilcSKRKey)key; + + return SILC_OK; err: silc_mutex_unlock(skr->lock); @@ -382,13 +484,17 @@ static SilcSKRStatus silc_skr_add_silc(SilcSKR skr, /* Add SILC style public key to repository, and only the public key, not other details from the key. */ -static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr, - SilcPublicKey public_key, - SilcSKRKeyUsage usage, - void *key_context) +static SilcResult silc_skr_add_silc_simple(SilcSKR skr, + SilcPublicKey public_key, + SilcSKRKeyUsage usage, + void *key_context, + SilcSKRKey *return_key) { SilcSKRKeyInternal key; - SilcSKRStatus status = SILC_SKR_ERROR; + SilcResult status = SILC_ERR; +#if defined(SILC_DEBUG) + char tmp[256]; +#endif /* SILC_DEBUG */ SILC_LOG_DEBUG(("Adding SILC public key")); @@ -399,20 +505,26 @@ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr, public_key, NULL, key_context, 0)) { silc_mutex_unlock(skr->lock); SILC_LOG_DEBUG(("Key already added")); - return status | SILC_SKR_ALREADY_EXIST; + return SILC_ERR_ALREADY_EXISTS; } /* Allocate key entry */ key = silc_calloc(1, sizeof(*key)); if (!key) { silc_mutex_unlock(skr->lock); - return status | SILC_SKR_NO_MEMORY; + return silc_errno; } key->key.usage = usage; key->key.key = public_key; key->key.key_context = key_context; +#if defined(SILC_DEBUG) + silc_skr_type_string(SILC_SKR_FIND_USAGE, SILC_32_TO_PTR(usage), + tmp, sizeof(tmp) - 1); + SILC_LOG_DEBUG(("Search cons %s", tmp)); +#endif /* SILC_DEBUG */ + /* Add key specifics */ if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY, @@ -429,62 +541,276 @@ static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr, silc_mutex_unlock(skr->lock); - return SILC_SKR_OK; + if (return_key) + *return_key = (SilcSKRKey)key; + + return SILC_OK; err: silc_mutex_unlock(skr->lock); return status; } -/* This performs AND operation. Any entry already in `results' that is not - in `list' will be removed from `results'. */ +/* Deletes SILC public key from repository */ -static SilcBool silc_skr_results_and(SilcDList list, SilcSKRStatus *status, - SilcDList *results) +static SilcResult silc_skr_del_silc_public_key(SilcSKR skr, + SilcPublicKey public_key, + void *key_context) { - SilcSKRKeyInternal entry, r; + SilcResult status = SILC_ERR; + SilcPublicKeyIdentifier ident; + SilcSILCPublicKey silc_pubkey; + SilcSKRKeyInternal key; + SilcDList entry; - if (*results == NULL) { - *results = silc_dlist_init(); - if (*results == NULL) { - *status |= SILC_SKR_NO_MEMORY; - return FALSE; - } + /* Get the SILC public key */ + silc_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SILC, public_key); + ident = &silc_pubkey->identifier; + + SILC_LOG_DEBUG(("Deleting SILC public key [%s]", ident->username)); + + silc_mutex_lock(skr->lock); + + /* Check that this key exists */ + if (!silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY, + public_key, &entry, key_context, 0)) { + silc_mutex_unlock(skr->lock); + SILC_LOG_DEBUG(("Key does not exist")); + return SILC_ERR_NOT_FOUND; } - /* If results is empty, just add all entries from list to results */ - if (!silc_dlist_count(*results)) { - silc_dlist_start(list); - while ((entry = silc_dlist_get(list)) != SILC_LIST_END) - silc_dlist_add(*results, entry); + silc_dlist_start(entry); + key = silc_dlist_get(entry); + silc_dlist_uninit(entry); + + silc_skr_del_entry(skr, SILC_SKR_FIND_PUBLIC_KEY, public_key, key); + silc_skr_del_entry(skr, SILC_SKR_FIND_PKCS_TYPE, + SILC_32_TO_PTR(SILC_PKCS_SILC), key); + silc_skr_del_entry(skr, SILC_SKR_FIND_USERNAME, ident->username, key); + silc_skr_del_entry(skr, SILC_SKR_FIND_HOST, ident->host, key); + silc_skr_del_entry(skr, SILC_SKR_FIND_REALNAME, ident->realname, key); + silc_skr_del_entry(skr, SILC_SKR_FIND_EMAIL, ident->email, key); + silc_skr_del_entry(skr, SILC_SKR_FIND_ORG, ident->org, key); + silc_skr_del_entry(skr, SILC_SKR_FIND_COUNTRY, ident->country, key); + silc_skr_del_entry(skr, SILC_SKR_FIND_CONTEXT, key_context, key); - return TRUE; + silc_mutex_unlock(skr->lock); + + return SILC_OK; +} + + +/***************************** SSH2 Public Key ******************************/ + +/* Add SSH2 style public key to repository */ + +static SilcResult silc_skr_add_ssh(SilcSKR skr, + SilcPublicKey public_key, + SilcSKRKeyUsage usage, + void *key_context, + SilcSKRKey *return_key) +{ + SilcSKRKeyInternal key; + SilcResult status = SILC_ERR; + SilcSshPublicKey ssh_pubkey; + const char *subject; +#if defined(SILC_DEBUG) + char tmp[256]; +#endif /* SILC_DEBUG */ + + /* Get the SSH public key */ + ssh_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SSH2, public_key); + + /* Get subject */ + subject = silc_ssh_public_key_get_field(ssh_pubkey, "Subject"); + + SILC_LOG_DEBUG(("Adding SSH public key %p [%s], context %p", public_key, + subject ? subject : "none", key_context)); + + silc_mutex_lock(skr->lock); + + /* Check that this key hasn't been added already */ + if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY, + public_key, NULL, key_context, 0)) { + silc_mutex_unlock(skr->lock); + SILC_LOG_DEBUG(("Key already added")); + return SILC_ERR_ALREADY_EXISTS; } - silc_dlist_start(*results); - while ((entry = silc_dlist_get(*results)) != SILC_LIST_END) { + /* Allocate key entry */ + key = silc_calloc(1, sizeof(*key)); + if (!key) { + silc_mutex_unlock(skr->lock); + return silc_errno; + } - /* Check if this entry is in list */ - silc_dlist_start(list); - while ((r = silc_dlist_get(list)) != SILC_LIST_END) { - if (r == entry) - break; - } - if (r != SILC_LIST_END) - continue; + key->key.usage = usage; + key->key.key = public_key; + key->key.key_context = key_context; - /* Remove from results */ - silc_dlist_del(*results, entry); +#if defined(SILC_DEBUG) + silc_skr_type_string(SILC_SKR_FIND_USAGE, SILC_32_TO_PTR(usage), + tmp, sizeof(tmp) - 1); + SILC_LOG_DEBUG((" Search constraint %s", tmp)); +#endif /* SILC_DEBUG */ + + /* Add key specifics */ + + if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY, + public_key, key)) + goto err; + key->refcnt++; + + if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PKCS_TYPE, + SILC_32_TO_PTR(SILC_PKCS_SSH2), key)) + goto err; + key->refcnt++; + + if (subject) { + if (!silc_skr_add_entry(skr, SILC_SKR_FIND_USERNAME, + (void *)subject, key)) + goto err; + key->refcnt++; } - /* If results became empty, we did not find any key */ - if (!silc_dlist_count(*results)) { - SILC_LOG_DEBUG(("Not all search constraints found")); - *status |= SILC_SKR_NOT_FOUND; - return FALSE; + if (key_context) { + if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT, + key_context, key)) + goto err; + key->refcnt++; } - return TRUE; + silc_mutex_unlock(skr->lock); + + if (return_key) + *return_key = (SilcSKRKey)key; + + return SILC_OK; + + err: + silc_mutex_unlock(skr->lock); + return status; +} + +/* Add SSH2 style public key to repository. Only the public key is added, + not other information from the key. */ + +static SilcResult silc_skr_add_ssh_simple(SilcSKR skr, + SilcPublicKey public_key, + SilcSKRKeyUsage usage, + void *key_context, + SilcSKRKey *return_key) +{ + SilcSKRKeyInternal key; + SilcResult status = SILC_ERR; + SilcSshPublicKey ssh_pubkey; +#if defined(SILC_DEBUG) + char tmp[256]; +#endif /* SILC_DEBUG */ + + /* Get the SSH public key */ + ssh_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SSH2, public_key); + + SILC_LOG_DEBUG(("Adding SSH public key %p, context %p", public_key, + key_context)); + + silc_mutex_lock(skr->lock); + + /* Check that this key hasn't been added already */ + if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY, + public_key, NULL, key_context, 0)) { + silc_mutex_unlock(skr->lock); + SILC_LOG_DEBUG(("Key already added")); + return SILC_ERR_ALREADY_EXISTS; + } + + /* Allocate key entry */ + key = silc_calloc(1, sizeof(*key)); + if (!key) { + silc_mutex_unlock(skr->lock); + return silc_errno; + } + + key->key.usage = usage; + key->key.key = public_key; + key->key.key_context = key_context; + +#if defined(SILC_DEBUG) + silc_skr_type_string(SILC_SKR_FIND_USAGE, SILC_32_TO_PTR(usage), + tmp, sizeof(tmp) - 1); + SILC_LOG_DEBUG((" Search constraint %s", tmp)); +#endif /* SILC_DEBUG */ + + /* Add key specifics */ + + if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY, + public_key, key)) + goto err; + key->refcnt++; + + if (key_context) { + if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT, + key_context, key)) + goto err; + key->refcnt++; + } + + silc_mutex_unlock(skr->lock); + + if (return_key) + *return_key = (SilcSKRKey)key; + + return SILC_OK; + + err: + silc_mutex_unlock(skr->lock); + return status; +} + +/* Deletes SSH public key from repository */ + +static SilcResult silc_skr_del_ssh_public_key(SilcSKR skr, + SilcPublicKey public_key, + void *key_context) +{ + SilcResult status = SILC_ERR; + SilcSshPublicKey ssh_pubkey; + SilcSKRKeyInternal key; + SilcDList entry; + const char *subject; + + /* Get the SSH public key */ + ssh_pubkey = silc_pkcs_public_key_get_pkcs(SILC_PKCS_SSH2, public_key); + + /* Get subject */ + subject = silc_ssh_public_key_get_field(ssh_pubkey, "Subject"); + + SILC_LOG_DEBUG(("Deleting SSH public key %p [%s]", public_key, + subject ? subject : "none")); + + silc_mutex_lock(skr->lock); + + /* Check that this key exists */ + if (!silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY, + public_key, &entry, key_context, 0)) { + silc_mutex_unlock(skr->lock); + SILC_LOG_DEBUG(("Key does not exist")); + return SILC_ERR_NOT_FOUND; + } + + silc_dlist_start(entry); + key = silc_dlist_get(entry); + silc_dlist_uninit(entry); + + silc_skr_del_entry(skr, SILC_SKR_FIND_PUBLIC_KEY, public_key, key); + silc_skr_del_entry(skr, SILC_SKR_FIND_PKCS_TYPE, + SILC_32_TO_PTR(SILC_PKCS_SSH2), key); + silc_skr_del_entry(skr, SILC_SKR_FIND_USERNAME, (void *)subject, key); + silc_skr_del_entry(skr, SILC_SKR_FIND_CONTEXT, key_context, key); + + silc_mutex_unlock(skr->lock); + + return SILC_OK; } @@ -492,7 +818,7 @@ static SilcBool silc_skr_results_and(SilcDList list, SilcSKRStatus *status, /* Allocate key repository */ -SilcSKR silc_skr_alloc(SilcSchedule scheduler) +SilcSKR silc_skr_alloc(void) { SilcSKR skr; @@ -500,7 +826,7 @@ SilcSKR silc_skr_alloc(SilcSchedule scheduler) if (!skr) return NULL; - if (!silc_skr_init(skr, scheduler)) { + if (!silc_skr_init(skr)) { silc_skr_free(skr); return NULL; } @@ -518,17 +844,12 @@ void silc_skr_free(SilcSKR skr) /* Initializes key repository */ -SilcBool silc_skr_init(SilcSKR skr, SilcSchedule scheduler) +SilcBool silc_skr_init(SilcSKR skr) { - if (!scheduler) - return FALSE; - - skr->scheduler = scheduler; - if (!silc_mutex_alloc(&skr->lock)) return FALSE; - skr->keys = silc_hash_table_alloc(0, silc_skr_hash, NULL, + skr->keys = silc_hash_table_alloc(NULL, 0, silc_skr_hash, NULL, silc_skr_compare, NULL, silc_skr_destructor, NULL, TRUE); if (!skr->keys) @@ -548,60 +869,137 @@ void silc_skr_uninit(SilcSKR skr) /* Adds public key to key repository */ -SilcSKRStatus silc_skr_add_public_key(SilcSKR skr, - SilcPublicKey public_key, - SilcSKRKeyUsage usage, - void *key_context) +SilcResult silc_skr_add_public_key(SilcSKR skr, + SilcPublicKey public_key, + SilcSKRKeyUsage usage, + void *key_context, + SilcSKRKey *return_key) { SilcPKCSType type; if (!public_key) - return SILC_SKR_ERROR; + return SILC_ERR_INVALID_ARGUMENT; type = silc_pkcs_get_type(public_key); - SILC_LOG_DEBUG(("Adding public key to repository")); + SILC_LOG_DEBUG(("Adding public key %p to repository", public_key)); switch (type) { case SILC_PKCS_SILC: - return silc_skr_add_silc(skr, public_key, usage, key_context); + return silc_skr_add_silc(skr, public_key, usage, key_context, return_key); + break; + + case SILC_PKCS_SSH2: + return silc_skr_add_ssh(skr, public_key, usage, key_context, return_key); break; default: break; } - return SILC_SKR_ERROR; + return SILC_ERR_NOT_SUPPORTED; } /* Adds public key to repository. */ -SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr, - SilcPublicKey public_key, - SilcSKRKeyUsage usage, - void *key_context) +SilcResult silc_skr_add_public_key_simple(SilcSKR skr, + SilcPublicKey public_key, + SilcSKRKeyUsage usage, + void *key_context, + SilcSKRKey *return_key) +{ + SilcPKCSType type; + + if (!public_key) + return SILC_ERR_INVALID_ARGUMENT; + + type = silc_pkcs_get_type(public_key); + + SILC_LOG_DEBUG(("Adding public key %p to repository", public_key)); + + switch (type) { + + case SILC_PKCS_SILC: + return silc_skr_add_silc_simple(skr, public_key, usage, key_context, + return_key); + break; + + case SILC_PKCS_SSH2: + return silc_skr_add_ssh_simple(skr, public_key, usage, key_context, + return_key); + break; + + default: + break; + } + + return SILC_ERR_NOT_SUPPORTED; +} + +/* Remove key from repository */ + +SilcResult silc_skr_del_public_key(SilcSKR skr, + SilcPublicKey public_key, + void *key_context) { SilcPKCSType type; if (!public_key) - return SILC_SKR_ERROR; + return SILC_ERR_INVALID_ARGUMENT; type = silc_pkcs_get_type(public_key); - SILC_LOG_DEBUG(("Adding public key to repository")); + SILC_LOG_DEBUG(("Deleting public key %p from repository", public_key)); switch (type) { case SILC_PKCS_SILC: - return silc_skr_add_silc_simple(skr, public_key, usage, key_context); + return silc_skr_del_silc_public_key(skr, public_key, key_context); + break; + + case SILC_PKCS_SSH2: + return silc_skr_del_ssh_public_key(skr, public_key, key_context); break; default: break; } - return SILC_SKR_ERROR; + return SILC_ERR_NOT_SUPPORTED; +} + +/* Reference key */ + +void silc_skr_ref_public_key(SilcSKR skr, SilcSKRKey key) +{ + SilcSKRKeyInternal k = (SilcSKRKeyInternal)key; + + silc_mutex_lock(skr->lock); + SILC_LOG_DEBUG(("SKR key %p ref %d -> %d", k->refcnt, k->refcnt + 1)); + k->refcnt++; + silc_mutex_unlock(skr->lock); +} + +/* Release key reference. */ + +void silc_skr_unref_public_key(SilcSKR skr, SilcSKRKey key) +{ + SilcSKRKeyInternal k = (SilcSKRKeyInternal)key; + + silc_mutex_lock(skr->lock); + + SILC_LOG_DEBUG(("SKR key %p ref %d -> %d", k->refcnt, k->refcnt - 1)); + k->refcnt--; + + if (k->refcnt == 0) { + /* If reference is zero, the key has been removed from the repository + already. Just destroy the public key. */ + silc_pkcs_public_key_free(key->key); + silc_free(key); + } + + silc_mutex_unlock(skr->lock); } @@ -617,7 +1015,8 @@ SilcSKRFind silc_skr_find_alloc(void) if (!find) return NULL; - find->constr = silc_hash_table_alloc(0, silc_hash_uint, NULL, NULL, NULL, + find->constr = silc_hash_table_alloc(NULL, 0, silc_hash_uint, + NULL, NULL, NULL, silc_skr_find_destructor, NULL, TRUE); if (!find->constr) { silc_skr_find_free(find); @@ -709,6 +1108,8 @@ SilcBool silc_skr_find_set_public_key(SilcSKRFind find, SilcBool silc_skr_find_set_context(SilcSKRFind find, void *context) { + if (!context) + return TRUE; return silc_hash_table_add(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_CONTEXT), context); } @@ -728,14 +1129,18 @@ SilcBool silc_skr_find_set_usage(SilcSKRFind find, SilcSKRKeyUsage usage) once keys has been found. */ /* This is now synchronous function but may later change async */ -SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find, +SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSchedule schedule, + SilcSKRFind find, SilcSKRFindCallback callback, void *callback_context) { - SilcSKRStatus status = SILC_SKR_ERROR; + SilcResult status = SILC_ERR; SilcHashTableList htl; SilcDList list, results = NULL; void *type, *ctx, *usage = NULL; +#if defined(SILC_DEBUG) + char tmp[256]; +#endif /* SILC_DEBUG */ SILC_LOG_DEBUG(("Finding key from repository")); @@ -748,21 +1153,28 @@ SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find, silc_hash_table_find(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_USAGE), NULL, &usage); +#if defined(SILC_DEBUG) + if (usage) { + memset(tmp, 0, sizeof(tmp)); + silc_skr_type_string(SILC_SKR_FIND_USAGE, usage, tmp, sizeof(tmp) - 1); + SILC_LOG_DEBUG(("Finding key by %s", tmp)); + } +#endif /* SILC_DEBUG */ + silc_hash_table_list(find->constr, &htl); while (silc_hash_table_get(&htl, &type, &ctx)) { + /* SILC_SKR_FIND_USAGE is handled separately while searching the keys. */ + if ((SilcSKRFindType)SILC_32_TO_PTR(type) == SILC_SKR_FIND_USAGE) + continue; + #if defined(SILC_DEBUG) - char tmp[256]; memset(tmp, 0, sizeof(tmp)); silc_skr_type_string((SilcSKRFindType)SILC_32_TO_PTR(type), ctx, tmp, sizeof(tmp) - 1); SILC_LOG_DEBUG(("Finding key by %s", tmp)); #endif /* SILC_DEBUG */ - /* SILC_SKR_FIND_USAGE is handled separately while searching the keys. */ - if ((SilcSKRFindType)SILC_32_TO_PTR(type) == SILC_SKR_FIND_USAGE) - continue; - /* Find entries by this search constraint */ if (!silc_skr_find_entry(skr, &status, (SilcSKRFindType)SILC_32_TO_PTR(type), @@ -798,7 +1210,7 @@ SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find, callback(skr, find, status, NULL, callback_context); } else { silc_dlist_start(results); - callback(skr, find, SILC_SKR_OK, results, callback_context); + callback(skr, find, SILC_OK, results, callback_context); } return NULL;