xref: /aosp_15_r20/external/mbedtls/library/mps_reader.c (revision 62c56f9862f102b96d72393aff6076c951fb8148)
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