21 log_debug(
"[HANDSHAKE_START] ===== ENTRY: crypto_handshake_server_start called =====");
22 log_debug(
"[HANDSHAKE_START] ctx=%p, transport=%p", (
void *)ctx, (
void *)transport);
24 if (!ctx || ctx->state != CRYPTO_HANDSHAKE_INIT) {
25 log_error(
"[HANDSHAKE_START] FAILED: Invalid state - ctx=%p, state=%d", (
void *)ctx, ctx ? (
int)ctx->state : -1);
26 return SET_ERRNO(ERROR_INVALID_STATE,
"Invalid state: ctx=%p, state=%d", (
void *)ctx, ctx ? (
int)ctx->state : -1);
28 log_debug(
"[HANDSHAKE_START] State check OK: state=%d (CRYPTO_HANDSHAKE_INIT)", ctx->state);
33 size_t expected_packet_size =
34 ctx->crypto_ctx.public_key_size + ctx->crypto_ctx.auth_public_key_size + ctx->crypto_ctx.signature_size;
36 log_debug(
"SERVER_KEY_EXCHANGE: kex_size=%u, auth_size=%u, sig_size=%u, expected_size=%zu",
37 ctx->crypto_ctx.public_key_size, ctx->crypto_ctx.auth_public_key_size, ctx->crypto_ctx.signature_size,
38 expected_packet_size);
41 if (ctx->server_private_key.type == KEY_TYPE_ED25519) {
44 uint8_t *extended_packet;
45 extended_packet = SAFE_MALLOC(expected_packet_size, uint8_t *);
46 if (!extended_packet) {
47 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate memory for extended packet");
51 memcpy(extended_packet, ctx->crypto_ctx.public_key, ctx->crypto_ctx.public_key_size);
54 memcpy(extended_packet + ctx->crypto_ctx.public_key_size, ctx->server_private_key.public_key,
55 ctx->crypto_ctx.auth_public_key_size);
58 char hex[HEX_STRING_SIZE_32];
59 for (
int i = 0; i < ED25519_PUBLIC_KEY_SIZE; i++) {
60 safe_snprintf(hex + i * 2, 3,
"%02x", ctx->server_private_key.public_key[i]);
62 hex[HEX_STRING_SIZE_32 - 1] =
'\0';
65 log_debug(
"Signing ephemeral key with server identity key");
68 char hex_ephemeral[65], hex_identity[65];
69 for (
int i = 0; i < 32; i++) {
70 safe_snprintf(hex_ephemeral + i * 2, 3,
"%02x", ctx->crypto_ctx.public_key[i]);
71 safe_snprintf(hex_identity + i * 2, 3,
"%02x", ctx->server_private_key.public_key[i]);
73 hex_ephemeral[64] = hex_identity[64] =
'\0';
74 log_debug(
"SERVER: Ephemeral key (32 bytes): %s", hex_ephemeral);
75 log_debug(
"SERVER: Identity public key: %s", hex_identity);
77 if (
ed25519_sign_message(&ctx->server_private_key, ctx->crypto_ctx.public_key, ctx->crypto_ctx.public_key_size,
78 extended_packet + ctx->crypto_ctx.public_key_size +
79 ctx->crypto_ctx.auth_public_key_size) != 0) {
80 SAFE_FREE(extended_packet);
81 return SET_ERRNO(ERROR_CRYPTO,
"Failed to sign ephemeral key with identity key");
84 log_debug(
"Sending authenticated KEY_EXCHANGE_INIT (%zu bytes: ephemeral + "
85 "identity + signature)",
86 expected_packet_size);
87 log_debug(
"[HANDSHAKE_START] Calling packet_send_via_transport(type=%d, payload_len=%zu, 0)...",
88 PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT, expected_packet_size);
90 expected_packet_size, 0);
91 log_debug(
"[HANDSHAKE_START] packet_send_via_transport returned %d", result);
92 SAFE_FREE(extended_packet);
95 log_debug(
"Sending simple KEY_EXCHANGE_INIT (%zu bytes: ephemeral key only)", ctx->crypto_ctx.public_key_size);
96 log_debug(
"[HANDSHAKE_START] Calling packet_send_via_transport(type=%d, payload_len=%zu, 0)...",
97 PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT, ctx->crypto_ctx.public_key_size);
99 ctx->crypto_ctx.public_key_size, 0);
100 log_debug(
"[HANDSHAKE_START] packet_send_via_transport returned %d", result);
103 if (result != ASCIICHAT_OK) {
104 log_error(
"[HANDSHAKE_START] FAILED: packet_send returned %d", result);
105 return SET_ERRNO(ERROR_NETWORK,
"Failed to send KEY_EXCHANGE_INIT packet");
107 log_debug(
"[HANDSHAKE_START] ===== SUCCESS: KEY_EXCHANGE_INIT sent =====");
109 ctx->state = CRYPTO_HANDSHAKE_KEY_EXCHANGE;
115 packet_type_t packet_type,
const uint8_t *payload,
116 size_t payload_len) {
117 if (!ctx || ctx->state != CRYPTO_HANDSHAKE_KEY_EXCHANGE) {
118 return SET_ERRNO(ERROR_INVALID_STATE,
"Invalid state: ctx=%p, state=%d", ctx, ctx ? ctx->state : -1);
121 return SET_ERRNO(ERROR_INVALID_PARAM,
"transport is NULL");
128 if (packet_type == PACKET_TYPE_CRYPTO_NO_ENCRYPTION) {
131 auth_failure_packet_t failure = {0};
132 failure.reason_flags = 0;
135 if (send_result != 0) {
136 return SET_ERRNO(ERROR_NETWORK,
"Failed to send AUTH_FAILED packet");
139 return SET_ERRNO(ERROR_CRYPTO,
"SECURITY: Client sent NO_ENCRYPTION response - encryption mode "
140 "mismatch. Server requires encryption, but "
141 "client has --no-encrypt. Use matching encryption settings on "
142 "both client and server");
146 if (packet_type != PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP) {
147 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Expected KEY_EXCHANGE_RESPONSE, got packet type %d", packet_type);
153 size_t simple_size = ctx->crypto_ctx.public_key_size;
156 size_t authenticated_size = ctx->crypto_ctx.public_key_size + ED25519_PUBLIC_KEY_SIZE + ED25519_SIGNATURE_SIZE;
158 bool client_sent_identity =
false;
159 uint8_t *client_ephemeral_key = SAFE_MALLOC(ctx->crypto_ctx.public_key_size, uint8_t *);
160 uint8_t *client_identity_key = SAFE_MALLOC(ED25519_PUBLIC_KEY_SIZE, uint8_t *);
161 uint8_t *client_signature = SAFE_MALLOC(ED25519_SIGNATURE_SIZE, uint8_t *);
163 if (!client_ephemeral_key || !client_identity_key || !client_signature) {
164 if (client_ephemeral_key)
165 SAFE_FREE(client_ephemeral_key);
166 if (client_identity_key)
167 SAFE_FREE(client_identity_key);
168 if (client_signature)
169 SAFE_FREE(client_signature);
170 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate memory for client keys");
174 asciichat_error_t validation_result =
176 if (validation_result != ASCIICHAT_OK) {
178 SAFE_FREE(client_ephemeral_key);
179 SAFE_FREE(client_identity_key);
180 SAFE_FREE(client_signature);
181 return validation_result;
186 if (payload_len >= authenticated_size) {
189 memcpy(client_ephemeral_key, payload, ctx->crypto_ctx.public_key_size);
190 memcpy(client_identity_key, payload + ctx->crypto_ctx.public_key_size, ED25519_PUBLIC_KEY_SIZE);
191 memcpy(client_signature, payload + ctx->crypto_ctx.public_key_size + ED25519_PUBLIC_KEY_SIZE,
192 ED25519_SIGNATURE_SIZE);
193 client_sent_identity =
true;
194 ctx->client_sent_identity =
true;
197 const char *client_gpg_key_id = NULL;
198 char gpg_key_id_buffer[41] = {0};
199 size_t gpg_offset = ctx->crypto_ctx.public_key_size + ED25519_PUBLIC_KEY_SIZE + ED25519_SIGNATURE_SIZE;
200 if (payload_len > gpg_offset) {
201 uint8_t gpg_key_id_len = payload[gpg_offset];
202 if (gpg_key_id_len > 0 && gpg_key_id_len <= 40 && payload_len >= gpg_offset + 1 + gpg_key_id_len) {
203 memcpy(gpg_key_id_buffer, payload + gpg_offset + 1, gpg_key_id_len);
204 gpg_key_id_buffer[gpg_key_id_len] =
'\0';
205 client_gpg_key_id = gpg_key_id_buffer;
206 log_debug(
"Extracted client GPG key ID from KEY_EXCHANGE_RESPONSE: %s", client_gpg_key_id);
211 bool client_has_null_identity =
true;
212 for (
size_t i = 0; i < ED25519_PUBLIC_KEY_SIZE; i++) {
213 if (client_identity_key[i] != 0) {
214 client_has_null_identity =
false;
219 if (client_has_null_identity) {
221 log_debug(
"Client sent null identity key - no client authentication required");
222 client_sent_identity =
false;
223 ctx->client_sent_identity =
false;
224 log_warn(
"Client connected without identity authentication");
229 if (!ctx->require_client_auth) {
230 log_info(
"Skipping client signature verification (no --client-keys specified)");
231 log_warn(
"Connection is encrypted but client identity is NOT verified");
234 log_debug(
"Verifying client's signature");
237 client_signature, client_gpg_key_id) != 0) {
239 auth_failure_packet_t failure = {0};
240 failure.reason_flags = AUTH_FAIL_SIGNATURE_INVALID;
243 if (send_result != 0) {
244 return SET_ERRNO(ERROR_NETWORK,
"Failed to send AUTH_FAILED packet");
247 return SET_ERRNO(ERROR_CRYPTO,
"Client signature verification FAILED - rejecting connection");
253 if (client_sent_identity) {
254 ctx->client_ed25519_key.type = KEY_TYPE_ED25519;
255 memcpy(ctx->client_ed25519_key.key, client_identity_key, ctx->crypto_ctx.public_key_size);
257 }
else if (payload_len == simple_size) {
259 log_debug(
"Client sent non-authenticated response (%zu bytes)", payload_len);
260 memcpy(client_ephemeral_key, payload, ctx->crypto_ctx.public_key_size);
261 client_sent_identity =
false;
262 ctx->client_sent_identity =
false;
263 log_warn(
"Client connected without identity authentication");
266 SAFE_FREE(client_ephemeral_key);
267 SAFE_FREE(client_identity_key);
268 SAFE_FREE(client_signature);
269 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
270 "Invalid client key response size: %zu bytes (expected %zu for "
271 "authenticated or %zu for simple)",
272 payload_len, authenticated_size, simple_size);
276 const uint8_t *client_x25519 = client_ephemeral_key;
277 const uint8_t *client_ed25519 = client_sent_identity ? client_identity_key : NULL;
281 if (client_sent_identity && ctx->require_client_auth && ctx->client_whitelist && ctx->num_whitelisted_clients > 0) {
282 bool key_found =
false;
285 char client_ed25519_hex[HEX_STRING_SIZE_32];
286 for (
int i = 0; i < ED25519_PUBLIC_KEY_SIZE; i++) {
287 safe_snprintf(client_ed25519_hex + i * 2, 3,
"%02x", client_ed25519[i]);
289 log_debug(
"Client Ed25519 identity key: %s", client_ed25519_hex);
292 for (
size_t i = 0; i < ctx->num_whitelisted_clients; i++) {
294 char whitelist_ed25519_hex[HEX_STRING_SIZE_32];
295 for (
int j = 0; j < ED25519_PUBLIC_KEY_SIZE; j++) {
296 safe_snprintf(whitelist_ed25519_hex + j * 2, 3,
"%02x", ctx->client_whitelist[i].key[j]);
298 log_debug(
"Whitelist[%zu] Ed25519 key: %s", i, whitelist_ed25519_hex);
302 if (sodium_memcmp(client_ed25519, ctx->client_whitelist[i].key, ED25519_PUBLIC_KEY_SIZE) == 0) {
304 ctx->client_ed25519_key_verified =
true;
307 memcpy(&ctx->client_ed25519_key, &ctx->client_whitelist[i],
sizeof(public_key_t));
309 log_debug(
"Client Ed25519 key authorized (whitelist entry %zu)", i);
310 if (strlen(ctx->client_whitelist[i].comment) > 0) {
311 log_info(
"Client identity: %s", ctx->client_whitelist[i].comment);
318 SET_ERRNO(ERROR_CRYPTO_AUTH,
"Client Ed25519 key not in whitelist - rejecting connection");
321 ctx->client_ed25519_key_verified =
false;
323 }
else if (client_sent_identity) {
326 ctx->client_ed25519_key_verified =
false;
331 if (crypto_result != CRYPTO_OK) {
332 return SET_ERRNO(ERROR_CRYPTO,
"Failed to set peer public key and derive shared secret: %s",
337 SAFE_FREE(client_ephemeral_key);
338 SAFE_FREE(client_identity_key);
339 SAFE_FREE(client_signature);
343 if (client_sent_identity || ctx->crypto_ctx.has_password || ctx->require_client_auth) {
346 if (crypto_result != CRYPTO_OK) {
351 size_t challenge_packet_size = AUTH_CHALLENGE_FLAGS_SIZE + ctx->crypto_ctx.auth_challenge_size;
352 uint8_t challenge_packet[1 + HMAC_SHA256_SIZE];
353 uint8_t auth_flags = 0;
356 if (ctx->crypto_ctx.has_password) {
357 auth_flags |= AUTH_REQUIRE_PASSWORD;
359 if (ctx->require_client_auth) {
360 auth_flags |= AUTH_REQUIRE_CLIENT_KEY;
363 challenge_packet[0] = auth_flags;
364 memcpy(challenge_packet + 1, ctx->crypto_ctx.auth_nonce, ctx->crypto_ctx.auth_challenge_size);
368 challenge_packet_size, 0);
370 return SET_ERRNO(ERROR_NETWORK,
"Failed to send AUTH_CHALLENGE packet");
373 ctx->state = CRYPTO_HANDSHAKE_AUTHENTICATING;
376 log_debug(
"Skipping authentication (no password and client has no identity key)");
381 return SET_ERRNO(ERROR_NETWORK,
"Failed to send HANDSHAKE_COMPLETE packet");
384 ctx->state = CRYPTO_HANDSHAKE_READY;
385 ctx->crypto_ctx.handshake_complete =
true;
386 log_debug(
"Crypto handshake completed successfully (no authentication)");
393 packet_type_t packet_type,
const uint8_t *payload,
394 size_t payload_len) {
395 if (!ctx || ctx->state != CRYPTO_HANDSHAKE_AUTHENTICATING) {
396 return SET_ERRNO(ERROR_INVALID_STATE,
"Invalid state: ctx=%p, state=%d", ctx, ctx ? ctx->state : -1);
399 return SET_ERRNO(ERROR_INVALID_PARAM,
"transport is NULL");
406 if (packet_type != PACKET_TYPE_CRYPTO_AUTH_RESPONSE) {
407 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Expected AUTH_RESPONSE, got packet type %d", packet_type);
411 if (ctx->crypto_ctx.has_password) {
413 asciichat_error_t validation_result =
415 if (validation_result != ASCIICHAT_OK) {
416 return validation_result;
421 if (!ctx->crypto_ctx.key_exchange_complete) {
422 SET_ERRNO(ERROR_CRYPTO,
"Password authentication failed - key exchange not complete");
425 auth_failure_packet_t failure = {0};
426 failure.reason_flags = AUTH_FAIL_PASSWORD_INCORRECT;
427 if (ctx->require_client_auth) {
428 failure.reason_flags |= AUTH_FAIL_CLIENT_KEY_REQUIRED;
431 return ERROR_NETWORK;
435 log_debug(
"Verifying password HMAC: has_password=%d, key_exchange_complete=%d", ctx->crypto_ctx.has_password,
436 ctx->crypto_ctx.key_exchange_complete);
438 SET_ERRNO(ERROR_INVALID_PARAM,
"Payload is NULL in password authentication");
442 log_debug(
"Password HMAC verification failed");
444 if (ctx->require_client_auth) {
445 SET_ERRNO(ERROR_CRYPTO,
446 "Password authentication failed - incorrect password (server also requires whitelisted client key)");
448 SET_ERRNO(ERROR_CRYPTO,
"Password authentication failed - incorrect password");
452 auth_failure_packet_t failure = {0};
453 failure.reason_flags = AUTH_FAIL_PASSWORD_INCORRECT;
454 if (ctx->require_client_auth) {
455 failure.reason_flags |= AUTH_FAIL_CLIENT_KEY_REQUIRED;
458 return ERROR_NETWORK;
463 memcpy(ctx->client_challenge_nonce, payload + ctx->crypto_ctx.hmac_size, ctx->crypto_ctx.auth_challenge_size);
464 log_info(
"Password authentication successful");
467 size_t expected_min_signature_size =
468 ctx->crypto_ctx.signature_size + ctx->crypto_ctx.auth_challenge_size + 1;
469 size_t expected_password_size = ctx->crypto_ctx.hmac_size + ctx->crypto_ctx.auth_challenge_size;
471 SET_ERRNO(ERROR_INVALID_PARAM,
"Payload is NULL in signature authentication");
474 if (payload_len >= expected_min_signature_size) {
476 const uint8_t *signature = payload;
477 const uint8_t *client_nonce = payload + ctx->crypto_ctx.signature_size;
480 size_t gpg_offset = ctx->crypto_ctx.signature_size + ctx->crypto_ctx.auth_challenge_size;
481 uint8_t gpg_key_id_len = payload[gpg_offset];
482 const char *client_gpg_key_id = NULL;
483 char gpg_key_id_buffer[41] = {0};
485 if (gpg_key_id_len > 0 && gpg_key_id_len <= 40) {
487 if (payload_len >= gpg_offset + 1 + gpg_key_id_len) {
488 memcpy(gpg_key_id_buffer, payload + gpg_offset + 1, gpg_key_id_len);
489 gpg_key_id_buffer[gpg_key_id_len] =
'\0';
490 client_gpg_key_id = gpg_key_id_buffer;
491 log_debug(
"Extracted client GPG key ID from AUTH_RESPONSE: %s", client_gpg_key_id);
497 if (ctx->client_ed25519_key_verified) {
500 log_debug(
"Verifying %s signature on challenge nonce",
501 ctx->client_ed25519_key.type == KEY_TYPE_GPG ?
"GPG" :
"Ed25519");
504 ctx->client_ed25519_key.key, ctx->crypto_ctx.auth_nonce, ctx->crypto_ctx.auth_challenge_size, signature,
508 if (verify_result != ASCIICHAT_OK) {
509 auth_failure_packet_t failure = {0};
510 failure.reason_flags = AUTH_FAIL_CLIENT_KEY_REJECTED;
511 SET_ERRNO(ERROR_CRYPTO_AUTH,
"%s signature verification failed on challenge nonce",
512 ctx->client_ed25519_key.type == KEY_TYPE_GPG ?
"GPG" :
"Ed25519");
514 return ERROR_CRYPTO_AUTH;
516 log_debug(
"%s signature on challenge nonce verified successfully",
517 ctx->client_ed25519_key.type == KEY_TYPE_GPG ?
"GPG" :
"Ed25519");
520 memcpy(ctx->client_challenge_nonce, client_nonce, ctx->crypto_ctx.auth_challenge_size);
521 }
else if (payload_len == expected_password_size) {
524 memcpy(ctx->client_challenge_nonce, payload + ctx->crypto_ctx.hmac_size, ctx->crypto_ctx.auth_challenge_size);
527 asciichat_error_t validation_result =
529 if (validation_result != ASCIICHAT_OK) {
530 return validation_result;
536 if (ctx->require_client_auth) {
537 if (!ctx->client_ed25519_key_verified) {
539 auth_failure_packet_t failure = {0};
542 if (ctx->client_sent_identity) {
543 SET_ERRNO(ERROR_CRYPTO_AUTH,
"Client key authentication failed - your key is not in the server's whitelist");
544 failure.reason_flags = AUTH_FAIL_CLIENT_KEY_REJECTED;
546 SET_ERRNO(ERROR_CRYPTO_AUTH,
"Client key authentication failed - client did not provide a key");
547 failure.reason_flags = AUTH_FAIL_CLIENT_KEY_REQUIRED;
550 if (ctx->crypto_ctx.has_password) {
552 SET_ERRNO(ERROR_CRYPTO_AUTH,
"Note: Password was correct, but client key is required");
555 return ERROR_NETWORK;
557 log_info(
"Client key authentication successful (whitelist verified)");
558 if (strlen(ctx->client_ed25519_key.comment) > 0) {
559 log_info(
"Authenticated client: %s", ctx->client_ed25519_key.comment);
566 uint8_t server_hmac[HMAC_SHA256_SIZE];
567 crypto_result_t crypto_result =
569 if (crypto_result != CRYPTO_OK) {
570 SET_ERRNO(ERROR_CRYPTO,
"Failed to compute server HMAC for mutual authentication: %s",
572 return ERROR_NETWORK;
575 log_debug(
"Sending SERVER_AUTH_RESPONSE packet with server HMAC (%u bytes) "
576 "for mutual authentication",
577 ctx->crypto_ctx.hmac_size);
579 ctx->crypto_ctx.hmac_size, 0);
580 if (result != ASCIICHAT_OK) {
581 SET_ERRNO(ERROR_NETWORK,
"Failed to send SERVER_AUTH_RESPONSE packet");
582 return ERROR_NETWORK;
585 ctx->state = CRYPTO_HANDSHAKE_READY;
586 log_debug(
"Crypto handshake completed successfully (mutual authentication)");