summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2020-01-01 00:00:00 +0100
committerVivien Kraus <vivien@planete-kraus.eu>2021-06-05 16:10:24 +0200
commit8df0af8301aca112804768f532a4a62dcf3d61d6 (patch)
treeca248ae8833de333f3a313596c5152a1d71deae7
parent7e125cc85c79e0854ca300dec6f819598e3fc6b0 (diff)
Add a random number generator.
-rw-r--r--ChangeLog4
-rw-r--r--Makefile.am1
-rw-r--r--NEWS2
-rw-r--r--po/ChangeLog4
-rw-r--r--po/POTFILES.in5
-rw-r--r--po/fr.po195
-rw-r--r--po/webid-oidc.pot98
-rw-r--r--src/ChangeLog5
-rw-r--r--src/Makefile.am1
-rw-r--r--src/libwebidoidc.c2
-rw-r--r--src/random/ChangeLog11
-rw-r--r--src/random/Makefile.am20
-rw-r--r--src/random/generate-random.c42
-rw-r--r--src/random/libwebidoidc-random.c35
-rw-r--r--src/random/random.c423
-rw-r--r--src/random/webid-oidc/random.h57
-rw-r--r--src/scm/webid-oidc/stubs.scm4
-rw-r--r--src/scm/webid-oidc/testing.scm1
-rw-r--r--tests/Makefile.am13
-rw-r--r--tests/random.scm17
20 files changed, 845 insertions, 95 deletions
diff --git a/ChangeLog b/ChangeLog
index f93cc8e..3a6d4da 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,6 +10,10 @@
* get-version: Never print a newline.
+2020-11-25 Vivien Kraus <vivien@planete-kraus.eu>
+
+ * NEWS (A random number generator): Update NEWS
+
2020-11-22 Vivien Kraus <vivien@planete-kraus.eu>
* README: Initial version
diff --git a/Makefile.am b/Makefile.am
index 207bba2..73af906 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,6 +12,7 @@ AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" -I. -I$(srcdir)
AM_CFLAGS = $(GUILE_CFLAGS) $(NETTLE_CFLAGS)
nodist_noinst_SCRIPTS = pre-inst-env
INDENTED =
+include_HEADERS =
include src/Makefile.am
include doc/Makefile.am
diff --git a/NEWS b/NEWS
index 816a170..0c91be2 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@
* Initial features
** Add base64 encoding and decoding
+** A random number generator
+The code provides a thread-safe, parallel, random number generator.
# Local Variables:
# mode: org
diff --git a/po/ChangeLog b/po/ChangeLog
index f303b24..7001ddd 100644
--- a/po/ChangeLog
+++ b/po/ChangeLog
@@ -1,3 +1,7 @@
+2020-11-25 Vivien Kraus <vivien@planete-kraus.eu>
+
+ * POTFILES.in: Put the random submodule in the list.
+
2020-11-22 Vivien Kraus <vivien@planete-kraus.eu>
* LINGUAS: add fr
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 987cc14..3b2cece 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,3 +1,6 @@
# List of source files which contain translatable strings.
src/libwebidoidc.c
-src/scm/webid-oidc/errors.scm \ No newline at end of file
+src/random/random.c
+src/random/libwebidoidc-random.c
+src/random/generate-random.c
+src/scm/webid-oidc/errors.scm
diff --git a/po/fr.po b/po/fr.po
index 6fcba28..857f50c 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -12,10 +12,115 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-#: src/libwebidoidc.c:7
+#: src/libwebidoidc.c:8
msgid "This is the main function."
msgstr "Ceci est la fonction principale."
+#: src/random/random.c:199
+#, c-format
+msgid "Could not set the global random generator up.\n"
+msgstr "Impossible d'initialiser le générateur de nombres aléatoires global.\n"
+
+#: src/random/random.c:213 src/random/random.c:225 src/random/random.c:238
+#: src/random/random.c:249 src/random/random.c:260
+#, c-format
+msgid "Could not set the global random generator up: out of memory.\n"
+msgstr ""
+"Impossible d'initialiser le générateur de nombres aléatoires global : plus "
+"de mémoire.\n"
+
+#: src/random/random.c:270
+#, c-format
+msgid ""
+"Warning: could not open the seed file, maybe the parent directory is "
+"missing...\n"
+msgstr ""
+"Attention : impossible d'ouvrir le fichier graine, peut-être que le dossier "
+"parent n'existe pas...\n"
+
+#: src/random/random.c:274
+#, c-format
+msgid "Warning: could not create the cache directory '%s'.\n"
+msgstr "Attention : impossible de créer le dossier de cache « %s ».\n"
+
+#: src/random/random.c:276
+msgid "when creating the cache directory"
+msgstr "en créant le dossier de cache"
+
+#: src/random/random.c:282
+#, c-format
+msgid "Warning: could not create the package cache directory '%s'.\n"
+msgstr ""
+"Attention : impossible de créer le dossier de cache du paquet « %s ».\n"
+
+#: src/random/random.c:284
+msgid "when creating the package cache directory"
+msgstr "en créant le dossier de cache du paquet"
+
+#: src/random/random.c:290
+#, c-format
+msgid "Could not open the seed file '%s'.\n"
+msgstr "Impossible d'ouvrir le fichier graine « %s ».\n"
+
+#: src/random/random.c:291
+msgid "when opening the seed file"
+msgstr "en ouvrant le fichier graine"
+
+#: src/random/random.c:311
+#, c-format
+msgid "Could not lock the seed file '%s'.\n"
+msgstr "Impossible de verrouiller le fichier graine « %s ».\n"
+
+#: src/random/random.c:313
+msgid "when locking the seed file"
+msgstr "en verrouillant le fichier graine"
+
+#: src/random/random.c:327
+#, c-format
+msgid ""
+"Warning: the seed file '%s' is too short. This weakens the random number "
+"generator. Please write more random data in it.\n"
+msgstr ""
+"Attention : le fichier de graine « %s » est trop court. Ceci affaiblit le "
+"générateur de nombres aléatoires. Veuillez écrire plus de données dedans.\n"
+
+#: src/random/random.c:344
+#, c-format
+msgid "Could not update the seed file '%s'.\n"
+msgstr "Impossible de mettre à jour le fichier graine « %s ».\n"
+
+#: src/random/random.c:345
+msgid "when rewinding the seed file"
+msgstr "en rembobinant le fichier de graine"
+
+#: src/random/random.c:377
+#, c-format
+msgid "Could not unlock the seed file '%s'.\n"
+msgstr "Impossible de déverrouiller le fichier graine « %s ».\n"
+
+#: src/random/random.c:379
+msgid "when unlocking the seed file"
+msgstr "en déverrouillant le fichier graine"
+
+#: src/random/random.c:407
+#, c-format
+msgid "Could not set the thread-local random generator up.\n"
+msgstr "Impossible d'initialiser le générateur de nombres aléatoires du fil.\n"
+
+#: src/random/random.c:415
+#, c-format
+msgid ""
+"The random module has not been initialized. Please call "
+"webid_oidc_random_init first.\n"
+msgstr ""
+"Le module aléatoire n'a pas été initialisé. Veuillez appeler "
+"webid_oidc_random_init d'abort.\n"
+
+#: src/random/generate-random.c:29
+#, c-format
+msgid "Usage: generate-random [NUMBER OF BYTES]\n"
+msgstr "Utilisation : generate-random [NOMBRE D'OCTETS]\n"
+
#: src/scm/webid-oidc/errors.scm:35
msgid "that’s how it is"
msgstr "c’est comme ça"
@@ -68,94 +173,6 @@ msgid "Unhandled exception type ~a."
msgstr "Type d’exception non pris en charge ~a."
#, c-format
-#~ msgid "Could not set the global random generator up.\n"
-#~ msgstr ""
-#~ "Impossible d'initialiser le générateur de nombres aléatoires global.\n"
-
-#, c-format
-#~ msgid "Could not set the global random generator up: out of memory.\n"
-#~ msgstr ""
-#~ "Impossible d'initialiser le générateur de nombres aléatoires global : "
-#~ "plus de mémoire.\n"
-
-#, c-format
-#~ msgid ""
-#~ "Warning: could not open the seed file, maybe the parent directory is "
-#~ "missing...\n"
-#~ msgstr ""
-#~ "Attention : impossible d'ouvrir le fichier graine, peut-être que le "
-#~ "dossier parent n'existe pas...\n"
-
-#, c-format
-#~ msgid "Warning: could not create the cache directory '%s'.\n"
-#~ msgstr "Attention : impossible de créer le dossier de cache « %s ».\n"
-
-#~ msgid "when creating the cache directory"
-#~ msgstr "en créant le dossier de cache"
-
-#, c-format
-#~ msgid "Warning: could not create the package cache directory '%s'.\n"
-#~ msgstr ""
-#~ "Attention : impossible de créer le dossier de cache du paquet « %s ».\n"
-
-#~ msgid "when creating the package cache directory"
-#~ msgstr "en créant le dossier de cache du paquet"
-
-#, c-format
-#~ msgid "Could not open the seed file '%s'.\n"
-#~ msgstr "Impossible d'ouvrir le fichier graine « %s ».\n"
-
-#~ msgid "when opening the seed file"
-#~ msgstr "en ouvrant le fichier graine"
-
-#, c-format
-#~ msgid "Could not lock the seed file '%s'.\n"
-#~ msgstr "Impossible de verrouiller le fichier graine « %s ».\n"
-
-#~ msgid "when locking the seed file"
-#~ msgstr "en verrouillant le fichier graine"
-
-#, c-format
-#~ msgid ""
-#~ "Warning: the seed file '%s' is too short. This weakens the random number "
-#~ "generator. Please write more random data in it.\n"
-#~ msgstr ""
-#~ "Attention : le fichier de graine « %s » est trop court. Ceci affaiblit le "
-#~ "générateur de nombres aléatoires. Veuillez écrire plus de données "
-#~ "dedans.\n"
-
-#, c-format
-#~ msgid "Could not update the seed file '%s'.\n"
-#~ msgstr "Impossible de mettre à jour le fichier graine « %s ».\n"
-
-#~ msgid "when rewinding the seed file"
-#~ msgstr "en rembobinant le fichier de graine"
-
-#, c-format
-#~ msgid "Could not unlock the seed file '%s'.\n"
-#~ msgstr "Impossible de déverrouiller le fichier graine « %s ».\n"
-
-#~ msgid "when unlocking the seed file"
-#~ msgstr "en déverrouillant le fichier graine"
-
-#, c-format
-#~ msgid "Could not set the thread-local random generator up.\n"
-#~ msgstr ""
-#~ "Impossible d'initialiser le générateur de nombres aléatoires du fil.\n"
-
-#, c-format
-#~ msgid ""
-#~ "The random module has not been initialized. Please call "
-#~ "webid_oidc_random_init first.\n"
-#~ msgstr ""
-#~ "Le module aléatoire n'a pas été initialisé. Veuillez appeler "
-#~ "webid_oidc_random_init d'abort.\n"
-
-#, c-format
-#~ msgid "Usage: generate-random [NUMBER OF BYTES]\n"
-#~ msgstr "Utilisation : generate-random [NOMBRE D'OCTETS]\n"
-
-#, c-format
#~ msgid "Usage: generate-key [NUMBER OF BITS | CURVE]\n"
#~ msgstr "Utilisation : generate-key [NOMBRE DE BITS | COURBE]\n"
diff --git a/po/webid-oidc.pot b/po/webid-oidc.pot
index dc31531..4c608e8 100644
--- a/po/webid-oidc.pot
+++ b/po/webid-oidc.pot
@@ -17,10 +17,106 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: src/libwebidoidc.c:7
+#: src/libwebidoidc.c:8
msgid "This is the main function."
msgstr ""
+#: src/random/random.c:199
+#, c-format
+msgid "Could not set the global random generator up.\n"
+msgstr ""
+
+#: src/random/random.c:213 src/random/random.c:225 src/random/random.c:238
+#: src/random/random.c:249 src/random/random.c:260
+#, c-format
+msgid "Could not set the global random generator up: out of memory.\n"
+msgstr ""
+
+#: src/random/random.c:270
+#, c-format
+msgid ""
+"Warning: could not open the seed file, maybe the parent directory is "
+"missing...\n"
+msgstr ""
+
+#: src/random/random.c:274
+#, c-format
+msgid "Warning: could not create the cache directory '%s'.\n"
+msgstr ""
+
+#: src/random/random.c:276
+msgid "when creating the cache directory"
+msgstr ""
+
+#: src/random/random.c:282
+#, c-format
+msgid "Warning: could not create the package cache directory '%s'.\n"
+msgstr ""
+
+#: src/random/random.c:284
+msgid "when creating the package cache directory"
+msgstr ""
+
+#: src/random/random.c:290
+#, c-format
+msgid "Could not open the seed file '%s'.\n"
+msgstr ""
+
+#: src/random/random.c:291
+msgid "when opening the seed file"
+msgstr ""
+
+#: src/random/random.c:311
+#, c-format
+msgid "Could not lock the seed file '%s'.\n"
+msgstr ""
+
+#: src/random/random.c:313
+msgid "when locking the seed file"
+msgstr ""
+
+#: src/random/random.c:327
+#, c-format
+msgid ""
+"Warning: the seed file '%s' is too short. This weakens the random number "
+"generator. Please write more random data in it.\n"
+msgstr ""
+
+#: src/random/random.c:344
+#, c-format
+msgid "Could not update the seed file '%s'.\n"
+msgstr ""
+
+#: src/random/random.c:345
+msgid "when rewinding the seed file"
+msgstr ""
+
+#: src/random/random.c:377
+#, c-format
+msgid "Could not unlock the seed file '%s'.\n"
+msgstr ""
+
+#: src/random/random.c:379
+msgid "when unlocking the seed file"
+msgstr ""
+
+#: src/random/random.c:407
+#, c-format
+msgid "Could not set the thread-local random generator up.\n"
+msgstr ""
+
+#: src/random/random.c:415
+#, c-format
+msgid ""
+"The random module has not been initialized. Please call "
+"webid_oidc_random_init first.\n"
+msgstr ""
+
+#: src/random/generate-random.c:29
+#, c-format
+msgid "Usage: generate-random [NUMBER OF BYTES]\n"
+msgstr ""
+
#: src/scm/webid-oidc/errors.scm:35
msgid "that’s how it is"
msgstr ""
diff --git a/src/ChangeLog b/src/ChangeLog
index 75ed3d1..e2e9bea 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -3,3 +3,8 @@
* Makefile.am (%canon_reldir%_libwebidoidc_la_SOURCES): the common code is considered a source.
* utilities.h: Put the common code in that header.
+
+ * Makefile.am: build the "random" submodule.
+
+ * libwebidoidc.c (init_webidoidc): Initialize the "random" submodule.
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 93fbada..732a941 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,6 +24,7 @@ install_go_targets = install-webidoidcgoDATA
install_mod_targets = install-webidoidcmodDATA install-dist_webidoidcmodDATA
include %reldir%/base64/Makefile.am
+include %reldir%/random/Makefile.am
include %reldir%/pre-inst/Makefile.am
include %reldir%/inst/Makefile.am
include %reldir%/scm/Makefile.am
diff --git a/src/libwebidoidc.c b/src/libwebidoidc.c
index 09af3fd..af26ae0 100644
--- a/src/libwebidoidc.c
+++ b/src/libwebidoidc.c
@@ -1,9 +1,11 @@
#define N_(s)
void init_webidoidc_base64 (void);
+void init_webidoidc_random (void);
void
init_webidoidc (void)
{
N_("This is the main function.");
init_webidoidc_base64 ();
+ init_webidoidc_random ();
}
diff --git a/src/random/ChangeLog b/src/random/ChangeLog
new file mode 100644
index 0000000..b2a1cc3
--- /dev/null
+++ b/src/random/ChangeLog
@@ -0,0 +1,11 @@
+2020-11-26 Vivien Kraus <vivien@planete-kraus.eu>
+
+ * libwebidoidc-random.c: Fix the submodule to use the package name.
+ (fopen_cache_seed): Fix in this function.
+
+2020-11-25 Vivien Kraus <vivien@planete-kraus.eu>
+
+ * libwebidoidc-random.c: New submodule.
+
+ * generate-random.c: New program.
+
diff --git a/src/random/Makefile.am b/src/random/Makefile.am
new file mode 100644
index 0000000..fbd548c
--- /dev/null
+++ b/src/random/Makefile.am
@@ -0,0 +1,20 @@
+noinst_LTLIBRARIES += %reldir%/libwebidoidc-random.la
+noinst_PROGRAMS += %reldir%/generate-random
+EXTRA_DIST += %reldir%/libwebidoidc-random.x
+BUILT_SOURCES += %reldir%/libwebidoidc-random.x
+include_HEADERS += %reldir%/webid-oidc/random.h
+
+%canon_reldir%_libwebidoidc_random_la_LIBADD = $(GUILE_LIBS) $(NETTLE_LIBS)
+%canon_reldir%_libwebidoidc_random_la_SOURCES = \
+ %reldir%/libwebidoidc-random.c \
+ %reldir%/random.c \
+ %reldir%/webid-oidc/random.h
+%canon_reldir%_generate_random_LDADD = %reldir%/libwebidoidc-random.la $(GUILE_LIBS)
+
+AM_CFLAGS += -I %reldir% -I $(srcdir)/%reldir%
+
+INDENTED += \
+ %reldir%/generate-random.c \
+ $(%canon_reldir%_libwebidoidc_random_la_SOURCES)
+
+%reldir%/libwebidoidc-random.o: %reldir%/libwebidoidc-random.x
diff --git a/src/random/generate-random.c b/src/random/generate-random.c
new file mode 100644
index 0000000..bde01b9
--- /dev/null
+++ b/src/random/generate-random.c
@@ -0,0 +1,42 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libguile.h>
+#include <gettext.h>
+
+#define _(s) gettext (s)
+
+SCM webidoidc_random_g (SCM length);
+
+int init_webidoidc_random (void);
+
+static void
+run (void *params, int argc, char *argv[])
+{
+ size_t n_bytes;
+ char *end;
+ SCM data;
+ (void) params;
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+ if (argc != 2
+ || (n_bytes = strtoull (argv[1], &end, 10)) == 0 || *end != '\0')
+ {
+ fprintf (stderr, _("Usage: generate-random [NUMBER OF BYTES]\n"));
+ exit (1);
+ }
+ init_webidoidc_random ();
+ data = webidoidc_random_g (scm_from_size_t (n_bytes));
+ printf ("%s\n", scm_to_locale_string (data));
+}
+
+int
+main (int argc, char *argv[])
+{
+ scm_boot_guile (argc, argv, run, NULL);
+ return 0;
+}
diff --git a/src/random/libwebidoidc-random.c b/src/random/libwebidoidc-random.c
new file mode 100644
index 0000000..2bea9bb
--- /dev/null
+++ b/src/random/libwebidoidc-random.c
@@ -0,0 +1,35 @@
+#include <utilities.h>
+#include <threads.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <webid-oidc/random.h>
+
+#define _(s) dgettext (PACKAGE, s)
+
+/* Register "random", a guile function to generate random data. */
+void init_webidoidc_random (void);
+
+SCM_DEFINE (webidoidc_random_g, "random", 1, 0, 0, (SCM length),
+ "Get @var{length} random bytes, and encode them in a base64-url string.")
+{
+ size_t c_length = scm_to_size_t (length);
+ uint8_t *data = scm_gc_malloc_pointerless (c_length, "random data");
+ webid_oidc_random (c_length, data);
+ return wrap_bytevector (c_length, data);
+}
+
+SCM_DEFINE (webidoidc_random_init_g, "random-init!", 0, 0, 0, (void),
+ "Re-initialize the random number generator so that future threads are not predictable.")
+{
+ webid_oidc_random_init ();
+ return SCM_UNDEFINED;
+}
+
+void
+init_webidoidc_random (void)
+{
+ webid_oidc_random_init ();
+#ifndef SCM_MAGIC_SNARFER
+#include "libwebidoidc-random.x"
+#endif /* not SCM_MAGIC_SNARFER */
+}
diff --git a/src/random/random.c b/src/random/random.c
new file mode 100644
index 0000000..d5c45f5
--- /dev/null
+++ b/src/random/random.c
@@ -0,0 +1,423 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* not HAVE_CONFIG_H */
+
+#include <string.h>
+#include <nettle/yarrow.h>
+#include <threads.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <webid-oidc/random.h>
+#include <gettext.h>
+#define _(s) dgettext (PACKAGE, s)
+
+struct webid_oidc_random_context
+{
+ struct yarrow256_ctx ctx;
+ enum webid_oidc_random_context_spawn_flags flags;
+ enum webid_oidc_random_context_state state;
+ unsigned int state_progress;
+ uint8_t seed[YARROW256_SEED_FILE_SIZE];
+ mtx_t mutex;
+};
+
+struct webid_oidc_random_context *
+webid_oidc_random_context_alloc (void)
+{
+ struct webid_oidc_random_context *ret =
+ malloc (sizeof (struct webid_oidc_random_context));
+ if (ret && mtx_init (&(ret->mutex), mtx_plain) != thrd_success)
+ {
+ free (ret);
+ ret = NULL;
+ }
+ if (ret)
+ {
+ yarrow256_init (&(ret->ctx), 0, NULL);
+ ret->flags = 0;
+ ret->state = WEBID_OIDC_RANDOM_CONTEXT_WAIT_LOCK_FILE;
+ }
+ return ret;
+}
+
+void
+webid_oidc_random_context_free (struct webid_oidc_random_context *ctx)
+{
+ if (ctx)
+ {
+ mtx_destroy (&(ctx->mutex));
+ }
+ free (ctx);
+}
+
+enum webid_oidc_random_context_state
+webid_oidc_random_context_get_state (const struct webid_oidc_random_context
+ *ctx)
+{
+ return ctx->state;
+}
+
+int
+webid_oidc_random_context_get_wait_bytes (const struct
+ webid_oidc_random_context *ctx,
+ size_t max, size_t start,
+ uint8_t * bytes, size_t *n_bytes)
+{
+ if (ctx->state == WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_WRITE)
+ {
+ if (start >= YARROW256_SEED_FILE_SIZE)
+ {
+ *n_bytes = 0;
+ }
+ else
+ {
+ if (max + start > YARROW256_SEED_FILE_SIZE)
+ {
+ max = YARROW256_SEED_FILE_SIZE - start;
+ }
+ memcpy (bytes, ctx->seed + start, max);
+ *n_bytes = YARROW256_SEED_FILE_SIZE - start;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int
+webid_oidc_random_context_ok (struct webid_oidc_random_context *ctx)
+{
+ switch (ctx->state)
+ {
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_LOCK_FILE:
+ ctx->state = WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_READ;
+ ctx->state_progress = 0;
+ break;
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_WRITE:
+ ctx->state = WEBID_OIDC_RANDOM_CONTEXT_WAIT_UNLOCK_FILE;
+ break;
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_UNLOCK_FILE:
+ ctx->state = WEBID_OIDC_RANDOM_CONTEXT_READY;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+int
+webid_oidc_random_context_bytes (struct webid_oidc_random_context *ctx,
+ size_t n_bytes, const uint8_t * bytes)
+{
+ switch (ctx->state)
+ {
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_READ:
+ if (n_bytes >= (YARROW256_SEED_FILE_SIZE - ctx->state_progress))
+ {
+ n_bytes = (YARROW256_SEED_FILE_SIZE - ctx->state_progress);
+ }
+ memcpy (ctx->seed + ctx->state_progress, bytes, n_bytes);
+ ctx->state_progress += n_bytes;
+ if (ctx->state_progress == YARROW256_SEED_FILE_SIZE)
+ {
+ yarrow256_seed (&(ctx->ctx), YARROW256_SEED_FILE_SIZE, ctx->seed);
+ yarrow256_random (&(ctx->ctx), YARROW256_SEED_FILE_SIZE, ctx->seed);
+ ctx->state = WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_WRITE;
+ }
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+int
+webid_oidc_random_context_spawn (struct webid_oidc_random_context *parent,
+ struct webid_oidc_random_context *child,
+ enum webid_oidc_random_context_spawn_flags
+ flags)
+{
+ if (!webid_oidc_random_context_get
+ (parent, YARROW256_SEED_FILE_SIZE, child->seed))
+ {
+ return 0;
+ }
+ child->flags = flags;
+ child->state = WEBID_OIDC_RANDOM_CONTEXT_READY;
+ yarrow256_seed (&(child->ctx), YARROW256_SEED_FILE_SIZE, child->seed);
+ return 1;
+}
+
+int
+webid_oidc_random_context_get (struct webid_oidc_random_context *ctx,
+ size_t request_size, uint8_t * data)
+{
+ if (ctx->state == WEBID_OIDC_RANDOM_CONTEXT_READY)
+ {
+ if (!(ctx->flags & WEBID_OIDC_RANDOM_CONTEXT_THREAD_UNSAFE))
+ {
+ if (mtx_lock (&(ctx->mutex)) != thrd_success)
+ {
+ assert (0);
+ }
+ }
+ yarrow256_random (&(ctx->ctx), request_size, data);
+ if (!(ctx->flags & WEBID_OIDC_RANDOM_CONTEXT_THREAD_UNSAFE))
+ {
+ if (mtx_unlock (&(ctx->mutex)) != thrd_success)
+ {
+ assert (0);
+ }
+ }
+ }
+ return (ctx->state == WEBID_OIDC_RANDOM_CONTEXT_READY);
+}
+
+static struct webid_oidc_random_context *global_ctx = NULL;
+
+void
+webid_oidc_random_init (void)
+{
+ char *cache_dir, *pkg_cache_dir, *filename;
+ char *home = getenv ("HOME");
+ char *xdg_cache_home = getenv ("XDG_CACHE_HOME");
+ char *application = getenv ("WEBID_OIDC_APPLICATION_NAME");
+ static const char *default_application = PACKAGE;
+ FILE *seed_file;
+ FILE *system_rng_file;
+ struct flock lock;
+ if (global_ctx)
+ {
+ webid_oidc_random_context_free (global_ctx);
+ global_ctx = NULL;
+ }
+ global_ctx = webid_oidc_random_context_alloc ();
+ if (!global_ctx)
+ {
+ fprintf (stderr, _("Could not set the global random generator up.\n"));
+ abort ();
+ }
+ if (!application)
+ {
+ application = (char *) default_application;
+ }
+ if (xdg_cache_home)
+ {
+ cache_dir = malloc (strlen (xdg_cache_home) + 1);
+ if (!cache_dir)
+ {
+ fprintf (stderr,
+ _
+ ("Could not set the global random generator up: out of memory.\n"));
+ abort ();
+ }
+ strcpy (cache_dir, xdg_cache_home);
+ }
+ else if (home)
+ {
+ cache_dir = malloc (strlen (home) + strlen ("/.cache") + 1);
+ if (!cache_dir)
+ {
+ fprintf (stderr,
+ _
+ ("Could not set the global random generator up: out of memory.\n"));
+ abort ();
+ }
+ strcpy (cache_dir, home);
+ strcat (cache_dir, "/.cache");
+ }
+ else
+ {
+ cache_dir = malloc (strlen ("/var/cache") + 1);
+ if (!cache_dir)
+ {
+ fprintf (stderr,
+ _
+ ("Could not set the global random generator up: out of memory.\n"));
+ abort ();
+ }
+ strcpy (cache_dir, "/var/cache");
+ }
+ pkg_cache_dir = malloc (strlen (cache_dir)
+ + strlen ("/") + strlen (application) + 1);
+ if (!pkg_cache_dir)
+ {
+ fprintf (stderr,
+ _
+ ("Could not set the global random generator up: out of memory.\n"));
+ abort ();
+ }
+ strcpy (pkg_cache_dir, cache_dir);
+ strcat (pkg_cache_dir, "/");
+ strcat (pkg_cache_dir, application);
+ filename = malloc (strlen (pkg_cache_dir) + strlen ("/seed") + 1);
+ if (!filename)
+ {
+ fprintf (stderr,
+ _
+ ("Could not set the global random generator up: out of memory.\n"));
+ abort ();
+ }
+ strcpy (filename, pkg_cache_dir);
+ strcat (filename, "/seed");
+ seed_file = fopen (filename, "r+");
+ if (!seed_file)
+ {
+ fprintf (stderr,
+ _
+ ("Warning: could not open the seed file, maybe the parent directory is missing...\n"));
+ if (mkdir (cache_dir, 0777) != 0)
+ {
+ fprintf (stderr,
+ _("Warning: could not create the cache directory '%s'.\n"),
+ cache_dir);
+ perror (_("when creating the cache directory"));
+ }
+ if (mkdir (pkg_cache_dir, 0777) != 0)
+ {
+ fprintf (stderr,
+ _
+ ("Warning: could not create the package cache directory '%s'.\n"),
+ pkg_cache_dir);
+ perror (_("when creating the package cache directory"));
+ }
+ seed_file = fopen (filename, "w+");
+ }
+ if (!seed_file)
+ {
+ fprintf (stderr, _("Could not open the seed file '%s'.\n"), filename);
+ perror (_("when opening the seed file"));
+ abort ();
+ }
+ system_rng_file = fopen ("/dev/random", "r");
+ while (global_ctx->state != WEBID_OIDC_RANDOM_CONTEXT_READY)
+ {
+ int error;
+ int c;
+ uint8_t byte = 0;
+ size_t i, n;
+ switch (global_ctx->state)
+ {
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_LOCK_FILE:
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ error = fcntl (fileno (seed_file), F_SETLKW, &lock);
+ if (error != 0)
+ {
+ fprintf (stderr, _("Could not lock the seed file '%s'.\n"),
+ filename);
+ perror (_("when locking the seed file"));
+ abort ();
+ }
+ if (!webid_oidc_random_context_ok (global_ctx))
+ {
+ assert (0);
+ }
+ break;
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_READ:
+ c = fgetc (seed_file);
+ if (c == EOF && system_rng_file == NULL)
+ {
+ fprintf (stderr,
+ _
+ ("Warning: the seed file '%s' is too short. This weakens the random number generator. Please write more random data in it.\n"),
+ filename);
+ }
+ else if (c == EOF)
+ {
+ c = fgetc (system_rng_file);
+ }
+ byte = c;
+ if (!webid_oidc_random_context_bytes (global_ctx, 1, &byte))
+ {
+ assert (0);
+ }
+ break;
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_WRITE:
+ if (fseek (seed_file, 0, SEEK_SET) != 0)
+ {
+ fprintf (stderr,
+ _("Could not update the seed file '%s'.\n"), filename);
+ perror (_("when rewinding the seed file"));
+ abort ();
+ }
+ if (!webid_oidc_random_context_get_wait_bytes
+ (global_ctx, 0, 0, NULL, &n))
+ {
+ assert (0);
+ }
+ for (i = 0; i < n; i++)
+ {
+ size_t remaining;
+ if (!webid_oidc_random_context_get_wait_bytes
+ (global_ctx, 1, i, &byte, &remaining))
+ {
+ assert (0);
+ }
+ assert (i + remaining == n);
+ fputc (byte, seed_file);
+ }
+ if (!webid_oidc_random_context_ok (global_ctx))
+ {
+ assert (0);
+ }
+ break;
+ case WEBID_OIDC_RANDOM_CONTEXT_WAIT_UNLOCK_FILE:
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ error = fcntl (fileno (seed_file), F_SETLKW, &lock);
+ if (error != 0)
+ {
+ fprintf (stderr, _("Could not unlock the seed file '%s'.\n"),
+ filename);
+ perror (_("when unlocking the seed file"));
+ abort ();
+ }
+ if (!webid_oidc_random_context_ok (global_ctx))
+ {
+ assert (0);
+ }
+ break;
+ default:
+ assert (0);
+ }
+ }
+ fclose (seed_file);
+ fclose (system_rng_file);
+}
+
+void
+webid_oidc_random (size_t request_size, uint8_t * data)
+{
+ static _Thread_local struct webid_oidc_random_context *thrd_ctx = NULL;
+ if (thrd_ctx == NULL)
+ {
+ assert (global_ctx);
+ thrd_ctx = webid_oidc_random_context_alloc ();
+ if (thrd_ctx == NULL)
+ {
+ fprintf (stderr,
+ _
+ ("Could not set the thread-local random generator up.\n"));
+ abort ();
+ }
+ if (!webid_oidc_random_context_spawn
+ (global_ctx, thrd_ctx, WEBID_OIDC_RANDOM_CONTEXT_THREAD_UNSAFE))
+ {
+ fprintf (stderr,
+ _
+ ("The random module has not been initialized. Please call webid_oidc_random_init first.\n"));
+ abort ();
+ }
+ }
+ if (!webid_oidc_random_context_get (thrd_ctx, request_size, data))
+ {
+ assert (0);
+ }
+}
diff --git a/src/random/webid-oidc/random.h b/src/random/webid-oidc/random.h
new file mode 100644
index 0000000..ae1adfc
--- /dev/null
+++ b/src/random/webid-oidc/random.h
@@ -0,0 +1,57 @@
+#ifndef H_RANDOM_INCLUDED
+#define H_RANDOM_INCLUDED
+
+struct webid_oidc_random_context;
+typedef struct webid_oidc_random_context webid_oidc_random_context;
+
+/* These functions allocate data, they are not reentrant. */
+struct webid_oidc_random_context *webid_oidc_random_context_alloc (void);
+void webid_oidc_random_context_free (struct webid_oidc_random_context *ctx);
+
+enum webid_oidc_random_context_state
+{
+ WEBID_OIDC_RANDOM_CONTEXT_READY = 0,
+ WEBID_OIDC_RANDOM_CONTEXT_WAIT_LOCK_FILE,
+ WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_READ,
+ WEBID_OIDC_RANDOM_CONTEXT_WAIT_FILE_WRITE,
+ WEBID_OIDC_RANDOM_CONTEXT_WAIT_UNLOCK_FILE
+};
+
+typedef enum webid_oidc_random_context_state webid_oidc_random_context_state;
+
+enum webid_oidc_random_context_state
+webid_oidc_random_context_get_state (const struct webid_oidc_random_context
+ *ctx);
+int webid_oidc_random_context_get_wait_bytes (const struct
+ webid_oidc_random_context *ctx,
+ size_t max, size_t start,
+ uint8_t * bytes,
+ size_t *n_bytes);
+int webid_oidc_random_context_ok (struct webid_oidc_random_context *ctx);
+int webid_oidc_random_context_bytes (struct webid_oidc_random_context *ctx,
+ size_t n_bytes, const uint8_t * bytes);
+
+enum webid_oidc_random_context_spawn_flags
+{
+ WEBID_OIDC_RANDOM_CONTEXT_THREAD_UNSAFE = 1
+};
+typedef enum webid_oidc_random_context_spawn_flags
+ webid_oidc_random_context_spawn_flags;
+
+int webid_oidc_random_context_spawn (struct webid_oidc_random_context *parent,
+ struct webid_oidc_random_context *child,
+ enum
+ webid_oidc_random_context_spawn_flags
+ flags);
+
+int webid_oidc_random_context_get (struct webid_oidc_random_context *ctx,
+ size_t request_size, uint8_t * data);
+
+/* These functions set up and use a global state. Neither are
+ reentrant. */
+void webid_oidc_random_init (void);
+
+/* This function is thread-safe. */
+void webid_oidc_random (size_t request_size, uint8_t * data);
+
+#endif /* not H_RANDOM_INCLUDED */
diff --git a/src/scm/webid-oidc/stubs.scm b/src/scm/webid-oidc/stubs.scm
index 12006e6..b022ef2 100644
--- a/src/scm/webid-oidc/stubs.scm
+++ b/src/scm/webid-oidc/stubs.scm
@@ -15,4 +15,6 @@
(export
base64-encode
- (fix-base64-decode . base64-decode))
+ (fix-base64-decode . base64-decode)
+ random
+ random-init!)
diff --git a/src/scm/webid-oidc/testing.scm b/src/scm/webid-oidc/testing.scm
index 40284cf..d4b7f4d 100644
--- a/src/scm/webid-oidc/testing.scm
+++ b/src/scm/webid-oidc/testing.scm
@@ -24,4 +24,5 @@
(error->str error))
(raise-exception error))
(lambda ()
+ (random-init!)
(f))))
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 12699f9..7efc3d1 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,12 +1,19 @@
-TESTS = \
- %reldir%/load-library.scm \
+TESTS = %reldir%/load-library.scm \
%reldir%/base64-ok.scm \
- %reldir%/base64-error.scm
+ %reldir%/base64-error.scm \
+ %reldir%/random.scm
EXTRA_DIST += $(TESTS)
TEST_EXTENSIONS = .scm
+.PHONY: %canon_reldir%-clean-local
+
+clean-local: %canon_reldir%-clean-local
+
+%canon_reldir%-clean-local:
+ rm -rf %reldir%/*.cache
+
AM_TESTS_ENVIRONMENT = $(top_builddir)/pre-inst-env
SCM_LOG_COMPILER = $(GUILE)
AM_SCM_LOG_FLAGS = --no-auto-compile -s
diff --git a/tests/random.scm b/tests/random.scm
new file mode 100644
index 0000000..9b85b15
--- /dev/null
+++ b/tests/random.scm
@@ -0,0 +1,17 @@
+(use-modules (webid-oidc stubs)
+ (webid-oidc testing))
+
+(with-test-environment
+ "random"
+ (lambda ()
+ (let ((data (random 12))
+ (expected "68OMG_V5x-KmI6TI"))
+ (unless (string=? data expected)
+ (format (current-error-port)
+ "Non-reproducibility issue with the random number generator:
+expected: ~a
+obtained: ~a
+"
+ expected
+ data)
+ (exit 1)))))