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