2 This file is part of GNUnet
3 (C) 2003-2013 Christian Grothoff (and other contributing authors)
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.
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.
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.
21 * @file fs/fs_pseudonym.c
22 * @brief pseudonym functions
23 * @author Christian Grothoff
26 * - all cryptographic operations are currently NOT implemented and
27 * provided by stubs that merely pretend to work!
30 #include "gnunet_util_lib.h"
31 #include "gnunet_fs_service.h"
35 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
37 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
39 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
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).
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);
49 * Name of the directory which stores meta data for pseudonym
51 #define PS_METADATA_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonym" DIR_SEPARATOR_STR "metadata" DIR_SEPARATOR_STR
54 * Name of the directory which stores names for pseudonyms
56 #define PS_NAMES_DIR DIR_SEPARATOR_STR "data" DIR_SEPARATOR_STR "pseudonym" DIR_SEPARATOR_STR "names" DIR_SEPARATOR_STR
60 * Configuration section we use.
62 #define GNUNET_CLIENT_SERVICE_NAME "fs"
65 /* ************************* Disk operations (pseudonym data mgmt) **************** */
68 * Registered callbacks for discovery of pseudonyms.
70 struct GNUNET_FS_pseudonym_DiscoveryHandle
73 * This is a doubly linked list.
75 struct GNUNET_FS_pseudonym_DiscoveryHandle *next;
78 * This is a doubly linked list.
80 struct GNUNET_FS_pseudonym_DiscoveryHandle *prev;
83 * Function to call each time a pseudonym is discovered.
85 GNUNET_FS_PseudonymIterator callback;
88 * Closure for callback.
95 * Head of the linked list of functions to call when
96 * new pseudonyms are added.
98 static struct GNUNET_FS_pseudonym_DiscoveryHandle *disco_head;
101 * Tail of the linked list of functions to call when
102 * new pseudonyms are added.
104 static struct GNUNET_FS_pseudonym_DiscoveryHandle *disco_tail;
107 * Pointer to indiate 'anonymous' pseudonym (global static,
108 * d=1, public key = G (generator).
110 static struct GNUNET_FS_PseudonymHandle anonymous;
113 * Internal notification about new tracked URI.
115 * @param pseudonym public key of the pseudonym
116 * @param md meta data to be written
117 * @param rating rating of pseudonym
120 internal_notify (const struct GNUNET_FS_PseudonymIdentifier *pseudonym,
121 const struct GNUNET_CONTAINER_MetaData *md, int rating)
123 struct GNUNET_FS_pseudonym_DiscoveryHandle *pos;
125 for (pos = disco_head; NULL != pos; pos = pos->next)
126 pos->callback (pos->callback_cls, pseudonym, NULL, NULL, md, rating);
131 * Register callback to be invoked whenever we discover
133 * Will immediately call provided iterator callback for all
134 * already discovered pseudonyms.
136 * @param cfg configuration to use
137 * @param iterator iterator over pseudonym
138 * @param iterator_cls point to a closure
139 * @return registration handle
141 struct GNUNET_FS_pseudonym_DiscoveryHandle *
142 GNUNET_FS_pseudonym_discovery_callback_register (const struct
143 GNUNET_CONFIGURATION_Handle *cfg,
144 GNUNET_FS_PseudonymIterator iterator,
147 struct GNUNET_FS_pseudonym_DiscoveryHandle *dh;
149 dh = GNUNET_malloc (sizeof (struct GNUNET_FS_pseudonym_DiscoveryHandle));
150 dh->callback = iterator;
151 dh->callback_cls = iterator_cls;
152 GNUNET_CONTAINER_DLL_insert (disco_head, disco_tail, dh);
153 GNUNET_FS_pseudonym_list_all (cfg, iterator, iterator_cls);
159 * Unregister pseudonym discovery callback.
161 * @param dh registration to unregister
164 GNUNET_FS_pseudonym_discovery_callback_unregister (struct GNUNET_FS_pseudonym_DiscoveryHandle *dh)
166 GNUNET_CONTAINER_DLL_remove (disco_head, disco_tail, dh);
172 * Get the filename (or directory name) for the given
173 * pseudonym identifier and directory prefix.
175 * @param cfg configuration to use
176 * @param prefix path components to append to the private directory name
177 * @param pseudonym the pseudonym, can be NULL
178 * @return filename of the pseudonym (if pseudonym != NULL) or directory with the data (if pseudonym == NULL)
181 get_data_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
183 const struct GNUNET_FS_PseudonymIdentifier *pseudonym)
185 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
186 struct GNUNET_HashCode psid;
188 if (NULL != pseudonym)
190 GNUNET_CRYPTO_hash (pseudonym,
191 sizeof (struct GNUNET_FS_PseudonymIdentifier),
193 GNUNET_CRYPTO_hash_to_enc (&psid, &enc);
195 return GNUNET_DISK_get_home_filename (cfg,
196 GNUNET_CLIENT_SERVICE_NAME, prefix,
199 : (const char *) &enc,
205 * Get the filename (or directory name) for the given
206 * hash code and directory prefix.
208 * @param cfg configuration to use
209 * @param prefix path components to append to the private directory name
210 * @param hc some hash code
211 * @return filename of the pseudonym (if hc != NULL) or directory with the data (if hc == NULL)
214 get_data_filename_hash (const struct GNUNET_CONFIGURATION_Handle *cfg,
216 const struct GNUNET_HashCode *hc)
218 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
221 GNUNET_CRYPTO_hash_to_enc (hc, &enc);
222 return GNUNET_DISK_get_home_filename (cfg,
223 GNUNET_CLIENT_SERVICE_NAME, prefix,
226 : (const char *) &enc,
232 * Set the pseudonym metadata, rank and name.
233 * Writes the pseudonym infomation into a file
235 * @param cfg overall configuration
236 * @param pseudonym id of the pseudonym
237 * @param name name to set. Must be the non-unique version of it.
238 * May be NULL, in which case it erases pseudonym's name!
239 * @param md metadata to set
240 * May be NULL, in which case it erases pseudonym's metadata!
241 * @param rank rank to assign
242 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
245 GNUNET_FS_pseudonym_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
246 const struct GNUNET_FS_PseudonymIdentifier *pseudonym,
248 const struct GNUNET_CONTAINER_MetaData *md,
252 struct GNUNET_BIO_WriteHandle *fileW;
254 fn = get_data_filename (cfg, PS_METADATA_DIR, pseudonym);
255 if (NULL == (fileW = GNUNET_BIO_write_open (fn)))
258 return GNUNET_SYSERR;
260 if ((GNUNET_OK != GNUNET_BIO_write (fileW, pseudonym,
261 sizeof (struct GNUNET_FS_PseudonymIdentifier))) ||
262 (GNUNET_OK != GNUNET_BIO_write_int32 (fileW, rank)) ||
263 (GNUNET_OK != GNUNET_BIO_write_string (fileW, name)) ||
264 (GNUNET_OK != GNUNET_BIO_write_meta_data (fileW, md)))
266 (void) GNUNET_BIO_write_close (fileW);
267 GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
269 return GNUNET_SYSERR;
271 if (GNUNET_OK != GNUNET_BIO_write_close (fileW))
273 GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
275 return GNUNET_SYSERR;
278 /* create entry for pseudonym name in names */
280 GNUNET_free_non_null (GNUNET_FS_pseudonym_name_uniquify (cfg, pseudonym,
287 * Read pseudonym infomation from a file
289 * @param cfg configuration to use
290 * @param pseudonym hash code of a pseudonym
291 * @param meta meta data to be read from a file
292 * @param rank rank of a pseudonym
293 * @param ns_name name of a pseudonym
294 * @return GNUNET_OK on success, GNUNET_SYSERR on error
297 read_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
298 const struct GNUNET_FS_PseudonymIdentifier *pseudonym,
299 struct GNUNET_CONTAINER_MetaData **meta,
303 struct GNUNET_FS_PseudonymIdentifier pd;
306 struct GNUNET_BIO_ReadHandle *fileR;
308 fn = get_data_filename (cfg, PS_METADATA_DIR, pseudonym);
310 GNUNET_DISK_file_test (fn))
313 return GNUNET_SYSERR;
315 if (NULL == (fileR = GNUNET_BIO_read_open (fn)))
318 return GNUNET_SYSERR;
322 if ( (GNUNET_OK != GNUNET_BIO_read (fileR, "pseudonym", &pd, sizeof (pd))) ||
323 (0 != memcmp (&pd, pseudonym, sizeof (pd))) ||
324 (GNUNET_OK != GNUNET_BIO_read_int32 (fileR, rank)) ||
326 GNUNET_BIO_read_string (fileR, "Read string error!", ns_name, 200)) ||
328 GNUNET_BIO_read_meta_data (fileR, "Read meta data error!", meta)) )
330 (void) GNUNET_BIO_read_close (fileR, &emsg);
331 GNUNET_free_non_null (emsg);
332 GNUNET_free_non_null (*ns_name);
334 GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
336 return GNUNET_SYSERR;
338 if (GNUNET_OK != GNUNET_BIO_read_close (fileR, &emsg))
340 LOG (GNUNET_ERROR_TYPE_WARNING,
341 _("Failed to parse metadata about pseudonym from file `%s': %s\n"), fn,
343 GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fn));
344 GNUNET_CONTAINER_meta_data_destroy (*meta);
346 GNUNET_free_non_null (*ns_name);
348 GNUNET_free_non_null (emsg);
350 return GNUNET_SYSERR;
358 * Return unique variant of the namespace name. Use it after
359 * GNUNET_FS_pseudonym_get_info() to make sure that name is unique.
361 * @param cfg configuration
362 * @param pseudonym public key of the pseudonym
363 * @param name name to uniquify
364 * @param suffix if not NULL, filled with the suffix value
365 * @return NULL on failure (should never happen), name on success.
366 * Free the name with GNUNET_free().
369 GNUNET_FS_pseudonym_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg,
370 const struct GNUNET_FS_PseudonymIdentifier *pseudonym,
372 unsigned int *suffix)
374 struct GNUNET_HashCode nh;
375 struct GNUNET_FS_PseudonymIdentifier pi;
378 struct GNUNET_DISK_FileHandle *fh;
384 GNUNET_CRYPTO_hash (name, strlen (name), &nh);
385 fn = get_data_filename_hash (cfg, PS_NAMES_DIR, &nh);
387 if (0 == STAT (fn, &sbuf))
388 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES));
389 fh = GNUNET_DISK_file_open (fn,
390 GNUNET_DISK_OPEN_CREATE |
391 GNUNET_DISK_OPEN_READWRITE,
392 GNUNET_DISK_PERM_USER_READ |
393 GNUNET_DISK_PERM_USER_WRITE);
396 while ((len >= sizeof (struct GNUNET_FS_PseudonymIdentifier)) &&
397 (sizeof (struct GNUNET_FS_PseudonymIdentifier) ==
398 GNUNET_DISK_file_read (fh, &pi, sizeof (struct GNUNET_FS_PseudonymIdentifier))))
400 if (0 == memcmp (&pi, pseudonym, sizeof (struct GNUNET_FS_PseudonymIdentifier)))
406 len -= sizeof (struct GNUNET_HashCode);
411 if (sizeof (struct GNUNET_FS_PseudonymIdentifier) !=
412 GNUNET_DISK_file_write (fh, pseudonym, sizeof (struct GNUNET_FS_PseudonymIdentifier)))
413 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "write", fn);
415 GNUNET_DISK_file_close (fh);
416 ret = GNUNET_malloc (strlen (name) + 32);
417 GNUNET_snprintf (ret, strlen (name) + 32, "%s-%u", name, idx);
426 * Get namespace name, metadata and rank
427 * This is a wrapper around internal read_info() call, and ensures that
428 * returned data is not invalid (not NULL).
430 * @param cfg configuration
431 * @param pseudonym public key of the pseudonym
432 * @param ret_meta a location to store metadata pointer. NULL, if metadata
433 * is not needed. Destroy with GNUNET_CONTAINER_meta_data_destroy().
434 * @param ret_rank a location to store rank. NULL, if rank not needed.
435 * @param ret_name a location to store human-readable name. Name is not unique.
436 * NULL, if name is not needed. Free with GNUNET_free().
437 * @param name_is_a_dup is set to GNUNET_YES, if ret_name was filled with
438 * a duplicate of a "no-name" placeholder
439 * @return GNUNET_OK on success. GNUENT_SYSERR if the data was
440 * unobtainable (in that case ret_* are filled with placeholders -
441 * empty metadata container, rank -1 and a "no-name" name).
444 GNUNET_FS_pseudonym_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
445 const struct GNUNET_FS_PseudonymIdentifier *pseudonym,
446 struct GNUNET_CONTAINER_MetaData **ret_meta,
451 struct GNUNET_CONTAINER_MetaData *meta;
457 if (GNUNET_OK == read_info (cfg, pseudonym, &meta, &rank, &name))
459 if ((meta != NULL) && (name == NULL))
461 GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
462 EXTRACTOR_METATYPE_TITLE,
463 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME,
464 EXTRACTOR_METATYPE_FILENAME,
465 EXTRACTOR_METATYPE_DESCRIPTION,
466 EXTRACTOR_METATYPE_SUBJECT,
467 EXTRACTOR_METATYPE_PUBLISHER,
468 EXTRACTOR_METATYPE_AUTHOR_NAME,
469 EXTRACTOR_METATYPE_COMMENT,
470 EXTRACTOR_METATYPE_SUMMARY,
472 if (ret_name != NULL)
476 name = GNUNET_strdup (_("no-name"));
477 if (name_is_a_dup != NULL)
478 *name_is_a_dup = GNUNET_YES;
480 else if (name_is_a_dup != NULL)
481 *name_is_a_dup = GNUNET_NO;
484 else if (name != NULL)
487 if (ret_meta != NULL)
490 meta = GNUNET_CONTAINER_meta_data_create ();
493 else if (meta != NULL)
494 GNUNET_CONTAINER_meta_data_destroy (meta);
496 if (ret_rank != NULL)
501 if (ret_name != NULL)
502 *ret_name = GNUNET_strdup (_("no-name"));
503 if (ret_meta != NULL)
504 *ret_meta = GNUNET_CONTAINER_meta_data_create ();
505 if (ret_rank != NULL)
507 if (name_is_a_dup != NULL)
508 *name_is_a_dup = GNUNET_YES;
509 return GNUNET_SYSERR;
514 * Get the namespace ID belonging to the given namespace name.
516 * @param cfg configuration to use
517 * @param ns_uname unique (!) human-readable name for the namespace
518 * @param pseudonym set to public key of pseudonym based on 'ns_uname'
519 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
522 GNUNET_FS_pseudonym_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg,
523 const char *ns_uname,
524 struct GNUNET_FS_PseudonymIdentifier *pseudonym)
530 struct GNUNET_HashCode nh;
532 struct GNUNET_DISK_FileHandle *fh;
535 slen = strlen (ns_uname);
536 while ((slen > 0) && (1 != SSCANF (&ns_uname[slen - 1], "-%u", &idx)))
539 return GNUNET_SYSERR;
540 name = GNUNET_strdup (ns_uname);
541 name[slen - 1] = '\0';
543 GNUNET_CRYPTO_hash (name, strlen (name), &nh);
545 fn = get_data_filename_hash (cfg, PS_NAMES_DIR, &nh);
547 if ((GNUNET_OK != GNUNET_DISK_file_test (fn) ||
548 (GNUNET_OK != GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES))) ||
549 ((idx + 1) * sizeof (struct GNUNET_FS_PseudonymIdentifier) > len))
552 return GNUNET_SYSERR;
554 fh = GNUNET_DISK_file_open (fn,
555 GNUNET_DISK_OPEN_CREATE |
556 GNUNET_DISK_OPEN_READWRITE,
557 GNUNET_DISK_PERM_USER_READ |
558 GNUNET_DISK_PERM_USER_WRITE);
561 GNUNET_DISK_file_seek (fh, idx * sizeof (struct GNUNET_FS_PseudonymIdentifier),
562 GNUNET_DISK_SEEK_SET))
564 GNUNET_DISK_file_close (fh);
565 return GNUNET_SYSERR;
567 if (sizeof (struct GNUNET_FS_PseudonymIdentifier) !=
568 GNUNET_DISK_file_read (fh, pseudonym, sizeof (struct GNUNET_FS_PseudonymIdentifier)))
570 GNUNET_DISK_file_close (fh);
571 return GNUNET_SYSERR;
573 GNUNET_DISK_file_close (fh);
580 * struct used to list the pseudonym
582 struct ListPseudonymClosure
586 * iterator over pseudonym
588 GNUNET_FS_PseudonymIterator iterator;
591 * Closure for iterator.
596 * Configuration to use.
598 const struct GNUNET_CONFIGURATION_Handle *cfg;
604 * Helper function to list all available pseudonyms
606 * @param cls point to a struct ListPseudonymClosure
607 * @param fullname name of pseudonym
610 list_pseudonym_helper (void *cls, const char *fullname)
612 struct ListPseudonymClosure *lpc = cls;
613 struct GNUNET_FS_PseudonymIdentifier pd;
615 struct GNUNET_BIO_ReadHandle *fileR;
618 struct GNUNET_CONTAINER_MetaData *meta;
622 if (NULL == (fileR = GNUNET_BIO_read_open (fullname)))
623 return GNUNET_SYSERR;
626 if ( (GNUNET_OK != GNUNET_BIO_read (fileR, "pseudonym", &pd, sizeof (pd))) ||
627 (GNUNET_OK != GNUNET_BIO_read_int32 (fileR, &rank)) ||
629 GNUNET_BIO_read_string (fileR, "Read string error!", &ns_name, 200)) ||
631 GNUNET_BIO_read_meta_data (fileR, "Read meta data error!", &meta)) )
633 (void) GNUNET_BIO_read_close (fileR, &emsg);
634 GNUNET_free_non_null (emsg);
635 GNUNET_free_non_null (ns_name);
636 GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fullname));
637 return GNUNET_SYSERR;
640 ns_name = GNUNET_strdup (_("no-name"));
641 if (GNUNET_OK != GNUNET_BIO_read_close (fileR, &emsg))
643 LOG (GNUNET_ERROR_TYPE_WARNING,
644 _("Failed to parse metadata about pseudonym from file `%s': %s\n"), fullname,
646 GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_remove (fullname));
647 GNUNET_CONTAINER_meta_data_destroy (meta);
648 GNUNET_free (ns_name);
649 GNUNET_free_non_null (emsg);
650 return GNUNET_SYSERR;
653 name_unique = GNUNET_FS_pseudonym_name_uniquify (lpc->cfg, &pd, ns_name, NULL);
654 if (NULL != lpc->iterator)
655 ret = lpc->iterator (lpc->iterator_cls, &pd, ns_name, name_unique, meta, rank);
656 GNUNET_free (ns_name);
657 GNUNET_free_non_null (name_unique);
658 GNUNET_CONTAINER_meta_data_destroy (meta);
664 * List all available pseudonyms.
666 * @param cfg overall configuration
667 * @param iterator function to call for each pseudonym
668 * @param iterator_cls closure for iterator
669 * @return number of pseudonyms found
672 GNUNET_FS_pseudonym_list_all (const struct GNUNET_CONFIGURATION_Handle *cfg,
673 GNUNET_FS_PseudonymIterator iterator,
676 struct ListPseudonymClosure cls;
680 cls.iterator = iterator;
681 cls.iterator_cls = iterator_cls;
683 fn = get_data_filename (cfg, PS_METADATA_DIR, NULL);
684 GNUNET_assert (fn != NULL);
685 GNUNET_DISK_directory_create (fn);
686 ret = GNUNET_DISK_directory_scan (fn, &list_pseudonym_helper, &cls);
693 * Change the rank of a pseudonym.
695 * @param cfg overall configuration
696 * @param pseudonym the pseudonym
697 * @param delta by how much should the rating be changed?
698 * @return new rating of the pseudonym
701 GNUNET_FS_pseudonym_rank (const struct GNUNET_CONFIGURATION_Handle *cfg,
702 const struct GNUNET_FS_PseudonymIdentifier *pseudonym,
705 struct GNUNET_CONTAINER_MetaData *meta;
711 ret = read_info (cfg, pseudonym, &meta, &rank, &name);
712 if (ret == GNUNET_SYSERR)
715 meta = GNUNET_CONTAINER_meta_data_create ();
718 GNUNET_FS_pseudonym_set_info (cfg, pseudonym, name, meta, rank);
719 GNUNET_CONTAINER_meta_data_destroy (meta);
720 GNUNET_free_non_null (name);
726 * Add a pseudonym to the set of known pseudonyms.
727 * For all pseudonym advertisements that we discover
728 * FS should automatically call this function.
730 * @param cfg overall configuration
731 * @param pseudonym the pseudonym to add
732 * @param meta metadata for the pseudonym
733 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
736 GNUNET_FS_pseudonym_add (const struct GNUNET_CONFIGURATION_Handle *cfg,
737 const struct GNUNET_FS_PseudonymIdentifier *pseudonym,
738 const struct GNUNET_CONTAINER_MetaData *meta)
742 struct GNUNET_CONTAINER_MetaData *old;
748 fn = get_data_filename (cfg, PS_METADATA_DIR, pseudonym);
749 GNUNET_assert (fn != NULL);
751 if ((0 == STAT (fn, &sbuf)) &&
752 (GNUNET_OK == read_info (cfg, pseudonym, &old, &rank, &name)))
754 GNUNET_CONTAINER_meta_data_merge (old, meta);
755 ret = GNUNET_FS_pseudonym_set_info (cfg, pseudonym, name, old, rank);
756 GNUNET_CONTAINER_meta_data_destroy (old);
757 GNUNET_free_non_null (name);
761 ret = GNUNET_FS_pseudonym_set_info (cfg, pseudonym, NULL, meta, rank);
764 internal_notify (pseudonym, meta, rank);
769 /* ***************************** cryptographic operations ************************* */
772 * Handle for a pseudonym (private key).
774 struct GNUNET_FS_PseudonymHandle
777 * 256-bit 'd' secret value (mod 'n', where n is 256-bit for NIST P-256).
779 unsigned char d[256 / 8];
782 * Public key corresponding to the private key.
784 struct GNUNET_FS_PseudonymIdentifier public_key;
789 * If target != size, move target bytes to the end of the size-sized
790 * buffer and zero out the first target-size bytes.
792 * @param buf original buffer
793 * @param size number of bytes in the buffer
794 * @param target target size of the buffer
797 adjust (unsigned char *buf, size_t size, size_t target)
801 memmove (&buf[target - size], buf, size);
802 memset (buf, 0, target - size);
808 * Extract values from an S-expression.
810 * @param array where to store the result(s)
811 * @param sexp S-expression to parse
812 * @param topname top-level name in the S-expression that is of interest
813 * @param elems names of the elements to extract
814 * @return 0 on success
817 key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
826 if (! (list = gcry_sexp_find_token (sexp, topname, 0)))
828 l2 = gcry_sexp_cadr (list);
829 gcry_sexp_release (list);
834 for (s = elems; *s; s++, idx++)
836 if (! (l2 = gcry_sexp_find_token (list, s, 1)))
838 for (i = 0; i < idx; i++)
840 gcry_free (array[i]);
843 gcry_sexp_release (list);
844 return 3; /* required parameter not found */
846 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
847 gcry_sexp_release (l2);
850 for (i = 0; i < idx; i++)
852 gcry_free (array[i]);
855 gcry_sexp_release (list);
856 return 4; /* required parameter is invalid */
859 gcry_sexp_release (list);
865 * Create a pseudonym.
867 * @param filename name of the file to use for storage, NULL for in-memory only
868 * @return handle to the private key of the pseudonym
870 struct GNUNET_FS_PseudonymHandle *
871 GNUNET_FS_pseudonym_create (const char *filename)
873 struct GNUNET_FS_PseudonymHandle *ph;
885 ph = GNUNET_malloc (sizeof (struct GNUNET_FS_PseudonymHandle));
886 if ( (NULL != filename) &&
887 (GNUNET_YES == GNUNET_DISK_file_test (filename)) )
889 ret = GNUNET_DISK_fn_read (filename, ph,
890 sizeof (struct GNUNET_FS_PseudonymHandle));
891 /* Note: we don't do any validation here, maybe we should? */
892 if (sizeof (struct GNUNET_FS_PseudonymHandle) == ret)
895 if (0 != (rc = gcry_sexp_build (¶ms, NULL,
896 "(genkey(ecdsa(curve \"NIST P-256\")))")))
898 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
901 if (0 != (rc = gcry_pk_genkey (&r_key, params)))
903 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
904 gcry_sexp_release (params);
905 gcry_sexp_release (r_key);
908 gcry_sexp_release (params);
909 /* extract "d" (secret key) from r_key */
910 rc = key_from_sexp (&d, r_key, "private-key", "d");
912 rc = key_from_sexp (&d, r_key, "private-key", "d");
914 rc = key_from_sexp (&d, r_key, "ecc", "d");
917 gcry_sexp_release (r_key);
918 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
921 size = sizeof (ph->d);
923 gcry_mpi_print (GCRYMPI_FMT_USG, ph->d, size, &size,
925 gcry_mpi_release (d);
926 adjust (ph->d, size, sizeof (ph->d));
928 /* extract 'q' (public key) from r_key */
929 if (0 != (rc = gcry_mpi_ec_new (&ctx, r_key, NULL)))
931 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
932 gcry_sexp_release (r_key);
935 gcry_sexp_release (r_key);
936 q = gcry_mpi_ec_get_point ("q", ctx, 0);
937 q_x = gcry_mpi_new (256);
938 q_y = gcry_mpi_new (256);
939 gcry_mpi_ec_get_affine (q_x, q_y, q, ctx);
940 gcry_mpi_point_release (q);
941 gcry_ctx_release (ctx);
943 /* store q_x/q_y in public key */
944 size = sizeof (ph->public_key.q_x);
946 gcry_mpi_print (GCRYMPI_FMT_USG, ph->public_key.q_x, size, &size,
949 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
950 gcry_mpi_release (q_x);
951 gcry_mpi_release (q_y);
955 adjust (ph->public_key.q_x, size, sizeof (ph->public_key.q_x));
956 gcry_mpi_release (q_x);
958 size = sizeof (ph->public_key.q_y);
960 gcry_mpi_print (GCRYMPI_FMT_USG, ph->public_key.q_y, size, &size,
963 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
964 gcry_mpi_release (q_y);
967 adjust (ph->public_key.q_y, size, sizeof (ph->public_key.q_y));
968 gcry_mpi_release (q_y);
971 if (NULL != filename)
973 ret = GNUNET_DISK_fn_write (filename, ph, sizeof (struct GNUNET_FS_PseudonymHandle),
974 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
975 if (sizeof (struct GNUNET_FS_PseudonymHandle) != ret)
986 * Create a pseudonym, from a file that must already exist.
988 * @param filename name of the file to use for storage, NULL for in-memory only
989 * @return handle to the private key of the pseudonym
991 struct GNUNET_FS_PseudonymHandle *
992 GNUNET_FS_pseudonym_create_from_existing_file (const char *filename)
994 struct GNUNET_FS_PseudonymHandle *ph;
997 ph = GNUNET_malloc (sizeof (struct GNUNET_FS_PseudonymHandle));
998 ret = GNUNET_DISK_fn_read (filename, ph,
999 sizeof (struct GNUNET_FS_PseudonymHandle));
1000 if (sizeof (struct GNUNET_FS_PseudonymHandle) != ret)
1005 /* Note: we don't do any validation here; maybe we should? */
1011 * Get the handle for the 'anonymous' pseudonym shared by all users.
1012 * That pseudonym uses a fixed 'secret' for the private key; this
1013 * construction is useful to make anonymous and pseudonymous APIs
1014 * (and packets) indistinguishable on the network. See #2564.
1016 * @return handle to the (non-secret) private key of the 'anonymous' pseudonym
1018 struct GNUNET_FS_PseudonymHandle *
1019 GNUNET_FS_pseudonym_get_anonymous_pseudonym_handle ()
1032 d = gcry_mpi_new (1);
1033 gcry_mpi_set_ui (d, 1);
1034 size = sizeof (anonymous.d);
1036 gcry_mpi_print (GCRYMPI_FMT_USG, anonymous.d, size, &size,
1038 gcry_mpi_release (d);
1039 adjust (anonymous.d, size, sizeof (anonymous.d));
1041 /* create basic ECC context */
1042 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256")))
1044 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
1045 "gcry_mpi_ec_new", rc);
1049 g = gcry_mpi_ec_get_point ("g", ctx, 0);
1050 g_x = gcry_mpi_new (256);
1051 g_y = gcry_mpi_new (256);
1052 gcry_mpi_ec_get_affine (g_x, g_y, g, ctx);
1053 gcry_mpi_point_release (g);
1054 gcry_ctx_release (ctx);
1056 /* store g_x/g_y in public key */
1057 size = sizeof (anonymous.public_key.q_x);
1059 gcry_mpi_print (GCRYMPI_FMT_USG, anonymous.public_key.q_x, size, &size,
1062 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1063 gcry_mpi_release (g_x);
1064 gcry_mpi_release (g_y);
1067 adjust (anonymous.public_key.q_x, size, sizeof (anonymous.public_key.q_x));
1068 gcry_mpi_release (g_x);
1070 size = sizeof (anonymous.public_key.q_y);
1072 gcry_mpi_print (GCRYMPI_FMT_USG, anonymous.public_key.q_y, size, &size,
1075 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1076 gcry_mpi_release (g_y);
1079 adjust (anonymous.public_key.q_y, size, sizeof (anonymous.public_key.q_y));
1080 gcry_mpi_release (g_y);
1088 * Destroy a pseudonym handle. Does NOT remove the private key from
1091 * @param ph pseudonym handle to destroy
1094 GNUNET_FS_pseudonym_destroy (struct GNUNET_FS_PseudonymHandle *ph)
1096 if (&anonymous != ph)
1102 * Convert the data specified in the given purpose argument to an
1103 * S-expression suitable for signature operations.
1105 * @param purpose data to convert
1106 * @param rfc6979 GNUNET_YES if we are to use deterministic ECDSA
1107 * @return converted s-expression
1110 data_to_pkcs1 (const struct GNUNET_FS_PseudonymSignaturePurpose *purpose,
1113 struct GNUNET_CRYPTO_ShortHashCode hc;
1119 GNUNET_CRYPTO_short_hash (purpose, ntohl (purpose->size), &hc);
1122 if (0 != (rc = gcry_sexp_build (&data, NULL,
1123 "(data(flags rfc6979)(hash %s %b))",
1128 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1134 fmt = "(data(flags raw)(5:value32:01234567890123456789012345678901))";
1135 bufSize = strlen (fmt) + 1;
1139 memcpy (buff, fmt, bufSize);
1143 ("01234567890123456789012345678901))")
1144 - 1], &hc, sizeof (struct GNUNET_CRYPTO_ShortHashCode));
1145 GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0));
1153 * Cryptographically sign some data with the pseudonym.
1155 * @param ph private key 'd' used for signing (corresponds to 'x' in #2564)
1156 * @param purpose data to sign
1157 * @param seed hash of the plaintext of the data that we are signing,
1158 * used for deterministic PRNG for anonymous signing;
1159 * corresponds to 'k' in section 2.7 of #2564
1160 * @param signing_key modifier to apply to the private key for signing ('h');
1161 * see section 2.3 of #2564.
1162 * @param signature where to store the signature
1163 * @return GNUNET_SYSERR on failure
1166 GNUNET_FS_pseudonym_sign (struct GNUNET_FS_PseudonymHandle *ph,
1167 const struct GNUNET_FS_PseudonymSignaturePurpose *purpose,
1168 const struct GNUNET_HashCode *seed,
1169 const struct GNUNET_HashCode *signing_key,
1170 struct GNUNET_FS_PseudonymSignature *signature)
1178 gcry_mpi_t n; /* n from P-256 */
1185 /* get private key 'd' from pseudonym */
1186 size = sizeof (ph->d);
1187 if (0 != (rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG,
1191 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1192 return GNUNET_SYSERR;
1194 /* get 'x' value from signing key */
1195 size = sizeof (struct GNUNET_HashCode);
1196 if (0 != (rc = gcry_mpi_scan (&h, GCRYMPI_FMT_USG,
1200 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1201 gcry_mpi_release (d);
1202 return GNUNET_SYSERR;
1205 /* initialize 'n' from P-256; hex copied from libgcrypt code */
1206 if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX,
1207 "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 0, NULL)))
1209 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1210 gcry_mpi_release (d);
1211 gcry_mpi_release (h);
1212 return GNUNET_SYSERR;
1215 /* calculate dh = d * h mod n */
1216 dh = gcry_mpi_new (256);
1217 gcry_mpi_mulm (dh, d, h, n);
1218 gcry_mpi_release (d);
1219 gcry_mpi_release (h);
1220 gcry_mpi_release (n);
1222 /* now build sexpression with the signing key */
1223 if (0 != (rc = gcry_sexp_build (&spriv, &erroff,
1224 "(private-key(ecdsa(curve \"NIST P-256\")(d %m)))",
1227 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1228 gcry_mpi_release (dh);
1229 return GNUNET_SYSERR;
1231 gcry_mpi_release (dh);
1232 /* prepare data for signing */
1233 data = data_to_pkcs1 (purpose, NULL != seed);
1236 gcry_sexp_release (spriv);
1237 return GNUNET_SYSERR;
1239 /* get 'k' value from seed, if available */
1242 size = sizeof (struct GNUNET_HashCode);
1243 if (0 != (rc = gcry_mpi_scan (&k, GCRYMPI_FMT_USG,
1247 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1248 gcry_sexp_release (spriv);
1249 gcry_sexp_release (data);
1250 return GNUNET_SYSERR;
1254 /* actually create signature */
1255 /* FIXME: need API to pass 'k' if 'seed' was non-NULL! */
1256 if (0 != (rc = gcry_pk_sign (&result, data, spriv)))
1258 LOG (GNUNET_ERROR_TYPE_WARNING,
1259 _("ECC signing failed at %s:%d: %s\n"), __FILE__,
1260 __LINE__, gcry_strerror (rc));
1261 gcry_sexp_release (data);
1262 gcry_sexp_release (spriv);
1264 gcry_mpi_release (k);
1265 memset (signature, 0, sizeof (struct GNUNET_FS_PseudonymSignature));
1266 return GNUNET_SYSERR;
1269 gcry_mpi_release (k);
1270 gcry_sexp_release (data);
1271 gcry_sexp_release (spriv);
1274 /* extract 'r' and 's' values from sexpression 'result' and store in 'signature' */
1275 if (0 != (rc = key_from_sexp (rs, result, "sig-val", "rs")))
1278 gcry_sexp_release (result);
1279 return GNUNET_SYSERR;
1281 gcry_sexp_release (result);
1282 size = sizeof (signature->sig_r);
1283 if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, signature->sig_r, size,
1286 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1287 gcry_mpi_release (rs[0]);
1288 gcry_mpi_release (rs[1]);
1289 return GNUNET_SYSERR;
1291 adjust (signature->sig_r, size, sizeof (signature->sig_r));
1292 gcry_mpi_release (rs[0]);
1294 size = sizeof (signature->sig_s);
1295 if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, signature->sig_s, size,
1298 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1299 gcry_mpi_release (rs[1]);
1300 return GNUNET_SYSERR;
1302 adjust (signature->sig_s, size, sizeof (signature->sig_s));
1303 gcry_mpi_release (rs[1]);
1307 struct GNUNET_FS_PseudonymIdentifier vk;
1308 struct GNUNET_FS_PseudonymIdentifier pi;
1310 GNUNET_FS_pseudonym_get_identifier (ph, &pi);
1311 GNUNET_assert (GNUNET_OK ==
1312 GNUNET_FS_pseudonym_derive_verification_key (&pi, signing_key, &vk));
1313 GNUNET_assert (GNUNET_OK ==
1314 GNUNET_FS_pseudonym_verify (purpose,
1320 GNUNET_FS_pseudonym_get_identifier (ph, &signature->signer);
1326 * Get an ECC context (with Q set to the respective public key) from
1329 * @param pseudonym with information on 'q'
1330 * @return curve context
1333 get_context_from_pseudonym (struct GNUNET_FS_PseudonymIdentifier *pseudonym)
1335 static struct GNUNET_FS_PseudonymIdentifier zerop;
1344 /* extract 'q' from pseudonym */
1345 if (0 == memcmp (pseudonym, &zerop, sizeof (zerop)))
1347 /* create basic ECC context */
1348 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256")))
1350 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
1353 /* FIXME: initialize 'ctx' with 'q' = G */
1354 zero = gcry_mpi_new (0);
1355 gcry_mpi_set_ui (zero, 0);
1356 q = gcry_mpi_point_new (0);
1357 gcry_mpi_point_set (q, zero, zero, zero);
1358 gcry_mpi_ec_set_point ("q", q, ctx);
1359 gcry_mpi_release (zero);
1360 gcry_mpi_point_release (q);
1363 size = sizeof (pseudonym->q_x);
1364 if (0 != (rc = gcry_mpi_scan (&q_x, GCRYMPI_FMT_USG, pseudonym->q_x, size, &size)))
1366 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1369 size = sizeof (pseudonym->q_y);
1370 if (0 != (rc = gcry_mpi_scan (&q_y, GCRYMPI_FMT_USG, pseudonym->q_y, size, &size)))
1372 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1373 gcry_mpi_release (q_x);
1376 q = gcry_mpi_point_new (256);
1377 gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE);
1378 gcry_mpi_release (q_x);
1379 gcry_mpi_release (q_y);
1381 /* create basic ECC context */
1382 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256")))
1384 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
1385 gcry_mpi_point_release (q);
1388 /* initialize 'ctx' with 'q' */
1389 gcry_mpi_ec_set_point ("q", q, ctx);
1390 gcry_mpi_point_release (q);
1396 * Given a pseudonym and a signing key, derive the corresponding public
1397 * key that would be used to verify the resulting signature.
1399 * @param pseudonym the public key (dQ in ECDSA)
1400 * @param signing_key input to derive 'h' (see section 2.4 of #2564)
1401 * @param verification_key resulting public key to verify the signature
1402 * created from the '(d*h)' of 'pseudonym' and the 'signing_key';
1403 * the value stored here can then be given to GNUNET_FS_pseudonym_verify.
1404 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1407 GNUNET_FS_pseudonym_derive_verification_key (struct GNUNET_FS_PseudonymIdentifier *pseudonym,
1408 const struct GNUNET_HashCode *signing_key,
1409 struct GNUNET_FS_PseudonymIdentifier *verification_key)
1420 gcry_mpi_t n; /* n from P-256 */
1422 /* get 'h' value from signing key */
1423 size = sizeof (struct GNUNET_HashCode);
1424 if (0 != (rc = gcry_mpi_scan (&h, GCRYMPI_FMT_USG,
1428 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1429 return GNUNET_SYSERR;
1431 /* create ECC context based on Q from pseudonym */
1432 if (NULL == (ctx = get_context_from_pseudonym (pseudonym)))
1434 gcry_mpi_release (h);
1435 return GNUNET_SYSERR;
1437 /* initialize 'n' from P-256; hex copied from libgcrypt code */
1438 if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX,
1439 "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 0, NULL)))
1441 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1442 gcry_mpi_release (h);
1443 return GNUNET_SYSERR;
1445 h_mod_n = gcry_mpi_new (0);
1446 gcry_mpi_mod (h_mod_n, h, n);
1447 gcry_mpi_release (h);
1449 /* get Q = dG from 'pseudonym' */
1450 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1451 /* calculate V = hQ = hdG */
1452 v = gcry_mpi_point_new (0);
1454 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1455 gcry_mpi_release (h_mod_n);
1457 /* store 'v' point in "verification_key" */
1458 v_x = gcry_mpi_new (256);
1459 v_y = gcry_mpi_new (256);
1460 gcry_mpi_ec_get_affine (v_x, v_y, v, ctx);
1462 gcry_mpi_point_release (v);
1463 gcry_ctx_release (ctx);
1465 size = sizeof (verification_key->q_x);
1466 if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, verification_key->q_x, size,
1469 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1470 gcry_mpi_release (v_x);
1471 gcry_mpi_release (v_y);
1472 return GNUNET_SYSERR;
1474 gcry_mpi_release (v_x);
1475 size = sizeof (verification_key->q_y);
1476 if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, verification_key->q_y, size,
1479 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1480 gcry_mpi_release (v_y);
1481 return GNUNET_SYSERR;
1483 gcry_mpi_release (v_y);
1489 * Verify a signature made with a pseudonym.
1491 * @param purpose data that was signed
1492 * @param signature signature to verify
1493 * @param verification_key public key to use for checking the signature;
1494 * corresponds to 'g^(x+h)' in section 2.4 of #2564.
1495 * @return GNUNET_OK on success (signature valid, 'pseudonym' set),
1496 * GNUNET_SYSERR if the signature is invalid
1499 GNUNET_FS_pseudonym_verify (const struct GNUNET_FS_PseudonymSignaturePurpose *purpose,
1500 const struct GNUNET_FS_PseudonymSignature *signature,
1501 const struct GNUNET_FS_PseudonymIdentifier *verification_key)
1504 gcry_sexp_t sig_sexpr;
1505 gcry_sexp_t pk_sexpr;
1516 /* build s-expression for signature */
1517 size = sizeof (signature->sig_r);
1518 if (0 != (rc = gcry_mpi_scan (&r, GCRYMPI_FMT_USG,
1519 signature->sig_r, size, &size)))
1521 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1522 return GNUNET_SYSERR;
1524 size = sizeof (signature->sig_s);
1525 if (0 != (rc = gcry_mpi_scan (&s, GCRYMPI_FMT_USG,
1526 signature->sig_s, size, &size)))
1528 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1529 gcry_mpi_release (r);
1530 return GNUNET_SYSERR;
1532 if (0 != (rc = gcry_sexp_build (&sig_sexpr, &erroff, "(sig-val(ecdsa(r %m)(s %m)))",
1535 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1536 gcry_mpi_release (r);
1537 gcry_mpi_release (s);
1538 return GNUNET_SYSERR;
1540 gcry_mpi_release (r);
1541 gcry_mpi_release (s);
1544 /* build s-expression for data that was signed */
1545 data = data_to_pkcs1 (purpose, GNUNET_NO);
1548 gcry_sexp_release (sig_sexpr);
1549 return GNUNET_SYSERR;
1551 /* create context of public key and initialize Q */
1552 size = sizeof (verification_key->q_x);
1553 if (0 != (rc = gcry_mpi_scan (&q_x, GCRYMPI_FMT_USG,
1554 verification_key->q_x, size, &size)))
1556 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1557 gcry_sexp_release (data);
1558 gcry_sexp_release (sig_sexpr);
1559 return GNUNET_SYSERR;
1561 size = sizeof (verification_key->q_y);
1562 if (0 != (rc = gcry_mpi_scan (&q_y, GCRYMPI_FMT_USG,
1563 verification_key->q_y, size, &size)))
1565 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1566 gcry_sexp_release (data);
1567 gcry_sexp_release (sig_sexpr);
1568 gcry_mpi_release (q_x);
1569 return GNUNET_SYSERR;
1571 q = gcry_mpi_point_new (256);
1572 gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE);
1573 gcry_mpi_release (q_x);
1574 gcry_mpi_release (q_y);
1576 /* create basic ECC context */
1577 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256")))
1579 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
1580 gcry_sexp_release (data);
1581 gcry_sexp_release (sig_sexpr);
1582 gcry_mpi_point_release (q);
1583 return GNUNET_SYSERR;
1585 /* initialize 'ctx' with 'q' */
1586 gcry_mpi_ec_set_point ("q", q, ctx);
1587 gcry_mpi_point_release (q);
1589 /* convert 'ctx' to 'sexp' */
1590 if (0 != (rc = gcry_pubkey_get_sexp (&pk_sexpr, GCRY_PK_GET_PUBKEY, ctx)))
1592 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_from_context", rc);
1593 gcry_ctx_release (ctx);
1594 gcry_sexp_release (data);
1595 gcry_sexp_release (sig_sexpr);
1596 return GNUNET_SYSERR;
1598 gcry_ctx_release (ctx);
1600 /* finally, verify the signature */
1601 rc = gcry_pk_verify (sig_sexpr, data, pk_sexpr);
1602 gcry_sexp_release (sig_sexpr);
1603 gcry_sexp_release (data);
1604 gcry_sexp_release (pk_sexpr);
1607 LOG (GNUNET_ERROR_TYPE_WARNING,
1608 _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__,
1609 __LINE__, gcry_strerror (rc));
1610 return GNUNET_SYSERR;
1617 * Get the identifier (public key) of a pseudonym.
1619 * @param ph pseudonym handle with the private key
1620 * @param pseudonym pseudonym identifier (set based on 'ph')
1623 GNUNET_FS_pseudonym_get_identifier (struct GNUNET_FS_PseudonymHandle *ph,
1624 struct GNUNET_FS_PseudonymIdentifier *pseudonym)
1626 memcpy (pseudonym, &ph->public_key,
1627 sizeof (struct GNUNET_FS_PseudonymIdentifier));
1632 * Remove pseudonym from the set of known pseudonyms.
1634 * @param cfg overall configuration
1635 * @param id the pseudonym identifier
1636 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1639 GNUNET_FS_pseudonym_remove (const struct GNUNET_CONFIGURATION_Handle *cfg,
1640 const struct GNUNET_FS_PseudonymIdentifier *id)
1645 fn = get_data_filename (cfg, PS_METADATA_DIR, id);
1647 return GNUNET_SYSERR;
1648 result = UNLINK (fn);
1650 return (0 == result) ? GNUNET_OK : GNUNET_SYSERR;
1653 /* end of pseudonym.c */