179 if (GET_OPTION(no_encrypt)) {
180 log_debug(
"Crypto handshake skipped (disabled)");
185 FATAL(ERROR_CRYPTO_HANDSHAKE,
"Client is NULL for crypto handshake");
191 const char *password = opts && opts->password[0] !=
'\0' ? opts->password :
"";
194 if (strlen(password) > 0) {
196 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Using password-based encryption");
200 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Using passwordless-based encryption");
204 if (init_result != ASCIICHAT_OK) {
205 FATAL(init_result,
"Failed to initialize crypto handshake for client %u", atomic_load(&client->client_id));
209 client->crypto_initialized =
false;
214 memcpy(&client->crypto_handshake_ctx.server_private_key, &
g_server_private_key,
sizeof(private_key_t));
217 client->crypto_handshake_ctx.server_public_key.type = KEY_TYPE_ED25519;
219 ED25519_PUBLIC_KEY_SIZE);
224 log_debug(
"Server identity keys configured for client %u", atomic_load(&client->client_id));
229 client->crypto_handshake_ctx.require_client_auth =
true;
237 if (GET_OPTION(require_server_verify)) {
238 client->crypto_handshake_ctx.require_client_auth =
true;
239 log_info(
"--require-server-verify enabled: clients must provide identity keys");
242 log_debug(
"Starting crypto handshake with client %u...", atomic_load(&client->client_id));
244 START_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
247 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Receiving client protocol version");
248 packet_type_t packet_type;
249 void *payload = NULL;
250 size_t payload_len = 0;
252 log_debug(
"SERVER_CRYPTO_HANDSHAKE: About to receive packet from client %u", atomic_load(&client->client_id));
255 mutex_lock(&client->client_state_mutex);
257 mutex_unlock(&client->client_state_mutex);
259 if (socket == INVALID_SOCKET_VALUE) {
260 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Socket is invalid for client %u", atomic_load(&client->client_id));
261 client->crypto_initialized =
false;
262 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
266 int result =
receive_packet(socket, &packet_type, &payload, &payload_len);
267 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Received packet from client %u: result=%d, type=%u",
268 atomic_load(&client->client_id), result, packet_type);
271 if (result != ASCIICHAT_OK) {
272 log_info(
"Client %u disconnected during crypto handshake (connection error)", atomic_load(&client->client_id));
276 client->crypto_initialized =
false;
277 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
283 if (packet_type != PACKET_TYPE_PROTOCOL_VERSION) {
284 log_info(
"Client %u sent packet type %u instead of PROTOCOL_VERSION - using unencrypted mode",
285 atomic_load(&client->client_id), packet_type);
289 client->pending_packet_type = packet_type;
290 client->pending_packet_payload = payload;
291 client->pending_packet_length = payload_len;
294 client->crypto_initialized =
false;
295 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
299 if (payload_len !=
sizeof(protocol_version_packet_t)) {
300 log_error(
"Invalid protocol version packet size: %zu, expected %zu", payload_len,
301 sizeof(protocol_version_packet_t));
303 client->crypto_initialized =
false;
304 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
308 protocol_version_packet_t client_version;
309 memcpy(&client_version, payload,
sizeof(protocol_version_packet_t));
310 log_debug(
"SERVER_CRYPTO_HANDSHAKE: About to free payload for client %u", atomic_load(&client->client_id));
312 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Payload freed for client %u", atomic_load(&client->client_id));
315 uint16_t client_proto_version = NET_TO_HOST_U16(client_version.protocol_version);
316 uint16_t client_proto_revision = NET_TO_HOST_U16(client_version.protocol_revision);
318 uint8_t client_mode = client_version.supports_encryption;
319 log_info(
"Client %u protocol version: %u.%u (crypto mode: 0x%02x)", atomic_load(&client->client_id),
320 client_proto_version, client_proto_revision, client_mode);
322 log_debug(
"SERVER_CRYPTO_HANDSHAKE: About to check encryption support for client %u",
323 atomic_load(&client->client_id));
326 if (client_mode == ACIP_CRYPTO_NONE) {
327 log_error(
"Client %u does not support any crypto protocol", atomic_load(&client->client_id));
328 log_info(
"Client %u disconnected - crypto protocol required", atomic_load(&client->client_id));
329 client->crypto_initialized =
false;
330 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
335 client->encrypt_data = ACIP_CRYPTO_HAS_ENCRYPT(client_mode);
338 log_debug(
"SERVER_CRYPTO_HANDSHAKE: About to prepare server protocol version for client %u",
339 atomic_load(&client->client_id));
340 protocol_version_packet_t server_version = {0};
341 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Initialized server_version struct for client %u",
342 atomic_load(&client->client_id));
343 server_version.protocol_version = HOST_TO_NET_U16(1);
344 server_version.protocol_revision = HOST_TO_NET_U16(0);
345 server_version.supports_encryption = client_mode;
346 server_version.compression_algorithms = 0;
347 server_version.compression_threshold = 0;
348 server_version.feature_flags = 0;
350 log_debug(
"SERVER_CRYPTO_HANDSHAKE: About to call send_protocol_version_packet for client %u",
351 atomic_load(&client->client_id));
353 log_debug(
"SERVER_CRYPTO_HANDSHAKE: send_protocol_version_packet returned %d for client %u", result,
354 atomic_load(&client->client_id));
356 log_error(
"Failed to send protocol version to client %u", atomic_load(&client->client_id));
357 log_info(
"Client %u disconnected - failed to send protocol version", atomic_load(&client->client_id));
358 client->crypto_initialized =
false;
359 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
362 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Protocol version sent successfully to client %u",
363 atomic_load(&client->client_id));
369 result =
receive_packet(socket, &packet_type, &payload, &payload_len);
370 if (result != ASCIICHAT_OK) {
371 log_info(
"Client %u disconnected during crypto capabilities exchange", atomic_load(&client->client_id));
375 client->crypto_initialized =
false;
376 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
380 if (packet_type != PACKET_TYPE_CRYPTO_CAPABILITIES) {
381 log_error(
"Server received packet type 0x%x (decimal %u) - Expected 0x%x (decimal %d)", packet_type, packet_type,
382 PACKET_TYPE_CRYPTO_CAPABILITIES, PACKET_TYPE_CRYPTO_CAPABILITIES);
383 log_error(
"Raw packet type bytes: %02x %02x %02x %02x", (packet_type >> 0) & 0xFF, (packet_type >> 8) & 0xFF,
384 (packet_type >> 16) & 0xFF, (packet_type >> 24) & 0xFF);
388 log_info(
"Client %u disconnected due to protocol mismatch in crypto capabilities", atomic_load(&client->client_id));
389 client->crypto_initialized =
false;
390 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
394 if (payload_len !=
sizeof(crypto_capabilities_packet_t)) {
395 SET_ERRNO(ERROR_NETWORK_PROTOCOL,
396 "Invalid crypto capabilities packet size: %zu (expected %zu) - we should disconnect this client",
397 payload_len,
sizeof(crypto_capabilities_packet_t));
402 client->crypto_initialized =
false;
403 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
408 SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Crypto capabilities payload is NULL after validation");
409 log_error(
"Client %u crypto capabilities payload is NULL after validation - disconnecting",
410 atomic_load(&client->client_id));
411 LOG_ERRNO_IF_SET(
"Crypto handshake: missing capabilities payload");
412 client->crypto_initialized =
false;
413 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
418 crypto_capabilities_packet_t client_caps;
419 memcpy(&client_caps, payload,
sizeof(crypto_capabilities_packet_t));
426 uint16_t supported_kex = NET_TO_HOST_U16(client_caps.supported_kex_algorithms);
427 uint16_t supported_auth = NET_TO_HOST_U16(client_caps.supported_auth_algorithms);
428 uint16_t supported_cipher = NET_TO_HOST_U16(client_caps.supported_cipher_algorithms);
430 log_debug(
"Client %u crypto capabilities: KEX=0x%04x, Auth=0x%04x, Cipher=0x%04x", atomic_load(&client->client_id),
431 supported_kex, supported_auth, supported_cipher);
434 crypto_parameters_packet_t server_params = {0};
437 server_params.selected_kex = KEX_ALGO_X25519;
438 server_params.selected_cipher =
439 ACIP_CRYPTO_HAS_ENCRYPT(client_mode) ? CIPHER_ALGO_XSALSA20_POLY1305 : CIPHER_ALGO_NONE;
451 server_params.selected_auth = AUTH_ALGO_ED25519;
455 server_params.selected_auth = AUTH_ALGO_NONE;
462 server_params.kex_public_key_size = CRYPTO_PUBLIC_KEY_SIZE;
465 if (server_params.selected_auth == AUTH_ALGO_ED25519) {
466 server_params.auth_public_key_size = ED25519_PUBLIC_KEY_SIZE;
467 server_params.signature_size = ED25519_SIGNATURE_SIZE;
469 server_params.auth_public_key_size = 0;
470 server_params.signature_size = 0;
473 server_params.shared_secret_size = CRYPTO_PUBLIC_KEY_SIZE;
474 server_params.nonce_size = CRYPTO_NONCE_SIZE;
475 server_params.mac_size = CRYPTO_MAC_SIZE;
476 server_params.hmac_size = CRYPTO_HMAC_SIZE;
478 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Sending crypto parameters to client %u", atomic_load(&client->client_id));
481 log_error(
"Failed to send crypto parameters to client %u", atomic_load(&client->client_id));
482 client->crypto_initialized =
false;
483 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
486 log_debug(
"Server selected crypto for client %u: KEX=%u, Auth=%u, Cipher=%u", atomic_load(&client->client_id),
487 server_params.selected_kex, server_params.selected_auth, server_params.selected_cipher);
491 if (result != ASCIICHAT_OK) {
492 client->crypto_initialized =
false;
493 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
494 FATAL(result,
"Failed to set crypto parameters for client %u", atomic_load(&client->client_id));
502 log_debug(
"SERVER_CRYPTO_HANDSHAKE: Waiting for optional CRYPTO_CLIENT_HELLO from client %u",
503 atomic_load(&client->client_id));
506 packet_type_t hello_packet_type;
507 uint8_t *hello_payload = NULL;
508 size_t hello_payload_len = 0;
510 result =
receive_packet(socket, &hello_packet_type, (
void **)&hello_payload, &hello_payload_len);
511 if (result != ASCIICHAT_OK) {
512 log_info(
"Client %u disconnected during handshake initialization", atomic_load(&client->client_id));
516 client->crypto_initialized =
false;
517 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
521 if (hello_packet_type == PACKET_TYPE_CRYPTO_CLIENT_HELLO) {
523 if (hello_payload_len != ED25519_PUBLIC_KEY_SIZE) {
524 log_error(
"Invalid CRYPTO_CLIENT_HELLO size: %zu (expected %d)", hello_payload_len, ED25519_PUBLIC_KEY_SIZE);
526 client->crypto_initialized =
false;
527 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
531 const uint8_t *expected_server_key = hello_payload;
534 char hex_expected[65];
536 log_debug(
"Client %u expects server key: %s", atomic_load(&client->client_id), hex_expected);
539 bool key_found =
false;
541 if (sodium_memcmp(expected_server_key,
g_server_identity_keys[i].public_key, ED25519_PUBLIC_KEY_SIZE) == 0) {
543 memcpy(&client->crypto_handshake_ctx.server_private_key, &
g_server_identity_keys[i],
sizeof(private_key_t));
545 char hex_selected[65];
547 log_debug(
"Client %u selected server identity key #%zu: %s", atomic_load(&client->client_id), i + 1,
557 log_error(
"Client %u requested unknown server key %s - rejecting connection", atomic_load(&client->client_id),
560 client->crypto_initialized =
false;
561 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
570 log_error(
"Client %u must send CRYPTO_CLIENT_HELLO when server has multiple keys (got packet type %u)",
571 atomic_load(&client->client_id), hello_packet_type);
573 client->crypto_initialized =
false;
574 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
580 log_debug(
"Client %u is using old protocol (no CLIENT_HELLO) - using default key",
581 atomic_load(&client->client_id));
584 client->pending_packet_type = hello_packet_type;
585 client->pending_packet_payload = hello_payload;
586 client->pending_packet_length = hello_payload_len;
591 log_debug(
"About to call crypto_handshake_server_start");
593 if (result != ASCIICHAT_OK) {
594 log_error(
"Crypto handshake start failed for client %u: %s", atomic_load(&client->client_id),
595 asciichat_error_string(result));
596 LOG_ERRNO_IF_SET(
"Crypto handshake: failed to send KEY_EXCHANGE_INIT");
597 client->crypto_initialized =
false;
598 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
604 if (result != ASCIICHAT_OK) {
605 log_error(
"Crypto authentication challenge failed for client %u: %s", atomic_load(&client->client_id),
606 asciichat_error_string(result));
607 client->crypto_initialized =
false;
608 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
613 if (client->crypto_handshake_ctx.state == CRYPTO_HANDSHAKE_READY) {
614 uint32_t cid = atomic_load(&client->client_id);
615 client->crypto_initialized =
true;
617 client->crypto_handshake_ctx.crypto_ctx.encrypt_data = client->encrypt_data;
618 STOP_TIMER_AND_LOG(debug, 100 * NS_PER_MS_INT,
"server_crypto_handshake_client_%u",
619 "Crypto handshake completed successfully for client %u (no authentication)", cid);
625 if (result != ASCIICHAT_OK) {
626 if (result == ERROR_NETWORK || result == ERROR_NETWORK_PROTOCOL || result == ERROR_CRYPTO_AUTH ||
627 result == ERROR_CRYPTO_VERIFICATION || result == ERROR_CRYPTO) {
628 if (result == ERROR_NETWORK) {
629 log_info(
"Client %u disconnected during authentication", atomic_load(&client->client_id));
631 log_error(
"Crypto authentication failed for client %u: %s", atomic_load(&client->client_id),
632 asciichat_error_string(result));
634 LOG_ERRNO_IF_SET(
"Crypto handshake completion failed");
635 client->crypto_initialized =
false;
636 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
639 STOP_TIMER(
"server_crypto_handshake_client_%u", atomic_load(&client->client_id));
640 FATAL(result,
"Crypto authentication response failed for client %u", atomic_load(&client->client_id));
641 client->crypto_initialized =
false;
645 uint32_t cid = atomic_load(&client->client_id);
646 client->crypto_initialized =
true;
648 client->crypto_handshake_ctx.crypto_ctx.encrypt_data = client->encrypt_data;
649 STOP_TIMER_AND_LOG(debug, 100 * NS_PER_MS_INT,
"server_crypto_handshake_client_%u",
650 "Crypto handshake completed successfully for client %u", cid);
653 log_info_client(client,
"Encryption established - secure channel ready");