summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2021-09-16 23:03:12 +0200
committerVivien Kraus <vivien@planete-kraus.eu>2021-09-21 22:25:03 +0200
commitfa486f2e136a898d1b1548ec90757a78c65a0b70 (patch)
tree7601f939c6859547cc2df38e587c5d9473bae76d
parent86bd90866fdc2ab5234c6e09e39bfa972f7fa395 (diff)
JWK: document it, and use GOOPS
-rw-r--r--doc/disfluid.texi149
-rw-r--r--po/disfluid.pot282
-rw-r--r--po/fr.po324
-rw-r--r--src/scm/webid-oidc/client/accounts.scm14
-rw-r--r--src/scm/webid-oidc/client/client.scm8
-rw-r--r--src/scm/webid-oidc/dpop-proof.scm21
-rw-r--r--src/scm/webid-oidc/example-app.scm1
-rw-r--r--src/scm/webid-oidc/identity-provider.scm10
-rw-r--r--src/scm/webid-oidc/jwk.scm468
-rw-r--r--src/scm/webid-oidc/jws.scm24
-rw-r--r--src/scm/webid-oidc/oidc-configuration.scm8
-rw-r--r--tests/dpop-proof-valid.scm2
-rw-r--r--tests/jwk-kty-rsa-incorrect.scm21
-rw-r--r--tests/jwk-public.scm15
-rw-r--r--tests/jwks-get.scm29
-rw-r--r--tests/jws.scm5
-rw-r--r--tests/oidc-configuration.scm7
-rw-r--r--tests/resource-server.scm7
18 files changed, 880 insertions, 515 deletions
diff --git a/doc/disfluid.texi b/doc/disfluid.texi
index cf413af..8004d3c 100644
--- a/doc/disfluid.texi
+++ b/doc/disfluid.texi
@@ -296,6 +296,7 @@ more closely respected.
* The access token::
* The DPoP proof::
* Generic JWTs::
+* Public-key cryptography::
@end menu
@node The ID token
@@ -524,6 +525,154 @@ exception.
Encode the JWT and sign it with @var{key}.
@end deffn
+@node Public-key cryptography
+@section Public-key cryptography
+
+Some functions require a key, or a key pair, to operate. The
+@emph{(webid-oidc jwk)} module provides you with everything required
+to manage keys.
+
+@deftp {Class} <private-key> ()
+This is the base class for a private key. You need it to issue
+signatures.
+@end deftp
+
+@deftp {Class} <public-key> ()
+This is the base class for a public key. You need it to check
+signatures.
+@end deftp
+
+@deftp {Class} <key-pair> () @var{public-key} @var{private-key}
+A key pair contains a @var{public-key} and a matching
+@var{private-key}. You use this form for keys you own.
+@end deftp
+
+@deftp {Class} <rsa-key-pair> () (@code{<key-pair>})
+This key pair contains matching RSA keys.
+@end deftp
+
+@deftp {Class} <ec-key-pair> () (@code{<key-pair>}) @var{crv}
+This key pair contains matching elliptic curve keys. @var{crv} is a
+symbol identifiying the curve.
+@end deftp
+
+@deftp {Class} <rsa-private-key> (<private-key>) @var{d} @var{p} @var{q} @var{dp} @var{dq} @var{qi}
+@deftpx {Class} <rsa-public-key> (<public-key>) @var{n} @var{e}
+@deftpx {Class} <ec-scalar> (<private-key>) @var{crv} @var{z}
+@deftpx {Class} <ec-point> (<public-key>) @var{crv} @var{x} @var{y}
+All fields are strings, base64 encoding the parameters, except
+@var{crv}, which is a symbol.
+@end deftp
+
+@deftp {Class} <jwks> () @var{keys}
+An identity provider may use different keys that are in validity to
+sign different access tokens. The JWKS encapsulates many public
+@var{keys}.
+@end deftp
+
+@deftypefn {Generic method} <public-key> public-key (@var{key} @code{<key-pair>})
+@deftypefnx {Generic method} <public-key> public-key (@var{key} @code{<public-key>})
+Return the public part of @var{key}, which may either be a key pair or
+a public key.
+@end deftypefn
+
+@deftypefn {Generic method} <private-key> private-key (@var{key} @code{<key-pair>})
+@deftypefnx {Generic method} <private-key> private-key (@var{key} @code{<private-key>})
+Return the private part of @var{key}.
+@end deftypefn
+
+@deftypefn {Generic method} <string> rsa-d (@var{key} @code{<rsa-key-pair>})
+@deftypefnx {Generic method} <string> rsa-d (@var{key} @code{<rsa-private-key>})
+@deftypefnx {Generic method} <string> rsa-p (@var{key} @code{<rsa-key-pair>})
+@deftypefnx {Generic method} <string> rsa-p (@var{key} @code{<rsa-private-key>})
+@deftypefnx {Generic method} <string> rsa-q (@var{key} @code{<rsa-key-pair>})
+@deftypefnx {Generic method} <string> rsa-q (@var{key} @code{<rsa-private-key>})
+@deftypefnx {Generic method} <string> rsa-dp (@var{key} @code{<rsa-key-pair>})
+@deftypefnx {Generic method} <string> rsa-dp (@var{key} @code{<rsa-private-key>})
+@deftypefnx {Generic method} <string> rsa-dq (@var{key} @code{<rsa-key-pair>})
+@deftypefnx {Generic method} <string> rsa-dq (@var{key} @code{<rsa-private-key>})
+@deftypefnx {Generic method} <string> rsa-qi (@var{key} @code{<rsa-key-pair>})
+@deftypefnx {Generic method} <string> rsa-qi (@var{key} @code{<rsa-private-key>})
+@deftypefnx {Generic method} <string> rsa-n (@var{key} @code{<rsa-key-pair>})
+@deftypefnx {Generic method} <string> rsa-n (@var{key} @code{<rsa-public-key>})
+@deftypefnx {Generic method} <string> rsa-e (@var{key} @code{<rsa-key-pair>})
+@deftypefnx {Generic method} <string> rsa-e (@var{key} @code{<rsa-public-key>})
+@deftypefnx {Generic method} <symbol> ec-crv (@var{key} @code{<ec-key-pair>})
+@deftypefnx {Generic method} <symbol> ec-crv (@var{key} @code{<ec-point>})
+@deftypefnx {Generic method} <symbol> ec-crv (@var{key} @code{<ec-scalar>})
+@deftypefnx {Generic method} <string> ec-x (@var{key} @code{<ec-key-pair>})
+@deftypefnx {Generic method} <string> ec-x (@var{key} @code{<ec-point>})
+@deftypefnx {Generic method} <string> ec-y (@var{key} @code{<ec-key-pair>})
+@deftypefnx {Generic method} <string> ec-y (@var{key} @code{<ec-point>})
+@deftypefnx {Generic method} <string> ec-z (@var{key} @code{<ec-key-pair>})
+@deftypefnx {Generic method} <string> ec-z (@var{key} @code{<ec-scalar>})
+Key parameter getters.
+@end deftypefn
+
+@deftypefn {Generic method} <list> keys (@var{jwks} @code{<jwks>})
+Return all the public keys used by @var{jwks}.
+@end deftypefn
+
+@deftypefn {Generic method} <undefined> check-key (@var{key} @code{<key>})
+@deftypefnx {Generic method} <undefined> check-key (@var{key} @code{<key-pair>})
+Check that the @var{key} parameters are consistent.
+@end deftypefn
+
+When exchanging keys, maybe you will have them in the form of a JWK:
+an alist from symbols to strings, as a representation for a JSON
+object.
+
+@deftypefn {Generic method} <list> key->jwk (@var{key} @code{<key>})
+@deftypefnx {Generic method} <list> key->jwk (@var{key} @code{<key-pair>})
+Return an alist with known parameter names for JSON.
+@end deftypefn
+
+@deffn function jwk->key @var{jwk}
+Parse @var{jwk} as a key or a key pair.
+@end deffn
+
+@deftypefn {Generic method} <symbol> kty (@var{key} @code{<rsa-key-pair>})
+@deftypefnx {Generic method} <symbol> kty (@var{key} @code{<rsa-public-key>})
+@deftypefnx {Generic method} <symbol> kty (@var{key} @code{<rsa-private-key>})
+@deftypefnx {Generic method} <symbol> kty (@var{key} @code{<ec-key-pair>})
+@deftypefnx {Generic method} <symbol> kty (@var{key} @code{<ec-point>})
+@deftypefnx {Generic method} <symbol> kty (@var{key} @code{<ec-scalar>})
+Return @code{'RSA} for RSA keys, or @code{'EC} for elliptic curve
+keys.
+@end deftypefn
+
+@deftypefn {Generic method} <string> jkt (@var{key} @code{<key-pair>})
+@deftypefnx {Generic method} <string> jkt (@var{key} @code{<public-key>})
+Hash the @var{key} parameters in a reproducible order to get the hash
+of a key.
+@end deftypefn
+
+@deffn function generate-key @var{[#:n-size]} @var{[#:e-size]} @var{[#:e=\"AQAB\"]} @var{[#:crv]}
+Generate a new key pair.
+@end deffn
+
+@deftypefn {Generic method} <values> serve (@var{jwks} @code{<jwks>}) @var{expiration-date}
+Return a response and response body for serving
+@var{jwks}. Client-side caching is very much necessary for a JWKS, so
+pass @var{expiration-date} as a SRFI-19 date to define a maximum date
+for caching. It should be in the future, for instance in 1 hour.
+@end deftypefn
+
+@deffn {function} get-jwks @var{uri} [#:@var{http-request}]
+Download a JWKS on the web at @var{uri}. Use @var{http-request}, with
+the same interface as that of @emph{(web client)}, to actually get the
+JWKS.
+@end deffn
+
+@deftp {Exception type} &not-a-jwk
+If the key parameters are incorrect, this exception is raised.
+@end deftp
+
+@deftp {Exception type} &not-a-jwks
+If the JWKS cannot be downloaded, or is incorrect, this exception is
+raised.
+@end deftp
+
@node Caching on server side
@chapter Caching on server side
diff --git a/po/disfluid.pot b/po/disfluid.pot
index 022b8db..d9126b9 100644
--- a/po/disfluid.pot
+++ b/po/disfluid.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: disfluid SNAPSHOT\n"
"Report-Msgid-Bugs-To: vivien@planete-kraus.eu\n"
-"POT-Creation-Date: 2021-09-17 14:10+0200\n"
+"POT-Creation-Date: 2021-09-17 14:13+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"
@@ -131,12 +131,12 @@ msgstr ""
msgid "this is not an access token, because it is not even a JWS"
msgstr ""
-#: src/scm/webid-oidc/access-token.scm:77 src/scm/webid-oidc/dpop-proof.scm:96
+#: src/scm/webid-oidc/access-token.scm:77 src/scm/webid-oidc/dpop-proof.scm:101
#, scheme-format
msgid "this is not an access token: ~a"
msgstr ""
-#: src/scm/webid-oidc/access-token.scm:79 src/scm/webid-oidc/dpop-proof.scm:98
+#: src/scm/webid-oidc/access-token.scm:79 src/scm/webid-oidc/dpop-proof.scm:103
msgid "this is not an access token"
msgstr ""
@@ -295,7 +295,7 @@ msgstr ""
#: src/scm/webid-oidc/authorization-page-unsafe.scm:52
#: src/scm/webid-oidc/hello-world.scm:40 src/scm/webid-oidc/hello-world.scm:167
#: src/scm/webid-oidc/hello-world.scm:187
-#: src/scm/webid-oidc/identity-provider.scm:139
+#: src/scm/webid-oidc/identity-provider.scm:143
#: src/scm/webid-oidc/token-endpoint.scm:111
#: src/scm/webid-oidc/token-endpoint.scm:137
#: src/scm/webid-oidc/token-endpoint.scm:164
@@ -477,78 +477,78 @@ msgstr ""
msgid "the client manifest is dereferenced from ~s, but it pretends to be ~s"
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:289
+#: src/scm/webid-oidc/client/accounts.scm:285
msgid "The refresh token has expired."
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:296
+#: src/scm/webid-oidc/client/accounts.scm:292
#, scheme-format
msgid "The token request failed with code ~s (~s)."
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:305
+#: src/scm/webid-oidc/client/accounts.scm:301
msgid "The token response did not set the content type."
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:313
+#: src/scm/webid-oidc/client/accounts.scm:309
msgid "The token endpoint did not respond in UTF-8."
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:325
+#: src/scm/webid-oidc/client/accounts.scm:321
#, scheme-format
msgid "The token response has content-type ~s, not application/json."
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:335
+#: src/scm/webid-oidc/client/accounts.scm:331
msgid "The token response is not valid JSON."
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:349
+#: src/scm/webid-oidc/client/accounts.scm:345
#, scheme-format
msgid "The token response did not include an ID token: ~s"
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:357
+#: src/scm/webid-oidc/client/accounts.scm:353
#, scheme-format
msgid "The token response did not include an access token: ~s\n"
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:368
+#: src/scm/webid-oidc/client/accounts.scm:364
#, scheme-format
msgid "the ID token signature is invalid: ~a"
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:370
+#: src/scm/webid-oidc/client/accounts.scm:366
msgid "the ID token signature is invalid"
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:388
+#: src/scm/webid-oidc/client/accounts.scm:384
#, scheme-format
msgid "the ID token delivered by the identity provider for ~s has ~s as webid"
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:398
+#: src/scm/webid-oidc/client/accounts.scm:394
#, scheme-format
msgid "The ID token delivered by the identity provider ~s is for issuer ~s."
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:413
+#: src/scm/webid-oidc/client/accounts.scm:409
msgid "The issuer is required."
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:418
+#: src/scm/webid-oidc/client/accounts.scm:414
msgid "The optional subject and required issuer should be strings or URI."
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:454
+#: src/scm/webid-oidc/client/accounts.scm:450
msgid "Cannot check the username and/or password."
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:464
+#: src/scm/webid-oidc/client/accounts.scm:460
msgid "The subject should be a string or URI."
msgstr ""
-#: src/scm/webid-oidc/client/accounts.scm:478
+#: src/scm/webid-oidc/client/accounts.scm:474
msgid "The issuer should be a string or URI."
msgstr ""
@@ -568,7 +568,7 @@ msgstr ""
msgid "You already have an account for ~a issued by ~a."
msgstr ""
-#: src/scm/webid-oidc/client/client.scm:106
+#: src/scm/webid-oidc/client/client.scm:108
msgid ""
"Client ID and redirect URIs should be URIs, and key pair should be a key "
"pair.."
@@ -582,213 +582,217 @@ msgstr ""
msgid "Hello, world!"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:91
+#: src/scm/webid-oidc/dpop-proof.scm:96
#, scheme-format
msgid "this is not a DPoP proof, because it is not even a JWS: ~a"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:93
+#: src/scm/webid-oidc/dpop-proof.scm:98
msgid "this is not a DPoP proof, because it is not even a JWS"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:124
+#: src/scm/webid-oidc/dpop-proof.scm:129
#, scheme-format
msgid "the DPoP proof is missing ~s"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:147
+#: src/scm/webid-oidc/dpop-proof.scm:152
#, scheme-format
msgid "the \"jti\" field should be a string, not ~s"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:154
+#: src/scm/webid-oidc/dpop-proof.scm:159
#, scheme-format
msgid "the \"htm\" field should be a string, not ~s"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:161
+#: src/scm/webid-oidc/dpop-proof.scm:166
#, scheme-format
msgid "the \"htu\" field should be an URI, not ~s"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:168
+#: src/scm/webid-oidc/dpop-proof.scm:173
#, scheme-format
msgid "the \"iat\" field should be a timestamp, not ~s"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:175
+#: src/scm/webid-oidc/dpop-proof.scm:180
#, scheme-format
msgid "the \"ath\" field should be an encoded JWT, not ~s"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:184
+#: src/scm/webid-oidc/dpop-proof.scm:189
#, scheme-format
msgid "the \"alg\" field should be a string, not ~s"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:189
+#: src/scm/webid-oidc/dpop-proof.scm:194
#, scheme-format
msgid "the \"typ\" field should be \"dpop+jwt\", not ~s"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:195
+#: src/scm/webid-oidc/dpop-proof.scm:200
+msgid "the \"jwk\" field should not contain the private key"
+msgstr ""
+
+#: src/scm/webid-oidc/dpop-proof.scm:202
#, scheme-format
msgid "the \"jwk\" field should be a valid public key, not ~s"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:274
+#: src/scm/webid-oidc/dpop-proof.scm:281
#, scheme-format
msgid "the DPoP proof is signed for ~s, but it is issued to ~s"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:305
+#: src/scm/webid-oidc/dpop-proof.scm:312
#, scheme-format
msgid "the DPoP proof cannot be decoded: ~a"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:307
+#: src/scm/webid-oidc/dpop-proof.scm:314
msgid "the DPoP proof cannot be decoded"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:317
+#: src/scm/webid-oidc/dpop-proof.scm:324
#, scheme-format
msgid "the DPoP proof is signed for access through ~s, but it is used with ~s"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:331
+#: src/scm/webid-oidc/dpop-proof.scm:338
#, scheme-format
msgid ""
"the DPoP proof is signed in the future, ~a, relative to the current date, ~a"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:340
+#: src/scm/webid-oidc/dpop-proof.scm:347
#, scheme-format
msgid "the DPoP proof is too old, it was signed ~a and now it is ~a"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:352
+#: src/scm/webid-oidc/dpop-proof.scm:359
#, scheme-format
msgid ""
"the DPoP proof should go along with an access token hashed to ~s, not ~s"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:361 src/scm/webid-oidc/dpop-proof.scm:372
+#: src/scm/webid-oidc/dpop-proof.scm:368 src/scm/webid-oidc/dpop-proof.scm:379
msgid "the DPoP proof is signed with the wrong key"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:370
+#: src/scm/webid-oidc/dpop-proof.scm:377
#, scheme-format
msgid "the DPoP proof is signed with the wrong key: ~a"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:381
+#: src/scm/webid-oidc/dpop-proof.scm:388
msgid "the cnf/check function returned #f"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:392
+#: src/scm/webid-oidc/dpop-proof.scm:399
#, scheme-format
msgid "cannot encode a DPoP proof: ~a"
msgstr ""
-#: src/scm/webid-oidc/dpop-proof.scm:394
+#: src/scm/webid-oidc/dpop-proof.scm:401
msgid "cannot encode a DPoP proof"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:98
+#: src/scm/webid-oidc/example-app.scm:97
#, scheme-format
msgid "~a (issued by ~a): no interaction required"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:101
+#: src/scm/webid-oidc/example-app.scm:100
#, scheme-format
msgid "~a (issued by ~a): offline but accessible"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:104
+#: src/scm/webid-oidc/example-app.scm:103
#, scheme-format
msgid "~a (issued by ~a): online"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:107
+#: src/scm/webid-oidc/example-app.scm:106
#, scheme-format
msgid "~a (issued by ~a): inaccessible"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:120
+#: src/scm/webid-oidc/example-app.scm:119
#, scheme-format
msgid "Your choice ~a does not exist.\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:138
+#: src/scm/webid-oidc/example-app.scm:137
msgid "Your choice is not a valid URI.\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:147
+#: src/scm/webid-oidc/example-app.scm:146
msgid "This is not a valid HTTP method.\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:163
+#: src/scm/webid-oidc/example-app.scm:162
msgid "This is not a valid value for this header.\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:201
+#: src/scm/webid-oidc/example-app.scm:200
msgid "Nothing to undo.\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:213
+#: src/scm/webid-oidc/example-app.scm:212
msgid "Nothing to redo.\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:273
+#: src/scm/webid-oidc/example-app.scm:272
msgid "Example app command|add-account"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:275
+#: src/scm/webid-oidc/example-app.scm:274
msgid "Example app command|choose-account"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:277
+#: src/scm/webid-oidc/example-app.scm:276
msgid "Example app command|set-uri"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:279
+#: src/scm/webid-oidc/example-app.scm:278
msgid "Example app command|set-method"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:281
+#: src/scm/webid-oidc/example-app.scm:280
msgid "Example app command|view-headers"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:283
+#: src/scm/webid-oidc/example-app.scm:282
msgid "Example app command|clear-headers"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:285
+#: src/scm/webid-oidc/example-app.scm:284
msgid "Example app command|add-header"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:287
+#: src/scm/webid-oidc/example-app.scm:286
msgid "Example app command|ok"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:289
+#: src/scm/webid-oidc/example-app.scm:288
msgid "Example app command|undo"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:291
+#: src/scm/webid-oidc/example-app.scm:290
msgid "Example app command|redo"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:301
+#: src/scm/webid-oidc/example-app.scm:300
#, scheme-format
msgid "To log in on ~a, please visit: ~a\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:304
+#: src/scm/webid-oidc/example-app.scm:303
msgid "Then, paste the authorization code you get:\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:322
+#: src/scm/webid-oidc/example-app.scm:321
#, scheme-format
msgid ""
"Account: ~a\n"
@@ -808,87 +812,87 @@ msgid ""
"\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:341
+#: src/scm/webid-oidc/example-app.scm:340
msgid "Account:|unset"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:345
+#: src/scm/webid-oidc/example-app.scm:344
msgid "URI:|unset"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:349
+#: src/scm/webid-oidc/example-app.scm:348
msgid "Method:|unset"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:352
+#: src/scm/webid-oidc/example-app.scm:351
msgid "Headers:|none"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:356
+#: src/scm/webid-oidc/example-app.scm:355
msgid "list separator|, "
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:366
+#: src/scm/webid-oidc/example-app.scm:365
#, scheme-format
msgid "You can undo your last command with \"~a\".\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:368
+#: src/scm/webid-oidc/example-app.scm:367
#, scheme-format
msgid "You can re-apply your last undone command with \"~a\".\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:369
+#: src/scm/webid-oidc/example-app.scm:368
msgid "Readline prompt|Command: "
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:376
+#: src/scm/webid-oidc/example-app.scm:375
#, scheme-format
msgid "An error happened: ~a.\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:388
+#: src/scm/webid-oidc/example-app.scm:387
msgid "Please enter your identity provider: "
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:394
+#: src/scm/webid-oidc/example-app.scm:393
msgid ""
"You don’t have other accounts available. Please add one with \"add-account"
"\".\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:400
+#: src/scm/webid-oidc/example-app.scm:399
#, scheme-format
msgid "- ~a: ~a\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:408
+#: src/scm/webid-oidc/example-app.scm:407
#, scheme-format
msgid "[1-~a] "
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:416
+#: src/scm/webid-oidc/example-app.scm:415
msgid "Visit this URI: "
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:422
+#: src/scm/webid-oidc/example-app.scm:421
msgid "Use this HTTP method [GET]: "
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:438
+#: src/scm/webid-oidc/example-app.scm:437
msgid "Which header? "
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:441
+#: src/scm/webid-oidc/example-app.scm:440
#, scheme-format
msgid "Which header value for ~a? "
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:464
+#: src/scm/webid-oidc/example-app.scm:463
msgid "Please define an account and the URI.\n"
msgstr ""
-#: src/scm/webid-oidc/example-app.scm:471
+#: src/scm/webid-oidc/example-app.scm:470
msgid "I don’t know that command.\n"
msgstr ""
@@ -1023,11 +1027,11 @@ msgstr ""
msgid "<p>You can only use the <emph>GET</emph> method on this resource.</p>"
msgstr ""
-#: src/scm/webid-oidc/identity-provider.scm:72
+#: src/scm/webid-oidc/identity-provider.scm:76
msgid "Warning: generating a new key pair."
msgstr ""
-#: src/scm/webid-oidc/identity-provider.scm:132
+#: src/scm/webid-oidc/identity-provider.scm:136
msgid "reason-phrase|Not Found"
msgstr ""
@@ -1036,152 +1040,136 @@ msgstr ""
msgid "a replay has been detected with JTI ~s"
msgstr ""
-#: src/scm/webid-oidc/jwk.scm:76
-#, scheme-format
-msgid "the JWK is invalid: ~a"
-msgstr ""
-
-#: src/scm/webid-oidc/jwk.scm:78
-msgid "the JWK is invalid"
-msgstr ""
-
-#: src/scm/webid-oidc/jwk.scm:87
-#, scheme-format
-msgid "unknown key type ~s"
+#: src/scm/webid-oidc/jwk.scm:141
+msgid "the point and scalar are not on the same curve"
msgstr ""
-#: src/scm/webid-oidc/jwk.scm:103
+#: src/scm/webid-oidc/jwk.scm:236
#, scheme-format
-msgid "the public JWK is invalid: ~a"
-msgstr ""
-
-#: src/scm/webid-oidc/jwk.scm:105
-msgid "the public JWK is invalid"
+msgid "the JWK is invalid: ~a"
msgstr ""
-#: src/scm/webid-oidc/jwk.scm:136
-#, scheme-format
-msgid "cannot extract the public part of the key: ~a"
+#: src/scm/webid-oidc/jwk.scm:238
+msgid "the JWK is invalid"
msgstr ""
-#: src/scm/webid-oidc/jwk.scm:138
-msgid "cannot extract the public part of the key"
+#: src/scm/webid-oidc/jwk.scm:247
+msgid "cannot compute the key type"
msgstr ""
-#: src/scm/webid-oidc/jwk.scm:188
-msgid "the JWKS is invalid, because it does not have keys"
+#: src/scm/webid-oidc/jwk.scm:284
+msgid "it is built as an RSA key or key pair, but it is not"
msgstr ""
-#: src/scm/webid-oidc/jwk.scm:197
-#, scheme-format
-msgid "the JWKS is invalid: ~a"
+#: src/scm/webid-oidc/jwk.scm:292
+msgid "it is built as an elliptic curve key or key pair, but it is not"
msgstr ""
-#: src/scm/webid-oidc/jwk.scm:199
-msgid "the JWKS is invalid"
+#: src/scm/webid-oidc/jwk.scm:365
+msgid "this is neither a RSA key nor an elliptic curve key"
msgstr ""
-#: src/scm/webid-oidc/jwk.scm:236
+#: src/scm/webid-oidc/jwk.scm:402
#, scheme-format
msgid "cannot fetch a JWKS: ~a"
msgstr ""
-#: src/scm/webid-oidc/jwk.scm:238
+#: src/scm/webid-oidc/jwk.scm:404
msgid "cannot fetch a JWKS"
msgstr ""
-#: src/scm/webid-oidc/jwk.scm:242
+#: src/scm/webid-oidc/jwk.scm:408
#, scheme-format
msgid "the request failed with ~s ~s"
msgstr ""
-#: src/scm/webid-oidc/jwk.scm:247
+#: src/scm/webid-oidc/jwk.scm:413
msgid "missing content-type"
msgstr ""
-#: src/scm/webid-oidc/jwk.scm:252
+#: src/scm/webid-oidc/jwk.scm:418
#, scheme-format
msgid "invalid content-type: ~s"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:72
+#: src/scm/webid-oidc/jws.scm:73
#, scheme-format
msgid "the JWS is invalid: ~a"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:74
+#: src/scm/webid-oidc/jws.scm:75
msgid "the JWS is invalid"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:93
+#: src/scm/webid-oidc/jws.scm:94
msgid "the JWS header does not have an \"alg\" field"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:101
+#: src/scm/webid-oidc/jws.scm:102
msgid "invalid JSON object as payload"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:110
+#: src/scm/webid-oidc/jws.scm:111
#, scheme-format
msgid "invalid signature algorithm: ~s"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:114
+#: src/scm/webid-oidc/jws.scm:115
#, scheme-format
msgid "invalid \"alg\" value: ~s"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:119
+#: src/scm/webid-oidc/jws.scm:120
msgid "invalid JSON object as header"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:121
+#: src/scm/webid-oidc/jws.scm:122
msgid "this is not a pair"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:138
+#: src/scm/webid-oidc/jws.scm:139
msgid "the encoded JWS is not in 3 parts"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:149
+#: src/scm/webid-oidc/jws.scm:150
#, scheme-format
msgid ""
"the encoded JWS header or payload is not a JSON object encoded in base64: ~a"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:151
+#: src/scm/webid-oidc/jws.scm:152
msgid ""
"the encoded JWS header or payload is not a JSON object encoded in base64"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:210
+#: src/scm/webid-oidc/jws.scm:211
msgid "the JWS is not signed by any of the expected set of public keys"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:221
+#: src/scm/webid-oidc/jws.scm:222
#, scheme-format
msgid "while verifying the JWS signature: ~a"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:223
+#: src/scm/webid-oidc/jws.scm:224
msgid "an unexpected error happened while verifying a JWS"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:240
+#: src/scm/webid-oidc/jws.scm:253
#, scheme-format
msgid "cannot decode a JWS: ~a"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:242
+#: src/scm/webid-oidc/jws.scm:255
msgid "cannot decode a JWS"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:262
+#: src/scm/webid-oidc/jws.scm:272
#, scheme-format
msgid "cannot encode a JWS: ~a"
msgstr ""
-#: src/scm/webid-oidc/jws.scm:264
+#: src/scm/webid-oidc/jws.scm:274
msgid "cannot encode a JWS"
msgstr ""
@@ -1223,25 +1211,25 @@ msgstr ""
msgid "invalid JSON object"
msgstr ""
-#: src/scm/webid-oidc/oidc-configuration.scm:174
+#: src/scm/webid-oidc/oidc-configuration.scm:178
#, scheme-format
msgid "cannot fetch the OIDC configuration: ~a"
msgstr ""
-#: src/scm/webid-oidc/oidc-configuration.scm:176
+#: src/scm/webid-oidc/oidc-configuration.scm:180
msgid "cannot fetch the OIDC configuration"
msgstr ""
-#: src/scm/webid-oidc/oidc-configuration.scm:184
+#: src/scm/webid-oidc/oidc-configuration.scm:188
#, scheme-format
msgid "the server responded with ~s ~s"
msgstr ""
-#: src/scm/webid-oidc/oidc-configuration.scm:189
+#: src/scm/webid-oidc/oidc-configuration.scm:193
msgid "there is no content-type"
msgstr ""
-#: src/scm/webid-oidc/oidc-configuration.scm:194
+#: src/scm/webid-oidc/oidc-configuration.scm:198
#, scheme-format
msgid "unexpected content-type: ~s"
msgstr ""
diff --git a/po/fr.po b/po/fr.po
index 7106ae3..42ef469 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: webid-oidc 0.0.0\n"
"Report-Msgid-Bugs-To: vivien@planete-kraus.eu\n"
-"POT-Creation-Date: 2021-09-17 14:10+0200\n"
-"PO-Revision-Date: 2021-09-17 14:11+0200\n"
+"POT-Creation-Date: 2021-09-17 14:13+0200\n"
+"PO-Revision-Date: 2021-09-17 14:15+0200\n"
"Last-Translator: Vivien Kraus <vivien@planete-kraus.eu>\n"
"Language-Team: French <vivien@planete-kraus.eu>\n"
"Language: fr\n"
@@ -135,12 +135,12 @@ msgstr "ce n’est pas un jeton d’accès, parce que ce n’est même pas un JW
msgid "this is not an access token, because it is not even a JWS"
msgstr "ce n’est pas un jeton d’accès, parce que ce n’est même pas un JWS"
-#: src/scm/webid-oidc/access-token.scm:77 src/scm/webid-oidc/dpop-proof.scm:96
+#: src/scm/webid-oidc/access-token.scm:77 src/scm/webid-oidc/dpop-proof.scm:101
#, scheme-format
msgid "this is not an access token: ~a"
msgstr "ce n’est pas un jeton d’accès : ~a"
-#: src/scm/webid-oidc/access-token.scm:79 src/scm/webid-oidc/dpop-proof.scm:98
+#: src/scm/webid-oidc/access-token.scm:79 src/scm/webid-oidc/dpop-proof.scm:103
msgid "this is not an access token"
msgstr "ce n’est pas un jeton d’accès"
@@ -306,7 +306,7 @@ msgstr "impossible d’encoder le code d’autorisation"
#: src/scm/webid-oidc/authorization-page-unsafe.scm:52
#: src/scm/webid-oidc/hello-world.scm:40 src/scm/webid-oidc/hello-world.scm:167
#: src/scm/webid-oidc/hello-world.scm:187
-#: src/scm/webid-oidc/identity-provider.scm:139
+#: src/scm/webid-oidc/identity-provider.scm:143
#: src/scm/webid-oidc/token-endpoint.scm:111
#: src/scm/webid-oidc/token-endpoint.scm:137
#: src/scm/webid-oidc/token-endpoint.scm:164
@@ -497,83 +497,83 @@ msgstr "impossible de télécharger le manifeste client ~s"
msgid "the client manifest is dereferenced from ~s, but it pretends to be ~s"
msgstr "le manifeste client est déréférencé depuis ~s, mais il prétend être ~s"
-#: src/scm/webid-oidc/client/accounts.scm:289
+#: src/scm/webid-oidc/client/accounts.scm:285
msgid "The refresh token has expired."
msgstr "le jeton de rafraîchissement a expiré."
-#: src/scm/webid-oidc/client/accounts.scm:296
+#: src/scm/webid-oidc/client/accounts.scm:292
#, scheme-format
msgid "The token request failed with code ~s (~s)."
msgstr "La requête de jeton a échoué avec un code ~s (~s)."
-#: src/scm/webid-oidc/client/accounts.scm:305
+#: src/scm/webid-oidc/client/accounts.scm:301
msgid "The token response did not set the content type."
msgstr "Le jeton de réponse n’a pas défini de type de contenu."
-#: src/scm/webid-oidc/client/accounts.scm:313
+#: src/scm/webid-oidc/client/accounts.scm:309
msgid "The token endpoint did not respond in UTF-8."
msgstr "Le terminal de jetonn n’a pas répondu en UTF-8."
-#: src/scm/webid-oidc/client/accounts.scm:325
+#: src/scm/webid-oidc/client/accounts.scm:321
#, scheme-format
msgid "The token response has content-type ~s, not application/json."
msgstr "La réponse de jeton a un type de contenu ~s, pas application/json."
-#: src/scm/webid-oidc/client/accounts.scm:335
+#: src/scm/webid-oidc/client/accounts.scm:331
msgid "The token response is not valid JSON."
msgstr "La réponse de jeton n’est pas un JSON valide."
-#: src/scm/webid-oidc/client/accounts.scm:349
+#: src/scm/webid-oidc/client/accounts.scm:345
#, scheme-format
msgid "The token response did not include an ID token: ~s"
msgstr "La réponse de jeton n’a pas inclus de jeton d’ID : ~s"
-#: src/scm/webid-oidc/client/accounts.scm:357
+#: src/scm/webid-oidc/client/accounts.scm:353
#, scheme-format
msgid "The token response did not include an access token: ~s\n"
msgstr "La réponse de jeton n’a pas inclus de jeton d’accès : ~s\n"
-#: src/scm/webid-oidc/client/accounts.scm:368
+#: src/scm/webid-oidc/client/accounts.scm:364
#, scheme-format
msgid "the ID token signature is invalid: ~a"
msgstr "la signature du jeton d’ID est invalide : ~a"
-#: src/scm/webid-oidc/client/accounts.scm:370
+#: src/scm/webid-oidc/client/accounts.scm:366
msgid "the ID token signature is invalid"
msgstr "la signature du jeton d’ID est invalide"
-#: src/scm/webid-oidc/client/accounts.scm:388
+#: src/scm/webid-oidc/client/accounts.scm:384
#, scheme-format
msgid "the ID token delivered by the identity provider for ~s has ~s as webid"
msgstr ""
"le jeton d’ID délivré par le fournisseur d’identité pour ~s a ~s pour webid"
-#: src/scm/webid-oidc/client/accounts.scm:398
+#: src/scm/webid-oidc/client/accounts.scm:394
#, scheme-format
msgid "The ID token delivered by the identity provider ~s is for issuer ~s."
msgstr ""
"Le jeton d’ID délivré par le fournisseur d’identité ~s est pour l’émetteur "
"~s."
-#: src/scm/webid-oidc/client/accounts.scm:413
+#: src/scm/webid-oidc/client/accounts.scm:409
msgid "The issuer is required."
msgstr "L’émetteur est requis."
-#: src/scm/webid-oidc/client/accounts.scm:418
+#: src/scm/webid-oidc/client/accounts.scm:414
msgid "The optional subject and required issuer should be strings or URI."
msgstr ""
"Le sujet optionnel et émetteur doivent être des chaînes de caractère ou des "
"URIs."
-#: src/scm/webid-oidc/client/accounts.scm:454
+#: src/scm/webid-oidc/client/accounts.scm:450
msgid "Cannot check the username and/or password."
msgstr "Impossible de vérifier le nom d’utilisateur et/ou le mot de passe."
-#: src/scm/webid-oidc/client/accounts.scm:464
+#: src/scm/webid-oidc/client/accounts.scm:460
msgid "The subject should be a string or URI."
msgstr "Le sujet doit être une chaîne de caractères ou une URI."
-#: src/scm/webid-oidc/client/accounts.scm:478
+#: src/scm/webid-oidc/client/accounts.scm:474
msgid "The issuer should be a string or URI."
msgstr "L’émetteur doit être une chaîne de caractères ou une URI."
@@ -595,7 +595,7 @@ msgstr ""
msgid "You already have an account for ~a issued by ~a."
msgstr "Vous avez déjà un compte pour ~a émis par ~a."
-#: src/scm/webid-oidc/client/client.scm:106
+#: src/scm/webid-oidc/client/client.scm:108
msgid ""
"Client ID and redirect URIs should be URIs, and key pair should be a key "
"pair.."
@@ -611,82 +611,86 @@ msgstr "Bonjour, le monde !\n"
msgid "Hello, world!"
msgstr "Bonjour, le monde !"
-#: src/scm/webid-oidc/dpop-proof.scm:91
+#: src/scm/webid-oidc/dpop-proof.scm:96
#, scheme-format
msgid "this is not a DPoP proof, because it is not even a JWS: ~a"
msgstr "ce n’est pas une preuve DPoP, parce que ce n’est même pas un JWS : ~a"
-#: src/scm/webid-oidc/dpop-proof.scm:93
+#: src/scm/webid-oidc/dpop-proof.scm:98
msgid "this is not a DPoP proof, because it is not even a JWS"
msgstr "ce n’est pas une preuve DPoP, parce que ce n’est même pas un JWS"
-#: src/scm/webid-oidc/dpop-proof.scm:124
+#: src/scm/webid-oidc/dpop-proof.scm:129
#, scheme-format
msgid "the DPoP proof is missing ~s"
msgstr "il manque ~s à la preuve DPoP"
-#: src/scm/webid-oidc/dpop-proof.scm:147
+#: src/scm/webid-oidc/dpop-proof.scm:152
#, scheme-format
msgid "the \"jti\" field should be a string, not ~s"
msgstr "le champ « jti » doit être une chaîne de caractères, pas ~s"
-#: src/scm/webid-oidc/dpop-proof.scm:154
+#: src/scm/webid-oidc/dpop-proof.scm:159
#, scheme-format
msgid "the \"htm\" field should be a string, not ~s"
msgstr "le champ « htm » doit être une chaîne de caractères, pas ~s"
-#: src/scm/webid-oidc/dpop-proof.scm:161
+#: src/scm/webid-oidc/dpop-proof.scm:166
#, scheme-format
msgid "the \"htu\" field should be an URI, not ~s"
msgstr "le champ « htu » doit être une URI, pas ~s"
-#: src/scm/webid-oidc/dpop-proof.scm:168
+#: src/scm/webid-oidc/dpop-proof.scm:173
#, scheme-format
msgid "the \"iat\" field should be a timestamp, not ~s"
msgstr "le champ « iat » doit être un horodatage, pas ~s"
-#: src/scm/webid-oidc/dpop-proof.scm:175
+#: src/scm/webid-oidc/dpop-proof.scm:180
#, scheme-format
msgid "the \"ath\" field should be an encoded JWT, not ~s"
msgstr "le champ « ath » doit être un JWT encodé, pas ~s"
-#: src/scm/webid-oidc/dpop-proof.scm:184
+#: src/scm/webid-oidc/dpop-proof.scm:189
#, scheme-format
msgid "the \"alg\" field should be a string, not ~s"
msgstr "le champ « alg » doit être une chaîne de caractères, pas ~s"
-#: src/scm/webid-oidc/dpop-proof.scm:189
+#: src/scm/webid-oidc/dpop-proof.scm:194
#, scheme-format
msgid "the \"typ\" field should be \"dpop+jwt\", not ~s"
msgstr "le champ « typ » doit être « dpop+jwt », pas ~s"
-#: src/scm/webid-oidc/dpop-proof.scm:195
+#: src/scm/webid-oidc/dpop-proof.scm:200
+msgid "the \"jwk\" field should not contain the private key"
+msgstr "le champ « jwk » ne doit pas contenir la clé privée"
+
+#: src/scm/webid-oidc/dpop-proof.scm:202
#, scheme-format
msgid "the \"jwk\" field should be a valid public key, not ~s"
msgstr "le champ « jwk » doit être unen clé publique valide, pas ~s"
-#: src/scm/webid-oidc/dpop-proof.scm:274
+#: src/scm/webid-oidc/dpop-proof.scm:281
#, scheme-format
msgid "the DPoP proof is signed for ~s, but it is issued to ~s"
msgstr "la preuve DPoP est signée pour ~s, mais elle est émise pour ~s"
-#: src/scm/webid-oidc/dpop-proof.scm:305
+#: src/scm/webid-oidc/dpop-proof.scm:312
#, scheme-format
msgid "the DPoP proof cannot be decoded: ~a"
msgstr "impossible de décoder la preuve DPoP : ~a"
-#: src/scm/webid-oidc/dpop-proof.scm:307
+#: src/scm/webid-oidc/dpop-proof.scm:314
msgid "the DPoP proof cannot be decoded"
msgstr "impossible de décoder la preuve DPoP"
-#: src/scm/webid-oidc/dpop-proof.scm:317
+#: src/scm/webid-oidc/dpop-proof.scm:324
#, scheme-format
msgid "the DPoP proof is signed for access through ~s, but it is used with ~s"
msgstr ""
"la preuve DPoP est signée pour un accès avec ~s, mais elle est utilisée avec "
"~s"
-#: src/scm/webid-oidc/dpop-proof.scm:331
+#: src/scm/webid-oidc/dpop-proof.scm:338
#, scheme-format
msgid ""
"the DPoP proof is signed in the future, ~a, relative to the current date, ~a"
@@ -694,14 +698,14 @@ msgstr ""
"la preuve DPoP est signée dans le futur, le ~a, par rapport à la date "
"courante, ~a"
-#: src/scm/webid-oidc/dpop-proof.scm:340
+#: src/scm/webid-oidc/dpop-proof.scm:347
#, scheme-format
msgid "the DPoP proof is too old, it was signed ~a and now it is ~a"
msgstr ""
"la preuve DPoP est trop vieille, elle a été signée le ~a et nous sommes "
"maintenant le ~a"
-#: src/scm/webid-oidc/dpop-proof.scm:352
+#: src/scm/webid-oidc/dpop-proof.scm:359
#, scheme-format
msgid ""
"the DPoP proof should go along with an access token hashed to ~s, not ~s"
@@ -709,123 +713,123 @@ msgstr ""
"la preuve DPoP devrait être accompagnée d’un jeton d’accès de condensat ~s, "
"pas ~s"
-#: src/scm/webid-oidc/dpop-proof.scm:361 src/scm/webid-oidc/dpop-proof.scm:372
+#: src/scm/webid-oidc/dpop-proof.scm:368 src/scm/webid-oidc/dpop-proof.scm:379
msgid "the DPoP proof is signed with the wrong key"
msgstr "la preuve DPoP est signée avec la mauvaise clé"
-#: src/scm/webid-oidc/dpop-proof.scm:370
+#: src/scm/webid-oidc/dpop-proof.scm:377
#, scheme-format
msgid "the DPoP proof is signed with the wrong key: ~a"
msgstr "la preuve DPoP est signée avec la mauvaise clé : ~a"
-#: src/scm/webid-oidc/dpop-proof.scm:381
+#: src/scm/webid-oidc/dpop-proof.scm:388
msgid "the cnf/check function returned #f"
msgstr "la fonction cnf/check a retourné #f"
-#: src/scm/webid-oidc/dpop-proof.scm:392
+#: src/scm/webid-oidc/dpop-proof.scm:399
#, scheme-format
msgid "cannot encode a DPoP proof: ~a"
msgstr "impossible d’encoder la preuve DPoP : ~a"
-#: src/scm/webid-oidc/dpop-proof.scm:394
+#: src/scm/webid-oidc/dpop-proof.scm:401
msgid "cannot encode a DPoP proof"
msgstr "impossible d’encoder la preuve DPoP"
-#: src/scm/webid-oidc/example-app.scm:98
+#: src/scm/webid-oidc/example-app.scm:97
#, scheme-format
msgid "~a (issued by ~a): no interaction required"
msgstr "~a (émis par ~a) : aucune interaction nécessaire"
-#: src/scm/webid-oidc/example-app.scm:101
+#: src/scm/webid-oidc/example-app.scm:100
#, scheme-format
msgid "~a (issued by ~a): offline but accessible"
msgstr "~a (émis par ~a) : hors ligne mais accessible"
-#: src/scm/webid-oidc/example-app.scm:104
+#: src/scm/webid-oidc/example-app.scm:103
#, scheme-format
msgid "~a (issued by ~a): online"
msgstr "~a (émis par ~a) : en ligne"
-#: src/scm/webid-oidc/example-app.scm:107
+#: src/scm/webid-oidc/example-app.scm:106
#, scheme-format
msgid "~a (issued by ~a): inaccessible"
msgstr "~a (émis par ~a) : inaccessible"
-#: src/scm/webid-oidc/example-app.scm:120
+#: src/scm/webid-oidc/example-app.scm:119
#, scheme-format
msgid "Your choice ~a does not exist.\n"
msgstr "Votre choix, ~a, n’existe pas.\n"
-#: src/scm/webid-oidc/example-app.scm:138
+#: src/scm/webid-oidc/example-app.scm:137
msgid "Your choice is not a valid URI.\n"
msgstr "Votre choix doit être une URI valide.\n"
-#: src/scm/webid-oidc/example-app.scm:147
+#: src/scm/webid-oidc/example-app.scm:146
msgid "This is not a valid HTTP method.\n"
msgstr "ce n’est pas une méthode HTTP valide.\n"
-#: src/scm/webid-oidc/example-app.scm:163
+#: src/scm/webid-oidc/example-app.scm:162
msgid "This is not a valid value for this header.\n"
msgstr "Ce n’est pas une valeur valide pour cet en-tête.\n"
-#: src/scm/webid-oidc/example-app.scm:201
+#: src/scm/webid-oidc/example-app.scm:200
msgid "Nothing to undo.\n"
msgstr "Rien à annuler.\n"
-#: src/scm/webid-oidc/example-app.scm:213
+#: src/scm/webid-oidc/example-app.scm:212
msgid "Nothing to redo.\n"
msgstr "Rien à refaire.\n"
-#: src/scm/webid-oidc/example-app.scm:273
+#: src/scm/webid-oidc/example-app.scm:272
msgid "Example app command|add-account"
msgstr "ajouter-compte"
-#: src/scm/webid-oidc/example-app.scm:275
+#: src/scm/webid-oidc/example-app.scm:274
msgid "Example app command|choose-account"
msgstr "choisir-compte"
-#: src/scm/webid-oidc/example-app.scm:277
+#: src/scm/webid-oidc/example-app.scm:276
msgid "Example app command|set-uri"
msgstr "définir-uri"
-#: src/scm/webid-oidc/example-app.scm:279
+#: src/scm/webid-oidc/example-app.scm:278
msgid "Example app command|set-method"
msgstr "définir-méthode"
-#: src/scm/webid-oidc/example-app.scm:281
+#: src/scm/webid-oidc/example-app.scm:280
msgid "Example app command|view-headers"
msgstr "voir-en-têtes"
-#: src/scm/webid-oidc/example-app.scm:283
+#: src/scm/webid-oidc/example-app.scm:282
msgid "Example app command|clear-headers"
msgstr "effacer-en-têtes"
-#: src/scm/webid-oidc/example-app.scm:285
+#: src/scm/webid-oidc/example-app.scm:284
msgid "Example app command|add-header"
msgstr "ajouter-en-tête"
-#: src/scm/webid-oidc/example-app.scm:287
+#: src/scm/webid-oidc/example-app.scm:286
msgid "Example app command|ok"
msgstr "ok"
-#: src/scm/webid-oidc/example-app.scm:289
+#: src/scm/webid-oidc/example-app.scm:288
msgid "Example app command|undo"
msgstr "annuler"
-#: src/scm/webid-oidc/example-app.scm:291
+#: src/scm/webid-oidc/example-app.scm:290
msgid "Example app command|redo"
msgstr "refaire"
-#: src/scm/webid-oidc/example-app.scm:301
+#: src/scm/webid-oidc/example-app.scm:300
#, scheme-format
msgid "To log in on ~a, please visit: ~a\n"
msgstr "Pour vous connecte avec ~a, veuillez visiter : ~a\n"
-#: src/scm/webid-oidc/example-app.scm:304
+#: src/scm/webid-oidc/example-app.scm:303
msgid "Then, paste the authorization code you get:\n"
msgstr "Ensuite, veuillez coller votre code d’autorisation :\n"
-#: src/scm/webid-oidc/example-app.scm:322
+#: src/scm/webid-oidc/example-app.scm:321
#, scheme-format
msgid ""
"Account: ~a\n"
@@ -860,50 +864,50 @@ msgstr ""
" - ~a : effectuer la requête.\n"
"\n"
-#: src/scm/webid-oidc/example-app.scm:341
+#: src/scm/webid-oidc/example-app.scm:340
msgid "Account:|unset"
msgstr "non défini"
-#: src/scm/webid-oidc/example-app.scm:345
+#: src/scm/webid-oidc/example-app.scm:344
msgid "URI:|unset"
msgstr "non défini"
-#: src/scm/webid-oidc/example-app.scm:349
+#: src/scm/webid-oidc/example-app.scm:348
msgid "Method:|unset"
msgstr "non définie"
-#: src/scm/webid-oidc/example-app.scm:352
+#: src/scm/webid-oidc/example-app.scm:351
msgid "Headers:|none"
msgstr "aucun"
-#: src/scm/webid-oidc/example-app.scm:356
+#: src/scm/webid-oidc/example-app.scm:355
msgid "list separator|, "
msgstr ", "
-#: src/scm/webid-oidc/example-app.scm:366
+#: src/scm/webid-oidc/example-app.scm:365
#, scheme-format
msgid "You can undo your last command with \"~a\".\n"
msgstr "Vous pouvez annuler votre dernière commande avec « ~a ».\n"
-#: src/scm/webid-oidc/example-app.scm:368
+#: src/scm/webid-oidc/example-app.scm:367
#, scheme-format
msgid "You can re-apply your last undone command with \"~a\".\n"
msgstr "Vous pouvez refaire votre dernière commande annulée avec « ~a ».\n"
-#: src/scm/webid-oidc/example-app.scm:369
+#: src/scm/webid-oidc/example-app.scm:368
msgid "Readline prompt|Command: "
msgstr "Commande : "
-#: src/scm/webid-oidc/example-app.scm:376
+#: src/scm/webid-oidc/example-app.scm:375
#, scheme-format
msgid "An error happened: ~a.\n"
msgstr "Une erreur est survenue : ~a.\n"
-#: src/scm/webid-oidc/example-app.scm:388
+#: src/scm/webid-oidc/example-app.scm:387
msgid "Please enter your identity provider: "
msgstr "Veuillez entrer votre fournisseur d’identité : "
-#: src/scm/webid-oidc/example-app.scm:394
+#: src/scm/webid-oidc/example-app.scm:393
msgid ""
"You don’t have other accounts available. Please add one with \"add-account"
"\".\n"
@@ -911,38 +915,38 @@ msgstr ""
"Vous n’avez pas d’autre compte disponible. Veuillez en ajouter un avec "
"« ajouter-compte ».\n"
-#: src/scm/webid-oidc/example-app.scm:400
+#: src/scm/webid-oidc/example-app.scm:399
#, scheme-format
msgid "- ~a: ~a\n"
msgstr "- ~a : ~a\n"
-#: src/scm/webid-oidc/example-app.scm:408
+#: src/scm/webid-oidc/example-app.scm:407
#, scheme-format
msgid "[1-~a] "
msgstr "[1-~a] "
-#: src/scm/webid-oidc/example-app.scm:416
+#: src/scm/webid-oidc/example-app.scm:415
msgid "Visit this URI: "
msgstr "Naviguer cette URI : "
-#: src/scm/webid-oidc/example-app.scm:422
+#: src/scm/webid-oidc/example-app.scm:421
msgid "Use this HTTP method [GET]: "
msgstr "Utiliser cette méthode HTTP [GET] : "
-#: src/scm/webid-oidc/example-app.scm:438
+#: src/scm/webid-oidc/example-app.scm:437
msgid "Which header? "
msgstr "Quel en-tête ? "
-#: src/scm/webid-oidc/example-app.scm:441
+#: src/scm/webid-oidc/example-app.scm:440
#, scheme-format
msgid "Which header value for ~a? "
msgstr "Quelle valeur pour l’en-tête ~a ? "
-#: src/scm/webid-oidc/example-app.scm:464
+#: src/scm/webid-oidc/example-app.scm:463
msgid "Please define an account and the URI.\n"
msgstr "Veuillez définir un compte et une URI.\n"
-#: src/scm/webid-oidc/example-app.scm:471
+#: src/scm/webid-oidc/example-app.scm:470
msgid "I don’t know that command.\n"
msgstr "Je ne connais pas cette commande.\n"
@@ -1106,11 +1110,11 @@ msgstr ""
"<p>Vous pouvez uniquement utiliser la méthode <emph>GET</emph> pour cette "
"ressource.</p>"
-#: src/scm/webid-oidc/identity-provider.scm:72
+#: src/scm/webid-oidc/identity-provider.scm:76
msgid "Warning: generating a new key pair."
msgstr "Attention : génération d'une nouvelle paire de clé."
-#: src/scm/webid-oidc/identity-provider.scm:132
+#: src/scm/webid-oidc/identity-provider.scm:136
msgid "reason-phrase|Not Found"
msgstr "Non Trouvé"
@@ -1119,114 +1123,102 @@ msgstr "Non Trouvé"
msgid "a replay has been detected with JTI ~s"
msgstr "une redite a été détectée avec le JTI ~s"
-#: src/scm/webid-oidc/jwk.scm:76
+#: src/scm/webid-oidc/jwk.scm:141
+msgid "the point and scalar are not on the same curve"
+msgstr "le point et le scalaire ne sont pas sur la même courbe elliptique"
+
+#: src/scm/webid-oidc/jwk.scm:236
#, scheme-format
msgid "the JWK is invalid: ~a"
msgstr "le JWK est invalide : ~a"
-#: src/scm/webid-oidc/jwk.scm:78
+#: src/scm/webid-oidc/jwk.scm:238
msgid "the JWK is invalid"
msgstr "le JWK est invalide"
-#: src/scm/webid-oidc/jwk.scm:87
-#, scheme-format
-msgid "unknown key type ~s"
-msgstr "type de clé inconnu ~s"
-
-#: src/scm/webid-oidc/jwk.scm:103
-#, scheme-format
-msgid "the public JWK is invalid: ~a"
-msgstr "la clé publique JWK est invalide : ~a"
-
-#: src/scm/webid-oidc/jwk.scm:105
-msgid "the public JWK is invalid"
-msgstr "la clé publique JWK est invalide"
-
-#: src/scm/webid-oidc/jwk.scm:136
-#, scheme-format
-msgid "cannot extract the public part of the key: ~a"
-msgstr "impossible d’extraire la partie publique de la clé : ~a"
-
-#: src/scm/webid-oidc/jwk.scm:138
-msgid "cannot extract the public part of the key"
-msgstr "impossible d’extraire la partie publique de la clé"
+#: src/scm/webid-oidc/jwk.scm:247
+msgid "cannot compute the key type"
+msgstr "impossible de calculer le type de clé"
-#: src/scm/webid-oidc/jwk.scm:188
-msgid "the JWKS is invalid, because it does not have keys"
-msgstr "le JWKS est invalide, parce qu’il n’a pas de clés"
+#: src/scm/webid-oidc/jwk.scm:284
+msgid "it is built as an RSA key or key pair, but it is not"
+msgstr ""
+"elle est construite comme une clé ou paire de clés RSA, mais ce n’en est pas "
+"une"
-#: src/scm/webid-oidc/jwk.scm:197
-#, scheme-format
-msgid "the JWKS is invalid: ~a"
-msgstr "le JWKS est invalide : ~a"
+#: src/scm/webid-oidc/jwk.scm:292
+msgid "it is built as an elliptic curve key or key pair, but it is not"
+msgstr ""
+"elle est construite comme une clé ou paire de clés sur une courbe "
+"elliptique, mais ce n’en est pas une"
-#: src/scm/webid-oidc/jwk.scm:199
-msgid "the JWKS is invalid"
-msgstr "le JWKS est invalide"
+#: src/scm/webid-oidc/jwk.scm:365
+msgid "this is neither a RSA key nor an elliptic curve key"
+msgstr "ce n’est ni une clé RSA ni une clé sur une courbe elliptique"
-#: src/scm/webid-oidc/jwk.scm:236
+#: src/scm/webid-oidc/jwk.scm:402
#, scheme-format
msgid "cannot fetch a JWKS: ~a"
msgstr "impossible de télécharger un JWKS : ~a"
-#: src/scm/webid-oidc/jwk.scm:238
+#: src/scm/webid-oidc/jwk.scm:404
msgid "cannot fetch a JWKS"
msgstr "impossible de télécharger un JWKS"
-#: src/scm/webid-oidc/jwk.scm:242
+#: src/scm/webid-oidc/jwk.scm:408
#, scheme-format
msgid "the request failed with ~s ~s"
msgstr "la requête a échoué avec ~s ~s"
-#: src/scm/webid-oidc/jwk.scm:247
+#: src/scm/webid-oidc/jwk.scm:413
msgid "missing content-type"
msgstr "type de contenu manquant"
-#: src/scm/webid-oidc/jwk.scm:252
+#: src/scm/webid-oidc/jwk.scm:418
#, scheme-format
msgid "invalid content-type: ~s"
msgstr "type de contenu invalide : ~s"
-#: src/scm/webid-oidc/jws.scm:72
+#: src/scm/webid-oidc/jws.scm:73
#, scheme-format
msgid "the JWS is invalid: ~a"
msgstr "le JWS est invalide : ~a"
-#: src/scm/webid-oidc/jws.scm:74
+#: src/scm/webid-oidc/jws.scm:75
msgid "the JWS is invalid"
msgstr "le JWS est invalide"
-#: src/scm/webid-oidc/jws.scm:93
+#: src/scm/webid-oidc/jws.scm:94
msgid "the JWS header does not have an \"alg\" field"
msgstr "l’en-tête JWS n’a pas de champ « alg »"
-#: src/scm/webid-oidc/jws.scm:101
+#: src/scm/webid-oidc/jws.scm:102
msgid "invalid JSON object as payload"
msgstr "objet JSON invalide comme charge utile"
-#: src/scm/webid-oidc/jws.scm:110
+#: src/scm/webid-oidc/jws.scm:111
#, scheme-format
msgid "invalid signature algorithm: ~s"
msgstr "algorithme de signature invalide : ~s"
-#: src/scm/webid-oidc/jws.scm:114
+#: src/scm/webid-oidc/jws.scm:115
#, scheme-format
msgid "invalid \"alg\" value: ~s"
msgstr "valeur « alg » invalide : ~s"
-#: src/scm/webid-oidc/jws.scm:119
+#: src/scm/webid-oidc/jws.scm:120
msgid "invalid JSON object as header"
msgstr "objet JSON d’en-tête invalide"
-#: src/scm/webid-oidc/jws.scm:121
+#: src/scm/webid-oidc/jws.scm:122
msgid "this is not a pair"
msgstr "ce n’est pas une paire"
-#: src/scm/webid-oidc/jws.scm:138
+#: src/scm/webid-oidc/jws.scm:139
msgid "the encoded JWS is not in 3 parts"
msgstr "le JWS encodé n’est pas en 3 parties"
-#: src/scm/webid-oidc/jws.scm:149
+#: src/scm/webid-oidc/jws.scm:150
#, scheme-format
msgid ""
"the encoded JWS header or payload is not a JSON object encoded in base64: ~a"
@@ -1234,41 +1226,41 @@ msgstr ""
"l’en-tête ou la charge utile du JWS encodé n’est pas un objet JSON encodé en "
"base64 : ~a"
-#: src/scm/webid-oidc/jws.scm:151
+#: src/scm/webid-oidc/jws.scm:152
msgid ""
"the encoded JWS header or payload is not a JSON object encoded in base64"
msgstr ""
"l’en-tête ou la charge utile du JWS encodé n’est pas un objet JSON encodé en "
"base64"
-#: src/scm/webid-oidc/jws.scm:210
+#: src/scm/webid-oidc/jws.scm:211
msgid "the JWS is not signed by any of the expected set of public keys"
msgstr "le JWS n’est signé par aucune des clés attendues"
-#: src/scm/webid-oidc/jws.scm:221
+#: src/scm/webid-oidc/jws.scm:222
#, scheme-format
msgid "while verifying the JWS signature: ~a"
msgstr "en vérifiant la signature du JWS : ~a"
-#: src/scm/webid-oidc/jws.scm:223
+#: src/scm/webid-oidc/jws.scm:224
msgid "an unexpected error happened while verifying a JWS"
msgstr "une erreur inattendue est survenue pendant la vérification d’un JWS"
-#: src/scm/webid-oidc/jws.scm:240
+#: src/scm/webid-oidc/jws.scm:253
#, scheme-format
msgid "cannot decode a JWS: ~a"
msgstr "impossible de décoder un JWS : ~a"
-#: src/scm/webid-oidc/jws.scm:242
+#: src/scm/webid-oidc/jws.scm:255
msgid "cannot decode a JWS"
msgstr "impossible de décoder un JWS"
-#: src/scm/webid-oidc/jws.scm:262
+#: src/scm/webid-oidc/jws.scm:272
#, scheme-format
msgid "cannot encode a JWS: ~a"
msgstr "impossible d’encoder un JWS : ~a"
-#: src/scm/webid-oidc/jws.scm:264
+#: src/scm/webid-oidc/jws.scm:274
msgid "cannot encode a JWS"
msgstr "impossible d’encoder un JWS"
@@ -1310,25 +1302,25 @@ msgstr "« solid_oidc_supported » doit valoir ~s, pas ~s"
msgid "invalid JSON object"
msgstr "objet JSON invalide"
-#: src/scm/webid-oidc/oidc-configuration.scm:174
+#: src/scm/webid-oidc/oidc-configuration.scm:178
#, scheme-format
msgid "cannot fetch the OIDC configuration: ~a"
msgstr "impossible de télécharger la configuration OIDC : ~a"
-#: src/scm/webid-oidc/oidc-configuration.scm:176
+#: src/scm/webid-oidc/oidc-configuration.scm:180
msgid "cannot fetch the OIDC configuration"
msgstr "impossible de télécharger la configuration OIDC"
-#: src/scm/webid-oidc/oidc-configuration.scm:184
+#: src/scm/webid-oidc/oidc-configuration.scm:188
#, scheme-format
msgid "the server responded with ~s ~s"
msgstr "le serveur a répondu ~s ~s"
-#: src/scm/webid-oidc/oidc-configuration.scm:189
+#: src/scm/webid-oidc/oidc-configuration.scm:193
msgid "there is no content-type"
msgstr "il n’y a pas de type de contenu"
-#: src/scm/webid-oidc/oidc-configuration.scm:194
+#: src/scm/webid-oidc/oidc-configuration.scm:198
#, scheme-format
msgid "unexpected content-type: ~s"
msgstr "type de contenu inattendu : ~s"
@@ -2563,6 +2555,34 @@ msgstr ""
"supporté.</p>"
#, scheme-format
+#~ msgid "unknown key type ~s"
+#~ msgstr "type de clé inconnu ~s"
+
+#, scheme-format
+#~ msgid "the public JWK is invalid: ~a"
+#~ msgstr "la clé publique JWK est invalide : ~a"
+
+#~ msgid "the public JWK is invalid"
+#~ msgstr "la clé publique JWK est invalide"
+
+#, scheme-format
+#~ msgid "cannot extract the public part of the key: ~a"
+#~ msgstr "impossible d’extraire la partie publique de la clé : ~a"
+
+#~ msgid "cannot extract the public part of the key"
+#~ msgstr "impossible d’extraire la partie publique de la clé"
+
+#~ msgid "the JWKS is invalid, because it does not have keys"
+#~ msgstr "le JWKS est invalide, parce qu’il n’a pas de clés"
+
+#, scheme-format
+#~ msgid "the JWKS is invalid: ~a"
+#~ msgstr "le JWKS est invalide : ~a"
+
+#~ msgid "the JWKS is invalid"
+#~ msgstr "le JWKS est invalide"
+
+#, scheme-format
#~ msgid ""
#~ "Usage: ~a COMMAND [OPTIONS]...\n"
#~ "See --~a (-h).\n"
diff --git a/src/scm/webid-oidc/client/accounts.scm b/src/scm/webid-oidc/client/accounts.scm
index 626cc6a..54c6e07 100644
--- a/src/scm/webid-oidc/client/accounts.scm
+++ b/src/scm/webid-oidc/client/accounts.scm
@@ -26,6 +26,7 @@
#:use-module (srfi srfi-9)
#:use-module (srfi srfi-19)
#:use-module (webid-oidc errors)
+ #:use-module (webid-oidc web-i18n)
#:use-module ((webid-oidc parameters) #:prefix p:)
#:use-module ((webid-oidc stubs) #:prefix stubs:)
#:use-module ((webid-oidc oidc-id-token) #:prefix id:)
@@ -85,12 +86,7 @@
)
#:declarative? #t)
-(define (G_ text)
- (let ((out (gettext text)))
- (if (string=? out text)
- ;; No translation, disambiguate
- (car (reverse (string-split text #\|)))
- out)))
+(define <jwk:key-pair> jwk:<key-pair>)
;; This exception is continuable! Continue with the authorization
;; code.
@@ -159,7 +155,7 @@
(define-method (->sexp (account <account>))
`(begin
- (use-modules (oop goops) (webid-oidc client accounts))
+ (use-modules (oop goops) (webid-oidc client accounts) (webid-oidc jwk))
(make <account>
#:subject ,(uri->string (subject account))
#:issuer ,(uri->string (issuer account))
@@ -175,7 +171,7 @@
(if refresh-token
`(#:refresh-token ,refresh-token)
'()))
- #:key-pair (quote ,(key-pair account)))))
+ #:key-pair (jwk->key (quote ,(key->jwk (key-pair account)))))))
(define-method (write (account <account>) port)
(let ((code (->sexp account)))
@@ -496,7 +492,7 @@
(slot-set! ret 'refresh-token refresh-token)
ret))
-(define-method (set-key-pair (a <account>) key-pair)
+(define-method (set-key-pair (a <account>) (key-pair <jwk:key-pair>))
(let ((ret (shallow-clone a)))
(slot-set! ret 'key-pair key-pair)
ret))
diff --git a/src/scm/webid-oidc/client/client.scm b/src/scm/webid-oidc/client/client.scm
index 1bf1c7c..5da701b 100644
--- a/src/scm/webid-oidc/client/client.scm
+++ b/src/scm/webid-oidc/client/client.scm
@@ -58,6 +58,8 @@
)
#:declarative? #t)
+(define <jwk:key-pair> jwk:<key-pair>)
+
(define-class <client> ()
(client-id #:init-keyword #:client-id #:getter client-id)
(key-pair #:init-keyword #:key-pair #:getter client-key-pair)
@@ -65,10 +67,10 @@
(define-method (->sexp (client <client>))
`(begin
- (use-modules (oop goops) (webid-oidc client))
+ (use-modules (oop goops) (webid-oidc client) (webid-oidc jwk))
(make <client>
#:client-id ,(uri->string (client-id client))
- #:key-pair (quote ,(client-key-pair client))
+ #:key-pair (jwk->key (quote ,(key->jwk (client-key-pair client))))
#:redirect-uri ,(uri->string (client-redirect-uri client)))))
(define-method (write (client <client>) port)
@@ -92,7 +94,7 @@
(match `(,client-id ,key-pair ,redirect-uri)
(((or (? string? (= string->uri (? uri? client-id)))
(? uri? client-id))
- (? jwk:jwk? client-key)
+ (? (cute is-a? <> <jwk:key-pair>) client-key)
(or (? string? (= string->uri (? uri? redirect-uri)))
(? uri? redirect-uri)))
(begin
diff --git a/src/scm/webid-oidc/dpop-proof.scm b/src/scm/webid-oidc/dpop-proof.scm
index cc756d3..5e01235 100644
--- a/src/scm/webid-oidc/dpop-proof.scm
+++ b/src/scm/webid-oidc/dpop-proof.scm
@@ -28,6 +28,7 @@
#:use-module (ice-9 match)
#:use-module (srfi srfi-19)
#:use-module (srfi srfi-26)
+ #:use-module (oop goops)
#:declarative? #t
#:export
(
@@ -81,6 +82,10 @@
make-invalid-dpop-proof
invalid-dpop-proof?)
+(define (parse-jwk data)
+ (false-if-exception
+ (jwk->key data)))
+
(define (the-dpop-proof x)
(with-exception-handler
(lambda (error)
@@ -131,7 +136,7 @@
,@(if iat '() '("iat"))))))
`(((alg . ,(symbol->string alg))
(typ . "dpop+jwt")
- (jwk . ,(strip jwk))
+ (jwk . ,(key->jwk (public-key jwk)))
,@other-header-fields)
. ((jti . ,jti)
(htm . ,(symbol->string htm))
@@ -188,9 +193,11 @@
((('typ . incorrect) header ...)
(fail (format #f (G_ "the \"typ\" field should be \"dpop+jwt\", not ~s")
incorrect)))
- ((('jwk . (? jwk-public? given-jwk)) header ...)
- (examine-header header alg typ (or jwk (the-public-jwk given-jwk))
+ ((('jwk . (= parse-jwk (? (cute is-a? <> <public-key>) given-jwk))) header ...)
+ (examine-header header alg typ (or jwk given-jwk)
other-header-fields))
+ ((('jwk . (= parse-jwk (? (cute is-a? <> <key-pair>) given-jwk))) header ...)
+ (fail (format #f (G_ "the \"jwk\" field should not contain the private key"))))
((('jwk . incorrect) header ...)
(fail (format #f (G_ "the \"jwk\" field should be a valid public key, not ~s")
incorrect)))
@@ -213,7 +220,7 @@
(define (dpop-proof-jwk proof)
(match (the-dpop-proof proof)
((header . _)
- (the-public-jwk (assq-ref header 'jwk)))))
+ (jwk->key (assq-ref header 'jwk)))))
(define (dpop-proof-jti proof)
(match (the-dpop-proof proof)
@@ -356,7 +363,7 @@
(make-dpop-invalid-ath (dpop-proof-ath decoded) access-token)
(make-exception-with-message final-message)))))))
(if (string? cnf/check)
- (unless (equal? cnf/check (stubs:jkt (dpop-proof-jwk decoded)))
+ (unless (equal? cnf/check (jkt (dpop-proof-jwk decoded)))
(let ((final-message
(format #f (G_ "the DPoP proof is signed with the wrong key"))))
(raise-exception
@@ -376,7 +383,7 @@
(make-exception-with-message final-message)
error))))
(lambda ()
- (unless (cnf/check (stubs:jkt (dpop-proof-jwk decoded)))
+ (unless (cnf/check (jkt (dpop-proof-jwk decoded)))
;; You should throw an error instead!
(fail (G_ "the cnf/check function returned #f"))))))
(parameterize ((p:current-date current-date))
@@ -410,7 +417,7 @@
(the-dpop-proof
`(((alg . ,(symbol->string alg))
(typ . "dpop+jwt")
- (jwk . ,client-key))
+ (jwk . ,(key->jwk (public-key client-key))))
. ((jti . ,(stubs:random 12))
(htm . ,(symbol->string htm))
(htu . ,(uri->string htu))
diff --git a/src/scm/webid-oidc/example-app.scm b/src/scm/webid-oidc/example-app.scm
index 9bf99c1..c293d69 100644
--- a/src/scm/webid-oidc/example-app.scm
+++ b/src/scm/webid-oidc/example-app.scm
@@ -23,7 +23,6 @@
#:use-module ((webid-oidc stubs) #:prefix stubs:)
#:use-module ((webid-oidc refresh-token) #:prefix refresh:)
#:use-module ((webid-oidc config) #:prefix cfg:)
- #:use-module ((webid-oidc jwk) #:prefix jwk:)
#:use-module (web uri)
#:use-module (web client)
#:use-module (web request)
diff --git a/src/scm/webid-oidc/identity-provider.scm b/src/scm/webid-oidc/identity-provider.scm
index 7f1fb48..cf06b62 100644
--- a/src/scm/webid-oidc/identity-provider.scm
+++ b/src/scm/webid-oidc/identity-provider.scm
@@ -41,6 +41,7 @@
#:use-module (sxml match)
#:use-module (srfi srfi-19)
#:use-module (rnrs bytevectors)
+ #:use-module (oop goops)
#:declarative? #t
#:export
(
@@ -66,7 +67,10 @@
(let ((key
(catch #t
(lambda ()
- (call-with-input-file key-file stubs:json->scm))
+ (call-with-input-file key-file
+ (lambda (port)
+ (jwk->key
+ (stubs:json->scm port)))))
(lambda error
(format (current-error-port)
(G_ "Warning: generating a new key pair."))
@@ -74,7 +78,7 @@
(stubs:call-with-output-file*
key-file
(lambda (port)
- (stubs:scm->json k port #:pretty #t)))
+ (stubs:scm->json (key->jwk k) port #:pretty #t)))
k)))))
(let ((alg
(if (eq? (kty key) 'RSA)
@@ -109,7 +113,7 @@
(exp-sec (+ current-sec 3600))
(exp (time-utc->date
(make-time time-utc 0 exp-sec))))
- (serve-jwks exp (make-jwks (list key)))))
+ (serve (make <jwks> #:keys (list key)) exp)))
((same-uri? uri authorization-endpoint-uri #:skip-query #t)
(authorization-endpoint request request-body))
((same-uri? uri token-endpoint-uri)
diff --git a/src/scm/webid-oidc/jwk.scm b/src/scm/webid-oidc/jwk.scm
index e4f2119..7675d04 100644
--- a/src/scm/webid-oidc/jwk.scm
+++ b/src/scm/webid-oidc/jwk.scm
@@ -25,26 +25,28 @@
#:use-module (web response)
#:use-module (web client)
#:use-module (rnrs bytevectors)
+ #:use-module (oop goops)
#:declarative? #t
#:export
(
- the-jwk
- jwk?
+ <private-key>
+ <public-key>
+ <key-pair> public-key private-key
+ <rsa-key-pair>
+ <ec-key-pair>
+ <rsa-private-key> rsa-d rsa-p rsa-q rsa-dp rsa-dq rsa-qi
+ <rsa-public-key> rsa-n rsa-e
+ <ec-scalar> ec-crv ec-x ec-y
+ <ec-point> ec-z
+ <jwks> keys
+
+ check-key
+ key->jwk
+ jwk->key
kty
- the-public-jwk
- jwk-public?
- strip
jkt
- make-rsa-public-key
- make-rsa-private-key
- make-ec-point
- make-ec-scalar
generate-key
- the-jwks
- jwks?
- make-jwks
- jwks-keys
- serve-jwks
+ serve
get-jwks
&not-a-jwk
@@ -68,7 +70,165 @@
make-not-a-jwks
not-a-jwks?)
-(define (the-jwk x)
+(define-class <private-key> ())
+
+(define-class <public-key> ())
+
+(define-class <key-pair> ()
+ (public-key #:init-keyword #:public-key #:accessor public-key)
+ (private-key #:init-keyword #:private-key #:accessor private-key))
+
+(define-class <rsa-key-pair> (<key-pair>))
+
+(define-class <ec-key-pair> (<key-pair>)
+ (crv #:init-keyword #:crv #:accessor ec-crv))
+
+(define-class <rsa-private-key> (<private-key>)
+ (d #:init-keyword #:d #:accessor rsa-d)
+ (p #:init-keyword #:p #:accessor rsa-p)
+ (q #:init-keyword #:q #:accessor rsa-q)
+ (dp #:init-keyword #:dp #:accessor rsa-dp)
+ (dq #:init-keyword #:dq #:accessor rsa-dq)
+ (qi #:init-keyword #:qi #:accessor rsa-qi))
+
+(define-class <rsa-public-key> (<public-key>)
+ (n #:init-keyword #:n #:accessor rsa-n)
+ (e #:init-keyword #:e #:accessor rsa-e))
+
+(define-class <ec-scalar> (<private-key>)
+ (crv #:init-keyword #:crv #:accessor ec-crv)
+ (z #:init-keyword #:z #:accessor ec-z))
+
+(define-class <ec-point> (<public-key>)
+ (crv #:init-keyword #:crv #:accessor ec-crv)
+ (x #:init-keyword #:x #:accessor ec-x)
+ (y #:init-keyword #:y #:accessor ec-y))
+
+(define-method (initialize-key-pair (key <key-pair>) (public <rsa-public-key>) (private <rsa-private-key>))
+ (set! (public-key key) public)
+ (set! (private-key key) private))
+
+(define-method (initialize-key-pair (key <key-pair>) (public <ec-point>) (private <ec-scalar>))
+ (set! (public-key key) public)
+ (set! (private-key key) private))
+
+(define-method (initialize (key <key-pair>) initargs)
+ (next-method)
+ (let-keywords
+ initargs #t
+ ((public-key #f)
+ (private-key #f))
+ (initialize-key-pair key public-key private-key))
+ (check-key key))
+
+(define-method (initialize-rsa-key-pair (key <rsa-key-pair>) (public <rsa-public-key>) (private <rsa-private-key>))
+ #t)
+
+(define-method (initialize (key <rsa-key-pair>) initargs)
+ (next-method)
+ (let-keywords
+ initargs #t
+ ((public-key #f)
+ (private-key #f))
+ (initialize-rsa-key-pair key public-key private-key))
+ (check-key key))
+
+(define-method (initialize-ec-key-pair (key <ec-key-pair>) (public <ec-point>) (private <ec-scalar>))
+ (unless (eq? (ec-crv public) (ec-crv private))
+ (raise-exception
+ (make-exception
+ (make-not-a-jwk)
+ (make-exception-with-message (G_ "the point and scalar are not on the same curve")))))
+ (set! (ec-crv key) (ec-crv public)))
+
+(define-method (initialize (key <ec-key-pair>) initargs)
+ (next-method)
+ (let-keywords
+ initargs #t
+ ((public-key #f)
+ (private-key #f))
+ (initialize-ec-key-pair key public-key private-key)
+ (check-key key)))
+
+(define-method (initialize (key <rsa-private-key>) initargs)
+ (next-method)
+ (check-key key))
+
+(define-method (initialize (key <rsa-public-key>) initargs)
+ (next-method)
+ (check-key key))
+
+(define-method (initialize (key <ec-point>) initargs)
+ (next-method)
+ (check-key key))
+
+(define-method (initialize (key <ec-scalar>) initargs)
+ (next-method)
+ (check-key key))
+
+(define-method (rsa-d (key <rsa-key-pair>))
+ (rsa-d (private-key key)))
+
+(define-method (rsa-p (key <rsa-key-pair>))
+ (rsa-p (private-key key)))
+
+(define-method (rsa-q (key <rsa-key-pair>))
+ (rsa-q (private-key key)))
+
+(define-method (rsa-dp (key <rsa-key-pair>))
+ (rsa-dp (private-key key)))
+
+(define-method (rsa-dq (key <rsa-key-pair>))
+ (rsa-dq (private-key key)))
+
+(define-method (rsa-qi (key <rsa-key-pair>))
+ (rsa-qi (private-key key)))
+
+(define-method (rsa-n (key <rsa-key-pair>))
+ (rsa-n (public-key key)))
+
+(define-method (rsa-e (key <rsa-key-pair>))
+ (rsa-e (public-key key)))
+
+(define-method (ec-x (key <ec-key-pair>))
+ (ec-x (public-key key)))
+
+(define-method (ec-y (key <ec-key-pair>))
+ (ec-y (public-key key)))
+
+(define-method (ec-z (key <ec-key-pair>))
+ (ec-z (private-key key)))
+
+(define-method (equal? (x <key-pair>) (y <key-pair>))
+ (and (equal? (public-key x) (public-key y))
+ (equal? (private-key x) (private-key y))))
+
+(define-method (equal? (x <public-key>) (y <public-key>))
+ #f)
+
+(define-method (equal? (x <private-key>) (y <private-key>))
+ #f)
+
+(define-method (equal? (x <rsa-public-key>) (y <rsa-public-key>))
+ (and (equal? (rsa-n x) (rsa-n y))
+ (equal? (rsa-e x) (rsa-e y))))
+
+(define-method (equal? (x <rsa-private-key>) (y <rsa-private-key>))
+ (and (equal? (rsa-d x) (rsa-d y))
+ (equal? (rsa-p x) (rsa-p y))
+ (equal? (rsa-q x) (rsa-q y))
+ (equal? (rsa-dp x) (rsa-dp y))
+ (equal? (rsa-dq x) (rsa-dq y))
+ (equal? (rsa-qi x) (rsa-qi y))))
+
+(define-method (equal? (x <ec-point>) (y <ec-point>))
+ (and (equal? (ec-x x) (ec-x y))
+ (equal? (ec-y x) (ec-y y))))
+
+(define-method (equal? (x <ec-scalar>) (y <ec-scalar>))
+ (equal? (ec-z x) (ec-z y)))
+
+(define (check-and-kty key)
(with-exception-handler
(lambda (error)
(let ((final-message
@@ -82,150 +242,156 @@
(make-exception-with-message final-message)
error))))
(lambda ()
- (let ((kty (stubs:kty x)))
- (unless (or (eq? kty 'EC) (eq? kty 'RSA))
- (fail (format #f (G_ "unknown key type ~s")
- kty)))
- x))))
+ (let ((kty (stubs:kty (key->jwk key))))
+ (unless kty
+ (fail (G_ "cannot compute the key type")))
+ kty))))
-(define (jwk? x)
- (false-if-exception
- (and (the-jwk x) #t)))
+(define-method (key->jwk (key <key-pair>))
+ (append (key->jwk (public-key key))
+ (key->jwk (private-key key))))
-(define (kty x)
- (stubs:kty (the-jwk x)))
+(define-method (key->jwk (key <rsa-private-key>))
+ `((d . ,(rsa-d key))
+ (p . ,(rsa-p key))
+ (q . ,(rsa-q key))
+ (dp . ,(rsa-dp key))
+ (dq . ,(rsa-dq key))
+ (qi . ,(rsa-qi key))))
-(define (the-public-jwk x)
- (with-exception-handler
- (lambda (error)
- (let ((final-message
- (if (exception-with-message? error)
- (format #f (G_ "the public JWK is invalid: ~a")
- (exception-message error))
- (format #f (G_ "the public JWK is invalid")))))
- (raise-exception
- (make-exception
- (make-not-a-jwk)
- (make-exception-with-message final-message)
- error))))
- (lambda ()
- (let ((key (the-jwk x)))
- (let ((crv (assq-ref key 'crv))
- (x (assq-ref key 'x))
- (y (assq-ref key 'y))
- (n (assq-ref key 'n))
- (e (assq-ref key 'e)))
- (let ((ec-part `((crv . ,crv)
- (x . ,x)
- (y . ,y)))
- (rsa-part `((n . ,n)
- (e . ,e))))
- (case (stubs:kty key)
- ((EC) ec-part)
- ((RSA) rsa-part))))))))
-
-(define (jwk-public? key)
- (false-if-exception
- (and (the-public-jwk key) #t)))
-
-(define (strip key)
- (with-exception-handler
- (lambda (error)
- (let ((final-message
- (if (exception-with-message? error)
- (format #f (G_ "cannot extract the public part of the key: ~a")
- (exception-message error))
- (format #f (G_ "cannot extract the public part of the key")))))
- (raise-exception
- (make-exception
- (make-not-a-jwk)
- (make-exception-with-message final-message)
- error))))
- (lambda ()
- (stubs:strip-key key))))
+(define-method (key->jwk (key <rsa-public-key>))
+ `((n . ,(rsa-n key))
+ (e . ,(rsa-e key))))
+
+(define-method (key->jwk (key <ec-point>))
+ `((crv . ,(symbol->string (ec-crv key)))
+ (x . ,(ec-x key))
+ (y . ,(ec-y key))))
+
+(define-method (key->jwk (key <ec-scalar>))
+ `((crv . ,(symbol->string (ec-crv key)))
+ (z . ,(ec-z key))))
+
+(define-method (check-key key)
+ (check-and-kty (key->jwk key)))
+
+(define (check-rsa-key key)
+ (unless (eq? (check-and-kty key) 'RSA)
+ (raise-exception
+ (make-exception
+ (make-not-a-jwk)
+ (make-exception-with-message
+ (format #f (G_ "it is built as an RSA key or key pair, but it is not")))))))
+
+(define (check-ec-key key)
+ (unless (eq? (check-and-kty key) 'EC)
+ (raise-exception
+ (make-exception
+ (make-not-a-jwk)
+ (make-exception-with-message
+ (format #f (G_ "it is built as an elliptic curve key or key pair, but it is not")))))))
+
+(define-method (check-key (key <rsa-key-pair>))
+ (check-rsa-key key))
+
+(define-method (check-key (key <rsa-public-key>))
+ (check-rsa-key key))
+
+(define-method (check-key (key <rsa-private-key>))
+ (check-rsa-key key))
+
+(define-method (check-key (key <ec-key-pair>))
+ (check-ec-key key))
+
+(define-method (check-key (key <ec-point>))
+ (check-ec-key key))
+
+(define-method (check-key (key <ec-scalar>))
+ (check-ec-key key))
+
+(define-method (kty (key <rsa-key-pair>)) 'RSA)
+(define-method (kty (key <rsa-public-key>)) 'RSA)
+(define-method (kty (key <rsa-private-key>)) 'RSA)
+
+(define-method (kty (key <ec-key-pair>)) 'EC)
+(define-method (kty (key <ec-point>)) 'EC)
+(define-method (kty (key <ec-scalar>)) 'EC)
+
+(define-method (public-key (key <public-key>))
+ key)
+
+(define-method (private-key (key <private-key>))
+ key)
+
+(define (jwk->key fields)
+ (let ((kty (stubs:kty fields)))
+ (case kty
+ ((RSA)
+ (let ((d (assq-ref fields 'd))
+ (p (assq-ref fields 'p))
+ (q (assq-ref fields 'q))
+ (dp (assq-ref fields 'dp))
+ (dq (assq-ref fields 'dq))
+ (qi (assq-ref fields 'qi))
+ (n (assq-ref fields 'n))
+ (e (assq-ref fields 'e)))
+ (let ((public
+ (and n e
+ (make <rsa-public-key> #:n n #:e e)))
+ (private
+ (and d p q dp dq qi
+ (make <rsa-private-key> #:d d #:p p #:q q #:dp dp #:dq dq #:qi qi))))
+ (if (and public private)
+ (make <rsa-key-pair> #:public-key public #:private-key private)
+ (or public private)))))
+ ((EC)
+ (let ((crv (string->symbol (assq-ref fields 'crv)))
+ (x (assq-ref fields 'x))
+ (y (assq-ref fields 'y))
+ (z (assq-ref fields 'z)))
+ (let ((public
+ (and x y
+ (make <ec-point> #:crv crv #:x x #:y y)))
+ (private
+ (and z
+ (make <ec-scalar> #:crv crv #:z z))))
+ (if (and public private)
+ (make <ec-key-pair> #:public-key public #:private-key private)
+ (or public private)))))
+ (else
+ (raise-exception
+ (make-exception
+ (make-not-a-jwk)
+ (make-exception-with-message (G_ "this is neither a RSA key nor an elliptic curve key"))))))))
(define (jkt x)
- (stubs:jkt (the-public-jwk x)))
-
-(define (make-rsa-public-key n e)
- (the-public-jwk
- `((n . ,n)
- (e . ,e))))
-
-(define (make-rsa-private-key d p q dp dq qi)
- (the-jwk
- `((d . ,d)
- (p . ,p)
- (q . ,q)
- (dp . ,dp)
- (dq . ,dq)
- (qi . ,qi))))
-
-(define (make-ec-point crv x y)
- (if (symbol? crv)
- (make-ec-point (symbol->string crv) x y)
- (the-public-jwk
- `((crv . ,crv)
- (x . ,x)
- (y . ,y)))))
-
-(define (make-ec-scalar crv d)
- (if (symbol? crv)
- (make-ec-scalar (symbol->string crv) d)
- (the-jwk
- `((crv . ,crv)
- (d . ,d)))))
-
-(define generate-key stubs:generate-key)
-
-(define (the-public-keys keys)
- (map the-public-jwk keys))
-
-(define (the-jwks jwks)
- (let ((keys (vector->list (assoc-ref jwks 'keys))))
- (unless keys
- (let ((final-message
- (format #f (G_ "the JWKS is invalid, because it does not have keys"))))
- (raise-exception
- (make-exception
- (make-not-a-jwks)
- (make-exception-with-message final-message)))))
- (with-exception-handler
- (lambda (error)
- (let ((final-message
- (if (exception-with-message? error)
- (format #f (G_ "the JWKS is invalid: ~a")
- (exception-message error))
- (format #f (G_ "the JWKS is invalid")))))
- (raise-exception
- (make-exception
- (make-not-a-jwks)
- (make-exception-with-message final-message)
- error))))
- (lambda ()
- `((keys . ,(list->vector (the-public-keys keys))))))))
+ (stubs:jkt (key->jwk x)))
-(define (jwks? jwks)
- (false-if-exception
- (and (the-jwks jwks) #t)))
+(define (generate-key . args)
+ (jwk->key (apply stubs:generate-key args)))
-(define (make-jwks keys)
- (if (vector? keys)
- (make-jwks (vector->list keys))
- (let ((pubs (list->vector (map strip keys))))
- (the-jwks `((keys . ,pubs))))))
+(define-class <jwks> ()
+ (keys #:init-keyword #:keys #:accessor keys))
-(define (jwks-keys jwks)
- (vector->list (assq-ref (the-jwks jwks) 'keys)))
+(define-method (initialize (jwks <jwks>) initargs)
+ (next-method)
+ (let-keywords
+ initargs #t
+ ((keys '()))
+ (slot-set! jwks 'keys (map public-key keys))))
-(define (serve-jwks expiration-date jwks)
- (values (build-response
- #:headers `((content-type . (application/json))
- (expires . ,expiration-date)))
- (stubs:scm->json-string (the-jwks jwks))))
+(define-method (serve (jwks <jwks>) expiration-date)
+ (values
+ (build-response
+ #:headers `((content-type . (application/json))
+ (expires . ,expiration-date)))
+ (stubs:scm->json-string
+ `((keys
+ . ,(list->vector
+ (map key->jwk (keys jwks))))))))
-(define* (get-jwks uri #:key (http-get http-get))
- (receive (response response-body) (http-get uri)
+(define* (get-jwks uri #:key (http-request http-request))
+ (receive (response response-body) (http-request uri)
(with-exception-handler
(lambda (error)
(raise-exception
@@ -252,4 +418,6 @@
(fail (format #f (G_ "invalid content-type: ~s") content-type)))
(unless (string? response-body)
(set! response-body (utf8->string response-body)))
- (the-jwks (stubs:json-string->scm response-body)))))))
+ (let ((data (stubs:json-string->scm response-body)))
+ (let ((keys (vector->list (assq-ref data 'keys))))
+ (make <jwks> #:keys (map jwk->key keys)))))))))
diff --git a/src/scm/webid-oidc/jws.scm b/src/scm/webid-oidc/jws.scm
index 24a8bbc..3e5e50b 100644
--- a/src/scm/webid-oidc/jws.scm
+++ b/src/scm/webid-oidc/jws.scm
@@ -23,6 +23,7 @@
#:use-module (ice-9 receive)
#:use-module (ice-9 exceptions)
#:use-module (ice-9 match)
+ #:use-module (oop goops)
#:declarative? #t
#:export
(
@@ -228,10 +229,22 @@
error))))
(try-with-key keys))
(lambda ()
- (stubs:verify alg next-key payload signature))
+ (stubs:verify alg (key->jwk next-key) payload signature))
#:unwind? #t
#:unwind-for-type stubs:&invalid-signature)))))
+;; For verification, we can supply a JWKS, or a public key, or a list
+;; of public keys. The JWKS case is handled in (webid-oidc jwk).
+
+(define-method (keys (key <public-key>))
+ (list key))
+
+(define-method (keys (key <key-pair>))
+ (list (public-key key)))
+
+(define-method (keys (keys <list>))
+ (map public-key keys))
+
(define (jws-decode str lookup-keys)
(with-exception-handler
(lambda (error)
@@ -248,11 +261,8 @@
(lambda ()
(parse str
(lambda (jws payload signature)
- (let ((keys (lookup-keys jws)))
- (let ((keys (cond ((jwk? keys) (list keys))
- ((jwks? keys) (jwks-keys keys))
- (else keys))))
- (verify-any (jws-alg jws) keys payload signature))))))))
+ (let ((k (keys (lookup-keys jws))))
+ (verify-any (jws-alg jws) k payload signature)))))))
(define (jws-encode jws key)
(with-exception-handler
@@ -275,5 +285,5 @@
(let ((header (stubs:base64-encode header))
(payload (stubs:base64-encode payload)))
(let ((payload (string-append header "." payload)))
- (let ((signature (stubs:sign (jws-alg jws) key payload)))
+ (let ((signature (stubs:sign (jws-alg jws) (key->jwk key) payload)))
(string-append payload "." signature))))))))))
diff --git a/src/scm/webid-oidc/oidc-configuration.scm b/src/scm/webid-oidc/oidc-configuration.scm
index d9aab84..2233d95 100644
--- a/src/scm/webid-oidc/oidc-configuration.scm
+++ b/src/scm/webid-oidc/oidc-configuration.scm
@@ -141,8 +141,12 @@
(define oidc-configuration-token-endpoint
(uri-field 'token_endpoint))
-(define (oidc-configuration-jwks cfg . args)
- (apply get-jwks (oidc-configuration-jwks-uri cfg) args))
+(define* (oidc-configuration-jwks cfg #:key (http-get http-get))
+ (let ((http-request-for-get-jwks
+ (lambda* (uri #:key (method 'GET))
+ (http-get uri))))
+ (get-jwks (oidc-configuration-jwks-uri cfg)
+ #:http-request http-request-for-get-jwks)))
(define (serve-oidc-configuration expiration-date cfg)
(values (build-response #:headers `((content-type . (application/json))
diff --git a/tests/dpop-proof-valid.scm b/tests/dpop-proof-valid.scm
index ec6b32a..893687d 100644
--- a/tests/dpop-proof-valid.scm
+++ b/tests/dpop-proof-valid.scm
@@ -1,4 +1,4 @@
-;; webid-oidc, implementation of the Solid specification
+;; disfluid, implementation of the Solid specification
;; Copyright (C) 2020, 2021 Vivien Kraus
;; This program is free software: you can redistribute it and/or modify
diff --git a/tests/jwk-kty-rsa-incorrect.scm b/tests/jwk-kty-rsa-incorrect.scm
index a13b430..c86297a 100644
--- a/tests/jwk-kty-rsa-incorrect.scm
+++ b/tests/jwk-kty-rsa-incorrect.scm
@@ -22,14 +22,13 @@
(with-test-environment
"jwk-kty-rsa-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)))))
+ (with-exception-handler
+ (lambda (exn)
+ (unless (not-a-jwk? exn)
+ (exit 1))
+ #f)
+ (lambda ()
+ (jwk->key (json-string->scm "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"kid\":\"db7cdbbf-0ca3-48da-abf6-8f34002a4651\",\"n\":\"--\"}"))
+ (exit 2))
+ #:unwind? #t
+ #:unwind-for-type &not-a-jwk)))
diff --git a/tests/jwk-public.scm b/tests/jwk-public.scm
index 4830845..c3a6b99 100644
--- a/tests/jwk-public.scm
+++ b/tests/jwk-public.scm
@@ -1,4 +1,4 @@
-;; webid-oidc, implementation of the Solid specification
+;; disfluid, implementation of the Solid specification
;; Copyright (C) 2020, 2021 Vivien Kraus
;; This program is free software: you can redistribute it and/or modify
@@ -15,12 +15,19 @@
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(use-modules (webid-oidc jwk)
- (webid-oidc testing))
+ (webid-oidc testing)
+ (oop goops))
(with-test-environment
"jwk-public"
(lambda ()
(let ((key
- '((kty . "RSA") (alg . "RS256") (n . "sV158-MQ-5-sP2iTJibiMap1ug8tNY97laOud3Se_3jd4INq36NwhLpgU3FC5SCfJOs9wehTLzv_hBuo-sW0JNjAEtMEE-SDtx5486gjymDR-5Iwv7bgt25tD0cDgiboZLt1RLn-nP-V3zgYHZa_s9zLjpNyArsWWcSh6tWe2R8yW6BqS8l4_9z8jkKeyAwWmdpkY8BtKS0zZ9yljiCxKvs8CKjfHmrayg45sZ8V1-aRcjtR2ECxATHjE8L96_oNddZ-rj2axf2vTmnkx3OvIMgx0tZ0ycMG6Wy8wxxaR5ir2LV3Gkyfh72U7tI8Q1sokPmH6G62JcduNY66jEQlvQ") (kid . "dedc012d07f52aedfd5f97784e1bcbe23c19724d") (use . "sig") (e . "AQAB"))))
- (unless (jwk-public? key)
+ (jwk->key
+ '((kty . "RSA")
+ (alg . "RS256")
+ (n . "sV158-MQ-5-sP2iTJibiMap1ug8tNY97laOud3Se_3jd4INq36NwhLpgU3FC5SCfJOs9wehTLzv_hBuo-sW0JNjAEtMEE-SDtx5486gjymDR-5Iwv7bgt25tD0cDgiboZLt1RLn-nP-V3zgYHZa_s9zLjpNyArsWWcSh6tWe2R8yW6BqS8l4_9z8jkKeyAwWmdpkY8BtKS0zZ9yljiCxKvs8CKjfHmrayg45sZ8V1-aRcjtR2ECxATHjE8L96_oNddZ-rj2axf2vTmnkx3OvIMgx0tZ0ycMG6Wy8wxxaR5ir2LV3Gkyfh72U7tI8Q1sokPmH6G62JcduNY66jEQlvQ")
+ (kid . "dedc012d07f52aedfd5f97784e1bcbe23c19724d")
+ (use . "sig")
+ (e . "AQAB")))))
+ (unless (is-a? key <public-key>)
(exit 1)))))
diff --git a/tests/jwks-get.scm b/tests/jwks-get.scm
index 8e9169e..8f23492 100644
--- a/tests/jwks-get.scm
+++ b/tests/jwks-get.scm
@@ -1,4 +1,4 @@
-;; webid-oidc, implementation of the Solid specification
+;; disfluid, implementation of the Solid specification
;; Copyright (C) 2020, 2021 Vivien Kraus
;; This program is free software: you can redistribute it and/or modify
@@ -19,14 +19,17 @@
(webid-oidc cache)
(web uri)
(srfi srfi-19)
- (web response))
+ (web response)
+ (oop goops))
(with-test-environment
"jwks-get"
(lambda ()
- (define* (respond uri #:key (headers '()))
+ (define* (respond uri #:key (headers '()) (method 'GET))
(unless (null? headers)
(exit 1))
+ (unless (eq? method 'GET)
+ (exit 2))
(when (string? uri)
(set! uri (string->uri uri)))
(if (string=? (uri->string uri) "https://example.com/keys")
@@ -54,16 +57,20 @@
]
}
")
- (exit 2)))
+ (exit 3)))
(define cache-http-get
(with-cache
#:http-get respond))
+ (define* (cache-http-request uri #:key (headers '()) (method 'GET))
+ (unless (eq? method 'GET)
+ (exit 4))
+ (cache-http-get uri #:headers headers))
(define jwks (get-jwks "https://example.com/keys"
- #:http-get cache-http-get))
- (define keys (jwks-keys jwks))
- (unless (eq? (length keys) 2)
- (exit 3))
+ #:http-request cache-http-request))
+ (define the-keys (keys jwks))
+ (unless (eq? (length the-keys) 2)
+ (exit 5))
(map (lambda (k)
- (unless (jwk-public? k)
- (exit 4)))
- keys)))
+ (unless (is-a? k <public-key>)
+ (exit 6)))
+ the-keys)))
diff --git a/tests/jws.scm b/tests/jws.scm
index 981e751..a5c9330 100644
--- a/tests/jws.scm
+++ b/tests/jws.scm
@@ -15,13 +15,16 @@
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(use-modules (webid-oidc stubs)
+ (webid-oidc jwk)
(webid-oidc jws)
(webid-oidc testing))
(with-test-environment
"jws"
(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\"}"))
+ (let* ((key
+ (jwk->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\"}")))
(other-key (generate-key #:n-size 2048))
(encoded "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.hZnl5amPk_I3tb4O-Otci_5XZdVWhPlFyVRvcqSwnDo_srcysDvhhKOD01DigPK1lJvTSTolyUgKGtpLqMfRDXQlekRsF4XhAjYZTmcynf-C-6wO5EI4wYewLNKFGGJzHAknMgotJFjDi_NCVSjHsW3a10nTao1lB82FRS305T226Q0VqNVJVWhE4G0JQvi2TssRtCxYTqzXVt22iDKkXeZJARZ1paXHGV5Kd1CljcZtkNZYIGcwnj65gvuCwohbkIxAnhZMJXCLaVvHqv9l-AAUV7esZvkQR1IpwBAiDQJh4qxPjFGylyXrHMqh5NlT_pWL2ZoULWTg_TJjMO9TuQ")
(expected-alg "PS256")
diff --git a/tests/oidc-configuration.scm b/tests/oidc-configuration.scm
index 983c0f7..7f76280 100644
--- a/tests/oidc-configuration.scm
+++ b/tests/oidc-configuration.scm
@@ -22,10 +22,11 @@
(web uri)
(web response)
(srfi srfi-19)
- (ice-9 receive))
+ (ice-9 receive)
+ (oop goops))
(with-test-environment
- "jwks-get"
+ "oidc-configuration"
(lambda ()
(define* (respond uri #:key (headers '()))
(unless (null? headers)
@@ -127,7 +128,7 @@
#:http-get cache-http-get))
(unless (oidc-configuration? cfg)
(exit 3))
- (unless (jwks? jwks)
+ (unless (is-a? jwks <jwks>)
(exit 4))
(let ((my-oidc `((jwks_uri . "https://example.com/keys")
(authorization_endpoint . "https://example.com/authorize")
diff --git a/tests/resource-server.scm b/tests/resource-server.scm
index b9f1036..4df742f 100644
--- a/tests/resource-server.scm
+++ b/tests/resource-server.scm
@@ -29,14 +29,15 @@
(srfi srfi-19)
(web response)
(ice-9 optargs)
- (ice-9 receive))
+ (ice-9 receive)
+ (oop goops))
(with-test-environment
"resource-server"
(lambda ()
(define client-key (generate-key #:n-size 2048))
(define idp-key (generate-key #:n-size 2048))
- (define jwks (make-jwks (list idp-key)))
+ (define jwks (make <jwks> #:keys (list idp-key)))
(define jwks-uri (string->uri "https://identity.provider/keys"))
(define oidc-config
`((jwks_uri . ,(uri->string jwks-uri))
@@ -52,7 +53,7 @@
(cond ((equal? uri oidc-config-uri)
(serve-oidc-configuration exp oidc-config))
((equal? uri jwks-uri)
- (serve-jwks exp jwks))
+ (serve jwks exp))
(else (exit 1))))
(define access-token
(parameterize ((p:current-date 10))