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