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