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