ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
peer_crypto.c
Go to the documentation of this file.
1#include "peer_crypto.h"
8#include "security.h"
9#include <emscripten.h>
10#include <string.h>
11
17typedef struct peer_output {
19 void *data;
20 size_t length;
22
31
32const char *peer_crypto_error(void) {
33 static asciichat_error_context_t error;
34 return HAS_ERRNO(&error) ? error.context_message : "Peer security operation failed";
35}
36
37static asciichat_error_t peer_send(acip_transport_t *transport, const void *data, size_t length) {
38 browser_peer_crypto_t *peer = transport->impl_data;
39 socket_buffer_t input = {.data = data, .len = length};
41 crypto_context_t *send_crypto = peer->security.ready ? transport->crypto_ctx : NULL;
42 asciichat_error_t result = acip_packet_plan(send_crypto, &input, 1, &plan);
43 if (result != ASCIICHAT_OK)
44 return result;
45 peer_output_t *output = SAFE_CALLOC(1, sizeof(*output), peer_output_t *);
46 if (!output)
47 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate peer output");
48 output->length = plan.encrypt ? sizeof(packet_header_t) + plan.ciphertext_capacity : length;
49 output->data = buffer_alloc(plan.domain, output->length);
50 if (!output->data) {
51 SAFE_FREE(output);
52 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate peer packet");
53 }
54 if (plan.encrypt) {
55 packet_header_t header;
56 size_t encrypted_length = 0;
57 result = acip_packet_encrypt(transport->crypto_ctx, &plan, plan.domain, (uint8_t *)output->data + sizeof(header),
58 plan.ciphertext_capacity, &header, &encrypted_length);
59 if (result != ASCIICHAT_OK) {
60 buffer_release(output->data);
61 SAFE_FREE(output);
62 return result;
63 }
64 memcpy(output->data, &header, sizeof(header));
65 output->length = sizeof(header) + encrypted_length;
66 } else {
67 memcpy(output->data, data, length);
68 }
69 if (peer->tail)
70 peer->tail->next = output;
71 else
72 peer->output = output;
73 peer->tail = output;
74 return ASCIICHAT_OK;
75}
76
77static bool peer_connected(acip_transport_t *transport) {
78 (void)transport;
79 return true;
80}
81
82static const acip_transport_methods_t peer_methods = {.send = peer_send, .is_connected = peer_connected};
83
85 if (!peer || !peer->output)
86 return;
87 peer_output_t *output = peer->output;
88 peer->output = output->next;
89 if (!peer->output)
90 peer->tail = NULL;
91 buffer_release(output->data);
92 SAFE_FREE(output);
93}
94
96 if (!peer)
97 return;
98 while (peer->output)
102 SAFE_FREE(peer);
103}
104
105browser_peer_crypto_t *peer_crypto_create(bool server, int encryption, const char *password, const uint8_t *identity,
106 const uint8_t *expected_key) {
107 browser_peer_crypto_t *peer = SAFE_CALLOC(1, sizeof(*peer), browser_peer_crypto_t *);
108 if (!peer) {
109 SET_ERRNO(ERROR_MEMORY, "Cannot allocate peer security state");
110 return NULL;
111 }
112 crypto_policy_t policy = {.transport_secure = true,
113 .encrypt = encryption == 1,
114 .no_encrypt = encryption == 0,
115 .has_password = password && password[0],
116 .has_identity = identity != NULL,
117 .has_verification_key = expected_key != NULL};
118 asciichat_error_t result = crypto_policy_resolve(&policy, &peer->security.mode);
120 peer->security.require_encryption = policy.encrypt;
122 if (result == ASCIICHAT_OK)
123 result = policy.has_password ? crypto_handshake_init_with_password("browser_peer", ctx, server, password)
124 : crypto_handshake_init("browser_peer", ctx, server);
125 if (result != ASCIICHAT_OK) {
127 return NULL;
128 }
129 if (identity) {
130 private_key_t *key = server ? &ctx->server_private_key : &ctx->client_private_key;
131 public_key_t *public_key = server ? &ctx->server_public_key : &ctx->client_public_key;
132 key->type = KEY_TYPE_ED25519;
133 memcpy(key->key.ed25519, identity, ED25519_PRIVATE_KEY_SIZE);
134 memcpy(key->public_key, identity + ED25519_SEED_SIZE, ED25519_PUBLIC_KEY_SIZE);
135 public_key->type = KEY_TYPE_ED25519;
136 memcpy(public_key->key, identity + ED25519_SEED_SIZE, ED25519_PUBLIC_KEY_SIZE);
137 }
138 if (expected_key && server) {
140 if (!ctx->client_whitelist) {
142 SET_ERRNO(ERROR_MEMORY, "Cannot allocate peer key whitelist");
143 return NULL;
144 }
146 memcpy(ctx->client_whitelist[0].key, expected_key, ED25519_PUBLIC_KEY_SIZE);
148 ctx->require_client_auth = true;
149 } else if (expected_key) {
150 ctx->verify_server_key = true;
152 memcpy(ctx->expected_server_key_bytes, expected_key, ED25519_PUBLIC_KEY_SIZE);
153 }
154 peer->transport.methods = &peer_methods;
155 peer->transport.impl_data = peer;
156 if (acip_security_start(&peer->security, &peer->transport) != ASCIICHAT_OK) {
158 return NULL;
159 }
160 return peer;
161}
162
164 return peer && peer->security.ready;
165}
166
168 return peer && peer->output ? peer->output->data : NULL;
169}
170
172 return peer && peer->output ? peer->output->length : 0;
173}
174
176 return peer ? peer->received : NULL;
177}
178
180 return peer ? peer->received_length : 0;
181}
182
183asciichat_error_t peer_crypto_send(browser_peer_crypto_t *peer, const void *data, size_t length) {
184 if (!peer || !data || !length)
185 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid peer packet or security state");
186 if (!peer->security.ready)
187 return SET_ERRNO(ERROR_INVALID_STATE, "Peer security is not ready");
188 return peer_send(&peer->transport, data, length);
189}
190
191asciichat_error_t peer_crypto_receive(browser_peer_crypto_t *peer, const void *data, size_t length) {
192 if (!peer || !data)
193 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid peer packet or security state");
194 if (length < sizeof(packet_header_t))
195 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid peer packet");
197 peer->received = NULL;
198 peer->received_length = 0;
199 packet_header_t header;
200 memcpy(&header, data, sizeof(header));
201 size_t payload_length = length - sizeof(header);
202 const void *payload = (const uint8_t *)data + sizeof(header);
203 packet_type_t type = NET_TO_HOST_U16(header.type);
204 asciichat_error_t validation = packet_validate(data, length, 0, NULL);
205 if (validation != ASCIICHAT_OK)
206 return validation;
207 if (!peer->security.ready) {
208 asciichat_error_t result = acip_security_receive(&peer->security, &peer->transport, type, payload, payload_length);
209 if (result != ASCIICHAT_OK || !peer->quic_handshake || type != PACKET_TYPE_PROTOCOL_VERSION)
210 return result;
219 result = packet_send_via_transport(&peer->transport, PACKET_TYPE_CRYPTO_CAPABILITIES, &caps, sizeof(caps), 0);
220 if (result != ASCIICHAT_OK || !caps.requires_verification)
221 return result;
224 }
225 bool encrypt = ACIP_CRYPTO_HAS_ENCRYPT(peer->security.mode);
226 if (packet_is_initial_handshake_type(type) || (encrypt != (type == PACKET_TYPE_ENCRYPTED)))
227 return SET_ERRNO(ERROR_CRYPTO, "Peer packet does not match negotiated security");
228 if (!encrypt) {
229 peer->received = buffer_alloc(NULL, length);
230 if (!peer->received)
231 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate peer input");
232 memcpy(peer->received, data, length);
233 peer->received_length = length;
234 return ASCIICHAT_OK;
235 }
236 bool consumed = false;
237 uint64_t sequence;
238 asciichat_error_t result =
240 length, (uint8_t **)&peer->received, &peer->received_length, &sequence, &consumed);
241 if (consumed) {
243 peer->received = NULL;
244 peer->received_length = 0;
245 }
246 return result;
247}
248
252
254 if (!peer)
255 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid peer security state");
256 if (!peer->security.ready || peer->quic_handshake || !ACIP_CRYPTO_HAS_ENCRYPT(peer->security.mode))
257 return ASCIICHAT_OK;
258 return acip_security_flush(&peer->transport);
259}
260
262 if (!peer || peer->security.version_received || peer->quic_handshake || !ACIP_CRYPTO_HAS_ENCRYPT(peer->security.mode))
263 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid peer QUIC handshake transition");
264 peer->quic_handshake = true;
265 return ASCIICHAT_OK;
266}
#define SET_ERRNO(code,...)
#define HAS_ERRNO(context)
void * buffer_alloc(buffer_domain_t *domain, size_t size)
Definition buffer.c:274
#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.
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.
🔄 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 SAFE_FREE(ptr)
Definition common.h:377
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
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_NETWORK_PROTOCOL
Definition error_codes.h:76
@ ERROR_MEMORY
Definition error_codes.h:51
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_CRYPTO
Definition error_codes.h:93
@ ERROR_INVALID_PARAM
uint8_t key[CRYPTO_PUBLIC_KEY_SIZE]
Definition key_types.h:74
uint8_t ed25519[ED25519_PRIVATE_KEY_SIZE]
Definition key_types.h:100
key_type_t type
Definition key_types.h:98
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]
Definition key_types.h:105
key_type_t type
Definition key_types.h:73
union private_key_t::@040247167361101132173265304166142033301213115260 key
@ KEY_TYPE_ED25519
Definition key_types.h:54
asciichat_error_t packet_validate(const void *packet, size_t length, size_t limit, packet_header_t *output)
Definition packet.c:86
#define AUTH_ALGO_ED25519
Ed25519 authentication (Edwards-curve signatures).
Definition packet.h:1121
#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 CIPHER_ALGO_NONE
No encryption (plaintext mode).
Definition packet.h:1124
#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_ENCRYPTED
Encrypted packet (after handshake completion).
Definition packet.h:355
@ PACKET_TYPE_PROTOCOL_VERSION
Protocol version and capabilities negotiation.
Definition packet.h:303
@ PACKET_TYPE_CRYPTO_CAPABILITIES
Client -> Server: Supported crypto algorithms (UNENCRYPTED).
Definition packet.h:322
struct acip_transport acip_transport_t
Forward declaration of ACIP transport.
Definition host.h:506
struct acip_security acip_security_t
acip security is intentionally a small, concrete record. Fields such as handshake,...
asciichat_error_t acip_security_start(acip_security_t *security, acip_transport_t *transport)
void acip_security_cleanup(acip_security_t *security)
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)
asciichat_error_t acip_security_flush(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)
const void * peer_crypto_received_data(browser_peer_crypto_t *peer)
asciichat_error_t peer_crypto_tick(browser_peer_crypto_t *peer)
bool peer_crypto_ready(browser_peer_crypto_t *peer)
asciichat_error_t peer_crypto_send(browser_peer_crypto_t *peer, const void *data, size_t length)
const char * peer_crypto_error(void)
Definition peer_crypto.c:32
size_t peer_crypto_received_size(browser_peer_crypto_t *peer)
void peer_crypto_output_pop(browser_peer_crypto_t *peer)
Definition peer_crypto.c:84
size_t peer_crypto_output_size(browser_peer_crypto_t *peer)
struct peer_output peer_output_t
peer output is intentionally a small, concrete record. Fields such as next, data, length give callers...
crypto_context_t * peer_security_context(browser_peer_crypto_t *peer)
asciichat_error_t peer_crypto_quic_begin(browser_peer_crypto_t *peer)
void peer_crypto_destroy(browser_peer_crypto_t *peer)
Definition peer_crypto.c:95
asciichat_error_t peer_crypto_receive(browser_peer_crypto_t *peer, const void *data, size_t length)
browser_peer_crypto_t * peer_crypto_create(bool server, int encryption, const char *password, const uint8_t *identity, const uint8_t *expected_key)
const void * peer_crypto_output_data(browser_peer_crypto_t *peer)
struct browser_peer_crypto browser_peer_crypto_t
Definition peer_crypto.h:9
asciichat_error_t crypto_policy_resolve(const crypto_policy_t *policy, uint8_t *mode)
Definition policy.c:4
asciichat_error_t acip_packet_plan(crypto_context_t *crypto, const socket_buffer_t *buffers, size_t count, acip_packet_plan_t *plan)
Definition prepare.c:9
asciichat_error_t acip_packet_encrypt(crypto_context_t *crypto, const acip_packet_plan_t *plan, buffer_domain_t *domain, void *ciphertext, size_t capacity, packet_header_t *header, size_t *length)
The useful part of acip packet plan is in buffers, count, plaintext_size, ciphertext_capacity: togeth...
Definition prepare.c:64
#define CRYPTO_RECORD_ANY_CHANNEL
Definition record.h:11
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_PUBLIC_KEY_SIZE
Ed25519 public key size in bytes.
Definition sizes.h:33
#define ED25519_SEED_SIZE
Definition sizes.h:165
#define ED25519_PRIVATE_KEY_SIZE
Ed25519 private key size (seed + public) in bytes.
Definition sizes.h:35
🔤 String Manipulation and Shell Escaping Utilities
size_t ciphertext_capacity
Definition prepare.h:20
buffer_domain_t * domain
Borrowed control reserve for handshake/error traffic; NULL otherwise.
Definition prepare.h:25
crypto_handshake_context_t handshake
Transport method table (virtual function table).
void * impl_data
Transport-specific state.
const acip_transport_methods_t * methods
Method table (virtual functions).
crypto_context_t * crypto_ctx
Optional encryption context.
peer_output_t * tail
Definition peer_crypto.c:27
acip_transport_t transport
Definition peer_crypto.c:26
peer_output_t * output
Definition peer_crypto.c:27
acip_security_t security
Definition peer_crypto.c:24
Crypto capabilities packet structure (Packet Type 14).
Definition packet.h:1008
uint8_t preferred_auth
Preferred authentication algorithm (AUTH_ALGO_*).
Definition packet.h:1020
uint16_t supported_auth_algorithms
Supported authentication algorithms bitmask (AUTH_ALGO_*).
Definition packet.h:1012
uint16_t supported_kex_algorithms
Supported key exchange algorithms bitmask (KEX_ALGO_*).
Definition packet.h:1010
uint8_t preferred_cipher
Preferred cipher algorithm (CIPHER_ALGO_*).
Definition packet.h:1022
uint16_t supported_cipher_algorithms
Supported cipher algorithms bitmask (CIPHER_ALGO_*).
Definition packet.h:1014
uint8_t preferred_kex
Preferred key exchange algorithm (KEX_ALGO_*).
Definition packet.h:1018
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.
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
Fixed prefix shared by every ACIP packet on the wire.
Definition packet.h:628
peer output is intentionally a small, concrete record. Fields such as next, data, length give callers...
Definition peer_crypto.c:17
size_t length
Definition peer_crypto.c:20
void * data
Definition peer_crypto.c:19
struct peer_output * next
Definition peer_crypto.c:18
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
@ ACIP_DELIVERY_RELIABLE
Definition traffic.h:12