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

Go to the source code of this file.

Data Structures

struct  acip_packet_plan_t

Functions

asciichat_error_t acip_packet_plan (crypto_context_t *crypto, const socket_buffer_t *buffers, size_t count, acip_packet_plan_t *plan)
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: together they describe what is pending, who owns it, and how much data is valid. Keep the object with its parent operation and use the parent cleanup path. Encrypt a successful encrypted plan into caller-owned ciphertext storage and construct its wire header. The caller chooses contiguous or vectored delivery, and must release storage only after delivery has consumed/copied it. This helper owns and releases only its temporary gather buffer, allocated from domain. Output length is zero on failure; no output may be sent on failure.
asciichat_error_t acip_packet_seal (crypto_record_t *, acip_traffic_class_t, acip_delivery_t, const void *, size_t, uint8_t **, size_t *)
asciichat_error_t acip_packet_open_sequence (crypto_record_t *, acip_traffic_class_t, acip_delivery_t, const void *, size_t, uint8_t **, size_t *, uint64_t *)
asciichat_error_t acip_packet_open (crypto_record_t *, acip_traffic_class_t, acip_delivery_t, const void *, size_t, uint8_t **, size_t *)
asciichat_error_t acip_packet_decrypt_payload (crypto_record_t *, unsigned channel, unsigned delivery, const void *, size_t, uint8_t **, size_t *, uint64_t *)

Function Documentation

◆ acip_packet_decrypt_payload()

asciichat_error_t acip_packet_decrypt_payload ( crypto_record_t * records,
unsigned channel,
unsigned delivery,
const void * payload,
size_t length,
uint8_t ** output,
size_t * written,
uint64_t * sequence )

Definition at line 188 of file prepare.c.

190 {
191 return crypto_record_open_sequence(records, flow, delivery, payload, length, output, written, sequence,
192 validate_record_packet, NULL);
193}
asciichat_error_t crypto_record_open_sequence(crypto_record_t *state, unsigned traffic_class, unsigned delivery, const void *packet, size_t length, uint8_t **out, size_t *out_length, uint64_t *sequence_out, crypto_record_validate_fn validate, void *context)
Definition record.c:88

References crypto_record_open_sequence().

Referenced by acip_packet_open_sequence(), and acip_security_decrypt().

◆ acip_packet_encrypt()

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: together they describe what is pending, who owns it, and how much data is valid. Keep the object with its parent operation and use the parent cleanup path. Encrypt a successful encrypted plan into caller-owned ciphertext storage and construct its wire header. The caller chooses contiguous or vectored delivery, and must release storage only after delivery has consumed/copied it. This helper owns and releases only its temporary gather buffer, allocated from domain. Output length is zero on failure; no output may be sent on failure.

Definition at line 64 of file prepare.c.

65 {
66 if (length)
67 *length = 0;
68 if (!crypto || !plan || !plan->encrypt || !plan->buffers || !plan->count || !ciphertext || !header || !length)
69 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid ACIP encryption arguments");
70 if (capacity < plan->ciphertext_capacity)
71 return SET_ERRNO(ERROR_NETWORK_SIZE, "ACIP ciphertext storage too small");
72 const uint8_t *plaintext = plan->buffers[0].data;
73 uint8_t *gathered = NULL;
74 if (plan->count > 1) {
75 gathered = buffer_alloc(domain, plan->plaintext_size);
76 if (!gathered)
77 return SET_ERRNO(ERROR_MEMORY, "Cannot gather ACIP encryption input");
78 size_t offset = 0;
79 for (size_t i = 0; i < plan->count; ++i) {
80 if (plan->buffers[i].len)
81 memcpy(gathered + offset, plan->buffers[i].data, plan->buffers[i].len);
82 offset += plan->buffers[i].len;
83 }
84 plaintext = gathered;
85 }
86 size_t encrypted_length = 0;
87 crypto_session_t *session = NULL;
88 bool shared = !plan->records_locked && crypto && crypto->session && plan->records == &crypto->session->records;
89 asciichat_error_t encrypted = shared ? crypto_session_lock(crypto, &session) : ASCIICHAT_OK;
90 if (encrypted == ASCIICHAT_OK)
92 plan->options.delivery, plaintext, plan->plaintext_size,
93 ciphertext, capacity, &encrypted_length, domain)
94 : SET_ERRNO(ERROR_INVALID_STATE, "Missing authenticated record context");
95 if (session)
96 crypto_session_unlock(session);
97 buffer_release(gathered);
98 if (encrypted != ASCIICHAT_OK)
99 return encrypted;
100 socket_buffer_t slice = {ciphertext, encrypted_length};
101 asciichat_error_t result = packet_header_build(header, PACKET_TYPE_ENCRYPTED, &slice, 1, 0);
102 if (result != ASCIICHAT_OK)
103 return result;
104 *length = encrypted_length;
105 return ASCIICHAT_OK;
106}
#define SET_ERRNO(code,...)
void * buffer_alloc(buffer_domain_t *domain, size_t size)
Definition buffer.c:274
#define buffer_release(data)
Definition buffer.h:91
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_MEMORY
Definition error_codes.h:51
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_NETWORK_SIZE
Definition error_codes.h:77
@ ERROR_INVALID_PARAM
asciichat_error_t packet_header_build(packet_header_t *header, packet_type_t type, const socket_buffer_t *payload, size_t count, uint32_t client_id)
Definition packet.c:47
@ PACKET_TYPE_ENCRYPTED
Encrypted packet (after handshake completion).
Definition packet.h:355
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)
asciichat_error_t crypto_record_seal_into_domain(crypto_record_t *state, unsigned traffic_class, unsigned delivery, const void *packet, size_t length, uint8_t *wire, size_t capacity, size_t *out_length, buffer_domain_t *requested_domain)
Definition record.c:39
crypto_record_t * records
Definition prepare.h:22
acip_send_options_t options
Definition prepare.h:24
const socket_buffer_t * buffers
Definition prepare.h:17
size_t plaintext_size
Definition prepare.h:19
acip_delivery_t delivery
Definition traffic.h:18
acip_traffic_class_t traffic_class
Definition traffic.h:17
struct crypto_session * session
Endpoint cryptographic state for handshake, packet protection, authentication, and rekeying.

References ASCIICHAT_OK, buffer_alloc(), buffer_release, acip_packet_plan_t::buffers, acip_packet_plan_t::count, crypto_record_seal_into_domain(), crypto_session_lock(), crypto_session_unlock(), acip_send_options_t::delivery, acip_packet_plan_t::encrypt, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, ERROR_MEMORY, ERROR_NETWORK_SIZE, acip_packet_plan_t::options, packet_header_build(), PACKET_TYPE_ENCRYPTED, acip_packet_plan_t::plaintext_size, acip_packet_plan_t::records, crypto_session::records, acip_packet_plan_t::records_locked, crypto_context_t::session, SET_ERRNO, and acip_send_options_t::traffic_class.

Referenced by acip_packet_seal(), and send_packet_secure().

◆ acip_packet_open()

asciichat_error_t acip_packet_open ( 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 at line 183 of file prepare.c.

184 {
185 return acip_packet_open_sequence(records, flow, delivery, packet, length, output, written, NULL);
186}
asciichat_error_t acip_packet_open_sequence(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, uint64_t *sequence)
Definition prepare.c:166

References acip_packet_open_sequence().

◆ acip_packet_open_sequence()

asciichat_error_t acip_packet_open_sequence ( 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,
uint64_t * sequence )

Definition at line 166 of file prepare.c.

168 {
169 if (!output || !written)
170 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing decrypted packet output");
171 *output = NULL;
172 *written = 0;
173 packet_header_t header;
174 asciichat_error_t result = packet_validate(packet, length, 0, &header);
175 if (result != ASCIICHAT_OK)
176 return result;
177 if (NET_TO_HOST_U16(header.type) != PACKET_TYPE_ENCRYPTED)
178 return SET_ERRNO(ERROR_CRYPTO, "Expected encrypted packet");
179 return acip_packet_decrypt_payload(records, flow, delivery, (const uint8_t *)packet + sizeof(header),
180 length - sizeof(header), output, written, sequence);
181}
#define NET_TO_HOST_U16(val)
Definition endian.h:111
@ 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
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
Fixed prefix shared by every ACIP packet on the wire.
Definition packet.h:628

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

Referenced by acip_packet_open().

◆ acip_packet_plan()

asciichat_error_t acip_packet_plan ( crypto_context_t * crypto,
const socket_buffer_t * buffers,
size_t count,
acip_packet_plan_t * plan )

Validate sizes and decide eligibility without allocating or advancing crypto state.

Definition at line 9 of file prepare.c.

10 {
11 if (!plan)
12 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing ACIP packet plan");
13 *plan = (acip_packet_plan_t){0};
14 if (!buffers || !count || count > SOCKET_IOV_MAX)
15 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid ACIP packet vectors");
16 size_t size = 0;
17 for (size_t i = 0; i < count; ++i) {
18 if ((buffers[i].len && !buffers[i].data) || buffers[i].len > SOCKET_SEND_BUFFER_MAX - size)
19 return SET_ERRNO(ERROR_NETWORK_SIZE, "Invalid ACIP packet vector size");
20 size += buffers[i].len;
21 }
22 bool encrypt = false;
23 acip_send_options_t options = {.delivery = ACIP_DELIVERY_RELIABLE};
24 buffer_domain_t *domain = NULL;
25 if (buffers[0].len >= sizeof(packet_header_t)) {
26 packet_header_t header;
27 memcpy(&header, buffers[0].data, sizeof(header));
28 packet_type_t type = NET_TO_HOST_U16(header.type);
29 if (packet_is_handshake_type(type) || type == PACKET_TYPE_ERROR_MESSAGE)
30 domain = buffer_control_domain();
32 ? (acip_traffic_class_t)NET_TO_HOST_U32(header.client_id)
34 encrypt = crypto && crypto->encrypt_data && crypto_is_ready(crypto) && type != PACKET_TYPE_ENCRYPTED &&
35 !packet_is_initial_handshake_type(type);
36 } else {
37 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing ACIP packet header");
38 }
39 size_t capacity = 0;
40 crypto_record_t *records = NULL;
41 if (encrypt) {
42 if (size > CRYPTO_MAX_PLAINTEXT_SIZE - 24 ||
43 size > SOCKET_SEND_BUFFER_MAX - sizeof(packet_header_t) - CRYPTO_NONCE_SIZE - CRYPTO_MAC_SIZE)
44 return SET_ERRNO(ERROR_NETWORK_SIZE, "Encrypted ACIP packet too large");
45 crypto_session_t *session = NULL;
46 asciichat_error_t result = crypto_session_lock(crypto, &session);
47 if (result != ASCIICHAT_OK)
48 return result;
49 records = &session->records;
50 crypto_session_unlock(session);
51 capacity = size + 32 + crypto->nonce_size + crypto->mac_size;
52 }
53 *plan = (acip_packet_plan_t){.buffers = buffers,
54 .count = count,
55 .plaintext_size = size,
56 .ciphertext_capacity = capacity,
57 .encrypt = encrypt,
58 .domain = domain,
59 .records = records,
60 .options = options};
61 return ASCIICHAT_OK;
62}
buffer_domain_t * buffer_control_domain(void)
Definition buffer.c:436
struct buffer_domain buffer_domain_t
Definition buffer.h:24
#define NET_TO_HOST_U32(val)
Definition endian.h:81
bool crypto_is_ready(const crypto_context_t *ctx)
Check if key exchange is complete and ready for encryption.
#define CRYPTO_MAX_PLAINTEXT_SIZE
Maximum plaintext size (1MB).
packet_type_t
Network protocol packet type enumeration.
Definition packet.h:301
@ PACKET_TYPE_CRYPTO_EPOCH_MARKER
Definition packet.h:345
@ PACKET_TYPE_ERROR_MESSAGE
Error packet with asciichat_error_t code and human-readable message.
Definition packet.h:374
struct crypto_record crypto_record_t
When code needs to work with crypto record, it keeps crypto, key_epoch, last_receive_epoch,...
#define CRYPTO_NONCE_SIZE
Nonce size (XSalsa20).
Definition sizes.h:79
#define CRYPTO_MAC_SIZE
MAC size (Poly1305).
Definition sizes.h:85
acip_traffic_class_t acip_packet_traffic_class(uint16_t type)
Definition traffic.c:4
acip_traffic_class_t
Definition traffic.h:5
@ ACIP_DELIVERY_RELIABLE
Definition traffic.h:12

References ACIP_DELIVERY_RELIABLE, acip_packet_traffic_class(), ASCIICHAT_OK, buffer_control_domain(), crypto_is_ready(), CRYPTO_MAC_SIZE, CRYPTO_MAX_PLAINTEXT_SIZE, CRYPTO_NONCE_SIZE, crypto_session_lock(), crypto_session_unlock(), crypto_context_t::encrypt_data, ERROR_INVALID_PARAM, ERROR_NETWORK_SIZE, crypto_context_t::mac_size, NET_TO_HOST_U16, NET_TO_HOST_U32, crypto_context_t::nonce_size, PACKET_TYPE_CRYPTO_EPOCH_MARKER, PACKET_TYPE_ENCRYPTED, PACKET_TYPE_ERROR_MESSAGE, crypto_session::records, SET_ERRNO, and acip_send_options_t::traffic_class.

Referenced by send_packet_secure().

◆ acip_packet_seal()

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 at line 125 of file prepare.c.

126 {
127 if (!output || !written || !records || !records->crypto)
128 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid packet encryption arguments");
129 *output = NULL;
130 *written = 0;
131 if ((unsigned)flow > ACIP_TRAFFIC_VISUAL || (unsigned)delivery > ACIP_DELIVERY_DATAGRAM ||
132 (flow == ACIP_TRAFFIC_CONTROL && delivery == ACIP_DELIVERY_DATAGRAM))
133 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid packet output channel");
134 asciichat_error_t result = validate_record_packet(NULL, flow, delivery, packet, length);
135 if (result != ASCIICHAT_OK)
136 return result;
137 socket_buffer_t slice = {packet, length};
138 if (length > CRYPTO_MAX_PLAINTEXT_SIZE - 24)
139 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet exceeds record plaintext capacity");
140 acip_packet_plan_t plan = {.buffers = &slice,
141 .count = 1,
142 .plaintext_size = length,
143 .encrypt = true,
144 .records = records,
145 .records_locked = true,
146 .options = {.traffic_class = flow, .delivery = delivery},
147 .ciphertext_capacity =
148 length + 32 + records->crypto->nonce_size + records->crypto->mac_size};
149 uint8_t *wire = buffer_alloc(plan.domain, sizeof(packet_header_t) + plan.ciphertext_capacity);
150 if (!wire)
151 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate encrypted packet");
152 packet_header_t header;
153 size_t encrypted_length = 0;
154 result = acip_packet_encrypt(records->crypto, &plan, plan.domain, wire + sizeof(header), plan.ciphertext_capacity,
155 &header, &encrypted_length);
156 if (result != ASCIICHAT_OK) {
157 buffer_release(wire);
158 return result;
159 }
160 memcpy(wire, &header, sizeof(header));
161 *output = wire;
162 *written = sizeof(header) + encrypted_length;
163 return ASCIICHAT_OK;
164}
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
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_context_t * crypto
Definition record.h:18
@ ACIP_TRAFFIC_CONTROL
Definition traffic.h:6
@ ACIP_TRAFFIC_VISUAL
Definition traffic.h:8
@ ACIP_DELIVERY_DATAGRAM
Definition traffic.h:13

References ACIP_DELIVERY_DATAGRAM, acip_packet_encrypt(), ACIP_TRAFFIC_CONTROL, ACIP_TRAFFIC_VISUAL, ASCIICHAT_OK, buffer_alloc(), buffer_release, acip_packet_plan_t::ciphertext_capacity, crypto_record::crypto, CRYPTO_MAX_PLAINTEXT_SIZE, acip_packet_plan_t::domain, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, ERROR_MEMORY, ERROR_NETWORK_SIZE, crypto_context_t::mac_size, crypto_context_t::nonce_size, and SET_ERRNO.

Referenced by acip_security_rekey_seal(), and acip_security_seal().