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

SSH session key material - types, pools, and security model. More...

Go to the source code of this file.

Classes

struct  SshKeyMat
 AES-256-CTR + HMAC-SHA2-256 session keys for one SSH connection. More...
 
struct  SshDhState
 Ephemeral Diffie-Hellman state for one SSH connection. More...
 

Enumerations

enum  { SSH_CIPHER_AES256CTR = 0 , SSH_CIPHER_CHACHA20POLY1305 = 1 , SSH_CIPHER_AES256GCM = 2 }
 Negotiated bulk cipher for a session. More...
 
enum  { SSH_MAC_HMAC_SHA256 = 0 , SSH_MAC_HMAC_SHA512 = 1 , SSH_MAC_HMAC_SHA256_ETM = 2 , SSH_MAC_HMAC_SHA512_ETM = 3 }
 Negotiated MAC for the aes256-ctr cipher (unused with the chacha AEAD). More...
 

Variables

SshKeyMat ssh_keys [MAX_SSH_CONNS]
 Pool of session key material, one entry per MAX_SSH_CONNS.
 
SshDhState ssh_dh [MAX_SSH_CONNS]
 Pool of ephemeral DH state, one entry per MAX_SSH_CONNS.
 

Detailed Description

SSH session key material - types, pools, and security model.

═══════════════════════════════════════════════════════════════════════════ SECURITY MODEL - READ BEFORE MODIFYING ANYTHING IN THIS FILE ═══════════════════════════════════════════════════════════════════════════

The fundamental threat this layout defends against is buffer-overflow key extraction: an attacker who can cause an out-of-bounds read or write in the packet receive path (ssh_pool[].pkt_buf) should not be able to reach AES session keys or HMAC keys in the same memory operation.

DEFENSE 1 - Physical BSS separation ───────────────────────────────────── All three pools are SEPARATE static symbols:

ssh_pool[MAX_SSH_CONNS] - packet assembly buffers, protocol state ssh_keys[MAX_SSH_CONNS] - AES-256 key schedules + HMAC keys ssh_dh[MAX_SSH_CONNS] - ephemeral DH scalar (y), server public (f), K

The linker places these as independent objects. An overflow inside pkt_buf must cross the entire ssh_pool[] symbol, then any objects the linker placed between it and ssh_keys[], before reaching key material. On ESP32 with the default linker script this is a different RAM region than a linear overflow from pkt_buf would reach.

An attacker relying on a single linear write cannot bridge both gaps in one step. This is not mitigation-by-obscurity - it is the same "separate key store" principle used by HSMs, but implemented in software via linker symbol separation.

DEFENSE 2 - RSA host private key is NEVER stored in static memory ────────────────────────────────────────────────────────────────── The RSA-2048 private key (d, p, q, dp, dq, qInv) is loaded from NVS (encrypted flash on ESP32) into a LOCAL STACK FRAME inside ssh_rsa_sign(). It is explicitly zeroed (via volatile memset, which the compiler cannot elide) before ssh_rsa_sign() returns.

Consequences:

  • A static memory scan never finds the private key.
  • Cold-boot attacks recover only the public key from BSS.
  • The exposure window is the duration of a single mbedtls_rsa_pkcs1_sign call, typically < 1 ms.

DEFENSE 3 - DH ephemeral scalar zeroing ───────────────────────────────────────── y (2048-bit private DH scalar) lives in ssh_dh[slot].y. After ssh_dh_finish() derives K it calls ssh_wipe() on the entire SshDhState struct, which uses a volatile loop to zero all 801 bytes including y, f, and K. K must be zeroed after session keys are derived from it (RFC 4253 §7.2 makes no requirement, but it reduces long-term exposure).

DEFENSE 4 - crypto_work scratch buffer zeroing ──────────────────────────────────────────────── crypto_work[SSH_CRYPTO_WORK_SIZE] is used for Montgomery multiplication temporaries (up to 516 bytes of intermediate products that contain combinations of y, K, and d fragments). It is zeroed via ssh_wipe() immediately after every call to bn_expmod_group14() or ssh_rsa_sign().

DEFENSE 5 - MAC-verify-before-use (all packet input) ────────────────────────────────────────────────────── After key exchange, every inbound SSH binary packet is:

  1. Received into pkt_buf.
  2. Decrypted in place (AES-256-CTR).
  3. HMAC-SHA2-256 verified over (seq_num_be32 || plaintext_packet).
  4. ONLY THEN forwarded to the protocol handler.

If HMAC verification fails the connection is closed immediately. No plaintext bytes are acted upon before the MAC is confirmed valid. This prevents padding oracle and chosen-ciphertext attacks.

DEFENSE 6 - Sequence number overflow guard ──────────────────────────────────────────── RFC 4253 §9.3.4 requires rekeying before the sequence number wraps. If seq_c2s or seq_s2c reaches 0xFFFFFFFF the connection is closed. (Rekeying is not yet implemented; close-on-wrap is the safe fallback.)

WHAT THIS DOES NOT PROTECT AGAINST ────────────────────────────────────

  • An attacker with arbitrary-read in the process can still read ssh_keys[] - physical separation only raises the bar, not a hard wall.
  • Timing side-channels in the software Montgomery/AES paths are not addressed. On ESP32 the hardware AES path (mbedtls) has implementation-level timing properties that are mbedtls's concern.
  • Cold-boot attacks on SRAM after power-loss are partially mitigated by the zeroing policies above, but ESP32 SRAM may retain data briefly.

═══════════════════════════════════════════════════════════════════════════

Definition in file ssh_keymat.h.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

Negotiated bulk cipher for a session.

Enumerator
SSH_CIPHER_AES256CTR 

aes256-ctr + a separate HMAC (the fallback)

SSH_CIPHER_CHACHA20POLY1305 

chach.nosp@m.a20-.nosp@m.poly1.nosp@m.305@.nosp@m.opens.nosp@m.sh.c.nosp@m.om (AEAD; no separate MAC)

SSH_CIPHER_AES256GCM 

aes25.nosp@m.6-gc.nosp@m.m@ope.nosp@m.nssh.nosp@m..com (AEAD, RFC 5647; no separate MAC)

Definition at line 116 of file ssh_keymat.h.

◆ anonymous enum

anonymous enum

Negotiated MAC for the aes256-ctr cipher (unused with the chacha AEAD).

Enumerator
SSH_MAC_HMAC_SHA256 

hmac-sha2-256 (encrypt-and-MAC, RFC 4253)

SSH_MAC_HMAC_SHA512 

hmac-sha2-512 (encrypt-and-MAC)

SSH_MAC_HMAC_SHA256_ETM 

hmac-.nosp@m.sha2.nosp@m.-256-.nosp@m.etm@.nosp@m.opens.nosp@m.sh.c.nosp@m.om (encrypt-then-MAC)

SSH_MAC_HMAC_SHA512_ETM 

hmac-.nosp@m.sha2.nosp@m.-512-.nosp@m.etm@.nosp@m.opens.nosp@m.sh.c.nosp@m.om (encrypt-then-MAC)

Definition at line 124 of file ssh_keymat.h.

Variable Documentation

◆ ssh_keys

SshKeyMat ssh_keys[MAX_SSH_CONNS]
extern

Pool of session key material, one entry per MAX_SSH_CONNS.

Separate BSS symbol from ssh_pool[] - see security model. Zeroed on connection close by ssh_keymat_wipe(slot).

Definition at line 16 of file ssh_keymat.cpp.

Referenced by ssh_dh_derive_keys_sid(), ssh_pkt_recv(), and ssh_pkt_send().

◆ ssh_dh

SshDhState ssh_dh[MAX_SSH_CONNS]
extern

Pool of ephemeral DH state, one entry per MAX_SSH_CONNS.

Definition at line 17 of file ssh_keymat.cpp.

Referenced by ssh_dh_generate(), and ssh_kexdh_handle().