95d157eb19a9f0b0981805fabaa6afc8616d501d
[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 || 1
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 (0 != gcry_pk_testkey (key->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 + (sizeof (be)));
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   int rc;
390
391   if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
392                                   "(genkey(ecdsa(curve 10:NIST P-521)))")))
393   {
394     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
395     return NULL;
396   }
397   if (0 != (rc = gcry_pk_genkey (&s_key, s_keyparam)))
398   {
399     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
400     gcry_sexp_release (s_keyparam);
401     return NULL;
402   }
403   gcry_sexp_release (s_keyparam);
404 #if EXTRA_CHECKS
405   if (0 != (rc = gcry_pk_testkey (s_key)))
406   {
407     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
408     gcry_sexp_release (s_key);
409     return NULL;
410   }
411 #endif
412   ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
413   ret->sexp = s_key;
414   return ret;
415 }
416
417
418 /**
419  * Try to read the private key from the given file.
420  *
421  * @param filename file to read the key from
422  * @return NULL on error
423  */
424 static struct GNUNET_CRYPTO_EccPrivateKey *
425 try_read_key (const char *filename)
426 {
427   struct GNUNET_CRYPTO_EccPrivateKey *ret;
428   struct GNUNET_DISK_FileHandle *fd;
429   OFF_T fs;
430
431   if (GNUNET_YES != GNUNET_DISK_file_test (filename))
432     return NULL;
433
434   /* hostkey file exists already, read it! */
435   if (NULL == (fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
436                                            GNUNET_DISK_PERM_NONE)))
437   {
438     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
439     return NULL;
440   }
441   if (GNUNET_OK != (GNUNET_DISK_file_handle_size (fd, &fs)))
442   {
443     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "stat", filename);
444     (void) GNUNET_DISK_file_close (fd);
445     return NULL;
446   }
447   if (0 == fs)
448   {
449     GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
450     return NULL;
451   }
452   if (fs > UINT16_MAX)
453   {
454     LOG (GNUNET_ERROR_TYPE_ERROR,
455          _("File `%s' does not contain a valid private key (too long, %llu bytes).  Deleting it.\n"),   
456          filename,
457          (unsigned long long) fs);
458     GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
459     if (0 != UNLINK (filename))    
460       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
461     return NULL;
462   }
463   {
464     char enc[fs];
465
466     GNUNET_break (fs == GNUNET_DISK_file_read (fd, enc, fs));
467     if (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, fs)))
468     {
469       LOG (GNUNET_ERROR_TYPE_ERROR,
470            _("File `%s' does not contain a valid private key (failed decode, %llu bytes).  Deleting it.\n"),
471            filename,
472            (unsigned long long) fs);
473       GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
474       if (0 != UNLINK (filename))    
475         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
476       return NULL;
477     }
478   }
479   GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
480   return ret;  
481 }
482
483
484 /**
485  * Wait for a short time (we're trying to lock a file or want
486  * to give another process a shot at finishing a disk write, etc.).
487  * Sleeps for 100ms (as that should be long enough for virtually all
488  * modern systems to context switch and allow another process to do
489  * some 'real' work).
490  */
491 static void
492 short_wait ()
493 {
494   struct GNUNET_TIME_Relative timeout;
495
496   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
497   (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
498 }
499
500
501 /**
502  * Create a new private key by reading it from a file.  If the
503  * files does not exist, create a new key and write it to the
504  * file.  Caller must free return value.  Note that this function
505  * can not guarantee that another process might not be trying
506  * the same operation on the same file at the same time.
507  * If the contents of the file
508  * are invalid the old file is deleted and a fresh key is
509  * created.
510  *
511  * @return new private key, NULL on error (for example,
512  *   permission denied)
513  */
514 struct GNUNET_CRYPTO_EccPrivateKey *
515 GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
516 {
517   struct GNUNET_CRYPTO_EccPrivateKey *ret;
518   struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
519   uint16_t len;
520   struct GNUNET_DISK_FileHandle *fd;
521   unsigned int cnt;
522   int ec;
523   uint64_t fs;
524   struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pub;
525   struct GNUNET_PeerIdentity pid;
526
527   if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
528     return NULL;
529   while (GNUNET_YES != GNUNET_DISK_file_test (filename))
530   {
531     fd = GNUNET_DISK_file_open (filename,
532                                 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
533                                 | GNUNET_DISK_OPEN_FAILIFEXISTS,
534                                 GNUNET_DISK_PERM_USER_READ |
535                                 GNUNET_DISK_PERM_USER_WRITE);
536     if (NULL == fd)
537     {
538       if (errno == EEXIST)
539       {
540         if (GNUNET_YES != GNUNET_DISK_file_test (filename))
541         {
542           /* must exist but not be accessible, fail for good! */
543           if (0 != ACCESS (filename, R_OK))
544             LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
545           else
546             GNUNET_break (0);   /* what is going on!? */
547           return NULL;
548         }
549         continue;
550       }
551       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
552       return NULL;
553     }
554     cnt = 0;
555
556     while (GNUNET_YES !=
557            GNUNET_DISK_file_lock (fd, 0,
558                                   sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded),
559                                   GNUNET_YES))
560     {
561       short_wait ();
562       if (0 == ++cnt % 10)
563       {
564         ec = errno;
565         LOG (GNUNET_ERROR_TYPE_ERROR,
566              _("Could not acquire lock on file `%s': %s...\n"), filename,
567              STRERROR (ec));
568       }
569     }
570     LOG (GNUNET_ERROR_TYPE_INFO,
571          _("Creating a new private key.  This may take a while.\n"));
572     ret = ecc_key_create ();
573     GNUNET_assert (ret != NULL);
574     enc = GNUNET_CRYPTO_ecc_encode_key (ret);
575     GNUNET_assert (enc != NULL);
576     GNUNET_assert (ntohs (enc->size) ==
577                    GNUNET_DISK_file_write (fd, enc, ntohs (enc->size)));
578     GNUNET_free (enc);
579
580     GNUNET_DISK_file_sync (fd);
581     if (GNUNET_YES !=
582         GNUNET_DISK_file_unlock (fd, 0,
583                                  sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
584       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
585     GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
586     GNUNET_CRYPTO_ecc_key_get_public (ret, &pub);
587     GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey);
588     LOG (GNUNET_ERROR_TYPE_INFO,
589          _("I am host `%s'.  Stored new private key in `%s'.\n"),
590          GNUNET_i2s (&pid), filename);
591     return ret;
592   }
593   /* hostkey file exists already, read it! */
594   fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
595                               GNUNET_DISK_PERM_NONE);
596   if (NULL == fd)
597   {
598     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
599     return NULL;
600   }
601   cnt = 0;
602   while (1)
603   {
604     if (GNUNET_YES !=
605         GNUNET_DISK_file_lock (fd, 0,
606                                sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded),
607                                GNUNET_NO))
608     {
609       if (0 == ++cnt % 60)
610       {
611         ec = errno;
612         LOG (GNUNET_ERROR_TYPE_ERROR,
613              _("Could not acquire lock on file `%s': %s...\n"), filename,
614              STRERROR (ec));
615         LOG (GNUNET_ERROR_TYPE_ERROR,
616              _
617              ("This may be ok if someone is currently generating a hostkey.\n"));
618       }
619       short_wait ();
620       continue;
621     }
622     if (GNUNET_YES != GNUNET_DISK_file_test (filename))
623     {
624       /* eh, what!? File we opened is now gone!? */
625       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
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       GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
631
632       return NULL;
633     }
634     if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
635       fs = 0;
636     if (fs < sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded))
637     {
638       /* maybe we got the read lock before the hostkey generating
639        * process had a chance to get the write lock; give it up! */
640       if (GNUNET_YES !=
641           GNUNET_DISK_file_unlock (fd, 0,
642                                    sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
643         LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
644       if (0 == ++cnt % 10)
645       {
646         LOG (GNUNET_ERROR_TYPE_ERROR,
647              _
648              ("When trying to read hostkey file `%s' I found %u bytes but I need at least %u.\n"),
649              filename, (unsigned int) fs,
650              (unsigned int) sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded));
651         LOG (GNUNET_ERROR_TYPE_ERROR,
652              _
653              ("This may be ok if someone is currently generating a hostkey.\n"));
654       }
655       short_wait ();                /* wait a bit longer! */
656       continue;
657     }
658     break;
659   }
660   enc = GNUNET_malloc (fs);
661   GNUNET_assert (fs == GNUNET_DISK_file_read (fd, enc, fs));
662   len = ntohs (enc->size);
663   ret = NULL;
664   if ((len != fs) ||
665       (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, len))))
666   {
667     LOG (GNUNET_ERROR_TYPE_ERROR,
668          _("File `%s' does not contain a valid private key.  Deleting it.\n"),
669          filename);
670     if (0 != UNLINK (filename))
671     {
672       LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
673     }
674   }
675   GNUNET_free (enc);
676   if (GNUNET_YES !=
677       GNUNET_DISK_file_unlock (fd, 0,
678                                sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
679     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
680   GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
681   if (ret != NULL)
682   {
683     GNUNET_CRYPTO_ecc_key_get_public (ret, &pub);
684     GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey);
685     LOG (GNUNET_ERROR_TYPE_INFO,
686          _("I am host `%s'.  Read private key from `%s'.\n"), GNUNET_i2s (&pid),
687          filename);
688   }
689   return ret;
690 }
691
692
693 /**
694  * Handle to cancel private key generation and state for the
695  * key generation operation.
696  */
697 struct GNUNET_CRYPTO_EccKeyGenerationContext
698 {
699   
700   /**
701    * Continuation to call upon completion.
702    */
703   GNUNET_CRYPTO_EccKeyCallback cont;
704
705   /**
706    * Closure for 'cont'.
707    */
708   void *cont_cls;
709
710   /**
711    * Name of the file.
712    */
713   char *filename;
714
715   /**
716    * Handle to the helper process which does the key generation.
717    */ 
718   struct GNUNET_OS_Process *gnunet_ecc;
719   
720   /**
721    * Handle to 'stdout' of gnunet-ecc.  We 'read' on stdout to detect
722    * process termination (instead of messing with SIGCHLD).
723    */
724   struct GNUNET_DISK_PipeHandle *gnunet_ecc_out;
725
726   /**
727    * Location where we store the private key if it already existed.
728    * (if this is used, 'filename', 'gnunet_ecc' and 'gnunet_ecc_out' will
729    * not be used).
730    */
731   struct GNUNET_CRYPTO_EccPrivateKey *pk;
732   
733   /**
734    * Task reading from 'gnunet_ecc_out' to wait for process termination.
735    */
736   GNUNET_SCHEDULER_TaskIdentifier read_task;
737   
738 };
739
740
741 /**
742  * Abort ECC key generation.
743  *
744  * @param gc key generation context to abort
745  */
746 void
747 GNUNET_CRYPTO_ecc_key_create_stop (struct GNUNET_CRYPTO_EccKeyGenerationContext *gc)
748 {
749   if (GNUNET_SCHEDULER_NO_TASK != gc->read_task)
750   {
751     GNUNET_SCHEDULER_cancel (gc->read_task);
752     gc->read_task = GNUNET_SCHEDULER_NO_TASK;
753   }
754   if (NULL != gc->gnunet_ecc)
755   {
756     (void) GNUNET_OS_process_kill (gc->gnunet_ecc, SIGKILL);
757     GNUNET_break (GNUNET_OK ==
758                   GNUNET_OS_process_wait (gc->gnunet_ecc));
759     GNUNET_OS_process_destroy (gc->gnunet_ecc);
760     GNUNET_DISK_pipe_close (gc->gnunet_ecc_out);
761   }
762
763   if (NULL != gc->filename)
764   {
765     if (0 != UNLINK (gc->filename))
766       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", gc->filename);
767     GNUNET_free (gc->filename);
768   }
769   if (NULL != gc->pk)
770     GNUNET_CRYPTO_ecc_key_free (gc->pk);
771   GNUNET_free (gc);
772 }
773
774
775 /**
776  * Task called upon shutdown or process termination of 'gnunet-ecc' during
777  * ECC key generation.  Check where we are and perform the appropriate
778  * action.
779  *
780  * @param cls the 'struct GNUNET_CRYPTO_EccKeyGenerationContext'
781  * @param tc scheduler context
782  */
783 static void
784 check_key_generation_completion (void *cls,
785                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
786 {
787   struct GNUNET_CRYPTO_EccKeyGenerationContext *gc = cls;
788   struct GNUNET_CRYPTO_EccPrivateKey *pk;
789
790   gc->read_task = GNUNET_SCHEDULER_NO_TASK;
791   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
792   {
793     gc->cont (gc->cont_cls, NULL, _("interrupted by shutdown"));
794     GNUNET_CRYPTO_ecc_key_create_stop (gc);
795     return;
796   }
797   GNUNET_assert (GNUNET_OK == 
798                  GNUNET_OS_process_wait (gc->gnunet_ecc));
799   GNUNET_OS_process_destroy (gc->gnunet_ecc);
800   gc->gnunet_ecc = NULL;
801   if (NULL == (pk = try_read_key (gc->filename)))
802   {
803     GNUNET_break (0);
804     gc->cont (gc->cont_cls, NULL, _("gnunet-ecc failed"));
805     GNUNET_CRYPTO_ecc_key_create_stop (gc);
806     return;
807   }
808   gc->cont (gc->cont_cls, pk, NULL);
809   GNUNET_DISK_pipe_close (gc->gnunet_ecc_out);
810   GNUNET_free (gc->filename);
811   GNUNET_free (gc);
812 }
813
814
815 /**
816  * Return the private ECC key which already existed on disk
817  * (asynchronously) to the caller.
818  *
819  * @param cls the 'struct GNUNET_CRYPTO_EccKeyGenerationContext'
820  * @param tc scheduler context (unused)
821  */
822 static void
823 async_return_key (void *cls,
824                   const struct GNUNET_SCHEDULER_TaskContext *tc)
825 {
826   struct GNUNET_CRYPTO_EccKeyGenerationContext *gc = cls;
827
828   gc->cont (gc->cont_cls,
829             gc->pk,
830             NULL);
831   GNUNET_free (gc);
832 }
833
834
835 /**
836  * Create a new private key by reading it from a file.  If the files
837  * does not exist, create a new key and write it to the file.  If the
838  * contents of the file are invalid the old file is deleted and a
839  * fresh key is created.
840  *
841  * @param filename name of file to use for storage
842  * @param cont function to call when done (or on errors)
843  * @param cont_cls closure for 'cont'
844  * @return handle to abort operation, NULL on fatal errors (cont will not be called if NULL is returned)
845  */
846 struct GNUNET_CRYPTO_EccKeyGenerationContext *
847 GNUNET_CRYPTO_ecc_key_create_start (const char *filename,
848                                     GNUNET_CRYPTO_EccKeyCallback cont,
849                                     void *cont_cls)
850 {
851   struct GNUNET_CRYPTO_EccKeyGenerationContext *gc;
852   struct GNUNET_CRYPTO_EccPrivateKey *pk;
853   const char *weak_random;
854
855   if (NULL != (pk = try_read_key (filename)))
856   {
857     /* quick happy ending: key already exists! */
858     gc = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccKeyGenerationContext));
859     gc->pk = pk;
860     gc->cont = cont;
861     gc->cont_cls = cont_cls;
862     gc->read_task = GNUNET_SCHEDULER_add_now (&async_return_key,
863                                               gc);
864     return gc;
865   }
866   gc = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccKeyGenerationContext));
867   gc->filename = GNUNET_strdup (filename);
868   gc->cont = cont;
869   gc->cont_cls = cont_cls;
870   gc->gnunet_ecc_out = GNUNET_DISK_pipe (GNUNET_NO,
871                                          GNUNET_NO,
872                                          GNUNET_NO,
873                                          GNUNET_YES);
874   if (NULL == gc->gnunet_ecc_out)
875   {
876     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "pipe");
877     GNUNET_free (gc->filename);
878     GNUNET_free (gc);
879     return NULL;
880   }
881   weak_random = NULL;
882   if (GNUNET_YES ==
883       GNUNET_CRYPTO_random_is_weak ())
884     weak_random = "-w";
885   gc->gnunet_ecc = GNUNET_OS_start_process (GNUNET_NO,
886                                             GNUNET_OS_INHERIT_STD_ERR,
887                                             NULL, 
888                                             gc->gnunet_ecc_out,
889                                             "gnunet-ecc",
890                                             "gnunet-ecc",                                           
891                                             gc->filename,
892                                             weak_random,
893                                             NULL);
894   if (NULL == gc->gnunet_ecc)
895   {
896     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fork");
897     GNUNET_DISK_pipe_close (gc->gnunet_ecc_out);
898     GNUNET_free (gc->filename);
899     GNUNET_free (gc);
900     return NULL;
901   }
902   GNUNET_assert (GNUNET_OK ==
903                  GNUNET_DISK_pipe_close_end (gc->gnunet_ecc_out,
904                                              GNUNET_DISK_PIPE_END_WRITE));
905   gc->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
906                                                   GNUNET_DISK_pipe_handle (gc->gnunet_ecc_out,
907                                                                            GNUNET_DISK_PIPE_END_READ),
908                                                   &check_key_generation_completion,
909                                                   gc);
910   return gc;
911 }
912
913
914 /**
915  * Setup a hostkey file for a peer given the name of the
916  * configuration file (!).  This function is used so that
917  * at a later point code can be certain that reading a
918  * hostkey is fast (for example in time-dependent testcases).
919  *
920  * @param cfg_name name of the configuration file to use
921  */
922 void
923 GNUNET_CRYPTO_ecc_setup_hostkey (const char *cfg_name)
924 {
925   struct GNUNET_CONFIGURATION_Handle *cfg;
926   struct GNUNET_CRYPTO_EccPrivateKey *pk;
927   char *fn;
928
929   cfg = GNUNET_CONFIGURATION_create ();
930   (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
931   if (GNUNET_OK == 
932       GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn))
933   {
934     pk = GNUNET_CRYPTO_ecc_key_create_from_file (fn);
935     if (NULL != pk)
936       GNUNET_CRYPTO_ecc_key_free (pk);
937     GNUNET_free (fn);
938   }
939   GNUNET_CONFIGURATION_destroy (cfg);
940 }
941
942
943 /**
944  * Convert the data specified in the given purpose argument to an
945  * S-expression suitable for signature operations.
946  *
947  * @param purpose data to convert
948  * @return converted s-expression
949  */
950 static gcry_sexp_t
951 data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
952 {
953   struct GNUNET_HashCode hc;
954   size_t bufSize;
955   gcry_sexp_t data;
956
957   GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
958 #define FORMATSTRING "(4:data(5:flags5:pkcs1)(4:hash6:sha51264:0123456789012345678901234567890123456789012345678901234567890123))"
959   bufSize = strlen (FORMATSTRING) + 1;
960   {
961     char buff[bufSize];
962
963     memcpy (buff, FORMATSTRING, bufSize);
964     memcpy (&buff
965             [bufSize -
966              strlen
967              ("0123456789012345678901234567890123456789012345678901234567890123))")
968              - 1], &hc, sizeof (struct GNUNET_HashCode));
969     GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0));
970   }
971 #undef FORMATSTRING
972   return data;
973 }
974
975
976 /**
977  * Sign a given block.
978  *
979  * @param key private key to use for the signing
980  * @param purpose what to sign (size, purpose)
981  * @param sig where to write the signature
982  * @return GNUNET_SYSERR on error, GNUNET_OK on success
983  */
984 int
985 GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *key,
986                         const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
987                         struct GNUNET_CRYPTO_EccSignature *sig)
988 {
989   gcry_sexp_t result;
990   gcry_sexp_t data;
991   size_t ssize;
992
993   data = data_to_pkcs1 (purpose);
994   GNUNET_assert (0 == gcry_pk_sign (&result, data, key->sexp));
995   gcry_sexp_release (data);
996   ssize = gcry_sexp_sprint (result, 
997                             GCRYSEXP_FMT_DEFAULT,
998                             sig->sexpr,
999                             GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH);
1000   if (0 == ssize)
1001   {
1002     GNUNET_break (0);
1003     return GNUNET_SYSERR;
1004   }
1005   sig->size = htons ((uint16_t) (ssize + sizeof (uint16_t)));
1006   /* padd with zeros */
1007   memset (&sig->sexpr[ssize], 0, GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH - ssize);
1008   gcry_sexp_release (result);
1009   return GNUNET_OK;
1010 }
1011
1012
1013 /**
1014  * Verify signature.
1015  *
1016  * @param purpose what is the purpose that the signature should have?
1017  * @param validate block to validate (size, purpose, data)
1018  * @param sig signature that is being validated
1019  * @param publicKey public key of the signer
1020  * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid
1021  */
1022 int
1023 GNUNET_CRYPTO_ecc_verify (uint32_t purpose,
1024                           const struct GNUNET_CRYPTO_EccSignaturePurpose
1025                           *validate,
1026                           const struct GNUNET_CRYPTO_EccSignature *sig,
1027                           const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded
1028                           *publicKey)
1029 {
1030   gcry_sexp_t data;
1031   gcry_sexp_t sigdata;
1032   size_t size;
1033   gcry_sexp_t psexp;
1034   size_t erroff;
1035   int rc;
1036
1037   if (purpose != ntohl (validate->purpose))
1038     return GNUNET_SYSERR;       /* purpose mismatch */
1039   size = ntohs (sig->size);
1040   if ( (size < sizeof (uint16_t)) ||
1041        (size > GNUNET_CRYPTO_ECC_DATA_ENCODING_LENGTH - sizeof (uint16_t)) )
1042     return GNUNET_SYSERR; /* size out of range */
1043   data = data_to_pkcs1 (validate);
1044   GNUNET_assert (0 ==
1045                  gcry_sexp_sscan (&sigdata, &erroff, 
1046                                   sig->sexpr, size - sizeof (uint16_t)));
1047   if (! (psexp = decode_public_key (publicKey)))
1048   {
1049     gcry_sexp_release (data);
1050     gcry_sexp_release (sigdata);
1051     return GNUNET_SYSERR;
1052   }
1053   rc = gcry_pk_verify (sigdata, data, psexp);
1054   gcry_sexp_release (psexp);
1055   gcry_sexp_release (data);
1056   gcry_sexp_release (sigdata);
1057   if (0 != rc)
1058   {
1059     LOG (GNUNET_ERROR_TYPE_WARNING,
1060          _("ECC signature verification failed at %s:%d: %s\n"), __FILE__,
1061          __LINE__, gcry_strerror (rc));
1062     return GNUNET_SYSERR;
1063   }
1064   return GNUNET_OK;
1065 }
1066
1067
1068 /* end of crypto_ecc.c */