ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
security.h File Reference

Go to the source code of this file.

Data Structures

struct  acip_security
 acip security is intentionally a small, concrete record. Fields such as handshake, mode, forbid_encryption, require_encryption give callers the identity and current value they need. It is normally borrowed from, or owned by, the surrounding subsystem—not independently managed. Callers serialize receive/start and keep the transport alive until cleanup. Media must wait for ready, including authentication-only connections. More...

Typedefs

typedef struct acip_security acip_security_t
 acip security is intentionally a small, concrete record. Fields such as handshake, mode, forbid_encryption, require_encryption give callers the identity and current value they need. It is normally borrowed from, or owned by, the surrounding subsystem—not independently managed. Callers serialize receive/start and keep the transport alive until cleanup. Media must wait for ready, including authentication-only connections.

Functions

asciichat_error_t acip_security_start (acip_security_t *security, acip_transport_t *transport)
asciichat_error_t acip_security_receive (acip_security_t *security, acip_transport_t *transport, packet_type_t type, const void *payload, size_t length)
asciichat_error_t acip_security_init_options (acip_security_t *security, bool server, bool transport_secure, const char *password)
void acip_security_cleanup (acip_security_t *security)
acip_transport_t * acip_webrtc_transport_create_secure (struct webrtc_peer_connection *peer, struct webrtc_data_channel *channel, acip_security_t *security, void(*on_ready)(acip_transport_t *, void *), void *user_data)
acip_security_t * acip_webrtc_transport_security (acip_transport_t *transport)
bool acip_security_rekey_packet (uint16_t type)
asciichat_error_t acip_security_rekey_encode (unsigned flow, crypto_rekey_message_t, const void *, size_t, void *, size_t, size_t *)
asciichat_error_t acip_security_rekey_receive (crypto_rekey_session_t *, acip_traffic_class_t, acip_delivery_t, const void *, size_t, uint64_t now_ns, bool *consumed)
asciichat_error_t acip_security_rekey_seal (crypto_record_t *, unsigned, crypto_rekey_message_t, const void *, size_t, uint8_t **, size_t *)
asciichat_error_t acip_security_activate (acip_transport_t *)
asciichat_error_t acip_security_flush (acip_transport_t *)
asciichat_error_t acip_security_request_rekey (acip_transport_t *)
asciichat_error_t acip_security_decrypt (crypto_context_t *, unsigned, unsigned, const void *, size_t, uint8_t **, size_t *, uint64_t *, bool *consumed)
asciichat_error_t acip_security_seal (crypto_context_t *, acip_traffic_class_t, acip_delivery_t, const void *, size_t, uint8_t **, size_t *)
asciichat_error_t acip_security_open (crypto_context_t *, acip_traffic_class_t, acip_delivery_t, const void *, size_t, uint8_t **, size_t *, uint64_t *, bool *)
asciichat_error_t acip_security_next_control (crypto_context_t *, acip_traffic_class_t *, uint8_t **, size_t *)

Typedef Documentation

◆ acip_security_t

acip security is intentionally a small, concrete record. Fields such as handshake, mode, forbid_encryption, require_encryption give callers the identity and current value they need. It is normally borrowed from, or owned by, the surrounding subsystem—not independently managed. Callers serialize receive/start and keep the transport alive until cleanup. Media must wait for ready, including authentication-only connections.

Per-peer, event-driven negotiation. The caller owns and configures handshake.

Function Documentation

◆ acip_security_activate()

asciichat_error_t acip_security_activate ( acip_transport_t * transport)

Definition at line 178 of file lib/network/acip/security.c.

178 {
179 if (!transport)
180 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing secure transport");
181 crypto_context_t *crypto = transport->crypto_ctx;
182 if (!crypto || !crypto->encrypt_data)
183 return ASCIICHAT_OK;
184 crypto_session_t *session = NULL;
185 asciichat_error_t result = crypto_session_lock(crypto, &session);
186 if (result == ASCIICHAT_OK) {
187 crypto_session_unlock(session);
188 atomic_store_bool(&transport->packet_security_active, true);
189 }
190 return result;
191}
#define SET_ERRNO(code,...)
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
struct crypto_session crypto_session_t
For crypto session, this is the live record that ties owner, mutex, records, rotation together....
void crypto_session_unlock(crypto_session_t *session)
asciichat_error_t crypto_session_lock(crypto_context_t *crypto, crypto_session_t **output)
atomic_t packet_security_active
Publishes the stable post-handshake crypto owner.
crypto_context_t * crypto_ctx
Optional encryption context.
Endpoint cryptographic state for handshake, packet protection, authentication, and rekeying.

References ASCIICHAT_OK, acip_transport::crypto_ctx, crypto_session_lock(), crypto_session_unlock(), crypto_context_t::encrypt_data, ERROR_INVALID_PARAM, acip_transport::packet_security_active, and SET_ERRNO.

Referenced by acip_security_receive(), and quic_transport_begin_security().

◆ acip_security_cleanup()

void acip_security_cleanup ( acip_security_t * security)

Definition at line 11 of file lib/network/acip/security.c.

11 {
12 if (!security)
13 return;
16}
void crypto_handshake_destroy(crypto_handshake_context_t *ctx)
Cleanup crypto handshake context with secure memory wiping.
#define SAFE_FREE(ptr)
Definition common.h:377
crypto_handshake_context_t handshake

References crypto_handshake_context_t::client_whitelist, crypto_handshake_destroy(), acip_security::handshake, and SAFE_FREE.

Referenced by acip_security_init_options(), and peer_crypto_destroy().

◆ acip_security_decrypt()

asciichat_error_t acip_security_decrypt ( crypto_context_t * crypto,
unsigned flow,
unsigned delivery,
const void * payload,
size_t length,
uint8_t ** output,
size_t * written,
uint64_t * sequence,
bool * consumed )

Definition at line 193 of file lib/network/acip/security.c.

195 {
196 if (!output || !written || !consumed)
197 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing security receive output");
198 *output = NULL;
199 *written = 0;
200 *consumed = false;
201 crypto_session_t *session = NULL;
202 asciichat_error_t result = crypto_session_lock(crypto, &session);
203 if (result != ASCIICHAT_OK)
204 return result;
205 result = acip_packet_decrypt_payload(&session->records, flow, delivery, payload, length, output, written, sequence);
206 if (result == ASCIICHAT_OK) {
207 packet_header_t header;
208 memcpy(&header, *output, sizeof(header));
209 result = crypto_session_receive(session, session->records.last_receive_channel, delivery,
210 rekey_message(NET_TO_HOST_U16(header.type)), *output + sizeof(header),
211 *written - sizeof(header), time_get_ns(), consumed);
212 }
213 crypto_session_unlock(session);
214 if (result != ASCIICHAT_OK) {
215 buffer_release(*output);
216 *output = NULL;
217 *written = 0;
218 }
219 return result;
220}
#define buffer_release(data)
Definition buffer.h:91
#define NET_TO_HOST_U16(val)
Definition endian.h:111
asciichat_error_t crypto_session_receive(crypto_session_t *session, unsigned channel, unsigned delivery, crypto_rekey_message_t type, const void *payload, size_t length, uint64_t now, bool *consumed)
asciichat_error_t acip_packet_decrypt_payload(crypto_record_t *records, unsigned flow, unsigned delivery, const void *payload, size_t length, uint8_t **output, size_t *written, uint64_t *sequence)
Definition prepare.c:188
unsigned last_receive_channel
Definition record.h:26
Fixed prefix shared by every ACIP packet on the wire.
Definition packet.h:628

References acip_packet_decrypt_payload(), ASCIICHAT_OK, buffer_release, crypto_session_lock(), crypto_session_receive(), crypto_session_unlock(), ERROR_INVALID_PARAM, crypto_record::last_receive_channel, NET_TO_HOST_U16, crypto_session::records, and SET_ERRNO.

Referenced by acip_security_open(), client_decrypt_packet(), and packet_decrypt_envelope().

◆ acip_security_flush()

asciichat_error_t acip_security_flush ( acip_transport_t * transport)

Definition at line 248 of file lib/network/acip/security.c.

248 {
249 if (!transport || !atomic_load_bool(&transport->packet_security_active))
250 return ASCIICHAT_OK;
251 for (unsigned i = 0; i < CRYPTO_SESSION_MESSAGES; ++i) {
252 uint8_t *wire = NULL;
253 size_t length = 0;
255 asciichat_error_t result = acip_security_next_control(transport->crypto_ctx, &channel, &wire, &length);
256 if (result != ASCIICHAT_OK || !wire)
257 return result;
258 defer(buffer_release(wire));
259 socket_buffer_t slice = {wire, length};
260 acip_send_options_t options = {.traffic_class = channel, .delivery = ACIP_DELIVERY_RELIABLE};
261 if (transport->methods->sendv_ex)
262 result = transport->methods->sendv_ex(transport, &slice, 1, &options);
263 else if (transport->methods->sendv)
264 result = transport->methods->sendv(transport, &slice, 1);
265 else
266 result = transport->methods->send(transport, wire, length);
267 if (result != ASCIICHAT_OK)
268 return result;
269 }
270 return ASCIICHAT_OK;
271}
unsigned char uint8_t
Definition common.h:60
#define CRYPTO_SESSION_MESSAGES
asciichat_error_t acip_security_next_control(crypto_context_t *crypto, acip_traffic_class_t *flow, uint8_t **wire, size_t *length)
asciichat_error_t(* send)(acip_transport_t *transport, const void *data, size_t len)
Send data through this transport.
asciichat_error_t(* sendv)(acip_transport_t *transport, const socket_buffer_t *buffers, size_t count)
Custom destroy implementation (optional).
asciichat_error_t(* sendv_ex)(acip_transport_t *transport, const socket_buffer_t *buffers, size_t count, const acip_send_options_t *options)
const acip_transport_methods_t * methods
Method table (virtual functions).
acip_traffic_class_t
Definition traffic.h:5
@ ACIP_TRAFFIC_CONTROL
Definition traffic.h:6
@ ACIP_DELIVERY_RELIABLE
Definition traffic.h:12

References ACIP_DELIVERY_RELIABLE, acip_security_next_control(), ACIP_TRAFFIC_CONTROL, ASCIICHAT_OK, buffer_release, acip_transport::crypto_ctx, CRYPTO_SESSION_MESSAGES, acip_transport::methods, acip_transport::packet_security_active, acip_transport_methods_t::send, acip_transport_methods_t::sendv, and acip_transport_methods_t::sendv_ex.

Referenced by peer_crypto_tick().

◆ acip_security_init_options()

asciichat_error_t acip_security_init_options ( acip_security_t * security,
bool server,
bool transport_secure,
const char * password )

Initialize a peer from native CLI options; cleanup releases owned credentials.

Definition at line 6 of file security_options.c.

7 {
8 if (!security)
9 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing peer security state");
10 memset(security, 0, sizeof(*security));
11 const options_t *options = options_get();
12 if (!options)
13 return SET_ERRNO(ERROR_INVALID_STATE, "Peer security requires initialized options");
14 const char *password = password_override ? password_override : options->password;
15 crypto_policy_t policy = {
16 .transport_secure = transport_secure,
17 .encrypt = options->encrypt_enabled,
18 .no_encrypt = options->no_encrypt,
19 .no_auth = options->no_auth,
20 .has_password = password[0] != '\0',
21 .has_identity = options->encrypt_key[0] != '\0',
22 .has_verification_key = server ? options->client_keys[0] != '\0' : options->server_key[0] != '\0',
23 };
24 asciichat_error_t result = crypto_policy_resolve(&policy, &security->mode);
25 security->forbid_encryption = policy.no_encrypt;
26 security->require_encryption = policy.encrypt;
27 if (result != ASCIICHAT_OK)
28 return result;
29 crypto_handshake_context_t *ctx = &security->handshake;
30 result = policy.has_password ? crypto_handshake_init_with_password("webrtc_peer", ctx, server, password)
31 : crypto_handshake_init("webrtc_peer", ctx, server);
32 if (result != ASCIICHAT_OK)
33 return result;
34 ctx->require_client_auth = server && options->require_server_verify;
36 if (policy.has_identity) {
37 private_key_t *private_key = server ? &ctx->server_private_key : &ctx->client_private_key;
38 public_key_t *public_key = server ? &ctx->server_public_key : &ctx->client_public_key;
39 result = parse_private_key(options->encrypt_key, private_key);
40 if (result != ASCIICHAT_OK)
41 goto failed;
42 public_key->type = KEY_TYPE_ED25519;
43 memcpy(public_key->key, private_key->public_key, ED25519_PUBLIC_KEY_SIZE);
44 if (!server && strncmp(options->encrypt_key, "gpg:", 4) == 0)
45 SAFE_STRNCPY(ctx->client_gpg_key_id, options->encrypt_key + 4, sizeof(ctx->client_gpg_key_id));
46 }
47 if (server && policy.has_verification_key) {
49 if (!ctx->client_whitelist) {
50 result = SET_ERRNO(ERROR_MEMORY, "Cannot allocate WebRTC client key list");
51 goto failed;
52 }
54 if (result != ASCIICHAT_OK)
55 goto failed;
56 if (!ctx->num_whitelisted_clients) {
57 result = SET_ERRNO(ERROR_CRYPTO_AUTH, "WebRTC client key list is empty");
58 goto failed;
59 }
60 ctx->require_client_auth = true;
61 } else if (!server && policy.has_verification_key) {
62 ctx->verify_server_key = true;
64 SAFE_STRNCPY(ctx->server_hostname, options->session_string, sizeof(ctx->server_hostname));
65 }
66 return ASCIICHAT_OK;
67failed:
68 acip_security_cleanup(security);
69 return result;
70}
asciichat_error_t crypto_handshake_init(const char *name, crypto_handshake_context_t *ctx, bool is_server)
Initialize named crypto handshake context.
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.
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:423
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
@ ERROR_INVALID_STATE
@ ERROR_MEMORY
Definition error_codes.h:51
@ ERROR_CRYPTO_AUTH
Definition error_codes.h:95
uint8_t key[CRYPTO_PUBLIC_KEY_SIZE]
Definition key_types.h:74
asciichat_error_t parse_private_key(const char *key_path, private_key_t *key_out)
Parse SSH private key from file.
Definition keys.c:219
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 ACIP_CRYPTO_HAS_ENCRYPT(mode)
Check if crypto mode includes payload encryption.
Definition packet.h:1148
struct options_state options_t
Immutable, RCU-published snapshot of the application's runtime configuration.
const options_t * options_get(void)
Get pointer to current options struct (lock-free, thread-safe).
Definition rcu.c:511
void acip_security_cleanup(acip_security_t *security)
asciichat_error_t crypto_policy_resolve(const crypto_policy_t *policy, uint8_t *mode)
Definition policy.c:4
#define ED25519_PUBLIC_KEY_SIZE
Ed25519 public key size in bytes.
Definition sizes.h:33
Cryptographic handshake context structure.
The useful part of crypto policy is in transport_secure, encrypt, no_encrypt, no_auth: together they ...
Definition policy.h:12
bool no_encrypt
Definition policy.h:15
bool has_password
Definition policy.h:17
bool has_identity
Definition policy.h:18
bool has_verification_key
Definition policy.h:19
bool encrypt_enabled
Enable encryption.
Definition options.h:1178
char password[256]
Password string.
Definition options.h:1180
char session_string[(38+1)]
Definition options.h:1026
bool no_encrypt
Disable encryption (opt-out).
Definition options.h:1182
bool no_auth
Disable authentication layer (–no-auth).
Definition options.h:1183
char server_key[256]
Expected server public key (client).
Definition options.h:1184
bool require_server_verify
Server: only accept clients who verified via ACDS.
Definition options.h:1198
char encrypt_key[256]
SSH/GPG key file path (first –key flag, kept for compatibility).
Definition options.h:1179
char client_keys[256]
Allowed client keys (server).
Definition options.h:1185
Private identity-key material used for server authentication and signing.
Definition key_types.h:97
The normalized public identity used by ascii-chat's crypto and key-management code.
Definition key_types.h:72

References ACIP_CRYPTO_HAS_ENCRYPT, acip_security_cleanup(), ASCIICHAT_OK, crypto_handshake_context_t::client_gpg_key_id, options_state::client_keys, crypto_handshake_context_t::client_private_key, crypto_handshake_context_t::client_public_key, crypto_handshake_context_t::client_whitelist, crypto_handshake_context_t::crypto_ctx, crypto_handshake_init(), crypto_handshake_init_with_password(), crypto_policy_resolve(), ED25519_PUBLIC_KEY_SIZE, crypto_policy_t::encrypt, crypto_context_t::encrypt_data, options_state::encrypt_enabled, options_state::encrypt_key, ERROR_CRYPTO_AUTH, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, ERROR_MEMORY, crypto_handshake_context_t::expected_server_key, acip_security::forbid_encryption, acip_security::handshake, crypto_policy_t::has_identity, crypto_policy_t::has_password, crypto_policy_t::has_verification_key, public_key_t::key, KEY_TYPE_ED25519, MAX_CLIENTS, acip_security::mode, options_state::no_auth, crypto_policy_t::no_encrypt, options_state::no_encrypt, crypto_handshake_context_t::num_whitelisted_clients, options_get(), parse_private_key(), parse_public_keys(), options_state::password, private_key_t::public_key, crypto_handshake_context_t::require_client_auth, acip_security::require_encryption, options_state::require_server_verify, SAFE_CALLOC, SAFE_STRNCPY, crypto_handshake_context_t::server_hostname, options_state::server_key, crypto_handshake_context_t::server_private_key, crypto_handshake_context_t::server_public_key, options_state::session_string, SET_ERRNO, public_key_t::type, and crypto_handshake_context_t::verify_server_key.

Referenced by network_connection_prepare_security().

◆ acip_security_next_control()

asciichat_error_t acip_security_next_control ( crypto_context_t * crypto,
acip_traffic_class_t * flow,
uint8_t ** wire,
size_t * length )

Definition at line 222 of file lib/network/acip/security.c.

223 {
224 if (!flow || !wire || !length)
225 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing security output");
226 *wire = NULL;
227 *length = 0;
228 crypto_session_t *session = NULL;
229 asciichat_error_t result = crypto_session_lock(crypto, &session);
230 if (result != ASCIICHAT_OK)
231 return result;
232 defer(crypto_session_unlock(session));
233 result = crypto_session_tick(session, time_get_ns());
234 if (result == ASCIICHAT_OK && session->count) {
235 crypto_session_message_t *message = &session->messages[session->head];
236 *flow = (acip_traffic_class_t)message->channel;
237 result = acip_security_rekey_seal(&session->records, message->channel, message->type, message->payload,
238 message->length, wire, length);
239 if (result == ASCIICHAT_OK) {
240 memset(message, 0, sizeof(*message));
241 session->head = (session->head + 1) % CRYPTO_SESSION_MESSAGES;
242 --session->count;
243 }
244 }
245 return result;
246}
asciichat_error_t crypto_session_tick(crypto_session_t *session, uint64_t now)
asciichat_error_t acip_security_rekey_seal(crypto_record_t *records, unsigned flow, crypto_rekey_message_t message, const void *payload, size_t length, uint8_t **wire, size_t *written)
crypto_session_message_t messages[16]

References acip_security_rekey_seal(), ASCIICHAT_OK, crypto_session_message_t::channel, crypto_session::count, crypto_session_lock(), CRYPTO_SESSION_MESSAGES, crypto_session_tick(), crypto_session_unlock(), ERROR_INVALID_PARAM, crypto_session::head, crypto_session_message_t::length, crypto_session::messages, crypto_session_message_t::payload, crypto_session::records, SET_ERRNO, and crypto_session_message_t::type.

Referenced by acip_security_flush(), and browser_security_output().

◆ acip_security_open()

asciichat_error_t acip_security_open ( crypto_context_t * crypto,
acip_traffic_class_t flow,
acip_delivery_t delivery,
const void * packet,
size_t length,
uint8_t ** output,
size_t * written,
uint64_t * sequence,
bool * consumed )

Definition at line 296 of file lib/network/acip/security.c.

298 {
299 packet_header_t header;
300 asciichat_error_t result = packet_validate(packet, length, 0, &header);
301 if (result != ASCIICHAT_OK)
302 return result;
303 if (NET_TO_HOST_U16(header.type) != PACKET_TYPE_ENCRYPTED)
304 return SET_ERRNO(ERROR_CRYPTO, "Expected authenticated session record");
305 return acip_security_decrypt(crypto, flow, delivery, (const uint8_t *)packet + sizeof(header),
306 length - sizeof(header), output, written, sequence, consumed);
307}
@ ERROR_CRYPTO
Definition error_codes.h:93
asciichat_error_t packet_validate(const void *packet, size_t length, size_t limit, packet_header_t *output)
Definition packet.c:86
@ PACKET_TYPE_ENCRYPTED
Encrypted packet (after handshake completion).
Definition packet.h:355
asciichat_error_t acip_security_decrypt(crypto_context_t *crypto, unsigned flow, unsigned delivery, const void *payload, size_t length, uint8_t **output, size_t *written, uint64_t *sequence, bool *consumed)

References acip_security_decrypt(), ASCIICHAT_OK, ERROR_CRYPTO, NET_TO_HOST_U16, PACKET_TYPE_ENCRYPTED, packet_validate(), and SET_ERRNO.

Referenced by browser_security_packet(), and peer_crypto_receive().

◆ acip_security_receive()

asciichat_error_t acip_security_receive ( acip_security_t * security,
acip_transport_t * transport,
packet_type_t type,
const void * payload,
size_t length )

Definition at line 32 of file lib/network/acip/security.c.

33 {
34 if (!security || !transport || (!payload && length) || security->ready)
35 return SET_ERRNO(ERROR_INVALID_STATE, "Unexpected peer security packet");
36 crypto_handshake_context_t *ctx = &security->handshake;
38 if (!security->version_received) {
39 if (type != PACKET_TYPE_PROTOCOL_VERSION || length != sizeof(protocol_version_packet_t))
40 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Expected peer security negotiation before media");
42 memcpy(&version, payload, sizeof(version));
43 uint8_t mode = version.supports_encryption;
47 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Unsupported peer security protocol");
48 if (ctx->is_server) {
49 // Match secure WebSocket policy: defaults do not override a client's explicit no-encrypt.
50 if ((ctx->has_password || ctx->require_client_auth) && !ACIP_CRYPTO_HAS_AUTH(mode))
51 return SET_ERRNO(ERROR_CRYPTO_AUTH, "Peer omitted required authentication");
52 if (security->require_encryption && !ACIP_CRYPTO_HAS_ENCRYPT(mode))
53 return SET_ERRNO(ERROR_CRYPTO, "Peer omitted required encryption");
54 if (security->forbid_encryption && ACIP_CRYPTO_HAS_ENCRYPT(mode))
55 return SET_ERRNO(ERROR_CRYPTO, "Peer requires encryption but local policy disables it");
56 version.supports_encryption = mode;
57 result = packet_send_via_transport(transport, PACKET_TYPE_PROTOCOL_VERSION, &version, sizeof(version), 0);
58 if (result != ASCIICHAT_OK)
59 return result;
60 } else if ((mode & security->mode) != security->mode) {
61 return SET_ERRNO(ERROR_CRYPTO, "Peer attempted to downgrade requested security");
62 }
63 if (security->forbid_encryption && ACIP_CRYPTO_HAS_ENCRYPT(mode))
64 return SET_ERRNO(ERROR_CRYPTO, "Peer requires encryption but local policy disables it");
65 security->mode = mode;
66 security->version_received = true;
68 if (mode == ACIP_CRYPTO_NONE) {
70 security->ready = true;
71 return ASCIICHAT_OK;
72 }
73 if (!ctx->is_server)
74 return ASCIICHAT_OK;
75 result = crypto_handshake_server_send_parameters(ctx, transport);
76 if (result == ASCIICHAT_OK)
77 result = crypto_handshake_server_start(ctx, transport);
78 return result;
79 }
80 if (ctx->is_server) {
82 result = crypto_handshake_server_auth_challenge(ctx, transport, type, payload, length);
84 result = crypto_handshake_server_complete(ctx, transport, type, payload, length);
85 else
86 result = SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Unexpected peer authentication state");
87 } else {
88 switch (type) {
90 if (security->parameters_received || ctx->state != CRYPTO_HANDSHAKE_INIT ||
91 length != sizeof(crypto_parameters_packet_t))
92 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid peer crypto parameters");
93 result = crypto_handshake_set_parameters(ctx, payload);
94 if (result == ASCIICHAT_OK && ctx->crypto_ctx.encrypt_data != !!ACIP_CRYPTO_HAS_ENCRYPT(security->mode))
95 return SET_ERRNO(ERROR_CRYPTO, "Peer cipher does not match negotiated policy");
96 security->parameters_received = result == ASCIICHAT_OK;
97 break;
99 if (!security->parameters_received)
100 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Missing peer crypto parameters");
101 if (ctx->verify_server_key && length == ctx->crypto_ctx.public_key_size)
102 return SET_ERRNO(ERROR_CRYPTO_AUTH, "Peer omitted the required identity key");
103 result = crypto_handshake_client_key_exchange(ctx, transport, type, payload, length);
104 break;
106 result = crypto_handshake_client_auth_response(ctx, transport, type, payload, length);
107 break;
110 return SET_ERRNO(ERROR_CRYPTO_AUTH, "Peer skipped required mutual authentication");
111 result = crypto_handshake_client_complete(ctx, transport, type, payload, length);
112 break;
115 result = crypto_handshake_client_complete(ctx, transport, type, payload, length);
116 break;
117 default:
118 result = SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Application packet before peer authentication");
119 }
120 }
121 if (result == ASCIICHAT_OK)
122 security->ready = ctx->state == CRYPTO_HANDSHAKE_READY;
123 else
125 if (result == ASCIICHAT_OK && security->ready)
126 result = acip_security_activate(transport);
127 return result;
128}
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_FAILED
@ CRYPTO_HANDSHAKE_AUTHENTICATING
@ CRYPTO_HANDSHAKE_INIT
@ CRYPTO_HANDSHAKE_DISABLED
@ CRYPTO_HANDSHAKE_KEY_EXCHANGE
@ CRYPTO_HANDSHAKE_READY
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:76
key_type_t type
Definition key_types.h:98
#define ACIP_CRYPTO_NONE
No encryption, no authentication (plaintext only).
Definition packet.h:1138
#define ACIP_CRYPTO_HAS_AUTH(mode)
Check if crypto mode includes authentication.
Definition packet.h:1155
#define ACIP_CRYPTO_FULL
Full crypto: encryption + authentication.
Definition packet.h:1141
@ PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE
Server -> Client: "encryption ready" (UNENCRYPTED).
Definition packet.h:338
@ PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT
Server -> Client: {server_pubkey[32]} (UNENCRYPTED).
Definition packet.h:326
@ PACKET_TYPE_CRYPTO_AUTH_FAILED
Server -> Client: "authentication failed" (UNENCRYPTED).
Definition packet.h:334
@ PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP
Server -> Client: {HMAC[32]} server proves knowledge (UNENCRYPTED).
Definition packet.h:336
@ PACKET_TYPE_PROTOCOL_VERSION
Protocol version and capabilities negotiation.
Definition packet.h:303
@ PACKET_TYPE_CRYPTO_AUTH_CHALLENGE
Server -> Client: {nonce[32]} (UNENCRYPTED).
Definition packet.h:330
@ PACKET_TYPE_CRYPTO_PARAMETERS
Server -> Client: Chosen algorithms + data sizes (UNENCRYPTED).
Definition packet.h:324
#define PROTOCOL_VERSION_MAJOR
Major protocol version number.
#define PROTOCOL_VERSION_MINOR
Minor protocol version number.
#define PROTOCOL_VERSION_PATCH
Patch protocol version number.
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 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
crypto_handshake_state_t state
Crypto parameters packet structure (Packet Type 15).
Definition packet.h:1037
Protocol version negotiation packet structure (Packet Type 1).
Definition packet.h:860
uint16_t protocol_patch
Patch protocol revision.
Definition packet.h:866
uint16_t protocol_revision
Minor protocol revision (server can be newer).
Definition packet.h:864
uint16_t protocol_version
Major protocol version (must match for compatibility).
Definition packet.h:862
uint8_t supports_encryption
Encryption & authentication mode bitmask (ACIP_CRYPTO_* constants: NONE, ENCRYPT, AUTH,...
Definition packet.h:868

References ACIP_CRYPTO_FULL, ACIP_CRYPTO_HAS_AUTH, ACIP_CRYPTO_HAS_ENCRYPT, ACIP_CRYPTO_NONE, acip_security_activate(), ASCIICHAT_OK, crypto_handshake_context_t::client_private_key, crypto_handshake_context_t::crypto_ctx, CRYPTO_HANDSHAKE_AUTHENTICATING, crypto_handshake_client_auth_response(), crypto_handshake_client_complete(), crypto_handshake_client_key_exchange(), CRYPTO_HANDSHAKE_DISABLED, CRYPTO_HANDSHAKE_FAILED, CRYPTO_HANDSHAKE_INIT, CRYPTO_HANDSHAKE_KEY_EXCHANGE, CRYPTO_HANDSHAKE_READY, crypto_handshake_server_auth_challenge(), crypto_handshake_server_complete(), crypto_handshake_server_send_parameters(), crypto_handshake_server_start(), crypto_handshake_set_parameters(), crypto_context_t::encrypt_data, ERROR_CRYPTO, ERROR_CRYPTO_AUTH, ERROR_INVALID_STATE, ERROR_NETWORK_PROTOCOL, acip_security::forbid_encryption, acip_security::handshake, crypto_handshake_context_t::has_password, crypto_handshake_context_t::is_server, KEY_TYPE_ED25519, acip_security::mode, NET_TO_HOST_U16, packet_send_via_transport(), PACKET_TYPE_CRYPTO_AUTH_CHALLENGE, PACKET_TYPE_CRYPTO_AUTH_FAILED, PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE, PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT, PACKET_TYPE_CRYPTO_PARAMETERS, PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP, PACKET_TYPE_PROTOCOL_VERSION, acip_security::parameters_received, protocol_version_packet_t::protocol_patch, protocol_version_packet_t::protocol_revision, protocol_version_packet_t::protocol_version, PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR, PROTOCOL_VERSION_PATCH, crypto_context_t::public_key_size, acip_security::ready, crypto_handshake_context_t::require_client_auth, acip_security::require_encryption, SET_ERRNO, crypto_handshake_context_t::state, protocol_version_packet_t::supports_encryption, private_key_t::type, crypto_handshake_context_t::verify_server_key, and acip_security::version_received.

Referenced by peer_crypto_receive().

◆ acip_security_rekey_encode()

asciichat_error_t acip_security_rekey_encode ( unsigned flow,
crypto_rekey_message_t type,
const void * payload,
size_t length,
void * packet,
size_t capacity,
size_t * written )

Definition at line 149 of file lib/network/acip/security.c.

150 {
151 if (type <= CRYPTO_REKEY_NONE || type > CRYPTO_REKEY_NEEDED || flow >= CRYPTO_RECORD_CHANNELS)
152 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid rekey message");
153 return packet_encode(rekey_types[type], payload, length, flow, packet, capacity, written);
154}
asciichat_error_t packet_encode(packet_type_t type, const void *payload, size_t length, uint32_t client_id, void *output, size_t capacity, size_t *written)
Definition packet.c:67
#define CRYPTO_RECORD_CHANNELS
Definition record.h:7
@ CRYPTO_REKEY_NEEDED
Definition rekey.h:13

References CRYPTO_RECORD_CHANNELS, CRYPTO_REKEY_NEEDED, ERROR_INVALID_PARAM, packet_encode(), and SET_ERRNO.

Referenced by acip_security_rekey_seal().

◆ acip_security_rekey_packet()

bool acip_security_rekey_packet ( uint16_t type)

Definition at line 145 of file lib/network/acip/security.c.

145 {
146 return rekey_message(type) != CRYPTO_REKEY_NONE;
147}
@ CRYPTO_REKEY_NONE
Definition rekey.h:7

References CRYPTO_REKEY_NONE.

Referenced by quic_connection_submit().

◆ acip_security_rekey_receive()

asciichat_error_t acip_security_rekey_receive ( crypto_rekey_session_t * session,
acip_traffic_class_t flow,
acip_delivery_t delivery,
const void * packet,
size_t length,
uint64_t now_ns,
bool * consumed )

Definition at line 156 of file lib/network/acip/security.c.

158 {
159 packet_header_t header;
160 asciichat_error_t result = packet_validate(packet, length, 0, &header);
161 if (result != ASCIICHAT_OK)
162 return result;
163 return crypto_rekey_session_receive(session, flow, delivery, rekey_message(NET_TO_HOST_U16(header.type)),
164 (const uint8_t *)packet + sizeof(header), length - sizeof(header), now, consumed);
165}
asciichat_error_t crypto_rekey_session_receive(crypto_rekey_session_t *s, unsigned flow, unsigned delivery, crypto_rekey_message_t type, const void *payload, size_t bytes, uint64_t now, bool *consumed)
Definition rekey.c:127

References ASCIICHAT_OK, crypto_rekey_session_receive(), NET_TO_HOST_U16, and packet_validate().

◆ acip_security_rekey_seal()

asciichat_error_t acip_security_rekey_seal ( crypto_record_t * records,
unsigned flow,
crypto_rekey_message_t message,
const void * payload,
size_t length,
uint8_t ** wire,
size_t * written )

Definition at line 167 of file lib/network/acip/security.c.

168 {
170 size_t packet_length = 0;
171 asciichat_error_t result =
172 acip_security_rekey_encode(flow, message, payload, length, packet, sizeof(packet), &packet_length);
173 return result == ASCIICHAT_OK ? acip_packet_seal(records, (acip_traffic_class_t)flow, ACIP_DELIVERY_RELIABLE, packet,
174 packet_length, wire, written)
175 : result;
176}
asciichat_error_t acip_security_rekey_encode(unsigned flow, crypto_rekey_message_t type, const void *payload, size_t length, void *packet, size_t capacity, size_t *written)
asciichat_error_t acip_packet_seal(crypto_record_t *records, acip_traffic_class_t flow, acip_delivery_t delivery, const void *packet, size_t length, uint8_t **output, size_t *written)
Definition prepare.c:125
#define CRYPTO_PUBLIC_KEY_SIZE
Public key size (X25519).
Definition sizes.h:67

References ACIP_DELIVERY_RELIABLE, acip_packet_seal(), acip_security_rekey_encode(), ASCIICHAT_OK, and CRYPTO_PUBLIC_KEY_SIZE.

Referenced by acip_security_next_control().

◆ acip_security_request_rekey()

asciichat_error_t acip_security_request_rekey ( acip_transport_t * transport)

Definition at line 273 of file lib/network/acip/security.c.

273 {
274 if (!transport || !transport->crypto_ctx || !transport->crypto_ctx->encrypt_data)
275 return SET_ERRNO(ERROR_INVALID_STATE, "An encrypted authenticated session is required for rotation");
276 crypto_session_t *session = NULL;
277 asciichat_error_t result = crypto_session_lock(transport->crypto_ctx, &session);
278 if (result == ASCIICHAT_OK) {
279 result = crypto_rekey_session_request(&session->rotation, time_get_ns());
280 crypto_session_unlock(session);
281 }
282 return result;
283}
asciichat_error_t crypto_rekey_session_request(crypto_rekey_session_t *s, uint64_t now)
Definition rekey.c:118
crypto_rekey_session_t rotation

References ASCIICHAT_OK, acip_transport::crypto_ctx, crypto_rekey_session_request(), crypto_session_lock(), crypto_session_unlock(), crypto_context_t::encrypt_data, ERROR_INVALID_STATE, crypto_session::rotation, and SET_ERRNO.

◆ acip_security_seal()

asciichat_error_t acip_security_seal ( crypto_context_t * crypto,
acip_traffic_class_t flow,
acip_delivery_t delivery,
const void * packet,
size_t length,
uint8_t ** output,
size_t * written )

Definition at line 285 of file lib/network/acip/security.c.

286 {
287 crypto_session_t *session = NULL;
288 asciichat_error_t result = crypto_session_lock(crypto, &session);
289 if (result == ASCIICHAT_OK) {
290 result = acip_packet_seal(&session->records, flow, delivery, packet, length, output, written);
291 crypto_session_unlock(session);
292 }
293 return result;
294}

References acip_packet_seal(), ASCIICHAT_OK, crypto_session_lock(), crypto_session_unlock(), and crypto_session::records.

Referenced by browser_security_packet(), client_encrypt_packet(), quic_connection_submit(), and quic_connection_submit_datagram().

◆ acip_security_start()

asciichat_error_t acip_security_start ( acip_security_t * security,
acip_transport_t * transport )

Definition at line 18 of file lib/network/acip/security.c.

18 {
19 if (!security || !transport || security->mode > ACIP_CRYPTO_FULL ||
21 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid peer security initialization");
22 security->handshake.addressless_transport = true;
23 transport->crypto_ctx = &security->handshake.crypto_ctx;
25 if (security->handshake.is_server)
26 return ASCIICHAT_OK;
28 protocol_version_packet_init(&version, security->mode);
29 return packet_send_via_transport(transport, PACKET_TYPE_PROTOCOL_VERSION, &version, sizeof(version), 0);
30}
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

References ACIP_CRYPTO_FULL, ACIP_CRYPTO_HAS_ENCRYPT, crypto_handshake_context_t::addressless_transport, ASCIICHAT_OK, acip_transport::crypto_ctx, crypto_handshake_context_t::crypto_ctx, CRYPTO_HANDSHAKE_INIT, crypto_context_t::encrypt_data, ERROR_INVALID_STATE, acip_security::handshake, crypto_handshake_context_t::is_server, acip_security::mode, packet_send_via_transport(), PACKET_TYPE_PROTOCOL_VERSION, protocol_version_packet_init(), SET_ERRNO, and crypto_handshake_context_t::state.

Referenced by peer_crypto_create().

◆ acip_webrtc_transport_create_secure()

acip_transport_t * acip_webrtc_transport_create_secure ( struct webrtc_peer_connection * peer,
struct webrtc_data_channel * channel,
acip_security_t * security,
void(* on_ready )(acip_transport_t *, void *),
void * user_data )

Transfer security ownership on success. Ready fires only after negotiation.

Definition at line 918 of file webrtc/transport.c.

920 {
921 if (!security) {
922 SET_ERRNO(ERROR_INVALID_PARAM, "Missing WebRTC security state");
923 return NULL;
924 }
925 return webrtc_transport_create(peer_conn, data_channel, &security->handshake.crypto_ctx, security, on_ready,
926 user_data);
927}

References crypto_handshake_context_t::crypto_ctx, ERROR_INVALID_PARAM, acip_security::handshake, and SET_ERRNO.

◆ acip_webrtc_transport_security()

acip_security_t * acip_webrtc_transport_security ( acip_transport_t * transport)

Borrow security already owned by an authenticated peer transport.

Definition at line 774 of file webrtc/transport.c.

774 {
775 if (!transport || transport->methods != &webrtc_methods || !transport->impl_data)
776 return NULL;
777 return ((webrtc_transport_data_t *)transport->impl_data)->security;
778}
void * impl_data
Transport-specific state.
WebRTC transport implementation data.

References acip_transport::impl_data, and acip_transport::methods.