1*62c56f98SSadaf Ebrahimi /*
2*62c56f98SSadaf Ebrahimi * Message Processing Stack, Reader implementation
3*62c56f98SSadaf Ebrahimi *
4*62c56f98SSadaf Ebrahimi * Copyright The Mbed TLS Contributors
5*62c56f98SSadaf Ebrahimi * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6*62c56f98SSadaf Ebrahimi */
7*62c56f98SSadaf Ebrahimi
8*62c56f98SSadaf Ebrahimi #include "common.h"
9*62c56f98SSadaf Ebrahimi
10*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
11*62c56f98SSadaf Ebrahimi
12*62c56f98SSadaf Ebrahimi #include "mps_reader.h"
13*62c56f98SSadaf Ebrahimi #include "mps_common.h"
14*62c56f98SSadaf Ebrahimi #include "mps_trace.h"
15*62c56f98SSadaf Ebrahimi
16*62c56f98SSadaf Ebrahimi #include <string.h>
17*62c56f98SSadaf Ebrahimi
18*62c56f98SSadaf Ebrahimi #if defined(MBEDTLS_MPS_ENABLE_TRACE)
19*62c56f98SSadaf Ebrahimi static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_READER;
20*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_MPS_ENABLE_TRACE */
21*62c56f98SSadaf Ebrahimi
22*62c56f98SSadaf Ebrahimi /*
23*62c56f98SSadaf Ebrahimi * GENERAL NOTE ON CODING STYLE
24*62c56f98SSadaf Ebrahimi *
25*62c56f98SSadaf Ebrahimi * The following code intentionally separates memory loads
26*62c56f98SSadaf Ebrahimi * and stores from other operations (arithmetic or branches).
27*62c56f98SSadaf Ebrahimi * This leads to the introduction of many local variables
28*62c56f98SSadaf Ebrahimi * and significantly increases the C-code line count, but
29*62c56f98SSadaf Ebrahimi * should not increase the size of generated assembly.
30*62c56f98SSadaf Ebrahimi *
31*62c56f98SSadaf Ebrahimi * The reason for this is twofold:
32*62c56f98SSadaf Ebrahimi * (1) It will ease verification efforts using the VST
33*62c56f98SSadaf Ebrahimi * (Verified Software Toolchain)
34*62c56f98SSadaf Ebrahimi * whose program logic cannot directly reason
35*62c56f98SSadaf Ebrahimi * about instructions containing a load or store in
36*62c56f98SSadaf Ebrahimi * addition to other operations (e.g. *p = *q or
37*62c56f98SSadaf Ebrahimi * tmp = *p + 42).
38*62c56f98SSadaf Ebrahimi * (2) Operating on local variables and writing the results
39*62c56f98SSadaf Ebrahimi * back to the target contexts on success only
40*62c56f98SSadaf Ebrahimi * allows to maintain structure invariants even
41*62c56f98SSadaf Ebrahimi * on failure - this in turn has two benefits:
42*62c56f98SSadaf Ebrahimi * (2.a) If for some reason an error code is not caught
43*62c56f98SSadaf Ebrahimi * and operation continues, functions are nonetheless
44*62c56f98SSadaf Ebrahimi * called with sane contexts, reducing the risk
45*62c56f98SSadaf Ebrahimi * of dangerous behavior.
46*62c56f98SSadaf Ebrahimi * (2.b) Randomized testing is easier if structures
47*62c56f98SSadaf Ebrahimi * remain intact even in the face of failing
48*62c56f98SSadaf Ebrahimi * and/or non-sensical calls.
49*62c56f98SSadaf Ebrahimi * Moreover, it might even reduce code-size because
50*62c56f98SSadaf Ebrahimi * the compiler need not write back temporary results
51*62c56f98SSadaf Ebrahimi * to memory in case of failure.
52*62c56f98SSadaf Ebrahimi *
53*62c56f98SSadaf Ebrahimi */
54*62c56f98SSadaf Ebrahimi
mps_reader_is_accumulating(mbedtls_mps_reader const * rd)55*62c56f98SSadaf Ebrahimi static inline int mps_reader_is_accumulating(
56*62c56f98SSadaf Ebrahimi mbedtls_mps_reader const *rd)
57*62c56f98SSadaf Ebrahimi {
58*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t acc_remaining;
59*62c56f98SSadaf Ebrahimi if (rd->acc == NULL) {
60*62c56f98SSadaf Ebrahimi return 0;
61*62c56f98SSadaf Ebrahimi }
62*62c56f98SSadaf Ebrahimi
63*62c56f98SSadaf Ebrahimi acc_remaining = rd->acc_share.acc_remaining;
64*62c56f98SSadaf Ebrahimi return acc_remaining > 0;
65*62c56f98SSadaf Ebrahimi }
66*62c56f98SSadaf Ebrahimi
mps_reader_is_producing(mbedtls_mps_reader const * rd)67*62c56f98SSadaf Ebrahimi static inline int mps_reader_is_producing(
68*62c56f98SSadaf Ebrahimi mbedtls_mps_reader const *rd)
69*62c56f98SSadaf Ebrahimi {
70*62c56f98SSadaf Ebrahimi unsigned char *frag = rd->frag;
71*62c56f98SSadaf Ebrahimi return frag == NULL;
72*62c56f98SSadaf Ebrahimi }
73*62c56f98SSadaf Ebrahimi
mps_reader_is_consuming(mbedtls_mps_reader const * rd)74*62c56f98SSadaf Ebrahimi static inline int mps_reader_is_consuming(
75*62c56f98SSadaf Ebrahimi mbedtls_mps_reader const *rd)
76*62c56f98SSadaf Ebrahimi {
77*62c56f98SSadaf Ebrahimi return !mps_reader_is_producing(rd);
78*62c56f98SSadaf Ebrahimi }
79*62c56f98SSadaf Ebrahimi
mps_reader_get_fragment_offset(mbedtls_mps_reader const * rd)80*62c56f98SSadaf Ebrahimi static inline mbedtls_mps_size_t mps_reader_get_fragment_offset(
81*62c56f98SSadaf Ebrahimi mbedtls_mps_reader const *rd)
82*62c56f98SSadaf Ebrahimi {
83*62c56f98SSadaf Ebrahimi unsigned char *acc = rd->acc;
84*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t frag_offset;
85*62c56f98SSadaf Ebrahimi
86*62c56f98SSadaf Ebrahimi if (acc == NULL) {
87*62c56f98SSadaf Ebrahimi return 0;
88*62c56f98SSadaf Ebrahimi }
89*62c56f98SSadaf Ebrahimi
90*62c56f98SSadaf Ebrahimi frag_offset = rd->acc_share.frag_offset;
91*62c56f98SSadaf Ebrahimi return frag_offset;
92*62c56f98SSadaf Ebrahimi }
93*62c56f98SSadaf Ebrahimi
mps_reader_serving_from_accumulator(mbedtls_mps_reader const * rd)94*62c56f98SSadaf Ebrahimi static inline mbedtls_mps_size_t mps_reader_serving_from_accumulator(
95*62c56f98SSadaf Ebrahimi mbedtls_mps_reader const *rd)
96*62c56f98SSadaf Ebrahimi {
97*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t frag_offset, end;
98*62c56f98SSadaf Ebrahimi
99*62c56f98SSadaf Ebrahimi frag_offset = mps_reader_get_fragment_offset(rd);
100*62c56f98SSadaf Ebrahimi end = rd->end;
101*62c56f98SSadaf Ebrahimi
102*62c56f98SSadaf Ebrahimi return end < frag_offset;
103*62c56f98SSadaf Ebrahimi }
104*62c56f98SSadaf Ebrahimi
mps_reader_zero(mbedtls_mps_reader * rd)105*62c56f98SSadaf Ebrahimi static inline void mps_reader_zero(mbedtls_mps_reader *rd)
106*62c56f98SSadaf Ebrahimi {
107*62c56f98SSadaf Ebrahimi /* A plain memset() would likely be more efficient,
108*62c56f98SSadaf Ebrahimi * but the current way of zeroing makes it harder
109*62c56f98SSadaf Ebrahimi * to overlook fields which should not be zero-initialized.
110*62c56f98SSadaf Ebrahimi * It's also more suitable for FV efforts since it
111*62c56f98SSadaf Ebrahimi * doesn't require reasoning about structs being
112*62c56f98SSadaf Ebrahimi * interpreted as unstructured binary blobs. */
113*62c56f98SSadaf Ebrahimi static mbedtls_mps_reader const zero =
114*62c56f98SSadaf Ebrahimi { .frag = NULL,
115*62c56f98SSadaf Ebrahimi .frag_len = 0,
116*62c56f98SSadaf Ebrahimi .commit = 0,
117*62c56f98SSadaf Ebrahimi .end = 0,
118*62c56f98SSadaf Ebrahimi .pending = 0,
119*62c56f98SSadaf Ebrahimi .acc = NULL,
120*62c56f98SSadaf Ebrahimi .acc_len = 0,
121*62c56f98SSadaf Ebrahimi .acc_available = 0,
122*62c56f98SSadaf Ebrahimi .acc_share = { .acc_remaining = 0 } };
123*62c56f98SSadaf Ebrahimi *rd = zero;
124*62c56f98SSadaf Ebrahimi }
125*62c56f98SSadaf Ebrahimi
mbedtls_mps_reader_init(mbedtls_mps_reader * rd,unsigned char * acc,mbedtls_mps_size_t acc_len)126*62c56f98SSadaf Ebrahimi int mbedtls_mps_reader_init(mbedtls_mps_reader *rd,
127*62c56f98SSadaf Ebrahimi unsigned char *acc,
128*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t acc_len)
129*62c56f98SSadaf Ebrahimi {
130*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_INIT("mbedtls_mps_reader_init");
131*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
132*62c56f98SSadaf Ebrahimi "* Accumulator size: %u bytes", (unsigned) acc_len);
133*62c56f98SSadaf Ebrahimi mps_reader_zero(rd);
134*62c56f98SSadaf Ebrahimi rd->acc = acc;
135*62c56f98SSadaf Ebrahimi rd->acc_len = acc_len;
136*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(0);
137*62c56f98SSadaf Ebrahimi }
138*62c56f98SSadaf Ebrahimi
mbedtls_mps_reader_free(mbedtls_mps_reader * rd)139*62c56f98SSadaf Ebrahimi int mbedtls_mps_reader_free(mbedtls_mps_reader *rd)
140*62c56f98SSadaf Ebrahimi {
141*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_INIT("mbedtls_mps_reader_free");
142*62c56f98SSadaf Ebrahimi mps_reader_zero(rd);
143*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(0);
144*62c56f98SSadaf Ebrahimi }
145*62c56f98SSadaf Ebrahimi
mbedtls_mps_reader_feed(mbedtls_mps_reader * rd,unsigned char * new_frag,mbedtls_mps_size_t new_frag_len)146*62c56f98SSadaf Ebrahimi int mbedtls_mps_reader_feed(mbedtls_mps_reader *rd,
147*62c56f98SSadaf Ebrahimi unsigned char *new_frag,
148*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t new_frag_len)
149*62c56f98SSadaf Ebrahimi {
150*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t copy_to_acc;
151*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_INIT("mbedtls_mps_reader_feed");
152*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
153*62c56f98SSadaf Ebrahimi "* Fragment length: %u bytes", (unsigned) new_frag_len);
154*62c56f98SSadaf Ebrahimi
155*62c56f98SSadaf Ebrahimi if (new_frag == NULL) {
156*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(MBEDTLS_ERR_MPS_READER_INVALID_ARG);
157*62c56f98SSadaf Ebrahimi }
158*62c56f98SSadaf Ebrahimi
159*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_STATE_VALIDATE_RAW(mps_reader_is_producing(
160*62c56f98SSadaf Ebrahimi rd),
161*62c56f98SSadaf Ebrahimi "mbedtls_mps_reader_feed() requires reader to be in producing mode");
162*62c56f98SSadaf Ebrahimi
163*62c56f98SSadaf Ebrahimi if (mps_reader_is_accumulating(rd)) {
164*62c56f98SSadaf Ebrahimi unsigned char *acc = rd->acc;
165*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t acc_remaining = rd->acc_share.acc_remaining;
166*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t acc_available = rd->acc_available;
167*62c56f98SSadaf Ebrahimi
168*62c56f98SSadaf Ebrahimi /* Skip over parts of the accumulator that have already been filled. */
169*62c56f98SSadaf Ebrahimi acc += acc_available;
170*62c56f98SSadaf Ebrahimi
171*62c56f98SSadaf Ebrahimi copy_to_acc = acc_remaining;
172*62c56f98SSadaf Ebrahimi if (copy_to_acc > new_frag_len) {
173*62c56f98SSadaf Ebrahimi copy_to_acc = new_frag_len;
174*62c56f98SSadaf Ebrahimi }
175*62c56f98SSadaf Ebrahimi
176*62c56f98SSadaf Ebrahimi /* Copy new contents to accumulator. */
177*62c56f98SSadaf Ebrahimi memcpy(acc, new_frag, copy_to_acc);
178*62c56f98SSadaf Ebrahimi
179*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
180*62c56f98SSadaf Ebrahimi "Copy new data of size %u of %u into accumulator at offset %u",
181*62c56f98SSadaf Ebrahimi (unsigned) copy_to_acc, (unsigned) new_frag_len,
182*62c56f98SSadaf Ebrahimi (unsigned) acc_available);
183*62c56f98SSadaf Ebrahimi
184*62c56f98SSadaf Ebrahimi /* Check if, with the new fragment, we have enough data. */
185*62c56f98SSadaf Ebrahimi acc_remaining -= copy_to_acc;
186*62c56f98SSadaf Ebrahimi if (acc_remaining > 0) {
187*62c56f98SSadaf Ebrahimi /* We need to accumulate more data. Stay in producing mode. */
188*62c56f98SSadaf Ebrahimi acc_available += copy_to_acc;
189*62c56f98SSadaf Ebrahimi rd->acc_share.acc_remaining = acc_remaining;
190*62c56f98SSadaf Ebrahimi rd->acc_available = acc_available;
191*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(MBEDTLS_ERR_MPS_READER_NEED_MORE);
192*62c56f98SSadaf Ebrahimi }
193*62c56f98SSadaf Ebrahimi
194*62c56f98SSadaf Ebrahimi /* We have filled the accumulator: Move to consuming mode. */
195*62c56f98SSadaf Ebrahimi
196*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
197*62c56f98SSadaf Ebrahimi "Enough data available to serve user request");
198*62c56f98SSadaf Ebrahimi
199*62c56f98SSadaf Ebrahimi /* Remember overlap of accumulator and fragment. */
200*62c56f98SSadaf Ebrahimi rd->acc_share.frag_offset = acc_available;
201*62c56f98SSadaf Ebrahimi acc_available += copy_to_acc;
202*62c56f98SSadaf Ebrahimi rd->acc_available = acc_available;
203*62c56f98SSadaf Ebrahimi } else { /* Not accumulating */
204*62c56f98SSadaf Ebrahimi rd->acc_share.frag_offset = 0;
205*62c56f98SSadaf Ebrahimi }
206*62c56f98SSadaf Ebrahimi
207*62c56f98SSadaf Ebrahimi rd->frag = new_frag;
208*62c56f98SSadaf Ebrahimi rd->frag_len = new_frag_len;
209*62c56f98SSadaf Ebrahimi rd->commit = 0;
210*62c56f98SSadaf Ebrahimi rd->end = 0;
211*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(0);
212*62c56f98SSadaf Ebrahimi }
213*62c56f98SSadaf Ebrahimi
214*62c56f98SSadaf Ebrahimi
mbedtls_mps_reader_get(mbedtls_mps_reader * rd,mbedtls_mps_size_t desired,unsigned char ** buffer,mbedtls_mps_size_t * buflen)215*62c56f98SSadaf Ebrahimi int mbedtls_mps_reader_get(mbedtls_mps_reader *rd,
216*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t desired,
217*62c56f98SSadaf Ebrahimi unsigned char **buffer,
218*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t *buflen)
219*62c56f98SSadaf Ebrahimi {
220*62c56f98SSadaf Ebrahimi unsigned char *frag;
221*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t frag_len, frag_offset, end, frag_fetched, frag_remaining;
222*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_INIT("mbedtls_mps_reader_get");
223*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
224*62c56f98SSadaf Ebrahimi "* Bytes requested: %u", (unsigned) desired);
225*62c56f98SSadaf Ebrahimi
226*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_STATE_VALIDATE_RAW(mps_reader_is_consuming(
227*62c56f98SSadaf Ebrahimi rd),
228*62c56f98SSadaf Ebrahimi "mbedtls_mps_reader_get() requires reader to be in consuming mode");
229*62c56f98SSadaf Ebrahimi
230*62c56f98SSadaf Ebrahimi end = rd->end;
231*62c56f98SSadaf Ebrahimi frag_offset = mps_reader_get_fragment_offset(rd);
232*62c56f98SSadaf Ebrahimi
233*62c56f98SSadaf Ebrahimi /* Check if we're still serving from the accumulator. */
234*62c56f98SSadaf Ebrahimi if (mps_reader_serving_from_accumulator(rd)) {
235*62c56f98SSadaf Ebrahimi /* Illustration of supported and unsupported cases:
236*62c56f98SSadaf Ebrahimi *
237*62c56f98SSadaf Ebrahimi * - Allowed #1
238*62c56f98SSadaf Ebrahimi *
239*62c56f98SSadaf Ebrahimi * +-----------------------------------+
240*62c56f98SSadaf Ebrahimi * | frag |
241*62c56f98SSadaf Ebrahimi * +-----------------------------------+
242*62c56f98SSadaf Ebrahimi *
243*62c56f98SSadaf Ebrahimi * end end+desired
244*62c56f98SSadaf Ebrahimi * | |
245*62c56f98SSadaf Ebrahimi * +-----v-------v-------------+
246*62c56f98SSadaf Ebrahimi * | acc |
247*62c56f98SSadaf Ebrahimi * +---------------------------+
248*62c56f98SSadaf Ebrahimi * | |
249*62c56f98SSadaf Ebrahimi * frag_offset acc_available
250*62c56f98SSadaf Ebrahimi *
251*62c56f98SSadaf Ebrahimi * - Allowed #2
252*62c56f98SSadaf Ebrahimi *
253*62c56f98SSadaf Ebrahimi * +-----------------------------------+
254*62c56f98SSadaf Ebrahimi * | frag |
255*62c56f98SSadaf Ebrahimi * +-----------------------------------+
256*62c56f98SSadaf Ebrahimi *
257*62c56f98SSadaf Ebrahimi * end end+desired
258*62c56f98SSadaf Ebrahimi * | |
259*62c56f98SSadaf Ebrahimi * +----------v----------------v
260*62c56f98SSadaf Ebrahimi * | acc |
261*62c56f98SSadaf Ebrahimi * +---------------------------+
262*62c56f98SSadaf Ebrahimi * | |
263*62c56f98SSadaf Ebrahimi * frag_offset acc_available
264*62c56f98SSadaf Ebrahimi *
265*62c56f98SSadaf Ebrahimi * - Not allowed #1 (could be served, but we don't actually use it):
266*62c56f98SSadaf Ebrahimi *
267*62c56f98SSadaf Ebrahimi * +-----------------------------------+
268*62c56f98SSadaf Ebrahimi * | frag |
269*62c56f98SSadaf Ebrahimi * +-----------------------------------+
270*62c56f98SSadaf Ebrahimi *
271*62c56f98SSadaf Ebrahimi * end end+desired
272*62c56f98SSadaf Ebrahimi * | |
273*62c56f98SSadaf Ebrahimi * +------v-------------v------+
274*62c56f98SSadaf Ebrahimi * | acc |
275*62c56f98SSadaf Ebrahimi * +---------------------------+
276*62c56f98SSadaf Ebrahimi * | |
277*62c56f98SSadaf Ebrahimi * frag_offset acc_available
278*62c56f98SSadaf Ebrahimi *
279*62c56f98SSadaf Ebrahimi *
280*62c56f98SSadaf Ebrahimi * - Not allowed #2 (can't be served with a contiguous buffer):
281*62c56f98SSadaf Ebrahimi *
282*62c56f98SSadaf Ebrahimi * +-----------------------------------+
283*62c56f98SSadaf Ebrahimi * | frag |
284*62c56f98SSadaf Ebrahimi * +-----------------------------------+
285*62c56f98SSadaf Ebrahimi *
286*62c56f98SSadaf Ebrahimi * end end + desired
287*62c56f98SSadaf Ebrahimi * | |
288*62c56f98SSadaf Ebrahimi * +------v--------------------+ v
289*62c56f98SSadaf Ebrahimi * | acc |
290*62c56f98SSadaf Ebrahimi * +---------------------------+
291*62c56f98SSadaf Ebrahimi * | |
292*62c56f98SSadaf Ebrahimi * frag_offset acc_available
293*62c56f98SSadaf Ebrahimi *
294*62c56f98SSadaf Ebrahimi * In case of Allowed #2 we're switching to serve from
295*62c56f98SSadaf Ebrahimi * `frag` starting from the next call to mbedtls_mps_reader_get().
296*62c56f98SSadaf Ebrahimi */
297*62c56f98SSadaf Ebrahimi
298*62c56f98SSadaf Ebrahimi unsigned char *acc;
299*62c56f98SSadaf Ebrahimi
300*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
301*62c56f98SSadaf Ebrahimi "Serve the request from the accumulator");
302*62c56f98SSadaf Ebrahimi if (frag_offset - end < desired) {
303*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t acc_available;
304*62c56f98SSadaf Ebrahimi acc_available = rd->acc_available;
305*62c56f98SSadaf Ebrahimi if (acc_available - end != desired) {
306*62c56f98SSadaf Ebrahimi /* It might be possible to serve some of these situations by
307*62c56f98SSadaf Ebrahimi * making additional space in the accumulator, removing those
308*62c56f98SSadaf Ebrahimi * parts that have already been committed.
309*62c56f98SSadaf Ebrahimi * On the other hand, this brings additional complexity and
310*62c56f98SSadaf Ebrahimi * enlarges the code size, while there doesn't seem to be a use
311*62c56f98SSadaf Ebrahimi * case where we don't attempt exactly the same `get` calls when
312*62c56f98SSadaf Ebrahimi * resuming on a reader than what we tried before pausing it.
313*62c56f98SSadaf Ebrahimi * If we believe we adhere to this restricted usage throughout
314*62c56f98SSadaf Ebrahimi * the library, this check is a good opportunity to
315*62c56f98SSadaf Ebrahimi * validate this. */
316*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(
317*62c56f98SSadaf Ebrahimi MBEDTLS_ERR_MPS_READER_INCONSISTENT_REQUESTS);
318*62c56f98SSadaf Ebrahimi }
319*62c56f98SSadaf Ebrahimi }
320*62c56f98SSadaf Ebrahimi
321*62c56f98SSadaf Ebrahimi acc = rd->acc;
322*62c56f98SSadaf Ebrahimi acc += end;
323*62c56f98SSadaf Ebrahimi
324*62c56f98SSadaf Ebrahimi *buffer = acc;
325*62c56f98SSadaf Ebrahimi if (buflen != NULL) {
326*62c56f98SSadaf Ebrahimi *buflen = desired;
327*62c56f98SSadaf Ebrahimi }
328*62c56f98SSadaf Ebrahimi
329*62c56f98SSadaf Ebrahimi end += desired;
330*62c56f98SSadaf Ebrahimi rd->end = end;
331*62c56f98SSadaf Ebrahimi rd->pending = 0;
332*62c56f98SSadaf Ebrahimi
333*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(0);
334*62c56f98SSadaf Ebrahimi }
335*62c56f98SSadaf Ebrahimi
336*62c56f98SSadaf Ebrahimi /* Attempt to serve the request from the current fragment */
337*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
338*62c56f98SSadaf Ebrahimi "Serve the request from the current fragment.");
339*62c56f98SSadaf Ebrahimi
340*62c56f98SSadaf Ebrahimi frag_len = rd->frag_len;
341*62c56f98SSadaf Ebrahimi frag_fetched = end - frag_offset; /* The amount of data from the current
342*62c56f98SSadaf Ebrahimi * fragment that has already been passed
343*62c56f98SSadaf Ebrahimi * to the user. */
344*62c56f98SSadaf Ebrahimi frag_remaining = frag_len - frag_fetched; /* Remaining data in fragment */
345*62c56f98SSadaf Ebrahimi
346*62c56f98SSadaf Ebrahimi /* Check if we can serve the read request from the fragment. */
347*62c56f98SSadaf Ebrahimi if (frag_remaining < desired) {
348*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
349*62c56f98SSadaf Ebrahimi "There's not enough data in the current fragment "
350*62c56f98SSadaf Ebrahimi "to serve the request.");
351*62c56f98SSadaf Ebrahimi /* There's not enough data in the current fragment,
352*62c56f98SSadaf Ebrahimi * so either just RETURN what we have or fail. */
353*62c56f98SSadaf Ebrahimi if (buflen == NULL) {
354*62c56f98SSadaf Ebrahimi if (frag_remaining > 0) {
355*62c56f98SSadaf Ebrahimi rd->pending = desired - frag_remaining;
356*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
357*62c56f98SSadaf Ebrahimi "Remember to collect %u bytes before re-opening",
358*62c56f98SSadaf Ebrahimi (unsigned) rd->pending);
359*62c56f98SSadaf Ebrahimi }
360*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(MBEDTLS_ERR_MPS_READER_OUT_OF_DATA);
361*62c56f98SSadaf Ebrahimi }
362*62c56f98SSadaf Ebrahimi
363*62c56f98SSadaf Ebrahimi desired = frag_remaining;
364*62c56f98SSadaf Ebrahimi }
365*62c56f98SSadaf Ebrahimi
366*62c56f98SSadaf Ebrahimi /* There's enough data in the current fragment to serve the
367*62c56f98SSadaf Ebrahimi * (potentially modified) read request. */
368*62c56f98SSadaf Ebrahimi
369*62c56f98SSadaf Ebrahimi frag = rd->frag;
370*62c56f98SSadaf Ebrahimi frag += frag_fetched;
371*62c56f98SSadaf Ebrahimi
372*62c56f98SSadaf Ebrahimi *buffer = frag;
373*62c56f98SSadaf Ebrahimi if (buflen != NULL) {
374*62c56f98SSadaf Ebrahimi *buflen = desired;
375*62c56f98SSadaf Ebrahimi }
376*62c56f98SSadaf Ebrahimi
377*62c56f98SSadaf Ebrahimi end += desired;
378*62c56f98SSadaf Ebrahimi rd->end = end;
379*62c56f98SSadaf Ebrahimi rd->pending = 0;
380*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(0);
381*62c56f98SSadaf Ebrahimi }
382*62c56f98SSadaf Ebrahimi
mbedtls_mps_reader_commit(mbedtls_mps_reader * rd)383*62c56f98SSadaf Ebrahimi int mbedtls_mps_reader_commit(mbedtls_mps_reader *rd)
384*62c56f98SSadaf Ebrahimi {
385*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t end;
386*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_INIT("mbedtls_mps_reader_commit");
387*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_STATE_VALIDATE_RAW(mps_reader_is_consuming(
388*62c56f98SSadaf Ebrahimi rd),
389*62c56f98SSadaf Ebrahimi "mbedtls_mps_reader_commit() requires reader to be in consuming mode");
390*62c56f98SSadaf Ebrahimi
391*62c56f98SSadaf Ebrahimi end = rd->end;
392*62c56f98SSadaf Ebrahimi rd->commit = end;
393*62c56f98SSadaf Ebrahimi
394*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(0);
395*62c56f98SSadaf Ebrahimi }
396*62c56f98SSadaf Ebrahimi
mbedtls_mps_reader_reclaim(mbedtls_mps_reader * rd,int * paused)397*62c56f98SSadaf Ebrahimi int mbedtls_mps_reader_reclaim(mbedtls_mps_reader *rd,
398*62c56f98SSadaf Ebrahimi int *paused)
399*62c56f98SSadaf Ebrahimi {
400*62c56f98SSadaf Ebrahimi unsigned char *frag, *acc;
401*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t pending, commit;
402*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t acc_len, frag_offset, frag_len;
403*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_INIT("mbedtls_mps_reader_reclaim");
404*62c56f98SSadaf Ebrahimi
405*62c56f98SSadaf Ebrahimi if (paused != NULL) {
406*62c56f98SSadaf Ebrahimi *paused = 0;
407*62c56f98SSadaf Ebrahimi }
408*62c56f98SSadaf Ebrahimi
409*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_STATE_VALIDATE_RAW(mps_reader_is_consuming(
410*62c56f98SSadaf Ebrahimi rd),
411*62c56f98SSadaf Ebrahimi "mbedtls_mps_reader_reclaim() requires reader to be in consuming mode");
412*62c56f98SSadaf Ebrahimi
413*62c56f98SSadaf Ebrahimi frag = rd->frag;
414*62c56f98SSadaf Ebrahimi acc = rd->acc;
415*62c56f98SSadaf Ebrahimi pending = rd->pending;
416*62c56f98SSadaf Ebrahimi commit = rd->commit;
417*62c56f98SSadaf Ebrahimi frag_len = rd->frag_len;
418*62c56f98SSadaf Ebrahimi
419*62c56f98SSadaf Ebrahimi frag_offset = mps_reader_get_fragment_offset(rd);
420*62c56f98SSadaf Ebrahimi
421*62c56f98SSadaf Ebrahimi if (pending == 0) {
422*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
423*62c56f98SSadaf Ebrahimi "No unsatisfied read-request has been logged.");
424*62c56f98SSadaf Ebrahimi
425*62c56f98SSadaf Ebrahimi /* Check if there's data left to be consumed. */
426*62c56f98SSadaf Ebrahimi if (commit < frag_offset || commit - frag_offset < frag_len) {
427*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
428*62c56f98SSadaf Ebrahimi "There is data left to be consumed.");
429*62c56f98SSadaf Ebrahimi rd->end = commit;
430*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(MBEDTLS_ERR_MPS_READER_DATA_LEFT);
431*62c56f98SSadaf Ebrahimi }
432*62c56f98SSadaf Ebrahimi
433*62c56f98SSadaf Ebrahimi rd->acc_available = 0;
434*62c56f98SSadaf Ebrahimi rd->acc_share.acc_remaining = 0;
435*62c56f98SSadaf Ebrahimi
436*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
437*62c56f98SSadaf Ebrahimi "Fragment has been fully processed and committed.");
438*62c56f98SSadaf Ebrahimi } else {
439*62c56f98SSadaf Ebrahimi int overflow;
440*62c56f98SSadaf Ebrahimi
441*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t acc_backup_offset;
442*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t acc_backup_len;
443*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t frag_backup_offset;
444*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t frag_backup_len;
445*62c56f98SSadaf Ebrahimi
446*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t backup_len;
447*62c56f98SSadaf Ebrahimi mbedtls_mps_size_t acc_len_needed;
448*62c56f98SSadaf Ebrahimi
449*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
450*62c56f98SSadaf Ebrahimi "There has been an unsatisfied read with %u bytes overhead.",
451*62c56f98SSadaf Ebrahimi (unsigned) pending);
452*62c56f98SSadaf Ebrahimi
453*62c56f98SSadaf Ebrahimi if (acc == NULL) {
454*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
455*62c56f98SSadaf Ebrahimi "No accumulator present");
456*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(
457*62c56f98SSadaf Ebrahimi MBEDTLS_ERR_MPS_READER_NEED_ACCUMULATOR);
458*62c56f98SSadaf Ebrahimi }
459*62c56f98SSadaf Ebrahimi acc_len = rd->acc_len;
460*62c56f98SSadaf Ebrahimi
461*62c56f98SSadaf Ebrahimi /* Check if the upper layer has already fetched
462*62c56f98SSadaf Ebrahimi * and committed the contents of the accumulator. */
463*62c56f98SSadaf Ebrahimi if (commit < frag_offset) {
464*62c56f98SSadaf Ebrahimi /* No, accumulator is still being processed. */
465*62c56f98SSadaf Ebrahimi frag_backup_offset = 0;
466*62c56f98SSadaf Ebrahimi frag_backup_len = frag_len;
467*62c56f98SSadaf Ebrahimi acc_backup_offset = commit;
468*62c56f98SSadaf Ebrahimi acc_backup_len = frag_offset - commit;
469*62c56f98SSadaf Ebrahimi } else {
470*62c56f98SSadaf Ebrahimi /* Yes, the accumulator is already processed. */
471*62c56f98SSadaf Ebrahimi frag_backup_offset = commit - frag_offset;
472*62c56f98SSadaf Ebrahimi frag_backup_len = frag_len - frag_backup_offset;
473*62c56f98SSadaf Ebrahimi acc_backup_offset = 0;
474*62c56f98SSadaf Ebrahimi acc_backup_len = 0;
475*62c56f98SSadaf Ebrahimi }
476*62c56f98SSadaf Ebrahimi
477*62c56f98SSadaf Ebrahimi backup_len = acc_backup_len + frag_backup_len;
478*62c56f98SSadaf Ebrahimi acc_len_needed = backup_len + pending;
479*62c56f98SSadaf Ebrahimi
480*62c56f98SSadaf Ebrahimi overflow = 0;
481*62c56f98SSadaf Ebrahimi overflow |= (backup_len < acc_backup_len);
482*62c56f98SSadaf Ebrahimi overflow |= (acc_len_needed < backup_len);
483*62c56f98SSadaf Ebrahimi
484*62c56f98SSadaf Ebrahimi if (overflow || acc_len < acc_len_needed) {
485*62c56f98SSadaf Ebrahimi /* Except for the different return code, we behave as if
486*62c56f98SSadaf Ebrahimi * there hadn't been a call to mbedtls_mps_reader_get()
487*62c56f98SSadaf Ebrahimi * since the last commit. */
488*62c56f98SSadaf Ebrahimi rd->end = commit;
489*62c56f98SSadaf Ebrahimi rd->pending = 0;
490*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_ERROR,
491*62c56f98SSadaf Ebrahimi "The accumulator is too small to handle the backup.");
492*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_ERROR,
493*62c56f98SSadaf Ebrahimi "* Size: %u", (unsigned) acc_len);
494*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_ERROR,
495*62c56f98SSadaf Ebrahimi "* Needed: %u (%u + %u)",
496*62c56f98SSadaf Ebrahimi (unsigned) acc_len_needed,
497*62c56f98SSadaf Ebrahimi (unsigned) backup_len, (unsigned) pending);
498*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(
499*62c56f98SSadaf Ebrahimi MBEDTLS_ERR_MPS_READER_ACCUMULATOR_TOO_SMALL);
500*62c56f98SSadaf Ebrahimi }
501*62c56f98SSadaf Ebrahimi
502*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
503*62c56f98SSadaf Ebrahimi "Fragment backup: %u", (unsigned) frag_backup_len);
504*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
505*62c56f98SSadaf Ebrahimi "Accumulator backup: %u", (unsigned) acc_backup_len);
506*62c56f98SSadaf Ebrahimi
507*62c56f98SSadaf Ebrahimi /* Move uncommitted parts from the accumulator to the front
508*62c56f98SSadaf Ebrahimi * of the accumulator. */
509*62c56f98SSadaf Ebrahimi memmove(acc, acc + acc_backup_offset, acc_backup_len);
510*62c56f98SSadaf Ebrahimi
511*62c56f98SSadaf Ebrahimi /* Copy uncommitted parts of the current fragment to the
512*62c56f98SSadaf Ebrahimi * accumulator. */
513*62c56f98SSadaf Ebrahimi memcpy(acc + acc_backup_len,
514*62c56f98SSadaf Ebrahimi frag + frag_backup_offset, frag_backup_len);
515*62c56f98SSadaf Ebrahimi
516*62c56f98SSadaf Ebrahimi rd->acc_available = backup_len;
517*62c56f98SSadaf Ebrahimi rd->acc_share.acc_remaining = pending;
518*62c56f98SSadaf Ebrahimi
519*62c56f98SSadaf Ebrahimi if (paused != NULL) {
520*62c56f98SSadaf Ebrahimi *paused = 1;
521*62c56f98SSadaf Ebrahimi }
522*62c56f98SSadaf Ebrahimi }
523*62c56f98SSadaf Ebrahimi
524*62c56f98SSadaf Ebrahimi rd->frag = NULL;
525*62c56f98SSadaf Ebrahimi rd->frag_len = 0;
526*62c56f98SSadaf Ebrahimi
527*62c56f98SSadaf Ebrahimi rd->commit = 0;
528*62c56f98SSadaf Ebrahimi rd->end = 0;
529*62c56f98SSadaf Ebrahimi rd->pending = 0;
530*62c56f98SSadaf Ebrahimi
531*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE(MBEDTLS_MPS_TRACE_TYPE_COMMENT,
532*62c56f98SSadaf Ebrahimi "Final state: aa %u, al %u, ar %u",
533*62c56f98SSadaf Ebrahimi (unsigned) rd->acc_available, (unsigned) rd->acc_len,
534*62c56f98SSadaf Ebrahimi (unsigned) rd->acc_share.acc_remaining);
535*62c56f98SSadaf Ebrahimi MBEDTLS_MPS_TRACE_RETURN(0);
536*62c56f98SSadaf Ebrahimi }
537*62c56f98SSadaf Ebrahimi
538*62c56f98SSadaf Ebrahimi #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
539