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