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:11:10 +0200
commitf8aefcf31ab49c063578190ee7f4a2721e5dc035 (patch)
treebb315506a1f63bee0437730a69029fcf4f1fee51
parent9ee1ca828e262553b68269e662f04252416b559e (diff)
Add a strip function
-rw-r--r--ChangeLog1
-rw-r--r--NEWS3
-rw-r--r--doc/webid-oidc.texi15
-rw-r--r--po/fr.po53
-rw-r--r--po/webid-oidc.pot41
-rw-r--r--src/jwk/ChangeLog7
-rw-r--r--src/jwk/libwebidoidc-jwk.c64
-rw-r--r--src/scm/webid-oidc/errors.scm34
-rw-r--r--src/scm/webid-oidc/stubs.scm21
-rw-r--r--src/utilities.h61
-rw-r--r--tests/Makefile.am6
-rw-r--r--tests/jwk-kty-ec-correct.scm15
-rw-r--r--tests/jwk-kty-ec-incorrect.scm23
-rw-r--r--tests/jwk-kty-rsa-correct.scm10
-rw-r--r--tests/jwk-kty-rsa-incorrect.scm18
15 files changed, 329 insertions, 43 deletions
diff --git a/ChangeLog b/ChangeLog
index 484f88a..c6aa356 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -14,6 +14,7 @@
* NEWS (A random number generator): Update NEWS
(Generating a key pair): Update NEWS
+ (Strip a public key): Update NEWS
2020-11-22 Vivien Kraus <vivien@planete-kraus.eu>
diff --git a/NEWS b/NEWS
index 9a99d63..5850dcd 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,9 @@
The code provides a thread-safe, parallel, random number generator.
** Generating a key pair
There is a function to generate a RSA or ECC key pair.
+** Strip a public key
+In order to avoid leaking the private components of a key, the
+=strip-key= function keeps only the required parts.
# Local Variables:
# mode: org
diff --git a/doc/webid-oidc.texi b/doc/webid-oidc.texi
index d63fc09..0a368e4 100644
--- a/doc/webid-oidc.texi
+++ b/doc/webid-oidc.texi
@@ -123,6 +123,7 @@ Return a string explaining the @var{error}. You can limit the
@menu
* Invalid data format::
+* Invalid JWT::
@end menu
@node Invalid data format
@@ -136,6 +137,20 @@ failed. @var{value} is the incorrect input, and @var{cause} is a
low-level error.
@end deftp
+@node Invalid JWT
+@section Invalid JWT
+Each JWT type – access token, DPoP proof, ID token, authorization code
+(this is internal to the identity provider) has different validation
+rules, and can fail in different ways.
+
+@deftp {exception type} &unsupported-crv @var{crv}
+The identifier @var{crv} does not identify an elliptic curve.
+@end deftp
+
+@deftp {exception type} &not-a-jwk @var{value} @var{cause}
+@var{value} does not identify a JWK.
+@end deftp
+
@node GNU Free Documentation License
@appendix GNU Free Documentation License
diff --git a/po/fr.po b/po/fr.po
index f075033..742edbb 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: webid-oidc 0.0.0\n"
"Report-Msgid-Bugs-To: vivien@planete-kraus.eu\n"
-"POT-Creation-Date: 2021-06-05 16:10+0200\n"
+"POT-Creation-Date: 2021-06-05 16:11+0200\n"
"PO-Revision-Date: 2021-06-05 11:07+0200\n"
"Last-Translator: Vivien Kraus <vivien@planete-kraus.eu>\n"
"Language-Team: French <vivien@planete-kraus.eu>\n"
@@ -126,58 +126,73 @@ msgstr "Utilisation : generate-random [NOMBRE D'OCTETS]\n"
msgid "Usage: generate-key [NUMBER OF BITS | CURVE]\n"
msgstr "Utilisation : generate-key [NOMBRE DE BITS | COURBE]\n"
-#: src/scm/webid-oidc/errors.scm:45
+#: src/scm/webid-oidc/errors.scm:65
msgid "that’s how it is"
msgstr "c’est comme ça"
-#: src/scm/webid-oidc/errors.scm:50
+#: src/scm/webid-oidc/errors.scm:70
#, scheme-format
msgid "the value ~s is not a base64 string (because ~a)"
msgstr "la valeur ~s n’est pas une chaîne base64 (parce que ~a)"
-#: src/scm/webid-oidc/errors.scm:53
+#: src/scm/webid-oidc/errors.scm:73
#, scheme-format
msgid "the value ~s is not JSON (because ~a)"
msgstr "la valeur ~s n’est pas du JSON (parce que ~a)"
-#: src/scm/webid-oidc/errors.scm:58
+#: src/scm/webid-oidc/errors.scm:76
+#, scheme-format
+msgid "the value ~s does not identify an elleptic curve"
+msgstr "la valeur ~s n’identifie pas une courbe elliptique"
+
+#: src/scm/webid-oidc/errors.scm:81
+#, scheme-format
+msgid "the value ~s does not identify a JWK (because ~a)"
+msgstr "la valeur ~s n’identifie pas une JWK (parce que ~a)"
+
+#: src/scm/webid-oidc/errors.scm:83
+#, scheme-format
+msgid "the value ~s does not identify a JWK"
+msgstr "la valeur ~s n’identifie pas une JWK"
+
+#: src/scm/webid-oidc/errors.scm:88
msgid "that’s it"
msgstr "c’est tout"
-#: src/scm/webid-oidc/errors.scm:62
+#: src/scm/webid-oidc/errors.scm:92
#, scheme-format
msgid "~a and ~a"
msgstr "~a et ~a"
-#: src/scm/webid-oidc/errors.scm:65
+#: src/scm/webid-oidc/errors.scm:95
#, scheme-format
msgid "~a, ~a"
msgstr "~a, ~a"
-#: src/scm/webid-oidc/errors.scm:69
+#: src/scm/webid-oidc/errors.scm:99
msgid "there is an undefined variable"
msgstr "il y a une variable non définie"
-#: src/scm/webid-oidc/errors.scm:71
+#: src/scm/webid-oidc/errors.scm:101
#, scheme-format
msgid "the origin is ~a"
msgstr "l’origine est ~a"
-#: src/scm/webid-oidc/errors.scm:74
+#: src/scm/webid-oidc/errors.scm:104
#, scheme-format
msgid "a message is attached: ~a"
msgstr "un message est attaché : ~a"
-#: src/scm/webid-oidc/errors.scm:77
+#: src/scm/webid-oidc/errors.scm:107
#, scheme-format
msgid "the values ~s are problematic"
msgstr "les valeurs ~s sont problématiques"
-#: src/scm/webid-oidc/errors.scm:80
+#: src/scm/webid-oidc/errors.scm:110
msgid "there is a kind and args"
msgstr "il y a un type et des arguments"
-#: src/scm/webid-oidc/errors.scm:82
+#: src/scm/webid-oidc/errors.scm:112
#, scheme-format
msgid "Unhandled exception type ~a."
msgstr "Type d’exception non pris en charge ~a."
@@ -187,18 +202,6 @@ msgstr "Type d’exception non pris en charge ~a."
#~ msgstr "la valeur ~s n’est pas du Turtle (parce que ~a)"
#, scheme-format
-#~ msgid "the value ~s does not identify an elleptic curve"
-#~ msgstr "la valeur ~s n’identifie pas une courbe elliptique"
-
-#, scheme-format
-#~ msgid "the value ~s does not identify a JWK (because ~a)"
-#~ msgstr "la valeur ~s n’identifie pas une JWK (parce que ~a)"
-
-#, scheme-format
-#~ msgid "the value ~s does not identify a JWK"
-#~ msgstr "la valeur ~s n’identifie pas une JWK"
-
-#, scheme-format
#~ msgid "the value ~s does not identify a public JWK (because ~a)"
#~ msgstr "la valeur ~s n’identifie pas une JWK publique (parce que ~a)"
diff --git a/po/webid-oidc.pot b/po/webid-oidc.pot
index 16dcfab..21b0d57 100644
--- a/po/webid-oidc.pot
+++ b/po/webid-oidc.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: webid-oidc SNAPSHOT\n"
"Report-Msgid-Bugs-To: vivien@planete-kraus.eu\n"
-"POT-Creation-Date: 2021-06-05 16:10+0200\n"
+"POT-Creation-Date: 2021-06-05 16:11+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -122,58 +122,73 @@ msgstr ""
msgid "Usage: generate-key [NUMBER OF BITS | CURVE]\n"
msgstr ""
-#: src/scm/webid-oidc/errors.scm:45
+#: src/scm/webid-oidc/errors.scm:65
msgid "that’s how it is"
msgstr ""
-#: src/scm/webid-oidc/errors.scm:50
+#: src/scm/webid-oidc/errors.scm:70
#, scheme-format
msgid "the value ~s is not a base64 string (because ~a)"
msgstr ""
-#: src/scm/webid-oidc/errors.scm:53
+#: src/scm/webid-oidc/errors.scm:73
#, scheme-format
msgid "the value ~s is not JSON (because ~a)"
msgstr ""
-#: src/scm/webid-oidc/errors.scm:58
+#: src/scm/webid-oidc/errors.scm:76
+#, scheme-format
+msgid "the value ~s does not identify an elleptic curve"
+msgstr ""
+
+#: src/scm/webid-oidc/errors.scm:81
+#, scheme-format
+msgid "the value ~s does not identify a JWK (because ~a)"
+msgstr ""
+
+#: src/scm/webid-oidc/errors.scm:83
+#, scheme-format
+msgid "the value ~s does not identify a JWK"
+msgstr ""
+
+#: src/scm/webid-oidc/errors.scm:88
msgid "that’s it"
msgstr ""
-#: src/scm/webid-oidc/errors.scm:62
+#: src/scm/webid-oidc/errors.scm:92
#, scheme-format
msgid "~a and ~a"
msgstr ""
-#: src/scm/webid-oidc/errors.scm:65
+#: src/scm/webid-oidc/errors.scm:95
#, scheme-format
msgid "~a, ~a"
msgstr ""
-#: src/scm/webid-oidc/errors.scm:69
+#: src/scm/webid-oidc/errors.scm:99
msgid "there is an undefined variable"
msgstr ""
-#: src/scm/webid-oidc/errors.scm:71
+#: src/scm/webid-oidc/errors.scm:101
#, scheme-format
msgid "the origin is ~a"
msgstr ""
-#: src/scm/webid-oidc/errors.scm:74
+#: src/scm/webid-oidc/errors.scm:104
#, scheme-format
msgid "a message is attached: ~a"
msgstr ""
-#: src/scm/webid-oidc/errors.scm:77
+#: src/scm/webid-oidc/errors.scm:107
#, scheme-format
msgid "the values ~s are problematic"
msgstr ""
-#: src/scm/webid-oidc/errors.scm:80
+#: src/scm/webid-oidc/errors.scm:110
msgid "there is a kind and args"
msgstr ""
-#: src/scm/webid-oidc/errors.scm:82
+#: src/scm/webid-oidc/errors.scm:112
#, scheme-format
msgid "Unhandled exception type ~a."
msgstr ""
diff --git a/src/jwk/ChangeLog b/src/jwk/ChangeLog
index 10e590f..ebd0873 100644
--- a/src/jwk/ChangeLog
+++ b/src/jwk/ChangeLog
@@ -1,6 +1,13 @@
+2020-11-28 Vivien Kraus <vivien@planete-kraus.eu>
+
+ * libwebidoidc-jwk.c (webidoidc_kty_g): check that we can load the
+ key before telling its kty, so that if the point is not on the
+ curve it is not an EC point.
+
2020-11-25 Vivien Kraus <vivien@planete-kraus.eu>
* libwebidoidc-jwk.c: new file.
+ Add the strip function.
* generate-key.c: new file.
diff --git a/src/jwk/libwebidoidc-jwk.c b/src/jwk/libwebidoidc-jwk.c
index 85386fb..84da5da 100644
--- a/src/jwk/libwebidoidc-jwk.c
+++ b/src/jwk/libwebidoidc-jwk.c
@@ -109,6 +109,70 @@ SCM_DEFINE (webidoidc_generate_key_g, "generate-key", 0, 0, 1, (SCM rest),
return ret;
}
+SCM_DEFINE (webidoidc_kty_g, "kty", 1, 0, 0, (SCM key),
+ "Return the type of @var{key}, @code{'EC} or @code{'RSA}. Return @code{#f} if this is not a JWK.")
+{
+ SCM crv = scm_assq_ref (key, kcrv);
+ const struct ecc_curve *c_crv = NULL;
+ struct ecc_point c_point;
+ struct ecc_scalar c_scalar;
+ struct rsa_public_key c_pub;
+ struct rsa_private_key c_key;
+ SCM ret = SCM_BOOL_F;
+ if (scm_is_true (crv))
+ {
+ c_crv = do_ecc_curve_load (crv, 0);
+ }
+ scm_dynwind_begin (0);
+ if (c_crv)
+ {
+ 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);
+ }
+ 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);
+ if (c_crv
+ && (do_ecc_point_load (&c_point, key)
+ || do_ecc_scalar_load (&c_scalar, key)))
+ {
+ ret = kty_ec;
+ }
+ else if (do_rsa_public_key_load (&c_pub, key)
+ || do_rsa_private_key_load (&c_key, key))
+ {
+ ret = kty_rsa;
+ }
+ scm_dynwind_end ();
+ return ret;
+}
+
+SCM_DEFINE (webidoidc_strip_key_g, "strip-key", 1, 0, 0, (SCM key),
+ "Strip a JWK, keeping only the parts that are required for a public key. The fields are sorted aphabetically.")
+{
+ SCM kty = webidoidc_kty_g (key);
+ SCM crv = scm_assq_ref (key, kcrv);
+ SCM x = scm_assq_ref (key, kx);
+ SCM y = scm_assq_ref (key, ky);
+ SCM n = scm_assq_ref (key, kn);
+ SCM e = scm_assq_ref (key, ke);
+ if (scm_is_eq (kty, kty_ec))
+ {
+ return scm_list_4 (scm_cons (kcrv, crv),
+ scm_cons (kkty, kty_ec),
+ scm_cons (kx, x), scm_cons (ky, y));
+ }
+ if (scm_is_eq (kty, kty_rsa))
+ {
+ return scm_list_3 (scm_cons (ke, e),
+ scm_cons (kkty, kty_rsa), scm_cons (kn, n));
+ }
+ scm_throw (unsupported_kty, scm_list_1 (key));
+}
+
void
init_webidoidc_jwk (void)
{
diff --git a/src/scm/webid-oidc/errors.scm b/src/scm/webid-oidc/errors.scm
index 9d08ed5..27dc6e2 100644
--- a/src/scm/webid-oidc/errors.scm
+++ b/src/scm/webid-oidc/errors.scm
@@ -26,7 +26,7 @@
(define-public &not-json
(make-exception-type
- 'not-json
+ '&not-json
&external-error
'(value cause)))
@@ -34,6 +34,26 @@
(raise-exception
((record-constructor &not-json) value cause)))
+(define-public &unsupported-crv
+ (make-exception-type
+ '&unsupported-crv
+ &external-error
+ '(crv)))
+
+(define-public (raise-unsupported-crv crv)
+ (raise-exception
+ ((record-constructor &unsupported-crv) crv)))
+
+(define-public &not-a-jwk
+ (make-exception-type
+ '&not-a-jwk
+ &external-error
+ '(value cause)))
+
+(define-public (raise-not-a-jwk value cause)
+ (raise-exception
+ ((record-constructor &not-a-jwk) value cause)))
+
(define*-public (error->str err #:key (max-depth #f))
(if (record? err)
(let* ((type (record-type-descriptor err))
@@ -49,9 +69,19 @@
((&not-base64)
(format #f (G_ "the value ~s is not a base64 string (because ~a)")
(get 'value) (recurse (get 'cause))))
- ((not-json)
+ ((&not-json)
(format #f (G_ "the value ~s is not JSON (because ~a)")
(get 'value) (recurse (get 'cause))))
+ ((&unsupported-crv)
+ (format #f (G_ "the value ~s does not identify an elleptic curve")
+ (get 'crv)))
+ ((&not-a-jwk)
+ (let ((cause (get 'cause)))
+ (if cause
+ (format #f (G_ "the value ~s does not identify a JWK (because ~a)")
+ (get 'value) cause)
+ (format #f (G_ "the value ~s does not identify a JWK")
+ (get 'value)))))
((&compound-exception)
(let ((components (get 'components)))
(if (null? components)
diff --git a/src/scm/webid-oidc/stubs.scm b/src/scm/webid-oidc/stubs.scm
index 0ef3fb5..ff94497 100644
--- a/src/scm/webid-oidc/stubs.scm
+++ b/src/scm/webid-oidc/stubs.scm
@@ -14,12 +14,31 @@
(lambda error
(raise-not-base64 data error))))
+(define (fix-generate-key . args)
+ (catch 'unsupported-crv
+ (lambda ()
+ (apply generate-key args))
+ (lambda (error)
+ (raise-unsupported-crv (cadr error)))))
+
+(define (fix-kty key)
+ (catch 'unsupported-crv
+ (lambda ()
+ (let ((ret (kty key)))
+ (unless ret
+ (raise-not-a-jwk key #f))
+ ret))
+ (lambda (error)
+ (raise-unsupported-crv (cadr error)))))
+
(export
base64-encode
(fix-base64-decode . base64-decode)
random
random-init!
- generate-key)
+ (fix-generate-key . generate-key)
+ (fix-kty . kty)
+ strip-key)
;; json reader from guile-json will not behave consistently with
;; SRFI-180 with objects: keys will be mapped to strings, not
diff --git a/src/utilities.h b/src/utilities.h
index d17f647..ae5d82c 100644
--- a/src/utilities.h
+++ b/src/utilities.h
@@ -64,6 +64,12 @@ static int do_mpz_t_load (mpz_t x, SCM data, int throw_if_fail);
static const struct ecc_curve *do_ecc_curve_load (SCM data,
int throw_if_fail);
+/* Set up a key, and return whether it was OK */
+static int do_ecc_point_load (struct ecc_point *x, SCM data);
+static int do_ecc_scalar_load (struct ecc_scalar *x, SCM data);
+static int do_rsa_public_key_load (struct rsa_public_key *x, SCM data);
+static int do_rsa_private_key_load (struct rsa_private_key *x, SCM data);
+
/* Register x to be destroyed at the end of the dynamic wind. */
static void dynwind_mpz_t_clear (mpz_t x);
static void dynwind_ecc_point_clear (struct ecc_point *x);
@@ -229,7 +235,7 @@ get_as_bytevector (SCM data, size_t *size, int throw_if_fail)
char *data_str = NULL;
struct base64_decode_ctx decoder;
int ok = 1;
- if (!scm_is_bytevector (data) && !throw_if_fail)
+ if (!scm_is_string (data) && !throw_if_fail)
{
return NULL;
}
@@ -301,6 +307,59 @@ do_ecc_curve_load (SCM crv, int throw_if_fail)
return NULL;
}
+static inline int
+do_ecc_point_load (struct ecc_point *point, SCM data)
+{
+ mpz_t x, y;
+ int ret = 1;
+ scm_dynwind_begin (0);
+ mpz_init (x);
+ dynwind_mpz_t_clear (x);
+ mpz_init (y);
+ dynwind_mpz_t_clear (y);
+ ret =
+ (do_mpz_t_load (x, scm_assq_ref (data, kx), 0)
+ && do_mpz_t_load (y, scm_assq_ref (data, ky), 0)
+ && ecc_point_set (point, x, y));
+ scm_dynwind_end ();
+ return ret;
+}
+
+static inline int
+do_ecc_scalar_load (struct ecc_scalar *scalar, SCM data)
+{
+ mpz_t z;
+ int ret = 1;
+ scm_dynwind_begin (0);
+ mpz_init (z);
+ dynwind_mpz_t_clear (z);
+ ret =
+ (do_mpz_t_load (z, scm_assq_ref (data, kd), 0)
+ && ecc_scalar_set (scalar, z));
+ scm_dynwind_end ();
+ return ret;
+}
+
+static inline int
+do_rsa_public_key_load (struct rsa_public_key *x, SCM data)
+{
+ return (do_mpz_t_load (x->n, scm_assq_ref (data, kn), 0)
+ && do_mpz_t_load (x->e, scm_assq_ref (data, ke), 0)
+ && rsa_public_key_prepare (x));
+}
+
+static inline int
+do_rsa_private_key_load (struct rsa_private_key *x, SCM data)
+{
+ return (do_mpz_t_load (x->d, scm_assq_ref (data, kd), 0)
+ && do_mpz_t_load (x->p, scm_assq_ref (data, kp), 0)
+ && do_mpz_t_load (x->q, scm_assq_ref (data, kq), 0)
+ && do_mpz_t_load (x->a, scm_assq_ref (data, kdp), 0)
+ && do_mpz_t_load (x->b, scm_assq_ref (data, kdq), 0)
+ && do_mpz_t_load (x->c, scm_assq_ref (data, kqi), 0)
+ && rsa_private_key_prepare (x));
+}
+
static void
do_mpz_t_clear (void *ptr)
{
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7efc3d1..65191b4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,7 +1,11 @@
TESTS = %reldir%/load-library.scm \
%reldir%/base64-ok.scm \
%reldir%/base64-error.scm \
- %reldir%/random.scm
+ %reldir%/random.scm \
+ %reldir%/jwk-kty-ec-correct.scm \
+ %reldir%/jwk-kty-ec-incorrect.scm \
+ %reldir%/jwk-kty-rsa-correct.scm \
+ %reldir%/jwk-kty-rsa-incorrect.scm
EXTRA_DIST += $(TESTS)
diff --git a/tests/jwk-kty-ec-correct.scm b/tests/jwk-kty-ec-correct.scm
new file mode 100644
index 0000000..04306eb
--- /dev/null
+++ b/tests/jwk-kty-ec-correct.scm
@@ -0,0 +1,15 @@
+(use-modules (webid-oidc stubs)
+ (webid-oidc testing))
+
+(with-test-environment
+ "jwk-kty-ec-correct"
+ (lambda ()
+ (let* ((key (json-string->scm "{
+ \"kty\":\"EC\",
+ \"x\":\"l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs\",
+ \"y\":\"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA\",
+ \"crv\":\"P-256\"
+ }"))
+ (kty (kty key)))
+ (unless (eq? kty 'EC)
+ (exit 1)))))
diff --git a/tests/jwk-kty-ec-incorrect.scm b/tests/jwk-kty-ec-incorrect.scm
new file mode 100644
index 0000000..5ada4f2
--- /dev/null
+++ b/tests/jwk-kty-ec-incorrect.scm
@@ -0,0 +1,23 @@
+(use-modules (webid-oidc stubs)
+ (webid-oidc testing)
+ (webid-oidc errors))
+
+(with-test-environment
+ "jwk-kty-ec-incorrect"
+ (lambda ()
+ (let* ((key (json-string->scm "{
+ \"kty\":\"EC\",
+ \"x\":\"This-point-does-not-exist-on-the-curve_____\",
+ \"y\":\"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA\",
+ \"crv\":\"P-256\"
+ }"))
+ (kty
+ (with-exception-handler
+ (lambda (exn)
+ #f)
+ (lambda ()
+ (kty key))
+ #:unwind? #t
+ #:unwind-for-type &not-a-jwk)))
+ (when kty
+ (exit 1)))))
diff --git a/tests/jwk-kty-rsa-correct.scm b/tests/jwk-kty-rsa-correct.scm
new file mode 100644
index 0000000..f6d42ad
--- /dev/null
+++ b/tests/jwk-kty-rsa-correct.scm
@@ -0,0 +1,10 @@
+(use-modules (webid-oidc stubs)
+ (webid-oidc testing))
+
+(with-test-environment
+ "jwk-kty-ec-correct"
+ (lambda ()
+ (let* ((key (json-string->scm "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"kid\":\"db7cdbbf-0ca3-48da-abf6-8f34002a4651\",\"n\":\"nzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA-kzeVOVpVWwkWdVha4s38XM_pa_yr47av7-z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr_Mrm_YtjCZVWgaOYIhwrXwKLqPr_11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e-lf4s4OxQawWD79J9_5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa-GSYOD2QU68Mb59oSk2OB-BtOLpJofmbGEGgvmwyCI9Mw\"}"))
+ (kty (kty key)))
+ (unless (eq? kty 'RSA)
+ (exit 1)))))
diff --git a/tests/jwk-kty-rsa-incorrect.scm b/tests/jwk-kty-rsa-incorrect.scm
new file mode 100644
index 0000000..11ab368
--- /dev/null
+++ b/tests/jwk-kty-rsa-incorrect.scm
@@ -0,0 +1,18 @@
+(use-modules (webid-oidc stubs)
+ (webid-oidc testing)
+ (webid-oidc errors))
+
+(with-test-environment
+ "jwk-kty-ec-incorrect"
+ (lambda ()
+ (let* ((key (json-string->scm "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"kid\":\"db7cdbbf-0ca3-48da-abf6-8f34002a4651\",\"n\":\"--\"}"))
+ (kty
+ (with-exception-handler
+ (lambda (exn)
+ #f)
+ (lambda ()
+ (kty key))
+ #:unwind? #t
+ #:unwind-for-type &not-a-jwk)))
+ (when kty
+ (exit 1)))))