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

Go to the source code of this file.

Macros

#define CRYPTO_REKEY_TIMEOUT_NS   (30ULL * NS_PER_SEC_INT)

Functions

asciichat_error_t crypto_rekey_session_init (crypto_rekey_session_t *s, crypto_record_t *security, crypto_rekey_emit_fn send, void *context, uint64_t now)
asciichat_error_t crypto_rekey_session_tick (crypto_rekey_session_t *s, uint64_t now)
asciichat_error_t crypto_rekey_session_request (crypto_rekey_session_t *s, uint64_t now)
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)
void crypto_rekey_session_cleanup (crypto_rekey_session_t *s)

Macro Definition Documentation

◆ CRYPTO_REKEY_TIMEOUT_NS

#define CRYPTO_REKEY_TIMEOUT_NS   (30ULL * NS_PER_SEC_INT)

Definition at line 6 of file rekey.c.

Referenced by crypto_rekey_session_tick().

Function Documentation

◆ crypto_rekey_session_cleanup()

void crypto_rekey_session_cleanup ( crypto_rekey_session_t * s)

Definition at line 203 of file rekey.c.

203 {
204 if (!s)
205 return;
208 sodium_memzero(s, sizeof(*s));
209}
void crypto_rekey_abort(crypto_context_t *ctx)
Abort rekeying and fallback to old keys.
crypto_context_t * crypto
Definition record.h:18
crypto_record_t * security
Definition rekey.h:21
uint64_t exchange_ns
Definition rekey.h:24

References crypto_record::crypto, crypto_rekey_abort(), crypto_rekey_session_t::exchange_ns, crypto_context_t::rekey_in_progress, and crypto_rekey_session_t::security.

Referenced by crypto_session_destroy().

◆ crypto_rekey_session_init()

asciichat_error_t crypto_rekey_session_init ( crypto_rekey_session_t * s,
crypto_record_t * security,
crypto_rekey_emit_fn send,
void * context,
uint64_t now_ns )

The caller serializes access with the associated record context.

Definition at line 53 of file rekey.c.

54 {
55 if (!s || s->security || !security || !security->crypto || !send || now == UINT64_MAX)
56 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid session rekey initialization");
57 *s = (crypto_rekey_session_t){.security = security,
58 .send = send,
59 .context = context,
60 .activated_ns = now,
61 .last_ns = now,
62 .seen_epoch = security->key_epoch,
63 .peer_ack = security->key_epoch};
64 return ASCIICHAT_OK;
65}
#define SET_ERRNO(code,...)
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
uint64_t key_epoch
Definition record.h:19
crypto rekey session is intentionally a small, concrete record. Fields such as security,...
Definition rekey.h:20

References ASCIICHAT_OK, crypto_record::crypto, ERROR_INVALID_PARAM, crypto_record::key_epoch, crypto_rekey_session_t::security, and SET_ERRNO.

Referenced by crypto_session_lock().

◆ crypto_rekey_session_receive()

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 at line 127 of file rekey.c.

129 {
130 if (!consumed || (!payload && bytes) || flow >= CRYPTO_RECORD_CHANNELS || type > CRYPTO_REKEY_NEEDED)
131 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid rekey input");
132 *consumed = false;
133 asciichat_error_t result = clock_step(s, now);
134 if (result != ASCIICHAT_OK)
135 return result;
136 result = observe_epoch(s);
137 if (result != ASCIICHAT_OK)
138 return result;
139 if (type == CRYPTO_REKEY_NONE)
140 return crypto_rekey_session_tick(s, now);
141 *consumed = true;
142 uint64_t epoch = s->security->key_epoch;
143 if (delivery != CRYPTO_RECORD_RELIABLE || s->security->last_receive_epoch != epoch ||
144 (type != CRYPTO_REKEY_MARKER && flow != 0))
145 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "session rekey message has invalid flow, delivery, or epoch");
146 crypto_context_t *crypto = s->security->crypto;
147 if (type == CRYPTO_REKEY_MARKER || type == CRYPTO_REKEY_ACK) {
148 uint64_t value;
149 if (bytes != sizeof(value))
150 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid session epoch marker length");
151 memcpy(&value, payload, sizeof(value));
152 if (!epoch || NET_TO_HOST_U64(value) != epoch || !s->markers_sent)
153 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Unexpected session epoch marker");
154 if (type == CRYPTO_REKEY_MARKER) {
155 if (!s->security->previous_valid || !s->security->previous_allowed[flow])
156 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Duplicate session flow retirement marker");
157 result = crypto_record_retire_epoch_flow(s->security, flow, epoch);
158 } else {
159 s->peer_ack = epoch;
160 }
161 } else if (type == CRYPTO_REKEY_NEEDED) {
162 if (!s->security->server || bytes)
163 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid session rekey request signal");
164 if (!s->exchange_ns)
165 s->requested = true;
166 } else if (type == CRYPTO_REKEY_REQUEST) {
169 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Unexpected session ephemeral rekey request");
170 s->exchange_ns = now;
171 s->remote_requested = false;
172 s->deferred_request = true;
173 memcpy(s->deferred_key, payload, sizeof(s->deferred_key));
174 } else if (type == CRYPTO_REKEY_RESPONSE) {
175 if (!s->security->server || !s->waiting_response || bytes != CRYPTO_PUBLIC_KEY_SIZE)
176 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Unexpected session ephemeral rekey response");
177 if (crypto_rekey_process_response(crypto, payload) != CRYPTO_OK)
178 return SET_ERRNO(ERROR_CRYPTO, "Cannot compute session next epoch");
180 if (result == ASCIICHAT_OK)
182 if (result == ASCIICHAT_OK) {
183 s->waiting_response = false;
184 s->activated_ns = now;
185 uint8_t proof = 0;
186 result = send_rekey_packet(s, 0, CRYPTO_REKEY_COMPLETE, &proof, 1);
187 }
188 } else {
189 if (s->security->server || !s->expecting_complete || bytes != 1 || ((const uint8_t *)payload)[0] || !epoch ||
191 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Unexpected session rekey confirmation");
192 s->expecting_complete = false;
193 s->activated_ns = now;
194 }
195 if (result != ASCIICHAT_OK)
196 return result;
197 result = observe_epoch(s);
198 if (result != ASCIICHAT_OK)
199 return result;
200 return crypto_rekey_session_tick(s, now);
201}
#define NET_TO_HOST_U64(val)
Definition endian.h:228
unsigned long long uint64_t
Definition common.h:63
unsigned char uint8_t
Definition common.h:60
crypto_result_t crypto_rekey_process_response(crypto_context_t *ctx, const uint8_t *peer_new_public_key)
Process REKEY_RESPONSE from peer (initiator side).
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:76
@ ERROR_CRYPTO
Definition error_codes.h:93
asciichat_error_t crypto_record_commit_epoch(crypto_record_t *state)
Definition record.c:211
asciichat_error_t crypto_record_prepare_epoch(crypto_record_t *state)
Definition record.c:203
asciichat_error_t crypto_record_retire_epoch_flow(crypto_record_t *state, unsigned traffic_class, uint64_t epoch)
Definition record.c:236
#define CRYPTO_RECORD_RELIABLE
Definition record.h:9
#define CRYPTO_RECORD_CHANNELS
Definition record.h:7
asciichat_error_t crypto_rekey_session_tick(crypto_rekey_session_t *s, uint64_t now)
Definition rekey.c:72
@ CRYPTO_REKEY_REQUEST
Definition rekey.h:8
@ CRYPTO_REKEY_NONE
Definition rekey.h:7
@ CRYPTO_REKEY_RESPONSE
Definition rekey.h:9
@ CRYPTO_REKEY_MARKER
Definition rekey.h:11
@ CRYPTO_REKEY_NEEDED
Definition rekey.h:13
@ CRYPTO_REKEY_COMPLETE
Definition rekey.h:10
@ CRYPTO_REKEY_ACK
Definition rekey.h:12
#define CRYPTO_PUBLIC_KEY_SIZE
Public key size (X25519).
Definition sizes.h:67
Endpoint cryptographic state for handshake, packet protection, authentication, and rekeying.
uint64_t last_receive_epoch
Definition record.h:19
bool previous_valid
Definition record.h:22
bool pending_prepared
Definition record.h:22
bool server
Definition record.h:27
bool previous_allowed[3]
Definition record.h:22
uint8_t deferred_key[CRYPTO_PUBLIC_KEY_SIZE]
Definition rekey.h:25
uint64_t activated_ns
Definition rekey.h:24
uint64_t peer_ack
Definition rekey.h:24

References crypto_rekey_session_t::activated_ns, ASCIICHAT_OK, crypto_record::crypto, CRYPTO_OK, CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_RECORD_CHANNELS, crypto_record_commit_epoch(), crypto_record_prepare_epoch(), CRYPTO_RECORD_RELIABLE, crypto_record_retire_epoch_flow(), CRYPTO_REKEY_ACK, CRYPTO_REKEY_COMPLETE, CRYPTO_REKEY_MARKER, CRYPTO_REKEY_NEEDED, CRYPTO_REKEY_NONE, crypto_rekey_process_response(), CRYPTO_REKEY_REQUEST, CRYPTO_REKEY_RESPONSE, crypto_rekey_session_tick(), crypto_rekey_session_t::deferred_key, crypto_rekey_session_t::deferred_request, ERROR_CRYPTO, ERROR_INVALID_PARAM, ERROR_NETWORK_PROTOCOL, crypto_rekey_session_t::exchange_ns, crypto_rekey_session_t::expecting_complete, crypto_record::key_epoch, crypto_record::last_receive_epoch, crypto_rekey_session_t::markers_sent, NET_TO_HOST_U64, crypto_rekey_session_t::peer_ack, crypto_record::pending_prepared, crypto_record::previous_allowed, crypto_record::previous_valid, crypto_rekey_session_t::remote_requested, crypto_rekey_session_t::requested, crypto_rekey_session_t::security, crypto_record::server, SET_ERRNO, and crypto_rekey_session_t::waiting_response.

Referenced by acip_security_rekey_receive(), and crypto_session_receive().

◆ crypto_rekey_session_request()

asciichat_error_t crypto_rekey_session_request ( crypto_rekey_session_t * s,
uint64_t now )

Definition at line 118 of file rekey.c.

118 {
119 asciichat_error_t result = clock_step(s, now);
120 if (result != ASCIICHAT_OK)
121 return result;
122 if (!s->exchange_ns)
123 s->requested = true;
124 return crypto_rekey_session_tick(s, now);
125}

References ASCIICHAT_OK, crypto_rekey_session_tick(), crypto_rekey_session_t::exchange_ns, and crypto_rekey_session_t::requested.

Referenced by acip_security_request_rekey().

◆ crypto_rekey_session_tick()

asciichat_error_t crypto_rekey_session_tick ( crypto_rekey_session_t * s,
uint64_t now )

Definition at line 72 of file rekey.c.

72 {
73 asciichat_error_t result = clock_step(s, now);
74 if (result != ASCIICHAT_OK)
75 return result;
76 result = observe_epoch(s);
77 if (result != ASCIICHAT_OK)
78 return result;
80 return SET_ERRNO(ERROR_NETWORK_TIMEOUT, "session key exchange or flow retirement timed out");
81 // A peer measures its interval at send time. Keep one authenticated request
82 // until our receive-side interval elapses; network jitter must not turn a
83 // valid rotation into a protocol violation or bypass the rate limit.
84 if (s->deferred_request && request_allowed(s, now)) {
85 crypto_context_t *crypto = s->security->crypto;
86 s->deferred_request = false;
87 s->expecting_complete = true;
88 s->last_request_ns = now;
90 return SET_ERRNO(ERROR_CRYPTO, "Cannot compute session rekey response");
91 sodium_memzero(s->deferred_key, sizeof(s->deferred_key));
93 if (result == ASCIICHAT_OK)
94 result = send_rekey_packet(s, 0, CRYPTO_REKEY_RESPONSE, crypto->temp_public_key, CRYPTO_PUBLIC_KEY_SIZE);
95 return result;
96 }
97 if (!settled(s) || !request_allowed(s, now))
98 return ASCIICHAT_OK;
99 crypto_context_t *crypto = s->security->crypto;
100 bool threshold =
101 crypto->rekey_packet_count >= crypto->rekey_packet_threshold ||
102 (crypto->rekey_time_threshold > 0 && now - s->activated_ns >= (uint64_t)crypto->rekey_time_threshold);
103 if (!s->requested && !threshold)
104 return ASCIICHAT_OK;
105 s->requested = false;
106 s->exchange_ns = now;
107 if (!s->security->server) {
108 s->remote_requested = true;
109 return send_rekey_packet(s, 0, CRYPTO_REKEY_NEEDED, NULL, 0);
110 }
111 if (crypto_rekey_init(crypto) != CRYPTO_OK)
112 return SET_ERRNO(ERROR_CRYPTO, "Cannot initiate session ephemeral rekey");
113 s->waiting_response = true;
114 s->last_request_ns = now;
115 return send_rekey_packet(s, 0, CRYPTO_REKEY_REQUEST, crypto->temp_public_key, CRYPTO_PUBLIC_KEY_SIZE);
116}
crypto_result_t crypto_rekey_process_request(crypto_context_t *ctx, const uint8_t *peer_new_public_key)
Process REKEY_REQUEST from peer (responder side).
crypto_result_t crypto_rekey_init(crypto_context_t *ctx)
Initiate rekeying by generating new ephemeral keys.
@ ERROR_NETWORK_TIMEOUT
Definition error_codes.h:75
#define CRYPTO_REKEY_TIMEOUT_NS
Definition rekey.c:6
uint64_t last_request_ns
Definition rekey.h:24

References crypto_rekey_session_t::activated_ns, ASCIICHAT_OK, crypto_record::crypto, CRYPTO_OK, CRYPTO_PUBLIC_KEY_SIZE, crypto_record_prepare_epoch(), crypto_rekey_init(), CRYPTO_REKEY_NEEDED, crypto_rekey_process_request(), CRYPTO_REKEY_REQUEST, CRYPTO_REKEY_RESPONSE, CRYPTO_REKEY_TIMEOUT_NS, crypto_rekey_session_t::deferred_key, crypto_rekey_session_t::deferred_request, ERROR_CRYPTO, ERROR_NETWORK_TIMEOUT, crypto_rekey_session_t::exchange_ns, crypto_rekey_session_t::expecting_complete, crypto_rekey_session_t::last_request_ns, crypto_context_t::rekey_packet_count, crypto_context_t::rekey_packet_threshold, crypto_context_t::rekey_time_threshold, crypto_rekey_session_t::remote_requested, crypto_rekey_session_t::requested, crypto_rekey_session_t::security, crypto_record::server, SET_ERRNO, crypto_context_t::temp_public_key, and crypto_rekey_session_t::waiting_response.

Referenced by crypto_rekey_session_receive(), crypto_rekey_session_request(), and crypto_session_tick().