aboutsummaryrefslogtreecommitdiff
path: root/src/fs/fs_pseudonym.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs/fs_pseudonym.c')
-rw-r--r--src/fs/fs_pseudonym.c977
1 files changed, 39 insertions, 938 deletions
diff --git a/src/fs/fs_pseudonym.c b/src/fs/fs_pseudonym.c
index 36eaab6fa..f5493ca16 100644
--- a/src/fs/fs_pseudonym.c
+++ b/src/fs/fs_pseudonym.c
@@ -21,15 +21,10 @@
21 * @file fs/fs_pseudonym.c 21 * @file fs/fs_pseudonym.c
22 * @brief pseudonym functions 22 * @brief pseudonym functions
23 * @author Christian Grothoff 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 */ 24 */
29#include "platform.h" 25#include "platform.h"
30#include "gnunet_util_lib.h" 26#include "gnunet_util_lib.h"
31#include "gnunet_fs_service.h" 27#include "gnunet_fs_service.h"
32#include <gcrypt.h>
33 28
34 29
35#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) 30#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
@@ -38,12 +33,6 @@
38 33
39#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) 34#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
40 35
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 36
48/** 37/**
49 * Name of the directory which stores meta data for pseudonym 38 * Name of the directory which stores meta data for pseudonym
@@ -67,17 +56,17 @@
67/** 56/**
68 * Registered callbacks for discovery of pseudonyms. 57 * Registered callbacks for discovery of pseudonyms.
69 */ 58 */
70struct GNUNET_FS_pseudonym_DiscoveryHandle 59struct GNUNET_FS_Pseudonym_DiscoveryHandle
71{ 60{
72 /** 61 /**
73 * This is a doubly linked list. 62 * This is a doubly linked list.
74 */ 63 */
75 struct GNUNET_FS_pseudonym_DiscoveryHandle *next; 64 struct GNUNET_FS_Pseudonym_DiscoveryHandle *next;
76 65
77 /** 66 /**
78 * This is a doubly linked list. 67 * This is a doubly linked list.
79 */ 68 */
80 struct GNUNET_FS_pseudonym_DiscoveryHandle *prev; 69 struct GNUNET_FS_Pseudonym_DiscoveryHandle *prev;
81 70
82 /** 71 /**
83 * Function to call each time a pseudonym is discovered. 72 * Function to call each time a pseudonym is discovered.
@@ -95,19 +84,14 @@ struct GNUNET_FS_pseudonym_DiscoveryHandle
95 * Head of the linked list of functions to call when 84 * Head of the linked list of functions to call when
96 * new pseudonyms are added. 85 * new pseudonyms are added.
97 */ 86 */
98static struct GNUNET_FS_pseudonym_DiscoveryHandle *disco_head; 87static struct GNUNET_FS_Pseudonym_DiscoveryHandle *disco_head;
99 88
100/** 89/**
101 * Tail of the linked list of functions to call when 90 * Tail of the linked list of functions to call when
102 * new pseudonyms are added. 91 * new pseudonyms are added.
103 */ 92 */
104static struct GNUNET_FS_pseudonym_DiscoveryHandle *disco_tail; 93static struct GNUNET_FS_Pseudonym_DiscoveryHandle *disco_tail;
105 94
106/**
107 * Pointer to indiate 'anonymous' pseudonym (global static,
108 * d=1, public key = G (generator).
109 */
110static struct GNUNET_FS_PseudonymHandle anonymous;
111 95
112/** 96/**
113 * Internal notification about new tracked URI. 97 * Internal notification about new tracked URI.
@@ -117,10 +101,10 @@ static struct GNUNET_FS_PseudonymHandle anonymous;
117 * @param rating rating of pseudonym 101 * @param rating rating of pseudonym
118 */ 102 */
119static void 103static void
120internal_notify (const struct GNUNET_FS_PseudonymIdentifier *pseudonym, 104internal_notify (const struct GNUNET_CRYPTO_EccPublicKey *pseudonym,
121 const struct GNUNET_CONTAINER_MetaData *md, int rating) 105 const struct GNUNET_CONTAINER_MetaData *md, int rating)
122{ 106{
123 struct GNUNET_FS_pseudonym_DiscoveryHandle *pos; 107 struct GNUNET_FS_Pseudonym_DiscoveryHandle *pos;
124 108
125 for (pos = disco_head; NULL != pos; pos = pos->next) 109 for (pos = disco_head; NULL != pos; pos = pos->next)
126 pos->callback (pos->callback_cls, pseudonym, NULL, NULL, md, rating); 110 pos->callback (pos->callback_cls, pseudonym, NULL, NULL, md, rating);
@@ -138,15 +122,15 @@ internal_notify (const struct GNUNET_FS_PseudonymIdentifier *pseudonym,
138 * @param iterator_cls point to a closure 122 * @param iterator_cls point to a closure
139 * @return registration handle 123 * @return registration handle
140 */ 124 */
141struct GNUNET_FS_pseudonym_DiscoveryHandle * 125struct GNUNET_FS_Pseudonym_DiscoveryHandle *
142GNUNET_FS_pseudonym_discovery_callback_register (const struct 126GNUNET_FS_pseudonym_discovery_callback_register (const struct
143 GNUNET_CONFIGURATION_Handle *cfg, 127 GNUNET_CONFIGURATION_Handle *cfg,
144 GNUNET_FS_PseudonymIterator iterator, 128 GNUNET_FS_PseudonymIterator iterator,
145 void *iterator_cls) 129 void *iterator_cls)
146{ 130{
147 struct GNUNET_FS_pseudonym_DiscoveryHandle *dh; 131 struct GNUNET_FS_Pseudonym_DiscoveryHandle *dh;
148 132
149 dh = GNUNET_malloc (sizeof (struct GNUNET_FS_pseudonym_DiscoveryHandle)); 133 dh = GNUNET_new (struct GNUNET_FS_Pseudonym_DiscoveryHandle);
150 dh->callback = iterator; 134 dh->callback = iterator;
151 dh->callback_cls = iterator_cls; 135 dh->callback_cls = iterator_cls;
152 GNUNET_CONTAINER_DLL_insert (disco_head, disco_tail, dh); 136 GNUNET_CONTAINER_DLL_insert (disco_head, disco_tail, dh);
@@ -161,7 +145,7 @@ GNUNET_FS_pseudonym_discovery_callback_register (const struct
161 * @param dh registration to unregister 145 * @param dh registration to unregister
162 */ 146 */
163void 147void
164GNUNET_FS_pseudonym_discovery_callback_unregister (struct GNUNET_FS_pseudonym_DiscoveryHandle *dh) 148GNUNET_FS_pseudonym_discovery_callback_unregister (struct GNUNET_FS_Pseudonym_DiscoveryHandle *dh)
165{ 149{
166 GNUNET_CONTAINER_DLL_remove (disco_head, disco_tail, dh); 150 GNUNET_CONTAINER_DLL_remove (disco_head, disco_tail, dh);
167 GNUNET_free (dh); 151 GNUNET_free (dh);
@@ -180,7 +164,7 @@ GNUNET_FS_pseudonym_discovery_callback_unregister (struct GNUNET_FS_pseudonym_Di
180static char * 164static char *
181get_data_filename (const struct GNUNET_CONFIGURATION_Handle *cfg, 165get_data_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
182 const char *prefix, 166 const char *prefix,
183 const struct GNUNET_FS_PseudonymIdentifier *pseudonym) 167 const struct GNUNET_CRYPTO_EccPublicKey *pseudonym)
184{ 168{
185 struct GNUNET_CRYPTO_HashAsciiEncoded enc; 169 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
186 struct GNUNET_HashCode psid; 170 struct GNUNET_HashCode psid;
@@ -188,7 +172,7 @@ get_data_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
188 if (NULL != pseudonym) 172 if (NULL != pseudonym)
189 { 173 {
190 GNUNET_CRYPTO_hash (pseudonym, 174 GNUNET_CRYPTO_hash (pseudonym,
191 sizeof (struct GNUNET_FS_PseudonymIdentifier), 175 sizeof (struct GNUNET_CRYPTO_EccPublicKey),
192 &psid); 176 &psid);
193 GNUNET_CRYPTO_hash_to_enc (&psid, &enc); 177 GNUNET_CRYPTO_hash_to_enc (&psid, &enc);
194 } 178 }
@@ -243,7 +227,7 @@ get_data_filename_hash (const struct GNUNET_CONFIGURATION_Handle *cfg,
243 */ 227 */
244int 228int
245GNUNET_FS_pseudonym_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg, 229GNUNET_FS_pseudonym_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
246 const struct GNUNET_FS_PseudonymIdentifier *pseudonym, 230 const struct GNUNET_CRYPTO_EccPublicKey *pseudonym,
247 const char *name, 231 const char *name,
248 const struct GNUNET_CONTAINER_MetaData *md, 232 const struct GNUNET_CONTAINER_MetaData *md,
249 int32_t rank) 233 int32_t rank)
@@ -258,7 +242,7 @@ GNUNET_FS_pseudonym_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
258 return GNUNET_SYSERR; 242 return GNUNET_SYSERR;
259 } 243 }
260 if ((GNUNET_OK != GNUNET_BIO_write (fileW, pseudonym, 244 if ((GNUNET_OK != GNUNET_BIO_write (fileW, pseudonym,
261 sizeof (struct GNUNET_FS_PseudonymIdentifier))) || 245 sizeof (struct GNUNET_CRYPTO_EccPublicKey))) ||
262 (GNUNET_OK != GNUNET_BIO_write_int32 (fileW, rank)) || 246 (GNUNET_OK != GNUNET_BIO_write_int32 (fileW, rank)) ||
263 (GNUNET_OK != GNUNET_BIO_write_string (fileW, name)) || 247 (GNUNET_OK != GNUNET_BIO_write_string (fileW, name)) ||
264 (GNUNET_OK != GNUNET_BIO_write_meta_data (fileW, md))) 248 (GNUNET_OK != GNUNET_BIO_write_meta_data (fileW, md)))
@@ -295,12 +279,12 @@ GNUNET_FS_pseudonym_set_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
295 */ 279 */
296static int 280static int
297read_info (const struct GNUNET_CONFIGURATION_Handle *cfg, 281read_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
298 const struct GNUNET_FS_PseudonymIdentifier *pseudonym, 282 const struct GNUNET_CRYPTO_EccPublicKey *pseudonym,
299 struct GNUNET_CONTAINER_MetaData **meta, 283 struct GNUNET_CONTAINER_MetaData **meta,
300 int32_t *rank, 284 int32_t *rank,
301 char **ns_name) 285 char **ns_name)
302{ 286{
303 struct GNUNET_FS_PseudonymIdentifier pd; 287 struct GNUNET_CRYPTO_EccPublicKey pd;
304 char *fn; 288 char *fn;
305 char *emsg; 289 char *emsg;
306 struct GNUNET_BIO_ReadHandle *fileR; 290 struct GNUNET_BIO_ReadHandle *fileR;
@@ -367,12 +351,12 @@ read_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
367 */ 351 */
368char * 352char *
369GNUNET_FS_pseudonym_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, 353GNUNET_FS_pseudonym_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg,
370 const struct GNUNET_FS_PseudonymIdentifier *pseudonym, 354 const struct GNUNET_CRYPTO_EccPublicKey *pseudonym,
371 const char *name, 355 const char *name,
372 unsigned int *suffix) 356 unsigned int *suffix)
373{ 357{
374 struct GNUNET_HashCode nh; 358 struct GNUNET_HashCode nh;
375 struct GNUNET_FS_PseudonymIdentifier pi; 359 struct GNUNET_CRYPTO_EccPublicKey pi;
376 uint64_t len; 360 uint64_t len;
377 char *fn; 361 char *fn;
378 struct GNUNET_DISK_FileHandle *fh; 362 struct GNUNET_DISK_FileHandle *fh;
@@ -393,11 +377,11 @@ GNUNET_FS_pseudonym_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg
393 GNUNET_DISK_PERM_USER_WRITE); 377 GNUNET_DISK_PERM_USER_WRITE);
394 i = 0; 378 i = 0;
395 idx = -1; 379 idx = -1;
396 while ((len >= sizeof (struct GNUNET_FS_PseudonymIdentifier)) && 380 while ((len >= sizeof (struct GNUNET_CRYPTO_EccPublicKey)) &&
397 (sizeof (struct GNUNET_FS_PseudonymIdentifier) == 381 (sizeof (struct GNUNET_CRYPTO_EccPublicKey) ==
398 GNUNET_DISK_file_read (fh, &pi, sizeof (struct GNUNET_FS_PseudonymIdentifier)))) 382 GNUNET_DISK_file_read (fh, &pi, sizeof (struct GNUNET_CRYPTO_EccPublicKey))))
399 { 383 {
400 if (0 == memcmp (&pi, pseudonym, sizeof (struct GNUNET_FS_PseudonymIdentifier))) 384 if (0 == memcmp (&pi, pseudonym, sizeof (struct GNUNET_CRYPTO_EccPublicKey)))
401 { 385 {
402 idx = i; 386 idx = i;
403 break; 387 break;
@@ -408,8 +392,8 @@ GNUNET_FS_pseudonym_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg
408 if (-1 == idx) 392 if (-1 == idx)
409 { 393 {
410 idx = i; 394 idx = i;
411 if (sizeof (struct GNUNET_FS_PseudonymIdentifier) != 395 if (sizeof (struct GNUNET_CRYPTO_EccPublicKey) !=
412 GNUNET_DISK_file_write (fh, pseudonym, sizeof (struct GNUNET_FS_PseudonymIdentifier))) 396 GNUNET_DISK_file_write (fh, pseudonym, sizeof (struct GNUNET_CRYPTO_EccPublicKey)))
413 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "write", fn); 397 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "write", fn);
414 } 398 }
415 GNUNET_DISK_file_close (fh); 399 GNUNET_DISK_file_close (fh);
@@ -442,11 +426,11 @@ GNUNET_FS_pseudonym_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg
442 */ 426 */
443int 427int
444GNUNET_FS_pseudonym_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg, 428GNUNET_FS_pseudonym_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
445 const struct GNUNET_FS_PseudonymIdentifier *pseudonym, 429 const struct GNUNET_CRYPTO_EccPublicKey *pseudonym,
446 struct GNUNET_CONTAINER_MetaData **ret_meta, 430 struct GNUNET_CONTAINER_MetaData **ret_meta,
447 int32_t *ret_rank, 431 int32_t *ret_rank,
448 char **ret_name, 432 char **ret_name,
449 int *name_is_a_dup) 433 int *name_is_a_dup)
450{ 434{
451 struct GNUNET_CONTAINER_MetaData *meta; 435 struct GNUNET_CONTAINER_MetaData *meta;
452 char *name; 436 char *name;
@@ -521,7 +505,7 @@ GNUNET_FS_pseudonym_get_info (const struct GNUNET_CONFIGURATION_Handle *cfg,
521int 505int
522GNUNET_FS_pseudonym_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, 506GNUNET_FS_pseudonym_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg,
523 const char *ns_uname, 507 const char *ns_uname,
524 struct GNUNET_FS_PseudonymIdentifier *pseudonym) 508 struct GNUNET_CRYPTO_EccPublicKey *pseudonym)
525{ 509{
526 size_t slen; 510 size_t slen;
527 uint64_t len; 511 uint64_t len;
@@ -546,7 +530,7 @@ GNUNET_FS_pseudonym_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg,
546 530
547 if ((GNUNET_OK != GNUNET_DISK_file_test (fn) || 531 if ((GNUNET_OK != GNUNET_DISK_file_test (fn) ||
548 (GNUNET_OK != GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES))) || 532 (GNUNET_OK != GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES))) ||
549 ((idx + 1) * sizeof (struct GNUNET_FS_PseudonymIdentifier) > len)) 533 ((idx + 1) * sizeof (struct GNUNET_CRYPTO_EccPublicKey) > len))
550 { 534 {
551 GNUNET_free (fn); 535 GNUNET_free (fn);
552 return GNUNET_SYSERR; 536 return GNUNET_SYSERR;
@@ -558,14 +542,14 @@ GNUNET_FS_pseudonym_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg,
558 GNUNET_DISK_PERM_USER_WRITE); 542 GNUNET_DISK_PERM_USER_WRITE);
559 GNUNET_free (fn); 543 GNUNET_free (fn);
560 if (GNUNET_SYSERR == 544 if (GNUNET_SYSERR ==
561 GNUNET_DISK_file_seek (fh, idx * sizeof (struct GNUNET_FS_PseudonymIdentifier), 545 GNUNET_DISK_file_seek (fh, idx * sizeof (struct GNUNET_CRYPTO_EccPublicKey),
562 GNUNET_DISK_SEEK_SET)) 546 GNUNET_DISK_SEEK_SET))
563 { 547 {
564 GNUNET_DISK_file_close (fh); 548 GNUNET_DISK_file_close (fh);
565 return GNUNET_SYSERR; 549 return GNUNET_SYSERR;
566 } 550 }
567 if (sizeof (struct GNUNET_FS_PseudonymIdentifier) != 551 if (sizeof (struct GNUNET_CRYPTO_EccPublicKey) !=
568 GNUNET_DISK_file_read (fh, pseudonym, sizeof (struct GNUNET_FS_PseudonymIdentifier))) 552 GNUNET_DISK_file_read (fh, pseudonym, sizeof (struct GNUNET_CRYPTO_EccPublicKey)))
569 { 553 {
570 GNUNET_DISK_file_close (fh); 554 GNUNET_DISK_file_close (fh);
571 return GNUNET_SYSERR; 555 return GNUNET_SYSERR;
@@ -610,7 +594,7 @@ static int
610list_pseudonym_helper (void *cls, const char *fullname) 594list_pseudonym_helper (void *cls, const char *fullname)
611{ 595{
612 struct ListPseudonymClosure *lpc = cls; 596 struct ListPseudonymClosure *lpc = cls;
613 struct GNUNET_FS_PseudonymIdentifier pd; 597 struct GNUNET_CRYPTO_EccPublicKey pd;
614 char *emsg; 598 char *emsg;
615 struct GNUNET_BIO_ReadHandle *fileR; 599 struct GNUNET_BIO_ReadHandle *fileR;
616 int32_t rank; 600 int32_t rank;
@@ -699,7 +683,7 @@ GNUNET_FS_pseudonym_list_all (const struct GNUNET_CONFIGURATION_Handle *cfg,
699 */ 683 */
700int 684int
701GNUNET_FS_pseudonym_rank (const struct GNUNET_CONFIGURATION_Handle *cfg, 685GNUNET_FS_pseudonym_rank (const struct GNUNET_CONFIGURATION_Handle *cfg,
702 const struct GNUNET_FS_PseudonymIdentifier *pseudonym, 686 const struct GNUNET_CRYPTO_EccPublicKey *pseudonym,
703 int32_t delta) 687 int32_t delta)
704{ 688{
705 struct GNUNET_CONTAINER_MetaData *meta; 689 struct GNUNET_CONTAINER_MetaData *meta;
@@ -734,8 +718,8 @@ GNUNET_FS_pseudonym_rank (const struct GNUNET_CONFIGURATION_Handle *cfg,
734 */ 718 */
735int 719int
736GNUNET_FS_pseudonym_add (const struct GNUNET_CONFIGURATION_Handle *cfg, 720GNUNET_FS_pseudonym_add (const struct GNUNET_CONFIGURATION_Handle *cfg,
737 const struct GNUNET_FS_PseudonymIdentifier *pseudonym, 721 const struct GNUNET_CRYPTO_EccPublicKey *pseudonym,
738 const struct GNUNET_CONTAINER_MetaData *meta) 722 const struct GNUNET_CONTAINER_MetaData *meta)
739{ 723{
740 char *name; 724 char *name;
741 int32_t rank; 725 int32_t rank;
@@ -766,888 +750,5 @@ GNUNET_FS_pseudonym_add (const struct GNUNET_CONFIGURATION_Handle *cfg,
766} 750}
767 751
768 752
769/* ***************************** cryptographic operations ************************* */
770
771/**
772 * Handle for a pseudonym (private key).
773 */
774struct GNUNET_FS_PseudonymHandle
775{
776 /**
777 * 256-bit 'd' secret value (mod 'n', where n is 256-bit for NIST P-256).
778 */
779 unsigned char d[256 / 8];
780
781 /**
782 * Public key corresponding to the private key.
783 */
784 struct GNUNET_FS_PseudonymIdentifier public_key;
785};
786
787
788/**
789 * If target != size, move target bytes to the end of the size-sized
790 * buffer and zero out the first target-size bytes.
791 *
792 * @param buf original buffer
793 * @param size number of bytes in the buffer
794 * @param target target size of the buffer
795 */
796static void
797adjust (unsigned char *buf, size_t size, size_t target)
798{
799 if (size < target)
800 {
801 memmove (&buf[target - size], buf, size);
802 memset (buf, 0, target - size);
803 }
804}
805
806
807/**
808 * Extract values from an S-expression.
809 *
810 * @param array where to store the result(s)
811 * @param sexp S-expression to parse
812 * @param topname top-level name in the S-expression that is of interest
813 * @param elems names of the elements to extract
814 * @return 0 on success
815 */
816static int
817key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
818 const char *elems)
819{
820 gcry_sexp_t list;
821 gcry_sexp_t l2;
822 const char *s;
823 unsigned int i;
824 unsigned int idx;
825
826 if (! (list = gcry_sexp_find_token (sexp, topname, 0)))
827 return 1;
828 l2 = gcry_sexp_cadr (list);
829 gcry_sexp_release (list);
830 list = l2;
831 if (! list)
832 return 2;
833 idx = 0;
834 for (s = elems; *s; s++, idx++)
835 {
836 if (! (l2 = gcry_sexp_find_token (list, s, 1)))
837 {
838 for (i = 0; i < idx; i++)
839 {
840 gcry_free (array[i]);
841 array[i] = NULL;
842 }
843 gcry_sexp_release (list);
844 return 3; /* required parameter not found */
845 }
846 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
847 gcry_sexp_release (l2);
848 if (! array[idx])
849 {
850 for (i = 0; i < idx; i++)
851 {
852 gcry_free (array[i]);
853 array[i] = NULL;
854 }
855 gcry_sexp_release (list);
856 return 4; /* required parameter is invalid */
857 }
858 }
859 gcry_sexp_release (list);
860 return 0;
861}
862
863
864/**
865 * Create a pseudonym.
866 *
867 * @param filename name of the file to use for storage, NULL for in-memory only
868 * @return handle to the private key of the pseudonym
869 */
870struct GNUNET_FS_PseudonymHandle *
871GNUNET_FS_pseudonym_create (const char *filename)
872{
873 struct GNUNET_FS_PseudonymHandle *ph;
874 ssize_t ret;
875 gcry_sexp_t r_key;
876 gcry_sexp_t params;
877 gcry_ctx_t ctx;
878 gcry_mpi_point_t q;
879 gcry_mpi_t q_x;
880 gcry_mpi_t q_y;
881 gcry_error_t rc;
882 gcry_mpi_t d;
883 size_t size;
884
885 ph = GNUNET_malloc (sizeof (struct GNUNET_FS_PseudonymHandle));
886 if ( (NULL != filename) &&
887 (GNUNET_YES == GNUNET_DISK_file_test (filename)) )
888 {
889 ret = GNUNET_DISK_fn_read (filename, ph,
890 sizeof (struct GNUNET_FS_PseudonymHandle));
891 /* Note: we don't do any validation here, maybe we should? */
892 if (sizeof (struct GNUNET_FS_PseudonymHandle) == ret)
893 return ph;
894 }
895 if (0 != (rc = gcry_sexp_build (&params, NULL,
896 "(genkey(ecdsa(curve \"NIST P-256\")))")))
897 {
898 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
899 return NULL;
900 }
901 if (0 != (rc = gcry_pk_genkey (&r_key, params)))
902 {
903 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
904 gcry_sexp_release (params);
905 gcry_sexp_release (r_key);
906 return NULL;
907 }
908 gcry_sexp_release (params);
909 /* extract "d" (secret key) from r_key */
910 rc = key_from_sexp (&d, r_key, "private-key", "d");
911 if (0 != rc)
912 rc = key_from_sexp (&d, r_key, "private-key", "d");
913 if (0 != rc)
914 rc = key_from_sexp (&d, r_key, "ecc", "d");
915 if (0 != rc)
916 {
917 gcry_sexp_release (r_key);
918 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
919 return NULL;
920 }
921 size = sizeof (ph->d);
922 GNUNET_assert (0 ==
923 gcry_mpi_print (GCRYMPI_FMT_USG, ph->d, size, &size,
924 d));
925 gcry_mpi_release (d);
926 adjust (ph->d, size, sizeof (ph->d));
927
928 /* extract 'q' (public key) from r_key */
929 if (0 != (rc = gcry_mpi_ec_new (&ctx, r_key, NULL)))
930 {
931 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
932 gcry_sexp_release (r_key);
933 return NULL;
934 }
935 gcry_sexp_release (r_key);
936 q = gcry_mpi_ec_get_point ("q", ctx, 0);
937 q_x = gcry_mpi_new (256);
938 q_y = gcry_mpi_new (256);
939 gcry_mpi_ec_get_affine (q_x, q_y, q, ctx);
940 gcry_mpi_point_release (q);
941 gcry_ctx_release (ctx);
942
943 /* store q_x/q_y in public key */
944 size = sizeof (ph->public_key.q_x);
945 if (0 !=
946 gcry_mpi_print (GCRYMPI_FMT_USG, ph->public_key.q_x, size, &size,
947 q_x))
948 {
949 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
950 gcry_mpi_release (q_x);
951 gcry_mpi_release (q_y);
952 return NULL;
953
954 }
955 adjust (ph->public_key.q_x, size, sizeof (ph->public_key.q_x));
956 gcry_mpi_release (q_x);
957
958 size = sizeof (ph->public_key.q_y);
959 if (0 !=
960 gcry_mpi_print (GCRYMPI_FMT_USG, ph->public_key.q_y, size, &size,
961 q_y))
962 {
963 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
964 gcry_mpi_release (q_y);
965 return NULL;
966 }
967 adjust (ph->public_key.q_y, size, sizeof (ph->public_key.q_y));
968 gcry_mpi_release (q_y);
969
970 /* write to disk */
971 if (NULL != filename)
972 {
973 ret = GNUNET_DISK_fn_write (filename, ph, sizeof (struct GNUNET_FS_PseudonymHandle),
974 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
975 if (sizeof (struct GNUNET_FS_PseudonymHandle) != ret)
976 {
977 GNUNET_free (ph);
978 return NULL;
979 }
980 }
981 return ph;
982}
983
984
985/**
986 * Create a pseudonym, from a file that must already exist.
987 *
988 * @param filename name of the file to use for storage, NULL for in-memory only
989 * @return handle to the private key of the pseudonym
990 */
991struct GNUNET_FS_PseudonymHandle *
992GNUNET_FS_pseudonym_create_from_existing_file (const char *filename)
993{
994 struct GNUNET_FS_PseudonymHandle *ph;
995 ssize_t ret;
996
997 ph = GNUNET_malloc (sizeof (struct GNUNET_FS_PseudonymHandle));
998 ret = GNUNET_DISK_fn_read (filename, ph,
999 sizeof (struct GNUNET_FS_PseudonymHandle));
1000 if (sizeof (struct GNUNET_FS_PseudonymHandle) != ret)
1001 {
1002 GNUNET_free (ph);
1003 return NULL;
1004 }
1005 /* Note: we don't do any validation here; maybe we should? */
1006 return ph;
1007}
1008
1009
1010/**
1011 * Get the handle for the 'anonymous' pseudonym shared by all users.
1012 * That pseudonym uses a fixed 'secret' for the private key; this
1013 * construction is useful to make anonymous and pseudonymous APIs
1014 * (and packets) indistinguishable on the network. See #2564.
1015 *
1016 * @return handle to the (non-secret) private key of the 'anonymous' pseudonym
1017 */
1018struct GNUNET_FS_PseudonymHandle *
1019GNUNET_FS_pseudonym_get_anonymous_pseudonym_handle ()
1020{
1021 static int once;
1022 gcry_mpi_t d;
1023 size_t size;
1024 gcry_ctx_t ctx;
1025 int rc;
1026 gcry_mpi_t g_x;
1027 gcry_mpi_t g_y;
1028 gcry_mpi_point_t g;
1029
1030 if (once)
1031 return &anonymous;
1032 d = gcry_mpi_new (1);
1033 gcry_mpi_set_ui (d, 1);
1034 size = sizeof (anonymous.d);
1035 GNUNET_assert (0 ==
1036 gcry_mpi_print (GCRYMPI_FMT_USG, anonymous.d, size, &size,
1037 d));
1038 gcry_mpi_release (d);
1039 adjust (anonymous.d, size, sizeof (anonymous.d));
1040
1041 /* create basic ECC context */
1042 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256")))
1043 {
1044 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
1045 "gcry_mpi_ec_new", rc);
1046 return NULL;
1047 }
1048
1049 g = gcry_mpi_ec_get_point ("g", ctx, 0);
1050 g_x = gcry_mpi_new (256);
1051 g_y = gcry_mpi_new (256);
1052 gcry_mpi_ec_get_affine (g_x, g_y, g, ctx);
1053 gcry_mpi_point_release (g);
1054 gcry_ctx_release (ctx);
1055
1056 /* store g_x/g_y in public key */
1057 size = sizeof (anonymous.public_key.q_x);
1058 if (0 !=
1059 gcry_mpi_print (GCRYMPI_FMT_USG, anonymous.public_key.q_x, size, &size,
1060 g_x))
1061 {
1062 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1063 gcry_mpi_release (g_x);
1064 gcry_mpi_release (g_y);
1065 return NULL;
1066 }
1067 adjust (anonymous.public_key.q_x, size, sizeof (anonymous.public_key.q_x));
1068 gcry_mpi_release (g_x);
1069
1070 size = sizeof (anonymous.public_key.q_y);
1071 if (0 !=
1072 gcry_mpi_print (GCRYMPI_FMT_USG, anonymous.public_key.q_y, size, &size,
1073 g_y))
1074 {
1075 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1076 gcry_mpi_release (g_y);
1077 return NULL;
1078 }
1079 adjust (anonymous.public_key.q_y, size, sizeof (anonymous.public_key.q_y));
1080 gcry_mpi_release (g_y);
1081
1082 once = 1;
1083 return &anonymous;
1084}
1085
1086
1087/**
1088 * Destroy a pseudonym handle. Does NOT remove the private key from
1089 * the disk.
1090 *
1091 * @param ph pseudonym handle to destroy
1092 */
1093void
1094GNUNET_FS_pseudonym_destroy (struct GNUNET_FS_PseudonymHandle *ph)
1095{
1096 if (&anonymous != ph)
1097 GNUNET_free (ph);
1098}
1099
1100
1101/**
1102 * Convert the data specified in the given purpose argument to an
1103 * S-expression suitable for signature operations.
1104 *
1105 * @param purpose data to convert
1106 * @param rfc6979 GNUNET_YES if we are to use deterministic ECDSA
1107 * @return converted s-expression
1108 */
1109static gcry_sexp_t
1110data_to_pkcs1 (const struct GNUNET_FS_PseudonymSignaturePurpose *purpose,
1111 int rfc6979)
1112{
1113 struct GNUNET_CRYPTO_ShortHashCode hc;
1114 size_t bufSize;
1115 gcry_sexp_t data;
1116 const char *fmt;
1117 int rc;
1118
1119 GNUNET_CRYPTO_short_hash (purpose, ntohl (purpose->size), &hc);
1120 if (rfc6979)
1121 {
1122 if (0 != (rc = gcry_sexp_build (&data, NULL,
1123 "(data(flags rfc6979)(hash %s %b))",
1124 "sha256",
1125 sizeof (hc),
1126 &hc)))
1127 {
1128 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1129 return NULL;
1130 }
1131 }
1132 else
1133 {
1134 fmt = "(data(flags raw)(5:value32:01234567890123456789012345678901))";
1135 bufSize = strlen (fmt) + 1;
1136 {
1137 char buff[bufSize];
1138
1139 memcpy (buff, fmt, bufSize);
1140 memcpy (&buff
1141 [bufSize -
1142 strlen
1143 ("01234567890123456789012345678901))")
1144 - 1], &hc, sizeof (struct GNUNET_CRYPTO_ShortHashCode));
1145 GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0));
1146 }
1147 }
1148 return data;
1149}
1150
1151
1152/**
1153 * Cryptographically sign some data with the pseudonym.
1154 *
1155 * @param ph private key 'd' used for signing (corresponds to 'x' in #2564)
1156 * @param purpose data to sign
1157 * @param seed hash of the plaintext of the data that we are signing,
1158 * used for deterministic PRNG for anonymous signing;
1159 * corresponds to 'k' in section 2.7 of #2564
1160 * @param signing_key modifier to apply to the private key for signing ('h');
1161 * see section 2.3 of #2564.
1162 * @param signature where to store the signature
1163 * @return GNUNET_SYSERR on failure
1164 */
1165int
1166GNUNET_FS_pseudonym_sign (struct GNUNET_FS_PseudonymHandle *ph,
1167 const struct GNUNET_FS_PseudonymSignaturePurpose *purpose,
1168 const struct GNUNET_HashCode *seed,
1169 const struct GNUNET_HashCode *signing_key,
1170 struct GNUNET_FS_PseudonymSignature *signature)
1171{
1172 size_t size;
1173 size_t erroff;
1174 gcry_mpi_t d;
1175 gcry_mpi_t k;
1176 gcry_mpi_t h;
1177 gcry_mpi_t dh;
1178 gcry_mpi_t n; /* n from P-256 */
1179 gcry_sexp_t spriv;
1180 gcry_sexp_t data;
1181 gcry_sexp_t result;
1182 gcry_mpi_t rs[2];
1183 int rc;
1184
1185 /* get private key 'd' from pseudonym */
1186 size = sizeof (ph->d);
1187 if (0 != (rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG,
1188 &ph->d,
1189 size, &size)))
1190 {
1191 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1192 return GNUNET_SYSERR;
1193 }
1194 /* get 'x' value from signing key */
1195 size = sizeof (struct GNUNET_HashCode);
1196 if (0 != (rc = gcry_mpi_scan (&h, GCRYMPI_FMT_USG,
1197 signing_key,
1198 size, &size)))
1199 {
1200 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1201 gcry_mpi_release (d);
1202 return GNUNET_SYSERR;
1203 }
1204
1205 /* initialize 'n' from P-256; hex copied from libgcrypt code */
1206 if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX,
1207 "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 0, NULL)))
1208 {
1209 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1210 gcry_mpi_release (d);
1211 gcry_mpi_release (h);
1212 return GNUNET_SYSERR;
1213 }
1214
1215 /* calculate dh = d * h mod n */
1216 dh = gcry_mpi_new (256);
1217 gcry_mpi_mulm (dh, d, h, n);
1218 gcry_mpi_release (d);
1219 gcry_mpi_release (h);
1220 gcry_mpi_release (n);
1221
1222 /* now build sexpression with the signing key */
1223 if (0 != (rc = gcry_sexp_build (&spriv, &erroff,
1224 "(private-key(ecdsa(curve \"NIST P-256\")(d %m)))",
1225 dh)))
1226 {
1227 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1228 gcry_mpi_release (dh);
1229 return GNUNET_SYSERR;
1230 }
1231 gcry_mpi_release (dh);
1232 /* prepare data for signing */
1233 data = data_to_pkcs1 (purpose, NULL != seed);
1234 if (NULL == data)
1235 {
1236 gcry_sexp_release (spriv);
1237 return GNUNET_SYSERR;
1238 }
1239 /* get 'k' value from seed, if available */
1240 if (NULL != seed)
1241 {
1242 size = sizeof (struct GNUNET_HashCode);
1243 if (0 != (rc = gcry_mpi_scan (&k, GCRYMPI_FMT_USG,
1244 seed,
1245 size, &size)))
1246 {
1247 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1248 gcry_sexp_release (spriv);
1249 gcry_sexp_release (data);
1250 return GNUNET_SYSERR;
1251 }
1252 }
1253
1254 /* actually create signature */
1255 /* FIXME: need API to pass 'k' if 'seed' was non-NULL! */
1256 if (0 != (rc = gcry_pk_sign (&result, data, spriv)))
1257 {
1258 LOG (GNUNET_ERROR_TYPE_WARNING,
1259 _("ECC signing failed at %s:%d: %s\n"), __FILE__,
1260 __LINE__, gcry_strerror (rc));
1261 gcry_sexp_release (data);
1262 gcry_sexp_release (spriv);
1263 if (NULL != seed)
1264 gcry_mpi_release (k);
1265 memset (signature, 0, sizeof (struct GNUNET_FS_PseudonymSignature));
1266 return GNUNET_SYSERR;
1267 }
1268 if (NULL != seed)
1269 gcry_mpi_release (k);
1270 gcry_sexp_release (data);
1271 gcry_sexp_release (spriv);
1272
1273
1274 /* extract 'r' and 's' values from sexpression 'result' and store in 'signature' */
1275 if (0 != (rc = key_from_sexp (rs, result, "sig-val", "rs")))
1276 {
1277 GNUNET_break (0);
1278 gcry_sexp_release (result);
1279 return GNUNET_SYSERR;
1280 }
1281 gcry_sexp_release (result);
1282 size = sizeof (signature->sig_r);
1283 if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, signature->sig_r, size,
1284 &size, rs[0])))
1285 {
1286 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1287 gcry_mpi_release (rs[0]);
1288 gcry_mpi_release (rs[1]);
1289 return GNUNET_SYSERR;
1290 }
1291 adjust (signature->sig_r, size, sizeof (signature->sig_r));
1292 gcry_mpi_release (rs[0]);
1293
1294 size = sizeof (signature->sig_s);
1295 if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, signature->sig_s, size,
1296 &size, rs[1])))
1297 {
1298 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1299 gcry_mpi_release (rs[1]);
1300 return GNUNET_SYSERR;
1301 }
1302 adjust (signature->sig_s, size, sizeof (signature->sig_s));
1303 gcry_mpi_release (rs[1]);
1304
1305#if EXTRA_CHECKS
1306 {
1307 struct GNUNET_FS_PseudonymIdentifier vk;
1308 struct GNUNET_FS_PseudonymIdentifier pi;
1309
1310 GNUNET_FS_pseudonym_get_identifier (ph, &pi);
1311 GNUNET_assert (GNUNET_OK ==
1312 GNUNET_FS_pseudonym_derive_verification_key (&pi, signing_key, &vk));
1313 GNUNET_assert (GNUNET_OK ==
1314 GNUNET_FS_pseudonym_verify (purpose,
1315 signature,
1316 &vk));
1317 }
1318#endif
1319
1320 GNUNET_FS_pseudonym_get_identifier (ph, &signature->signer);
1321 return GNUNET_OK;
1322}
1323
1324
1325/**
1326 * Get an ECC context (with Q set to the respective public key) from
1327 * a pseudonym.
1328 *
1329 * @param pseudonym with information on 'q'
1330 * @return curve context
1331 */
1332static gcry_ctx_t
1333get_context_from_pseudonym (struct GNUNET_FS_PseudonymIdentifier *pseudonym)
1334{
1335 static struct GNUNET_FS_PseudonymIdentifier zerop;
1336 gcry_ctx_t ctx;
1337 gcry_mpi_t q_x;
1338 gcry_mpi_t q_y;
1339 gcry_mpi_t zero;
1340 gcry_mpi_point_t q;
1341 size_t size;
1342 int rc;
1343
1344 /* extract 'q' from pseudonym */
1345 if (0 == memcmp (pseudonym, &zerop, sizeof (zerop)))
1346 {
1347 /* create basic ECC context */
1348 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256")))
1349 {
1350 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
1351 return NULL;
1352 }
1353 /* FIXME: initialize 'ctx' with 'q' = G */
1354 zero = gcry_mpi_new (0);
1355 gcry_mpi_set_ui (zero, 0);
1356 q = gcry_mpi_point_new (0);
1357 gcry_mpi_point_set (q, zero, zero, zero);
1358 gcry_mpi_ec_set_point ("q", q, ctx);
1359 gcry_mpi_release (zero);
1360 gcry_mpi_point_release (q);
1361 return ctx;
1362 }
1363 size = sizeof (pseudonym->q_x);
1364 if (0 != (rc = gcry_mpi_scan (&q_x, GCRYMPI_FMT_USG, pseudonym->q_x, size, &size)))
1365 {
1366 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1367 return NULL;
1368 }
1369 size = sizeof (pseudonym->q_y);
1370 if (0 != (rc = gcry_mpi_scan (&q_y, GCRYMPI_FMT_USG, pseudonym->q_y, size, &size)))
1371 {
1372 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1373 gcry_mpi_release (q_x);
1374 return NULL;
1375 }
1376 q = gcry_mpi_point_new (256);
1377 gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE);
1378 gcry_mpi_release (q_x);
1379 gcry_mpi_release (q_y);
1380
1381 /* create basic ECC context */
1382 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256")))
1383 {
1384 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
1385 gcry_mpi_point_release (q);
1386 return NULL;
1387 }
1388 /* initialize 'ctx' with 'q' */
1389 gcry_mpi_ec_set_point ("q", q, ctx);
1390 gcry_mpi_point_release (q);
1391 return ctx;
1392}
1393
1394
1395/**
1396 * Given a pseudonym and a signing key, derive the corresponding public
1397 * key that would be used to verify the resulting signature.
1398 *
1399 * @param pseudonym the public key (dQ in ECDSA)
1400 * @param signing_key input to derive 'h' (see section 2.4 of #2564)
1401 * @param verification_key resulting public key to verify the signature
1402 * created from the '(d*h)' of 'pseudonym' and the 'signing_key';
1403 * the value stored here can then be given to GNUNET_FS_pseudonym_verify.
1404 * @return GNUNET_OK on success, GNUNET_SYSERR on error
1405 */
1406int
1407GNUNET_FS_pseudonym_derive_verification_key (struct GNUNET_FS_PseudonymIdentifier *pseudonym,
1408 const struct GNUNET_HashCode *signing_key,
1409 struct GNUNET_FS_PseudonymIdentifier *verification_key)
1410{
1411 gcry_mpi_t h;
1412 size_t size;
1413 int rc;
1414 gcry_ctx_t ctx;
1415 gcry_mpi_point_t q;
1416 gcry_mpi_point_t v;
1417 gcry_mpi_t v_x;
1418 gcry_mpi_t v_y;
1419 gcry_mpi_t h_mod_n;
1420 gcry_mpi_t n; /* n from P-256 */
1421
1422 /* get 'h' value from signing key */
1423 size = sizeof (struct GNUNET_HashCode);
1424 if (0 != (rc = gcry_mpi_scan (&h, GCRYMPI_FMT_USG,
1425 signing_key,
1426 size, &size)))
1427 {
1428 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1429 return GNUNET_SYSERR;
1430 }
1431 /* create ECC context based on Q from pseudonym */
1432 if (NULL == (ctx = get_context_from_pseudonym (pseudonym)))
1433 {
1434 gcry_mpi_release (h);
1435 return GNUNET_SYSERR;
1436 }
1437 /* initialize 'n' from P-256; hex copied from libgcrypt code */
1438 if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX,
1439 "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 0, NULL)))
1440 {
1441 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1442 gcry_mpi_release (h);
1443 return GNUNET_SYSERR;
1444 }
1445 h_mod_n = gcry_mpi_new (0);
1446 gcry_mpi_mod (h_mod_n, h, n);
1447 gcry_mpi_release (h);
1448
1449 /* get Q = dG from 'pseudonym' */
1450 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1451 /* calculate V = hQ = hdG */
1452 v = gcry_mpi_point_new (0);
1453
1454 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1455 gcry_mpi_release (h_mod_n);
1456
1457 /* store 'v' point in "verification_key" */
1458 v_x = gcry_mpi_new (256);
1459 v_y = gcry_mpi_new (256);
1460 gcry_mpi_ec_get_affine (v_x, v_y, v, ctx);
1461
1462 gcry_mpi_point_release (v);
1463 gcry_ctx_release (ctx);
1464
1465 size = sizeof (verification_key->q_x);
1466 if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, verification_key->q_x, size,
1467 &size, v_x)))
1468 {
1469 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1470 gcry_mpi_release (v_x);
1471 gcry_mpi_release (v_y);
1472 return GNUNET_SYSERR;
1473 }
1474 gcry_mpi_release (v_x);
1475 size = sizeof (verification_key->q_y);
1476 if (0 != (rc = gcry_mpi_print (GCRYMPI_FMT_USG, verification_key->q_y, size,
1477 &size, v_y)))
1478 {
1479 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_print", rc);
1480 gcry_mpi_release (v_y);
1481 return GNUNET_SYSERR;
1482 }
1483 gcry_mpi_release (v_y);
1484 return GNUNET_OK;
1485}
1486
1487
1488/**
1489 * Verify a signature made with a pseudonym.
1490 *
1491 * @param purpose data that was signed
1492 * @param signature signature to verify
1493 * @param verification_key public key to use for checking the signature;
1494 * corresponds to 'g^(x+h)' in section 2.4 of #2564.
1495 * @return GNUNET_OK on success (signature valid, 'pseudonym' set),
1496 * GNUNET_SYSERR if the signature is invalid
1497 */
1498int
1499GNUNET_FS_pseudonym_verify (const struct GNUNET_FS_PseudonymSignaturePurpose *purpose,
1500 const struct GNUNET_FS_PseudonymSignature *signature,
1501 const struct GNUNET_FS_PseudonymIdentifier *verification_key)
1502{
1503 gcry_sexp_t data;
1504 gcry_sexp_t sig_sexpr;
1505 gcry_sexp_t pk_sexpr;
1506 size_t size;
1507 gcry_ctx_t ctx;
1508 gcry_mpi_t r;
1509 gcry_mpi_t s;
1510 gcry_mpi_point_t q;
1511 gcry_mpi_t q_x;
1512 gcry_mpi_t q_y;
1513 size_t erroff;
1514 int rc;
1515
1516 /* build s-expression for signature */
1517 size = sizeof (signature->sig_r);
1518 if (0 != (rc = gcry_mpi_scan (&r, GCRYMPI_FMT_USG,
1519 signature->sig_r, size, &size)))
1520 {
1521 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1522 return GNUNET_SYSERR;
1523 }
1524 size = sizeof (signature->sig_s);
1525 if (0 != (rc = gcry_mpi_scan (&s, GCRYMPI_FMT_USG,
1526 signature->sig_s, size, &size)))
1527 {
1528 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1529 gcry_mpi_release (r);
1530 return GNUNET_SYSERR;
1531 }
1532 if (0 != (rc = gcry_sexp_build (&sig_sexpr, &erroff, "(sig-val(ecdsa(r %m)(s %m)))",
1533 r, s)))
1534 {
1535 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1536 gcry_mpi_release (r);
1537 gcry_mpi_release (s);
1538 return GNUNET_SYSERR;
1539 }
1540 gcry_mpi_release (r);
1541 gcry_mpi_release (s);
1542
1543
1544 /* build s-expression for data that was signed */
1545 data = data_to_pkcs1 (purpose, GNUNET_NO);
1546 if (NULL == data)
1547 {
1548 gcry_sexp_release (sig_sexpr);
1549 return GNUNET_SYSERR;
1550 }
1551 /* create context of public key and initialize Q */
1552 size = sizeof (verification_key->q_x);
1553 if (0 != (rc = gcry_mpi_scan (&q_x, GCRYMPI_FMT_USG,
1554 verification_key->q_x, size, &size)))
1555 {
1556 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1557 gcry_sexp_release (data);
1558 gcry_sexp_release (sig_sexpr);
1559 return GNUNET_SYSERR;
1560 }
1561 size = sizeof (verification_key->q_y);
1562 if (0 != (rc = gcry_mpi_scan (&q_y, GCRYMPI_FMT_USG,
1563 verification_key->q_y, size, &size)))
1564 {
1565 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1566 gcry_sexp_release (data);
1567 gcry_sexp_release (sig_sexpr);
1568 gcry_mpi_release (q_x);
1569 return GNUNET_SYSERR;
1570 }
1571 q = gcry_mpi_point_new (256);
1572 gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE);
1573 gcry_mpi_release (q_x);
1574 gcry_mpi_release (q_y);
1575
1576 /* create basic ECC context */
1577 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256")))
1578 {
1579 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
1580 gcry_sexp_release (data);
1581 gcry_sexp_release (sig_sexpr);
1582 gcry_mpi_point_release (q);
1583 return GNUNET_SYSERR;
1584 }
1585 /* initialize 'ctx' with 'q' */
1586 gcry_mpi_ec_set_point ("q", q, ctx);
1587 gcry_mpi_point_release (q);
1588
1589 /* convert 'ctx' to 'sexp' */
1590 if (0 != (rc = gcry_pubkey_get_sexp (&pk_sexpr, GCRY_PK_GET_PUBKEY, ctx)))
1591 {
1592 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_from_context", rc);
1593 gcry_ctx_release (ctx);
1594 gcry_sexp_release (data);
1595 gcry_sexp_release (sig_sexpr);
1596 return GNUNET_SYSERR;
1597 }
1598 gcry_ctx_release (ctx);
1599
1600 /* finally, verify the signature */
1601 rc = gcry_pk_verify (sig_sexpr, data, pk_sexpr);
1602 gcry_sexp_release (sig_sexpr);
1603 gcry_sexp_release (data);
1604 gcry_sexp_release (pk_sexpr);
1605 if (rc)
1606 {
1607 LOG (GNUNET_ERROR_TYPE_WARNING,
1608 _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__,
1609 __LINE__, gcry_strerror (rc));
1610 return GNUNET_SYSERR;
1611 }
1612 return GNUNET_OK;
1613}
1614
1615
1616/**
1617 * Get the identifier (public key) of a pseudonym.
1618 *
1619 * @param ph pseudonym handle with the private key
1620 * @param pseudonym pseudonym identifier (set based on 'ph')
1621 */
1622void
1623GNUNET_FS_pseudonym_get_identifier (struct GNUNET_FS_PseudonymHandle *ph,
1624 struct GNUNET_FS_PseudonymIdentifier *pseudonym)
1625{
1626 memcpy (pseudonym, &ph->public_key,
1627 sizeof (struct GNUNET_FS_PseudonymIdentifier));
1628}
1629
1630
1631/**
1632 * Remove pseudonym from the set of known pseudonyms.
1633 *
1634 * @param cfg overall configuration
1635 * @param id the pseudonym identifier
1636 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1637 */
1638int
1639GNUNET_FS_pseudonym_remove (const struct GNUNET_CONFIGURATION_Handle *cfg,
1640 const struct GNUNET_FS_PseudonymIdentifier *id)
1641{
1642 char *fn;
1643 int result;
1644
1645 fn = get_data_filename (cfg, PS_METADATA_DIR, id);
1646 if (NULL == fn)
1647 return GNUNET_SYSERR;
1648 result = UNLINK (fn);
1649 GNUNET_free (fn);
1650 return (0 == result) ? GNUNET_OK : GNUNET_SYSERR;
1651}
1652 753
1653/* end of pseudonym.c */ 754/* end of pseudonym.c */