Skip to content

Commit

Permalink
fix(jwt): offload ECDSA signature format conversion
Browse files Browse the repository at this point in the history
before this patch we transformed signature formats in the
`jwt_parser` module to the specified signature format

See The RFC for more details: https://www.rfc-editor.org/rfc/rfc7518#section-3.4

`lua-resty-openssl` 0.8.18 can do do this directly.

Fixes: https://konghq.atlassian.net/browse/KAG-844

Signed-off-by: Joshua Schmid <jaiks@posteo.de>
  • Loading branch information
jschmid1 authored and fffonion committed Mar 10, 2023
1 parent ff384be commit be622ef
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 35 deletions.
2 changes: 1 addition & 1 deletion kong-3.2.1-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ dependencies = {
"lua-resty-healthcheck == 1.6.2",
"lua-resty-mlcache == 2.6.0",
"lua-messagepack == 0.5.2",
"lua-resty-openssl == 0.8.17",
"lua-resty-openssl == 0.8.18",
"lua-resty-counter == 0.2.1",
"lua-resty-ipmatcher == 0.6.1",
"lua-resty-acme == 0.10.1",
Expand Down
59 changes: 25 additions & 34 deletions kong/plugins/jwt/jwt_parser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -53,29 +53,19 @@ local alg_sign = {
end,
ES256 = function(data, key)
local pkey = openssl_pkey.new(key)
local digest = openssl_digest.new("sha256")
assert(digest:update(data))
local signature = assert(pkey:sign(digest))

local derSequence = asn_sequence.parse_simple_sequence(signature)
local r = asn_sequence.unsign_integer(derSequence[1], 32)
local s = asn_sequence.unsign_integer(derSequence[2], 32)
assert(#r == 32)
assert(#s == 32)
return r .. s
local sig = assert(pkey:sign(data, "sha256", nil, { ecdsa_use_raw = true }))
if not sig then
return nil
end
return sig
end,
ES384 = function(data, key)
local pkey = openssl_pkey.new(key)
local digest = openssl_digest.new("sha384")
assert(digest:update(data))
local signature = assert(pkey:sign(digest))

local derSequence = asn_sequence.parse_simple_sequence(signature)
local r = asn_sequence.unsign_integer(derSequence[1], 48)
local s = asn_sequence.unsign_integer(derSequence[2], 48)
assert(#r == 48)
assert(#s == 48)
return r .. s
local sig = assert(pkey:sign(data, "sha384", nil, { ecdsa_use_raw = true }))
if not sig then
return nil
end
return sig
end
}

Expand Down Expand Up @@ -106,28 +96,29 @@ local alg_verify = {
assert(digest:update(data))
return pkey:verify(signature, digest)
end,
-- https://www.rfc-editor.org/rfc/rfc7518#section-3.4
ES256 = function(data, signature, key)
local pkey, _ = openssl_pkey.new(key)
assert(pkey, "Consumer Public Key is Invalid")
-- The ECDSA P-256 SHA-256 digital signature for a JWS is validated as
-- follows:

-- 1. The JWS Signature value MUST be a 64-octet sequence. If it is
-- not a 64-octet sequence, the validation has failed.
assert(#signature == 64, "Signature must be 64 bytes.")
local asn = {}
asn[1] = asn_sequence.resign_integer(sub(signature, 1, 32))
asn[2] = asn_sequence.resign_integer(sub(signature, 33, 64))
local signatureAsn = asn_sequence.create_simple_sequence(asn)
local digest = openssl_digest.new("sha256")
assert(digest:update(data))
return pkey:verify(signatureAsn, digest)
return pkey:verify(signature, data, "sha256", nil, { ecdsa_use_raw = true })
end,
ES384 = 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 == 96, "Signature must be 96 bytes.")
local asn = {}
asn[1] = asn_sequence.resign_integer(sub(signature, 1, 48))
asn[2] = asn_sequence.resign_integer(sub(signature, 49, 96))
local signatureAsn = asn_sequence.create_simple_sequence(asn)
local digest = openssl_digest.new("sha384")
assert(digest:update(data))
return pkey:verify(signatureAsn, digest)
return pkey:verify(signature, data, "sha384", nil, { ecdsa_use_raw = true })
end
}

Expand Down

0 comments on commit be622ef

Please sign in to comment.