summaryrefslogtreecommitdiff
path: root/src/jwk
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-19 15:44:24 +0200
commitfbdb021dc275080f1e817317306defc354828715 (patch)
tree6b7df45e448ed296958b97178d5c11222dc4c9d8 /src/jwk
parentc54ad2f70f705a62946fb93902f9a9bd65ae1fed (diff)
Generate a key pair.
Diffstat (limited to 'src/jwk')
-rw-r--r--src/jwk/ChangeLog8
-rw-r--r--src/jwk/Makefile.am13
-rw-r--r--src/jwk/generate-key.c59
-rw-r--r--src/jwk/libwebidoidc-jwk.c118
4 files changed, 198 insertions, 0 deletions
diff --git a/src/jwk/ChangeLog b/src/jwk/ChangeLog
new file mode 100644
index 0000000..10e590f
--- /dev/null
+++ b/src/jwk/ChangeLog
@@ -0,0 +1,8 @@
+2020-11-25 Vivien Kraus <vivien@planete-kraus.eu>
+
+ * libwebidoidc-jwk.c: new file.
+
+ * generate-key.c: new file.
+
+ * Makefile.am: new file.
+
diff --git a/src/jwk/Makefile.am b/src/jwk/Makefile.am
new file mode 100644
index 0000000..686f450
--- /dev/null
+++ b/src/jwk/Makefile.am
@@ -0,0 +1,13 @@
+noinst_LTLIBRARIES += %reldir%/libwebidoidc-jwk.la
+noinst_PROGRAMS += %reldir%/generate-key
+EXTRA_DIST += %reldir%/libwebidoidc-jwk.x
+BUILT_SOURCES += %reldir%/libwebidoidc-jwk.x
+
+%canon_reldir%_libwebidoidc_jwk_la_LIBADD = $(GUILE_LIBS) $(NETTLE_LIBS) $(HOGWEED_LIBS)
+%canon_reldir%_generate_key_LDADD = src/libwebidoidc.la $(GUILE_LIBS)
+
+AM_CFLAGS += -I %reldir% -I $(srcdir)/%reldir%
+
+INDENTED += %reldir%/libwebidoidc-jwk.c %reldir%/generate-key.c
+
+%reldir%/libwebidoidc-jwk.o: %reldir%/libwebidoidc-jwk.x
diff --git a/src/jwk/generate-key.c b/src/jwk/generate-key.c
new file mode 100644
index 0000000..ec8ce76
--- /dev/null
+++ b/src/jwk/generate-key.c
@@ -0,0 +1,59 @@
+#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_generate_key_g (SCM args);
+
+extern int init_webidoidc (void);
+
+static void
+run (void *params, int argc, char *argv[])
+{
+ SCM data;
+ char *end;
+ size_t n_size = 0;
+ (void) params;
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+ if (argc != 2
+ || (strcmp (argv[1], "P-256") != 0
+ && strcmp (argv[1], "P-384") != 0
+ && strcmp (argv[1], "P-521") != 0
+ && ((n_size = strtoull (argv[1], &end, 10)) == 0 || *end != '\0')))
+ {
+ fprintf (stderr, _("Usage: generate-key [NUMBER OF BITS | CURVE]\n"));
+ exit (1);
+ }
+ init_webidoidc ();
+ if (strcmp (argv[1], "P-256") == 0
+ || strcmp (argv[1], "P-384") == 0 || strcmp (argv[1], "P-521") == 0)
+ {
+ data =
+ webidoidc_generate_key_g (scm_list_2
+ (scm_from_utf8_keyword ("crv"),
+ scm_from_utf8_symbol (argv[1])));
+ }
+ else
+ {
+ data =
+ webidoidc_generate_key_g (scm_list_2
+ (scm_from_utf8_keyword ("n-size"),
+ scm_from_size_t (n_size)));
+ }
+ scm_display (data, scm_current_output_port ());
+}
+
+int
+main (int argc, char *argv[])
+{
+ scm_boot_guile (argc, argv, run, NULL);
+ return 0;
+}
diff --git a/src/jwk/libwebidoidc-jwk.c b/src/jwk/libwebidoidc-jwk.c
new file mode 100644
index 0000000..85386fb
--- /dev/null
+++ b/src/jwk/libwebidoidc-jwk.c
@@ -0,0 +1,118 @@
+#include <utilities.h>
+
+#define _(s) dgettext (PACKAGE, s)
+
+void webid_oidc_random (size_t len, uint8_t * dst);
+
+/* Register "generate-key", a guile function to generate a keypair. */
+void init_webidoidc_jwk (void);
+
+SCM_KEYWORD (kw_crv, "crv");
+SCM_KEYWORD (kw_e, "e");
+SCM_KEYWORD (kw_n_size, "n-size");
+SCM_KEYWORD (kw_e_size, "e-size");
+
+SCM_SYMBOL (kty_ec, "EC");
+SCM_SYMBOL (kty_rsa, "RSA");
+
+SCM_SYMBOL (unsupported_kty, "unsupported-kty");
+SCM_SYMBOL (unsupported_crv, "unsupported-crv");
+SCM_SYMBOL (invalid_parameters, "invalid-parameters");
+SCM_SYMBOL (base64_decoding_error, "base64-decoding-error");
+
+/* Required for utilities.h */
+SCM_SYMBOL (p256, "P-256");
+SCM_SYMBOL (p384, "P-384");
+SCM_SYMBOL (p521, "P-521");
+SCM_SYMBOL (kcrv, "crv");
+SCM_SYMBOL (kx, "x");
+SCM_SYMBOL (ky, "y");
+SCM_SYMBOL (kd, "d");
+SCM_SYMBOL (kn, "n");
+SCM_SYMBOL (ke, "e");
+SCM_SYMBOL (kp, "p");
+SCM_SYMBOL (kq, "q");
+SCM_SYMBOL (kdp, "dp");
+SCM_SYMBOL (kdq, "dq");
+SCM_SYMBOL (kqi, "qi");
+
+SCM_SYMBOL (kkty, "kty");
+
+static void
+generate_random (void *unused, size_t len, uint8_t * dst)
+{
+ (void) unused;
+ webid_oidc_random (len, dst);
+}
+
+SCM_DEFINE (webidoidc_generate_key_g, "generate-key", 0, 0, 1, (SCM rest),
+ "Generate a key pair. The parameters are passed as keyword arguments: @code{#:crv}, @code{#:n-size}, @code{#:e} or @code{#:e-size}. Return an alist of the parameters. If @code{#:crv} is specified, generate an EC key pair using the curve, @code{'P-256}, @code{'P-384} or @code{'P-521}. If @code{#:n-size} is specified, generate an RSA key pair that many bits long. Otherwise, this is an error. If @code{#:e} is set, use that for the exponent instead of AQAB. If @code{#:e-size} is set, generate the exponent that many bits long.")
+{
+ SCM crv = SCM_UNDEFINED;
+ SCM n_size = SCM_UNDEFINED;
+ SCM e_size = scm_from_int (0);
+ SCM e = scm_from_utf8_string ("AQAB");
+ const struct ecc_curve *c_crv = NULL;
+ SCM ret = SCM_EOL;
+ scm_c_bind_keyword_arguments ("generate-key", rest, 0,
+ kw_crv, &crv,
+ kw_n_size, &n_size,
+ kw_e_size, &e_size, kw_e, &e, SCM_UNDEFINED);
+ if (!SCM_UNBNDP (crv))
+ {
+ c_crv = do_ecc_curve_load (crv, 1);
+ }
+ else if (!SCM_UNBNDP (n_size))
+ {
+ /* This is a RSA key pair */
+ }
+ else
+ {
+ scm_throw (unsupported_kty, SCM_EOL);
+ }
+ if (c_crv)
+ {
+ struct ecc_point c_point;
+ struct ecc_scalar c_scalar;
+ scm_dynwind_begin (0);
+ ecc_point_init (&c_point, c_crv);
+ dynwind_ecc_point_clear (&c_point);
+ ecc_scalar_init (&c_scalar, c_crv);
+ dynwind_ecc_scalar_clear (&c_scalar);
+ ecdsa_generate_keypair (&c_point, &c_scalar, NULL, generate_random);
+ ret = wrap_ecc_key_pair (c_crv, &c_point, &c_scalar);
+ scm_dynwind_end ();
+ }
+ else
+ {
+ struct rsa_public_key c_pub;
+ struct rsa_private_key c_key;
+ scm_dynwind_begin (0);
+ rsa_public_key_init (&c_pub);
+ dynwind_rsa_public_key_clear (&c_pub);
+ rsa_private_key_init (&c_key);
+ dynwind_rsa_private_key_clear (&c_key);
+ do_mpz_t_load (c_pub.e, e, 1);
+ if (rsa_generate_keypair (&c_pub, &c_key,
+ NULL, &generate_random,
+ NULL, NULL,
+ scm_to_uint (n_size), scm_to_uint (e_size)))
+ {
+ ret = wrap_rsa_key_pair (&c_pub, &c_key);;
+ }
+ else
+ {
+ scm_throw (invalid_parameters, scm_list_3 (n_size, e_size, e));
+ }
+ scm_dynwind_end ();
+ }
+ return ret;
+}
+
+void
+init_webidoidc_jwk (void)
+{
+#ifndef SCM_MAGIC_SNARFER
+#include "libwebidoidc-jwk.x"
+#endif /* not SCM_MAGIC_SNARFER */
+}