Tom Rini | 0344c60 | 2024-10-08 13:56:50 -0600 | [diff] [blame] | 1 | /* |
| 2 | * Copyright The Mbed TLS Contributors |
| 3 | * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
| 4 | */ |
| 5 | |
| 6 | /** |
| 7 | * \file mps_reader.h |
| 8 | * |
| 9 | * \brief This file defines reader objects, which together with their |
| 10 | * sibling writer objects form the basis for the communication |
| 11 | * between the various layers of the Mbed TLS messaging stack, |
| 12 | * as well as the communication between the messaging stack and |
| 13 | * the (D)TLS handshake protocol implementation. |
| 14 | * |
| 15 | * Readers provide a means of transferring incoming data from |
| 16 | * a 'producer' providing it in chunks of arbitrary size, to |
| 17 | * a 'consumer' which fetches and processes it in chunks of |
| 18 | * again arbitrary, and potentially different, size. |
| 19 | * |
| 20 | * Readers can thus be seen as datagram-to-stream converters, |
| 21 | * and they abstract away the following two tasks from the user: |
| 22 | * 1. The pointer arithmetic of stepping through a producer- |
| 23 | * provided chunk in smaller chunks. |
| 24 | * 2. The merging of incoming data chunks in case the |
| 25 | * consumer requests data in larger chunks than what the |
| 26 | * producer provides. |
| 27 | * |
| 28 | * The basic abstract flow of operation is the following: |
| 29 | * - Initially, the reader is in 'producing mode'. |
| 30 | * - The producer hands an incoming data buffer to the reader, |
| 31 | * moving it from 'producing' to 'consuming' mode. |
| 32 | * - The consumer subsequently fetches and processes the buffer |
| 33 | * content. Once that's done -- or partially done and a consumer's |
| 34 | * request can't be fulfilled -- the producer revokes the reader's |
| 35 | * access to the incoming data buffer, putting the reader back to |
| 36 | * producing mode. |
| 37 | * - The producer subsequently gathers more incoming data and hands |
| 38 | * it to the reader until it switches back to consuming mode |
| 39 | * if enough data is available for the last consumer request to |
| 40 | * be satisfiable. |
| 41 | * - Repeat the above. |
| 42 | * |
| 43 | * The abstract states of the reader from the producer's and |
| 44 | * consumer's perspective are as follows: |
| 45 | * |
| 46 | * - From the perspective of the consumer, the state of the |
| 47 | * reader consists of the following: |
| 48 | * - A byte stream representing (concatenation of) the data |
| 49 | * received through calls to mbedtls_mps_reader_get(), |
| 50 | * - A marker within that byte stream indicating which data |
| 51 | * can be considered processed, and hence need not be retained, |
| 52 | * when the reader is passed back to the producer via |
| 53 | * mbedtls_mps_reader_reclaim(). |
| 54 | * The marker is set via mbedtls_mps_reader_commit() |
| 55 | * which places it at the end of the current byte stream. |
| 56 | * The consumer need not be aware of the distinction between consumer |
| 57 | * and producer mode, because it only interfaces with the reader |
| 58 | * when the latter is in consuming mode. |
| 59 | * |
| 60 | * - From the perspective of the producer, the reader's state is one of: |
| 61 | * - Attached: The reader is in consuming mode. |
| 62 | * - Unset: No incoming data buffer is currently managed by the reader, |
| 63 | * and all previously handed incoming data buffers have been |
| 64 | * fully processed. More data needs to be fed into the reader |
| 65 | * via mbedtls_mps_reader_feed(). |
| 66 | * |
| 67 | * - Accumulating: No incoming data buffer is currently managed by the |
| 68 | * reader, but some data from the previous incoming data |
| 69 | * buffer hasn't been processed yet and is internally |
| 70 | * held back. |
| 71 | * The Attached state belongs to consuming mode, while the Unset and |
| 72 | * Accumulating states belong to producing mode. |
| 73 | * |
| 74 | * Transitioning from the Unset or Accumulating state to Attached is |
| 75 | * done via successful calls to mbedtls_mps_reader_feed(), while |
| 76 | * transitioning from Attached to either Unset or Accumulating (depending |
| 77 | * on what has been processed) is done via mbedtls_mps_reader_reclaim(). |
| 78 | * |
| 79 | * The following diagram depicts the producer-state progression: |
| 80 | * |
| 81 | * +------------------+ reclaim |
| 82 | * | Unset +<-------------------------------------+ get |
| 83 | * +--------|---------+ | +------+ |
| 84 | * | | | | |
| 85 | * | | | | |
| 86 | * | feed +---------+---+--+ | |
| 87 | * +--------------------------------------> <---+ |
| 88 | * | Attached | |
| 89 | * +--------------------------------------> <---+ |
| 90 | * | feed, enough data available +---------+---+--+ | |
| 91 | * | to serve previous consumer request | | | |
| 92 | * | | | | |
| 93 | * +--------+---------+ | +------+ |
| 94 | * +----> Accumulating |<-------------------------------------+ commit |
| 95 | * | +---+--------------+ reclaim, previous read request |
| 96 | * | | couldn't be fulfilled |
| 97 | * | | |
| 98 | * +--------+ |
| 99 | * feed, need more data to serve |
| 100 | * previous consumer request |
| 101 | * | |
| 102 | * | |
| 103 | * producing mode | consuming mode |
| 104 | * | |
| 105 | * |
| 106 | */ |
| 107 | |
| 108 | #ifndef MBEDTLS_READER_H |
| 109 | #define MBEDTLS_READER_H |
| 110 | |
| 111 | #include <stdio.h> |
| 112 | |
| 113 | #include "mps_common.h" |
| 114 | #include "mps_error.h" |
| 115 | |
| 116 | struct mbedtls_mps_reader; |
| 117 | typedef struct mbedtls_mps_reader mbedtls_mps_reader; |
| 118 | |
| 119 | /* |
| 120 | * Structure definitions |
| 121 | */ |
| 122 | |
| 123 | struct mbedtls_mps_reader { |
| 124 | unsigned char *frag; /*!< The fragment of incoming data managed by |
| 125 | * the reader; it is provided to the reader |
| 126 | * through mbedtls_mps_reader_feed(). The reader |
| 127 | * does not own the fragment and does not |
| 128 | * perform any allocation operations on it, |
| 129 | * but does have read and write access to it. |
| 130 | * |
| 131 | * The reader is in consuming mode if |
| 132 | * and only if \c frag is not \c NULL. */ |
| 133 | mbedtls_mps_stored_size_t frag_len; |
| 134 | /*!< The length of the current fragment. |
| 135 | * Must be 0 if \c frag == \c NULL. */ |
| 136 | mbedtls_mps_stored_size_t commit; |
| 137 | /*!< The offset of the last commit, relative |
| 138 | * to the first byte in the fragment, if |
| 139 | * no accumulator is present. If an accumulator |
| 140 | * is present, it is viewed as a prefix to the |
| 141 | * current fragment, and this variable contains |
| 142 | * an offset from the beginning of the accumulator. |
| 143 | * |
| 144 | * This is only used when the reader is in |
| 145 | * consuming mode, i.e. \c frag != \c NULL; |
| 146 | * otherwise, its value is \c 0. */ |
| 147 | mbedtls_mps_stored_size_t end; |
| 148 | /*!< The offset of the end of the last chunk |
| 149 | * passed to the user through a call to |
| 150 | * mbedtls_mps_reader_get(), relative to the first |
| 151 | * byte in the fragment, if no accumulator is |
| 152 | * present. If an accumulator is present, it is |
| 153 | * viewed as a prefix to the current fragment, and |
| 154 | * this variable contains an offset from the |
| 155 | * beginning of the accumulator. |
| 156 | * |
| 157 | * This is only used when the reader is in |
| 158 | * consuming mode, i.e. \c frag != \c NULL; |
| 159 | * otherwise, its value is \c 0. */ |
| 160 | mbedtls_mps_stored_size_t pending; |
| 161 | /*!< The amount of incoming data missing on the |
| 162 | * last call to mbedtls_mps_reader_get(). |
| 163 | * In particular, it is \c 0 if the last call |
| 164 | * was successful. |
| 165 | * If a reader is reclaimed after an |
| 166 | * unsuccessful call to mbedtls_mps_reader_get(), |
| 167 | * this variable is used to have the reader |
| 168 | * remember how much data should be accumulated |
| 169 | * so that the call to mbedtls_mps_reader_get() |
| 170 | * succeeds next time. |
| 171 | * This is only used when the reader is in |
| 172 | * consuming mode, i.e. \c frag != \c NULL; |
| 173 | * otherwise, its value is \c 0. */ |
| 174 | |
| 175 | /* The accumulator is only needed if we need to be able to pause |
| 176 | * the reader. A few bytes could be saved by moving this to a |
| 177 | * separate struct and using a pointer here. */ |
| 178 | |
| 179 | unsigned char *acc; /*!< The accumulator is used to gather incoming |
| 180 | * data if a read-request via mbedtls_mps_reader_get() |
| 181 | * cannot be served from the current fragment. */ |
| 182 | mbedtls_mps_stored_size_t acc_len; |
| 183 | /*!< The total size of the accumulator. */ |
| 184 | mbedtls_mps_stored_size_t acc_available; |
| 185 | /*!< The number of bytes currently gathered in |
| 186 | * the accumulator. This is both used in |
| 187 | * producing and in consuming mode: |
| 188 | * While producing, it is increased until |
| 189 | * it reaches the value of \c acc_remaining below. |
| 190 | * While consuming, it is used to judge if a |
| 191 | * get request can be served from the |
| 192 | * accumulator or not. |
| 193 | * Must not be larger than \c acc_len. */ |
| 194 | union { |
| 195 | mbedtls_mps_stored_size_t acc_remaining; |
| 196 | /*!< This indicates the amount of data still |
| 197 | * to be gathered in the accumulator. It is |
| 198 | * only used in producing mode. |
| 199 | * Must be at most acc_len - acc_available. */ |
| 200 | mbedtls_mps_stored_size_t frag_offset; |
| 201 | /*!< If an accumulator is present and in use, this |
| 202 | * field indicates the offset of the current |
| 203 | * fragment from the beginning of the |
| 204 | * accumulator. If no accumulator is present |
| 205 | * or the accumulator is not in use, this is \c 0. |
| 206 | * It is only used in consuming mode. |
| 207 | * Must not be larger than \c acc_available. */ |
| 208 | } acc_share; |
| 209 | }; |
| 210 | |
| 211 | /* |
| 212 | * API organization: |
| 213 | * A reader object is usually prepared and maintained |
| 214 | * by some lower layer and passed for usage to an upper |
| 215 | * layer, and the API naturally splits according to which |
| 216 | * layer is supposed to use the respective functions. |
| 217 | */ |
| 218 | |
| 219 | /* |
| 220 | * Maintenance API (Lower layer) |
| 221 | */ |
| 222 | |
| 223 | /** |
| 224 | * \brief Initialize a reader object |
| 225 | * |
| 226 | * \param reader The reader to be initialized. |
| 227 | * \param acc The buffer to be used as a temporary accumulator |
| 228 | * in case get requests through mbedtls_mps_reader_get() |
| 229 | * exceed the buffer provided by mbedtls_mps_reader_feed(). |
| 230 | * This buffer is owned by the caller and exclusive use |
| 231 | * for reading and writing is given to the reader for the |
| 232 | * duration of the reader's lifetime. It is thus the caller's |
| 233 | * responsibility to maintain (and not touch) the buffer for |
| 234 | * the lifetime of the reader, and to properly zeroize and |
| 235 | * free the memory after the reader has been destroyed. |
| 236 | * \param acc_len The size in Bytes of \p acc. |
| 237 | * |
| 238 | * \return \c 0 on success. |
| 239 | * \return A negative \c MBEDTLS_ERR_READER_XXX error code on failure. |
| 240 | */ |
| 241 | int mbedtls_mps_reader_init(mbedtls_mps_reader *reader, |
| 242 | unsigned char *acc, |
| 243 | mbedtls_mps_size_t acc_len); |
| 244 | |
| 245 | /** |
| 246 | * \brief Free a reader object |
| 247 | * |
| 248 | * \param reader The reader to be freed. |
| 249 | * |
| 250 | * \return \c 0 on success. |
| 251 | * \return A negative \c MBEDTLS_ERR_READER_XXX error code on failure. |
| 252 | */ |
| 253 | int mbedtls_mps_reader_free(mbedtls_mps_reader *reader); |
| 254 | |
| 255 | /** |
| 256 | * \brief Pass chunk of data for the reader to manage. |
| 257 | * |
| 258 | * \param reader The reader context to use. The reader must be |
| 259 | * in producing mode. |
| 260 | * \param buf The buffer to be managed by the reader. |
| 261 | * \param buflen The size in Bytes of \p buffer. |
| 262 | * |
| 263 | * \return \c 0 on success. In this case, the reader will be |
| 264 | * moved to consuming mode and obtains read access |
| 265 | * of \p buf until mbedtls_mps_reader_reclaim() |
| 266 | * is called. It is the responsibility of the caller |
| 267 | * to ensure that the \p buf persists and is not changed |
| 268 | * between successful calls to mbedtls_mps_reader_feed() |
| 269 | * and mbedtls_mps_reader_reclaim(). |
| 270 | * \return \c MBEDTLS_ERR_MPS_READER_NEED_MORE if more input data is |
| 271 | * required to fulfill a previous request to mbedtls_mps_reader_get(). |
| 272 | * In this case, the reader remains in producing mode and |
| 273 | * takes no ownership of the provided buffer (an internal copy |
| 274 | * is made instead). |
| 275 | * \return Another negative \c MBEDTLS_ERR_READER_XXX error code on |
| 276 | * different kinds of failures. |
| 277 | */ |
| 278 | int mbedtls_mps_reader_feed(mbedtls_mps_reader *reader, |
| 279 | unsigned char *buf, |
| 280 | mbedtls_mps_size_t buflen); |
| 281 | |
| 282 | /** |
| 283 | * \brief Reclaim reader's access to the current input buffer. |
| 284 | * |
| 285 | * \param reader The reader context to use. The reader must be |
| 286 | * in consuming mode. |
| 287 | * \param paused If not \c NULL, the integer at address \p paused will be |
| 288 | * modified to indicate whether the reader has been paused |
| 289 | * (value \c 1) or not (value \c 0). Pausing happens if there |
| 290 | * is uncommitted data and a previous request to |
| 291 | * mbedtls_mps_reader_get() has exceeded the bounds of the |
| 292 | * input buffer. |
| 293 | * |
| 294 | * \return \c 0 on success. |
| 295 | * \return A negative \c MBEDTLS_ERR_READER_XXX error code on failure. |
| 296 | */ |
| 297 | int mbedtls_mps_reader_reclaim(mbedtls_mps_reader *reader, |
| 298 | int *paused); |
| 299 | |
| 300 | /* |
| 301 | * Usage API (Upper layer) |
| 302 | */ |
| 303 | |
| 304 | /** |
| 305 | * \brief Request data from the reader. |
| 306 | * |
| 307 | * \param reader The reader context to use. The reader must |
| 308 | * be in consuming mode. |
| 309 | * \param desired The desired amount of data to be read, in Bytes. |
| 310 | * \param buffer The address to store the buffer pointer in. |
| 311 | * This must not be \c NULL. |
| 312 | * \param buflen The address to store the actual buffer |
| 313 | * length in, or \c NULL. |
| 314 | * |
| 315 | * \return \c 0 on success. In this case, \c *buf holds the |
| 316 | * address of a buffer of size \c *buflen |
| 317 | * (if \c buflen != \c NULL) or \c desired |
| 318 | * (if \c buflen == \c NULL). The user has read access |
| 319 | * to the buffer and guarantee of stability of the data |
| 320 | * until the next call to mbedtls_mps_reader_reclaim(). |
| 321 | * \return #MBEDTLS_ERR_MPS_READER_OUT_OF_DATA if there is not enough |
| 322 | * data available to serve the get request. In this case, the |
| 323 | * reader remains intact and in consuming mode, and the consumer |
| 324 | * should retry the call after a successful cycle of |
| 325 | * mbedtls_mps_reader_reclaim() and mbedtls_mps_reader_feed(). |
| 326 | * If, after such a cycle, the consumer requests a different |
| 327 | * amount of data, the result is implementation-defined; |
| 328 | * progress is guaranteed only if the same amount of data |
| 329 | * is requested after a mbedtls_mps_reader_reclaim() and |
| 330 | * mbedtls_mps_reader_feed() cycle. |
| 331 | * \return Another negative \c MBEDTLS_ERR_READER_XXX error |
| 332 | * code for different kinds of failure. |
| 333 | * |
| 334 | * \note Passing \c NULL as \p buflen is a convenient way to |
| 335 | * indicate that fragmentation is not tolerated. |
| 336 | * It's functionally equivalent to passing a valid |
| 337 | * address as buflen and checking \c *buflen == \c desired |
| 338 | * afterwards. |
| 339 | */ |
| 340 | int mbedtls_mps_reader_get(mbedtls_mps_reader *reader, |
| 341 | mbedtls_mps_size_t desired, |
| 342 | unsigned char **buffer, |
| 343 | mbedtls_mps_size_t *buflen); |
| 344 | |
| 345 | /** |
| 346 | * \brief Mark data obtained from mbedtls_mps_reader_get() as processed. |
| 347 | * |
| 348 | * This call indicates that all data received from prior calls to |
| 349 | * mbedtls_mps_reader_get() has been or will have been |
| 350 | * processed when mbedtls_mps_reader_reclaim() is called, |
| 351 | * and thus need not be backed up. |
| 352 | * |
| 353 | * This function has no user observable effect until |
| 354 | * mbedtls_mps_reader_reclaim() is called. In particular, |
| 355 | * buffers received from mbedtls_mps_reader_get() remain |
| 356 | * valid until mbedtls_mps_reader_reclaim() is called. |
| 357 | * |
| 358 | * \param reader The reader context to use. |
| 359 | * |
| 360 | * \return \c 0 on success. |
| 361 | * \return A negative \c MBEDTLS_ERR_READER_XXX error code on failure. |
| 362 | * |
| 363 | */ |
| 364 | int mbedtls_mps_reader_commit(mbedtls_mps_reader *reader); |
| 365 | |
| 366 | #endif /* MBEDTLS_READER_H */ |