aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-09-17 10:45:23 +0000
committerChristian Grothoff <christian@grothoff.org>2012-09-17 10:45:23 +0000
commit7e065c18499688141eb68513058131a49344cac1 (patch)
treee441b44c8f0db8a4f214775e4945039cc820cf2f /src/util
parentb3ad920b6e0107c3da946fe1f2f720955dbac151 (diff)
downloadgnunet-7e065c18499688141eb68513058131a49344cac1.tar.gz
gnunet-7e065c18499688141eb68513058131a49344cac1.zip
fixing #1551/#2503
Diffstat (limited to 'src/util')
-rw-r--r--src/util/crypto_random.c37
-rw-r--r--src/util/crypto_rsa.c46
-rw-r--r--src/util/gnunet-rsa.c10
-rw-r--r--src/util/server.c95
4 files changed, 136 insertions, 52 deletions
diff --git a/src/util/crypto_random.c b/src/util/crypto_random.c
index dbf71d78a..8dce1080c 100644
--- a/src/util/crypto_random.c
+++ b/src/util/crypto_random.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2001, 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) 3 (C) 2001, 2002, 2003, 2004, 2005, 2006, 2012 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -34,6 +34,14 @@
34 34
35#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) 35#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
36 36
37
38/**
39 * GNUNET_YES if we are using a 'weak' (low-entropy) PRNG.
40 */
41static int weak_random;
42
43
44
37/* TODO: ndurner, move this to plibc? */ 45/* TODO: ndurner, move this to plibc? */
38/* The code is derived from glibc, obviously */ 46/* The code is derived from glibc, obviously */
39#if MINGW 47#if MINGW
@@ -49,14 +57,18 @@
49#undef RAND_MAX 57#undef RAND_MAX
50#endif 58#endif
51#define RAND_MAX 0x7fffffff /* Hopefully this is correct */ 59#define RAND_MAX 0x7fffffff /* Hopefully this is correct */
60
61
52static int32_t glibc_weak_rand32_state = 1; 62static int32_t glibc_weak_rand32_state = 1;
53 63
64
54void 65void
55glibc_weak_srand32 (int32_t s) 66glibc_weak_srand32 (int32_t s)
56{ 67{
57 glibc_weak_rand32_state = s; 68 glibc_weak_rand32_state = s;
58} 69}
59 70
71
60int32_t 72int32_t
61glibc_weak_rand32 () 73glibc_weak_rand32 ()
62{ 74{
@@ -74,11 +86,12 @@ glibc_weak_rand32 ()
74 * @return number between 0 and 1. 86 * @return number between 0 and 1.
75 */ 87 */
76static double 88static double
77weak_random () 89get_weak_random ()
78{ 90{
79 return ((double) RANDOM () / RAND_MAX); 91 return ((double) RANDOM () / RAND_MAX);
80} 92}
81 93
94
82/** 95/**
83 * Seed a weak random generator. Only GNUNET_CRYPTO_QUALITY_WEAK-mode generator 96 * Seed a weak random generator. Only GNUNET_CRYPTO_QUALITY_WEAK-mode generator
84 * can be seeded. 97 * can be seeded.
@@ -91,6 +104,7 @@ GNUNET_CRYPTO_seed_weak_random (int32_t seed)
91 SRANDOM (seed); 104 SRANDOM (seed);
92} 105}
93 106
107
94/** 108/**
95 * Produce a random value. 109 * Produce a random value.
96 * 110 *
@@ -134,7 +148,7 @@ GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode, uint32_t i)
134 while (ret >= ul); 148 while (ret >= ul);
135 return ret % i; 149 return ret % i;
136 case GNUNET_CRYPTO_QUALITY_WEAK: 150 case GNUNET_CRYPTO_QUALITY_WEAK:
137 ret = i * weak_random (); 151 ret = i * get_weak_random ();
138 if (ret >= i) 152 if (ret >= i)
139 ret = i - 1; 153 ret = i - 1;
140 return ret; 154 return ret;
@@ -211,7 +225,7 @@ GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max)
211 225
212 return ret % max; 226 return ret % max;
213 case GNUNET_CRYPTO_QUALITY_WEAK: 227 case GNUNET_CRYPTO_QUALITY_WEAK:
214 ret = max * weak_random (); 228 ret = max * get_weak_random ();
215 if (ret >= max) 229 if (ret >= max)
216 ret = max - 1; 230 ret = max - 1;
217 return ret; 231 return ret;
@@ -221,6 +235,19 @@ GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max)
221 return 0; 235 return 0;
222} 236}
223 237
238
239/**
240 * Check if we are using weak random number generation.
241 *
242 * @return GNUNET_YES if weak number generation is on
243 */
244int
245GNUNET_CRYPTO_random_is_weak ()
246{
247 return weak_random;
248}
249
250
224/** 251/**
225 * This function should only be called in testcases 252 * This function should only be called in testcases
226 * where strong entropy gathering is not desired 253 * where strong entropy gathering is not desired
@@ -229,6 +256,7 @@ GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, uint64_t max)
229void 256void
230GNUNET_CRYPTO_random_disable_entropy_gathering () 257GNUNET_CRYPTO_random_disable_entropy_gathering ()
231{ 258{
259 weak_random = GNUNET_YES;
232 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); 260 gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
233} 261}
234 262
@@ -239,6 +267,7 @@ GNUNET_CRYPTO_random_disable_entropy_gathering ()
239 */ 267 */
240static struct GNUNET_OS_Process *genproc; 268static struct GNUNET_OS_Process *genproc;
241 269
270
242/** 271/**
243 * Function called by libgcrypt whenever we are 272 * Function called by libgcrypt whenever we are
244 * blocked gathering entropy. 273 * blocked gathering entropy.
diff --git a/src/util/crypto_rsa.c b/src/util/crypto_rsa.c
index 4afda1f6e..8843464a2 100644
--- a/src/util/crypto_rsa.c
+++ b/src/util/crypto_rsa.c
@@ -629,11 +629,17 @@ try_read_key (const char *filename)
629 (void) GNUNET_DISK_file_close (fd); 629 (void) GNUNET_DISK_file_close (fd);
630 return NULL; 630 return NULL;
631 } 631 }
632 if (0 == fs)
633 {
634 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
635 return NULL;
636 }
632 if (fs > UINT16_MAX) 637 if (fs > UINT16_MAX)
633 { 638 {
634 LOG (GNUNET_ERROR_TYPE_ERROR, 639 LOG (GNUNET_ERROR_TYPE_ERROR,
635 _("File `%s' does not contain a valid private key. Deleting it.\n"), 640 _("File `%s' does not contain a valid private key (too long, %llu bytes). Deleting it.\n"),
636 filename); 641 filename,
642 (unsigned long long) fs);
637 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd)); 643 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
638 if (0 != UNLINK (filename)) 644 if (0 != UNLINK (filename))
639 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); 645 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
@@ -648,8 +654,9 @@ try_read_key (const char *filename)
648 (NULL == (ret = GNUNET_CRYPTO_rsa_decode_key ((char *) enc, len)))) 654 (NULL == (ret = GNUNET_CRYPTO_rsa_decode_key ((char *) enc, len))))
649 { 655 {
650 LOG (GNUNET_ERROR_TYPE_ERROR, 656 LOG (GNUNET_ERROR_TYPE_ERROR,
651 _("File `%s' does not contain a valid private key. Deleting it.\n"), 657 _("File `%s' does not contain a valid private key (failed decode, %llu bytes). Deleting it.\n"),
652 filename); 658 filename,
659 (unsigned long long) fs);
653 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd)); 660 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fd));
654 if (0 != UNLINK (filename)) 661 if (0 != UNLINK (filename))
655 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); 662 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
@@ -664,6 +671,23 @@ try_read_key (const char *filename)
664 671
665 672
666/** 673/**
674 * Wait for a short time (we're trying to lock a file or want
675 * to give another process a shot at finishing a disk write, etc.).
676 * Sleeps for 100ms (as that should be long enough for virtually all
677 * modern systems to context switch and allow another process to do
678 * some 'real' work).
679 */
680static void
681short_wait ()
682{
683 struct GNUNET_TIME_Relative timeout;
684
685 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
686 GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
687}
688
689
690/**
667 * Create a new private key by reading it from a file. If the 691 * Create a new private key by reading it from a file. If the
668 * files does not exist, create a new key and write it to the 692 * files does not exist, create a new key and write it to the
669 * file. Caller must free return value. Note that this function 693 * file. Caller must free return value. Note that this function
@@ -723,7 +747,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
723 sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded), 747 sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded),
724 GNUNET_YES)) 748 GNUNET_YES))
725 { 749 {
726 sleep (1); 750 short_wait (1);
727 if (0 == ++cnt % 10) 751 if (0 == ++cnt % 10)
728 { 752 {
729 ec = errno; 753 ec = errno;
@@ -781,7 +805,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
781 _ 805 _
782 ("This may be ok if someone is currently generating a hostkey.\n")); 806 ("This may be ok if someone is currently generating a hostkey.\n"));
783 } 807 }
784 sleep (1); 808 short_wait (1);
785 continue; 809 continue;
786 } 810 }
787 if (GNUNET_YES != GNUNET_DISK_file_test (filename)) 811 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
@@ -817,7 +841,7 @@ GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
817 _ 841 _
818 ("This may be ok if someone is currently generating a hostkey.\n")); 842 ("This may be ok if someone is currently generating a hostkey.\n"));
819 } 843 }
820 sleep (2); /* wait a bit longer! */ 844 short_wait (1); /* wait a bit longer! */
821 continue; 845 continue;
822 } 846 }
823 break; 847 break;
@@ -996,6 +1020,7 @@ GNUNET_CRYPTO_rsa_key_create_start (const char *filename,
996{ 1020{
997 struct GNUNET_CRYPTO_RsaKeyGenerationContext *gc; 1021 struct GNUNET_CRYPTO_RsaKeyGenerationContext *gc;
998 struct GNUNET_CRYPTO_RsaPrivateKey *pk; 1022 struct GNUNET_CRYPTO_RsaPrivateKey *pk;
1023 const char *weak_random;
999 1024
1000 if (NULL != (pk = try_read_key (filename))) 1025 if (NULL != (pk = try_read_key (filename)))
1001 { 1026 {
@@ -1023,13 +1048,18 @@ GNUNET_CRYPTO_rsa_key_create_start (const char *filename,
1023 GNUNET_free (gc); 1048 GNUNET_free (gc);
1024 return NULL; 1049 return NULL;
1025 } 1050 }
1051 weak_random = NULL;
1052 if (GNUNET_YES ==
1053 GNUNET_CRYPTO_random_is_weak ())
1054 weak_random = "-w";
1026 gc->gnunet_rsa = GNUNET_OS_start_process (GNUNET_NO, 1055 gc->gnunet_rsa = GNUNET_OS_start_process (GNUNET_NO,
1027 GNUNET_OS_INHERIT_STD_ERR, 1056 GNUNET_OS_INHERIT_STD_ERR,
1028 NULL, 1057 NULL,
1029 gc->gnunet_rsa_out, 1058 gc->gnunet_rsa_out,
1030 "gnunet-rsa", 1059 "gnunet-rsa",
1031 "gnunet-rsa", 1060 "gnunet-rsa",
1032 gc->filename, 1061 gc->filename,
1062 weak_random,
1033 NULL); 1063 NULL);
1034 if (NULL == gc->gnunet_rsa) 1064 if (NULL == gc->gnunet_rsa)
1035 { 1065 {
diff --git a/src/util/gnunet-rsa.c b/src/util/gnunet-rsa.c
index 61e1b66df..e9fbf15df 100644
--- a/src/util/gnunet-rsa.c
+++ b/src/util/gnunet-rsa.c
@@ -43,6 +43,11 @@ static int print_peer_identity;
43 */ 43 */
44static int print_short_identity; 44static int print_short_identity;
45 45
46/**
47 * Use weak random number generator for key generation.
48 */
49static int weak_random;
50
46 51
47/** 52/**
48 * The private information of an RSA key pair. 53 * The private information of an RSA key pair.
@@ -104,6 +109,8 @@ run (void *cls, char *const *args, const char *cfgfile,
104 fprintf (stderr, _("No hostkey file specified on command line\n")); 109 fprintf (stderr, _("No hostkey file specified on command line\n"));
105 return; 110 return;
106 } 111 }
112 if (0 != weak_random)
113 GNUNET_CRYPTO_random_disable_entropy_gathering ();
107 pk = GNUNET_CRYPTO_rsa_key_create_from_file (args[0]); 114 pk = GNUNET_CRYPTO_rsa_key_create_from_file (args[0]);
108 if (NULL == pk) 115 if (NULL == pk)
109 return; 116 return;
@@ -159,6 +166,9 @@ main (int argc, char *const *argv)
159 { 's', "print-short-identity", NULL, 166 { 's', "print-short-identity", NULL,
160 gettext_noop ("print the short hash of the public key in ASCII format"), 167 gettext_noop ("print the short hash of the public key in ASCII format"),
161 0, &GNUNET_GETOPT_set_one, &print_short_identity }, 168 0, &GNUNET_GETOPT_set_one, &print_short_identity },
169 { 'w', "weak-random", NULL,
170 gettext_noop ("use insecure, weak random number generator for key generation (for testing only)"),
171 0, &GNUNET_GETOPT_set_one, &weak_random },
162 GNUNET_GETOPT_OPTION_END 172 GNUNET_GETOPT_OPTION_END
163 }; 173 };
164 174
diff --git a/src/util/server.c b/src/util/server.c
index ff4584677..4622e0779 100644
--- a/src/util/server.c
+++ b/src/util/server.c
@@ -334,43 +334,6 @@ process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
334 334
335 335
336/** 336/**
337 * Add a listen task with the scheduler for this server.
338 *
339 * @param server handle to our server for which we are adding the listen
340 * socket
341 */
342static void
343schedule_listen_task (struct GNUNET_SERVER_Handle *server)
344{
345 struct GNUNET_NETWORK_FDSet *r;
346 unsigned int i;
347
348 if (NULL == server->listen_sockets[0])
349 return; /* nothing to do, no listen sockets! */
350 if (NULL == server->listen_sockets[1])
351 {
352 /* simplified method: no fd set needed; this is then much simpler and
353 much more efficient */
354 server->listen_task =
355 GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
356 GNUNET_SCHEDULER_PRIORITY_HIGH,
357 server->listen_sockets[0],
358 &process_listen_socket, server);
359 return;
360 }
361 r = GNUNET_NETWORK_fdset_create ();
362 i = 0;
363 while (NULL != server->listen_sockets[i])
364 GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
365 server->listen_task =
366 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
367 GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
368 &process_listen_socket, server);
369 GNUNET_NETWORK_fdset_destroy (r);
370}
371
372
373/**
374 * Scheduler says our listen socket is ready. Process it! 337 * Scheduler says our listen socket is ready. Process it!
375 * 338 *
376 * @param cls handle to our server for which we are processing the listen 339 * @param cls handle to our server for which we are processing the listen
@@ -389,7 +352,7 @@ process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
389 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) 352 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
390 { 353 {
391 /* ignore shutdown, someone else will take care of it! */ 354 /* ignore shutdown, someone else will take care of it! */
392 schedule_listen_task (server); 355 GNUNET_SERVER_resume (server);
393 return; 356 return;
394 } 357 }
395 i = 0; 358 i = 0;
@@ -412,7 +375,7 @@ process_listen_socket (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
412 i++; 375 i++;
413 } 376 }
414 /* listen for more! */ 377 /* listen for more! */
415 schedule_listen_task (server); 378 GNUNET_SERVER_resume (server);
416} 379}
417 380
418 381
@@ -536,7 +499,7 @@ GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access,
536 server->access_cls = access_cls; 499 server->access_cls = access_cls;
537 server->require_found = require_found; 500 server->require_found = require_found;
538 if (NULL != lsocks) 501 if (NULL != lsocks)
539 schedule_listen_task (server); 502 GNUNET_SERVER_resume (server);
540 return server; 503 return server;
541} 504}
542 505
@@ -671,6 +634,58 @@ test_monitor_clients (struct GNUNET_SERVER_Handle *server)
671 634
672 635
673/** 636/**
637 * Suspend accepting connections from the listen socket temporarily.
638 *
639 * @param server server to stop accepting connections.
640 */
641void
642GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server)
643{
644 if (GNUNET_SCHEDULER_NO_TASK != server->listen_task)
645 {
646 GNUNET_SCHEDULER_cancel (server->listen_task);
647 server->listen_task = GNUNET_SCHEDULER_NO_TASK;
648 }
649}
650
651
652/**
653 * Resume accepting connections from the listen socket.
654 *
655 * @param server server to stop accepting connections.
656 */
657void
658GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server)
659{
660 struct GNUNET_NETWORK_FDSet *r;
661 unsigned int i;
662
663 if (NULL == server->listen_sockets[0])
664 return; /* nothing to do, no listen sockets! */
665 if (NULL == server->listen_sockets[1])
666 {
667 /* simplified method: no fd set needed; this is then much simpler and
668 much more efficient */
669 server->listen_task =
670 GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
671 GNUNET_SCHEDULER_PRIORITY_HIGH,
672 server->listen_sockets[0],
673 &process_listen_socket, server);
674 return;
675 }
676 r = GNUNET_NETWORK_fdset_create ();
677 i = 0;
678 while (NULL != server->listen_sockets[i])
679 GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
680 server->listen_task =
681 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
682 GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
683 &process_listen_socket, server);
684 GNUNET_NETWORK_fdset_destroy (r);
685}
686
687
688/**
674 * Stop the listen socket and get ready to shutdown the server 689 * Stop the listen socket and get ready to shutdown the server
675 * once only 'monitor' clients are left. 690 * once only 'monitor' clients are left.
676 * 691 *