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