ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
ntlmssp.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_NTLMSSP_H
5#define PROTOCORE_NTLMSSP_H
6
7#include "protocore_config.h" // the entry point: protocore_types.h for the widths
8
10
11/**
12 * @file ntlmssp.h
13 * @brief NTLMSSP message codec (MS-NLMP §2.2.1) for the SMB2 client (PROTOCORE_ENABLE_SMB).
14 *
15 * The three-message NTLM handshake tokens that carry the NTLMv2 response (ntlm.h) inside SMB2
16 * SESSION_SETUP: the client sends a NEGOTIATE (type 1), the server replies with a CHALLENGE
17 * (type 2) carrying the 8-byte server challenge + the target-info AV_PAIRs, and the client sends
18 * an AUTHENTICATE (type 3) carrying the NtChallengeResponse and the user/domain. All fields
19 * little-endian; text is UTF-16LE. Pure, zero heap. This builds the raw NTLMSSP tokens; the
20 * SPNEGO/GSS wrapping + the SESSION_SETUP framing are the next increment.
21 *
22 * @c work is bytes the CALLER holds. This module reads none of them: it carries nothing
23 * between calls, so there is no state to keep and nothing to wipe. The parameter is there so
24 * a caller drives every namespace the same way.
25 *
26 * @author Douglas Quigg (dstroy0)
27 * @date 2026
28 */
29
30// PROTOCORE_NTLMSSP_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
31// it into its arena. Its size and its offset are each a static_assert, so a feature
32// combination that does not fit fails to compile rather than overrunning at run time.
33
34/** @brief NTLMSSP NegotiateFlags (MS-NLMP §2.2.2.5), the subset a basic NTLMv2 client uses. */
35#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001
36#define NTLMSSP_REQUEST_TARGET 0x00000004
37#define NTLMSSP_NEGOTIATE_NTLM 0x00000200
38#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000
39#define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000
40#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000
41#define NTLMSSP_NEGOTIATE_VERSION 0x02000000
42#define NTLMSSP_NEGOTIATE_128 0x20000000
43#define NTLMSSP_NEGOTIATE_56 0x80000000
44
45/** @brief The NEGOTIATE flag set an NTLMv2 client sends. */
46#define NTLMSSP_CLIENT_DEFAULT_FLAGS \
47 (NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
48 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)
49
50/**
51 * @brief Offset of the 16-byte MIC field within an AUTHENTICATE_MESSAGE built @p with_mic (MS-NLMP
52 * §2.2.1.3): the 64-byte fixed header + the 8-byte Version field. The caller writes the computed
53 * MIC here after the message is built and the digest taken over it with these bytes zeroed.
54 */
55#define PROTOCORE_NTLMSSP_MIC_OFFSET 72
56
57/** @brief Length of the AUTHENTICATE MIC field (an HMAC-MD5 digest). */
58#define PROTOCORE_NTLMSSP_MIC_LEN 16
59
60/** @brief Parsed CHALLENGE_MESSAGE (type 2). @ref target_info points INTO the source message. */
61typedef struct
62{
63 uint32_t flags;
64 uint8_t server_challenge[8];
65 const uint8_t *target_info; ///< the AV_PAIR blob, or nullptr if absent
68
69/** @brief Dispatch table. Addressed by offset, so the layout is asserted below. */
70typedef struct
71{
72 size_t (*build_negotiate)(uint8_t *, uint8_t *, size_t, uint32_t);
73 proto_bool (*parse_challenge)(uint8_t *, const uint8_t *, size_t, NtlmChallenge *);
74 size_t (*build_authenticate)(uint8_t *, uint8_t *, size_t, const uint8_t *, size_t, const uint8_t *, size_t,
75 const char *, const char *, const char *, uint32_t, proto_bool);
76} NtlmsspNs;
77PROTOCORE_NS_LAYOUT(NtlmsspNs, build_negotiate, parse_challenge, build_authenticate);
78
79/**
80 * @brief Build a NEGOTIATE_MESSAGE (type 1) with flags and empty .
81 * @param work PROTOCORE_NTLMSSP_BORROW bytes the caller took. Not held past the call.
82 * @param buf Buf
83 * @param cap Cap
84 * @param flags Flags
85 * @return The size_t.
86 */
87size_t protocore_ntlmssp_build_negotiate(uint8_t *work, uint8_t *buf, size_t cap, uint32_t flags);
88/**
89 * @brief Parse a CHALLENGE_MESSAGE (type 2): extract the flags, the 8-byte .
90 * @param work PROTOCORE_NTLMSSP_BORROW bytes the caller took. Not held past the call.
91 * @param msg Msg
92 * @param len Len
93 * @param out Out
94 * @return PROTO_TRUE on success.
95 */
96proto_bool protocore_ntlmssp_parse_challenge(uint8_t *work, const uint8_t *msg, size_t len, NtlmChallenge *out);
97/**
98 * @brief Build an AUTHENTICATE_MESSAGE (type 3) carrying the LM + NT .
99 * @param work PROTOCORE_NTLMSSP_BORROW bytes the caller took. Not held past the call.
100 * @param buf Buf
101 * @param cap Cap
102 * @param lm_resp / lm_len the LM(v2) response (may be null/0)
103 * @param lm_len Lm len
104 * @param nt_resp / nt_len the NtChallengeResponse from protocore_ntlm_v2_response
105 * @param nt_len Nt len
106 * @param domain / user / workstation ASCII/UTF-8 identity strings (encoded UTF-16LE); user and domain are
107 * @param user User
108 * @param workstation Workstation
109 * @param flags the NegotiateFlags to echo (usually the server's from the CHALLENGE)
110 * @param with_mic when true, reserve the 8-byte Version + 16-byte MIC fields between the fixed header and the
111 * @return The size_t.
112 */
113size_t protocore_ntlmssp_build_authenticate(uint8_t *work, uint8_t *buf, size_t cap, const uint8_t *lm_resp,
114 size_t lm_len, const uint8_t *nt_resp, size_t nt_len, const char *domain,
115 const char *user, const char *workstation, uint32_t flags,
116 proto_bool with_mic);
117
118/** @brief Module namespace. */
122
124
125#endif // PROTOCORE_NTLMSSP_H
#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.
proto_bool protocore_ntlmssp_parse_challenge(uint8_t *work, const uint8_t *msg, size_t len, NtlmChallenge *out)
Parse a CHALLENGE_MESSAGE (type 2): extract the flags, the 8-byte .
PROTOCORE_NS NtlmsspNs Ntlmssp PROTOCORE_UNUSED
Module namespace.
Definition ntlmssp.h:119
size_t protocore_ntlmssp_build_authenticate(uint8_t *work, uint8_t *buf, size_t cap, const uint8_t *lm_resp, size_t lm_len, const uint8_t *nt_resp, size_t nt_len, const char *domain, const char *user, const char *workstation, uint32_t flags, proto_bool with_mic)
Build an AUTHENTICATE_MESSAGE (type 3) carrying the LM + NT .
size_t protocore_ntlmssp_build_negotiate(uint8_t *work, uint8_t *buf, size_t cap, uint32_t flags)
Build a NEGOTIATE_MESSAGE (type 1) with flags and empty .
Parsed CHALLENGE_MESSAGE (type 2). target_info points INTO the source message.
Definition ntlmssp.h:62
uint32_t flags
Definition ntlmssp.h:63
const uint8_t * target_info
the AV_PAIR blob, or nullptr if absent
Definition ntlmssp.h:65
uint16_t target_info_len
Definition ntlmssp.h:66
Dispatch table. Addressed by offset, so the layout is asserted below.
Definition ntlmssp.h:71
size_t(* build_negotiate)(uint8_t *, uint8_t *, size_t, uint32_t)
Definition ntlmssp.h:72
#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