ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
snmp_v3.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/**
5 * @file snmp_v3.h
6 * @brief SNMPv3: the message framing and the User-based Security Model (PROTOCORE_ENABLE_SNMP_V3).
7 *
8 * Authenticated and optionally encrypted SNMP on top of the same MIB the community framings reach.
9 *
10 * RFC 3412 sec 6 gives the message: `SNMPv3Message ::= SEQUENCE { msgVersion, msgGlobalData
11 * HeaderData, msgSecurityParameters OCTET STRING, msgData ScopedPduData }`, where HeaderData is
12 * msgID, msgMaxSize, msgFlags and msgSecurityModel, and a ScopedPDU is contextEngineID,
13 * contextName and the PDU. RFC 3412 sec 6.4 defines the msgFlags bits authFlag, privFlag and
14 * reportableFlag.
15 *
16 * RFC 3414 sec 2.4 gives msgSecurityParameters for USM: msgAuthoritativeEngineID,
17 * msgAuthoritativeEngineBoots, msgAuthoritativeEngineTime, msgUserName,
18 * msgAuthenticationParameters and msgPrivacyParameters. This agent is the authoritative engine,
19 * so it answers discovery (RFC 3414 sec 4) with a Report PDU naming usmStatsUnknownEngineIDs, and
20 * enforces the 150-second time window of RFC 3414 sec 2.2.3. Every failure is reported as the
21 * matching usmStats counter of RFC 3414 sec 5.
22 *
23 * One authPriv user is configured:
24 * - **Authentication:** usmHMAC192SHA256AuthProtocol (RFC 7860 sec 8), HMAC-SHA-256 truncated to
25 * 24 octets (RFC 7860 sec 4.1). The digest is computed over the whole message with
26 * msgAuthenticationParameters replaced by zero octets (RFC 7860 sec 4.2.1 and sec 4.2.2).
27 * - **Privacy:** usmAesCfb128Protocol (RFC 3826), CFB128-AES-128 under the IV of RFC 3826
28 * sec 3.1.2.1.
29 *
30 * The decrypted, authenticated inner PDU is dispatched through the shared MIB core
31 * (@ref SnmpAgentNs::dispatch_pdu), so all three framings expose the same objects. The localized
32 * keys are derived once in @ref SnmpV3Ns::set_user, not per message.
33 *
34 * @author Douglas Quigg (dstroy0)
35 * @date 2026
36 */
37
38#ifndef PROTOCORE_SNMP_V3_H
39#define PROTOCORE_SNMP_V3_H
40
41#include "protocore_config.h" // the entry point: protocore_types.h for the widths
42
43#if PROTOCORE_ENABLE_SNMP_V3
44
46
47#if PROTOCORE_ENABLE_SNMP_TRAP
48#include "services/net/snmp/snmp_notify/snmp_notify.h" // SnmpVarbind: the bindings a v3 notification carries
49#endif
50
51/** @brief msgAuthenticationParameters length: HMAC-SHA-256 truncated to 192 bits (RFC 7860 sec 4.1). */
52#define SNMP_V3_AUTH_PARAM_LEN 24
53/** @brief msgPrivacyParameters length: the 64-bit salt of RFC 3826 sec 3.1.2.1. */
54#define SNMP_V3_PRIV_PARAM_LEN 8
55
56/** @brief RFC 3414 sec 2.4: the authoritative engine this agent is. */
57typedef struct
58{
59 const uint8_t *engine_id; ///< the snmpEngineID octets; NULL keeps the built-in default
60 size_t engine_id_len; ///< how many, 5 through SNMP_V3_ENGINEID_MAX
61 uint32_t boots; ///< msgAuthoritativeEngineBoots (RFC 3414 sec 2.2.2)
62} SnmpV3EngineArgs;
63
64/** @brief RFC 3414 sec 2.1: the USM user, and the passwords its localized keys come from. */
65typedef struct
66{
67 const char *user; ///< msgUserName
68 const char *auth_pass; ///< the authentication password; NULL or empty leaves no usable user
69 const char *priv_pass; ///< the privacy password; NULL or empty is authNoPriv
70} SnmpV3UserArgs;
71
72/** @brief RFC 3412 sec 6: the SNMPv3Message read, and the one written back. */
73typedef struct
74{
75 const uint8_t *req; ///< the received message octets
76 size_t req_len; ///< how many
77 uint8_t *resp; ///< where the response message is written
78 size_t resp_cap; ///< how many octets that holds
79} SnmpV3MsgArgs;
80
81#if PROTOCORE_ENABLE_SNMP_TRAP
82/** @brief RFC 3416 sec 4.2.6 and sec 4.2.7: what a v3 notification carries, and where it goes. */
83typedef struct
84{
85 const char *dst_ip; ///< the notification receiver's address, as text
86 uint16_t port; ///< its port, 162 by convention (RFC 3417 sec 3.2)
87 uint32_t request_id; ///< the PDU's request-id, echoed by an inform's Response-PDU
88 const uint32_t *trap_oid; ///< the snmpTrapOID.0 value (RFC 3418 sec 2)
89 size_t trap_oid_len; ///< how many subidentifiers
90 const SnmpVarbind *vbs; ///< the caller bindings that follow the mandatory two
91 size_t vb_count; ///< how many
92} SnmpV3NotifyArgs;
93#endif
94
95/**
96 * @brief The SNMPv3 engine (RFC 3412 sec 6, RFC 3414).
97 *
98 * A caller sets the members a call takes, invokes it through ::SnmpV3, and reads the outcome off
99 * the same handle.
100 *
101 * @var SnmpV3Ns::engine the authoritative engine identity and its boot count
102 * @var SnmpV3Ns::user the USM user and its passwords
103 * @var SnmpV3Ns::msg the message read and the one written back
104 * @var SnmpV3Ns::notify what an outgoing notification carries and where it goes
105 * @var SnmpV3Ns::ok a call's true/false outcome
106 * @var SnmpV3Ns::n response octets written, 0 to send nothing
107 * @var SnmpV3Ns::u32 msgAuthoritativeEngineBoots, as a read reports it
108 * @var SnmpV3Ns::init take the authoritative snmpEngineID and forget the configured user
109 * @var SnmpV3Ns::set_user take the USM user and derive its localized keys
110 * @var SnmpV3Ns::set_boots take the persisted msgAuthoritativeEngineBoots
111 * @var SnmpV3Ns::get_boots report msgAuthoritativeEngineBoots, for persisting it back
112 * @var SnmpV3Ns::process answer one SNMPv3Message: discovery, timeliness, auth, privacy, dispatch
113 * @var SnmpV3Ns::trap send an authenticated SNMPv2-Trap-PDU in a v3 message
114 * @var SnmpV3Ns::inform send an authenticated InformRequest-PDU in a v3 message
115 */
116typedef struct
117{
118 SnmpV3EngineArgs engine; ///< the authoritative engine (RFC 3414 sec 2.4)
119 SnmpV3UserArgs user; ///< the USM user (RFC 3414 sec 2.1)
120 SnmpV3MsgArgs msg; ///< the message pair (RFC 3412 sec 6)
121#if PROTOCORE_ENABLE_SNMP_TRAP
122 SnmpV3NotifyArgs notify; ///< what an outgoing notification carries
123#endif
124 proto_bool ok;
125 size_t n;
126 uint32_t u32;
127#if PROTOCORE_ENABLE_SNMP_TRAP
128#endif
129} SnmpV3Vars;
130
131/** @brief The operands and the outcome. */
132extern SnmpV3Vars SnmpV3V;
133
134/** @brief The entries. */
135typedef struct
136{
137 void (*const init)(uint8_t *work);
138 void (*const set_user)(uint8_t *work);
139 void (*const set_boots)(uint8_t *work);
140 void (*const get_boots)(uint8_t *work);
141 void (*const process)(uint8_t *work);
142 void (*const trap)(uint8_t *work);
143 void (*const inform)(uint8_t *work);
144} SnmpV3Ns;
145
146// What the table binds, defined once in the .c and taking one parameter each: everything
147// else an entry needs is an operand in SnmpV3V or a region of the borrow at a fixed offset.
148void protocore_snmp_v3_init(uint8_t *work);
149void protocore_snmp_v3_set_user(uint8_t *work);
150void protocore_snmp_v3_set_boots(uint8_t *work);
151void protocore_snmp_v3_get_boots(uint8_t *work);
152void protocore_snmp_v3_process(uint8_t *work);
153void protocore_snmp_v3_trap(uint8_t *work);
154void protocore_snmp_v3_inform(uint8_t *work);
155
156// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
157// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
158// `SnmpV3.init(work)` resolves to a named function and becomes a DIRECT call. An extern table
159// leaves the call indirect and the symbol live at every level, -O2 -flto included.
160static const SnmpV3Ns SnmpV3 __attribute__((unused)) = {
161 .init = protocore_snmp_v3_init,
162 .set_user = protocore_snmp_v3_set_user,
163 .set_boots = protocore_snmp_v3_set_boots,
164 .get_boots = protocore_snmp_v3_get_boots,
165 .process = protocore_snmp_v3_process,
166 .trap = protocore_snmp_v3_trap,
167 .inform = protocore_snmp_v3_inform,
168};
169
170/**
171 * @brief The PROTOCORE_SNMP_V3_BORROW bytes this module's state lives in.
172 *
173 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where
174 * that borrow comes from. Taken once from the end of the pool, which no mark and no release
175 * walks, so the state lasts the life of the program.
176 *
177 * @return the span.
178 */
179uint8_t *protocore_snmp_v3_span(void);
180
182
183#endif // PROTOCORE_ENABLE_SNMP_V3
184
185#endif // PROTOCORE_SNMP_V3_H
Notifications: the SNMPv2-Trap-PDU and the InformRequest-PDU (PROTOCORE_ENABLE_SNMP_TRAP).
#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