ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
Cryptographic Operations

🔐 Client-side cryptographic handshake and key management More...

Files

file  crypto.c
 🔐 Client cryptography: handshake integration, X25519 key exchange, and per-session encryption
 
file  crypto.h
 ascii-chat Client Cryptography Handler Interface
 

Functions

void client_crypto_set_mode (uint8_t mode)
 Set crypto mode for handshake (encryption + authentication)
 
int client_crypto_init (void)
 Initialize client crypto handshake.
 
int client_crypto_handshake (socket_t socket)
 Perform crypto handshake with server.
 
bool crypto_client_is_ready (void)
 Check if crypto handshake is ready.
 
const crypto_context_t * crypto_client_get_context (void)
 Get crypto context for encryption/decryption.
 
int crypto_client_encrypt_packet (const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_len)
 Encrypt a packet for transmission.
 
int crypto_client_decrypt_packet (const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_len)
 Decrypt a received packet.
 
void crypto_client_cleanup (void)
 Cleanup crypto client resources.
 
bool crypto_client_should_rekey (void)
 Check if session rekeying should be triggered.
 
int crypto_client_initiate_rekey (void)
 Initiate session rekeying (client-initiated)
 
int crypto_client_process_rekey_request (const uint8_t *packet, size_t packet_len)
 Process received REKEY_REQUEST packet from server.
 
int crypto_client_send_rekey_response (void)
 Send REKEY_RESPONSE packet to server.
 
int crypto_client_process_rekey_response (const uint8_t *packet, size_t packet_len)
 Process received REKEY_RESPONSE packet from server.
 
int crypto_client_send_rekey_complete (void)
 Send REKEY_COMPLETE packet to server and commit to new key.
 

Detailed Description

🔐 Client-side cryptographic handshake and key management

Cryptographic Operations

Overview

The client crypto subsystem coordinates the cryptographic handshake with the server, loads client and server keys, verifies host identity, and manages the encryption context for secure communication.

Implementation: src/client/crypto.c, src/client/crypto.h

Handshake Process

{
crypto_handshake_context_t handshake_ctx;
// Perform client-side handshake
crypto_handshake_result_t result =
perform_crypto_handshake_client(socket, &handshake_ctx,
opt_server_key, server_ip, opt_client_key);
switch (result) {
case HANDSHAKE_SUCCESS:
log_info("Secure connection established");
g_crypto_ctx = handshake_ctx.crypto_ctx;
g_crypto_ready = true;
return 0;
case HANDSHAKE_WARNING_NO_CLIENT_AUTH:
log_warn("Server not verifying client identity");
g_crypto_ctx = handshake_ctx.crypto_ctx;
g_crypto_ready = true;
case HANDSHAKE_ERROR_AUTH_FAILED:
log_error("Client authentication failed - wrong client key?");
return CONNECTION_ERROR_AUTH_FAILED; // No retry
case HANDSHAKE_ERROR_HOST_KEY_FAILED:
log_error("Server host key verification failed");
default:
log_error("Handshake failed");
return CONNECTION_ERROR_GENERIC; // Allow retry
}
}
@ CONNECTION_ERROR_GENERIC
Generic error (retry allowed)
@ CONNECTION_ERROR_HOST_KEY_FAILED
Host key verification failed (no retry)
@ CONNECTION_ERROR_AUTH_FAILED
Authentication failure (no retry)
@ CONNECTION_WARNING_NO_CLIENT_AUTH
Server not using client verification (warning)
crypto_handshake_context_t g_crypto_ctx
Global crypto handshake context for this client connection.
int client_crypto_handshake(socket_t socket)
Perform crypto handshake with server.
int socket_t

Key Management

Client Keys (--client-key):

  • Ed25519 SSH private keys for client authentication
  • Loaded from filesystem or SSH agent
  • Password support via $ASCII_CHAT_KEY_PASSWORD

Server Keys (--server-key):

  • Ed25519 SSH public keys for server verification
  • Can be loaded from:
    • Filesystem path (~/.ssh/server_id_ed25519.pub)
    • GitHub URL (github:username)
    • GitLab URL (gitlab:username)
  • Verified against known_hosts file
Note
Native Decryption: Encrypted SSH keys are decrypted natively using bcrypt_pbkdf (from libsodium-bcrypt-pbkdf) + BearSSL AES-256-CTR. No external tools required. Alternatively, use $SSH_AUTH_SOCK (ssh-agent) for password-free authentication.

Known Hosts Verification

TOFU (Trust On First Use):

  • First connection: Record server public key by IP
  • Subsequent connections: Verify key matches recorded value
  • Key mismatch: Connection rejected (possible MITM attack)

Known hosts file: ~/.ascii-chat/known_hosts

See also
src/client/crypto.c
src/client/crypto.h
lib/crypto/handshake.h
lib/crypto/keys/keys.h
Client Overview

Function Documentation

◆ client_crypto_handshake()

int client_crypto_handshake ( socket_t  socket)

#include <crypto.c>

Perform crypto handshake with server.

Perform crypto handshake with server

Parameters
socketConnected socket to server
Returns
0 on success, -1 on failure

Executes the complete cryptographic handshake protocol with the server, including protocol negotiation, key exchange, and authentication.

Parameters
socketConnected socket to server
Returns
0 on success, -1 on failure

Definition at line 441 of file src/client/crypto.c.

441 {
442 // If client has --no-encrypt, skip handshake entirely
443 if (GET_OPTION(no_encrypt)) {
444 log_debug("Client has --no-encrypt, skipping crypto handshake");
445 return 0;
446 }
447
448 // If we reach here, crypto must be initialized for encryption
449 static_mutex_lock(&g_crypto_init_mutex);
450 bool is_initialized = g_crypto_initialized;
451 static_mutex_unlock(&g_crypto_init_mutex);
452
453 if (!is_initialized) {
454 log_error("Crypto not initialized but server requires encryption");
455 log_error("Server requires encrypted connection but client has no encryption configured");
456 log_error("Use --key to specify a client key or --password for password authentication");
457 return CONNECTION_ERROR_AUTH_FAILED; // No retry - configuration error
458 }
459
460 log_debug("Starting crypto handshake with server...");
461
462 START_TIMER("client_crypto_handshake");
463
464 // Step 0a: Send protocol version to server
465 protocol_version_packet_t client_version = {0};
466 client_version.protocol_version = HOST_TO_NET_U16(1); // Protocol version 1
467 client_version.protocol_revision = HOST_TO_NET_U16(0); // Revision 0
468 client_version.supports_encryption = g_crypto_mode; // Send crypto mode bitmask
469 client_version.compression_algorithms = 0; // No compression for now
470 client_version.compression_threshold = 0;
471 client_version.feature_flags = 0;
472
473 int result = send_protocol_version_packet(socket, &client_version);
474 if (result != 0) {
475 log_error("Failed to send protocol version to server");
476 STOP_TIMER("client_crypto_handshake");
477 return -1;
478 }
479 log_debug("CLIENT_CRYPTO_HANDSHAKE: Protocol version sent successfully");
480
481 // Step 0b: Receive server's protocol version
482 packet_type_t packet_type;
483 void *payload = NULL;
484 size_t payload_len = 0;
485
486 result = receive_packet(socket, &packet_type, &payload, &payload_len);
487 if (result != ASCIICHAT_OK || packet_type != PACKET_TYPE_PROTOCOL_VERSION) {
488 log_error("Failed to receive server protocol version (got type %u)", packet_type);
489 log_error("Packet type 0x%x (decimal %u) - Expected 0x%x (decimal %d)", packet_type, packet_type,
490 PACKET_TYPE_PROTOCOL_VERSION, PACKET_TYPE_PROTOCOL_VERSION);
491 log_error("This suggests a protocol mismatch or packet corruption");
492 log_error("Raw packet type bytes: %02x %02x %02x %02x", (packet_type >> 0) & 0xFF, (packet_type >> 8) & 0xFF,
493 (packet_type >> 16) & 0xFF, (packet_type >> 24) & 0xFF);
494 if (payload) {
495 buffer_pool_free(NULL, payload, payload_len);
496 }
497 STOP_TIMER("client_crypto_handshake");
498 return -1;
499 }
500
501 if (payload_len != sizeof(protocol_version_packet_t)) {
502 log_error("Invalid protocol version packet size: %zu, expected %zu", payload_len,
503 sizeof(protocol_version_packet_t));
504 buffer_pool_free(NULL, payload, payload_len);
505 STOP_TIMER("client_crypto_handshake");
506 return -1;
507 }
508
509 protocol_version_packet_t server_version;
510 memcpy(&server_version, payload, sizeof(protocol_version_packet_t));
511 buffer_pool_free(NULL, payload, payload_len);
512
513 // Convert from network byte order
514 uint16_t server_proto_version = NET_TO_HOST_U16(server_version.protocol_version);
515 uint16_t server_proto_revision = NET_TO_HOST_U16(server_version.protocol_revision);
516 uint8_t server_mode = server_version.supports_encryption;
517
518 log_info("Server protocol version: %u.%u (crypto mode: 0x%02x)", server_proto_version, server_proto_revision,
519 server_mode);
520
521 // Verify server echoed our mode
522 if (server_mode != g_crypto_mode) {
523 log_error("Server mode mismatch: got 0x%02x, expected 0x%02x", server_mode, g_crypto_mode);
524 STOP_TIMER("client_crypto_handshake");
526 }
527
528 // Step 0c: Send crypto capabilities to server
529 log_debug("CLIENT_CRYPTO_HANDSHAKE: Sending crypto capabilities");
530 crypto_capabilities_packet_t client_caps = {0};
531 client_caps.supported_kex_algorithms = HOST_TO_NET_U16(KEX_ALGO_X25519);
532 client_caps.supported_auth_algorithms = HOST_TO_NET_U16(AUTH_ALGO_ED25519 | AUTH_ALGO_NONE);
533 client_caps.supported_cipher_algorithms = HOST_TO_NET_U16(CIPHER_ALGO_XSALSA20_POLY1305 | CIPHER_ALGO_NONE);
534 client_caps.requires_verification = 0; // Client doesn't require server verification (uses known_hosts)
535 client_caps.preferred_kex = KEX_ALGO_X25519;
536 client_caps.preferred_auth = ACIP_CRYPTO_HAS_AUTH(g_crypto_mode) ? AUTH_ALGO_ED25519 : AUTH_ALGO_NONE;
537 client_caps.preferred_cipher =
538 ACIP_CRYPTO_HAS_ENCRYPT(g_crypto_mode) ? CIPHER_ALGO_XSALSA20_POLY1305 : CIPHER_ALGO_NONE;
539
540 result = send_crypto_capabilities_packet(socket, &client_caps);
541 if (result != 0) {
542 log_error("Failed to send crypto capabilities to server");
543 STOP_TIMER("client_crypto_handshake");
544 return -1;
545 }
546 log_debug("CLIENT_CRYPTO_HANDSHAKE: Crypto capabilities sent successfully");
547
548 // Step 0d: Receive server's crypto parameters
549 log_debug("CLIENT_CRYPTO_HANDSHAKE: Receiving server crypto parameters");
550 payload = NULL;
551 payload_len = 0;
552
553 result = receive_packet(socket, &packet_type, &payload, &payload_len);
554 if (result != ASCIICHAT_OK || packet_type != PACKET_TYPE_CRYPTO_PARAMETERS) {
555 log_error("Failed to receive server crypto parameters (got type %u)", packet_type);
556 if (payload) {
557 buffer_pool_free(NULL, payload, payload_len);
558 }
559 STOP_TIMER("client_crypto_handshake");
560 return -1;
561 }
562
563 if (payload_len != sizeof(crypto_parameters_packet_t)) {
564 log_error("Invalid crypto parameters packet size: %zu, expected %zu", payload_len,
565 sizeof(crypto_parameters_packet_t));
566 buffer_pool_free(NULL, payload, payload_len);
567 STOP_TIMER("client_crypto_handshake");
568 return -1;
569 }
570
571 crypto_parameters_packet_t server_params;
572 memcpy(&server_params, payload, sizeof(crypto_parameters_packet_t));
573 buffer_pool_free(NULL, payload, payload_len);
574
575 // Convert from network byte order
576 uint16_t kex_pubkey_size = NET_TO_HOST_U16(server_params.kex_public_key_size);
577 uint16_t auth_pubkey_size = NET_TO_HOST_U16(server_params.auth_public_key_size);
578 uint16_t signature_size = NET_TO_HOST_U16(server_params.signature_size);
579 uint16_t shared_secret_size = NET_TO_HOST_U16(server_params.shared_secret_size);
580
581 log_debug("Server crypto parameters: KEX=%u, Auth=%u, Cipher=%u (key_size=%u, auth_size=%u, sig_size=%u, "
582 "secret_size=%u, verification=%u)",
583 server_params.selected_kex, server_params.selected_auth, server_params.selected_cipher, kex_pubkey_size,
584 auth_pubkey_size, signature_size, shared_secret_size, server_params.verification_enabled);
585 log_debug("Raw server_params.kex_public_key_size = %u (network byte order)", server_params.kex_public_key_size);
586
587 // Set the crypto parameters in the handshake context
588 result = crypto_handshake_set_parameters(&g_crypto_ctx, &server_params);
589 if (result != ASCIICHAT_OK) {
590 FATAL(result, "Failed to set crypto parameters");
591 }
592
593 // Store verification flag - server will verify client identity (whitelist check)
594 // This is independent of whether server provides its own identity
595 if (server_params.verification_enabled) {
596 g_crypto_ctx.server_uses_client_auth = true;
597 g_crypto_ctx.require_client_auth = true;
598 log_info("Server will verify client identity (whitelist enabled)");
599 }
600
601 // Validate that server chose algorithms we support
602 if (server_params.selected_kex != KEX_ALGO_X25519) {
603 log_error("Server selected unsupported KEX algorithm: %u", server_params.selected_kex);
604 STOP_TIMER("client_crypto_handshake");
606 }
607
608 // Validate cipher selection based on negotiated mode
609 bool expect_cipher = ACIP_CRYPTO_HAS_ENCRYPT(g_crypto_mode);
610 if (expect_cipher && server_params.selected_cipher != CIPHER_ALGO_XSALSA20_POLY1305) {
611 log_error("Server selected unsupported cipher algorithm: %u", server_params.selected_cipher);
612 STOP_TIMER("client_crypto_handshake");
614 }
615 if (!expect_cipher && server_params.selected_cipher != CIPHER_ALGO_NONE) {
616 log_error("Server chose cipher %u but client requested no encryption", server_params.selected_cipher);
617 STOP_TIMER("client_crypto_handshake");
619 }
620
621 log_debug("CLIENT_CRYPTO_HANDSHAKE: Protocol negotiation completed successfully");
622
623 // Step 0.5: Send CRYPTO_CLIENT_HELLO with expected server key (multi-key support)
624 // This allows the server to select the correct identity key from g_server_identity_keys[]
625 if (g_crypto_ctx.verify_server_key && strlen(g_crypto_ctx.expected_server_key) > 0) {
626 log_debug("CLIENT_CRYPTO_HANDSHAKE: Sending expected server key to support multi-key selection");
627
628 // Parse expected server key to get the Ed25519 public key
629 public_key_t expected_keys[MAX_CLIENTS];
630 size_t num_expected_keys = 0;
631
632 if (parse_public_keys(g_crypto_ctx.expected_server_key, expected_keys, &num_expected_keys, MAX_CLIENTS) == 0 &&
633 num_expected_keys > 0) {
634 // Send the first expected key (client should only have one expected server key)
635 // Format: 32-byte Ed25519 public key
636 log_debug("Sending CRYPTO_CLIENT_HELLO with expected server key for multi-key selection");
637 result = send_packet(socket, PACKET_TYPE_CRYPTO_CLIENT_HELLO, expected_keys[0].key, ED25519_PUBLIC_KEY_SIZE);
638
639 if (result != ASCIICHAT_OK) {
640 FATAL(result, "Failed to send CRYPTO_CLIENT_HELLO packet");
641 }
642
643 // Log the key fingerprint for debugging
644 char hex_key[65];
645 pubkey_to_hex(expected_keys[0].key, hex_key);
646 log_debug("Sent expected server key: %s", hex_key);
647 } else {
648 log_warn("Failed to parse expected server key '%s' - server will use default key",
649 g_crypto_ctx.expected_server_key);
650 }
651 }
652
653 // Step 1: Receive server's public key and send our public key
654 log_debug("CLIENT_CRYPTO_HANDSHAKE: Starting key exchange");
656 if (result != ASCIICHAT_OK) {
657#ifdef _WIN32
658 // On Windows: Cleanup capture resources before exiting to prevent Media Foundation threads from hanging exit()
659 // Media Foundation creates background COM threads that can block exit() if not properly shut down
661#endif
662 FATAL(result, "Crypto key exchange failed");
663 }
664 log_debug("CLIENT_CRYPTO_HANDSHAKE: Key exchange completed successfully");
665
666 // SECURITY: Warn when server requires client verification but client has no identity key
667 bool client_has_identity = (g_crypto_ctx.client_public_key.type == KEY_TYPE_ED25519);
668
669 if (g_crypto_ctx.require_client_auth && !client_has_identity) {
670 // Server requires client verification but client has no identity key
671 log_warn("Server requires client verification but client has no identity key");
672
673 // Check if we're running interactively (stdin is a terminal)
674 // In debug builds with CLAUDECODE, skip interactive prompts (LLM can't type)
675#ifndef NDEBUG
676 bool skip_interactive = platform_getenv("CLAUDECODE") != NULL;
677#else
678 bool skip_interactive = false;
679#endif
680 if (!skip_interactive && platform_is_interactive()) {
681 // Interactive mode - prompt user for confirmation
682 // Lock terminal for the warning message
683 bool previous_terminal_state = log_lock_terminal();
684
685 log_plain("\n"
686 "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
687 "@ WARNING: CLIENT AUTHENTICATION REQUIRED @\n"
688 "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
689 "\n"
690 "The server requires client authentication (--client-keys enabled),\n"
691 "but you have not provided a client identity key with --key.\n"
692 "\n"
693 "To connect to this server, you need to:\n"
694 " 1. Generate an Ed25519 key: ssh-keygen -t ed25519\n"
695 " 2. Add the public key to the server's --client-keys list\n"
696 " 3. Connect with: ascii-chat client --key /path/to/private/key\n");
697
698 // Unlock before prompt (prompt_yes_no handles its own terminal locking)
699 log_unlock_terminal(previous_terminal_state);
700
701 // Prompt user - default is No since this will likely fail
702 if (!platform_prompt_yes_no("Do you want to continue anyway (this will likely fail)", false)) {
703 log_plain("Connection aborted by user.");
704 exit(0); // User declined - exit cleanly
705 }
706
707 log_plain("Warning: Continuing without client identity key (connection may fail).\n");
708 } else {
709 // Non-interactive mode (background/script) - just log warning and continue
710 log_warn("Non-interactive mode: Continuing without client identity key (connection may fail)");
711 }
712 }
713
714 // Step 2: Receive auth challenge and send response
715 log_debug("CLIENT_CRYPTO: Sending auth response to server...");
716 log_debug("CLIENT_CRYPTO_HANDSHAKE: Starting auth response");
718 if (result != ASCIICHAT_OK) {
719 FATAL(result, "Crypto authentication failed");
720 }
721 log_debug("CLIENT_CRYPTO: Auth response sent successfully");
722 log_debug("CLIENT_CRYPTO_HANDSHAKE: Auth response completed successfully");
723
724 // Check if handshake completed during auth response (no authentication needed)
725 if (g_crypto_ctx.state == CRYPTO_HANDSHAKE_READY) {
726 // Propagate encryption flag to crypto context
727 g_crypto_ctx.crypto_ctx.encrypt_data = ACIP_CRYPTO_HAS_ENCRYPT(g_crypto_mode);
728 STOP_TIMER_AND_LOG(debug, 100 * NS_PER_MS_INT, "client_crypto_handshake",
729 "Crypto handshake completed successfully (no authentication)");
730 return 0;
731 }
732
733 // Step 3: Receive handshake complete message
734 log_debug("CLIENT_CRYPTO_HANDSHAKE: Waiting for handshake complete message");
736 if (result != ASCIICHAT_OK) {
737 FATAL(result, "Crypto handshake completion failed");
738 }
739
740 // Propagate encryption flag to crypto context
741 g_crypto_ctx.crypto_ctx.encrypt_data = ACIP_CRYPTO_HAS_ENCRYPT(g_crypto_mode);
742
743 STOP_TIMER_AND_LOG(debug, 100 * NS_PER_MS_INT, "client_crypto_handshake", "Crypto handshake completed successfully");
744 log_debug("CLIENT_CRYPTO_HANDSHAKE: Handshake completed successfully, state=%d", g_crypto_ctx.state);
745 return 0;
746}
void buffer_pool_free(buffer_pool_t *pool, void *data, size_t size)
asciichat_error_t crypto_handshake_set_parameters(crypto_handshake_context_t *ctx, const crypto_parameters_packet_t *params)
void pubkey_to_hex(const uint8_t pubkey[32], char hex_out[65])
Definition discovery.c:49
void capture_cleanup()
Cleanup capture subsystem.
asciichat_error_t parse_public_keys(const char *input, public_key_t *keys_out, size_t *num_keys, size_t max_keys)
Definition keys.c:345
asciichat_error_t crypto_handshake_client_complete_socket(crypto_handshake_context_t *ctx, socket_t client_socket)
Legacy wrapper: Complete handshake using socket (TCP clients only)
asciichat_error_t crypto_handshake_client_auth_response_socket(crypto_handshake_context_t *ctx, socket_t client_socket)
Legacy wrapper: Auth response using socket (TCP clients only)
asciichat_error_t crypto_handshake_client_key_exchange_socket(crypto_handshake_context_t *ctx, socket_t client_socket)
Legacy wrapper: Key exchange using socket (TCP clients only)
bool log_lock_terminal(void)
void log_unlock_terminal(bool previous_state)
int send_protocol_version_packet(socket_t sockfd, const protocol_version_packet_t *version)
Send protocol version packet.
Definition packet.c:1013
int receive_packet(socket_t sockfd, packet_type_t *type, void **data, size_t *len)
Receive a basic packet without encryption.
Definition packet.c:766
int send_packet(socket_t sockfd, packet_type_t type, const void *data, size_t len)
Send a basic packet without encryption.
Definition packet.c:753
int send_crypto_capabilities_packet(socket_t sockfd, const crypto_capabilities_packet_t *caps)
Send crypto capabilities packet.
Definition packet.c:1027
bool platform_prompt_yes_no(const char *question, bool default_yes)
Definition util.c:81
const char * platform_getenv(const char *name)
Definition wasm/system.c:13

References buffer_pool_free(), capture_cleanup(), CONNECTION_ERROR_AUTH_FAILED, crypto_handshake_client_auth_response_socket(), crypto_handshake_client_complete_socket(), crypto_handshake_client_key_exchange_socket(), crypto_handshake_set_parameters(), g_crypto_ctx, log_lock_terminal(), log_unlock_terminal(), parse_public_keys(), platform_getenv(), platform_prompt_yes_no(), pubkey_to_hex(), receive_packet(), send_crypto_capabilities_packet(), send_packet(), and send_protocol_version_packet().

Referenced by connection_attempt_tcp(), and server_connection_establish().

◆ client_crypto_init()

int client_crypto_init ( void  )

#include <crypto.c>

Initialize client crypto handshake.

Initialize client crypto handshake

Returns
0 on success, -1 on failure

Sets up the client-side cryptographic context with authentication credentials. Supports SSH key, password, and passwordless modes.

Returns
0 on success, -1 on failure

Definition at line 208 of file src/client/crypto.c.

208 {
209 log_debug("CLIENT_CRYPTO_INIT: Starting crypto initialization");
210
211 // Check and reset initialization state with thread safety
212 static_mutex_lock(&g_crypto_init_mutex);
213 bool was_initialized = g_crypto_initialized;
214 g_crypto_initialized = false;
215 static_mutex_unlock(&g_crypto_init_mutex);
216
217 if (was_initialized) {
218 log_debug("CLIENT_CRYPTO_INIT: Already initialized, cleaning up and reinitializing");
220 }
221
222 // Check if encryption is disabled
223 if (GET_OPTION(no_encrypt)) {
224 log_info("Encryption disabled");
225 log_debug("CLIENT_CRYPTO_INIT: Encryption disabled, returning 0");
226 return 0;
227 }
228
229 log_debug("CLIENT_CRYPTO_INIT: Initializing crypto handshake context");
230
231 // Check if we have an SSH key, password, or neither
232 int result;
233 bool is_ssh_key = false;
234 private_key_t private_key;
235
236 // Get string options safely
237 const options_t *opts = options_get();
238 const char *encrypt_key = opts && opts->encrypt_key[0] != '\0' ? opts->encrypt_key : "";
239 const char *password = opts && opts->password[0] != '\0' ? opts->password : "";
240 const char *address = opts && opts->address[0] != '\0' ? opts->address : "localhost";
241 int port = opts ? opts->port : OPT_PORT_INT_DEFAULT;
242 const char *server_key = opts && opts->server_key[0] != '\0' ? opts->server_key : "";
243
244 // Load client private key if provided via --key
245 if (strlen(encrypt_key) > 0) {
246 // --key supports file-based authentication (SSH keys, GPG keys via gpg:keyid)
247
248 // For SSH key files (not gpg:keyid format), validate the file exists
249 if (strncmp(encrypt_key, "gpg:", 4) != 0) {
250 if (validate_ssh_key_file(encrypt_key) != 0) {
251 return -1;
252 }
253 }
254
255 // Parse key (handles SSH files and gpg:keyid format)
256 log_debug("CLIENT_CRYPTO_INIT: Loading private key for authentication: %s", encrypt_key);
257 if (parse_private_key(encrypt_key, &private_key) == ASCIICHAT_OK) {
258 log_debug("Successfully parsed SSH private key");
259 log_debug("CLIENT_CRYPTO_INIT: Parsed key type=%d, KEY_TYPE_ED25519=%d", private_key.type, KEY_TYPE_ED25519);
260 is_ssh_key = true;
261 } else {
262 log_error("Failed to parse SSH key file: %s", encrypt_key);
263 log_error("This may be due to:");
264 log_error(" - Wrong password for encrypted key");
265 log_error(" - Unsupported key type (only Ed25519 is currently supported)");
266 log_error(" - Corrupted key file");
267 log_error("");
268 log_error("Note: RSA and ECDSA keys are not yet supported");
269 log_error("To generate an Ed25519 key: ssh-keygen -t ed25519");
270 return -1;
271 }
272 }
273
274 if (is_ssh_key) {
275 // Use SSH private key for authentication
276 log_debug("CLIENT_CRYPTO_INIT: Using SSH key for authentication");
277
278 // Initialize crypto context (generates ephemeral X25519 keys)
279 result = crypto_handshake_init(&g_crypto_ctx, false); // false = client
280 if (result != ASCIICHAT_OK) {
281 FATAL(result, "Failed to initialize crypto handshake");
282 }
283
284 // Store the Ed25519 keys for authentication
285 memcpy(&g_crypto_ctx.client_private_key, &private_key, sizeof(private_key_t));
286
287 // Extract Ed25519 public key from private key
288 g_crypto_ctx.client_public_key.type = KEY_TYPE_ED25519;
289 memcpy(g_crypto_ctx.client_public_key.key, private_key.public_key, ED25519_PUBLIC_KEY_SIZE);
290 SAFE_STRNCPY(g_crypto_ctx.client_public_key.comment, private_key.key_comment,
291 sizeof(g_crypto_ctx.client_public_key.comment) - 1);
292
293 // Extract GPG key ID if this is a GPG key (format: "gpg:KEYID")
294 if (strncmp(encrypt_key, "gpg:", 4) == 0) {
295 const char *key_id = encrypt_key + 4;
296 size_t key_id_len = strlen(key_id);
297 // Accept 8, 16, or 40 character GPG key IDs (short/long/full fingerprint)
298 if (key_id_len == 8 || key_id_len == 16 || key_id_len == 40) {
299 SAFE_STRNCPY(g_crypto_ctx.client_gpg_key_id, key_id, sizeof(g_crypto_ctx.client_gpg_key_id));
300 log_debug("CLIENT_CRYPTO_INIT: Extracted client GPG key ID (%zu chars): %s", key_id_len,
301 g_crypto_ctx.client_gpg_key_id);
302 } else {
303 log_warn("CLIENT_CRYPTO_INIT: Invalid GPG key ID length: %zu (expected 8, 16, or 40)", key_id_len);
304 g_crypto_ctx.client_gpg_key_id[0] = '\0';
305 }
306 } else {
307 // Not a GPG key, clear the field
308 g_crypto_ctx.client_gpg_key_id[0] = '\0';
309 }
310
311 // SSH key is already configured in the handshake context above
312 // No additional setup needed - SSH keys are used only for authentication
313
314 // Clear the temporary private_key variable (we've already copied it to g_crypto_ctx)
315 sodium_memzero(&private_key, sizeof(private_key));
316
317 // If password is also provided, derive password key for dual authentication
318 if (strlen(password) > 0) {
319 log_debug("CLIENT_CRYPTO_INIT: Password also provided, deriving password key");
320 crypto_result_t crypto_result = crypto_derive_password_key(&g_crypto_ctx.crypto_ctx, password);
321 if (crypto_result != CRYPTO_OK) {
322 log_error("Failed to derive password key: %s", crypto_result_to_string(crypto_result));
323 return -1;
324 }
325 g_crypto_ctx.crypto_ctx.has_password = true;
326 log_debug("Password authentication enabled alongside SSH key");
327 }
328
329 } else if (strlen(GET_OPTION(password)) > 0) {
330 // Password provided - use password-based initialization
331 log_debug("CLIENT_CRYPTO_INIT: Using password authentication");
332 result = crypto_handshake_init_with_password(&g_crypto_ctx, false, GET_OPTION(password)); // false = client
333 if (result != ASCIICHAT_OK) {
334 FATAL(result, "Failed to initialize crypto handshake with password");
335 }
336 } else {
337 // No password or SSH key - use standard initialization with random keys
338 log_debug("CLIENT_CRYPTO_INIT: Using standard initialization");
339 result = crypto_handshake_init(&g_crypto_ctx, false); // false = client
340 if (result != ASCIICHAT_OK) {
341 FATAL(result, "Failed to initialize crypto handshake");
342 }
343 }
344
345 log_debug("CLIENT_CRYPTO_INIT: crypto_handshake_init succeeded");
346
347 // Set up server connection info for known_hosts
348 SAFE_STRNCPY(g_crypto_ctx.server_hostname, address, sizeof(g_crypto_ctx.server_hostname) - 1);
349 const char *server_ip = server_connection_get_ip();
350 log_debug("CLIENT_CRYPTO_INIT: server_connection_get_ip() returned: '%s'", server_ip ? server_ip : "NULL");
351 SAFE_STRNCPY(g_crypto_ctx.server_ip, server_ip ? server_ip : "", sizeof(g_crypto_ctx.server_ip) - 1);
352 g_crypto_ctx.server_port = (uint16_t)port;
353 log_debug("CLIENT_CRYPTO_INIT: Set server_ip='%s', server_port=%u", g_crypto_ctx.server_ip, g_crypto_ctx.server_port);
354
355 // Configure server key verification if specified
356 if (strlen(server_key) > 0) {
357 g_crypto_ctx.verify_server_key = true;
358 SAFE_STRNCPY(g_crypto_ctx.expected_server_key, server_key, sizeof(g_crypto_ctx.expected_server_key) - 1);
359 log_debug("Server key verification enabled: %s", server_key);
360 }
361
362 // If --require-client-verify is set, perform ACDS session lookup for server identity
363 if (GET_OPTION(require_client_verify) && strlen(GET_OPTION(session_string)) > 0) {
364 log_debug("--require-client-verify enabled: performing ACDS session lookup for '%s'", GET_OPTION(session_string));
365
366 // Connect to ACDS server (configurable via --acds-server and --acds-port options)
367 acds_client_config_t acds_config;
369 SAFE_STRNCPY(acds_config.server_address, GET_OPTION(discovery_server), sizeof(acds_config.server_address));
370 acds_config.server_port = GET_OPTION(discovery_port);
371 acds_config.timeout_ms = 5 * MS_PER_SEC_INT;
372
373 // ACDS key verification (optional in debug builds, only if --discovery-service-key is provided)
374 if (strlen(GET_OPTION(discovery_service_key)) > 0) {
375 log_debug("Verifying ACDS server key for %s...", acds_config.server_address);
376 uint8_t acds_pubkey[32];
377 asciichat_error_t verify_result =
378 discovery_keys_verify(acds_config.server_address, GET_OPTION(discovery_service_key), acds_pubkey);
379 if (verify_result != ASCIICHAT_OK) {
380 log_error("ACDS key verification failed for %s", acds_config.server_address);
381 return -1;
382 }
383 log_debug("ACDS server key verified successfully");
384 }
385#ifndef NDEBUG
386 else {
387 log_debug("Skipping ACDS key verification (debug build, no --discovery-service-key provided)");
388 }
389#endif
390
391 acds_client_t acds_client;
392 asciichat_error_t acds_result = acds_client_connect(&acds_client, &acds_config);
393 if (acds_result != ASCIICHAT_OK) {
394 log_error("Failed to connect to ACDS server at %s:%d", acds_config.server_address, acds_config.server_port);
395 return -1;
396 }
397
398 // Perform SESSION_LOOKUP to get server's identity
399 acds_session_lookup_result_t lookup_result;
400 acds_result = acds_session_lookup(&acds_client, GET_OPTION(session_string), &lookup_result);
401 acds_client_disconnect(&acds_client);
402
403 if (acds_result != ASCIICHAT_OK || !lookup_result.found) {
404 log_error("ACDS session lookup failed for '%s': %s", GET_OPTION(session_string),
405 lookup_result.found ? "session not found" : "lookup error");
406 return -1;
407 }
408
409 // Convert server's Ed25519 public key (32 bytes) to hex string
410 char server_key_hex[65]; // 32 bytes * 2 + null terminator
411 for (size_t i = 0; i < 32; i++) {
412 SAFE_SNPRINTF(&server_key_hex[i * 2], 3, "%02x", lookup_result.host_pubkey[i]);
413 }
414 server_key_hex[64] = '\0';
415
416 // Set expected server key for verification during handshake
417 g_crypto_ctx.verify_server_key = true;
418 SAFE_STRNCPY(g_crypto_ctx.expected_server_key, server_key_hex, sizeof(g_crypto_ctx.expected_server_key) - 1);
419 log_debug("ACDS session lookup succeeded - server identity will be verified");
420 log_debug("Expected server key (from ACDS): %s", server_key_hex);
421 }
422
423 // Mark initialization as complete with thread safety
424 static_mutex_lock(&g_crypto_init_mutex);
425 g_crypto_initialized = true;
426 static_mutex_unlock(&g_crypto_init_mutex);
427
428 log_debug("Client crypto handshake initialized");
429 log_debug("CLIENT_CRYPTO_INIT: Initialization complete, g_crypto_initialized=true");
430 return 0;
431}
asciichat_error_t acds_session_lookup(acds_client_t *client, const char *session_string, acds_session_lookup_result_t *result)
void acds_client_config_init_defaults(acds_client_config_t *config)
Definition acds_client.c:45
asciichat_error_t acds_client_connect(acds_client_t *client, const acds_client_config_t *config)
Definition acds_client.c:60
void acds_client_disconnect(acds_client_t *client)
void crypto_handshake_destroy(crypto_handshake_context_t *ctx)
asciichat_error_t crypto_handshake_init_with_password(crypto_handshake_context_t *ctx, bool is_server, const char *password)
asciichat_error_t crypto_handshake_init(crypto_handshake_context_t *ctx, bool is_server)
asciichat_error_t discovery_keys_verify(const char *acds_server, const char *key_spec, uint8_t pubkey_out[32])
const char * server_connection_get_ip()
Get resolved server IP address.
asciichat_error_t parse_private_key(const char *key_path, private_key_t *key_out)
Definition keys.c:194
const char * crypto_result_to_string(crypto_result_t result)
crypto_result_t crypto_derive_password_key(crypto_context_t *ctx, const char *password)
const options_t * options_get(void)
Definition rcu.c:347
asciichat_error_t validate_ssh_key_file(const char *key_path)
Definition ssh_keys.c:940

References acds_client_config_init_defaults(), acds_client_connect(), acds_client_disconnect(), acds_session_lookup(), crypto_derive_password_key(), crypto_handshake_destroy(), crypto_handshake_init(), crypto_handshake_init_with_password(), crypto_result_to_string(), discovery_keys_verify(), g_crypto_ctx, options_get(), parse_private_key(), server_connection_get_ip(), and validate_ssh_key_file().

Referenced by connection_attempt_tcp(), connection_attempt_websocket(), and server_connection_establish().

◆ client_crypto_set_mode()

void client_crypto_set_mode ( uint8_t  mode)

#include <crypto.c>

Set crypto mode for handshake (encryption + authentication)

Set crypto mode for handshake (encryption + authentication)

Parameters
modeCrypto mode bitmask (ACIP_CRYPTO_*)

Sets the crypto mode bitmask (ACIP_CRYPTO_*) to negotiate with server. Must be called before client_crypto_init().

Parameters
modeCrypto mode bitmask (ACIP_CRYPTO_NONE, ACIP_CRYPTO_ENCRYPT, ACIP_CRYPTO_AUTH, ACIP_CRYPTO_FULL)

Definition at line 196 of file src/client/crypto.c.

196 {
197 log_debug("CLIENT_CRYPTO: Setting crypto mode to 0x%02x", mode);
198 g_crypto_mode = mode;
199}

Referenced by connection_attempt_tcp().

◆ crypto_client_cleanup()

void crypto_client_cleanup ( void  )

#include <crypto.c>

Cleanup crypto client resources.

Cleanup crypto client resources

Definition at line 819 of file src/client/crypto.c.

819 {
820 // Check and reset initialization state with thread safety
821 static_mutex_lock(&g_crypto_init_mutex);
822 bool was_initialized = g_crypto_initialized;
823 g_crypto_initialized = false;
824 static_mutex_unlock(&g_crypto_init_mutex);
825
826 if (was_initialized) {
828 log_debug("Client crypto handshake cleaned up");
829 }
830}

References crypto_handshake_destroy(), and g_crypto_ctx.

◆ crypto_client_decrypt_packet()

int crypto_client_decrypt_packet ( const uint8_t *  ciphertext,
size_t  ciphertext_len,
uint8_t *  plaintext,
size_t  plaintext_size,
size_t *  plaintext_len 
)

#include <crypto.c>

Decrypt a received packet.

Decrypt a received packet

Parameters
ciphertextEncrypted data to decrypt
ciphertext_lenLength of encrypted data
plaintextOutput buffer for decrypted data
plaintext_sizeSize of output buffer
plaintext_lenOutput length of decrypted data
Returns
0 on success, -1 on failure
Parameters
ciphertextEncrypted data to decrypt
ciphertext_lenLength of encrypted data
plaintextOutput buffer for decrypted data
plaintext_sizeSize of output buffer
plaintext_lenOutput length of decrypted data
Returns
0 on success, -1 on failure

Definition at line 808 of file src/client/crypto.c.

809 {
810 return crypto_decrypt_packet_or_passthrough(&g_crypto_ctx, crypto_client_is_ready(), ciphertext, ciphertext_len,
811 plaintext, plaintext_size, plaintext_len);
812}
asciichat_error_t crypto_decrypt_packet_or_passthrough(const crypto_handshake_context_t *ctx, bool crypto_ready, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_len)
bool crypto_client_is_ready(void)
Check if crypto handshake is ready.

References crypto_client_is_ready(), crypto_decrypt_packet_or_passthrough(), and g_crypto_ctx.

◆ crypto_client_encrypt_packet()

int crypto_client_encrypt_packet ( const uint8_t *  plaintext,
size_t  plaintext_len,
uint8_t *  ciphertext,
size_t  ciphertext_size,
size_t *  ciphertext_len 
)

#include <crypto.c>

Encrypt a packet for transmission.

Encrypt a packet for transmission

Parameters
plaintextPlaintext data to encrypt
plaintext_lenLength of plaintext data
ciphertextOutput buffer for encrypted data
ciphertext_sizeSize of output buffer
ciphertext_lenOutput length of encrypted data
Returns
0 on success, -1 on failure
Parameters
plaintextPlaintext data to encrypt
plaintext_lenLength of plaintext data
ciphertextOutput buffer for encrypted data
ciphertext_sizeSize of output buffer
ciphertext_lenOutput length of encrypted data
Returns
0 on success, -1 on failure

Definition at line 790 of file src/client/crypto.c.

791 {
793 ciphertext, ciphertext_size, ciphertext_len);
794}
asciichat_error_t crypto_encrypt_packet_or_passthrough(const crypto_handshake_context_t *ctx, bool crypto_ready, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_len)

References crypto_client_is_ready(), crypto_encrypt_packet_or_passthrough(), and g_crypto_ctx.

◆ crypto_client_get_context()

const crypto_context_t * crypto_client_get_context ( void  )

#include <crypto.c>

Get crypto context for encryption/decryption.

Get crypto context for encryption/decryption

Returns
crypto context or NULL if not ready
crypto context or NULL if not ready

Definition at line 770 of file src/client/crypto.c.

770 {
771 if (!crypto_client_is_ready()) {
772 return NULL;
773 }
774
776}
const crypto_context_t * crypto_handshake_get_context(const crypto_handshake_context_t *ctx)

References crypto_client_is_ready(), crypto_handshake_get_context(), and g_crypto_ctx.

Referenced by connection_attempt_tcp(), connection_attempt_websocket(), server_connection_establish(), and threaded_send_client_join_packet().

◆ crypto_client_initiate_rekey()

int crypto_client_initiate_rekey ( void  )

#include <crypto.c>

Initiate session rekeying (client-initiated)

Initiate session rekeying (client-initiated)

Returns
0 on success, -1 on failure
0 on success, -1 on failure

Definition at line 857 of file src/client/crypto.c.

857 {
858 if (!g_crypto_initialized || !crypto_client_is_ready()) {
859 log_error("Cannot initiate rekey: crypto not initialized or not ready");
860 return -1;
861 }
862
864 if (socket == INVALID_SOCKET_VALUE) {
865 log_error("Cannot initiate rekey: invalid socket");
866 return -1;
867 }
868
869 asciichat_error_t result = crypto_handshake_rekey_request(&g_crypto_ctx, socket);
870 if (result != ASCIICHAT_OK) {
871 log_error("Failed to send REKEY_REQUEST: %d", result);
872 return -1;
873 }
874
875 return 0;
876}
asciichat_error_t crypto_handshake_rekey_request(crypto_handshake_context_t *ctx, socket_t socket)
socket_t server_connection_get_socket()
Get current socket file descriptor.

References crypto_client_is_ready(), crypto_handshake_rekey_request(), g_crypto_ctx, and server_connection_get_socket().

◆ crypto_client_is_ready()

bool crypto_client_is_ready ( void  )

#include <crypto.c>

Check if crypto handshake is ready.

Check if crypto handshake is ready

Returns
true if encryption is ready, false otherwise
true if encryption is ready, false otherwise

Definition at line 755 of file src/client/crypto.c.

755 {
756 if (!g_crypto_initialized || GET_OPTION(no_encrypt)) {
757 return false;
758 }
759
761}
bool crypto_handshake_is_ready(const crypto_handshake_context_t *ctx)

References crypto_handshake_is_ready(), and g_crypto_ctx.

Referenced by connection_attempt_tcp(), connection_attempt_websocket(), crypto_client_decrypt_packet(), crypto_client_encrypt_packet(), crypto_client_get_context(), crypto_client_initiate_rekey(), crypto_client_process_rekey_request(), crypto_client_process_rekey_response(), crypto_client_send_rekey_complete(), crypto_client_send_rekey_response(), crypto_client_should_rekey(), server_connection_establish(), and threaded_send_client_join_packet().

◆ crypto_client_process_rekey_request()

int crypto_client_process_rekey_request ( const uint8_t *  packet,
size_t  packet_len 
)

#include <crypto.c>

Process received REKEY_REQUEST packet from server.

Process received REKEY_REQUEST packet from server

Parameters
packetPacket data
packet_lenPacket length
Returns
0 on success, -1 on failure
Parameters
packetPacket data
packet_lenPacket length
Returns
0 on success, -1 on failure

Definition at line 887 of file src/client/crypto.c.

887 {
888 if (!g_crypto_initialized || !crypto_client_is_ready()) {
889 log_error("Cannot process rekey request: crypto not initialized or not ready");
890 return -1;
891 }
892
893 asciichat_error_t result = crypto_handshake_process_rekey_request(&g_crypto_ctx, packet, packet_len);
894 if (result != ASCIICHAT_OK) {
895 log_error("Failed to process REKEY_REQUEST: %d", result);
896 return -1;
897 }
898
899 return 0;
900}
asciichat_error_t crypto_handshake_process_rekey_request(crypto_handshake_context_t *ctx, const uint8_t *packet, size_t packet_len)

References crypto_client_is_ready(), crypto_handshake_process_rekey_request(), and g_crypto_ctx.

◆ crypto_client_process_rekey_response()

int crypto_client_process_rekey_response ( const uint8_t *  packet,
size_t  packet_len 
)

#include <crypto.c>

Process received REKEY_RESPONSE packet from server.

Process received REKEY_RESPONSE packet from server

Parameters
packetPacket data
packet_lenPacket length
Returns
0 on success, -1 on failure
Parameters
packetPacket data
packet_lenPacket length
Returns
0 on success, -1 on failure

Definition at line 939 of file src/client/crypto.c.

939 {
940 if (!g_crypto_initialized || !crypto_client_is_ready()) {
941 log_error("Cannot process rekey response: crypto not initialized or not ready");
942 return -1;
943 }
944
945 asciichat_error_t result = crypto_handshake_process_rekey_response(&g_crypto_ctx, packet, packet_len);
946 if (result != ASCIICHAT_OK) {
947 log_error("Failed to process REKEY_RESPONSE: %d", result);
948 return -1;
949 }
950
951 return 0;
952}
asciichat_error_t crypto_handshake_process_rekey_response(crypto_handshake_context_t *ctx, const uint8_t *packet, size_t packet_len)

References crypto_client_is_ready(), crypto_handshake_process_rekey_response(), and g_crypto_ctx.

◆ crypto_client_send_rekey_complete()

int crypto_client_send_rekey_complete ( void  )

#include <crypto.c>

Send REKEY_COMPLETE packet to server and commit to new key.

Send REKEY_COMPLETE packet to server and commit to new key

Returns
0 on success, -1 on failure
0 on success, -1 on failure

Definition at line 961 of file src/client/crypto.c.

961 {
962 if (!g_crypto_initialized || !crypto_client_is_ready()) {
963 log_error("Cannot send rekey complete: crypto not initialized or not ready");
964 return -1;
965 }
966
968 if (socket == INVALID_SOCKET_VALUE) {
969 log_error("Cannot send rekey complete: invalid socket");
970 return -1;
971 }
972
973 asciichat_error_t result = crypto_handshake_rekey_complete(&g_crypto_ctx, socket);
974 if (result != ASCIICHAT_OK) {
975 log_error("Failed to send REKEY_COMPLETE: %d", result);
976 return -1;
977 }
978
979 return 0;
980}
asciichat_error_t crypto_handshake_rekey_complete(crypto_handshake_context_t *ctx, socket_t socket)

References crypto_client_is_ready(), crypto_handshake_rekey_complete(), g_crypto_ctx, and server_connection_get_socket().

◆ crypto_client_send_rekey_response()

int crypto_client_send_rekey_response ( void  )

#include <crypto.c>

Send REKEY_RESPONSE packet to server.

Send REKEY_RESPONSE packet to server

Returns
0 on success, -1 on failure
0 on success, -1 on failure

Definition at line 909 of file src/client/crypto.c.

909 {
910 if (!g_crypto_initialized || !crypto_client_is_ready()) {
911 log_error("Cannot send rekey response: crypto not initialized or not ready");
912 return -1;
913 }
914
916 if (socket == INVALID_SOCKET_VALUE) {
917 log_error("Cannot send rekey response: invalid socket");
918 return -1;
919 }
920
921 asciichat_error_t result = crypto_handshake_rekey_response(&g_crypto_ctx, socket);
922 if (result != ASCIICHAT_OK) {
923 log_error("Failed to send REKEY_RESPONSE: %d", result);
924 return -1;
925 }
926
927 return 0;
928}
asciichat_error_t crypto_handshake_rekey_response(crypto_handshake_context_t *ctx, socket_t socket)

References crypto_client_is_ready(), crypto_handshake_rekey_response(), g_crypto_ctx, and server_connection_get_socket().

◆ crypto_client_should_rekey()

bool crypto_client_should_rekey ( void  )

#include <crypto.c>

Check if session rekeying should be triggered.

Check if session rekeying should be triggered

Returns
true if rekey should be initiated, false otherwise
true if rekey should be initiated, false otherwise

Definition at line 843 of file src/client/crypto.c.

843 {
844 if (!g_crypto_initialized || !crypto_client_is_ready()) {
845 return false;
846 }
848}
bool crypto_handshake_should_rekey(const crypto_handshake_context_t *ctx)

References crypto_client_is_ready(), crypto_handshake_should_rekey(), and g_crypto_ctx.