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