DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
csrf.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file csrf.h
6 * @brief Stateless HMAC-signed CSRF token (DETWS_ENABLE_CSRF).
7 *
8 * A CSRF token is `<nonce_hex>.<sig_hex>` where sig = the first CSRF_SIG_BYTES of
9 * HMAC-SHA256(secret, nonce). The secret is seeded once from the hardware RNG at
10 * begin(); the nonce is a per-issue counter (it need not be secret - the security
11 * is the HMAC). Verification recomputes the HMAC over the embedded nonce and
12 * constant-time compares the signature, so no server-side session state is kept.
13 *
14 * The token is sized to fit a single MAX_VAL_LEN header value and a `csrf=`
15 * cookie. These functions are pure (no Arduino dependency) so they unit-test on
16 * the host (with DETWS_ENABLE_CSRF set) using a fixed secret.
17 *
18 * @author Douglas Quigg (dstroy0)
19 * @date 2026
20 */
21
22#ifndef DETERMINISTICESPASYNCWEBSERVER_CSRF_H
23#define DETERMINISTICESPASYNCWEBSERVER_CSRF_H
24
25#include "ServerConfig.h"
26
27#if DETWS_ENABLE_CSRF
28
29#include <stddef.h>
30#include <stdint.h>
31
32/** @brief Nonce length in bytes (hex-encoded in the token). */
33#define CSRF_NONCE_BYTES 6
34/** @brief Signature length in bytes (truncated HMAC, hex-encoded in the token). */
35#define CSRF_SIG_BYTES 14
36/** @brief Buffer size for a token string: 2*nonce + '.' + 2*sig + NUL = 42, rounded up. */
37#define CSRF_TOKEN_BUF 48
38
39/**
40 * @brief Set the HMAC secret (call once at begin() with hardware-random bytes).
41 *
42 * @param secret Secret key bytes.
43 * @param len Length in bytes; capped at 32 (longer keys are truncated).
44 */
45void csrf_set_secret(const uint8_t *secret, size_t len);
46
47/**
48 * @brief Issue a fresh signed token into @p out.
49 *
50 * @param out Destination buffer (>= CSRF_TOKEN_BUF).
51 * @param cap Size of @p out.
52 * @return Token length in characters, or 0 if no secret is set or @p cap is too small.
53 */
54int csrf_issue(char *out, size_t cap);
55
56/**
57 * @brief Verify a token's signature against the current secret.
58 *
59 * @return true if @p token is well-formed and its HMAC signature is valid;
60 * false otherwise (or if no secret is set).
61 */
62bool csrf_verify(const char *token);
63
64/** @brief Clear the secret and nonce counter (e.g. between tests). */
65void csrf_reset(void);
66
67#endif // DETWS_ENABLE_CSRF
68
69#endif // DETERMINISTICESPASYNCWEBSERVER_CSRF_H
User-facing configuration for DeterministicESPAsyncWebServer.