From fa486f2e136a898d1b1548ec90757a78c65a0b70 Mon Sep 17 00:00:00 2001 From: Vivien Kraus Date: Thu, 16 Sep 2021 23:03:12 +0200 Subject: JWK: document it, and use GOOPS --- doc/disfluid.texi | 149 ++++++++++ po/disfluid.pot | 282 +++++++++--------- po/fr.po | 324 +++++++++++---------- src/scm/webid-oidc/client/accounts.scm | 14 +- src/scm/webid-oidc/client/client.scm | 8 +- src/scm/webid-oidc/dpop-proof.scm | 21 +- src/scm/webid-oidc/example-app.scm | 1 - src/scm/webid-oidc/identity-provider.scm | 10 +- src/scm/webid-oidc/jwk.scm | 468 ++++++++++++++++++++---------- src/scm/webid-oidc/jws.scm | 24 +- src/scm/webid-oidc/oidc-configuration.scm | 8 +- tests/dpop-proof-valid.scm | 2 +- tests/jwk-kty-rsa-incorrect.scm | 21 +- tests/jwk-public.scm | 15 +- tests/jwks-get.scm | 29 +- tests/jws.scm | 5 +- tests/oidc-configuration.scm | 7 +- tests/resource-server.scm | 7 +- 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} () +This is the base class for a private key. You need it to issue +signatures. +@end deftp + +@deftp {Class} () +This is the base class for a public key. You need it to check +signatures. +@end deftp + +@deftp {Class} () @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} () (@code{}) +This key pair contains matching RSA keys. +@end deftp + +@deftp {Class} () (@code{}) @var{crv} +This key pair contains matching elliptic curve keys. @var{crv} is a +symbol identifiying the curve. +@end deftp + +@deftp {Class} () @var{d} @var{p} @var{q} @var{dp} @var{dq} @var{qi} +@deftpx {Class} () @var{n} @var{e} +@deftpx {Class} () @var{crv} @var{z} +@deftpx {Class} () @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} () @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 (@var{key} @code{}) +@deftypefnx {Generic method} public-key (@var{key} @code{}) +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 (@var{key} @code{}) +@deftypefnx {Generic method} private-key (@var{key} @code{}) +Return the private part of @var{key}. +@end deftypefn + +@deftypefn {Generic method} rsa-d (@var{key} @code{}) +@deftypefnx {Generic method} rsa-d (@var{key} @code{}) +@deftypefnx {Generic method} rsa-p (@var{key} @code{}) +@deftypefnx {Generic method} rsa-p (@var{key} @code{}) +@deftypefnx {Generic method} rsa-q (@var{key} @code{}) +@deftypefnx {Generic method} rsa-q (@var{key} @code{}) +@deftypefnx {Generic method} rsa-dp (@var{key} @code{}) +@deftypefnx {Generic method} rsa-dp (@var{key} @code{}) +@deftypefnx {Generic method} rsa-dq (@var{key} @code{}) +@deftypefnx {Generic method} rsa-dq (@var{key} @code{}) +@deftypefnx {Generic method} rsa-qi (@var{key} @code{}) +@deftypefnx {Generic method} rsa-qi (@var{key} @code{}) +@deftypefnx {Generic method} rsa-n (@var{key} @code{}) +@deftypefnx {Generic method} rsa-n (@var{key} @code{}) +@deftypefnx {Generic method} rsa-e (@var{key} @code{}) +@deftypefnx {Generic method} rsa-e (@var{key} @code{}) +@deftypefnx {Generic method} ec-crv (@var{key} @code{}) +@deftypefnx {Generic method} ec-crv (@var{key} @code{}) +@deftypefnx {Generic method} ec-crv (@var{key} @code{}) +@deftypefnx {Generic method} ec-x (@var{key} @code{}) +@deftypefnx {Generic method} ec-x (@var{key} @code{}) +@deftypefnx {Generic method} ec-y (@var{key} @code{}) +@deftypefnx {Generic method} ec-y (@var{key} @code{}) +@deftypefnx {Generic method} ec-z (@var{key} @code{}) +@deftypefnx {Generic method} ec-z (@var{key} @code{}) +Key parameter getters. +@end deftypefn + +@deftypefn {Generic method} keys (@var{jwks} @code{}) +Return all the public keys used by @var{jwks}. +@end deftypefn + +@deftypefn {Generic method} check-key (@var{key} @code{}) +@deftypefnx {Generic method} check-key (@var{key} @code{}) +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} key->jwk (@var{key} @code{}) +@deftypefnx {Generic method} key->jwk (@var{key} @code{}) +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} kty (@var{key} @code{}) +@deftypefnx {Generic method} kty (@var{key} @code{}) +@deftypefnx {Generic method} kty (@var{key} @code{}) +@deftypefnx {Generic method} kty (@var{key} @code{}) +@deftypefnx {Generic method} kty (@var{key} @code{}) +@deftypefnx {Generic method} kty (@var{key} @code{}) +Return @code{'RSA} for RSA keys, or @code{'EC} for elliptic curve +keys. +@end deftypefn + +@deftypefn {Generic method} jkt (@var{key} @code{}) +@deftypefnx {Generic method} jkt (@var{key} @code{}) +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} serve (@var{jwks} @code{}) @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} ¬-a-jwk +If the key parameters are incorrect, this exception is raised. +@end deftp + +@deftp {Exception type} ¬-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 \n" "Language-Team: LANGUAGE \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 "

You can only use the GET method on this resource.

" 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 \n" "Language-Team: French \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 "" "

Vous pouvez uniquement utiliser la méthode GET pour cette " "ressource.

" -#: 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" @@ -2562,6 +2554,34 @@ msgstr "" "

Vous voulez utiliser

~s
comme type d’offre, mais ce n’est pas " "supporté.

" +#, 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" 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:) ;; This exception is continuable! Continue with the authorization ;; code. @@ -159,7 +155,7 @@ (define-method (->sexp (account )) `(begin - (use-modules (oop goops) (webid-oidc client accounts)) + (use-modules (oop goops) (webid-oidc client accounts) (webid-oidc jwk)) (make #: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 ) port) (let ((code (->sexp account))) @@ -496,7 +492,7 @@ (slot-set! ret 'refresh-token refresh-token) ret)) -(define-method (set-key-pair (a ) key-pair) +(define-method (set-key-pair (a ) (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:) + (define-class () (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 )) `(begin - (use-modules (oop goops) (webid-oidc client)) + (use-modules (oop goops) (webid-oidc client) (webid-oidc jwk)) (make #: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 ) 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? <> ) 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? <> ) given-jwk))) header ...) + (examine-header header alg typ (or jwk given-jwk) other-header-fields)) + ((('jwk . (= parse-jwk (? (cute is-a? <> ) 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 #: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? + + + public-key private-key + + + rsa-d rsa-p rsa-q rsa-dp rsa-dq rsa-qi + rsa-n rsa-e + ec-crv ec-x ec-y + ec-z + 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 ¬-a-jwk @@ -68,7 +70,165 @@ make-not-a-jwks not-a-jwks?) -(define (the-jwk x) +(define-class ()) + +(define-class ()) + +(define-class () + (public-key #:init-keyword #:public-key #:accessor public-key) + (private-key #:init-keyword #:private-key #:accessor private-key)) + +(define-class ()) + +(define-class () + (crv #:init-keyword #:crv #:accessor ec-crv)) + +(define-class () + (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 () + (n #:init-keyword #:n #:accessor rsa-n) + (e #:init-keyword #:e #:accessor rsa-e)) + +(define-class () + (crv #:init-keyword #:crv #:accessor ec-crv) + (z #:init-keyword #:z #:accessor ec-z)) + +(define-class () + (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 ) (public ) (private )) + (set! (public-key key) public) + (set! (private-key key) private)) + +(define-method (initialize-key-pair (key ) (public ) (private )) + (set! (public-key key) public) + (set! (private-key key) private)) + +(define-method (initialize (key ) 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 ) (public ) (private )) + #t) + +(define-method (initialize (key ) 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 ) (public ) (private )) + (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 ) 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 ) initargs) + (next-method) + (check-key key)) + +(define-method (initialize (key ) initargs) + (next-method) + (check-key key)) + +(define-method (initialize (key ) initargs) + (next-method) + (check-key key)) + +(define-method (initialize (key ) initargs) + (next-method) + (check-key key)) + +(define-method (rsa-d (key )) + (rsa-d (private-key key))) + +(define-method (rsa-p (key )) + (rsa-p (private-key key))) + +(define-method (rsa-q (key )) + (rsa-q (private-key key))) + +(define-method (rsa-dp (key )) + (rsa-dp (private-key key))) + +(define-method (rsa-dq (key )) + (rsa-dq (private-key key))) + +(define-method (rsa-qi (key )) + (rsa-qi (private-key key))) + +(define-method (rsa-n (key )) + (rsa-n (public-key key))) + +(define-method (rsa-e (key )) + (rsa-e (public-key key))) + +(define-method (ec-x (key )) + (ec-x (public-key key))) + +(define-method (ec-y (key )) + (ec-y (public-key key))) + +(define-method (ec-z (key )) + (ec-z (private-key key))) + +(define-method (equal? (x ) (y )) + (and (equal? (public-key x) (public-key y)) + (equal? (private-key x) (private-key y)))) + +(define-method (equal? (x ) (y )) + #f) + +(define-method (equal? (x ) (y )) + #f) + +(define-method (equal? (x ) (y )) + (and (equal? (rsa-n x) (rsa-n y)) + (equal? (rsa-e x) (rsa-e y)))) + +(define-method (equal? (x ) (y )) + (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 ) (y )) + (and (equal? (ec-x x) (ec-x y)) + (equal? (ec-y x) (ec-y y)))) + +(define-method (equal? (x ) (y )) + (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 )) + (append (key->jwk (public-key key)) + (key->jwk (private-key key)))) -(define (kty x) - (stubs:kty (the-jwk x))) +(define-method (key->jwk (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 )) + `((n . ,(rsa-n key)) + (e . ,(rsa-e key)))) + +(define-method (key->jwk (key )) + `((crv . ,(symbol->string (ec-crv key))) + (x . ,(ec-x key)) + (y . ,(ec-y key)))) + +(define-method (key->jwk (key )) + `((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 )) + (check-rsa-key key)) + +(define-method (check-key (key )) + (check-rsa-key key)) + +(define-method (check-key (key )) + (check-rsa-key key)) + +(define-method (check-key (key )) + (check-ec-key key)) + +(define-method (check-key (key )) + (check-ec-key key)) + +(define-method (check-key (key )) + (check-ec-key key)) + +(define-method (kty (key )) 'RSA) +(define-method (kty (key )) 'RSA) +(define-method (kty (key )) 'RSA) + +(define-method (kty (key )) 'EC) +(define-method (kty (key )) 'EC) +(define-method (kty (key )) 'EC) + +(define-method (public-key (key )) + key) + +(define-method (private-key (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 #:n n #:e e))) + (private + (and d p q dp dq qi + (make #:d d #:p p #:q q #:dp dp #:dq dq #:qi qi)))) + (if (and public private) + (make #: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 #:crv crv #:x x #:y y))) + (private + (and z + (make #:crv crv #:z z)))) + (if (and public private) + (make #: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 () + (keys #:init-keyword #:keys #:accessor keys)) -(define (jwks-keys jwks) - (vector->list (assq-ref (the-jwks jwks) 'keys))) +(define-method (initialize (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 ) 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 #: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 )) + (list key)) + +(define-method (keys (key )) + (list (public-key key))) + +(define-method (keys (keys )) + (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 ¬-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 ¬-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 . (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 ) (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 ) + (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 . (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 ) (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 #: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)) -- cgit v1.2.3