ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
common.h File Reference

Common declarations and data structures for cryptographic handshake. More...

Go to the source code of this file.

Data Structures

struct  crypto_handshake_context_t
 Cryptographic handshake context structure. More...
 

Macros

Authentication Requirement Flags

Flags sent in AUTH_CHALLENGE packet to indicate server requirements.

#define AUTH_REQUIRE_PASSWORD   0x01
 Server requires password authentication.
 
#define AUTH_REQUIRE_CLIENT_KEY   0x02
 Server requires client key authentication (whitelist)
 

Typedefs

typedef struct crypto_handshake_context_t crypto_handshake_context_t
 Cryptographic handshake context structure.
 

Enumerations

enum  crypto_handshake_state_t {
  CRYPTO_HANDSHAKE_DISABLED = 0 , CRYPTO_HANDSHAKE_INIT , CRYPTO_HANDSHAKE_KEY_EXCHANGE , CRYPTO_HANDSHAKE_AUTHENTICATING ,
  CRYPTO_HANDSHAKE_READY , CRYPTO_HANDSHAKE_FAILED
}
 Cryptographic handshake state enumeration. More...
 

Functions

Common Handshake Functions
asciichat_error_t crypto_handshake_init (crypto_handshake_context_t *ctx, bool is_server)
 Initialize crypto handshake context.
 
asciichat_error_t crypto_handshake_set_parameters (crypto_handshake_context_t *ctx, const crypto_parameters_packet_t *params)
 Set crypto parameters from crypto_parameters_packet_t.
 
asciichat_error_t crypto_handshake_validate_packet_size (const crypto_handshake_context_t *ctx, uint16_t packet_type, size_t packet_size)
 Validate crypto packet size based on session parameters.
 
asciichat_error_t crypto_handshake_init_with_password (crypto_handshake_context_t *ctx, bool is_server, const char *password)
 Initialize crypto handshake context with password authentication.
 
void crypto_handshake_cleanup (crypto_handshake_context_t *ctx)
 Cleanup crypto handshake context with secure memory wiping.
 
bool crypto_handshake_is_ready (const crypto_handshake_context_t *ctx)
 Check if handshake is complete and encryption is ready.
 
const crypto_context_tcrypto_handshake_get_context (const crypto_handshake_context_t *ctx)
 Get the crypto context for encryption/decryption.
 
asciichat_error_t crypto_handshake_encrypt_packet (const crypto_handshake_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_len)
 Encrypt a packet using the established crypto context.
 
asciichat_error_t crypto_handshake_decrypt_packet (const crypto_handshake_context_t *ctx, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_len)
 Decrypt a packet using the established crypto context.
 
asciichat_error_t crypto_encrypt_packet_or_passthrough (const crypto_handshake_context_t *ctx, bool crypto_ready, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_len)
 Encrypt with automatic passthrough if crypto not ready.
 
asciichat_error_t crypto_decrypt_packet_or_passthrough (const crypto_handshake_context_t *ctx, bool crypto_ready, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_len)
 Decrypt with automatic passthrough if crypto not ready.
 
Session Rekeying Functions
asciichat_error_t crypto_handshake_rekey_request (crypto_handshake_context_t *ctx, socket_t socket)
 Send REKEY_REQUEST packet (initiator side)
 
asciichat_error_t crypto_handshake_rekey_response (crypto_handshake_context_t *ctx, socket_t socket)
 Send REKEY_RESPONSE packet (responder side)
 
asciichat_error_t crypto_handshake_rekey_complete (crypto_handshake_context_t *ctx, socket_t socket)
 Send REKEY_COMPLETE packet (initiator side)
 
asciichat_error_t crypto_handshake_process_rekey_request (crypto_handshake_context_t *ctx, const uint8_t *packet, size_t packet_len)
 Process received REKEY_REQUEST packet (responder side)
 
asciichat_error_t crypto_handshake_process_rekey_response (crypto_handshake_context_t *ctx, const uint8_t *packet, size_t packet_len)
 Process received REKEY_RESPONSE packet (initiator side)
 
asciichat_error_t crypto_handshake_process_rekey_complete (crypto_handshake_context_t *ctx, const uint8_t *packet, size_t packet_len)
 Process received REKEY_COMPLETE packet (responder side)
 
bool crypto_handshake_should_rekey (const crypto_handshake_context_t *ctx)
 Check if rekeying should be triggered for this handshake context.
 

Detailed Description

Common declarations and data structures for cryptographic handshake.

Definition in file crypto/handshake/common.h.

Macro Definition Documentation

◆ AUTH_REQUIRE_CLIENT_KEY

#define AUTH_REQUIRE_CLIENT_KEY   0x02

Server requires client key authentication (whitelist)

Definition at line 26 of file crypto/handshake/common.h.

◆ AUTH_REQUIRE_PASSWORD

#define AUTH_REQUIRE_PASSWORD   0x01

Server requires password authentication.

Definition at line 24 of file crypto/handshake/common.h.

Function Documentation

◆ crypto_decrypt_packet_or_passthrough()

asciichat_error_t crypto_decrypt_packet_or_passthrough ( const crypto_handshake_context_t ctx,
bool  crypto_ready,
const uint8_t ciphertext,
size_t  ciphertext_len,
uint8_t plaintext,
size_t  plaintext_size,
size_t *  plaintext_len 
)

Decrypt with automatic passthrough if crypto not ready.

Parameters
ctxHandshake context
crypto_readyTrue if crypto is ready, false to passthrough
ciphertextCiphertext or plaintext data to decrypt
ciphertext_lenLength of ciphertext/plaintext data
plaintextOutput buffer for plaintext
plaintext_sizeSize of output buffer
plaintext_lenOutput parameter for actual plaintext length
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 340 of file crypto/handshake/common.c.

343 {
344 if (!crypto_ready) {
345 // No encryption - just copy data
346 if (ciphertext_len > plaintext_size) {
347 SET_ERRNO(ERROR_BUFFER, "Ciphertext too large for plaintext buffer: %zu > %zu", ciphertext_len, plaintext_size);
348 return ERROR_BUFFER;
349 }
350 memcpy(plaintext, ciphertext, ciphertext_len);
351 *plaintext_len = ciphertext_len;
352 return ASCIICHAT_OK;
353 }
354
355 return crypto_handshake_decrypt_packet(ctx, ciphertext, ciphertext_len, plaintext, plaintext_size, plaintext_len);
356}
asciichat_error_t crypto_handshake_decrypt_packet(const crypto_handshake_context_t *ctx, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_len)
Decrypt a packet using the established crypto context.
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
@ ASCIICHAT_OK
Definition error_codes.h:48
@ ERROR_BUFFER
Definition error_codes.h:96

References ASCIICHAT_OK, crypto_handshake_decrypt_packet(), ERROR_BUFFER, and SET_ERRNO.

Referenced by crypto_client_decrypt_packet(), and crypto_server_decrypt_packet().

◆ crypto_encrypt_packet_or_passthrough()

asciichat_error_t crypto_encrypt_packet_or_passthrough ( const crypto_handshake_context_t ctx,
bool  crypto_ready,
const uint8_t plaintext,
size_t  plaintext_len,
uint8_t ciphertext,
size_t  ciphertext_size,
size_t *  ciphertext_len 
)

Encrypt with automatic passthrough if crypto not ready.

Parameters
ctxHandshake context
crypto_readyTrue if crypto is ready, false to passthrough
plaintextPlaintext data to encrypt
plaintext_lenLength of plaintext data
ciphertextOutput buffer for ciphertext or plaintext (if passthrough)
ciphertext_sizeSize of output buffer
ciphertext_lenOutput parameter for actual length
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 321 of file crypto/handshake/common.c.

324 {
325 if (!crypto_ready) {
326 // No encryption - just copy data
327 if (plaintext_len > ciphertext_size) {
328 SET_ERRNO(ERROR_BUFFER, "Plaintext too large for ciphertext buffer: %zu > %zu", plaintext_len, ciphertext_size);
329 return ERROR_BUFFER;
330 }
331 memcpy(ciphertext, plaintext, plaintext_len);
332 *ciphertext_len = plaintext_len;
333 return ASCIICHAT_OK;
334 }
335
336 return crypto_handshake_encrypt_packet(ctx, plaintext, plaintext_len, ciphertext, ciphertext_size, ciphertext_len);
337}
asciichat_error_t crypto_handshake_encrypt_packet(const crypto_handshake_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_len)
Encrypt a packet using the established crypto context.

References ASCIICHAT_OK, crypto_handshake_encrypt_packet(), ERROR_BUFFER, and SET_ERRNO.

Referenced by crypto_client_encrypt_packet(), and crypto_server_encrypt_packet().

◆ crypto_handshake_cleanup()

void crypto_handshake_cleanup ( crypto_handshake_context_t ctx)

Cleanup crypto handshake context with secure memory wiping.

Parameters
ctxHandshake context to cleanup

Definition at line 259 of file crypto/handshake/common.c.

259 {
260 if (!ctx)
261 return;
262
263 // Cleanup core crypto context
265
266 // Zero out sensitive data
267 sodium_memzero(ctx, sizeof(crypto_handshake_context_t));
268}
void crypto_cleanup(crypto_context_t *ctx)
Cleanup crypto context with secure memory wiping.
Cryptographic handshake context structure.

References crypto_cleanup(), and crypto_handshake_context_t::crypto_ctx.

Referenced by client_crypto_init(), crypto_client_cleanup(), crypto_server_cleanup_client(), and server_connection_close().

◆ crypto_handshake_decrypt_packet()

asciichat_error_t crypto_handshake_decrypt_packet ( const crypto_handshake_context_t ctx,
const uint8_t ciphertext,
size_t  ciphertext_len,
uint8_t plaintext,
size_t  plaintext_size,
size_t *  plaintext_len 
)

Decrypt a packet using the established crypto context.

Parameters
ctxHandshake context (must be ready)
ciphertextCiphertext data to decrypt
ciphertext_lenLength of ciphertext data
plaintextOutput buffer for plaintext
plaintext_sizeSize of output buffer
plaintext_lenOutput parameter for actual plaintext length
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 303 of file crypto/handshake/common.c.

305 {
306 if (!ctx || !crypto_handshake_is_ready(ctx)) {
307 SET_ERRNO(ERROR_INVALID_STATE, "Invalid state: ctx=%p, ready=%d", ctx, ctx ? crypto_handshake_is_ready(ctx) : 0);
308 return ERROR_INVALID_STATE;
309 }
310
311 crypto_result_t result = crypto_decrypt((crypto_context_t *)&ctx->crypto_ctx, ciphertext, ciphertext_len, plaintext,
312 plaintext_size, plaintext_len);
313 if (result != CRYPTO_OK) {
314 return SET_ERRNO(ERROR_NETWORK, "Failed to decrypt packet: %s", crypto_result_to_string(result));
315 }
316
317 return ASCIICHAT_OK;
318}
bool crypto_handshake_is_ready(const crypto_handshake_context_t *ctx)
Check if handshake is complete and encryption is ready.
const char * crypto_result_to_string(crypto_result_t result)
Convert crypto result to human-readable string.
crypto_result_t
Cryptographic operation result codes.
crypto_result_t crypto_decrypt(crypto_context_t *ctx, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext_out, size_t plaintext_out_size, size_t *plaintext_len_out)
Decrypt data using XSalsa20-Poly1305.
@ CRYPTO_OK
@ ERROR_INVALID_STATE
@ ERROR_NETWORK
Definition error_codes.h:69
Cryptographic context structure.

References ASCIICHAT_OK, crypto_handshake_context_t::crypto_ctx, crypto_decrypt(), crypto_handshake_is_ready(), CRYPTO_OK, crypto_result_to_string(), ERROR_INVALID_STATE, ERROR_NETWORK, and SET_ERRNO.

Referenced by crypto_decrypt_packet_or_passthrough().

◆ crypto_handshake_encrypt_packet()

asciichat_error_t crypto_handshake_encrypt_packet ( const crypto_handshake_context_t ctx,
const uint8_t plaintext,
size_t  plaintext_len,
uint8_t ciphertext,
size_t  ciphertext_size,
size_t *  ciphertext_len 
)

Encrypt a packet using the established crypto context.

Parameters
ctxHandshake context (must be ready)
plaintextPlaintext data to encrypt
plaintext_lenLength of plaintext data
ciphertextOutput buffer for ciphertext
ciphertext_sizeSize of output buffer
ciphertext_lenOutput parameter for actual ciphertext length
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 285 of file crypto/handshake/common.c.

287 {
288 if (!ctx || !crypto_handshake_is_ready(ctx)) {
289 SET_ERRNO(ERROR_INVALID_STATE, "Invalid state: ctx=%p, ready=%d", ctx, ctx ? crypto_handshake_is_ready(ctx) : 0);
290 return ERROR_INVALID_STATE;
291 }
292
293 crypto_result_t result = crypto_encrypt((crypto_context_t *)&ctx->crypto_ctx, plaintext, plaintext_len, ciphertext,
294 ciphertext_size, ciphertext_len);
295 if (result != CRYPTO_OK) {
296 return SET_ERRNO(ERROR_NETWORK, "Failed to encrypt packet: %s", crypto_result_to_string(result));
297 }
298
299 return ASCIICHAT_OK;
300}
crypto_result_t crypto_encrypt(crypto_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext_out, size_t ciphertext_out_size, size_t *ciphertext_len_out)
Encrypt data using XSalsa20-Poly1305.

References ASCIICHAT_OK, crypto_handshake_context_t::crypto_ctx, crypto_encrypt(), crypto_handshake_is_ready(), CRYPTO_OK, crypto_result_to_string(), ERROR_INVALID_STATE, ERROR_NETWORK, and SET_ERRNO.

Referenced by crypto_encrypt_packet_or_passthrough().

◆ crypto_handshake_get_context()

const crypto_context_t * crypto_handshake_get_context ( const crypto_handshake_context_t ctx)

Get the crypto context for encryption/decryption.

Parameters
ctxHandshake context
Returns
Pointer to crypto context, or NULL if ctx is NULL

Definition at line 278 of file crypto/handshake/common.c.

278 {
279 if (!ctx || !crypto_handshake_is_ready(ctx))
280 return NULL;
281 return &ctx->crypto_ctx;
282}

References crypto_handshake_context_t::crypto_ctx, and crypto_handshake_is_ready().

Referenced by broadcast_server_state_to_all_clients(), client_send_thread_func(), crypto_client_get_context(), crypto_server_get_context(), disconnect_client_for_bad_data(), tcp_client_send_audio_batch(), tcp_client_send_audio_opus(), tcp_client_send_audio_opus_batch(), tcp_client_send_join(), and tcp_client_send_packet().

◆ crypto_handshake_init()

asciichat_error_t crypto_handshake_init ( crypto_handshake_context_t ctx,
bool  is_server 
)

Initialize crypto handshake context.

Parameters
ctxHandshake context to initialize (must not be NULL)
is_serverTrue if this is the server side, false for client
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 17 of file crypto/handshake/common.c.

17 {
18 if (!ctx) {
19 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: ctx=%p", ctx);
20 }
21
22 // Zero out the context
23 memset(ctx, 0, sizeof(crypto_handshake_context_t));
24
25 // Initialize core crypto context
27 if (result != CRYPTO_OK) {
28 return SET_ERRNO(ERROR_CRYPTO, "Failed to initialize crypto context: %s", crypto_result_to_string(result));
29 }
30
32 ctx->is_server = is_server;
33 ctx->verify_server_key = false;
34 ctx->require_client_auth = false;
35 ctx->server_uses_client_auth = false; // Set to true only if authenticated packet received
36
37 // Load server keys if this is a server
38 if (is_server) {
39 log_info("Server crypto handshake initialized (ephemeral keys)");
40 } else {
41 log_info("Client crypto handshake initialized");
42 }
43
44 return ASCIICHAT_OK;
45}
crypto_result_t crypto_init(crypto_context_t *ctx)
Initialize libsodium and crypto context.
@ ERROR_CRYPTO
Definition error_codes.h:88
@ ERROR_INVALID_PARAM
@ CRYPTO_HANDSHAKE_INIT
#define log_info(...)
Log an INFO message.
crypto_handshake_state_t state

References ASCIICHAT_OK, crypto_handshake_context_t::crypto_ctx, CRYPTO_HANDSHAKE_INIT, crypto_init(), CRYPTO_OK, crypto_result_to_string(), ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_handshake_context_t::is_server, log_info, crypto_handshake_context_t::require_client_auth, crypto_handshake_context_t::server_uses_client_auth, SET_ERRNO, crypto_handshake_context_t::state, and crypto_handshake_context_t::verify_server_key.

Referenced by client_crypto_init(), and server_crypto_handshake().

◆ crypto_handshake_init_with_password()

asciichat_error_t crypto_handshake_init_with_password ( crypto_handshake_context_t ctx,
bool  is_server,
const char *  password 
)

Initialize crypto handshake context with password authentication.

Parameters
ctxHandshake context to initialize (must not be NULL)
is_serverTrue if this is the server side, false for client
passwordPassword for authentication (must meet length requirements)
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 229 of file crypto/handshake/common.c.

230 {
231 if (!ctx || !password) {
232 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: ctx=%p, password=%p", ctx, password);
233 }
234
235 // Zero out the context
236 memset(ctx, 0, sizeof(crypto_handshake_context_t));
237
238 // Initialize core crypto context with password
239 crypto_result_t result = crypto_init_with_password(&ctx->crypto_ctx, password);
240 if (result != CRYPTO_OK) {
241 return SET_ERRNO(ERROR_CRYPTO, "Failed to initialize crypto context with password: %s",
243 }
244
246 ctx->is_server = is_server;
247 ctx->verify_server_key = false;
248 ctx->require_client_auth = false;
249 ctx->server_uses_client_auth = false; // Set to true only if authenticated packet received
250 ctx->has_password = true;
251
252 // Store password temporarily (will be cleared after key derivation)
253 SAFE_STRNCPY(ctx->password, password, sizeof(ctx->password) - 1);
254
255 return ASCIICHAT_OK;
256}
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:358
crypto_result_t crypto_init_with_password(crypto_context_t *ctx, const char *password)
Initialize with password-based encryption.

References ASCIICHAT_OK, crypto_handshake_context_t::crypto_ctx, CRYPTO_HANDSHAKE_INIT, crypto_init_with_password(), CRYPTO_OK, crypto_result_to_string(), ERROR_CRYPTO, ERROR_INVALID_PARAM, crypto_handshake_context_t::has_password, crypto_handshake_context_t::is_server, crypto_handshake_context_t::password, crypto_handshake_context_t::require_client_auth, SAFE_STRNCPY, crypto_handshake_context_t::server_uses_client_auth, SET_ERRNO, crypto_handshake_context_t::state, and crypto_handshake_context_t::verify_server_key.

Referenced by client_crypto_init(), and server_crypto_handshake().

◆ crypto_handshake_is_ready()

◆ crypto_handshake_process_rekey_complete()

asciichat_error_t crypto_handshake_process_rekey_complete ( crypto_handshake_context_t ctx,
const uint8_t packet,
size_t  packet_len 
)

Process received REKEY_COMPLETE packet (responder side)

Parameters
ctxCrypto handshake context (must be ready)
packetEncrypted packet (empty payload, encrypted with NEW key)
packet_lenPacket length
Returns
ASCIICHAT_OK on success, error code on failure

Process received REKEY_COMPLETE packet (responder side). Verifies that the packet decrypts with the new shared secret. If successful, commits to the new key.

Definition at line 563 of file crypto/handshake/common.c.

564 {
565 if (!ctx || !crypto_handshake_is_ready(ctx)) {
566 return SET_ERRNO(ERROR_INVALID_STATE, "Handshake not ready for rekeying: ctx=%p, ready=%d", ctx,
567 ctx ? crypto_handshake_is_ready(ctx) : 0);
568 }
569
571 return SET_ERRNO(ERROR_INVALID_STATE, "No rekey in progress or temp key missing");
572 }
573
574 log_info("Received REKEY_COMPLETE packet (%zu bytes), verifying with NEW key", packet_len);
575
576 // Temporarily swap keys to decrypt with NEW key
577 uint8_t old_shared_key[CRYPTO_SHARED_KEY_SIZE];
578 memcpy(old_shared_key, ctx->crypto_ctx.shared_key, CRYPTO_SHARED_KEY_SIZE);
580
581 // Attempt to decrypt with NEW key
582 uint8_t plaintext[256];
583 size_t plaintext_len = 0;
584 crypto_result_t result =
585 crypto_decrypt(&ctx->crypto_ctx, packet, packet_len, plaintext, sizeof(plaintext), &plaintext_len);
586
587 // Restore old key immediately
588 memcpy(ctx->crypto_ctx.shared_key, old_shared_key, CRYPTO_SHARED_KEY_SIZE);
589 sodium_memzero(old_shared_key, sizeof(old_shared_key));
590
591 if (result != CRYPTO_OK) {
593 return SET_ERRNO(ERROR_CRYPTO, "REKEY_COMPLETE decryption failed (key mismatch): %s",
595 }
596
597 log_info("REKEY_COMPLETE verified successfully, committing to new key");
598
599 // Commit to new key (atomic switch)
600 result = crypto_rekey_commit(&ctx->crypto_ctx);
601 if (result != CRYPTO_OK) {
602 return SET_ERRNO(ERROR_CRYPTO, "Failed to commit rekey: %s", crypto_result_to_string(result));
603 }
604
605 log_info("Session rekeying completed successfully (responder side)");
606 return ASCIICHAT_OK;
607}
unsigned char uint8_t
Definition common.h:56
crypto_result_t crypto_rekey_commit(crypto_context_t *ctx)
Commit to new keys after successful REKEY_COMPLETE.
#define CRYPTO_SHARED_KEY_SIZE
Shared key size (X25519)
void crypto_rekey_abort(crypto_context_t *ctx)
Abort rekeying and fallback to old keys.
uint8_t temp_shared_key[32]

References ASCIICHAT_OK, crypto_handshake_context_t::crypto_ctx, crypto_decrypt(), crypto_handshake_is_ready(), CRYPTO_OK, crypto_rekey_abort(), crypto_rekey_commit(), crypto_result_to_string(), CRYPTO_SHARED_KEY_SIZE, ERROR_CRYPTO, ERROR_INVALID_STATE, crypto_context_t::has_temp_key, log_info, crypto_context_t::rekey_in_progress, SET_ERRNO, crypto_context_t::shared_key, and crypto_context_t::temp_shared_key.

◆ crypto_handshake_process_rekey_request()

asciichat_error_t crypto_handshake_process_rekey_request ( crypto_handshake_context_t ctx,
const uint8_t packet,
size_t  packet_len 
)

Process received REKEY_REQUEST packet (responder side)

Parameters
ctxCrypto handshake context (must be ready)
packetPacket payload (32-byte public key)
packet_lenPacket length (should be 32)
Returns
ASCIICHAT_OK on success, error code on failure

Process received REKEY_REQUEST packet (responder side). Extracts peer's new ephemeral public key and computes new shared secret.

Definition at line 478 of file crypto/handshake/common.c.

479 {
480 if (!ctx || !crypto_handshake_is_ready(ctx)) {
481 return SET_ERRNO(ERROR_INVALID_STATE, "Handshake not ready for rekeying: ctx=%p, ready=%d", ctx,
482 ctx ? crypto_handshake_is_ready(ctx) : 0);
483 }
484
485 // DDoS PROTECTION: Rate limit rekey requests
486 time_t now = time(NULL);
487 if (ctx->crypto_ctx.rekey_last_request_time > 0) {
488 time_t elapsed = now - ctx->crypto_ctx.rekey_last_request_time;
489 if (elapsed < REKEY_MIN_REQUEST_INTERVAL) {
490 return SET_ERRNO(ERROR_CRYPTO,
491 "SECURITY: Rekey request rejected - too frequent (%ld sec since last, minimum %d sec required)",
492 (long)elapsed, REKEY_MIN_REQUEST_INTERVAL);
493 }
494 }
495
496 // Update last request time
498
499 // Validate packet size (should be 32 bytes for X25519 public key)
500 if (packet_len != CRYPTO_PUBLIC_KEY_SIZE) {
501 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid REKEY_REQUEST packet size: %zu (expected %d)", packet_len,
503 }
504
505 log_info("Received REKEY_REQUEST with peer's new ephemeral public key (32 bytes)");
506
507 // Initialize our rekey process (generates our new ephemeral keypair)
509 if (result != CRYPTO_OK) {
510 return SET_ERRNO(ERROR_CRYPTO, "Failed to initialize rekey: %s", crypto_result_to_string(result));
511 }
512
513 // Process peer's public key and compute new shared secret
514 result = crypto_rekey_process_request(&ctx->crypto_ctx, packet);
515 if (result != CRYPTO_OK) {
517 return SET_ERRNO(ERROR_CRYPTO, "Failed to process REKEY_REQUEST: %s", crypto_result_to_string(result));
518 }
519
520 log_debug("REKEY_REQUEST processed successfully, new shared secret computed (responder side)");
521 return ASCIICHAT_OK;
522}
crypto_result_t crypto_rekey_process_request(crypto_context_t *ctx, const uint8_t *peer_new_public_key)
Process REKEY_REQUEST from peer (responder side)
#define CRYPTO_PUBLIC_KEY_SIZE
Public key size (X25519)
#define REKEY_MIN_REQUEST_INTERVAL
Minimum interval between rekey requests (60 seconds, DDoS protection)
crypto_result_t crypto_rekey_init(crypto_context_t *ctx)
Initiate rekeying by generating new ephemeral keys.
#define log_debug(...)
Log a DEBUG message.

References ASCIICHAT_OK, crypto_handshake_context_t::crypto_ctx, crypto_handshake_is_ready(), CRYPTO_OK, CRYPTO_PUBLIC_KEY_SIZE, crypto_rekey_abort(), crypto_rekey_init(), crypto_rekey_process_request(), crypto_result_to_string(), ERROR_CRYPTO, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, log_debug, log_info, crypto_context_t::rekey_last_request_time, REKEY_MIN_REQUEST_INTERVAL, and SET_ERRNO.

Referenced by crypto_client_process_rekey_request().

◆ crypto_handshake_process_rekey_response()

asciichat_error_t crypto_handshake_process_rekey_response ( crypto_handshake_context_t ctx,
const uint8_t packet,
size_t  packet_len 
)

Process received REKEY_RESPONSE packet (initiator side)

Parameters
ctxCrypto handshake context (must be ready)
packetPacket payload (32-byte public key)
packet_lenPacket length (should be 32)
Returns
ASCIICHAT_OK on success, error code on failure

Process received REKEY_RESPONSE packet (initiator side). Extracts peer's new ephemeral public key and computes new shared secret.

Definition at line 528 of file crypto/handshake/common.c.

529 {
530 if (!ctx || !crypto_handshake_is_ready(ctx)) {
531 return SET_ERRNO(ERROR_INVALID_STATE, "Handshake not ready for rekeying: ctx=%p, ready=%d", ctx,
532 ctx ? crypto_handshake_is_ready(ctx) : 0);
533 }
534
535 // Validate packet size (should be 32 bytes for X25519 public key)
536 if (packet_len != CRYPTO_PUBLIC_KEY_SIZE) {
537 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid REKEY_RESPONSE packet size: %zu (expected %d)", packet_len,
539 }
540
542 return SET_ERRNO(ERROR_INVALID_STATE, "No rekey in progress or temp key missing");
543 }
544
545 log_info("Received REKEY_RESPONSE with peer's new ephemeral public key (32 bytes)");
546
547 // Process peer's public key and compute new shared secret
549 if (result != CRYPTO_OK) {
551 return SET_ERRNO(ERROR_CRYPTO, "Failed to process REKEY_RESPONSE: %s", crypto_result_to_string(result));
552 }
553
554 log_debug("REKEY_RESPONSE processed successfully, new shared secret computed (initiator side)");
555 return ASCIICHAT_OK;
556}
crypto_result_t crypto_rekey_process_response(crypto_context_t *ctx, const uint8_t *peer_new_public_key)
Process REKEY_RESPONSE from peer (initiator side)

References ASCIICHAT_OK, crypto_handshake_context_t::crypto_ctx, crypto_handshake_is_ready(), CRYPTO_OK, CRYPTO_PUBLIC_KEY_SIZE, crypto_rekey_abort(), crypto_rekey_process_response(), crypto_result_to_string(), ERROR_CRYPTO, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, crypto_context_t::has_temp_key, log_debug, log_info, crypto_context_t::rekey_in_progress, and SET_ERRNO.

Referenced by crypto_client_process_rekey_response().

◆ crypto_handshake_rekey_complete()

asciichat_error_t crypto_handshake_rekey_complete ( crypto_handshake_context_t ctx,
socket_t  socket 
)

Send REKEY_COMPLETE packet (initiator side)

Parameters
ctxCrypto handshake context (must be ready)
socketSocket to send on
Returns
ASCIICHAT_OK on success, error code on failure

Send REKEY_COMPLETE packet (initiator side). CRITICAL: This packet is encrypted with the NEW shared secret. It proves that both sides have computed the same shared secret.

Definition at line 423 of file crypto/handshake/common.c.

423 {
424 if (!ctx || !crypto_handshake_is_ready(ctx)) {
425 return SET_ERRNO(ERROR_INVALID_STATE, "Handshake not ready for rekeying: ctx=%p, ready=%d", ctx,
426 ctx ? crypto_handshake_is_ready(ctx) : 0);
427 }
428
430 return SET_ERRNO(ERROR_INVALID_STATE, "No rekey in progress or temp key missing");
431 }
432
433 // Encrypt empty payload with NEW key to prove possession
434 uint8_t plaintext[1] = {0}; // Minimal payload
435 uint8_t ciphertext[256]; // Sufficient for nonce + MAC + minimal payload
436 size_t ciphertext_len = 0;
437
438 // Temporarily swap keys to encrypt with NEW key
439 uint8_t old_shared_key[CRYPTO_SHARED_KEY_SIZE];
440 memcpy(old_shared_key, ctx->crypto_ctx.shared_key, CRYPTO_SHARED_KEY_SIZE);
442
443 // Encrypt with NEW key
444 crypto_result_t result =
445 crypto_encrypt(&ctx->crypto_ctx, plaintext, sizeof(plaintext), ciphertext, sizeof(ciphertext), &ciphertext_len);
446
447 // Restore old key immediately (commit will happen after successful send)
448 memcpy(ctx->crypto_ctx.shared_key, old_shared_key, CRYPTO_SHARED_KEY_SIZE);
449 sodium_memzero(old_shared_key, sizeof(old_shared_key));
450
451 if (result != CRYPTO_OK) {
453 return SET_ERRNO(ERROR_CRYPTO, "Failed to encrypt REKEY_COMPLETE: %s", crypto_result_to_string(result));
454 }
455
456 // Send encrypted REKEY_COMPLETE
457 log_info("Sending REKEY_COMPLETE (encrypted with NEW key, %zu bytes)", ciphertext_len);
458 int send_result = send_packet(socket, PACKET_TYPE_CRYPTO_REKEY_COMPLETE, ciphertext, ciphertext_len);
459 if (send_result != 0) {
461 return SET_ERRNO(ERROR_NETWORK, "Failed to send REKEY_COMPLETE packet");
462 }
463
464 // Commit to new key (atomic switch)
465 result = crypto_rekey_commit(&ctx->crypto_ctx);
466 if (result != CRYPTO_OK) {
467 return SET_ERRNO(ERROR_CRYPTO, "Failed to commit rekey: %s", crypto_result_to_string(result));
468 }
469
470 log_info("Session rekeying completed successfully (initiator side)");
471 return ASCIICHAT_OK;
472}
int send_packet(socket_t sockfd, packet_type_t type, const void *data, size_t len)
Send a basic packet without encryption.
Definition packet.c:754
@ PACKET_TYPE_CRYPTO_REKEY_COMPLETE
Initiator -> Responder: Empty (encrypted with NEW key, but still handshake)
Definition packet.h:340

References ASCIICHAT_OK, crypto_handshake_context_t::crypto_ctx, crypto_encrypt(), crypto_handshake_is_ready(), CRYPTO_OK, crypto_rekey_abort(), crypto_rekey_commit(), crypto_result_to_string(), CRYPTO_SHARED_KEY_SIZE, ERROR_CRYPTO, ERROR_INVALID_STATE, ERROR_NETWORK, crypto_context_t::has_temp_key, log_info, PACKET_TYPE_CRYPTO_REKEY_COMPLETE, crypto_context_t::rekey_in_progress, send_packet(), SET_ERRNO, crypto_context_t::shared_key, and crypto_context_t::temp_shared_key.

Referenced by crypto_client_send_rekey_complete().

◆ crypto_handshake_rekey_request()

asciichat_error_t crypto_handshake_rekey_request ( crypto_handshake_context_t ctx,
socket_t  socket 
)

Send REKEY_REQUEST packet (initiator side)

Parameters
ctxCrypto handshake context (must be ready)
socketSocket to send on
Returns
ASCIICHAT_OK on success, error code on failure

Send REKEY_REQUEST packet (initiator side). Sends the initiator's new ephemeral public key to the peer.

Definition at line 366 of file crypto/handshake/common.c.

366 {
367 if (!ctx || !crypto_handshake_is_ready(ctx)) {
368 return SET_ERRNO(ERROR_INVALID_STATE, "Handshake not ready for rekeying: ctx=%p, ready=%d", ctx,
369 ctx ? crypto_handshake_is_ready(ctx) : 0);
370 }
371
372 // Initialize rekey process (generates new ephemeral keypair)
374 if (result != CRYPTO_OK) {
375 return SET_ERRNO(ERROR_CRYPTO, "Failed to initialize rekey: %s", crypto_result_to_string(result));
376 }
377
378 // Send REKEY_REQUEST with new ephemeral public key (32 bytes)
379 log_info("Sending REKEY_REQUEST with new ephemeral X25519 public key (32 bytes)");
380 int send_result =
382 if (send_result != 0) {
383 crypto_rekey_abort(&ctx->crypto_ctx); // Clean up temp keys on failure
384 return SET_ERRNO(ERROR_NETWORK, "Failed to send REKEY_REQUEST packet");
385 }
386
387 log_debug("REKEY_REQUEST sent successfully, awaiting REKEY_RESPONSE");
388 return ASCIICHAT_OK;
389}
@ PACKET_TYPE_CRYPTO_REKEY_REQUEST
Initiator -> Responder: {new_ephemeral_pk[32]} (UNENCRYPTED during rekey)
Definition packet.h:336
uint8_t temp_public_key[32]

References ASCIICHAT_OK, crypto_handshake_context_t::crypto_ctx, crypto_handshake_is_ready(), CRYPTO_OK, CRYPTO_PUBLIC_KEY_SIZE, crypto_rekey_abort(), crypto_rekey_init(), crypto_result_to_string(), ERROR_CRYPTO, ERROR_INVALID_STATE, ERROR_NETWORK, log_debug, log_info, PACKET_TYPE_CRYPTO_REKEY_REQUEST, send_packet(), SET_ERRNO, and crypto_context_t::temp_public_key.

Referenced by client_send_thread_func(), and crypto_client_initiate_rekey().

◆ crypto_handshake_rekey_response()

asciichat_error_t crypto_handshake_rekey_response ( crypto_handshake_context_t ctx,
socket_t  socket 
)

Send REKEY_RESPONSE packet (responder side)

Parameters
ctxCrypto handshake context (must be ready)
socketSocket to send on
Returns
ASCIICHAT_OK on success, error code on failure

Send REKEY_RESPONSE packet (responder side). Sends the responder's new ephemeral public key to the peer.

Definition at line 395 of file crypto/handshake/common.c.

395 {
396 if (!ctx || !crypto_handshake_is_ready(ctx)) {
397 return SET_ERRNO(ERROR_INVALID_STATE, "Handshake not ready for rekeying: ctx=%p, ready=%d", ctx,
398 ctx ? crypto_handshake_is_ready(ctx) : 0);
399 }
400
402 return SET_ERRNO(ERROR_INVALID_STATE, "No rekey in progress or temp key missing");
403 }
404
405 // Send REKEY_RESPONSE with new ephemeral public key (32 bytes)
406 log_info("Sending REKEY_RESPONSE with new ephemeral X25519 public key (32 bytes)");
407 int send_result =
409 if (send_result != 0) {
410 crypto_rekey_abort(&ctx->crypto_ctx); // Clean up temp keys on failure
411 return SET_ERRNO(ERROR_NETWORK, "Failed to send REKEY_RESPONSE packet");
412 }
413
414 log_debug("REKEY_RESPONSE sent successfully, awaiting REKEY_COMPLETE");
415 return ASCIICHAT_OK;
416}
@ PACKET_TYPE_CRYPTO_REKEY_RESPONSE
Responder -> Initiator: {new_ephemeral_pk[32]} (UNENCRYPTED during rekey)
Definition packet.h:338

References ASCIICHAT_OK, crypto_handshake_context_t::crypto_ctx, crypto_handshake_is_ready(), CRYPTO_PUBLIC_KEY_SIZE, crypto_rekey_abort(), ERROR_INVALID_STATE, ERROR_NETWORK, crypto_context_t::has_temp_key, log_debug, log_info, PACKET_TYPE_CRYPTO_REKEY_RESPONSE, crypto_context_t::rekey_in_progress, send_packet(), SET_ERRNO, and crypto_context_t::temp_public_key.

Referenced by crypto_client_send_rekey_response().

◆ crypto_handshake_set_parameters()

asciichat_error_t crypto_handshake_set_parameters ( crypto_handshake_context_t ctx,
const crypto_parameters_packet_t params 
)

Set crypto parameters from crypto_parameters_packet_t.

Parameters
ctxHandshake context
paramsNegotiated crypto parameters (from capabilities negotiation)
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 48 of file crypto/handshake/common.c.

49 {
50 if (!ctx || !params) {
51 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: ctx=%p, params=%p", ctx, params);
52 }
53
54 // Client receives network byte order and must convert
55 // Server uses host byte order and must NOT convert
56 if (ctx->is_server) {
57 // Server: values are already in host byte order
58 // Update crypto context with negotiated parameters directly
63 } else {
64 // Client: convert from network byte order
65 // Update crypto context with negotiated parameters directly
70 }
71 // Update crypto context with negotiated parameters directly
72 ctx->crypto_ctx.nonce_size = params->nonce_size;
73 ctx->crypto_ctx.mac_size = params->mac_size;
74 ctx->crypto_ctx.hmac_size = params->hmac_size;
76 AUTH_CHALLENGE_SIZE; // Auth challenge size is fixed for now, could be negotiated later
78 (uint8_t)ctx->crypto_ctx.shared_key_size; // Use shared key size as encryption key size
79 ctx->crypto_ctx.private_key_size = ctx->crypto_ctx.public_key_size; // Same as public key for X25519
80 ctx->crypto_ctx.salt_size = ARGON2ID_SALT_SIZE; // Salt size doesn't change
81
82 log_debug("Crypto parameters set: kex_key=%u, auth_key=%u, sig=%u, "
83 "secret=%u, nonce=%u, mac=%u, hmac=%u",
87
88 return ASCIICHAT_OK;
89}
#define NET_TO_HOST_U16(val)
Definition endian.h:116
#define AUTH_CHALLENGE_SIZE
Challenge nonce size (32 bytes)
#define ARGON2ID_SALT_SIZE
Argon2id salt size in bytes.
uint8_t hmac_size
HMAC size in bytes (e.g., 32 for HMAC-SHA256)
Definition packet.h:895
uint16_t auth_public_key_size
Authentication public key size in bytes (e.g., 32 for Ed25519, 1952 for Dilithium3)
Definition packet.h:885
uint16_t signature_size
Signature size in bytes (e.g., 64 for Ed25519, 3309 for Dilithium3)
Definition packet.h:887
uint8_t nonce_size
Nonce size in bytes (e.g., 24 for XSalsa20)
Definition packet.h:891
uint8_t mac_size
MAC size in bytes (e.g., 16 for Poly1305)
Definition packet.h:893
uint16_t shared_secret_size
Shared secret size in bytes (e.g., 32 for X25519)
Definition packet.h:889
uint16_t kex_public_key_size
Key exchange public key size in bytes (e.g., 32 for X25519, 1568 for Kyber1024)
Definition packet.h:883

References ARGON2ID_SALT_SIZE, ASCIICHAT_OK, AUTH_CHALLENGE_SIZE, crypto_context_t::auth_challenge_size, crypto_context_t::auth_public_key_size, crypto_parameters_packet_t::auth_public_key_size, crypto_handshake_context_t::crypto_ctx, crypto_context_t::encryption_key_size, ERROR_INVALID_PARAM, crypto_context_t::hmac_size, crypto_parameters_packet_t::hmac_size, crypto_handshake_context_t::is_server, crypto_parameters_packet_t::kex_public_key_size, log_debug, crypto_context_t::mac_size, crypto_parameters_packet_t::mac_size, NET_TO_HOST_U16, crypto_context_t::nonce_size, crypto_parameters_packet_t::nonce_size, crypto_context_t::private_key_size, crypto_context_t::public_key_size, crypto_context_t::salt_size, SET_ERRNO, crypto_context_t::shared_key_size, crypto_parameters_packet_t::shared_secret_size, crypto_context_t::signature_size, and crypto_parameters_packet_t::signature_size.

Referenced by client_crypto_handshake(), and server_crypto_handshake().

◆ crypto_handshake_should_rekey()

bool crypto_handshake_should_rekey ( const crypto_handshake_context_t ctx)

Check if rekeying should be triggered for this handshake context.

Parameters
ctxCrypto handshake context
Returns
true if rekey should be initiated, false otherwise

Check if rekeying should be triggered for this handshake context. Wrapper around crypto_should_rekey() for handshake context.

Definition at line 613 of file crypto/handshake/common.c.

613 {
614 if (!ctx || !crypto_handshake_is_ready(ctx)) {
615 return false;
616 }
617 return crypto_should_rekey(&ctx->crypto_ctx);
618}
bool crypto_should_rekey(const crypto_context_t *ctx)
Check if rekeying should be triggered based on time or packet count thresholds.

References crypto_handshake_context_t::crypto_ctx, crypto_handshake_is_ready(), and crypto_should_rekey().

Referenced by client_send_thread_func(), and crypto_client_should_rekey().

◆ crypto_handshake_validate_packet_size()

asciichat_error_t crypto_handshake_validate_packet_size ( const crypto_handshake_context_t ctx,
uint16_t  packet_type,
size_t  packet_size 
)

Validate crypto packet size based on session parameters.

Parameters
ctxHandshake context (must have parameters set)
packet_typePacket type to validate
packet_sizeActual packet size received
Returns
ASCIICHAT_OK if valid, error code on failure

Definition at line 92 of file crypto/handshake/common.c.

93 {
94 if (!ctx) {
95 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: ctx=%p", ctx);
96 }
97
98 switch (packet_type) {
100 if (packet_size != sizeof(crypto_capabilities_packet_t)) {
101 // Don't return an error code, just set the errno and return the error code
102 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid crypto capabilities packet size: %zu (expected %zu)",
103 packet_size, sizeof(crypto_capabilities_packet_t));
104 }
105 break;
106
108 if (packet_size != sizeof(crypto_parameters_packet_t)) {
109 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid crypto parameters packet size: %zu (expected %zu)", packet_size,
111 }
112 break;
113
115 // Server can send either:
116 // 1. Simple format: kex_public_key_size (when server has no identity key)
117 // 2. Authenticated format: kex_public_key_size + auth_public_key_size + signature_size
118 {
119 size_t simple_size = ctx->crypto_ctx.public_key_size;
120 size_t authenticated_size =
122
123 if (packet_size != simple_size && packet_size != authenticated_size) {
125 "Invalid KEY_EXCHANGE_INIT size: %zu (expected %zu for simple or %zu for authenticated: "
126 "kex=%u + auth=%u + sig=%u)",
127 packet_size, simple_size, authenticated_size, ctx->crypto_ctx.public_key_size,
129 }
130 }
131 break;
132
134 // Client can send either:
135 // 1. Simple format: kex_public_key_size (when server has no identity key)
136 // 2. Authenticated format: kex_public_key_size + client_auth_key_size + client_sig_size + [gpg_key_id_len:1] +
137 // [gpg_key_id:0-16]
138 {
139 size_t simple_size = ctx->crypto_ctx.public_key_size;
140 // For authenticated format, use Ed25519 sizes since client has Ed25519 key
141 size_t ed25519_auth_size = ED25519_PUBLIC_KEY_SIZE; // Ed25519 public key is always 32 bytes
142 size_t ed25519_sig_size = ED25519_SIGNATURE_SIZE; // Ed25519 signature is always 64 bytes
143 size_t authenticated_min_size = ctx->crypto_ctx.public_key_size + ed25519_auth_size + ed25519_sig_size;
144 size_t authenticated_max_size = authenticated_min_size + 1 + 40; // +1 for length, +40 for max GPG key ID
145
146 if (packet_size != simple_size &&
147 (packet_size < authenticated_min_size || packet_size > authenticated_max_size)) {
149 "Invalid KEY_EXCHANGE_RESP size: %zu (expected %zu for simple or %zu-%zu for authenticated: "
150 "kex=%u + auth=%u + sig=%u + optional GPG key ID)",
151 packet_size, simple_size, authenticated_min_size, authenticated_max_size,
152 ctx->crypto_ctx.public_key_size, ed25519_auth_size, ed25519_sig_size);
153 }
154 }
155 break;
156
158 // Server sends: 1 byte auth_flags + auth_challenge_size byte nonce
159 {
160 size_t expected_size = AUTH_CHALLENGE_FLAGS_SIZE + ctx->crypto_ctx.auth_challenge_size;
161 if (packet_size != expected_size) {
162 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid AUTH_CHALLENGE size: %zu (expected %zu: flags=%d + nonce=%u)",
163 packet_size, expected_size, AUTH_CHALLENGE_FLAGS_SIZE, ctx->crypto_ctx.auth_challenge_size);
164 }
165 }
166 break;
167
169 // Client sends: hmac_size + auth_challenge_size bytes client_nonce + [gpg_key_id_len:1] + [gpg_key_id:0-40]
170 {
171 size_t min_size = ctx->crypto_ctx.hmac_size + ctx->crypto_ctx.auth_challenge_size;
172 size_t max_size = min_size + 1 + 40; // +1 for length, +40 for max GPG key ID
173 if (packet_size < min_size || packet_size > max_size) {
175 "Invalid AUTH_RESPONSE size: %zu (expected %zu-%zu: hmac=%u + "
176 "nonce=%u + optional GPG key ID)",
177 packet_size, min_size, max_size, ctx->crypto_ctx.hmac_size,
179 }
180 }
181 break;
182
184 // Variable size - just check reasonable limits
185 if (packet_size > MAX_AUTH_FAILED_PACKET_SIZE) {
186 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid AUTH_FAILED size: %zu (max %d)", packet_size,
188 }
189 break;
190
192 // Server sends: hmac_size bytes
193 if (packet_size != ctx->crypto_ctx.hmac_size) {
194 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid SERVER_AUTH_RESP size: %zu (expected %u)", packet_size,
195 ctx->crypto_ctx.hmac_size);
196 }
197 break;
198
200 // Empty packet
201 if (packet_size != 0) {
202 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid HANDSHAKE_COMPLETE size: %zu (expected 0)", packet_size);
203 }
204 break;
205
207 // Empty packet
208 if (packet_size != 0) {
209 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid NO_ENCRYPTION size: %zu (expected 0)", packet_size);
210 }
211 break;
212
214 // Variable size - check reasonable limits
215 if (packet_size > MAX_ENCRYPTED_PACKET_SIZE) { // 64KB max for encrypted packets
216 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid ENCRYPTED size: %zu (max %d)", packet_size,
218 }
219 break;
220
221 default:
222 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Unknown crypto packet type: %u", packet_type);
223 }
224
225 return ASCIICHAT_OK;
226}
#define ED25519_SIGNATURE_SIZE
Ed25519 signature size in bytes.
#define MAX_AUTH_FAILED_PACKET_SIZE
Maximum AUTH_FAILED packet size (256 bytes)
#define MAX_ENCRYPTED_PACKET_SIZE
Maximum encrypted packet size (64KB)
#define ED25519_PUBLIC_KEY_SIZE
Ed25519 public key size in bytes.
#define AUTH_CHALLENGE_FLAGS_SIZE
Authentication flags size (1 byte)
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:73
@ PACKET_TYPE_CRYPTO_AUTH_RESPONSE
Client -> Server: {HMAC[32]} (UNENCRYPTED)
Definition packet.h:323
@ PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE
Server -> Client: "encryption ready" (UNENCRYPTED)
Definition packet.h:329
@ PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT
Server -> Client: {server_pubkey[32]} (UNENCRYPTED)
Definition packet.h:317
@ PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP
Client -> Server: {client_pubkey[32]} (UNENCRYPTED)
Definition packet.h:319
@ PACKET_TYPE_CRYPTO_AUTH_FAILED
Server -> Client: "authentication failed" (UNENCRYPTED)
Definition packet.h:325
@ PACKET_TYPE_ENCRYPTED
Encrypted packet (after handshake completion)
Definition packet.h:333
@ PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP
Server -> Client: {HMAC[32]} server proves knowledge (UNENCRYPTED)
Definition packet.h:327
@ PACKET_TYPE_CRYPTO_NO_ENCRYPTION
Client -> Server: "I want to proceed without encryption" (UNENCRYPTED)
Definition packet.h:331
@ PACKET_TYPE_CRYPTO_AUTH_CHALLENGE
Server -> Client: {nonce[32]} (UNENCRYPTED)
Definition packet.h:321
@ PACKET_TYPE_CRYPTO_PARAMETERS
Server -> Client: Chosen algorithms + data sizes (UNENCRYPTED)
Definition packet.h:315
@ PACKET_TYPE_CRYPTO_CAPABILITIES
Client -> Server: Supported crypto algorithms (UNENCRYPTED)
Definition packet.h:313
Crypto capabilities packet structure (Packet Type 14)
Definition packet.h:844
Crypto parameters packet structure (Packet Type 15)
Definition packet.h:873

References ASCIICHAT_OK, AUTH_CHALLENGE_FLAGS_SIZE, crypto_context_t::auth_challenge_size, crypto_context_t::auth_public_key_size, crypto_handshake_context_t::crypto_ctx, ED25519_PUBLIC_KEY_SIZE, ED25519_SIGNATURE_SIZE, ERROR_INVALID_PARAM, ERROR_NETWORK_PROTOCOL, crypto_context_t::hmac_size, MAX_AUTH_FAILED_PACKET_SIZE, MAX_ENCRYPTED_PACKET_SIZE, PACKET_TYPE_CRYPTO_AUTH_CHALLENGE, PACKET_TYPE_CRYPTO_AUTH_FAILED, PACKET_TYPE_CRYPTO_AUTH_RESPONSE, PACKET_TYPE_CRYPTO_CAPABILITIES, PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE, PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT, PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP, PACKET_TYPE_CRYPTO_NO_ENCRYPTION, PACKET_TYPE_CRYPTO_PARAMETERS, PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP, PACKET_TYPE_ENCRYPTED, crypto_context_t::public_key_size, SET_ERRNO, and crypto_context_t::signature_size.

Referenced by crypto_handshake_client_auth_response(), crypto_handshake_client_key_exchange(), crypto_handshake_server_auth_challenge(), and crypto_handshake_server_complete().