| /* | |
| * Copyright The Mbed TLS Contributors | |
| * SPDX-License-Identifier: Apache-2.0 | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may | |
| * not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| * | |
| * This file is part of Mbed TLS (https://tls.mbed.org) | |
| */ | |
| /** | |
| * \file mps_reader.h | |
| * | |
| * \brief This file defines reader objects, which together with their | |
| * sibling writer objects form the basis for the communication | |
| * between the various layers of the Mbed TLS messaging stack, | |
| * as well as the communication between the messaging stack and | |
| * the (D)TLS handshake protocol implementation. | |
| * | |
| * Readers provide a means of transferring incoming data from | |
| * a 'producer' providing it in chunks of arbitrary size, to | |
| * a 'consumer' which fetches and processes it in chunks of | |
| * again arbitrary, and potentially different, size. | |
| * | |
| * Readers can thus be seen as datagram-to-stream converters, | |
| * and they abstract away the following two tasks from the user: | |
| * 1. The pointer arithmetic of stepping through a producer- | |
| * provided chunk in smaller chunks. | |
| * 2. The merging of incoming data chunks in case the | |
| * consumer requests data in larger chunks than what the | |
| * producer provides. | |
| * | |
| * The basic abstract flow of operation is the following: | |
| * - Initially, the reader is in 'producing mode'. | |
| * - The producer hands an incoming data buffer to the reader, | |
| * moving it from 'producing' to 'consuming' mode. | |
| * - The consumer subsequently fetches and processes the buffer | |
| * content. Once that's done -- or partially done and a consumer's | |
| * request can't be fulfilled -- the producer revokes the reader's | |
| * access to the incoming data buffer, putting the reader back to | |
| * producing mode. | |
| * - The producer subsequently gathers more incoming data and hands | |
| * it to the reader until it switches back to consuming mode | |
| * if enough data is available for the last consumer request to | |
| * be satisfiable. | |
| * - Repeat the above. | |
| * | |
| * The abstract states of the reader from the producer's and | |
| * consumer's perspective are as follows: | |
| * | |
| * - From the perspective of the consumer, the state of the | |
| * reader consists of the following: | |
| * - A byte stream representing (concatenation of) the data | |
| * received through calls to mbedtls_mps_reader_get(), | |
| * - A marker within that byte stream indicating which data | |
| * can be considered processed, and hence need not be retained, | |
| * when the reader is passed back to the producer via | |
| * mbedtls_mps_reader_reclaim(). | |
| * The marker is set via mbedtls_mps_reader_commit() | |
| * which places it at the end of the current byte stream. | |
| * The consumer need not be aware of the distinction between consumer | |
| * and producer mode, because it only interfaces with the reader | |
| * when the latter is in consuming mode. | |
| * | |
| * - From the perspective of the producer, the reader's state is one of: | |
| * - Attached: The reader is in consuming mode. | |
| * - Unset: No incoming data buffer is currently managed by the reader, | |
| * and all previously handed incoming data buffers have been | |
| * fully processed. More data needs to be fed into the reader | |
| * via mbedtls_mps_reader_feed(). | |
| * | |
| * - Accumulating: No incoming data buffer is currently managed by the | |
| * reader, but some data from the previous incoming data | |
| * buffer hasn't been processed yet and is internally | |
| * held back. | |
| * The Attached state belongs to consuming mode, while the Unset and | |
| * Accumulating states belong to producing mode. | |
| * | |
| * Transitioning from the Unset or Accumulating state to Attached is | |
| * done via successful calls to mbedtls_mps_reader_feed(), while | |
| * transitioning from Attached to either Unset or Accumulating (depending | |
| * on what has been processed) is done via mbedtls_mps_reader_reclaim(). | |
| * | |
| * The following diagram depicts the producer-state progression: | |
| * | |
| * +------------------+ reclaim | |
| * | Unset +<-------------------------------------+ get | |
| * +--------|---------+ | +------+ | |
| * | | | | | |
| * | | | | | |
| * | feed +---------+---+--+ | | |
| * +--------------------------------------> <---+ | |
| * | Attached | | |
| * +--------------------------------------> <---+ | |
| * | feed, enough data available +---------+---+--+ | | |
| * | to serve previous consumer request | | | | |
| * | | | | | |
| * +--------+---------+ | +------+ | |
| * +----> Accumulating |<-------------------------------------+ commit | |
| * | +---+--------------+ reclaim, previous read request | |
| * | | couldn't be fulfilled | |
| * | | | |
| * +--------+ | |
| * feed, need more data to serve | |
| * previous consumer request | |
| * | | |
| * | | |
| * producing mode | consuming mode | |
| * | | |
| * | |
| */ | |
| #ifndef MBEDTLS_READER_H | |
| #define MBEDTLS_READER_H | |
| #include <stdio.h> | |
| #include "mps_common.h" | |
| #include "mps_error.h" | |
| struct mbedtls_mps_reader; | |
| typedef struct mbedtls_mps_reader mbedtls_mps_reader; | |
| /* | |
| * Structure definitions | |
| */ | |
| struct mbedtls_mps_reader { | |
| unsigned char *frag; /*!< The fragment of incoming data managed by | |
| * the reader; it is provided to the reader | |
| * through mbedtls_mps_reader_feed(). The reader | |
| * does not own the fragment and does not | |
| * perform any allocation operations on it, | |
| * but does have read and write access to it. | |
| * | |
| * The reader is in consuming mode if | |
| * and only if \c frag is not \c NULL. */ | |
| mbedtls_mps_stored_size_t frag_len; | |
| /*!< The length of the current fragment. | |
| * Must be 0 if \c frag == \c NULL. */ | |
| mbedtls_mps_stored_size_t commit; | |
| /*!< The offset of the last commit, relative | |
| * to the first byte in the fragment, if | |
| * no accumulator is present. If an accumulator | |
| * is present, it is viewed as a prefix to the | |
| * current fragment, and this variable contains | |
| * an offset from the beginning of the accumulator. | |
| * | |
| * This is only used when the reader is in | |
| * consuming mode, i.e. \c frag != \c NULL; | |
| * otherwise, its value is \c 0. */ | |
| mbedtls_mps_stored_size_t end; | |
| /*!< The offset of the end of the last chunk | |
| * passed to the user through a call to | |
| * mbedtls_mps_reader_get(), relative to the first | |
| * byte in the fragment, if no accumulator is | |
| * present. If an accumulator is present, it is | |
| * viewed as a prefix to the current fragment, and | |
| * this variable contains an offset from the | |
| * beginning of the accumulator. | |
| * | |
| * This is only used when the reader is in | |
| * consuming mode, i.e. \c frag != \c NULL; | |
| * otherwise, its value is \c 0. */ | |
| mbedtls_mps_stored_size_t pending; | |
| /*!< The amount of incoming data missing on the | |
| * last call to mbedtls_mps_reader_get(). | |
| * In particular, it is \c 0 if the last call | |
| * was successful. | |
| * If a reader is reclaimed after an | |
| * unsuccessful call to mbedtls_mps_reader_get(), | |
| * this variable is used to have the reader | |
| * remember how much data should be accumulated | |
| * so that the call to mbedtls_mps_reader_get() | |
| * succeeds next time. | |
| * This is only used when the reader is in | |
| * consuming mode, i.e. \c frag != \c NULL; | |
| * otherwise, its value is \c 0. */ | |
| /* The accumulator is only needed if we need to be able to pause | |
| * the reader. A few bytes could be saved by moving this to a | |
| * separate struct and using a pointer here. */ | |
| unsigned char *acc; /*!< The accumulator is used to gather incoming | |
| * data if a read-request via mbedtls_mps_reader_get() | |
| * cannot be served from the current fragment. */ | |
| mbedtls_mps_stored_size_t acc_len; | |
| /*!< The total size of the accumulator. */ | |
| mbedtls_mps_stored_size_t acc_available; | |
| /*!< The number of bytes currently gathered in | |
| * the accumulator. This is both used in | |
| * producing and in consuming mode: | |
| * While producing, it is increased until | |
| * it reaches the value of \c acc_remaining below. | |
| * While consuming, it is used to judge if a | |
| * get request can be served from the | |
| * accumulator or not. | |
| * Must not be larger than \c acc_len. */ | |
| union { | |
| mbedtls_mps_stored_size_t acc_remaining; | |
| /*!< This indicates the amount of data still | |
| * to be gathered in the accumulator. It is | |
| * only used in producing mode. | |
| * Must be at most acc_len - acc_available. */ | |
| mbedtls_mps_stored_size_t frag_offset; | |
| /*!< If an accumulator is present and in use, this | |
| * field indicates the offset of the current | |
| * fragment from the beginning of the | |
| * accumulator. If no accumulator is present | |
| * or the accumulator is not in use, this is \c 0. | |
| * It is only used in consuming mode. | |
| * Must not be larger than \c acc_available. */ | |
| } acc_share; | |
| }; | |
| /* | |
| * API organization: | |
| * A reader object is usually prepared and maintained | |
| * by some lower layer and passed for usage to an upper | |
| * layer, and the API naturally splits according to which | |
| * layer is supposed to use the respective functions. | |
| */ | |
| /* | |
| * Maintenance API (Lower layer) | |
| */ | |
| /** | |
| * \brief Initialize a reader object | |
| * | |
| * \param reader The reader to be initialized. | |
| * \param acc The buffer to be used as a temporary accumulator | |
| * in case get requests through mbedtls_mps_reader_get() | |
| * exceed the buffer provided by mbedtls_mps_reader_feed(). | |
| * This buffer is owned by the caller and exclusive use | |
| * for reading and writing is given to the reader for the | |
| * duration of the reader's lifetime. It is thus the caller's | |
| * responsibility to maintain (and not touch) the buffer for | |
| * the lifetime of the reader, and to properly zeroize and | |
| * free the memory after the reader has been destroyed. | |
| * \param acc_len The size in Bytes of \p acc. | |
| * | |
| * \return \c 0 on success. | |
| * \return A negative \c MBEDTLS_ERR_READER_XXX error code on failure. | |
| */ | |
| int mbedtls_mps_reader_init(mbedtls_mps_reader *reader, | |
| unsigned char *acc, | |
| mbedtls_mps_size_t acc_len); | |
| /** | |
| * \brief Free a reader object | |
| * | |
| * \param reader The reader to be freed. | |
| * | |
| * \return \c 0 on success. | |
| * \return A negative \c MBEDTLS_ERR_READER_XXX error code on failure. | |
| */ | |
| int mbedtls_mps_reader_free(mbedtls_mps_reader *reader); | |
| /** | |
| * \brief Pass chunk of data for the reader to manage. | |
| * | |
| * \param reader The reader context to use. The reader must be | |
| * in producing mode. | |
| * \param buf The buffer to be managed by the reader. | |
| * \param buflen The size in Bytes of \p buffer. | |
| * | |
| * \return \c 0 on success. In this case, the reader will be | |
| * moved to consuming mode and obtains read access | |
| * of \p buf until mbedtls_mps_reader_reclaim() | |
| * is called. It is the responsibility of the caller | |
| * to ensure that the \p buf persists and is not changed | |
| * between successful calls to mbedtls_mps_reader_feed() | |
| * and mbedtls_mps_reader_reclaim(). | |
| * \return \c MBEDTLS_ERR_MPS_READER_NEED_MORE if more input data is | |
| * required to fulfill a previous request to mbedtls_mps_reader_get(). | |
| * In this case, the reader remains in producing mode and | |
| * takes no ownership of the provided buffer (an internal copy | |
| * is made instead). | |
| * \return Another negative \c MBEDTLS_ERR_READER_XXX error code on | |
| * different kinds of failures. | |
| */ | |
| int mbedtls_mps_reader_feed(mbedtls_mps_reader *reader, | |
| unsigned char *buf, | |
| mbedtls_mps_size_t buflen); | |
| /** | |
| * \brief Reclaim reader's access to the current input buffer. | |
| * | |
| * \param reader The reader context to use. The reader must be | |
| * in consuming mode. | |
| * \param paused If not \c NULL, the integer at address \p paused will be | |
| * modified to indicate whether the reader has been paused | |
| * (value \c 1) or not (value \c 0). Pausing happens if there | |
| * is uncommitted data and a previous request to | |
| * mbedtls_mps_reader_get() has exceeded the bounds of the | |
| * input buffer. | |
| * | |
| * \return \c 0 on success. | |
| * \return A negative \c MBEDTLS_ERR_READER_XXX error code on failure. | |
| */ | |
| int mbedtls_mps_reader_reclaim(mbedtls_mps_reader *reader, | |
| int *paused); | |
| /* | |
| * Usage API (Upper layer) | |
| */ | |
| /** | |
| * \brief Request data from the reader. | |
| * | |
| * \param reader The reader context to use. The reader must | |
| * be in consuming mode. | |
| * \param desired The desired amount of data to be read, in Bytes. | |
| * \param buffer The address to store the buffer pointer in. | |
| * This must not be \c NULL. | |
| * \param buflen The address to store the actual buffer | |
| * length in, or \c NULL. | |
| * | |
| * \return \c 0 on success. In this case, \c *buf holds the | |
| * address of a buffer of size \c *buflen | |
| * (if \c buflen != \c NULL) or \c desired | |
| * (if \c buflen == \c NULL). The user has read access | |
| * to the buffer and guarantee of stability of the data | |
| * until the next call to mbedtls_mps_reader_reclaim(). | |
| * \return #MBEDTLS_ERR_MPS_READER_OUT_OF_DATA if there is not enough | |
| * data available to serve the get request. In this case, the | |
| * reader remains intact and in consuming mode, and the consumer | |
| * should retry the call after a successful cycle of | |
| * mbedtls_mps_reader_reclaim() and mbedtls_mps_reader_feed(). | |
| * If, after such a cycle, the consumer requests a different | |
| * amount of data, the result is implementation-defined; | |
| * progress is guaranteed only if the same amount of data | |
| * is requested after a mbedtls_mps_reader_reclaim() and | |
| * mbedtls_mps_reader_feed() cycle. | |
| * \return Another negative \c MBEDTLS_ERR_READER_XXX error | |
| * code for different kinds of failure. | |
| * | |
| * \note Passing \c NULL as \p buflen is a convenient way to | |
| * indicate that fragmentation is not tolerated. | |
| * It's functionally equivalent to passing a valid | |
| * address as buflen and checking \c *buflen == \c desired | |
| * afterwards. | |
| */ | |
| int mbedtls_mps_reader_get(mbedtls_mps_reader *reader, | |
| mbedtls_mps_size_t desired, | |
| unsigned char **buffer, | |
| mbedtls_mps_size_t *buflen); | |
| /** | |
| * \brief Mark data obtained from mbedtls_mps_reader_get() as processed. | |
| * | |
| * This call indicates that all data received from prior calls to | |
| * mbedtls_mps_reader_get() has been or will have been | |
| * processed when mbedtls_mps_reader_reclaim() is called, | |
| * and thus need not be backed up. | |
| * | |
| * This function has no user observable effect until | |
| * mbedtls_mps_reader_reclaim() is called. In particular, | |
| * buffers received from mbedtls_mps_reader_get() remain | |
| * valid until mbedtls_mps_reader_reclaim() is called. | |
| * | |
| * \param reader The reader context to use. | |
| * | |
| * \return \c 0 on success. | |
| * \return A negative \c MBEDTLS_ERR_READER_XXX error code on failure. | |
| * | |
| */ | |
| int mbedtls_mps_reader_commit(mbedtls_mps_reader *reader); | |
| #endif /* MBEDTLS_READER_H */ |