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