Skip to content

Commit

Permalink
feat(jwt): add support for ES512, PS256, PS384, PS512
Browse files Browse the repository at this point in the history
* feat(jwt): add support for  ES512, PS256, PS384 and PS512

---------

Signed-off-by: Joshua Schmid <[email protected]>
  • Loading branch information
jschmid1 authored Mar 8, 2024
1 parent 109e0b8 commit b57e553
Show file tree
Hide file tree
Showing 6 changed files with 487 additions and 5 deletions.
4 changes: 4 additions & 0 deletions changelog/unreleased/kong/feat-jwt-es512.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
message: |
Addded support for ES512, PS256, PS384, PS512 algorithms in JWT plugin
type: feature
scope: Plugin
14 changes: 12 additions & 2 deletions kong/plugins/jwt/daos.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,25 @@ return {
"RS384",
"RS512",
"ES256",
"ES384"
"ES384",
"ES512",
"PS256",
"PS384",
"PS512",
},
}, },
{ tags = typedefs.tags },
},
entity_checks = {
{ conditional = { if_field = "algorithm",
if_match = {
match_any = { patterns = { "^RS256$", "^RS384$", "^RS512$" }, },
match_any = { patterns = { "^RS256$",
"^RS384$",
"^RS512$",
"^PS256$",
"^PS384$",
"^PS512$",
}, },
},
then_field = "rsa_public_key",
then_match = {
Expand Down
68 changes: 67 additions & 1 deletion kong/plugins/jwt/jwt_parser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,39 @@ local alg_sign = {
return nil
end
return sig
end,
ES512 = function(data, key)
local pkey = openssl_pkey.new(key)
local sig = assert(pkey:sign(data, "sha512", nil, { ecdsa_use_raw = true }))
if not sig then
return nil
end
return sig
end,

PS256 = function(data, key)
local pkey = openssl_pkey.new(key)
local sig = assert(pkey:sign(data, "sha256", openssl_pkey.PADDINGS.RSA_PKCS1_PSS_PADDING))
if not sig then
return nil
end
return sig
end,
PS384 = function(data, key)
local pkey = openssl_pkey.new(key)
local sig = assert(pkey:sign(data, "sha384", openssl_pkey.PADDINGS.RSA_PKCS1_PSS_PADDING))
if not sig then
return nil
end
return sig
end,
PS512 = function(data, key)
local pkey = openssl_pkey.new(key)
local sig = assert(pkey:sign(data, "sha512", openssl_pkey.PADDINGS.RSA_PKCS1_PSS_PADDING))
if not sig then
return nil
end
return sig
end
}

Expand Down Expand Up @@ -119,7 +152,40 @@ local alg_verify = {
local pkey, _ = openssl_pkey.new(key)
assert(#signature == 96, "Signature must be 96 bytes.")
return pkey:verify(signature, data, "sha384", nil, { ecdsa_use_raw = true })
end
end,

ES512 = function(data, signature, key)
-- Signing and validation with the ECDSA P-384 SHA-384 and ECDSA P-521
-- SHA-512 algorithms is performed identically to the procedure for
-- ECDSA P-256 SHA-256 -- just using the corresponding hash algorithms
-- with correspondingly larger result values. For ECDSA P-384 SHA-384,
-- R and S will be 384 bits each, resulting in a 96-octet sequence. For
-- ECDSA P-521 SHA-512, R and S will be 521 bits each, resulting in a
-- 132-octet sequence.
local pkey, _ = openssl_pkey.new(key)
assert(#signature == 132, "Signature must be 132 bytes.")
return pkey:verify(signature, data, "sha512", nil, { ecdsa_use_raw = true })
end,

PS256 = function(data, signature, key)
local pkey, _ = openssl_pkey.new(key)
assert(pkey, "Consumer Public Key is Invalid")
assert(#signature == 256, "Signature must be 256 bytes")
return pkey:verify(signature, data, "sha256", openssl_pkey.PADDINGS.RSA_PKCS1_PSS_PADDING)
end,
PS384 = function(data, signature, key)
local pkey, _ = openssl_pkey.new(key)
assert(pkey, "Consumer Public Key is Invalid")
assert(#signature == 256, "Signature must be 256 bytes")
return pkey:verify(signature, data, "sha384", openssl_pkey.PADDINGS.RSA_PKCS1_PSS_PADDING)
end,
PS512 = function(data, signature, key)
local pkey, _ = openssl_pkey.new(key)
assert(pkey, "Consumer Public Key is Invalid")
assert(#signature == 256, "Signature must be 256 bytes")
return pkey:verify(signature, data, "sha512", openssl_pkey.PADDINGS.RSA_PKCS1_PSS_PADDING)
end,

}


Expand Down
80 changes: 80 additions & 0 deletions spec/03-plugins/16-jwt/01-jwt_parser_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,54 @@ describe("Plugin: jwt (parser)", function()
local jwt = assert(jwt_parser:new(token))
assert.True(jwt:verify_signature(fixtures.es384_public_key))
end)

it("should encode using ES512", function()
local token = jwt_parser.encode({
sub = "5656565656",
name = "Jane Doe",
admin = true
}, fixtures.es512_private_key, 'ES512')

assert.truthy(token)
local jwt = assert(jwt_parser:new(token))
assert.True(jwt:verify_signature(fixtures.es512_public_key))
end)
it("should encode using PS256", function()
local token = jwt_parser.encode({
sub = "5656565656",
name = "Jane Doe",
admin = true
}, fixtures.ps256_private_key, 'PS256')

assert.truthy(token)
local jwt = assert(jwt_parser:new(token))
assert.True(jwt:verify_signature(fixtures.ps256_public_key))
end)

it("should encode using PS384", function()
local token = jwt_parser.encode({
sub = "5656565656",
name = "Jane Doe",
admin = true
}, fixtures.ps384_private_key, 'PS384')

assert.truthy(token)
local jwt = assert(jwt_parser:new(token))
assert.True(jwt:verify_signature(fixtures.ps384_public_key))
end)

it("should encode using PS512", function()
local token = jwt_parser.encode({
sub = "5656565656",
name = "Jane Doe",
admin = true
}, fixtures.ps512_private_key, 'PS512')

assert.truthy(token)
local jwt = assert(jwt_parser:new(token))
assert.True(jwt:verify_signature(fixtures.ps512_public_key))
end)

end)
describe("Decoding", function()
it("throws an error if not given a string", function()
Expand Down Expand Up @@ -181,6 +229,38 @@ describe("Plugin: jwt (parser)", function()
assert.False(jwt:verify_signature(fixtures.rs256_public_key))
end
end)
it("using ES512", function()
for _ = 1, 500 do
local token = jwt_parser.encode({sub = "foo"}, fixtures.es512_private_key, 'ES512')
local jwt = assert(jwt_parser:new(token))
assert.True(jwt:verify_signature(fixtures.es512_public_key))
assert.False(jwt:verify_signature(fixtures.rs256_public_key))
end
end)
it("using PS256", function()
for _ = 1, 500 do
local token = jwt_parser.encode({sub = "foo"}, fixtures.ps256_private_key, 'PS256')
local jwt = assert(jwt_parser:new(token))
assert.True(jwt:verify_signature(fixtures.ps256_public_key))
assert.False(jwt:verify_signature(fixtures.es256_public_key))
end
end)
it("using PS384", function()
for _ = 1, 500 do
local token = jwt_parser.encode({sub = "foo"}, fixtures.ps384_private_key, 'PS384')
local jwt = assert(jwt_parser:new(token))
assert.True(jwt:verify_signature(fixtures.ps384_public_key))
assert.False(jwt:verify_signature(fixtures.es256_public_key))
end
end)
it("using PS512", function()
for _ = 1, 500 do
local token = jwt_parser.encode({sub = "foo"}, fixtures.ps512_private_key, 'PS512')
local jwt = assert(jwt_parser:new(token))
assert.True(jwt:verify_signature(fixtures.ps512_public_key))
assert.False(jwt:verify_signature(fixtures.es256_public_key))
end
end)
end)
describe("verify registered claims", function()
it("requires claims passed as arguments", function()
Expand Down
Loading

1 comment on commit b57e553

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bazel Build

Docker image available kong/kong:b57e553754ad8169fc604b7f1cbb16f561c97568
Artifacts available https://github.com/Kong/kong/actions/runs/8200742223

Please sign in to comment.