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