4#ifndef PROTOCORE_SMB2_H
5#define PROTOCORE_SMB2_H
52#define PROTOCORE_SMB2_HEADER_SIZE 64
55#define SMB2_NEGOTIATE_SIGNING_ENABLED 0x0001
56#define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x0002
59#define SMB2_FLAGS_SERVER_TO_REDIR 0x00000001
60#define SMB2_FLAGS_SIGNED 0x00000008
63#define SMB2_SESSION_FLAG_IS_GUEST 0x0001
64#define SMB2_SESSION_FLAG_IS_NULL 0x0002
65#define SMB2_SESSION_FLAG_ENCRYPT_DATA 0x0004
68#define SMB2_STATUS_SUCCESS 0x00000000
69#define SMB2_STATUS_MORE_PROCESSING_REQUIRED 0xC0000016
70#define SMB2_STATUS_END_OF_FILE 0xC0000011
73#define SMB2_SHARE_TYPE_DISK 0x01
74#define SMB2_SHARE_TYPE_PIPE 0x02
75#define SMB2_SHARE_TYPE_PRINT 0x03
78#define SMB2_FILE_READ_DATA 0x00000001
79#define SMB2_FILE_WRITE_DATA 0x00000002
80#define SMB2_FILE_APPEND_DATA 0x00000004
81#define SMB2_FILE_READ_ATTRIBUTES 0x00000080
82#define SMB2_FILE_GENERIC_READ 0x00120089
83#define SMB2_FILE_GENERIC_WRITE 0x00120116
86#define SMB2_FILE_SHARE_READ 0x01
87#define SMB2_FILE_SHARE_WRITE 0x02
88#define SMB2_FILE_SHARE_DELETE 0x04
91#define SMB2_FILE_SUPERSEDE 0
92#define SMB2_FILE_OPEN 1
93#define SMB2_FILE_CREATE 2
94#define SMB2_FILE_OPEN_IF 3
95#define SMB2_FILE_OVERWRITE 4
96#define SMB2_FILE_OVERWRITE_IF 5
99#define SMB2_FILE_DIRECTORY_FILE 0x00000001
100#define SMB2_FILE_NON_DIRECTORY_FILE 0x00000040
103#define SMB2_PREAUTH_INTEGRITY_CAPABILITIES 0x0001
104#define SMB2_ENCRYPTION_CAPABILITIES 0x0002
105#define SMB2_COMPRESSION_CAPABILITIES 0x0003
106#define SMB2_NETNAME_NEGOTIATE_CONTEXT_ID 0x0005
107#define SMB2_TRANSPORT_CAPABILITIES 0x0006
108#define SMB2_RDMA_TRANSFORM_CAPABILITIES 0x0007
109#define SMB2_SIGNING_CAPABILITIES 0x0008
112#define SMB2_PREAUTH_INTEGRITY_SHA512 0x0001
115#define SMB2_SIGNING_HMAC_SHA256 0x0000
116#define SMB2_SIGNING_AES_CMAC 0x0001
117#define SMB2_SIGNING_AES_GMAC 0x0002
122#define SMB2_GLOBAL_CAP_ENCRYPTION 0x00000040
125#define SMB2_ENCRYPTION_AES128_CCM 0x0001
126#define SMB2_ENCRYPTION_AES128_GCM 0x0002
127#define SMB2_ENCRYPTION_AES256_CCM 0x0003
128#define SMB2_ENCRYPTION_AES256_GCM 0x0004
131#define PROTOCORE_SMB2_MAX_OFFER_CIPHERS 4
134#define PROTOCORE_SMB2_PREAUTH_HASH_LEN 64
137#define SMB2_SHAREFLAG_ENCRYPT_DATA 0x00008000
141#define PROTOCORE_SMB2_TRANSFORM_HDR_LEN 52
144#define PROTOCORE_SMB2_TRANSFORM_PROTOCOL_ID 0x424D53FDu
148#define PROTOCORE_SMB2_NONCE_FIELD_LEN 16
151#define PROTOCORE_SMB2_GCM_NONCE_LEN 12
154#define PROTOCORE_SMB2_CCM_NONCE_LEN 11
157#define PROTOCORE_SMB2_MAX_CIPHER_KEY_LEN 32
213 uint8_t server_guid[16];
287static inline size_t protocore_smb2_cipher_key_len(uint16_t cipher)
305static inline size_t protocore_smb2_cipher_nonce_len(uint16_t cipher)
323 size_t (*transport_frame)(uint8_t *, uint8_t *, size_t,
const uint8_t *, size_t);
324 uint32_t (*transport_len)(uint8_t *,
const uint8_t *, size_t);
325 size_t (*build_header)(uint8_t *, uint8_t *, size_t,
Smb2Command, uint16_t, uint64_t, uint32_t, uint64_t);
327 size_t (*build_negotiate)(uint8_t *, uint8_t *, size_t,
const uint8_t *, uint16_t);
329 size_t (*build_negotiate_311)(uint8_t *, uint8_t *, size_t,
const uint8_t *, uint16_t,
const uint8_t *, size_t,
330 const uint16_t *, size_t);
333 void (*preauth_update)(uint8_t *, uint8_t *,
SmbPreauth *,
const uint8_t *, size_t);
334 size_t (*build_session_setup)(uint8_t *, uint8_t *, size_t, uint64_t, uint64_t, uint8_t,
const uint8_t *, size_t);
336 size_t (*build_tree_connect)(uint8_t *, uint8_t *, size_t, uint64_t, uint64_t,
const uint8_t *, size_t);
338 size_t (*build_create)(uint8_t *, uint8_t *, size_t, uint64_t, uint64_t, uint32_t, uint32_t, uint32_t, uint32_t,
339 uint32_t,
const uint8_t *, size_t);
341 size_t (*build_close)(uint8_t *, uint8_t *, size_t, uint64_t, uint64_t, uint32_t,
const uint8_t *);
343 size_t (*build_read)(uint8_t *, uint8_t *, size_t, uint64_t, uint64_t, uint32_t,
const uint8_t *, uint32_t,
346 size_t (*build_write)(uint8_t *, uint8_t *, size_t, uint64_t, uint64_t, uint32_t,
const uint8_t *,
const uint8_t *,
349 void (*sign)(uint8_t *, uint8_t *,
const uint8_t *, uint8_t *, size_t);
350 proto_bool (*verify)(uint8_t *, uint8_t *,
const uint8_t *, uint8_t *, size_t);
351 void (*sign_cmac)(uint8_t *, uint8_t *,
const uint8_t *, uint8_t *, size_t);
352 proto_bool (*verify_cmac)(uint8_t *, uint8_t *,
const uint8_t *, uint8_t *, size_t);
353 proto_bool (*derive_signing_key)(uint8_t *,
const uint8_t *, uint16_t,
const uint8_t *, uint8_t *);
354 proto_bool (*derive_encryption_keys)(uint8_t *,
const uint8_t *, uint16_t,
const uint8_t *, size_t, uint8_t *,
356 size_t (*encrypt)(uint8_t *, uint16_t,
const uint8_t *,
const uint8_t *, uint64_t,
const uint8_t *, size_t,
358 size_t (*decrypt)(uint8_t *, uint16_t,
const uint8_t *,
const uint8_t *, size_t, uint8_t *, size_t);
361 parse_negotiate_response, build_negotiate_311, parse_negotiate_contexts, preauth_init,
362 preauth_update, build_session_setup, parse_session_setup_response, build_tree_connect,
363 parse_tree_connect_response, build_create, parse_create_response, build_close, parse_close_response,
364 build_read, parse_read_response, build_write, parse_write_response, sign, verify, sign_cmac,
365 verify_cmac, derive_signing_key, derive_encryption_keys, encrypt, decrypt);
398 uint16_t credit_request, uint64_t message_id, uint32_t tree_id, uint64_t session_id);
418 uint16_t security_mode);
443 uint16_t security_mode,
const uint8_t *salt,
size_t salt_len,
444 const uint16_t *ciphers,
size_t cipher_count);
483 uint64_t session_id, uint8_t security_mode,
const uint8_t *sec_buf,
507 uint64_t session_id,
const uint8_t *path_utf16,
size_t path_len);
535 uint32_t tree_id, uint32_t desired_access, uint32_t share_access,
536 uint32_t create_disposition, uint32_t create_options,
const uint8_t *name_utf16,
559 uint32_t tree_id,
const uint8_t *file_id);
583 uint32_t tree_id,
const uint8_t *file_id, uint32_t length, uint64_t offset);
608 uint32_t tree_id,
const uint8_t *file_id,
const uint8_t *data,
size_t data_len,
627void protocore_smb2_sign(uint8_t *work, uint8_t *crypto_work,
const uint8_t *key, uint8_t *msg,
size_t msg_len);
668 const uint8_t *preauth, uint8_t *out_key);
681 const uint8_t *preauth,
size_t key_len, uint8_t *out_c2s,
697 uint64_t session_id,
const uint8_t *msg,
size_t msg_len, uint8_t *out,
size_t out_cap);
710 uint8_t *out,
size_t out_cap);
724 .parse_session_setup_response =
PROTO_ENUM_PACKED
Application protocol spoken on a listener port or connection slot.
#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.
size_t protocore_smb2_transport_frame(uint8_t *work, uint8_t *out, size_t cap, const uint8_t *msg, size_t msg_len)
Prefix an SMB2 message with the 4-byte Direct-TCP transport header .
size_t protocore_smb2_build_header(uint8_t *work, uint8_t *buf, size_t cap, Smb2Command command, uint16_t credit_request, uint64_t message_id, uint32_t tree_id, uint64_t session_id)
Build a 64-byte SMB2 sync header into buf.
void protocore_smb2_preauth_init(uint8_t *work, SmbPreauth *p)
Seed the preauth-integrity hash with 64 zero bytes (the initial .
enum PROTO_ENUM_PACKED Smb2Dialect
SMB2 dialect revision numbers (MS-SMB2 §2.2.4).
size_t protocore_smb2_build_tree_connect(uint8_t *work, uint8_t *buf, size_t cap, uint64_t message_id, uint64_t session_id, const uint8_t *path_utf16, size_t path_len)
Build a TREE_CONNECT request (header + §2.2.9 body) for a share path.
proto_bool protocore_smb2_parse_write_response(uint8_t *work, const uint8_t *msg, size_t len, Smb2WriteResp *out)
Parse a WRITE response message (validates command + StructureSize .
proto_bool protocore_smb2_verify_cmac(uint8_t *work, uint8_t *crypto_work, const uint8_t *key, uint8_t *msg, size_t msg_len)
Verify an AES-128-CMAC-signed SMB2 message (MS-SMB2 §3.1.5.1, SMB .
proto_bool protocore_smb2_parse_tree_connect_response(uint8_t *work, const uint8_t *msg, size_t len, Smb2TreeConnectResp *out)
Parse a TREE_CONNECT response message (validates command + .
#define SMB2_ENCRYPTION_AES128_CCM
Encryption cipher IDs (MS-SMB2 §2.2.3.1.2).
void protocore_smb2_sign(uint8_t *work, uint8_t *crypto_work, const uint8_t *key, uint8_t *msg, size_t msg_len)
Sign an SMB2 message in place (MS-SMB2 §3.1.4.1, SMB 2.x). Sets .
proto_bool protocore_smb2_parse_create_response(uint8_t *work, const uint8_t *msg, size_t len, Smb2CreateResp *out)
Parse a CREATE response message (validates command + StructureSize .
proto_bool protocore_smb2_parse_negotiate_response(uint8_t *work, const uint8_t *msg, size_t len, Smb2NegotiateResp *out)
Parse a NEGOTIATE response message (the SMB2 header + §2.2.4 body).
enum PROTO_ENUM_PACKED Smb2Command
SMB2 command codes (MS-SMB2 §2.2.1.2).
size_t protocore_smb2_build_create(uint8_t *work, uint8_t *buf, size_t cap, uint64_t message_id, uint64_t session_id, uint32_t tree_id, uint32_t desired_access, uint32_t share_access, uint32_t create_disposition, uint32_t create_options, const uint8_t *name_utf16, size_t name_len)
Build a CREATE request (header + §2.2.13 body) to open/create a .
#define SMB2_ENCRYPTION_AES256_GCM
proto_bool protocore_smb2_parse_read_response(uint8_t *work, const uint8_t *msg, size_t len, Smb2ReadResp *out)
Parse a READ response message (validates command + StructureSize .
enum PROTO_ENUM_PACKED Smb2SignAlgo
The per-session message-signing algorithm the client selects from the negotiated dialect.
size_t protocore_smb2_build_session_setup(uint8_t *work, uint8_t *buf, size_t cap, uint64_t message_id, uint64_t session_id, uint8_t security_mode, const uint8_t *sec_buf, size_t sec_len)
Build a SESSION_SETUP request (header + §2.2.5 body) carrying a .
size_t protocore_smb2_encrypt(uint8_t *work, uint16_t cipher, const uint8_t *key, const uint8_t *nonce, uint64_t session_id, const uint8_t *msg, size_t msg_len, uint8_t *out, size_t out_cap)
Encrypt one SMB2 message into a TRANSFORM_HEADER-wrapped blob .
size_t protocore_smb2_build_close(uint8_t *work, uint8_t *buf, size_t cap, uint64_t message_id, uint64_t session_id, uint32_t tree_id, const uint8_t *file_id)
Build a CLOSE request (header + §2.2.15 body) for an open FileId.
size_t protocore_smb2_build_negotiate_311(uint8_t *work, uint8_t *buf, size_t cap, const uint8_t *client_guid, uint16_t security_mode, const uint8_t *salt, size_t salt_len, const uint16_t *ciphers, size_t cipher_count)
Build an SMB 3.1.1 NEGOTIATE request: the dialect list SMB 2.0.2 .. .
proto_bool protocore_smb2_derive_signing_key(uint8_t *work, const uint8_t *session_key, uint16_t dialect, const uint8_t *preauth, uint8_t *out_key)
Derive the 16-byte SMB 3.x signing key from the NTLM session key .
size_t protocore_smb2_build_negotiate(uint8_t *work, uint8_t *buf, size_t cap, const uint8_t *client_guid, uint16_t security_mode)
Build a NEGOTIATE request (header + body) offering SMB 2.0.2 / 2.1 .
void protocore_smb2_sign_cmac(uint8_t *work, uint8_t *crypto_work, const uint8_t *key, uint8_t *msg, size_t msg_len)
Sign an SMB2 message in place with AES-128-CMAC (MS-SMB2 §3.1.4.1, .
PROTOCORE_NS Smb2Ns Smb2 PROTOCORE_UNUSED
Module namespace.
proto_bool protocore_smb2_parse_negotiate_contexts(uint8_t *work, const uint8_t *msg, size_t len, Smb2NegotiateContexts *out)
Walk the negotiate-context list of a 3.1.1 NEGOTIATE response .
@ SMB2_DIALECT_0202
SMB 2.0.2.
@ SMB2_DIALECT_0300
SMB 3.0.
@ SMB2_DIALECT_0210
SMB 2.1.
@ SMB2_SIGN_ALGO_AES_CMAC
SMB 3.0 / 3.0.2 / 3.1.1 (key = the SP800-108-derived signing key)
@ SMB2_DIALECT_0302
SMB 3.0.2.
@ SMB2_DIALECT_0311
SMB 3.1.1.
@ SMB2_SIGN_ALGO_HMAC_SHA256
SMB 2.0.2 / 2.1 (key = the NTLMv2 session key)
uint32_t protocore_smb2_transport_len(uint8_t *work, const uint8_t *buf, size_t len)
Read the Direct-TCP transport length prefix.
size_t protocore_smb2_decrypt(uint8_t *work, uint16_t cipher, const uint8_t *key, const uint8_t *in, size_t in_len, uint8_t *out, size_t out_cap)
Decrypt a TRANSFORM_HEADER-wrapped SMB2 message (MS-SMB2 §3.1.4.4): .
#define PROTOCORE_SMB2_PREAUTH_HASH_LEN
Length of the SMB 3.1.1 preauth-integrity hash (SHA-512 digest size).
proto_bool protocore_smb2_parse_session_setup_response(uint8_t *work, const uint8_t *msg, size_t len, Smb2SessionSetupResp *out)
Parse a SESSION_SETUP response message (the SMB2 header + §2.2.6 .
#define SMB2_ENCRYPTION_AES128_GCM
size_t protocore_smb2_build_read(uint8_t *work, uint8_t *buf, size_t cap, uint64_t message_id, uint64_t session_id, uint32_t tree_id, const uint8_t *file_id, uint32_t length, uint64_t offset)
Build a READ request (header + §2.2.19 body) for length bytes at .
proto_bool protocore_smb2_derive_encryption_keys(uint8_t *work, const uint8_t *session_key, uint16_t dialect, const uint8_t *preauth, size_t key_len, uint8_t *out_c2s, uint8_t *out_s2c)
Derive the two SMB 3.x cipher keys from the NTLM session key .
void protocore_smb2_preauth_update(uint8_t *work, uint8_t *crypto_work, SmbPreauth *p, const uint8_t *msg, size_t len)
Fold one handshake message into the preauth-integrity hash: hash = .
proto_bool protocore_smb2_verify(uint8_t *work, uint8_t *crypto_work, const uint8_t *key, uint8_t *msg, size_t msg_len)
Verify an SMB2 message's signature (MS-SMB2 §3.1.5.1). Recomputes .
proto_bool protocore_smb2_parse_close_response(uint8_t *work, const uint8_t *msg, size_t len, Smb2CloseResp *out)
Parse a CLOSE response message (validates command + StructureSize .
proto_bool protocore_smb2_parse_header(uint8_t *work, const uint8_t *buf, size_t len, Smb2Header *out)
Parse a 64-byte SMB2 sync header (validates ProtocolId + .
size_t protocore_smb2_build_write(uint8_t *work, uint8_t *buf, size_t cap, uint64_t message_id, uint64_t session_id, uint32_t tree_id, const uint8_t *file_id, const uint8_t *data, size_t data_len, uint64_t offset)
Build a WRITE request (header + §2.2.21 body) writing data at .
#define SMB2_ENCRYPTION_AES256_CCM
Parsed CLOSE response (MS-SMB2 §2.2.16).
Parsed CREATE response (MS-SMB2 §2.2.14).
Parsed SMB 3.1.1 NEGOTIATE-response negotiate contexts (MS-SMB2 §2.2.4 / §2.2.3.1).
uint16_t salt_len
length of salt
uint16_t hash_algorithm
the server's chosen preauth hash (expect SMB2_PREAUTH_INTEGRITY_SHA512)
proto_bool have_preauth
a PREAUTH_INTEGRITY_CAPABILITIES context was present
proto_bool have_signing
a SIGNING_CAPABILITIES context was present
uint16_t signing_algorithm
the server's chosen signing algorithm
proto_bool have_encryption
an ENCRYPTION_CAPABILITIES context was present
uint16_t cipher
the server's chosen cipher
const uint8_t * salt
the preauth-integrity salt (points into msg), or nullptr
Parsed NEGOTIATE response (MS-SMB2 §2.2.4).
uint16_t dialect
the DialectRevision the server chose
const uint8_t * sec_buf
SPNEGO/NTLM security token (points into msg), or nullptr.
Dispatch table. Addressed by offset, so the layout is asserted below.
size_t(* transport_frame)(uint8_t *, uint8_t *, size_t, const uint8_t *, size_t)
Parsed READ response (MS-SMB2 §2.2.20).
const uint8_t * data
the file bytes read (points into msg), or nullptr when DataLength is 0
Parsed SESSION_SETUP response (MS-SMB2 §2.2.6).
const uint8_t * sec_buf
the server's SPNEGO/NTLM token (points into msg), or nullptr
Parsed TREE_CONNECT response (MS-SMB2 §2.2.10). The TreeId is in the response header.
Parsed WRITE response (MS-SMB2 §2.2.22).
uint32_t count
bytes actually written
The SMB 3.1.1 preauth-integrity hash value (MS-SMB2 §3.1.5.2): a running SHA-512 chained over every N...
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
_Bool proto_bool
The truth value.
#define PROTOCORE_END_DECLS