-fix doxygen
[oweals/gnunet.git] / src / util / crypto_ecc.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012, 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 /**
22  * @file util/crypto_ecc.c
23  * @brief public key cryptography (ECC) with libgcrypt
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include <gcrypt.h>
28 #include "gnunet_common.h"
29 #include "gnunet_util_lib.h"
30
31 #define EXTRA_CHECKS ALLOW_EXTRA_CHECKS 
32
33 /**
34  * Name of the curve we are using.  Note that we have hard-coded
35  * structs that use 256 bits, so using a bigger curve will require
36  * changes that break stuff badly.  The name of the curve given here
37  * must be agreed by all peers and be supported by libgcrypt.
38  */
39 #define CURVE "Ed25519"
40
41 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
42
43 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
44
45 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
46
47 /**
48  * Log an error message at log-level 'level' that indicates
49  * a failure of the command 'cmd' with the message given
50  * by gcry_strerror(rc).
51  */
52 #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)
53
54
55 /**
56  * Extract values from an S-expression.
57  *
58  * @param array where to store the result(s)
59  * @param sexp S-expression to parse
60  * @param topname top-level name in the S-expression that is of interest
61  * @param elems names of the elements to extract
62  * @return 0 on success
63  */
64 static int
65 key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
66                const char *elems)
67 {
68   gcry_sexp_t list;
69   gcry_sexp_t l2;
70   const char *s;
71   unsigned int i;
72   unsigned int idx;
73
74   list = gcry_sexp_find_token (sexp, topname, 0);
75   if (! list)  
76     return 1;  
77   l2 = gcry_sexp_cadr (list);
78   gcry_sexp_release (list);
79   list = l2;
80   if (! list)  
81     return 2;  
82
83   idx = 0;
84   for (s = elems; *s; s++, idx++)
85   {
86     l2 = gcry_sexp_find_token (list, s, 1);
87     if (! l2)
88     {
89       for (i = 0; i < idx; i++)
90       {
91         gcry_free (array[i]);
92         array[i] = NULL;
93       }
94       gcry_sexp_release (list);
95       return 3;                 /* required parameter not found */
96     }
97     array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
98     gcry_sexp_release (l2);
99     if (! array[idx])
100     {
101       for (i = 0; i < idx; i++)
102       {
103         gcry_free (array[i]);
104         array[i] = NULL;
105       }
106       gcry_sexp_release (list);
107       return 4;                 /* required parameter is invalid */
108     }
109   }
110   gcry_sexp_release (list);
111   return 0;
112 }
113
114
115 /**
116  * If target != size, move @a target bytes to the end of the size-sized
117  * buffer and zero out the first @a target - @a size bytes.
118  *
119  * @param buf original buffer
120  * @param size number of bytes in @a buf
121  * @param target target size of the buffer
122  */
123 static void
124 adjust (unsigned char *buf,
125         size_t size,
126         size_t target)
127 {
128   if (size < target)
129   {
130     memmove (&buf[target - size], buf, size);
131     memset (buf, 0, target - size);
132   }
133 }
134
135
136 /**
137  * Output the given MPI value to the given buffer.
138  * 
139  * @param buf where to output to
140  * @param size number of bytes in @a buf
141  * @param val value to write to @a buf
142  */
143 static void
144 mpi_print (unsigned char *buf,
145            size_t size,
146            gcry_mpi_t val)
147 {
148   size_t rsize;
149
150   rsize = size;
151   GNUNET_assert (0 ==
152                  gcry_mpi_print (GCRYMPI_FMT_USG, buf, rsize, &rsize,
153                                  val));
154   adjust (buf, rsize, size);
155 }
156
157
158 /**
159  * Convert data buffer into MPI value.
160  *
161  * @param result where to store MPI value (allocated)
162  * @param data raw data (GCRYMPI_FMT_USG)
163  * @param size number of bytes in data
164  */
165 static void
166 mpi_scan (gcry_mpi_t *result,
167           const unsigned char *data,
168           size_t size)
169 {
170   int rc;
171
172   if (0 != (rc = gcry_mpi_scan (result,
173                                 GCRYMPI_FMT_USG, 
174                                 data, size, &size)))
175   {
176     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
177     GNUNET_assert (0);
178   }
179 }
180
181
182 /**
183  * Convert the given private key from the network format to the
184  * S-expression that can be used by libgcrypt.
185  *
186  * @param priv private key to decode
187  * @return NULL on error
188  */
189 static gcry_sexp_t
190 decode_private_key (const struct GNUNET_CRYPTO_EccPrivateKey *priv)
191 {
192   gcry_sexp_t result;
193   gcry_mpi_t d;
194   int rc;
195
196   mpi_scan (&d,
197             priv->d,
198             sizeof (priv->d));
199   rc = gcry_sexp_build (&result, NULL,
200                         "(private-key(ecc(curve \"" CURVE "\")(d %m)))",
201                         d);
202   gcry_mpi_release (d);
203   if (0 != rc)
204   {
205     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); 
206     GNUNET_assert (0);
207   }
208 #if EXTRA_CHECKS
209   if (0 != (rc = gcry_pk_testkey (result)))
210   {
211     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
212     GNUNET_assert (0);
213   }
214 #endif
215   return result;
216 }
217
218
219 /**
220  * Extract the public key for the given private key.
221  *
222  * @param priv the private key
223  * @param pub where to write the public key
224  */
225 void
226 GNUNET_CRYPTO_ecc_key_get_public_for_signature (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
227                                                 struct GNUNET_CRYPTO_EccPublicSignKey *pub)
228 {
229   gcry_sexp_t sexp;
230   gcry_ctx_t ctx;
231   gcry_mpi_t q_y;
232
233   sexp = decode_private_key (priv);
234   gcry_sexp_dump (sexp);
235   GNUNET_assert (NULL != sexp);
236   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
237   gcry_sexp_release (sexp);
238   if (NULL == (q_y = gcry_mpi_ec_get_mpi ("y", ctx, 0)))
239   {
240     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, 
241               "gcry_mpi_ec_get_mpi failed", 0);
242     return;
243   }
244   mpi_print (pub->q_y, sizeof (pub->q_y), q_y);
245   gcry_ctx_release (ctx);
246   // gcry_mpi_release (q_y); /* needed? we set copy to 0... */
247 }
248
249
250 /**
251  * Extract the public key for the given private key.
252  *
253  * @param priv the private key
254  * @param pub where to write the public key
255  */
256 void
257 GNUNET_CRYPTO_ecc_key_get_public_for_encryption (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
258                                                  struct GNUNET_CRYPTO_EccPublicEncryptKey *pub)
259 {
260   gcry_sexp_t sexp;
261   gcry_ctx_t ctx;
262   gcry_mpi_t q_x;
263
264   sexp = decode_private_key (priv);
265   GNUNET_assert (NULL != sexp);
266   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
267   gcry_sexp_release (sexp);
268   if (NULL == (q_x = gcry_mpi_ec_get_mpi ("x", ctx, 0)))
269   {
270     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, 
271               "gcry_mpi_ec_get_mpi failed", 0);
272     return;
273   }
274   mpi_print (pub->q_x, sizeof (pub->q_x), q_x);
275   gcry_ctx_release (ctx);
276 }
277
278
279 /**
280  * Convert a public key to a string.
281  *
282  * @param pub key to convert
283  * @return string representing @a pub
284  */
285 char *
286 GNUNET_CRYPTO_ecc_public_sign_key_to_string (const struct GNUNET_CRYPTO_EccPublicSignKey *pub)
287 {
288   char *pubkeybuf;
289   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicSignKey)) * 8;
290   char *end;
291
292   if (keylen % 5 > 0)
293     keylen += 5 - keylen % 5;
294   keylen /= 5;
295   pubkeybuf = GNUNET_malloc (keylen + 1);
296   end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub, 
297                                        sizeof (struct GNUNET_CRYPTO_EccPublicSignKey), 
298                                        pubkeybuf, 
299                                        keylen);
300   if (NULL == end)
301   {
302     GNUNET_free (pubkeybuf);
303     return NULL;
304   }
305   *end = '\0';
306   return pubkeybuf;
307 }
308
309
310 /**
311  * Convert a string representing a public key to a public key.
312  *
313  * @param enc encoded public key
314  * @param enclen number of bytes in @a enc (without 0-terminator)
315  * @param pub where to store the public key
316  * @return #GNUNET_OK on success
317  */
318 int
319 GNUNET_CRYPTO_ecc_public_sign_key_from_string (const char *enc, 
320                                           size_t enclen,
321                                           struct GNUNET_CRYPTO_EccPublicSignKey *pub)
322 {
323   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicSignKey)) * 8;
324
325   if (keylen % 5 > 0)
326     keylen += 5 - keylen % 5;
327   keylen /= 5;
328   if (enclen != keylen)
329     return GNUNET_SYSERR;
330
331   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
332                                                   pub,
333                                                   sizeof (struct GNUNET_CRYPTO_EccPublicSignKey)))
334     return GNUNET_SYSERR;
335   return GNUNET_OK;
336 }
337
338
339 /**
340  * Convert the given public key from the network format to the
341  * S-expression that can be used by libgcrypt.
342  *
343  * @param pub public key to decode
344  * @return NULL on error
345  */
346 static gcry_sexp_t
347 decode_public_sign_key (const struct GNUNET_CRYPTO_EccPublicSignKey *pub)
348 {
349   gcry_sexp_t pub_sexp;
350   gcry_mpi_t q_y;
351   gcry_ctx_t ctx;
352
353   mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y));
354   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
355   gcry_mpi_ec_set_mpi ("y", q_y, ctx);
356   gcry_mpi_release (q_y);
357
358   /* convert 'ctx' to 'sexp' */
359   GNUNET_assert (0 == gcry_pubkey_get_sexp (&pub_sexp, GCRY_PK_GET_PUBKEY, ctx));
360   gcry_ctx_release (ctx);
361   return pub_sexp;
362 }
363
364
365 /**
366  * @ingroup crypto
367  * Clear memory that was used to store a private key. 
368  *
369  * @param pk location of the key
370  */
371 void
372 GNUNET_CRYPTO_ecc_key_clear (struct GNUNET_CRYPTO_EccPrivateKey *pk)
373 {
374   memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
375 }
376
377
378 /**
379  * Create a new private key. Caller must free return value.
380  *
381  * @return fresh private key
382  */
383 struct GNUNET_CRYPTO_EccPrivateKey *
384 GNUNET_CRYPTO_ecc_key_create ()
385 {
386   struct GNUNET_CRYPTO_EccPrivateKey *priv;
387   gcry_sexp_t priv_sexp;
388   gcry_sexp_t s_keyparam;
389   gcry_mpi_t d;
390   int rc;
391
392   if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
393                                   "(genkey(ecc(curve \"" CURVE "\")))")))
394   {
395     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
396     return NULL;
397   }
398   if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
399   {
400     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
401     gcry_sexp_release (s_keyparam);
402     return NULL;
403   }
404   gcry_sexp_release (s_keyparam);
405 #if EXTRA_CHECKS
406   if (0 != (rc = gcry_pk_testkey (priv_sexp)))
407   {
408     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
409     gcry_sexp_release (priv_sexp);
410     return NULL;
411   }
412 #endif
413   if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
414   {
415     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
416     gcry_sexp_release (priv_sexp);
417     return NULL;
418   }
419   gcry_sexp_release (priv_sexp);
420   priv = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
421   mpi_print (priv->d, sizeof (priv->d), d);
422   gcry_mpi_release (d);
423   return priv;
424 }
425
426
427 /**
428  * Get the shared private key we use for anonymous users.
429  *
430  * @return "anonymous" private key
431  */
432 const struct GNUNET_CRYPTO_EccPrivateKey *
433 GNUNET_CRYPTO_ecc_key_get_anonymous ()
434 {
435   /**
436    * 'anonymous' pseudonym (global static, d=1, public key = G
437    * (generator).
438    */
439   static struct GNUNET_CRYPTO_EccPrivateKey anonymous;
440   static int once;
441
442   if (once)
443     return &anonymous;
444   mpi_print (anonymous.d, 
445              sizeof (anonymous.d), 
446              GCRYMPI_CONST_ONE);
447   once = 1;
448   return &anonymous;
449 }
450
451
452 /**
453  * Wait for a short time (we're trying to lock a file or want
454  * to give another process a shot at finishing a disk write, etc.).
455  * Sleeps for 100ms (as that should be long enough for virtually all
456  * modern systems to context switch and allow another process to do
457  * some 'real' work).
458  */
459 static void
460 short_wait ()
461 {
462   struct GNUNET_TIME_Relative timeout;
463
464   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
465   (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
466 }
467
468
469 /**
470  * Create a new private key by reading it from a file.  If the
471  * files does not exist, create a new key and write it to the
472  * file.  Caller must free return value.  Note that this function
473  * can not guarantee that another process might not be trying
474  * the same operation on the same file at the same time.
475  * If the contents of the file
476  * are invalid the old file is deleted and a fresh key is
477  * created.
478  *
479  * @param filename name of file to use to store the key
480  * @return new private key, NULL on error (for example,
481  *   permission denied)
482  */
483 struct GNUNET_CRYPTO_EccPrivateKey *
484 GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
485 {
486   struct GNUNET_CRYPTO_EccPrivateKey *priv;
487   struct GNUNET_DISK_FileHandle *fd;
488   unsigned int cnt;
489   int ec;
490   uint64_t fs;
491
492   if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
493     return NULL;
494   while (GNUNET_YES != GNUNET_DISK_file_test (filename))
495   {
496     fd = GNUNET_DISK_file_open (filename,
497                                 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
498                                 | GNUNET_DISK_OPEN_FAILIFEXISTS,
499                                 GNUNET_DISK_PERM_USER_READ |
500                                 GNUNET_DISK_PERM_USER_WRITE);
501     if (NULL == fd)
502     {
503       if (EEXIST == errno)
504       {
505         if (GNUNET_YES != GNUNET_DISK_file_test (filename))
506         {
507           /* must exist but not be accessible, fail for good! */
508           if (0 != ACCESS (filename, R_OK))
509             LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
510           else
511             GNUNET_break (0);   /* what is going on!? */
512           return NULL;
513         }
514         continue;
515       }
516       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
517       return NULL;
518     }
519     cnt = 0;
520     while (GNUNET_YES !=
521            GNUNET_DISK_file_lock (fd, 0,
522                                   sizeof (struct GNUNET_CRYPTO_EccPrivateKey),
523                                   GNUNET_YES))
524     {
525       short_wait ();
526       if (0 == ++cnt % 10)
527       {
528         ec = errno;
529         LOG (GNUNET_ERROR_TYPE_ERROR,
530              _("Could not acquire lock on file `%s': %s...\n"), filename,
531              STRERROR (ec));
532       }
533     }
534     LOG (GNUNET_ERROR_TYPE_INFO,
535          _("Creating a new private key.  This may take a while.\n"));
536     priv = GNUNET_CRYPTO_ecc_key_create ();
537     GNUNET_assert (NULL != priv);
538     GNUNET_assert (sizeof (*priv) ==
539                    GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
540     GNUNET_DISK_file_sync (fd);
541     if (GNUNET_YES !=
542         GNUNET_DISK_file_unlock (fd, 0,
543                                  sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
544       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
545     GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
546     return priv;
547   }
548   /* key file exists already, read it! */
549   fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
550                               GNUNET_DISK_PERM_NONE);
551   if (NULL == fd)
552   {
553     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
554     return NULL;
555   }
556   cnt = 0;
557   while (1)
558   {
559     if (GNUNET_YES !=
560         GNUNET_DISK_file_lock (fd, 0,
561                                sizeof (struct GNUNET_CRYPTO_EccPrivateKey),
562                                GNUNET_NO))
563     {
564       if (0 == ++cnt % 60)
565       {
566         ec = errno;
567         LOG (GNUNET_ERROR_TYPE_ERROR,
568              _("Could not acquire lock on file `%s': %s...\n"), filename,
569              STRERROR (ec));
570         LOG (GNUNET_ERROR_TYPE_ERROR,
571              _
572              ("This may be ok if someone is currently generating a private key.\n"));
573       }
574       short_wait ();
575       continue;
576     }
577     if (GNUNET_YES != GNUNET_DISK_file_test (filename))
578     {
579       /* eh, what!? File we opened is now gone!? */
580       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
581       if (GNUNET_YES !=
582           GNUNET_DISK_file_unlock (fd, 0,
583                                    sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
584         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
585       GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
586
587       return NULL;
588     }
589     if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
590       fs = 0;
591     if (fs < sizeof (struct GNUNET_CRYPTO_EccPrivateKey))
592     {
593       /* maybe we got the read lock before the key generating
594        * process had a chance to get the write lock; give it up! */
595       if (GNUNET_YES !=
596           GNUNET_DISK_file_unlock (fd, 0,
597                                    sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
598         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
599       if (0 == ++cnt % 10)
600       {
601         LOG (GNUNET_ERROR_TYPE_ERROR,
602              _
603              ("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
604              filename, (unsigned int) fs,
605              (unsigned int) sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
606         LOG (GNUNET_ERROR_TYPE_ERROR,
607              _
608              ("This may be ok if someone is currently generating a key.\n"));
609       }
610       short_wait ();                /* wait a bit longer! */
611       continue;
612     }
613     break;
614   }
615   fs = sizeof (struct GNUNET_CRYPTO_EccPrivateKey);
616   priv = GNUNET_malloc (fs);
617   GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
618   if (GNUNET_YES !=
619       GNUNET_DISK_file_unlock (fd, 0,
620                                sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
621     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
622   GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
623   return priv;
624 }
625
626
627 /**
628  * Create a new private key by reading our peer's key from
629  * the file specified in the configuration.
630  *
631  * @param cfg the configuration to use
632  * @return new private key, NULL on error (for example,
633  *   permission denied)
634  */
635 struct GNUNET_CRYPTO_EccPrivateKey *
636 GNUNET_CRYPTO_ecc_key_create_from_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
637 {
638   struct GNUNET_CRYPTO_EccPrivateKey *priv;
639   char *fn;
640
641   if (GNUNET_OK != 
642       GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn))
643     return NULL;
644   priv = GNUNET_CRYPTO_ecc_key_create_from_file (fn);
645   GNUNET_free (fn);
646   return priv;
647 }
648
649
650 /**
651  * Setup a key file for a peer given the name of the
652  * configuration file (!).  This function is used so that
653  * at a later point code can be certain that reading a
654  * key is fast (for example in time-dependent testcases).
655  *
656  * @param cfg_name name of the configuration file to use
657  */
658 void
659 GNUNET_CRYPTO_ecc_setup_key (const char *cfg_name)
660 {
661   struct GNUNET_CONFIGURATION_Handle *cfg;
662   struct GNUNET_CRYPTO_EccPrivateKey *priv;
663
664   cfg = GNUNET_CONFIGURATION_create ();
665   (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
666   priv = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg);
667   if (NULL != priv)
668     GNUNET_free (priv);
669   GNUNET_CONFIGURATION_destroy (cfg);
670 }
671
672
673 /**
674  * Retrieve the identity of the host's peer.
675  *
676  * @param cfg configuration to use
677  * @param dst pointer to where to write the peer identity
678  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the identity
679  *         could not be retrieved
680  */
681 int
682 GNUNET_CRYPTO_get_host_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
683                                  struct GNUNET_PeerIdentity *dst)
684 {
685   struct GNUNET_CRYPTO_EccPrivateKey *priv;
686   struct GNUNET_CRYPTO_EccPublicSignKey pub;
687
688   if (NULL == (priv = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg)))
689   {
690     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691                 _("Could not load peer's private key\n"));
692     return GNUNET_SYSERR;
693   }
694   GNUNET_CRYPTO_ecc_key_get_public_for_signature (priv, &pub);
695   GNUNET_free (priv);
696   GNUNET_CRYPTO_hash (&pub, sizeof (pub), &dst->hashPubKey);
697   return GNUNET_OK;
698 }
699
700
701 /**
702  * Convert the data specified in the given purpose argument to an
703  * S-expression suitable for signature operations.
704  *
705  * @param purpose data to convert
706  * @return converted s-expression
707  */
708 static gcry_sexp_t
709 data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
710 {
711   struct GNUNET_HashCode hc;
712   gcry_sexp_t data;
713   int rc;
714
715   GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
716   if (0 != (rc = gcry_sexp_build (&data, NULL,
717                                   "(data(flags eddsa)(hash %s %b))",
718                                   "sha512",
719                                   sizeof (hc),
720                                   &hc)))
721   {
722     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
723     return NULL;
724   }
725   return data;
726 }
727
728
729 /**
730  * Sign a given block.
731  *
732  * @param priv private key to use for the signing
733  * @param purpose what to sign (size, purpose)
734  * @param sig where to write the signature
735  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
736  */
737 int
738 GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
739                         const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
740                         struct GNUNET_CRYPTO_EccSignature *sig)
741 {
742   gcry_sexp_t priv_sexp;
743   gcry_sexp_t sig_sexp;
744   gcry_sexp_t data;
745   int rc;
746   gcry_mpi_t rs[2];
747
748   priv_sexp = decode_private_key (priv);
749   data = data_to_pkcs1 (purpose);
750   if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
751   {
752     LOG (GNUNET_ERROR_TYPE_WARNING,
753          _("ECC signing failed at %s:%d: %s\n"), __FILE__,
754          __LINE__, gcry_strerror (rc));
755     gcry_sexp_release (data);
756     gcry_sexp_release (priv_sexp);
757     return GNUNET_SYSERR;
758   }
759   gcry_sexp_release (priv_sexp);
760   gcry_sexp_release (data);
761
762   /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
763      'signature' */
764   if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
765   {
766     GNUNET_break (0);
767     gcry_sexp_release (sig_sexp);
768     return GNUNET_SYSERR;
769   }
770   gcry_sexp_release (sig_sexp);
771   mpi_print (sig->r, sizeof (sig->r), rs[0]);
772   mpi_print (sig->s, sizeof (sig->s), rs[1]);
773   gcry_mpi_release (rs[0]);
774   gcry_mpi_release (rs[1]);
775   return GNUNET_OK;
776 }
777
778
779 /**
780  * Verify signature.
781  *
782  * @param purpose what is the purpose that the signature should have?
783  * @param validate block to validate (size, purpose, data)
784  * @param sig signature that is being validated
785  * @param pub public key of the signer
786  * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
787  */
788 int
789 GNUNET_CRYPTO_ecc_verify (uint32_t purpose,
790                           const struct GNUNET_CRYPTO_EccSignaturePurpose
791                           *validate,
792                           const struct GNUNET_CRYPTO_EccSignature *sig,
793                           const struct GNUNET_CRYPTO_EccPublicSignKey *pub)
794 {
795   gcry_sexp_t data;
796   gcry_sexp_t sig_sexpr;
797   gcry_sexp_t pub_sexpr;
798   int rc;
799   gcry_mpi_t r;
800   gcry_mpi_t s;
801
802   if (purpose != ntohl (validate->purpose))
803     return GNUNET_SYSERR;       /* purpose mismatch */
804
805   /* build s-expression for signature */
806   mpi_scan (&r, sig->r, sizeof (sig->r));
807   mpi_scan (&s, sig->s, sizeof (sig->s));
808   if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL, 
809                                   "(sig-val(eddsa(r %m)(s %m)))",
810                                   r, s)))
811   {
812     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
813     gcry_mpi_release (r);
814     gcry_mpi_release (s);
815     return GNUNET_SYSERR;
816   }
817   gcry_mpi_release (r);
818   gcry_mpi_release (s);
819   data = data_to_pkcs1 (validate);
820   if (! (pub_sexpr = decode_public_sign_key (pub)))
821   {
822     gcry_sexp_release (data);
823     gcry_sexp_release (sig_sexpr);
824     return GNUNET_SYSERR;
825   }
826   rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
827   gcry_sexp_release (pub_sexpr);
828   gcry_sexp_release (data);
829   gcry_sexp_release (sig_sexpr);
830   if (0 != rc)
831   {
832     LOG (GNUNET_ERROR_TYPE_INFO,
833          _("ECC signature verification failed at %s:%d: %s\n"), __FILE__,
834          __LINE__, gcry_strerror (rc));
835     return GNUNET_SYSERR;
836   }
837   return GNUNET_OK;
838 }
839
840
841 /**
842  * Convert the given public key from the network format to the
843  * S-expression that can be used by libgcrypt.
844  *
845  * @param pub public key to decode
846  * @return NULL on error
847  */
848 static gcry_sexp_t
849 decode_public_encrypt_key (const struct GNUNET_CRYPTO_EccPublicEncryptKey *pub)
850 {
851   gcry_sexp_t pub_sexp;
852   gcry_mpi_t q_x;
853   gcry_ctx_t ctx;
854   int rc;
855
856   mpi_scan (&q_x, pub->q_x, sizeof (pub->q_x));
857   /* initialize 'ctx' with 'x' */
858   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
859   if (0 != (rc = gcry_mpi_ec_set_mpi ("x", q_x, ctx)))
860     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_set_mpi", rc);
861   gcry_mpi_release (q_x);
862
863   /* convert 'ctx' to 'sexp' */
864   GNUNET_assert (0 == gcry_pubkey_get_sexp (&pub_sexp, GCRY_PK_GET_PUBKEY, ctx));
865   gcry_ctx_release (ctx);
866   return pub_sexp;
867 }
868
869
870 /**
871  * Derive key material from a public and a private ECC key.
872  *
873  * @param priv private key to use for the ECDH (x)
874  * @param pub public key to use for the ECDH (yG)
875  * @param key_material where to write the key material (xyG)
876  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
877  */
878 int
879 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
880                         const struct GNUNET_CRYPTO_EccPublicEncryptKey *pub,
881                         struct GNUNET_HashCode *key_material)
882
883   gcry_mpi_point_t result;
884   gcry_mpi_point_t q;
885   gcry_mpi_t d;
886   gcry_ctx_t ctx;
887   gcry_sexp_t pub_sexpr;
888   gcry_mpi_t result_x;
889   gcry_mpi_t result_y;
890   unsigned char xbuf[256 / 8];
891   int rc;
892
893   /* first, extract the q = dP value from the public key */
894   if (! (pub_sexpr = decode_public_encrypt_key (pub)))
895     return GNUNET_SYSERR;
896   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
897   gcry_sexp_release (pub_sexpr);
898   q = gcry_mpi_ec_get_point ("q", ctx, 0);
899   if (NULL == q)
900   {
901     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_get_point", 0);
902     return GNUNET_SYSERR;
903   }
904
905   /* second, extract the d value from our private key */
906   mpi_scan (&d, priv->d, sizeof (priv->d));
907
908   /* then call the 'multiply' function, to compute the product */
909   result = gcry_mpi_point_new (0);
910   gcry_mpi_ec_mul (result, d, q, ctx);
911   gcry_mpi_point_release (q);
912   gcry_mpi_release (d);
913
914   /* finally, convert point to string for hashing */
915   result_x = gcry_mpi_new (256);
916   result_y = gcry_mpi_new (256);
917   if (0 != (rc = gcry_mpi_ec_get_affine (result_x, result_y, result, ctx)))
918   {
919     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_get_affine", rc);
920     gcry_mpi_point_release (result);
921     gcry_ctx_release (ctx);
922     return GNUNET_SYSERR;
923   }
924   gcry_mpi_point_release (result);
925   gcry_ctx_release (ctx);
926
927   mpi_print (xbuf, sizeof (xbuf), result_x);
928   GNUNET_CRYPTO_hash (xbuf, sizeof (xbuf), key_material);
929   gcry_mpi_release (result_x);
930   gcry_mpi_release (result_y);
931   return GNUNET_OK;
932 }
933
934
935 /**
936  * Derive the 'h' value for key derivation, where 
937  * 'h = H(l,P)'.
938  *
939  * @param pub public key for deriviation
940  * @param label label for deriviation
941  * @param context additional context to use for HKDF of 'h';
942  *        typically the name of the subsystem/application
943  * @return h value
944  */ 
945 static gcry_mpi_t 
946 derive_h (const struct GNUNET_CRYPTO_EccPublicSignKey *pub,
947           const char *label,
948           const char *context)
949 {
950   gcry_mpi_t h;
951   struct GNUNET_HashCode hc;
952
953   GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
954                      "key-derivation", strlen ("key-derivation"),
955                      pub, sizeof (*pub),
956                      label, strlen (label),
957                      context, strlen (context),
958                      NULL, 0);
959   mpi_scan (&h, (unsigned char *) &hc, sizeof (hc));
960   return h;
961 }
962
963
964 /**
965  * Derive a private key from a given private key and a label.
966  * Essentially calculates a private key 'd = H(l,P) * x mod n'
967  * where n is the size of the ECC group and P is the public
968  * key associated with the private key 'd'.
969  *
970  * @param priv original private key
971  * @param label label to use for key deriviation
972  * @param context additional context to use for HKDF of 'h';
973  *        typically the name of the subsystem/application
974  * @return derived private key
975  */
976 struct GNUNET_CRYPTO_EccPrivateKey *
977 GNUNET_CRYPTO_ecc_key_derive (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
978                               const char *label,
979                               const char *context)
980 {
981   struct GNUNET_CRYPTO_EccPublicSignKey pub;
982   struct GNUNET_CRYPTO_EccPrivateKey *ret;
983   gcry_mpi_t h;
984   gcry_mpi_t x;
985   gcry_mpi_t d;
986   gcry_mpi_t n;
987   gcry_ctx_t ctx;
988
989   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
990   n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
991   GNUNET_CRYPTO_ecc_key_get_public_for_signature (priv, &pub);
992   h = derive_h (&pub, label, context);
993   mpi_scan (&x, priv->d, sizeof (priv->d));
994   d = gcry_mpi_new (256);
995   gcry_mpi_mulm (d, h, x, n);
996   gcry_mpi_release (h);
997   gcry_mpi_release (x);
998   gcry_mpi_release (n);
999   gcry_ctx_release (ctx);
1000   ret = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
1001   mpi_print (ret->d, sizeof (ret->d), d);
1002   gcry_mpi_release (d);
1003   return ret;
1004 }
1005
1006
1007 /**
1008  * Derive a public key from a given public key and a label.
1009  * Essentially calculates a public key 'V = H(l,P) * P'.
1010  *
1011  * @param pub original public key
1012  * @param label label to use for key deriviation
1013  * @param context additional context to use for HKDF of 'h';
1014  *        typically the name of the subsystem/application
1015  * @param result where to write the derived public key
1016  */
1017 void
1018 GNUNET_CRYPTO_ecc_public_key_derive (const struct GNUNET_CRYPTO_EccPublicSignKey *pub,
1019                                      const char *label,
1020                                      const char *context,
1021                                      struct GNUNET_CRYPTO_EccPublicSignKey *result)
1022 {
1023   gcry_ctx_t ctx;
1024   gcry_mpi_t h;
1025   gcry_mpi_t n;
1026   gcry_mpi_t h_mod_n;
1027   gcry_mpi_t q_y;
1028   gcry_mpi_point_t q;
1029   gcry_mpi_point_t v;
1030   int rc;
1031
1032   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1033   
1034   /* obtain point 'y' from original public key */
1035   mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y));
1036   if (0 != (rc = gcry_mpi_ec_set_mpi ("y", q_y, ctx)))
1037   {
1038     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_set_mpi", rc);
1039     GNUNET_assert (0);
1040   }
1041   gcry_mpi_release (q_y);
1042
1043   /* calulcate h_mod_n = h % n */
1044   h = derive_h (pub, label, context);
1045   n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1046   GNUNET_assert (NULL != n);
1047   h_mod_n = gcry_mpi_new (256);
1048   gcry_mpi_mod (h_mod_n, h, n);
1049   /* calculate v = h_mod_n * q */
1050   v = gcry_mpi_point_new (0);
1051   q = gcry_mpi_ec_get_point ("q", ctx, 0);
1052   GNUNET_assert (NULL != q);
1053   gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1054   gcry_mpi_release (h_mod_n);
1055   gcry_mpi_release (h);
1056   gcry_mpi_release (n);
1057   gcry_mpi_point_release (q);
1058   /* convert point 'v' to public key that we return */
1059   if (0 != (rc = gcry_mpi_ec_set_point ("q", v, ctx)))
1060     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_set_point", rc);
1061   gcry_mpi_point_release (v);
1062   if (NULL == (q_y = gcry_mpi_ec_get_mpi ("y", ctx, 0)))
1063   {
1064     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, 
1065               "gcry_mpi_ec_get_mpi", 0);
1066     GNUNET_assert (0);
1067   }
1068   mpi_print (result->q_y, sizeof (result->q_y), q_y);
1069   // gcry_mpi_release (q_y); /* needed? we set copy to 0... */
1070   gcry_ctx_release (ctx);
1071 }
1072
1073
1074 /* end of crypto_ecc.c */