ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
transport.h File Reference

RFC 4253 transport layer: identification exchange, algorithm negotiation, key exchange. More...

Go to the source code of this file.

Classes

struct  SshDir
 One direction's codec state, handed to the packet layer per call. More...
 
struct  SshSession
 SSH transport/session state for one connection (BSS pool). More...
 
struct  SshPacketArgs
 RFC 4253 sec 6 binary packet: the bytes a receive consumes, and the body it carries. More...
 
struct  SshTransportOut
 Where a build or a send writes, and what it wrote. More...
 
struct  SshKexHashArgs
 RFC 4253 sec 8: every term the exchange hash H is taken over, and where H lands. More...
 
struct  SshRekeyArgs
 RFC 4253 sec 9 key re-exchange: what has passed since the last one, against its budget. More...
 
struct  SshTransportVars
 
struct  SshTransportNs
 The entries. More...
 
struct  SshKdfInputs
 One key exchange's derivation inputs, passed by reference. More...
 
struct  SshPacketState
 Per-connection SSH binary packet state. More...
 
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...
 
struct  SshKexEphemeral
 

Macros

#define SSH_TRANSPORT   (&SshTransport)
 Reader shorthand: SSH_TRANSPORT->kexinit_parse(...).
 
#define SSH_KDF_MAX   (4 * PROTOCORE_SHA256_DIGEST_LEN)
 Max bytes ssh_kdf_derive() can produce (4 SHA-256 blocks).
 
#define SSH_UNIMPLEMENTED_LEN   5u
 Bytes in an SSH_MSG_UNIMPLEMENTED payload: the message number and one uint32.
 

Typedefs

typedef enum PROTO_ENUM_PACKED SshKexAlg
 Negotiated key-exchange method.
 
typedef enum PROTO_ENUM_PACKED SshHostkeyAlg
 Negotiated host-key / signature algorithm.
 
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.
 

Enumerations

enum  PROTO_ENUM_PACKED {
  SSH_KEX_DH_GROUP14 = 0 , SSH_KEX_CURVE25519 = 1 , SSH_KEX_MLKEM768_X25519 = 2 , SSH_KEX_ECDH_NISTP256 = 3 ,
  SSH_KEX_SNTRUP761_X25519 = 4 , SSH_HOSTKEY_RSA_SHA256 = 0 , SSH_HOSTKEY_ED25519 = 1 , SSH_HOSTKEY_RSA_SHA512 = 2 ,
  SSH_HOSTKEY_ECDSA_NISTP256 = 3
}
 Negotiated key-exchange method. More...
 
enum  PROTO_ENUM_PACKED {
  SSH_KEX_DH_GROUP14 = 0 , SSH_KEX_CURVE25519 = 1 , SSH_KEX_MLKEM768_X25519 = 2 , SSH_KEX_ECDH_NISTP256 = 3 ,
  SSH_KEX_SNTRUP761_X25519 = 4 , SSH_HOSTKEY_RSA_SHA256 = 0 , SSH_HOSTKEY_ED25519 = 1 , SSH_HOSTKEY_RSA_SHA512 = 2 ,
  SSH_HOSTKEY_ECDSA_NISTP256 = 3
}
 Negotiated host-key / signature algorithm. More...
 
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...
 

Functions

void ssh_kex_set_prefer_rsa (proto_bool prefer)
 Steer KEX and host-key negotiation toward RSA with DH-group14, or toward curve25519 with ed25519.
 
proto_bool ssh_kex_prefer_rsa (void)
 Current negotiation preference (true = prefer RSA / DH).
 
const uint8_t * ssh_session_id (uint8_t i, size_t *len)
 The session identifier for slot i, or null before the first key exchange completes.
 
void ssh_session_id_latch (uint8_t i, const uint8_t *h, size_t h_len)
 Latch the first exchange's hash as slot i's session identifier (RFC 4253 sec 7.2).
 
proto_bool ssh_kex_is_sha512 (SshKexAlg a)
 True when a hashes with SHA-512 rather than SHA-256 (RFC 8268, RFC 8731).
 
proto_bool ssh_hostkey_verify (uint8_t i, const uint8_t *ks, size_t ks_len, const uint8_t *sig, size_t sig_len, const uint8_t *h, size_t h_len)
 Verify the server's signature over the exchange hash with its host key (RFC 4253 sec 8).
 
void protocore_ssh_transport_recv_ident (uint8_t *work)
 
void protocore_ssh_transport_send_ident (uint8_t *work)
 
void protocore_ssh_transport_kexinit_build (uint8_t *work)
 
void protocore_ssh_transport_kexinit_parse (uint8_t *work)
 
void protocore_ssh_transport_kex_generate (uint8_t *work)
 
void protocore_ssh_transport_exchange_hash (uint8_t *work)
 
void protocore_ssh_transport_kexdh_reply (uint8_t *work)
 
void protocore_ssh_transport_newkeys_sent (uint8_t *work)
 
void protocore_ssh_transport_newkeys_complete (uint8_t *work)
 
void protocore_ssh_transport_rekey_due (uint8_t *work)
 
void protocore_ssh_transport_begin_rekey (uint8_t *work)
 
uint8_t * protocore_ssh_transport_span (void)
 The PROTOCORE_SSH_TRANSPORT_BORROW bytes this module's state lives in.
 
void ssh_pkt_init (uint8_t i)
 Initialize the packet state for SSH connection slot i.
 
void ssh_transport_init (uint8_t i)
 Bind the session state for SSH connection slot i to the slot's storage.
 
proto_bool ssh_pkt_slot_storage (SshPacketState *s)
 Take the slot's one persistent borrow if it has none yet, and split it.
 
void ssh_pkt_set_client (uint8_t i)
 Mark slot i as the SSH client role (call once, right after ssh_pkt_init).
 
int ssh_pkt_send_at (uint8_t i, uint8_t *wire, size_t payload_len, size_t *out_len, size_t wire_cap, const SshDir *dir)
 Frame the payload_len bytes already written at wire + SSH_WIRE_PAYLOAD_OFF.
 
int ssh_pkt_emit (uint8_t i, const uint8_t *payload, size_t len, const SshDir *dir)
 Frame payload for slot i into the secure pool and raise the flag a worker drains.
 
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, const SshDir *dir)
 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, const SshDir *dir)
 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, const SshDir *dir)
 Send SSH_MSG_DISCONNECT with reason reason_code.
 
int ssh_pkt_unimplemented (uint8_t i, uint8_t *out, size_t *out_len, size_t out_cap)
 Build the SSH_MSG_UNIMPLEMENTED payload answering the packet slot i last received.
 
int ssh_dh_generate (uint8_t i)
 Generate slot i's DH ephemeral: a random y, and f = g^y mod p (RFC 4253 sec 8).
 
void ssh_kdf_derive (const SshKdfInputs *in, char label, uint8_t *out, size_t out_len)
 Derive the RFC 4253 sec 7.2 keys from K, H and the session id into slot i's epoch, one letter per direction.
 
void ssh_kex_install_keys (uint8_t i, const SshKdfInputs *in)
 
int ssh_pkt_build_disconnect (uint32_t reason_code, const char *desc, size_t desc_len, uint8_t *out, size_t *out_len, size_t cap)
 Send DISCONNECT with the no-more-auth-methods reason, then drop.
 
int ssh_transport_dispatch (uint8_t i, uint8_t msg_type, const uint8_t *payload, size_t len)
 Dispatch one decrypted message; 50 and above go up to the authentication protocol.
 
void ssh_transport_key_re_exchange (uint8_t i)
 Emit a fresh KEXINIT for slot i once its volume or time budget is spent.
 
int ssh_transport_service_request (const uint8_t *payload, size_t len, uint8_t *out, size_t *out_len, size_t cap)
 Handle SSH_MSG_SERVICE_REQUEST; emit SERVICE_ACCEPT for ssh-userauth (RFC 4253 sec 10).
 
int ssh_transport_version_exchange_recv (uint8_t i, const uint8_t *buf, size_t n, size_t *off)
 Take the peer identification string off buf (RFC 4253 sec 4.2).
 
proto_bool ssh_kex_shared_secret (const SshKexEphemeral *e, const uint8_t *peer_pub, uint32_t peer_pub_len, uint8_t k_be[256])
 Compute K from the peer's exchange value, for the role that sent the first message.
 
proto_bool ssh_pubkey_blob_valid (const uint8_t *blob, uint32_t blob_len)
 True when blob holds a public key in one of the formats this build decodes.
 
proto_bool ssh_pubkey_algo_supported (const char *pk_algo, const uint8_t *blob, uint32_t blob_len)
 True when pk_algo names an algorithm this end verifies, and blob is of its key type.
 
proto_bool ssh_pubkey_verify (uint8_t i, const char *pk_algo, const uint8_t *blob, uint32_t blob_len, const uint8_t *sig, uint32_t sig_len, const uint8_t *signed_data, size_t signed_len)
 Verify sig over signed_data against the public key in blob, out of slot i's crypto_work. The key type comes from the blob; pk_algo steers the RSA signature hash (RFC 8332).
 

Variables

SshSession ssh_sess [MAX_SSH_CONNS]
 Static pool of SSH session state (BSS), one per SSH slot.
 
SshTransportVars SshTransportV
 The operands and the outcome.
 
SshPacketState ssh_pkt [MAX_SSH_CONNS]
 Static packet state pool (BSS). One entry per SSH slot.
 
SshKeyMat ssh_keys [MAX_SSH_CONNS][2]
 Pool of session key material, two epochs per MAX_SSH_CONNS.
 
SshDhState ssh_dh [MAX_SSH_CONNS]
 Pool of ephemeral DH state, one entry per MAX_SSH_CONNS.
 

Detailed Description

RFC 4253 transport layer: identification exchange, algorithm negotiation, key exchange.

Definition in file transport.h.

Macro Definition Documentation

◆ SSH_TRANSPORT

#define SSH_TRANSPORT   (&SshTransport)

Reader shorthand: SSH_TRANSPORT->kexinit_parse(...).

Definition at line 325 of file transport.h.

◆ SSH_KDF_MAX

#define SSH_KDF_MAX   (4 * PROTOCORE_SHA256_DIGEST_LEN)

Max bytes ssh_kdf_derive() can produce (4 SHA-256 blocks).

Definition at line 344 of file transport.h.

◆ SSH_UNIMPLEMENTED_LEN

#define SSH_UNIMPLEMENTED_LEN   5u

Bytes in an SSH_MSG_UNIMPLEMENTED payload: the message number and one uint32.

Definition at line 552 of file transport.h.

Typedef Documentation

◆ SshKexAlg

Negotiated key-exchange method.

◆ SshHostkeyAlg

Negotiated host-key / signature algorithm.

◆ 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 511 of file transport.h.

Enumeration Type Documentation

◆ PROTO_ENUM_PACKED [1/2]

Negotiated key-exchange method.

Enumerator
SSH_KEX_DH_GROUP14 

diffie-hellman-group14-sha256 (RFC 8268)

SSH_KEX_CURVE25519 

curve25519-sha256 (RFC 8731)

SSH_KEX_MLKEM768_X25519 

mlkem768x25519-sha256

SSH_KEX_ECDH_NISTP256 

ecdh-sha2-nistp256 (RFC 5656 sec 4)

SSH_KEX_SNTRUP761_X25519 

sntru.nosp@m.p761.nosp@m.x2551.nosp@m.9-sh.nosp@m.a512@.nosp@m.open.nosp@m.ssh.c.nosp@m.om

SSH_HOSTKEY_RSA_SHA256 

rsa-sha2-256 (RFC 8332)

SSH_HOSTKEY_ED25519 

ssh-ed25519 (RFC 8709)

SSH_HOSTKEY_RSA_SHA512 

rsa-sha2-512 (RFC 8332)

SSH_HOSTKEY_ECDSA_NISTP256 

ecdsa-sha2-nistp256 (RFC 5656)

Definition at line 38 of file transport.h.

◆ PROTO_ENUM_PACKED [2/2]

Negotiated host-key / signature algorithm.

Enumerator
SSH_KEX_DH_GROUP14 

diffie-hellman-group14-sha256 (RFC 8268)

SSH_KEX_CURVE25519 

curve25519-sha256 (RFC 8731)

SSH_KEX_MLKEM768_X25519 

mlkem768x25519-sha256

SSH_KEX_ECDH_NISTP256 

ecdh-sha2-nistp256 (RFC 5656 sec 4)

SSH_KEX_SNTRUP761_X25519 

sntru.nosp@m.p761.nosp@m.x2551.nosp@m.9-sh.nosp@m.a512@.nosp@m.open.nosp@m.ssh.c.nosp@m.om

SSH_HOSTKEY_RSA_SHA256 

rsa-sha2-256 (RFC 8332)

SSH_HOSTKEY_ED25519 

ssh-ed25519 (RFC 8709)

SSH_HOSTKEY_RSA_SHA512 

rsa-sha2-512 (RFC 8332)

SSH_HOSTKEY_ECDSA_NISTP256 

ecdsa-sha2-nistp256 (RFC 5656)

Definition at line 48 of file transport.h.

◆ 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 578 of file transport.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 586 of file transport.h.

Function Documentation

◆ ssh_kex_set_prefer_rsa()

void ssh_kex_set_prefer_rsa ( proto_bool  prefer)

Steer KEX and host-key negotiation toward RSA with DH-group14, or toward curve25519 with ed25519.

Both suites are advertised whatever this is set to; it orders them, so a peer that supports only one still connects. Runtime-selectable, before the handshake.

◆ ssh_kex_prefer_rsa()

proto_bool ssh_kex_prefer_rsa ( void  )

Current negotiation preference (true = prefer RSA / DH).

◆ ssh_session_id()

const uint8_t * ssh_session_id ( uint8_t  i,
size_t *  len 
)

The session identifier for slot i, or null before the first key exchange completes.

RFC 4253 sec 10: "When the service starts, it may have access to the session identifier generated during the key exchange." It is the first exchange's hash H (sec 7.2) and does not change on a re-exchange, so a service that binds to it stays bound.

Parameters
iSSH slot index.
lenSet to the identifier's length: 32 for the SHA-256 methods, 64 for the SHA-512 one.

◆ ssh_session_id_latch()

void ssh_session_id_latch ( uint8_t  i,
const uint8_t *  h,
size_t  h_len 
)

Latch the first exchange's hash as slot i's session identifier (RFC 4253 sec 7.2).

"The exchange hash H from the first key exchange is additionally used as the session identifier." Both roles compute H in their own half of sec 8 and hand it here; the second and later exchanges are ignored, so the identifier never moves under a service that bound to it.

◆ ssh_kex_is_sha512()

proto_bool ssh_kex_is_sha512 ( SshKexAlg  a)

True when a hashes with SHA-512 rather than SHA-256 (RFC 8268, RFC 8731).

◆ ssh_hostkey_verify()

proto_bool ssh_hostkey_verify ( uint8_t  i,
const uint8_t *  ks,
size_t  ks_len,
const uint8_t *  sig,
size_t  sig_len,
const uint8_t *  h,
size_t  h_len 
)

Verify the server's signature over the exchange hash with its host key (RFC 4253 sec 8).

Parameters
ithe SSH slot the exchange belongs to
ksthe host key blob the server sent
ks_lenits length
sigthe signature blob
sig_lenits length
hthe exchange hash the signature is taken over
h_lenits length
Returns
true when the signature checks out under the blob's own algorithm.

◆ protocore_ssh_transport_recv_ident()

void protocore_ssh_transport_recv_ident ( uint8_t *  work)

◆ protocore_ssh_transport_send_ident()

void protocore_ssh_transport_send_ident ( uint8_t *  work)

◆ protocore_ssh_transport_kexinit_build()

void protocore_ssh_transport_kexinit_build ( uint8_t *  work)

◆ protocore_ssh_transport_kexinit_parse()

void protocore_ssh_transport_kexinit_parse ( uint8_t *  work)

◆ protocore_ssh_transport_kex_generate()

void protocore_ssh_transport_kex_generate ( uint8_t *  work)

◆ protocore_ssh_transport_exchange_hash()

void protocore_ssh_transport_exchange_hash ( uint8_t *  work)

◆ protocore_ssh_transport_kexdh_reply()

void protocore_ssh_transport_kexdh_reply ( uint8_t *  work)

◆ protocore_ssh_transport_newkeys_sent()

void protocore_ssh_transport_newkeys_sent ( uint8_t *  work)

◆ protocore_ssh_transport_newkeys_complete()

void protocore_ssh_transport_newkeys_complete ( uint8_t *  work)

◆ protocore_ssh_transport_rekey_due()

void protocore_ssh_transport_rekey_due ( uint8_t *  work)

◆ protocore_ssh_transport_begin_rekey()

void protocore_ssh_transport_begin_rekey ( uint8_t *  work)

◆ protocore_ssh_transport_span()

uint8_t * protocore_ssh_transport_span ( void  )

The PROTOCORE_SSH_TRANSPORT_BORROW bytes this module's state lives in.

Stated beside the namespace rather than on it: an entry takes a borrow, and this is where that borrow comes from. Taken once from the end of the pool, which no mark and no release walks, so the state lasts the life of the program.

Returns
the span.

◆ ssh_pkt_init()

void ssh_pkt_init ( uint8_t  i)

Initialize the packet state for SSH connection slot i.

Zeroes the sequence numbers and the transmit state, keeping the slot's storage pointers. The protocol flags are the session's (ssh_transport.h) and are reset by ssh_transport_init().

Parameters
iSSH slot index.

◆ ssh_transport_init()

void ssh_transport_init ( uint8_t  i)

Bind the session state for SSH connection slot i to the slot's storage.

Zeroes the session, then points each of its buffers and both key epochs at their offsets within the slot, leaves the phase at SSH_PHASE_IDENT with the first key exchange already running, and marks both epochs inactive.

Parameters
iSSH slot index.

◆ ssh_pkt_slot_storage()

proto_bool ssh_pkt_slot_storage ( SshPacketState *  s)

Take the slot's one persistent borrow if it has none yet, and split it.

Sets SshPacketState::tx_wire, SshPacketState::mac_work and SshPacketState::crypto_work. Idempotent, and false only when the pool cannot cover the slot.

◆ ssh_pkt_set_client()

void ssh_pkt_set_client ( uint8_t  i)

Mark slot i as the SSH client role (call once, right after ssh_pkt_init).

Flips the send/receive key direction: the client encrypts with the c2s key set and decrypts with the s2c one, the mirror of the server. Without this a slot defaults to the server role.

◆ ssh_pkt_send_at()

int ssh_pkt_send_at ( uint8_t  i,
uint8_t *  wire,
size_t  payload_len,
size_t *  out_len,
size_t  wire_cap,
const SshDir *  dir 
)

Frame the payload_len bytes already written at wire + SSH_WIRE_PAYLOAD_OFF.

The in-place form of ssh_pkt_send(): same framing, padding, encryption and MAC, over a payload the caller has already placed. wire holds the finished packet on return.

Returns
0 on success, -1 on overflow or sequence-number exhaustion.

◆ ssh_pkt_emit()

int ssh_pkt_emit ( uint8_t  i,
const uint8_t *  payload,
size_t  len,
const SshDir *  dir 
)

Frame payload for slot i into the secure pool and raise the flag a worker drains.

Borrows the wire buffer itself, for a caller that already holds its message somewhere else - handshake and control traffic, which is small and infrequent. On return the packet is framed and SshPacketState::tx_ready is set; a worker puts the bytes on the wire and releases the borrow. This layer never reaches the wire.

Returns
0 on success, -1 if a packet is already pending, the pool is exhausted, or framing fails.

◆ 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,
const SshDir *  dir 
)

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.

◆ ssh_pkt_recv()

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

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).

◆ 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,
const SshDir *  dir 
)

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.

◆ ssh_pkt_unimplemented()

int ssh_pkt_unimplemented ( uint8_t  i,
uint8_t *  out,
size_t *  out_len,
size_t  out_cap 
)

Build the SSH_MSG_UNIMPLEMENTED payload answering the packet slot i last received.

"An implementation MUST respond to all unrecognized messages with an SSH_MSG_UNIMPLEMENTED message in the order in which the messages were received." The sequence number it carries is the receive counter's, which this layer owns; the caller frames and sends the payload.

Parameters
iSSH slot index.
outOutput buffer for the payload.
out_lenSet to SSH_UNIMPLEMENTED_LEN.
out_capCapacity of out.
Returns
0 on success, -1 on a bad slot or too small a buffer.

◆ ssh_dh_generate()

int ssh_dh_generate ( uint8_t  i)

Generate slot i's DH ephemeral: a random y, and f = g^y mod p (RFC 4253 sec 8).

Returns
0 on success, -1 if the slot has no storage.

◆ ssh_kdf_derive()

void ssh_kdf_derive ( const SshKdfInputs *  in,
char  label,
uint8_t *  out,
size_t  out_len 
)

Derive the RFC 4253 sec 7.2 keys from K, H and the session id into slot i's epoch, one letter per direction.

One RFC 4253 sec 7.2 derivation: out_len bytes of the key label names.

"Encryption keys MUST be computed as HASH, of a known value and K": K1 = HASH(K || H || X || session_id) with X the label byte, and where more bytes are wanted than one hash gives, "the key is extended by computing HASH of the concatenation of K and H and the entire key so far" - K2 = HASH(K || H || K1), K3 = HASH(K || H || K1 || K2), key = K1 || K2 || K3.

Parameters
label'A'..'F', the six keys sec 7.2 lists in order.
out_lenBytes wanted, clamped to SSH_KDF_MAX.

◆ ssh_kex_install_keys()

void ssh_kex_install_keys ( uint8_t  i,
const SshKdfInputs *  in 
)

◆ ssh_pkt_build_disconnect()

int ssh_pkt_build_disconnect ( uint32_t  reason_code,
const char *  desc,
size_t  desc_len,
uint8_t *  out,
size_t *  out_len,
size_t  cap 
)

Send DISCONNECT with the no-more-auth-methods reason, then drop.

Build an SSH_MSG_DISCONNECT payload (RFC 4253 sec 11.1).

Parameters
reason_codeOne of SSH_DISCONNECT_* constants.
descDescription bytes, sent as the message's first string.
desc_lenLength of desc.
outOutput buffer for the payload.
out_lenSet to the number of bytes written.
capCapacity of out.
Returns
0 on success, -1 when cap cannot hold the whole message.

◆ ssh_transport_dispatch()

int ssh_transport_dispatch ( uint8_t  i,
uint8_t  msg_type,
const uint8_t *  payload,
size_t  len 
)

Dispatch one decrypted message; 50 and above go up to the authentication protocol.

◆ ssh_transport_key_re_exchange()

void ssh_transport_key_re_exchange ( uint8_t  i)

Emit a fresh KEXINIT for slot i once its volume or time budget is spent.

◆ ssh_transport_service_request()

int ssh_transport_service_request ( const uint8_t *  payload,
size_t  len,
uint8_t *  out,
size_t *  out_len,
size_t  cap 
)

Handle SSH_MSG_SERVICE_REQUEST; emit SERVICE_ACCEPT for ssh-userauth (RFC 4253 sec 10).

Returns
0 and writes SERVICE_ACCEPT to out, or -1 if the service is not "ssh-userauth" or the message is malformed.

◆ ssh_transport_version_exchange_recv()

int ssh_transport_version_exchange_recv ( uint8_t  i,
const uint8_t *  buf,
size_t  n,
size_t *  off 
)

Take the peer identification string off buf (RFC 4253 sec 4.2).

Returns
1 once it is whole and the phase has advanced, 0 while more bytes are needed, -1 on a string the section does not admit. off is left at the first binary packet byte.

◆ ssh_kex_shared_secret()

proto_bool ssh_kex_shared_secret ( const SshKexEphemeral *  e,
const uint8_t *  peer_pub,
uint32_t  peer_pub_len,
uint8_t  k_be[256] 
)

Compute K from the peer's exchange value, for the role that sent the first message.

One switch over the negotiated method, beside the responder half that shares this file: RFC 4253 sec 8 is the transport's, whichever end is running it. K is written right-aligned into k_be, which is how sec 8 and sec 7.2 both consume it - as an mpint for the classical methods, and as a fixed 32 or 64-byte string for the hybrids.

Parameters
eThis end's ephemeral for the exchange.
peer_pubThe peer's exchange value: Q_S, f, or ciphertext || Q_S for a hybrid.
peer_pub_lenLength of peer_pub; each method checks it against its own.
k_be256 bytes, zeroed then filled from the right.
Returns
false on a wrong length, a rejected point (RFC 7748 sec 6.1), or an unsupported method.

◆ ssh_pubkey_blob_valid()

proto_bool ssh_pubkey_blob_valid ( const uint8_t *  blob,
uint32_t  blob_len 
)

True when blob holds a public key in one of the formats this build decodes.

◆ ssh_pubkey_algo_supported()

proto_bool ssh_pubkey_algo_supported ( const char *  pk_algo,
const uint8_t *  blob,
uint32_t  blob_len 
)

True when pk_algo names an algorithm this end verifies, and blob is of its key type.

RFC 4252 sec 7: "Any public key algorithm may be offered for use in authentication... If the server does not support some algorithm, it MUST simply reject the request." The name arrives independently of the blob, so both are checked against what the blob parsers here accept: either RSA signature name takes an "ssh-rsa" blob, the other two take a blob named for themselves.

◆ ssh_pubkey_verify()

proto_bool ssh_pubkey_verify ( uint8_t  i,
const char *  pk_algo,
const uint8_t *  blob,
uint32_t  blob_len,
const uint8_t *  sig,
uint32_t  sig_len,
const uint8_t *  signed_data,
size_t  signed_len 
)

Verify sig over signed_data against the public key in blob, out of slot i's crypto_work. The key type comes from the blob; pk_algo steers the RSA signature hash (RFC 8332).

Variable Documentation

◆ ssh_sess

SshSession ssh_sess[MAX_SSH_CONNS]
extern

Static pool of SSH session state (BSS), one per SSH slot.

◆ SshTransportV

SshTransportVars SshTransportV
extern

The operands and the outcome.

◆ ssh_pkt

SshPacketState ssh_pkt[MAX_SSH_CONNS]
extern

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

◆ ssh_keys

SshKeyMat ssh_keys[MAX_SSH_CONNS][2]
extern

Pool of session key material, two epochs per MAX_SSH_CONNS.

RFC 4253 sec 7.3 switches each direction on its own NEWKEYS, so a re-key derives into the epoch neither direction is reading and each direction moves to it when its NEWKEYS crosses. The SshDir the codec is handed selects which one that site reads. Zeroed on connection close by ssh_keymat_wipe(slot).

◆ ssh_dh

SshDhState ssh_dh[MAX_SSH_CONNS]
extern

Pool of ephemeral DH state, one entry per MAX_SSH_CONNS.