From 2a23e57e4216593e83e7235e23988564825e4229 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 5 Mar 2013 16:10:55 +0000 Subject: starting major change towards implementing #2564, this breaks some FS tests and FS APIs --- src/fs/Makefile.am | 1 - src/fs/fs.h | 15 +- src/fs/fs_api.h | 18 +- src/fs/fs_namespace.c | 288 ++++------------ src/fs/fs_namespace_advertise.c | 363 -------------------- src/fs/fs_publish_ksk.c | 89 ++--- src/fs/fs_search.c | 249 +++++--------- src/fs/fs_unindex.c | 84 +++-- src/fs/fs_uri.c | 71 ++-- src/fs/gnunet-pseudonym.c | 41 ++- src/fs/gnunet-service-fs.c | 4 +- src/fs/gnunet-service-fs.h | 6 - src/fs/gnunet-service-fs_cp.c | 18 +- src/fs/gnunet-service-fs_lc.c | 12 +- src/fs/gnunet-service-fs_pr.c | 36 +- src/fs/gnunet-service-fs_pr.h | 8 - src/fs/gnunet-service-fs_put.c | 4 +- src/fs/plugin_block_fs.c | 181 +++------- src/fs/test_fs_namespace.c | 182 +++------- src/fs/test_fs_uri.c | 23 +- src/include/block_fs.h | 98 +----- src/include/gnunet_block_lib.h | 102 +++--- src/include/gnunet_fs_service.h | 121 +------ src/include/gnunet_pseudonym_lib.h | 271 ++++++++++++--- src/include/gnunet_signatures.h | 12 +- src/util/pseudonym.c | 669 +++++++++++++++++++++++++------------ src/util/strings.c | 5 - src/util/test_pseudonym.c | 109 +++--- 28 files changed, 1299 insertions(+), 1781 deletions(-) delete mode 100644 src/fs/fs_namespace_advertise.c (limited to 'src') diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am index 84c0a61d9..54267c57c 100644 --- a/src/fs/Makefile.am +++ b/src/fs/Makefile.am @@ -38,7 +38,6 @@ libgnunetfs_la_SOURCES = \ fs_publish_ksk.c \ fs_misc.c \ fs_namespace.c \ - fs_namespace_advertise.c \ fs_search.c \ fs_sharetree.c \ fs_tree.c fs_tree.h \ diff --git a/src/fs/fs.h b/src/fs/fs.h index ffd448d2b..9a987303b 100644 --- a/src/fs/fs.h +++ b/src/fs/fs.h @@ -240,26 +240,21 @@ struct SearchMessage * nevertheless, we should probably not use it for a DHT-lookup * or similar blunt actions in order to avoid exposing ourselves). *

- * If the request is for an SBLOCK, this is the identity of the - * pseudonym to which the SBLOCK belongs. - *

- * If the request is for a KBLOCK, "target" must be all zeros. + * Otherwise, "target" must be all zeros. */ struct GNUNET_HashCode target; /** - * Hash of the keyword (aka query) for KBLOCKs; Hash of - * the CHK-encoded block for DBLOCKS and IBLOCKS (aka query) - * and hash of the identifier XORed with the target for - * SBLOCKS (aka query). + * Hash of the public key for UBLOCKs; Hash of + * the CHK-encoded block for DBLOCKS and IBLOCKS. */ struct GNUNET_HashCode query; /* this is followed by the hash codes of already-known * results (which should hence be excluded from what * the service returns); naturally, this only applies - * to queries that can have multiple results, such as - * those for KBLOCKS (KSK) and SBLOCKS (SKS) */ + * to queries that can have multiple results (UBLOCKS). + */ }; diff --git a/src/fs/fs_api.h b/src/fs/fs_api.h index 61a568fa0..b2744237e 100644 --- a/src/fs/fs_api.h +++ b/src/fs/fs_api.h @@ -204,9 +204,9 @@ struct GNUNET_FS_Uri struct { /** - * Hash of the public key for the namespace. + * Identifier of the namespace. */ - struct GNUNET_HashCode ns; + struct GNUNET_PseudonymIdentifier ns; /** * Human-readable identifier chosen for this @@ -1390,14 +1390,14 @@ struct GNUNET_FS_UnindexContext struct GNUNET_DATASTORE_QueueEntry *dqe; /** - * Current key for decrypting KBLocks from 'get_key' operation. + * Current key for decrypting UBLocks from 'get_key' operation. */ - struct GNUNET_HashCode key; + struct GNUNET_HashCode ukey; /** * Current query of 'get_key' operation. */ - struct GNUNET_HashCode query; + struct GNUNET_HashCode uquery; /** * First content UID, 0 for none. @@ -1449,15 +1449,15 @@ struct GNUNET_FS_UnindexContext struct SearchRequestEntry { /** - * Hash of the original keyword, also known as the + * Hash of the original keyword, used to derive the * key (for decrypting the KBlock). */ - struct GNUNET_HashCode key; + struct GNUNET_HashCode ukey; /** * Hash of the public key, also known as the query. */ - struct GNUNET_HashCode query; + struct GNUNET_HashCode uquery; /** * Map that contains a "struct GNUNET_FS_SearchResult" for each result that @@ -2008,7 +2008,7 @@ struct GNUNET_FS_Namespace /** * Private key for the namespace. */ - struct GNUNET_CRYPTO_RsaPrivateKey *key; + struct GNUNET_PseudonymHandle *key; /** * Hash map mapping identifiers of update nodes diff --git a/src/fs/fs_namespace.c b/src/fs/fs_namespace.c index 3cc3ca299..87ddb667f 100644 --- a/src/fs/fs_namespace.c +++ b/src/fs/fs_namespace.c @@ -31,49 +31,6 @@ #include "fs_api.h" -/** - * Maximum legal size for an sblock. - */ -#define MAX_SBLOCK_SIZE (60 * 1024) - - -/** - * Context for creating a namespace asynchronously. - */ -struct GNUNET_FS_NamespaceCreationContext -{ - /** - * Context for asynchronous key creation. - */ - struct GNUNET_CRYPTO_RsaKeyGenerationContext *keycreator; - - /** - * Name of the file to store key in / read key from. - */ - char *filename; - - /** - * Name of the namespace. - */ - char *name; - - /** - * Global fs handle - */ - struct GNUNET_FS_Handle *h; - - /** - * Function to call when generation ends (successfully or not) - */ - GNUNET_FS_NamespaceCreationCallback cont; - - /** - * Client value to pass to continuation function. - */ - void *cont_cls; -}; - - /** * Return the name of the directory in which we store * our local namespaces (or rather, their public keys). @@ -288,7 +245,7 @@ GNUNET_FS_namespace_create (struct GNUNET_FS_Handle *h, const char *name) ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Namespace)); ret->h = h; ret->rc = 1; - ret->key = GNUNET_CRYPTO_rsa_key_create_from_file (fn); + ret->key = GNUNET_PSEUDONYM_create (fn); if (NULL == ret->key) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -332,7 +289,7 @@ GNUNET_FS_namespace_open_existing (struct GNUNET_FS_Handle *h, const char *name) ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Namespace)); ret->h = h; ret->rc = 1; - ret->key = GNUNET_CRYPTO_rsa_key_create_from_existing_file (fn); + ret->key = GNUNET_PSEUDONYM_create_from_existing_file (fn); if (NULL == ret->key) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -347,118 +304,6 @@ GNUNET_FS_namespace_open_existing (struct GNUNET_FS_Handle *h, const char *name) } -/** - * Function called upon completion of 'GNUNET_CRYPTO_rsa_key_create_start'. - * - * @param cls closure - * @param pk NULL on error, otherwise the private key (which must be free'd by the callee) - * @param emsg NULL on success, otherwise an error message - */ -static void -ns_key_created (void *cls, struct GNUNET_CRYPTO_RsaPrivateKey *pk, - const char *emsg) -{ - struct GNUNET_FS_NamespaceCreationContext *ncc = cls; - - ncc->keycreator = NULL; - - if (pk) - { - struct GNUNET_FS_Namespace *ret; - ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Namespace)); - ret->rc = 1; - ret->key = pk; - ret->h = ncc->h; - ret->name = ncc->name; - ret->filename = ncc->filename; - ncc->cont (ncc->cont_cls, ret, NULL); - } - else - { - GNUNET_free (ncc->filename); - GNUNET_free (ncc->name); - ncc->cont (ncc->cont_cls, NULL, emsg); - } - GNUNET_free (ncc); -} - - -/** - * Create a namespace with the given name. - * If one already exists, the continuation will be called with a handle to - * the existing namespace. - * Otherwise creates a new namespace. - * - * @param h handle to the file sharing subsystem - * @param name name to use for the namespace - * @return namespace creation context, NULL on error (i.e. invalid filename) - */ -struct GNUNET_FS_NamespaceCreationContext * -GNUNET_FS_namespace_create_start (struct GNUNET_FS_Handle *h, const char *name, - GNUNET_FS_NamespaceCreationCallback cont, void *cont_cls) -{ - char *dn; - char *fn; - struct GNUNET_FS_NamespaceCreationContext *ret; - - dn = get_namespace_directory (h); - if (NULL == dn) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Can't determine where namespace directory is\n")); - return NULL; - } - GNUNET_asprintf (&fn, "%s%s%s", dn, DIR_SEPARATOR_STR, name); - GNUNET_free (dn); - - ret = GNUNET_malloc (sizeof (struct GNUNET_FS_NamespaceCreationContext)); - ret->filename = fn; - ret->h = h; - ret->name = GNUNET_strdup (name); - ret->cont = cont; - ret->cont_cls = cont_cls; - - ret->keycreator = GNUNET_CRYPTO_rsa_key_create_start (fn, - ns_key_created, ret); - - if (NULL == ret->keycreator) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to start creating or reading private key for namespace `%s'\n"), - name); - GNUNET_free (fn); - GNUNET_free (ret->name); - GNUNET_free (ret); - return NULL; - } - return ret; -} - - -/** - * Abort namespace creation. - * - * @param ncc namespace creation context to abort - */ -void -GNUNET_FS_namespace_create_stop (struct GNUNET_FS_NamespaceCreationContext *ncc) -{ - if (NULL != ncc->keycreator) - { - GNUNET_CRYPTO_rsa_key_create_stop (ncc->keycreator); - ncc->keycreator = NULL; - } - if (NULL != ncc->filename) - { - if (0 != UNLINK (ncc->filename)) - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", ncc->filename); - GNUNET_free (ncc->filename); - } - GNUNET_free_non_null (ncc->name); - GNUNET_free (ncc); -} - - /** * Rename a local namespace. * @@ -468,7 +313,9 @@ GNUNET_FS_namespace_create_stop (struct GNUNET_FS_NamespaceCreationContext *ncc) * @return GNUNET_OK on success, GNUNET_SYSERR on error (see errno for details) */ int -GNUNET_FS_namespace_rename (struct GNUNET_FS_Handle *h, const char *old_name, const char *new_name) +GNUNET_FS_namespace_rename (struct GNUNET_FS_Handle *h, + const char *old_name, + const char *new_name) { char *dn; char *fn_old; @@ -496,6 +343,7 @@ GNUNET_FS_namespace_rename (struct GNUNET_FS_Handle *h, const char *old_name, co return GNUNET_SYSERR; } + /** * Duplicate a namespace handle. * @@ -536,7 +384,7 @@ GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *ns, int freeze) } if (0 != ns->rc) return GNUNET_OK; - GNUNET_CRYPTO_rsa_key_free (ns->key); + GNUNET_PSEUDONYM_destroy (ns->key); GNUNET_free (ns->filename); GNUNET_free (ns->name); for (i = 0; i < ns->update_node_count; i++) @@ -584,12 +432,12 @@ struct ProcessNamespaceContext * GNUNET_SYSERR on failure (contents of id remain intact) */ int -GNUNET_FS_namespace_get_public_key_hash (struct GNUNET_FS_Namespace *ns, - struct GNUNET_HashCode *id) +GNUNET_FS_namespace_get_public_identifier (struct GNUNET_FS_Namespace *ns, + struct GNUNET_PseudonymIdentifier *id) { if ((NULL == ns) || (NULL == id)) return GNUNET_SYSERR; - GNUNET_CRYPTO_rsa_get_public_key_hash (ns->key, id); + GNUNET_PSEUDONYM_get_identifier (ns->key, id); return GNUNET_OK; } @@ -607,13 +455,12 @@ static int process_namespace (void *cls, const char *filename) { struct ProcessNamespaceContext *pnc = cls; - struct GNUNET_CRYPTO_RsaPrivateKey *key; - struct GNUNET_HashCode id; + struct GNUNET_PseudonymHandle *ph; + struct GNUNET_PseudonymIdentifier id; const char *name; const char *t; - key = GNUNET_CRYPTO_rsa_key_create_from_file (filename); - if (NULL == key) + if (NULL == (ph = GNUNET_PSEUDONYM_create (filename))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ @@ -623,8 +470,8 @@ process_namespace (void *cls, const char *filename) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); return GNUNET_OK; } - GNUNET_CRYPTO_rsa_get_public_key_hash (key, &id); - GNUNET_CRYPTO_rsa_key_free (key); + GNUNET_PSEUDONYM_get_identifier (ph, &id); + GNUNET_PSEUDONYM_destroy (ph); name = filename; while (NULL != (t = strstr (name, DIR_SEPARATOR_STR))) name = t + 1; @@ -705,7 +552,7 @@ struct GNUNET_FS_PublishSksContext /** * Function called by the datastore API with - * the result from the PUT (SBlock) request. + * the result from the PUT (UBlock) request. * * @param cls closure of type "struct GNUNET_FS_PublishSksContext*" * @param success GNUNET_OK on success @@ -737,7 +584,7 @@ sb_put_cont (void *cls, int success, read_update_information_graph (psc->ns); GNUNET_array_append (psc->ns->update_nodes, psc->ns->update_node_count, psc->nsn); - if (psc->ns->update_map != NULL) + if (NULL != psc->ns->update_map) { GNUNET_CRYPTO_hash (psc->nsn->id, strlen (psc->nsn->id), &hc); GNUNET_CONTAINER_multihashmap_put (psc->ns->update_map, &hc, @@ -788,13 +635,15 @@ GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, size_t nidlen; size_t idlen; ssize_t mdsize; - struct SBlock *sb; - struct SBlock *sb_enc; + struct UBlock *ub; + struct UBlock *ub_enc; char *dest; struct GNUNET_CONTAINER_MetaData *mmeta; - struct GNUNET_HashCode key; /* hash of thisId = key */ - struct GNUNET_HashCode id; /* hash of hc = identifier */ - struct GNUNET_HashCode query; /* id ^ nsid = DB query */ + struct GNUNET_HashCode id_hash; /* hash of thisId */ + struct GNUNET_HashCode ns_hash; /* hash of namespace public key */ + struct GNUNET_HashCode key; /* id_hash ^ ns_hash, for AES key */ + struct GNUNET_HashCode signing_key; /* H(key) = input for public key */ + struct GNUNET_HashCode query; /* H(verification_key) = query */ idlen = strlen (identifier); if (NULL != update) @@ -803,11 +652,11 @@ GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, nidlen = 1; uris = GNUNET_FS_uri_to_string (uri); slen = strlen (uris) + 1; - if ( (slen >= MAX_SBLOCK_SIZE - sizeof (struct SBlock)) || - (nidlen >= MAX_SBLOCK_SIZE - sizeof (struct SBlock) - slen) ) + if ( (slen >= MAX_UBLOCK_SIZE - sizeof (struct UBlock)) || + (nidlen >= MAX_UBLOCK_SIZE - sizeof (struct UBlock) - slen) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Identifiers or URI too long to create SBlock")); + _("Identifiers or URI too long to create UBlock")); GNUNET_free (uris); return NULL; } @@ -816,15 +665,15 @@ GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, else mmeta = GNUNET_CONTAINER_meta_data_duplicate (meta); mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (mmeta); - size = sizeof (struct SBlock) + slen + nidlen + mdsize; - if ( (size > MAX_SBLOCK_SIZE) || - (size < sizeof (struct SBlock) + slen + nidlen) ) + size = sizeof (struct UBlock) + slen + nidlen + mdsize; + if ( (size > MAX_UBLOCK_SIZE) || + (size < sizeof (struct UBlock) + slen + nidlen) ) { - size = MAX_SBLOCK_SIZE; - mdsize = MAX_SBLOCK_SIZE - (sizeof (struct SBlock) + slen + nidlen); + size = MAX_UBLOCK_SIZE; + mdsize = MAX_UBLOCK_SIZE - (sizeof (struct UBlock) + slen + nidlen); } - sb = GNUNET_malloc (sizeof (struct SBlock) + size); - dest = (char *) &sb[1]; + ub = GNUNET_malloc (sizeof (struct UBlock) + size); + dest = (char *) &ub[1]; if (NULL != update) memcpy (dest, update, nidlen); else @@ -840,34 +689,44 @@ GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, if (-1 == mdsize) { GNUNET_break (0); - GNUNET_free (sb); + GNUNET_free (ub); if (NULL != cont) cont (cont_cls, NULL, _("Internal error.")); return NULL; } - size = sizeof (struct SBlock) + mdsize + slen + nidlen; - sb_enc = GNUNET_malloc (size); - GNUNET_CRYPTO_hash (identifier, idlen, &key); - GNUNET_CRYPTO_hash (&key, sizeof (struct GNUNET_HashCode), &id); sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); sks_uri->type = GNUNET_FS_URI_SKS; - GNUNET_CRYPTO_rsa_key_get_public (ns->key, &sb_enc->subspace); - GNUNET_CRYPTO_hash (&sb_enc->subspace, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &sks_uri->data.sks.ns); sks_uri->data.sks.identifier = GNUNET_strdup (identifier); - GNUNET_CRYPTO_hash_xor (&id, &sks_uri->data.sks.ns, - &sb_enc->identifier); + GNUNET_FS_namespace_get_public_identifier (ns, + &sks_uri->data.sks.ns); + + size = sizeof (struct UBlock) + mdsize + slen + nidlen; + ub_enc = GNUNET_malloc (size); + GNUNET_CRYPTO_hash (identifier, idlen, &id_hash); + GNUNET_CRYPTO_hash (&sks_uri->data.sks.ns, + sizeof (sks_uri->data.sks.ns), &ns_hash); + GNUNET_CRYPTO_hash_xor (&id_hash, &ns_hash, &key); GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv); - GNUNET_CRYPTO_aes_encrypt (&sb[1], size - sizeof (struct SBlock), &sk, &iv, - &sb_enc[1]); - sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK); - sb_enc->purpose.size = - htonl (slen + mdsize + nidlen + sizeof (struct SBlock) - - sizeof (struct GNUNET_CRYPTO_RsaSignature)); - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_rsa_sign (ns->key, &sb_enc->purpose, - &sb_enc->signature)); + GNUNET_CRYPTO_hash (&key, sizeof (struct GNUNET_HashCode), &signing_key); + + GNUNET_CRYPTO_aes_encrypt (&ub[1], + size - sizeof (struct UBlock), + &sk, &iv, + &ub_enc[1]); + ub_enc->purpose.size = htonl (nidlen + slen + mdsize + sizeof (struct UBlock) + - sizeof (struct GNUNET_PseudonymSignature)); + ub_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK); + GNUNET_PSEUDONYM_sign (ns->key, + &ub_enc->purpose, + NULL, + &signing_key, + &ub_enc->signature); + GNUNET_PSEUDONYM_derive_verification_key (&sks_uri->data.sks.ns, + &signing_key, + &ub_enc->verification_key); + GNUNET_CRYPTO_hash (&ub_enc->verification_key, + sizeof (ub_enc->verification_key), + &query); psc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishSksContext)); psc->uri = sks_uri; psc->cont = cont; @@ -875,20 +734,20 @@ GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, psc->cont_cls = cont_cls; if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY)) { - GNUNET_free (sb_enc); - GNUNET_free (sb); + GNUNET_free (ub_enc); + GNUNET_free (ub); sb_put_cont (psc, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); return NULL; } psc->dsh = GNUNET_DATASTORE_connect (h->cfg); if (NULL == psc->dsh) { - GNUNET_free (sb_enc); - GNUNET_free (sb); + GNUNET_free (ub_enc); + GNUNET_free (ub); sb_put_cont (psc, GNUNET_NO, GNUNET_TIME_UNIT_ZERO_ABS, _("Failed to connect to datastore.")); return NULL; } - GNUNET_CRYPTO_hash_xor (&sks_uri->data.sks.ns, &id, &query); + if (NULL != update) { psc->nsn = GNUNET_malloc (sizeof (struct NamespaceUpdateNode)); @@ -897,13 +756,14 @@ GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h, psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate (meta); psc->nsn->uri = GNUNET_FS_uri_dup (uri); } - psc->dqe = GNUNET_DATASTORE_put (psc->dsh, 0, &sb_enc->identifier, size, sb_enc, - GNUNET_BLOCK_TYPE_FS_SBLOCK, bo->content_priority, + + psc->dqe = GNUNET_DATASTORE_put (psc->dsh, 0, &query, size, ub_enc, + GNUNET_BLOCK_TYPE_FS_UBLOCK, bo->content_priority, bo->anonymity_level, bo->replication_level, bo->expiration_time, -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, &sb_put_cont, psc); - GNUNET_free (sb); - GNUNET_free (sb_enc); + GNUNET_free (ub); + GNUNET_free (ub_enc); return psc; } diff --git a/src/fs/fs_namespace_advertise.c b/src/fs/fs_namespace_advertise.c deleted file mode 100644 index 554f61657..000000000 --- a/src/fs/fs_namespace_advertise.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - This file is part of GNUnet - (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file fs/fs_namespace_advertise.c - * @brief advertise namespaces (creating NBlocks) - * @author Christian Grothoff - */ -#include "platform.h" -#include "gnunet_constants.h" -#include "gnunet_signatures.h" -#include "gnunet_util_lib.h" -#include "gnunet_fs_service.h" -#include "fs_api.h" - - -/** - * Maximum legal size for an nblock. - */ -#define MAX_NBLOCK_SIZE (60 * 1024) - - -/** - * Context for advertising a namespace. - */ -struct GNUNET_FS_AdvertisementContext -{ - /** - * Function to call with the result. - */ - GNUNET_FS_PublishContinuation cont; - - /** - * Closure for cont. - */ - void *cont_cls; - - /** - * Datastore handle. - */ - struct GNUNET_DATASTORE_Handle *dsh; - - /** - * Our KSK URI. - */ - struct GNUNET_FS_Uri *ksk_uri; - - /** - * Plaintext. - */ - char *pt; - - /** - * NBlock to sign and store. - */ - struct NBlock *nb; - - /** - * The namespace. - */ - struct GNUNET_FS_Namespace *ns; - - /** - * Current datastore queue entry for advertising. - */ - struct GNUNET_DATASTORE_QueueEntry *dqe; - - /** - * Block options. - */ - struct GNUNET_FS_BlockOptions bo; - - /** - * Number of bytes of plaintext. - */ - size_t pt_size; - - /** - * Current keyword offset. - */ - unsigned int pos; -}; - - -// FIXME: I see no good reason why this should need to be done -// in a new task (anymore). Integrate with 'cancel' function below? -/** - * Disconnect from the datastore. - * - * @param cls datastore handle - * @param tc scheduler context - */ -static void -do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_DATASTORE_Handle *dsh = cls; - - GNUNET_DATASTORE_disconnect (dsh, GNUNET_NO); -} - - -/** - * Continuation called to notify client about result of the - * operation. - * - * @param cls closure (our struct GNUNET_FS_AdvertismentContext) - * @param success GNUNET_SYSERR on failure - * @param min_expiration minimum expiration time required for content to be stored - * @param msg NULL on success, otherwise an error message - */ -static void -advertisement_cont (void *cls, int success, - struct GNUNET_TIME_Absolute min_expiration, - const char *msg) -{ - struct GNUNET_FS_AdvertisementContext *ac = cls; - const char *keyword; - struct GNUNET_HashCode key; - struct GNUNET_HashCode query; - struct GNUNET_CRYPTO_AesSessionKey skey; - struct GNUNET_CRYPTO_AesInitializationVector iv; - struct GNUNET_CRYPTO_RsaPrivateKey *pk; - - ac->dqe = NULL; - if (GNUNET_SYSERR == success) - { - /* error! */ - (void) GNUNET_SCHEDULER_add_now (&do_disconnect, ac->dsh); - ac->dsh = NULL; - if (msg == NULL) - { - GNUNET_break (0); - msg = _("Unknown error"); - } - if (ac->cont != NULL) - { - ac->cont (ac->cont_cls, NULL, msg); - ac->cont = NULL; - } - GNUNET_FS_namespace_advertise_cancel (ac); - return; - } - if (ac->pos == ac->ksk_uri->data.ksk.keywordCount) - { - /* done! */ - (void) GNUNET_SCHEDULER_add_now (&do_disconnect, ac->dsh); - ac->dsh = NULL; - if (ac->cont != NULL) - { - ac->cont (ac->cont_cls, ac->ksk_uri, NULL); - ac->cont = NULL; - } - GNUNET_FS_namespace_advertise_cancel (ac); - return; - } - keyword = ac->ksk_uri->data.ksk.keywords[ac->pos++]; - /* first character of keyword indicates if it is - * mandatory or not -- ignore for hashing */ - GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key); - GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); - GNUNET_CRYPTO_aes_encrypt (ac->pt, ac->pt_size, &skey, &iv, &ac->nb[1]); - GNUNET_break (GNUNET_OK == - GNUNET_CRYPTO_rsa_sign (ac->ns->key, &ac->nb->ns_purpose, - &ac->nb->ns_signature)); - pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key); - GNUNET_assert (pk != NULL); - GNUNET_CRYPTO_rsa_key_get_public (pk, &ac->nb->keyspace); - GNUNET_CRYPTO_hash (&ac->nb->keyspace, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &query); - GNUNET_break (GNUNET_OK == - GNUNET_CRYPTO_rsa_sign (pk, &ac->nb->ksk_purpose, - &ac->nb->ksk_signature)); - GNUNET_CRYPTO_rsa_key_free (pk); - ac->dqe = GNUNET_DATASTORE_put (ac->dsh, 0 /* no reservation */ , - &query, ac->pt_size + sizeof (struct NBlock), ac->nb, - GNUNET_BLOCK_TYPE_FS_NBLOCK, ac->bo.content_priority, - ac->bo.anonymity_level, ac->bo.replication_level, - ac->bo.expiration_time, -2, 1, - GNUNET_CONSTANTS_SERVICE_TIMEOUT, &advertisement_cont, - ac); -} - - -/** - * Create an SKS uri that points to the root entry of the namespace, - * then insert that SKS uri into metadata. - * - * @param ns handle for the namespace that should be advertised - * @param meta meta-data into which namespace advertisement should be inserted - * @param rootEntry name of the root of the namespace (use NULL to use default) - * @return GNUNET_OK on success, GNUNET_SYSERR on error - */ -int -GNUNET_FS_namespace_insert_advertisement_into_metadata ( - struct GNUNET_FS_Namespace *ns, struct GNUNET_CONTAINER_MetaData *meta, - const char *rootEntry) -{ - struct GNUNET_FS_Uri *sks_uri; - char *emsg; - char *sks_uri_string; - int md_insert; - - if (NULL == rootEntry) - rootEntry = "/"; - - emsg = NULL; - sks_uri = GNUNET_FS_uri_sks_create (ns, rootEntry, &emsg); - GNUNET_free_non_null (emsg); - if (NULL == sks_uri) - return GNUNET_SYSERR; - - sks_uri_string = GNUNET_FS_uri_to_string (sks_uri); - GNUNET_FS_uri_destroy (sks_uri); - if (NULL == sks_uri_string) - return GNUNET_SYSERR; - - md_insert = GNUNET_CONTAINER_meta_data_insert (meta, "", - EXTRACTOR_METATYPE_URI, EXTRACTOR_METAFORMAT_UTF8, - "text/plain", sks_uri_string, strlen (sks_uri_string) + 1); - GNUNET_free (sks_uri_string); - return md_insert; -} - -/** - * Publish an advertismement for a namespace. - * - * @param h handle to the file sharing subsystem - * @param ksk_uri keywords to use for advertisment - * @param ns handle for the namespace that should be advertised - * @param meta meta-data for the namespace advertisement - * @param bo block options - * @param rootEntry name of the root of the namespace - * @param cont continuation - * @param cont_cls closure for cont - * @return NULL on error ('cont' is still called) - */ -struct GNUNET_FS_AdvertisementContext * -GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, - struct GNUNET_FS_Uri *ksk_uri, - struct GNUNET_FS_Namespace *ns, - const struct GNUNET_CONTAINER_MetaData *meta, - const struct GNUNET_FS_BlockOptions *bo, - const char *rootEntry, - GNUNET_FS_PublishContinuation cont, - void *cont_cls) -{ - size_t reslen; - size_t size; - ssize_t mdsize; - struct NBlock *nb; - char *mdst; - struct GNUNET_DATASTORE_Handle *dsh; - struct GNUNET_FS_AdvertisementContext *ctx; - char *pt; - - /* create advertisements */ - mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta); - if (-1 == mdsize) - { - cont (cont_cls, NULL, _("Failed to serialize meta data")); - return NULL; - } - reslen = strlen (rootEntry) + 1; - size = mdsize + sizeof (struct NBlock) + reslen; - if (size > MAX_NBLOCK_SIZE) - { - size = MAX_NBLOCK_SIZE; - mdsize = size - sizeof (struct NBlock) - reslen; - } - - pt = GNUNET_malloc (mdsize + reslen); - memcpy (pt, rootEntry, reslen); - mdst = &pt[reslen]; - mdsize = - GNUNET_CONTAINER_meta_data_serialize (meta, &mdst, mdsize, - GNUNET_CONTAINER_META_DATA_SERIALIZE_PART); - if (-1 == mdsize) - { - GNUNET_break (0); - GNUNET_free (pt); - cont (cont_cls, NULL, _("Failed to serialize meta data")); - return NULL; - } - size = mdsize + sizeof (struct NBlock) + reslen; - nb = GNUNET_malloc (size); - GNUNET_CRYPTO_rsa_key_get_public (ns->key, &nb->subspace); - nb->ns_purpose.size = - htonl (mdsize + reslen + - sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); - nb->ns_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK); - nb->ksk_purpose.size = - htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature)); - nb->ksk_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG); - dsh = GNUNET_DATASTORE_connect (h->cfg); - if (NULL == dsh) - { - GNUNET_free (nb); - GNUNET_free (pt); - cont (cont_cls, NULL, _("Failed to connect to datastore service")); - return NULL; - } - ctx = GNUNET_malloc (sizeof (struct GNUNET_FS_AdvertisementContext)); - ctx->cont = cont; - ctx->cont_cls = cont_cls; - ctx->dsh = dsh; - ctx->ksk_uri = GNUNET_FS_uri_dup (ksk_uri); - ctx->nb = nb; - ctx->pt = pt; - ctx->pt_size = mdsize + reslen; - ctx->ns = ns; - ctx->ns->rc++; - ctx->bo = *bo; - advertisement_cont (ctx, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL); - return ctx; -} - - -/** - * Abort the namespace advertisement operation. - * - * @param ac context of the operation to abort. - */ -void -GNUNET_FS_namespace_advertise_cancel (struct GNUNET_FS_AdvertisementContext *ac) -{ - if (NULL != ac->dqe) - { - GNUNET_DATASTORE_cancel (ac->dqe); - ac->dqe = NULL; - } - if (NULL != ac->dsh) - { - GNUNET_DATASTORE_disconnect (ac->dsh, GNUNET_NO); - ac->dsh = NULL; - } - GNUNET_FS_uri_destroy (ac->ksk_uri); - GNUNET_free (ac->pt); - GNUNET_free (ac->nb); - GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO); - GNUNET_free (ac); -} - - -/* end of fs_namespace_advertise.c */ diff --git a/src/fs/fs_publish_ksk.c b/src/fs/fs_publish_ksk.c index 5511fb93d..bbbbdc1d6 100644 --- a/src/fs/fs_publish_ksk.c +++ b/src/fs/fs_publish_ksk.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) + (C) 2009, 2010, 2012, 2013 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -21,7 +21,7 @@ /** * @file fs/fs_publish_ksk.c * @brief publish a URI under a keyword in GNUnet - * @see https://gnunet.org/encoding + * @see https://gnunet.org/encoding and #2564 * @author Krista Bennett * @author Christian Grothoff */ @@ -35,12 +35,6 @@ #include "fs_tree.h" -/** - * Maximum legal size for a kblock. - */ -#define MAX_KBLOCK_SIZE (60 * 1024) - - /** * Context for the KSK publication. */ @@ -62,13 +56,13 @@ struct GNUNET_FS_PublishKskContext * (in plaintext), has "mdsize+slen" more * bytes than the struct would suggest. */ - struct KBlock *kb; + struct UBlock *ub; /** * Buffer of the same size as "kb" for * the encrypted version. */ - struct KBlock *cpy; + struct UBlock *cpy; /** * Handle to the datastore, NULL if we are just @@ -173,10 +167,13 @@ publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) struct GNUNET_FS_PublishKskContext *pkc = cls; const char *keyword; struct GNUNET_HashCode key; + struct GNUNET_HashCode seed; + struct GNUNET_HashCode signing_key; struct GNUNET_HashCode query; struct GNUNET_CRYPTO_AesSessionKey skey; struct GNUNET_CRYPTO_AesInitializationVector iv; - struct GNUNET_CRYPTO_RsaPrivateKey *pk; + struct GNUNET_PseudonymHandle *ph; + struct GNUNET_PseudonymIdentifier pseudonym; pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK; if ((pkc->i == pkc->ksk_uri->data.ksk.keywordCount) || (NULL == pkc->dsh)) @@ -186,29 +183,43 @@ publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_FS_publish_ksk_cancel (pkc); return; } + /* derive signing seed from plaintext */ + GNUNET_CRYPTO_hash (&pkc->ub[1], + 1 + pkc->slen + pkc->mdsize, + &seed); keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing under keyword `%s'\n", - &keyword[1]); + &keyword[1]); /* first character of keyword indicates if it is * mandatory or not -- ignore for hashing */ GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key); GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); - GNUNET_CRYPTO_aes_encrypt (&pkc->kb[1], pkc->slen + pkc->mdsize, &skey, &iv, + GNUNET_CRYPTO_aes_encrypt (&pkc->ub[1], + 1 + pkc->slen + pkc->mdsize, + &skey, &iv, &pkc->cpy[1]); - pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key); - GNUNET_assert (NULL != pk); - GNUNET_CRYPTO_rsa_key_get_public (pk, &pkc->cpy->keyspace); - GNUNET_CRYPTO_hash (&pkc->cpy->keyspace, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &query); - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_rsa_sign (pk, &pkc->cpy->purpose, - &pkc->cpy->signature)); - GNUNET_CRYPTO_rsa_key_free (pk); + ph = GNUNET_PSEUDONYM_get_anonymous_pseudonym_handle (); + GNUNET_CRYPTO_hash (&key, sizeof (key), &signing_key); + pkc->cpy->purpose.size = htonl (1 + pkc->slen + pkc->mdsize + sizeof (struct UBlock) + - sizeof (struct GNUNET_PseudonymSignature)); + pkc->cpy->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK); + GNUNET_PSEUDONYM_sign (ph, + &pkc->cpy->purpose, + &seed, + &signing_key, + &pkc->cpy->signature); + GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym); + GNUNET_PSEUDONYM_derive_verification_key (&pseudonym, + &signing_key, + &pkc->cpy->verification_key); + GNUNET_CRYPTO_hash (&pkc->cpy->verification_key, + sizeof (pkc->cpy->verification_key), + &query); + GNUNET_PSEUDONYM_destroy (ph); pkc->qre = GNUNET_DATASTORE_put (pkc->dsh, 0, &query, - pkc->mdsize + sizeof (struct KBlock) + pkc->slen, - pkc->cpy, GNUNET_BLOCK_TYPE_FS_KBLOCK, + 1 + pkc->slen + pkc->mdsize + sizeof (struct UBlock), + pkc->cpy, GNUNET_BLOCK_TYPE_FS_UBLOCK, pkc->bo.content_priority, pkc->bo.anonymity_level, pkc->bo.replication_level, pkc->bo.expiration_time, -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT, @@ -267,14 +278,15 @@ GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, GNUNET_assert (pkc->mdsize >= 0); uris = GNUNET_FS_uri_to_string (uri); pkc->slen = strlen (uris) + 1; - size = pkc->mdsize + sizeof (struct KBlock) + pkc->slen; - if (size > MAX_KBLOCK_SIZE) + size = pkc->mdsize + sizeof (struct UBlock) + pkc->slen + 1; + if (size > MAX_UBLOCK_SIZE) { - size = MAX_KBLOCK_SIZE; - pkc->mdsize = size - sizeof (struct KBlock) - pkc->slen; + size = MAX_UBLOCK_SIZE; + pkc->mdsize = size - sizeof (struct UBlock) - pkc->slen + 1; } - pkc->kb = GNUNET_malloc (size); - kbe = (char *) &pkc->kb[1]; + pkc->ub = GNUNET_malloc (size); + kbe = (char *) &pkc->ub[1]; + kbe++; /* leave one '\0' for the update identifier */ memcpy (kbe, uris, pkc->slen); GNUNET_free (uris); sptr = &kbe[pkc->slen]; @@ -285,8 +297,8 @@ GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, if (-1 == pkc->mdsize) { GNUNET_break (0); - GNUNET_free (pkc->kb); - if (pkc->dsh != NULL) + GNUNET_free (pkc->ub); + if (NULL != pkc->dsh) { GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO); pkc->dsh = NULL; @@ -295,14 +307,13 @@ GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h, cont (cont_cls, NULL, _("Internal error.")); return NULL; } - size = sizeof (struct KBlock) + pkc->slen + pkc->mdsize; + size = sizeof (struct UBlock) + pkc->slen + pkc->mdsize + 1; pkc->cpy = GNUNET_malloc (size); pkc->cpy->purpose.size = - htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + - pkc->mdsize + pkc->slen); - pkc->cpy->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK); + htonl (sizeof (struct GNUNET_PseudonymSignaturePurpose) + + pkc->mdsize + pkc->slen + 1); + pkc->cpy->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK); pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri); pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc); return pkc; @@ -333,7 +344,7 @@ GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc) pkc->dsh = NULL; } GNUNET_free (pkc->cpy); - GNUNET_free (pkc->kb); + GNUNET_free (pkc->ub); GNUNET_FS_uri_destroy (pkc->ksk_uri); GNUNET_free (pkc); } diff --git a/src/fs/fs_search.c b/src/fs/fs_search.c index fc05498cc..eaf26f73f 100644 --- a/src/fs/fs_search.c +++ b/src/fs/fs_search.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2001-2006, 2008-2012 Christian Grothoff (and other contributing authors) + (C) 2001-2013 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -22,7 +22,6 @@ * @brief Helper functions for searching. * @author Christian Grothoff */ - #include "platform.h" #include "gnunet_constants.h" #include "gnunet_fs_service.h" @@ -575,22 +574,22 @@ process_sks_result (struct GNUNET_FS_SearchContext *sc, const char *id_update, /** - * Decrypt a block using a 'keyword' as the passphrase. Given the + * Decrypt a ublock using a 'keyword' as the passphrase. Given the * KSK public key derived from the keyword, this function looks up * the original keyword in the search context and decrypts the * given ciphertext block. * * @param sc search context with the keywords - * @param public_key public key to use to lookup the keyword + * @param verification_key public key to use to lookup the keyword * @param edata encrypted data * @param edata_size number of bytes in 'edata' (and 'data') * @param data where to store the plaintext * @return keyword index on success, GNUNET_SYSERR on error (no such - * keyword, internal error) + * keyword, internal error) */ static int decrypt_block_with_keyword (const struct GNUNET_FS_SearchContext *sc, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, + const struct GNUNET_PseudonymIdentifier *verification_key, const void *edata, size_t edata_size, char *data) @@ -600,12 +599,12 @@ decrypt_block_with_keyword (const struct GNUNET_FS_SearchContext *sc, struct GNUNET_CRYPTO_AesInitializationVector iv; int i; - GNUNET_CRYPTO_hash (public_key, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + GNUNET_CRYPTO_hash (verification_key, + sizeof (struct GNUNET_PseudonymIdentifier), &q); /* find key */ for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) - if (0 == memcmp (&q, &sc->requests[i].query, sizeof (struct GNUNET_HashCode))) + if (0 == memcmp (&q, &sc->requests[i].uquery, sizeof (struct GNUNET_HashCode))) break; if (i == sc->uri->data.ksk.keywordCount) { @@ -614,7 +613,7 @@ decrypt_block_with_keyword (const struct GNUNET_FS_SearchContext *sc, return GNUNET_SYSERR; } /* decrypt */ - GNUNET_CRYPTO_hash_to_aes_key (&sc->requests[i].key, &skey, &iv); + GNUNET_CRYPTO_hash_to_aes_key (&sc->requests[i].ukey, &skey, &iv); if (-1 == GNUNET_CRYPTO_aes_decrypt (edata, edata_size, &skey, &iv, data)) @@ -627,18 +626,20 @@ decrypt_block_with_keyword (const struct GNUNET_FS_SearchContext *sc, /** - * Process a keyword-search result. + * Process a keyword search result. The actual type of block is + * a UBlock; we know it is a keyword search result because that's + * what we were searching for. * * @param sc our search context - * @param kb the kblock - * @param size size of kb + * @param ub the ublock with the keyword search result + * @param size size of nb */ static void -process_kblock (struct GNUNET_FS_SearchContext *sc, const struct KBlock *kb, +process_kblock (struct GNUNET_FS_SearchContext *sc, const struct UBlock *ub, size_t size) { size_t j; - char pt[size - sizeof (struct KBlock)]; + char pt[size - sizeof (struct UBlock)]; const char *eos; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *uri; @@ -646,75 +647,22 @@ process_kblock (struct GNUNET_FS_SearchContext *sc, const struct KBlock *kb, int i; if (-1 == (i = decrypt_block_with_keyword (sc, - &kb->keyspace, - &kb[1], - size - sizeof (struct KBlock), + &ub->verification_key, + &ub[1], + size - sizeof (struct UBlock), pt))) return; - /* parse */ - eos = memchr (pt, 0, sizeof (pt)); + /* parse; pt[0] is just '\0', so we skip over that */ + eos = memchr (&pt[1], '\0', sizeof (pt) - 1); if (NULL == eos) { GNUNET_break_op (0); return; } - j = eos - pt + 1; - if (sizeof (pt) == j) - meta = GNUNET_CONTAINER_meta_data_create (); - else - meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[j], sizeof (pt) - j); - if (NULL == meta) + if (NULL == (uri = GNUNET_FS_uri_parse (&pt[1], &emsg))) { - GNUNET_break_op (0); /* kblock malformed */ - return; - } - uri = GNUNET_FS_uri_parse (pt, &emsg); - if (NULL == uri) - { - GNUNET_break_op (0); /* kblock malformed */ - GNUNET_free_non_null (emsg); - GNUNET_CONTAINER_meta_data_destroy (meta); - return; - } - /* process */ - process_ksk_result (sc, &sc->requests[i], uri, meta); - - /* clean up */ - GNUNET_CONTAINER_meta_data_destroy (meta); - GNUNET_FS_uri_destroy (uri); -} - - -/** - * Process a keyword-search result with a namespace advertisment. - * - * @param sc our search context - * @param nb the nblock - * @param size size of nb - */ -static void -process_nblock (struct GNUNET_FS_SearchContext *sc, const struct NBlock *nb, - size_t size) -{ - size_t j; - char pt[size - sizeof (struct NBlock)]; - const char *eos; - struct GNUNET_CONTAINER_MetaData *meta; - struct GNUNET_FS_Uri *uri; - char *uris; - int i; - - if (-1 == (i = decrypt_block_with_keyword (sc, - &nb->keyspace, - &nb[1], - size - sizeof (struct NBlock), - pt))) - return; - /* parse */ - eos = memchr (pt, 0, sizeof (pt)); - if (NULL == eos) - { - GNUNET_break_op (0); + GNUNET_break_op (0); /* ublock malformed */ + GNUNET_free_non_null (emsg); return; } j = eos - pt + 1; @@ -724,23 +672,10 @@ process_nblock (struct GNUNET_FS_SearchContext *sc, const struct NBlock *nb, meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[j], sizeof (pt) - j); if (NULL == meta) { - GNUNET_break_op (0); /* nblock malformed */ + GNUNET_break_op (0); /* ublock malformed */ + GNUNET_FS_uri_destroy (uri); return; } - - uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); - uri->type = GNUNET_FS_URI_SKS; - uri->data.sks.identifier = GNUNET_strdup (pt); - GNUNET_CRYPTO_hash (&nb->subspace, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &uri->data.sks.ns); - uris = GNUNET_FS_uri_to_string (uri); - GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_URI, - EXTRACTOR_METAFORMAT_UTF8, "text/plain", - uris, strlen (uris) + 1); - GNUNET_free (uris); - GNUNET_PSEUDONYM_add (sc->h->cfg, &uri->data.sks.ns, meta); - /* process */ process_ksk_result (sc, &sc->requests[i], uri, meta); /* clean up */ @@ -750,17 +685,20 @@ process_nblock (struct GNUNET_FS_SearchContext *sc, const struct NBlock *nb, /** - * Process a namespace-search result. + * Process a namespace-search result. The actual type of block is + * a UBlock; we know it is a namespace search result because that's + * what we were searching for. * * @param sc our search context - * @param sb the sblock + * @param ub the ublock with a namespace result * @param size size of sb */ static void -process_sblock (struct GNUNET_FS_SearchContext *sc, const struct SBlock *sb, +process_sblock (struct GNUNET_FS_SearchContext *sc, + const struct UBlock *ub, size_t size) { - size_t len = size - sizeof (struct SBlock); + size_t len = size - sizeof (struct UBlock); char pt[len]; struct GNUNET_CRYPTO_AesSessionKey skey; struct GNUNET_CRYPTO_AesInitializationVector iv; @@ -771,36 +709,39 @@ process_sblock (struct GNUNET_FS_SearchContext *sc, const struct SBlock *sb, size_t off; char *emsg; struct GNUNET_HashCode key; + struct GNUNET_HashCode id_hash; + struct GNUNET_HashCode ns_hash; char *identifier; /* decrypt */ identifier = sc->uri->data.sks.identifier; - GNUNET_CRYPTO_hash (identifier, strlen (identifier), &key); + GNUNET_CRYPTO_hash (identifier, strlen (identifier), &id_hash); + GNUNET_CRYPTO_hash (&sc->uri->data.sks.ns, + sizeof (sc->uri->data.sks.ns), &ns_hash); + GNUNET_CRYPTO_hash_xor (&id_hash, &ns_hash, &key); GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv); - if (-1 == GNUNET_CRYPTO_aes_decrypt (&sb[1], len, &skey, &iv, pt)) + if (-1 == GNUNET_CRYPTO_aes_decrypt (&ub[1], len, &skey, &iv, pt)) { GNUNET_break (0); return; } /* parse */ - off = GNUNET_STRINGS_buffer_tokenize (pt, len, 2, &id, &uris); - if (0 == off) + if (0 == (off = GNUNET_STRINGS_buffer_tokenize (pt, len, 2, &id, &uris))) { - GNUNET_break_op (0); /* sblock malformed */ + GNUNET_break_op (0); /* ublock malformed */ return; } - meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[off], len - off); - if (meta == NULL) + if (NULL == (meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[off], len - off))) { - GNUNET_break_op (0); /* sblock malformed */ + GNUNET_break_op (0); /* ublock malformed */ return; } - uri = GNUNET_FS_uri_parse (uris, &emsg); - if (NULL == uri) + if (NULL == (uri = GNUNET_FS_uri_parse (uris, &emsg))) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to parse URI `%s': %s\n", uris, - emsg); - GNUNET_break_op (0); /* sblock malformed */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to parse URI `%s': %s\n"), + uris, emsg); + GNUNET_break_op (0); /* ublock malformed */ GNUNET_free_non_null (emsg); GNUNET_CONTAINER_meta_data_destroy (meta); return; @@ -836,44 +777,11 @@ process_result (struct GNUNET_FS_SearchContext *sc, enum GNUNET_BLOCK_Type type, } switch (type) { - case GNUNET_BLOCK_TYPE_FS_KBLOCK: - if (!GNUNET_FS_uri_test_ksk (sc->uri)) - { - GNUNET_break (0); - return; - } - if (sizeof (struct KBlock) > size) - { - GNUNET_break_op (0); - return; - } - process_kblock (sc, data, size); - break; - case GNUNET_BLOCK_TYPE_FS_SBLOCK: - if (!GNUNET_FS_uri_test_sks (sc->uri)) - { - GNUNET_break (0); - return; - } - if (sizeof (struct SBlock) > size) - { - GNUNET_break_op (0); - return; - } - process_sblock (sc, data, size); - break; - case GNUNET_BLOCK_TYPE_FS_NBLOCK: - if (!GNUNET_FS_uri_test_ksk (sc->uri)) - { - GNUNET_break (0); - return; - } - if (sizeof (struct NBlock) > size) - { - GNUNET_break_op (0); - return; - } - process_nblock (sc, data, size); + case GNUNET_BLOCK_TYPE_FS_UBLOCK: + if (GNUNET_FS_URI_SKS == sc->uri->type) + process_sblock (sc, data, size); + else + process_kblock (sc, data, size); break; case GNUNET_BLOCK_TYPE_ANY: GNUNET_break (0); @@ -1054,7 +962,10 @@ transmit_search_request (void *cls, size_t size, void *buf) struct SearchMessage *sm; const char *identifier; struct GNUNET_HashCode key; - struct GNUNET_HashCode idh; + struct GNUNET_HashCode signing_key; + struct GNUNET_HashCode ns_hash; + struct GNUNET_HashCode id_hash; + struct GNUNET_PseudonymIdentifier verification_key; unsigned int sqms; uint32_t options; @@ -1090,10 +1001,10 @@ transmit_search_request (void *cls, size_t size, void *buf) /* now build message */ msize += sizeof (struct GNUNET_HashCode) * mbc.put_cnt; sm->header.size = htons (msize); - sm->type = htonl (GNUNET_BLOCK_TYPE_ANY); + sm->type = htonl (GNUNET_BLOCK_TYPE_FS_UBLOCK); sm->anonymity_level = htonl (sc->anonymity); memset (&sm->target, 0, sizeof (struct GNUNET_HashCode)); - sm->query = sc->requests[sc->keyword_offset].query; + sm->query = sc->requests[sc->keyword_offset].uquery; GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map, &build_result_set, &mbc); GNUNET_assert (sqms >= sc->search_request_map_offset); @@ -1118,13 +1029,22 @@ transmit_search_request (void *cls, size_t size, void *buf) GNUNET_assert (GNUNET_FS_uri_test_sks (sc->uri)); msize = sizeof (struct SearchMessage); GNUNET_assert (size >= msize); - sm->type = htonl (GNUNET_BLOCK_TYPE_FS_SBLOCK); + sm->type = htonl (GNUNET_BLOCK_TYPE_FS_UBLOCK); sm->anonymity_level = htonl (sc->anonymity); - sm->target = sc->uri->data.sks.ns; + memset (&sm->target, 0, sizeof (struct GNUNET_HashCode)); + identifier = sc->uri->data.sks.identifier; - GNUNET_CRYPTO_hash (identifier, strlen (identifier), &key); - GNUNET_CRYPTO_hash (&key, sizeof (struct GNUNET_HashCode), &idh); - GNUNET_CRYPTO_hash_xor (&idh, &sm->target, &sm->query); + GNUNET_CRYPTO_hash (identifier, strlen (identifier), &id_hash); + GNUNET_CRYPTO_hash (&sc->uri->data.sks.ns, + sizeof (sc->uri->data.sks.ns), &ns_hash); + GNUNET_CRYPTO_hash_xor (&id_hash, &ns_hash, &key); + GNUNET_CRYPTO_hash (&key, sizeof (struct GNUNET_HashCode), &signing_key); + GNUNET_PSEUDONYM_derive_verification_key (&sc->uri->data.sks.ns, + &signing_key, + &verification_key); + GNUNET_CRYPTO_hash (&verification_key, + sizeof (verification_key), + &sm->query); mbc.put_cnt = (size - msize) / sizeof (struct GNUNET_HashCode); sqms = GNUNET_CONTAINER_multihashmap_size (sc->master_result_map); mbc.put_cnt = GNUNET_MIN (mbc.put_cnt, sqms - mbc.skip_cnt); @@ -1287,28 +1207,35 @@ GNUNET_FS_search_start_searching_ (struct GNUNET_FS_SearchContext *sc) { unsigned int i; const char *keyword; - struct GNUNET_HashCode hc; - struct GNUNET_CRYPTO_RsaPrivateKey *pk; + struct GNUNET_HashCode signing_key; + struct GNUNET_PseudonymHandle *ph; + struct GNUNET_PseudonymIdentifier anon; + struct GNUNET_PseudonymIdentifier verification_key; GNUNET_assert (NULL == sc->client); if (GNUNET_FS_uri_test_ksk (sc->uri)) { GNUNET_assert (0 != sc->uri->data.ksk.keywordCount); + ph = GNUNET_PSEUDONYM_get_anonymous_pseudonym_handle (); + GNUNET_PSEUDONYM_get_identifier (ph, &anon); + GNUNET_PSEUDONYM_destroy (ph); sc->requests = GNUNET_malloc (sizeof (struct SearchRequestEntry) * sc->uri->data.ksk.keywordCount); for (i = 0; i < sc->uri->data.ksk.keywordCount; i++) { keyword = &sc->uri->data.ksk.keywords[i][1]; - GNUNET_CRYPTO_hash (keyword, strlen (keyword), &hc); - pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&hc); - GNUNET_assert (NULL != pk); - GNUNET_CRYPTO_rsa_get_public_key_hash (pk, &sc->requests[i].query); + GNUNET_CRYPTO_hash (keyword, strlen (keyword), &sc->requests[i].ukey); + GNUNET_CRYPTO_hash (&sc->requests[i].ukey, sizeof (struct GNUNET_HashCode), &signing_key); + GNUNET_PSEUDONYM_derive_verification_key (&anon, + &signing_key, + &verification_key); + GNUNET_CRYPTO_hash (&verification_key, sizeof (struct GNUNET_PseudonymIdentifier), + &sc->requests[i].uquery); sc->requests[i].mandatory = (sc->uri->data.ksk.keywords[i][0] == '+'); if (sc->requests[i].mandatory) sc->mandatory_count++; sc->requests[i].results = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO); - GNUNET_CRYPTO_hash (keyword, strlen (keyword), &sc->requests[i].key); } } sc->client = GNUNET_CLIENT_connect ("fs", sc->h->cfg); diff --git a/src/fs/fs_unindex.c b/src/fs/fs_unindex.c index 49518a3df..17c3731fe 100644 --- a/src/fs/fs_unindex.c +++ b/src/fs/fs_unindex.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2003, 2004, 2006, 2009 Christian Grothoff (and other contributing authors) + (C) 2003--2013 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -260,7 +260,7 @@ process_fs_response (void *cls, const struct GNUNET_MessageHeader *msg) /** - * Function called when we are done with removing KBlocks. + * Function called when we are done with removing UBlocks. * Disconnect from datastore and notify FS service about * the unindex event. * @@ -314,7 +314,7 @@ unindex_finish (struct GNUNET_FS_UnindexContext *uc) /** * Function called by the directory scanner as we extract keywords - * that we will need to remove KBlocks. + * that we will need to remove UBlocks. * * @param cls the 'struct GNUNET_FS_UnindexContext *' * @param filename which file we are making progress on @@ -369,7 +369,7 @@ unindex_directory_scan_cb (void *cls, /** - * If necessary, connect to the datastore and remove the KBlocks. + * If necessary, connect to the datastore and remove the UBlocks. * * @param uc context for the unindex operation. */ @@ -391,7 +391,7 @@ GNUNET_FS_unindex_do_extract_keywords_ (struct GNUNET_FS_UnindexContext *uc) /** * Continuation called to notify client about result of the remove - * operation for the KBlock. + * operation for the UBlock. * * @param cls the 'struct GNUNET_FS_UnindexContext *' * @param success GNUNET_SYSERR on failure (including timeout/queue drop) @@ -413,7 +413,7 @@ continue_after_remove (void *cls, uc->dqe = NULL; if (success != GNUNET_YES) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Failed to remove KBlock: %s\n"), + _("Failed to remove UBlock: %s\n"), msg); uc->ksk_offset++; GNUNET_FS_unindex_do_remove_kblocks_ (uc); @@ -422,11 +422,11 @@ continue_after_remove (void *cls, /** * Function called from datastore with result from us looking for - * a KBlock. There are four cases: + * a UBlock. There are four cases: * 1) no result, means we move on to the next keyword * 2) UID is the same as the first UID, means we move on to next keyword - * 3) KBlock for a different CHK, means we keep looking for more - * 4) KBlock is for our CHK, means we remove the block and then move + * 3) UBlock for a different CHK, means we keep looking for more + * 4) UBlock is for our CHK, means we remove the block and then move * on to the next keyword * * @param cls the 'struct GNUNET_FS_UnindexContext *' @@ -442,7 +442,7 @@ continue_after_remove (void *cls, */ static void process_kblock_for_unindex (void *cls, - const struct GNUNET_HashCode * key, + const struct GNUNET_HashCode *key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, @@ -451,8 +451,9 @@ process_kblock_for_unindex (void *cls, expiration, uint64_t uid) { struct GNUNET_FS_UnindexContext *uc = cls; - const struct KBlock *kb; + const struct UBlock *ub; struct GNUNET_FS_Uri *chk_uri; + struct GNUNET_HashCode query; uc->dqe = NULL; if (NULL == data) @@ -474,38 +475,43 @@ process_kblock_for_unindex (void *cls, GNUNET_FS_unindex_do_remove_kblocks_ (uc); return; } - GNUNET_assert (GNUNET_BLOCK_TYPE_FS_KBLOCK == type); - if (size < sizeof (struct KBlock)) + GNUNET_assert (GNUNET_BLOCK_TYPE_FS_UBLOCK == type); + if (size < sizeof (struct UBlock)) { GNUNET_break (0); goto get_next; } - kb = data; + ub = data; + GNUNET_CRYPTO_hash (&ub->verification_key, + sizeof (ub->verification_key), + &query); + if (0 != memcmp (&query, key, sizeof (struct GNUNET_HashCode))) + { + /* result does not match our keyword, skip */ + goto get_next; + } { - char pt[size - sizeof (struct KBlock)]; + char pt[size - sizeof (struct UBlock)]; struct GNUNET_CRYPTO_AesSessionKey skey; struct GNUNET_CRYPTO_AesInitializationVector iv; - - GNUNET_CRYPTO_hash_to_aes_key (&uc->key, &skey, &iv); + + GNUNET_CRYPTO_hash_to_aes_key (&uc->ukey, &skey, &iv); if (-1 == - GNUNET_CRYPTO_aes_decrypt (&kb[1], size - sizeof (struct KBlock), &skey, + GNUNET_CRYPTO_aes_decrypt (&ub[1], size - sizeof (struct UBlock), &skey, &iv, pt)) { GNUNET_break (0); goto get_next; } - if (NULL == memchr (pt, 0, sizeof (pt))) + if (NULL == memchr (&pt[1], 0, sizeof (pt) - 1)) { - GNUNET_break (0); + GNUNET_break_op (0); /* malformed UBlock */ goto get_next; } - chk_uri = GNUNET_FS_uri_parse (pt, NULL); + chk_uri = GNUNET_FS_uri_parse (&pt[1], NULL); if (NULL == chk_uri) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to parse URI `%s' from KBlock!\n"), - pt); - GNUNET_break (0); + GNUNET_break_op (0); /* malformed UBlock */ goto get_next; } } @@ -529,8 +535,8 @@ process_kblock_for_unindex (void *cls, get_next: uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh, uc->roff++, - &uc->query, - GNUNET_BLOCK_TYPE_FS_KBLOCK, + &uc->uquery, + GNUNET_BLOCK_TYPE_FS_UBLOCK, 0 /* priority */, 1 /* queue size */, GNUNET_TIME_UNIT_FOREVER_REL, &process_kblock_for_unindex, @@ -547,7 +553,10 @@ void GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc) { const char *keyword; - struct GNUNET_CRYPTO_RsaPrivateKey *pk; + struct GNUNET_PseudonymHandle *ph; + struct GNUNET_PseudonymIdentifier anon; + struct GNUNET_PseudonymIdentifier verification_key; + struct GNUNET_HashCode signing_key; if (NULL == uc->dsh) uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg); @@ -566,16 +575,23 @@ GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc) return; } /* FIXME: code duplication with fs_search.c here... */ + ph = GNUNET_PSEUDONYM_get_anonymous_pseudonym_handle (); + GNUNET_PSEUDONYM_get_identifier (ph, &anon); + GNUNET_PSEUDONYM_destroy (ph); keyword = &uc->ksk_uri->data.ksk.keywords[uc->ksk_offset][1]; - GNUNET_CRYPTO_hash (keyword, strlen (keyword), &uc->key); - pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&uc->key); - GNUNET_assert (pk != NULL); - GNUNET_CRYPTO_rsa_get_public_key_hash (pk, &uc->query); + GNUNET_CRYPTO_hash (keyword, strlen (keyword), &uc->ukey); + GNUNET_CRYPTO_hash (&uc->ukey, sizeof (struct GNUNET_HashCode), &signing_key); + GNUNET_PSEUDONYM_derive_verification_key (&anon, + &signing_key, + &verification_key); + GNUNET_CRYPTO_hash (&verification_key, + sizeof (struct GNUNET_PseudonymIdentifier), + &uc->uquery); uc->first_uid = 0; uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh, uc->roff++, - &uc->query, - GNUNET_BLOCK_TYPE_FS_KBLOCK, + &uc->uquery, + GNUNET_BLOCK_TYPE_FS_UBLOCK, 0 /* priority */, 1 /* queue size */, GNUNET_TIME_UNIT_FOREVER_REL, &process_kblock_for_unindex, diff --git a/src/fs/fs_uri.c b/src/fs/fs_uri.c index e76693521..2b7af3c9e 100644 --- a/src/fs/fs_uri.c +++ b/src/fs/fs_uri.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + (C) 2003--2013 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -356,36 +356,30 @@ static struct GNUNET_FS_Uri * uri_sks_parse (const char *s, char **emsg) { struct GNUNET_FS_Uri *ret; - struct GNUNET_HashCode ns; - char *identifier; - unsigned int pos; - size_t slen; - char enc[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; + struct GNUNET_PseudonymIdentifier id; + size_t pos; + char *end; GNUNET_assert (s != NULL); - slen = strlen (s); pos = strlen (GNUNET_FS_URI_SKS_PREFIX); - if ((slen <= pos) || (0 != strncmp (s, GNUNET_FS_URI_SKS_PREFIX, pos))) + if ((strlen (s) <= pos) || (0 != strncmp (s, GNUNET_FS_URI_SKS_PREFIX, pos))) return NULL; /* not an SKS URI */ - if ((slen < pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) || - (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '/')) - { - *emsg = GNUNET_strdup (_("Malformed SKS URI")); - return NULL; - } - memcpy (enc, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); - enc[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; - if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (enc, &ns)) + end = strchr (&s[pos], '/'); + if ( (NULL == end) || + (GNUNET_OK != + GNUNET_STRINGS_string_to_data (&s[pos], + end - &s[pos], + &id, + sizeof (id))) ) { *emsg = GNUNET_strdup (_("Malformed SKS URI")); - return NULL; + return NULL; /* malformed */ } - identifier = - GNUNET_strdup (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]); + end++; /* skip over '/' */ ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ret->type = GNUNET_FS_URI_SKS; - ret->data.sks.ns = ns; - ret->data.sks.identifier = identifier; + ret->data.sks.ns = id; + ret->data.sks.identifier = GNUNET_strdup (end); return ret; } @@ -957,7 +951,7 @@ GNUNET_FS_uri_sks_create (struct GNUNET_FS_Namespace *ns, const char *id, } ns_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ns_uri->type = GNUNET_FS_URI_SKS; - GNUNET_FS_namespace_get_public_key_hash (ns, &ns_uri->data.sks.ns); + GNUNET_FS_namespace_get_public_identifier (ns, &ns_uri->data.sks.ns); ns_uri->data.sks.identifier = GNUNET_strdup (id); return ns_uri; } @@ -966,18 +960,19 @@ GNUNET_FS_uri_sks_create (struct GNUNET_FS_Namespace *ns, const char *id, /** * Create an SKS URI from a namespace ID and an identifier. * - * @param nsid namespace ID + * @param pseudonym namespace ID * @param id identifier * @return an FS URI for the given namespace and identifier */ struct GNUNET_FS_Uri * -GNUNET_FS_uri_sks_create_from_nsid (struct GNUNET_HashCode * nsid, const char *id) +GNUNET_FS_uri_sks_create_from_nsid (struct GNUNET_PseudonymIdentifier *pseudonym, + const char *id) { struct GNUNET_FS_Uri *ns_uri; ns_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ns_uri->type = GNUNET_FS_URI_SKS; - ns_uri->data.sks.ns = *nsid; + ns_uri->data.sks.ns = *pseudonym; ns_uri->data.sks.identifier = GNUNET_strdup (id); return ns_uri; } @@ -1337,19 +1332,19 @@ GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri) * namespace URI. * * @param uri the uri to get the namespace ID from - * @param nsid where to store the ID of the namespace + * @param pseudonym where to store the ID of the namespace * @return GNUNET_OK on success */ int GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri, - struct GNUNET_HashCode * nsid) + struct GNUNET_PseudonymIdentifier *pseudonym) { if (!GNUNET_FS_uri_test_sks (uri)) { GNUNET_break (0); return GNUNET_SYSERR; } - *nsid = uri->data.sks.ns; + *pseudonym = uri->data.sks.ns; return GNUNET_OK; } @@ -1939,18 +1934,20 @@ uri_ksk_to_string (const struct GNUNET_FS_Uri *uri) static char * uri_sks_to_string (const struct GNUNET_FS_Uri *uri) { - const struct GNUNET_HashCode *ns; - const char *identifier; char *ret; - struct GNUNET_CRYPTO_HashAsciiEncoded nsasc; + char buf[1024]; - if (uri->type != GNUNET_FS_URI_SKS) + if (GNUNET_FS_URI_SKS != uri->type) return NULL; - ns = &uri->data.sks.ns; - identifier = uri->data.sks.identifier; - GNUNET_CRYPTO_hash_to_enc (ns, &nsasc); + ret = GNUNET_STRINGS_data_to_string (&uri->data.sks.ns, + sizeof (struct GNUNET_PseudonymIdentifier), + buf, + sizeof (buf)); + GNUNET_assert (NULL != ret); + ret[0] = '\0'; GNUNET_asprintf (&ret, "%s%s%s/%s", GNUNET_FS_URI_PREFIX, - GNUNET_FS_URI_SKS_INFIX, (const char *) &nsasc, identifier); + GNUNET_FS_URI_SKS_INFIX, buf, + uri->data.sks.identifier); return ret; } diff --git a/src/fs/gnunet-pseudonym.c b/src/fs/gnunet-pseudonym.c index a692917da..dd3c9d4a2 100644 --- a/src/fs/gnunet-pseudonym.c +++ b/src/fs/gnunet-pseudonym.c @@ -95,19 +95,37 @@ progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info) static void -ns_printer (void *cls, const char *name, const struct GNUNET_HashCode * id) +ns_printer (void *cls, const char *name, const struct GNUNET_PseudonymIdentifier *pseudonym) { struct GNUNET_CRYPTO_HashAsciiEncoded enc; + struct GNUNET_HashCode hc; - GNUNET_CRYPTO_hash_to_enc (id, &enc); + GNUNET_CRYPTO_hash (pseudonym, + sizeof (struct GNUNET_PseudonymIdentifier), + &hc); + GNUNET_CRYPTO_hash_to_enc (&hc, &enc); FPRINTF (stdout, "%s (%s)\n", name, (const char *) &enc); } +/** + * Output information about a pseudonym. + * + * @param cls closure + * @param pseudonym hash code of public key of pseudonym + * @param name name of the pseudonym (might be NULL) + * @param unique_name unique name of the pseudonym (might be NULL) + * @param md meta data known about the pseudonym + * @param rating the local rating of the pseudonym + * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort + */ static int -pseudo_printer (void *cls, const struct GNUNET_HashCode * pseudonym, - const char *name, const char *unique_name, - const struct GNUNET_CONTAINER_MetaData *md, int rating) +pseudo_printer (void *cls, + const struct GNUNET_PseudonymIdentifier *pseudonym, + const char *name, + const char *unique_name, + const struct GNUNET_CONTAINER_MetaData *md, + int32_t rating) { char *id; char *unique_id; @@ -136,7 +154,7 @@ pseudo_printer (void *cls, const struct GNUNET_HashCode * pseudonym, static void post_advertising (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) { - struct GNUNET_HashCode nsid; + struct GNUNET_PseudonymIdentifier nsid; char *set; int delta; @@ -203,6 +221,7 @@ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { + struct GNUNET_FS_Uri *sks_uri; char *emsg; cfg = c; @@ -239,9 +258,13 @@ run (void *cls, char *const *args, const char *cfgfile, ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/namespace", &emsg); GNUNET_assert (NULL == emsg); } - GNUNET_FS_namespace_advertise (h, ksk_uri, ns, adv_metadata, &bo, - root_identifier, &post_advertising, - NULL); + sks_uri = GNUNET_FS_uri_sks_create (ns, root_identifier, &emsg); + GNUNET_assert (NULL == emsg); + GNUNET_FS_publish_ksk (h, ksk_uri, adv_metadata, sks_uri, + &bo, + GNUNET_FS_PUBLISH_OPTION_NONE, + &post_advertising, NULL); + GNUNET_FS_uri_destroy (sks_uri); return; } else diff --git a/src/fs/gnunet-service-fs.c b/src/fs/gnunet-service-fs.c index 0f4d513ff..4364265a8 100644 --- a/src/fs/gnunet-service-fs.c +++ b/src/fs/gnunet-service-fs.c @@ -405,9 +405,7 @@ start_p2p_processing (void *cls, struct GSF_PendingRequest *pr, "Considering stream-based download for block\n"); GSF_stream_lookup_ (pr); break; - case GNUNET_BLOCK_TYPE_FS_KBLOCK: - case GNUNET_BLOCK_TYPE_FS_SBLOCK: - case GNUNET_BLOCK_TYPE_FS_NBLOCK: + case GNUNET_BLOCK_TYPE_FS_UBLOCK: /* the above block types are in the DHT */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Considering DHT-based search for block\n"); diff --git a/src/fs/gnunet-service-fs.h b/src/fs/gnunet-service-fs.h index 3213712c8..60075e097 100644 --- a/src/fs/gnunet-service-fs.h +++ b/src/fs/gnunet-service-fs.h @@ -62,12 +62,6 @@ */ #define GET_MESSAGE_BIT_RETURN_TO 1 -/** - * The hash of the public key of the target - * namespace is included (for SKS queries). - */ -#define GET_MESSAGE_BIT_SKS_NAMESPACE 2 - /** * The peer identity of a peer that had claimed to have the content * previously is included (can be used if responder-anonymity is not diff --git a/src/fs/gnunet-service-fs_cp.c b/src/fs/gnunet-service-fs_cp.c index e389a24b2..f38a32c81 100644 --- a/src/fs/gnunet-service-fs_cp.c +++ b/src/fs/gnunet-service-fs_cp.c @@ -1143,7 +1143,6 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other, struct GSF_PendingRequestData *prd; struct GSF_ConnectedPeer *cp; struct GSF_ConnectedPeer *cps; - const struct GNUNET_HashCode *namespace; const struct GNUNET_PeerIdentity *target; enum GSF_PendingRequestOptions options; uint16_t msize; @@ -1244,17 +1243,6 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other, "Received request for `%s' of type %u from peer `%4s' with flags %u\n", GNUNET_h2s (&gm->query), (unsigned int) type, GNUNET_i2s (other), (unsigned int) bm); - namespace = (0 != (bm & GET_MESSAGE_BIT_SKS_NAMESPACE)) ? &opt[bits++] : NULL; - if ((GNUNET_BLOCK_TYPE_FS_SBLOCK == type) && (NULL == namespace)) - { - GNUNET_break_op (0); - return NULL; - } - if ((GNUNET_BLOCK_TYPE_FS_SBLOCK != type) && (NULL != namespace)) - { - GNUNET_break_op (0); - return NULL; - } target = (0 != (bm & GET_MESSAGE_BIT_TRANSMIT_TO)) ? ((const struct GNUNET_PeerIdentity @@ -1298,9 +1286,7 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other, { pr = peerreq->pr; prd = GSF_pending_request_get_data_ (pr); - if ((prd->type == type) && - ((type != GNUNET_BLOCK_TYPE_FS_SBLOCK) || - (0 == memcmp (&prd->namespace, namespace, sizeof (struct GNUNET_HashCode))))) + if (prd->type == type) { if (prd->ttl.abs_value >= GNUNET_TIME_absolute_get ().abs_value + ttl) { @@ -1324,7 +1310,7 @@ GSF_handle_p2p_query_ (const struct GNUNET_PeerIdentity *other, peerreq = GNUNET_malloc (sizeof (struct PeerRequest)); peerreq->cp = cp; - pr = GSF_pending_request_create_ (options, type, &gm->query, namespace, + pr = GSF_pending_request_create_ (options, type, &gm->query, target, (bfsize > 0) ? (const char *) &opt[bits] : NULL, diff --git a/src/fs/gnunet-service-fs_lc.c b/src/fs/gnunet-service-fs_lc.c index c3b6f40b0..f90131815 100644 --- a/src/fs/gnunet-service-fs_lc.c +++ b/src/fs/gnunet-service-fs_lc.c @@ -335,9 +335,9 @@ GSF_local_client_start_search_handler_ (struct GNUNET_SERVER_Client *client, GNUNET_h2s (&sm->query), (unsigned int) type); lc = GSF_local_client_lookup_ (client); cr = NULL; - /* detect duplicate KBLOCK requests */ - if ((type == GNUNET_BLOCK_TYPE_FS_KBLOCK) || - (type == GNUNET_BLOCK_TYPE_FS_NBLOCK) || (type == GNUNET_BLOCK_TYPE_ANY)) + /* detect duplicate UBLOCK requests */ + if ((type == GNUNET_BLOCK_TYPE_FS_UBLOCK) || + (type == GNUNET_BLOCK_TYPE_ANY)) { cr = lc->cr_head; while (cr != NULL) @@ -353,7 +353,7 @@ GSF_local_client_start_search_handler_ (struct GNUNET_SERVER_Client *client, cr = cr->next; } } - if (cr != NULL) + if (NULL != cr) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have existing request, merging content-seen lists.\n"); @@ -374,8 +374,8 @@ GSF_local_client_start_search_handler_ (struct GNUNET_SERVER_Client *client, options = GSF_PRO_LOCAL_REQUEST; if (0 != (SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY & ntohl (sm->options))) options |= GSF_PRO_LOCAL_ONLY; - cr->pr = GSF_pending_request_create_ (options, type, &sm->query, (type == GNUNET_BLOCK_TYPE_FS_SBLOCK) ? &sm->target /* namespace */ - : NULL, + cr->pr = GSF_pending_request_create_ (options, type, + &sm->query, (0 != memcmp (&sm->target, &all_zeros, sizeof (struct GNUNET_HashCode))) diff --git a/src/fs/gnunet-service-fs_pr.c b/src/fs/gnunet-service-fs_pr.c index 76e04f57c..2ab4771b5 100644 --- a/src/fs/gnunet-service-fs_pr.c +++ b/src/fs/gnunet-service-fs_pr.c @@ -268,7 +268,6 @@ refresh_bloomfilter (struct GSF_PendingRequest *pr) * @param options request options * @param type type of the block that is being requested * @param query key for the lookup - * @param namespace namespace to lookup, NULL for no namespace * @param target preferred target for the request, NULL for none * @param bf_data raw data for bloom filter for known replies, can be NULL * @param bf_size number of bytes in bf_data @@ -288,7 +287,6 @@ struct GSF_PendingRequest * GSF_pending_request_create_ (enum GSF_PendingRequestOptions options, enum GNUNET_BLOCK_Type type, const struct GNUNET_HashCode *query, - const struct GNUNET_HashCode *namespace, const struct GNUNET_PeerIdentity *target, const char *bf_data, size_t bf_size, uint32_t mingle, uint32_t anonymity_level, @@ -313,8 +311,6 @@ GSF_pending_request_create_ (enum GSF_PendingRequestOptions options, GNUNET_NO); #endif extra = 0; - if (GNUNET_BLOCK_TYPE_FS_SBLOCK == type) - extra += sizeof (struct GNUNET_HashCode); if (NULL != target) extra += sizeof (struct GNUNET_PeerIdentity); pr = GNUNET_malloc (sizeof (struct GSF_PendingRequest) + extra); @@ -322,13 +318,6 @@ GSF_pending_request_create_ (enum GSF_PendingRequestOptions options, GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); pr->public_data.query = *query; eptr = (struct GNUNET_HashCode *) &pr[1]; - if (GNUNET_BLOCK_TYPE_FS_SBLOCK == type) - { - GNUNET_assert (NULL != namespace); - pr->public_data.namespace = eptr; - memcpy (eptr, namespace, sizeof (struct GNUNET_HashCode)); - eptr++; - } if (NULL != target) { pr->public_data.target = (struct GNUNET_PeerIdentity *) eptr; @@ -435,12 +424,7 @@ GSF_pending_request_is_compatible_ (struct GSF_PendingRequest *pra, if ((pra->public_data.type != prb->public_data.type) || (0 != memcmp (&pra->public_data.query, &prb->public_data.query, - sizeof (struct GNUNET_HashCode))) || - ((pra->public_data.type == GNUNET_BLOCK_TYPE_FS_SBLOCK) && - (0 != - memcmp (pra->public_data.namespace, - prb->public_data.namespace, - sizeof (struct GNUNET_HashCode))))) + sizeof (struct GNUNET_HashCode)))) return GNUNET_NO; return GNUNET_OK; } @@ -546,11 +530,6 @@ GSF_pending_request_get_message_ (struct GSF_PendingRequest *pr, bm |= GET_MESSAGE_BIT_RETURN_TO; k++; } - if (GNUNET_BLOCK_TYPE_FS_SBLOCK == pr->public_data.type) - { - bm |= GET_MESSAGE_BIT_SKS_NAMESPACE; - k++; - } if (NULL != pr->public_data.target) { bm |= GET_MESSAGE_BIT_TRANSMIT_TO; @@ -586,8 +565,6 @@ GSF_pending_request_get_message_ (struct GSF_PendingRequest *pr, if (!do_route) GNUNET_PEER_resolve (pr->sender_pid, (struct GNUNET_PeerIdentity *) &ext[k++]); - if (GNUNET_BLOCK_TYPE_FS_SBLOCK == pr->public_data.type) - memcpy (&ext[k++], pr->public_data.namespace, sizeof (struct GNUNET_HashCode)); if (NULL != pr->public_data.target) memcpy (&ext[k++], pr->public_data.target, @@ -836,10 +813,7 @@ process_reply (void *cls, const struct GNUNET_HashCode * key, void *value) GNUNET_NO); prq->eval = GNUNET_BLOCK_evaluate (GSF_block_ctx, prq->type, key, &pr->bf, pr->mingle, - pr->public_data.namespace, - (prq->type == - GNUNET_BLOCK_TYPE_FS_SBLOCK) ? - sizeof (struct GNUNET_HashCode) : 0, prq->data, + NULL, 0, prq->data, prq->size); switch (prq->eval) { @@ -1140,12 +1114,6 @@ GSF_dht_lookup_ (struct GSF_PendingRequest *pr) } xquery = NULL; xquery_size = 0; - if (GNUNET_BLOCK_TYPE_FS_SBLOCK == pr->public_data.type) - { - xquery = buf; - memcpy (buf, pr->public_data.namespace, sizeof (struct GNUNET_HashCode)); - xquery_size = sizeof (struct GNUNET_HashCode); - } if (0 != (pr->public_data.options & GSF_PRO_FORWARD_ONLY)) { GNUNET_assert (0 != pr->sender_pid); diff --git a/src/fs/gnunet-service-fs_pr.h b/src/fs/gnunet-service-fs_pr.h index 371aa660b..66488f79c 100644 --- a/src/fs/gnunet-service-fs_pr.h +++ b/src/fs/gnunet-service-fs_pr.h @@ -86,12 +86,6 @@ struct GSF_PendingRequestData */ struct GNUNET_HashCode query; - /** - * Namespace to query, only set if the type is SBLOCK. - * Allocated after struct only if needed. Do not free! - */ - const struct GNUNET_HashCode *namespace; - /** * Identity of a peer hosting the content, otherwise NULl. * Allocated after struct only if needed. Do not free! @@ -212,7 +206,6 @@ typedef void (*GSF_PendingRequestReplyHandler) (void *cls, * @param options request options * @param type type of the block that is being requested * @param query key for the lookup - * @param namespace namespace to lookup, NULL for no namespace * @param target preferred target for the request, NULL for none * @param bf_data raw data for bloom filter for known replies, can be NULL * @param bf_size number of bytes in bf_data @@ -233,7 +226,6 @@ struct GSF_PendingRequest * GSF_pending_request_create_ (enum GSF_PendingRequestOptions options, enum GNUNET_BLOCK_Type type, const struct GNUNET_HashCode * query, - const struct GNUNET_HashCode * namespace, const struct GNUNET_PeerIdentity *target, const char *bf_data, size_t bf_size, uint32_t mingle, uint32_t anonymity_level, diff --git a/src/fs/gnunet-service-fs_put.c b/src/fs/gnunet-service-fs_put.c index 49962d314..ef796f559 100644 --- a/src/fs/gnunet-service-fs_put.c +++ b/src/fs/gnunet-service-fs_put.c @@ -83,9 +83,7 @@ struct PutOperator * of block that we're putting into the DHT). */ static struct PutOperator operators[] = { - {NULL, GNUNET_BLOCK_TYPE_FS_KBLOCK, 0, 0, 0}, - {NULL, GNUNET_BLOCK_TYPE_FS_SBLOCK, 0, 0, 0}, - {NULL, GNUNET_BLOCK_TYPE_FS_NBLOCK, 0, 0, 0}, + {NULL, GNUNET_BLOCK_TYPE_FS_UBLOCK, 0, 0, 0}, {NULL, GNUNET_BLOCK_TYPE_ANY, 0, 0, 0} }; diff --git a/src/fs/plugin_block_fs.c b/src/fs/plugin_block_fs.c index 8e90589cf..468dd96a3 100644 --- a/src/fs/plugin_block_fs.c +++ b/src/fs/plugin_block_fs.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - (C) 2010 Christian Grothoff (and other contributing authors) + (C) 2010, 2013 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -56,75 +56,67 @@ */ static enum GNUNET_BLOCK_EvaluationResult block_plugin_fs_evaluate (void *cls, enum GNUNET_BLOCK_Type type, - const struct GNUNET_HashCode * query, + const struct GNUNET_HashCode *query, struct GNUNET_CONTAINER_BloomFilter **bf, int32_t bf_mutator, const void *xquery, size_t xquery_size, const void *reply_block, size_t reply_block_size) { - const struct SBlock *sb; + const struct UBlock *ub; + struct GNUNET_HashCode hc; struct GNUNET_HashCode chash; struct GNUNET_HashCode mhash; - const struct GNUNET_HashCode *nsid; - struct GNUNET_HashCode sh; switch (type) { case GNUNET_BLOCK_TYPE_FS_DBLOCK: case GNUNET_BLOCK_TYPE_FS_IBLOCK: - if (xquery_size != 0) + if (0 != xquery_size) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } - if (reply_block == NULL) + if (NULL == reply_block) return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; return GNUNET_BLOCK_EVALUATION_OK_LAST; - case GNUNET_BLOCK_TYPE_FS_KBLOCK: - case GNUNET_BLOCK_TYPE_FS_NBLOCK: - if (xquery_size != 0) + case GNUNET_BLOCK_TYPE_FS_UBLOCK: + if (0 != xquery_size) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; } - if (reply_block == NULL) + if (NULL == reply_block) return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; - if (NULL != bf) + + if (reply_block_size < sizeof (struct UBlock)) { - GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); - GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash); - if (NULL != *bf) - { - if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash)) - return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; - } - else - { - *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K); - } - GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash); + GNUNET_break_op (0); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } - return GNUNET_BLOCK_EVALUATION_OK_MORE; - case GNUNET_BLOCK_TYPE_FS_SBLOCK: - if (xquery_size != sizeof (struct GNUNET_HashCode)) + ub = reply_block; + GNUNET_CRYPTO_hash (&ub->verification_key, + sizeof (ub->verification_key), + &hc); + if (0 != memcmp (&hc, + query, + sizeof (struct GNUNET_HashCode))) { GNUNET_break_op (0); - return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } - if (reply_block == NULL) - return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; - nsid = xquery; - if (reply_block_size < sizeof (struct SBlock)) + if (reply_block_size != ntohl (ub->purpose.size) + sizeof (struct GNUNET_PseudonymSignature)) + { + GNUNET_break_op (0); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + } + if (GNUNET_OK != + GNUNET_PSEUDONYM_verify (&ub->purpose, + &ub->signature, + &ub->verification_key)) { GNUNET_break_op (0); return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; } - sb = reply_block; - GNUNET_CRYPTO_hash (&sb->subspace, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &sh); - if (0 != memcmp (nsid, &sh, sizeof (struct GNUNET_HashCode))) - return GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT; if (NULL != bf) { GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash); @@ -161,11 +153,9 @@ block_plugin_fs_evaluate (void *cls, enum GNUNET_BLOCK_Type type, static int block_plugin_fs_get_key (void *cls, enum GNUNET_BLOCK_Type type, const void *block, size_t block_size, - struct GNUNET_HashCode * key) + struct GNUNET_HashCode *key) { - const struct KBlock *kb; - const struct SBlock *sb; - const struct NBlock *nb; + const struct UBlock *ub; switch (type) { @@ -173,104 +163,19 @@ block_plugin_fs_get_key (void *cls, enum GNUNET_BLOCK_Type type, case GNUNET_BLOCK_TYPE_FS_IBLOCK: GNUNET_CRYPTO_hash (block, block_size, key); return GNUNET_OK; - case GNUNET_BLOCK_TYPE_FS_KBLOCK: - if (block_size < sizeof (struct KBlock)) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - kb = block; - if (block_size - sizeof (struct KBlock) != - ntohl (kb->purpose.size) - - sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) - - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - if (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK, - &kb->purpose, &kb->signature, &kb->keyspace)) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - if (key != NULL) - GNUNET_CRYPTO_hash (&kb->keyspace, - sizeof (struct - GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - key); - return GNUNET_OK; - case GNUNET_BLOCK_TYPE_FS_SBLOCK: - if (block_size < sizeof (struct SBlock)) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - sb = block; - if (block_size != - ntohl (sb->purpose.size) + sizeof (struct GNUNET_CRYPTO_RsaSignature)) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - if (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK, - &sb->purpose, &sb->signature, &sb->subspace)) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - if (key != NULL) - *key = sb->identifier; - return GNUNET_OK; - case GNUNET_BLOCK_TYPE_FS_NBLOCK: - if (block_size < sizeof (struct NBlock)) + case GNUNET_BLOCK_TYPE_FS_UBLOCK: + if (block_size < sizeof (struct UBlock)) { - GNUNET_break_op (0); - return GNUNET_NO; - } - nb = block; - if (block_size - sizeof (struct NBlock) != - ntohl (nb->ns_purpose.size) - - sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) - - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - if (block_size != - ntohl (nb->ksk_purpose.size) + - sizeof (struct GNUNET_CRYPTO_RsaSignature)) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - if (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG, - &nb->ksk_purpose, &nb->ksk_signature, - &nb->keyspace)) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - if (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK, - &nb->ns_purpose, &nb->ns_signature, - &nb->subspace)) - { - GNUNET_break_op (0); - return GNUNET_NO; + GNUNET_break (0); + return GNUNET_SYSERR; } - /* FIXME: we used to xor ID with NSID, - * why not here? */ - if (key != NULL) - GNUNET_CRYPTO_hash (&nb->keyspace, - sizeof (struct - GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - key); + ub = block; + GNUNET_CRYPTO_hash (&ub->verification_key, + sizeof (ub->verification_key), + key); return GNUNET_OK; default: + GNUNET_break (0); return GNUNET_SYSERR; } } @@ -286,9 +191,7 @@ libgnunet_plugin_block_fs_init (void *cls) { GNUNET_BLOCK_TYPE_FS_DBLOCK, GNUNET_BLOCK_TYPE_FS_IBLOCK, - GNUNET_BLOCK_TYPE_FS_KBLOCK, - GNUNET_BLOCK_TYPE_FS_SBLOCK, - GNUNET_BLOCK_TYPE_FS_NBLOCK, + GNUNET_BLOCK_TYPE_FS_UBLOCK, GNUNET_BLOCK_TYPE_ANY /* end of list */ }; struct GNUNET_BLOCK_PluginFunctions *api; diff --git a/src/fs/test_fs_namespace.c b/src/fs/test_fs_namespace.c index 5d7eb841c..a72197e10 100644 --- a/src/fs/test_fs_namespace.c +++ b/src/fs/test_fs_namespace.c @@ -29,7 +29,7 @@ #include "gnunet_fs_service.h" -static struct GNUNET_HashCode nsid; +static struct GNUNET_PseudonymIdentifier nsid; static struct GNUNET_FS_Uri *sks_expect_uri; @@ -43,64 +43,27 @@ static struct GNUNET_FS_SearchContext *ksk_search; static GNUNET_SCHEDULER_TaskIdentifier kill_task; -static GNUNET_SCHEDULER_TaskIdentifier kill_ncc_task; - -struct GNUNET_FS_NamespaceCreationContext *ncc; - static int update_started; static int err; -static int phase; - -const struct GNUNET_CONFIGURATION_Handle *config; - -static void ns_created (void *cls, struct GNUNET_FS_Namespace *ns, const char *emsg); - -static void do_ncc_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - static void -next_phase () +abort_ksk_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - switch (phase) + if (ksk_search != NULL) { - case 0: - phase += 1; - FPRINTF (stderr, "%s", "Testing asynchronous namespace creation\n"); - ncc = GNUNET_FS_namespace_create_start (fs, "testNamespace", ns_created, NULL); - if (NULL == ncc) + GNUNET_FS_search_stop (ksk_search); + ksk_search = NULL; + if (sks_search == NULL) { - FPRINTF (stderr, "%s", "Failed to start asynchronous namespace creation\n"); - err = 1; - next_phase (); - return; + GNUNET_FS_stop (fs); + if (GNUNET_SCHEDULER_NO_TASK != kill_task) + GNUNET_SCHEDULER_cancel (kill_task); } - kill_ncc_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &do_ncc_timeout, - NULL); - break; - case 1: - FPRINTF (stderr, "%s", "Shutting down FS\n"); - GNUNET_FS_stop (fs); - if (GNUNET_SCHEDULER_NO_TASK != kill_task) - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; } } -static void -abort_ksk_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if (NULL == ksk_search) - return; - FPRINTF (stderr, "%s", "Stopping KSK search\n"); - GNUNET_FS_search_stop (ksk_search); - ksk_search = NULL; - if (sks_search == NULL) - next_phase (); -} - static void abort_sks_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) @@ -109,14 +72,17 @@ abort_sks_search_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) if (sks_search == NULL) return; - FPRINTF (stderr, "%s", "Stopping SKS search\n"); GNUNET_FS_search_stop (sks_search); sks_search = NULL; ns = GNUNET_FS_namespace_create (fs, "testNamespace"); GNUNET_assert (NULL != ns); GNUNET_assert (GNUNET_OK == GNUNET_FS_namespace_delete (ns, GNUNET_YES)); if (ksk_search == NULL) - next_phase (); + { + GNUNET_FS_stop (fs); + if (GNUNET_SCHEDULER_NO_TASK != kill_task) + GNUNET_SCHEDULER_cancel (kill_task); + } } @@ -133,25 +99,18 @@ do_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static void * progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) { - char *got; switch (event->status) { case GNUNET_FS_STATUS_SEARCH_RESULT: - got = GNUNET_FS_uri_to_string (event->value.search.specifics.result.uri); - FPRINTF (stderr, "Got a search result `%s'\n", got); if (sks_search == event->value.search.sc) { if (!GNUNET_FS_uri_test_equal (sks_expect_uri, event->value.search.specifics.result.uri)) { - char *expected; - expected = GNUNET_FS_uri_to_string (sks_expect_uri); - FPRINTF (stderr, "Wrong result for sks search! Expected:\n%s\nGot:\n%s\n", expected, got); - GNUNET_free (expected); + FPRINTF (stderr, "%s", "Wrong result for sks search!\n"); err = 1; } /* give system 1ms to initiate update search! */ - FPRINTF (stderr, "scheduling `%s'\n", "abort_sks_search_task"); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, &abort_sks_search_task, NULL); } @@ -160,22 +119,17 @@ progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) if (!GNUNET_FS_uri_test_equal (ksk_expect_uri, event->value.search.specifics.result.uri)) { - char *expected; - expected = GNUNET_FS_uri_to_string (ksk_expect_uri); - FPRINTF (stderr, "Wrong result for ksk search! Expected:\n%s\nGot:\n%s\n", expected, got); - GNUNET_free (expected); + FPRINTF (stderr, "%s", "Wrong result for ksk search!\n"); err = 1; } - FPRINTF (stderr, "scheduling `%s'\n", "abort_ksk_search_task"); GNUNET_SCHEDULER_add_continuation (&abort_ksk_search_task, NULL, GNUNET_SCHEDULER_REASON_PREREQ_DONE); } else { - FPRINTF (stderr, "Unexpected search result `%s' received!\n", got); + FPRINTF (stderr, "%s", "Unexpected search result received!\n"); GNUNET_break (0); } - GNUNET_free (got); break; case GNUNET_FS_STATUS_SEARCH_ERROR: FPRINTF (stderr, "Error searching file: %s\n", @@ -190,7 +144,6 @@ progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) GNUNET_break (0); break; case GNUNET_FS_STATUS_SEARCH_START: - FPRINTF (stderr, "Search %s started\n", event->value.search.pctx); GNUNET_assert ((NULL == event->value.search.cctx) || (0 == strcmp ("sks_search", event->value.search.cctx)) || (0 == strcmp ("ksk_search", event->value.search.cctx))); @@ -202,10 +155,8 @@ progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *event) GNUNET_assert (1 == event->value.search.anonymity); break; case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED: - FPRINTF (stderr, "%s", "Search result stopped\n"); return NULL; case GNUNET_FS_STATUS_SEARCH_STOPPED: - FPRINTF (stderr, "%s", "Search stopped\n"); return NULL; default: FPRINTF (stderr, "Unexpected event: %d\n", event->status); @@ -221,18 +172,20 @@ publish_cont (void *cls, const struct GNUNET_FS_Uri *ksk_uri, const char *emsg) char *msg; struct GNUNET_FS_Uri *sks_uri; char sbuf[1024]; - struct GNUNET_CRYPTO_HashAsciiEncoded enc; + char buf[1024]; + char *ret; if (NULL != emsg) { - FPRINTF (stderr, "Error publishing ksk: %s\n", emsg); + FPRINTF (stderr, "Error publishing: %s\n", emsg); err = 1; GNUNET_FS_stop (fs); return; } - FPRINTF (stderr, "%s", "Published ksk\n"); - GNUNET_CRYPTO_hash_to_enc (&nsid, &enc); - GNUNET_snprintf (sbuf, sizeof (sbuf), "gnunet://fs/sks/%s/this", &enc); + ret = GNUNET_STRINGS_data_to_string (&nsid, sizeof (nsid), buf, sizeof (buf)); + GNUNET_assert (NULL != ret); + ret[0] = '\0'; + GNUNET_snprintf (sbuf, sizeof (sbuf), "gnunet://fs/sks/%s/this", buf); sks_uri = GNUNET_FS_uri_parse (sbuf, &msg); if (NULL == sks_uri) { @@ -242,7 +195,6 @@ publish_cont (void *cls, const struct GNUNET_FS_Uri *ksk_uri, const char *emsg) GNUNET_free_non_null (msg); return; } - FPRINTF (stderr, "%s", "Starting searches\n"); ksk_search = GNUNET_FS_search_start (fs, ksk_uri, 1, GNUNET_FS_SEARCH_OPTION_NONE, "ksk_search"); @@ -260,21 +212,17 @@ sks_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) struct GNUNET_FS_Uri *ksk_uri; char *msg; struct GNUNET_FS_BlockOptions bo; - char *suri; if (NULL == uri) { - fprintf (stderr, "Error publishing sks: %s\n", emsg); + fprintf (stderr, "Error publishing: %s\n", emsg); err = 1; GNUNET_FS_stop (fs); return; } - FPRINTF (stderr, "%s", "Published sks\n"); meta = GNUNET_CONTAINER_meta_data_create (); msg = NULL; - GNUNET_asprintf (&suri, "gnunet://fs/ksk/ns-search%d", phase); - ksk_uri = GNUNET_FS_uri_parse (suri, &msg); - GNUNET_free (suri); + ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/ns-search", &msg); GNUNET_assert (NULL == msg); ksk_expect_uri = GNUNET_FS_uri_dup (uri); bo.content_priority = 1; @@ -298,12 +246,11 @@ adv_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) if (NULL != emsg) { - FPRINTF (stderr, "Error advertising: %s\n", emsg); + FPRINTF (stderr, "Error publishing: %s\n", emsg); err = 1; GNUNET_FS_stop (fs); return; } - FPRINTF (stderr, "%s", "Created an advertising\n"); ns = GNUNET_FS_namespace_create (fs, "testNamespace"); GNUNET_assert (NULL != ns); meta = GNUNET_CONTAINER_meta_data_create (); @@ -314,7 +261,7 @@ adv_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); - GNUNET_FS_publish_sks (fs, ns, "this", "next", meta, uri, /* FIXME: this is non-sense (use CHK URI!?) */ + GNUNET_FS_publish_sks (fs, ns, "this", "next", meta, uri, &bo, GNUNET_FS_PUBLISH_OPTION_NONE, &sks_cont, NULL); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_FS_namespace_delete (ns, GNUNET_NO); @@ -322,27 +269,29 @@ adv_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg) static void -ns_iterator (void *cls, const char *name, const struct GNUNET_HashCode * id) +ns_iterator (void *cls, const char *name, const struct GNUNET_PseudonymIdentifier *id) { int *ok = cls; - FPRINTF (stderr, "Namespace in the list: %s\n", name); if (0 != strcmp (name, "testNamespace")) return; *ok = GNUNET_YES; nsid = *id; } + static void -testCreatedNamespace (struct GNUNET_FS_Namespace *ns) +testNamespace () { + struct GNUNET_FS_Namespace *ns; struct GNUNET_FS_BlockOptions bo; struct GNUNET_CONTAINER_MetaData *meta; struct GNUNET_FS_Uri *ksk_uri; + struct GNUNET_FS_Uri *sks_uri; int ok; - char *uri; - FPRINTF (stderr, "%s", "Listing namespaces\n"); + ns = GNUNET_FS_namespace_create (fs, "testNamespace"); + GNUNET_assert (NULL != ns); ok = GNUNET_NO; GNUNET_FS_namespace_list (fs, &ns_iterator, &ok); if (GNUNET_NO == ok) @@ -353,65 +302,24 @@ testCreatedNamespace (struct GNUNET_FS_Namespace *ns) err = 1; return; } - FPRINTF (stderr, "%s", "Creating an advertising\n"); meta = GNUNET_CONTAINER_meta_data_create (); - GNUNET_asprintf (&uri, "gnunet://fs/ksk/testnsa%d", phase); - ksk_uri = GNUNET_FS_uri_parse (uri, NULL); - GNUNET_free (uri); + ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/testnsa", NULL); bo.content_priority = 1; bo.anonymity_level = 1; bo.replication_level = 0; bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); - GNUNET_FS_namespace_advertise (fs, ksk_uri, ns, meta, &bo, "root", &adv_cont, - NULL); - GNUNET_FS_uri_destroy (ksk_uri); - GNUNET_FS_namespace_delete (ns, GNUNET_NO); - GNUNET_CONTAINER_meta_data_destroy (meta); -} - -static void -do_ncc_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - FPRINTF (stderr, "%s", "Asynchronous NS creation timed out\n"); - kill_ncc_task = GNUNET_SCHEDULER_NO_TASK; - if (NULL == ncc) - return; - GNUNET_FS_namespace_create_stop (ncc); - ncc = NULL; - err = 1; -} - -static void -ns_created (void *cls, struct GNUNET_FS_Namespace *ns, const char *emsg) -{ - if (GNUNET_SCHEDULER_NO_TASK != kill_ncc_task) - GNUNET_SCHEDULER_cancel (kill_ncc_task); - kill_ncc_task = GNUNET_SCHEDULER_NO_TASK; - if (NULL == ns) - { - FPRINTF (stderr, "Asynchronous NS creation failed: %s\n", emsg); - err = 1; - return; - } - - FPRINTF (stderr, "%s", "Namespace created asynchronously\n"); - testCreatedNamespace (ns); -} - -static void -testNamespace () -{ - struct GNUNET_FS_Namespace *ns; - - FPRINTF (stderr, "%s", "Testing synchronous namespace creation\n"); - ns = GNUNET_FS_namespace_create (fs, "testNamespace"); - GNUNET_assert (NULL != ns); - testCreatedNamespace (ns); - + sks_uri = GNUNET_FS_uri_sks_create (ns, "root", NULL); + GNUNET_FS_publish_ksk (fs, + ksk_uri, meta, sks_uri, &bo, GNUNET_FS_PUBLISH_OPTION_NONE, + &adv_cont, NULL); + GNUNET_FS_uri_destroy (sks_uri); kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &do_timeout, NULL); + GNUNET_FS_uri_destroy (ksk_uri); + GNUNET_FS_namespace_delete (ns, GNUNET_NO); + GNUNET_CONTAINER_meta_data_destroy (meta); } @@ -420,10 +328,8 @@ run (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TESTING_Peer *peer) { - config = cfg; fs = GNUNET_FS_start (cfg, "test-fs-namespace", &progress_cb, NULL, GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END); - phase = 0; testNamespace (); } diff --git a/src/fs/test_fs_uri.c b/src/fs/test_fs_uri.c index 47fa2024b..6d0bfdea9 100644 --- a/src/fs/test_fs_uri.c +++ b/src/fs/test_fs_uri.c @@ -162,6 +162,11 @@ testNamespace (int i) char *uri; struct GNUNET_FS_Uri *ret; char *emsg; + struct GNUNET_PseudonymHandle *ph; + struct GNUNET_PseudonymIdentifier id; + char buf[1024]; + char ubuf[1024]; + char *sret; if (NULL != (ret = @@ -187,11 +192,17 @@ testNamespace (int i) GNUNET_assert (0); } GNUNET_free (emsg); - ret = - GNUNET_FS_uri_parse - ("gnunet://fs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test", - &emsg); - if (ret == NULL) + ph = GNUNET_PSEUDONYM_create (NULL); + GNUNET_PSEUDONYM_get_identifier (ph, &id); + sret = GNUNET_STRINGS_data_to_string (&id, sizeof (id), + ubuf, sizeof (ubuf) - 1); + GNUNET_assert (NULL != sret); + sret[0] = '\0'; + GNUNET_snprintf (buf, sizeof (buf), + "gnunet://fs/sks/%s/test", + ubuf); + ret = GNUNET_FS_uri_parse (buf, &emsg); + if (NULL == ret) { GNUNET_free (emsg); GNUNET_assert (0); @@ -210,7 +221,7 @@ testNamespace (int i) uri = GNUNET_FS_uri_to_string (ret); if (0 != strcmp (uri, - "gnunet://fs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test")) + buf)) { GNUNET_FS_uri_destroy (ret); GNUNET_free (uri); diff --git a/src/include/block_fs.h b/src/include/block_fs.h index 0b77adc49..6f37dcf0e 100644 --- a/src/include/block_fs.h +++ b/src/include/block_fs.h @@ -28,119 +28,49 @@ #include "gnunet_util_lib.h" -/** - * @brief keyword block (advertising data under a keyword) - */ -struct KBlock -{ - - /** - * GNUNET_RSA_Signature using RSA-key generated from search keyword. - */ - struct GNUNET_CRYPTO_RsaSignature signature; - - /** - * What is being signed and why? - */ - struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; - - /** - * Key generated (!) from the H(keyword) as the seed! - */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded keyspace; - - /* 0-terminated URI here */ - - /* variable-size Meta-Data follows here */ - -}; - /** - * @brief namespace content block (advertising data under an identifier in a namespace) + * Maximum legal size for a ublock. */ -struct SBlock -{ +#define MAX_UBLOCK_SIZE (60 * 1024) - /** - * GNUNET_RSA_Signature using RSA-key of the namespace - */ - struct GNUNET_CRYPTO_RsaSignature signature; - /** - * What is being signed and why? - */ - struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; - - /** - * Hash of the hash of the human-readable identifier used for - * this entry (the hash of the human-readable identifier is - * used as the key for decryption; the xor of this identifier - * and the hash of the "keyspace" is the datastore-query hash). - */ - struct GNUNET_HashCode identifier; - - /** - * Public key of the namespace. - */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded subspace; - - /* 0-terminated update-identifier here */ - - /* 0-terminated URI here (except for NBlocks) */ - - /* variable-size Meta-Data follows here */ - -}; +GNUNET_NETWORK_STRUCT_BEGIN /** - * @brief namespace advertisement block (advertising root of a namespace) + * @brief universal block for keyword and namespace search results */ -struct NBlock +struct UBlock { /** - * GNUNET_RSA_Signature using RSA-key generated from search keyword. + * Signature using pseudonym and search keyword / identifier. */ - struct GNUNET_CRYPTO_RsaSignature ksk_signature; + struct GNUNET_PseudonymSignature signature; /** * What is being signed and why? */ - struct GNUNET_CRYPTO_RsaSignaturePurpose ksk_purpose; + struct GNUNET_PseudonymSignaturePurpose purpose; /** - * Key generated (!) from the H(keyword) as the seed! + * Public key used to sign this block. Hash of this value + * is the query. */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded keyspace; + struct GNUNET_PseudonymIdentifier verification_key; - /** - * GNUNET_RSA_Signature using RSA-key of the namespace - */ - struct GNUNET_CRYPTO_RsaSignature ns_signature; - - /** - * What is being signed and why? - */ - struct GNUNET_CRYPTO_RsaSignaturePurpose ns_purpose; + /* rest of the data is encrypted */ - /** - * Public key of the namespace. - */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded subspace; - - /* from here on, data is encrypted with H(keyword) */ + /* 0-terminated update-identifier here (ignored for keyword results) */ - /* 0-terminated root identifier here */ + /* 0-terminated URI here */ /* variable-size Meta-Data follows here */ }; -GNUNET_NETWORK_STRUCT_BEGIN - /** * @brief index block (indexing a DBlock that * can be obtained directly from reading diff --git a/src/include/gnunet_block_lib.h b/src/include/gnunet_block_lib.h index 002d5c11b..ac9d9d5f8 100644 --- a/src/include/gnunet_block_lib.h +++ b/src/include/gnunet_block_lib.h @@ -41,15 +41,15 @@ extern "C" */ enum GNUNET_BLOCK_Type { - /** - * Any type of block, used as a wildcard when searching. Should - * never be attached to a specific block. - */ + /** + * Any type of block, used as a wildcard when searching. Should + * never be attached to a specific block. + */ GNUNET_BLOCK_TYPE_ANY = 0, - /** - * Data block (leaf) in the CHK tree. - */ + /** + * Data block (leaf) in the CHK tree. + */ GNUNET_BLOCK_TYPE_FS_DBLOCK = 1, /** @@ -57,67 +57,73 @@ enum GNUNET_BLOCK_Type */ GNUNET_BLOCK_TYPE_FS_IBLOCK = 2, - /** - * Type of a block representing a keyword search result. Note that - * the values for KBLOCK, SBLOCK and NBLOCK must be consecutive. - */ + /** + * Legacy type, no longer in use. + */ GNUNET_BLOCK_TYPE_FS_KBLOCK = 3, - /** - * Type of a block that is used to advertise content in a namespace. - */ + /** + * Legacy type, no longer in use. + */ GNUNET_BLOCK_TYPE_FS_SBLOCK = 4, - /** - * Type of a block that is used to advertise a namespace. - */ + /** + * Legacy type, no longer in use. + */ GNUNET_BLOCK_TYPE_FS_NBLOCK = 5, - /** - * Type of a block representing a block to be encoded on demand from disk. - * Should never appear on the network directly. - */ + /** + * Type of a block representing a block to be encoded on demand from disk. + * Should never appear on the network directly. + */ GNUNET_BLOCK_TYPE_FS_ONDEMAND = 6, - /** - * Type of a block that contains a HELLO for a peer (for - * DHT find-peer operations). - */ + /** + * Type of a block that contains a HELLO for a peer (for + * DHT find-peer operations). + */ GNUNET_BLOCK_TYPE_DHT_HELLO = 7, - /** - * Block for testing. - */ + /** + * Block for testing. + */ GNUNET_BLOCK_TYPE_TEST = 8, - - /** - * Block for storing .gnunet-domains - */ + + /** + * Type of a block representing any type of search result + * (universal). Implemented in the context of #2564, replaces + * SBLOCKS, KBLOCKS and NBLOCKS. + */ + GNUNET_BLOCK_TYPE_FS_UBLOCK = 9, + + /** + * Block for storing .gnunet-domains + */ GNUNET_BLOCK_TYPE_DNS = 10, - /** - * Block for storing record data - */ + /** + * Block for storing record data + */ GNUNET_BLOCK_TYPE_GNS_NAMERECORD = 11, - /** - * Block for storing mesh peers - */ + /** + * Block for storing mesh peers + */ GNUNET_BLOCK_TYPE_MESH_PEER = 20, - - /** - * Block for finding peers by type - */ + + /** + * Block for finding peers by type + */ GNUNET_BLOCK_TYPE_MESH_PEER_BY_TYPE = 21, - /** - * Block to store a mesh regex state - */ + /** + * Block to store a mesh regex state + */ GNUNET_BLOCK_TYPE_REGEX = 22, - /** - * Block to store a mesh regex accepting state - */ + /** + * Block to store a mesh regex accepting state + */ GNUNET_BLOCK_TYPE_REGEX_ACCEPT = 23 }; diff --git a/src/include/gnunet_fs_service.h b/src/include/gnunet_fs_service.h index efe2cd004..931406e2d 100644 --- a/src/include/gnunet_fs_service.h +++ b/src/include/gnunet_fs_service.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet - (C) 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + (C) 2004--2013 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -54,8 +54,9 @@ extern "C" * 6.1.x: with simplified namespace support * 9.0.0: CPS-style integrated API * 9.1.1: asynchronous directory scanning + * 9.2.0: unified K-Block and S-block format (#2564) */ -#define GNUNET_FS_VERSION 0x00090103 +#define GNUNET_FS_VERSION 0x00090200 /* ******************** URI API *********************** */ @@ -342,25 +343,26 @@ GNUNET_FS_uri_sks_create (struct GNUNET_FS_Namespace *ns, const char *id, /** * Create an SKS URI from a namespace ID and an identifier. * - * @param nsid namespace ID + * @param pseudonym pseudonym to use * @param id identifier * @return an FS URI for the given namespace and identifier */ struct GNUNET_FS_Uri * -GNUNET_FS_uri_sks_create_from_nsid (struct GNUNET_HashCode * nsid, const char *id); +GNUNET_FS_uri_sks_create_from_nsid (struct GNUNET_PseudonymIdentifier *pseudonym, + const char *id); /** - * Get the ID of a namespace from the given + * Get the public key of a namespace from the given * namespace URI. * * @param uri the uri to get the namespace ID from - * @param nsid where to store the ID of the namespace + * @param pseudonym where to store the public key of the namespace * @return GNUNET_OK on success */ int GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri, - struct GNUNET_HashCode * nsid); + struct GNUNET_PseudonymIdentifier *pseudonym); /** @@ -1403,9 +1405,9 @@ struct GNUNET_FS_ProgressInfo const struct GNUNET_CONTAINER_MetaData *meta; /** - * Hash-identifier for the namespace. + * Public key of the namespace. */ - struct GNUNET_HashCode id; + struct GNUNET_PseudonymIdentifier pseudonym; } ns; @@ -2188,60 +2190,6 @@ void GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc); -/** - * Context for advertising a namespace. - */ -struct GNUNET_FS_AdvertisementContext; - - -/** - * Publish an advertismement for a namespace. - * - * @param h handle to the file sharing subsystem - * @param ksk_uri keywords to use for advertisment - * @param ns handle for the namespace that should be advertised - * @param meta meta-data for the namespace advertisement - * @param bo block options - * @param rootEntry name of the root of the namespace - * @param cont continuation - * @param cont_cls closure for cont - * @return NULL on error ('cont' will still be called) - */ -struct GNUNET_FS_AdvertisementContext * -GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, - struct GNUNET_FS_Uri *ksk_uri, - struct GNUNET_FS_Namespace *ns, - const struct GNUNET_CONTAINER_MetaData *meta, - const struct GNUNET_FS_BlockOptions *bo, - const char *rootEntry, - GNUNET_FS_PublishContinuation cont, - void *cont_cls); - - -/** - * Create an SKS uri that points to the root entry of the namespace, - * then insert that SKS uri into metadata. - * - * @param ns handle for the namespace that should be advertised - * @param meta meta-data into which namespace advertisement should be inserted - * @param rootEntry name of the root of the namespace (use NULL to use default) - * @return GNUNET_OK on success, GNUNET_SYSERR on error - */ -int -GNUNET_FS_namespace_insert_advertisement_into_metadata ( - struct GNUNET_FS_Namespace *ns, struct GNUNET_CONTAINER_MetaData *meta, - const char *rootEntry); - - -/** - * Abort the namespace advertisement operation. - * - * @param ac context of the operation to abort. - */ -void -GNUNET_FS_namespace_advertise_cancel (struct GNUNET_FS_AdvertisementContext *ac); - - /** * Create a namespace with the given name; if one already * exists, return a handle to the existing namespace. @@ -2267,45 +2215,6 @@ struct GNUNET_FS_Namespace * GNUNET_FS_namespace_open_existing (struct GNUNET_FS_Handle *h, const char *name); -/** - * Context for creating a namespace asynchronously. - */ -struct GNUNET_FS_NamespaceCreationContext; - -/** - * Function called upon completion of 'GNUNET_FS_namespace_create_start'. - * - * @param cls closure - * @param ns NULL on error, otherwise the namespace (which must be free'd by the callee) - * @param emsg NULL on success, otherwise an error message - */ -typedef void (*GNUNET_FS_NamespaceCreationCallback)(void *cls, - struct GNUNET_FS_Namespace *ns, const char *emsg); - - -/** - * Create a namespace with the given name; if one already - * exists, return a handle to the existing namespace immediately. - * Otherwise create a namespace asynchronously. - * - * @param h handle to the file sharing subsystem - * @param name name to use for the namespace - * @return namespace creation context, NULL on error (i.e. invalid filename) - */ -struct GNUNET_FS_NamespaceCreationContext * -GNUNET_FS_namespace_create_start (struct GNUNET_FS_Handle *h, const char *name, - GNUNET_FS_NamespaceCreationCallback cont, void *cont_cls); - - -/** - * Abort namespace creation. - * - * @param ncc namespace creation context to abort - */ -void -GNUNET_FS_namespace_create_stop (struct GNUNET_FS_NamespaceCreationContext *ncc); - - /** * Rename a local namespace. * @@ -2338,8 +2247,8 @@ GNUNET_FS_namespace_dup (struct GNUNET_FS_Namespace *ns); * GNUNET_SYSERR on failure (contents of id remain intact) */ int -GNUNET_FS_namespace_get_public_key_hash (struct GNUNET_FS_Namespace *ns, - struct GNUNET_HashCode *id); +GNUNET_FS_namespace_get_public_identifier (struct GNUNET_FS_Namespace *ns, + struct GNUNET_PseudonymIdentifier *id); /** @@ -2364,10 +2273,10 @@ GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *ns, int freeze); * * @param cls closure * @param name human-readable identifier of the namespace - * @param id hash identifier for the namespace + * @param id identifier for the namespace */ typedef void (*GNUNET_FS_NamespaceInfoProcessor) (void *cls, const char *name, - const struct GNUNET_HashCode * id); + const struct GNUNET_PseudonymIdentifier *id); /** diff --git a/src/include/gnunet_pseudonym_lib.h b/src/include/gnunet_pseudonym_lib.h index 6ec51b678..11b5cd9e4 100644 --- a/src/include/gnunet_pseudonym_lib.h +++ b/src/include/gnunet_pseudonym_lib.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + (C) 2001--2013 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -39,6 +39,166 @@ extern "C" #include "gnunet_configuration_lib.h" #include "gnunet_container_lib.h" + +/** + * Identifier for a GNUnet pseudonym (the public key). + */ +struct GNUNET_PseudonymIdentifier +{ + /** + * The public key of the pseudonym. + */ + char public_key[42]; +}; + + +/** + * Handle for a pseudonym (private key). + */ +struct GNUNET_PseudonymHandle; + + +/** + * Signature made with a pseudonym (includes the full public key) + */ +struct GNUNET_PseudonymSignature +{ + + /** + * Who created the signature? (public key of the signer) + */ + struct GNUNET_PseudonymIdentifier signer; + + /** + * Binary signature data, padded with zeros if needed. + */ + char signature[42]; +}; + + +/** + * Purpose for signature made with a pseudonym. + */ +struct GNUNET_PseudonymSignaturePurpose +{ + /** + * How many bytes are being signed (including this header)? + */ + uint32_t size; + + /** + * What is the context/purpose of the signature? + */ + uint32_t purpose; +}; + + +/** + * Create a pseudonym. + * + * @param filename name of the file to use for storage, NULL for in-memory only + * @return handle to the private key of the pseudonym + */ +struct GNUNET_PseudonymHandle * +GNUNET_PSEUDONYM_create (const char *filename); + + +/** + * Create a pseudonym, from a file that must already exist. + * + * @param filename name of the file to use for storage, NULL for in-memory only + * @return handle to the private key of the pseudonym + */ +struct GNUNET_PseudonymHandle * +GNUNET_PSEUDONYM_create_from_existing_file (const char *filename); + + +/** + * Get the handle for the 'anonymous' pseudonym shared by all users. + * That pseudonym uses a fixed 'secret' for the private key; this + * construction is useful to make anonymous and pseudonymous APIs + * (and packets) indistinguishable on the network. See #2564. + * + * @return handle to the (non-secret) private key of the 'anonymous' pseudonym + */ +struct GNUNET_PseudonymHandle * +GNUNET_PSEUDONYM_get_anonymous_pseudonym_handle (void); + + +/** + * Destroy a pseudonym handle. Does NOT remove the private key from + * the disk. + * + * @param ph pseudonym handle to destroy + */ +void +GNUNET_PSEUDONYM_destroy (struct GNUNET_PseudonymHandle *ph); + + +/** + * Cryptographically sign some data with the pseudonym. + * + * @param ph private key used for signing (corresponds to 'x' in #2564) + * @param purpose data to sign + * @param seed hash of the plaintext of the data that we are signing, + * used for deterministic PRNG for anonymous signing; + * corresponds to 'k' in section 2.7 of #2564 + * @param signing_key modifier to apply to the private key for signing; + * corresponds to 'h' in section 2.3 of #2564. + * @param signature where to store the signature + */ +void +GNUNET_PSEUDONYM_sign (struct GNUNET_PseudonymHandle *ph, + const struct GNUNET_PseudonymSignaturePurpose *purpose, + const struct GNUNET_HashCode *seed, + const struct GNUNET_HashCode *signing_key, + struct GNUNET_PseudonymSignature *signature); + + +/** + * Given a pseudonym and a signing key, derive the corresponding public + * key that would be used to verify the resulting signature. + * + * @param pseudonym the public key (g^x) + * @param signing_key input to derive 'h' (see section 2.4 of #2564) + * @param verification_key resulting public key to verify the signature + * created from the 'ph' of 'pseudonym' and the 'signing_key'; + * the value stored here can then be given to GNUNET_PSEUDONYM_verify. + */ +void +GNUNET_PSEUDONYM_derive_verification_key (struct GNUNET_PseudonymIdentifier *pseudonym, + const struct GNUNET_HashCode *signing_key, + struct GNUNET_PseudonymIdentifier *verification_key); + + +/** + * Verify a signature made with a pseudonym. + * + * @param purpose data that was signed + * @param signature signature to verify + * @param verification_key public key to use for checking the signature; + * corresponds to 'g^(x+h)' in section 2.4 of #2564. + * @return GNUNET_OK on success (signature valid, 'pseudonym' set), + * GNUNET_SYSERR if the signature is invalid + */ +int +GNUNET_PSEUDONYM_verify (const struct GNUNET_PseudonymSignaturePurpose *purpose, + const struct GNUNET_PseudonymSignature *signature, + const struct GNUNET_PseudonymIdentifier *verification_key); + + +/** + * Get the identifier (public key) of a pseudonym. + * + * @param ph pseudonym handle with the private key + * @param pseudonym pseudonym identifier (set based on 'ph') + */ +void +GNUNET_PSEUDONYM_get_identifier (struct GNUNET_PseudonymHandle *ph, + struct GNUNET_PseudonymIdentifier *pseudonym); + + + /** * Iterator over all known pseudonyms. * @@ -51,23 +211,26 @@ extern "C" * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort */ typedef int (*GNUNET_PSEUDONYM_Iterator) (void *cls, - const struct GNUNET_HashCode * pseudonym, + const struct GNUNET_PseudonymIdentifier *pseudonym, const char *name, const char *unique_name, - const struct GNUNET_CONTAINER_MetaData - * md, int rating); + const struct GNUNET_CONTAINER_MetaData *md, + int32_t rating); + /** - * Change the ranking of a pseudonym. + * Change the rank of a pseudonym. * * @param cfg overall configuration - * @param nsid id of the pseudonym + * @param pseudonym identity of the pseudonym * @param delta by how much should the rating be changed? - * @return new rating of the namespace + * @return new rating of the pseudonym */ int GNUNET_PSEUDONYM_rank (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_HashCode * nsid, int delta); + const struct GNUNET_PseudonymIdentifier *pseudonym, + int32_t delta); + /** * Add a pseudonym to the set of known pseudonyms. @@ -77,10 +240,11 @@ GNUNET_PSEUDONYM_rank (const struct GNUNET_CONFIGURATION_Handle *cfg, * @param cfg overall configuration * @param id the pseudonym identifier * @param meta metadata for the pseudonym + * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ -void +int GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_HashCode * id, + const struct GNUNET_PseudonymIdentifier *pseudonym, const struct GNUNET_CONTAINER_MetaData *meta); @@ -89,37 +253,51 @@ GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg, * * @param cfg overall configuration * @param iterator function to call for each pseudonym - * @param closure closure for iterator + * @param iterator_cls closure for iterator * @return number of pseudonyms found */ int GNUNET_PSEUDONYM_list_all (const struct GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_PSEUDONYM_Iterator iterator, void *closure); + GNUNET_PSEUDONYM_Iterator iterator, + void *iterator_cls); + + +/** + * Handle for a discovery callback registration. + */ +struct GNUNET_PSEUDONYM_DiscoveryHandle; + /** * Register callback to be invoked whenever we discover * a new pseudonym. + * + * @param cfg our configuration + * @param iterator function to invoke on discovery + * @param iterator_cls closure for iterator + * @return registration handle */ -int -GNUNET_PSEUDONYM_discovery_callback_register (const struct - GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_PSEUDONYM_Iterator - iterator, void *closure); +struct GNUNET_PSEUDONYM_DiscoveryHandle * +GNUNET_PSEUDONYM_discovery_callback_register (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_PSEUDONYM_Iterator iterator, + void *iterator_cls); + /** - * Unregister namespace discovery callback. + * Unregister pseudonym discovery callback. + * + * @param dh registration to unregister */ -int -GNUNET_PSEUDONYM_discovery_callback_unregister (GNUNET_PSEUDONYM_Iterator - iterator, void *closure); +void +GNUNET_PSEUDONYM_discovery_callback_unregister (struct GNUNET_PSEUDONYM_DiscoveryHandle *dh); + /** - * Return unique variant of the namespace name. - * Use after GNUNET_PSEUDONYM_id_to_name() to make sure - * that name is unique. + * Return unique variant of the pseudonym name. Use after + * GNUNET_PSEUDONYM_id_to_name() to make sure that name is unique. * * @param cfg configuration - * @param nsid cryptographic ID of the namespace + * @param pseudonym cryptographic ID of the pseudonym * @param name name to uniquify * @param suffix if not NULL, filled with the suffix value * @return NULL on failure (should never happen), name on success. @@ -127,18 +305,20 @@ GNUNET_PSEUDONYM_discovery_callback_unregister (GNUNET_PSEUDONYM_Iterator */ char * GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_HashCode * nsid, const char *name, unsigned int *suffix); + const struct GNUNET_PseudonymIdentifier *pseudonym, + const char *name, + unsigned int *suffix); + /** - * Get namespace name, metadata and rank - * This is a wrapper around internal read_info() call, and ensures that - * returned data is not invalid (not NULL). - * Writing back information returned by this function will give - * a name "no-name" to pseudonyms that have no name. This side-effect is - * unavoidable, but hardly harmful. + * Get pseudonym name, metadata and rank. This is a wrapper around + * internal read_info() call, and ensures that returned data is not + * invalid (not NULL). Writing back information returned by this + * function will give a name "no-name" to pseudonyms that have no + * name. This side-effect is unavoidable, but hardly harmful. * * @param cfg configuration - * @param nsid cryptographic ID of the namespace + * @param pseudonym cryptographic ID of the pseudonym * @param ret_meta a location to store metadata pointer. NULL, if metadata * is not needed. Destroy with GNUNET_CONTAINER_meta_data_destroy(). * @param ret_rank a location to store rank. NULL, if rank not needed. @@ -152,27 +332,32 @@ GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, */ int GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_HashCode * nsid, struct GNUNET_CONTAINER_MetaData **ret_meta, - int32_t *ret_rank, char **ret_name, int *name_is_a_dup); + const struct GNUNET_PseudonymIdentifier *pseudonym, + struct GNUNET_CONTAINER_MetaData **ret_meta, + int32_t *ret_rank, + char **ret_name, + int *name_is_a_dup); /** - * Get the namespace ID belonging to the given namespace name. + * Get the pseudonym ID belonging to the given pseudonym name. * * @param cfg configuration to use - * @param ns_uname unique (!) human-readable name for the namespace - * @param nsid set to namespace ID based on 'ns_uname' + * @param ps_uname unique (!) human-readable name for the pseudonym + * @param pseudonym set to pseudonym ID based on 'ns_uname' * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *ns_uname, struct GNUNET_HashCode * nsid); + const char *ps_uname, + struct GNUNET_PseudonymIdentifier *pseudonym); + /** * Set the pseudonym metadata, rank and name. * * @param cfg overall configuration - * @param nsid id of the pseudonym + * @param pseudonym id of the pseudonym * @param name name to set. Must be the non-unique version of it. * May be NULL, in which case it erases pseudonym's name! * @param md metadata to set @@ -182,8 +367,10 @@ GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, */ int GNUNET_PSEUDONYM_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_HashCode * nsid, const char *name, - const struct GNUNET_CONTAINER_MetaData *md, int rank); + const struct GNUNET_PseudonymIdentifier *pseudonym, + const char *name, + const struct GNUNET_CONTAINER_MetaData *md, + int32_t rank); #if 0 /* keep Emacsens' auto-indent happy */ diff --git a/src/include/gnunet_signatures.h b/src/include/gnunet_signatures.h index 2a2ba4755..a821a74df 100644 --- a/src/include/gnunet_signatures.h +++ b/src/include/gnunet_signatures.h @@ -66,22 +66,22 @@ extern "C" #define GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT 5 /** - * Signature in a KBlock of the FS module. + * Obsolete, legacy value. */ #define GNUNET_SIGNATURE_PURPOSE_FS_KBLOCK 6 /** - * Signature of content URI placed into a namespace. + * Obsolete, legacy value. */ #define GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK 7 /** - * Signature of advertisment for a namespace. + * Obsolete, legacy value. */ #define GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK 8 /** - * Keyword-based signature of advertisment for a namespace. + * Obsolete, legacy value. */ #define GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG 9 @@ -121,6 +121,10 @@ extern "C" #define GNUNET_SIGNATURE_PURPOSE_SET_ECC_KEY 16 +/** + * UBlock Signature, done using DSS, not ECC + */ +#define GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK 17 #if 0 /* keep Emacsens' auto-indent happy */ { diff --git a/src/util/pseudonym.c b/src/util/pseudonym.c index fa48e19e3..02600cd6d 100644 --- a/src/util/pseudonym.c +++ b/src/util/pseudonym.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - (C) 2003, 2004, 2005, 2006, 2007, 2008 Christian Grothoff (and other contributing authors) + (C) 2003, 2004, 2005, 2006, 2007, 2008, 2013 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -17,19 +17,22 @@ Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - /** * @file util/pseudonym.c * @brief helper functions * @author Christian Grothoff + * + * TODO: + * - all cryptographic operations are currently NOT implemented and + * provided by stubs that merely pretend to work! */ - #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" #include "gnunet_disk_lib.h" #include "gnunet_pseudonym_lib.h" #include "gnunet_bio_lib.h" +#include #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) @@ -38,12 +41,12 @@ /** * Name of the directory which stores meta data for pseudonym */ -#define PS_METADATA_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonyms" DIR_SEPARATOR_STR "metadata" DIR_SEPARATOR_STR +#define PS_METADATA_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonym" DIR_SEPARATOR_STR "metadata" DIR_SEPARATOR_STR /** * Name of the directory which stores names for pseudonyms */ -#define PS_NAMES_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonyms" DIR_SEPARATOR_STR "names" DIR_SEPARATOR_STR +#define PS_NAMES_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonym" DIR_SEPARATOR_STR "names" DIR_SEPARATOR_STR /** @@ -52,16 +55,22 @@ #define GNUNET_CLIENT_SERVICE_NAME "client" +/* ************************* Disk operations (pseudonym data mgmt) **************** */ /** * Registered callbacks for discovery of pseudonyms. */ -struct DiscoveryCallback +struct GNUNET_PSEUDONYM_DiscoveryHandle { /** - * This is a linked list. + * This is a doubly linked list. */ - struct DiscoveryCallback *next; + struct GNUNET_PSEUDONYM_DiscoveryHandle *next; + + /** + * This is a doubly linked list. + */ + struct GNUNET_PSEUDONYM_DiscoveryHandle *prev; /** * Function to call each time a pseudonym is discovered. @@ -71,7 +80,7 @@ struct DiscoveryCallback /** * Closure for callback. */ - void *closure; + void *callback_cls; }; @@ -79,28 +88,33 @@ struct DiscoveryCallback * Head of the linked list of functions to call when * new pseudonyms are added. */ -static struct DiscoveryCallback *head; +static struct GNUNET_PSEUDONYM_DiscoveryHandle *disco_head; + +/** + * Tail of the linked list of functions to call when + * new pseudonyms are added. + */ +static struct GNUNET_PSEUDONYM_DiscoveryHandle *disco_tail; + /** * Internal notification about new tracked URI. - * @param id a point to the hash code of pseudonym + * + * @param pseudonym public key of the pseudonym * @param md meta data to be written * @param rating rating of pseudonym */ static void -internal_notify (const struct GNUNET_HashCode * id, +internal_notify (const struct GNUNET_PseudonymIdentifier *pseudonym, const struct GNUNET_CONTAINER_MetaData *md, int rating) { - struct DiscoveryCallback *pos; + struct GNUNET_PSEUDONYM_DiscoveryHandle *pos; - pos = head; - while (pos != NULL) - { - pos->callback (pos->closure, id, NULL, NULL, md, rating); - pos = pos->next; - } + for (pos = disco_head; NULL != pos; pos = pos->next) + pos->callback (pos->callback_cls, pseudonym, NULL, NULL, md, rating); } + /** * Register callback to be invoked whenever we discover * a new pseudonym. @@ -109,164 +123,197 @@ internal_notify (const struct GNUNET_HashCode * id, * * @param cfg configuration to use * @param iterator iterator over pseudonym - * @param closure point to a closure + * @param iterator_cls point to a closure + * @return registration handle */ -int +struct GNUNET_PSEUDONYM_DiscoveryHandle * GNUNET_PSEUDONYM_discovery_callback_register (const struct - GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_PSEUDONYM_Iterator - iterator, void *closure) + GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_PSEUDONYM_Iterator iterator, + void *iterator_cls) { - struct DiscoveryCallback *list; - - list = GNUNET_malloc (sizeof (struct DiscoveryCallback)); - list->callback = iterator; - list->closure = closure; - list->next = head; - head = list; - GNUNET_PSEUDONYM_list_all (cfg, iterator, closure); - return GNUNET_OK; + struct GNUNET_PSEUDONYM_DiscoveryHandle *dh; + + dh = GNUNET_malloc (sizeof (struct GNUNET_PSEUDONYM_DiscoveryHandle)); + dh->callback = iterator; + dh->callback_cls = iterator_cls; + GNUNET_CONTAINER_DLL_insert (disco_head, disco_tail, dh); + GNUNET_PSEUDONYM_list_all (cfg, iterator, iterator_cls); + return dh; } + /** * Unregister pseudonym discovery callback. - * @param iterator iterator over pseudonym - * @param closure point to a closure + * + * @param dh registration to unregister */ -int -GNUNET_PSEUDONYM_discovery_callback_unregister (GNUNET_PSEUDONYM_Iterator - iterator, void *closure) +void +GNUNET_PSEUDONYM_discovery_callback_unregister (struct GNUNET_PSEUDONYM_DiscoveryHandle *dh) { - struct DiscoveryCallback *prev; - struct DiscoveryCallback *pos; - - prev = NULL; - pos = head; - while ((pos != NULL) && - ((pos->callback != iterator) || (pos->closure != closure))) - { - prev = pos; - pos = pos->next; - } - if (pos == NULL) - return GNUNET_SYSERR; - if (prev == NULL) - head = pos->next; - else - prev->next = pos->next; - GNUNET_free (pos); - return GNUNET_OK; + GNUNET_CONTAINER_DLL_remove (disco_head, disco_tail, dh); + GNUNET_free (dh); } /** * Get the filename (or directory name) for the given * pseudonym identifier and directory prefix. + * * @param cfg configuration to use * @param prefix path components to append to the private directory name - * @param psid hash code of pseudonym, can be NULL - * @return filename of the pseudonym (if psid != NULL) or directory with the data (if psid == NULL) + * @param pseudonym the pseudonym, can be NULL + * @return filename of the pseudonym (if pseudonym != NULL) or directory with the data (if pseudonym == NULL) */ static char * get_data_filename (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *prefix, const struct GNUNET_HashCode * psid) + const char *prefix, + const struct GNUNET_PseudonymIdentifier *pseudonym) { struct GNUNET_CRYPTO_HashAsciiEncoded enc; + struct GNUNET_HashCode psid; - if (psid != NULL) - GNUNET_CRYPTO_hash_to_enc (psid, &enc); - return GNUNET_DISK_get_home_filename (cfg, GNUNET_CLIENT_SERVICE_NAME, prefix, - (psid == - NULL) ? NULL : (const char *) &enc, + if (NULL != pseudonym) + { + GNUNET_CRYPTO_hash (pseudonym, + sizeof (struct GNUNET_PseudonymIdentifier), + &psid); + GNUNET_CRYPTO_hash_to_enc (&psid, &enc); + } + return GNUNET_DISK_get_home_filename (cfg, + GNUNET_CLIENT_SERVICE_NAME, prefix, + (NULL == pseudonym) + ? NULL + : (const char *) &enc, NULL); } /** - * Write the pseudonym infomation into a file + * Get the filename (or directory name) for the given + * hash code and directory prefix. + * * @param cfg configuration to use - * @param nsid hash code of a pseudonym - * @param meta meta data to be written into a file - * @param ranking ranking of a pseudonym - * @param ns_name non-unique name of a pseudonym + * @param prefix path components to append to the private directory name + * @param hc some hash code + * @return filename of the pseudonym (if hc != NULL) or directory with the data (if hc == NULL) */ -static void -write_pseudonym_info (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_HashCode * nsid, - const struct GNUNET_CONTAINER_MetaData *meta, - int32_t ranking, const char *ns_name) +static char * +get_data_filename_hash (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *prefix, + const struct GNUNET_HashCode *hc) +{ + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + + if (NULL != hc) + GNUNET_CRYPTO_hash_to_enc (hc, &enc); + return GNUNET_DISK_get_home_filename (cfg, + GNUNET_CLIENT_SERVICE_NAME, prefix, + (NULL == hc) + ? NULL + : (const char *) &enc, + NULL); +} + + +/** + * Set the pseudonym metadata, rank and name. + * Writes the pseudonym infomation into a file + * + * @param cfg overall configuration + * @param nsid id of the pseudonym + * @param name name to set. Must be the non-unique version of it. + * May be NULL, in which case it erases pseudonym's name! + * @param md metadata to set + * May be NULL, in which case it erases pseudonym's metadata! + * @param rank rank to assign + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_PSEUDONYM_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PseudonymIdentifier *pseudonym, + const char *name, + const struct GNUNET_CONTAINER_MetaData *md, + int32_t rank) { char *fn; struct GNUNET_BIO_WriteHandle *fileW; - fn = get_data_filename (cfg, PS_METADATA_DIR, nsid); - GNUNET_assert (fn != NULL); - fileW = GNUNET_BIO_write_open (fn); - if (NULL != fileW) + fn = get_data_filename (cfg, PS_METADATA_DIR, pseudonym); + if (NULL == (fileW = GNUNET_BIO_write_open (fn))) { - if ((GNUNET_OK != GNUNET_BIO_write_int32 (fileW, ranking)) || - (GNUNET_OK != GNUNET_BIO_write_string (fileW, ns_name)) || - (GNUNET_OK != GNUNET_BIO_write_meta_data (fileW, meta))) - { - (void) GNUNET_BIO_write_close (fileW); - GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); - GNUNET_free (fn); - return; - } - if (GNUNET_OK != GNUNET_BIO_write_close (fileW)) - { - GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); - GNUNET_free (fn); - return; - } + GNUNET_free (fn); + return GNUNET_SYSERR; } + if ((GNUNET_OK != GNUNET_BIO_write (fileW, pseudonym, + sizeof (struct GNUNET_PseudonymIdentifier))) || + (GNUNET_OK != GNUNET_BIO_write_int32 (fileW, rank)) || + (GNUNET_OK != GNUNET_BIO_write_string (fileW, name)) || + (GNUNET_OK != GNUNET_BIO_write_meta_data (fileW, md))) + { + (void) GNUNET_BIO_write_close (fileW); + GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); + GNUNET_free (fn); + return GNUNET_SYSERR; + } + if (GNUNET_OK != GNUNET_BIO_write_close (fileW)) + { + GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); + GNUNET_free (fn); + return GNUNET_SYSERR; + } GNUNET_free (fn); /* create entry for pseudonym name in names */ - if (ns_name != NULL) - GNUNET_free_non_null (GNUNET_PSEUDONYM_name_uniquify (cfg, nsid, ns_name, - NULL)); + if (NULL != name) + GNUNET_free_non_null (GNUNET_PSEUDONYM_name_uniquify (cfg, pseudonym, + name, NULL)); + return GNUNET_OK; } /** - * read the pseudonym infomation from a file + * Read pseudonym infomation from a file + * * @param cfg configuration to use * @param nsid hash code of a pseudonym * @param meta meta data to be read from a file - * @param ranking ranking of a pseudonym + * @param rank rank of a pseudonym * @param ns_name name of a pseudonym + * @return GNUNET_OK on success, GNUNET_SYSERR on error */ static int read_info (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_HashCode * nsid, - struct GNUNET_CONTAINER_MetaData **meta, int32_t * ranking, + const struct GNUNET_PseudonymIdentifier *pseudonym, + struct GNUNET_CONTAINER_MetaData **meta, + int32_t *rank, char **ns_name) { + struct GNUNET_PseudonymIdentifier pd; char *fn; char *emsg; struct GNUNET_BIO_ReadHandle *fileR; - fn = get_data_filename (cfg, PS_METADATA_DIR, nsid); - GNUNET_assert (fn != NULL); + fn = get_data_filename (cfg, PS_METADATA_DIR, pseudonym); if (GNUNET_YES != GNUNET_DISK_file_test (fn)) { GNUNET_free (fn); return GNUNET_SYSERR; } - fileR = GNUNET_BIO_read_open (fn); - if (fileR == NULL) + if (NULL == (fileR = GNUNET_BIO_read_open (fn))) { GNUNET_free (fn); return GNUNET_SYSERR; } emsg = NULL; *ns_name = NULL; - if ((GNUNET_OK != GNUNET_BIO_read_int32 (fileR, ranking)) || - (GNUNET_OK != - GNUNET_BIO_read_string (fileR, "Read string error!", ns_name, 200)) || - (GNUNET_OK != - GNUNET_BIO_read_meta_data (fileR, "Read meta data error!", meta))) + if ( (GNUNET_OK != GNUNET_BIO_read (fileR, "pseudonym", &pd, sizeof (pd))) || + (0 != memcmp (&pd, pseudonym, sizeof (pd))) || + (GNUNET_OK != GNUNET_BIO_read_int32 (fileR, rank)) || + (GNUNET_OK != + GNUNET_BIO_read_string (fileR, "Read string error!", ns_name, 200)) || + (GNUNET_OK != + GNUNET_BIO_read_meta_data (fileR, "Read meta data error!", meta)) ) { (void) GNUNET_BIO_read_close (fileR, &emsg); GNUNET_free_non_null (emsg); @@ -296,12 +343,11 @@ read_info (const struct GNUNET_CONFIGURATION_Handle *cfg, /** - * Return unique variant of the namespace name. - * Use it after GNUNET_PSEUDONYM_get_info() to make sure - * that name is unique. + * Return unique variant of the namespace name. Use it after + * GNUNET_PSEUDONYM_get_info() to make sure that name is unique. * * @param cfg configuration - * @param nsid cryptographic ID of the namespace + * @param pseudonym public key of the pseudonym * @param name name to uniquify * @param suffix if not NULL, filled with the suffix value * @return NULL on failure (should never happen), name on success. @@ -309,9 +355,12 @@ read_info (const struct GNUNET_CONFIGURATION_Handle *cfg, */ char * GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_HashCode * nsid, const char *name, unsigned int *suffix) + const struct GNUNET_PseudonymIdentifier *pseudonym, + const char *name, + unsigned int *suffix) { struct GNUNET_HashCode nh; + struct GNUNET_PseudonymIdentifier pi; uint64_t len; char *fn; struct GNUNET_DISK_FileHandle *fh; @@ -321,9 +370,7 @@ GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, struct stat sbuf; GNUNET_CRYPTO_hash (name, strlen (name), &nh); - fn = get_data_filename (cfg, PS_NAMES_DIR, &nh); - GNUNET_assert (fn != NULL); - + fn = get_data_filename_hash (cfg, PS_NAMES_DIR, &nh); len = 0; if (0 == STAT (fn, &sbuf)) GNUNET_break (GNUNET_OK == GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES)); @@ -334,11 +381,11 @@ GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_DISK_PERM_USER_WRITE); i = 0; idx = -1; - while ((len >= sizeof (struct GNUNET_HashCode)) && - (sizeof (struct GNUNET_HashCode) == - GNUNET_DISK_file_read (fh, &nh, sizeof (struct GNUNET_HashCode)))) + while ((len >= sizeof (struct GNUNET_PseudonymIdentifier)) && + (sizeof (struct GNUNET_PseudonymIdentifier) == + GNUNET_DISK_file_read (fh, &pi, sizeof (struct GNUNET_PseudonymIdentifier)))) { - if (0 == memcmp (&nh, nsid, sizeof (struct GNUNET_HashCode))) + if (0 == memcmp (&pi, pseudonym, sizeof (struct GNUNET_PseudonymIdentifier))) { idx = i; break; @@ -346,11 +393,11 @@ GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, i++; len -= sizeof (struct GNUNET_HashCode); } - if (idx == -1) + if (-1 == idx) { idx = i; - if (sizeof (struct GNUNET_HashCode) != - GNUNET_DISK_file_write (fh, nsid, sizeof (struct GNUNET_HashCode))) + if (sizeof (struct GNUNET_PseudonymIdentifier) != + GNUNET_DISK_file_write (fh, pseudonym, sizeof (struct GNUNET_PseudonymIdentifier))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "write", fn); } GNUNET_DISK_file_close (fh); @@ -362,13 +409,14 @@ GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, return ret; } + /** * Get namespace name, metadata and rank * This is a wrapper around internal read_info() call, and ensures that * returned data is not invalid (not NULL). * * @param cfg configuration - * @param nsid cryptographic ID of the namespace + * @param pseudonym public key of the pseudonym * @param ret_meta a location to store metadata pointer. NULL, if metadata * is not needed. Destroy with GNUNET_CONTAINER_meta_data_destroy(). * @param ret_rank a location to store rank. NULL, if rank not needed. @@ -382,8 +430,11 @@ GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, */ int GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_HashCode * nsid, struct GNUNET_CONTAINER_MetaData **ret_meta, - int32_t *ret_rank, char **ret_name, int *name_is_a_dup) + const struct GNUNET_PseudonymIdentifier *pseudonym, + struct GNUNET_CONTAINER_MetaData **ret_meta, + int32_t *ret_rank, + char **ret_name, + int *name_is_a_dup) { struct GNUNET_CONTAINER_MetaData *meta; char *name; @@ -391,7 +442,7 @@ GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg, meta = NULL; name = NULL; - if (GNUNET_OK == read_info (cfg, nsid, &meta, &rank, &name)) + if (GNUNET_OK == read_info (cfg, pseudonym, &meta, &rank, &name)) { if ((meta != NULL) && (name == NULL)) name = @@ -446,17 +497,19 @@ GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg, return GNUNET_SYSERR; } + /** * Get the namespace ID belonging to the given namespace name. * * @param cfg configuration to use * @param ns_uname unique (!) human-readable name for the namespace - * @param nsid set to namespace ID based on 'ns_uname' + * @param pseudonym set to public key of pseudonym based on 'ns_uname' * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *ns_uname, struct GNUNET_HashCode * nsid) + const char *ns_uname, + struct GNUNET_PseudonymIdentifier *pseudonym) { size_t slen; uint64_t len; @@ -470,19 +523,18 @@ GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, slen = strlen (ns_uname); while ((slen > 0) && (1 != SSCANF (&ns_uname[slen - 1], "-%u", &idx))) slen--; - if (slen == 0) + if (0 == slen) return GNUNET_SYSERR; name = GNUNET_strdup (ns_uname); name[slen - 1] = '\0'; GNUNET_CRYPTO_hash (name, strlen (name), &nh); GNUNET_free (name); - fn = get_data_filename (cfg, PS_NAMES_DIR, &nh); - GNUNET_assert (fn != NULL); + fn = get_data_filename_hash (cfg, PS_NAMES_DIR, &nh); if ((GNUNET_OK != GNUNET_DISK_file_test (fn) || (GNUNET_OK != GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES))) || - ((idx + 1) * sizeof (struct GNUNET_HashCode) > len)) + ((idx + 1) * sizeof (struct GNUNET_PseudonymIdentifier) > len)) { GNUNET_free (fn); return GNUNET_SYSERR; @@ -494,14 +546,14 @@ GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_DISK_PERM_USER_WRITE); GNUNET_free (fn); if (GNUNET_SYSERR == - GNUNET_DISK_file_seek (fh, idx * sizeof (struct GNUNET_HashCode), + GNUNET_DISK_file_seek (fh, idx * sizeof (struct GNUNET_PseudonymIdentifier), GNUNET_DISK_SEEK_SET)) { GNUNET_DISK_file_close (fh); return GNUNET_SYSERR; } - if (sizeof (struct GNUNET_HashCode) != - GNUNET_DISK_file_read (fh, nsid, sizeof (struct GNUNET_HashCode))) + if (sizeof (struct GNUNET_PseudonymIdentifier) != + GNUNET_DISK_file_read (fh, pseudonym, sizeof (struct GNUNET_PseudonymIdentifier))) { GNUNET_DISK_file_close (fh); return GNUNET_SYSERR; @@ -526,7 +578,7 @@ struct ListPseudonymClosure /** * Closure for iterator. */ - void *closure; + void *iterator_cls; /** * Configuration to use. @@ -537,47 +589,59 @@ struct ListPseudonymClosure /** - * the help function to list all available pseudonyms + * Helper function to list all available pseudonyms + * * @param cls point to a struct ListPseudonymClosure * @param fullname name of pseudonym */ static int list_pseudonym_helper (void *cls, const char *fullname) { - struct ListPseudonymClosure *c = cls; - int ret; - struct GNUNET_HashCode id; - int32_t rating; + struct ListPseudonymClosure *lpc = cls; + struct GNUNET_PseudonymIdentifier pd; + char *emsg; + struct GNUNET_BIO_ReadHandle *fileR; + int32_t rank; + char *ns_name; struct GNUNET_CONTAINER_MetaData *meta; - const char *fn; - char *str; + int ret; char *name_unique; - if (strlen (fullname) < sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) - return GNUNET_OK; - fn = &fullname[strlen (fullname) + 1 - - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; - if (fn[-1] != DIR_SEPARATOR) - return GNUNET_OK; - ret = GNUNET_OK; - if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (fn, &id)) - return GNUNET_OK; /* invalid name */ - str = NULL; - if (GNUNET_OK != GNUNET_PSEUDONYM_get_info (c->cfg, &id, &meta, &rating, - &str, NULL)) + if (NULL == (fileR = GNUNET_BIO_read_open (fullname))) + return GNUNET_SYSERR; + emsg = NULL; + ns_name = NULL; + if ( (GNUNET_OK != GNUNET_BIO_read (fileR, "pseudonym", &pd, sizeof (pd))) || + (GNUNET_OK != GNUNET_BIO_read_int32 (fileR, &rank)) || + (GNUNET_OK != + GNUNET_BIO_read_string (fileR, "Read string error!", &ns_name, 200)) || + (GNUNET_OK != + GNUNET_BIO_read_meta_data (fileR, "Read meta data error!", &meta)) ) { - /* ignore entry. FIXME: Why? Lack of data about a pseudonym is not a reason - * to ignore it... So yeah, it will have placeholders instead of name, - * empty metadata container and a default rank == -1, so what? We know - * its nsid - that's all we really need. Right? */ - GNUNET_free (str); + (void) GNUNET_BIO_read_close (fileR, &emsg); + GNUNET_free_non_null (emsg); + GNUNET_free_non_null (ns_name); + GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fullname)); + return GNUNET_SYSERR; + } + if (NULL == ns_name) + ns_name = GNUNET_strdup (_("no-name")); + if (GNUNET_OK != GNUNET_BIO_read_close (fileR, &emsg)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Failed to parse metadata about pseudonym from file `%s': %s\n"), fullname, + emsg); + GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fullname)); GNUNET_CONTAINER_meta_data_destroy (meta); - return GNUNET_OK; + GNUNET_free (ns_name); + GNUNET_free_non_null (emsg); + return GNUNET_SYSERR; } - name_unique = GNUNET_PSEUDONYM_name_uniquify (c->cfg, &id, str, NULL); - if (c->iterator != NULL) - ret = c->iterator (c->closure, &id, str, name_unique, meta, rating); - GNUNET_free_non_null (str); + ret = GNUNET_OK; + name_unique = GNUNET_PSEUDONYM_name_uniquify (lpc->cfg, &pd, ns_name, NULL); + if (NULL != lpc->iterator) + ret = lpc->iterator (lpc->iterator_cls, &pd, ns_name, name_unique, meta, rank); + GNUNET_free (ns_name); GNUNET_free_non_null (name_unique); GNUNET_CONTAINER_meta_data_destroy (meta); return ret; @@ -589,19 +653,20 @@ list_pseudonym_helper (void *cls, const char *fullname) * * @param cfg overall configuration * @param iterator function to call for each pseudonym - * @param closure closure for iterator + * @param iterator_cls closure for iterator * @return number of pseudonyms found */ int GNUNET_PSEUDONYM_list_all (const struct GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_PSEUDONYM_Iterator iterator, void *closure) + GNUNET_PSEUDONYM_Iterator iterator, + void *iterator_cls) { struct ListPseudonymClosure cls; char *fn; int ret; cls.iterator = iterator; - cls.closure = closure; + cls.iterator_cls = iterator_cls; cls.cfg = cfg; fn = get_data_filename (cfg, PS_METADATA_DIR, NULL); GNUNET_assert (fn != NULL); @@ -613,60 +678,35 @@ GNUNET_PSEUDONYM_list_all (const struct GNUNET_CONFIGURATION_Handle *cfg, /** - * Change the ranking of a pseudonym. + * Change the rank of a pseudonym. * * @param cfg overall configuration - * @param nsid id of the pseudonym - * @param delta by how much should the rating be - * changed? + * @param pseudonym the pseudonym + * @param delta by how much should the rating be changed? * @return new rating of the pseudonym */ int GNUNET_PSEUDONYM_rank (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_HashCode * nsid, int delta) + const struct GNUNET_PseudonymIdentifier *pseudonym, + int32_t delta) { struct GNUNET_CONTAINER_MetaData *meta; int ret; - int32_t ranking; + int32_t rank; char *name; name = NULL; - ret = read_info (cfg, nsid, &meta, &ranking, &name); + ret = read_info (cfg, pseudonym, &meta, &rank, &name); if (ret == GNUNET_SYSERR) { - ranking = 0; + rank = 0; meta = GNUNET_CONTAINER_meta_data_create (); } - ranking += delta; - write_pseudonym_info (cfg, nsid, meta, ranking, name); + rank += delta; + GNUNET_PSEUDONYM_set_info (cfg, pseudonym, name, meta, rank); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_free_non_null (name); - return ranking; -} - - -/** - * Set the pseudonym metadata, rank and name. - * - * @param cfg overall configuration - * @param nsid id of the pseudonym - * @param name name to set. Must be the non-unique version of it. - * May be NULL, in which case it erases pseudonym's name! - * @param md metadata to set - * May be NULL, in which case it erases pseudonym's metadata! - * @param rank rank to assign - * @return GNUNET_OK on success, GNUNET_SYSERR on failure - */ -int -GNUNET_PSEUDONYM_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_HashCode * nsid, const char *name, - const struct GNUNET_CONTAINER_MetaData *md, int rank) -{ - GNUNET_assert (cfg != NULL); - GNUNET_assert (nsid != NULL); - - write_pseudonym_info (cfg, nsid, md, rank, name); - return GNUNET_OK; + return rank; } @@ -676,38 +716,233 @@ GNUNET_PSEUDONYM_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg, * FS should automatically call this function. * * @param cfg overall configuration - * @param id the pseudonym identifier + * @param pseudonym the pseudonym to add * @param meta metadata for the pseudonym + * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ -void +int GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_HashCode * id, + const struct GNUNET_PseudonymIdentifier *pseudonym, const struct GNUNET_CONTAINER_MetaData *meta) { char *name; - int32_t ranking; + int32_t rank; struct GNUNET_CONTAINER_MetaData *old; char *fn; struct stat sbuf; + int ret; - ranking = 0; - fn = get_data_filename (cfg, PS_METADATA_DIR, id); + rank = 0; + fn = get_data_filename (cfg, PS_METADATA_DIR, pseudonym); GNUNET_assert (fn != NULL); if ((0 == STAT (fn, &sbuf)) && - (GNUNET_OK == read_info (cfg, id, &old, &ranking, &name))) + (GNUNET_OK == read_info (cfg, pseudonym, &old, &rank, &name))) { GNUNET_CONTAINER_meta_data_merge (old, meta); - write_pseudonym_info (cfg, id, old, ranking, name); + ret = GNUNET_PSEUDONYM_set_info (cfg, pseudonym, name, old, rank); GNUNET_CONTAINER_meta_data_destroy (old); GNUNET_free_non_null (name); } else { - write_pseudonym_info (cfg, id, meta, ranking, NULL); + ret = GNUNET_PSEUDONYM_set_info (cfg, pseudonym, NULL, meta, rank); } GNUNET_free (fn); - internal_notify (id, meta, ranking); + internal_notify (pseudonym, meta, rank); + return ret; +} + + +/* ***************************** cryptographic operations ************************* */ + +/** + * Handle for a pseudonym (private key). + */ +struct GNUNET_PseudonymHandle +{ + /** + * FIXME. + */ + char data[42]; +}; + + +/** + * Create a pseudonym. + * + * @param filename name of the file to use for storage, NULL for in-memory only + * @return handle to the private key of the pseudonym + */ +struct GNUNET_PseudonymHandle * +GNUNET_PSEUDONYM_create (const char *filename) +{ + struct GNUNET_PseudonymHandle *ph; + ssize_t ret; + + ph = GNUNET_malloc (sizeof (struct GNUNET_PseudonymHandle)); + if (NULL != filename) + { + ret = GNUNET_DISK_fn_read (filename, ph, + sizeof (struct GNUNET_PseudonymHandle)); + if (sizeof (struct GNUNET_PseudonymHandle) == ret) + return ph; + } + GNUNET_break (0); // not implemented... + gcry_randomize (ph, sizeof (struct GNUNET_PseudonymHandle), + GCRY_STRONG_RANDOM); + if (NULL != filename) + { + ret = GNUNET_DISK_fn_write (filename, ph, sizeof (struct GNUNET_PseudonymHandle), + GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); + if (sizeof (struct GNUNET_PseudonymHandle) != ret) + { + GNUNET_free (ph); + return NULL; + } + } + return ph; +} + + +/** + * Create a pseudonym, from a file that must already exist. + * + * @param filename name of the file to use for storage, NULL for in-memory only + * @return handle to the private key of the pseudonym + */ +struct GNUNET_PseudonymHandle * +GNUNET_PSEUDONYM_create_from_existing_file (const char *filename) +{ + struct GNUNET_PseudonymHandle *ph; + ssize_t ret; + + ph = GNUNET_malloc (sizeof (struct GNUNET_PseudonymHandle)); + ret = GNUNET_DISK_fn_read (filename, ph, + sizeof (struct GNUNET_PseudonymHandle)); + if (sizeof (struct GNUNET_PseudonymHandle) == ret) + return ph; + GNUNET_free (ph); + return NULL; +} + + +/** + * Get the handle for the 'anonymous' pseudonym shared by all users. + * That pseudonym uses a fixed 'secret' for the private key; this + * construction is useful to make anonymous and pseudonymous APIs + * (and packets) indistinguishable on the network. See #2564. + * + * @return handle to the (non-secret) private key of the 'anonymous' pseudonym + */ +struct GNUNET_PseudonymHandle * +GNUNET_PSEUDONYM_get_anonymous_pseudonym_handle () +{ + struct GNUNET_PseudonymHandle *ph; + + ph = GNUNET_malloc (sizeof (struct GNUNET_PseudonymHandle)); + GNUNET_break (0); + return ph; +} + + +/** + * Destroy a pseudonym handle. Does NOT remove the private key from + * the disk. + * + * @param ph pseudonym handle to destroy + */ +void +GNUNET_PSEUDONYM_destroy (struct GNUNET_PseudonymHandle *ph) +{ + GNUNET_free (ph); +} + + +/** + * Cryptographically sign some data with the pseudonym. + * + * @param ph private key used for signing (corresponds to 'x' in #2564) + * @param purpose data to sign + * @param seed hash of the plaintext of the data that we are signing, + * used for deterministic PRNG for anonymous signing; + * corresponds to 'k' in section 2.7 of #2564 + * @param signing_key modifier to apply to the private key for signing; + * corresponds to 'h' in section 2.3 of #2564. + * @param signature where to store the signature + */ +void +GNUNET_PSEUDONYM_sign (struct GNUNET_PseudonymHandle *ph, + const struct GNUNET_PseudonymSignaturePurpose *purpose, + const struct GNUNET_HashCode *seed, + const struct GNUNET_HashCode *signing_key, + struct GNUNET_PseudonymSignature *signature) +{ + memset (signature, 0, sizeof (struct GNUNET_PseudonymSignature)); + GNUNET_break (0); +} + + +/** + * Given a pseudonym and a signing key, derive the corresponding public + * key that would be used to verify the resulting signature. + * + * @param pseudonym the public key (g^x) + * @param signing_key input to derive 'h' (see section 2.4 of #2564) + * @param verification_key resulting public key to verify the signature + * created from the 'ph' of 'pseudonym' and the 'signing_key'; + * the value stored here can then be given to GNUNET_PSEUDONYM_verify. + */ +void +GNUNET_PSEUDONYM_derive_verification_key (struct GNUNET_PseudonymIdentifier *pseudonym, + const struct GNUNET_HashCode *signing_key, + struct GNUNET_PseudonymIdentifier *verification_key) +{ + struct GNUNET_HashCode hc; + struct GNUNET_HashCode x; + + GNUNET_break (0); + GNUNET_CRYPTO_hash (pseudonym, sizeof (*pseudonym), &hc); + GNUNET_CRYPTO_hash_xor (&hc, signing_key, &x); + memset (verification_key, 0, sizeof (struct GNUNET_PseudonymIdentifier)); + memcpy (verification_key, &x, GNUNET_MIN (sizeof (x), sizeof (*verification_key))); +} + + +/** + * Verify a signature made with a pseudonym. + * + * @param purpose data that was signed + * @param signature signature to verify + * @param verification_key public key to use for checking the signature; + * corresponds to 'g^(x+h)' in section 2.4 of #2564. + * @return GNUNET_OK on success (signature valid, 'pseudonym' set), + * GNUNET_SYSERR if the signature is invalid + */ +int +GNUNET_PSEUDONYM_verify (const struct GNUNET_PseudonymSignaturePurpose *purpose, + const struct GNUNET_PseudonymSignature *signature, + const struct GNUNET_PseudonymIdentifier *verification_key) +{ + GNUNET_break (0); + return GNUNET_OK; +} + + +/** + * Get the identifier (public key) of a pseudonym. + * + * @param ph pseudonym handle with the private key + * @param pseudonym pseudonym identifier (set based on 'ph') + */ +void +GNUNET_PSEUDONYM_get_identifier (struct GNUNET_PseudonymHandle *ph, + struct GNUNET_PseudonymIdentifier *pseudonym) +{ + GNUNET_break (0); + memcpy (pseudonym, ph, + GNUNET_MIN (sizeof (struct GNUNET_PseudonymIdentifier), + sizeof (*ph))); } diff --git a/src/util/strings.c b/src/util/strings.c index 9856a15c4..de32b1c03 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -803,11 +803,6 @@ GNUNET_STRINGS_data_to_string (const void *data, size_t size, char *out, size_t out[wpos++] = encTable__[(bits >> (vbit - 5)) & 31]; vbit -= 5; } - if (wpos != out_size) - { - GNUNET_break (0); - return NULL; - } GNUNET_assert (vbit == 0); return &out[wpos]; } diff --git a/src/util/test_pseudonym.c b/src/util/test_pseudonym.c index 56159be1c..2586aadd0 100644 --- a/src/util/test_pseudonym.c +++ b/src/util/test_pseudonym.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) + (C) 2005--2013 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -23,7 +23,6 @@ * @brief testcase for pseudonym.c * @author Christian Grothoff */ - #include "platform.h" #include "gnunet_common.h" #include "gnunet_container_lib.h" @@ -35,16 +34,17 @@ static struct GNUNET_CONTAINER_MetaData *meta; -static struct GNUNET_HashCode id1; +static struct GNUNET_PseudonymIdentifier id1; + static int -iter (void *cls, const struct GNUNET_HashCode * pseudonym, +iter (void *cls, const struct GNUNET_PseudonymIdentifier * pseudonym, const char *name, const char *unique_name, - const struct GNUNET_CONTAINER_MetaData *md, int rating) + const struct GNUNET_CONTAINER_MetaData *md, int32_t rating) { int *ok = cls; - if ((0 == memcmp (pseudonym, &id1, sizeof (struct GNUNET_HashCode))) && + if ((0 == memcmp (pseudonym, &id1, sizeof (struct GNUNET_PseudonymIdentifier))) && (!GNUNET_CONTAINER_meta_data_test_equal (md, meta))) { *ok = GNUNET_NO; @@ -53,10 +53,11 @@ iter (void *cls, const struct GNUNET_HashCode * pseudonym, return GNUNET_OK; } + static int -noti_callback (void *cls, const struct GNUNET_HashCode * pseudonym, +noti_callback (void *cls, const struct GNUNET_PseudonymIdentifier * pseudonym, const char *name, const char *unique_name, - const struct GNUNET_CONTAINER_MetaData *md, int rating) + const struct GNUNET_CONTAINER_MetaData *md, int32_t rating) { int *ret = cls; @@ -64,10 +65,11 @@ noti_callback (void *cls, const struct GNUNET_HashCode * pseudonym, return GNUNET_OK; } + static int -fake_noti_callback (void *cls, const struct GNUNET_HashCode * pseudonym, +fake_noti_callback (void *cls, const struct GNUNET_PseudonymIdentifier * pseudonym, const char *name, const char *unique_name, - const struct GNUNET_CONTAINER_MetaData *md, int rating) + const struct GNUNET_CONTAINER_MetaData *md, int32_t rating) { int *ret = cls; @@ -75,24 +77,30 @@ fake_noti_callback (void *cls, const struct GNUNET_HashCode * pseudonym, return GNUNET_OK; } -static int -false_callback (void *cls, const struct GNUNET_HashCode * pseudonym, - const char *name, const char *unique_name, - const struct GNUNET_CONTAINER_MetaData *md, int rating) + +static void +create_pseu (struct GNUNET_PseudonymIdentifier *pseu) { - return GNUNET_OK; + struct GNUNET_PseudonymHandle *ph; + + ph = GNUNET_PSEUDONYM_create (NULL); + GNUNET_PSEUDONYM_get_identifier (ph, pseu); + GNUNET_PSEUDONYM_destroy (ph); } -int -main (int argc, char *argv[]) + +/** + * Testcase for meta data / ranking IO routines. + */ +static int +test_io () { int ok; - struct GNUNET_HashCode rid1; - struct GNUNET_HashCode id2; - struct GNUNET_HashCode rid2; - struct GNUNET_HashCode fid; - struct GNUNET_HashCode id3; - + struct GNUNET_PseudonymIdentifier rid1; + struct GNUNET_PseudonymIdentifier id2; + struct GNUNET_PseudonymIdentifier rid2; + struct GNUNET_PseudonymIdentifier fid; + struct GNUNET_PseudonymIdentifier id3; int old; int newVal; struct GNUNET_CONFIGURATION_Handle *cfg; @@ -104,8 +112,9 @@ main (int argc, char *argv[]) char *noname; int noname_is_a_dup; int notiCount, fakenotiCount; - int count; static char m[1024 * 1024 * 10]; + struct GNUNET_PSEUDONYM_DiscoveryHandle *dh1; + struct GNUNET_PSEUDONYM_DiscoveryHandle *dh2; memset (m, 'b', sizeof (m)); m[sizeof (m) - 1] = '\0'; @@ -122,14 +131,11 @@ main (int argc, char *argv[]) } notiCount = 0; fakenotiCount = 0; - count = 0; - GNUNET_PSEUDONYM_discovery_callback_register (cfg, &fake_noti_callback, - &fakenotiCount); - GNUNET_PSEUDONYM_discovery_callback_register (cfg, ¬i_callback, - ¬iCount); - GNUNET_PSEUDONYM_discovery_callback_unregister (&false_callback, &count); - GNUNET_PSEUDONYM_discovery_callback_unregister (&fake_noti_callback, - &fakenotiCount); + dh1 = GNUNET_PSEUDONYM_discovery_callback_register (cfg, &fake_noti_callback, + &fakenotiCount); + dh2 = GNUNET_PSEUDONYM_discovery_callback_register (cfg, ¬i_callback, + ¬iCount); + GNUNET_PSEUDONYM_discovery_callback_unregister (dh1); /* ACTUAL TEST CODE */ old = GNUNET_PSEUDONYM_list_all (cfg, NULL, NULL); @@ -137,7 +143,7 @@ main (int argc, char *argv[]) GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_TITLE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "test", strlen ("test") + 1); - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id1); + create_pseu (&id1); GNUNET_PSEUDONYM_add (cfg, &id1, meta); CHECK (notiCount == 1); GNUNET_PSEUDONYM_add (cfg, &id1, meta); @@ -145,7 +151,7 @@ main (int argc, char *argv[]) newVal = GNUNET_PSEUDONYM_list_all (cfg, &iter, &ok); CHECK (old < newVal); old = newVal; - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id2); + create_pseu (&id2); GNUNET_PSEUDONYM_add (cfg, &id2, meta); CHECK (notiCount == 3); newVal = GNUNET_PSEUDONYM_list_all (cfg, &iter, &ok); @@ -156,7 +162,7 @@ main (int argc, char *argv[]) EXTRACTOR_METAFORMAT_UTF8, "text/plain", m, strlen (m) + 1)); - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &id3); + create_pseu (&id3); GNUNET_PSEUDONYM_add (cfg, &id3, meta); GNUNET_PSEUDONYM_get_info (cfg, &id3, NULL, NULL, &name3, NULL); CHECK (name3 != NULL); @@ -173,10 +179,10 @@ main (int argc, char *argv[]) CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, name1, &rid1)); CHECK (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, name2_unique, &rid2)); CHECK (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, name1_unique, &rid1)); - CHECK (0 == memcmp (&id1, &rid1, sizeof (struct GNUNET_HashCode))); - CHECK (0 == memcmp (&id2, &rid2, sizeof (struct GNUNET_HashCode))); + CHECK (0 == memcmp (&id1, &rid1, sizeof (struct GNUNET_PseudonymIdentifier))); + CHECK (0 == memcmp (&id2, &rid2, sizeof (struct GNUNET_PseudonymIdentifier))); - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &fid); + create_pseu (&fid); GNUNET_log_skip (1, GNUNET_NO); CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &fid, 0)); GNUNET_log_skip (0, GNUNET_NO); @@ -195,7 +201,7 @@ main (int argc, char *argv[]) GNUNET_free (noname); /* END OF TEST CODE */ FAILURE: - GNUNET_PSEUDONYM_discovery_callback_unregister (¬i_callback, ¬iCount); + GNUNET_PSEUDONYM_discovery_callback_unregister (dh2); GNUNET_CONTAINER_meta_data_destroy (meta); GNUNET_CONFIGURATION_destroy (cfg); GNUNET_break (GNUNET_OK == @@ -203,4 +209,29 @@ FAILURE: return (ok == GNUNET_YES) ? 0 : 1; } + +static int +test_crypto () +{ + struct GNUNET_PseudonymHandle *ph; + + ph = GNUNET_PSEUDONYM_create (NULL); + // FIXME: call sign, verify APIs... + GNUNET_PSEUDONYM_destroy (ph); + return 0; +} + + +int +main (int argc, char *argv[]) +{ + if (0 != test_io ()) + return 1; + if (0 != test_crypto ()) + return 1; + + return 0; +} + + /* end of test_pseudoynm.c */ -- cgit v1.2.3