- refactor kx sending, unify under send_kx
[oweals/gnunet.git] / src / util / crypto_ecc.c
1 /*
2      This file is part of GNUnet.
3      Copyright (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 0
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 #define CURVE "Ed25519"
39
40 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
41
42 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
43
44 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
45
46 /**
47  * Log an error message at log-level 'level' that indicates
48  * a failure of the command 'cmd' with the message given
49  * by gcry_strerror(rc).
50  */
51 #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)
52
53
54 /**
55  * Extract values from an S-expression.
56  *
57  * @param array where to store the result(s)
58  * @param sexp S-expression to parse
59  * @param topname top-level name in the S-expression that is of interest
60  * @param elems names of the elements to extract
61  * @return 0 on success
62  */
63 static int
64 key_from_sexp (gcry_mpi_t * array,
65                gcry_sexp_t sexp,
66                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  * Convert the given private key from the network format to the
118  * S-expression that can be used by libgcrypt.
119  *
120  * @param priv private key to decode
121  * @return NULL on error
122  */
123 static gcry_sexp_t
124 decode_private_ecdsa_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
125 {
126   gcry_sexp_t result;
127   int rc;
128
129   rc = gcry_sexp_build (&result, NULL,
130                         "(private-key(ecc(curve \"" CURVE "\")"
131                         "(d %b)))",
132                         (int)sizeof (priv->d), priv->d);
133   if (0 != rc)
134   {
135     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
136     GNUNET_assert (0);
137   }
138 #if EXTRA_CHECKS
139   if (0 != (rc = gcry_pk_testkey (result)))
140   {
141     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
142     GNUNET_assert (0);
143   }
144 #endif
145   return result;
146 }
147
148
149 /**
150  * Convert the given private key from the network format to the
151  * S-expression that can be used by libgcrypt.
152  *
153  * @param priv private key to decode
154  * @return NULL on error
155  */
156 static gcry_sexp_t
157 decode_private_eddsa_key (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
158 {
159   gcry_sexp_t result;
160   int rc;
161
162   rc = gcry_sexp_build (&result, NULL,
163                         "(private-key(ecc(curve \"" CURVE "\")"
164                         "(flags eddsa)(d %b)))",
165                         (int)sizeof (priv->d), priv->d);
166   if (0 != rc)
167   {
168     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
169     GNUNET_assert (0);
170   }
171 #if EXTRA_CHECKS
172   if (0 != (rc = gcry_pk_testkey (result)))
173   {
174     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
175     GNUNET_assert (0);
176   }
177 #endif
178   return result;
179 }
180
181
182 /**
183  * Convert the given private key from the network format to the
184  * S-expression that can be used by libgcrypt.
185  *
186  * @param priv private key to decode
187  * @return NULL on error
188  */
189 static gcry_sexp_t
190 decode_private_ecdhe_key (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv)
191 {
192   gcry_sexp_t result;
193   int rc;
194
195   rc = gcry_sexp_build (&result, NULL,
196                         "(private-key(ecc(curve \"" CURVE "\")"
197                         "(d %b)))",
198                         (int)sizeof (priv->d), priv->d);
199   if (0 != rc)
200   {
201     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
202     GNUNET_assert (0);
203   }
204 #if EXTRA_CHECKS
205   if (0 != (rc = gcry_pk_testkey (result)))
206   {
207     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
208     GNUNET_assert (0);
209   }
210 #endif
211   return result;
212 }
213
214
215 /**
216  * Extract the public key for the given private key.
217  *
218  * @param priv the private key
219  * @param pub where to write the public key
220  */
221 void
222 GNUNET_CRYPTO_ecdsa_key_get_public (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
223                                     struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
224 {
225   gcry_sexp_t sexp;
226   gcry_ctx_t ctx;
227   gcry_mpi_t q;
228
229   sexp = decode_private_ecdsa_key (priv);
230   GNUNET_assert (NULL != sexp);
231   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
232   gcry_sexp_release (sexp);
233   q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
234   GNUNET_assert (NULL != q);
235   GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
236   gcry_mpi_release (q);
237   gcry_ctx_release (ctx);
238 }
239
240
241 /**
242  * Extract the public key for the given private key.
243  *
244  * @param priv the private key
245  * @param pub where to write the public key
246  */
247 void
248 GNUNET_CRYPTO_eddsa_key_get_public (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
249                                     struct GNUNET_CRYPTO_EddsaPublicKey *pub)
250 {
251   gcry_sexp_t sexp;
252   gcry_ctx_t ctx;
253   gcry_mpi_t q;
254
255   sexp = decode_private_eddsa_key (priv);
256   GNUNET_assert (NULL != sexp);
257   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
258   gcry_sexp_release (sexp);
259   q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
260   GNUNET_assert (q);
261   GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
262   gcry_mpi_release (q);
263   gcry_ctx_release (ctx);
264 }
265
266
267 /**
268  * Extract the public key for the given private key.
269  *
270  * @param priv the private key
271  * @param pub where to write the public key
272  */
273 void
274 GNUNET_CRYPTO_ecdhe_key_get_public (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
275                                     struct GNUNET_CRYPTO_EcdhePublicKey *pub)
276 {
277   gcry_sexp_t sexp;
278   gcry_ctx_t ctx;
279   gcry_mpi_t q;
280
281   sexp = decode_private_ecdhe_key (priv);
282   GNUNET_assert (NULL != sexp);
283   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
284   gcry_sexp_release (sexp);
285   q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
286   GNUNET_assert (q);
287   GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
288   gcry_mpi_release (q);
289   gcry_ctx_release (ctx);
290 }
291
292
293 /**
294  * Convert a public key to a string.
295  *
296  * @param pub key to convert
297  * @return string representing @a pub
298  */
299 char *
300 GNUNET_CRYPTO_ecdsa_public_key_to_string (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
301 {
302   char *pubkeybuf;
303   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
304   char *end;
305
306   if (keylen % 5 > 0)
307     keylen += 5 - keylen % 5;
308   keylen /= 5;
309   pubkeybuf = GNUNET_malloc (keylen + 1);
310   end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
311                                        sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
312                                        pubkeybuf,
313                                        keylen);
314   if (NULL == end)
315   {
316     GNUNET_free (pubkeybuf);
317     return NULL;
318   }
319   *end = '\0';
320   return pubkeybuf;
321 }
322
323
324 /**
325  * Convert a public key to a string.
326  *
327  * @param pub key to convert
328  * @return string representing @a pub
329  */
330 char *
331 GNUNET_CRYPTO_eddsa_public_key_to_string (const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
332 {
333   char *pubkeybuf;
334   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
335   char *end;
336
337   if (keylen % 5 > 0)
338     keylen += 5 - keylen % 5;
339   keylen /= 5;
340   pubkeybuf = GNUNET_malloc (keylen + 1);
341   end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
342                                        sizeof (struct GNUNET_CRYPTO_EddsaPublicKey),
343                                        pubkeybuf,
344                                        keylen);
345   if (NULL == end)
346   {
347     GNUNET_free (pubkeybuf);
348     return NULL;
349   }
350   *end = '\0';
351   return pubkeybuf;
352 }
353
354
355 /**
356  * Convert a string representing a public key to a public key.
357  *
358  * @param enc encoded public key
359  * @param enclen number of bytes in @a enc (without 0-terminator)
360  * @param pub where to store the public key
361  * @return #GNUNET_OK on success
362  */
363 int
364 GNUNET_CRYPTO_ecdsa_public_key_from_string (const char *enc,
365                                             size_t enclen,
366                                             struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
367 {
368   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
369
370   if (keylen % 5 > 0)
371     keylen += 5 - keylen % 5;
372   keylen /= 5;
373   if (enclen != keylen)
374     return GNUNET_SYSERR;
375
376   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
377                                                   pub,
378                                                   sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
379     return GNUNET_SYSERR;
380   return GNUNET_OK;
381 }
382
383
384 /**
385  * Convert a string representing a public key to a public key.
386  *
387  * @param enc encoded public key
388  * @param enclen number of bytes in @a enc (without 0-terminator)
389  * @param pub where to store the public key
390  * @return #GNUNET_OK on success
391  */
392 int
393 GNUNET_CRYPTO_eddsa_public_key_from_string (const char *enc,
394                                             size_t enclen,
395                                             struct GNUNET_CRYPTO_EddsaPublicKey *pub)
396 {
397   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
398
399   if (keylen % 5 > 0)
400     keylen += 5 - keylen % 5;
401   keylen /= 5;
402   if (enclen != keylen)
403     return GNUNET_SYSERR;
404
405   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
406                                                   pub,
407                                                   sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
408     return GNUNET_SYSERR;
409   return GNUNET_OK;
410 }
411
412
413 /**
414  * Convert a string representing a private key to a private key.
415  *
416  * @param enc encoded public key
417  * @param enclen number of bytes in @a enc (without 0-terminator)
418  * @param priv where to store the private key
419  * @return #GNUNET_OK on success
420  */
421 int
422 GNUNET_CRYPTO_eddsa_private_key_from_string (const char *enc,
423                                              size_t enclen,
424                                              struct GNUNET_CRYPTO_EddsaPrivateKey *pub)
425 {
426   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
427
428   if (keylen % 5 > 0)
429     keylen += 5 - keylen % 5;
430   keylen /= 5;
431   if (enclen != keylen)
432     return GNUNET_SYSERR;
433
434   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
435                                                   pub,
436                                                   sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
437     return GNUNET_SYSERR;
438   return GNUNET_OK;
439 }
440
441
442 /**
443  * @ingroup crypto
444  * Clear memory that was used to store a private key.
445  *
446  * @param pk location of the key
447  */
448 void
449 GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
450 {
451   memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
452 }
453
454
455 /**
456  * @ingroup crypto
457  * Clear memory that was used to store a private key.
458  *
459  * @param pk location of the key
460  */
461 void
462 GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
463 {
464   memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
465 }
466
467
468 /**
469  * @ingroup crypto
470  * Clear memory that was used to store a private key.
471  *
472  * @param pk location of the key
473  */
474 void
475 GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
476 {
477   memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
478 }
479
480
481 /**
482  * Create a new private key. Caller must free return value.
483  *
484  * @return fresh private key
485  */
486 struct GNUNET_CRYPTO_EcdhePrivateKey *
487 GNUNET_CRYPTO_ecdhe_key_create ()
488 {
489   struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
490   gcry_sexp_t priv_sexp;
491   gcry_sexp_t s_keyparam;
492   gcry_mpi_t d;
493   int rc;
494
495   if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
496                                   "(genkey(ecc(curve \"" CURVE "\")"
497                                   "(flags)))")))
498   {
499     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
500     return NULL;
501   }
502   if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
503   {
504     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
505     gcry_sexp_release (s_keyparam);
506     return NULL;
507   }
508   gcry_sexp_release (s_keyparam);
509 #if EXTRA_CHECKS
510   if (0 != (rc = gcry_pk_testkey (priv_sexp)))
511   {
512     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
513     gcry_sexp_release (priv_sexp);
514     return NULL;
515   }
516 #endif
517   if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
518   {
519     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
520     gcry_sexp_release (priv_sexp);
521     return NULL;
522   }
523   gcry_sexp_release (priv_sexp);
524   priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey);
525   GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
526   gcry_mpi_release (d);
527   return priv;
528 }
529
530
531 /**
532  * Create a new private key. Caller must free return value.
533  *
534  * @return fresh private key
535  */
536 struct GNUNET_CRYPTO_EcdsaPrivateKey *
537 GNUNET_CRYPTO_ecdsa_key_create ()
538 {
539   struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
540   gcry_sexp_t priv_sexp;
541   gcry_sexp_t s_keyparam;
542   gcry_mpi_t d;
543   int rc;
544
545   if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
546                                   "(genkey(ecc(curve \"" CURVE "\")"
547                                   "(flags)))")))
548   {
549     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
550     return NULL;
551   }
552   if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
553   {
554     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
555     gcry_sexp_release (s_keyparam);
556     return NULL;
557   }
558   gcry_sexp_release (s_keyparam);
559 #if EXTRA_CHECKS
560   if (0 != (rc = gcry_pk_testkey (priv_sexp)))
561   {
562     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
563     gcry_sexp_release (priv_sexp);
564     return NULL;
565   }
566 #endif
567   if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
568   {
569     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
570     gcry_sexp_release (priv_sexp);
571     return NULL;
572   }
573   gcry_sexp_release (priv_sexp);
574   priv = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
575   GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
576   gcry_mpi_release (d);
577   return priv;
578 }
579
580 /**
581  * Create a new private key. Caller must free return value.
582  *
583  * @return fresh private key
584  */
585 struct GNUNET_CRYPTO_EddsaPrivateKey *
586 GNUNET_CRYPTO_eddsa_key_create ()
587 {
588   struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
589   gcry_sexp_t priv_sexp;
590   gcry_sexp_t s_keyparam;
591   gcry_mpi_t d;
592   int rc;
593
594   if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
595                                   "(genkey(ecc(curve \"" CURVE "\")"
596                                   "(flags eddsa)))")))
597   {
598     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
599     return NULL;
600   }
601   if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
602   {
603     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
604     gcry_sexp_release (s_keyparam);
605     return NULL;
606   }
607   gcry_sexp_release (s_keyparam);
608 #if EXTRA_CHECKS
609   if (0 != (rc = gcry_pk_testkey (priv_sexp)))
610   {
611     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
612     gcry_sexp_release (priv_sexp);
613     return NULL;
614   }
615 #endif
616   if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
617   {
618     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
619     gcry_sexp_release (priv_sexp);
620     return NULL;
621   }
622   gcry_sexp_release (priv_sexp);
623   priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
624   GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
625   gcry_mpi_release (d);
626   return priv;
627 }
628
629
630 /**
631  * Get the shared private key we use for anonymous users.
632  *
633  * @return "anonymous" private key
634  */
635 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
636 GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
637 {
638   /**
639    * 'anonymous' pseudonym (global static, d=1, public key = G
640    * (generator).
641    */
642   static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
643   static int once;
644
645   if (once)
646     return &anonymous;
647   GNUNET_CRYPTO_mpi_print_unsigned (anonymous.d,
648              sizeof (anonymous.d),
649              GCRYMPI_CONST_ONE);
650   once = 1;
651   return &anonymous;
652 }
653
654
655 /**
656  * Wait for a short time (we're trying to lock a file or want
657  * to give another process a shot at finishing a disk write, etc.).
658  * Sleeps for 100ms (as that should be long enough for virtually all
659  * modern systems to context switch and allow another process to do
660  * some 'real' work).
661  */
662 static void
663 short_wait ()
664 {
665   struct GNUNET_TIME_Relative timeout;
666
667   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
668   (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
669 }
670
671
672 /**
673  * Create a new private key by reading it from a file.  If the
674  * files does not exist, create a new key and write it to the
675  * file.  Caller must free return value.  Note that this function
676  * can not guarantee that another process might not be trying
677  * the same operation on the same file at the same time.
678  * If the contents of the file
679  * are invalid the old file is deleted and a fresh key is
680  * created.
681  *
682  * @param filename name of file to use to store the key
683  * @return new private key, NULL on error (for example,
684  *   permission denied)
685  */
686 struct GNUNET_CRYPTO_EddsaPrivateKey *
687 GNUNET_CRYPTO_eddsa_key_create_from_file (const char *filename)
688 {
689   struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
690   struct GNUNET_DISK_FileHandle *fd;
691   unsigned int cnt;
692   int ec;
693   uint64_t fs;
694
695   if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
696     return NULL;
697   while (GNUNET_YES != GNUNET_DISK_file_test (filename))
698   {
699     fd = GNUNET_DISK_file_open (filename,
700                                 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
701                                 | GNUNET_DISK_OPEN_FAILIFEXISTS,
702                                 GNUNET_DISK_PERM_USER_READ |
703                                 GNUNET_DISK_PERM_USER_WRITE);
704     if (NULL == fd)
705     {
706       if (EEXIST == errno)
707       {
708         if (GNUNET_YES != GNUNET_DISK_file_test (filename))
709         {
710           /* must exist but not be accessible, fail for good! */
711           if (0 != ACCESS (filename, R_OK))
712             LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
713           else
714             GNUNET_break (0);   /* what is going on!? */
715           return NULL;
716         }
717         continue;
718       }
719       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
720       return NULL;
721     }
722     cnt = 0;
723     while (GNUNET_YES !=
724            GNUNET_DISK_file_lock (fd, 0,
725                                   sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
726                                   GNUNET_YES))
727     {
728       short_wait ();
729       if (0 == ++cnt % 10)
730       {
731         ec = errno;
732         LOG (GNUNET_ERROR_TYPE_ERROR,
733              _("Could not acquire lock on file `%s': %s...\n"), filename,
734              STRERROR (ec));
735       }
736     }
737     LOG (GNUNET_ERROR_TYPE_INFO,
738          _("Creating a new private key.  This may take a while.\n"));
739     priv = GNUNET_CRYPTO_eddsa_key_create ();
740     GNUNET_assert (NULL != priv);
741     GNUNET_assert (sizeof (*priv) ==
742                    GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
743     GNUNET_DISK_file_sync (fd);
744     if (GNUNET_YES !=
745         GNUNET_DISK_file_unlock (fd, 0,
746                                  sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
747       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
748     GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
749     return priv;
750   }
751   /* key file exists already, read it! */
752   fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
753                               GNUNET_DISK_PERM_NONE);
754   if (NULL == fd)
755   {
756     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
757     return NULL;
758   }
759   cnt = 0;
760   while (1)
761   {
762     if (GNUNET_YES !=
763         GNUNET_DISK_file_lock (fd, 0,
764                                sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
765                                GNUNET_NO))
766     {
767       if (0 == ++cnt % 60)
768       {
769         ec = errno;
770         LOG (GNUNET_ERROR_TYPE_ERROR,
771              _("Could not acquire lock on file `%s': %s...\n"), filename,
772              STRERROR (ec));
773         LOG (GNUNET_ERROR_TYPE_ERROR,
774              _
775              ("This may be ok if someone is currently generating a private key.\n"));
776       }
777       short_wait ();
778       continue;
779     }
780     if (GNUNET_YES != GNUNET_DISK_file_test (filename))
781     {
782       /* eh, what!? File we opened is now gone!? */
783       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
784       if (GNUNET_YES !=
785           GNUNET_DISK_file_unlock (fd, 0,
786                                    sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
787         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
788       GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
789
790       return NULL;
791     }
792     if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
793       fs = 0;
794     if (fs < sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey))
795     {
796       /* maybe we got the read lock before the key generating
797        * process had a chance to get the write lock; give it up! */
798       if (GNUNET_YES !=
799           GNUNET_DISK_file_unlock (fd, 0,
800                                    sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
801         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
802       if (0 == ++cnt % 10)
803       {
804         LOG (GNUNET_ERROR_TYPE_ERROR,
805              _("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
806              filename, (unsigned int) fs,
807              (unsigned int) sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
808         LOG (GNUNET_ERROR_TYPE_ERROR,
809              _("This may be ok if someone is currently generating a key.\n"));
810       }
811       short_wait ();                /* wait a bit longer! */
812       continue;
813     }
814     break;
815   }
816   fs = sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey);
817   priv = GNUNET_malloc (fs);
818   GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
819   if (GNUNET_YES !=
820       GNUNET_DISK_file_unlock (fd, 0,
821                                sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
822     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
823   GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
824   return priv;
825 }
826
827
828 /**
829  * Create a new private key by reading it from a file.  If the
830  * files does not exist, create a new key and write it to the
831  * file.  Caller must free return value.  Note that this function
832  * can not guarantee that another process might not be trying
833  * the same operation on the same file at the same time.
834  * If the contents of the file
835  * are invalid the old file is deleted and a fresh key is
836  * created.
837  *
838  * @param filename name of file to use to store the key
839  * @return new private key, NULL on error (for example,
840  *   permission denied)
841  */
842 struct GNUNET_CRYPTO_EcdsaPrivateKey *
843 GNUNET_CRYPTO_ecdsa_key_create_from_file (const char *filename)
844 {
845   struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
846   struct GNUNET_DISK_FileHandle *fd;
847   unsigned int cnt;
848   int ec;
849   uint64_t fs;
850
851   if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
852     return NULL;
853   while (GNUNET_YES != GNUNET_DISK_file_test (filename))
854   {
855     fd = GNUNET_DISK_file_open (filename,
856                                 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
857                                 | GNUNET_DISK_OPEN_FAILIFEXISTS,
858                                 GNUNET_DISK_PERM_USER_READ |
859                                 GNUNET_DISK_PERM_USER_WRITE);
860     if (NULL == fd)
861     {
862       if (EEXIST == errno)
863       {
864         if (GNUNET_YES != GNUNET_DISK_file_test (filename))
865         {
866           /* must exist but not be accessible, fail for good! */
867           if (0 != ACCESS (filename, R_OK))
868             LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
869           else
870             GNUNET_break (0);   /* what is going on!? */
871           return NULL;
872         }
873         continue;
874       }
875       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
876       return NULL;
877     }
878     cnt = 0;
879     while (GNUNET_YES !=
880            GNUNET_DISK_file_lock (fd, 0,
881                                   sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
882                                   GNUNET_YES))
883     {
884       short_wait ();
885       if (0 == ++cnt % 10)
886       {
887         ec = errno;
888         LOG (GNUNET_ERROR_TYPE_ERROR,
889              _("Could not acquire lock on file `%s': %s...\n"), filename,
890              STRERROR (ec));
891       }
892     }
893     LOG (GNUNET_ERROR_TYPE_INFO,
894          _("Creating a new private key.  This may take a while.\n"));
895     priv = GNUNET_CRYPTO_ecdsa_key_create ();
896     GNUNET_assert (NULL != priv);
897     GNUNET_assert (sizeof (*priv) ==
898                    GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
899     GNUNET_DISK_file_sync (fd);
900     if (GNUNET_YES !=
901         GNUNET_DISK_file_unlock (fd, 0,
902                                  sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
903       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
904     GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
905     return priv;
906   }
907   /* key file exists already, read it! */
908   fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
909                               GNUNET_DISK_PERM_NONE);
910   if (NULL == fd)
911   {
912     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
913     return NULL;
914   }
915   cnt = 0;
916   while (1)
917   {
918     if (GNUNET_YES !=
919         GNUNET_DISK_file_lock (fd, 0,
920                                sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
921                                GNUNET_NO))
922     {
923       if (0 == ++cnt % 60)
924       {
925         ec = errno;
926         LOG (GNUNET_ERROR_TYPE_ERROR,
927              _("Could not acquire lock on file `%s': %s...\n"), filename,
928              STRERROR (ec));
929         LOG (GNUNET_ERROR_TYPE_ERROR,
930              _
931              ("This may be ok if someone is currently generating a private key.\n"));
932       }
933       short_wait ();
934       continue;
935     }
936     if (GNUNET_YES != GNUNET_DISK_file_test (filename))
937     {
938       /* eh, what!? File we opened is now gone!? */
939       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
940       if (GNUNET_YES !=
941           GNUNET_DISK_file_unlock (fd, 0,
942                                    sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
943         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
944       GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
945
946       return NULL;
947     }
948     if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
949       fs = 0;
950     if (fs < sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))
951     {
952       /* maybe we got the read lock before the key generating
953        * process had a chance to get the write lock; give it up! */
954       if (GNUNET_YES !=
955           GNUNET_DISK_file_unlock (fd, 0,
956                                    sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
957         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
958       if (0 == ++cnt % 10)
959       {
960         LOG (GNUNET_ERROR_TYPE_ERROR,
961              _("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
962              filename, (unsigned int) fs,
963              (unsigned int) sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
964         LOG (GNUNET_ERROR_TYPE_ERROR,
965              _("This may be ok if someone is currently generating a key.\n"));
966       }
967       short_wait ();                /* wait a bit longer! */
968       continue;
969     }
970     break;
971   }
972   fs = sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
973   priv = GNUNET_malloc (fs);
974   GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
975   if (GNUNET_YES !=
976       GNUNET_DISK_file_unlock (fd, 0,
977                                sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
978     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
979   GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
980   return priv;
981 }
982
983
984 /**
985  * Create a new private key by reading our peer's key from
986  * the file specified in the configuration.
987  *
988  * @param cfg the configuration to use
989  * @return new private key, NULL on error (for example,
990  *   permission denied)
991  */
992 struct GNUNET_CRYPTO_EddsaPrivateKey *
993 GNUNET_CRYPTO_eddsa_key_create_from_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
994 {
995   struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
996   char *fn;
997
998   if (GNUNET_OK !=
999       GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn))
1000     return NULL;
1001   priv = GNUNET_CRYPTO_eddsa_key_create_from_file (fn);
1002   GNUNET_free (fn);
1003   return priv;
1004 }
1005
1006
1007 /**
1008  * Setup a key file for a peer given the name of the
1009  * configuration file (!).  This function is used so that
1010  * at a later point code can be certain that reading a
1011  * key is fast (for example in time-dependent testcases).
1012  *
1013  * @param cfg_name name of the configuration file to use
1014  */
1015 void
1016 GNUNET_CRYPTO_eddsa_setup_key (const char *cfg_name)
1017 {
1018   struct GNUNET_CONFIGURATION_Handle *cfg;
1019   struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
1020
1021   cfg = GNUNET_CONFIGURATION_create ();
1022   (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
1023   priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
1024   if (NULL != priv)
1025     GNUNET_free (priv);
1026   GNUNET_CONFIGURATION_destroy (cfg);
1027 }
1028
1029
1030 /**
1031  * Retrieve the identity of the host's peer.
1032  *
1033  * @param cfg configuration to use
1034  * @param dst pointer to where to write the peer identity
1035  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the identity
1036  *         could not be retrieved
1037  */
1038 int
1039 GNUNET_CRYPTO_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
1040                                  struct GNUNET_PeerIdentity *dst)
1041 {
1042   struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
1043
1044   if (NULL == (priv = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg)))
1045   {
1046     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1047                 _("Could not load peer's private key\n"));
1048     return GNUNET_SYSERR;
1049   }
1050   GNUNET_CRYPTO_eddsa_key_get_public (priv, &dst->public_key);
1051   GNUNET_free (priv);
1052   return GNUNET_OK;
1053 }
1054
1055
1056 /**
1057  * Compare two Peer Identities.
1058  *
1059  * @param first first peer identity
1060  * @param second second peer identity
1061  * @return bigger than 0 if first > second,
1062  *         0 if they are the same
1063  *         smaller than 0 if second > first
1064  */
1065 int
1066 GNUNET_CRYPTO_cmp_peer_identity (const struct GNUNET_PeerIdentity *first,
1067                                  const struct GNUNET_PeerIdentity *second)
1068 {
1069   return memcmp (first, second, sizeof (struct GNUNET_PeerIdentity));
1070 }
1071
1072
1073 /**
1074  * Convert the data specified in the given purpose argument to an
1075  * S-expression suitable for signature operations.
1076  *
1077  * @param purpose data to convert
1078  * @return converted s-expression
1079  */
1080 static gcry_sexp_t
1081 data_to_eddsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
1082 {
1083   struct GNUNET_HashCode hc;
1084   gcry_sexp_t data;
1085   int rc;
1086
1087   GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
1088   if (0 != (rc = gcry_sexp_build (&data, NULL,
1089                                   "(data(flags eddsa)(hash-algo %s)(value %b))",
1090                                   "sha512",
1091                                   (int)sizeof (hc), &hc)))
1092   {
1093     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1094     return NULL;
1095   }
1096   return data;
1097 }
1098
1099
1100 /**
1101  * Convert the data specified in the given purpose argument to an
1102  * S-expression suitable for signature operations.
1103  *
1104  * @param purpose data to convert
1105  * @return converted s-expression
1106  */
1107 static gcry_sexp_t
1108 data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
1109 {
1110   struct GNUNET_HashCode hc;
1111   gcry_sexp_t data;
1112   int rc;
1113
1114   GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
1115   if (0 != (rc = gcry_sexp_build (&data, NULL,
1116                                   "(data(flags rfc6979)(hash %s %b))",
1117                                   "sha512",
1118                                   (int)sizeof (hc), &hc)))
1119   {
1120     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1121     return NULL;
1122   }
1123   return data;
1124 }
1125
1126
1127 /**
1128  * Sign a given block.
1129  *
1130  * @param priv private key to use for the signing
1131  * @param purpose what to sign (size, purpose)
1132  * @param sig where to write the signature
1133  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1134  */
1135 int
1136 GNUNET_CRYPTO_ecdsa_sign (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1137                           const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
1138                           struct GNUNET_CRYPTO_EcdsaSignature *sig)
1139 {
1140   gcry_sexp_t priv_sexp;
1141   gcry_sexp_t sig_sexp;
1142   gcry_sexp_t data;
1143   int rc;
1144   gcry_mpi_t rs[2];
1145
1146   priv_sexp = decode_private_ecdsa_key (priv);
1147   data = data_to_ecdsa_value (purpose);
1148   if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
1149   {
1150     LOG (GNUNET_ERROR_TYPE_WARNING,
1151          _("ECC signing failed at %s:%d: %s\n"), __FILE__,
1152          __LINE__, gcry_strerror (rc));
1153     gcry_sexp_release (data);
1154     gcry_sexp_release (priv_sexp);
1155     return GNUNET_SYSERR;
1156   }
1157   gcry_sexp_release (priv_sexp);
1158   gcry_sexp_release (data);
1159
1160   /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
1161      'signature' */
1162   if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
1163   {
1164     GNUNET_break (0);
1165     gcry_sexp_release (sig_sexp);
1166     return GNUNET_SYSERR;
1167   }
1168   gcry_sexp_release (sig_sexp);
1169   GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof (sig->r), rs[0]);
1170   GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof (sig->s), rs[1]);
1171   gcry_mpi_release (rs[0]);
1172   gcry_mpi_release (rs[1]);
1173   return GNUNET_OK;
1174 }
1175
1176
1177 /**
1178  * Sign a given block.
1179  *
1180  * @param priv private key to use for the signing
1181  * @param purpose what to sign (size, purpose)
1182  * @param sig where to write the signature
1183  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1184  */
1185 int
1186 GNUNET_CRYPTO_eddsa_sign (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
1187                           const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
1188                           struct GNUNET_CRYPTO_EddsaSignature *sig)
1189 {
1190   gcry_sexp_t priv_sexp;
1191   gcry_sexp_t sig_sexp;
1192   gcry_sexp_t data;
1193   int rc;
1194   gcry_mpi_t rs[2];
1195
1196   priv_sexp = decode_private_eddsa_key (priv);
1197   data = data_to_eddsa_value (purpose);
1198   if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
1199   {
1200     LOG (GNUNET_ERROR_TYPE_WARNING,
1201          _("EdDSA signing failed at %s:%d: %s\n"), __FILE__,
1202          __LINE__, gcry_strerror (rc));
1203     gcry_sexp_release (data);
1204     gcry_sexp_release (priv_sexp);
1205     return GNUNET_SYSERR;
1206   }
1207   gcry_sexp_release (priv_sexp);
1208   gcry_sexp_release (data);
1209
1210   /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
1211      'signature' */
1212   if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
1213   {
1214     GNUNET_break (0);
1215     gcry_sexp_release (sig_sexp);
1216     return GNUNET_SYSERR;
1217   }
1218   gcry_sexp_release (sig_sexp);
1219   GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof (sig->r), rs[0]);
1220   GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof (sig->s), rs[1]);
1221   gcry_mpi_release (rs[0]);
1222   gcry_mpi_release (rs[1]);
1223   return GNUNET_OK;
1224 }
1225
1226
1227 /**
1228  * Verify signature.
1229  *
1230  * @param purpose what is the purpose that the signature should have?
1231  * @param validate block to validate (size, purpose, data)
1232  * @param sig signature that is being validated
1233  * @param pub public key of the signer
1234  * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
1235  */
1236 int
1237 GNUNET_CRYPTO_ecdsa_verify (uint32_t purpose,
1238                             const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
1239                             const struct GNUNET_CRYPTO_EcdsaSignature *sig,
1240                             const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
1241 {
1242   gcry_sexp_t data;
1243   gcry_sexp_t sig_sexpr;
1244   gcry_sexp_t pub_sexpr;
1245   int rc;
1246
1247   if (purpose != ntohl (validate->purpose))
1248     return GNUNET_SYSERR;       /* purpose mismatch */
1249
1250   /* build s-expression for signature */
1251   if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
1252                                   "(sig-val(ecdsa(r %b)(s %b)))",
1253                                   (int)sizeof (sig->r), sig->r,
1254                                   (int)sizeof (sig->s), sig->s)))
1255   {
1256     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1257     return GNUNET_SYSERR;
1258   }
1259   data = data_to_ecdsa_value (validate);
1260   if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
1261                             "(public-key(ecc(curve " CURVE ")(q %b)))",
1262                                   (int)sizeof (pub->q_y), pub->q_y)))
1263   {
1264     gcry_sexp_release (data);
1265     gcry_sexp_release (sig_sexpr);
1266     return GNUNET_SYSERR;
1267   }
1268   rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
1269   gcry_sexp_release (pub_sexpr);
1270   gcry_sexp_release (data);
1271   gcry_sexp_release (sig_sexpr);
1272   if (0 != rc)
1273   {
1274     LOG (GNUNET_ERROR_TYPE_INFO,
1275          _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__,
1276          __LINE__, gcry_strerror (rc));
1277     return GNUNET_SYSERR;
1278   }
1279   return GNUNET_OK;
1280 }
1281
1282
1283
1284 /**
1285  * Verify signature.
1286  *
1287  * @param purpose what is the purpose that the signature should have?
1288  * @param validate block to validate (size, purpose, data)
1289  * @param sig signature that is being validated
1290  * @param pub public key of the signer
1291  * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
1292  */
1293 int
1294 GNUNET_CRYPTO_eddsa_verify (uint32_t purpose,
1295                             const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
1296                             const struct GNUNET_CRYPTO_EddsaSignature *sig,
1297                             const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
1298 {
1299   gcry_sexp_t data;
1300   gcry_sexp_t sig_sexpr;
1301   gcry_sexp_t pub_sexpr;
1302   int rc;
1303
1304   if (purpose != ntohl (validate->purpose))
1305     return GNUNET_SYSERR;       /* purpose mismatch */
1306
1307   /* build s-expression for signature */
1308   if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
1309                                   "(sig-val(eddsa(r %b)(s %b)))",
1310                                   (int)sizeof (sig->r), sig->r,
1311                                   (int)sizeof (sig->s), sig->s)))
1312   {
1313     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1314     return GNUNET_SYSERR;
1315   }
1316   data = data_to_eddsa_value (validate);
1317   if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
1318                                   "(public-key(ecc(curve " CURVE ")(flags eddsa)(q %b)))",
1319                                   (int)sizeof (pub->q_y), pub->q_y)))
1320   {
1321     gcry_sexp_release (data);
1322     gcry_sexp_release (sig_sexpr);
1323     return GNUNET_SYSERR;
1324   }
1325   rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
1326   gcry_sexp_release (pub_sexpr);
1327   gcry_sexp_release (data);
1328   gcry_sexp_release (sig_sexpr);
1329   if (0 != rc)
1330   {
1331     LOG (GNUNET_ERROR_TYPE_INFO,
1332          _("EdDSA signature verification failed at %s:%d: %s\n"), __FILE__,
1333          __LINE__, gcry_strerror (rc));
1334     return GNUNET_SYSERR;
1335   }
1336   return GNUNET_OK;
1337 }
1338
1339
1340 /**
1341  * Derive key material from a public and a private ECDHE key.
1342  *
1343  * @param priv private key to use for the ECDH (x)
1344  * @param pub public key to use for the ECDH (yG)
1345  * @param key_material where to write the key material (xyG)
1346  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1347  */
1348 int
1349 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1350                         const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1351                         struct GNUNET_HashCode *key_material)
1352 {
1353   gcry_mpi_point_t result;
1354   gcry_mpi_point_t q;
1355   gcry_mpi_t d;
1356   gcry_ctx_t ctx;
1357   gcry_sexp_t pub_sexpr;
1358   gcry_mpi_t result_x;
1359   unsigned char xbuf[256 / 8];
1360   size_t rsize;
1361
1362   /* first, extract the q = dP value from the public key */
1363   if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1364                             "(public-key(ecc(curve " CURVE ")(q %b)))",
1365                             (int)sizeof (pub->q_y), pub->q_y))
1366     return GNUNET_SYSERR;
1367   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1368   gcry_sexp_release (pub_sexpr);
1369   q = gcry_mpi_ec_get_point ("q", ctx, 0);
1370
1371   /* second, extract the d value from our private key */
1372   GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1373
1374   /* then call the 'multiply' function, to compute the product */
1375   result = gcry_mpi_point_new (0);
1376   gcry_mpi_ec_mul (result, d, q, ctx);
1377   gcry_mpi_point_release (q);
1378   gcry_mpi_release (d);
1379
1380   /* finally, convert point to string for hashing */
1381   result_x = gcry_mpi_new (256);
1382   if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1383   {
1384     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1385     gcry_mpi_point_release (result);
1386     gcry_ctx_release (ctx);
1387     return GNUNET_SYSERR;
1388   }
1389   gcry_mpi_point_release (result);
1390   gcry_ctx_release (ctx);
1391
1392   rsize = sizeof (xbuf);
1393   GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1394   /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1395      as that does not include the sign bit; x should be a 255-bit
1396      value, so with the sign it should fit snugly into the 256-bit
1397      xbuf */
1398   GNUNET_assert (0 ==
1399                  gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
1400                                  result_x));
1401   GNUNET_CRYPTO_hash (xbuf, rsize, key_material);
1402   gcry_mpi_release (result_x);
1403   return GNUNET_OK;
1404 }
1405
1406
1407 /**
1408  * Derive the 'h' value for key derivation, where
1409  * 'h = H(l,P)'.
1410  *
1411  * @param pub public key for deriviation
1412  * @param label label for deriviation
1413  * @param context additional context to use for HKDF of 'h';
1414  *        typically the name of the subsystem/application
1415  * @return h value
1416  */
1417 static gcry_mpi_t
1418 derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1419           const char *label,
1420           const char *context)
1421 {
1422   gcry_mpi_t h;
1423   struct GNUNET_HashCode hc;
1424
1425   GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
1426                      "key-derivation", strlen ("key-derivation"),
1427                      pub, sizeof (*pub),
1428                      label, strlen (label),
1429                      context, strlen (context),
1430                      NULL, 0);
1431   GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof (hc));
1432   return h;
1433 }
1434
1435
1436 /**
1437  * Derive a private key from a given private key and a label.
1438  * Essentially calculates a private key 'd = H(l,P) * x mod n'
1439  * where n is the size of the ECC group and P is the public
1440  * key associated with the private key 'd'.
1441  *
1442  * @param priv original private key
1443  * @param label label to use for key deriviation
1444  * @param context additional context to use for HKDF of 'h';
1445  *        typically the name of the subsystem/application
1446  * @return derived private key
1447  */
1448 struct GNUNET_CRYPTO_EcdsaPrivateKey *
1449 GNUNET_CRYPTO_ecdsa_private_key_derive (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1450                                         const char *label,
1451                                         const char *context)
1452 {
1453   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
1454   struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
1455   gcry_mpi_t h;
1456   gcry_mpi_t x;
1457   gcry_mpi_t d;
1458   gcry_mpi_t n;
1459   gcry_ctx_t ctx;
1460
1461   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1462
1463   n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1464   GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
1465
1466   h = derive_h (&pub, label, context);
1467   GNUNET_CRYPTO_mpi_scan_unsigned (&x, priv->d, sizeof (priv->d));
1468   d = gcry_mpi_new (256);
1469   gcry_mpi_mulm (d, h, x, n);
1470   gcry_mpi_release (h);
1471   gcry_mpi_release (x);
1472   gcry_mpi_release (n);
1473   gcry_ctx_release (ctx);
1474   ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
1475   GNUNET_CRYPTO_mpi_print_unsigned (ret->d, sizeof (ret->d), d);
1476   gcry_mpi_release (d);
1477   return ret;
1478 }
1479
1480
1481 /**
1482  * Derive a public key from a given public key and a label.
1483  * Essentially calculates a public key 'V = H(l,P) * P'.
1484  *
1485  * @param pub original public key
1486  * @param label label to use for key derivation
1487  * @param context additional context to use for HKDF of 'h';
1488  *        typically the name of the subsystem/application
1489  * @param result where to write the derived public key
1490  */
1491 void
1492 GNUNET_CRYPTO_ecdsa_public_key_derive (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1493                                        const char *label,
1494                                        const char *context,
1495                                        struct GNUNET_CRYPTO_EcdsaPublicKey *result)
1496 {
1497   gcry_ctx_t ctx;
1498   gcry_mpi_t q_y;
1499   gcry_mpi_t h;
1500   gcry_mpi_t n;
1501   gcry_mpi_t h_mod_n;
1502   gcry_mpi_point_t q;
1503   gcry_mpi_point_t v;
1504
1505   GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1506
1507   /* obtain point 'q' from original public key.  The provided 'q' is
1508      compressed thus we first store it in the context and then get it
1509      back as a (decompresssed) point.  */
1510   q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8*sizeof (pub->q_y));
1511   GNUNET_assert (NULL != q_y);
1512   GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
1513   gcry_mpi_release (q_y);
1514   q = gcry_mpi_ec_get_point ("q", ctx, 0);
1515   GNUNET_assert (q);
1516
1517   /* calculate h_mod_n = h % n */
1518   h = derive_h (pub, label, context);
1519   n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1520   h_mod_n = gcry_mpi_new (256);
1521   gcry_mpi_mod (h_mod_n, h, n);
1522   /* calculate v = h_mod_n * q */
1523   v = gcry_mpi_point_new (0);
1524   gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1525   gcry_mpi_release (h_mod_n);
1526   gcry_mpi_release (h);
1527   gcry_mpi_release (n);
1528   gcry_mpi_point_release (q);
1529
1530   /* convert point 'v' to public key that we return */
1531   GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
1532   gcry_mpi_point_release (v);
1533   q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
1534   GNUNET_assert (q_y);
1535   GNUNET_CRYPTO_mpi_print_unsigned (result->q_y,
1536                                     sizeof (result->q_y),
1537                                     q_y);
1538   gcry_mpi_release (q_y);
1539   gcry_ctx_release (ctx);
1540 }
1541
1542
1543 /**
1544  * @ingroup crypto
1545  * Convert ECDSA public key to ECDHE public key.
1546  * Please be very careful when using this function, as mixing
1547  * cryptographic primitives is not always healthy.
1548  *
1549  * @param ecdsa ecdsa public key
1550  * @param ecdhe[OUT] ecdhe public key
1551  */
1552 void
1553 GNUNET_CRYPTO_ecdsa_public_to_ecdhe (const struct GNUNET_CRYPTO_EcdsaPublicKey *ecdsa,
1554                                      struct GNUNET_CRYPTO_EcdhePublicKey *ecdhe)
1555 {
1556   GNUNET_assert (sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) ==
1557                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1558   memcpy (ecdhe,
1559           ecdsa,
1560           sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1561 }
1562
1563
1564
1565 /**
1566  * @ingroup crypto
1567  * Convert ECDSA private key to ECDHE private key.
1568  * Please be very careful when using this function, as mixing
1569  * cryptographic primitives is not always healthy.
1570  *
1571  * @param ecdsa ecdsa private key
1572  * @param ecdhe[OUT] ecdhe private key
1573  */
1574 void
1575 GNUNET_CRYPTO_ecdsa_private_to_ecdhe (const struct GNUNET_CRYPTO_EcdsaPrivateKey *ecdsa,
1576                                      struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe)
1577 {
1578   GNUNET_assert (sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey) ==
1579                  sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
1580   memcpy (ecdhe,
1581           ecdsa,
1582           sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1583
1584 }
1585
1586
1587 /* end of crypto_ecc.c */