af3fe33599def8e4628c7eef6b979159fb262f67
[oweals/gnunet.git] / src / util / crypto_ecc.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2012 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 2, 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  * This is just a first, completely untested, draft hack for future ECC support.
27  * TODO:
28  * - declare public API in gnunet_crypto_lib (move some structs, etc.)
29  * - implement gnunet-ecc binary
30  * - convert existing RSA testcases
31  * - adjust encoding length and other parameters
32  * - actually test it!
33  */
34 #include "platform.h"
35 #include <gcrypt.h>
36 #include "gnunet_common.h"
37 #include "gnunet_util_lib.h"
38
39 #define EXTRA_CHECKS ALLOW_EXTRA_CHECKS
40
41 #define CURVE "NIST P-521"
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  * The private information of an ECC private key.
59  */
60 struct GNUNET_CRYPTO_EccPrivateKey
61 {
62   
63   /**
64    * Libgcrypt S-expression for the ECC key.
65    */
66   gcry_sexp_t sexp;
67 };
68
69
70 /**
71  * If target != size, move target bytes to the
72  * end of the size-sized buffer and zero out the
73  * first target-size bytes.
74  *
75  * @param buf original buffer
76  * @param size number of bytes in the buffer
77  * @param target target size of the buffer
78  */
79 static void
80 adjust (unsigned char *buf, size_t size, size_t target)
81 {
82   if (size < target)
83   {
84     memmove (&buf[target - size], buf, size);
85     memset (buf, 0, target - size);
86   }
87 }
88
89
90 /**
91  * Free memory occupied by ECC key
92  *
93  * @param privatekey pointer to the memory to free
94  */
95 void
96 GNUNET_CRYPTO_ecc_key_free (struct GNUNET_CRYPTO_EccPrivateKey *privatekey)
97 {
98   gcry_sexp_release (privatekey->sexp);
99   GNUNET_free (privatekey);
100 }
101
102
103 /**
104  * Extract values from an S-expression.
105  *
106  * @param array where to store the result(s)
107  * @param sexp S-expression to parse
108  * @param topname top-level name in the S-expression that is of interest
109  * @param elems names of the elements to extract
110  * @return 0 on success
111  */
112 static int
113 key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
114                const char *elems)
115 {
116   gcry_sexp_t list;
117   gcry_sexp_t l2;
118   const char *s;
119   unsigned int i;
120   unsigned int idx;
121
122   list = gcry_sexp_find_token (sexp, topname, 0);
123   if (! list)  
124     return 1;  
125   l2 = gcry_sexp_cadr (list);
126   gcry_sexp_release (list);
127   list = l2;
128   if (! list)  
129     return 2;  
130
131   idx = 0;
132   for (s = elems; *s; s++, idx++)
133   {
134     l2 = gcry_sexp_find_token (list, s, 1);
135     if (! l2)
136     {
137       for (i = 0; i < idx; i++)
138       {
139         gcry_free (array[i]);
140         array[i] = NULL;
141       }
142       gcry_sexp_release (list);
143       return 3;                 /* required parameter not found */
144     }
145     array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
146     gcry_sexp_release (l2);
147     if (! array[idx])
148     {
149       for (i = 0; i < idx; i++)
150       {
151         gcry_free (array[i]);
152         array[i] = NULL;
153       }
154       gcry_sexp_release (list);
155       return 4;                 /* required parameter is invalid */
156     }
157   }
158   gcry_sexp_release (list);
159   return 0;
160 }
161
162
163 /**
164  * Extract the public key for the given private key.
165  *
166  * @param priv the private key
167  * @param pub where to write the public key
168  */
169 void
170 GNUNET_CRYPTO_ecc_key_get_public (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
171                                   struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub)
172 {
173   gcry_mpi_t skey;
174   size_t size;
175   int rc;
176
177   rc = key_from_sexp (&skey, priv->sexp, "public-key", "q");
178   if (rc)
179     rc = key_from_sexp (&skey, priv->sexp, "private-key", "q");
180   if (rc)
181     rc = key_from_sexp (&skey, priv->sexp, "ecc", "q");
182   GNUNET_assert (0 == rc);
183   pub->size = htons (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded));
184   size = GNUNET_CRYPTO_ECC_MAX_PUBLIC_KEY_LENGTH;
185   GNUNET_assert (0 ==
186                  gcry_mpi_print (GCRYMPI_FMT_USG, pub->key, size, &size,
187                                  skey));
188   pub->len = htons (size);
189   adjust (&pub->key[0], size, GNUNET_CRYPTO_ECC_MAX_PUBLIC_KEY_LENGTH);
190   gcry_mpi_release (skey);
191 }
192
193
194 /**
195  * Convert a public key to a string.
196  *
197  * @param pub key to convert
198  * @return string representing  'pub'
199  */
200 char *
201 GNUNET_CRYPTO_ecc_public_key_to_string (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub)
202 {
203   char *pubkeybuf;
204   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) * 8;
205   char *end;
206
207   if (keylen % 5 > 0)
208     keylen += 5 - keylen % 5;
209   keylen /= 5;
210   pubkeybuf = GNUNET_malloc (keylen + 1);
211   end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub, 
212                                        sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded), 
213                                        pubkeybuf, 
214                                        keylen);
215   if (NULL == end)
216   {
217     GNUNET_free (pubkeybuf);
218     return NULL;
219   }
220   *end = '\0';
221   return pubkeybuf;
222 }
223
224
225 /**
226  * Convert a string representing a public key to a public key.
227  *
228  * @param enc encoded public key
229  * @param enclen number of bytes in enc (without 0-terminator)
230  * @param pub where to store the public key
231  * @return GNUNET_OK on success
232  */
233 int
234 GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc, 
235                                           size_t enclen,
236                                           struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub)
237 {
238   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) * 8;
239
240   if (keylen % 5 > 0)
241     keylen += 5 - keylen % 5;
242   keylen /= 5;
243   if (enclen != keylen)
244     return GNUNET_SYSERR;
245
246   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
247                                                  (unsigned char*) pub,
248                                                  sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)))
249     return GNUNET_SYSERR;
250   if ( (ntohs (pub->size) != sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) ||
251        (ntohs (pub->len) > GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH) )
252     return GNUNET_SYSERR;
253   return GNUNET_OK;
254 }
255
256
257 /**
258  * Convert the given public key from the network format to the
259  * S-expression that can be used by libgcrypt.
260  *
261  * @param publicKey public key to decode
262  * @return NULL on error
263  */
264 static gcry_sexp_t
265 decode_public_key (const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *publicKey)
266 {
267   gcry_sexp_t result;
268   gcry_mpi_t q;
269   size_t size;
270   size_t erroff;
271   int rc;
272
273   if (ntohs (publicKey->len) > GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH) 
274   {
275     GNUNET_break (0);
276     return NULL;
277   }
278   size = ntohs (publicKey->size);
279   if (0 != (rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG, publicKey->key, size, &size)))
280   {
281     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
282     return NULL;
283   }
284   rc = gcry_sexp_build (&result, &erroff, "(public-key(ecc((curve \"" CURVE "\")(q %m)))", q);
285   gcry_mpi_release (q);
286   if (0 != rc)
287   {
288     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);  /* erroff gives more info */
289     return NULL;
290   }
291   return result;
292 }
293
294
295 /**
296  * Encode the private key in a format suitable for
297  * storing it into a file.
298  *
299  * @param key key to encode
300  * @return encoding of the private key.
301  *    The first 4 bytes give the size of the array, as usual.
302  */
303 struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *
304 GNUNET_CRYPTO_ecc_encode_key (const struct GNUNET_CRYPTO_EccPrivateKey *key)
305 {
306   struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *retval;
307   char buf[65536];
308   uint16_t be;
309   size_t size;
310
311 #if EXTRA_CHECKS
312   if (gcry_pk_testkey (hostkey->sexp))
313   {
314     GNUNET_break (0);
315     return NULL;
316   }
317 #endif
318   size = gcry_sexp_sprint (key->sexp, 
319                            GCRYSEXP_FMT_DEFAULT,
320                            &buf[2], sizeof (buf) - sizeof (uint16_t));
321   if (0 == size)
322   {
323     GNUNET_break (0);
324     return NULL;
325   }
326   GNUNET_assert (size < 65536 - sizeof (uint16_t));
327   be = htons ((uint16_t) size);
328   memcpy (buf, &be, sizeof (be));
329   size += sizeof (be);
330   retval = GNUNET_malloc (size);
331   memcpy (retval, buf, size);
332   return retval;
333 }
334
335
336 /**
337  * Decode the private key from the file-format back
338  * to the "normal", internal format.
339  *
340  * @param buf the buffer where the private key data is stored
341  * @param len the length of the data in 'buffer'
342  * @return NULL on error
343  */
344 struct GNUNET_CRYPTO_EccPrivateKey *
345 GNUNET_CRYPTO_ecc_decode_key (const char *buf, 
346                               size_t len)
347 {
348   struct GNUNET_CRYPTO_EccPrivateKey *ret;
349   uint16_t be;
350   gcry_sexp_t sexp;
351   int rc;
352   size_t erroff;
353
354   if (len < sizeof (uint16_t)) 
355     return NULL;
356   memcpy (&be, buf, sizeof (be));
357   if (len != ntohs (be))
358     return NULL;
359   if (0 != (rc = gcry_sexp_sscan (&sexp,
360                                   &erroff,
361                                   &buf[2],
362                                   len - sizeof (uint16_t))))
363   {
364     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_scan", rc);
365     return NULL;
366   }
367   if (0 != (rc = gcry_pk_testkey (sexp)))
368   {
369     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
370     return NULL;
371   }
372   ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
373   ret->sexp = sexp;
374   return ret;
375 }
376
377
378 /**
379  * Create a new private key. Caller must free return value.
380  *
381  * @return fresh private key
382  */
383 static struct GNUNET_CRYPTO_EccPrivateKey *
384 ecc_key_create ()
385 {
386   struct GNUNET_CRYPTO_EccPrivateKey *ret;
387   gcry_sexp_t s_key;
388   gcry_sexp_t s_keyparam;
389
390   GNUNET_assert (0 ==
391                  gcry_sexp_build (&s_keyparam, NULL,
392                                   "(genkey(ecc(curve \"" CURVE "\")))"));
393   GNUNET_assert (0 == gcry_pk_genkey (&s_key, s_keyparam));
394   gcry_sexp_release (s_keyparam);
395 #if EXTRA_CHECKS
396   GNUNET_assert (0 == gcry_pk_testkey (s_key));
397 #endif
398   ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
399   ret->sexp = s_key;
400   return ret;
401 }
402
403
404 /**
405  * Try to read the private key from the given file.
406  *
407  * @param filename file to read the key from
408  * @return NULL on error
409  */
410 static struct GNUNET_CRYPTO_EccPrivateKey *
411 try_read_key (const char *filename)
412 {
413   struct GNUNET_CRYPTO_EccPrivateKey *ret;
414   struct GNUNET_DISK_FileHandle *fd;
415   OFF_T fs;
416
417   if (GNUNET_YES != GNUNET_DISK_file_test (filename))
418     return NULL;
419
420   /* hostkey file exists already, read it! */
421   if (NULL == (fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
422                                            GNUNET_DISK_PERM_NONE)))
423   {
424     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
425     return NULL;
426   }
427   if (GNUNET_OK != (GNUNET_DISK_file_handle_size (fd, &fs)))
428   {
429     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "stat", filename);
430     (void) GNUNET_DISK_file_close (fd);
431     return NULL;
432   }
433   if (0 == fs)
434   {
435     GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
436     return NULL;
437   }
438   if (fs > UINT16_MAX)
439   {
440     LOG (GNUNET_ERROR_TYPE_ERROR,
441          _("File `%s' does not contain a valid private key (too long, %llu bytes).  Deleting it.\n"),   
442          filename,
443          (unsigned long long) fs);
444     GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
445     if (0 != UNLINK (filename))    
446       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
447     return NULL;
448   }
449   {
450     char enc[fs];
451
452     GNUNET_break (fs == GNUNET_DISK_file_read (fd, enc, fs));
453     if (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, fs)))
454     {
455       LOG (GNUNET_ERROR_TYPE_ERROR,
456            _("File `%s' does not contain a valid private key (failed decode, %llu bytes).  Deleting it.\n"),
457            filename,
458            (unsigned long long) fs);
459       GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
460       if (0 != UNLINK (filename))    
461         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
462       return NULL;
463     }
464   }
465   GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
466   return ret;  
467 }
468
469
470 /**
471  * Wait for a short time (we're trying to lock a file or want
472  * to give another process a shot at finishing a disk write, etc.).
473  * Sleeps for 100ms (as that should be long enough for virtually all
474  * modern systems to context switch and allow another process to do
475  * some 'real' work).
476  */
477 static void
478 short_wait ()
479 {
480   struct GNUNET_TIME_Relative timeout;
481
482   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
483   (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
484 }
485
486
487 /**
488  * Create a new private key by reading it from a file.  If the
489  * files does not exist, create a new key and write it to the
490  * file.  Caller must free return value.  Note that this function
491  * can not guarantee that another process might not be trying
492  * the same operation on the same file at the same time.
493  * If the contents of the file
494  * are invalid the old file is deleted and a fresh key is
495  * created.
496  *
497  * @return new private key, NULL on error (for example,
498  *   permission denied)
499  */
500 struct GNUNET_CRYPTO_EccPrivateKey *
501 GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
502 {
503   struct GNUNET_CRYPTO_EccPrivateKey *ret;
504   struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
505   uint16_t len;
506   struct GNUNET_DISK_FileHandle *fd;
507   unsigned int cnt;
508   int ec;
509   uint64_t fs;
510   struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pub;
511   struct GNUNET_PeerIdentity pid;
512
513   if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
514     return NULL;
515   while (GNUNET_YES != GNUNET_DISK_file_test (filename))
516   {
517     fd = GNUNET_DISK_file_open (filename,
518                                 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
519                                 | GNUNET_DISK_OPEN_FAILIFEXISTS,
520                                 GNUNET_DISK_PERM_USER_READ |
521                                 GNUNET_DISK_PERM_USER_WRITE);
522     if (NULL == fd)
523     {
524       if (errno == EEXIST)
525       {
526         if (GNUNET_YES != GNUNET_DISK_file_test (filename))
527         {
528           /* must exist but not be accessible, fail for good! */
529           if (0 != ACCESS (filename, R_OK))
530             LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
531           else
532             GNUNET_break (0);   /* what is going on!? */
533           return NULL;
534         }
535         continue;
536       }
537       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
538       return NULL;
539     }
540     cnt = 0;
541
542     while (GNUNET_YES !=
543            GNUNET_DISK_file_lock (fd, 0,
544                                   sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded),
545                                   GNUNET_YES))
546     {
547       short_wait ();
548       if (0 == ++cnt % 10)
549       {
550         ec = errno;
551         LOG (GNUNET_ERROR_TYPE_ERROR,
552              _("Could not acquire lock on file `%s': %s...\n"), filename,
553              STRERROR (ec));
554       }
555     }
556     LOG (GNUNET_ERROR_TYPE_INFO,
557          _("Creating a new private key.  This may take a while.\n"));
558     ret = ecc_key_create ();
559     GNUNET_assert (ret != NULL);
560     enc = GNUNET_CRYPTO_ecc_encode_key (ret);
561     GNUNET_assert (enc != NULL);
562     GNUNET_assert (ntohs (enc->size) ==
563                    GNUNET_DISK_file_write (fd, enc, ntohs (enc->size)));
564     GNUNET_free (enc);
565
566     GNUNET_DISK_file_sync (fd);
567     if (GNUNET_YES !=
568         GNUNET_DISK_file_unlock (fd, 0,
569                                  sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
570       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
571     GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
572     GNUNET_CRYPTO_ecc_key_get_public (ret, &pub);
573     GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey);
574     LOG (GNUNET_ERROR_TYPE_INFO,
575          _("I am host `%s'.  Stored new private key in `%s'.\n"),
576          GNUNET_i2s (&pid), filename);
577     return ret;
578   }
579   /* hostkey file exists already, read it! */
580   fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
581                               GNUNET_DISK_PERM_NONE);
582   if (NULL == fd)
583   {
584     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
585     return NULL;
586   }
587   cnt = 0;
588   while (1)
589   {
590     if (GNUNET_YES !=
591         GNUNET_DISK_file_lock (fd, 0,
592                                sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded),
593                                GNUNET_NO))
594     {
595       if (0 == ++cnt % 60)
596       {
597         ec = errno;
598         LOG (GNUNET_ERROR_TYPE_ERROR,
599              _("Could not acquire lock on file `%s': %s...\n"), filename,
600              STRERROR (ec));
601         LOG (GNUNET_ERROR_TYPE_ERROR,
602              _
603              ("This may be ok if someone is currently generating a hostkey.\n"));
604       }
605       short_wait ();
606       continue;
607     }
608     if (GNUNET_YES != GNUNET_DISK_file_test (filename))
609     {
610       /* eh, what!? File we opened is now gone!? */
611       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
612       if (GNUNET_YES !=
613           GNUNET_DISK_file_unlock (fd, 0,
614                                    sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
615         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
616       GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
617
618       return NULL;
619     }
620     if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
621       fs = 0;
622     if (fs < sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded))
623     {
624       /* maybe we got the read lock before the hostkey generating
625        * process had a chance to get the write lock; give it up! */
626       if (GNUNET_YES !=
627           GNUNET_DISK_file_unlock (fd, 0,
628                                    sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
629         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
630       if (0 == ++cnt % 10)
631       {
632         LOG (GNUNET_ERROR_TYPE_ERROR,
633              _
634              ("When trying to read hostkey file `%s' I found %u bytes but I need at least %u.\n"),
635              filename, (unsigned int) fs,
636              (unsigned int) sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded));
637         LOG (GNUNET_ERROR_TYPE_ERROR,
638              _
639              ("This may be ok if someone is currently generating a hostkey.\n"));
640       }
641       short_wait ();                /* wait a bit longer! */
642       continue;
643     }
644     break;
645   }
646   enc = GNUNET_malloc (fs);
647   GNUNET_assert (fs == GNUNET_DISK_file_read (fd, enc, fs));
648   len = ntohs (enc->size);
649   ret = NULL;
650   if ((len != fs) ||
651       (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, len))))
652   {
653     LOG (GNUNET_ERROR_TYPE_ERROR,
654          _("File `%s' does not contain a valid private key.  Deleting it.\n"),
655          filename);
656     if (0 != UNLINK (filename))
657     {
658       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
659     }
660   }
661   GNUNET_free (enc);
662   if (GNUNET_YES !=
663       GNUNET_DISK_file_unlock (fd, 0,
664                                sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
665     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
666   GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
667   if (ret != NULL)
668   {
669     GNUNET_CRYPTO_ecc_key_get_public (ret, &pub);
670     GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey);
671     LOG (GNUNET_ERROR_TYPE_INFO,
672          _("I am host `%s'.  Read private key from `%s'.\n"), GNUNET_i2s (&pid),
673          filename);
674   }
675   return ret;
676 }
677
678
679 /**
680  * Handle to cancel private key generation and state for the
681  * key generation operation.
682  */
683 struct GNUNET_CRYPTO_EccKeyGenerationContext
684 {
685   
686   /**
687    * Continuation to call upon completion.
688    */
689   GNUNET_CRYPTO_EccKeyCallback cont;
690
691   /**
692    * Closure for 'cont'.
693    */
694   void *cont_cls;
695
696   /**
697    * Name of the file.
698    */
699   char *filename;
700
701   /**
702    * Handle to the helper process which does the key generation.
703    */ 
704   struct GNUNET_OS_Process *gnunet_ecc;
705   
706   /**
707    * Handle to 'stdout' of gnunet-ecc.  We 'read' on stdout to detect
708    * process termination (instead of messing with SIGCHLD).
709    */
710   struct GNUNET_DISK_PipeHandle *gnunet_ecc_out;
711
712   /**
713    * Location where we store the private key if it already existed.
714    * (if this is used, 'filename', 'gnunet_ecc' and 'gnunet_ecc_out' will
715    * not be used).
716    */
717   struct GNUNET_CRYPTO_EccPrivateKey *pk;
718   
719   /**
720    * Task reading from 'gnunet_ecc_out' to wait for process termination.
721    */
722   GNUNET_SCHEDULER_TaskIdentifier read_task;
723   
724 };
725
726
727 /**
728  * Abort ECC key generation.
729  *
730  * @param gc key generation context to abort
731  */
732 void
733 GNUNET_CRYPTO_ecc_key_create_stop (struct GNUNET_CRYPTO_EccKeyGenerationContext *gc)
734 {
735   if (GNUNET_SCHEDULER_NO_TASK != gc->read_task)
736   {
737     GNUNET_SCHEDULER_cancel (gc->read_task);
738     gc->read_task = GNUNET_SCHEDULER_NO_TASK;
739   }
740   if (NULL != gc->gnunet_ecc)
741   {
742     (void) GNUNET_OS_process_kill (gc->gnunet_ecc, SIGKILL);
743     GNUNET_break (GNUNET_OK ==
744                   GNUNET_OS_process_wait (gc->gnunet_ecc));
745     GNUNET_OS_process_destroy (gc->gnunet_ecc);
746     GNUNET_DISK_pipe_close (gc->gnunet_ecc_out);
747   }
748
749   if (NULL != gc->filename)
750   {
751     if (0 != UNLINK (gc->filename))
752       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", gc->filename);
753     GNUNET_free (gc->filename);
754   }
755   if (NULL != gc->pk)
756     GNUNET_CRYPTO_ecc_key_free (gc->pk);
757   GNUNET_free (gc);
758 }
759
760
761 /**
762  * Task called upon shutdown or process termination of 'gnunet-ecc' during
763  * ECC key generation.  Check where we are and perform the appropriate
764  * action.
765  *
766  * @param cls the 'struct GNUNET_CRYPTO_EccKeyGenerationContext'
767  * @param tc scheduler context
768  */
769 static void
770 check_key_generation_completion (void *cls,
771                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
772 {
773   struct GNUNET_CRYPTO_EccKeyGenerationContext *gc = cls;
774   struct GNUNET_CRYPTO_EccPrivateKey *pk;
775
776   gc->read_task = GNUNET_SCHEDULER_NO_TASK;
777   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
778   {
779     gc->cont (gc->cont_cls, NULL, _("interrupted by shutdown"));
780     GNUNET_CRYPTO_ecc_key_create_stop (gc);
781     return;
782   }
783   GNUNET_assert (GNUNET_OK == 
784                  GNUNET_OS_process_wait (gc->gnunet_ecc));
785   GNUNET_OS_process_destroy (gc->gnunet_ecc);
786   gc->gnunet_ecc = NULL;
787   if (NULL == (pk = try_read_key (gc->filename)))
788   {
789     GNUNET_break (0);
790     gc->cont (gc->cont_cls, NULL, _("gnunet-ecc failed"));
791     GNUNET_CRYPTO_ecc_key_create_stop (gc);
792     return;
793   }
794   gc->cont (gc->cont_cls, pk, NULL);
795   GNUNET_DISK_pipe_close (gc->gnunet_ecc_out);
796   GNUNET_free (gc->filename);
797   GNUNET_free (gc);
798 }
799
800
801 /**
802  * Return the private ECC key which already existed on disk
803  * (asynchronously) to the caller.
804  *
805  * @param cls the 'struct GNUNET_CRYPTO_EccKeyGenerationContext'
806  * @param tc scheduler context (unused)
807  */
808 static void
809 async_return_key (void *cls,
810                   const struct GNUNET_SCHEDULER_TaskContext *tc)
811 {
812   struct GNUNET_CRYPTO_EccKeyGenerationContext *gc = cls;
813
814   gc->cont (gc->cont_cls,
815             gc->pk,
816             NULL);
817   GNUNET_free (gc);
818 }
819
820
821 /**
822  * Create a new private key by reading it from a file.  If the files
823  * does not exist, create a new key and write it to the file.  If the
824  * contents of the file are invalid the old file is deleted and a
825  * fresh key is created.
826  *
827  * @param filename name of file to use for storage
828  * @param cont function to call when done (or on errors)
829  * @param cont_cls closure for 'cont'
830  * @return handle to abort operation, NULL on fatal errors (cont will not be called if NULL is returned)
831  */
832 struct GNUNET_CRYPTO_EccKeyGenerationContext *
833 GNUNET_CRYPTO_ecc_key_create_start (const char *filename,
834                                     GNUNET_CRYPTO_EccKeyCallback cont,
835                                     void *cont_cls)
836 {
837   struct GNUNET_CRYPTO_EccKeyGenerationContext *gc;
838   struct GNUNET_CRYPTO_EccPrivateKey *pk;
839   const char *weak_random;
840
841   if (NULL != (pk = try_read_key (filename)))
842   {
843     /* quick happy ending: key already exists! */
844     gc = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccKeyGenerationContext));
845     gc->pk = pk;
846     gc->cont = cont;
847     gc->cont_cls = cont_cls;
848     gc->read_task = GNUNET_SCHEDULER_add_now (&async_return_key,
849                                               gc);
850     return gc;
851   }
852   gc = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccKeyGenerationContext));
853   gc->filename = GNUNET_strdup (filename);
854   gc->cont = cont;
855   gc->cont_cls = cont_cls;
856   gc->gnunet_ecc_out = GNUNET_DISK_pipe (GNUNET_NO,
857                                          GNUNET_NO,
858                                          GNUNET_NO,
859                                          GNUNET_YES);
860   if (NULL == gc->gnunet_ecc_out)
861   {
862     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "pipe");
863     GNUNET_free (gc->filename);
864     GNUNET_free (gc);
865     return NULL;
866   }
867   weak_random = NULL;
868   if (GNUNET_YES ==
869       GNUNET_CRYPTO_random_is_weak ())
870     weak_random = "-w";
871   gc->gnunet_ecc = GNUNET_OS_start_process (GNUNET_NO,
872                                             GNUNET_OS_INHERIT_STD_ERR,
873                                             NULL, 
874                                             gc->gnunet_ecc_out,
875                                             "gnunet-ecc",
876                                             "gnunet-ecc",                                           
877                                             gc->filename,
878                                             weak_random,
879                                             NULL);
880   if (NULL == gc->gnunet_ecc)
881   {
882     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fork");
883     GNUNET_DISK_pipe_close (gc->gnunet_ecc_out);
884     GNUNET_free (gc->filename);
885     GNUNET_free (gc);
886     return NULL;
887   }
888   GNUNET_assert (GNUNET_OK ==
889                  GNUNET_DISK_pipe_close_end (gc->gnunet_ecc_out,
890                                              GNUNET_DISK_PIPE_END_WRITE));
891   gc->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
892                                                   GNUNET_DISK_pipe_handle (gc->gnunet_ecc_out,
893                                                                            GNUNET_DISK_PIPE_END_READ),
894                                                   &check_key_generation_completion,
895                                                   gc);
896   return gc;
897 }
898
899
900 /**
901  * Setup a hostkey file for a peer given the name of the
902  * configuration file (!).  This function is used so that
903  * at a later point code can be certain that reading a
904  * hostkey is fast (for example in time-dependent testcases).
905  *
906  * @param cfg_name name of the configuration file to use
907  */
908 void
909 GNUNET_CRYPTO_ecc_setup_hostkey (const char *cfg_name)
910 {
911   struct GNUNET_CONFIGURATION_Handle *cfg;
912   struct GNUNET_CRYPTO_EccPrivateKey *pk;
913   char *fn;
914
915   cfg = GNUNET_CONFIGURATION_create ();
916   (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
917   if (GNUNET_OK == 
918       GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn))
919   {
920     pk = GNUNET_CRYPTO_ecc_key_create_from_file (fn);
921     if (NULL != pk)
922       GNUNET_CRYPTO_ecc_key_free (pk);
923     GNUNET_free (fn);
924   }
925   GNUNET_CONFIGURATION_destroy (cfg);
926 }
927
928
929 /**
930  * Encrypt a block with the public key of another host that uses the
931  * same cipher.
932  *
933  * @param block the block to encrypt
934  * @param size the size of block
935  * @param publicKey the encoded public key used to encrypt
936  * @param target where to store the encrypted block
937  * @returns GNUNET_SYSERR on error, GNUNET_OK if ok
938  */
939 int
940 GNUNET_CRYPTO_ecc_encrypt (const void *block, size_t size,
941                            const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded
942                            *publicKey,
943                            struct GNUNET_CRYPTO_EccEncryptedData *target)
944 {
945   gcry_sexp_t result;
946   gcry_sexp_t data;
947   gcry_sexp_t psexp;
948   gcry_mpi_t val;
949   size_t isize;
950   size_t erroff;
951
952   GNUNET_assert (size <= sizeof (struct GNUNET_HashCode));
953   if (! (psexp = decode_public_key (publicKey)))
954     return GNUNET_SYSERR;
955   isize = size;
956   GNUNET_assert (0 ==
957                  gcry_mpi_scan (&val, GCRYMPI_FMT_USG, block, isize, &isize));
958   GNUNET_assert (0 ==
959                  gcry_sexp_build (&data, &erroff,
960                                   "(data (flags pkcs1)(value %m))", val));
961   gcry_mpi_release (val);
962   GNUNET_assert (0 == gcry_pk_encrypt (&result, data, psexp));
963   gcry_sexp_release (data);
964   gcry_sexp_release (psexp);
965   isize = gcry_sexp_sprint (result, 
966                             GCRYSEXP_FMT_DEFAULT,
967                             target->encoding,
968                             GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH);
969   if (0 == isize)
970   {
971     GNUNET_break (0);
972     return GNUNET_SYSERR;
973   }
974   target->size = htons ((uint16_t) isize);
975   /* padd with zeros */
976   memset (&target->encoding[isize], 0, GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH - isize);
977   return GNUNET_OK;
978 }
979
980
981 /**
982  * Decrypt a given block with the hostkey.
983  *
984  * @param key the key with which to decrypt this block
985  * @param block the data to decrypt, encoded as returned by encrypt
986  * @param result pointer to a location where the result can be stored
987  * @param max the maximum number of bits to store for the result, if
988  *        the decrypted block is bigger, an error is returned
989  * @return the size of the decrypted block, -1 on error
990  */
991 ssize_t
992 GNUNET_CRYPTO_ecc_decrypt (const struct GNUNET_CRYPTO_EccPrivateKey *key,
993                            const struct GNUNET_CRYPTO_EccEncryptedData *block,
994                            void *result, size_t max)
995 {
996   gcry_sexp_t resultsexp;
997   gcry_sexp_t data;
998   size_t erroff;
999   size_t size;
1000   gcry_mpi_t val;
1001   unsigned char *endp;
1002
1003 #if EXTRA_CHECKS
1004   GNUNET_assert (0 == gcry_pk_testkey (key->sexp));
1005 #endif
1006   size = ntohs (block->size);
1007   GNUNET_assert (0 ==
1008                  gcry_sexp_sscan (&data,
1009                                   &erroff,
1010                                   block->encoding, size));
1011   GNUNET_assert (0 == gcry_pk_decrypt (&resultsexp, data, key->sexp));
1012   gcry_sexp_release (data);
1013   /* resultsexp has format "(value %m)" */
1014   GNUNET_assert (NULL !=
1015                  (val = gcry_sexp_nth_mpi (resultsexp, 1, GCRYMPI_FMT_USG)));
1016   gcry_sexp_release (resultsexp);
1017   size = max + GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH * 2;
1018   {
1019     unsigned char tmp[size];
1020
1021     GNUNET_assert (0 == gcry_mpi_print (GCRYMPI_FMT_USG, tmp, size, &size, val));
1022     gcry_mpi_release (val);
1023     endp = tmp;
1024     endp += (size - max);
1025     size = max;
1026     memcpy (result, endp, size);
1027   }
1028   return size;
1029 }
1030
1031
1032 /**
1033  * Convert the data specified in the given purpose argument to an
1034  * S-expression suitable for signature operations.
1035  *
1036  * @param purpose data to convert
1037  * @return converted s-expression
1038  */
1039 static gcry_sexp_t
1040 data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
1041 {
1042   struct GNUNET_HashCode hc;
1043   size_t bufSize;
1044   gcry_sexp_t data;
1045
1046   GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
1047 #define FORMATSTRING "(4:data(5:flags5:pkcs1)(4:hash6:sha51264:0123456789012345678901234567890123456789012345678901234567890123))"
1048   bufSize = strlen (FORMATSTRING) + 1;
1049   {
1050     char buff[bufSize];
1051
1052     memcpy (buff, FORMATSTRING, bufSize);
1053     memcpy (&buff
1054             [bufSize -
1055              strlen
1056              ("0123456789012345678901234567890123456789012345678901234567890123))")
1057              - 1], &hc, sizeof (struct GNUNET_HashCode));
1058     GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0));
1059   }
1060 #undef FORMATSTRING
1061   return data;
1062 }
1063
1064
1065 /**
1066  * Sign a given block.
1067  *
1068  * @param key private key to use for the signing
1069  * @param purpose what to sign (size, purpose)
1070  * @param sig where to write the signature
1071  * @return GNUNET_SYSERR on error, GNUNET_OK on success
1072  */
1073 int
1074 GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *key,
1075                         const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
1076                         struct GNUNET_CRYPTO_EccSignature *sig)
1077 {
1078   gcry_sexp_t result;
1079   gcry_sexp_t data;
1080   size_t ssize;
1081
1082   data = data_to_pkcs1 (purpose);
1083   GNUNET_assert (0 == gcry_pk_sign (&result, data, key->sexp));
1084   gcry_sexp_release (data);
1085   ssize = gcry_sexp_sprint (result, 
1086                             GCRYSEXP_FMT_DEFAULT,
1087                             sig->sexpr,
1088                             GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH);
1089   if (0 == ssize)
1090   {
1091     GNUNET_break (0);
1092     return GNUNET_SYSERR;
1093   }
1094   sig->size = htons ((uint16_t) ssize);
1095   /* padd with zeros */
1096   memset (&sig->sexpr[ssize], 0, GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH - ssize);
1097   gcry_sexp_release (result);
1098   return GNUNET_OK;
1099 }
1100
1101
1102 /**
1103  * Verify signature.
1104  *
1105  * @param purpose what is the purpose that the signature should have?
1106  * @param validate block to validate (size, purpose, data)
1107  * @param sig signature that is being validated
1108  * @param publicKey public key of the signer
1109  * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid
1110  */
1111 int
1112 GNUNET_CRYPTO_ecc_verify (uint32_t purpose,
1113                           const struct GNUNET_CRYPTO_EccSignaturePurpose
1114                           *validate,
1115                           const struct GNUNET_CRYPTO_EccSignature *sig,
1116                           const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded
1117                           *publicKey)
1118 {
1119   gcry_sexp_t data;
1120   gcry_sexp_t sigdata;
1121   size_t size;
1122   gcry_sexp_t psexp;
1123   size_t erroff;
1124   int rc;
1125
1126   if (purpose != ntohl (validate->purpose))
1127     return GNUNET_SYSERR;       /* purpose mismatch */
1128   size = ntohs (sig->size);
1129   if (size > GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH - sizeof (uint16_t))
1130     return GNUNET_SYSERR; /* size out of range */
1131   data = data_to_pkcs1 (validate);
1132   GNUNET_assert (0 ==
1133                  gcry_sexp_sscan (&sigdata, &erroff, sig->sexpr, size));
1134   if (! (psexp = decode_public_key (publicKey)))
1135   {
1136     gcry_sexp_release (data);
1137     gcry_sexp_release (sigdata);
1138     return GNUNET_SYSERR;
1139   }
1140   rc = gcry_pk_verify (sigdata, data, psexp);
1141   gcry_sexp_release (psexp);
1142   gcry_sexp_release (data);
1143   gcry_sexp_release (sigdata);
1144   if (0 != rc)
1145   {
1146     LOG (GNUNET_ERROR_TYPE_WARNING,
1147          _("ECC signature verification failed at %s:%d: %s\n"), __FILE__,
1148          __LINE__, gcry_strerror (rc));
1149     return GNUNET_SYSERR;
1150   }
1151   return GNUNET_OK;
1152 }
1153
1154
1155 /* end of crypto_ecc.c */