Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(oauth2): use new style KDF API to work better with FIPS mode #12212

Merged
merged 1 commit into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 29 additions & 14 deletions kong/plugins/oauth2/secret.lua
Original file line number Diff line number Diff line change
Expand Up @@ -201,27 +201,42 @@ if ENABLED_ALGORITHMS.PBKDF2 then
local PBKDF2_PREFIX

local ok, crypt = pcall(function()
local kdf = require "resty.openssl.kdf"
local openssl_kdf = require "resty.openssl.kdf"

-- pbkdf2 settings
-- pbkdf2 default settings
local PBKDF2_DIGEST = "sha512"
local PBKDF2_ITERATIONS = 10000
local PBKDF2_HASH_LEN = 32
local PBKDF2_SALT_LEN = 16

local EMPTY = {}

local kdf

local function derive(secret, opts)
opts = opts or EMPTY
local err
if kdf then
local _, err = kdf:reset()
if err then
kdf = nil
end
end

if not kdf then
kdf, err = openssl_kdf.new("PBKDF2")
if err then
return nil, err
end
end

local salt = opts.salt or utils.get_rand_bytes(PBKDF2_SALT_LEN)
local hash, err = kdf.derive({
type = kdf.PBKDF2,
outlen = opts.outlen or PBKDF2_HASH_LEN,
local hash, err = kdf:derive(opts.outlen or PBKDF2_HASH_LEN, {
pass = secret,
salt = salt,
md = opts.md or PBKDF2_DIGEST,
pbkdf2_iter = opts.pbkdf2_iter or PBKDF2_ITERATIONS,
})
digest = opts.digest or PBKDF2_DIGEST,
iter = opts.iter or PBKDF2_ITERATIONS,
}, 4)
if not hash then
return nil, err
end
Expand All @@ -245,8 +260,8 @@ if ENABLED_ALGORITHMS.PBKDF2 then

local crypt = {}

function crypt.hash(secret)
return derive(secret)
function crypt.hash(secret, options)
return derive(secret, options)
end

function crypt.verify(secret, hash)
Expand All @@ -263,8 +278,8 @@ if ENABLED_ALGORITHMS.PBKDF2 then
local calculated_hash, err = derive(secret, {
outlen = outlen,
salt = phc.salt,
md = phc.digest,
pbkdf2_iter = phc.params.i
digest = phc.digest,
iter = phc.params.i
})
if not calculated_hash then
return nil, err
Expand All @@ -287,7 +302,7 @@ end
local crypt = {}


function crypt.hash(secret)
function crypt.hash(secret, options)
assert(type(secret) == "string", "secret needs to be a string")

if ARGON2 then
Expand All @@ -299,7 +314,7 @@ function crypt.hash(secret)
end

if PBKDF2 then
return PBKDF2.hash(secret)
return PBKDF2.hash(secret, options)
end

return nil, "no suitable password hashing algorithm found"
Expand Down
51 changes: 51 additions & 0 deletions spec/03-plugins/25-oauth2/05-kdf_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
-- This software is copyright Kong Inc. and its licensors.
-- Use of the software is subject to the agreement between your organization
-- and Kong Inc. If there is no such agreement, use is governed by and
-- subject to the terms of the Kong Master Software License Agreement found
-- at https://konghq.com/enterprisesoftwarelicense/.
-- [ END OF LICENSE 0867164ffc95e54f04670b5169c09574bdbd9bba ]

local secret_impl = require "kong.plugins.oauth2.secret"


describe("Plugin: oauth2 (secret)", function()
describe("PBKDF", function()

local static_key = "$pbkdf2-sha512$i=10000,l=32$YSBsaXR0ZSBiaXQsIGp1c3QgYSBsaXR0bGUgYml0$z6ysNworexAhDELywIDi0ba0B0T7F/MBZ6Ige9lWRYI"

it("sanity test", function()
-- Note: to pass test in FIPS mode, salt length has to be 16 bytes or more
local derived, err = secret_impl.hash("tofu", { salt = "a litte bit, just a little bit" })
assert.is_nil(err)
assert.same(static_key, derived)
end)

it("uses random salt by default", function()
local derived, err = secret_impl.hash("tofu")
assert.is_nil(err)
assert.not_same(static_key, derived)
end)

it("verifies correctly", function()
local derived, err = secret_impl.hash("tofu")
assert.is_nil(err)

local ok, err = secret_impl.verify("tofu", derived)
assert.is_nil(err)
assert.is_truthy(ok)

local ok, err = secret_impl.verify("tofu", static_key)
assert.is_nil(err)
assert.is_truthy(ok)


local derived2, err = secret_impl.hash("bun")
assert.is_nil(err)

local ok, err = secret_impl.verify("tofu", derived2)
assert.is_nil(err)
assert.is_falsy(ok)
end)

end)
end)
Loading