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