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

feat(hmac-auth): add support for RSA signatures #11133

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

locao
Copy link
Contributor

@locao locao commented Jun 27, 2023

Summary

The hmac-auth plugin allow authentication with HMAC signatures based on the draft-cavage-http-signatures draft.
This commit aims to add support for RSA signatures as described in the draft, providing a stronger layer
of security via asymmetric encryption.

Co-authored-by: Jérémy Quilleré [email protected]

Note: the feature was coded by @mideuger in #8530, this PR adds cluster compatibility support.

Checklist

Full changelog

  • Add possible values to algorithms (rsa-sha256 and rsa-sha512)
  • Add a new field to this plugin's credential (public_key)
  • Add tests showing failed and succeeded authentications using rsa algorithms

How to test

First, create a RSA key pair :

openssl genrsa -out private_key.pem
openssl rsa -in private_key.pem -pubout -out public_key.pem

Then, enable the plugin, create a consumer and a corresponding credential with the public key :

curl -X POST http://localhost:8001/plugins \
    --form "name=hmac-auth"  \
    --form "config.algorithms=rsa-sha256" \
    --form "config.algorithms=rsa-sha512"

curl -X POST http://localhost:8001/consumers \
    --form "username=alice"

curl -X POST http://localhost:8001/consumers/alice/hmac-auth \
    --form "username=alice" \
    --form "public_key=@public_key.pem"

Finally, make a signed request :

export DATE="date: $(echo -n $(TZ=GMT date '+%a, %d %b %Y %T %Z'))"
export SIGNATURE=$(printf %s "${DATE}" | openssl dgst -binary -sha512 -sign private_key.pem | openssl base64 -A)
export AUTHORIZATION='authorization: username="alice", algorithm="rsa-sha512", headers="date", signature="'${SIGNATURE}'"'

curl -X GET http://localhost:8000 \
    --header "${DATE}" \
    --header "${AUTHORIZATION}"

Possible improvements

Here are some improvements that we might want to implement after this one :

  • Check public key validity during credential creation/update
  • Rebrand the plugin to HTTP Signature
  • Use Signature header to provide the signature (or let it be configurable)
  • Implement keyId from the draft

Issue reference

KAG-1934
Closes: #8530

@locao locao marked this pull request as draft June 27, 2023 19:29
@locao locao force-pushed the feat/rsa-http-signature branch from f404e20 to 46ae28a Compare June 27, 2023 21:37
@locao locao marked this pull request as ready for review June 28, 2023 11:36
@locao locao force-pushed the feat/rsa-http-signature branch from 46ae28a to ab0a2bc Compare June 30, 2023 20:24
@kikito kikito requested a review from bungle August 15, 2023 08:43
@kikito
Copy link
Member

kikito commented Aug 22, 2023

@bungle please give this a review

@catbro666

This comment was marked as resolved.

@@ -97,7 +125,7 @@ local function retrieve_hmac_fields(authorization_header)
-- parse the header to retrieve hamc parameters
if authorization_header then
local iterator, iter_err = re_gmatch(authorization_header,
"\\s*[Hh]mac\\s*username=\"(.+)\"," ..
"(\\s*[Hh]mac)?\\s*username=\"(.+)\"," ..
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to specify rsa here when using rsa signature for consistency?

@@ -31,18 +32,45 @@ local SIGNATURE_NOT_VALID = "HMAC signature cannot be verified"
local SIGNATURE_NOT_SAME = "HMAC signature does not match"
Copy link
Contributor

Choose a reason for hiding this comment

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

error message needs to be changed accordingly

Copy link
Contributor

Choose a reason for hiding this comment

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

The specific string format for the "Authorization" header that includes the method (e.g., "Hmac" or "Rsa") and the various components (e.g., "username," "algorithm," "headers," and "signature") may not be standardized in the HTTP Signatures draft (draft-cavage-http-signatures). The draft defines the concept of HTTP signatures and how they can be generated and verified, but it doesn't prescribe a specific format for the "Authorization" header.

The format you are using, which includes "Hmac" or "Rsa" as the method prefix, is a common convention used in some implementations for clarity and to distinguish between different authentication methods (HMAC and RSA, in this case). However, this specific format might not be explicitly detailed in the draft itself.

Copy link
Contributor

Choose a reason for hiding this comment

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

agree. need to output the right error message

@catbro666
Copy link
Contributor

catbro666 commented Sep 7, 2023

Strictly speaking, rsa doesn't belong to hmac. The scope of the plugin name feels a little small now. Maybe something like "sign-auth" would have been better

@chobits
Copy link
Contributor

chobits commented Sep 23, 2023

hi @locao I'm helping to resolve this conflict, recently I have also reviewed original community PRs. Hans and me will be helping to move the progress of this communit PR into our master.

@@ -17,6 +17,7 @@ return {
{ consumer = { type = "foreign", reference = "consumers", required = true, on_delete = "cascade", }, },
{ username = { type = "string", required = true, unique = true }, },
{ secret = { type = "string", auto = true }, },
{ public_key = { type = "string" }, },
Copy link
Contributor

Choose a reason for hiding this comment

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

how about typedefs.key { required = false, referenceable = true, encrypted = true }, }, ?

Suggested change
{ public_key = { type = "string" }, },
{ public_key = typedefs.key {
description = "The RSA public key used to validate signature.",
type = "string",
encrypted = true, -- Kong Enterprise-exclusive feature, does nothing in Kong CE
referenceable = true,
}, },

An additional validator to validate it's a RSA key (not EC or ECX keys) would be good.

mideuger and others added 7 commits September 25, 2023 15:41
The hmac-auth plugin allow authentication with HMAC signatures based on
the draft-cavage-http-signatures draft. This commit aims to add support
for RSA signatures as described in the draft, providing a stronger layer
of security via asymmetric encryption.

This implementation has been made with backward compatibility in mind
and only one new field has been added to the DAOs to store the RSA
public key. Depending on the algorithm used during the request, the
plugin will use either the HMAC secret or the RSA public key to verify
the signature.
@chobits chobits force-pushed the feat/rsa-http-signature branch from 8f737a8 to f52df68 Compare September 25, 2023 07:41
@team-eng-enablement team-eng-enablement added author/community PRs from the open-source community (not Kong Inc) and removed author/community PRs from the open-source community (not Kong Inc) labels Sep 26, 2023
@@ -6,6 +6,8 @@ local ALGORITHMS = {
"hmac-sha256",
"hmac-sha384",
"hmac-sha512",
"rsa-sha256",
"rsa-sha512",
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we add these new options in the description of the algorithms field? (line 30)

@AndyZhang0707 AndyZhang0707 modified the milestones: 3.5.0, 3.6.0 Oct 19, 2023
@kikito kikito requested review from nowNick and gszr October 31, 2023 09:45
Copy link
Contributor

@nowNick nowNick left a comment

Choose a reason for hiding this comment

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

Just one concern regarding the if statement. Other than that it looks good 👍

@@ -113,10 +141,10 @@ local function retrieve_hmac_fields(authorization_header)
end

if m and #m >= 4 then
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we increment the check in the if as well?

Suggested change
if m and #m >= 4 then
if m and #m >= 5 then

["proxy-authorization"] = hmacAuth,
},
})
assert.res_status(401, res)
Copy link
Contributor

Choose a reason for hiding this comment

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

Depending on which PR goes it first - we need to either change it here or there (#11791) but in the end we need to make sure we return proper WWW-Authenticate header on 401 response

@bungle
Copy link
Member

bungle commented Dec 7, 2023

Looks like this is the latest draft:
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures

So in theory at least I would rather move this plugin in direction of this:
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#iana-hsa-contents

That lists there:

  • rsa-pss-sha512
  • rsa-v1_5-sha256
  • hmac-sha256
  • ecdsa-p256-sha256
  • ecdsa-p384-sha384
  • ed25519

And perhaps later:
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#name-json-web-signature-jws-algo

@kikito kikito modified the milestones: 3.6.0, 3.7.0 Jan 22, 2024
@locao locao marked this pull request as draft February 20, 2024 18:12
@kikito kikito modified the milestones: 3.7.0, 3.8.0 Apr 23, 2024
@AndyZhang0707
Copy link
Collaborator

3.8 FF is done, so I don't think we will ship this feature in 3.8. Removing it from the 3.8.0 milestone. cc: @locao

@AndyZhang0707 AndyZhang0707 removed this from the 3.8.0 milestone Aug 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.