ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
negotiation.c
Go to the documentation of this file.
2#include <ascii-chat/buffer.h>
8#ifndef __EMSCRIPTEN__
10#endif
18#include <ascii-chat/log/log.h>
19#include <sodium.h>
20#include <string.h>
21
22static bool is_quic(acip_transport_t *transport) {
23#ifdef __EMSCRIPTEN__
24 (void)transport;
25 return false;
26#else
27 return acip_transport_get_type(transport) == ACIP_TRANSPORT_QUIC;
28#endif
29}
30
31static asciichat_error_t finish_transport_security(acip_transport_t *transport, crypto_handshake_context_t *handshake) {
32 asciichat_error_t activated = acip_security_activate(transport);
33 if (activated != ASCIICHAT_OK)
34 return activated;
35#ifdef __EMSCRIPTEN__
36 (void)transport;
37 (void)handshake;
38 return ASCIICHAT_OK;
39#else
40 if (!is_quic(transport))
41 return ASCIICHAT_OK;
42 if (!handshake->crypto_ctx.encrypt_data || !crypto_handshake_is_ready(handshake))
43 return SET_ERRNO(ERROR_CRYPTO, "QUIC requires authenticated ACIP encryption");
44 asciichat_error_t result = quic_transport_begin_security(transport, &handshake->crypto_ctx);
45 if (result == ASCIICHAT_OK)
46 result = quic_transport_wait_security(transport, 30 * NS_PER_SEC_INT);
47 if (result == ASCIICHAT_OK)
48 result = quic_transport_allow_media(transport);
49 return result;
50#endif
51}
52
57static asciichat_error_t media_receive(network_negotiation_t *n, acip_transport_t *transport, packet_type_t type,
58 const void *payload, size_t length) {
61 if (n->step == 0) {
62 if (type != PACKET_TYPE_PROTOCOL_VERSION || length != sizeof(protocol_version_packet_t))
63 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Expected protocol version before application traffic");
65 memcpy(&version, payload, sizeof(version));
66 uint8_t mode = version.supports_encryption;
68 return SET_ERRNO(ERROR_CRYPTO, "Unsupported crypto mode or protocol version");
69 bool requires_auth = n->require_auth;
70 if (requires_auth && !ACIP_CRYPTO_HAS_AUTH(mode))
71 return SET_ERRNO(ERROR_CRYPTO_AUTH, "Server requires authentication");
74 return SET_ERRNO(ERROR_CRYPTO, "Requested encryption conflicts with server policy");
75 if (!n->secure && !n->forbid_encryption && !ACIP_CRYPTO_HAS_ENCRYPT(mode))
76 return SET_ERRNO(ERROR_CRYPTO, "Plain transports require encryption unless --no-encrypt is explicit");
77 if (mode == ACIP_CRYPTO_NONE) {
78 result = packet_send_via_transport(transport, PACKET_TYPE_PROTOCOL_VERSION, &version, sizeof(version), 0);
79 n->ready = result == ASCIICHAT_OK;
80 n->step = 5;
81 return result;
82 }
83 const char *password = n->password ? n->password : "";
84 result = n->initialized ? ASCIICHAT_OK
85 : password[0] ? crypto_handshake_init_with_password("server_async", ctx, true, password)
86 : crypto_handshake_init("server_async", ctx, true);
87 if (result != ASCIICHAT_OK)
88 return result;
89 n->initialized = true;
94 memcpy(ctx->server_public_key.key, n->identity_keys[0].public_key, sizeof(n->identity_keys[0].public_key));
95 }
100 version.compression_algorithms = 0;
101 version.compression_threshold = 0;
103 result = packet_send_via_transport(transport, PACKET_TYPE_PROTOCOL_VERSION, &version, sizeof(version), 0);
104 n->step = 1;
105 return result;
106 }
107 if (n->step == 1) {
108 // Select algorithms once; a pinned identity request defers the server hello.
109 if (type != PACKET_TYPE_CRYPTO_CAPABILITIES || length != sizeof(crypto_capabilities_packet_t))
110 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Expected crypto capabilities");
111 crypto_capabilities_packet_t capabilities;
112 memcpy(&capabilities, payload, sizeof(capabilities));
113 crypto_parameters_packet_t parameters = {0};
114 parameters.selected_kex = KEX_ALGO_X25519;
116 parameters.selected_auth =
118 parameters.verification_enabled = n->whitelist_count > 0;
121 parameters.nonce_size = CRYPTO_NONCE_SIZE;
122 parameters.mac_size = CRYPTO_MAC_SIZE;
123 parameters.hmac_size = CRYPTO_HMAC_SIZE;
124 if (parameters.selected_auth == AUTH_ALGO_ED25519) {
127 }
128 result = crypto_handshake_set_parameters(ctx, &parameters);
129 if (result != ASCIICHAT_OK)
130 return result;
133 parameters.signature_size = HOST_TO_NET_U16(parameters.signature_size);
135 result = packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_PARAMETERS, &parameters, sizeof(parameters), 0);
136 if (result != ASCIICHAT_OK)
137 return result;
138 if (n->identity_key_count > 0 && capabilities.requires_verification) {
139 n->step = 2;
140 return ASCIICHAT_OK;
141 }
142 n->step = 3;
143 return crypto_handshake_server_start(ctx, transport);
144 }
145 if (n->step == 2) {
146 // A legacy single-key client can send its key exchange response directly.
149 return SET_ERRNO(ERROR_CRYPTO, "Expected pinned server identity");
150 // Keep this packet for the key-exchange step after sending the default key.
153 memcpy(ctx->server_public_key.key, n->identity_keys[0].public_key, sizeof(n->identity_keys[0].public_key));
154 result = crypto_handshake_server_start(ctx, transport);
155 if (result != ASCIICHAT_OK)
156 return result;
157 n->step = 3;
158 } else {
159 if (!length || length % ED25519_PUBLIC_KEY_SIZE || length > MAX_CLIENTS * ED25519_PUBLIC_KEY_SIZE)
160 return SET_ERRNO(ERROR_CRYPTO, "Expected a bounded pinned server identity set");
161 bool found = false;
162 for (size_t i = 0; i < n->identity_key_count; ++i) {
163 bool requested = false;
164 for (size_t offset = 0; offset < length; offset += ED25519_PUBLIC_KEY_SIZE)
165 requested |= sodium_memcmp((const uint8_t *)payload + offset, n->identity_keys[i].public_key,
167 if (requested) {
170 memcpy(ctx->server_public_key.key, n->identity_keys[i].public_key, sizeof(n->identity_keys[i].public_key));
171 found = true;
172 break;
173 }
174 }
175 if (!found)
176 return SET_ERRNO(ERROR_CRYPTO, "Unknown pinned server identity");
177 n->step = 3;
178 return crypto_handshake_server_start(ctx, transport);
179 }
180 }
181 if (n->step == 3) {
182 // Keep challenge/response verification separate from key derivation.
183 result = crypto_handshake_server_auth_challenge(ctx, transport, type, payload, length);
184 n->step = 4;
185 } else if (n->step == 4) {
186 result = crypto_handshake_server_complete(ctx, transport, type, payload, length);
187 } else {
188 return SET_ERRNO(ERROR_INVALID_STATE, "Unexpected server handshake step");
189 }
190 if (result == ASCIICHAT_OK && ctx->state == CRYPTO_HANDSHAKE_READY) {
191 n->initialized = true;
194 n->ready = true;
195 n->step = 5;
196 }
197 return result;
198}
199
201 const void *payload, size_t length) {
202 if (!n || !n->handshake || !transport || n->ready)
203 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid connection negotiation state");
204 if (is_quic(transport) && n->step == 0 && type == PACKET_TYPE_PROTOCOL_VERSION &&
205 length == sizeof(protocol_version_packet_t)) {
207 memcpy(&version, payload, sizeof(version));
209 return SET_ERRNO(ERROR_CRYPTO, "QUIC requires ACIP encryption");
210 }
212 asciichat_error_t result = media_receive(n, transport, type, payload, length);
213 if (result == ASCIICHAT_OK && n->ready) {
214 result = finish_transport_security(transport, n->handshake);
215 if (result != ASCIICHAT_OK)
216 n->ready = false;
217 }
218 return result;
219 }
221 asciichat_error_t result;
222 switch (n->step) {
223 case 0: {
224 if (type != PACKET_TYPE_PROTOCOL_VERSION || length != sizeof(protocol_version_packet_t))
225 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Expected discovery protocol version");
227 memcpy(&version, payload, sizeof(version));
229 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Unsupported discovery protocol version");
230 uint8_t mode = version.supports_encryption;
232 if (result != ASCIICHAT_OK)
233 return result;
235 if (mode == ACIP_CRYPTO_NONE) {
237 n->ready = true;
238 return ASCIICHAT_OK;
239 }
240 result = crypto_handshake_server_send_parameters(ctx, transport);
241 if (result == ASCIICHAT_OK)
242 result = crypto_handshake_server_start(ctx, transport);
243 break;
244 }
245 case 1:
246 result = crypto_handshake_server_auth_challenge(ctx, transport, type, payload, length);
247 break;
248 case 2:
249 result = crypto_handshake_server_complete(ctx, transport, type, payload, length);
250 break;
251 default:
252 return SET_ERRNO(ERROR_CRYPTO, "Invalid discovery negotiation state");
253 }
254 if (result != ASCIICHAT_OK)
255 return result;
256 ++n->step;
258 if (n->ready)
259 transport->crypto_ctx = &ctx->crypto_ctx;
260 if (n->ready) {
261 result = finish_transport_security(transport, ctx);
262 if (result != ASCIICHAT_OK)
263 n->ready = false;
264 }
265 return result;
266}
267
268static asciichat_error_t negotiation_read(acip_transport_t *transport, uint64_t deadline, packet_type_t *type,
269 void **payload, size_t *length, void **allocation) {
270 for (;;) {
271 uint64_t now = time_get_ns();
273 acip_transport_interrupt(transport);
274 return SET_ERRNO(ERROR_NETWORK, "Connection negotiation cancelled");
275 }
276 if (now >= deadline)
277 return SET_ERRNO(ERROR_NETWORK_TIMEOUT, "Connection negotiation deadline expired");
278 transport->receive_timeout_ns = MIN(deadline - now, 100 * NS_PER_MS_INT);
280 asciichat_error_t result = packet_receive_via_transport(transport, type, payload, length, allocation);
281 if (result == ERROR_NETWORK_TIMEOUT || result == ERROR_NETWORK_INCOMPLETE) {
283 continue;
284 }
286 if (result == ASCIICHAT_OK && *type == PACKET_TYPE_ERROR_MESSAGE)
287 result = network_error_decode(*type, *payload, *length);
288 return result;
289 }
290}
291static asciichat_error_t client_negotiate(acip_transport_t *transport, crypto_handshake_context_t *ctx, uint8_t mode) {
292 const uint64_t deadline = time_get_ns() + 30 * NS_PER_SEC_INT;
294 protocol_version_packet_init(&version, mode);
296 asciichat_error_t result =
297 packet_send_via_transport(transport, PACKET_TYPE_PROTOCOL_VERSION, &version, sizeof(version), 0);
298 packet_type_t type = 0;
299 void *payload = NULL, *allocation = NULL;
300 size_t length = 0;
301 if (result == ASCIICHAT_OK)
302 result = negotiation_read(transport, deadline, &type, &payload, &length, &allocation);
303 if (result == ASCIICHAT_OK) {
304 if (type != PACKET_TYPE_PROTOCOL_VERSION || length != sizeof(version))
305 result = SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Expected media protocol version");
306 else {
307 memcpy(&version, payload, sizeof(version));
309 result = SET_ERRNO(ERROR_CRYPTO_AUTH, "Peer changed requested security mode");
310 }
311 }
312 buffer_release(allocation);
313 if (result != ASCIICHAT_OK)
314 return result;
315 if (mode == ACIP_CRYPTO_NONE) {
317 return ASCIICHAT_OK;
318 }
320 .supported_kex_algorithms = HOST_TO_NET_U16(KEX_ALGO_X25519),
321 .supported_auth_algorithms = HOST_TO_NET_U16(AUTH_ALGO_ED25519 | AUTH_ALGO_NONE),
322 .supported_cipher_algorithms = HOST_TO_NET_U16(CIPHER_ALGO_XSALSA20_POLY1305 | CIPHER_ALGO_NONE),
323 .requires_verification = ctx->verify_server_key && ctx->expected_server_key[0],
324 .preferred_kex = KEX_ALGO_X25519,
325 .preferred_auth = ACIP_CRYPTO_HAS_AUTH(mode) ? AUTH_ALGO_ED25519 : AUTH_ALGO_NONE,
327 result = packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_CAPABILITIES, &caps, sizeof(caps), 0);
328 allocation = NULL;
329 if (result == ASCIICHAT_OK)
330 result = negotiation_read(transport, deadline, &type, &payload, &length, &allocation);
331 if (result == ASCIICHAT_OK) {
333 if (type != PACKET_TYPE_CRYPTO_PARAMETERS || length != sizeof(params))
334 result = SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Expected crypto parameters");
335 else {
336 memcpy(&params, payload, sizeof(params));
337 if (params.selected_kex != KEX_ALGO_X25519 || params.selected_cipher != caps.preferred_cipher)
338 result = SET_ERRNO(ERROR_CRYPTO_AUTH, "Unsupported negotiated algorithms");
339 else {
340 result = crypto_handshake_set_parameters(ctx, &params);
341 if (params.verification_enabled)
343 }
344 }
345 }
346 buffer_release(allocation);
347 if (result != ASCIICHAT_OK)
348 return result;
349 if (caps.requires_verification) {
351 size_t count = 0;
352 result = parse_public_keys(ctx->expected_server_key, keys, &count, MAX_CLIENTS);
353 if (result != ASCIICHAT_OK || !count)
354 return SET_ERRNO(ERROR_CRYPTO_AUTH, "Cannot resolve pinned server identity");
356 size_t requested_count = NET_TO_HOST_U16(version.feature_flags) & PROTOCOL_FEATURE_IDENTITY_SET ? count : 1;
357 for (size_t i = 0; i < requested_count; ++i)
358 memcpy(requested[i], keys[i].key, sizeof(requested[i]));
359 result = packet_send_via_transport(transport, PACKET_TYPE_CRYPTO_CLIENT_HELLO, requested,
360 requested_count * ED25519_PUBLIC_KEY_SIZE, 0);
361 if (result != ASCIICHAT_OK)
362 return result;
363 }
364 for (unsigned step = 0; step < 3 && ctx->state != CRYPTO_HANDSHAKE_READY; ++step) {
365 allocation = NULL;
366 result = negotiation_read(transport, deadline, &type, &payload, &length, &allocation);
367 if (result == ASCIICHAT_OK) {
368 if (!step)
369 result = crypto_handshake_client_key_exchange(ctx, transport, type, payload, length);
370 else if (step == 1)
371 result = crypto_handshake_client_auth_response(ctx, transport, type, payload, length);
372 else
373 result = crypto_handshake_client_complete(ctx, transport, type, payload, length);
374 }
375 buffer_release(allocation);
376 if (result != ASCIICHAT_OK)
377 return result;
378 }
379 if (ctx->state != CRYPTO_HANDSHAKE_READY)
380 return SET_ERRNO(ERROR_CRYPTO_HANDSHAKE, "Negotiation did not reach readiness");
382 transport->crypto_ctx = &ctx->crypto_ctx;
383 return ASCIICHAT_OK;
384}
385static asciichat_error_t discovery_client_negotiate(acip_transport_t *transport, crypto_handshake_context_t *ctx,
386 uint8_t mode) {
388 asciichat_error_t result = acds_handshake_begin(transport, mode);
389 if (result != ASCIICHAT_OK)
390 return result;
391 if (mode == ACIP_CRYPTO_NONE) {
393 return ASCIICHAT_OK;
394 }
395 uint64_t deadline = time_get_ns() + 30 * NS_PER_SEC_INT;
396 // Discovery sends parameters before key exchange. An identity-bearing client
397 // also receives an auth request and acknowledgment before reaching readiness.
398 for (unsigned step = 0; step < 4 && ctx->state != CRYPTO_HANDSHAKE_READY; ++step) {
399 packet_type_t type;
400 void *payload = NULL, *allocation = NULL;
401 size_t length = 0;
402 result = negotiation_read(transport, deadline, &type, &payload, &length, &allocation);
403 if (result == ASCIICHAT_OK)
404 result = acds_handshake_receive(ctx, transport, type, payload, length);
405 buffer_release(allocation);
406 if (result != ASCIICHAT_OK)
407 return result;
408 }
409 if (ctx->state != CRYPTO_HANDSHAKE_READY)
410 return SET_ERRNO(ERROR_CRYPTO_HANDSHAKE, "Discovery negotiation did not reach readiness");
411 transport->crypto_ctx = &ctx->crypto_ctx;
412 return ASCIICHAT_OK;
413}
415 network_protocol_t protocol) {
416 if (!transport || !ctx || mode > ACIP_CRYPTO_FULL || protocol > NETWORK_PROTOCOL_DISCOVERY)
417 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid client negotiation");
418 if (is_quic(transport) && !ACIP_CRYPTO_HAS_ENCRYPT(mode))
419 return SET_ERRNO(ERROR_CRYPTO, "QUIC requires ACIP encryption");
420 uint64_t timeout = transport->receive_timeout_ns;
421 asciichat_error_t result = protocol == NETWORK_PROTOCOL_DISCOVERY ? discovery_client_negotiate(transport, ctx, mode)
422 : client_negotiate(transport, ctx, mode);
423 transport->receive_timeout_ns = timeout;
424 if (result == ASCIICHAT_OK)
425 result = finish_transport_security(transport, ctx);
426 return result;
427}
asciichat_error_t acds_handshake_begin(acip_transport_t *transport, uint8_t mode)
asciichat_error_t acds_handshake_receive(crypto_handshake_context_t *ctx, acip_transport_t *transport, packet_type_t type, const void *payload, size_t length)
Application-level callbacks for library code.
#define APP_CALLBACK_BOOL(callback_name)
void errno_scope_end(asciichat_errno_scope_t scope, asciichat_errno_outcome_t outcome)
asciichat_errno_scope_t errno_scope_begin(void)
#define SET_ERRNO(code,...)
@ ASCIICHAT_ERRNO_HANDLED
@ ASCIICHAT_ERRNO_DISMISSED
#define buffer_release(data)
Definition buffer.h:91
asciichat_error_t crypto_handshake_init(const char *name, crypto_handshake_context_t *ctx, bool is_server)
Initialize named crypto handshake context.
const crypto_context_t * crypto_handshake_get_context(const crypto_handshake_context_t *ctx)
Get the crypto context for encryption/decryption.
asciichat_error_t crypto_handshake_init_with_password(const char *name, crypto_handshake_context_t *ctx, bool is_server, const char *password)
Initialize named crypto handshake context with password authentication.
bool crypto_handshake_is_ready(const crypto_handshake_context_t *ctx)
Check if handshake is complete and encryption is ready.
asciichat_error_t crypto_handshake_set_parameters(crypto_handshake_context_t *ctx, const crypto_parameters_packet_t *params)
Set crypto parameters from crypto_parameters_packet_t.
@ CRYPTO_HANDSHAKE_DISABLED
@ CRYPTO_HANDSHAKE_READY
🔄 Network byte order conversion helpers
#define HOST_TO_NET_U16(val)
Definition endian.h:96
#define NET_TO_HOST_U16(val)
Definition endian.h:111
#define MIN(a, b)
Return the minimum of two values.
Definition common.h:170
unsigned long long uint64_t
Definition common.h:63
unsigned char uint8_t
Definition common.h:60
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_INVALID_STATE
@ ERROR_CRYPTO_HANDSHAKE
Definition error_codes.h:96
@ ERROR_NETWORK_INCOMPLETE
Definition error_codes.h:90
@ ERROR_NETWORK
Definition error_codes.h:72
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:76
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_CRYPTO_AUTH
Definition error_codes.h:95
@ ERROR_CRYPTO
Definition error_codes.h:93
@ ERROR_INVALID_PARAM
@ ERROR_NETWORK_TIMEOUT
Definition error_codes.h:75
uint8_t key[CRYPTO_PUBLIC_KEY_SIZE]
Definition key_types.h:74
key_type_t type
Definition key_types.h:98
asciichat_error_t parse_public_keys(const char *input, public_key_t *keys_out, size_t *num_keys, size_t max_keys)
Parse all SSH/GPG public keys from any format (returns all keys).
Definition keys.c:411
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]
Definition key_types.h:105
key_type_t type
Definition key_types.h:73
@ KEY_TYPE_ED25519
Definition key_types.h:54
#define MAX_CLIENTS
Maximum possible clients (static array size) - actual runtime limit set by –max-clients (1-128).
#define NS_PER_SEC_INT
Definition time.h:169
#define NS_PER_MS_INT
Definition time.h:168
#define AUTH_ALGO_ED25519
Ed25519 authentication (Edwards-curve signatures).
Definition packet.h:1121
#define ACIP_CRYPTO_NONE
No encryption, no authentication (plaintext only).
Definition packet.h:1138
void protocol_version_packet_init(protocol_version_packet_t *version, uint8_t supports_encryption)
Initialize a protocol version packet with the current wire version.
Definition packet.c:37
#define ACIP_CRYPTO_HAS_AUTH(mode)
Check if crypto mode includes authentication.
Definition packet.h:1155
#define KEX_ALGO_X25519
X25519 key exchange (Curve25519).
Definition packet.h:1120
#define ACIP_CRYPTO_HAS_ENCRYPT(mode)
Check if crypto mode includes payload encryption.
Definition packet.h:1148
packet_type_t
Network protocol packet type enumeration.
Definition packet.h:301
#define AUTH_ALGO_NONE
No authentication (plaintext mode).
Definition packet.h:1122
#define PROTOCOL_FEATURE_RECOVERABLE_ERRORS
Definition packet.h:844
#define CIPHER_ALGO_NONE
No encryption (plaintext mode).
Definition packet.h:1124
#define PROTOCOL_FEATURE_IDENTITY_SET
Definition packet.h:845
#define ACIP_CRYPTO_FULL
Full crypto: encryption + authentication.
Definition packet.h:1141
#define CIPHER_ALGO_XSALSA20_POLY1305
XSalsa20-Poly1305 authenticated encryption.
Definition packet.h:1123
@ PACKET_TYPE_CRYPTO_CLIENT_HELLO
Client -> Server: Expected server key fingerprint for multi-key selection (UNENCRYPTED).
Definition packet.h:314
@ PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP
Client -> Server: {client_pubkey[32]} (UNENCRYPTED).
Definition packet.h:328
@ PACKET_TYPE_PROTOCOL_VERSION
Protocol version and capabilities negotiation.
Definition packet.h:303
@ PACKET_TYPE_CRYPTO_PARAMETERS
Server -> Client: Chosen algorithms + data sizes (UNENCRYPTED).
Definition packet.h:324
@ PACKET_TYPE_CRYPTO_CAPABILITIES
Client -> Server: Supported crypto algorithms (UNENCRYPTED).
Definition packet.h:322
@ PACKET_TYPE_ERROR_MESSAGE
Error packet with asciichat_error_t code and human-readable message.
Definition packet.h:374
#define PROTOCOL_VERSION_MAJOR
Major protocol version number.
struct acip_transport acip_transport_t
Forward declaration of ACIP transport.
Definition host.h:506
Client-side handshake functions.
Server-side handshake functions.
@ ACIP_TRANSPORT_QUIC
QUIC/UDP (future).
Network error handling utilities.
asciichat_error_t crypto_handshake_client_complete(crypto_handshake_context_t *ctx, acip_transport_t *transport, packet_type_t packet_type, const uint8_t *payload, size_t payload_len)
Client: Wait for handshake complete confirmation.
asciichat_error_t crypto_handshake_client_key_exchange(crypto_handshake_context_t *ctx, acip_transport_t *transport, packet_type_t packet_type, const uint8_t *payload, size_t payload_len)
Client: Process server's public key and send our public key.
asciichat_error_t crypto_handshake_client_auth_response(crypto_handshake_context_t *ctx, acip_transport_t *transport, packet_type_t packet_type, const uint8_t *payload, size_t payload_len)
Client: Process auth challenge and send response.
asciichat_error_t crypto_handshake_server_send_parameters(crypto_handshake_context_t *ctx, acip_transport_t *transport)
Server: Send CRYPTO_PARAMETERS and set handshake context sizes.
asciichat_error_t crypto_handshake_server_complete(crypto_handshake_context_t *ctx, acip_transport_t *transport, packet_type_t packet_type, const uint8_t *payload, size_t payload_len)
Server: Process auth response and complete handshake.
asciichat_error_t crypto_handshake_server_auth_challenge(crypto_handshake_context_t *ctx, acip_transport_t *transport, packet_type_t packet_type, const uint8_t *payload, size_t payload_len)
Server: Process client's public key and send auth challenge.
asciichat_error_t crypto_handshake_server_start(crypto_handshake_context_t *ctx, acip_transport_t *transport)
Server: Start crypto handshake by sending public key.
asciichat_error_t acip_security_activate(acip_transport_t *transport)
asciichat_error_t network_error_decode(packet_type_t type, const void *payload, size_t size)
📝 Logging API with multiple log levels and terminal output control
bool should_exit(void)
Definition main.c:249
asciichat_error_t network_negotiation_receive(network_negotiation_t *n, acip_transport_t *transport, packet_type_t type, const void *payload, size_t length)
asciichat_error_t network_client_negotiate(acip_transport_t *transport, crypto_handshake_context_t *ctx, uint8_t mode, network_protocol_t protocol)
network_protocol_t
Definition negotiation.h:5
@ NETWORK_PROTOCOL_MEDIA
Definition negotiation.h:5
@ NETWORK_PROTOCOL_DISCOVERY
Definition negotiation.h:5
asciichat_error_t crypto_policy_check_mode(bool transport_secure, bool encrypt, bool no_encrypt, bool require_auth, uint8_t mode)
Definition policy.c:17
Protocol version, features, compression, and frame flag constants.
return true
Definition queries.h:13
asciichat_error_t quic_transport_wait_security(acip_transport_t *transport, uint64_t timeout_ns)
asciichat_error_t quic_transport_begin_security(acip_transport_t *transport, crypto_context_t *crypto)
asciichat_error_t quic_transport_allow_media(acip_transport_t *transport)
asciichat_error_t packet_receive_via_transport(acip_transport_t *transport, packet_type_t *type, void **payload, size_t *payload_len, void **alloc_buffer)
Receive a packet via transport with header parsing and validation.
Definition send.c:200
asciichat_error_t packet_send_via_transport(acip_transport_t *transport, packet_type_t type, const void *payload, size_t payload_len, uint32_t client_id)
Definition send.c:190
ACIP shared/bidirectional packet sending functions.
#define ED25519_SIGNATURE_SIZE
Ed25519 signature size in bytes.
Definition sizes.h:37
#define CRYPTO_NONCE_SIZE
Nonce size (XSalsa20).
Definition sizes.h:79
#define CRYPTO_HMAC_SIZE
HMAC size (HMAC-SHA256).
Definition sizes.h:87
#define ED25519_PUBLIC_KEY_SIZE
Ed25519 public key size in bytes.
Definition sizes.h:33
#define CRYPTO_MAC_SIZE
MAC size (Poly1305).
Definition sizes.h:85
#define CRYPTO_PUBLIC_KEY_SIZE
Public key size (X25519).
Definition sizes.h:67
🔤 String Manipulation and Shell Escaping Utilities
crypto_context_t * crypto_ctx
Optional encryption context.
uint64_t receive_timeout_ns
Optional TCP receive timeout override; zero uses the normal polling timeout.
When code needs to work with asciichat errno snapshot, it keeps total, copied here instead of scatter...
Crypto capabilities packet structure (Packet Type 14).
Definition packet.h:1008
uint8_t preferred_cipher
Preferred cipher algorithm (CIPHER_ALGO_*).
Definition packet.h:1022
uint8_t requires_verification
Server verification requirement flag (1=required, 0=optional).
Definition packet.h:1016
Endpoint cryptographic state for handshake, packet protection, authentication, and rekeying.
Cryptographic handshake context structure.
crypto_handshake_state_t state
Crypto parameters packet structure (Packet Type 15).
Definition packet.h:1037
uint8_t hmac_size
HMAC size in bytes (e.g., 32 for HMAC-SHA256).
Definition packet.h:1059
uint8_t selected_kex
Selected key exchange algorithm (KEX_ALGO_*).
Definition packet.h:1039
uint8_t selected_cipher
Selected cipher algorithm (CIPHER_ALGO_*).
Definition packet.h:1043
uint16_t auth_public_key_size
Authentication public key size in bytes (e.g., 32 for Ed25519, 1952 for Dilithium3).
Definition packet.h:1049
uint8_t selected_auth
Selected authentication algorithm (AUTH_ALGO_*).
Definition packet.h:1041
uint8_t verification_enabled
Server verification enabled flag (1=enabled, 0=disabled).
Definition packet.h:1045
uint16_t signature_size
Signature size in bytes (e.g., 64 for Ed25519, 3309 for Dilithium3).
Definition packet.h:1051
uint8_t nonce_size
Nonce size in bytes (e.g., 24 for XSalsa20).
Definition packet.h:1055
uint8_t mac_size
MAC size in bytes (e.g., 16 for Poly1305).
Definition packet.h:1057
uint16_t shared_secret_size
Shared secret size in bytes (e.g., 32 for X25519).
Definition packet.h:1053
uint16_t kex_public_key_size
Key exchange public key size in bytes (e.g., 32 for X25519, 1568 for Kyber1024).
Definition packet.h:1047
When code needs to work with network negotiation, it keeps protocol, handshake, identity_keys,...
Definition negotiation.h:12
const private_key_t * identity_keys
Definition negotiation.h:15
const char * password
Definition negotiation.h:19
crypto_handshake_context_t * handshake
Definition negotiation.h:14
network_protocol_t protocol
Definition negotiation.h:13
public_key_t * whitelist
Definition negotiation.h:17
Protocol version negotiation packet structure (Packet Type 1).
Definition packet.h:860
uint8_t compression_threshold
Compression threshold percentage (0-100, e.g., 80 = compress if >80% size reduction).
Definition packet.h:872
uint16_t protocol_version
Major protocol version (must match for compatibility).
Definition packet.h:862
uint16_t feature_flags
Feature flags bitmask (FEATURE_RLE_ENCODING, etc.).
Definition packet.h:874
uint8_t compression_algorithms
Supported compression algorithms bitmask (COMPRESS_ALGO_*).
Definition packet.h:870
uint8_t supports_encryption
Encryption & authentication mode bitmask (ACIP_CRYPTO_* constants: NONE, ENCRYPT, AUTH,...
Definition packet.h:868
The normalized public identity used by ascii-chat's crypto and key-management code.
Definition key_types.h:72
⏱️ High-precision timing utilities using sokol_time.h and uthash