From 7d9d8f793ebc261192fe33a87905133e1bf36512 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 14 Apr 2013 18:45:55 +0000 Subject: -move pseudonym code to fs, mark fs as experimental for now --- src/Makefile.am | 3 +- src/fs/Makefile.am | 14 +- src/fs/fs_pseudonym.c | 1590 ++++++++++++++++++++++++++++++++++++ src/fs/plugin_block_fs.c | 1 + src/fs/test_pseudonym.c | 327 ++++++++ src/include/Makefile.am | 1 - src/include/block_fs.h | 1 + src/include/gnunet_fs_service.h | 371 +++++++++ src/include/gnunet_pseudonym_lib.h | 418 ---------- src/include/gnunet_util_lib.h | 1 - src/util/Makefile.am | 7 - src/util/pseudonym.c | 1526 ---------------------------------- src/util/test_pseudonym.c | 323 -------- 13 files changed, 2304 insertions(+), 2279 deletions(-) create mode 100644 src/fs/fs_pseudonym.c create mode 100644 src/fs/test_pseudonym.c delete mode 100644 src/include/gnunet_pseudonym_lib.h delete mode 100644 src/util/pseudonym.c delete mode 100644 src/util/test_pseudonym.c diff --git a/src/Makefile.am b/src/Makefile.am index 771432a91..11e260e5a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,7 +3,7 @@ #endif if HAVE_EXPERIMENTAL - EXP_DIR = chat consensus dv + EXP_DIR = fs chat consensus dv endif if LINUX @@ -55,7 +55,6 @@ SUBDIRS = \ mesh \ lockmanager \ stream \ - fs \ $(LINUX_DIR) \ $(MINGW_DIR) \ integration-tests \ diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am index 54267c57c..e9d5f40db 100644 --- a/src/fs/Makefile.am +++ b/src/fs/Makefile.am @@ -34,6 +34,7 @@ libgnunetfs_la_SOURCES = \ fs_file_information.c \ fs_getopt.c \ fs_list_indexed.c \ + fs_pseudonym.c \ fs_publish.c \ fs_publish_ksk.c \ fs_misc.c \ @@ -47,7 +48,7 @@ libgnunetfs_la_SOURCES = \ libgnunetfs_la_LIBADD = \ $(top_builddir)/src/datastore/libgnunetdatastore.la \ $(top_builddir)/src/util/libgnunetutil.la \ - $(GN_LIBINTL) $(XLIB) -lunistring -lextractor + $(GN_LIBINTL) $(XLIB) -lunistring -lextractor -lgcrypt libgnunetfs_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) $(WINFLAGS) \ @@ -214,6 +215,7 @@ libgnunet_plugin_block_fs_la_SOURCES = \ plugin_block_fs.c libgnunet_plugin_block_fs_la_LIBADD = \ $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(LTLIBINTL) libgnunet_plugin_block_fs_la_LDFLAGS = \ @@ -243,6 +245,7 @@ check_PROGRAMS = \ test_fs_list_indexed \ test_fs_namespace \ test_fs_namespace_list_updateable \ + test_pseudonym \ test_fs_publish \ test_fs_publish_persistence \ test_fs_search \ @@ -288,6 +291,7 @@ TESTS = \ test_fs_list_indexed \ test_fs_namespace \ test_fs_namespace_list_updateable \ + test_pseudonym \ test_fs_publish \ test_fs_publish_persistence \ test_fs_search \ @@ -308,6 +312,14 @@ TESTS = \ endif +test_pseudonym_SOURCES = \ + test_pseudonym.c +test_pseudonym_LDADD = \ + -lgcrypt \ + $(top_builddir)/src/fs/libgnunetfs.la \ + $(top_builddir)/src/util/libgnunetutil.la + + test_fs_directory_SOURCES = \ test_fs_directory.c test_fs_directory_LDADD = \ diff --git a/src/fs/fs_pseudonym.c b/src/fs/fs_pseudonym.c new file mode 100644 index 000000000..5e9c9816e --- /dev/null +++ b/src/fs/fs_pseudonym.c @@ -0,0 +1,1590 @@ +/* + This file is part of GNUnet + (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 + by the Free Software Foundation; either version 2, 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_pseudonym.c + * @brief pseudonym 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_util_lib.h" +#include "gnunet_fs_service.h" +#include + + +#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) + +#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' with the message given + * by gcry_strerror(rc). + */ +#define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0); + +/** + * Name of the directory which stores meta data for pseudonym + */ +#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 "pseudonym" DIR_SEPARATOR_STR "names" DIR_SEPARATOR_STR + + +/** + * Configuration section we use. + */ +#define GNUNET_CLIENT_SERVICE_NAME "fs" + + +/* ************************* Disk operations (pseudonym data mgmt) **************** */ + +/** + * Registered callbacks for discovery of pseudonyms. + */ +struct GNUNET_PSEUDONYM_DiscoveryHandle +{ + /** + * This is a doubly linked list. + */ + 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. + */ + GNUNET_PSEUDONYM_Iterator callback; + + /** + * Closure for callback. + */ + void *callback_cls; +}; + + +/** + * Head of the linked list of functions to call when + * new pseudonyms are added. + */ +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 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_PseudonymIdentifier *pseudonym, + const struct GNUNET_CONTAINER_MetaData *md, int rating) +{ + struct GNUNET_PSEUDONYM_DiscoveryHandle *pos; + + 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. + * Will immediately call provided iterator callback for all + * already discovered pseudonyms. + * + * @param cfg configuration to use + * @param iterator iterator over pseudonym + * @param iterator_cls point to a closure + * @return registration handle + */ +struct GNUNET_PSEUDONYM_DiscoveryHandle * +GNUNET_PSEUDONYM_discovery_callback_register (const struct + GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_PSEUDONYM_Iterator iterator, + void *iterator_cls) +{ + 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 dh registration to unregister + */ +void +GNUNET_PSEUDONYM_discovery_callback_unregister (struct GNUNET_PSEUDONYM_DiscoveryHandle *dh) +{ + 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 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_PseudonymIdentifier *pseudonym) +{ + struct GNUNET_CRYPTO_HashAsciiEncoded enc; + struct GNUNET_HashCode psid; + + 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); +} + + +/** + * Get the filename (or directory name) for the given + * hash code and directory prefix. + * + * @param cfg configuration to use + * @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 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 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 + * 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, pseudonym); + if (NULL == (fileW = GNUNET_BIO_write_open (fn))) + { + 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 (NULL != name) + GNUNET_free_non_null (GNUNET_PSEUDONYM_name_uniquify (cfg, pseudonym, + name, NULL)); + return GNUNET_OK; +} + + +/** + * Read pseudonym infomation from a file + * + * @param cfg configuration to use + * @param pseudonym hash code of a pseudonym + * @param meta meta data to be read from a file + * @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_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, pseudonym); + if (GNUNET_YES != + GNUNET_DISK_file_test (fn)) + { + GNUNET_free (fn); + return GNUNET_SYSERR; + } + 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 (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); + GNUNET_free_non_null (*ns_name); + *ns_name = NULL; + GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); + GNUNET_free (fn); + return GNUNET_SYSERR; + } + 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"), fn, + emsg); + GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); + GNUNET_CONTAINER_meta_data_destroy (*meta); + *meta = NULL; + GNUNET_free_non_null (*ns_name); + *ns_name = NULL; + GNUNET_free_non_null (emsg); + GNUNET_free (fn); + return GNUNET_SYSERR; + } + GNUNET_free (fn); + return GNUNET_OK; +} + + +/** + * 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 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. + * Free the name with GNUNET_free(). + */ +char * +GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, + 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; + unsigned int i; + unsigned int idx; + char *ret; + struct stat sbuf; + + GNUNET_CRYPTO_hash (name, strlen (name), &nh); + 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)); + fh = GNUNET_DISK_file_open (fn, + GNUNET_DISK_OPEN_CREATE | + GNUNET_DISK_OPEN_READWRITE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + i = 0; + idx = -1; + while ((len >= sizeof (struct GNUNET_PseudonymIdentifier)) && + (sizeof (struct GNUNET_PseudonymIdentifier) == + GNUNET_DISK_file_read (fh, &pi, sizeof (struct GNUNET_PseudonymIdentifier)))) + { + if (0 == memcmp (&pi, pseudonym, sizeof (struct GNUNET_PseudonymIdentifier))) + { + idx = i; + break; + } + i++; + len -= sizeof (struct GNUNET_HashCode); + } + if (-1 == idx) + { + idx = i; + 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); + ret = GNUNET_malloc (strlen (name) + 32); + GNUNET_snprintf (ret, strlen (name) + 32, "%s-%u", name, idx); + if (suffix != NULL) + *suffix = idx; + GNUNET_free (fn); + 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 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. + * @param ret_name a location to store human-readable name. Name is not unique. + * NULL, if name is not needed. Free with GNUNET_free(). + * @param name_is_a_dup is set to GNUNET_YES, if ret_name was filled with + * a duplicate of a "no-name" placeholder + * @return GNUNET_OK on success. GNUENT_SYSERR if the data was + * unobtainable (in that case ret_* are filled with placeholders - + * empty metadata container, rank -1 and a "no-name" name). + */ +int +GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg, + 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; + int32_t rank = -1; + + meta = NULL; + name = NULL; + if (GNUNET_OK == read_info (cfg, pseudonym, &meta, &rank, &name)) + { + if ((meta != NULL) && (name == NULL)) + name = + GNUNET_CONTAINER_meta_data_get_first_by_types (meta, + EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, + EXTRACTOR_METATYPE_FILENAME, + EXTRACTOR_METATYPE_DESCRIPTION, + EXTRACTOR_METATYPE_SUBJECT, + EXTRACTOR_METATYPE_PUBLISHER, + EXTRACTOR_METATYPE_AUTHOR_NAME, + EXTRACTOR_METATYPE_COMMENT, + EXTRACTOR_METATYPE_SUMMARY, + -1); + if (ret_name != NULL) + { + if (name == NULL) + { + name = GNUNET_strdup (_("no-name")); + if (name_is_a_dup != NULL) + *name_is_a_dup = GNUNET_YES; + } + else if (name_is_a_dup != NULL) + *name_is_a_dup = GNUNET_NO; + *ret_name = name; + } + else if (name != NULL) + GNUNET_free (name); + + if (ret_meta != NULL) + { + if (meta == NULL) + meta = GNUNET_CONTAINER_meta_data_create (); + *ret_meta = meta; + } + else if (meta != NULL) + GNUNET_CONTAINER_meta_data_destroy (meta); + + if (ret_rank != NULL) + *ret_rank = rank; + + return GNUNET_OK; + } + if (ret_name != NULL) + *ret_name = GNUNET_strdup (_("no-name")); + if (ret_meta != NULL) + *ret_meta = GNUNET_CONTAINER_meta_data_create (); + if (ret_rank != NULL) + *ret_rank = -1; + if (name_is_a_dup != NULL) + *name_is_a_dup = GNUNET_YES; + 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 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_PseudonymIdentifier *pseudonym) +{ + size_t slen; + uint64_t len; + unsigned int idx; + char *name; + struct GNUNET_HashCode nh; + char *fn; + struct GNUNET_DISK_FileHandle *fh; + + idx = -1; + slen = strlen (ns_uname); + while ((slen > 0) && (1 != SSCANF (&ns_uname[slen - 1], "-%u", &idx))) + slen--; + 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_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_PseudonymIdentifier) > len)) + { + GNUNET_free (fn); + return GNUNET_SYSERR; + } + fh = GNUNET_DISK_file_open (fn, + GNUNET_DISK_OPEN_CREATE | + GNUNET_DISK_OPEN_READWRITE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + GNUNET_free (fn); + if (GNUNET_SYSERR == + 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_PseudonymIdentifier) != + GNUNET_DISK_file_read (fh, pseudonym, sizeof (struct GNUNET_PseudonymIdentifier))) + { + GNUNET_DISK_file_close (fh); + return GNUNET_SYSERR; + } + GNUNET_DISK_file_close (fh); + return GNUNET_OK; +} + + + +/** + * struct used to list the pseudonym + */ +struct ListPseudonymClosure +{ + + /** + * iterator over pseudonym + */ + GNUNET_PSEUDONYM_Iterator iterator; + + /** + * Closure for iterator. + */ + void *iterator_cls; + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; +}; + + + +/** + * 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 *lpc = cls; + struct GNUNET_PseudonymIdentifier pd; + char *emsg; + struct GNUNET_BIO_ReadHandle *fileR; + int32_t rank; + char *ns_name; + struct GNUNET_CONTAINER_MetaData *meta; + int ret; + char *name_unique; + + 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)) ) + { + (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); + GNUNET_free (ns_name); + GNUNET_free_non_null (emsg); + return GNUNET_SYSERR; + } + 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; +} + + +/** + * List all available pseudonyms. + * + * @param cfg overall configuration + * @param iterator function to call for each pseudonym + * @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 *iterator_cls) +{ + struct ListPseudonymClosure cls; + char *fn; + int ret; + + cls.iterator = iterator; + cls.iterator_cls = iterator_cls; + cls.cfg = cfg; + fn = get_data_filename (cfg, PS_METADATA_DIR, NULL); + GNUNET_assert (fn != NULL); + GNUNET_DISK_directory_create (fn); + ret = GNUNET_DISK_directory_scan (fn, &list_pseudonym_helper, &cls); + GNUNET_free (fn); + return ret; +} + + +/** + * Change the rank of a pseudonym. + * + * @param cfg overall configuration + * @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_PseudonymIdentifier *pseudonym, + int32_t delta) +{ + struct GNUNET_CONTAINER_MetaData *meta; + int ret; + int32_t rank; + char *name; + + name = NULL; + ret = read_info (cfg, pseudonym, &meta, &rank, &name); + if (ret == GNUNET_SYSERR) + { + rank = 0; + meta = GNUNET_CONTAINER_meta_data_create (); + } + rank += delta; + GNUNET_PSEUDONYM_set_info (cfg, pseudonym, name, meta, rank); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_free_non_null (name); + return rank; +} + + +/** + * Add a pseudonym to the set of known pseudonyms. + * For all pseudonym advertisements that we discover + * FS should automatically call this function. + * + * @param cfg overall configuration + * @param pseudonym the pseudonym to add + * @param meta metadata for the pseudonym + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PseudonymIdentifier *pseudonym, + const struct GNUNET_CONTAINER_MetaData *meta) +{ + char *name; + int32_t rank; + struct GNUNET_CONTAINER_MetaData *old; + char *fn; + struct stat sbuf; + int ret; + + 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, pseudonym, &old, &rank, &name))) + { + GNUNET_CONTAINER_meta_data_merge (old, meta); + ret = GNUNET_PSEUDONYM_set_info (cfg, pseudonym, name, old, rank); + GNUNET_CONTAINER_meta_data_destroy (old); + GNUNET_free_non_null (name); + } + else + { + ret = GNUNET_PSEUDONYM_set_info (cfg, pseudonym, NULL, meta, rank); + } + GNUNET_free (fn); + internal_notify (pseudonym, meta, rank); + return ret; +} + + +/* ***************************** cryptographic operations ************************* */ + +/** + * Handle for a pseudonym (private key). + */ +struct GNUNET_PseudonymHandle +{ + /** + * 256-bit 'd' secret value (mod 'n', where n is 256-bit for NIST P-256). + */ + unsigned char d[256 / 8]; + + /** + * Public key corresponding to the private key. + */ + struct GNUNET_PseudonymIdentifier public_key; +}; + + +/** + * If target != size, move target bytes to the end of the size-sized + * buffer and zero out the first target-size bytes. + * + * @param buf original buffer + * @param size number of bytes in the buffer + * @param target target size of the buffer + */ +static void +adjust (unsigned char *buf, size_t size, size_t target) +{ + if (size < target) + { + memmove (&buf[target - size], buf, size); + memset (buf, 0, target - size); + } +} + + +/** + * Extract values from an S-expression. + * + * @param array where to store the result(s) + * @param sexp S-expression to parse + * @param topname top-level name in the S-expression that is of interest + * @param elems names of the elements to extract + * @return 0 on success + */ +static int +key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname, + const char *elems) +{ + gcry_sexp_t list; + gcry_sexp_t l2; + const char *s; + unsigned int i; + unsigned int idx; + + if (! (list = gcry_sexp_find_token (sexp, topname, 0))) + return 1; + l2 = gcry_sexp_cadr (list); + gcry_sexp_release (list); + list = l2; + if (! list) + return 2; + idx = 0; + for (s = elems; *s; s++, idx++) + { + if (! (l2 = gcry_sexp_find_token (list, s, 1))) + { + for (i = 0; i < idx; i++) + { + gcry_free (array[i]); + array[i] = NULL; + } + gcry_sexp_release (list); + return 3; /* required parameter not found */ + } + array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (l2); + if (! array[idx]) + { + for (i = 0; i < idx; i++) + { + gcry_free (array[i]); + array[i] = NULL; + } + gcry_sexp_release (list); + return 4; /* required parameter is invalid */ + } + } + gcry_sexp_release (list); + return 0; +} + + +/** + * 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; + gcry_sexp_t r_key; + gcry_sexp_t params; + gcry_ctx_t ctx; + gcry_mpi_point_t q; + gcry_mpi_t q_x; + gcry_mpi_t q_y; + gcry_error_t rc; + gcry_mpi_t d; + size_t size; + + ph = GNUNET_malloc (sizeof (struct GNUNET_PseudonymHandle)); + if ( (NULL != filename) && + (GNUNET_YES == GNUNET_DISK_file_test (filename)) ) + { + ret = GNUNET_DISK_fn_read (filename, ph, + sizeof (struct GNUNET_PseudonymHandle)); + /* Note: we don't do any validation here, maybe we should? */ + if (sizeof (struct GNUNET_PseudonymHandle) == ret) + return ph; + } + if (0 != (rc = gcry_sexp_build (¶ms, NULL, + "(genkey(ecdsa(curve \"NIST P-256\")))"))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); + return NULL; + } + if (0 != (rc = gcry_pk_genkey (&r_key, params))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc); + gcry_sexp_release (r_key); + return NULL; + } + /* extract "d" (secret key) from r_key */ + rc = key_from_sexp (&d, r_key, "private-key", "d"); + if (0 != rc) + rc = key_from_sexp (&d, r_key, "private-key", "d"); + if (0 != rc) + rc = key_from_sexp (&d, r_key, "ecc", "d"); + if (0 != rc) + { + gcry_sexp_release (r_key); + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc); + return NULL; + } + size = sizeof (ph->d); + GNUNET_assert (0 == + gcry_mpi_print (GCRYMPI_FMT_USG, ph->d, size, &size, + d)); + gcry_mpi_release (d); + adjust (ph->d, size, sizeof (ph->d)); + + /* extract 'q' (public key) from r_key */ + if (0 != (rc = gcry_mpi_ec_new (&ctx, r_key, NULL))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ + gcry_sexp_release (r_key); + return NULL; + } + gcry_sexp_release (r_key); + q = gcry_mpi_ec_get_point ("q", ctx, 0); + q_x = gcry_mpi_new (256); + q_y = gcry_mpi_new (256); + gcry_mpi_ec_get_affine (q_x, q_y, q, ctx); + gcry_mpi_point_release (q); + + /* store q_x/q_y in public key */ + size = sizeof (ph->public_key.q_x); + if (0 != + gcry_mpi_print (GCRYMPI_FMT_USG, ph->public_key.q_x, size, &size, + q_x)) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc); + gcry_mpi_release (q_x); + gcry_mpi_release (q_y); + return NULL; + + } + adjust (ph->public_key.q_x, size, sizeof (ph->public_key.q_x)); + gcry_mpi_release (q_x); + + size = sizeof (ph->public_key.q_y); + if (0 != + gcry_mpi_print (GCRYMPI_FMT_USG, ph->public_key.q_y, size, &size, + q_y)) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc); + gcry_mpi_release (q_y); + return NULL; + } + adjust (ph->public_key.q_y, size, sizeof (ph->public_key.q_y)); + gcry_mpi_release (q_y); + + /* write to disk */ + 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) + { + GNUNET_free (ph); + return NULL; + } + /* Note: we don't do any validation here; maybe we should? */ + return ph; +} + + +/** + * 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)); + /* Note if we use 'd=0' for the anonymous handle (as per#2564), + then I believe the public key should be also zero, as Q=0P=0; + so setting everything to all-zeros (as per GNUNET_malloc) + should be all that is needed here). + */ + 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); +} + + +/** + * Convert the data specified in the given purpose argument to an + * S-expression suitable for signature operations. + * + * @param purpose data to convert + * @return converted s-expression + */ +static gcry_sexp_t +data_to_pkcs1 (const struct GNUNET_PseudonymSignaturePurpose *purpose) +{ + struct GNUNET_CRYPTO_ShortHashCode hc; + size_t bufSize; + gcry_sexp_t data; + + GNUNET_CRYPTO_short_hash (purpose, ntohl (purpose->size), &hc); +#define FORMATSTRING "(4:data(5:flags3:raw)(5:value32:01234567890123456789012345678901))" + bufSize = strlen (FORMATSTRING) + 1; + { + char buff[bufSize]; + + memcpy (buff, FORMATSTRING, bufSize); + memcpy (&buff + [bufSize - + strlen + ("01234567890123456789012345678901))") + - 1], &hc, sizeof (struct GNUNET_CRYPTO_ShortHashCode)); + GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0)); + } +#undef FORMATSTRING + return data; +} + +gcry_ctx_t xctx; + + +/** + * Cryptographically sign some data with the pseudonym. + * + * @param ph private key 'd' 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 ('h'); + * see section 2.3 of #2564. + * @param signature where to store the signature + * @return GNUNET_SYSERR on failure + */ +int +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) +{ + size_t size; + size_t erroff; + gcry_mpi_t d; + gcry_mpi_t k; + gcry_mpi_t h; + gcry_mpi_t dh; + gcry_mpi_t n; /* n from P-256 */ + gcry_sexp_t spriv; + gcry_sexp_t data; + gcry_sexp_t result; + gcry_mpi_t rs[2]; + int rc; + + /* get private key 'd' from pseudonym */ + size = sizeof (ph->d); + if (0 != (rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG, + &ph->d, + size, &size))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + return GNUNET_SYSERR; + } + /* get 'x' value from signing key */ + size = sizeof (struct GNUNET_HashCode); + if (0 != (rc = gcry_mpi_scan (&h, GCRYMPI_FMT_USG, + signing_key, + size, &size))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (d); + return GNUNET_SYSERR; + } + + /* initialize 'n' from P-256; hex copied from libgcrypt code */ + if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX, + "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 0, NULL))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (d); + gcry_mpi_release (h); + return GNUNET_SYSERR; + } + + /* calculate dx = d + h mod n */ + dh = gcry_mpi_new (256); + gcry_mpi_addm (dh, d, h, n); + // gcry_mpi_release (d); + // gcry_mpi_release (h); + gcry_mpi_release (n); + + if (1) { + gcry_mpi_point_t g; + gcry_mpi_point_t v; + gcry_mpi_point_t hg; + gcry_mpi_point_t q; + gcry_mpi_t v_x; + gcry_mpi_t v_y; + + gcry_mpi_ec_new (&xctx, NULL, "NIST P-256"); + g = gcry_mpi_ec_get_point ("g", xctx, 0); + + hg = gcry_mpi_point_new (0); + gcry_mpi_ec_mul (hg, h, g, xctx); + fprintf (stderr, "\nExpected verification hG value:\n"); + v_x = gcry_mpi_new (256); + v_y = gcry_mpi_new (256); + gcry_mpi_ec_get_affine (v_x, v_y, hg, xctx); + gcry_mpi_dump (v_x); + gcry_mpi_dump (v_y); + + q = gcry_mpi_point_new (0); + gcry_mpi_ec_mul (q, d, g, xctx); + fprintf (stderr, "\nExpected verification q value:\n"); + gcry_mpi_ec_get_affine (v_x, v_y, q, xctx); + gcry_mpi_dump (v_x); + gcry_mpi_dump (v_y); + + v = gcry_mpi_point_new (0); + gcry_mpi_ec_add (v, q, hg, xctx); + gcry_mpi_ec_get_affine (v_x, v_y, v, xctx); + fprintf (stderr, "\nExpected verification key public point value V := q + hG:\n"); + gcry_mpi_dump (v_x); + gcry_mpi_dump (v_y); + fprintf (stderr, "\n"); + + } + + + /* now build sexpression with the signing key */ + if (0 != (rc = gcry_sexp_build (&spriv, &erroff, + "(private-key(ecdsa(curve \"NIST P-256\")(d %m)))", + dh))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); + gcry_mpi_release (dh); + return GNUNET_SYSERR; + } + gcry_mpi_release (dh); + /* prepare data for signing */ + data = data_to_pkcs1 (purpose); + + /* get 'k' value from seed, if available */ + if (NULL != seed) + { + size = sizeof (struct GNUNET_HashCode); + if (0 != (rc = gcry_mpi_scan (&k, GCRYMPI_FMT_USG, + seed, + size, &size))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + return GNUNET_SYSERR; + } + } + + /* actually create signature */ + /* FIXME: need API to pass 'k' if 'seed' was non-NULL! */ + if (0 != (rc = gcry_pk_sign (&result, data, spriv))) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("ECC signing failed at %s:%d: %s\n"), __FILE__, + __LINE__, gcry_strerror (rc)); + gcry_sexp_release (data); + gcry_sexp_release (spriv); + if (NULL != seed) + gcry_mpi_release (k); + memset (signature, 0, sizeof (struct GNUNET_PseudonymSignature)); + return GNUNET_SYSERR; + } + if (NULL != seed) + gcry_mpi_release (k); + gcry_sexp_release (data); + gcry_sexp_release (spriv); + + + /* extract 'r' and 's' values from sexpression 'result' and store in 'signature' */ + if (0 != (rc = key_from_sexp (rs, result, "sig-val", "rs"))) + { + GNUNET_break (0); + gcry_sexp_release (result); + return GNUNET_SYSERR; + } + gcry_sexp_release (result); + size = sizeof (signature->sig_r); + if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, signature->sig_r, size, + &size, rs[0]))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc); + gcry_mpi_release (rs[0]); + gcry_mpi_release (rs[1]); + return GNUNET_SYSERR; + } + gcry_mpi_release (rs[0]); + size = sizeof (signature->sig_s); + if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, signature->sig_s, size, + &size, rs[1]))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc); + gcry_mpi_release (rs[1]); + return GNUNET_SYSERR; + } + gcry_mpi_release (rs[1]); + return GNUNET_OK; +} + + +/** + * Get an ECC context (with Q set to the respective public key) from + * a pseudonym. + * + * @param pseudonym with information on 'q' + * @return curve context + */ +static gcry_ctx_t +get_context_from_pseudonym (struct GNUNET_PseudonymIdentifier *pseudonym) +{ + gcry_ctx_t ctx; + gcry_mpi_t ONE; + gcry_mpi_t q_x; + gcry_mpi_t q_y; + gcry_mpi_point_t q; + size_t size; + int rc; + + /* extract 'q' from pseudonym */ + size = sizeof (pseudonym->q_x); + if (0 != (rc = gcry_mpi_scan (&q_x, GCRYMPI_FMT_USG, pseudonym->q_x, size, &size))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + return NULL; + } + size = sizeof (pseudonym->q_y); + if (0 != (rc = gcry_mpi_scan (&q_y, GCRYMPI_FMT_USG, pseudonym->q_y, size, &size))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (q_x); + return NULL; + } + q = gcry_mpi_point_new (256); + ONE = gcry_mpi_new (1); + gcry_mpi_set_ui (ONE, 1); + gcry_mpi_point_set (q, q_x, q_y, ONE); /* FIXME: convenience function 'set_affine'? */ + gcry_mpi_release (ONE); + gcry_mpi_release (q_x); + gcry_mpi_release (q_y); + + /* create basic ECC context */ + if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256"))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ + gcry_mpi_point_release (q); + return NULL; + } + /* initialize 'ctx' with 'q' */ + gcry_mpi_ec_set_point ("q", q, ctx); + gcry_mpi_point_release (q); + return ctx; +} + + +/** + * 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 (dQ in ECDSA) + * @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 '(d+h)' of 'pseudonym' and the 'signing_key'; + * the value stored here can then be given to GNUNET_PSEUDONYM_verify. + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_PSEUDONYM_derive_verification_key (struct GNUNET_PseudonymIdentifier *pseudonym, + const struct GNUNET_HashCode *signing_key, + struct GNUNET_PseudonymIdentifier *verification_key) +{ + gcry_mpi_t h; + size_t size; + int rc; + gcry_ctx_t ctx; + gcry_mpi_point_t g; + gcry_mpi_point_t q; + gcry_mpi_point_t hg; + gcry_mpi_point_t v; + gcry_mpi_t v_x; + gcry_mpi_t v_y; + + /* get 'h' value from signing key */ + size = sizeof (struct GNUNET_HashCode); + if (0 != (rc = gcry_mpi_scan (&h, GCRYMPI_FMT_USG, + signing_key, + size, &size))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + return GNUNET_SYSERR; + } + /* create ECC context based on Q from pseudonym */ + if (NULL == (ctx = get_context_from_pseudonym (pseudonym))) + { + gcry_mpi_release (h); + return GNUNET_SYSERR; + } + /* get G */ + g = gcry_mpi_ec_get_point ("g", ctx, 0); + + /* then call the 'multiply' function, to compute the product hG */ + hg = gcry_mpi_point_new (0); + gcry_mpi_ec_mul (hg, h, g, ctx); + + { + fprintf (stderr, "\nVerification hG value:\n"); + v_x = gcry_mpi_new (256); + v_y = gcry_mpi_new (256); + gcry_mpi_ec_get_affine (v_x, v_y, hg, ctx); + gcry_mpi_dump (v_x); + gcry_mpi_dump (v_y); + } + gcry_mpi_release (h); + + /* get Q = dG from 'pseudonym' */ + q = gcry_mpi_ec_get_point ("q", ctx, 0); + { + fprintf (stderr, "\nVerification q value:\n"); + v_x = gcry_mpi_new (256); + v_y = gcry_mpi_new (256); + gcry_mpi_ec_get_affine (v_x, v_y, q, ctx); + gcry_mpi_dump (v_x); + gcry_mpi_dump (v_y); + } + /* calculate V = Q + hG = dG + hG = (d + h)G*/ + v = gcry_mpi_point_new (0); + gcry_mpi_ec_add (v, q, hg, xctx); + /* FIXME: free 'hg'? */ + + /* store 'v' point in "verification_key" */ + v_x = gcry_mpi_new (256); + v_y = gcry_mpi_new (256); + gcry_mpi_ec_get_affine (v_x, v_y, v, xctx); + + { + fprintf (stderr, "\nVerification key public point value V := q + hG:\n"); + gcry_mpi_dump (v_x); + gcry_mpi_dump (v_y); + fprintf (stderr, " <=== WTF!?\n"); + } + + + gcry_mpi_point_release (v); + gcry_ctx_release (ctx); + + size = sizeof (verification_key->q_x); + if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, verification_key->q_x, size, + &size, v_x))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc); + gcry_mpi_release (v_x); + gcry_mpi_release (v_y); + return GNUNET_SYSERR; + } + gcry_mpi_release (v_x); + size = sizeof (verification_key->q_y); + if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, verification_key->q_y, size, + &size, v_y))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc); + gcry_mpi_release (v_y); + return GNUNET_SYSERR; + } + gcry_mpi_release (v_y); + return GNUNET_OK; +} + + +/** + * 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) +{ + gcry_sexp_t data; + gcry_sexp_t sig_sexpr; + gcry_sexp_t pk_sexpr; + size_t size; + gcry_ctx_t ctx; + gcry_mpi_t ONE; + gcry_mpi_t r; + gcry_mpi_t s; + gcry_mpi_point_t q; + gcry_mpi_t q_x; + gcry_mpi_t q_y; + size_t erroff; + int rc; + + /* build s-expression for signature */ + size = sizeof (signature->sig_r); + if (0 != (rc = gcry_mpi_scan (&r, GCRYMPI_FMT_USG, + signature->sig_r, size, &size))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + return GNUNET_SYSERR; + } + size = sizeof (signature->sig_s); + if (0 != (rc = gcry_mpi_scan (&s, GCRYMPI_FMT_USG, + signature->sig_s, size, &size))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_mpi_release (r); + return GNUNET_SYSERR; + } + if (0 != (rc = gcry_sexp_build (&sig_sexpr, &erroff, "(sig-val(ecdsa(r %m)(s %m)))", + r, s))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); + gcry_mpi_release (r); + gcry_mpi_release (s); + return GNUNET_SYSERR; + } + gcry_mpi_release (r); + gcry_mpi_release (s); + + /* build s-expression for data that was signed */ + data = data_to_pkcs1 (purpose); + + /* create context of public key and initialize Q */ + size = sizeof (verification_key->q_x); + if (0 != (rc = gcry_mpi_scan (&q_x, GCRYMPI_FMT_USG, + verification_key->q_x, size, &size))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_sexp_release (data); + gcry_sexp_release (sig_sexpr); + return GNUNET_SYSERR; + } + size = sizeof (verification_key->q_y); + if (0 != (rc = gcry_mpi_scan (&q_y, GCRYMPI_FMT_USG, + verification_key->q_y, size, &size))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); + gcry_sexp_release (data); + gcry_sexp_release (sig_sexpr); + gcry_mpi_release (q_x); + return GNUNET_SYSERR; + } + q = gcry_mpi_point_new (256); + ONE = gcry_mpi_new (1); + gcry_mpi_set_ui (ONE, 1); + gcry_mpi_point_set (q, q_x, q_y, ONE); /* FIXME: convenience function 'set_affine'? */ + gcry_mpi_release (ONE); + gcry_mpi_release (q_x); + gcry_mpi_release (q_y); + + /* create basic ECC context */ + if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256"))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ + gcry_sexp_release (data); + gcry_sexp_release (sig_sexpr); + gcry_mpi_point_release (q); + return GNUNET_SYSERR; + } + /* initialize 'ctx' with 'q' */ + gcry_mpi_ec_set_point ("q", q, ctx); + gcry_mpi_point_release (q); + + /* convert 'ctx' to 'sexp' */ + if (0 != (rc = gcry_pubkey_get_sexp (&pk_sexpr, GCRY_PK_GET_PUBKEY, ctx))) + { + LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_from_context", rc); + gcry_ctx_release (ctx); + gcry_sexp_release (data); + gcry_sexp_release (sig_sexpr); + return GNUNET_SYSERR; + } + gcry_ctx_release (ctx); + + /* finally, verify the signature */ + rc = gcry_pk_verify (sig_sexpr, data, pk_sexpr); + gcry_sexp_release (sig_sexpr); + gcry_sexp_release (data); + gcry_sexp_release (pk_sexpr); + if (rc) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__, + __LINE__, gcry_strerror (rc)); +exit (1); + return GNUNET_SYSERR; + } + 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) +{ + memcpy (pseudonym, &ph->public_key, + sizeof (struct GNUNET_PseudonymIdentifier)); +} + + +/** + * Remove pseudonym from the set of known pseudonyms. + * + * @param cfg overall configuration + * @param id the pseudonym identifier + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_PSEUDONYM_remove (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PseudonymIdentifier *id) +{ + char *fn; + int result; + + fn = get_data_filename (cfg, PS_METADATA_DIR, id); + if (NULL == fn) + return GNUNET_SYSERR; + result = UNLINK (fn); + GNUNET_free (fn); + return (0 == result) ? GNUNET_OK : GNUNET_SYSERR; +} + +/* end of pseudonym.c */ diff --git a/src/fs/plugin_block_fs.c b/src/fs/plugin_block_fs.c index 468dd96a3..a05283f16 100644 --- a/src/fs/plugin_block_fs.c +++ b/src/fs/plugin_block_fs.c @@ -26,6 +26,7 @@ #include "platform.h" #include "gnunet_block_plugin.h" +#include "gnunet_fs_service.h" #include "block_fs.h" #include "gnunet_signatures.h" diff --git a/src/fs/test_pseudonym.c b/src/fs/test_pseudonym.c new file mode 100644 index 000000000..5247d6dcc --- /dev/null +++ b/src/fs/test_pseudonym.c @@ -0,0 +1,327 @@ +/* + This file is part of GNUnet. + (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 + 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/test_pseudonym.c + * @brief testcase for fs_pseudonym.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" +#include "gnunet_signatures.h" + +#define CHECK(a) do { if (!(a)) { ok = GNUNET_NO; GNUNET_break(0); goto FAILURE; } } while (0) + +static struct GNUNET_CONTAINER_MetaData *meta; + +static struct GNUNET_PseudonymIdentifier id1; + + +static int +iter (void *cls, const struct GNUNET_PseudonymIdentifier * pseudonym, + const char *name, const char *unique_name, + const struct GNUNET_CONTAINER_MetaData *md, int32_t rating) +{ + int *ok = cls; + + if ((0 == memcmp (pseudonym, &id1, sizeof (struct GNUNET_PseudonymIdentifier))) && + (!GNUNET_CONTAINER_meta_data_test_equal (md, meta))) + { + *ok = GNUNET_NO; + GNUNET_break (0); + } + return GNUNET_OK; +} + + +static int +noti_callback (void *cls, const struct GNUNET_PseudonymIdentifier * pseudonym, + const char *name, const char *unique_name, + const struct GNUNET_CONTAINER_MetaData *md, int32_t rating) +{ + int *ret = cls; + + (*ret)++; + return GNUNET_OK; +} + + +static int +fake_noti_callback (void *cls, const struct GNUNET_PseudonymIdentifier * pseudonym, + const char *name, const char *unique_name, + const struct GNUNET_CONTAINER_MetaData *md, int32_t rating) +{ + int *ret = cls; + + (*ret)++; + return GNUNET_OK; +} + + +static void +create_pseu (struct GNUNET_PseudonymIdentifier *pseu) +{ + struct GNUNET_PseudonymHandle *ph; + + ph = GNUNET_PSEUDONYM_create (NULL); + GNUNET_PSEUDONYM_get_identifier (ph, pseu); + GNUNET_PSEUDONYM_destroy (ph); +} + + +/** + * Testcase for meta data / ranking IO routines. + */ +static int +test_io () +{ + int ok; + 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; + char *name1; + char *name2; + char *name3; + char *name1_unique; + char *name2_unique; + char *noname; + int noname_is_a_dup; + int notiCount, fakenotiCount; + 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'; + + GNUNET_log_setup ("test-pseudonym", "WARNING", NULL); + ok = GNUNET_YES; + (void) GNUNET_DISK_directory_remove ("/tmp/gnunet-pseudonym-test"); + cfg = GNUNET_CONFIGURATION_create (); + if (-1 == GNUNET_CONFIGURATION_parse (cfg, "test_pseudonym_data.conf")) + { + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_break (0); + return -1; + } + notiCount = 0; + fakenotiCount = 0; + 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); + meta = GNUNET_CONTAINER_meta_data_create (); + GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, "text/plain", + "test", strlen ("test") + 1); + create_pseu (&id1); + GNUNET_PSEUDONYM_add (cfg, &id1, meta); + CHECK (notiCount == 1); + GNUNET_PSEUDONYM_add (cfg, &id1, meta); + CHECK (notiCount == 2); + newVal = GNUNET_PSEUDONYM_list_all (cfg, &iter, &ok); + CHECK (old < newVal); + old = newVal; + create_pseu (&id2); + GNUNET_PSEUDONYM_add (cfg, &id2, meta); + CHECK (notiCount == 3); + newVal = GNUNET_PSEUDONYM_list_all (cfg, &iter, &ok); + CHECK (old < newVal); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_meta_data_insert (meta, "", + EXTRACTOR_METATYPE_COMMENT, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", m, + strlen (m) + 1)); + create_pseu (&id3); + GNUNET_PSEUDONYM_add (cfg, &id3, meta); + GNUNET_PSEUDONYM_get_info (cfg, &id3, NULL, NULL, &name3, NULL); + CHECK (name3 != NULL); + GNUNET_PSEUDONYM_get_info (cfg, &id2, NULL, NULL, &name2, NULL); + CHECK (name2 != NULL); + GNUNET_PSEUDONYM_get_info (cfg, &id1, NULL, NULL, &name1, NULL); + CHECK (name1 != NULL); + CHECK (0 == strcmp (name1, name2)); + name1_unique = GNUNET_PSEUDONYM_name_uniquify (cfg, &id1, name1, NULL); + name2_unique = GNUNET_PSEUDONYM_name_uniquify (cfg, &id2, name2, NULL); + CHECK (0 != strcmp (name1_unique, name2_unique)); + CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, "fake", &rid2)); + CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, name2, &rid2)); + 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_PseudonymIdentifier))); + CHECK (0 == memcmp (&id2, &rid2, sizeof (struct GNUNET_PseudonymIdentifier))); + + create_pseu (&fid); + GNUNET_log_skip (1, GNUNET_NO); + CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &fid, 0)); + GNUNET_log_skip (0, GNUNET_NO); + CHECK (GNUNET_OK == GNUNET_PSEUDONYM_get_info (cfg, &fid, NULL, NULL, &noname, &noname_is_a_dup)); + CHECK (noname != NULL); + CHECK (noname_is_a_dup == GNUNET_YES); + CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &id1, 0)); + CHECK (5 == GNUNET_PSEUDONYM_rank (cfg, &id1, 5)); + CHECK (-5 == GNUNET_PSEUDONYM_rank (cfg, &id1, -10)); + CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &id1, 5)); + GNUNET_free (name1); + GNUNET_free (name2); + GNUNET_free (name1_unique); + GNUNET_free (name2_unique); + GNUNET_free (name3); + GNUNET_free (noname); + /* END OF TEST CODE */ +FAILURE: + GNUNET_PSEUDONYM_discovery_callback_unregister (dh2); + GNUNET_CONTAINER_meta_data_destroy (meta); + GNUNET_CONFIGURATION_destroy (cfg); + return (ok == GNUNET_YES) ? 0 : 1; +} + + +/** + * Use the given input to sign and check the resulting signature. + */ +static void +test_signature (struct GNUNET_PseudonymHandle *ph, + struct GNUNET_PseudonymSignaturePurpose *purpose, + struct GNUNET_HashCode *seed, + struct GNUNET_HashCode *signing_key, + char *bit) +{ + struct GNUNET_PseudonymSignature signature; + struct GNUNET_PseudonymSignature signature2; + struct GNUNET_PseudonymIdentifier pseudonym; + struct GNUNET_PseudonymIdentifier verification_key; + + GNUNET_PSEUDONYM_sign (ph, purpose, seed, signing_key, &signature); + if (0) + { + GNUNET_PSEUDONYM_sign (ph, purpose, seed, signing_key, &signature2); + /* with seed, two sigs must be identical, without, they must be different! */ + if (NULL != seed) + GNUNET_break (0 == memcmp (&signature, &signature2, sizeof (signature))); + else /* crypto not implemented, thus for now 'break' */ + GNUNET_break (0 != memcmp (&signature, &signature2, sizeof (signature))); + } + GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym); + GNUNET_PSEUDONYM_derive_verification_key (&pseudonym, + signing_key, + &verification_key); + GNUNET_break (GNUNET_OK == + GNUNET_PSEUDONYM_verify (purpose, &signature, &verification_key)); + /* also check that if the data is changed, the signature no longer matches */ + (*bit)++; + /* crypto not implemented, thus for now 'break' */ + GNUNET_break (GNUNET_OK != + GNUNET_PSEUDONYM_verify (purpose, &signature, &verification_key)); + (*bit)--; +} + + +/** + * Test cryptographic operations for a given private key. + * + * @param ph private key to test + */ +static void +test_crypto_ops (struct GNUNET_PseudonymHandle *ph) +{ + char data[16]; + struct GNUNET_PseudonymSignaturePurpose *purpose; + struct GNUNET_HashCode seed; + struct GNUNET_HashCode signing_key; + + memset (data, 42, sizeof (data)); + purpose = (struct GNUNET_PseudonymSignaturePurpose *) data; + purpose->size = htonl (sizeof (data)); + purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST); + memset (&seed, 41, sizeof (seed)); + memset (&signing_key, 40, sizeof (signing_key)); + test_signature (ph, purpose, &seed, &signing_key, &data[sizeof (struct GNUNET_PseudonymSignaturePurpose)]); + test_signature (ph, purpose, NULL, &signing_key, &data[sizeof (struct GNUNET_PseudonymSignaturePurpose)]); +} + + +/** + * Test cryptographic operations. + */ +static int +test_crypto () +{ + struct GNUNET_PseudonymHandle *ph; + struct GNUNET_PseudonymIdentifier pseudonym; + struct GNUNET_PseudonymIdentifier pseudonym2; + + /* check writing to and reading from disk */ + ph = GNUNET_PSEUDONYM_create ("/tmp/gnunet-pseudonym-test/pseu.dsa"); + GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym); + GNUNET_PSEUDONYM_destroy (ph); + ph = GNUNET_PSEUDONYM_create ("/tmp/gnunet-pseudonym-test/pseu.dsa"); + GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym2); + test_crypto_ops (ph); + GNUNET_PSEUDONYM_destroy (ph); + if (0 != memcmp (&pseudonym, &pseudonym2, sizeof (pseudonym))) + return 1; + + /* check in-memory generation */ + ph = GNUNET_PSEUDONYM_create (NULL); + GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym2); + if (0 == memcmp (&pseudonym, &pseudonym2, sizeof (pseudonym))) + return 1; + test_crypto_ops (ph); + GNUNET_PSEUDONYM_destroy (ph); + + /* check anonymous pseudonym operations generation */ + ph = GNUNET_PSEUDONYM_get_anonymous_pseudonym_handle (); + GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym2); + if (0 == memcmp (&pseudonym, &pseudonym2, sizeof (pseudonym))) + return 1; + test_crypto_ops (ph); + GNUNET_PSEUDONYM_destroy (ph); + return 0; +} + + +int +main (int argc, char *argv[]) +{ + if (0 != test_io ()) + return 1; + if (0 != test_crypto ()) + return 1; + GNUNET_break (GNUNET_OK == + GNUNET_DISK_directory_remove ("/tmp/gnunet-pseudonym-test")); + return 0; +} + + +/* end of test_pseudoynm.c */ diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 0d7a52d39..e27fc7027 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -67,7 +67,6 @@ gnunetinclude_HEADERS = \ gnunet_postgres_lib.h \ gnunet_program_lib.h \ gnunet_protocols.h \ - gnunet_pseudonym_lib.h \ gnunet_resolver_service.h \ gnunet_regex_lib.h \ gnunet_scheduler_lib.h \ diff --git a/src/include/block_fs.h b/src/include/block_fs.h index 6f37dcf0e..233d8035e 100644 --- a/src/include/block_fs.h +++ b/src/include/block_fs.h @@ -27,6 +27,7 @@ #define BLOCK_FS_H #include "gnunet_util_lib.h" +#include "gnunet_fs_service.h" /** diff --git a/src/include/gnunet_fs_service.h b/src/include/gnunet_fs_service.h index 931406e2d..6143f0630 100644 --- a/src/include/gnunet_fs_service.h +++ b/src/include/gnunet_fs_service.h @@ -79,6 +79,78 @@ extern "C" */ struct GNUNET_FS_Uri; + +/** + * Identifier for a GNUnet pseudonym (the public key). + * Q-point, Q=dp. + */ +struct GNUNET_PseudonymIdentifier +{ + /** + * Q consists of an x- and a y-value, each mod p (256 bits), + * given here in affine coordinates. + */ + unsigned char q_x[256 / 8]; + + /** + * Q consists of an x- and a y-value, each mod p (256 bits), + * given here in affine coordinates. + */ + unsigned char q_y[256 / 8]; + +}; + + +/** + * Handle for a pseudonym (private key). + */ +struct GNUNET_PseudonymHandle; + + +/** + * Signature made with a pseudonym (includes the full public key). + * The ECDSA signature is a pair (r,s) with r = x1 mod n where + * (x1,y1) = kG for "random" k and s = k^{-1}(z + rd) mod n, + * where z is derived from the hash of the message that is being + * signed. + */ +struct GNUNET_PseudonymSignature +{ + + /** + * Who created the signature? (public key of the signer), 'd' value in NIST P-256. + */ + struct GNUNET_PseudonymIdentifier signer; + + /** + * Binary ECDSA signature data, r-value. Value is mod n, and n is 256 bits. + */ + unsigned char sig_r[256 / 8]; + + /** + * Binary ECDSA signature data, s-value. Value is mod n, and n is 256 bits. + */ + unsigned char sig_s[256 / 8]; +}; + + +/** + * 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; +}; + + /** * Iterator over keywords * @@ -90,6 +162,303 @@ struct GNUNET_FS_Uri; typedef int (*GNUNET_FS_KeywordIterator) (void *cls, const char *keyword, int is_mandatory); + + + +/** + * 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 + * @return GNUNET_SYSERR on failure + */ +int +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 in DSA, dQ in ECDSA) + * @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. + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +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. + * + * @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 + */ +typedef int (*GNUNET_PSEUDONYM_Iterator) (void *cls, + const struct GNUNET_PseudonymIdentifier *pseudonym, + const char *name, + const char *unique_name, + const struct GNUNET_CONTAINER_MetaData *md, + int32_t rating); + + +/** + * Change the rank of a pseudonym. + * + * @param cfg overall configuration + * @param pseudonym identity of 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_PseudonymIdentifier *pseudonym, + int32_t delta); + + +/** + * Add a pseudonym to the set of known pseudonyms. + * For all pseudonym advertisements that we discover + * FS should automatically call this function. + * + * @param cfg overall configuration + * @param pseudonym the pseudonym identifier + * @param meta metadata for the pseudonym + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PseudonymIdentifier *pseudonym, + const struct GNUNET_CONTAINER_MetaData *meta); + + +/** + * List all known pseudonyms. + * + * @param cfg overall configuration + * @param iterator function to call for each pseudonym + * @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 *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 + */ +struct GNUNET_PSEUDONYM_DiscoveryHandle * +GNUNET_PSEUDONYM_discovery_callback_register (const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_PSEUDONYM_Iterator iterator, + void *iterator_cls); + + +/** + * Unregister pseudonym discovery callback. + * + * @param dh registration to unregister + */ +void +GNUNET_PSEUDONYM_discovery_callback_unregister (struct GNUNET_PSEUDONYM_DiscoveryHandle *dh); + + +/** + * 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 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. + * Free the name with GNUNET_free(). + */ +char * +GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PseudonymIdentifier *pseudonym, + const char *name, + unsigned int *suffix); + + +/** + * 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 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. + * @param ret_name a location to store human-readable name. Name is not unique. + * NULL, if name is not needed. Free with GNUNET_free(). + * @param name_is_a_dup is set to GNUNET_YES, if ret_name was filled with + * a duplicate of a "no-name" placeholder + * @return GNUNET_OK on success. GNUENT_SYSERR if the data was + * unobtainable (in that case ret_* are filled with placeholders - + * empty metadata container, rank -1 and a "no-name" name). + */ +int +GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg, + 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 pseudonym ID belonging to the given pseudonym name. + * + * @param cfg configuration to use + * @param ns_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_PseudonymIdentifier *pseudonym); + + +/** + * Set the pseudonym metadata, rank and name. + * + * @param cfg overall configuration + * @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 + * 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); + + +/** + * Remove pseudonym from the set of known pseudonyms. + * + * @param cfg overall configuration + * @param id the pseudonym identifier + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_PSEUDONYM_remove (const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_PseudonymIdentifier *id); + + /** * Get a unique key from a URI. This is for putting URIs * into HashMaps. The key may change between FS implementations. @@ -100,6 +469,7 @@ typedef int (*GNUNET_FS_KeywordIterator) (void *cls, const char *keyword, void GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri, struct GNUNET_HashCode * key); + /** * Convert a URI to a UTF-8 String. * @@ -109,6 +479,7 @@ GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri, struct GNUNET_HashCode * char * GNUNET_FS_uri_to_string (const struct GNUNET_FS_Uri *uri); + /** * Convert keyword URI to a human readable format * (i.e. the search query that was used in the first place) diff --git a/src/include/gnunet_pseudonym_lib.h b/src/include/gnunet_pseudonym_lib.h deleted file mode 100644 index e0b36887b..000000000 --- a/src/include/gnunet_pseudonym_lib.h +++ /dev/null @@ -1,418 +0,0 @@ -/* - This file is part of GNUnet. - (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 - by the Free Software Foundation; either version 2, 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 include/gnunet_pseudonym_lib.h - * @brief functions related to pseudonyms - * @author Christian Grothoff - */ - -#ifndef GNUNET_PSEUDONYM_LIB_H -#define GNUNET_PSEUDONYM_LIB_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "gnunet_common.h" -#include "gnunet_configuration_lib.h" -#include "gnunet_container_lib.h" - - -/** - * Identifier for a GNUnet pseudonym (the public key). - * Q-point, Q=dp. - */ -struct GNUNET_PseudonymIdentifier -{ - /** - * Q consists of an x- and a y-value, each mod p (256 bits), - * given here in affine coordinates. - */ - unsigned char q_x[256 / 8]; - - /** - * Q consists of an x- and a y-value, each mod p (256 bits), - * given here in affine coordinates. - */ - unsigned char q_y[256 / 8]; - -}; - - -/** - * Handle for a pseudonym (private key). - */ -struct GNUNET_PseudonymHandle; - - -/** - * Signature made with a pseudonym (includes the full public key). - * The ECDSA signature is a pair (r,s) with r = x1 mod n where - * (x1,y1) = kG for "random" k and s = k^{-1}(z + rd) mod n, - * where z is derived from the hash of the message that is being - * signed. - */ -struct GNUNET_PseudonymSignature -{ - - /** - * Who created the signature? (public key of the signer), 'd' value in NIST P-256. - */ - struct GNUNET_PseudonymIdentifier signer; - - /** - * Binary ECDSA signature data, r-value. Value is mod n, and n is 256 bits. - */ - unsigned char sig_r[256 / 8]; - - /** - * Binary ECDSA signature data, s-value. Value is mod n, and n is 256 bits. - */ - unsigned char sig_s[256 / 8]; -}; - - -/** - * 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 - * @return GNUNET_SYSERR on failure - */ -int -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 in DSA, dQ in ECDSA) - * @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. - * @return GNUNET_OK on success, GNUNET_SYSERR on error - */ -int -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. - * - * @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 - */ -typedef int (*GNUNET_PSEUDONYM_Iterator) (void *cls, - const struct GNUNET_PseudonymIdentifier *pseudonym, - const char *name, - const char *unique_name, - const struct GNUNET_CONTAINER_MetaData *md, - int32_t rating); - - -/** - * Change the rank of a pseudonym. - * - * @param cfg overall configuration - * @param pseudonym identity of 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_PseudonymIdentifier *pseudonym, - int32_t delta); - - -/** - * Add a pseudonym to the set of known pseudonyms. - * For all pseudonym advertisements that we discover - * FS should automatically call this function. - * - * @param cfg overall configuration - * @param pseudonym the pseudonym identifier - * @param meta metadata for the pseudonym - * @return GNUNET_OK on success, GNUNET_SYSERR on failure - */ -int -GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_PseudonymIdentifier *pseudonym, - const struct GNUNET_CONTAINER_MetaData *meta); - - -/** - * List all known pseudonyms. - * - * @param cfg overall configuration - * @param iterator function to call for each pseudonym - * @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 *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 - */ -struct GNUNET_PSEUDONYM_DiscoveryHandle * -GNUNET_PSEUDONYM_discovery_callback_register (const struct GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_PSEUDONYM_Iterator iterator, - void *iterator_cls); - - -/** - * Unregister pseudonym discovery callback. - * - * @param dh registration to unregister - */ -void -GNUNET_PSEUDONYM_discovery_callback_unregister (struct GNUNET_PSEUDONYM_DiscoveryHandle *dh); - - -/** - * 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 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. - * Free the name with GNUNET_free(). - */ -char * -GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_PseudonymIdentifier *pseudonym, - const char *name, - unsigned int *suffix); - - -/** - * 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 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. - * @param ret_name a location to store human-readable name. Name is not unique. - * NULL, if name is not needed. Free with GNUNET_free(). - * @param name_is_a_dup is set to GNUNET_YES, if ret_name was filled with - * a duplicate of a "no-name" placeholder - * @return GNUNET_OK on success. GNUENT_SYSERR if the data was - * unobtainable (in that case ret_* are filled with placeholders - - * empty metadata container, rank -1 and a "no-name" name). - */ -int -GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg, - 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 pseudonym ID belonging to the given pseudonym name. - * - * @param cfg configuration to use - * @param ns_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_PseudonymIdentifier *pseudonym); - - -/** - * Set the pseudonym metadata, rank and name. - * - * @param cfg overall configuration - * @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 - * 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); - - -/** - * Remove pseudonym from the set of known pseudonyms. - * - * @param cfg overall configuration - * @param id the pseudonym identifier - * @return GNUNET_OK on success, GNUNET_SYSERR on failure - */ -int -GNUNET_PSEUDONYM_remove (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_PseudonymIdentifier *id); - - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_PSEUDONYM_LIB_H */ -#endif -/* end of gnunet_pseudonym_lib.h */ diff --git a/src/include/gnunet_util_lib.h b/src/include/gnunet_util_lib.h index 5f01cded8..30ec7cd3f 100644 --- a/src/include/gnunet_util_lib.h +++ b/src/include/gnunet_util_lib.h @@ -53,7 +53,6 @@ extern "C" #include "gnunet_plugin_lib.h" #include "gnunet_program_lib.h" #include "gnunet_protocols.h" -#include "gnunet_pseudonym_lib.h" #include "gnunet_scheduler_lib.h" #include "gnunet_server_lib.h" #include "gnunet_service_lib.h" diff --git a/src/util/Makefile.am b/src/util/Makefile.am index ef9ec7281..42d91c0ba 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -96,7 +96,6 @@ libgnunetutil_la_SOURCES = \ peer.c \ plugin.c \ program.c \ - pseudonym.c \ resolver_api.c resolver.h \ scheduler.c \ server.c \ @@ -234,7 +233,6 @@ check_PROGRAMS = \ test_peer \ test_plugin \ test_program \ - test_pseudonym \ test_resolver_api \ test_scheduler \ test_scheduler_delay \ @@ -436,11 +434,6 @@ test_program_SOURCES = \ test_program_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la -test_pseudonym_SOURCES = \ - test_pseudonym.c -test_pseudonym_LDADD = \ - $(top_builddir)/src/util/libgnunetutil.la - test_resolver_api_SOURCES = \ test_resolver_api.c test_resolver_api_LDADD = \ diff --git a/src/util/pseudonym.c b/src/util/pseudonym.c deleted file mode 100644 index 497f6ad6f..000000000 --- a/src/util/pseudonym.c +++ /dev/null @@ -1,1526 +0,0 @@ -/* - This file is part of GNUnet - (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 - by the Free Software Foundation; either version 2, 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 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__) - -#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) - -#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) - -/** - * Log an error message at log-level 'level' that indicates - * a failure of the command 'cmd' with the message given - * by gcry_strerror(rc). - */ -#define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0); - -/** - * Name of the directory which stores meta data for pseudonym - */ -#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 "pseudonym" DIR_SEPARATOR_STR "names" DIR_SEPARATOR_STR - - -/** - * Configuration section we use. - */ -#define GNUNET_CLIENT_SERVICE_NAME "client" - - -/* ************************* Disk operations (pseudonym data mgmt) **************** */ - -/** - * Registered callbacks for discovery of pseudonyms. - */ -struct GNUNET_PSEUDONYM_DiscoveryHandle -{ - /** - * This is a doubly linked list. - */ - 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. - */ - GNUNET_PSEUDONYM_Iterator callback; - - /** - * Closure for callback. - */ - void *callback_cls; -}; - - -/** - * Head of the linked list of functions to call when - * new pseudonyms are added. - */ -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 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_PseudonymIdentifier *pseudonym, - const struct GNUNET_CONTAINER_MetaData *md, int rating) -{ - struct GNUNET_PSEUDONYM_DiscoveryHandle *pos; - - 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. - * Will immediately call provided iterator callback for all - * already discovered pseudonyms. - * - * @param cfg configuration to use - * @param iterator iterator over pseudonym - * @param iterator_cls point to a closure - * @return registration handle - */ -struct GNUNET_PSEUDONYM_DiscoveryHandle * -GNUNET_PSEUDONYM_discovery_callback_register (const struct - GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_PSEUDONYM_Iterator iterator, - void *iterator_cls) -{ - 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 dh registration to unregister - */ -void -GNUNET_PSEUDONYM_discovery_callback_unregister (struct GNUNET_PSEUDONYM_DiscoveryHandle *dh) -{ - 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 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_PseudonymIdentifier *pseudonym) -{ - struct GNUNET_CRYPTO_HashAsciiEncoded enc; - struct GNUNET_HashCode psid; - - 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); -} - - -/** - * Get the filename (or directory name) for the given - * hash code and directory prefix. - * - * @param cfg configuration to use - * @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 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 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 - * 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, pseudonym); - if (NULL == (fileW = GNUNET_BIO_write_open (fn))) - { - 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 (NULL != name) - GNUNET_free_non_null (GNUNET_PSEUDONYM_name_uniquify (cfg, pseudonym, - name, NULL)); - return GNUNET_OK; -} - - -/** - * Read pseudonym infomation from a file - * - * @param cfg configuration to use - * @param pseudonym hash code of a pseudonym - * @param meta meta data to be read from a file - * @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_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, pseudonym); - if (GNUNET_YES != - GNUNET_DISK_file_test (fn)) - { - GNUNET_free (fn); - return GNUNET_SYSERR; - } - 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 (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); - GNUNET_free_non_null (*ns_name); - *ns_name = NULL; - GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); - GNUNET_free (fn); - return GNUNET_SYSERR; - } - 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"), fn, - emsg); - GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn)); - GNUNET_CONTAINER_meta_data_destroy (*meta); - *meta = NULL; - GNUNET_free_non_null (*ns_name); - *ns_name = NULL; - GNUNET_free_non_null (emsg); - GNUNET_free (fn); - return GNUNET_SYSERR; - } - GNUNET_free (fn); - return GNUNET_OK; -} - - -/** - * 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 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. - * Free the name with GNUNET_free(). - */ -char * -GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, - 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; - unsigned int i; - unsigned int idx; - char *ret; - struct stat sbuf; - - GNUNET_CRYPTO_hash (name, strlen (name), &nh); - 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)); - fh = GNUNET_DISK_file_open (fn, - GNUNET_DISK_OPEN_CREATE | - GNUNET_DISK_OPEN_READWRITE, - GNUNET_DISK_PERM_USER_READ | - GNUNET_DISK_PERM_USER_WRITE); - i = 0; - idx = -1; - while ((len >= sizeof (struct GNUNET_PseudonymIdentifier)) && - (sizeof (struct GNUNET_PseudonymIdentifier) == - GNUNET_DISK_file_read (fh, &pi, sizeof (struct GNUNET_PseudonymIdentifier)))) - { - if (0 == memcmp (&pi, pseudonym, sizeof (struct GNUNET_PseudonymIdentifier))) - { - idx = i; - break; - } - i++; - len -= sizeof (struct GNUNET_HashCode); - } - if (-1 == idx) - { - idx = i; - 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); - ret = GNUNET_malloc (strlen (name) + 32); - GNUNET_snprintf (ret, strlen (name) + 32, "%s-%u", name, idx); - if (suffix != NULL) - *suffix = idx; - GNUNET_free (fn); - 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 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. - * @param ret_name a location to store human-readable name. Name is not unique. - * NULL, if name is not needed. Free with GNUNET_free(). - * @param name_is_a_dup is set to GNUNET_YES, if ret_name was filled with - * a duplicate of a "no-name" placeholder - * @return GNUNET_OK on success. GNUENT_SYSERR if the data was - * unobtainable (in that case ret_* are filled with placeholders - - * empty metadata container, rank -1 and a "no-name" name). - */ -int -GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg, - 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; - int32_t rank = -1; - - meta = NULL; - name = NULL; - if (GNUNET_OK == read_info (cfg, pseudonym, &meta, &rank, &name)) - { - if ((meta != NULL) && (name == NULL)) - name = - GNUNET_CONTAINER_meta_data_get_first_by_types (meta, - EXTRACTOR_METATYPE_TITLE, - EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, - EXTRACTOR_METATYPE_FILENAME, - EXTRACTOR_METATYPE_DESCRIPTION, - EXTRACTOR_METATYPE_SUBJECT, - EXTRACTOR_METATYPE_PUBLISHER, - EXTRACTOR_METATYPE_AUTHOR_NAME, - EXTRACTOR_METATYPE_COMMENT, - EXTRACTOR_METATYPE_SUMMARY, - -1); - if (ret_name != NULL) - { - if (name == NULL) - { - name = GNUNET_strdup (_("no-name")); - if (name_is_a_dup != NULL) - *name_is_a_dup = GNUNET_YES; - } - else if (name_is_a_dup != NULL) - *name_is_a_dup = GNUNET_NO; - *ret_name = name; - } - else if (name != NULL) - GNUNET_free (name); - - if (ret_meta != NULL) - { - if (meta == NULL) - meta = GNUNET_CONTAINER_meta_data_create (); - *ret_meta = meta; - } - else if (meta != NULL) - GNUNET_CONTAINER_meta_data_destroy (meta); - - if (ret_rank != NULL) - *ret_rank = rank; - - return GNUNET_OK; - } - if (ret_name != NULL) - *ret_name = GNUNET_strdup (_("no-name")); - if (ret_meta != NULL) - *ret_meta = GNUNET_CONTAINER_meta_data_create (); - if (ret_rank != NULL) - *ret_rank = -1; - if (name_is_a_dup != NULL) - *name_is_a_dup = GNUNET_YES; - 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 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_PseudonymIdentifier *pseudonym) -{ - size_t slen; - uint64_t len; - unsigned int idx; - char *name; - struct GNUNET_HashCode nh; - char *fn; - struct GNUNET_DISK_FileHandle *fh; - - idx = -1; - slen = strlen (ns_uname); - while ((slen > 0) && (1 != SSCANF (&ns_uname[slen - 1], "-%u", &idx))) - slen--; - 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_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_PseudonymIdentifier) > len)) - { - GNUNET_free (fn); - return GNUNET_SYSERR; - } - fh = GNUNET_DISK_file_open (fn, - GNUNET_DISK_OPEN_CREATE | - GNUNET_DISK_OPEN_READWRITE, - GNUNET_DISK_PERM_USER_READ | - GNUNET_DISK_PERM_USER_WRITE); - GNUNET_free (fn); - if (GNUNET_SYSERR == - 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_PseudonymIdentifier) != - GNUNET_DISK_file_read (fh, pseudonym, sizeof (struct GNUNET_PseudonymIdentifier))) - { - GNUNET_DISK_file_close (fh); - return GNUNET_SYSERR; - } - GNUNET_DISK_file_close (fh); - return GNUNET_OK; -} - - - -/** - * struct used to list the pseudonym - */ -struct ListPseudonymClosure -{ - - /** - * iterator over pseudonym - */ - GNUNET_PSEUDONYM_Iterator iterator; - - /** - * Closure for iterator. - */ - void *iterator_cls; - - /** - * Configuration to use. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; -}; - - - -/** - * 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 *lpc = cls; - struct GNUNET_PseudonymIdentifier pd; - char *emsg; - struct GNUNET_BIO_ReadHandle *fileR; - int32_t rank; - char *ns_name; - struct GNUNET_CONTAINER_MetaData *meta; - int ret; - char *name_unique; - - 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)) ) - { - (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); - GNUNET_free (ns_name); - GNUNET_free_non_null (emsg); - return GNUNET_SYSERR; - } - 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; -} - - -/** - * List all available pseudonyms. - * - * @param cfg overall configuration - * @param iterator function to call for each pseudonym - * @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 *iterator_cls) -{ - struct ListPseudonymClosure cls; - char *fn; - int ret; - - cls.iterator = iterator; - cls.iterator_cls = iterator_cls; - cls.cfg = cfg; - fn = get_data_filename (cfg, PS_METADATA_DIR, NULL); - GNUNET_assert (fn != NULL); - GNUNET_DISK_directory_create (fn); - ret = GNUNET_DISK_directory_scan (fn, &list_pseudonym_helper, &cls); - GNUNET_free (fn); - return ret; -} - - -/** - * Change the rank of a pseudonym. - * - * @param cfg overall configuration - * @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_PseudonymIdentifier *pseudonym, - int32_t delta) -{ - struct GNUNET_CONTAINER_MetaData *meta; - int ret; - int32_t rank; - char *name; - - name = NULL; - ret = read_info (cfg, pseudonym, &meta, &rank, &name); - if (ret == GNUNET_SYSERR) - { - rank = 0; - meta = GNUNET_CONTAINER_meta_data_create (); - } - rank += delta; - GNUNET_PSEUDONYM_set_info (cfg, pseudonym, name, meta, rank); - GNUNET_CONTAINER_meta_data_destroy (meta); - GNUNET_free_non_null (name); - return rank; -} - - -/** - * Add a pseudonym to the set of known pseudonyms. - * For all pseudonym advertisements that we discover - * FS should automatically call this function. - * - * @param cfg overall configuration - * @param pseudonym the pseudonym to add - * @param meta metadata for the pseudonym - * @return GNUNET_OK on success, GNUNET_SYSERR on failure - */ -int -GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_PseudonymIdentifier *pseudonym, - const struct GNUNET_CONTAINER_MetaData *meta) -{ - char *name; - int32_t rank; - struct GNUNET_CONTAINER_MetaData *old; - char *fn; - struct stat sbuf; - int ret; - - 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, pseudonym, &old, &rank, &name))) - { - GNUNET_CONTAINER_meta_data_merge (old, meta); - ret = GNUNET_PSEUDONYM_set_info (cfg, pseudonym, name, old, rank); - GNUNET_CONTAINER_meta_data_destroy (old); - GNUNET_free_non_null (name); - } - else - { - ret = GNUNET_PSEUDONYM_set_info (cfg, pseudonym, NULL, meta, rank); - } - GNUNET_free (fn); - internal_notify (pseudonym, meta, rank); - return ret; -} - - -/* ***************************** cryptographic operations ************************* */ - -/** - * Handle for a pseudonym (private key). - */ -struct GNUNET_PseudonymHandle -{ - /** - * 256-bit 'd' secret value (mod 'n', where n is 256-bit for NIST P-256). - */ - unsigned char d[256 / 8]; - - /** - * Public key corresponding to the private key. - */ - struct GNUNET_PseudonymIdentifier public_key; -}; - - -/** - * If target != size, move target bytes to the end of the size-sized - * buffer and zero out the first target-size bytes. - * - * @param buf original buffer - * @param size number of bytes in the buffer - * @param target target size of the buffer - */ -static void -adjust (unsigned char *buf, size_t size, size_t target) -{ - if (size < target) - { - memmove (&buf[target - size], buf, size); - memset (buf, 0, target - size); - } -} - - -/** - * Extract values from an S-expression. - * - * @param array where to store the result(s) - * @param sexp S-expression to parse - * @param topname top-level name in the S-expression that is of interest - * @param elems names of the elements to extract - * @return 0 on success - */ -static int -key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname, - const char *elems) -{ - gcry_sexp_t list; - gcry_sexp_t l2; - const char *s; - unsigned int i; - unsigned int idx; - - if (! (list = gcry_sexp_find_token (sexp, topname, 0))) - return 1; - l2 = gcry_sexp_cadr (list); - gcry_sexp_release (list); - list = l2; - if (! list) - return 2; - idx = 0; - for (s = elems; *s; s++, idx++) - { - if (! (l2 = gcry_sexp_find_token (list, s, 1))) - { - for (i = 0; i < idx; i++) - { - gcry_free (array[i]); - array[i] = NULL; - } - gcry_sexp_release (list); - return 3; /* required parameter not found */ - } - array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l2); - if (! array[idx]) - { - for (i = 0; i < idx; i++) - { - gcry_free (array[i]); - array[i] = NULL; - } - gcry_sexp_release (list); - return 4; /* required parameter is invalid */ - } - } - gcry_sexp_release (list); - return 0; -} - - -/** - * 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; - gcry_sexp_t r_key; - gcry_sexp_t params; - gcry_ctx_t ctx; - gcry_mpi_point_t q; - gcry_mpi_t q_x; - gcry_mpi_t q_y; - gcry_error_t rc; - gcry_mpi_t d; - size_t size; - - ph = GNUNET_malloc (sizeof (struct GNUNET_PseudonymHandle)); - if ( (NULL != filename) && - (GNUNET_YES == GNUNET_DISK_file_test (filename)) ) - { - ret = GNUNET_DISK_fn_read (filename, ph, - sizeof (struct GNUNET_PseudonymHandle)); - /* Note: we don't do any validation here, maybe we should? */ - if (sizeof (struct GNUNET_PseudonymHandle) == ret) - return ph; - } - if (0 != (rc = gcry_sexp_build (¶ms, NULL, - "(genkey(ecdsa(curve \"NIST P-256\")))"))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); - return NULL; - } - if (0 != (rc = gcry_pk_genkey (&r_key, params))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc); - gcry_sexp_release (r_key); - return NULL; - } - /* extract "d" (secret key) from r_key */ - rc = key_from_sexp (&d, r_key, "private-key", "d"); - if (0 != rc) - rc = key_from_sexp (&d, r_key, "private-key", "d"); - if (0 != rc) - rc = key_from_sexp (&d, r_key, "ecc", "d"); - if (0 != rc) - { - gcry_sexp_release (r_key); - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc); - return NULL; - } - size = sizeof (ph->d); - GNUNET_assert (0 == - gcry_mpi_print (GCRYMPI_FMT_USG, ph->d, size, &size, - d)); - gcry_mpi_release (d); - adjust (ph->d, size, sizeof (ph->d)); - - /* extract 'q' (public key) from r_key */ - if (0 != (rc = gcry_mpi_ec_new (&ctx, r_key, NULL))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ - gcry_sexp_release (r_key); - return NULL; - } - gcry_sexp_release (r_key); - q = gcry_mpi_ec_get_point ("q", ctx, 0); - q_x = gcry_mpi_new (256); - q_y = gcry_mpi_new (256); - gcry_mpi_ec_get_affine (q_x, q_y, q, ctx); - gcry_mpi_point_release (q); - - /* store q_x/q_y in public key */ - size = sizeof (ph->public_key.q_x); - if (0 != - gcry_mpi_print (GCRYMPI_FMT_USG, ph->public_key.q_x, size, &size, - q_x)) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc); - gcry_mpi_release (q_x); - gcry_mpi_release (q_y); - return NULL; - - } - adjust (ph->public_key.q_x, size, sizeof (ph->public_key.q_x)); - gcry_mpi_release (q_x); - - size = sizeof (ph->public_key.q_y); - if (0 != - gcry_mpi_print (GCRYMPI_FMT_USG, ph->public_key.q_y, size, &size, - q_y)) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc); - gcry_mpi_release (q_y); - return NULL; - } - adjust (ph->public_key.q_y, size, sizeof (ph->public_key.q_y)); - gcry_mpi_release (q_y); - - /* write to disk */ - 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) - { - GNUNET_free (ph); - return NULL; - } - /* Note: we don't do any validation here; maybe we should? */ - return ph; -} - - -/** - * 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)); - /* Note if we use 'd=0' for the anonymous handle (as per#2564), - then I believe the public key should be also zero, as Q=0P=0; - so setting everything to all-zeros (as per GNUNET_malloc) - should be all that is needed here). - */ - 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); -} - - -/** - * Convert the data specified in the given purpose argument to an - * S-expression suitable for signature operations. - * - * @param purpose data to convert - * @return converted s-expression - */ -static gcry_sexp_t -data_to_pkcs1 (const struct GNUNET_PseudonymSignaturePurpose *purpose) -{ - struct GNUNET_CRYPTO_ShortHashCode hc; - size_t bufSize; - gcry_sexp_t data; - - GNUNET_CRYPTO_short_hash (purpose, ntohl (purpose->size), &hc); -#define FORMATSTRING "(4:data(5:flags3:raw)(5:value32:01234567890123456789012345678901))" - bufSize = strlen (FORMATSTRING) + 1; - { - char buff[bufSize]; - - memcpy (buff, FORMATSTRING, bufSize); - memcpy (&buff - [bufSize - - strlen - ("01234567890123456789012345678901))") - - 1], &hc, sizeof (struct GNUNET_CRYPTO_ShortHashCode)); - GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0)); - } -#undef FORMATSTRING - return data; -} - - -/** - * 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 - * @return GNUNET_SYSERR on failure - */ -int -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) -{ - size_t size; - size_t erroff; - gcry_mpi_t x; - gcry_mpi_t k; - gcry_mpi_t h; - gcry_mpi_t d; - gcry_mpi_t n; /* n from P-256 */ - gcry_sexp_t spriv; - gcry_sexp_t data; - gcry_sexp_t result; - gcry_mpi_t rs[2]; - int rc; - - /* get private key 'x' from pseudonym */ - size = sizeof (ph->d); - if (0 != (rc = gcry_mpi_scan (&x, GCRYMPI_FMT_USG, - &ph->d, - size, &size))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - return GNUNET_SYSERR; - } - /* get 'h' value from signing key */ - size = sizeof (struct GNUNET_HashCode); - if (0 != (rc = gcry_mpi_scan (&h, GCRYMPI_FMT_USG, - signing_key, - size, &size))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - gcry_mpi_release (x); - return GNUNET_SYSERR; - } - - /* initialize 'n' from P-256; hex copied from libgcrypt code */ - if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX, - "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 0, NULL))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - gcry_mpi_release (x); - gcry_mpi_release (h); - return GNUNET_SYSERR; - } - - /* calculate d = x + h mod n */ - d = gcry_mpi_new (256); - gcry_mpi_addm (d, x, h, n); - gcry_mpi_release (x); - gcry_mpi_release (h); - gcry_mpi_release (n); - - /* now build sexpression with the signing key */ - if (0 != (rc = gcry_sexp_build (&spriv, &erroff, - "(private-key(ecdsa(curve \"NIST P-256\")(d %m)))", - d))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); - gcry_mpi_release (d); - return GNUNET_SYSERR; - } - gcry_mpi_release (d); - /* prepare data for signing */ - data = data_to_pkcs1 (purpose); - - /* get 'k' value from seed, if available */ - if (NULL != seed) - { - size = sizeof (struct GNUNET_HashCode); - if (0 != (rc = gcry_mpi_scan (&k, GCRYMPI_FMT_USG, - seed, - size, &size))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - gcry_mpi_release (x); - return GNUNET_SYSERR; - } - } - - /* actually create signature */ - /* FIXME: need API to pass 'k' if 'seed' was non-NULL! */ - if (0 != (rc = gcry_pk_sign (&result, data, spriv))) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - _("ECC signing failed at %s:%d: %s\n"), __FILE__, - __LINE__, gcry_strerror (rc)); - gcry_sexp_release (data); - gcry_sexp_release (spriv); - if (NULL != seed) - gcry_mpi_release (k); - memset (signature, 0, sizeof (struct GNUNET_PseudonymSignature)); - return GNUNET_SYSERR; - } - if (NULL != seed) - gcry_mpi_release (k); - gcry_sexp_release (data); - gcry_sexp_release (spriv); - - - /* extract 'r' and 's' values from sexpression 'result' and store in 'signature' */ - if (0 != (rc = key_from_sexp (rs, result, "sig-val", "rs"))) - { - GNUNET_break (0); - gcry_sexp_release (result); - return GNUNET_SYSERR; - } - gcry_sexp_release (result); - size = sizeof (signature->sig_r); - if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, signature->sig_r, size, - &size, rs[0]))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc); - gcry_mpi_release (rs[0]); - gcry_mpi_release (rs[1]); - return GNUNET_SYSERR; - } - gcry_mpi_release (rs[0]); - size = sizeof (signature->sig_s); - if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, signature->sig_s, size, - &size, rs[1]))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc); - gcry_mpi_release (rs[1]); - return GNUNET_SYSERR; - } - gcry_mpi_release (rs[1]); - return GNUNET_OK; -} - - -/** - * Get an ECC context (with Q set to the respective public key) from - * a pseudonym. - * - * @param pseudonym with information on 'q' - * @return curve context - */ -static gcry_ctx_t -get_context_from_pseudonym (struct GNUNET_PseudonymIdentifier *pseudonym) -{ - gcry_ctx_t ctx; - gcry_mpi_t ONE; - gcry_mpi_t q_x; - gcry_mpi_t q_y; - gcry_mpi_point_t q; - size_t size; - int rc; - - /* extract 'q' from pseudonym */ - size = sizeof (pseudonym->q_x); - if (0 != (rc = gcry_mpi_scan (&q_x, GCRYMPI_FMT_USG, pseudonym->q_x, size, &size))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - return NULL; - } - size = sizeof (pseudonym->q_y); - if (0 != (rc = gcry_mpi_scan (&q_y, GCRYMPI_FMT_USG, pseudonym->q_y, size, &size))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - gcry_mpi_release (q_x); - return NULL; - } - q = gcry_mpi_point_new (256); - ONE = gcry_mpi_new (1); - gcry_mpi_set_ui (ONE, 1); - gcry_mpi_point_set (q, q_x, q_y, ONE); /* FIXME: convenience function 'set_affine'? */ - gcry_mpi_release (ONE); - gcry_mpi_release (q_x); - gcry_mpi_release (q_y); - - /* create basic ECC context */ - if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256"))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ - gcry_mpi_point_release (q); - return NULL; - } - /* initialize 'ctx' with 'q' */ - gcry_mpi_ec_set_point ("q", q, ctx); - gcry_mpi_point_release (q); - return ctx; -} - - -/** - * 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 in DSA, dQ in ECDSA) - * @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. - * @return GNUNET_OK on success, GNUNET_SYSERR on error - */ -int -GNUNET_PSEUDONYM_derive_verification_key (struct GNUNET_PseudonymIdentifier *pseudonym, - const struct GNUNET_HashCode *signing_key, - struct GNUNET_PseudonymIdentifier *verification_key) -{ - gcry_mpi_t h; - size_t size; - int rc; - gcry_ctx_t ctx; - gcry_mpi_point_t g; - gcry_mpi_point_t q; - gcry_mpi_point_t hg; - gcry_mpi_point_t v; - gcry_mpi_t v_x; - gcry_mpi_t v_y; - - /* get 'h' value from signing key */ - size = sizeof (struct GNUNET_HashCode); - if (0 != (rc = gcry_mpi_scan (&h, GCRYMPI_FMT_USG, - signing_key, - size, &size))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - return GNUNET_SYSERR; - } - /* create ECC context based on Q from pseudonym */ - if (NULL == (ctx = get_context_from_pseudonym (pseudonym))) - { - gcry_mpi_release (h); - return GNUNET_SYSERR; - } - /* get G */ - g = gcry_mpi_ec_get_point ("g", ctx, 0); - - /* then call the 'multiply' function, to compute the product hG */ - hg = gcry_mpi_point_new (0); - gcry_mpi_ec_mul (hg, h, g, ctx); - gcry_mpi_release (h); - - /* get Q = dG from 'pseudonym' */ - q = gcry_mpi_ec_get_point ("q", ctx, 0); - - /* calculate V = q + hG = dG + hG */ - v = gcry_mpi_point_new (0); - gcry_mpi_ec_add (v, q, hg, ctx); - - /* store 'v' point in "verification_key" */ - v_x = gcry_mpi_new (256); - v_y = gcry_mpi_new (256); - gcry_mpi_ec_get_affine (v_x, v_y, v, ctx); - gcry_mpi_point_release (v); - gcry_ctx_release (ctx); - - size = sizeof (verification_key->q_x); - if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, verification_key->q_x, size, - &size, v_x))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc); - gcry_mpi_release (v_x); - gcry_mpi_release (v_y); - return GNUNET_SYSERR; - } - gcry_mpi_release (v_x); - size = sizeof (verification_key->q_y); - if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, verification_key->q_y, size, - &size, v_y))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc); - gcry_mpi_release (v_y); - return GNUNET_SYSERR; - } - gcry_mpi_release (v_y); - return GNUNET_OK; -} - - -/** - * 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) -{ - gcry_sexp_t data; - gcry_sexp_t sig_sexpr; - gcry_sexp_t pk_sexpr; - size_t size; - gcry_ctx_t ctx; - gcry_mpi_t ONE; - gcry_mpi_t r; - gcry_mpi_t s; - gcry_mpi_point_t q; - gcry_mpi_t q_x; - gcry_mpi_t q_y; - size_t erroff; - int rc; - - /* build s-expression for signature */ - size = sizeof (signature->sig_r); - if (0 != (rc = gcry_mpi_scan (&r, GCRYMPI_FMT_USG, - signature->sig_r, size, &size))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - return GNUNET_SYSERR; - } - size = sizeof (signature->sig_s); - if (0 != (rc = gcry_mpi_scan (&s, GCRYMPI_FMT_USG, - signature->sig_s, size, &size))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - gcry_mpi_release (r); - return GNUNET_SYSERR; - } - if (0 != (rc = gcry_sexp_build (&sig_sexpr, &erroff, "(sig-val(ecdsa(r %m)(s %m)))", - r, s))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); - gcry_mpi_release (r); - gcry_mpi_release (s); - return GNUNET_SYSERR; - } - gcry_mpi_release (r); - gcry_mpi_release (s); - - /* build s-expression for data that was signed */ - data = data_to_pkcs1 (purpose); - - /* create context of public key and initialize Q */ - size = sizeof (verification_key->q_x); - if (0 != (rc = gcry_mpi_scan (&q_x, GCRYMPI_FMT_USG, - verification_key->q_x, size, &size))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - gcry_sexp_release (data); - gcry_sexp_release (sig_sexpr); - return GNUNET_SYSERR; - } - size = sizeof (verification_key->q_y); - if (0 != (rc = gcry_mpi_scan (&q_y, GCRYMPI_FMT_USG, - verification_key->q_y, size, &size))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); - gcry_sexp_release (data); - gcry_sexp_release (sig_sexpr); - gcry_mpi_release (q_x); - return GNUNET_SYSERR; - } - q = gcry_mpi_point_new (256); - ONE = gcry_mpi_new (1); - gcry_mpi_set_ui (ONE, 1); - gcry_mpi_point_set (q, q_x, q_y, ONE); /* FIXME: convenience function 'set_affine'? */ - gcry_mpi_release (ONE); - gcry_mpi_release (q_x); - gcry_mpi_release (q_y); - - /* create basic ECC context */ - if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256"))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ - gcry_sexp_release (data); - gcry_sexp_release (sig_sexpr); - gcry_mpi_point_release (q); - return GNUNET_SYSERR; - } - /* initialize 'ctx' with 'q' */ - gcry_mpi_ec_set_point ("q", q, ctx); - gcry_mpi_point_release (q); - - /* convert 'ctx' to 'sexp' */ - if (0 != (rc = gcry_pubkey_get_sexp (&pk_sexpr, GCRY_PK_GET_PUBKEY, ctx))) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_from_context", rc); - gcry_ctx_release (ctx); - gcry_sexp_release (data); - gcry_sexp_release (sig_sexpr); - return GNUNET_SYSERR; - } - gcry_ctx_release (ctx); - - /* finally, verify the signature */ - rc = gcry_pk_verify (sig_sexpr, data, pk_sexpr); - gcry_sexp_release (sig_sexpr); - gcry_sexp_release (data); - gcry_sexp_release (pk_sexpr); - if (rc) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__, - __LINE__, gcry_strerror (rc)); - return GNUNET_SYSERR; - } - 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) -{ - memcpy (pseudonym, &ph->public_key, - sizeof (struct GNUNET_PseudonymIdentifier)); -} - - -/** - * Remove pseudonym from the set of known pseudonyms. - * - * @param cfg overall configuration - * @param id the pseudonym identifier - * @return GNUNET_OK on success, GNUNET_SYSERR on failure - */ -int -GNUNET_PSEUDONYM_remove (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_PseudonymIdentifier *id) -{ - char *fn; - int result; - - fn = get_data_filename (cfg, PS_METADATA_DIR, id); - if (NULL == fn) - return GNUNET_SYSERR; - result = UNLINK (fn); - GNUNET_free (fn); - return (0 == result) ? GNUNET_OK : GNUNET_SYSERR; -} - -/* end of pseudonym.c */ diff --git a/src/util/test_pseudonym.c b/src/util/test_pseudonym.c deleted file mode 100644 index a3b3f3fdb..000000000 --- a/src/util/test_pseudonym.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - This file is part of GNUnet. - (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 - 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 util/test_pseudonym.c - * @brief testcase for pseudonym.c - * @author Christian Grothoff - */ -#include "platform.h" -#include "gnunet_common.h" -#include "gnunet_util_lib.h" -#include "gnunet_signatures.h" - -#define CHECK(a) do { if (!(a)) { ok = GNUNET_NO; GNUNET_break(0); goto FAILURE; } } while (0) - -static struct GNUNET_CONTAINER_MetaData *meta; - -static struct GNUNET_PseudonymIdentifier id1; - - -static int -iter (void *cls, const struct GNUNET_PseudonymIdentifier * pseudonym, - const char *name, const char *unique_name, - const struct GNUNET_CONTAINER_MetaData *md, int32_t rating) -{ - int *ok = cls; - - if ((0 == memcmp (pseudonym, &id1, sizeof (struct GNUNET_PseudonymIdentifier))) && - (!GNUNET_CONTAINER_meta_data_test_equal (md, meta))) - { - *ok = GNUNET_NO; - GNUNET_break (0); - } - return GNUNET_OK; -} - - -static int -noti_callback (void *cls, const struct GNUNET_PseudonymIdentifier * pseudonym, - const char *name, const char *unique_name, - const struct GNUNET_CONTAINER_MetaData *md, int32_t rating) -{ - int *ret = cls; - - (*ret)++; - return GNUNET_OK; -} - - -static int -fake_noti_callback (void *cls, const struct GNUNET_PseudonymIdentifier * pseudonym, - const char *name, const char *unique_name, - const struct GNUNET_CONTAINER_MetaData *md, int32_t rating) -{ - int *ret = cls; - - (*ret)++; - return GNUNET_OK; -} - - -static void -create_pseu (struct GNUNET_PseudonymIdentifier *pseu) -{ - struct GNUNET_PseudonymHandle *ph; - - ph = GNUNET_PSEUDONYM_create (NULL); - GNUNET_PSEUDONYM_get_identifier (ph, pseu); - GNUNET_PSEUDONYM_destroy (ph); -} - - -/** - * Testcase for meta data / ranking IO routines. - */ -static int -test_io () -{ - int ok; - 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; - char *name1; - char *name2; - char *name3; - char *name1_unique; - char *name2_unique; - char *noname; - int noname_is_a_dup; - int notiCount, fakenotiCount; - 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'; - - GNUNET_log_setup ("test-pseudonym", "WARNING", NULL); - ok = GNUNET_YES; - (void) GNUNET_DISK_directory_remove ("/tmp/gnunet-pseudonym-test"); - cfg = GNUNET_CONFIGURATION_create (); - if (-1 == GNUNET_CONFIGURATION_parse (cfg, "test_pseudonym_data.conf")) - { - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_break (0); - return -1; - } - notiCount = 0; - fakenotiCount = 0; - 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); - meta = GNUNET_CONTAINER_meta_data_create (); - GNUNET_CONTAINER_meta_data_insert (meta, "", EXTRACTOR_METATYPE_TITLE, - EXTRACTOR_METAFORMAT_UTF8, "text/plain", - "test", strlen ("test") + 1); - create_pseu (&id1); - GNUNET_PSEUDONYM_add (cfg, &id1, meta); - CHECK (notiCount == 1); - GNUNET_PSEUDONYM_add (cfg, &id1, meta); - CHECK (notiCount == 2); - newVal = GNUNET_PSEUDONYM_list_all (cfg, &iter, &ok); - CHECK (old < newVal); - old = newVal; - create_pseu (&id2); - GNUNET_PSEUDONYM_add (cfg, &id2, meta); - CHECK (notiCount == 3); - newVal = GNUNET_PSEUDONYM_list_all (cfg, &iter, &ok); - CHECK (old < newVal); - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_meta_data_insert (meta, "", - EXTRACTOR_METATYPE_COMMENT, - EXTRACTOR_METAFORMAT_UTF8, - "text/plain", m, - strlen (m) + 1)); - create_pseu (&id3); - GNUNET_PSEUDONYM_add (cfg, &id3, meta); - GNUNET_PSEUDONYM_get_info (cfg, &id3, NULL, NULL, &name3, NULL); - CHECK (name3 != NULL); - GNUNET_PSEUDONYM_get_info (cfg, &id2, NULL, NULL, &name2, NULL); - CHECK (name2 != NULL); - GNUNET_PSEUDONYM_get_info (cfg, &id1, NULL, NULL, &name1, NULL); - CHECK (name1 != NULL); - CHECK (0 == strcmp (name1, name2)); - name1_unique = GNUNET_PSEUDONYM_name_uniquify (cfg, &id1, name1, NULL); - name2_unique = GNUNET_PSEUDONYM_name_uniquify (cfg, &id2, name2, NULL); - CHECK (0 != strcmp (name1_unique, name2_unique)); - CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, "fake", &rid2)); - CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, name2, &rid2)); - 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_PseudonymIdentifier))); - CHECK (0 == memcmp (&id2, &rid2, sizeof (struct GNUNET_PseudonymIdentifier))); - - create_pseu (&fid); - GNUNET_log_skip (1, GNUNET_NO); - CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &fid, 0)); - GNUNET_log_skip (0, GNUNET_NO); - CHECK (GNUNET_OK == GNUNET_PSEUDONYM_get_info (cfg, &fid, NULL, NULL, &noname, &noname_is_a_dup)); - CHECK (noname != NULL); - CHECK (noname_is_a_dup == GNUNET_YES); - CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &id1, 0)); - CHECK (5 == GNUNET_PSEUDONYM_rank (cfg, &id1, 5)); - CHECK (-5 == GNUNET_PSEUDONYM_rank (cfg, &id1, -10)); - CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &id1, 5)); - GNUNET_free (name1); - GNUNET_free (name2); - GNUNET_free (name1_unique); - GNUNET_free (name2_unique); - GNUNET_free (name3); - GNUNET_free (noname); - /* END OF TEST CODE */ -FAILURE: - GNUNET_PSEUDONYM_discovery_callback_unregister (dh2); - GNUNET_CONTAINER_meta_data_destroy (meta); - GNUNET_CONFIGURATION_destroy (cfg); - return (ok == GNUNET_YES) ? 0 : 1; -} - - -/** - * Use the given input to sign and check the resulting signature. - */ -static void -test_signature (struct GNUNET_PseudonymHandle *ph, - struct GNUNET_PseudonymSignaturePurpose *purpose, - struct GNUNET_HashCode *seed, - struct GNUNET_HashCode *signing_key, - char *bit) -{ - struct GNUNET_PseudonymSignature signature; - struct GNUNET_PseudonymSignature signature2; - struct GNUNET_PseudonymIdentifier pseudonym; - struct GNUNET_PseudonymIdentifier verification_key; - - GNUNET_PSEUDONYM_sign (ph, purpose, seed, signing_key, &signature); - GNUNET_PSEUDONYM_sign (ph, purpose, seed, signing_key, &signature2); - /* with seed, two sigs must be identical, without, they must be different! */ - if (NULL != seed) - GNUNET_break (0 == memcmp (&signature, &signature2, sizeof (signature))); - else /* crypto not implemented, thus for now 'break' */ - GNUNET_break (0 != memcmp (&signature, &signature2, sizeof (signature))); - GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym); - GNUNET_PSEUDONYM_derive_verification_key (&pseudonym, - signing_key, - &verification_key); - GNUNET_break (GNUNET_OK == - GNUNET_PSEUDONYM_verify (purpose, &signature, &verification_key)); - /* also check that if the data is changed, the signature no longer matches */ - (*bit)++; - /* crypto not implemented, thus for now 'break' */ - GNUNET_break (GNUNET_OK != - GNUNET_PSEUDONYM_verify (purpose, &signature, &verification_key)); - (*bit)--; -} - - -/** - * Test cryptographic operations for a given private key. - * - * @param ph private key to test - */ -static void -test_crypto_ops (struct GNUNET_PseudonymHandle *ph) -{ - char data[16]; - struct GNUNET_PseudonymSignaturePurpose *purpose; - struct GNUNET_HashCode seed; - struct GNUNET_HashCode signing_key; - - memset (data, 42, sizeof (data)); - purpose = (struct GNUNET_PseudonymSignaturePurpose *) data; - purpose->size = htonl (sizeof (data)); - purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST); - memset (&seed, 41, sizeof (seed)); - memset (&signing_key, 40, sizeof (signing_key)); - test_signature (ph, purpose, &seed, &signing_key, &data[sizeof (struct GNUNET_PseudonymSignaturePurpose)]); - test_signature (ph, purpose, NULL, &signing_key, &data[sizeof (struct GNUNET_PseudonymSignaturePurpose)]); -} - - -/** - * Test cryptographic operations. - */ -static int -test_crypto () -{ - struct GNUNET_PseudonymHandle *ph; - struct GNUNET_PseudonymIdentifier pseudonym; - struct GNUNET_PseudonymIdentifier pseudonym2; - - /* check writing to and reading from disk */ - ph = GNUNET_PSEUDONYM_create ("/tmp/gnunet-pseudonym-test/pseu.dsa"); - GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym); - GNUNET_PSEUDONYM_destroy (ph); - ph = GNUNET_PSEUDONYM_create ("/tmp/gnunet-pseudonym-test/pseu.dsa"); - GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym2); - test_crypto_ops (ph); - GNUNET_PSEUDONYM_destroy (ph); - if (0 != memcmp (&pseudonym, &pseudonym2, sizeof (pseudonym))) - return 1; - - /* check in-memory generation */ - ph = GNUNET_PSEUDONYM_create (NULL); - GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym2); - if (0 == memcmp (&pseudonym, &pseudonym2, sizeof (pseudonym))) - return 1; - test_crypto_ops (ph); - GNUNET_PSEUDONYM_destroy (ph); - - /* check anonymous pseudonym operations generation */ - ph = GNUNET_PSEUDONYM_get_anonymous_pseudonym_handle (); - GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym2); - if (0 == memcmp (&pseudonym, &pseudonym2, sizeof (pseudonym))) - return 1; - test_crypto_ops (ph); - GNUNET_PSEUDONYM_destroy (ph); - return 0; -} - - -int -main (int argc, char *argv[]) -{ - if (0 != test_io ()) - return 1; - if (0 != test_crypto ()) - return 1; - GNUNET_break (GNUNET_OK == - GNUNET_DISK_directory_remove ("/tmp/gnunet-pseudonym-test")); - return 0; -} - - -/* end of test_pseudoynm.c */ -- cgit v1.2.3