aboutsummaryrefslogtreecommitdiff
path: root/src/fs
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-04-14 18:45:55 +0000
committerChristian Grothoff <christian@grothoff.org>2013-04-14 18:45:55 +0000
commit7d9d8f793ebc261192fe33a87905133e1bf36512 (patch)
treed9dd0eaa5863a36878cd65190aeff96a41f25ca4 /src/fs
parentd03a033c429a993d0d0511600fef0c15ada5d950 (diff)
downloadgnunet-7d9d8f793ebc261192fe33a87905133e1bf36512.tar.gz
gnunet-7d9d8f793ebc261192fe33a87905133e1bf36512.zip
-move pseudonym code to fs, mark fs as experimental for now
Diffstat (limited to 'src/fs')
-rw-r--r--src/fs/Makefile.am14
-rw-r--r--src/fs/fs_pseudonym.c1590
-rw-r--r--src/fs/plugin_block_fs.c1
-rw-r--r--src/fs/test_pseudonym.c327
4 files changed, 1931 insertions, 1 deletions
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 = \
34 fs_file_information.c \ 34 fs_file_information.c \
35 fs_getopt.c \ 35 fs_getopt.c \
36 fs_list_indexed.c \ 36 fs_list_indexed.c \
37 fs_pseudonym.c \
37 fs_publish.c \ 38 fs_publish.c \
38 fs_publish_ksk.c \ 39 fs_publish_ksk.c \
39 fs_misc.c \ 40 fs_misc.c \
@@ -47,7 +48,7 @@ libgnunetfs_la_SOURCES = \
47libgnunetfs_la_LIBADD = \ 48libgnunetfs_la_LIBADD = \
48 $(top_builddir)/src/datastore/libgnunetdatastore.la \ 49 $(top_builddir)/src/datastore/libgnunetdatastore.la \
49 $(top_builddir)/src/util/libgnunetutil.la \ 50 $(top_builddir)/src/util/libgnunetutil.la \
50 $(GN_LIBINTL) $(XLIB) -lunistring -lextractor 51 $(GN_LIBINTL) $(XLIB) -lunistring -lextractor -lgcrypt
51 52
52libgnunetfs_la_LDFLAGS = \ 53libgnunetfs_la_LDFLAGS = \
53 $(GN_LIB_LDFLAGS) $(WINFLAGS) \ 54 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
@@ -214,6 +215,7 @@ libgnunet_plugin_block_fs_la_SOURCES = \
214 plugin_block_fs.c 215 plugin_block_fs.c
215libgnunet_plugin_block_fs_la_LIBADD = \ 216libgnunet_plugin_block_fs_la_LIBADD = \
216 $(top_builddir)/src/block/libgnunetblock.la \ 217 $(top_builddir)/src/block/libgnunetblock.la \
218 $(top_builddir)/src/fs/libgnunetfs.la \
217 $(top_builddir)/src/util/libgnunetutil.la \ 219 $(top_builddir)/src/util/libgnunetutil.la \
218 $(LTLIBINTL) 220 $(LTLIBINTL)
219libgnunet_plugin_block_fs_la_LDFLAGS = \ 221libgnunet_plugin_block_fs_la_LDFLAGS = \
@@ -243,6 +245,7 @@ check_PROGRAMS = \
243 test_fs_list_indexed \ 245 test_fs_list_indexed \
244 test_fs_namespace \ 246 test_fs_namespace \
245 test_fs_namespace_list_updateable \ 247 test_fs_namespace_list_updateable \
248 test_pseudonym \
246 test_fs_publish \ 249 test_fs_publish \
247 test_fs_publish_persistence \ 250 test_fs_publish_persistence \
248 test_fs_search \ 251 test_fs_search \
@@ -288,6 +291,7 @@ TESTS = \
288 test_fs_list_indexed \ 291 test_fs_list_indexed \
289 test_fs_namespace \ 292 test_fs_namespace \
290 test_fs_namespace_list_updateable \ 293 test_fs_namespace_list_updateable \
294 test_pseudonym \
291 test_fs_publish \ 295 test_fs_publish \
292 test_fs_publish_persistence \ 296 test_fs_publish_persistence \
293 test_fs_search \ 297 test_fs_search \
@@ -308,6 +312,14 @@ TESTS = \
308endif 312endif
309 313
310 314
315test_pseudonym_SOURCES = \
316 test_pseudonym.c
317test_pseudonym_LDADD = \
318 -lgcrypt \
319 $(top_builddir)/src/fs/libgnunetfs.la \
320 $(top_builddir)/src/util/libgnunetutil.la
321
322
311test_fs_directory_SOURCES = \ 323test_fs_directory_SOURCES = \
312 test_fs_directory.c 324 test_fs_directory.c
313test_fs_directory_LDADD = \ 325test_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 @@
1/*
2 This file is part of GNUnet
3 (C) 2003, 2004, 2005, 2006, 2007, 2008, 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file fs/fs_pseudonym.c
22 * @brief pseudonym functions
23 * @author Christian Grothoff
24 *
25 * TODO:
26 * - all cryptographic operations are currently NOT implemented and
27 * provided by stubs that merely pretend to work!
28 */
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_fs_service.h"
32#include <gcrypt.h>
33
34
35#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
36
37#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
38
39#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
40
41/**
42 * Log an error message at log-level 'level' that indicates
43 * a failure of the command 'cmd' with the message given
44 * by gcry_strerror(rc).
45 */
46#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);
47
48/**
49 * Name of the directory which stores meta data for pseudonym
50 */
51#define PS_METADATA_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonym" DIR_SEPARATOR_STR "metadata" DIR_SEPARATOR_STR
52
53/**
54 * Name of the directory which stores names for pseudonyms
55 */
56#define PS_NAMES_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonym" DIR_SEPARATOR_STR "names" DIR_SEPARATOR_STR
57
58
59/**
60 * Configuration section we use.
61 */
62#define GNUNET_CLIENT_SERVICE_NAME "fs"
63
64
65/* ************************* Disk operations (pseudonym data mgmt) **************** */
66
67/**
68 * Registered callbacks for discovery of pseudonyms.
69 */
70struct GNUNET_PSEUDONYM_DiscoveryHandle
71{
72 /**
73 * This is a doubly linked list.
74 */
75 struct GNUNET_PSEUDONYM_DiscoveryHandle *next;
76
77 /**
78 * This is a doubly linked list.
79 */
80 struct GNUNET_PSEUDONYM_DiscoveryHandle *prev;
81
82 /**
83 * Function to call each time a pseudonym is discovered.
84 */
85 GNUNET_PSEUDONYM_Iterator callback;
86
87 /**
88 * Closure for callback.
89 */
90 void *callback_cls;
91};
92
93
94/**
95 * Head of the linked list of functions to call when
96 * new pseudonyms are added.
97 */
98static struct GNUNET_PSEUDONYM_DiscoveryHandle *disco_head;
99
100/**
101 * Tail of the linked list of functions to call when
102 * new pseudonyms are added.
103 */
104static struct GNUNET_PSEUDONYM_DiscoveryHandle *disco_tail;
105
106
107/**
108 * Internal notification about new tracked URI.
109 *
110 * @param pseudonym public key of the pseudonym
111 * @param md meta data to be written
112 * @param rating rating of pseudonym
113 */
114static void
115internal_notify (const struct GNUNET_PseudonymIdentifier *pseudonym,
116 const struct GNUNET_CONTAINER_MetaData *md, int rating)
117{
118 struct GNUNET_PSEUDONYM_DiscoveryHandle *pos;
119
120 for (pos = disco_head; NULL != pos; pos = pos->next)
121 pos->callback (pos->callback_cls, pseudonym, NULL, NULL, md, rating);
122}
123
124
125/**
126 * Register callback to be invoked whenever we discover
127 * a new pseudonym.
128 * Will immediately call provided iterator callback for all
129 * already discovered pseudonyms.
130 *
131 * @param cfg configuration to use
132 * @param iterator iterator over pseudonym
133 * @param iterator_cls point to a closure
134 * @return registration handle
135 */
136struct GNUNET_PSEUDONYM_DiscoveryHandle *
137GNUNET_PSEUDONYM_discovery_callback_register (const struct
138 GNUNET_CONFIGURATION_Handle *cfg,
139 GNUNET_PSEUDONYM_Iterator iterator,
140 void *iterator_cls)
141{
142 struct GNUNET_PSEUDONYM_DiscoveryHandle *dh;
143
144 dh = GNUNET_malloc (sizeof (struct GNUNET_PSEUDONYM_DiscoveryHandle));
145 dh->callback = iterator;
146 dh->callback_cls = iterator_cls;
147 GNUNET_CONTAINER_DLL_insert (disco_head, disco_tail, dh);
148 GNUNET_PSEUDONYM_list_all (cfg, iterator, iterator_cls);
149 return dh;
150}
151
152
153/**
154 * Unregister pseudonym discovery callback.
155 *
156 * @param dh registration to unregister
157 */
158void
159GNUNET_PSEUDONYM_discovery_callback_unregister (struct GNUNET_PSEUDONYM_DiscoveryHandle *dh)
160{
161 GNUNET_CONTAINER_DLL_remove (disco_head, disco_tail, dh);
162 GNUNET_free (dh);
163}
164
165
166/**
167 * Get the filename (or directory name) for the given
168 * pseudonym identifier and directory prefix.
169 *
170 * @param cfg configuration to use
171 * @param prefix path components to append to the private directory name
172 * @param pseudonym the pseudonym, can be NULL
173 * @return filename of the pseudonym (if pseudonym != NULL) or directory with the data (if pseudonym == NULL)
174 */
175static char *
176get_data_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
177 const char *prefix,
178 const struct GNUNET_PseudonymIdentifier *pseudonym)
179{
180 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
181 struct GNUNET_HashCode psid;
182
183 if (NULL != pseudonym)
184 {
185 GNUNET_CRYPTO_hash (pseudonym,
186 sizeof (struct GNUNET_PseudonymIdentifier),
187 &psid);
188 GNUNET_CRYPTO_hash_to_enc (&psid, &enc);
189 }
190 return GNUNET_DISK_get_home_filename (cfg,
191 GNUNET_CLIENT_SERVICE_NAME, prefix,
192 (NULL == pseudonym)
193 ? NULL
194 : (const char *) &enc,
195 NULL);
196}
197
198
199/**
200 * Get the filename (or directory name) for the given
201 * hash code and directory prefix.
202 *
203 * @param cfg configuration to use
204 * @param prefix path components to append to the private directory name
205 * @param hc some hash code
206 * @return filename of the pseudonym (if hc != NULL) or directory with the data (if hc == NULL)
207 */
208static char *
209get_data_filename_hash (const struct GNUNET_CONFIGURATION_Handle *cfg,
210 const char *prefix,
211 const struct GNUNET_HashCode *hc)
212{
213 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
214
215 if (NULL != hc)
216 GNUNET_CRYPTO_hash_to_enc (hc, &enc);
217 return GNUNET_DISK_get_home_filename (cfg,
218 GNUNET_CLIENT_SERVICE_NAME, prefix,
219 (NULL == hc)
220 ? NULL
221 : (const char *) &enc,
222 NULL);
223}
224
225
226/**
227 * Set the pseudonym metadata, rank and name.
228 * Writes the pseudonym infomation into a file
229 *
230 * @param cfg overall configuration
231 * @param pseudonym id of the pseudonym
232 * @param name name to set. Must be the non-unique version of it.
233 * May be NULL, in which case it erases pseudonym's name!
234 * @param md metadata to set
235 * May be NULL, in which case it erases pseudonym's metadata!
236 * @param rank rank to assign
237 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
238 */
239int
240GNUNET_PSEUDONYM_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
241 const struct GNUNET_PseudonymIdentifier *pseudonym,
242 const char *name,
243 const struct GNUNET_CONTAINER_MetaData *md,
244 int32_t rank)
245{
246 char *fn;
247 struct GNUNET_BIO_WriteHandle *fileW;
248
249 fn = get_data_filename (cfg, PS_METADATA_DIR, pseudonym);
250 if (NULL == (fileW = GNUNET_BIO_write_open (fn)))
251 {
252 GNUNET_free (fn);
253 return GNUNET_SYSERR;
254 }
255 if ((GNUNET_OK != GNUNET_BIO_write (fileW, pseudonym,
256 sizeof (struct GNUNET_PseudonymIdentifier))) ||
257 (GNUNET_OK != GNUNET_BIO_write_int32 (fileW, rank)) ||
258 (GNUNET_OK != GNUNET_BIO_write_string (fileW, name)) ||
259 (GNUNET_OK != GNUNET_BIO_write_meta_data (fileW, md)))
260 {
261 (void) GNUNET_BIO_write_close (fileW);
262 GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
263 GNUNET_free (fn);
264 return GNUNET_SYSERR;
265 }
266 if (GNUNET_OK != GNUNET_BIO_write_close (fileW))
267 {
268 GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
269 GNUNET_free (fn);
270 return GNUNET_SYSERR;
271 }
272 GNUNET_free (fn);
273 /* create entry for pseudonym name in names */
274 if (NULL != name)
275 GNUNET_free_non_null (GNUNET_PSEUDONYM_name_uniquify (cfg, pseudonym,
276 name, NULL));
277 return GNUNET_OK;
278}
279
280
281/**
282 * Read pseudonym infomation from a file
283 *
284 * @param cfg configuration to use
285 * @param pseudonym hash code of a pseudonym
286 * @param meta meta data to be read from a file
287 * @param rank rank of a pseudonym
288 * @param ns_name name of a pseudonym
289 * @return GNUNET_OK on success, GNUNET_SYSERR on error
290 */
291static int
292read_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
293 const struct GNUNET_PseudonymIdentifier *pseudonym,
294 struct GNUNET_CONTAINER_MetaData **meta,
295 int32_t *rank,
296 char **ns_name)
297{
298 struct GNUNET_PseudonymIdentifier pd;
299 char *fn;
300 char *emsg;
301 struct GNUNET_BIO_ReadHandle *fileR;
302
303 fn = get_data_filename (cfg, PS_METADATA_DIR, pseudonym);
304 if (GNUNET_YES !=
305 GNUNET_DISK_file_test (fn))
306 {
307 GNUNET_free (fn);
308 return GNUNET_SYSERR;
309 }
310 if (NULL == (fileR = GNUNET_BIO_read_open (fn)))
311 {
312 GNUNET_free (fn);
313 return GNUNET_SYSERR;
314 }
315 emsg = NULL;
316 *ns_name = NULL;
317 if ( (GNUNET_OK != GNUNET_BIO_read (fileR, "pseudonym", &pd, sizeof (pd))) ||
318 (0 != memcmp (&pd, pseudonym, sizeof (pd))) ||
319 (GNUNET_OK != GNUNET_BIO_read_int32 (fileR, rank)) ||
320 (GNUNET_OK !=
321 GNUNET_BIO_read_string (fileR, "Read string error!", ns_name, 200)) ||
322 (GNUNET_OK !=
323 GNUNET_BIO_read_meta_data (fileR, "Read meta data error!", meta)) )
324 {
325 (void) GNUNET_BIO_read_close (fileR, &emsg);
326 GNUNET_free_non_null (emsg);
327 GNUNET_free_non_null (*ns_name);
328 *ns_name = NULL;
329 GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
330 GNUNET_free (fn);
331 return GNUNET_SYSERR;
332 }
333 if (GNUNET_OK != GNUNET_BIO_read_close (fileR, &emsg))
334 {
335 LOG (GNUNET_ERROR_TYPE_WARNING,
336 _("Failed to parse metadata about pseudonym from file `%s': %s\n"), fn,
337 emsg);
338 GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
339 GNUNET_CONTAINER_meta_data_destroy (*meta);
340 *meta = NULL;
341 GNUNET_free_non_null (*ns_name);
342 *ns_name = NULL;
343 GNUNET_free_non_null (emsg);
344 GNUNET_free (fn);
345 return GNUNET_SYSERR;
346 }
347 GNUNET_free (fn);
348 return GNUNET_OK;
349}
350
351
352/**
353 * Return unique variant of the namespace name. Use it after
354 * GNUNET_PSEUDONYM_get_info() to make sure that name is unique.
355 *
356 * @param cfg configuration
357 * @param pseudonym public key of the pseudonym
358 * @param name name to uniquify
359 * @param suffix if not NULL, filled with the suffix value
360 * @return NULL on failure (should never happen), name on success.
361 * Free the name with GNUNET_free().
362 */
363char *
364GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg,
365 const struct GNUNET_PseudonymIdentifier *pseudonym,
366 const char *name,
367 unsigned int *suffix)
368{
369 struct GNUNET_HashCode nh;
370 struct GNUNET_PseudonymIdentifier pi;
371 uint64_t len;
372 char *fn;
373 struct GNUNET_DISK_FileHandle *fh;
374 unsigned int i;
375 unsigned int idx;
376 char *ret;
377 struct stat sbuf;
378
379 GNUNET_CRYPTO_hash (name, strlen (name), &nh);
380 fn = get_data_filename_hash (cfg, PS_NAMES_DIR, &nh);
381 len = 0;
382 if (0 == STAT (fn, &sbuf))
383 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES));
384 fh = GNUNET_DISK_file_open (fn,
385 GNUNET_DISK_OPEN_CREATE |
386 GNUNET_DISK_OPEN_READWRITE,
387 GNUNET_DISK_PERM_USER_READ |
388 GNUNET_DISK_PERM_USER_WRITE);
389 i = 0;
390 idx = -1;
391 while ((len >= sizeof (struct GNUNET_PseudonymIdentifier)) &&
392 (sizeof (struct GNUNET_PseudonymIdentifier) ==
393 GNUNET_DISK_file_read (fh, &pi, sizeof (struct GNUNET_PseudonymIdentifier))))
394 {
395 if (0 == memcmp (&pi, pseudonym, sizeof (struct GNUNET_PseudonymIdentifier)))
396 {
397 idx = i;
398 break;
399 }
400 i++;
401 len -= sizeof (struct GNUNET_HashCode);
402 }
403 if (-1 == idx)
404 {
405 idx = i;
406 if (sizeof (struct GNUNET_PseudonymIdentifier) !=
407 GNUNET_DISK_file_write (fh, pseudonym, sizeof (struct GNUNET_PseudonymIdentifier)))
408 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "write", fn);
409 }
410 GNUNET_DISK_file_close (fh);
411 ret = GNUNET_malloc (strlen (name) + 32);
412 GNUNET_snprintf (ret, strlen (name) + 32, "%s-%u", name, idx);
413 if (suffix != NULL)
414 *suffix = idx;
415 GNUNET_free (fn);
416 return ret;
417}
418
419
420/**
421 * Get namespace name, metadata and rank
422 * This is a wrapper around internal read_info() call, and ensures that
423 * returned data is not invalid (not NULL).
424 *
425 * @param cfg configuration
426 * @param pseudonym public key of the pseudonym
427 * @param ret_meta a location to store metadata pointer. NULL, if metadata
428 * is not needed. Destroy with GNUNET_CONTAINER_meta_data_destroy().
429 * @param ret_rank a location to store rank. NULL, if rank not needed.
430 * @param ret_name a location to store human-readable name. Name is not unique.
431 * NULL, if name is not needed. Free with GNUNET_free().
432 * @param name_is_a_dup is set to GNUNET_YES, if ret_name was filled with
433 * a duplicate of a "no-name" placeholder
434 * @return GNUNET_OK on success. GNUENT_SYSERR if the data was
435 * unobtainable (in that case ret_* are filled with placeholders -
436 * empty metadata container, rank -1 and a "no-name" name).
437 */
438int
439GNUNET_PSEUDONYM_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
440 const struct GNUNET_PseudonymIdentifier *pseudonym,
441 struct GNUNET_CONTAINER_MetaData **ret_meta,
442 int32_t *ret_rank,
443 char **ret_name,
444 int *name_is_a_dup)
445{
446 struct GNUNET_CONTAINER_MetaData *meta;
447 char *name;
448 int32_t rank = -1;
449
450 meta = NULL;
451 name = NULL;
452 if (GNUNET_OK == read_info (cfg, pseudonym, &meta, &rank, &name))
453 {
454 if ((meta != NULL) && (name == NULL))
455 name =
456 GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
457 EXTRACTOR_METATYPE_TITLE,
458 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME,
459 EXTRACTOR_METATYPE_FILENAME,
460 EXTRACTOR_METATYPE_DESCRIPTION,
461 EXTRACTOR_METATYPE_SUBJECT,
462 EXTRACTOR_METATYPE_PUBLISHER,
463 EXTRACTOR_METATYPE_AUTHOR_NAME,
464 EXTRACTOR_METATYPE_COMMENT,
465 EXTRACTOR_METATYPE_SUMMARY,
466 -1);
467 if (ret_name != NULL)
468 {
469 if (name == NULL)
470 {
471 name = GNUNET_strdup (_("no-name"));
472 if (name_is_a_dup != NULL)
473 *name_is_a_dup = GNUNET_YES;
474 }
475 else if (name_is_a_dup != NULL)
476 *name_is_a_dup = GNUNET_NO;
477 *ret_name = name;
478 }
479 else if (name != NULL)
480 GNUNET_free (name);
481
482 if (ret_meta != NULL)
483 {
484 if (meta == NULL)
485 meta = GNUNET_CONTAINER_meta_data_create ();
486 *ret_meta = meta;
487 }
488 else if (meta != NULL)
489 GNUNET_CONTAINER_meta_data_destroy (meta);
490
491 if (ret_rank != NULL)
492 *ret_rank = rank;
493
494 return GNUNET_OK;
495 }
496 if (ret_name != NULL)
497 *ret_name = GNUNET_strdup (_("no-name"));
498 if (ret_meta != NULL)
499 *ret_meta = GNUNET_CONTAINER_meta_data_create ();
500 if (ret_rank != NULL)
501 *ret_rank = -1;
502 if (name_is_a_dup != NULL)
503 *name_is_a_dup = GNUNET_YES;
504 return GNUNET_SYSERR;
505}
506
507
508/**
509 * Get the namespace ID belonging to the given namespace name.
510 *
511 * @param cfg configuration to use
512 * @param ns_uname unique (!) human-readable name for the namespace
513 * @param pseudonym set to public key of pseudonym based on 'ns_uname'
514 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
515 */
516int
517GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg,
518 const char *ns_uname,
519 struct GNUNET_PseudonymIdentifier *pseudonym)
520{
521 size_t slen;
522 uint64_t len;
523 unsigned int idx;
524 char *name;
525 struct GNUNET_HashCode nh;
526 char *fn;
527 struct GNUNET_DISK_FileHandle *fh;
528
529 idx = -1;
530 slen = strlen (ns_uname);
531 while ((slen > 0) && (1 != SSCANF (&ns_uname[slen - 1], "-%u", &idx)))
532 slen--;
533 if (0 == slen)
534 return GNUNET_SYSERR;
535 name = GNUNET_strdup (ns_uname);
536 name[slen - 1] = '\0';
537
538 GNUNET_CRYPTO_hash (name, strlen (name), &nh);
539 GNUNET_free (name);
540 fn = get_data_filename_hash (cfg, PS_NAMES_DIR, &nh);
541
542 if ((GNUNET_OK != GNUNET_DISK_file_test (fn) ||
543 (GNUNET_OK != GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES))) ||
544 ((idx + 1) * sizeof (struct GNUNET_PseudonymIdentifier) > len))
545 {
546 GNUNET_free (fn);
547 return GNUNET_SYSERR;
548 }
549 fh = GNUNET_DISK_file_open (fn,
550 GNUNET_DISK_OPEN_CREATE |
551 GNUNET_DISK_OPEN_READWRITE,
552 GNUNET_DISK_PERM_USER_READ |
553 GNUNET_DISK_PERM_USER_WRITE);
554 GNUNET_free (fn);
555 if (GNUNET_SYSERR ==
556 GNUNET_DISK_file_seek (fh, idx * sizeof (struct GNUNET_PseudonymIdentifier),
557 GNUNET_DISK_SEEK_SET))
558 {
559 GNUNET_DISK_file_close (fh);
560 return GNUNET_SYSERR;
561 }
562 if (sizeof (struct GNUNET_PseudonymIdentifier) !=
563 GNUNET_DISK_file_read (fh, pseudonym, sizeof (struct GNUNET_PseudonymIdentifier)))
564 {
565 GNUNET_DISK_file_close (fh);
566 return GNUNET_SYSERR;
567 }
568 GNUNET_DISK_file_close (fh);
569 return GNUNET_OK;
570}
571
572
573
574/**
575 * struct used to list the pseudonym
576 */
577struct ListPseudonymClosure
578{
579
580 /**
581 * iterator over pseudonym
582 */
583 GNUNET_PSEUDONYM_Iterator iterator;
584
585 /**
586 * Closure for iterator.
587 */
588 void *iterator_cls;
589
590 /**
591 * Configuration to use.
592 */
593 const struct GNUNET_CONFIGURATION_Handle *cfg;
594};
595
596
597
598/**
599 * Helper function to list all available pseudonyms
600 *
601 * @param cls point to a struct ListPseudonymClosure
602 * @param fullname name of pseudonym
603 */
604static int
605list_pseudonym_helper (void *cls, const char *fullname)
606{
607 struct ListPseudonymClosure *lpc = cls;
608 struct GNUNET_PseudonymIdentifier pd;
609 char *emsg;
610 struct GNUNET_BIO_ReadHandle *fileR;
611 int32_t rank;
612 char *ns_name;
613 struct GNUNET_CONTAINER_MetaData *meta;
614 int ret;
615 char *name_unique;
616
617 if (NULL == (fileR = GNUNET_BIO_read_open (fullname)))
618 return GNUNET_SYSERR;
619 emsg = NULL;
620 ns_name = NULL;
621 if ( (GNUNET_OK != GNUNET_BIO_read (fileR, "pseudonym", &pd, sizeof (pd))) ||
622 (GNUNET_OK != GNUNET_BIO_read_int32 (fileR, &rank)) ||
623 (GNUNET_OK !=
624 GNUNET_BIO_read_string (fileR, "Read string error!", &ns_name, 200)) ||
625 (GNUNET_OK !=
626 GNUNET_BIO_read_meta_data (fileR, "Read meta data error!", &meta)) )
627 {
628 (void) GNUNET_BIO_read_close (fileR, &emsg);
629 GNUNET_free_non_null (emsg);
630 GNUNET_free_non_null (ns_name);
631 GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fullname));
632 return GNUNET_SYSERR;
633 }
634 if (NULL == ns_name)
635 ns_name = GNUNET_strdup (_("no-name"));
636 if (GNUNET_OK != GNUNET_BIO_read_close (fileR, &emsg))
637 {
638 LOG (GNUNET_ERROR_TYPE_WARNING,
639 _("Failed to parse metadata about pseudonym from file `%s': %s\n"), fullname,
640 emsg);
641 GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fullname));
642 GNUNET_CONTAINER_meta_data_destroy (meta);
643 GNUNET_free (ns_name);
644 GNUNET_free_non_null (emsg);
645 return GNUNET_SYSERR;
646 }
647 ret = GNUNET_OK;
648 name_unique = GNUNET_PSEUDONYM_name_uniquify (lpc->cfg, &pd, ns_name, NULL);
649 if (NULL != lpc->iterator)
650 ret = lpc->iterator (lpc->iterator_cls, &pd, ns_name, name_unique, meta, rank);
651 GNUNET_free (ns_name);
652 GNUNET_free_non_null (name_unique);
653 GNUNET_CONTAINER_meta_data_destroy (meta);
654 return ret;
655}
656
657
658/**
659 * List all available pseudonyms.
660 *
661 * @param cfg overall configuration
662 * @param iterator function to call for each pseudonym
663 * @param iterator_cls closure for iterator
664 * @return number of pseudonyms found
665 */
666int
667GNUNET_PSEUDONYM_list_all (const struct GNUNET_CONFIGURATION_Handle *cfg,
668 GNUNET_PSEUDONYM_Iterator iterator,
669 void *iterator_cls)
670{
671 struct ListPseudonymClosure cls;
672 char *fn;
673 int ret;
674
675 cls.iterator = iterator;
676 cls.iterator_cls = iterator_cls;
677 cls.cfg = cfg;
678 fn = get_data_filename (cfg, PS_METADATA_DIR, NULL);
679 GNUNET_assert (fn != NULL);
680 GNUNET_DISK_directory_create (fn);
681 ret = GNUNET_DISK_directory_scan (fn, &list_pseudonym_helper, &cls);
682 GNUNET_free (fn);
683 return ret;
684}
685
686
687/**
688 * Change the rank of a pseudonym.
689 *
690 * @param cfg overall configuration
691 * @param pseudonym the pseudonym
692 * @param delta by how much should the rating be changed?
693 * @return new rating of the pseudonym
694 */
695int
696GNUNET_PSEUDONYM_rank (const struct GNUNET_CONFIGURATION_Handle *cfg,
697 const struct GNUNET_PseudonymIdentifier *pseudonym,
698 int32_t delta)
699{
700 struct GNUNET_CONTAINER_MetaData *meta;
701 int ret;
702 int32_t rank;
703 char *name;
704
705 name = NULL;
706 ret = read_info (cfg, pseudonym, &meta, &rank, &name);
707 if (ret == GNUNET_SYSERR)
708 {
709 rank = 0;
710 meta = GNUNET_CONTAINER_meta_data_create ();
711 }
712 rank += delta;
713 GNUNET_PSEUDONYM_set_info (cfg, pseudonym, name, meta, rank);
714 GNUNET_CONTAINER_meta_data_destroy (meta);
715 GNUNET_free_non_null (name);
716 return rank;
717}
718
719
720/**
721 * Add a pseudonym to the set of known pseudonyms.
722 * For all pseudonym advertisements that we discover
723 * FS should automatically call this function.
724 *
725 * @param cfg overall configuration
726 * @param pseudonym the pseudonym to add
727 * @param meta metadata for the pseudonym
728 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
729 */
730int
731GNUNET_PSEUDONYM_add (const struct GNUNET_CONFIGURATION_Handle *cfg,
732 const struct GNUNET_PseudonymIdentifier *pseudonym,
733 const struct GNUNET_CONTAINER_MetaData *meta)
734{
735 char *name;
736 int32_t rank;
737 struct GNUNET_CONTAINER_MetaData *old;
738 char *fn;
739 struct stat sbuf;
740 int ret;
741
742 rank = 0;
743 fn = get_data_filename (cfg, PS_METADATA_DIR, pseudonym);
744 GNUNET_assert (fn != NULL);
745
746 if ((0 == STAT (fn, &sbuf)) &&
747 (GNUNET_OK == read_info (cfg, pseudonym, &old, &rank, &name)))
748 {
749 GNUNET_CONTAINER_meta_data_merge (old, meta);
750 ret = GNUNET_PSEUDONYM_set_info (cfg, pseudonym, name, old, rank);
751 GNUNET_CONTAINER_meta_data_destroy (old);
752 GNUNET_free_non_null (name);
753 }
754 else
755 {
756 ret = GNUNET_PSEUDONYM_set_info (cfg, pseudonym, NULL, meta, rank);
757 }
758 GNUNET_free (fn);
759 internal_notify (pseudonym, meta, rank);
760 return ret;
761}
762
763
764/* ***************************** cryptographic operations ************************* */
765
766/**
767 * Handle for a pseudonym (private key).
768 */
769struct GNUNET_PseudonymHandle
770{
771 /**
772 * 256-bit 'd' secret value (mod 'n', where n is 256-bit for NIST P-256).
773 */
774 unsigned char d[256 / 8];
775
776 /**
777 * Public key corresponding to the private key.
778 */
779 struct GNUNET_PseudonymIdentifier public_key;
780};
781
782
783/**
784 * If target != size, move target bytes to the end of the size-sized
785 * buffer and zero out the first target-size bytes.
786 *
787 * @param buf original buffer
788 * @param size number of bytes in the buffer
789 * @param target target size of the buffer
790 */
791static void
792adjust (unsigned char *buf, size_t size, size_t target)
793{
794 if (size < target)
795 {
796 memmove (&buf[target - size], buf, size);
797 memset (buf, 0, target - size);
798 }
799}
800
801
802/**
803 * Extract values from an S-expression.
804 *
805 * @param array where to store the result(s)
806 * @param sexp S-expression to parse
807 * @param topname top-level name in the S-expression that is of interest
808 * @param elems names of the elements to extract
809 * @return 0 on success
810 */
811static int
812key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
813 const char *elems)
814{
815 gcry_sexp_t list;
816 gcry_sexp_t l2;
817 const char *s;
818 unsigned int i;
819 unsigned int idx;
820
821 if (! (list = gcry_sexp_find_token (sexp, topname, 0)))
822 return 1;
823 l2 = gcry_sexp_cadr (list);
824 gcry_sexp_release (list);
825 list = l2;
826 if (! list)
827 return 2;
828 idx = 0;
829 for (s = elems; *s; s++, idx++)
830 {
831 if (! (l2 = gcry_sexp_find_token (list, s, 1)))
832 {
833 for (i = 0; i < idx; i++)
834 {
835 gcry_free (array[i]);
836 array[i] = NULL;
837 }
838 gcry_sexp_release (list);
839 return 3; /* required parameter not found */
840 }
841 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
842 gcry_sexp_release (l2);
843 if (! array[idx])
844 {
845 for (i = 0; i < idx; i++)
846 {
847 gcry_free (array[i]);
848 array[i] = NULL;
849 }
850 gcry_sexp_release (list);
851 return 4; /* required parameter is invalid */
852 }
853 }
854 gcry_sexp_release (list);
855 return 0;
856}
857
858
859/**
860 * Create a pseudonym.
861 *
862 * @param filename name of the file to use for storage, NULL for in-memory only
863 * @return handle to the private key of the pseudonym
864 */
865struct GNUNET_PseudonymHandle *
866GNUNET_PSEUDONYM_create (const char *filename)
867{
868 struct GNUNET_PseudonymHandle *ph;
869 ssize_t ret;
870 gcry_sexp_t r_key;
871 gcry_sexp_t params;
872 gcry_ctx_t ctx;
873 gcry_mpi_point_t q;
874 gcry_mpi_t q_x;
875 gcry_mpi_t q_y;
876 gcry_error_t rc;
877 gcry_mpi_t d;
878 size_t size;
879
880 ph = GNUNET_malloc (sizeof (struct GNUNET_PseudonymHandle));
881 if ( (NULL != filename) &&
882 (GNUNET_YES == GNUNET_DISK_file_test (filename)) )
883 {
884 ret = GNUNET_DISK_fn_read (filename, ph,
885 sizeof (struct GNUNET_PseudonymHandle));
886 /* Note: we don't do any validation here, maybe we should? */
887 if (sizeof (struct GNUNET_PseudonymHandle) == ret)
888 return ph;
889 }
890 if (0 != (rc = gcry_sexp_build (&params, NULL,
891 "(genkey(ecdsa(curve \"NIST P-256\")))")))
892 {
893 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
894 return NULL;
895 }
896 if (0 != (rc = gcry_pk_genkey (&r_key, params)))
897 {
898 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
899 gcry_sexp_release (r_key);
900 return NULL;
901 }
902 /* extract "d" (secret key) from r_key */
903 rc = key_from_sexp (&d, r_key, "private-key", "d");
904 if (0 != rc)
905 rc = key_from_sexp (&d, r_key, "private-key", "d");
906 if (0 != rc)
907 rc = key_from_sexp (&d, r_key, "ecc", "d");
908 if (0 != rc)
909 {
910 gcry_sexp_release (r_key);
911 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
912 return NULL;
913 }
914 size = sizeof (ph->d);
915 GNUNET_assert (0 ==
916 gcry_mpi_print (GCRYMPI_FMT_USG, ph->d, size, &size,
917 d));
918 gcry_mpi_release (d);
919 adjust (ph->d, size, sizeof (ph->d));
920
921 /* extract 'q' (public key) from r_key */
922 if (0 != (rc = gcry_mpi_ec_new (&ctx, r_key, NULL)))
923 {
924 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
925 gcry_sexp_release (r_key);
926 return NULL;
927 }
928 gcry_sexp_release (r_key);
929 q = gcry_mpi_ec_get_point ("q", ctx, 0);
930 q_x = gcry_mpi_new (256);
931 q_y = gcry_mpi_new (256);
932 gcry_mpi_ec_get_affine (q_x, q_y, q, ctx);
933 gcry_mpi_point_release (q);
934
935 /* store q_x/q_y in public key */
936 size = sizeof (ph->public_key.q_x);
937 if (0 !=
938 gcry_mpi_print (GCRYMPI_FMT_USG, ph->public_key.q_x, size, &size,
939 q_x))
940 {
941 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
942 gcry_mpi_release (q_x);
943 gcry_mpi_release (q_y);
944 return NULL;
945
946 }
947 adjust (ph->public_key.q_x, size, sizeof (ph->public_key.q_x));
948 gcry_mpi_release (q_x);
949
950 size = sizeof (ph->public_key.q_y);
951 if (0 !=
952 gcry_mpi_print (GCRYMPI_FMT_USG, ph->public_key.q_y, size, &size,
953 q_y))
954 {
955 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
956 gcry_mpi_release (q_y);
957 return NULL;
958 }
959 adjust (ph->public_key.q_y, size, sizeof (ph->public_key.q_y));
960 gcry_mpi_release (q_y);
961
962 /* write to disk */
963 if (NULL != filename)
964 {
965 ret = GNUNET_DISK_fn_write (filename, ph, sizeof (struct GNUNET_PseudonymHandle),
966 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
967 if (sizeof (struct GNUNET_PseudonymHandle) != ret)
968 {
969 GNUNET_free (ph);
970 return NULL;
971 }
972 }
973 return ph;
974}
975
976
977/**
978 * Create a pseudonym, from a file that must already exist.
979 *
980 * @param filename name of the file to use for storage, NULL for in-memory only
981 * @return handle to the private key of the pseudonym
982 */
983struct GNUNET_PseudonymHandle *
984GNUNET_PSEUDONYM_create_from_existing_file (const char *filename)
985{
986 struct GNUNET_PseudonymHandle *ph;
987 ssize_t ret;
988
989 ph = GNUNET_malloc (sizeof (struct GNUNET_PseudonymHandle));
990 ret = GNUNET_DISK_fn_read (filename, ph,
991 sizeof (struct GNUNET_PseudonymHandle));
992 if (sizeof (struct GNUNET_PseudonymHandle) != ret)
993 {
994 GNUNET_free (ph);
995 return NULL;
996 }
997 /* Note: we don't do any validation here; maybe we should? */
998 return ph;
999}
1000
1001
1002/**
1003 * Get the handle for the 'anonymous' pseudonym shared by all users.
1004 * That pseudonym uses a fixed 'secret' for the private key; this
1005 * construction is useful to make anonymous and pseudonymous APIs
1006 * (and packets) indistinguishable on the network. See #2564.
1007 *
1008 * @return handle to the (non-secret) private key of the 'anonymous' pseudonym
1009 */
1010struct GNUNET_PseudonymHandle *
1011GNUNET_PSEUDONYM_get_anonymous_pseudonym_handle ()
1012{
1013 struct GNUNET_PseudonymHandle *ph;
1014
1015 ph = GNUNET_malloc (sizeof (struct GNUNET_PseudonymHandle));
1016 /* Note if we use 'd=0' for the anonymous handle (as per#2564),
1017 then I believe the public key should be also zero, as Q=0P=0;
1018 so setting everything to all-zeros (as per GNUNET_malloc)
1019 should be all that is needed here).
1020 */
1021 return ph;
1022}
1023
1024
1025/**
1026 * Destroy a pseudonym handle. Does NOT remove the private key from
1027 * the disk.
1028 *
1029 * @param ph pseudonym handle to destroy
1030 */
1031void
1032GNUNET_PSEUDONYM_destroy (struct GNUNET_PseudonymHandle *ph)
1033{
1034 GNUNET_free (ph);
1035}
1036
1037
1038/**
1039 * Convert the data specified in the given purpose argument to an
1040 * S-expression suitable for signature operations.
1041 *
1042 * @param purpose data to convert
1043 * @return converted s-expression
1044 */
1045static gcry_sexp_t
1046data_to_pkcs1 (const struct GNUNET_PseudonymSignaturePurpose *purpose)
1047{
1048 struct GNUNET_CRYPTO_ShortHashCode hc;
1049 size_t bufSize;
1050 gcry_sexp_t data;
1051
1052 GNUNET_CRYPTO_short_hash (purpose, ntohl (purpose->size), &hc);
1053#define FORMATSTRING "(4:data(5:flags3:raw)(5:value32:01234567890123456789012345678901))"
1054 bufSize = strlen (FORMATSTRING) + 1;
1055 {
1056 char buff[bufSize];
1057
1058 memcpy (buff, FORMATSTRING, bufSize);
1059 memcpy (&buff
1060 [bufSize -
1061 strlen
1062 ("01234567890123456789012345678901))")
1063 - 1], &hc, sizeof (struct GNUNET_CRYPTO_ShortHashCode));
1064 GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0));
1065 }
1066#undef FORMATSTRING
1067 return data;
1068}
1069
1070gcry_ctx_t xctx;
1071
1072
1073/**
1074 * Cryptographically sign some data with the pseudonym.
1075 *
1076 * @param ph private key 'd' used for signing (corresponds to 'x' in #2564)
1077 * @param purpose data to sign
1078 * @param seed hash of the plaintext of the data that we are signing,
1079 * used for deterministic PRNG for anonymous signing;
1080 * corresponds to 'k' in section 2.7 of #2564
1081 * @param signing_key modifier to apply to the private key for signing ('h');
1082 * see section 2.3 of #2564.
1083 * @param signature where to store the signature
1084 * @return GNUNET_SYSERR on failure
1085 */
1086int
1087GNUNET_PSEUDONYM_sign (struct GNUNET_PseudonymHandle *ph,
1088 const struct GNUNET_PseudonymSignaturePurpose *purpose,
1089 const struct GNUNET_HashCode *seed,
1090 const struct GNUNET_HashCode *signing_key,
1091 struct GNUNET_PseudonymSignature *signature)
1092{
1093 size_t size;
1094 size_t erroff;
1095 gcry_mpi_t d;
1096 gcry_mpi_t k;
1097 gcry_mpi_t h;
1098 gcry_mpi_t dh;
1099 gcry_mpi_t n; /* n from P-256 */
1100 gcry_sexp_t spriv;
1101 gcry_sexp_t data;
1102 gcry_sexp_t result;
1103 gcry_mpi_t rs[2];
1104 int rc;
1105
1106 /* get private key 'd' from pseudonym */
1107 size = sizeof (ph->d);
1108 if (0 != (rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG,
1109 &ph->d,
1110 size, &size)))
1111 {
1112 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1113 return GNUNET_SYSERR;
1114 }
1115 /* get 'x' value from signing key */
1116 size = sizeof (struct GNUNET_HashCode);
1117 if (0 != (rc = gcry_mpi_scan (&h, GCRYMPI_FMT_USG,
1118 signing_key,
1119 size, &size)))
1120 {
1121 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1122 gcry_mpi_release (d);
1123 return GNUNET_SYSERR;
1124 }
1125
1126 /* initialize 'n' from P-256; hex copied from libgcrypt code */
1127 if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX,
1128 "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 0, NULL)))
1129 {
1130 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1131 gcry_mpi_release (d);
1132 gcry_mpi_release (h);
1133 return GNUNET_SYSERR;
1134 }
1135
1136 /* calculate dx = d + h mod n */
1137 dh = gcry_mpi_new (256);
1138 gcry_mpi_addm (dh, d, h, n);
1139 // gcry_mpi_release (d);
1140 // gcry_mpi_release (h);
1141 gcry_mpi_release (n);
1142
1143 if (1) {
1144 gcry_mpi_point_t g;
1145 gcry_mpi_point_t v;
1146 gcry_mpi_point_t hg;
1147 gcry_mpi_point_t q;
1148 gcry_mpi_t v_x;
1149 gcry_mpi_t v_y;
1150
1151 gcry_mpi_ec_new (&xctx, NULL, "NIST P-256");
1152 g = gcry_mpi_ec_get_point ("g", xctx, 0);
1153
1154 hg = gcry_mpi_point_new (0);
1155 gcry_mpi_ec_mul (hg, h, g, xctx);
1156 fprintf (stderr, "\nExpected verification hG value:\n");
1157 v_x = gcry_mpi_new (256);
1158 v_y = gcry_mpi_new (256);
1159 gcry_mpi_ec_get_affine (v_x, v_y, hg, xctx);
1160 gcry_mpi_dump (v_x);
1161 gcry_mpi_dump (v_y);
1162
1163 q = gcry_mpi_point_new (0);
1164 gcry_mpi_ec_mul (q, d, g, xctx);
1165 fprintf (stderr, "\nExpected verification q value:\n");
1166 gcry_mpi_ec_get_affine (v_x, v_y, q, xctx);
1167 gcry_mpi_dump (v_x);
1168 gcry_mpi_dump (v_y);
1169
1170 v = gcry_mpi_point_new (0);
1171 gcry_mpi_ec_add (v, q, hg, xctx);
1172 gcry_mpi_ec_get_affine (v_x, v_y, v, xctx);
1173 fprintf (stderr, "\nExpected verification key public point value V := q + hG:\n");
1174 gcry_mpi_dump (v_x);
1175 gcry_mpi_dump (v_y);
1176 fprintf (stderr, "\n");
1177
1178 }
1179
1180
1181 /* now build sexpression with the signing key */
1182 if (0 != (rc = gcry_sexp_build (&spriv, &erroff,
1183 "(private-key(ecdsa(curve \"NIST P-256\")(d %m)))",
1184 dh)))
1185 {
1186 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1187 gcry_mpi_release (dh);
1188 return GNUNET_SYSERR;
1189 }
1190 gcry_mpi_release (dh);
1191 /* prepare data for signing */
1192 data = data_to_pkcs1 (purpose);
1193
1194 /* get 'k' value from seed, if available */
1195 if (NULL != seed)
1196 {
1197 size = sizeof (struct GNUNET_HashCode);
1198 if (0 != (rc = gcry_mpi_scan (&k, GCRYMPI_FMT_USG,
1199 seed,
1200 size, &size)))
1201 {
1202 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1203 return GNUNET_SYSERR;
1204 }
1205 }
1206
1207 /* actually create signature */
1208 /* FIXME: need API to pass 'k' if 'seed' was non-NULL! */
1209 if (0 != (rc = gcry_pk_sign (&result, data, spriv)))
1210 {
1211 LOG (GNUNET_ERROR_TYPE_WARNING,
1212 _("ECC signing failed at %s:%d: %s\n"), __FILE__,
1213 __LINE__, gcry_strerror (rc));
1214 gcry_sexp_release (data);
1215 gcry_sexp_release (spriv);
1216 if (NULL != seed)
1217 gcry_mpi_release (k);
1218 memset (signature, 0, sizeof (struct GNUNET_PseudonymSignature));
1219 return GNUNET_SYSERR;
1220 }
1221 if (NULL != seed)
1222 gcry_mpi_release (k);
1223 gcry_sexp_release (data);
1224 gcry_sexp_release (spriv);
1225
1226
1227 /* extract 'r' and 's' values from sexpression 'result' and store in 'signature' */
1228 if (0 != (rc = key_from_sexp (rs, result, "sig-val", "rs")))
1229 {
1230 GNUNET_break (0);
1231 gcry_sexp_release (result);
1232 return GNUNET_SYSERR;
1233 }
1234 gcry_sexp_release (result);
1235 size = sizeof (signature->sig_r);
1236 if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, signature->sig_r, size,
1237 &size, rs[0])))
1238 {
1239 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1240 gcry_mpi_release (rs[0]);
1241 gcry_mpi_release (rs[1]);
1242 return GNUNET_SYSERR;
1243 }
1244 gcry_mpi_release (rs[0]);
1245 size = sizeof (signature->sig_s);
1246 if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, signature->sig_s, size,
1247 &size, rs[1])))
1248 {
1249 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1250 gcry_mpi_release (rs[1]);
1251 return GNUNET_SYSERR;
1252 }
1253 gcry_mpi_release (rs[1]);
1254 return GNUNET_OK;
1255}
1256
1257
1258/**
1259 * Get an ECC context (with Q set to the respective public key) from
1260 * a pseudonym.
1261 *
1262 * @param pseudonym with information on 'q'
1263 * @return curve context
1264 */
1265static gcry_ctx_t
1266get_context_from_pseudonym (struct GNUNET_PseudonymIdentifier *pseudonym)
1267{
1268 gcry_ctx_t ctx;
1269 gcry_mpi_t ONE;
1270 gcry_mpi_t q_x;
1271 gcry_mpi_t q_y;
1272 gcry_mpi_point_t q;
1273 size_t size;
1274 int rc;
1275
1276 /* extract 'q' from pseudonym */
1277 size = sizeof (pseudonym->q_x);
1278 if (0 != (rc = gcry_mpi_scan (&q_x, GCRYMPI_FMT_USG, pseudonym->q_x, size, &size)))
1279 {
1280 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1281 return NULL;
1282 }
1283 size = sizeof (pseudonym->q_y);
1284 if (0 != (rc = gcry_mpi_scan (&q_y, GCRYMPI_FMT_USG, pseudonym->q_y, size, &size)))
1285 {
1286 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1287 gcry_mpi_release (q_x);
1288 return NULL;
1289 }
1290 q = gcry_mpi_point_new (256);
1291 ONE = gcry_mpi_new (1);
1292 gcry_mpi_set_ui (ONE, 1);
1293 gcry_mpi_point_set (q, q_x, q_y, ONE); /* FIXME: convenience function 'set_affine'? */
1294 gcry_mpi_release (ONE);
1295 gcry_mpi_release (q_x);
1296 gcry_mpi_release (q_y);
1297
1298 /* create basic ECC context */
1299 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256")))
1300 {
1301 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
1302 gcry_mpi_point_release (q);
1303 return NULL;
1304 }
1305 /* initialize 'ctx' with 'q' */
1306 gcry_mpi_ec_set_point ("q", q, ctx);
1307 gcry_mpi_point_release (q);
1308 return ctx;
1309}
1310
1311
1312/**
1313 * Given a pseudonym and a signing key, derive the corresponding public
1314 * key that would be used to verify the resulting signature.
1315 *
1316 * @param pseudonym the public key (dQ in ECDSA)
1317 * @param signing_key input to derive 'h' (see section 2.4 of #2564)
1318 * @param verification_key resulting public key to verify the signature
1319 * created from the '(d+h)' of 'pseudonym' and the 'signing_key';
1320 * the value stored here can then be given to GNUNET_PSEUDONYM_verify.
1321 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1322 */
1323int
1324GNUNET_PSEUDONYM_derive_verification_key (struct GNUNET_PseudonymIdentifier *pseudonym,
1325 const struct GNUNET_HashCode *signing_key,
1326 struct GNUNET_PseudonymIdentifier *verification_key)
1327{
1328 gcry_mpi_t h;
1329 size_t size;
1330 int rc;
1331 gcry_ctx_t ctx;
1332 gcry_mpi_point_t g;
1333 gcry_mpi_point_t q;
1334 gcry_mpi_point_t hg;
1335 gcry_mpi_point_t v;
1336 gcry_mpi_t v_x;
1337 gcry_mpi_t v_y;
1338
1339 /* get 'h' value from signing key */
1340 size = sizeof (struct GNUNET_HashCode);
1341 if (0 != (rc = gcry_mpi_scan (&h, GCRYMPI_FMT_USG,
1342 signing_key,
1343 size, &size)))
1344 {
1345 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1346 return GNUNET_SYSERR;
1347 }
1348 /* create ECC context based on Q from pseudonym */
1349 if (NULL == (ctx = get_context_from_pseudonym (pseudonym)))
1350 {
1351 gcry_mpi_release (h);
1352 return GNUNET_SYSERR;
1353 }
1354 /* get G */
1355 g = gcry_mpi_ec_get_point ("g", ctx, 0);
1356
1357 /* then call the 'multiply' function, to compute the product hG */
1358 hg = gcry_mpi_point_new (0);
1359 gcry_mpi_ec_mul (hg, h, g, ctx);
1360
1361 {
1362 fprintf (stderr, "\nVerification hG value:\n");
1363 v_x = gcry_mpi_new (256);
1364 v_y = gcry_mpi_new (256);
1365 gcry_mpi_ec_get_affine (v_x, v_y, hg, ctx);
1366 gcry_mpi_dump (v_x);
1367 gcry_mpi_dump (v_y);
1368 }
1369 gcry_mpi_release (h);
1370
1371 /* get Q = dG from 'pseudonym' */
1372 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1373 {
1374 fprintf (stderr, "\nVerification q value:\n");
1375 v_x = gcry_mpi_new (256);
1376 v_y = gcry_mpi_new (256);
1377 gcry_mpi_ec_get_affine (v_x, v_y, q, ctx);
1378 gcry_mpi_dump (v_x);
1379 gcry_mpi_dump (v_y);
1380 }
1381 /* calculate V = Q + hG = dG + hG = (d + h)G*/
1382 v = gcry_mpi_point_new (0);
1383 gcry_mpi_ec_add (v, q, hg, xctx);
1384 /* FIXME: free 'hg'? */
1385
1386 /* store 'v' point in "verification_key" */
1387 v_x = gcry_mpi_new (256);
1388 v_y = gcry_mpi_new (256);
1389 gcry_mpi_ec_get_affine (v_x, v_y, v, xctx);
1390
1391 {
1392 fprintf (stderr, "\nVerification key public point value V := q + hG:\n");
1393 gcry_mpi_dump (v_x);
1394 gcry_mpi_dump (v_y);
1395 fprintf (stderr, " <=== WTF!?\n");
1396 }
1397
1398
1399 gcry_mpi_point_release (v);
1400 gcry_ctx_release (ctx);
1401
1402 size = sizeof (verification_key->q_x);
1403 if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, verification_key->q_x, size,
1404 &size, v_x)))
1405 {
1406 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1407 gcry_mpi_release (v_x);
1408 gcry_mpi_release (v_y);
1409 return GNUNET_SYSERR;
1410 }
1411 gcry_mpi_release (v_x);
1412 size = sizeof (verification_key->q_y);
1413 if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, verification_key->q_y, size,
1414 &size, v_y)))
1415 {
1416 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1417 gcry_mpi_release (v_y);
1418 return GNUNET_SYSERR;
1419 }
1420 gcry_mpi_release (v_y);
1421 return GNUNET_OK;
1422}
1423
1424
1425/**
1426 * Verify a signature made with a pseudonym.
1427 *
1428 * @param purpose data that was signed
1429 * @param signature signature to verify
1430 * @param verification_key public key to use for checking the signature;
1431 * corresponds to 'g^(x+h)' in section 2.4 of #2564.
1432 * @return GNUNET_OK on success (signature valid, 'pseudonym' set),
1433 * GNUNET_SYSERR if the signature is invalid
1434 */
1435int
1436GNUNET_PSEUDONYM_verify (const struct GNUNET_PseudonymSignaturePurpose *purpose,
1437 const struct GNUNET_PseudonymSignature *signature,
1438 const struct GNUNET_PseudonymIdentifier *verification_key)
1439{
1440 gcry_sexp_t data;
1441 gcry_sexp_t sig_sexpr;
1442 gcry_sexp_t pk_sexpr;
1443 size_t size;
1444 gcry_ctx_t ctx;
1445 gcry_mpi_t ONE;
1446 gcry_mpi_t r;
1447 gcry_mpi_t s;
1448 gcry_mpi_point_t q;
1449 gcry_mpi_t q_x;
1450 gcry_mpi_t q_y;
1451 size_t erroff;
1452 int rc;
1453
1454 /* build s-expression for signature */
1455 size = sizeof (signature->sig_r);
1456 if (0 != (rc = gcry_mpi_scan (&r, GCRYMPI_FMT_USG,
1457 signature->sig_r, size, &size)))
1458 {
1459 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1460 return GNUNET_SYSERR;
1461 }
1462 size = sizeof (signature->sig_s);
1463 if (0 != (rc = gcry_mpi_scan (&s, GCRYMPI_FMT_USG,
1464 signature->sig_s, size, &size)))
1465 {
1466 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1467 gcry_mpi_release (r);
1468 return GNUNET_SYSERR;
1469 }
1470 if (0 != (rc = gcry_sexp_build (&sig_sexpr, &erroff, "(sig-val(ecdsa(r %m)(s %m)))",
1471 r, s)))
1472 {
1473 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1474 gcry_mpi_release (r);
1475 gcry_mpi_release (s);
1476 return GNUNET_SYSERR;
1477 }
1478 gcry_mpi_release (r);
1479 gcry_mpi_release (s);
1480
1481 /* build s-expression for data that was signed */
1482 data = data_to_pkcs1 (purpose);
1483
1484 /* create context of public key and initialize Q */
1485 size = sizeof (verification_key->q_x);
1486 if (0 != (rc = gcry_mpi_scan (&q_x, GCRYMPI_FMT_USG,
1487 verification_key->q_x, size, &size)))
1488 {
1489 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1490 gcry_sexp_release (data);
1491 gcry_sexp_release (sig_sexpr);
1492 return GNUNET_SYSERR;
1493 }
1494 size = sizeof (verification_key->q_y);
1495 if (0 != (rc = gcry_mpi_scan (&q_y, GCRYMPI_FMT_USG,
1496 verification_key->q_y, size, &size)))
1497 {
1498 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1499 gcry_sexp_release (data);
1500 gcry_sexp_release (sig_sexpr);
1501 gcry_mpi_release (q_x);
1502 return GNUNET_SYSERR;
1503 }
1504 q = gcry_mpi_point_new (256);
1505 ONE = gcry_mpi_new (1);
1506 gcry_mpi_set_ui (ONE, 1);
1507 gcry_mpi_point_set (q, q_x, q_y, ONE); /* FIXME: convenience function 'set_affine'? */
1508 gcry_mpi_release (ONE);
1509 gcry_mpi_release (q_x);
1510 gcry_mpi_release (q_y);
1511
1512 /* create basic ECC context */
1513 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256")))
1514 {
1515 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
1516 gcry_sexp_release (data);
1517 gcry_sexp_release (sig_sexpr);
1518 gcry_mpi_point_release (q);
1519 return GNUNET_SYSERR;
1520 }
1521 /* initialize 'ctx' with 'q' */
1522 gcry_mpi_ec_set_point ("q", q, ctx);
1523 gcry_mpi_point_release (q);
1524
1525 /* convert 'ctx' to 'sexp' */
1526 if (0 != (rc = gcry_pubkey_get_sexp (&pk_sexpr, GCRY_PK_GET_PUBKEY, ctx)))
1527 {
1528 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_from_context", rc);
1529 gcry_ctx_release (ctx);
1530 gcry_sexp_release (data);
1531 gcry_sexp_release (sig_sexpr);
1532 return GNUNET_SYSERR;
1533 }
1534 gcry_ctx_release (ctx);
1535
1536 /* finally, verify the signature */
1537 rc = gcry_pk_verify (sig_sexpr, data, pk_sexpr);
1538 gcry_sexp_release (sig_sexpr);
1539 gcry_sexp_release (data);
1540 gcry_sexp_release (pk_sexpr);
1541 if (rc)
1542 {
1543 LOG (GNUNET_ERROR_TYPE_WARNING,
1544 _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__,
1545 __LINE__, gcry_strerror (rc));
1546exit (1);
1547 return GNUNET_SYSERR;
1548 }
1549 return GNUNET_OK;
1550}
1551
1552
1553/**
1554 * Get the identifier (public key) of a pseudonym.
1555 *
1556 * @param ph pseudonym handle with the private key
1557 * @param pseudonym pseudonym identifier (set based on 'ph')
1558 */
1559void
1560GNUNET_PSEUDONYM_get_identifier (struct GNUNET_PseudonymHandle *ph,
1561 struct GNUNET_PseudonymIdentifier *pseudonym)
1562{
1563 memcpy (pseudonym, &ph->public_key,
1564 sizeof (struct GNUNET_PseudonymIdentifier));
1565}
1566
1567
1568/**
1569 * Remove pseudonym from the set of known pseudonyms.
1570 *
1571 * @param cfg overall configuration
1572 * @param id the pseudonym identifier
1573 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1574 */
1575int
1576GNUNET_PSEUDONYM_remove (const struct GNUNET_CONFIGURATION_Handle *cfg,
1577 const struct GNUNET_PseudonymIdentifier *id)
1578{
1579 char *fn;
1580 int result;
1581
1582 fn = get_data_filename (cfg, PS_METADATA_DIR, id);
1583 if (NULL == fn)
1584 return GNUNET_SYSERR;
1585 result = UNLINK (fn);
1586 GNUNET_free (fn);
1587 return (0 == result) ? GNUNET_OK : GNUNET_SYSERR;
1588}
1589
1590/* 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 @@
26 26
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_block_plugin.h" 28#include "gnunet_block_plugin.h"
29#include "gnunet_fs_service.h"
29#include "block_fs.h" 30#include "block_fs.h"
30#include "gnunet_signatures.h" 31#include "gnunet_signatures.h"
31 32
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 @@
1/*
2 This file is part of GNUnet.
3 (C) 2005--2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file fs/test_pseudonym.c
23 * @brief testcase for fs_pseudonym.c
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_common.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_fs_service.h"
30#include "gnunet_signatures.h"
31
32#define CHECK(a) do { if (!(a)) { ok = GNUNET_NO; GNUNET_break(0); goto FAILURE; } } while (0)
33
34static struct GNUNET_CONTAINER_MetaData *meta;
35
36static struct GNUNET_PseudonymIdentifier id1;
37
38
39static int
40iter (void *cls, const struct GNUNET_PseudonymIdentifier * pseudonym,
41 const char *name, const char *unique_name,
42 const struct GNUNET_CONTAINER_MetaData *md, int32_t rating)
43{
44 int *ok = cls;
45
46 if ((0 == memcmp (pseudonym, &id1, sizeof (struct GNUNET_PseudonymIdentifier))) &&
47 (!GNUNET_CONTAINER_meta_data_test_equal (md, meta)))
48 {
49 *ok = GNUNET_NO;
50 GNUNET_break (0);
51 }
52 return GNUNET_OK;
53}
54
55
56static int
57noti_callback (void *cls, const struct GNUNET_PseudonymIdentifier * pseudonym,
58 const char *name, const char *unique_name,
59 const struct GNUNET_CONTAINER_MetaData *md, int32_t rating)
60{
61 int *ret = cls;
62
63 (*ret)++;
64 return GNUNET_OK;
65}
66
67
68static int
69fake_noti_callback (void *cls, const struct GNUNET_PseudonymIdentifier * pseudonym,
70 const char *name, const char *unique_name,
71 const struct GNUNET_CONTAINER_MetaData *md, int32_t rating)
72{
73 int *ret = cls;
74
75 (*ret)++;
76 return GNUNET_OK;
77}
78
79
80static void
81create_pseu (struct GNUNET_PseudonymIdentifier *pseu)
82{
83 struct GNUNET_PseudonymHandle *ph;
84
85 ph = GNUNET_PSEUDONYM_create (NULL);
86 GNUNET_PSEUDONYM_get_identifier (ph, pseu);
87 GNUNET_PSEUDONYM_destroy (ph);
88}
89
90
91/**
92 * Testcase for meta data / ranking IO routines.
93 */
94static int
95test_io ()
96{
97 int ok;
98 struct GNUNET_PseudonymIdentifier rid1;
99 struct GNUNET_PseudonymIdentifier id2;
100 struct GNUNET_PseudonymIdentifier rid2;
101 struct GNUNET_PseudonymIdentifier fid;
102 struct GNUNET_PseudonymIdentifier id3;
103 int old;
104 int newVal;
105 struct GNUNET_CONFIGURATION_Handle *cfg;
106 char *name1;
107 char *name2;
108 char *name3;
109 char *name1_unique;
110 char *name2_unique;
111 char *noname;
112 int noname_is_a_dup;
113 int notiCount, fakenotiCount;
114 static char m[1024 * 1024 * 10];
115 struct GNUNET_PSEUDONYM_DiscoveryHandle *dh1;
116 struct GNUNET_PSEUDONYM_DiscoveryHandle *dh2;
117
118 memset (m, 'b', sizeof (m));
119 m[sizeof (m) - 1] = '\0';
120
121 GNUNET_log_setup ("test-pseudonym", "WARNING", NULL);
122 ok = GNUNET_YES;
123 (void) GNUNET_DISK_directory_remove ("/tmp/gnunet-pseudonym-test");
124 cfg = GNUNET_CONFIGURATION_create ();
125 if (-1 == GNUNET_CONFIGURATION_parse (cfg, "test_pseudonym_data.conf"))
126 {
127 GNUNET_CONFIGURATION_destroy (cfg);
128 GNUNET_break (0);
129 return -1;
130 }
131 notiCount = 0;
132 fakenotiCount = 0;
133 dh1 = GNUNET_PSEUDONYM_discovery_callback_register (cfg, &fake_noti_callback,
134 &fakenotiCount);
135 dh2 = GNUNET_PSEUDONYM_discovery_callback_register (cfg, &noti_callback,
136 &notiCount);
137 GNUNET_PSEUDONYM_discovery_callback_unregister (dh1);
138
139 /* ACTUAL TEST CODE */
140 old = GNUNET_PSEUDONYM_list_all (cfg, NULL, NULL);
141 meta = GNUNET_CONTAINER_meta_data_create ();
142 GNUNET_CONTAINER_meta_data_insert (meta, "<test>", EXTRACTOR_METATYPE_TITLE,
143 EXTRACTOR_METAFORMAT_UTF8, "text/plain",
144 "test", strlen ("test") + 1);
145 create_pseu (&id1);
146 GNUNET_PSEUDONYM_add (cfg, &id1, meta);
147 CHECK (notiCount == 1);
148 GNUNET_PSEUDONYM_add (cfg, &id1, meta);
149 CHECK (notiCount == 2);
150 newVal = GNUNET_PSEUDONYM_list_all (cfg, &iter, &ok);
151 CHECK (old < newVal);
152 old = newVal;
153 create_pseu (&id2);
154 GNUNET_PSEUDONYM_add (cfg, &id2, meta);
155 CHECK (notiCount == 3);
156 newVal = GNUNET_PSEUDONYM_list_all (cfg, &iter, &ok);
157 CHECK (old < newVal);
158 GNUNET_assert (GNUNET_OK ==
159 GNUNET_CONTAINER_meta_data_insert (meta, "<test>",
160 EXTRACTOR_METATYPE_COMMENT,
161 EXTRACTOR_METAFORMAT_UTF8,
162 "text/plain", m,
163 strlen (m) + 1));
164 create_pseu (&id3);
165 GNUNET_PSEUDONYM_add (cfg, &id3, meta);
166 GNUNET_PSEUDONYM_get_info (cfg, &id3, NULL, NULL, &name3, NULL);
167 CHECK (name3 != NULL);
168 GNUNET_PSEUDONYM_get_info (cfg, &id2, NULL, NULL, &name2, NULL);
169 CHECK (name2 != NULL);
170 GNUNET_PSEUDONYM_get_info (cfg, &id1, NULL, NULL, &name1, NULL);
171 CHECK (name1 != NULL);
172 CHECK (0 == strcmp (name1, name2));
173 name1_unique = GNUNET_PSEUDONYM_name_uniquify (cfg, &id1, name1, NULL);
174 name2_unique = GNUNET_PSEUDONYM_name_uniquify (cfg, &id2, name2, NULL);
175 CHECK (0 != strcmp (name1_unique, name2_unique));
176 CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, "fake", &rid2));
177 CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, name2, &rid2));
178 CHECK (GNUNET_SYSERR == GNUNET_PSEUDONYM_name_to_id (cfg, name1, &rid1));
179 CHECK (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, name2_unique, &rid2));
180 CHECK (GNUNET_OK == GNUNET_PSEUDONYM_name_to_id (cfg, name1_unique, &rid1));
181 CHECK (0 == memcmp (&id1, &rid1, sizeof (struct GNUNET_PseudonymIdentifier)));
182 CHECK (0 == memcmp (&id2, &rid2, sizeof (struct GNUNET_PseudonymIdentifier)));
183
184 create_pseu (&fid);
185 GNUNET_log_skip (1, GNUNET_NO);
186 CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &fid, 0));
187 GNUNET_log_skip (0, GNUNET_NO);
188 CHECK (GNUNET_OK == GNUNET_PSEUDONYM_get_info (cfg, &fid, NULL, NULL, &noname, &noname_is_a_dup));
189 CHECK (noname != NULL);
190 CHECK (noname_is_a_dup == GNUNET_YES);
191 CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &id1, 0));
192 CHECK (5 == GNUNET_PSEUDONYM_rank (cfg, &id1, 5));
193 CHECK (-5 == GNUNET_PSEUDONYM_rank (cfg, &id1, -10));
194 CHECK (0 == GNUNET_PSEUDONYM_rank (cfg, &id1, 5));
195 GNUNET_free (name1);
196 GNUNET_free (name2);
197 GNUNET_free (name1_unique);
198 GNUNET_free (name2_unique);
199 GNUNET_free (name3);
200 GNUNET_free (noname);
201 /* END OF TEST CODE */
202FAILURE:
203 GNUNET_PSEUDONYM_discovery_callback_unregister (dh2);
204 GNUNET_CONTAINER_meta_data_destroy (meta);
205 GNUNET_CONFIGURATION_destroy (cfg);
206 return (ok == GNUNET_YES) ? 0 : 1;
207}
208
209
210/**
211 * Use the given input to sign and check the resulting signature.
212 */
213static void
214test_signature (struct GNUNET_PseudonymHandle *ph,
215 struct GNUNET_PseudonymSignaturePurpose *purpose,
216 struct GNUNET_HashCode *seed,
217 struct GNUNET_HashCode *signing_key,
218 char *bit)
219{
220 struct GNUNET_PseudonymSignature signature;
221 struct GNUNET_PseudonymSignature signature2;
222 struct GNUNET_PseudonymIdentifier pseudonym;
223 struct GNUNET_PseudonymIdentifier verification_key;
224
225 GNUNET_PSEUDONYM_sign (ph, purpose, seed, signing_key, &signature);
226 if (0)
227 {
228 GNUNET_PSEUDONYM_sign (ph, purpose, seed, signing_key, &signature2);
229 /* with seed, two sigs must be identical, without, they must be different! */
230 if (NULL != seed)
231 GNUNET_break (0 == memcmp (&signature, &signature2, sizeof (signature)));
232 else /* crypto not implemented, thus for now 'break' */
233 GNUNET_break (0 != memcmp (&signature, &signature2, sizeof (signature)));
234 }
235 GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym);
236 GNUNET_PSEUDONYM_derive_verification_key (&pseudonym,
237 signing_key,
238 &verification_key);
239 GNUNET_break (GNUNET_OK ==
240 GNUNET_PSEUDONYM_verify (purpose, &signature, &verification_key));
241 /* also check that if the data is changed, the signature no longer matches */
242 (*bit)++;
243 /* crypto not implemented, thus for now 'break' */
244 GNUNET_break (GNUNET_OK !=
245 GNUNET_PSEUDONYM_verify (purpose, &signature, &verification_key));
246 (*bit)--;
247}
248
249
250/**
251 * Test cryptographic operations for a given private key.
252 *
253 * @param ph private key to test
254 */
255static void
256test_crypto_ops (struct GNUNET_PseudonymHandle *ph)
257{
258 char data[16];
259 struct GNUNET_PseudonymSignaturePurpose *purpose;
260 struct GNUNET_HashCode seed;
261 struct GNUNET_HashCode signing_key;
262
263 memset (data, 42, sizeof (data));
264 purpose = (struct GNUNET_PseudonymSignaturePurpose *) data;
265 purpose->size = htonl (sizeof (data));
266 purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST);
267 memset (&seed, 41, sizeof (seed));
268 memset (&signing_key, 40, sizeof (signing_key));
269 test_signature (ph, purpose, &seed, &signing_key, &data[sizeof (struct GNUNET_PseudonymSignaturePurpose)]);
270 test_signature (ph, purpose, NULL, &signing_key, &data[sizeof (struct GNUNET_PseudonymSignaturePurpose)]);
271}
272
273
274/**
275 * Test cryptographic operations.
276 */
277static int
278test_crypto ()
279{
280 struct GNUNET_PseudonymHandle *ph;
281 struct GNUNET_PseudonymIdentifier pseudonym;
282 struct GNUNET_PseudonymIdentifier pseudonym2;
283
284 /* check writing to and reading from disk */
285 ph = GNUNET_PSEUDONYM_create ("/tmp/gnunet-pseudonym-test/pseu.dsa");
286 GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym);
287 GNUNET_PSEUDONYM_destroy (ph);
288 ph = GNUNET_PSEUDONYM_create ("/tmp/gnunet-pseudonym-test/pseu.dsa");
289 GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym2);
290 test_crypto_ops (ph);
291 GNUNET_PSEUDONYM_destroy (ph);
292 if (0 != memcmp (&pseudonym, &pseudonym2, sizeof (pseudonym)))
293 return 1;
294
295 /* check in-memory generation */
296 ph = GNUNET_PSEUDONYM_create (NULL);
297 GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym2);
298 if (0 == memcmp (&pseudonym, &pseudonym2, sizeof (pseudonym)))
299 return 1;
300 test_crypto_ops (ph);
301 GNUNET_PSEUDONYM_destroy (ph);
302
303 /* check anonymous pseudonym operations generation */
304 ph = GNUNET_PSEUDONYM_get_anonymous_pseudonym_handle ();
305 GNUNET_PSEUDONYM_get_identifier (ph, &pseudonym2);
306 if (0 == memcmp (&pseudonym, &pseudonym2, sizeof (pseudonym)))
307 return 1;
308 test_crypto_ops (ph);
309 GNUNET_PSEUDONYM_destroy (ph);
310 return 0;
311}
312
313
314int
315main (int argc, char *argv[])
316{
317 if (0 != test_io ())
318 return 1;
319 if (0 != test_crypto ())
320 return 1;
321 GNUNET_break (GNUNET_OK ==
322 GNUNET_DISK_directory_remove ("/tmp/gnunet-pseudonym-test"));
323 return 0;
324}
325
326
327/* end of test_pseudoynm.c */