Skip to content

Commit 9a3b845

Browse files
committed
Add RFC 9421 HTTP Message Signatures example using wolfCrypt Ed25519
Initial implementation of RFC 9421 HTTP Message Signatures as a wolfssl-examples project. Covers a minimal interoperable subset: derived components (@method, @authority, @path, @query), arbitrary HTTP header fields, Ed25519 signing/verification, single signature (sig1), and timestamp-based replay protection. Files: - common/wc_sf.{c,h}: Minimal RFC 8941 structured fields subset (dictionary lookup, inner lists, parameters, byte sequences) - common/wc_http_sig.{c,h}: RFC 9421 Sign/Verify/GetKeyId API - sign_request.c: Standalone signing example - http_server_verify.c: Demo HTTP server with signature verification - http_client_signed.c: Demo HTTP client sending signed requests - test_vectors.c: 11 tests including RFC 9421 Appendix B.2.6 Design decisions: - Ed25519-only (alg enforced on verify path) - sigOut/inputOut are char* (NUL-terminated strings) - Header names lowercased per RFC 9421 Section 2.1 - Portable case-insensitive comparison (no POSIX strcasecmp) - SO_RCVTIMEO on server to prevent blocking on slow clients - Signature base written directly to caller buffer (no double-buffer) Known limitations: - 32-bit long: parse_sf_integer caps at 9 digits, breaking current UNIX timestamps (needs fix, see below) - No content-digest, multi-signature, or full RFC 8941 support - Duplicate headers: first match wins, no folding Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
1 parent 9afdb06 commit 9a3b845

File tree

12 files changed

+3412
-0
lines changed

12 files changed

+3412
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,5 +412,11 @@ stsafe/stsafe_test
412412
stsafe/wolfssl_stsafe_test
413413
stsafe/wolfssl_stsafe_full_test
414414

415+
# HTTP Message Signatures (RFC 9421) example
416+
http-message-signatures/sign_request
417+
http-message-signatures/test_vectors
418+
http-message-signatures/http_server_verify
419+
http-message-signatures/http_client_signed
420+
415421
# uefi-library generated filesystem content
416422
uefi-library/efifs

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,19 @@ Please see the [uefi-static/README.md](uefi-static/README.md) for further usage
389389
details.
390390

391391

392+
<br />
393+
394+
#### http-message-signatures (RFC 9421 HTTP Message Signatures)
395+
396+
This directory contains examples that demonstrate RFC 9421 HTTP Message
397+
Signatures using wolfCrypt Ed25519, including a signing example,
398+
client/server demo, and test vectors for RFC 9421 Appendix B.2.6.
399+
400+
Please see the
401+
[http-message-signatures/README.md](http-message-signatures/README.md)
402+
for further usage and details.
403+
404+
392405
<br />
393406

394407
#### uefi-library (wolfCrypt UEFI boot module and test app)

http-message-signatures/Makefile

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
CC ?= gcc
2+
WOLFSSL_INSTALL_DIR = /usr/local
3+
CFLAGS = -I$(WOLFSSL_INSTALL_DIR)/include -I. -Wall -Wextra
4+
LDFLAGS = -L$(WOLFSSL_INSTALL_DIR)/lib
5+
LDLIBS = -lwolfssl
6+
7+
COMMON_SRC = common/wc_sf.c common/wc_http_sig.c
8+
COMMON_OBJ = $(COMMON_SRC:.c=.o)
9+
10+
TARGETS = sign_request test_vectors http_server_verify http_client_signed
11+
12+
all: $(TARGETS)
13+
14+
sign_request: sign_request.o $(COMMON_OBJ)
15+
$(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
16+
17+
test_vectors: test_vectors.o $(COMMON_OBJ)
18+
$(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
19+
20+
http_server_verify: http_server_verify.o $(COMMON_OBJ)
21+
$(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
22+
23+
http_client_signed: http_client_signed.o $(COMMON_OBJ)
24+
$(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)
25+
26+
%.o: %.c
27+
$(CC) -c -o $@ $< $(CFLAGS)
28+
29+
.PHONY: all clean test
30+
31+
clean:
32+
rm -f $(TARGETS) *.o common/*.o
33+
34+
test: test_vectors
35+
./test_vectors

http-message-signatures/README.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# RFC 9421 HTTP Message Signatures with wolfCrypt
2+
3+
Minimal [RFC 9421](https://www.rfc-editor.org/rfc/rfc9421) implementation
4+
using wolfCrypt Ed25519. Covers derived components (`@method`, `@authority`,
5+
`@path`, `@query`), arbitrary headers, timestamp validation, and `keyid`
6+
extraction. Single signature (`sig1`), Ed25519 only.
7+
8+
## Quick start
9+
10+
```sh
11+
# wolfSSL prerequisite
12+
cd wolfssl && ./configure --enable-ed25519 --enable-coding && make && sudo make install
13+
14+
# Build and test
15+
cd http-message-signatures
16+
make
17+
make test # 17 tests including RFC 9421 B.2.6 vector
18+
./sign_request # standalone signing example
19+
```
20+
21+
## Client/server demo
22+
23+
```sh
24+
./http_server_verify & # terminal 1
25+
./http_client_signed # terminal 2
26+
```
27+
28+
The client sends three requests: a valid signed POST (→ 200), a tampered
29+
request (→ 401), and a valid signed GET (→ 200).
30+
31+
## API
32+
33+
```c
34+
/* Sign — outputs NUL-terminated Signature and Signature-Input header values */
35+
int wc_HttpSig_Sign(
36+
const char* method, const char* authority,
37+
const char* path, const char* query,
38+
const wc_HttpHeader* headers, int headerCount,
39+
ed25519_key* key, const char* keyId, long created,
40+
char* sigOut, word32* sigOutSz,
41+
char* inputOut, word32* inputOutSz);
42+
43+
/* Extract keyid from Signature-Input */
44+
int wc_HttpSig_GetKeyId(
45+
const char* signatureInput, const char* label,
46+
char* keyIdOut, word32* keyIdOutSz);
47+
48+
/* Verify — returns 0 on success; maxAgeSec=0 skips timestamp check */
49+
int wc_HttpSig_Verify(
50+
const char* method, const char* authority,
51+
const char* path, const char* query,
52+
const wc_HttpHeader* headers, int headerCount,
53+
const char* signature, const char* signatureInput,
54+
const char* label, ed25519_key* pubKey, int maxAgeSec);
55+
```
56+
57+
Typical verify flow:
58+
59+
```
60+
1. wc_HttpSig_GetKeyId(sigInput, label, keyIdBuf, &sz)
61+
2. my_key_store_lookup(keyIdBuf) → pubKey
62+
3. wc_HttpSig_Verify(..., pubKey, maxAgeSec)
63+
```
64+
65+
## Limitations
66+
67+
- **No body protection** — no `content-digest` (RFC 9530); signatures cover
68+
components and headers only
69+
- **No replay prevention** — `maxAgeSec` limits the window; nonce tracking
70+
is the caller's responsibility
71+
- **Duplicate headers** — first match wins, no folding
72+
- **Y2038** — `created` uses `long`; overflows on platforms where `long` is
73+
32-bit (all 32-bit targets and 64-bit Windows/LLP64) after 2038-01-19
74+
- **Canonicalization** — signer and verifier must agree on component
75+
representation; intermediaries that rewrite headers will break verification
76+
77+
## Files
78+
79+
```
80+
common/wc_http_sig.{c,h} RFC 9421 sign/verify/getKeyId
81+
common/wc_sf.{c,h} RFC 8941 structured fields (subset)
82+
sign_request.c Standalone signing example
83+
http_server_verify.c Demo server with signature verification
84+
http_client_signed.c Demo client sending signed requests
85+
test_vectors.c 17 tests including RFC 9421 B.2.6
86+
```
87+
88+
## References
89+
90+
- [RFC 9421 — HTTP Message Signatures](https://www.rfc-editor.org/rfc/rfc9421)
91+
- [RFC 8941 — Structured Field Values for HTTP](https://www.rfc-editor.org/rfc/rfc8941)
92+
- [wolfSSL Ed25519 Documentation](https://www.wolfssl.com/documentation/manuals/wolfssl/group__ED25519.html)

0 commit comments

Comments
 (0)