ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
server.h File Reference

Server-side handshake functions. More...

Go to the source code of this file.

Functions

Server Handshake Protocol
asciichat_error_t crypto_handshake_server_start (crypto_handshake_context_t *ctx, acip_transport_t *transport)
 Server: Start crypto handshake by sending public key.
asciichat_error_t crypto_handshake_server_send_parameters (crypto_handshake_context_t *ctx, acip_transport_t *transport)
 Server: Send CRYPTO_PARAMETERS and set handshake context sizes.
asciichat_error_t crypto_handshake_server_auth_challenge (crypto_handshake_context_t *ctx, acip_transport_t *transport, packet_type_t packet_type, const uint8_t *payload, size_t payload_len)
 Server: Process client's public key and send auth challenge.
asciichat_error_t crypto_handshake_server_complete (crypto_handshake_context_t *ctx, acip_transport_t *transport, packet_type_t packet_type, const uint8_t *payload, size_t payload_len)
 Server: Process auth response and complete handshake.

Detailed Description

Server-side handshake functions.

Definition in file include/ascii-chat/crypto/handshake/server.h.

Function Documentation

◆ crypto_handshake_server_auth_challenge()

asciichat_error_t crypto_handshake_server_auth_challenge ( crypto_handshake_context_t * ctx,
acip_transport_t * transport,
packet_type_t packet_type,
const uint8_t * payload,
size_t payload_len )

Server: Process client's public key and send auth challenge.

Parameters
ctxHandshake context (must be in CRYPTO_HANDSHAKE_KEY_EXCHANGE state)
transportACIP transport to send on
packet_typePacket type received (should be PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP or PACKET_TYPE_CRYPTO_NO_ENCRYPTION)
payloadReceived packet payload
payload_lenLength of received payload
Returns
ASCIICHAT_OK on success, error code on failure

Server processes client's KEY_EXCHANGE_RESP packet and sends AUTH_CHALLENGE. Computes shared secret and generates authentication challenge nonce.

Note
Packet must be received by ACIP handler before calling this function
State transition: CRYPTO_HANDSHAKE_KEY_EXCHANGE -> CRYPTO_HANDSHAKE_AUTHENTICATING

Definition at line 173 of file lib/crypto/handshake/server.c.

175 {
176 ASCII_OTEL_SCOPE(CRYPTO_HANDSHAKE_SERVER_AUTH_CHALLENGE);
177 if (!ctx || ctx->state != CRYPTO_HANDSHAKE_KEY_EXCHANGE) {
178 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid state: ctx=%p, state=%d", ctx, ctx ? ctx->state : -1);
179 }
180 if (!transport) {
181 return SET_ERRNO(ERROR_INVALID_PARAM, "transport is NULL");
182 }
183
184 // Note: Packet already received by ACIP handler
185 int result;
186
187 // Check if client sent NO_ENCRYPTION response
188 if (packet_type == PACKET_TYPE_CRYPTO_NO_ENCRYPTION) {
189
190 // Send AUTH_FAILED to inform client (though they already know)
191 auth_failure_packet_t failure = {0};
192 failure.reason_flags = 0; // No specific auth failure, just encryption mismatch
193 int send_result =
194 packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_AUTH_FAILED, &failure, sizeof(failure), 0);
195 if (send_result != 0) {
196 return SET_ERRNO(ERROR_NETWORK, "Failed to send AUTH_FAILED packet");
197 }
198
199 return SET_ERRNO(ERROR_CRYPTO, "SECURITY: Client sent NO_ENCRYPTION response - encryption mode "
200 "mismatch. Server requires encryption, but "
201 "client has --no-encrypt. Use matching encryption settings on "
202 "both client and server");
203 }
204
205 // Verify packet type
206 if (packet_type != PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP) {
207 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Expected KEY_EXCHANGE_RESPONSE, got packet type %d", packet_type);
208 }
209
210 // Verify payload size - client can send either simple or authenticated format
211 // Simple: kex_public_key_size bytes
212 // Authenticated: public_key_size + client_auth_key_size + client_sig_size bytes
213 size_t simple_size = ctx->crypto_ctx.public_key_size;
214 // Ed25519 public key is always 32 bytes
215 // Ed25519 signature is always 64 bytes
217
218 bool client_sent_identity = false;
219 const size_t identity_size = ED25519_PUBLIC_KEY_SIZE;
220 const size_t signature_size = ED25519_SIGNATURE_SIZE;
221 SAFE_MALLOC_DEFER_FREE(client_ephemeral_key, ctx->crypto_ctx.public_key_size, uint8_t *);
222 SAFE_MALLOC_DEFER_FREE(client_identity_key, identity_size, uint8_t *);
223 SAFE_MALLOC_DEFER_FREE(client_signature, signature_size, uint8_t *);
224
225 if (!client_ephemeral_key || !client_identity_key || !client_signature) {
226 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate memory for client keys");
227 }
228
229 // Validate packet size using session parameters
230 asciichat_error_t validation_result =
232 if (validation_result != ASCIICHAT_OK) {
233 // Payload ownership remains with caller
234
235 return validation_result;
236 }
237
238 // Handle both authenticated and non-authenticated responses
239 // authenticated_size is now a minimum - packet may be larger with GPG key ID
240 if (payload_len >= authenticated_size) {
241 // Authenticated format (may have optional GPG key ID):
242 // [ephemeral:kex_size][identity:auth_size][signature:sig_size][gpg_key_id_len:1][gpg_key_id:0-16]
243 memcpy(client_ephemeral_key, payload, ctx->crypto_ctx.public_key_size);
244 memcpy(client_identity_key, payload + ctx->crypto_ctx.public_key_size, ED25519_PUBLIC_KEY_SIZE);
245 memcpy(client_signature, payload + ctx->crypto_ctx.public_key_size + ED25519_PUBLIC_KEY_SIZE,
247 client_sent_identity = true;
248 ctx->client_sent_identity = true;
249
250 // Extract GPG key ID if present
251 const char *client_gpg_key_id = NULL;
252 char gpg_key_id_buffer[GPG_FINGERPRINT_HEX_BUFFER_SIZE] = {0};
254 if (payload_len > gpg_offset) {
255 uint8_t gpg_key_id_len = payload[gpg_offset];
256 if (gpg_key_id_len > 0 && gpg_key_id_len <= 40 && payload_len >= gpg_offset + 1 + gpg_key_id_len) {
257 memcpy(gpg_key_id_buffer, payload + gpg_offset + 1, gpg_key_id_len);
258 gpg_key_id_buffer[gpg_key_id_len] = '\0';
259 client_gpg_key_id = gpg_key_id_buffer;
260 log_debug("Extracted client GPG key ID from KEY_EXCHANGE_RESPONSE: %s", client_gpg_key_id);
261 }
262 }
263
264 // Check if client sent a null identity key (all zeros)
265 bool client_has_null_identity = true;
266 for (size_t i = 0; i < ED25519_PUBLIC_KEY_SIZE; i++) {
267 if (client_identity_key[i] != 0) {
268 client_has_null_identity = false;
269 break;
270 }
271 }
272
273 if (client_has_null_identity) {
274 // Client has no identity key - this is allowed for servers without client authentication
275 log_debug("Client sent null identity key - no client authentication required");
276 client_sent_identity = false;
277 ctx->client_sent_identity = false;
278 NOTICE(WARNING, "UNVERIFIED CLIENT IDENTITY", "Client connected without identity authentication");
279 } else {
280 // Client has a real identity key
281 // If server didn't specify --client-keys, skip signature verification
282 // (server doesn't care about client identity verification)
283 if (!ctx->require_client_auth) {
284 log_info("Skipping client signature verification (no --client-keys specified)");
285 NOTICE(WARNING, "UNVERIFIED CLIENT IDENTITY", "Connection is encrypted but client identity is NOT verified");
286 } else {
287 // Verify client's signature
288 log_debug("Verifying client's signature");
289 // Pass client's GPG key ID if available
290 if (ed25519_verify_signature(client_identity_key, client_ephemeral_key, ctx->crypto_ctx.public_key_size,
291 client_signature, client_gpg_key_id) != 0) {
292 // Send AUTH_FAILED with specific reason
293 auth_failure_packet_t failure = {0};
295 int send_result =
296 packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_AUTH_FAILED, &failure, sizeof(failure), 0);
297 if (send_result != 0) {
298 return SET_ERRNO(ERROR_NETWORK, "Failed to send AUTH_FAILED packet");
299 }
300
301 return SET_ERRNO(ERROR_CRYPTO, "Client signature verification FAILED - rejecting connection");
302 }
303 }
304 }
305
306 // Store the verified client identity for whitelist checking (only if client has identity)
307 if (client_sent_identity) {
309 memcpy(ctx->client_ed25519_key.key, client_identity_key, ctx->crypto_ctx.public_key_size);
310 }
311 } else if (payload_len == simple_size) {
312 // Non-authenticated format: [ephemeral:public_key_size] only
313 log_debug("Client sent non-authenticated response (%zu bytes)", payload_len);
314 memcpy(client_ephemeral_key, payload, ctx->crypto_ctx.public_key_size);
315 client_sent_identity = false;
316 ctx->client_sent_identity = false;
317 NOTICE(WARNING, "UNVERIFIED CLIENT IDENTITY", "Client connected without identity authentication");
318 } else {
319 // Payload ownership remains with caller
320
322 "Invalid client key response size: %zu bytes (expected %zu for "
323 "authenticated or %zu for simple)",
324 payload_len, authenticated_size, simple_size);
325 }
326
327 // Extract pointers for compatibility with existing code
328 const uint8_t *client_x25519 = client_ephemeral_key;
329 const uint8_t *client_ed25519 = client_sent_identity ? client_identity_key : NULL;
330
331 // Check client Ed25519 key against whitelist if client provided one and
332 // whitelist is enabled
333 if (client_sent_identity && ctx->require_client_auth && ctx->client_whitelist && ctx->num_whitelisted_clients > 0) {
334 bool key_found = false;
335
336 // Debug: print client's Ed25519 identity key
337 char client_ed25519_hex[HEX_STRING_SIZE_32];
338 for (int i = 0; i < ED25519_PUBLIC_KEY_SIZE; i++) {
339 safe_snprintf(client_ed25519_hex + i * 2, 3, "%02x", client_ed25519[i]);
340 }
341 log_debug("Client Ed25519 identity key: %s", client_ed25519_hex);
342
343 // Compare against whitelist (direct Ed25519 comparison - no conversion!)
344 for (size_t i = 0; i < ctx->num_whitelisted_clients; i++) {
345 // Debug: print whitelist Ed25519 key
346 char whitelist_ed25519_hex[HEX_STRING_SIZE_32];
347 for (int j = 0; j < ED25519_PUBLIC_KEY_SIZE; j++) {
348 safe_snprintf(whitelist_ed25519_hex + j * 2, 3, "%02x", ctx->client_whitelist[i].key[j]);
349 }
350 log_debug("Whitelist[%zu] Ed25519 key: %s", i, whitelist_ed25519_hex);
351
352 // Direct comparison of Ed25519 keys (constant-time to prevent timing
353 // attacks)
354 if (sodium_memcmp(client_ed25519, ctx->client_whitelist[i].key, ED25519_PUBLIC_KEY_SIZE) == 0) {
355 key_found = true;
356 ctx->client_ed25519_key_verified = true;
357
358 // Store the client's Ed25519 key for signature verification
359 memcpy(&ctx->client_ed25519_key, &ctx->client_whitelist[i], sizeof(public_key_t));
360
361 log_debug("Client Ed25519 key authorized (whitelist entry %zu)", i);
362 if (strlen(ctx->client_whitelist[i].comment) > 0) {
363 log_info("Client identity: %s", ctx->client_whitelist[i].comment);
364 }
365 break;
366 }
367 }
368
369 if (!key_found) {
370 SET_ERRNO(ERROR_CRYPTO_AUTH, "Client Ed25519 key not in whitelist - rejecting connection");
371 // Don't send AUTH_FAILED here - wait until server_complete
372 // Just mark that the key was rejected
373 ctx->client_ed25519_key_verified = false;
374 }
375 } else if (client_sent_identity) {
376 // No whitelist checking - just store the client's Ed25519 key for later
377 // (Already stored at line 313-314, but keep this for clarity)
378 // Discovery can require proof of identity without restricting which identities may join.
379 // require_client_auth ensured that the signature was verified above.
381 }
382
383 // Set peer's X25519 encryption key - this also derives the shared secret
384 crypto_result_t crypto_result = crypto_set_peer_public_key(&ctx->crypto_ctx, client_x25519);
385 if (crypto_result != CRYPTO_OK) {
386 return SET_ERRNO(ERROR_CRYPTO, "Failed to set peer public key and derive shared secret: %s",
387 crypto_result_to_string(crypto_result));
388 }
389
390 // Do authentication challenge if client provided identity key OR server
391 // requires password
392 if (client_sent_identity || ctx->crypto_ctx.has_password || ctx->require_client_auth) {
393 // Generate nonce and store it in the context
394 crypto_result = crypto_generate_nonce(ctx->crypto_ctx.auth_nonce);
395 if (crypto_result != CRYPTO_OK) {
396 return SET_ERRNO(ERROR_CRYPTO, "Failed to generate nonce: %s", crypto_result_to_string(crypto_result));
397 }
398
399 // Prepare AUTH_CHALLENGE packet: 1 byte flags + auth_challenge_size byte nonce
400 size_t challenge_packet_size = AUTH_CHALLENGE_FLAGS_SIZE + ctx->crypto_ctx.auth_challenge_size;
401 uint8_t challenge_packet[1 + HMAC_SHA256_SIZE]; // Maximum size buffer
402 uint8_t auth_flags = 0;
403
404 // Set flags based on server requirements
405 if (ctx->crypto_ctx.has_password) {
406 auth_flags |= AUTH_REQUIRE_PASSWORD;
407 }
408 if (ctx->require_client_auth) {
409 auth_flags |= AUTH_REQUIRE_CLIENT_KEY;
410 }
411
412 challenge_packet[0] = auth_flags;
413 memcpy(challenge_packet + 1, ctx->crypto_ctx.auth_nonce, ctx->crypto_ctx.auth_challenge_size);
414
415 // Send AUTH_CHALLENGE with flags + nonce (challenge_packet_size bytes)
416 result = packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_AUTH_CHALLENGE, challenge_packet,
417 challenge_packet_size, 0);
418 if (result != 0) {
419 return SET_ERRNO(ERROR_NETWORK, "Failed to send AUTH_CHALLENGE packet");
420 }
421
423 } else {
424 // No authentication needed - skip to completion
425 log_debug("Skipping authentication (no password and client has no identity key)");
426
427 // Send HANDSHAKE_COMPLETE immediately
429 if (result != 0) {
430 return SET_ERRNO(ERROR_NETWORK, "Failed to send HANDSHAKE_COMPLETE packet");
431 }
432
434 ctx->crypto_ctx.handshake_complete = true; // Mark crypto context as ready for rekeying
435 log_debug("Crypto handshake completed successfully (no authentication)");
436 }
437
438 return ASCIICHAT_OK;
439}
#define SET_ERRNO(code,...)
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.
@ CRYPTO_HANDSHAKE_AUTHENTICATING
@ CRYPTO_HANDSHAKE_KEY_EXCHANGE
@ CRYPTO_HANDSHAKE_READY
#define AUTH_REQUIRE_PASSWORD
Server requires password authentication.
#define AUTH_REQUIRE_CLIENT_KEY
Server requires client key authentication (whitelist).
#define SAFE_MALLOC_DEFER_FREE(name, size, cast)
Definition common.h:386
unsigned char uint8_t
Definition common.h:60
crypto_result_t crypto_set_peer_public_key(crypto_context_t *ctx, const uint8_t *peer_public_key)
Set peer's public key and compute shared secret (step 2 of handshake).
const char * crypto_result_to_string(crypto_result_t result)
Convert crypto result to human-readable string.
crypto_result_t
Cryptographic operation result codes.
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_INVALID_STATE
@ ERROR_NETWORK
Definition error_codes.h:72
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:76
@ ERROR_MEMORY
Definition error_codes.h:51
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_CRYPTO_AUTH
Definition error_codes.h:95
@ ERROR_CRYPTO
Definition error_codes.h:93
@ ERROR_INVALID_PARAM
uint8_t key[CRYPTO_PUBLIC_KEY_SIZE]
Definition key_types.h:74
char comment[MAX_COMMENT_LEN]
Definition key_types.h:75
key_type_t type
Definition key_types.h:73
@ KEY_TYPE_ED25519
Definition key_types.h:54
#define log_info(...)
Log an INFO message.
Definition log/log.h:608
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:595
@ AUTH_FAIL_SIGNATURE_INVALID
Client signature verification failed (invalid signature).
Definition packet.h:811
@ PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE
Server -> Client: "encryption ready" (UNENCRYPTED).
Definition packet.h:338
@ PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP
Client -> Server: {client_pubkey[32]} (UNENCRYPTED).
Definition packet.h:328
@ PACKET_TYPE_CRYPTO_AUTH_FAILED
Server -> Client: "authentication failed" (UNENCRYPTED).
Definition packet.h:334
@ PACKET_TYPE_CRYPTO_NO_ENCRYPTION
Client -> Server: "I want to proceed without encryption" (UNENCRYPTED).
Definition packet.h:340
@ PACKET_TYPE_CRYPTO_AUTH_CHALLENGE
Server -> Client: {nonce[32]} (UNENCRYPTED).
Definition packet.h:330
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Platform-safe snprintf wrapper.
crypto_result_t crypto_generate_nonce(uint8_t nonce[AUTH_CHALLENGE_SIZE])
#define NOTICE(severity, title,...)
Definition notice.h:68
#define ASCII_OTEL_SCOPE(id)
Definition otel.h:72
asciichat_error_t packet_send_via_transport(acip_transport_t *transport, packet_type_t type, const void *payload, size_t payload_len, uint32_t client_id)
Definition send.c:190
#define ED25519_SIGNATURE_SIZE
Ed25519 signature size in bytes.
Definition sizes.h:37
#define HMAC_SHA256_SIZE
HMAC-SHA256 output size in bytes.
Definition sizes.h:43
#define GPG_FINGERPRINT_HEX_BUFFER_SIZE
Definition sizes.h:168
#define ED25519_PUBLIC_KEY_SIZE
Ed25519 public key size in bytes.
Definition sizes.h:33
#define HEX_STRING_SIZE_32
Hex string size for 32-byte values (64 hex chars + null terminator).
Definition sizes.h:154
#define AUTH_CHALLENGE_FLAGS_SIZE
Authentication flags size (1 byte).
Definition sizes.h:115
asciichat_error_t ed25519_verify_signature(const uint8_t public_key[ED25519_PUBLIC_KEY_SIZE], const uint8_t *message, size_t message_len, const uint8_t signature[ED25519_SIGNATURE_SIZE], const char *gpg_key_id)
Definition ssh_keys.c:1235
Authentication failure packet structure.
Definition packet.h:822
uint8_t reason_flags
Bitmask of auth_failure_reason_t values indicating failure causes.
Definition packet.h:824
crypto_handshake_state_t state
bool allow_unlisted_client_identity
Require proof of key possession without whitelist membership (discovery).
The normalized public identity used by ascii-chat's crypto and key-management code.
Definition key_types.h:72

References crypto_handshake_context_t::allow_unlisted_client_identity, ASCII_OTEL_SCOPE, ASCIICHAT_OK, AUTH_CHALLENGE_FLAGS_SIZE, crypto_context_t::auth_challenge_size, AUTH_FAIL_SIGNATURE_INVALID, crypto_context_t::auth_nonce, AUTH_REQUIRE_CLIENT_KEY, AUTH_REQUIRE_PASSWORD, crypto_handshake_context_t::client_ed25519_key, crypto_handshake_context_t::client_ed25519_key_verified, crypto_handshake_context_t::client_sent_identity, crypto_handshake_context_t::client_whitelist, public_key_t::comment, crypto_handshake_context_t::crypto_ctx, crypto_generate_nonce(), CRYPTO_HANDSHAKE_AUTHENTICATING, CRYPTO_HANDSHAKE_KEY_EXCHANGE, CRYPTO_HANDSHAKE_READY, crypto_handshake_validate_packet_size(), CRYPTO_OK, crypto_result_to_string(), crypto_set_peer_public_key(), ED25519_PUBLIC_KEY_SIZE, ED25519_SIGNATURE_SIZE, ed25519_verify_signature(), ERROR_CRYPTO, ERROR_CRYPTO_AUTH, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, ERROR_MEMORY, ERROR_NETWORK, ERROR_NETWORK_PROTOCOL, GPG_FINGERPRINT_HEX_BUFFER_SIZE, crypto_context_t::handshake_complete, crypto_context_t::has_password, HEX_STRING_SIZE_32, HMAC_SHA256_SIZE, public_key_t::key, KEY_TYPE_ED25519, log_debug, log_info, NOTICE, crypto_handshake_context_t::num_whitelisted_clients, packet_send_via_transport(), PACKET_TYPE_CRYPTO_AUTH_CHALLENGE, PACKET_TYPE_CRYPTO_AUTH_FAILED, PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE, PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP, PACKET_TYPE_CRYPTO_NO_ENCRYPTION, crypto_context_t::public_key_size, auth_failure_packet_t::reason_flags, crypto_handshake_context_t::require_client_auth, SAFE_MALLOC_DEFER_FREE, safe_snprintf(), SET_ERRNO, crypto_handshake_context_t::state, and public_key_t::type.

Referenced by acip_security_receive(), and network_negotiation_receive().

◆ crypto_handshake_server_complete()

asciichat_error_t crypto_handshake_server_complete ( crypto_handshake_context_t * ctx,
acip_transport_t * transport,
packet_type_t packet_type,
const uint8_t * payload,
size_t payload_len )

Server: Process auth response and complete handshake.

Parameters
ctxHandshake context (must be in CRYPTO_HANDSHAKE_AUTHENTICATING state)
transportACIP transport to send on
packet_typePacket type received (should be PACKET_TYPE_CRYPTO_AUTH_RESPONSE)
payloadReceived packet payload
payload_lenLength of received payload
Returns
ASCIICHAT_OK on success, error code on failure

Server processes client's AUTH_RESPONSE packet and sends SERVER_AUTH_RESP. Verifies authentication HMAC or signature and completes handshake.

Note
Packet must be received by ACIP handler before calling this function
State transition: CRYPTO_HANDSHAKE_AUTHENTICATING -> CRYPTO_HANDSHAKE_READY

Definition at line 441 of file lib/crypto/handshake/server.c.

443 {
444 ASCII_OTEL_SCOPE(CRYPTO_HANDSHAKE_SERVER_COMPLETE);
445 if (!ctx || ctx->state != CRYPTO_HANDSHAKE_AUTHENTICATING) {
446 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid state: ctx=%p, state=%d", ctx, ctx ? ctx->state : -1);
447 }
448 if (!transport) {
449 return SET_ERRNO(ERROR_INVALID_PARAM, "transport is NULL");
450 }
451
452 // Note: Packet already received by ACIP handler
453 int result;
454
455 // Verify packet type
456 if (packet_type != PACKET_TYPE_CRYPTO_AUTH_RESPONSE) {
457 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Expected AUTH_RESPONSE, got packet type %d", packet_type);
458 }
459
460 // Verify password if required
461 if (ctx->crypto_ctx.has_password) {
462 // Validate packet size using session parameters
463 asciichat_error_t validation_result =
465 if (validation_result != ASCIICHAT_OK) {
466 return validation_result;
467 }
468
469 // Ensure shared secret is derived before password verification
470 // This is critical for password HMAC verification which binds to the shared secret
472 SET_ERRNO(ERROR_CRYPTO, "Password authentication failed - key exchange not complete");
473
474 // Send AUTH_FAILED with specific reason
475 auth_failure_packet_t failure = {0};
477 if (ctx->require_client_auth) {
479 }
480 packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_AUTH_FAILED, &failure, sizeof(failure), 0);
481 return ERROR_NETWORK;
482 }
483
484 // Verify password HMAC (binds to DH shared_secret to prevent MITM)
485 log_debug("Verifying password HMAC: has_password=%d, key_exchange_complete=%d", ctx->crypto_ctx.has_password,
487 if (!payload) {
488 SET_ERRNO(ERROR_INVALID_PARAM, "Payload is NULL in password authentication");
489 return ERROR_CRYPTO;
490 }
491 if (!crypto_verify_auth_response(&ctx->crypto_ctx, ctx->crypto_ctx.auth_nonce, payload)) {
492 log_debug("Password HMAC verification failed");
493 // Enhanced error message when both password and whitelist are required
494 if (ctx->require_client_auth) {
496 "Password authentication failed - incorrect password (server also requires whitelisted client key)");
497 } else {
498 SET_ERRNO(ERROR_CRYPTO, "Password authentication failed - incorrect password");
499 }
500
501 // Send AUTH_FAILED with specific reason
502 auth_failure_packet_t failure = {0};
504 if (ctx->require_client_auth) {
506 }
507 packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_AUTH_FAILED, &failure, sizeof(failure), 0);
508 return ERROR_NETWORK;
509 }
510
511 // Extract client challenge nonce for mutual authentication
512 // Use ctx->crypto_ctx.hmac_size and ctx->crypto_ctx.auth_challenge_size (negotiated during handshake)
514 log_info("Password authentication successful");
515 } else {
516 // Ed25519 signature auth (payload format: signature + client_nonce + gpg_key_id_len + gpg_key_id)
517 size_t expected_min_signature_size =
518 ctx->crypto_ctx.signature_size + ctx->crypto_ctx.auth_challenge_size + 1; // +1 for gpg_key_id_len byte
519 size_t expected_password_size = ctx->crypto_ctx.hmac_size + ctx->crypto_ctx.auth_challenge_size;
520 if (!payload) {
521 SET_ERRNO(ERROR_INVALID_PARAM, "Payload is NULL in signature authentication");
522 return ERROR_CRYPTO;
523 }
524 if (payload_len >= expected_min_signature_size) {
525 // Signature + client nonce + optional GPG key ID - VERIFY the signature on the challenge nonce
526 const uint8_t *signature = payload;
527 const uint8_t *client_nonce = payload + ctx->crypto_ctx.signature_size;
528
529 // Extract GPG key ID if present
530 size_t gpg_offset = ctx->crypto_ctx.signature_size + ctx->crypto_ctx.auth_challenge_size;
531 uint8_t gpg_key_id_len = payload[gpg_offset];
532 const char *client_gpg_key_id = NULL;
533 char gpg_key_id_buffer[GPG_FINGERPRINT_HEX_BUFFER_SIZE] = {0};
534
535 if (gpg_key_id_len > 0 && gpg_key_id_len <= 40) {
536 // Validate packet has enough bytes for GPG key ID
537 if (payload_len >= gpg_offset + 1 + gpg_key_id_len) {
538 memcpy(gpg_key_id_buffer, payload + gpg_offset + 1, gpg_key_id_len);
539 gpg_key_id_buffer[gpg_key_id_len] = '\0';
540 client_gpg_key_id = gpg_key_id_buffer;
541 log_debug("Extracted client GPG key ID from AUTH_RESPONSE: %s", client_gpg_key_id);
542 }
543 }
544
545 // Actually verify the Ed25519/GPG signature on the challenge nonce
546 // This was missing, allowing authentication bypass
548 // Use unified verification function that handles both Ed25519 and GPG keys
549 // This matches the KEY_EXCHANGE verification path
550 log_debug("Verifying %s signature on challenge nonce",
551 ctx->client_ed25519_key.type == KEY_TYPE_GPG ? "GPG" : "Ed25519");
552
555 client_gpg_key_id // GPG key ID for fallback verification
556 );
557
558 if (verify_result != ASCIICHAT_OK) {
559 auth_failure_packet_t failure = {0};
561 SET_ERRNO(ERROR_CRYPTO_AUTH, "%s signature verification failed on challenge nonce",
562 ctx->client_ed25519_key.type == KEY_TYPE_GPG ? "GPG" : "Ed25519");
563 packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_AUTH_FAILED, &failure, sizeof(failure), 0);
564 return ERROR_CRYPTO_AUTH;
565 }
566 log_debug("%s signature on challenge nonce verified successfully",
567 ctx->client_ed25519_key.type == KEY_TYPE_GPG ? "GPG" : "Ed25519");
568 }
569
570 memcpy(ctx->client_challenge_nonce, client_nonce, ctx->crypto_ctx.auth_challenge_size);
571 } else if (payload_len == expected_password_size) {
572 // Just client nonce (legacy or password-only mode without password enabled)
573 // Use ctx->crypto_ctx.hmac_size and ctx->crypto_ctx.auth_challenge_size (negotiated during handshake)
575 } else {
576 // Validate packet size using session parameters
577 asciichat_error_t validation_result =
579 if (validation_result != ASCIICHAT_OK) {
580 return validation_result;
581 }
582 }
583 }
584
585 // Verify client key if required (whitelist)
586 if (ctx->require_client_auth) {
587 if (!ctx->client_ed25519_key_verified) {
588 // Send AUTH_FAILED with specific reason
589 auth_failure_packet_t failure = {0};
590
591 // Check if client provided a key but it wasn't in whitelist
592 if (ctx->client_sent_identity) {
593 SET_ERRNO(ERROR_CRYPTO_AUTH, "Client key authentication failed - your key is not in the server's whitelist");
595 } else {
596 SET_ERRNO(ERROR_CRYPTO_AUTH, "Client key authentication failed - client did not provide a key");
598 }
599
600 if (ctx->crypto_ctx.has_password) {
601 // Password was verified, but key was not
602 SET_ERRNO(ERROR_CRYPTO_AUTH, "Note: Password was correct, but client key is required");
603 }
604 packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_AUTH_FAILED, &failure, sizeof(failure), 0);
605 return ERROR_NETWORK;
606 }
607 log_info("Client key authentication successful (whitelist verified)");
608 if (strlen(ctx->client_ed25519_key.comment) > 0) {
609 log_info("Authenticated client: %s", ctx->client_ed25519_key.comment);
610 }
611 }
612
613 // Send SERVER_AUTH_RESPONSE with server's HMAC for mutual authentication
614 // Bind to DH shared_secret to prevent MITM (even if attacker knows password)
615 // Allocate buffer using negotiated hmac_size (should match AUTH_HMAC_SIZE)
616 uint8_t server_hmac[HMAC_SHA256_SIZE]; // Maximum size, actual size is ctx->hmac_size
617 crypto_result_t crypto_result =
619 if (crypto_result != CRYPTO_OK) {
620 SET_ERRNO(ERROR_CRYPTO, "Failed to compute server HMAC for mutual authentication: %s",
621 crypto_result_to_string(crypto_result));
622 return ERROR_NETWORK;
623 }
624
625 log_debug("Sending SERVER_AUTH_RESPONSE packet with server HMAC (%u bytes) "
626 "for mutual authentication",
627 ctx->crypto_ctx.hmac_size);
628 result = packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP, server_hmac,
629 ctx->crypto_ctx.hmac_size, 0);
630 if (result != ASCIICHAT_OK) {
631 SET_ERRNO(ERROR_NETWORK, "Failed to send SERVER_AUTH_RESPONSE packet");
632 return ERROR_NETWORK;
633 }
634
636 ctx->crypto_ctx.handshake_complete = true;
637 log_debug("Crypto handshake completed successfully (mutual authentication)");
638
639 return ASCIICHAT_OK;
640}
@ KEY_TYPE_GPG
Definition key_types.h:56
@ AUTH_FAIL_PASSWORD_INCORRECT
Password verification failed (incorrect password).
Definition packet.h:805
@ AUTH_FAIL_CLIENT_KEY_REQUIRED
Server requires client key but client didn't provide one.
Definition packet.h:807
@ AUTH_FAIL_CLIENT_KEY_REJECTED
Client key not in whitelist (access denied).
Definition packet.h:809
@ PACKET_TYPE_CRYPTO_AUTH_RESPONSE
Client -> Server: {HMAC[32]} (UNENCRYPTED).
Definition packet.h:332
@ PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP
Server -> Client: {HMAC[32]} server proves knowledge (UNENCRYPTED).
Definition packet.h:336
bool crypto_verify_auth_response(const crypto_context_t *ctx, const uint8_t nonce[AUTH_CHALLENGE_SIZE], const uint8_t expected_hmac[HMAC_SHA256_SIZE])
crypto_result_t crypto_compute_auth_response(const crypto_context_t *ctx, const uint8_t nonce[AUTH_CHALLENGE_SIZE], uint8_t hmac_out[HMAC_SHA256_SIZE])

References ASCII_OTEL_SCOPE, ASCIICHAT_OK, crypto_context_t::auth_challenge_size, AUTH_FAIL_CLIENT_KEY_REJECTED, AUTH_FAIL_CLIENT_KEY_REQUIRED, AUTH_FAIL_PASSWORD_INCORRECT, crypto_context_t::auth_nonce, crypto_handshake_context_t::client_challenge_nonce, crypto_handshake_context_t::client_ed25519_key, crypto_handshake_context_t::client_ed25519_key_verified, crypto_handshake_context_t::client_sent_identity, public_key_t::comment, crypto_compute_auth_response(), crypto_handshake_context_t::crypto_ctx, CRYPTO_HANDSHAKE_AUTHENTICATING, CRYPTO_HANDSHAKE_READY, crypto_handshake_validate_packet_size(), CRYPTO_OK, crypto_result_to_string(), crypto_verify_auth_response(), ed25519_verify_signature(), ERROR_CRYPTO, ERROR_CRYPTO_AUTH, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, ERROR_NETWORK, ERROR_NETWORK_PROTOCOL, GPG_FINGERPRINT_HEX_BUFFER_SIZE, crypto_context_t::handshake_complete, crypto_context_t::has_password, HMAC_SHA256_SIZE, crypto_context_t::hmac_size, public_key_t::key, crypto_context_t::key_exchange_complete, KEY_TYPE_GPG, log_debug, log_info, packet_send_via_transport(), PACKET_TYPE_CRYPTO_AUTH_FAILED, PACKET_TYPE_CRYPTO_AUTH_RESPONSE, PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP, auth_failure_packet_t::reason_flags, crypto_handshake_context_t::require_client_auth, SET_ERRNO, crypto_context_t::signature_size, crypto_handshake_context_t::state, and public_key_t::type.

Referenced by acip_security_receive(), and network_negotiation_receive().

◆ crypto_handshake_server_send_parameters()

asciichat_error_t crypto_handshake_server_send_parameters ( crypto_handshake_context_t * ctx,
acip_transport_t * transport )

Server: Send CRYPTO_PARAMETERS and set handshake context sizes.

Parameters
ctxHandshake context
transportACIP transport to send on
Returns
ASCIICHAT_OK on success, error code on failure

Must be called before crypto_handshake_server_start(). Builds crypto parameters based on server state (identity key presence), sends them to the client, and updates context sizes to match.

TCP server path calls this indirectly via its own negotiation in src/server/crypto.c (which customizes parameters based on client capabilities). WebSocket and discovery-service paths call this directly.

<X25519 key exchange (Curve25519)

<Ed25519 authentication (Edwards-curve signatures)

<No authentication (plaintext mode)

<XSalsa20-Poly1305 authenticated encryption

<No encryption (plaintext mode)

Definition at line 28 of file lib/crypto/handshake/server.c.

29 {
30 if (!ctx || !transport) {
31 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: ctx=%p, transport=%p", (void *)ctx, (void *)transport);
32 }
33
34 bool has_identity_key = (ctx->server_private_key.type == KEY_TYPE_ED25519);
35
37 memset(&params, 0, sizeof(params));
38
40 params.selected_auth = has_identity_key ? AUTH_ALGO_ED25519 : AUTH_ALGO_NONE;
42 params.verification_enabled = ctx->require_client_auth ? 1 : 0;
47 params.hmac_size = 32; // SHA256 output size
48
49 if (has_identity_key) {
52 }
53
54 // Set context sizes to match what we send (host byte order)
56
57 // Convert to network byte order for the wire
58 params.kex_public_key_size = htons(params.kex_public_key_size);
59 params.auth_public_key_size = htons(params.auth_public_key_size);
60 params.signature_size = htons(params.signature_size);
61 params.shared_secret_size = htons(params.shared_secret_size);
62
63 int result =
64 packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_PARAMETERS, (uint8_t *)&params, sizeof(params), 0);
65 if (result != ASCIICHAT_OK) {
66 return SET_ERRNO(ERROR_NETWORK, "Failed to send CRYPTO_PARAMETERS packet");
67 }
68
69 log_debug("[HANDSHAKE] CRYPTO_PARAMETERS sent: auth=%s, cipher=XSALSA20_POLY1305",
70 has_identity_key ? "ED25519" : "NONE");
71 return ASCIICHAT_OK;
72}
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.
key_type_t type
Definition key_types.h:98
#define AUTH_ALGO_ED25519
Ed25519 authentication (Edwards-curve signatures).
Definition packet.h:1121
#define KEX_ALGO_X25519
X25519 key exchange (Curve25519).
Definition packet.h:1120
#define AUTH_ALGO_NONE
No authentication (plaintext mode).
Definition packet.h:1122
#define CIPHER_ALGO_NONE
No encryption (plaintext mode).
Definition packet.h:1124
#define CIPHER_ALGO_XSALSA20_POLY1305
XSalsa20-Poly1305 authenticated encryption.
Definition packet.h:1123
@ PACKET_TYPE_CRYPTO_PARAMETERS
Server -> Client: Chosen algorithms + data sizes (UNENCRYPTED).
Definition packet.h:324
#define CRYPTO_SHARED_KEY_SIZE
Shared key size (X25519).
Definition sizes.h:71
#define XSALSA20_NONCE_SIZE
XSalsa20 nonce size in bytes.
Definition sizes.h:39
#define POLY1305_MAC_SIZE
Poly1305 MAC size in bytes.
Definition sizes.h:41
Crypto parameters packet structure (Packet Type 15).
Definition packet.h:1037
uint8_t hmac_size
HMAC size in bytes (e.g., 32 for HMAC-SHA256).
Definition packet.h:1059
uint8_t selected_kex
Selected key exchange algorithm (KEX_ALGO_*).
Definition packet.h:1039
uint8_t selected_cipher
Selected cipher algorithm (CIPHER_ALGO_*).
Definition packet.h:1043
uint16_t auth_public_key_size
Authentication public key size in bytes (e.g., 32 for Ed25519, 1952 for Dilithium3).
Definition packet.h:1049
uint8_t selected_auth
Selected authentication algorithm (AUTH_ALGO_*).
Definition packet.h:1041
uint8_t verification_enabled
Server verification enabled flag (1=enabled, 0=disabled).
Definition packet.h:1045
uint16_t signature_size
Signature size in bytes (e.g., 64 for Ed25519, 3309 for Dilithium3).
Definition packet.h:1051
uint8_t nonce_size
Nonce size in bytes (e.g., 24 for XSalsa20).
Definition packet.h:1055
uint8_t mac_size
MAC size in bytes (e.g., 16 for Poly1305).
Definition packet.h:1057
uint16_t shared_secret_size
Shared secret size in bytes (e.g., 32 for X25519).
Definition packet.h:1053
uint16_t kex_public_key_size
Key exchange public key size in bytes (e.g., 32 for X25519, 1568 for Kyber1024).
Definition packet.h:1047

References ASCIICHAT_OK, AUTH_ALGO_ED25519, AUTH_ALGO_NONE, crypto_parameters_packet_t::auth_public_key_size, CIPHER_ALGO_NONE, CIPHER_ALGO_XSALSA20_POLY1305, crypto_handshake_context_t::crypto_ctx, crypto_handshake_set_parameters(), CRYPTO_SHARED_KEY_SIZE, ED25519_PUBLIC_KEY_SIZE, ED25519_SIGNATURE_SIZE, crypto_context_t::encrypt_data, ERROR_INVALID_PARAM, ERROR_NETWORK, crypto_parameters_packet_t::hmac_size, KEX_ALGO_X25519, crypto_parameters_packet_t::kex_public_key_size, KEY_TYPE_ED25519, log_debug, crypto_parameters_packet_t::mac_size, crypto_parameters_packet_t::nonce_size, packet_send_via_transport(), PACKET_TYPE_CRYPTO_PARAMETERS, POLY1305_MAC_SIZE, crypto_context_t::public_key_size, crypto_handshake_context_t::require_client_auth, crypto_parameters_packet_t::selected_auth, crypto_parameters_packet_t::selected_cipher, crypto_parameters_packet_t::selected_kex, crypto_handshake_context_t::server_private_key, SET_ERRNO, crypto_parameters_packet_t::shared_secret_size, crypto_parameters_packet_t::signature_size, private_key_t::type, crypto_parameters_packet_t::verification_enabled, and XSALSA20_NONCE_SIZE.

Referenced by acip_security_receive(), and network_negotiation_receive().

◆ crypto_handshake_server_start()

asciichat_error_t crypto_handshake_server_start ( crypto_handshake_context_t * ctx,
acip_transport_t * transport )

Server: Start crypto handshake by sending public key.

Parameters
ctxHandshake context (must be in CRYPTO_HANDSHAKE_INIT state)
transportACIP transport to send on
Returns
ASCIICHAT_OK on success, error code on failure

Server initiates handshake by sending KEY_EXCHANGE_INIT packet. Supports both simple and authenticated formats based on server identity key.

Note
Packet formats:
  • Simple: [ephemeral_key:public_key_size] (when server has no identity key)
  • Authenticated: [ephemeral_key:public_key_size][identity_key:auth_public_key_size][signature:signature_size] (when server has Ed25519 identity key)
State transition: CRYPTO_HANDSHAKE_INIT -> CRYPTO_HANDSHAKE_KEY_EXCHANGE

Definition at line 75 of file lib/crypto/handshake/server.c.

75 {
76 ASCII_OTEL_SCOPE(CRYPTO_HANDSHAKE_SERVER_START);
77 log_debug("[HANDSHAKE_START] ctx=%p, transport=%p", (void *)ctx, (void *)transport);
78
79 if (!ctx || ctx->state != CRYPTO_HANDSHAKE_INIT) {
80 log_error("[HANDSHAKE_START] FAILED: Invalid state - ctx=%p, state=%d", (void *)ctx, ctx ? (int)ctx->state : -1);
81 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid state: ctx=%p, state=%d", (void *)ctx, ctx ? (int)ctx->state : -1);
82 }
83 log_debug("[HANDSHAKE_START] State check OK: state=%d (CRYPTO_HANDSHAKE_INIT)", ctx->state);
84
85 int result;
86
87 // Caller is responsible for sending CRYPTO_PARAMETERS and calling
88 // crypto_handshake_set_parameters() before this function. This function
89 // only handles KEY_EXCHANGE_INIT.
90
91 // Calculate packet size based on negotiated crypto parameters
92 size_t expected_packet_size =
93 ctx->crypto_ctx.public_key_size + ctx->crypto_ctx.auth_public_key_size + ctx->crypto_ctx.signature_size;
94
95 log_debug("SERVER_KEY_EXCHANGE: kex_size=%u, auth_size=%u, sig_size=%u, expected_size=%zu",
96 ctx->crypto_ctx.public_key_size, ctx->crypto_ctx.auth_public_key_size, ctx->crypto_ctx.signature_size,
97 expected_packet_size);
98
99 // Check if we have an identity key to send authenticated packet
100 if (ctx->server_private_key.type == KEY_TYPE_ED25519) {
101 // Extended packet format:
102 // [ephemeral_key:kex_size][identity_key:auth_size][signature:sig_size]
103 uint8_t *extended_packet;
104 extended_packet = SAFE_MALLOC(expected_packet_size, uint8_t *);
105 if (!extended_packet) {
106 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate memory for extended packet");
107 }
108
109 // Copy ephemeral public key
110 memcpy(extended_packet, ctx->crypto_ctx.public_key, ctx->crypto_ctx.public_key_size);
111
112 // Copy identity public key
113 memcpy(extended_packet + ctx->crypto_ctx.public_key_size, ctx->server_public_key.key,
114 ctx->crypto_ctx.auth_public_key_size);
115
116 // DEBUG: Print identity key being sent
117 char hex[HEX_STRING_SIZE_32];
118 for (int i = 0; i < ED25519_PUBLIC_KEY_SIZE; i++) {
119 safe_snprintf(hex + i * 2, 3, "%02x", ctx->server_public_key.key[i]);
120 }
121 hex[HEX_STRING_SIZE_32 - 1] = '\0';
122
123 // Sign the ephemeral key with our identity key
124 log_debug("Signing ephemeral key with server identity key");
125
126 // Log key details in debug mode
128 for (int i = 0; i < 32; i++) {
129 safe_snprintf(hex_ephemeral + i * 2, 3, "%02x", ctx->crypto_ctx.public_key[i]);
130 safe_snprintf(hex_identity + i * 2, 3, "%02x", ctx->server_public_key.key[i]);
131 }
132 hex_ephemeral[64] = hex_identity[64] = '\0';
133 log_debug("SERVER: Ephemeral key (32 bytes): %s", hex_ephemeral);
134 log_debug("SERVER: Identity public key: %s", hex_identity);
135
136 if (ed25519_sign_message(&ctx->server_private_key, ctx->crypto_ctx.public_key, ctx->crypto_ctx.public_key_size,
137 extended_packet + ctx->crypto_ctx.public_key_size +
138 ctx->crypto_ctx.auth_public_key_size) != 0) {
139 SAFE_FREE(extended_packet);
140 return SET_ERRNO(ERROR_CRYPTO, "Failed to sign ephemeral key with identity key");
141 }
142
143 log_debug("Sending authenticated KEY_EXCHANGE_INIT (%zu bytes: ephemeral + "
144 "identity + signature)",
145 expected_packet_size);
146 log_debug("[HANDSHAKE_START] Calling packet_send_via_transport(type=%d, payload_len=%zu, 0)...",
147 PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT, expected_packet_size);
148 result = packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT, extended_packet,
149 expected_packet_size, 0);
150 log_debug("[HANDSHAKE_START] packet_send_via_transport returned %d", result);
151 SAFE_FREE(extended_packet);
152 } else {
153 // No identity key - send just the ephemeral key
154 log_debug("Sending simple KEY_EXCHANGE_INIT (%zu bytes: ephemeral key only)", ctx->crypto_ctx.public_key_size);
155 log_debug("[HANDSHAKE_START] Calling packet_send_via_transport(type=%d, payload_len=%zu, 0)...",
156 PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT, ctx->crypto_ctx.public_key_size);
157 result = packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT, ctx->crypto_ctx.public_key,
158 ctx->crypto_ctx.public_key_size, 0);
159 log_debug("[HANDSHAKE_START] packet_send_via_transport returned %d", result);
160 }
161
162 if (result != ASCIICHAT_OK) {
163 log_error("[HANDSHAKE_START] FAILED: packet_send returned %d", result);
164 return SET_ERRNO(ERROR_NETWORK, "Failed to send KEY_EXCHANGE_INIT packet");
165 }
166 log_debug("[HANDSHAKE_START] ===== SUCCESS: KEY_EXCHANGE_INIT sent =====");
167
169
170 return ASCIICHAT_OK;
171}
@ CRYPTO_HANDSHAKE_INIT
#define SAFE_FREE(ptr)
Definition common.h:377
#define SAFE_MALLOC(size, cast)
Definition common.h:265
#define log_error(...)
Log an ERROR message.
Definition log/log.h:634
@ PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT
Server -> Client: {server_pubkey[32]} (UNENCRYPTED).
Definition packet.h:326
#define CRYPTO_HANDSHAKE_SERVER_HEX_IDENTITY_BUFFER_SIZE
asciichat_error_t ed25519_sign_message(const private_key_t *key, const uint8_t *message, size_t message_len, uint8_t signature[ED25519_SIGNATURE_SIZE])
Definition ssh_keys.c:1133

References ASCII_OTEL_SCOPE, ASCIICHAT_OK, crypto_context_t::auth_public_key_size, crypto_handshake_context_t::crypto_ctx, CRYPTO_HANDSHAKE_INIT, CRYPTO_HANDSHAKE_KEY_EXCHANGE, CRYPTO_HANDSHAKE_SERVER_HEX_IDENTITY_BUFFER_SIZE, ED25519_PUBLIC_KEY_SIZE, ed25519_sign_message(), ERROR_CRYPTO, ERROR_INVALID_STATE, ERROR_MEMORY, ERROR_NETWORK, HEX_STRING_SIZE_32, public_key_t::key, KEY_TYPE_ED25519, log_debug, log_error, packet_send_via_transport(), PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT, crypto_context_t::public_key, crypto_context_t::public_key_size, SAFE_FREE, SAFE_MALLOC, safe_snprintf(), crypto_handshake_context_t::server_private_key, crypto_handshake_context_t::server_public_key, SET_ERRNO, crypto_context_t::signature_size, crypto_handshake_context_t::state, and private_key_t::type.

Referenced by acip_security_receive(), and network_negotiation_receive().