DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
ssh_packet.h File Reference

SSH binary packet protocol: framing, AES-256-CTR encryption, HMAC-SHA2-256 integrity, and sequence-number tracking. More...

Go to the source code of this file.

Classes

struct  SshPacketState
 Per-connection SSH binary packet state. More...
 

Macros

#define SSH_SEQ_CLOSE_THRESHOLD   0xFFFFFFF0u
 Close the connection when seq_no reaches this value.
 
#define SSH_MSG_DISCONNECT   1
 
#define SSH_MSG_IGNORE   2
 
#define SSH_MSG_UNIMPLEMENTED   3
 
#define SSH_MSG_SERVICE_REQUEST   5
 
#define SSH_MSG_SERVICE_ACCEPT   6
 
#define SSH_MSG_EXT_INFO   7
 
#define SSH_MSG_KEXINIT   20
 
#define SSH_MSG_NEWKEYS   21
 
#define SSH_MSG_KEXDH_INIT   30
 
#define SSH_MSG_KEXDH_REPLY   31
 
#define SSH_MSG_USERAUTH_REQUEST   50
 
#define SSH_MSG_USERAUTH_FAILURE   51
 
#define SSH_MSG_USERAUTH_SUCCESS   52
 
#define SSH_MSG_USERAUTH_PK_OK   60
 
#define SSH_MSG_GLOBAL_REQUEST   80
 
#define SSH_MSG_REQUEST_SUCCESS   81
 
#define SSH_MSG_REQUEST_FAILURE   82
 
#define SSH_MSG_CHANNEL_OPEN   90
 
#define SSH_MSG_CHANNEL_OPEN_CONFIRM   91
 
#define SSH_MSG_CHANNEL_OPEN_FAILURE   92
 
#define SSH_MSG_CHANNEL_WINDOW_ADJUST   93
 
#define SSH_MSG_CHANNEL_DATA   94
 
#define SSH_MSG_CHANNEL_EOF   96
 
#define SSH_MSG_CHANNEL_CLOSE   97
 
#define SSH_MSG_CHANNEL_REQUEST   98
 
#define SSH_MSG_CHANNEL_SUCCESS   99
 
#define SSH_MSG_CHANNEL_FAILURE   100
 
#define SSH_DISCONNECT_PROTOCOL_ERROR   2
 
#define SSH_DISCONNECT_MAC_ERROR   5
 
#define SSH_DISCONNECT_TOO_MANY_CONNECTIONS   11
 
#define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE   14
 
#define SSH_MAX_EFFECTIVE_PAYLOAD   (SSH_PKT_BUF_SIZE)
 
#define SSH_MAX_PAD   32
 
#define SSH_MAX_MAC   64
 
#define SSH_WIRE_CAP   ((size_t)(4 + 1 + SSH_MAX_EFFECTIVE_PAYLOAD + SSH_MAX_PAD + SSH_MAX_MAC))
 

Typedefs

typedef void(* ssh_msg_handler_t) (uint8_t slot, uint8_t msg_type, const uint8_t *payload, size_t payload_len)
 Callback invoked once per complete, verified inbound SSH message.
 

Functions

void ssh_pkt_init (uint8_t i)
 Initialize the packet state for SSH connection slot i.
 
int ssh_pkt_send (uint8_t i, const uint8_t *payload, size_t payload_len, uint8_t *out, size_t *out_len, size_t out_cap)
 Build and send one SSH binary packet.
 
int ssh_pkt_recv (uint8_t i, const uint8_t *data, size_t len, ssh_msg_handler_t handler)
 Receive and process one or more SSH binary packets from data.
 
int ssh_pkt_disconnect (uint8_t i, uint32_t reason_code, uint8_t *out, size_t *out_len, size_t out_cap)
 Send SSH_MSG_DISCONNECT with reason reason_code.
 

Variables

SshPacketState ssh_pkt [MAX_SSH_CONNS]
 Static packet state pool (BSS). One entry per SSH slot.
 

Detailed Description

SSH binary packet protocol: framing, AES-256-CTR encryption, HMAC-SHA2-256 integrity, and sequence-number tracking.

═══════════════════════════════════════════════════════════════════════════ WIRE FORMAT (RFC 4253 §6) ═══════════════════════════════════════════════════════════════════════════

Each SSH packet on the wire (after KEX completes):

[4 bytes] packet_length - big-endian uint32 (does NOT include itself or the MAC; includes padding_length, payload, and random_padding fields) [1 byte] padding_length - number of bytes of random padding [N bytes] payload - the SSH message [P bytes] random_padding - random bytes; total pkt_len % blocksize == 0 [32 bytes] MAC - HMAC-SHA2-256 over: uint32(seq_no) || packet_length || padding_length || payload || random_padding

AES-256-CTR encrypts: packet_length || padding_length || payload || padding The MAC is computed over the PLAINTEXT (before encryption) prepended with the 4-byte sequence number. This is the "encrypt-then-MAC" variant used by openssh with hmac-sha2-256 (ETM) - but RFC 4253 default is MAC-then- encrypt. We implement STANDARD RFC 4253 (MAC over plaintext, then encrypt) to match the base SSH specification.

═══════════════════════════════════════════════════════════════════════════ MAC-VERIFY-BEFORE-USE INVARIANT ═══════════════════════════════════════════════════════════════════════════

On receive: decrypt → verify HMAC → then process the payload. If HMAC verification fails: close the connection immediately, zero the decrypted buffer. Do NOT process or reflect any byte of the payload.

This ordering closes the "BEAST" class of attack where an attacker can influence decryption outputs by injecting invalid packets.

═══════════════════════════════════════════════════════════════════════════ SEQUENCE NUMBER OVERFLOW GUARD ═══════════════════════════════════════════════════════════════════════════

SSH sequence numbers are 32-bit values that wrap at 2^32. RFC 4253 does not mandate rekeying before wrap; however, CTR-mode keystream repetition at wrap would be a catastrophic confidentiality failure.

Policy: close the connection if seq_no_send or seq_no_recv reaches SSH_SEQ_CLOSE_THRESHOLD. A future rekey implementation would reset the counters instead.

═══════════════════════════════════════════════════════════════════════════ PADDING ═══════════════════════════════════════════════════════════════════════════

AES-256-CTR block size = 16 bytes. RFC 4253 §6 requires the padded packet (packet_length + 1 + payload + padding) to be a multiple of max(8, cipher_block_size) = 16. Minimum padding is 4 bytes.

padding_len = (16 - ((5 + payload_len) % 16)) % 16 if (padding_len < 4) padding_len += 16;

Author
Douglas Quigg (dstroy0)
Date
2026

Definition in file ssh_packet.h.

Macro Definition Documentation

◆ SSH_SEQ_CLOSE_THRESHOLD

#define SSH_SEQ_CLOSE_THRESHOLD   0xFFFFFFF0u

Close the connection when seq_no reaches this value.

Set to 0xFFFFFFF0 (16 below the 32-bit wrap) as a conservative margin. This prevents CTR keystream reuse that would occur at wrap. A rekey implementation would reset this counter; until then, we close.

Definition at line 90 of file ssh_packet.h.

◆ SSH_MSG_DISCONNECT

#define SSH_MSG_DISCONNECT   1

Definition at line 96 of file ssh_packet.h.

◆ SSH_MSG_IGNORE

#define SSH_MSG_IGNORE   2

Definition at line 97 of file ssh_packet.h.

◆ SSH_MSG_UNIMPLEMENTED

#define SSH_MSG_UNIMPLEMENTED   3

Definition at line 98 of file ssh_packet.h.

◆ SSH_MSG_SERVICE_REQUEST

#define SSH_MSG_SERVICE_REQUEST   5

Definition at line 99 of file ssh_packet.h.

◆ SSH_MSG_SERVICE_ACCEPT

#define SSH_MSG_SERVICE_ACCEPT   6

Definition at line 100 of file ssh_packet.h.

◆ SSH_MSG_EXT_INFO

#define SSH_MSG_EXT_INFO   7

Definition at line 101 of file ssh_packet.h.

◆ SSH_MSG_KEXINIT

#define SSH_MSG_KEXINIT   20

Definition at line 102 of file ssh_packet.h.

◆ SSH_MSG_NEWKEYS

#define SSH_MSG_NEWKEYS   21

Definition at line 103 of file ssh_packet.h.

◆ SSH_MSG_KEXDH_INIT

#define SSH_MSG_KEXDH_INIT   30

Definition at line 104 of file ssh_packet.h.

◆ SSH_MSG_KEXDH_REPLY

#define SSH_MSG_KEXDH_REPLY   31

Definition at line 105 of file ssh_packet.h.

◆ SSH_MSG_USERAUTH_REQUEST

#define SSH_MSG_USERAUTH_REQUEST   50

Definition at line 106 of file ssh_packet.h.

◆ SSH_MSG_USERAUTH_FAILURE

#define SSH_MSG_USERAUTH_FAILURE   51

Definition at line 107 of file ssh_packet.h.

◆ SSH_MSG_USERAUTH_SUCCESS

#define SSH_MSG_USERAUTH_SUCCESS   52

Definition at line 108 of file ssh_packet.h.

◆ SSH_MSG_USERAUTH_PK_OK

#define SSH_MSG_USERAUTH_PK_OK   60

Definition at line 109 of file ssh_packet.h.

◆ SSH_MSG_GLOBAL_REQUEST

#define SSH_MSG_GLOBAL_REQUEST   80

Definition at line 110 of file ssh_packet.h.

◆ SSH_MSG_REQUEST_SUCCESS

#define SSH_MSG_REQUEST_SUCCESS   81

Definition at line 111 of file ssh_packet.h.

◆ SSH_MSG_REQUEST_FAILURE

#define SSH_MSG_REQUEST_FAILURE   82

Definition at line 112 of file ssh_packet.h.

◆ SSH_MSG_CHANNEL_OPEN

#define SSH_MSG_CHANNEL_OPEN   90

Definition at line 113 of file ssh_packet.h.

◆ SSH_MSG_CHANNEL_OPEN_CONFIRM

#define SSH_MSG_CHANNEL_OPEN_CONFIRM   91

Definition at line 114 of file ssh_packet.h.

◆ SSH_MSG_CHANNEL_OPEN_FAILURE

#define SSH_MSG_CHANNEL_OPEN_FAILURE   92

Definition at line 115 of file ssh_packet.h.

◆ SSH_MSG_CHANNEL_WINDOW_ADJUST

#define SSH_MSG_CHANNEL_WINDOW_ADJUST   93

Definition at line 116 of file ssh_packet.h.

◆ SSH_MSG_CHANNEL_DATA

#define SSH_MSG_CHANNEL_DATA   94

Definition at line 117 of file ssh_packet.h.

◆ SSH_MSG_CHANNEL_EOF

#define SSH_MSG_CHANNEL_EOF   96

Definition at line 118 of file ssh_packet.h.

◆ SSH_MSG_CHANNEL_CLOSE

#define SSH_MSG_CHANNEL_CLOSE   97

Definition at line 119 of file ssh_packet.h.

◆ SSH_MSG_CHANNEL_REQUEST

#define SSH_MSG_CHANNEL_REQUEST   98

Definition at line 120 of file ssh_packet.h.

◆ SSH_MSG_CHANNEL_SUCCESS

#define SSH_MSG_CHANNEL_SUCCESS   99

Definition at line 121 of file ssh_packet.h.

◆ SSH_MSG_CHANNEL_FAILURE

#define SSH_MSG_CHANNEL_FAILURE   100

Definition at line 122 of file ssh_packet.h.

◆ SSH_DISCONNECT_PROTOCOL_ERROR

#define SSH_DISCONNECT_PROTOCOL_ERROR   2

Definition at line 128 of file ssh_packet.h.

◆ SSH_DISCONNECT_MAC_ERROR

#define SSH_DISCONNECT_MAC_ERROR   5

Definition at line 129 of file ssh_packet.h.

◆ SSH_DISCONNECT_TOO_MANY_CONNECTIONS

#define SSH_DISCONNECT_TOO_MANY_CONNECTIONS   11

Definition at line 130 of file ssh_packet.h.

◆ SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE

#define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE   14

Definition at line 131 of file ssh_packet.h.

◆ SSH_MAX_EFFECTIVE_PAYLOAD

#define SSH_MAX_EFFECTIVE_PAYLOAD   (SSH_PKT_BUF_SIZE)

Definition at line 177 of file ssh_packet.h.

◆ SSH_MAX_PAD

#define SSH_MAX_PAD   32

Definition at line 179 of file ssh_packet.h.

◆ SSH_MAX_MAC

#define SSH_MAX_MAC   64

Definition at line 180 of file ssh_packet.h.

◆ SSH_WIRE_CAP

#define SSH_WIRE_CAP   ((size_t)(4 + 1 + SSH_MAX_EFFECTIVE_PAYLOAD + SSH_MAX_PAD + SSH_MAX_MAC))

Definition at line 181 of file ssh_packet.h.

Typedef Documentation

◆ ssh_msg_handler_t

typedef void(* ssh_msg_handler_t) (uint8_t slot, uint8_t msg_type, const uint8_t *payload, size_t payload_len)

Callback invoked once per complete, verified inbound SSH message.

Parameters
slotSSH slot index.
msg_typeFirst payload byte (SSH message number).
payloadDecrypted message payload (includes msg_type at [0]).
payload_lenLength of payload.

Definition at line 226 of file ssh_packet.h.

Function Documentation

◆ ssh_pkt_init()

void ssh_pkt_init ( uint8_t  i)

Initialize the packet state for SSH connection slot i.

Zeroes seq numbers; sets encrypted=false, kex_active=true.

Parameters
iSSH slot index.

Definition at line 101 of file ssh_packet.cpp.

References SshPacketState::enc_in, SshPacketState::enc_out, SshPacketState::kex_active, MAX_SSH_CONNS, and ssh_pkt.

Referenced by ssh_conn_accept(), and ssh_pkt_disconnect().

◆ ssh_pkt_send()

int ssh_pkt_send ( uint8_t  i,
const uint8_t *  payload,
size_t  payload_len,
uint8_t *  out,
size_t *  out_len,
size_t  out_cap 
)

Build and send one SSH binary packet.

Frames payload according to RFC 4253 §6:

  • Adds random padding to align to 16-byte boundary.
  • If encrypted: encrypts with AES-256-CTR, appends HMAC-SHA2-256 MAC.
  • Increments seq_no_send; closes connection if threshold reached.

The serialized packet is written into out. *out_len is set to the number of bytes written. out must be at least (4 + 1 + payload_len + 16 + 32) bytes.

Parameters
iSSH slot index.
payloadPlaintext SSH message payload.
payload_lenLength of payload.
outOutput buffer for the wire packet.
out_lenSet to the number of bytes written into out.
out_capCapacity of out.
Returns
0 on success, -1 on overflow or sequence-number exhaustion.

Definition at line 116 of file ssh_packet.cpp.

References SshKeyMat::chacha_key_s2c, SshKeyMat::cipher_mode, SshPacketState::enc_out, SshKeyMat::gcm_s2c, SshKeyMat::mac_key_s2c, SshKeyMat::mac_mode, MAX_SSH_CONNS, SshKeyMat::s2c_ctx, scratch_alloc(), SshPacketState::seq_no_send, ssh_aes256ctr_crypt(), ssh_aesgcm_seal(), ssh_chachapoly_encrypt(), SSH_CHACHAPOLY_TAG_LEN, SSH_CIPHER_AES256CTR, SSH_CIPHER_AES256GCM, SSH_CIPHER_CHACHA20POLY1305, ssh_keys, ssh_pkt, and SSH_SEQ_CLOSE_THRESHOLD.

Referenced by ssh_conn_close_channel(), ssh_conn_open_forwarded(), ssh_conn_send(), and ssh_pkt_disconnect().

◆ ssh_pkt_recv()

int ssh_pkt_recv ( uint8_t  i,
const uint8_t *  data,
size_t  len,
ssh_msg_handler_t  handler 
)

Receive and process one or more SSH binary packets from data.

Appends len bytes from data to the receive buffer for slot i, then extracts complete packets. For each complete packet:

  • If encrypted: decrypts with AES-256-CTR, verifies HMAC-SHA2-256. Closes connection (returns -1) on MAC failure without processing payload.
  • Increments seq_no_recv; closes connection if threshold reached.
  • Calls handler(slot, msg_type, payload, payload_len) for the payload.
Parameters
iSSH slot index.
dataReceived bytes (from TCP).
lenNumber of bytes in data.
handlerCallback invoked once per complete, verified packet.
Returns
0 on success, -1 on MAC failure or sequence-number exhaustion (caller must close the TCP connection).

Definition at line 233 of file ssh_packet.cpp.

References SshKeyMat::c2s_ctx, SshKeyMat::chacha_key_c2s, SshKeyMat::cipher_mode, SshAesCtrCtx::counter, SshPacketState::enc_in, SshKeyMat::gcm_c2s, SshAesCtrCtx::keystream, SshKeyMat::mac_key_c2s, SshKeyMat::mac_mode, MAX_SSH_CONNS, SshAesCtrCtx::pos, SshPacketState::rx_buf, SshPacketState::rx_len, scratch_alloc(), SshPacketState::seq_no_recv, ssh_aes256ctr_crypt(), ssh_aesgcm_open(), ssh_chachapoly_decrypt(), ssh_chachapoly_get_length(), SSH_CHACHAPOLY_TAG_LEN, SSH_CIPHER_AES256GCM, SSH_CIPHER_CHACHA20POLY1305, ssh_keys, ssh_pkt, SSH_PKT_BUF_SIZE, and SSH_SEQ_CLOSE_THRESHOLD.

Referenced by ssh_conn_rx().

◆ ssh_pkt_disconnect()

int ssh_pkt_disconnect ( uint8_t  i,
uint32_t  reason_code,
uint8_t *  out,
size_t *  out_len,
size_t  out_cap 
)

Send SSH_MSG_DISCONNECT with reason reason_code.

Sends the packet, then zeroes the packet state and key material for slot i.

Parameters
iSSH slot index.
reason_codeOne of SSH_DISCONNECT_* constants.
outOutput buffer for the wire packet.
out_lenSet to the number of bytes written.
out_capCapacity of out.
Returns
0 on success, -1 on error.

Definition at line 584 of file ssh_packet.cpp.

References MAX_SSH_CONNS, SSH_MSG_DISCONNECT, ssh_pkt_init(), and ssh_pkt_send().

Variable Documentation

◆ ssh_pkt

SshPacketState ssh_pkt[MAX_SSH_CONNS]
extern

Static packet state pool (BSS). One entry per SSH slot.

Definition at line 32 of file ssh_packet.cpp.

Referenced by ssh_conn_poll(), ssh_newkeys_complete(), ssh_newkeys_sent(), ssh_pkt_init(), ssh_pkt_recv(), ssh_pkt_send(), ssh_rekey_needed(), and ssh_server_dispatch().