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