I have been dabbling with Ping Access using JWKS endpoints, and see Kong has some EC support(ES256) but not all flavors(ES384, ES512) just yet:
I will be frank and say that I am just not the best with crypto and signing, but I was wondering if Kong would be okay with expanding the options here and if what I am doing looks right?
Signing around EC
--- Supported algorithms for signing tokens.
["ES256"] = function(data, key)
local pkeyPrivate = openssl_pkey.new(key)
local signature = pkeyPrivate:sign(openssl_digest.new("sha256"):update(data))
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
end,
["ES384"] = function(data, key)
local pkeyPrivate = openssl_pkey.new(key)
local signature = pkeyPrivate:sign(openssl_digest.new("sha384"):update(data))
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
end,
["ES512"] = function(data, key)
local pkeyPrivate = openssl_pkey.new(key)
local signature = pkeyPrivate:sign(openssl_digest.new("sha512"):update(data))
local derSequence = asn_sequence.parse_simple_sequence(signature)
local r = asn_sequence.unsign_integer(derSequence[1], 64)
local s = asn_sequence.unsign_integer(derSequence[2], 64)
assert(#r == 64)
assert(#s == 64)
return r .. s
end
}
And the Verify additions around EC
--- Supported algorithms for verifying tokens.
local alg_verify = {
["ES256"] = function(data, signature, key)
local pkey_ok, pkey = pcall(openssl_pkey.new, key)
assert(pkey_ok, "Consumer Public Key is Invalid")
assert(#signature == 64, "Signature must be 64 bytes.")
local asn = {}
asn[1] = asn_sequence.resign_integer(string_sub(signature, 1, 32))
asn[2] = asn_sequence.resign_integer(string_sub(signature, 33, 64))
local signatureAsn = asn_sequence.create_simple_sequence(asn)
local digest = openssl_digest.new('sha256'):update(data)
return pkey:verify(signatureAsn, digest)
end,
["ES384"] = function(data, signature, key)
local pkey_ok, pkey = pcall(openssl_pkey.new, key)
assert(pkey_ok, "Consumer Public Key is Invalid")
assert(#signature == 96, "Signature must be 96 bytes.")
local asn = {}
asn[1] = asn_sequence.resign_integer(string_sub(signature, 1, 48))
asn[2] = asn_sequence.resign_integer(string_sub(signature, 49, 96))
local signatureAsn = asn_sequence.create_simple_sequence(asn)
local digest = openssl_digest.new('sha384'):update(data)
return pkey:verify(signatureAsn, digest)
end,
["ES512"] = function(data, signature, key)
local pkey_ok, pkey = pcall(openssl_pkey.new, key)
assert(pkey_ok, "Consumer Public Key is Invalid")
assert(#signature == 128, "Signature must be 128 bytes.")
local asn = {}
asn[1] = asn_sequence.resign_integer(string_sub(signature, 1, 64))
asn[2] = asn_sequence.resign_integer(string_sub(signature, 65, 128))
local signatureAsn = asn_sequence.create_simple_sequence(asn)
local digest = openssl_digest.new('sha512'):update(data)
return pkey:verify(signatureAsn, digest)
end
}
Also anyone know much about jwks in general? Yes I get the kty, and kid is to help pick which record to pick from in the jwks list, and ES256 tells me the alg. I am curious if we need to account for crv at all in signature validation as I don’t see Kong doing that for the existing ES256. But essentially how can I take x and y to produce the public key is what I am getting at in the Kongs signature verify calls -> [“ES256”] = function(data, signature, key) or am I totally off base and x and y are not even used as the public key .
{
"kty": "EC",
"kid": "7s",
"use": "sig",
"alg": "ES256",
"x": "XXXXXXXXXXXXXXXXXXXXXX",
"y": "XXXXXXXXXXXXXXXXXXXXXX",
"crv": "P-256"
}