ascii-chat 0.11.33
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 165 of file lib/crypto/handshake/server.c.

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

References 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, 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, log_warn, 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_FREE, SAFE_MALLOC, safe_snprintf(), SET_ERRNO, crypto_handshake_context_t::state, and public_key_t::type.

Referenced by server_crypto_handshake().

◆ 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 443 of file lib/crypto/handshake/server.c.

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

References 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, 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 server_crypto_handshake().

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

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

21 {
22 if (!ctx || !transport) {
23 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: ctx=%p, transport=%p", (void *)ctx, (void *)transport);
24 }
25
26 bool has_identity_key = (ctx->server_private_key.type == KEY_TYPE_ED25519);
27
29 memset(&params, 0, sizeof(params));
30
32 params.selected_auth = has_identity_key ? AUTH_ALGO_ED25519 : AUTH_ALGO_NONE;
34 params.verification_enabled = ctx->require_client_auth ? 1 : 0;
39 params.hmac_size = 32; // SHA256 output size
40
41 if (has_identity_key) {
44 }
45
46 // Set context sizes to match what we send (host byte order)
48
49 // Convert to network byte order for the wire
50 params.kex_public_key_size = htons(params.kex_public_key_size);
51 params.auth_public_key_size = htons(params.auth_public_key_size);
52 params.signature_size = htons(params.signature_size);
53 params.shared_secret_size = htons(params.shared_secret_size);
54
55 int result =
56 packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_PARAMETERS, (uint8_t *)&params, sizeof(params), 0);
57 if (result != ASCIICHAT_OK) {
58 return SET_ERRNO(ERROR_NETWORK, "Failed to send CRYPTO_PARAMETERS packet");
59 }
60
61 log_debug("[HANDSHAKE] CRYPTO_PARAMETERS sent: auth=%s, cipher=XSALSA20_POLY1305",
62 has_identity_key ? "ED25519" : "NONE");
63 return ASCIICHAT_OK;
64}
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.
#define CRYPTO_SHARED_KEY_SIZE
Shared key size (X25519)
#define XSALSA20_NONCE_SIZE
XSalsa20 nonce size in bytes.
#define POLY1305_MAC_SIZE
Poly1305 MAC size in bytes.
key_type_t type
Definition key_types.h:92
#define AUTH_ALGO_ED25519
Ed25519 authentication (Edwards-curve signatures)
Definition packet.h:1065
#define KEX_ALGO_X25519
X25519 key exchange (Curve25519)
Definition packet.h:1064
#define AUTH_ALGO_NONE
No authentication (plaintext mode)
Definition packet.h:1066
#define CIPHER_ALGO_XSALSA20_POLY1305
XSalsa20-Poly1305 authenticated encryption.
Definition packet.h:1067
@ PACKET_TYPE_CRYPTO_PARAMETERS
Server -> Client: Chosen algorithms + data sizes (UNENCRYPTED)
Definition packet.h:309
Crypto parameters packet structure (Packet Type 15)
Definition packet.h:981
uint8_t hmac_size
HMAC size in bytes (e.g., 32 for HMAC-SHA256)
Definition packet.h:1003
uint8_t selected_kex
Selected key exchange algorithm (KEX_ALGO_*)
Definition packet.h:983
uint8_t selected_cipher
Selected cipher algorithm (CIPHER_ALGO_*)
Definition packet.h:987
uint16_t auth_public_key_size
Authentication public key size in bytes (e.g., 32 for Ed25519, 1952 for Dilithium3)
Definition packet.h:993
uint8_t selected_auth
Selected authentication algorithm (AUTH_ALGO_*)
Definition packet.h:985
uint8_t verification_enabled
Server verification enabled flag (1=enabled, 0=disabled)
Definition packet.h:989
uint16_t signature_size
Signature size in bytes (e.g., 64 for Ed25519, 3309 for Dilithium3)
Definition packet.h:995
uint8_t nonce_size
Nonce size in bytes (e.g., 24 for XSalsa20)
Definition packet.h:999
uint8_t mac_size
MAC size in bytes (e.g., 16 for Poly1305)
Definition packet.h:1001
uint16_t shared_secret_size
Shared secret size in bytes (e.g., 32 for X25519)
Definition packet.h:997
uint16_t kex_public_key_size
Key exchange public key size in bytes (e.g., 32 for X25519, 1568 for Kyber1024)
Definition packet.h:991

References ASCIICHAT_OK, AUTH_ALGO_ED25519, AUTH_ALGO_NONE, crypto_parameters_packet_t::auth_public_key_size, 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, 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.

◆ 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 67 of file lib/crypto/handshake/server.c.

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

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

Referenced by server_crypto_handshake().