summaryrefslogtreecommitdiff
path: root/src/jwk/libwebidoidc-jwk.c
blob: 85386fb7e361ea31c35129f4f701975a97670381 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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 */
}