ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
esp.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4#ifndef PROTOCORE_ESP_H
5#define PROTOCORE_ESP_H
6
7#include "protocore_config.h" // the entry point: protocore_types.h for the widths
8
10
11/**
12 * @file esp.h
13 * @brief ESP (RFC 4303) packet transform with AES-256-GCM (RFC 4106) - the IPsec datapath's crypto core.
14 *
15 * Tier 3 of the IPsec roadmap item is the ESP datapath. Its two halves separate cleanly: this pure,
16 * host-testable PACKET transform (encapsulate a payload into an ESP packet / verify + decapsulate one),
17 * and the device-side network-layer integration (hooking lwIP's IP input/output + the SAD/SPD), which is
18 * a separate, later track. This file is only the transform, gated with the IKEv2 feature (its Child-SA
19 * keys - SK_ei / SK_er from Ike.child_keymat - drive it) and reusing the library's AES-256-GCM.
20 *
21 * Wire layout (RFC 4303 ยง2, AES-GCM per RFC 4106):
22 * SPI(4) | Sequence Number(4) | IV(8, explicit) | { AES-GCM: Payload | Padding | Pad Length | Next
23 * Header } | ICV(16).
24 * The AEAD authenticates SPI | Seq as additional data; the nonce is the 4-byte salt (from the ESP key)
25 * concatenated with the 8-byte explicit IV. Padding right-aligns Pad Length + Next Header to a 4-octet
26 * boundary and holds the RFC 4303 monotonic bytes 1, 2, 3 ...
27 *
28 * @c work is bytes the CALLER holds. This module reads none of them: it carries nothing
29 * between calls, so there is no state to keep and nothing to wipe. The parameter is there so
30 * a caller drives every namespace the same way.
31 *
32 * @author Douglas Quigg (dstroy0)
33 * @date 2026
34 */
35
36// PROTOCORE_ESP_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
37// it into its arena. Its size and its offset are each a static_assert, so a feature
38// combination that does not fit fails to compile rather than overrunning at run time.
39
40/** @brief ESP header size: SPI(4) + Sequence Number(4). */
41#define PROTOCORE_ESP_HDR_LEN 8
42
43/** @brief Explicit IV length carried in the packet (AES-GCM, RFC 4106). */
44#define PROTOCORE_ESP_IV_LEN 8
45
46/** @brief Implicit salt length (the tail of the ESP key, not on the wire). */
47#define PROTOCORE_ESP_SALT_LEN 4
48
49/** @brief AES-GCM authentication tag / ICV length. */
50#define PROTOCORE_ESP_ICV_LEN 16
51
52/** @brief AES-256 key length. */
53#define PROTOCORE_ESP_KEY_LEN 32
54
55/** @brief ESP anti-replay window size (fixed by the 64-bit bitmap). */
56#define PROTOCORE_ESP_REPLAY_WINDOW 64
57
58/** @brief Anti-replay sliding-window state for one inbound SA (zero-heap). */
59typedef struct
60{
61 uint32_t highest; ///< highest accepted sequence number so far
62 uint64_t bitmap; ///< bit i set = (highest - i) already accepted (bit 0 = highest itself)
63 proto_bool seen_any; ///< false until the first packet is accepted
64} EspReplay;
65
66/** @brief Dispatch table. Addressed by offset, so the layout is asserted below. */
67typedef struct
68{
69 size_t (*gcm_encapsulate)(uint8_t *, uint32_t, uint32_t, const uint8_t *, const uint8_t *, const uint8_t *, uint8_t,
70 const uint8_t *, size_t, uint8_t *, size_t);
71 proto_bool (*gcm_decapsulate)(uint8_t *, const uint8_t *, const uint8_t *, uint8_t *, size_t, uint32_t *,
72 uint32_t *, uint8_t *, const uint8_t **, size_t *);
73 void (*replay_init)(uint8_t *, EspReplay *);
74 proto_bool (*replay_check)(uint8_t *, EspReplay *, uint32_t);
75} EspNs;
76PROTOCORE_NS_LAYOUT(EspNs, gcm_encapsulate, gcm_decapsulate, replay_init, replay_check);
77
78/**
79 * @brief Encapsulate payload in an RFC 4303 ESP packet with AES-256-GCM. .
80 * @param work PROTOCORE_ESP_BORROW bytes the caller took. Not held past the call.
81 * @param spi Spi
82 * @param seq Seq
83 * @param key 32-byte AES-256 key (SK_ei / SK_er without the salt) PROTOCORE_ESP_KEY_LEN bytes
84 * @param salt the 4-byte salt (the ESP key's tail) PROTOCORE_ESP_SALT_LEN bytes
85 * @param iv the 8-byte explicit IV (unique per packet under a key - e.g. the sequence number)
86 * @param next_header Next header
87 * @param payload Payload
88 * @param payload_len Payload len
89 * @param out Out
90 * @param out_cap Out cap
91 * @return The size_t.
92 */
93size_t protocore_esp_gcm_encapsulate(uint8_t *work, uint32_t spi, uint32_t seq, const uint8_t *key, const uint8_t *salt,
94 const uint8_t *iv, uint8_t next_header, const uint8_t *payload, size_t payload_len,
95 uint8_t *out, size_t out_cap);
96/**
97 * @brief Verify + decapsulate an ESP packet in place (the ciphertext is .
98 * @param work PROTOCORE_ESP_BORROW bytes the caller took. Not held past the call.
99 * @param key PROTOCORE_ESP_KEY_LEN bytes
100 * @param salt PROTOCORE_ESP_SALT_LEN bytes
101 * @param packet the ESP packet (mutated: decrypted in place). payload_out points into it on success
102 * @param len Len
103 * @param spi_out Spi out
104 * @param seq_out Seq out
105 * @param next_header_out Next header out
106 * @param payload_out Payload out
107 * @param payload_len_out Payload len out
108 * @return PROTO_TRUE on success.
109 */
110proto_bool protocore_esp_gcm_decapsulate(uint8_t *work, const uint8_t *key, const uint8_t *salt, uint8_t *packet,
111 size_t len, uint32_t *spi_out, uint32_t *seq_out, uint8_t *next_header_out,
112 const uint8_t **payload_out, size_t *payload_len_out);
113/**
114 * @brief Reset an anti-replay window (no packets seen yet).
115 * @param work PROTOCORE_ESP_BORROW bytes the caller took. Not held past the call.
116 * @param r R
117 */
118void protocore_esp_replay_init(uint8_t *work, EspReplay *r);
119/**
120 * @brief Anti-replay check + record for a received sequence number seq (RFC .
121 * @param work PROTOCORE_ESP_BORROW bytes the caller took. Not held past the call.
122 * @param r R
123 * @param seq Seq
124 * @return PROTO_TRUE on success.
125 */
126proto_bool protocore_esp_replay_check(uint8_t *work, EspReplay *r, uint32_t seq);
127
128/** @brief Module namespace. */
133
135
136#endif // PROTOCORE_ESP_H
void protocore_esp_replay_init(uint8_t *work, EspReplay *r)
Reset an anti-replay window (no packets seen yet).
proto_bool protocore_esp_replay_check(uint8_t *work, EspReplay *r, uint32_t seq)
Anti-replay check + record for a received sequence number seq (RFC .
PROTOCORE_NS EspNs Esp PROTOCORE_UNUSED
Module namespace.
Definition esp.h:129
size_t protocore_esp_gcm_encapsulate(uint8_t *work, uint32_t spi, uint32_t seq, const uint8_t *key, const uint8_t *salt, const uint8_t *iv, uint8_t next_header, const uint8_t *payload, size_t payload_len, uint8_t *out, size_t out_cap)
Encapsulate payload in an RFC 4303 ESP packet with AES-256-GCM. .
proto_bool protocore_esp_gcm_decapsulate(uint8_t *work, const uint8_t *key, const uint8_t *salt, uint8_t *packet, size_t len, uint32_t *spi_out, uint32_t *seq_out, uint8_t *next_header_out, const uint8_t **payload_out, size_t *payload_len_out)
Verify + decapsulate an ESP packet in place (the ciphertext is .
#define PROTOCORE_NS_LAYOUT(T,...)
Pin every dispatch slot of a table that is nothing but function pointers.
#define PROTOCORE_NS
Storage for a dispatch table. The const is load bearing.
Dispatch table. Addressed by offset, so the layout is asserted below.
Definition esp.h:68
size_t(* gcm_encapsulate)(uint8_t *, uint32_t, uint32_t, const uint8_t *, const uint8_t *, const uint8_t *, uint8_t, const uint8_t *, size_t, uint8_t *, size_t)
Definition esp.h:69
Anti-replay sliding-window state for one inbound SA (zero-heap).
Definition esp.h:60
uint64_t bitmap
bit i set = (highest - i) already accepted (bit 0 = highest itself)
Definition esp.h:62
uint32_t highest
highest accepted sequence number so far
Definition esp.h:61
proto_bool seen_any
false until the first packet is accepted
Definition esp.h:63
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97