Skip to content

Conversation

@iFergal
Copy link
Collaborator

@iFergal iFergal commented Jan 15, 2025

This PR adds an alternative mechanism to authenticate with the KERIA API from a Signify client, and leaves the current RFC-9421 signed headers in place too. Beyond confidentiality, it also resolves other issues from before such as unsigned query params and bodies. (#287)

The unsigned HTTP request from the client is converted to a HTTP bytestream and embedded in an ESSR payload. This payload becomes the body of a wrapper HTTP request for the "/" path - so tunneled via ESSR. The wrapper could be handled by pure TCP but for now this works quite nicely in the Falcon middlewares with minimal changes.

Because nothing else uses "/" as the path, the authentication type is determined based on the path. A cleaner approach in a TCP world would just to have a CESR based command signed and optionally encrypted following ESSR, rather than complicating things with managing headers, or embedding HTTP requests within each other.

I have written the corresponding code in Signify and all integration tests pass.


Flow for generating request from Signify:

  1. Create HTTP request - e.g. POST /identifiers <body>
  2. Add Signify-Resource header (Encrypt Sender)
  3. Serialize HTTP request as a HTTP string
  4. crypto_box_seal(http_request_string, public_key_of_keria_agent)
  5. Create a new HTTP request to POST / where the body of the request is the sealed box bytes (application/octet-stream)
  6. Add Signify-Resource, Signify-Timestamp and Signify-Receiver headers (receiver is Sign Receiver)
  7. Sign the request and add as a header

Note:
Like the keripy ESSR parser, the commitment to unsigned HTTP request is done by taking a digest:

payload = dict(
    src=<sender>,
    dest=<receiver>,
    d=coring.Diger(ser=cipher, code=MtrDex.Blake3_256).qb64,
    dt=dt,
)

A signature is created over this dict. I'm re-using the signature style of the signed headers.

ESSR drawio

@iFergal iFergal self-assigned this Jan 15, 2025
@iFergal iFergal changed the title feat: ESSR client authentication feat: ESSR protected client APIs Jan 16, 2025
@iFergal
Copy link
Collaborator Author

iFergal commented Jan 17, 2025

WebOfTrust/signify-ts#304 created on Signify side

@codecov
Copy link

codecov bot commented Jan 23, 2025

Codecov Report

❌ Patch coverage is 98.39572% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.99%. Comparing base (676d7e8) to head (1d83e66).
⚠️ Report is 43 commits behind head on main.

Files with missing lines Patch % Lines
src/keria/core/authing.py 97.51% 4 Missing ⚠️
src/keria/app/aiding.py 66.66% 1 Missing ⚠️
tests/core/test_authing.py 99.51% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #351      +/-   ##
==========================================
+ Coverage   93.80%   93.99%   +0.18%     
==========================================
  Files          37       37              
  Lines        8462     8704     +242     
==========================================
+ Hits         7938     8181     +243     
+ Misses        524      523       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@iFergal iFergal marked this pull request as draft June 18, 2025 17:45
@iFergal
Copy link
Collaborator Author

iFergal commented Jun 18, 2025

Updated PR to allow both signed headers and ESSR. I'm leaving this as draft as I still have the edge case I need to test for in the comment I left on the PR above, and I need to update my Signify PR.

@iFergal iFergal marked this pull request as ready for review June 24, 2025 12:57

if not self.authn.verify(req):
# @TODO - foconnor: Not sure if this should be here - Signify is not signing headers for passcode rotation.
if not self.authn.inbound(req):
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@pfeairheller Passcode rotation (PUT /agent/{caid}) in Signify doesn't use signed headers (just has a signed body), like the rest of the /agent endpoints, so perhaps this shouldn't be checking for signed headers here. If not, I can update Signify to use the correct fetch, and adjust this to accept ESSR if needed.

Any idea @rodolfomiranda?

if req.path.startswith(path):
return

req.path = quote(req.path)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The path is already encoded when sending over the wire. e.g. set 'alice' to 'alice test' in a test, and it will fail on main, as /alice%20test is being turned into /alice%2520test with this line (double encoded).

@m00sey m00sey self-requested a review October 22, 2025 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants