32 packet_type_t packet_type,
const uint8_t *payload,
34 if (!ctx || ctx->state != CRYPTO_HANDSHAKE_INIT) {
35 return SET_ERRNO(ERROR_INVALID_STATE,
"Invalid state: ctx=%p, state=%d", (
void *)ctx, ctx ? (
int)ctx->state : -1);
38 return SET_ERRNO(ERROR_INVALID_PARAM,
"transport is NULL");
45 if (packet_type != PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT) {
46 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Expected KEY_EXCHANGE_INIT, got packet type %d", packet_type);
49 log_debug(
"CLIENT_KEY_EXCHANGE: Received packet with payload_len=%zu, kex_size=%u, auth_size=%u, sig_size=%u",
50 payload_len, ctx->crypto_ctx.public_key_size, ctx->crypto_ctx.auth_public_key_size,
51 ctx->crypto_ctx.signature_size);
55 size_t expected_auth_size =
56 ctx->crypto_ctx.public_key_size + ctx->crypto_ctx.auth_public_key_size + ctx->crypto_ctx.signature_size;
58 uint8_t *server_ephemeral_key;
60 size_t key_size =
sizeof(ctx->crypto_ctx.public_key);
61 server_ephemeral_key = SAFE_MALLOC(key_size, uint8_t *);
62 if (!server_ephemeral_key) {
63 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate memory for server ephemeral key");
65 uint8_t *server_identity_key;
66 server_identity_key = SAFE_MALLOC(ctx->crypto_ctx.auth_public_key_size, uint8_t *);
67 uint8_t *server_signature;
68 server_signature = SAFE_MALLOC(ctx->crypto_ctx.signature_size, uint8_t *);
70 if (!server_identity_key || !server_signature) {
71 SAFE_FREE(server_ephemeral_key);
72 if (server_identity_key)
73 SAFE_FREE(server_identity_key);
75 SAFE_FREE(server_signature);
76 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate memory for server identity key or signature");
80 asciichat_error_t validation_result =
82 if (validation_result != ASCIICHAT_OK) {
86 SAFE_FREE(server_ephemeral_key);
87 SAFE_FREE(server_identity_key);
88 SAFE_FREE(server_signature);
89 return validation_result;
94 if (ctx->crypto_ctx.auth_public_key_size > 0 && payload_len == expected_auth_size) {
97 log_debug(
"Received authenticated KEY_EXCHANGE_INIT (%zu bytes)", expected_auth_size);
98 memcpy(server_ephemeral_key, payload, ctx->crypto_ctx.public_key_size);
99 memcpy(server_identity_key, payload + ctx->crypto_ctx.public_key_size, ctx->crypto_ctx.auth_public_key_size);
100 memcpy(server_signature, payload + ctx->crypto_ctx.public_key_size + ctx->crypto_ctx.auth_public_key_size,
101 ctx->crypto_ctx.signature_size);
104 ctx->server_uses_client_auth =
true;
107 char hex_id[HEX_STRING_SIZE_32];
108 for (
int i = 0; i < ED25519_PUBLIC_KEY_SIZE; i++) {
109 safe_snprintf(hex_id + i * 2, 3,
"%02x", server_identity_key[i]);
111 hex_id[HEX_STRING_SIZE_32 - 1] =
'\0';
112 log_debug(
"Received identity key: %s", hex_id);
115 char hex_eph[HEX_STRING_SIZE_32];
116 for (
int i = 0; i < ED25519_PUBLIC_KEY_SIZE; i++) {
117 safe_snprintf(hex_eph + i * 2, 3,
"%02x", server_ephemeral_key[i]);
119 hex_eph[HEX_STRING_SIZE_32 - 1] =
'\0';
120 log_debug(
"Received ephemeral key: %s", hex_eph);
122 char hex_sig[HEX_STRING_SIZE_64];
123 for (
int i = 0; i < ED25519_SIGNATURE_SIZE; i++) {
124 safe_snprintf(hex_sig + i * 2, 3,
"%02x", server_signature[i]);
126 hex_sig[HEX_STRING_SIZE_64 - 1] =
'\0';
127 log_debug(
"Received signature: %s", hex_sig);
130 log_debug(
"Verifying server's signature over ephemeral key (already logged above)");
134 if (!ctx->verify_server_key) {
135 log_info(
"Skipping server signature verification (no --server-key specified)");
136 log_warn(
"Connection is encrypted but server identity is NOT verified (vulnerable to MITM)");
139 const char *gpg_key_id = NULL;
140 if (ctx->expected_server_key[0] !=
'\0' && strncmp(ctx->expected_server_key,
"gpg:", 4) == 0) {
141 const char *key_id_start = ctx->expected_server_key + 4;
142 size_t key_id_len = strlen(key_id_start);
144 if (key_id_len == 8 || key_id_len == 16 || key_id_len == 40) {
145 gpg_key_id = key_id_start;
146 log_debug(
"Using GPG key ID from --server-key for verification: %s", gpg_key_id);
151 server_signature, gpg_key_id) != 0) {
155 SAFE_FREE(server_ephemeral_key);
156 SAFE_FREE(server_identity_key);
157 SAFE_FREE(server_signature);
158 return SET_ERRNO(ERROR_CRYPTO,
"Server signature verification FAILED - rejecting connection. "
159 "This indicates: Server's identity key does not "
160 "match its ephemeral key, Potential man-in-the-middle attack, "
161 "Corrupted or malicious server");
163 log_debug(
"Server signature verified successfully");
167 if (ctx->verify_server_key && strlen(ctx->expected_server_key) > 0) {
169 public_key_t expected_keys[MAX_CLIENTS];
170 size_t num_expected_keys = 0;
171 if (
parse_public_keys(ctx->expected_server_key, expected_keys, &num_expected_keys, MAX_CLIENTS) != 0 ||
172 num_expected_keys == 0) {
176 SAFE_FREE(server_ephemeral_key);
177 SAFE_FREE(server_identity_key);
178 SAFE_FREE(server_signature);
179 return SET_ERRNO(ERROR_CONFIG,
180 "Failed to parse expected server key: %s. Check that "
181 "--server-key value is valid (ssh-ed25519 "
182 "format, github:username, or hex)",
183 ctx->expected_server_key);
188 bool key_matched =
false;
189 for (
size_t i = 0; i < num_expected_keys; i++) {
190 if (sodium_memcmp(server_identity_key, expected_keys[i].key, ED25519_PUBLIC_KEY_SIZE) == 0) {
192 log_debug(
"Server identity key matched expected key %zu/%zu", i + 1, num_expected_keys);
201 SAFE_FREE(server_ephemeral_key);
202 SAFE_FREE(server_identity_key);
203 SAFE_FREE(server_signature);
204 return SET_ERRNO(ERROR_CRYPTO,
205 "Server identity key mismatch - potential MITM attack! "
206 "Expected key(s) from: %s (checked %zu keys), Server presented a different key "
207 "than specified with --server-key, DO NOT CONNECT to this "
208 "server - likely man-in-the-middle attack!",
209 ctx->expected_server_key, num_expected_keys);
211 log_info(
"Server identity key verified against --server-key (%zu key(s) checked)", num_expected_keys);
218 if (ctx->server_ip[0] ==
'\0') {
219 log_debug(
"Server IP not set - skipping known_hosts verification (non-TCP transport)");
221 log_debug(
"Server IP already set: %s", ctx->server_ip);
226 bool skip_known_hosts =
false;
227 const char *env_skip =
platform_getenv(
"ASCII_CHAT_INSECURE_NO_HOST_IDENTITY_CHECK");
228 if (env_skip && strcmp(env_skip, STR_ONE) == 0) {
230 "Skipping known_hosts checking for authenticated connection (ASCII_CHAT_INSECURE_NO_HOST_IDENTITY_CHECK=1)");
231 skip_known_hosts =
true;
236 log_warn(
"Skipping known_hosts checking (CLAUDECODE set in debug build)");
237 skip_known_hosts =
true;
241 if (!skip_known_hosts && ctx->server_ip[0] !=
'\0' && ctx->server_port > 0) {
242 asciichat_error_t known_host_result =
check_known_host(ctx->server_ip, ctx->server_port, server_identity_key);
243 if (known_host_result == ERROR_CRYPTO_VERIFICATION) {
245 log_error(
"SECURITY: Server key does NOT match known_hosts entry!\n"
246 "This indicates a possible man-in-the-middle attack!");
247 uint8_t stored_key[ZERO_KEY_SIZE] = {0};
254 SAFE_FREE(server_ephemeral_key);
255 SAFE_FREE(server_identity_key);
256 SAFE_FREE(server_signature);
257 return SET_ERRNO(ERROR_CRYPTO_VERIFICATION,
258 "SECURITY: Connection aborted - server key mismatch (possible MITM attack)");
261 log_warn(
"SECURITY WARNING: User accepted MITM risk - continuing with connection");
262 }
else if (known_host_result == ASCIICHAT_OK) {
269 SAFE_FREE(server_ephemeral_key);
270 SAFE_FREE(server_identity_key);
271 SAFE_FREE(server_signature);
272 return SET_ERRNO(ERROR_CRYPTO,
"User declined to verify unknown host");
276 if (
add_known_host(ctx->server_ip, ctx->server_port, server_identity_key) != ASCIICHAT_OK) {
280 SAFE_FREE(server_ephemeral_key);
281 SAFE_FREE(server_identity_key);
282 SAFE_FREE(server_signature);
283 return SET_ERRNO(ERROR_CONFIG,
284 "CRITICAL SECURITY ERROR: Failed to create known_hosts "
285 "file! This is a security vulnerability - the "
286 "program cannot track known hosts. Please check file "
287 "permissions and ensure the program can write to: %s",
290 log_debug(
"Server host added to known_hosts successfully");
291 }
else if (known_host_result == 1) {
293 log_info(
"Server host key verified from known_hosts - connection secure");
299 SAFE_FREE(server_ephemeral_key);
300 SAFE_FREE(server_identity_key);
301 SAFE_FREE(server_signature);
302 return SET_ERRNO(known_host_result,
"SECURITY: known_hosts verification failed with error code %d",
306 }
else if (payload_len == ctx->crypto_ctx.public_key_size) {
308 log_debug(
"Received simple KEY_EXCHANGE_INIT (%zu bytes) - server has no "
311 memcpy(server_ephemeral_key, payload, ctx->crypto_ctx.public_key_size);
314 memset(server_identity_key, 0, ctx->crypto_ctx.auth_public_key_size);
315 memset(server_signature, 0, ctx->crypto_ctx.signature_size);
318 ctx->server_uses_client_auth =
false;
320 log_debug(
"Received ephemeral key (simple format)");
327 if (ctx->server_ip[0] ==
'\0' || ctx->server_port <= 0) {
328 SAFE_FREE(server_ephemeral_key);
329 SAFE_FREE(server_identity_key);
330 SAFE_FREE(server_signature);
331 return SET_ERRNO(ERROR_CRYPTO,
"Server IP or port not set, cannot check known_hosts");
335 bool skip_known_hosts =
false;
336 asciichat_error_t known_host_result = ASCIICHAT_OK;
337 const char *env_skip_known_hosts_checking =
platform_getenv(
"ASCII_CHAT_INSECURE_NO_HOST_IDENTITY_CHECK");
338 if (env_skip_known_hosts_checking && strcmp(env_skip_known_hosts_checking, STR_ONE) == 0) {
339 log_warn(
"Skipping known_hosts checking. This is a security vulnerability.");
340 skip_known_hosts =
true;
345 log_warn(
"Skipping known_hosts checking (CLAUDECODE set in debug build).");
346 skip_known_hosts =
true;
353 if (skip_known_hosts || known_host_result == 1) {
355 log_info(
"SECURITY: Server IP %s:%u is known (no-identity entry found) - connection verified", ctx->server_ip,
357 }
else if (known_host_result == ASCIICHAT_OK) {
359 log_warn(
"SECURITY: Unknown server IP %s:%u with no identity key\n"
360 "This connection is vulnerable to man-in-the-middle attacks\n"
361 "Anyone can intercept your connection and read your data",
362 ctx->server_ip, ctx->server_port);
368 SAFE_FREE(server_ephemeral_key);
369 SAFE_FREE(server_identity_key);
370 SAFE_FREE(server_signature);
371 return SET_ERRNO(ERROR_CRYPTO,
"User declined to connect to unknown server without identity key");
376 uint8_t zero_key[ZERO_KEY_SIZE] = {0};
377 if (
add_known_host(ctx->server_ip, ctx->server_port, zero_key) != ASCIICHAT_OK) {
381 SAFE_FREE(server_ephemeral_key);
382 SAFE_FREE(server_identity_key);
383 SAFE_FREE(server_signature);
384 return SET_ERRNO(ERROR_CONFIG,
385 "CRITICAL SECURITY ERROR: Failed to create known_hosts "
386 "file! This is a security vulnerability - the "
387 "program cannot track known hosts. Please check file "
388 "permissions and ensure the program can write to: %s",
391 log_debug(
"Server host added to known_hosts successfully");
392 }
else if (known_host_result == ERROR_CRYPTO_VERIFICATION) {
394 log_warn(
"SECURITY: Server previously had identity key but now has none - potential security issue");
398 SAFE_FREE(server_ephemeral_key);
399 SAFE_FREE(server_identity_key);
400 SAFE_FREE(server_signature);
401 return SET_ERRNO(ERROR_CRYPTO_VERIFICATION,
"Server key configuration changed - potential security issue");
407 SAFE_FREE(server_ephemeral_key);
408 SAFE_FREE(server_identity_key);
409 SAFE_FREE(server_signature);
410 return SET_ERRNO(ERROR_CRYPTO,
"Failed to verify server IP address");
416 SAFE_FREE(server_ephemeral_key);
417 SAFE_FREE(server_identity_key);
418 SAFE_FREE(server_signature);
419 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
420 "Invalid KEY_EXCHANGE_INIT size: %zu bytes (expected %zu or "
421 "%zu). This indicates: Protocol violation "
422 "or incompatible server version, Potential man-in-the-middle "
423 "attack, Network corruption",
424 payload_len, expected_auth_size, ctx->crypto_ctx.public_key_size);
433 if (crypto_result != CRYPTO_OK) {
434 SAFE_FREE(server_ephemeral_key);
435 SAFE_FREE(server_identity_key);
436 SAFE_FREE(server_signature);
437 return SET_ERRNO(ERROR_CRYPTO,
"Failed to set peer public key and derive shared secret: %s",
442 bool client_has_identity_key = (ctx->client_private_key.type == KEY_TYPE_ED25519);
448 bool server_has_identity = (ctx->crypto_ctx.auth_public_key_size > 0 && ctx->crypto_ctx.signature_size > 0);
449 bool server_requires_auth = server_has_identity || ctx->require_client_auth;
451 if (server_requires_auth) {
455 size_t ed25519_pubkey_size = ED25519_PUBLIC_KEY_SIZE;
456 size_t ed25519_sig_size = ED25519_SIGNATURE_SIZE;
457 size_t response_size = ctx->crypto_ctx.public_key_size + ed25519_pubkey_size + ed25519_sig_size;
460 uint8_t gpg_key_id_len = 0;
461 if (ctx->client_gpg_key_id[0] !=
'\0') {
462 gpg_key_id_len = (uint8_t)strlen(ctx->client_gpg_key_id);
463 if (gpg_key_id_len > 40) {
466 response_size += 1 + gpg_key_id_len;
471 uint8_t *key_response = SAFE_MALLOC(response_size, uint8_t *);
475 memcpy(key_response + offset, ctx->crypto_ctx.public_key,
476 ctx->crypto_ctx.public_key_size);
477 offset += ctx->crypto_ctx.public_key_size;
479 if (client_has_identity_key) {
481 memcpy(key_response + offset, ctx->client_private_key.public_key, ed25519_pubkey_size);
482 offset += ed25519_pubkey_size;
485 if (
ed25519_sign_message(&ctx->client_private_key, ctx->crypto_ctx.public_key, ctx->crypto_ctx.public_key_size,
486 key_response + offset) != 0) {
487 SAFE_FREE(key_response);
488 SAFE_FREE(server_ephemeral_key);
489 SAFE_FREE(server_identity_key);
490 SAFE_FREE(server_signature);
491 return SET_ERRNO(ERROR_CRYPTO,
"Failed to sign client ephemeral key");
493 offset += ed25519_sig_size;
496 memset(key_response + offset, 0, ed25519_pubkey_size);
497 offset += ed25519_pubkey_size;
498 memset(key_response + offset, 0, ed25519_sig_size);
499 offset += ed25519_sig_size;
503 key_response[offset] = gpg_key_id_len;
507 if (gpg_key_id_len > 0) {
508 memcpy(key_response + offset, ctx->client_gpg_key_id, gpg_key_id_len);
509 offset += gpg_key_id_len;
510 log_debug(
"Including client GPG key ID in KEY_EXCHANGE_RESPONSE: %.*s", gpg_key_id_len, ctx->client_gpg_key_id);
515 SAFE_FREE(key_response);
516 SAFE_FREE(server_ephemeral_key);
517 SAFE_FREE(server_identity_key);
518 SAFE_FREE(server_signature);
519 return SET_ERRNO(ERROR_NETWORK,
"Failed to send KEY_EXCHANGE_RESPONSE packet");
523 sodium_memzero(key_response, response_size);
524 SAFE_FREE(key_response);
529 ctx->crypto_ctx.public_key_size, 0);
531 SAFE_FREE(server_ephemeral_key);
532 SAFE_FREE(server_identity_key);
533 SAFE_FREE(server_signature);
534 return SET_ERRNO(ERROR_NETWORK,
"Failed to send KEY_EXCHANGE_RESPONSE packet");
538 ctx->state = CRYPTO_HANDSHAKE_KEY_EXCHANGE;
541 SAFE_FREE(server_ephemeral_key);
542 SAFE_FREE(server_identity_key);
543 SAFE_FREE(server_signature);
658 packet_type_t packet_type,
const uint8_t *payload,
659 size_t payload_len) {
660 if (!ctx || ctx->state != CRYPTO_HANDSHAKE_KEY_EXCHANGE) {
661 return SET_ERRNO(ERROR_INVALID_STATE,
"Invalid state: ctx=%p, state=%d", ctx, ctx ? ctx->state : -1);
664 return SET_ERRNO(ERROR_INVALID_PARAM,
"transport is NULL");
672 if (packet_type == PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE) {
676 ctx->state = CRYPTO_HANDSHAKE_READY;
677 ctx->crypto_ctx.handshake_complete =
true;
678 log_debug(
"Crypto handshake completed successfully (no authentication required)");
683 if (packet_type == PACKET_TYPE_CRYPTO_AUTH_FAILED) {
687 return SET_ERRNO(ERROR_CRYPTO,
"Server rejected authentication - client key not authorized");
691 if (packet_type != PACKET_TYPE_CRYPTO_AUTH_CHALLENGE) {
695 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
696 "Expected AUTH_CHALLENGE, HANDSHAKE_COMPLETE, or AUTH_FAILED, "
697 "got packet type %d",
702 asciichat_error_t validation_result =
704 if (validation_result != ASCIICHAT_OK) {
708 return validation_result;
712 uint8_t auth_flags = payload[0];
717 uint8_t nonce_buffer[256];
718 memcpy(nonce_buffer, payload + 1, ctx->crypto_ctx.auth_challenge_size);
719 const uint8_t *nonce = nonce_buffer;
721 log_debug(
"Server auth requirements: password=%s, client_key=%s",
722 (auth_flags & AUTH_REQUIRE_PASSWORD) ?
"required" :
"no",
723 (auth_flags & AUTH_REQUIRE_CLIENT_KEY) ?
"required" :
"no");
726 bool has_password = ctx->crypto_ctx.has_password;
727 bool has_client_key = (ctx->client_private_key.type == KEY_TYPE_ED25519);
728 bool password_required = (auth_flags & AUTH_REQUIRE_PASSWORD);
729 bool client_key_required = (auth_flags & AUTH_REQUIRE_CLIENT_KEY);
732 if (password_required && !has_password) {
733 if (client_key_required && !has_client_key) {
737 return SET_ERRNO(ERROR_CRYPTO,
"Server requires both password and client key authentication. Please "
738 "provide --password and --key to authenticate");
741 char prompted_password[PASSWORD_BUFFER_SIZE];
742 if (
prompt_password(
"Server password required - please enter password:", prompted_password,
743 sizeof(prompted_password)) != 0) {
747 return SET_ERRNO(ERROR_CRYPTO,
"Failed to read password");
751 log_debug(
"Deriving key from prompted password");
753 sodium_memzero(prompted_password,
sizeof(prompted_password));
755 if (crypto_result != CRYPTO_OK) {
763 ctx->crypto_ctx.has_password =
true;
783 if (password_required) {
788 return SET_ERRNO(ERROR_CRYPTO,
"Server requires password authentication\n"
789 "Please provide --password for this server");
792 result = send_password_auth_response(ctx, transport, nonce,
"required password");
793 if (result != ASCIICHAT_OK) {
794 SET_ERRNO(ERROR_NETWORK,
"Failed to send password auth response");
797 }
else if (client_key_required) {
799 if (!has_client_key) {
800 return SET_ERRNO(ERROR_CRYPTO,
"Server requires client key authentication (whitelist)\n"
801 "Please provide --key with your authorized Ed25519 key");
804 result = send_key_auth_response(ctx, transport, nonce,
"required client key");
805 if (result != ASCIICHAT_OK) {
806 SET_ERRNO(ERROR_NETWORK,
"Failed to send key auth response");
809 }
else if (has_password) {
812 result = send_password_auth_response(ctx, transport, nonce,
"optional password");
813 if (result != ASCIICHAT_OK) {
814 SET_ERRNO(ERROR_NETWORK,
"Failed to send password auth response");
817 }
else if (has_client_key) {
820 result = send_key_auth_response(ctx, transport, nonce,
"optional identity");
821 if (result != ASCIICHAT_OK) {
822 SET_ERRNO(ERROR_NETWORK,
"Failed to send key auth response");
829 log_debug(
"No authentication credentials provided - continuing without "
833 ctx->state = CRYPTO_HANDSHAKE_AUTHENTICATING;
839 packet_type_t packet_type,
const uint8_t *payload,
840 size_t payload_len) {
843 if (!ctx || (ctx->state != CRYPTO_HANDSHAKE_KEY_EXCHANGE && ctx->state != CRYPTO_HANDSHAKE_AUTHENTICATING)) {
844 SET_ERRNO(ERROR_INVALID_STATE,
"Invalid state: ctx=%p, state=%d", ctx, ctx ? ctx->state : -1);
845 return ERROR_INVALID_STATE;
848 return SET_ERRNO(ERROR_INVALID_PARAM,
"transport is NULL");
855 if (packet_type == PACKET_TYPE_CRYPTO_AUTH_FAILED) {
857 if (payload_len >=
sizeof(auth_failure_packet_t)) {
858 auth_failure_packet_t *failure = (auth_failure_packet_t *)payload;
859 SET_ERRNO(ERROR_CRYPTO_AUTH,
"Server rejected authentication:");
861 if (failure->reason_flags & AUTH_FAIL_PASSWORD_INCORRECT) {
862 SET_ERRNO(ERROR_CRYPTO_AUTH,
" - Incorrect password");
864 if (failure->reason_flags & AUTH_FAIL_PASSWORD_REQUIRED) {
865 SET_ERRNO(ERROR_CRYPTO_AUTH,
" - Server requires a password (use --password)");
867 if (failure->reason_flags & AUTH_FAIL_CLIENT_KEY_REQUIRED) {
868 SET_ERRNO(ERROR_CRYPTO_AUTH,
" - Server requires a whitelisted client key (use --key "
869 "with your SSH key)");
871 if (failure->reason_flags & AUTH_FAIL_CLIENT_KEY_REJECTED) {
872 SET_ERRNO(ERROR_CRYPTO_AUTH,
" - Your client key is not in the server's whitelist");
874 if (failure->reason_flags & AUTH_FAIL_SIGNATURE_INVALID) {
875 SET_ERRNO(ERROR_CRYPTO_AUTH,
" - Client signature verification failed");
879 if (failure->reason_flags & (AUTH_FAIL_PASSWORD_INCORRECT | AUTH_FAIL_CLIENT_KEY_REQUIRED)) {
880 if ((failure->reason_flags & AUTH_FAIL_PASSWORD_INCORRECT) &&
881 (failure->reason_flags & AUTH_FAIL_CLIENT_KEY_REQUIRED)) {
882 SET_ERRNO(ERROR_CRYPTO_AUTH,
"Hint: Server requires BOTH correct password AND "
884 }
else if (failure->reason_flags & AUTH_FAIL_PASSWORD_INCORRECT) {
885 SET_ERRNO(ERROR_CRYPTO_AUTH,
"Hint: Check your password and try again");
886 }
else if (failure->reason_flags & AUTH_FAIL_CLIENT_KEY_REQUIRED) {
887 SET_ERRNO(ERROR_CRYPTO_AUTH,
"Hint: Provide your SSH key with --key ~/.ssh/id_ed25519");
888 }
else if (failure->reason_flags & AUTH_FAIL_CLIENT_KEY_REJECTED) {
889 SET_ERRNO(ERROR_CRYPTO_AUTH,
"Hint: Your key needs to be added to the server's whitelist");
893 SET_ERRNO(ERROR_CRYPTO_AUTH,
"Server rejected authentication (no details provided)");
898 return SET_ERRNO(ERROR_CRYPTO_AUTH,
899 "Server authentication failed - incorrect HMAC");
905 if (packet_type == PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE) {
909 ctx->state = CRYPTO_HANDSHAKE_READY;
910 log_info(
"Handshake complete (no authentication required)");
915 if (packet_type != PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP) {
919 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
920 "Expected HANDSHAKE_COMPLETE, SERVER_AUTH_RESPONSE, or AUTH_FAILED, got packet type %d",
926 if (payload_len != ctx->crypto_ctx.hmac_size) {
930 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Invalid SERVER_AUTH_RESPONSE size: %zu bytes (expected %u)", payload_len,
931 ctx->crypto_ctx.hmac_size);
936 SET_ERRNO(ERROR_CRYPTO_AUTH,
"SECURITY: Server authentication failed - incorrect HMAC");
937 SET_ERRNO(ERROR_CRYPTO_AUTH,
"This may indicate a man-in-the-middle attack!");
941 return SET_ERRNO(ERROR_CRYPTO_AUTH,
942 "Server authentication failed - incorrect HMAC");
951 ctx->state = CRYPTO_HANDSHAKE_READY;
952 log_info(
"Server authentication successful - mutual authentication complete");