From 5faa4e2e67f1d0b0d420449fdfd585f30d28b94d Mon Sep 17 00:00:00 2001 From: Johan Fylling Date: Tue, 12 Aug 2025 18:52:47 +0200 Subject: [PATCH] Adding EdDSA support for `io.jwt` built-ins (#7824) Introducing the `io.jwt.verify_eddsa` built-in, and adding support to the following built-ins: * `io.jwt.decode_verify` * `io.jwt.encode_sign` * `io.jwt.encode_sign_raw` Signed-off-by: Johan Fylling --- CHANGELOG.md | 2 + builtin_metadata.json | 28 +++- capabilities.json | 17 +++ v1/ast/builtins.go | 17 ++- .../test-jwtdecodeverify-eddsa.yaml | 24 ++++ .../test-jwtencodesign-eddsa.yaml | 19 +++ .../test-jwtencodesignraw-eddsa.yaml | 18 +++ .../jwtverifyeddsa/test-jwtverifyeddsa.yaml | 17 +++ .../test-jwtdecodeverify-eddsa.yaml | 24 ++++ .../test-jwtencodesign-eddsa.yaml | 19 +++ .../test-jwtencodesignraw-eddsa.yaml | 18 +++ .../jwtverifyeddsa/test-jwtverifyeddsa.yaml | 17 +++ v1/topdown/tokens.go | 32 +++++ v1/topdown/tokens_test.go | 123 ++++++++++++++++++ 14 files changed, 373 insertions(+), 2 deletions(-) create mode 100644 v1/test/cases/testdata/v0/jwtdecodeverify/test-jwtdecodeverify-eddsa.yaml create mode 100644 v1/test/cases/testdata/v0/jwtencodesign/test-jwtencodesign-eddsa.yaml create mode 100644 v1/test/cases/testdata/v0/jwtencodesignraw/test-jwtencodesignraw-eddsa.yaml create mode 100644 v1/test/cases/testdata/v0/jwtverifyeddsa/test-jwtverifyeddsa.yaml create mode 100644 v1/test/cases/testdata/v1/jwtdecodeverify/test-jwtdecodeverify-eddsa.yaml create mode 100644 v1/test/cases/testdata/v1/jwtencodesign/test-jwtencodesign-eddsa.yaml create mode 100644 v1/test/cases/testdata/v1/jwtencodesignraw/test-jwtencodesignraw-eddsa.yaml create mode 100644 v1/test/cases/testdata/v1/jwtverifyeddsa/test-jwtverifyeddsa.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d41e478e1..d8cb278a17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +- topdown: Add support for EdDSA in `io.jwt` built-ins ([#]()) authored by @johanfylling reported by @aromeyer + ## 1.7.1 This is a bug fix release addressing two issues for users that include OPA's CLI in their own application's CLI: diff --git a/builtin_metadata.json b/builtin_metadata.json index d815e075cb..59be19ff5a 100644 --- a/builtin_metadata.json +++ b/builtin_metadata.json @@ -207,6 +207,7 @@ "tokens": [ "io.jwt.decode", "io.jwt.decode_verify", + "io.jwt.verify_eddsa", "io.jwt.verify_es256", "io.jwt.verify_es384", "io.jwt.verify_es512", @@ -9255,7 +9256,7 @@ "v1.7.0", "edge" ], - "description": "Verifies a JWT signature under parameterized constraints and decodes the claims if it is valid.\nSupports the following algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384 and PS512.", + "description": "Verifies a JWT signature under parameterized constraints and decodes the claims if it is valid.\nSupports the following algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512, and EdDSA.", "introduced": "v0.17.0", "result": { "description": "`[valid, header, payload]`: if the input token is verified and meets the requirements of `constraints` then `valid` is `true`; `header` and `payload` are objects containing the JOSE header and the JWT claim set; otherwise, `valid` is `false`, `header` and `payload` are `{}`", @@ -9564,6 +9565,31 @@ }, "wasm": false }, + "io.jwt.verify_eddsa": { + "args": [ + { + "description": "JWT token whose signature is to be verified", + "name": "jwt", + "type": "string" + }, + { + "description": "PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature", + "name": "certificate", + "type": "string" + } + ], + "available": [ + "edge" + ], + "description": "Verifies if an EdDSA JWT signature is valid.", + "introduced": "edge", + "result": { + "description": "`true` if the signature is valid, `false` otherwise", + "name": "result", + "type": "boolean" + }, + "wasm": false + }, "io.jwt.verify_es256": { "args": [ { diff --git a/capabilities.json b/capabilities.json index 110c3eca91..0a37621d0c 100644 --- a/capabilities.json +++ b/capabilities.json @@ -1814,6 +1814,23 @@ }, "nondeterministic": true }, + { + "name": "io.jwt.verify_eddsa", + "decl": { + "args": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "result": { + "type": "boolean" + }, + "type": "function" + } + }, { "name": "io.jwt.verify_es256", "decl": { diff --git a/v1/ast/builtins.go b/v1/ast/builtins.go index 7552c145bd..948334410e 100644 --- a/v1/ast/builtins.go +++ b/v1/ast/builtins.go @@ -198,6 +198,7 @@ var DefaultBuiltins = [...]*Builtin{ JWTVerifyES256, JWTVerifyES384, JWTVerifyES512, + JWTVerifyEdDSA, JWTVerifyHS256, JWTVerifyHS384, JWTVerifyHS512, @@ -2236,6 +2237,20 @@ var JWTVerifyES512 = &Builtin{ canSkipBctx: false, } +var JWTVerifyEdDSA = &Builtin{ + Name: "io.jwt.verify_eddsa", + Description: "Verifies if an EdDSA JWT signature is valid.", + Decl: types.NewFunction( + types.Args( + types.Named("jwt", types.S).Description("JWT token whose signature is to be verified"), + types.Named("certificate", types.S).Description("PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature"), + ), + types.Named("result", types.B).Description("`true` if the signature is valid, `false` otherwise"), + ), + Categories: tokensCat, + canSkipBctx: false, +} + var JWTVerifyHS256 = &Builtin{ Name: "io.jwt.verify_hs256", Description: "Verifies if a HS256 (secret) JWT signature is valid.", @@ -2282,7 +2297,7 @@ var JWTVerifyHS512 = &Builtin{ var JWTDecodeVerify = &Builtin{ Name: "io.jwt.decode_verify", Description: `Verifies a JWT signature under parameterized constraints and decodes the claims if it is valid. -Supports the following algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384 and PS512.`, +Supports the following algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512, and EdDSA.`, Decl: types.NewFunction( types.Args( types.Named("jwt", types.S).Description("JWT token whose signature is to be verified and whose claims are to be checked"), diff --git a/v1/test/cases/testdata/v0/jwtdecodeverify/test-jwtdecodeverify-eddsa.yaml b/v1/test/cases/testdata/v0/jwtdecodeverify/test-jwtdecodeverify-eddsa.yaml new file mode 100644 index 0000000000..07709185db --- /dev/null +++ b/v1/test/cases/testdata/v0/jwtdecodeverify/test-jwtdecodeverify-eddsa.yaml @@ -0,0 +1,24 @@ +--- +cases: + - data: + modules: + - | + package generated + + p = [x, y, z] { + io.jwt.decode_verify( + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.JkKWCY39IdWEQttmdqR7VdsvT-_QxheW_eb0S5wr_j83ltux_JDUIXs7a3Dtn3xuqzuhetiuJrWIvy5TzimeCg", + {"cert": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwmK6SSAu2E9V7uynkCKEaj5nZJyTvNG4x0KohsRzLpg=\n-----END PUBLIC KEY-----\n"}, + [x, y, z]) + } + note: jwtdecodeverify/EdDSA + query: data.generated.p = x + want_result: + - x: + - true + - alg: EdDSA + typ: JWT + - admin: true + iat: 1516239022 + name: John Doe + sub: "1234567890" diff --git a/v1/test/cases/testdata/v0/jwtencodesign/test-jwtencodesign-eddsa.yaml b/v1/test/cases/testdata/v0/jwtencodesign/test-jwtencodesign-eddsa.yaml new file mode 100644 index 0000000000..ba5aa92102 --- /dev/null +++ b/v1/test/cases/testdata/v0/jwtencodesign/test-jwtencodesign-eddsa.yaml @@ -0,0 +1,19 @@ +--- +cases: + - note: jwtencodesign/EdDSA + query: data.test.p = x + modules: + - | + package test + + p := x { + io.jwt.encode_sign( + {"alg": "EdDSA", "typ": "JWT"}, + {"aud": ["bob", "saul"], "exp": 1300819380, "http://example.com/is_root": true, "iss": "joe", "privateParams": {"private_one": "one", "private_two": "two"}}, + {"kty": "OKP", "alg": "EdDSA", "crv": "Ed25519", "x": "wEZFfoAj1rFKTLOOmjJjVZlCHwksuvMb2I5y_hg70E8", "d": "9XI34uQzYUJfWhDZf_0nYsLMBRVu8a6dFsy60P8uugk"}, + x, + ) + } + data: {} + want_result: + - x: eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiYm9iIiwic2F1bCJdLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UiLCJwcml2YXRlUGFyYW1zIjp7InByaXZhdGVfb25lIjoib25lIiwicHJpdmF0ZV90d28iOiJ0d28ifX0.T_X7SzKEehTnRdgYrDobpKO-EqZ0LW3Y-idx16wNHXCL5aiR24h2Ei0pWRHG2X2BYomwbvNwyxPcasgHqs_eBA diff --git a/v1/test/cases/testdata/v0/jwtencodesignraw/test-jwtencodesignraw-eddsa.yaml b/v1/test/cases/testdata/v0/jwtencodesignraw/test-jwtencodesignraw-eddsa.yaml new file mode 100644 index 0000000000..cd41b8c018 --- /dev/null +++ b/v1/test/cases/testdata/v0/jwtencodesignraw/test-jwtencodesignraw-eddsa.yaml @@ -0,0 +1,18 @@ +--- +cases: + - note: jwtencodesignraw/EdDSA + query: data.test.p = x + modules: + - | + package test + p := x { + io.jwt.encode_sign_raw( + `{"alg":"EdDSA","typ":"JWT"}`, + `{"iss":"joe","exp":1300819380,"http://example.com/is_root":true}`, + `{"kty":"OKP","alg":"EdDSA","crv":"Ed25519","x":"wEZFfoAj1rFKTLOOmjJjVZlCHwksuvMb2I5y_hg70E8","d":"9XI34uQzYUJfWhDZf_0nYsLMBRVu8a6dFsy60P8uugk"}`, + x, + ) + } + data: {} + want_result: + - x: eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.jS1so-rsTaC8DdA8_ZnFXYbi9xOrMVXOviMFrahQ7ez0UKKzjU-2vxrM0ON-Vu3GXKhtBkkO3SUtNMoeYw3zDQ diff --git a/v1/test/cases/testdata/v0/jwtverifyeddsa/test-jwtverifyeddsa.yaml b/v1/test/cases/testdata/v0/jwtverifyeddsa/test-jwtverifyeddsa.yaml new file mode 100644 index 0000000000..aae8e2714c --- /dev/null +++ b/v1/test/cases/testdata/v0/jwtverifyeddsa/test-jwtverifyeddsa.yaml @@ -0,0 +1,17 @@ +--- +cases: + - note: jwtverifyeddsa/success-cert + query: data.generated.p = x + modules: + - | + package generated + + p := x { + io.jwt.verify_eddsa( + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.JkKWCY39IdWEQttmdqR7VdsvT-_QxheW_eb0S5wr_j83ltux_JDUIXs7a3Dtn3xuqzuhetiuJrWIvy5TzimeCg", + "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwmK6SSAu2E9V7uynkCKEaj5nZJyTvNG4x0KohsRzLpg=\n-----END PUBLIC KEY-----", + x) + } + data: {} + want_result: + - x: true diff --git a/v1/test/cases/testdata/v1/jwtdecodeverify/test-jwtdecodeverify-eddsa.yaml b/v1/test/cases/testdata/v1/jwtdecodeverify/test-jwtdecodeverify-eddsa.yaml new file mode 100644 index 0000000000..cf27fa9404 --- /dev/null +++ b/v1/test/cases/testdata/v1/jwtdecodeverify/test-jwtdecodeverify-eddsa.yaml @@ -0,0 +1,24 @@ +--- +cases: + - data: + modules: + - | + package generated + + p = [x, y, z] if { + io.jwt.decode_verify( + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.JkKWCY39IdWEQttmdqR7VdsvT-_QxheW_eb0S5wr_j83ltux_JDUIXs7a3Dtn3xuqzuhetiuJrWIvy5TzimeCg", + {"cert": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwmK6SSAu2E9V7uynkCKEaj5nZJyTvNG4x0KohsRzLpg=\n-----END PUBLIC KEY-----\n"}, + [x, y, z]) + } + note: jwtdecodeverify/EdDSA + query: data.generated.p = x + want_result: + - x: + - true + - alg: EdDSA + typ: JWT + - admin: true + iat: 1516239022 + name: John Doe + sub: "1234567890" diff --git a/v1/test/cases/testdata/v1/jwtencodesign/test-jwtencodesign-eddsa.yaml b/v1/test/cases/testdata/v1/jwtencodesign/test-jwtencodesign-eddsa.yaml new file mode 100644 index 0000000000..c3ffd747aa --- /dev/null +++ b/v1/test/cases/testdata/v1/jwtencodesign/test-jwtencodesign-eddsa.yaml @@ -0,0 +1,19 @@ +--- +cases: + - note: jwtencodesign/EdDSA + query: data.test.p = x + modules: + - | + package test + + p := x if { + io.jwt.encode_sign( + {"alg": "EdDSA", "typ": "JWT"}, + {"aud": ["bob", "saul"], "exp": 1300819380, "http://example.com/is_root": true, "iss": "joe", "privateParams": {"private_one": "one", "private_two": "two"}}, + {"kty": "OKP", "alg": "EdDSA", "crv": "Ed25519", "x": "wEZFfoAj1rFKTLOOmjJjVZlCHwksuvMb2I5y_hg70E8", "d": "9XI34uQzYUJfWhDZf_0nYsLMBRVu8a6dFsy60P8uugk"}, + x, + ) + } + data: {} + want_result: + - x: eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiYm9iIiwic2F1bCJdLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UiLCJwcml2YXRlUGFyYW1zIjp7InByaXZhdGVfb25lIjoib25lIiwicHJpdmF0ZV90d28iOiJ0d28ifX0.T_X7SzKEehTnRdgYrDobpKO-EqZ0LW3Y-idx16wNHXCL5aiR24h2Ei0pWRHG2X2BYomwbvNwyxPcasgHqs_eBA diff --git a/v1/test/cases/testdata/v1/jwtencodesignraw/test-jwtencodesignraw-eddsa.yaml b/v1/test/cases/testdata/v1/jwtencodesignraw/test-jwtencodesignraw-eddsa.yaml new file mode 100644 index 0000000000..83e2141e4d --- /dev/null +++ b/v1/test/cases/testdata/v1/jwtencodesignraw/test-jwtencodesignraw-eddsa.yaml @@ -0,0 +1,18 @@ +--- +cases: + - note: jwtencodesignraw/EdDSA + query: data.test.p = x + modules: + - | + package test + p := x if { + io.jwt.encode_sign_raw( + `{"alg":"EdDSA","typ":"JWT"}`, + `{"iss":"joe","exp":1300819380,"http://example.com/is_root":true}`, + `{"kty":"OKP","alg":"EdDSA","crv":"Ed25519","x":"wEZFfoAj1rFKTLOOmjJjVZlCHwksuvMb2I5y_hg70E8","d":"9XI34uQzYUJfWhDZf_0nYsLMBRVu8a6dFsy60P8uugk"}`, + x, + ) + } + data: {} + want_result: + - x: eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.jS1so-rsTaC8DdA8_ZnFXYbi9xOrMVXOviMFrahQ7ez0UKKzjU-2vxrM0ON-Vu3GXKhtBkkO3SUtNMoeYw3zDQ diff --git a/v1/test/cases/testdata/v1/jwtverifyeddsa/test-jwtverifyeddsa.yaml b/v1/test/cases/testdata/v1/jwtverifyeddsa/test-jwtverifyeddsa.yaml new file mode 100644 index 0000000000..82aba13540 --- /dev/null +++ b/v1/test/cases/testdata/v1/jwtverifyeddsa/test-jwtverifyeddsa.yaml @@ -0,0 +1,17 @@ +--- +cases: + - note: jwtverifyeddsa/success-cert + query: data.generated.p = x + modules: + - | + package generated + p := x if { + io.jwt.verify_eddsa( + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.JkKWCY39IdWEQttmdqR7VdsvT-_QxheW_eb0S5wr_j83ltux_JDUIXs7a3Dtn3xuqzuhetiuJrWIvy5TzimeCg", + "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwmK6SSAu2E9V7uynkCKEaj5nZJyTvNG4x0KohsRzLpg=\n-----END PUBLIC KEY-----", + x + ) + } + data: {} + want_result: + - x: true diff --git a/v1/topdown/tokens.go b/v1/topdown/tokens.go index 7a8e03d62b..72d290073c 100644 --- a/v1/topdown/tokens.go +++ b/v1/topdown/tokens.go @@ -7,6 +7,7 @@ package topdown import ( "crypto" "crypto/ecdsa" + "crypto/ed25519" "crypto/hmac" "crypto/rsa" "crypto/sha256" @@ -270,6 +271,31 @@ func verifyES(publicKey any, digest []byte, signature []byte) (err error) { return errors.New("ECDSA signature verification error") } +// Implements EdDSA JWT signature verification +func builtinJWTVerifyEdDSA(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { + result, err := builtinJWTVerify(bctx, operands[0].Value, operands[1].Value, nil, verifyEd25519) + if err == nil { + return iter(ast.InternedTerm(result)) + } + return err +} + +func verifyEd25519(publicKey any, digest []byte, signature []byte) (err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("EdDSA signature verification error: %v", r) + } + }() + publicKeyEcdsa, ok := publicKey.(ed25519.PublicKey) + if !ok { + return errors.New("incorrect public key type") + } + if ed25519.Verify(publicKeyEcdsa, digest, signature) { + return nil + } + return errors.New("ECDSA signature verification error") +} + type verificationKey struct { alg string kid string @@ -723,6 +749,7 @@ var tokenAlgorithms = map[string]struct{}{ "HS256": {}, "HS384": {}, "HS512": {}, + "EdDSA": {}, } // errSignatureNotVerified is returned when a signature cannot be verified. @@ -1198,6 +1225,10 @@ func extractJSONObject(s string) (ast.Object, error) { // getInputSha returns the SHA checksum of the input func getInputSHA(input []byte, h func() hash.Hash) []byte { + if h == nil { + return input + } + hasher := h() hasher.Write(input) return hasher.Sum(nil) @@ -1270,6 +1301,7 @@ func init() { RegisterBuiltinFunc(ast.JWTVerifyES256.Name, builtinJWTVerifyES256) RegisterBuiltinFunc(ast.JWTVerifyES384.Name, builtinJWTVerifyES384) RegisterBuiltinFunc(ast.JWTVerifyES512.Name, builtinJWTVerifyES512) + RegisterBuiltinFunc(ast.JWTVerifyEdDSA.Name, builtinJWTVerifyEdDSA) RegisterBuiltinFunc(ast.JWTVerifyHS256.Name, builtinJWTVerifyHS256) RegisterBuiltinFunc(ast.JWTVerifyHS384.Name, builtinJWTVerifyHS384) RegisterBuiltinFunc(ast.JWTVerifyHS512.Name, builtinJWTVerifyHS512) diff --git a/v1/topdown/tokens_test.go b/v1/topdown/tokens_test.go index 3f9ffb6426..926baf88c9 100644 --- a/v1/topdown/tokens_test.go +++ b/v1/topdown/tokens_test.go @@ -1125,6 +1125,13 @@ func TestBuiltinJWTVerify_TokenCache(t *testing.T) { badKey: `{"kty":"EC","crv":"P-256","x":"z8J91ghFy5o6f2xZ4g8LsLH7u2wEpT2ntj8loahnlsE","y":"7bdeXLH61KrGWRdh7ilnbcGQACxykaPKfmBccTHIOUo"}`, builtin: builtinJWTVerifyES512, }, + { + note: "EdDSA", + jwt: `eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.JkKWCY39IdWEQttmdqR7VdsvT-_QxheW_eb0S5wr_j83ltux_JDUIXs7a3Dtn3xuqzuhetiuJrWIvy5TzimeCg`, + key: "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwmK6SSAu2E9V7uynkCKEaj5nZJyTvNG4x0KohsRzLpg=\n-----END PUBLIC KEY-----", + badKey: `{"kty":"EC","crv":"P-256","x":"z8J91ghFy5o6f2xZ4g8LsLH7u2wEpT2ntj8loahnlsE","y":"7bdeXLH61KrGWRdh7ilnbcGQACxykaPKfmBccTHIOUo"}`, + builtin: builtinJWTVerifyEdDSA, + }, } ctx := context.Background() @@ -1189,3 +1196,119 @@ func TestBuiltinJWTVerify_TokenCache(t *testing.T) { }) } } + +func TestBuiltinJWTDecodeVerify(t *testing.T) { + tests := []struct { + note string + jwt string + key string + keyType string + }{ + { + note: "HS256", + jwt: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWxpY2UiLCJhenAiOiJhbGljZSIsInN1Ym9yZGluYXRlcyI6W10sImhyIjpmYWxzZX0.rz3jTY033z-NrKfwrK89_dcLF7TN4gwCMj-fVBDyLoM`, + key: `secret`, + keyType: `secret`, + }, + { + note: "HS384", + jwt: `eyJhbGciOiJIUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.g98lHYzuqINVppLMoEZT7jlpX0IBSo9zKGoN9DhQg7Ua3YjLXbJMjzESjIHXOGLB`, + key: `secret`, + keyType: `secret`, + }, + { + note: "HS512", + jwt: `eyJhbGciOiJIUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.F6-xviRhK2OLcJJHFivhQqMN_dgX5boDrwbVKkdo9flQQNk-AaKpH3uYycFvBEd_erVefcsri_PkL4fjLSZ7ZA`, + key: `secret`, + keyType: `secret`, + }, + { + note: "RS256", + jwt: `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.N0-EVdv5pvUfZYFRzMGnsWpNLHgwMEgViPwpuLBEtt32682OgnOK-N4X-2gpQEjQIbUr0IFym8YsRQU9GZvqQP72Sd6yOQNGSNeE74DpUZCAjBa9SBIb1UlD2MxZB-e7YJiEyo7pZhimaqorXrgorlaXYGMvsCFWDYmBLzGaGYaGJyEpkZHzHb7ujsDrJJjdEtDV3kh13gTHzLPvqnoXuuxelXye_8LPIhvgDy52gT4shUEso71pJCMv_IqAR19ljVE17lJzoi6VhRn6ReNUE-yg4KfCO4Ypnuu-mcQr7XtmSYoWkX72L5UQ-EyWkoz-w0SYKoJTPzHkTL2thYStksVpeNkGuck25aUdtrQgmPbao0QOWBFlkg03e6mPCD2-aXOt1ofth9mZGjxWMHX-mUqHaNmaWM3WhRztJ73hWrmB1YOdYQtOEHejfvR_td5tqIw4W6ufRy2ScOypGQe7kNaUZxpgxZ1927ZGNiQgawIOAQwXOcFx1JNSEIeg55-cYJrHPxsXGOB9ZxW-qnswmFJp474iUVXjzGhLexJDXBwvKGs_O3JFjMsvyV9_hm7bnQU0vG_HgPYs5i9VOHRMujq1vFBcm52TFVOBGdWaGfb9RRdLLYvVkJLk0Poh19rsCWb7-Vc3mAaGGpvuk4Wv-PnGGNC-V-FQqIbijHDrn_g`, + key: "-----BEGIN CERTIFICATE-----\nMIIFiDCCA3ACCQCGV6XsfG/oRTANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMC\nVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFTATBgNVBAcMDFJlZHdvb2QgQ2l0eTEO\nMAwGA1UECgwFU3R5cmExDDAKBgNVBAsMA0RldjESMBAGA1UEAwwJbG9jYWxob3N0\nMRgwFgYJKoZIhvcNAQkBFglhc2hAc3R5cmEwHhcNMTgwMzA2MDAxNTU5WhcNMTkw\nMzA2MDAxNTU5WjCBhTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx\nFTATBgNVBAcMDFJlZHdvb2QgQ2l0eTEOMAwGA1UECgwFU3R5cmExDDAKBgNVBAsM\nA0RldjESMBAGA1UEAwwJbG9jYWxob3N0MRgwFgYJKoZIhvcNAQkBFglhc2hAc3R5\ncmEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDucnAwTRA0zqDQ671L\nKWOVwhjhycFyzyhZUd7vhsnslOBiYM6TYIDXhETfAk2RQoRE/9xF16woMD8FOglc\nlSuhi+GNfFRif6LfArm84ZFj1ZS1MX2logikhXhRJQ7AOHe5+ED0re3KH5lWyqfz\nR6bQuPYwTQSBJy6Tq7T9RiOM29yadCX64OaCEbzEFmHtNlbb5px4zCVvgskg/fpV\nGGCMpAYjGDatbxE5eAloVs1EJuI5RSqWr1JRm6EejxM04BFdfGn1HgWrsKXtlvBa\n00/AC0zXL5n6LK7+L3WbRguVTZcE4Yu70gDwhmM+VsKeT9LKClX003BNj0NJDRB9\ndw9MaWxsXDNHNOWEfbnASXeP7ZRv3D81ftij6P8SL14ZnxyrRty8TAN4ij3wd41l\nastRQCtrJFi+HzO606XOp6HDzBoWT0DGl8Sn2hZ6RLPyBnD04vvvcSGeCVjHGOQ8\nc3OTroK58u5MR/q4T00sTkeeVAxuKoEWKsjIBYYrJTe/a2mEq9yiDGbPNYDnWnQZ\njSUZm+Us23Y2sm/agZ5zKXcEuoecGL6sYCixr/xeB9BPxEiTthH+0M8OY99qpIhz\nSmj41wdgQfzZi/6B8pIr77V/KywYKxJEmzw8Uy48aC/rZ8WsT8QdKwclo1aiNJhx\n79OvGbZFoeHD/w7igpx+ttpF/wIDAQABMA0GCSqGSIb3DQEBBQUAA4ICAQC3wWUs\nfXz+aSfFVz+O3mLFkr65NIgazbGAySgMgMNVuadheIkPL4k21atyflfpx4pg9FGv\n40vWCLMajpvynfz4oqah0BACnpqzQ8Dx6HYkmlXK8fLB+WtPrZBeUEsGPKuJYt4M\nd5TeY3VpNgWOPXmnE4lvxHZqh/8OwmOpjBfC9E3e2eqgwiwOkXnMaZEPgKP6JiWk\nEFaQ9jgMQqJZnNcv6NmiqqsZeI0/NNjBpkmEWQl+wLegVusHiQ0FMBMQ0taEo21r\nzUwHoNJR3h3wgGQiKxKOH1FUKHBV7hEqObLraD/hfG5xYucJfvvAAP1iH0ycPs+9\nhSccrn5/HY1c9AZnW8Kh7atp/wFP+sHjtECWK/lUmXfhASS293hprCpJk2n9pkmR\nziXKJhjwkxlC8NcHuiVfaxdfDa4+1Qta2gK7GEypbvLoEmIt/dsYUsxUg84lwJJ9\nnyC/pfZ5a8wFSf186JeVH4kHd3bnkzlQz460HndOMSJ/Xi1wSfuZlOVupFf8TVKl\np4j28MTLH2Wqx50NssKThdaX6hoCiMqreYa+EVaN1f/cIGQxZSCzdzMCKqdB8lKB\n3Eax+5zsIa/UyPwGxZcyXBRHAlz5ZnkjuRxInyiMkBWWz3IZXjTe6Fq8BNd2UWNc\nw35+2nO5n1LKXgR2+nzhZUOk8TPsi9WUywRluQ==\n-----END CERTIFICATE-----", + keyType: `cert`, + }, + { + note: "RS384", + jwt: `eyJhbGciOiJSUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.b__y2zjqMoD7iWbHeQ0lNpnche3ph5-AwrIQICLMQQGtEz9WMBteHydkC5g01bm3TBX1d04Z5IEOsuK6btAtWma04c5NYqaUyNEUJKYCFoY02uH0jGdGfL6R5Kkv0lkNvN0s3Nex9jMaVVgqx8bcrOU0uRBFT67sXcm11LHaB9BwKFslolzHClxgXy5RIZb4OFk_7Yk7xTC6PcvEWkkGR9uXBhfDEig5WqdwOWPeulimvARDw14U35rzeh9xpGAPjBKeE-y20fXAk0cSF1H69C-Qa1jDQheYIrAJ6XMYGNZWuay5-smmeefe67eweEt1q-AD1NFepqkmZX382DGuYQ`, + key: "-----BEGIN CERTIFICATE-----\nMIIDXDCCAkSgAwIBAgIBLjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJVUzEV\nMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMD\nRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjAwNTA3MDg1MTAzWhcNMjAwNTA3\nMTA1MTAzWjBWMQswCQYDVQQGEwJVUzEVMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4w\nDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3Qw\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDeRmygX/fOOUu5Wm91PFNo\nsHDG1CzG9a1iKBjUeMgi9bXXScUfatPmsNlxb56uSi0RXUsvJmY/yxkIIhRyapxW\n49j2idAM3SGGL1nOZf/XdpDHYsAFFZ237HGb8DOEk/p3xCFv0tH/iQ+kLP36EM1+\ntn6BfUXdJnVyvkSK2iMNeRY7A4DMX7sGX39LXsVJiCokIC8E0QUFrSjvrAm9ejKE\ntPojydo4c3VUxLfmFuyMXoD3bfk1Jv5i2J5RjtomjgK6zNCvgYzpspiodHChkzlU\nX8yk2YqlAHX3XdJA94LaDE2kNXiOQnFkUb8GsP7hmEbwGtMUEQie+jfgKplxJ49B\nAgMBAAGjNTAzMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAM\nBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQC9f2/kxT7DnQ94ownhHvd6\nrzk1WirI90rFM2MxhfkaDrOHhSGZL9nDf6TIZ4qeFKZXthpKxpiZm2Oxmn+vUsik\nW6bYjq1nX0GCchQLaaFf9Jh1IOLwkfoBdX55tV8xUGHRWgDlCuGbqiixz+Bm0Kap\nkmbyJynVcoiKhdLyYm/YTn/pC32SJW666reQ+0qCAoxzLQowBetHjwDam9RsDEf4\n+JRDjYPutNXyJ5X8BaBA6PzHanzMG/7RFYcx/2YhXwVxdfPHku4ALJcddIGAGNx2\n5yte+HY0aEu+06J67eD9+4fU7NixRMKigk9KbjqpeWD+0be+VgX8Dot4jaISgI/3\n-----END CERTIFICATE-----", + keyType: `cert`, + }, + { + note: "RS512", + jwt: `eyJhbGciOiJSUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.VSe3qK5Gp0Q0_5nRgMFu25yw74FIgX-kXPOemSi62l-AxeVdUw8rOpEFrSTCaVjd3mPfKb-B056a-gtrbpXK9sUQnFdqdsyt8gHK-umz5lVyWfoAgj51Ontv-9K_pRORD9wqKqdTLZjCxJ5tyKoO0gY3SwwqSqGrp85vUjvEcK3jbMKINGRUNnOokeSm7byUEJsfKVUbPboSX1TGyvjDOZxxSITj8-bzZZ3F21DJ23N2IiJN7FW8Xj-SYyphXo-ML50o5bjW9YlQ5BDk-RW1I4eE-KpsxhApPv_xIgE8d89PVtXFuoJtv0yLRaZ1q04Fl9KNoMyZrmr349yppn0JlQ`, + key: "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3kZsoF/3zjlLuVpvdTxT\naLBwxtQsxvWtYigY1HjIIvW110nFH2rT5rDZcW+erkotEV1LLyZmP8sZCCIUcmqc\nVuPY9onQDN0hhi9ZzmX/13aQx2LABRWdt+xxm/AzhJP6d8Qhb9LR/4kPpCz9+hDN\nfrZ+gX1F3SZ1cr5EitojDXkWOwOAzF+7Bl9/S17FSYgqJCAvBNEFBa0o76wJvXoy\nhLT6I8naOHN1VMS35hbsjF6A9235NSb+YtieUY7aJo4CuszQr4GM6bKYqHRwoZM5\nVF/MpNmKpQB1913SQPeC2gxNpDV4jkJxZFG/BrD+4ZhG8BrTFBEInvo34CqZcSeP\nQQIDAQAB\n-----END PUBLIC KEY-----", + keyType: `cert`, + }, + { + note: "PS256", + jwt: `eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJQUzI1NiJ9.eyJuYmYiOiAxNDQ0NDc4NDAwLCAiZm9vIjogImJhciJ9.i0F3MHWzOsBNLqjQzK1UVeQid9xPMowCoUsoM-C2BDxUY-FMKmCeJ1NJ4TGnS9HzFK1ftEvRnPT7EOxOkHPoCk1rz3feTFgtHtNzQqLM1IBTnz6aHHOrda_bKPHH9ZIYCRQUPXhpC90ivW_IJR-f7Z1WLrMXaJ71i1XteruENHrJJJDn0HedHG6N0VHugBHrak5k57cbE31utAdx83TEd8v2Y8wAkCJXKrdmTa-8419LNxW_yjkvoDD53n3X5CHhYkSymU77p0v6yWO38qDWeKJ-Fm_PrMAo72_rizDBj_yPa5LA3bT_EnsgZtC-sp8_SCDIH41bjiCGpRHhqgZmyw`, + key: `{"kty":"RSA","e":"AQAB","kid":"bf688c97-bf51-49ba-b9d3-115195bb0eb8","n":"uJApsyzFv-Y85M5JjezHvMDw_spgVCI7BqpYhnzK3xXw1dnkz1bWXGA9yF6AeADlE-1yc1ozrAURTnFSihIgj414i3MC2_0FkNcdAbnX7d9q9_jdCkHda4HER0zzXCaHlgnzoAz6edUU800-h0LleLnfgg4UST-0DFTCIGpfTbs7OPSy2WgT1vP6xbB45CUOJA7o0q6XE-hdhWWN0plrDiYD-0Y1SpOQYXmHhSmr-WVeKeoh5_0zeEVab6TQYec_16ByEyepaZB0g6WyGkFE6aG1NrpvDd24s_h7BAJg_S2mtu1lKWEqYjOgwzEl5XQQyXbpnq1USb12ArX16rZdew"}`, + keyType: `cert`, + }, + { + note: "PS384", + jwt: `eyJhbGciOiJQUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.EHPUvPr6uJOYqdza95WbM1SYD8atZHJEVRggpwOWnHGsjQBoEarJb8QgW7TY22OXwGw2HWluTiyT_MAz02NaHRzZv6AgrmxCLChMWkCHLwPxqjs0xSvVAMLzHHq2X2Bcujo9KORGudR7zKz8pOX5Mfnm7Z6OGtqPCPLaIdVJlddNsG6a571NOuVuDWbcg0omeRDANZpCZMJeAQN2M-4Q61ef6zcQHK1R-QqzBhw6HzMgqR1LRJ0xbrmD-L5o53JM3pV1e1juKNXVK3vWkDQRCQORFn1lyH5isfSsiiHW-x90sUC7TrU_cOji4MMmOCME6kkwxe57ZgpeXtdVTvldpw`, + key: "-----BEGIN CERTIFICATE-----\nMIIDXDCCAkSgAwIBAgIBKjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJVUzEV\nMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMD\nRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjAwNTA3MDkxMjU2WhcNMjAwNTA3\nMTExMjU2WjBWMQswCQYDVQQGEwJVUzEVMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4w\nDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3Qw\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtyVWH2FE8cU8LRcArH4Tw\nDhBOFcmJF28LrvRObcbDYsae6rEwby0aRgSxjTEMgyGBjroBSl22wOSA93kwx4pu\npfXEqbwywn9FhyKBb/OXQSglPmwrpmzQtPJGzBHncL+PPjRhPfqimwf7ZIPKAAgI\nz9O6ppGhE/x4Ct444jthUIBZuG5cUXhgiPBQdIQ3K88QhgVwcufTZkNHj4iSDfhl\nVFDHVjXjd2B/yGODjyv0TyChV0YBNGjMv7YFLWmIFUFzK+6qNSxu4czPtRkyfwaV\n2GW/PBT5f8fc6fKgQZ6k6BLK6+pi0iPh5TUizyHtqtueWDbrJ+wfdJilQS8D+EGr\nAgMBAAGjNTAzMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAM\nBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQBgVAM50/0aBTBxESYKIKN4\nE+qbV6aE0C+wYJLet0EWPTxwmFZamq5LNEO/D6xyoY5WHY60EyHRMs0agSB/ATBX\n5ULdEwh9G0NjxqivCcoddQ1fuVS2PrrqNL7VlRnYbTpd8/Dh4qnyl5FltlyZ/29L\ny7BWOwlcBlZdhsfH8svNX4PUxjRD+jmnczCDi7XSOKT8htKUV2ih1c9JrWpIhCi/\nHzEXkaAxNdhBNdIsLQMo3qq9fkSgNZQk9/ecJNPeuJ/UYyr5Xa4PxIWl4U+P7yuI\n+Q3FSPmUbiVsSGqMhh6V/DN8M+T5/KiSB47gFOfxc2/RR5aw4HkSp3WxwbT9njbE\n-----END CERTIFICATE-----", + keyType: `cert`, + }, + { + note: "PS512", + jwt: `eyJhbGciOiJQUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.VRlkPtiUq5MmBNgyuBqxv2_aX40STrWrBB2sSmGbxI78jVG_3hVoh7Mk-wUmFL389qpf05xNdn-gpMe-MSDUux7U7EuFspFZdYTUBo9wRvEBe4e1rHUCG00lVdYCG7eEgbAxM3cUhrHRwExBte30qBrFFUY9FgG-kJdYhgyh7VquMGuKgiS8CP_H0Gp1mIvTw6eEnSFAoKiryw9edUZ78pHELNn4y18YZvEndeNZh7f19LCtrB0G2bJUHGM4vPcwo2D-UAhEFBpSlnnqXDLSWOhUgLNLu0kZACXhT808KT6fdF6eFihdThmWN7_HUz2znjrjs71CqqDJgLhkGs8UvQ`, + key: "-----BEGIN CERTIFICATE-----\nMIIDXDCCAkSgAwIBAgIBKjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJVUzEV\nMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMD\nRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjAwNTA3MDkxMjU2WhcNMjAwNTA3\nMTExMjU2WjBWMQswCQYDVQQGEwJVUzEVMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4w\nDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3Qw\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtyVWH2FE8cU8LRcArH4Tw\nDhBOFcmJF28LrvRObcbDYsae6rEwby0aRgSxjTEMgyGBjroBSl22wOSA93kwx4pu\npfXEqbwywn9FhyKBb/OXQSglPmwrpmzQtPJGzBHncL+PPjRhPfqimwf7ZIPKAAgI\nz9O6ppGhE/x4Ct444jthUIBZuG5cUXhgiPBQdIQ3K88QhgVwcufTZkNHj4iSDfhl\nVFDHVjXjd2B/yGODjyv0TyChV0YBNGjMv7YFLWmIFUFzK+6qNSxu4czPtRkyfwaV\n2GW/PBT5f8fc6fKgQZ6k6BLK6+pi0iPh5TUizyHtqtueWDbrJ+wfdJilQS8D+EGr\nAgMBAAGjNTAzMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAM\nBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQBgVAM50/0aBTBxESYKIKN4\nE+qbV6aE0C+wYJLet0EWPTxwmFZamq5LNEO/D6xyoY5WHY60EyHRMs0agSB/ATBX\n5ULdEwh9G0NjxqivCcoddQ1fuVS2PrrqNL7VlRnYbTpd8/Dh4qnyl5FltlyZ/29L\ny7BWOwlcBlZdhsfH8svNX4PUxjRD+jmnczCDi7XSOKT8htKUV2ih1c9JrWpIhCi/\nHzEXkaAxNdhBNdIsLQMo3qq9fkSgNZQk9/ecJNPeuJ/UYyr5Xa4PxIWl4U+P7yuI\n+Q3FSPmUbiVsSGqMhh6V/DN8M+T5/KiSB47gFOfxc2/RR5aw4HkSp3WxwbT9njbE\n-----END CERTIFICATE-----", + keyType: `cert`, + }, + { + note: "ES256", + jwt: `eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJFUzI1NiJ9.eyJuYmYiOiAxNDQ0NDc4NDAwLCAiaXNzIjogInh4eCJ9.lArczfN-pIL8oUU-7PU83u-zfXougXBZj6drFeKFsPEoVhy9WAyiZlRshYqjTSXdaw8yw2L-ovt4zTUZb2PWMg`, + key: `{"kty":"EC","crv":"P-256","x":"z8J91ghFy5o6f2xZ4g8LsLH7u2wEpT2ntj8loahnlsE","y":"7bdeXLH61KrGWRdh7ilnbcGQACxykaPKfmBccTHIOUo"}`, + keyType: `cert`, + }, + { + note: "ES384", + jwt: `eyJhbGciOiJFUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.w85PzWrIQbJBOROnah0pa8or2LsXWnj88bwG1R-zf5Mm20CaYGPKPTQEsU_y-dzaWyDV1Na7nfaGaH3Khcvj8yS-bidZ0OZVVFDk9oabX7ZYvAHo2pTAOfxc11TeOYSF`, + key: "-----BEGIN CERTIFICATE-----\nMIICDDCCAZOgAwIBAgIBIzAKBggqhkjOPQQDAzBWMQswCQYDVQQGEwJVUzEVMBMG\nA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2\nMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjAwNTA3MDk0MzU1WhcNMjAwNTA3MTE0\nMzU1WjBWMQswCQYDVQQGEwJVUzEVMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYD\nVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3QwdjAQ\nBgcqhkjOPQIBBgUrgQQAIgNiAARjcwW7g9wx4ePsuwcVzDJCVo4f8I1C1X5US4B1\nrWN+5zFSJoGCKaPTXMDhAdS08D1G20AIRmA0AlVVXRxrZYZ+Y282O6s+EGsB5T1W\nMCnUFk2Sa+xZiGPApYz4zSGbNEqjNTAzMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE\nDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMAoGCCqGSM49BAMDA2cAMGQCMGSG\nVjx3DZP71ZGNDBw+AVdhNU3pgJW8kNpqjta3HFLb6pzqNOsfOn1ZeIWciEcyEgIw\nTGxli48W1AJ2s7Pw+3wOA6f9HAmczJPaiZ9CY038UiT8mk+pND5FEdqLhT/5lMEz\n-----END CERTIFICATE-----", + keyType: `cert`, + }, + { + note: "ES512", + jwt: `eyJhbGciOiJFUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.AYpssEoEqq9We9aKsnRykpECAVEOBRJJu8UgDzoL-F8fmB2LPxpS4Gl7D-9wAO5AJt4-9YSsgOb5FLc20MrZN30AAFYopZf75T1pEJQFrdDmOKT45abbrorcR7G_AHDbhBdDNM_R6GojYFg_HPxHndof745Yq5Tfw9PpJc-9kSyk6kqO`, + key: "-----BEGIN CERTIFICATE-----\nMIICWDCCAbmgAwIBAgIBAjAKBggqhkjOPQQDBDBWMQswCQYDVQQGEwJVUzEVMBMG\nA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2\nMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjAwNTA3MTA1NDM3WhcNMjAwNTA3MTI1\nNDM3WjBWMQswCQYDVQQGEwJVUzEVMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYD\nVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3QwgZsw\nEAYHKoZIzj0CAQYFK4EEACMDgYYABAHLm3IMD/88vC/S1cCTyjrCjwHIGsjibFBw\nPBXt36YKCjUdS7jiJJR5YQVPypSv7gPaKKn1E8CqkfVdd3rrp1TocAEms4XvigtW\nZBZzffw9xyZCgmtQ2dTHsufi/5W/Yx8N3Uw+D2wl1LKcJraouo+qgamGfuou6WbA\noPEtdOg0+B4jF6M1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUF\nBwMBMAwGA1UdEwEB/wQCMAAwCgYIKoZIzj0EAwQDgYwAMIGIAkIAzAAYDqMghX3S\n8UbS8s5TPAztJy9oNXFra5V8pPlUdNFc2ov2LN++scW46wCb/cJUyEc58sY7xFuK\nI5sCOkv95N8CQgFXmu354LZJ31zIovuUA8druOPe3TDnxMGwEEm2Lt43JNuhzNyP\nhJYh9/QKfe2AiwrLXEG4VVOIXdjq7vexl87evg==\n-----END CERTIFICATE-----", + keyType: `cert`, + }, + { + note: "EdDSA", + jwt: `eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.JkKWCY39IdWEQttmdqR7VdsvT-_QxheW_eb0S5wr_j83ltux_JDUIXs7a3Dtn3xuqzuhetiuJrWIvy5TzimeCg`, + key: "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwmK6SSAu2E9V7uynkCKEaj5nZJyTvNG4x0KohsRzLpg=\n-----END PUBLIC KEY-----", + keyType: `cert`, + }, + } + + ctx := context.Background() + + for _, tc := range tests { + t.Run(tc.note, func(t *testing.T) { + var verified bool + iter := func(r *ast.Term) error { + verified = bool(r.Value.(*ast.Array).Get(ast.NumberTerm("0")).Value.(ast.Boolean)) + return nil + } + + bctx := BuiltinContext{ + Context: ctx, + Time: ast.NumberTerm(int64ToJSONNumber(time.Now().UnixNano())), + } + + keysTerm := ast.ObjectTerm(ast.Item(ast.StringTerm(tc.keyType), ast.StringTerm(tc.key))) + operands := []*ast.Term{ast.StringTerm(tc.jwt), keysTerm} + err := builtinJWTDecodeVerify(bctx, operands, iter) + if err != nil { + t.Fatalf("unexpected error: %q", err) + } + + if !verified { + t.Fatal("expected token to be successfully verified") + } + }) + } +}