Repository navigation
feat(security): ES256 and Ed25519 JWT signing/verification (closes #401) - #414
Merged
Merged
Conversation
New API next to the unchanged HS256 entry points: - cwist_jwt_sign_es256 / cwist_jwt_verify_es256 (ECDSA P-256, JOSE raw R||S signatures, optional kid header) - cwist_jwt_sign_ed25519 / cwist_jwt_verify_ed25519 (EdDSA, RFC 8037) Keys are PEM; verifiers accept a public key or the public half of a private key. Every verifier requires the header to declare exactly its own alg, so HS256/ES256/EdDSA tokens never cross-verify (RFC 8725). Key type is checked too: an off-curve or wrong-type key fails signing and verification outright. The HS256 sign/verify bodies are folded into shared helpers with the new algorithms; behaviour of the existing API is unchanged (test_jwt and test_middleware_jwt pass unmodified). Rust bindings expose sign_es256/verify_es256/sign_ed25519/verify_ed25519 with tests covering round trips, kid, wrong-key and alg confusion.
Member
Author
Build fails |
jwt.o now references BoringSSL-only symbols (ECDSA_SIG_from_bytes, ECDSA_SIG_to_bytes, BIO_reset, EVP_PKEY_id) after the ES256/Ed25519 work, so the example must resolve -lssl/-lcrypto from lib/boringssl/build like the tutorials do.
gg582
added a commit
that referenced
this pull request
Oct 19, 2026
…) (#414) * feat(security): ES256 and Ed25519 JWT signing/verification (closes #401) New API next to the unchanged HS256 entry points: - cwist_jwt_sign_es256 / cwist_jwt_verify_es256 (ECDSA P-256, JOSE raw R||S signatures, optional kid header) - cwist_jwt_sign_ed25519 / cwist_jwt_verify_ed25519 (EdDSA, RFC 8037) Keys are PEM; verifiers accept a public key or the public half of a private key. Every verifier requires the header to declare exactly its own alg, so HS256/ES256/EdDSA tokens never cross-verify (RFC 8725). Key type is checked too: an off-curve or wrong-type key fails signing and verification outright. The HS256 sign/verify bodies are folded into shared helpers with the new algorithms; behaviour of the existing API is unchanged (test_jwt and test_middleware_jwt pass unmodified). Rust bindings expose sign_es256/verify_es256/sign_ed25519/verify_ed25519 with tests covering round trips, kid, wrong-key and alg confusion. * fix(example/jwt): link vendored BoringSSL instead of system OpenSSL jwt.o now references BoringSSL-only symbols (ECDSA_SIG_from_bytes, ECDSA_SIG_to_bytes, BIO_reset, EVP_PKEY_id) after the ES256/Ed25519 work, so the example must resolve -lssl/-lcrypto from lib/boringssl/build like the tutorials do.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #401. JWT gains asymmetric algorithms alongside the unchanged HS256 entry points:
cwist_jwt_sign_es256/cwist_jwt_verify_es256— ECDSA over P-256 with SHA-256; JOSE raw R||S signatures (RFC 7518 §3.4); optionalkidheader claimcwist_jwt_sign_ed25519/cwist_jwt_verify_ed25519— EdDSA (RFC 8037)Keys are PEM (SEC 1 or PKCS#8). Verifiers accept a public key or the public half of a private key.
Security properties
alg, so HS256/ES256/EdDSA tokens never cross-verify (RFC 8725 §3.1).cwist_jwt_sign/cwist_jwt_verifysignatures and behavior are unchanged (the bodies are folded into shared helpers).Implementation notes
ECDSA_SIG_from_bytes/ECDSA_SIG_to_bytes+BN_bn2bin_padded.PEM_read_bio_PUBKEYtoPEM_read_bio_PrivateKeywith aBIO_reset(a failed first read consumes the buffer).exp/nbfvalidation with the existing 300 s leeway applies to all algorithms.Tests
tests/test_jwt_asym.c(new, inTEST_TARGETS): ES256/Ed25519 round trips,kidheader, wrong-key, wrong-curve, wrong-type, garbage-PEM, expired-token, and full cross-algorithm confusion matrix.test_jwtandtest_middleware_jwtpass unmodified (HS256 regression check).sign_es256/verify_es256/sign_ed25519/verify_ed25519incwist::jwtwith two new tests intests/advanced.rs(14/14 pass).docs/api/v4.0-api-baseline.txtregenerated (make api-baseline;make api-checkgreen).