#include "silc.h"
#include "silcskr.h"
-/* XXX Locking, when removing keys */
-
/************************** Types and definitions ***************************/
/* Search constraints */
break;
case SILC_SKR_FIND_PUBLIC_KEY:
+ case SILC_SKR_FIND_CONTEXT:
silc_snprintf(retbuf, retbuf_size, "[%s] [%p]", find_name[type], data);
break;
(char *)data);
}
}
-
#endif /* SILC_DEBUG */
/* Hash table destructor for search constraints */
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:
break;
default:
+ /* In SILC Public key 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)
+ break;
+
silc_free(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 */
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);
}
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, SilcSKRStatus *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)
+ void *key_context,
+ SilcSKRKey *return_key)
{
SilcSKRKeyInternal key;
SilcSKRStatus status = SILC_SKR_ERROR;
silc_mutex_unlock(skr->lock);
+ if (return_key)
+ *return_key = (SilcSKRKey)key;
+
return SILC_SKR_OK;
err:
static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr,
SilcPublicKey public_key,
SilcSKRKeyUsage usage,
- void *key_context)
+ void *key_context,
+ SilcSKRKey *return_key)
{
SilcSKRKeyInternal key;
SilcSKRStatus status = SILC_SKR_ERROR;
silc_mutex_unlock(skr->lock);
+ if (return_key)
+ *return_key = (SilcSKRKey)key;
+
return SILC_SKR_OK;
err:
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 SilcSKRStatus silc_skr_del_silc_public_key(SilcSKR skr,
+ SilcPublicKey public_key,
+ void *key_context)
{
- 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);
+ SilcSKRStatus status = SILC_SKR_ERROR;
+ SilcPublicKeyIdentifier ident;
+ SilcSILCPublicKey silc_pubkey;
+ SilcSKRKeyInternal key;
+ SilcDList entry;
- return TRUE;
- }
+ /* Get the SILC public key */
+ silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
+ ident = &silc_pubkey->identifier;
- silc_dlist_start(*results);
- while ((entry = silc_dlist_get(*results)) != SILC_LIST_END) {
+ SILC_LOG_DEBUG(("Deleting SILC public key [%s]", ident->username));
- /* 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;
+ silc_mutex_lock(skr->lock);
- /* Remove from results */
- silc_dlist_del(*results, entry);
+ /* 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 status | SILC_SKR_NOT_FOUND;
}
- /* 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;
- }
+ 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_SKR_OK;
}
SilcSKRStatus silc_skr_add_public_key(SilcSKR skr,
SilcPublicKey public_key,
SilcSKRKeyUsage usage,
- void *key_context)
+ void *key_context,
+ SilcSKRKey *return_key)
{
SilcPKCSType type;
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;
default:
SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr,
SilcPublicKey public_key,
SilcSKRKeyUsage usage,
- void *key_context)
+ void *key_context,
+ SilcSKRKey *return_key)
+{
+ SilcPKCSType type;
+
+ if (!public_key)
+ return SILC_SKR_ERROR;
+
+ 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;
+
+ default:
+ break;
+ }
+
+ return SILC_SKR_ERROR;
+}
+
+/* Remove key from repository */
+
+SilcSKRStatus silc_skr_del_public_key(SilcSKR skr,
+ SilcPublicKey public_key,
+ void *key_context)
{
SilcPKCSType type;
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;
default:
return SILC_SKR_ERROR;
}
+/* 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);
+}
+
/************************** Search Constraints API **************************/
*
* DESCRIPTION
*
- * SILC Key Repository
+ * SILC Key repository is a generic public key and certificate repository
+ * which allows fast and versatile ways to retrieve public keys from the
+ * the repository.
*
* SILC Key Repository is thread safe. Same key repository context can be
* safely used in multi threaded environment.
* then at least SILC_SKR_ERROR is set, and possibly other error
* status also.
*
+ * If the SILC_SKR_UNSUPPORTED_TYPE is returned the repository does not
+ * support the public key type and it cannot be added to the repository.
+ *
* SOURCE
*/
typedef enum {
* SilcSKRStatus silc_skr_add_public_key(SilcSKR skr,
* SilcPublicKey public_key,
* SilcSKRKeyUsage usage,
- * void *key_context);
+ * void *key_context,
+ * SilcSKRKey *return_key);
*
* DESCRIPTION
*
* repository. To add same key more than once to repository different
* `key_context' must be used each time.
*
+ * Returns an entry of the added public key in the repository to the
+ * `return_key' pointer, if it is non-NULL. The returned entry remains
+ * valid as long as the public key is in the repository, however a
+ * reference may be taken with silc_skr_ref_public_key to assure the
+ * entry remains valid.
+ *
* Returns SILC_SKR_OK if the key was added successfully, and error
* status if key could not be added, or has been added already.
*
* EXAMPLE
*
* // Add a key to repository
- * if (silc_skr_add_public_key(repository, public_key,
- * SILC_SKR_USAGE_ANY, NULL) != SILC_SKR_OK)
+ * if (silc_skr_add_public_key(repository, pubkey, SILC_SKR_USAGE_ANY,
+ * NULL, NULL) != SILC_SKR_OK)
* goto error;
*
***/
SilcSKRStatus silc_skr_add_public_key(SilcSKR skr,
SilcPublicKey public_key,
SilcSKRKeyUsage usage,
- void *key_context);
+ void *key_context,
+ SilcSKRKey *return_key);
/****f* silcskr/SilcSKRAPI/silc_skr_add_public_key_simple
*
* SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr,
* SilcPublicKey public_key,
* SilcSKRKeyUsage usage,
- * void *key_context);
+ * void *key_context,
+ * SilcSKRKey *return_key);
*
* DESCRIPTION
*
* key with as little memory as possible to the repository, and makes
* it a good way to cheaply store large amounts of public keys.
*
+ * Returns an entry of the added public key in the repository to the
+ * `return_key' pointer, if it is non-NULL. The returned entry remains
+ * valid as long as the public key is in the repository, however a
+ * reference may be taken with silc_skr_ref_public_key to assure the
+ * entry remains valid.
+ *
* Returns SILC_SKR_OK if the key was added successfully, and error
* status if key could not be added, or has been added already.
*
SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr,
SilcPublicKey public_key,
SilcSKRKeyUsage usage,
- void *key_context);
+ void *key_context,
+ SilcSKRKey *return_key);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_del_public_key
+ *
+ * SYNOPSIS
+ *
+ * SilcSKRStatus silc_skr_del_public_key(SilcSKR skr,
+ * SilcPublicKey public_key,
+ * void *key_context);
+ *
+ * DESCRIPTION
+ *
+ * Removes and destroyes the public key from the repository. The
+ * public_key will become invalid after this call returns.
+ *
+ * Returns SILC_SKR_OK if the key was added successfully, and error
+ * status if key could not be added, or has been added already.
+ *
+ ***/
+SilcSKRStatus silc_skr_del_public_key(SilcSKR skr,
+ SilcPublicKey public_key,
+ void *key_context);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_ref_public_key
+ *
+ * SYNOPSIS
+ *
+ * void silc_skr_ref_public_key(SilcSKR skr, SilcSKRKey key);
+ *
+ * DESCRIPTION
+ *
+ * Takes a reference of the public key added to repository indicated
+ * by `key'. The reference must be released by calling the function
+ * silc_skr_unref_public_key when it is not needed anymore.
+ *
+ ***/
+void silc_skr_ref_public_key(SilcSKR skr, SilcSKRKey key);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_unref_public_key
+ *
+ * SYNOPSIS
+ *
+ * void silc_skr_unref_public_key(SilcSKR skr, SilcSKRKey key);
+ *
+ * DESCRIPTION
+ *
+ * Releases the reference of the public key added to the repository
+ * indicated by `key'. If the released reference is the last reference
+ * to the key it will become invalid after this function returns.
+ *
+ ***/
+void silc_skr_unref_public_key(SilcSKR skr, SilcSKRKey key);
/****f* silcskr/SilcSKRAPI/silc_skr_find_alloc
*