|
DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
|
SSH binary packet protocol: framing, AES-256-CTR encryption, HMAC-SHA2-256 integrity, and sequence-number tracking. More...
#include "ServerConfig.h"#include "network_drivers/presentation/ssh/crypto/ssh_hmac_sha256.h"#include "network_drivers/presentation/ssh/transport/ssh_keymat.h"#include <stddef.h>#include <stdint.h>Go to the source code of this file.
Classes | |
| struct | SshPacketState |
| Per-connection SSH binary packet state. More... | |
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. | |
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;
Definition in file ssh_packet.h.
| #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.
| #define SSH_MSG_DISCONNECT 1 |
Definition at line 96 of file ssh_packet.h.
| #define SSH_MSG_IGNORE 2 |
Definition at line 97 of file ssh_packet.h.
| #define SSH_MSG_UNIMPLEMENTED 3 |
Definition at line 98 of file ssh_packet.h.
| #define SSH_MSG_SERVICE_REQUEST 5 |
Definition at line 99 of file ssh_packet.h.
| #define SSH_MSG_SERVICE_ACCEPT 6 |
Definition at line 100 of file ssh_packet.h.
| #define SSH_MSG_EXT_INFO 7 |
Definition at line 101 of file ssh_packet.h.
| #define SSH_MSG_KEXINIT 20 |
Definition at line 102 of file ssh_packet.h.
| #define SSH_MSG_NEWKEYS 21 |
Definition at line 103 of file ssh_packet.h.
| #define SSH_MSG_KEXDH_INIT 30 |
Definition at line 104 of file ssh_packet.h.
| #define SSH_MSG_KEXDH_REPLY 31 |
Definition at line 105 of file ssh_packet.h.
| #define SSH_MSG_USERAUTH_REQUEST 50 |
Definition at line 106 of file ssh_packet.h.
| #define SSH_MSG_USERAUTH_FAILURE 51 |
Definition at line 107 of file ssh_packet.h.
| #define SSH_MSG_USERAUTH_SUCCESS 52 |
Definition at line 108 of file ssh_packet.h.
| #define SSH_MSG_USERAUTH_PK_OK 60 |
Definition at line 109 of file ssh_packet.h.
| #define SSH_MSG_GLOBAL_REQUEST 80 |
Definition at line 110 of file ssh_packet.h.
| #define SSH_MSG_REQUEST_SUCCESS 81 |
Definition at line 111 of file ssh_packet.h.
| #define SSH_MSG_REQUEST_FAILURE 82 |
Definition at line 112 of file ssh_packet.h.
| #define SSH_MSG_CHANNEL_OPEN 90 |
Definition at line 113 of file ssh_packet.h.
| #define SSH_MSG_CHANNEL_OPEN_CONFIRM 91 |
Definition at line 114 of file ssh_packet.h.
| #define SSH_MSG_CHANNEL_OPEN_FAILURE 92 |
Definition at line 115 of file ssh_packet.h.
| #define SSH_MSG_CHANNEL_WINDOW_ADJUST 93 |
Definition at line 116 of file ssh_packet.h.
| #define SSH_MSG_CHANNEL_DATA 94 |
Definition at line 117 of file ssh_packet.h.
| #define SSH_MSG_CHANNEL_EOF 96 |
Definition at line 118 of file ssh_packet.h.
| #define SSH_MSG_CHANNEL_CLOSE 97 |
Definition at line 119 of file ssh_packet.h.
| #define SSH_MSG_CHANNEL_REQUEST 98 |
Definition at line 120 of file ssh_packet.h.
| #define SSH_MSG_CHANNEL_SUCCESS 99 |
Definition at line 121 of file ssh_packet.h.
| #define SSH_MSG_CHANNEL_FAILURE 100 |
Definition at line 122 of file ssh_packet.h.
| #define SSH_DISCONNECT_PROTOCOL_ERROR 2 |
Definition at line 128 of file ssh_packet.h.
| #define SSH_DISCONNECT_MAC_ERROR 5 |
Definition at line 129 of file ssh_packet.h.
| #define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 11 |
Definition at line 130 of file ssh_packet.h.
| #define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 |
Definition at line 131 of file ssh_packet.h.
| #define SSH_MAX_EFFECTIVE_PAYLOAD (SSH_PKT_BUF_SIZE) |
Definition at line 177 of file ssh_packet.h.
| #define SSH_MAX_PAD 32 |
Definition at line 179 of file ssh_packet.h.
| #define SSH_MAX_MAC 64 |
Definition at line 180 of file ssh_packet.h.
| #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 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.
| slot | SSH slot index. |
| msg_type | First payload byte (SSH message number). |
| payload | Decrypted message payload (includes msg_type at [0]). |
| payload_len | Length of payload. |
Definition at line 226 of file ssh_packet.h.
| 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.
| i | SSH 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().
| 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:
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.
| i | SSH slot index. |
| payload | Plaintext SSH message payload. |
| payload_len | Length of payload. |
| out | Output buffer for the wire packet. |
| out_len | Set to the number of bytes written into out. |
| out_cap | Capacity of out. |
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().
| 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:
handler(slot, msg_type, payload, payload_len) for the payload.| i | SSH slot index. |
| data | Received bytes (from TCP). |
| len | Number of bytes in data. |
| handler | Callback invoked once per complete, verified packet. |
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().
| 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.
| i | SSH slot index. |
| reason_code | One of SSH_DISCONNECT_* constants. |
| out | Output buffer for the wire packet. |
| out_len | Set to the number of bytes written. |
| out_cap | Capacity of out. |
Definition at line 584 of file ssh_packet.cpp.
References MAX_SSH_CONNS, SSH_MSG_DISCONNECT, ssh_pkt_init(), and ssh_pkt_send().
|
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().