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