Add MBEDTLS_SSL_RUNTIME_CONTENT_LEN and per-connection content lengths

Signed-off-by: Barak Gutman <barak381@gmail.com>
This commit is contained in:
Barak Gutman 2026-09-11 22:27:51 +00:00
parent 3361ae00b4
commit bf4df4203b
19 changed files with 1673 additions and 126 deletions

View File

@ -0,0 +1,13 @@
Features
* Add the MBEDTLS_SSL_RUNTIME_CONTENT_LEN option and the
mbedtls_ssl_set_in_content_len() and mbedtls_ssl_set_out_content_len()
functions to choose the maximum plaintext fragment length of each
connection before mbedtls_ssl_setup(). An application that holds several
connections can then size each one's I/O buffers for its own peer
instead of for its most demanding peer. MBEDTLS_SSL_IN_CONTENT_LEN and
MBEDTLS_SSL_OUT_CONTENT_LEN remain the upper bound, so the worst-case
memory footprint is unchanged; enabling the option without calling
either function changes nothing. Shrinking the incoming length can break
against a conforming peer unless a maximum fragment length or
record_size_limit extension is negotiated; see the documentation of
mbedtls_ssl_set_in_content_len(). Fixes #4892.

View File

@ -844,10 +844,56 @@
* When this option is enabled, the SSL buffer will be resized automatically
* based on the negotiated maximum fragment length in each direction.
*
* This option shrinks the buffers only once a Maximum Fragment Length
* negotiation has completed, so on its own it leaves the peak allocation of a
* connection at the build-time maximum. If you want to bound the allocation
* of a connection from the moment it is set up, see
* MBEDTLS_SSL_RUNTIME_CONTENT_LEN. The two options may be enabled together;
* that option describes how they combine.
*
* Requires: MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
*/
//#define MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH
/**
* \def MBEDTLS_SSL_RUNTIME_CONTENT_LEN
*
* When this option is enabled, the maximum length of a plaintext fragment can
* be set per connection, at runtime, with
* mbedtls_ssl_set_in_content_len() and mbedtls_ssl_set_out_content_len().
* The connection then allocates its I/O buffers from those lengths when it is
* set up, so an application holding several connections can size each one for
* its own peer instead of for its most demanding peer.
*
* MBEDTLS_SSL_IN_CONTENT_LEN and MBEDTLS_SSL_OUT_CONTENT_LEN keep their
* present meaning as a hard upper bound: a connection may ask for less than
* the compiled maximum, never for more. The worst-case build footprint is
* therefore unchanged; only the runtime heap of a connection shrinks.
*
* Enabling this option without calling either setter changes nothing
* observable: both lengths default to the corresponding build-time maximum.
*
* How this differs from MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH:
* MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH shrinks the buffers automatically, once
* a Maximum Fragment Length has been negotiated, so a connection still
* allocates the build-time maximum while it is set up and handshaking.
* MBEDTLS_SSL_RUNTIME_CONTENT_LEN bounds the allocation from
* mbedtls_ssl_setup() onwards, at a length the application chooses, and does
* not require MBEDTLS_SSL_MAX_FRAGMENT_LENGTH. In exchange, the peer learns
* of a shrunk incoming length only through a negotiated extension; see
* mbedtls_ssl_set_in_content_len() for what happens otherwise.
*
* The two options may be enabled together: the buffers of a connection then
* start at its own lengths, may shrink further after a handshake to a
* configured or negotiated Maximum Fragment Length, and grow back at the
* start of each later handshake (renegotiation, or after
* mbedtls_ssl_session_reset()) only as far as the connection's lengths, never
* to the build-time maximum.
*
* Uncomment this macro to enable per-connection content lengths.
*/
//#define MBEDTLS_SSL_RUNTIME_CONTENT_LEN
//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 or 384 bits) */
//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */
//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */

View File

@ -1584,6 +1584,20 @@ struct mbedtls_ssl_config {
mbedtls_ssl_unused_data_t MBEDTLS_PRIVATE(unused);
};
/**
* \def MBEDTLS_SSL_HAVE_BUFFER_LEN_FIELDS
*
* Defined when an SSL context records the length of each of its I/O buffers,
* because at least one enabled option lets a buffer be shorter than the
* build-time maximum: #MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH shrinks it after a
* Maximum Fragment Length negotiation, and #MBEDTLS_SSL_RUNTIME_CONTENT_LEN
* allocates it short in the first place.
*/
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) || \
defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
#define MBEDTLS_SSL_HAVE_BUFFER_LEN_FIELDS
#endif
/*
* Warning: whenever a change is applied to "mbedtls_ssl_context" please re-run
* the script "tests/scripts/generate_ssl_session_reset_check.py".
@ -1721,9 +1735,12 @@ struct mbedtls_ssl_context {
int MBEDTLS_PRIVATE(in_msgtype); /*!< record header: message type */
size_t MBEDTLS_PRIVATE(in_msglen); /*!< record header: message length */
size_t MBEDTLS_PRIVATE(in_left); /*!< amount of data read so far */
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
#if defined(MBEDTLS_SSL_HAVE_BUFFER_LEN_FIELDS)
size_t MBEDTLS_PRIVATE(in_buf_len); /*!< length of input buffer */
#endif
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
size_t MBEDTLS_PRIVATE(in_content_len); /*!< max incoming plaintext fragment */
#endif
#if defined(MBEDTLS_SSL_PROTO_DTLS)
uint16_t MBEDTLS_PRIVATE(in_epoch); /*!< DTLS epoch for incoming records */
size_t MBEDTLS_PRIVATE(next_record_offset); /*!< offset of the next record in datagram
@ -1798,9 +1815,12 @@ struct mbedtls_ssl_context {
int MBEDTLS_PRIVATE(out_msgtype); /*!< record header: message type */
size_t MBEDTLS_PRIVATE(out_msglen); /*!< record header: message length */
size_t MBEDTLS_PRIVATE(out_left); /*!< amount of data not yet written */
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
#if defined(MBEDTLS_SSL_HAVE_BUFFER_LEN_FIELDS)
size_t MBEDTLS_PRIVATE(out_buf_len); /*!< length of output buffer */
#endif
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
size_t MBEDTLS_PRIVATE(out_content_len); /*!< max outgoing plaintext fragment */
#endif
unsigned char MBEDTLS_PRIVATE(cur_out_ctr)[MBEDTLS_SSL_SEQUENCE_NUMBER_LEN]; /*!< Outgoing record sequence number. */
@ -1942,6 +1962,11 @@ void mbedtls_ssl_init(mbedtls_ssl_context *ssl);
*
* \return 0 if successful, or #PSA_ERROR_INSUFFICIENT_MEMORY if
* memory allocation failed
* \return #MBEDTLS_ERR_SSL_BAD_CONFIG if \p conf is invalid, including,
* for a client that may negotiate TLS 1.2, a maximum fragment
* length configured with mbedtls_ssl_conf_max_frag_len()
* longer than the length set with
* mbedtls_ssl_set_in_content_len()
*/
int mbedtls_ssl_setup(mbedtls_ssl_context *ssl,
const mbedtls_ssl_config *conf);
@ -2388,6 +2413,95 @@ int mbedtls_ssl_get_peer_cid(mbedtls_ssl_context *ssl,
void mbedtls_ssl_set_mtu(mbedtls_ssl_context *ssl, uint16_t mtu);
#endif /* MBEDTLS_SSL_PROTO_DTLS */
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
/**
* \brief Set the maximum length of a plaintext fragment that this
* connection can receive.
*
* mbedtls_ssl_setup() sizes the input buffer from this
* length, so a connection that asks for less than
* #MBEDTLS_SSL_IN_CONTENT_LEN allocates less.
*
* \note This function is valid only after mbedtls_ssl_init() and
* before mbedtls_ssl_setup(). It fails once
* mbedtls_ssl_setup() has succeeded, and also once
* mbedtls_ssl_setup() has rejected the configuration; free
* and re-initialise the context to choose another length.
* The length is kept across mbedtls_ssl_session_reset().
*
* \warning Nothing tells the peer about this length unless a
* Maximum Fragment Length or record_size_limit no longer
* than this length is negotiated. Otherwise a conforming peer
* may send a record longer than this length. Over TLS, the
* call that reads such a record fails: with
* #MBEDTLS_ERR_SSL_INVALID_RECORD if the record still fits in
* the input buffer, otherwise with
* #MBEDTLS_ERR_SSL_BAD_INPUT_DATA. Over DTLS, the record is
* discarded, so its data is lost. A build with
* #MBEDTLS_SSL_IN_CONTENT_LEN set to the same length behaves
* the same way.
*
* \warning A server in particular has no standardised way to
* announce this length. Only a client requests a Maximum
* Fragment Length, and it may request one longer than this
* length; a TLS 1.3 server sends record_size_limit only if
* the client offered it. Shrink the incoming length of a
* server only when you know what its clients will send.
*
* \note With #MBEDTLS_SSL_RECORD_SIZE_LIMIT, a TLS 1.3 endpoint
* advertises this length as its record_size_limit, so a
* length below 64, the smallest limit RFC 8449 permits, makes
* the handshake fail. A client that may negotiate TLS 1.2
* must not configure a maximum fragment length with
* mbedtls_ssl_conf_max_frag_len() longer than this length, or
* mbedtls_ssl_setup() fails.
*
* \param ssl SSL context
* \param len Maximum incoming plaintext fragment length in bytes.
*
* \return 0 on success.
* \return #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if \p len is 0 or
* exceeds #MBEDTLS_SSL_IN_CONTENT_LEN, or if called outside
* the window described above.
*/
int mbedtls_ssl_set_in_content_len(mbedtls_ssl_context *ssl, size_t len);
/**
* \brief Set the maximum length of a plaintext fragment that this
* connection can send.
*
* mbedtls_ssl_setup() sizes the output buffer from this
* length, so a connection that asks for less than
* #MBEDTLS_SSL_OUT_CONTENT_LEN allocates less. Application
* data longer than this length is treated as it is for a
* negotiated maximum fragment length: over TLS,
* mbedtls_ssl_write() sends only the first part of it, and
* over DTLS, mbedtls_ssl_write() rejects it.
*
* \note This function is valid only after mbedtls_ssl_init() and
* before mbedtls_ssl_setup(). It fails once
* mbedtls_ssl_setup() has succeeded, and also once
* mbedtls_ssl_setup() has rejected the configuration; free
* and re-initialise the context to choose another length.
* The length is kept across mbedtls_ssl_session_reset().
*
* \note The lower bound this function enforces, 12 bytes or the
* TLS 1.3 padding granularity if larger, only keeps internal
* size arithmetic sound. Whether a handshake fits depends on
* the certificate chain, ciphersuites and extensions; a
* length too short for them makes the handshake fail.
*
* \param ssl SSL context
* \param len Maximum outgoing plaintext fragment length in bytes.
*
* \return 0 on success.
* \return #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if \p len is below the
* lower bound or exceeds #MBEDTLS_SSL_OUT_CONTENT_LEN, or if
* called outside the window described above.
*/
int mbedtls_ssl_set_out_content_len(mbedtls_ssl_context *ssl, size_t len);
#endif /* MBEDTLS_SSL_RUNTIME_CONTENT_LEN */
#if defined(MBEDTLS_X509_CRT_PARSE_C)
/**
* \brief Set a connection-specific verification callback (optional).
@ -4687,7 +4801,8 @@ int mbedtls_ssl_get_record_expansion(const mbedtls_ssl_context *ssl);
*
* \note The logic to determine the maximum outgoing record payload is
* version-specific. It takes into account various factors, such as
* the mbedtls_config.h setting \c MBEDTLS_SSL_OUT_CONTENT_LEN, extensions
* the mbedtls_config.h setting \c MBEDTLS_SSL_OUT_CONTENT_LEN or
* the length set with \c mbedtls_ssl_set_out_content_len(), extensions
* such as the max fragment length or record size limit extension if
* used, and for DTLS the path MTU as configured and current
* record expansion.
@ -4714,7 +4829,8 @@ int mbedtls_ssl_get_max_out_record_payload(const mbedtls_ssl_context *ssl);
*
* \note The logic to determine the maximum incoming record payload is
* version-specific. It takes into account various factors, such as
* the mbedtls_config.h setting \c MBEDTLS_SSL_IN_CONTENT_LEN, extensions
* the mbedtls_config.h setting \c MBEDTLS_SSL_IN_CONTENT_LEN or
* the length set with \c mbedtls_ssl_set_in_content_len(), extensions
* such as the max fragment length extension or record size limit
* extension if used, and the current record expansion.
*

View File

@ -399,6 +399,185 @@ uint32_t mbedtls_ssl_get_extension_mask(unsigned int extension_type);
+ (MBEDTLS_SSL_CID_OUT_LEN_MAX))
#endif
/*
* Smallest per-connection content lengths that
* mbedtls_ssl_set_in_content_len() and mbedtls_ssl_set_out_content_len()
* accept, under MBEDTLS_SSL_RUNTIME_CONTENT_LEN. These are not the smallest
* lengths a handshake can succeed with, which depend on the
* certificate chain, ciphersuite and extensions; they are the points below
* which internal size arithmetic stops meaning anything.
*
* Incoming: nothing subtracts from the incoming length, so any non-zero
* value is structurally sound. Keep this below
* MBEDTLS_SSL_RECORD_SIZE_LIMIT_MIN, so that the runtime check in the TLS 1.3
* record_size_limit writer stays reachable.
*
* Outgoing: 12 covers the DTLS handshake header, which the message layer
* subtracts from the outgoing length, and with it the 7-byte handshake header
* plus 3-byte length that precede the first certificate. With TLS 1.3 the
* maximum outgoing record payload is rounded down to a multiple of the
* padding granularity and then decremented, so the length must be at least
* one granule.
*
* The documentation of both setters in ssl.h states these values; update it
* if they change.
*/
#define MBEDTLS_SSL_IN_CONTENT_LEN_MIN 1
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && \
MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY > 12
#define MBEDTLS_SSL_OUT_CONTENT_LEN_MIN MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY
#else
#define MBEDTLS_SSL_OUT_CONTENT_LEN_MIN 12
#endif
/**
* \brief Get the maximum length, in bytes, of a plaintext fragment
* that may be received on this connection.
*
* This is the single canonical way for the TLS code to ask
* how large an incoming plaintext fragment may be. Without
* #MBEDTLS_SSL_RUNTIME_CONTENT_LEN it is the build-time
* maximum #MBEDTLS_SSL_IN_CONTENT_LEN; with that option it is
* the per-connection length, which defaults to the build-time
* maximum and can never exceed it.
*
* \param ssl SSL context
*
* \return The maximum incoming plaintext fragment length in bytes.
*/
static inline size_t mbedtls_ssl_get_in_content_len(const mbedtls_ssl_context *ssl)
{
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
return ssl->in_content_len;
#else
(void) ssl;
return MBEDTLS_SSL_IN_CONTENT_LEN;
#endif
}
/**
* \brief Get the maximum length, in bytes, of a plaintext fragment
* that may be sent on this connection.
*
* This is the single canonical way for the TLS code to ask
* how large an outgoing plaintext fragment may be. Without
* #MBEDTLS_SSL_RUNTIME_CONTENT_LEN it is the build-time
* maximum #MBEDTLS_SSL_OUT_CONTENT_LEN; with that option it is
* the per-connection length, which defaults to the build-time
* maximum and can never exceed it.
*
* \param ssl SSL context
*
* \return The maximum outgoing plaintext fragment length in bytes.
*/
static inline size_t mbedtls_ssl_get_out_content_len(const mbedtls_ssl_context *ssl)
{
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
return ssl->out_content_len;
#else
(void) ssl;
return MBEDTLS_SSL_OUT_CONTENT_LEN;
#endif
}
/**
* \brief Get the length, in bytes, of this connection's input buffer.
*
* Valid once the connection has been set up with
* mbedtls_ssl_setup(); before that there is no buffer and the
* return value is meaningless. Allocation, teardown, the
* message-layer reset and the automatic-resize path must all
* agree on this one value.
*
* \param ssl SSL context
*
* \return The length of \c ssl->in_buf in bytes.
*/
static inline size_t mbedtls_ssl_get_in_buf_len(const mbedtls_ssl_context *ssl)
{
#if defined(MBEDTLS_SSL_HAVE_BUFFER_LEN_FIELDS)
return ssl->in_buf_len;
#else
(void) ssl;
return MBEDTLS_SSL_IN_BUFFER_LEN;
#endif
}
/**
* \brief Get the length, in bytes, of this connection's output
* buffer.
*
* Valid once the connection has been set up with
* mbedtls_ssl_setup(); before that there is no buffer and the
* return value is meaningless. Allocation, teardown, the
* message-layer reset and the automatic-resize path must all
* agree on this one value.
*
* \param ssl SSL context
*
* \return The length of \c ssl->out_buf in bytes.
*/
static inline size_t mbedtls_ssl_get_out_buf_len(const mbedtls_ssl_context *ssl)
{
#if defined(MBEDTLS_SSL_HAVE_BUFFER_LEN_FIELDS)
return ssl->out_buf_len;
#else
(void) ssl;
return MBEDTLS_SSL_OUT_BUFFER_LEN;
#endif
}
/**
* \brief Compute the input buffer length that holds a full-size
* incoming record for this connection.
*
* This is what mbedtls_ssl_setup() allocates: the connection's
* incoming content length plus the record header, the crypto
* expansion and, where enabled, the maximum incoming
* connection ID.
*
* \param ssl SSL context
*
* \return The required input buffer length in bytes.
*/
static inline size_t mbedtls_ssl_compute_in_buf_len(const mbedtls_ssl_context *ssl)
{
#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
return mbedtls_ssl_get_in_content_len(ssl)
+ MBEDTLS_SSL_HEADER_LEN + MBEDTLS_SSL_PAYLOAD_OVERHEAD
+ MBEDTLS_SSL_CID_IN_LEN_MAX;
#else
return mbedtls_ssl_get_in_content_len(ssl)
+ MBEDTLS_SSL_HEADER_LEN + MBEDTLS_SSL_PAYLOAD_OVERHEAD;
#endif
}
/**
* \brief Compute the output buffer length that holds a full-size
* outgoing record for this connection.
*
* This is what mbedtls_ssl_setup() allocates: the connection's
* outgoing content length plus the record header, the crypto
* expansion and, where enabled, the maximum outgoing
* connection ID.
*
* \param ssl SSL context
*
* \return The required output buffer length in bytes.
*/
static inline size_t mbedtls_ssl_compute_out_buf_len(const mbedtls_ssl_context *ssl)
{
#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
return mbedtls_ssl_get_out_content_len(ssl)
+ MBEDTLS_SSL_HEADER_LEN + MBEDTLS_SSL_PAYLOAD_OVERHEAD
+ MBEDTLS_SSL_CID_OUT_LEN_MAX;
#else
return mbedtls_ssl_get_out_content_len(ssl)
+ MBEDTLS_SSL_HEADER_LEN + MBEDTLS_SSL_PAYLOAD_OVERHEAD;
#endif
}
#define MBEDTLS_CLIENT_HELLO_RANDOM_LEN 32
#define MBEDTLS_SERVER_HELLO_RANDOM_LEN 32
@ -407,7 +586,8 @@ uint32_t mbedtls_ssl_get_extension_mask(unsigned int extension_type);
* \brief Return the maximum fragment length (payload, in bytes) for
* the output buffer. For the client, this is the configured
* value. For the server, it is the minimum of two - the
* configured value and the negotiated one.
* configured value and the negotiated one. Either way it is
* no more than the connection's outgoing content length.
*
* \sa mbedtls_ssl_conf_max_frag_len()
* \sa mbedtls_ssl_get_max_out_record_payload()
@ -421,9 +601,10 @@ size_t mbedtls_ssl_get_output_max_frag_len(const mbedtls_ssl_context *ssl);
/**
* \brief Return the maximum fragment length (payload, in bytes) for
* the input buffer. This is the negotiated maximum fragment
* length, or, if there is none, MBEDTLS_SSL_IN_CONTENT_LEN.
* If it is not defined either, the value is 2^14. This function
* works as its predecessor, \c mbedtls_ssl_get_max_frag_len().
* length, or, if there is none, the connection's incoming
* content length, and never more than the latter. This
* function works as its predecessor,
* \c mbedtls_ssl_get_max_frag_len().
*
* \sa mbedtls_ssl_conf_max_frag_len()
* \sa mbedtls_ssl_get_max_in_record_payload()
@ -2665,6 +2846,23 @@ int mbedtls_ssl_tls13_parse_record_size_limit_ext(mbedtls_ssl_context *ssl,
const unsigned char *buf,
const unsigned char *end);
/**
* \brief Write the record_size_limit extension, advertising this
* connection's maximum incoming plaintext fragment length.
*
* \param ssl SSL context
* \param buf Start of the extension write buffer
* \param end End of the extension write buffer
* \param out_len On success, the number of bytes written
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if the connection's
* incoming content length is below
* #MBEDTLS_SSL_RECORD_SIZE_LIMIT_MIN, leaving nothing valid
* to advertise.
* \return #MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL if the write buffer is
* too small for the extension.
*/
MBEDTLS_CHECK_RETURN_CRITICAL
int mbedtls_ssl_tls13_write_record_size_limit_ext(mbedtls_ssl_context *ssl,
unsigned char *buf,

View File

@ -292,11 +292,7 @@ static int ssl_next_record_is_in_datagram(mbedtls_ssl_context *ssl);
static size_t ssl_get_maximum_datagram_size(mbedtls_ssl_context const *ssl)
{
size_t mtu = mbedtls_ssl_get_current_mtu(ssl);
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
size_t out_buf_len = ssl->out_buf_len;
#else
size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
#endif
size_t out_buf_len = mbedtls_ssl_get_out_buf_len(ssl);
if (mtu != 0 && mtu < out_buf_len) {
return mtu;
@ -326,7 +322,7 @@ static int ssl_get_remaining_payload_in_datagram(mbedtls_ssl_context const *ssl)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t remaining, expansion;
size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
size_t max_len = mbedtls_ssl_get_out_content_len(ssl);
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
const size_t mfl = mbedtls_ssl_get_output_max_frag_len(ssl);
@ -830,6 +826,13 @@ int mbedtls_ssl_encrypt_buf(mbedtls_ssl_context *ssl,
MBEDTLS_SSL_DEBUG_BUF(4, "before encrypt: output payload",
data, rec->data_len);
/* This is a sanity check against the build-time ceiling, not against this
* connection's outgoing length: the ssl parameter is a debugging aid
* here and is NULL when MBEDTLS_DEBUG_C is off, so it cannot be asked.
* The per-connection bound is enforced before a record reaches this
* point: mbedtls_ssl_write_handshake_msg_ext() rejects an over-long
* handshake message, and application data is clamped to
* mbedtls_ssl_get_max_out_record_payload(). */
if (rec->data_len > MBEDTLS_SSL_OUT_CONTENT_LEN) {
MBEDTLS_SSL_DEBUG_MSG(1, ("Record content %" MBEDTLS_PRINTF_SIZET
" too large, maximum %" MBEDTLS_PRINTF_SIZET,
@ -1856,11 +1859,7 @@ int mbedtls_ssl_fetch_input(mbedtls_ssl_context *ssl, size_t nb_want)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len;
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
size_t in_buf_len = ssl->in_buf_len;
#else
size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN;
#endif
size_t in_buf_len = mbedtls_ssl_get_in_buf_len(ssl);
MBEDTLS_SSL_DEBUG_MSG(2, ("=> fetch input"));
@ -2453,7 +2452,7 @@ int mbedtls_ssl_start_handshake_msg(mbedtls_ssl_context *ssl, unsigned char hs_t
* ...
*/
*buf = ssl->out_msg + 4;
*buf_len = MBEDTLS_SSL_OUT_CONTENT_LEN - 4;
*buf_len = mbedtls_ssl_get_out_content_len(ssl) - 4;
ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE;
ssl->out_msg[0] = hs_type;
@ -2528,12 +2527,12 @@ int mbedtls_ssl_write_handshake_msg_ext(mbedtls_ssl_context *ssl,
*
* Note: We deliberately do not check for the MTU or MFL here.
*/
if (ssl->out_msglen > MBEDTLS_SSL_OUT_CONTENT_LEN) {
if (ssl->out_msglen > mbedtls_ssl_get_out_content_len(ssl)) {
MBEDTLS_SSL_DEBUG_MSG(1, ("Record too large: "
"size %" MBEDTLS_PRINTF_SIZET
", maximum %" MBEDTLS_PRINTF_SIZET,
ssl->out_msglen,
(size_t) MBEDTLS_SSL_OUT_CONTENT_LEN));
mbedtls_ssl_get_out_content_len(ssl)));
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
@ -2555,12 +2554,12 @@ int mbedtls_ssl_write_handshake_msg_ext(mbedtls_ssl_context *ssl,
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
/* Make room for the additional DTLS fields */
if (MBEDTLS_SSL_OUT_CONTENT_LEN - ssl->out_msglen < 8) {
if (mbedtls_ssl_get_out_content_len(ssl) - ssl->out_msglen < 8) {
MBEDTLS_SSL_DEBUG_MSG(1, ("DTLS handshake message too large: "
"size %" MBEDTLS_PRINTF_SIZET ", maximum %"
MBEDTLS_PRINTF_SIZET,
hs_len,
(size_t) (MBEDTLS_SSL_OUT_CONTENT_LEN - 12)));
mbedtls_ssl_get_out_content_len(ssl) - 12));
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
@ -2656,11 +2655,7 @@ int mbedtls_ssl_write_record(mbedtls_ssl_context *ssl, int force_flush)
if (!done) {
unsigned i;
size_t protected_record_size;
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
size_t out_buf_len = ssl->out_buf_len;
#else
size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
#endif
size_t out_buf_len = mbedtls_ssl_get_out_buf_len(ssl);
/* Skip writing the record content type to after the encryption,
* as it may change when using the CID extension. */
mbedtls_ssl_protocol_version tls_ver = ssl->tls_version;
@ -3107,11 +3102,7 @@ int mbedtls_ssl_prepare_handshake_record(mbedtls_ssl_context *ssl)
* after the explicit IV, but here we move it to start where the
* IV was.
*/
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
size_t const in_buf_len = ssl->in_buf_len;
#else
size_t const in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN;
#endif
size_t const in_buf_len = mbedtls_ssl_get_in_buf_len(ssl);
if (payload_end + ssl->in_msglen > ssl->in_buf + in_buf_len) {
MBEDTLS_SSL_DEBUG_MSG(1,
("Shouldn't happen: no room to move handshake fragment %"
@ -3492,7 +3483,7 @@ static int ssl_handle_possible_reconnect(mbedtls_ssl_context *ssl)
ssl,
ssl->cli_id, ssl->cli_id_len,
ssl->in_buf, ssl->in_left,
ssl->out_buf, MBEDTLS_SSL_OUT_CONTENT_LEN, &len);
ssl->out_buf, mbedtls_ssl_get_out_content_len(ssl), &len);
MBEDTLS_SSL_DEBUG_RET(2, "mbedtls_ssl_check_dtls_clihlo_cookie", ret);
@ -4008,7 +3999,7 @@ static int ssl_prepare_record_content(mbedtls_ssl_context *ssl,
/* Check actual (decrypted) record content length against
* configured maximum. */
if (rec->data_len > MBEDTLS_SSL_IN_CONTENT_LEN) {
if (rec->data_len > mbedtls_ssl_get_in_content_len(ssl)) {
MBEDTLS_SSL_DEBUG_MSG(1, ("bad message length"));
return MBEDTLS_ERR_SSL_INVALID_RECORD;
}
@ -4185,7 +4176,7 @@ static int ssl_load_buffered_message(mbedtls_ssl_context *ssl)
/* Double-check that we haven't accidentally buffered
* a message that doesn't fit into the input buffer. */
if (msg_len + 12 > MBEDTLS_SSL_IN_CONTENT_LEN) {
if (msg_len + 12 > mbedtls_ssl_get_in_content_len(ssl)) {
MBEDTLS_SSL_DEBUG_MSG(1, ("should never happen"));
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
@ -4321,7 +4312,7 @@ static int ssl_buffer_message(mbedtls_ssl_context *ssl)
* This is an implementation-specific limitation
* and not one from the standard, hence it is not
* checked in ssl_check_hs_header(). */
if (msg_len + 12 > MBEDTLS_SSL_IN_CONTENT_LEN) {
if (msg_len + 12 > mbedtls_ssl_get_in_content_len(ssl)) {
/* Ignore message */
goto exit;
}
@ -4583,11 +4574,7 @@ static int ssl_load_buffered_record(mbedtls_ssl_context *ssl)
unsigned char *rec;
size_t rec_len;
unsigned rec_epoch;
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
size_t in_buf_len = ssl->in_buf_len;
#else
size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN;
#endif
size_t in_buf_len = mbedtls_ssl_get_in_buf_len(ssl);
if (ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
return 0;
}

View File

@ -1003,8 +1003,11 @@ static int ssl_handshake_init(mbedtls_ssl_context *ssl)
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
/* If the buffers are too small - reallocate */
handle_buffer_resizing(ssl, 0, MBEDTLS_SSL_IN_BUFFER_LEN,
MBEDTLS_SSL_OUT_BUFFER_LEN);
/* Grow back to what this connection asked for, not to the build-time
* maximum: growing to the maximum here would undo the saving that
* MBEDTLS_SSL_RUNTIME_CONTENT_LEN made at setup. */
handle_buffer_resizing(ssl, 0, mbedtls_ssl_compute_in_buf_len(ssl),
mbedtls_ssl_compute_out_buf_len(ssl));
#endif
/* All pointers should exist and can be directly freed without issue */
@ -1114,6 +1117,14 @@ static int ssl_cookie_check_dummy(void *ctx,
void mbedtls_ssl_init(mbedtls_ssl_context *ssl)
{
memset(ssl, 0, sizeof(mbedtls_ssl_context));
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
/* Default to the build-time maxima, so that enabling
* MBEDTLS_SSL_RUNTIME_CONTENT_LEN without calling either setter is
* observably a no-op. */
ssl->in_content_len = MBEDTLS_SSL_IN_CONTENT_LEN;
ssl->out_content_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
#endif
}
MBEDTLS_CHECK_RETURN_CRITICAL
@ -1165,6 +1176,26 @@ static int ssl_conf_check(const mbedtls_ssl_context *ssl)
return ret;
}
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN) && \
defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && defined(MBEDTLS_SSL_CLI_C)
/* A client proposing TLS 1.2 advertises its configured fragment length,
* so it must not invite records longer than this connection can take in.
* A server's configured fragment length only caps what it sends. */
if (ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
ssl->conf->min_tls_version <= MBEDTLS_SSL_VERSION_TLS1_2 &&
ssl->conf->mfl_code != MBEDTLS_SSL_MAX_FRAG_LEN_NONE) {
const unsigned int mfl = ssl_mfl_code_to_length(ssl->conf->mfl_code);
const size_t in_content_len = mbedtls_ssl_get_in_content_len(ssl);
if (mfl > in_content_len) {
MBEDTLS_SSL_DEBUG_MSG(1, ("max_fragment_length %u exceeds the incoming "
"content length %" MBEDTLS_PRINTF_SIZET,
mfl, in_content_len));
return MBEDTLS_ERR_SSL_BAD_CONFIG;
}
}
#endif
/* Space for further checks */
return 0;
@ -1178,8 +1209,8 @@ int mbedtls_ssl_setup(mbedtls_ssl_context *ssl,
const mbedtls_ssl_config *conf)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN;
size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
size_t in_buf_len = mbedtls_ssl_compute_in_buf_len(ssl);
size_t out_buf_len = mbedtls_ssl_compute_out_buf_len(ssl);
ssl->conf = conf;
@ -1195,7 +1226,7 @@ int mbedtls_ssl_setup(mbedtls_ssl_context *ssl,
/* Set to NULL in case of an error condition */
ssl->out_buf = NULL;
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
#if defined(MBEDTLS_SSL_HAVE_BUFFER_LEN_FIELDS)
ssl->in_buf_len = in_buf_len;
#endif
ssl->in_buf = mbedtls_calloc(1, in_buf_len);
@ -1205,7 +1236,7 @@ int mbedtls_ssl_setup(mbedtls_ssl_context *ssl,
goto error;
}
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
#if defined(MBEDTLS_SSL_HAVE_BUFFER_LEN_FIELDS)
ssl->out_buf_len = out_buf_len;
#endif
ssl->out_buf = mbedtls_calloc(1, out_buf_len);
@ -1234,7 +1265,7 @@ error:
ssl->conf = NULL;
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
#if defined(MBEDTLS_SSL_HAVE_BUFFER_LEN_FIELDS)
ssl->in_buf_len = 0;
ssl->out_buf_len = 0;
#endif
@ -1266,13 +1297,8 @@ error:
void mbedtls_ssl_session_reset_msg_layer(mbedtls_ssl_context *ssl,
int partial)
{
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
size_t in_buf_len = ssl->in_buf_len;
size_t out_buf_len = ssl->out_buf_len;
#else
size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN;
size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
#endif
size_t in_buf_len = mbedtls_ssl_get_in_buf_len(ssl);
size_t out_buf_len = mbedtls_ssl_get_out_buf_len(ssl);
#if !defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) || !defined(MBEDTLS_SSL_SRV_C)
partial = 0;
@ -1501,6 +1527,39 @@ void mbedtls_ssl_set_mtu(mbedtls_ssl_context *ssl, uint16_t mtu)
}
#endif
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
int mbedtls_ssl_set_in_content_len(mbedtls_ssl_context *ssl, size_t len)
{
/* Only before mbedtls_ssl_setup(): afterwards the buffers exist and
* may hold data and interior pointers sized from the current length. */
if (ssl->conf != NULL) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
if (len < MBEDTLS_SSL_IN_CONTENT_LEN_MIN || len > MBEDTLS_SSL_IN_CONTENT_LEN) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
ssl->in_content_len = len;
return 0;
}
int mbedtls_ssl_set_out_content_len(mbedtls_ssl_context *ssl, size_t len)
{
/* Only before mbedtls_ssl_setup(), as for the incoming length. */
if (ssl->conf != NULL) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
if (len < MBEDTLS_SSL_OUT_CONTENT_LEN_MIN || len > MBEDTLS_SSL_OUT_CONTENT_LEN) {
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
ssl->out_content_len = len;
return 0;
}
#endif /* MBEDTLS_SSL_RUNTIME_CONTENT_LEN */
void mbedtls_ssl_conf_read_timeout(mbedtls_ssl_config *conf, uint32_t timeout)
{
conf->read_timeout = timeout;
@ -1919,7 +1978,8 @@ static int ssl_conf_set_psk_identity(mbedtls_ssl_config *conf,
unsigned char const *psk_identity,
size_t psk_identity_len)
{
/* Identity len will be encoded on two bytes */
/* Identity len will be encoded on two bytes.
* Configuration-scoped, so this checks the build-time ceiling. */
if (psk_identity == NULL ||
psk_identity_len == 0 ||
(psk_identity_len >> 16) != 0 ||
@ -2819,7 +2879,7 @@ const char *mbedtls_ssl_get_version(const mbedtls_ssl_context *ssl)
size_t mbedtls_ssl_get_output_record_size_limit(const mbedtls_ssl_context *ssl)
{
const size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
const size_t max_len = mbedtls_ssl_get_out_content_len(ssl);
size_t record_size_limit = max_len;
if (ssl->session != NULL &&
@ -2843,14 +2903,18 @@ size_t mbedtls_ssl_get_output_record_size_limit(const mbedtls_ssl_context *ssl)
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
size_t mbedtls_ssl_get_input_max_frag_len(const mbedtls_ssl_context *ssl)
{
size_t max_len = MBEDTLS_SSL_IN_CONTENT_LEN;
size_t max_len = mbedtls_ssl_get_in_content_len(ssl);
size_t read_mfl;
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
/* Use the configured MFL for the client if we're past SERVER_HELLO_DONE */
if (ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
ssl->state >= MBEDTLS_SSL_SERVER_HELLO_DONE) {
return ssl_mfl_code_to_length(ssl->conf->mfl_code);
read_mfl = ssl_mfl_code_to_length(ssl->conf->mfl_code);
if (read_mfl < max_len) {
max_len = read_mfl;
}
return max_len;
}
#endif
@ -2875,12 +2939,14 @@ size_t mbedtls_ssl_get_input_max_frag_len(const mbedtls_ssl_context *ssl)
size_t mbedtls_ssl_get_output_max_frag_len(const mbedtls_ssl_context *ssl)
{
size_t max_len;
size_t max_len = mbedtls_ssl_get_out_content_len(ssl);
/*
* Assume mfl_code is correct since it was checked when set
*/
max_len = ssl_mfl_code_to_length(ssl->conf->mfl_code);
if (ssl_mfl_code_to_length(ssl->conf->mfl_code) < max_len) {
max_len = ssl_mfl_code_to_length(ssl->conf->mfl_code);
}
/* Check if a smaller max length was negotiated */
if (ssl->session_out != NULL &&
@ -2916,7 +2982,7 @@ size_t mbedtls_ssl_get_current_mtu(const mbedtls_ssl_context *ssl)
int mbedtls_ssl_get_max_out_record_payload(const mbedtls_ssl_context *ssl)
{
size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
size_t max_len = mbedtls_ssl_get_out_content_len(ssl);
#if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && \
!defined(MBEDTLS_SSL_RECORD_SIZE_LIMIT) && \
@ -2988,7 +3054,7 @@ int mbedtls_ssl_get_max_out_record_payload(const mbedtls_ssl_context *ssl)
int mbedtls_ssl_get_max_in_record_payload(const mbedtls_ssl_context *ssl)
{
size_t max_len = MBEDTLS_SSL_IN_CONTENT_LEN;
size_t max_len = mbedtls_ssl_get_in_content_len(ssl);
#if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
(void) ssl;
@ -5187,22 +5253,14 @@ void mbedtls_ssl_free(mbedtls_ssl_context *ssl)
MBEDTLS_SSL_DEBUG_MSG(2, ("=> free"));
if (ssl->out_buf != NULL) {
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
size_t out_buf_len = ssl->out_buf_len;
#else
size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN;
#endif
size_t out_buf_len = mbedtls_ssl_get_out_buf_len(ssl);
mbedtls_zeroize_and_free(ssl->out_buf, out_buf_len);
ssl->out_buf = NULL;
}
if (ssl->in_buf != NULL) {
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
size_t in_buf_len = ssl->in_buf_len;
#else
size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN;
#endif
size_t in_buf_len = mbedtls_ssl_get_in_buf_len(ssl);
mbedtls_zeroize_and_free(ssl->in_buf, in_buf_len);
ssl->in_buf = NULL;
@ -6732,13 +6790,17 @@ int mbedtls_ssl_write_certificate(mbedtls_ssl_context *ssl)
*/
i = 7;
crt = mbedtls_ssl_own_cert(ssl);
const size_t out_content_len = mbedtls_ssl_get_out_content_len(ssl);
while (crt != NULL) {
n = crt->raw.len;
if (n > MBEDTLS_SSL_OUT_CONTENT_LEN - 3 - i) {
/* Written as an addition rather than i + 3 subtracted from the
* outgoing length, so that a short outgoing length cannot underflow
* the bound into a huge value and wave the memcpy below through. */
if (i + 3 + n > out_content_len) {
MBEDTLS_SSL_DEBUG_MSG(1, ("certificate too large, %" MBEDTLS_PRINTF_SIZET
" > %" MBEDTLS_PRINTF_SIZET,
i + 3 + n, (size_t) MBEDTLS_SSL_OUT_CONTENT_LEN));
i + 3 + n, out_content_len));
return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
}

View File

@ -2415,7 +2415,7 @@ static int ssl_write_client_key_exchange(mbedtls_ssl_context *ssl)
* The export format is an ECPoint structure as expected by TLS,
* but we just need to add a length byte before that. */
unsigned char *own_pubkey = ssl->out_msg + header_len + 1;
unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN;
unsigned char *end = ssl->out_msg + mbedtls_ssl_get_out_content_len(ssl);
size_t own_pubkey_max_len = (size_t) (end - own_pubkey);
size_t own_pubkey_len;
@ -2475,12 +2475,16 @@ static int ssl_write_client_key_exchange(mbedtls_ssl_context *ssl)
const size_t ecpoint_max_len =
PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(handshake->xxdh_psa_type,
handshake->xxdh_psa_bits);
const size_t out_content_len = mbedtls_ssl_get_out_content_len(ssl);
header_len = 4;
if (ecpoint_max_len > MBEDTLS_SSL_OUT_CONTENT_LEN - ecpoint_len_size ||
/* The second comparison is only reached when the first one is false,
* that is when ecpoint_len_size + ecpoint_max_len <= out_content_len,
* so neither subtraction can wrap. */
if (ecpoint_max_len > out_content_len - ecpoint_len_size ||
header_len + content_len_size + ssl->conf->psk_identity_len
> MBEDTLS_SSL_OUT_CONTENT_LEN - ecpoint_len_size - ecpoint_max_len) {
> out_content_len - ecpoint_len_size - ecpoint_max_len) {
MBEDTLS_SSL_DEBUG_MSG(1,
("psk identity too long or SSL buffer too short"));
return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
@ -2528,7 +2532,7 @@ static int ssl_write_client_key_exchange(mbedtls_ssl_context *ssl)
* The export format is an ECPoint structure as expected by TLS,
* but we just need to add a length byte before that. */
unsigned char *own_pubkey = p + 1;
unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN;
unsigned char *end = ssl->out_msg + mbedtls_ssl_get_out_content_len(ssl);
size_t own_pubkey_max_len = (size_t) (end - own_pubkey);
size_t own_pubkey_len = 0;
@ -2595,7 +2599,7 @@ static int ssl_write_client_key_exchange(mbedtls_ssl_context *ssl)
header_len = 4;
content_len = ssl->conf->psk_identity_len;
if (header_len + 2 + content_len > MBEDTLS_SSL_OUT_CONTENT_LEN) {
if (header_len + 2 + content_len > mbedtls_ssl_get_out_content_len(ssl)) {
MBEDTLS_SSL_DEBUG_MSG(1,
("psk identity too long or SSL buffer too short"));
return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
@ -2626,7 +2630,7 @@ static int ssl_write_client_key_exchange(mbedtls_ssl_context *ssl)
header_len = 4;
unsigned char *out_p = ssl->out_msg + header_len;
unsigned char *end_p = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN -
unsigned char *end_p = ssl->out_msg + mbedtls_ssl_get_out_content_len(ssl) -
header_len;
ret = mbedtls_psa_ecjpake_write_round(&ssl->handshake->psa_pake_ctx,
out_p, end_p - out_p, &content_len,
@ -2698,11 +2702,8 @@ static int ssl_write_certificate_verify(mbedtls_ssl_context *ssl)
mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE;
size_t hashlen;
void *rs_ctx = NULL;
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
size_t out_buf_len = ssl->out_buf_len - (size_t) (ssl->out_msg - ssl->out_buf);
#else
size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN - (size_t) (ssl->out_msg - ssl->out_buf);
#endif
size_t out_buf_len = mbedtls_ssl_get_out_buf_len(ssl)
- (size_t) (ssl->out_msg - ssl->out_buf);
MBEDTLS_SSL_DEBUG_MSG(2, ("=> write certificate verify"));

View File

@ -1528,7 +1528,7 @@ static void ssl_write_cid_ext(mbedtls_ssl_context *ssl,
{
unsigned char *p = buf;
size_t ext_len;
const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN;
const unsigned char *end = ssl->out_msg + mbedtls_ssl_get_out_content_len(ssl);
*olen = 0;
@ -1763,7 +1763,7 @@ static int ssl_write_ecjpake_kkpp_ext(mbedtls_ssl_context *ssl,
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char *p = buf;
const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN;
const unsigned char *end = ssl->out_msg + mbedtls_ssl_get_out_content_len(ssl);
size_t kkpp_len;
*olen = 0;
@ -1809,7 +1809,7 @@ static void ssl_write_use_srtp_ext(mbedtls_ssl_context *ssl,
{
size_t mki_len = 0, ext_len = 0;
uint16_t profile_value = 0;
const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN;
const unsigned char *end = ssl->out_msg + mbedtls_ssl_get_out_content_len(ssl);
*olen = 0;
@ -1898,7 +1898,8 @@ static int ssl_write_hello_verify_request(mbedtls_ssl_context *ssl)
cookie_len_byte = p++;
if ((ret = ssl->conf->f_cookie_write(ssl->conf->p_cookie,
&p, ssl->out_buf + MBEDTLS_SSL_OUT_BUFFER_LEN,
&p,
ssl->out_buf + mbedtls_ssl_get_out_buf_len(ssl),
ssl->cli_id, ssl->cli_id_len)) != 0) {
MBEDTLS_SSL_DEBUG_RET(1, "f_cookie_write", ret);
return ret;
@ -2190,7 +2191,7 @@ static int ssl_write_server_hello(mbedtls_ssl_context *ssl)
#endif
#if defined(MBEDTLS_SSL_ALPN)
unsigned char *end = buf + MBEDTLS_SSL_OUT_CONTENT_LEN - 4;
unsigned char *end = buf + mbedtls_ssl_get_out_content_len(ssl) - 4;
if ((ret = mbedtls_ssl_write_alpn_ext(ssl, p + 2 + ext_len, end, &olen))
!= 0) {
return ret;
@ -2251,7 +2252,7 @@ static int ssl_write_certificate_request(mbedtls_ssl_context *ssl)
uint16_t dn_size, total_dn_size; /* excluding length bytes */
size_t ct_len, sa_len; /* including length bytes */
unsigned char *buf, *p;
const unsigned char * const end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN;
const unsigned char * const end = ssl->out_msg + mbedtls_ssl_get_out_content_len(ssl);
const mbedtls_x509_crt *crt;
int authmode;
@ -2426,8 +2427,16 @@ static int ssl_resume_server_key_exchange(mbedtls_ssl_context *ssl,
* ssl_write_server_key_exchange also takes care of incrementing
* ssl->out_msglen. */
unsigned char *sig_start = ssl->out_msg + ssl->out_msglen + 2;
size_t sig_max_len = (ssl->out_buf + MBEDTLS_SSL_OUT_CONTENT_LEN
- sig_start);
/* Deliberately based on out_buf rather than out_msg: this bound therefore
* stops short of the end of the content area by the record header, which
* is conservative. Do not "simplify" it to out_msg without checking the
* non-async path below, which bounds the same write more loosely. */
const unsigned char *end = ssl->out_buf + mbedtls_ssl_get_out_content_len(ssl);
/* Compare before subtracting: with a short per-connection outgoing
* length, sig_start can lie past end, and the difference would wrap.
* A zero budget leaves the callback no room, so the handshake fails
* instead. */
size_t sig_max_len = sig_start < end ? (size_t) (end - sig_start) : 0;
int ret = ssl->conf->f_async_resume(ssl,
sig_start, signature_len, sig_max_len);
if (ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) {
@ -2462,11 +2471,8 @@ static int ssl_prepare_server_key_exchange(mbedtls_ssl_context *ssl,
#endif /* MBEDTLS_KEY_EXCHANGE_WITH_SERVER_SIGNATURE_ENABLED */
#if defined(MBEDTLS_KEY_EXCHANGE_WITH_SERVER_SIGNATURE_ENABLED)
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
size_t out_buf_len = ssl->out_buf_len - (size_t) (ssl->out_msg - ssl->out_buf);
#else
size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN - (size_t) (ssl->out_msg - ssl->out_buf);
#endif
size_t out_buf_len = mbedtls_ssl_get_out_buf_len(ssl)
- (size_t) (ssl->out_msg - ssl->out_buf);
#endif
ssl->out_msglen = 4; /* header (type:1, length:3) to be written later */
@ -2484,7 +2490,7 @@ static int ssl_prepare_server_key_exchange(mbedtls_ssl_context *ssl,
if (ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE) {
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char *out_p = ssl->out_msg + ssl->out_msglen;
unsigned char *end_p = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN -
unsigned char *end_p = ssl->out_msg + mbedtls_ssl_get_out_content_len(ssl) -
ssl->out_msglen;
size_t output_offset = 0;
size_t output_len = 0;
@ -2635,7 +2641,7 @@ curve_matching_done:
*/
unsigned char *own_pubkey = p + data_length_size;
size_t own_pubkey_max_len = (size_t) (MBEDTLS_SSL_OUT_CONTENT_LEN
size_t own_pubkey_max_len = (size_t) (mbedtls_ssl_get_out_content_len(ssl)
- (own_pubkey - ssl->out_msg));
status = psa_export_public_key(handshake->xxdh_psa_privkey,
@ -3407,7 +3413,7 @@ static int ssl_write_new_session_ticket(mbedtls_ssl_context *ssl)
if ((ret = ssl->conf->f_ticket_write(ssl->conf->p_ticket,
ssl->session_negotiate,
ssl->out_msg + 10,
ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN,
ssl->out_msg + mbedtls_ssl_get_out_content_len(ssl),
&tlen, &lifetime)) != 0) {
MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_ticket_write", ret);
}

View File

@ -1307,7 +1307,7 @@ int mbedtls_ssl_tls13_write_change_cipher_spec(mbedtls_ssl_context *ssl)
/* Write CCS message */
MBEDTLS_SSL_PROC_CHK(ssl_tls13_write_change_cipher_spec_body(
ssl, ssl->out_msg,
ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN,
ssl->out_msg + mbedtls_ssl_get_out_content_len(ssl),
&ssl->out_msglen));
ssl->out_msgtype = MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC;
@ -1746,23 +1746,31 @@ int mbedtls_ssl_tls13_write_record_size_limit_ext(mbedtls_ssl_context *ssl,
size_t *out_len)
{
unsigned char *p = buf;
const size_t record_size_limit = mbedtls_ssl_get_in_content_len(ssl);
*out_len = 0;
MBEDTLS_STATIC_ASSERT(MBEDTLS_SSL_IN_CONTENT_LEN >= MBEDTLS_SSL_RECORD_SIZE_LIMIT_MIN,
"MBEDTLS_SSL_IN_CONTENT_LEN is less than the "
"minimum record size limit");
/* The incoming content length is a runtime value, so this bound cannot be
* checked at compile time. A connection that cannot hold the smallest
* record RFC 8449 permits has nothing valid to advertise. */
if (record_size_limit < MBEDTLS_SSL_RECORD_SIZE_LIMIT_MIN) {
MBEDTLS_SSL_DEBUG_MSG(1, ("incoming content length %" MBEDTLS_PRINTF_SIZET
" is less than the minimum record size limit %d",
record_size_limit,
MBEDTLS_SSL_RECORD_SIZE_LIMIT_MIN));
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
}
MBEDTLS_SSL_CHK_BUF_PTR(p, end, 6);
MBEDTLS_PUT_UINT16_BE(MBEDTLS_TLS_EXT_RECORD_SIZE_LIMIT, p, 0);
MBEDTLS_PUT_UINT16_BE(MBEDTLS_SSL_RECORD_SIZE_LIMIT_EXTENSION_DATA_LENGTH,
p, 2);
MBEDTLS_PUT_UINT16_BE(MBEDTLS_SSL_IN_CONTENT_LEN, p, 4);
MBEDTLS_PUT_UINT16_BE(record_size_limit, p, 4);
*out_len = 6;
MBEDTLS_SSL_DEBUG_MSG(2, ("Sent RecordSizeLimit: %d Bytes",
MBEDTLS_SSL_IN_CONTENT_LEN));
MBEDTLS_SSL_DEBUG_MSG(2, ("Sent RecordSizeLimit: %" MBEDTLS_PRINTF_SIZET " Bytes",
record_size_limit));
mbedtls_ssl_tls13_set_hs_sent_ext_mask(ssl, MBEDTLS_TLS_EXT_RECORD_SIZE_LIMIT);

View File

@ -67,6 +67,8 @@ int main(void)
#define DFL_AUTH_MODE -1
#define DFL_SET_HOSTNAME 1
#define DFL_MFL_CODE MBEDTLS_SSL_MAX_FRAG_LEN_NONE
#define DFL_IN_CONTENT_LEN 0
#define DFL_OUT_CONTENT_LEN 0
#define DFL_TRUNC_HMAC -1
#define DFL_RECSPLIT -1
#define DFL_RECONNECT 0
@ -231,6 +233,14 @@ int main(void)
#define USAGE_MAX_FRAG_LEN ""
#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
#define USAGE_CONTENT_LEN \
" in_content_len=%%d default: MBEDTLS_SSL_IN_CONTENT_LEN\n" \
" out_content_len=%%d default: MBEDTLS_SSL_OUT_CONTENT_LEN\n"
#else
#define USAGE_CONTENT_LEN ""
#endif /* MBEDTLS_SSL_RUNTIME_CONTENT_LEN */
#if defined(MBEDTLS_SSL_ALPN)
#define USAGE_ALPN \
" alpn=%%s default: \"\" (disabled)\n" \
@ -425,6 +435,7 @@ int main(void)
USAGE_TICKETS \
USAGE_EAP_TLS \
USAGE_MAX_FRAG_LEN \
USAGE_CONTENT_LEN \
USAGE_CONTEXT_CRT_CB \
USAGE_ALPN \
USAGE_EMS \
@ -504,6 +515,8 @@ struct options {
int set_hostname; /* call mbedtls_ssl_set_hostname()? */
/* 0=no, 1=yes, -1=NULL */
unsigned char mfl_code; /* code for maximum fragment length */
int in_content_len; /* incoming content length (0: default) */
int out_content_len; /* outgoing content length (0: default) */
int trunc_hmac; /* negotiate truncated hmac or not */
int recsplit; /* enable record splitting? */
int reconnect; /* attempt to resume session */
@ -941,6 +954,8 @@ int main(int argc, char *argv[])
opt.auth_mode = DFL_AUTH_MODE;
opt.set_hostname = DFL_SET_HOSTNAME;
opt.mfl_code = DFL_MFL_CODE;
opt.in_content_len = DFL_IN_CONTENT_LEN;
opt.out_content_len = DFL_OUT_CONTENT_LEN;
opt.trunc_hmac = DFL_TRUNC_HMAC;
opt.recsplit = DFL_RECSPLIT;
opt.reconnect = DFL_RECONNECT;
@ -1350,6 +1365,18 @@ usage:
} else {
goto usage;
}
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
} else if (strcmp(p, "in_content_len") == 0) {
opt.in_content_len = atoi(q);
if (opt.in_content_len <= 0) {
goto usage;
}
} else if (strcmp(p, "out_content_len") == 0) {
opt.out_content_len = atoi(q);
if (opt.out_content_len <= 0) {
goto usage;
}
#endif /* MBEDTLS_SSL_RUNTIME_CONTENT_LEN */
} else if (strcmp(p, "trunc_hmac") == 0) {
switch (atoi(q)) {
case 0: opt.trunc_hmac = MBEDTLS_SSL_TRUNC_HMAC_DISABLED; break;
@ -2020,6 +2047,22 @@ usage:
}
#endif /* MBEDTLS_SSL_EARLY_DATA */
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
if (opt.in_content_len != DFL_IN_CONTENT_LEN &&
(ret = mbedtls_ssl_set_in_content_len(&ssl, opt.in_content_len)) != 0) {
mbedtls_printf(" failed\n ! mbedtls_ssl_set_in_content_len returned -0x%x\n\n",
(unsigned int) -ret);
goto exit;
}
if (opt.out_content_len != DFL_OUT_CONTENT_LEN &&
(ret = mbedtls_ssl_set_out_content_len(&ssl, opt.out_content_len)) != 0) {
mbedtls_printf(" failed\n ! mbedtls_ssl_set_out_content_len returned -0x%x\n\n",
(unsigned int) -ret);
goto exit;
}
#endif /* MBEDTLS_SSL_RUNTIME_CONTENT_LEN */
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned -0x%x\n\n",
(unsigned int) -ret);

View File

@ -111,6 +111,8 @@ int main(void)
#define DFL_CERT_REQ_CA_LIST MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED
#define DFL_CERT_REQ_DN_HINT 0
#define DFL_MFL_CODE MBEDTLS_SSL_MAX_FRAG_LEN_NONE
#define DFL_IN_CONTENT_LEN 0
#define DFL_OUT_CONTENT_LEN 0
#define DFL_TRUNC_HMAC -1
#define DFL_TICKETS MBEDTLS_SSL_SESSION_TICKETS_ENABLED
#define DFL_DUMMY_TICKET 0
@ -345,6 +347,14 @@ int main(void)
#define USAGE_MAX_FRAG_LEN ""
#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
#define USAGE_CONTENT_LEN \
" in_content_len=%%d default: MBEDTLS_SSL_IN_CONTENT_LEN\n" \
" out_content_len=%%d default: MBEDTLS_SSL_OUT_CONTENT_LEN\n"
#else
#define USAGE_CONTENT_LEN ""
#endif /* MBEDTLS_SSL_RUNTIME_CONTENT_LEN */
#if defined(MBEDTLS_SSL_ALPN)
#define USAGE_ALPN \
" alpn=%%s default: \"\" (disabled)\n" \
@ -550,6 +560,7 @@ int main(void)
USAGE_CACHE \
USAGE_CACHE_TIME \
USAGE_MAX_FRAG_LEN \
USAGE_CONTENT_LEN \
USAGE_ALPN \
USAGE_EMS \
USAGE_ETM \
@ -650,6 +661,8 @@ struct options {
int cert_req_ca_list; /* should we send the CA list? */
int cert_req_dn_hint; /* mode to set DN hints for CA list to send */
unsigned char mfl_code; /* code for maximum fragment length */
int in_content_len; /* incoming content length (0: default) */
int out_content_len; /* outgoing content length (0: default) */
int trunc_hmac; /* accept truncated hmac? */
int tickets; /* enable / disable session tickets */
int dummy_ticket; /* enable / disable dummy ticket generator */
@ -1718,6 +1731,8 @@ int main(int argc, char *argv[])
opt.cert_req_ca_list = DFL_CERT_REQ_CA_LIST;
opt.cert_req_dn_hint = DFL_CERT_REQ_DN_HINT;
opt.mfl_code = DFL_MFL_CODE;
opt.in_content_len = DFL_IN_CONTENT_LEN;
opt.out_content_len = DFL_OUT_CONTENT_LEN;
opt.trunc_hmac = DFL_TRUNC_HMAC;
opt.tickets = DFL_TICKETS;
opt.dummy_ticket = DFL_DUMMY_TICKET;
@ -2125,6 +2140,18 @@ usage:
} else {
goto usage;
}
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
} else if (strcmp(p, "in_content_len") == 0) {
opt.in_content_len = atoi(q);
if (opt.in_content_len <= 0) {
goto usage;
}
} else if (strcmp(p, "out_content_len") == 0) {
opt.out_content_len = atoi(q);
if (opt.out_content_len <= 0) {
goto usage;
}
#endif /* MBEDTLS_SSL_RUNTIME_CONTENT_LEN */
} else if (strcmp(p, "alpn") == 0) {
opt.alpn_string = q;
} else if (strcmp(p, "trunc_hmac") == 0) {
@ -3179,6 +3206,22 @@ usage:
mbedtls_ssl_conf_max_tls_version(&conf, opt.max_version);
}
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
if (opt.in_content_len != DFL_IN_CONTENT_LEN &&
(ret = mbedtls_ssl_set_in_content_len(&ssl, opt.in_content_len)) != 0) {
mbedtls_printf(" failed\n ! mbedtls_ssl_set_in_content_len returned -0x%x\n\n",
(unsigned int) -ret);
goto exit;
}
if (opt.out_content_len != DFL_OUT_CONTENT_LEN &&
(ret = mbedtls_ssl_set_out_content_len(&ssl, opt.out_content_len)) != 0) {
mbedtls_printf(" failed\n ! mbedtls_ssl_set_out_content_len returned -0x%x\n\n",
(unsigned int) -ret);
goto exit;
}
#endif /* MBEDTLS_SSL_RUNTIME_CONTENT_LEN */
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", (unsigned int) -ret);
goto exit;

View File

@ -47,6 +47,7 @@ MBEDTLS_SSL_PROTO_TLS1_2
MBEDTLS_SSL_PROTO_TLS1_3
MBEDTLS_SSL_RECORD_SIZE_LIMIT
MBEDTLS_SSL_RENEGOTIATION
MBEDTLS_SSL_RUNTIME_CONTENT_LEN
MBEDTLS_SSL_SERVER_NAME_INDICATION
MBEDTLS_SSL_SESSION_TICKETS
MBEDTLS_SSL_SRV_C

View File

@ -344,6 +344,22 @@ component_test_variable_ssl_in_out_buffer_len () {
tests/compat.sh
}
component_test_ssl_runtime_content_len () {
msg "build: MBEDTLS_SSL_RUNTIME_CONTENT_LEN enabled (ASan build)"
scripts/config.py set MBEDTLS_SSL_RUNTIME_CONTENT_LEN
CC=$ASAN_CC cmake -D CMAKE_BUILD_TYPE:String=Asan .
make
msg "test: MBEDTLS_SSL_RUNTIME_CONTENT_LEN enabled"
make test
msg "test: ssl-opt.sh, MBEDTLS_SSL_RUNTIME_CONTENT_LEN enabled"
tests/ssl-opt.sh
msg "test: compat.sh, MBEDTLS_SSL_RUNTIME_CONTENT_LEN enabled"
tests/compat.sh
}
component_test_ssl_alloc_buffer_and_mfl () {
msg "build: default config with memory buffer allocator and MFL extension"
scripts/config.py set MBEDTLS_MEMORY_BUFFER_ALLOC_C
@ -361,6 +377,24 @@ component_test_ssl_alloc_buffer_and_mfl () {
tests/ssl-opt.sh -f "Handshake memory usage"
}
component_test_ssl_alloc_buffer_and_runtime_content_len () {
msg "build: default config with memory buffer allocator and runtime content lengths"
scripts/config.py set MBEDTLS_MEMORY_BUFFER_ALLOC_C
scripts/config.py set MBEDTLS_PLATFORM_MEMORY
scripts/config.py set MBEDTLS_MEMORY_DEBUG
scripts/config.py set MBEDTLS_SSL_RUNTIME_CONTENT_LEN
scripts/config.py set MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH
scripts/config.py set MBEDTLS_SSL_RECORD_SIZE_LIMIT
cmake -DCMAKE_BUILD_TYPE:String=Release .
make
msg "test: MBEDTLS_SSL_RUNTIME_CONTENT_LEN, MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH, MBEDTLS_MEMORY_BUFFER_ALLOC_C and MBEDTLS_MEMORY_DEBUG"
make test
msg "test: ssl-opt.sh memory usage and runtime content length, MBEDTLS_SSL_RUNTIME_CONTENT_LEN and MBEDTLS_SSL_RECORD_SIZE_LIMIT"
tests/ssl-opt.sh -f "Handshake memory usage\|Runtime content length"
}
component_test_when_no_ciphersuites_have_mac () {
msg "build: when no ciphersuites have MAC"
scripts/config.py unset PSA_WANT_ALG_CBC_NO_PADDING

View File

@ -48,6 +48,7 @@ RULES = {
'in_msglen': ssl_session_reset_check.ResetBehavior.RESET,
'in_left': ssl_session_reset_check.ResetBehavior.RESET,
'in_buf_len': ssl_session_reset_check.ResetBehavior.SPECIAL,
'in_content_len': ssl_session_reset_check.ResetBehavior.KEEP,
'in_epoch': ssl_session_reset_check.ResetBehavior.RESET,
'next_record_offset': ssl_session_reset_check.ResetBehavior.RESET,
'in_window_top': ssl_session_reset_check.ResetBehavior.RESET,
@ -75,6 +76,7 @@ RULES = {
'out_msglen': ssl_session_reset_check.ResetBehavior.RESET,
'out_left': ssl_session_reset_check.ResetBehavior.RESET,
'out_buf_len': ssl_session_reset_check.ResetBehavior.SPECIAL,
'out_content_len': ssl_session_reset_check.ResetBehavior.KEEP,
'cur_out_ctr': ssl_session_reset_check.ResetBehavior.RESET,
'mtu': ssl_session_reset_check.ResetBehavior.KEEP,
'hostname': ssl_session_reset_check.ResetBehavior.KEEP,
@ -102,8 +104,18 @@ SPECIAL_BEHAVIORS = {
'(after->flags & MBEDTLS_SSL_CONTEXT_FLAGS_KEEP_AT_SESSION));'],
'tls_version': ['TEST_ASSERT(after->tls_version == after->conf->max_tls_version);'],
'user_data': ['TEST_ASSERT(before->user_data.n == after->user_data.n);'],
'in_buf_len': ['TEST_ASSERT(after->in_buf_len == MBEDTLS_SSL_IN_BUFFER_LEN);'],
'out_buf_len': ['TEST_ASSERT(after->out_buf_len == MBEDTLS_SSL_OUT_BUFFER_LEN);'],
'in_buf_len': ['#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)',
'TEST_ASSERT(after->in_buf_len == MBEDTLS_SSL_IN_BUFFER_LEN -',
' (MBEDTLS_SSL_IN_CONTENT_LEN - after->in_content_len));',
'#else',
'TEST_ASSERT(after->in_buf_len == MBEDTLS_SSL_IN_BUFFER_LEN);',
'#endif'],
'out_buf_len': ['#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)',
'TEST_ASSERT(after->out_buf_len == MBEDTLS_SSL_OUT_BUFFER_LEN -',
' (MBEDTLS_SSL_OUT_CONTENT_LEN - after->out_content_len));',
'#else',
'TEST_ASSERT(after->out_buf_len == MBEDTLS_SSL_OUT_BUFFER_LEN);',
'#endif'],
}
NAMED_STRUCTURES = frozenset([

View File

@ -84,8 +84,16 @@ int mbedtls_test_ssl_check_context_after_session_reset(const mbedtls_ssl_context
TEST_ASSERT(after->in_msgtype == initial.in_msgtype);
TEST_ASSERT(after->in_msglen == initial.in_msglen);
TEST_ASSERT(after->in_left == initial.in_left);
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
#if defined(MBEDTLS_SSL_HAVE_BUFFER_LEN_FIELDS)
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
TEST_ASSERT(after->in_buf_len == MBEDTLS_SSL_IN_BUFFER_LEN -
(MBEDTLS_SSL_IN_CONTENT_LEN - after->in_content_len));
#else
TEST_ASSERT(after->in_buf_len == MBEDTLS_SSL_IN_BUFFER_LEN);
#endif
#endif
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
TEST_EQUAL(before->in_content_len, after->in_content_len);
#endif
#if defined(MBEDTLS_SSL_PROTO_DTLS)
TEST_ASSERT(after->in_epoch == initial.in_epoch);
@ -132,8 +140,16 @@ int mbedtls_test_ssl_check_context_after_session_reset(const mbedtls_ssl_context
TEST_ASSERT(after->out_msgtype == initial.out_msgtype);
TEST_ASSERT(after->out_msglen == initial.out_msglen);
TEST_ASSERT(after->out_left == initial.out_left);
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
#if defined(MBEDTLS_SSL_HAVE_BUFFER_LEN_FIELDS)
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
TEST_ASSERT(after->out_buf_len == MBEDTLS_SSL_OUT_BUFFER_LEN -
(MBEDTLS_SSL_OUT_CONTENT_LEN - after->out_content_len));
#else
TEST_ASSERT(after->out_buf_len == MBEDTLS_SSL_OUT_BUFFER_LEN);
#endif
#endif
#if defined(MBEDTLS_SSL_RUNTIME_CONTENT_LEN)
TEST_EQUAL(before->out_content_len, after->out_content_len);
#endif
TEST_MEMORY_COMPARE(after->cur_out_ctr, sizeof(after->cur_out_ctr), initial.cur_out_ctr, sizeof(initial.cur_out_ctr));
#if defined(MBEDTLS_SSL_PROTO_DTLS)

View File

@ -2152,9 +2152,14 @@ static int test_renegotiation(const mbedtls_test_handshake_test_options *options
ret = mbedtls_ssl_renegotiate(&(client->ssl));
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
if (options->resize_buffers != 0) {
/* Ensure that the buffer sizes are appropriate before resizes */
TEST_EQUAL(client->ssl.out_buf_len, MBEDTLS_SSL_OUT_BUFFER_LEN);
TEST_EQUAL(client->ssl.in_buf_len, MBEDTLS_SSL_IN_BUFFER_LEN);
/* Starting the renegotiation grew the buffers back to the full size
* of this connection: its own content lengths, not the build-time
* maximum, so that MBEDTLS_SSL_RUNTIME_CONTENT_LEN keeps its saving.
* Without that option the two are the same. */
TEST_EQUAL(client->ssl.out_buf_len,
mbedtls_ssl_compute_out_buf_len(&client->ssl));
TEST_EQUAL(client->ssl.in_buf_len,
mbedtls_ssl_compute_in_buf_len(&client->ssl));
}
#endif
TEST_ASSERT(ret == 0 ||
@ -2233,9 +2238,11 @@ static int test_serialization(const mbedtls_test_handshake_test_options *options
#endif
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
if (options->resize_buffers != 0) {
/* Ensure that the buffer sizes are appropriate before resizes */
TEST_EQUAL(server->ssl.out_buf_len, MBEDTLS_SSL_OUT_BUFFER_LEN);
TEST_EQUAL(server->ssl.in_buf_len, MBEDTLS_SSL_IN_BUFFER_LEN);
/* The freshly set up connection starts at its own full size. */
TEST_EQUAL(server->ssl.out_buf_len,
mbedtls_ssl_compute_out_buf_len(&server->ssl));
TEST_EQUAL(server->ssl.in_buf_len,
mbedtls_ssl_compute_in_buf_len(&server->ssl));
}
#endif
TEST_EQUAL(mbedtls_ssl_context_load(&(server->ssl), context_buf,
@ -2283,11 +2290,18 @@ int mbedtls_test_ssl_perform_connection(
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
if (options->resize_buffers != 0) {
/* Ensure that the buffer sizes are appropriate before resizes */
TEST_EQUAL(client->ssl.out_buf_len, MBEDTLS_SSL_OUT_BUFFER_LEN);
TEST_EQUAL(client->ssl.in_buf_len, MBEDTLS_SSL_IN_BUFFER_LEN);
TEST_EQUAL(server->ssl.out_buf_len, MBEDTLS_SSL_OUT_BUFFER_LEN);
TEST_EQUAL(server->ssl.in_buf_len, MBEDTLS_SSL_IN_BUFFER_LEN);
/* Before the handshake, including after a session reset, each
* buffer is the full size of its connection: its own content length,
* which is the build-time maximum unless
* MBEDTLS_SSL_RUNTIME_CONTENT_LEN shrank it. */
TEST_EQUAL(client->ssl.out_buf_len,
mbedtls_ssl_compute_out_buf_len(&client->ssl));
TEST_EQUAL(client->ssl.in_buf_len,
mbedtls_ssl_compute_in_buf_len(&client->ssl));
TEST_EQUAL(server->ssl.out_buf_len,
mbedtls_ssl_compute_out_buf_len(&server->ssl));
TEST_EQUAL(server->ssl.in_buf_len,
mbedtls_ssl_compute_in_buf_len(&server->ssl));
}
#endif

View File

@ -1235,6 +1235,45 @@ handshake_memory_check() {
fi
}
# Get peak memory usage from server output and put it into the variable specified by the first argument
handshake_peak_memory_get() {
OUTPUT_VARIABLE="$1"
OUTPUT_FILE="$2"
# Get peak memory usage from a pattern like "Heap memory usage after handshake: 23112 bytes. Peak memory usage was 33112"
MEM_USAGE=$(sed -n 's/.*Peak memory usage was //p' < "$OUTPUT_FILE" | grep -o "[0-9]*" | head -1)
# Check if peak memory usage was read
if [ -z "$MEM_USAGE" ]; then
echo "Error: Can not read the value of peak memory usage"
return 1
else
eval "$OUTPUT_VARIABLE=$MEM_USAGE"
return 0
fi
}
# Get peak memory usage from server output and check if this value
# is not higher than the maximum given by the first argument
handshake_peak_memory_check() {
MAX_MEMORY="$1"
OUTPUT_FILE="$2"
# Get peak memory usage
if ! handshake_peak_memory_get "MEMORY_USAGE" "$OUTPUT_FILE"; then
return 1
fi
# Check if peak memory usage is below max value
if [ "$MEMORY_USAGE" -gt "$MAX_MEMORY" ]; then
echo "\nFailed: Peak memory usage was $MEMORY_USAGE bytes," \
"but should be below $MAX_MEMORY bytes"
return 1
else
return 0
fi
}
# wait for client to terminate and set CLI_EXIT
# must be called right after starting the client
wait_client_done() {
@ -1910,6 +1949,55 @@ run_tests_memory_after_handshake()
run_test_memory_after_handshake_with_mfl 512 "$MEMORY_USAGE_MFL_16K"
}
# Test that the server's peak memory usage falls when it shrinks its own content
# lengths at runtime.
# first argument ($1) is the server's incoming content length
# second argument ($2) is the server's outgoing content length
# third argument ($3) is the server's peak memory usage with the default lengths
run_test_memory_with_runtime_content_len()
{
# The I/O buffers shrink by exactly (16384 - $1) + (16384 - $2). Require
# most of that saving, so that the test fails if the lengths never reach
# the allocation.
MEMORY_USAGE_LIMIT="$(( $3 - ( ( 16384 - $1 ) + ( 16384 - $2 ) ) * 9 / 10 ))"
run_test "Handshake memory usage (runtime content length in $1, out $2)" \
"$P_SRV debug_level=3 auth_mode=required force_version=tls12 \
in_content_len=$1 out_content_len=$2" \
"$P_CLI debug_level=3 \
crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key \
force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM" \
0 \
-F "handshake_peak_memory_check $MEMORY_USAGE_LIMIT"
}
# Test that the server's peak memory usage falls when it shrinks its incoming
# length, its outgoing length, or both
run_tests_memory_with_runtime_content_len()
{
# all tests in this sequence requires the same configuration (see requires_config_enabled())
SKIP_THIS_TESTS="$SKIP_NEXT"
# first test with the default lengths is to get reference memory usage
PEAK_MEMORY_USAGE_16K=0
run_test "Handshake memory usage initial (runtime content length default)" \
"$P_SRV debug_level=3 auth_mode=required force_version=tls12" \
"$P_CLI debug_level=3 \
crt_file=$DATA_FILES_PATH/server5.crt key_file=$DATA_FILES_PATH/server5.key \
force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM" \
0 \
-F "handshake_peak_memory_get PEAK_MEMORY_USAGE_16K"
SKIP_NEXT="$SKIP_THIS_TESTS"
run_test_memory_with_runtime_content_len 4096 4096 "$PEAK_MEMORY_USAGE_16K"
SKIP_NEXT="$SKIP_THIS_TESTS"
run_test_memory_with_runtime_content_len 1024 16384 "$PEAK_MEMORY_USAGE_16K"
SKIP_NEXT="$SKIP_THIS_TESTS"
run_test_memory_with_runtime_content_len 16384 1024 "$PEAK_MEMORY_USAGE_16K"
}
run_test_export_keying_material() {
unset EXPORTED_KEY1
unset EXPORTED_KEY2
@ -5134,6 +5222,105 @@ run_test "Record Size Limit: TLS 1.3 m->m: both peer comply with record size
# End of Record size limit tests
# Tests for runtime content lengths: a client that shrinks its incoming length
# against a full-size server. Only a negotiated max_fragment_length or
# record_size_limit tells the server about it; without either, a record longer
# than the client's incoming length makes the read fail cleanly, the same way
# it does when MBEDTLS_SSL_IN_CONTENT_LEN is set to that length at build time.
requires_config_enabled MBEDTLS_SSL_RUNTIME_CONTENT_LEN
requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
requires_max_content_len 2048
run_test "Runtime content length: client in 1024, MFL 1024" \
"$P_SRV debug_level=3 response_size=2000" \
"$P_CLI debug_level=3 force_version=tls12 in_content_len=1024 max_frag_len=1024" \
0 \
-c "client hello, adding max_fragment_length extension" \
-s "server hello, max_fragment_length extension" \
-c "Maximum incoming record payload length is 1024" \
-s "Maximum outgoing record payload length is 1024" \
-s "2000 bytes written in 2 fragments" \
-c "1024 bytes read" \
-c "976 bytes read"
requires_config_enabled MBEDTLS_SSL_RUNTIME_CONTENT_LEN
requires_config_enabled MBEDTLS_SSL_CLI_C
requires_config_enabled MBEDTLS_SSL_SRV_C
requires_config_enabled MBEDTLS_DEBUG_C
requires_config_enabled MBEDTLS_SSL_RECORD_SIZE_LIMIT
requires_config_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
requires_max_content_len 2048
run_test "Runtime content length: client in 1024, record_size_limit" \
"$P_SRV debug_level=3 response_size=2000" \
"$P_CLI debug_level=3 force_version=tls13 in_content_len=1024" \
0 \
-c "Sent RecordSizeLimit: 1024 Bytes" \
-s "RecordSizeLimit: 1024 Bytes" \
-c "Maximum incoming record payload length is 1024" \
-s "Maximum outgoing record payload length is 1023" \
-s "2000 bytes written in 2 fragments" \
-c "1023 bytes read" \
-c "977 bytes read"
requires_config_enabled MBEDTLS_SSL_RUNTIME_CONTENT_LEN
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
requires_max_content_len 2048
run_test "Runtime content length: client in 1024, no extension, short record" \
"$P_SRV debug_level=3" \
"$P_CLI debug_level=3 force_version=tls12 in_content_len=1024" \
0 \
-C "client hello, adding max_fragment_length extension" \
-c "Maximum incoming record payload length is 1024" \
-s "Maximum outgoing record payload length is 16384" \
-c "[0-9]\+ bytes read"
requires_config_enabled MBEDTLS_SSL_RUNTIME_CONTENT_LEN
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
requires_max_content_len 2048
run_test "Runtime content length: client in 1024, no extension, 1025 bytes" \
"$P_SRV debug_level=3 response_size=1025" \
"$P_CLI debug_level=3 force_version=tls12 in_content_len=1024" \
1 \
-C "client hello, adding max_fragment_length extension" \
-s "Maximum outgoing record payload length is 16384" \
-s "1025 bytes written in 1 fragments" \
-c "bad message length" \
-c "mbedtls_ssl_read returned -0x7200" \
-C "[0-9]\+ bytes read"
requires_config_enabled MBEDTLS_SSL_RUNTIME_CONTENT_LEN
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
requires_max_content_len 2048
run_test "Runtime content length: client in 1024, no extension, 2000 bytes" \
"$P_SRV debug_level=3 response_size=2000" \
"$P_CLI debug_level=3 force_version=tls12 in_content_len=1024" \
1 \
-C "client hello, adding max_fragment_length extension" \
-s "Maximum outgoing record payload length is 16384" \
-s "2000 bytes written in 1 fragments" \
-c "requesting more data than fits" \
-c "mbedtls_ssl_read returned -0x87" \
-C "[0-9]\+ bytes read"
requires_config_enabled MBEDTLS_SSL_RUNTIME_CONTENT_LEN
requires_config_enabled MBEDTLS_SSL_CLI_C
requires_config_enabled MBEDTLS_SSL_SRV_C
requires_config_disabled MBEDTLS_SSL_RECORD_SIZE_LIMIT
requires_config_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
requires_max_content_len 2048
run_test "Runtime content length: client in 1024, TLS 1.3, no extension" \
"$P_SRV debug_level=3 response_size=2000" \
"$P_CLI debug_level=3 force_version=tls13 in_content_len=1024" \
1 \
-s "Maximum outgoing record payload length is 16383" \
-s "2000 bytes written in 1 fragments" \
-c "requesting more data than fits" \
-c "mbedtls_ssl_read returned -0x87" \
-C "[0-9]\+ bytes read"
# End of runtime content length tests
# Tests for renegotiation
# G_NEXT_SRV is used in renegotiation tests becuase of the increased
@ -14440,6 +14627,14 @@ requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
requires_max_content_len 16384
run_tests_memory_after_handshake
# Test peak heap memory usage with runtime content lengths
requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
requires_config_enabled MBEDTLS_MEMORY_DEBUG
requires_config_enabled MBEDTLS_MEMORY_BUFFER_ALLOC_C
requires_config_enabled MBEDTLS_SSL_RUNTIME_CONTENT_LEN
requires_max_content_len 16384
run_tests_memory_with_runtime_content_len
if [ "$LIST_TESTS" -eq 0 ]; then
# Final report

View File

@ -3632,3 +3632,194 @@ tls13_record_boundary_alignment:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_HS_FINISHED
TLS 1.3 EndOfEarlyData record boundary alignment enforcement
depends_on:MBEDTLS_SSL_EARLY_DATA:MBEDTLS_SSL_SESSION_TICKETS
tls13_record_boundary_alignment:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_HS_END_OF_EARLY_DATA
Runtime content length: enabling the option alone changes nothing, TLS
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_default_is_noop:0
Runtime content length: enabling the option alone changes nothing, DTLS
depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_PROTO_DTLS
ssl_runtime_content_len_default_is_noop:1
Runtime content length: incoming above the build-time ceiling is rejected
ssl_runtime_content_len_set:0:0:MBEDTLS_SSL_IN_CONTENT_LEN + 1:MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Runtime content length: outgoing above the build-time ceiling is rejected
ssl_runtime_content_len_set:1:0:MBEDTLS_SSL_OUT_CONTENT_LEN + 1:MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Runtime content length: incoming at the build-time ceiling is accepted
ssl_runtime_content_len_set:0:0:MBEDTLS_SSL_IN_CONTENT_LEN:0
Runtime content length: outgoing at the build-time ceiling is accepted
ssl_runtime_content_len_set:1:0:MBEDTLS_SSL_OUT_CONTENT_LEN:0
Runtime content length: incoming below the floor is rejected
ssl_runtime_content_len_set:0:0:MBEDTLS_SSL_IN_CONTENT_LEN_MIN - 1:MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Runtime content length: incoming at the floor is accepted
ssl_runtime_content_len_set:0:0:MBEDTLS_SSL_IN_CONTENT_LEN_MIN:0
Runtime content length: outgoing below the floor is rejected
ssl_runtime_content_len_set:1:0:MBEDTLS_SSL_OUT_CONTENT_LEN_MIN - 1:MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Runtime content length: outgoing at the floor is accepted
ssl_runtime_content_len_set:1:0:MBEDTLS_SSL_OUT_CONTENT_LEN_MIN:0
Runtime content length: zero incoming is rejected
ssl_runtime_content_len_set:0:0:0:MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Runtime content length: outgoing too short for a certificate header is rejected
ssl_runtime_content_len_set:1:0:10:MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Runtime content length: outgoing too short for a DTLS handshake header is rejected
ssl_runtime_content_len_set:1:0:11:MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Runtime content length: outgoing below TLS 1.3 padding granularity is rejected
depends_on:MBEDTLS_SSL_PROTO_TLS1_3
ssl_runtime_content_len_set:1:0:MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY - 1:MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Runtime content length: incoming after setup is rejected
ssl_runtime_content_len_set:0:1:MBEDTLS_SSL_IN_CONTENT_LEN / 2:MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Runtime content length: outgoing after setup is rejected
ssl_runtime_content_len_set:1:1:MBEDTLS_SSL_OUT_CONTENT_LEN / 2:MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Runtime content length: incoming after session reset is rejected
ssl_runtime_content_len_set:0:2:MBEDTLS_SSL_IN_CONTENT_LEN / 2:MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Runtime content length: outgoing after session reset is rejected
ssl_runtime_content_len_set:1:2:MBEDTLS_SSL_OUT_CONTENT_LEN / 2:MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Runtime content length: one connection, different incoming and outgoing, TLS 1.2
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_handshake:MBEDTLS_SSL_VERSION_TLS1_2:0:2048:512:0:0:1024:2:2048:1:0
Runtime content length: two peers with different lengths, TLS 1.2
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_handshake:MBEDTLS_SSL_VERSION_TLS1_2:0:4096:1024:1024:4096:2048:2:4096:1:0
Runtime content length: two peers with different lengths, DTLS 1.2
depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_PROTO_DTLS
ssl_runtime_content_len_handshake:MBEDTLS_SSL_VERSION_TLS1_2:1:4096:1024:1024:4096:1024:1:4096:1:0
Runtime content length: DTLS 1.2 refuses a message above the outgoing length
depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_PROTO_DTLS
ssl_runtime_content_len_handshake:MBEDTLS_SSL_VERSION_TLS1_2:1:4096:1024:1024:4096:1025:0:4096:1:0
Runtime content length: two peers with different lengths, TLS 1.3
depends_on:MBEDTLS_SSL_PROTO_TLS1_3
ssl_runtime_content_len_handshake:MBEDTLS_SSL_VERSION_TLS1_3:0:4096:1024:1024:4096:2048:3:4095:1:0
Runtime content length: lengths survive a session reset, TLS 1.2
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_handshake:MBEDTLS_SSL_VERSION_TLS1_2:0:0:1024:0:1024:2048:2:2048:2:1
Runtime content length: lengths survive a session reset, TLS 1.3
depends_on:MBEDTLS_SSL_PROTO_TLS1_3
ssl_runtime_content_len_handshake:MBEDTLS_SSL_VERSION_TLS1_3:0:0:1024:0:1024:2046:2:2046:2:1
Runtime content length: resize, TLS 1.2
ssl_runtime_content_len_resize_buffers:0:MBEDTLS_SSL_MAX_FRAG_LEN_NONE:0:2048:1024:1024:2048
Runtime content length: resize, MFL=512, TLS 1.2
ssl_runtime_content_len_resize_buffers:0:MBEDTLS_SSL_MAX_FRAG_LEN_512:0:2048:1024:1024:2048
Runtime content length: resize, reneg, DTLS 1.2
depends_on:MBEDTLS_SSL_RENEGOTIATION:MBEDTLS_SSL_PROTO_DTLS
ssl_runtime_content_len_resize_buffers:1:MBEDTLS_SSL_MAX_FRAG_LEN_NONE:1:2048:1024:1024:2048
Runtime content length: resize, MFL=512, reneg, DTLS 1.2
depends_on:MBEDTLS_SSL_RENEGOTIATION:MBEDTLS_SSL_PROTO_DTLS
ssl_runtime_content_len_resize_buffers:1:MBEDTLS_SSL_MAX_FRAG_LEN_512:1:2048:1024:1024:2048
Runtime content length: resize, MFL above out len, reneg, DTLS 1.2
depends_on:MBEDTLS_SSL_RENEGOTIATION:MBEDTLS_SSL_PROTO_DTLS
ssl_runtime_content_len_resize_buffers:1:MBEDTLS_SSL_MAX_FRAG_LEN_4096:1:4096:1024:1024:2048
Runtime content length: resize, server shrunk, reneg, DTLS 1.2
depends_on:MBEDTLS_SSL_RENEGOTIATION:MBEDTLS_SSL_PROTO_DTLS
ssl_runtime_content_len_resize_buffers:1:MBEDTLS_SSL_MAX_FRAG_LEN_1024:1:0:0:2048:1024
Runtime content length: record at the incoming length is accepted, TLS 1.2
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_oversized_record:MBEDTLS_SSL_VERSION_TLS1_2:1024:1024:0
Runtime content length: record above the incoming length is rejected, TLS 1.2
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_oversized_record:MBEDTLS_SSL_VERSION_TLS1_2:1024:1025:MBEDTLS_ERR_SSL_INVALID_RECORD
Runtime content length: record at the incoming length is accepted, TLS 1.3
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:!MBEDTLS_SSL_RECORD_SIZE_LIMIT
ssl_runtime_content_len_oversized_record:MBEDTLS_SSL_VERSION_TLS1_3:1024:1024:0
Runtime content length: record above the incoming length is rejected, TLS 1.3
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:!MBEDTLS_SSL_RECORD_SIZE_LIMIT
ssl_runtime_content_len_oversized_record:MBEDTLS_SSL_VERSION_TLS1_3:1024:1025:MBEDTLS_ERR_SSL_INVALID_RECORD
Runtime content length: client setup accepts a fragment length at the incoming length
depends_on:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_setup_mfl:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:1024:MBEDTLS_SSL_MAX_FRAG_LEN_1024:0
Runtime content length: client setup rejects a fragment length above the incoming length
depends_on:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_setup_mfl:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:1023:MBEDTLS_SSL_MAX_FRAG_LEN_1024:MBEDTLS_ERR_SSL_BAD_CONFIG
Runtime content length: client setup rejects the largest fragment length above the incoming length
depends_on:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_setup_mfl:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:4095:MBEDTLS_SSL_MAX_FRAG_LEN_4096:MBEDTLS_ERR_SSL_BAD_CONFIG
Runtime content length: client setup accepts a short incoming length without a fragment length
depends_on:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_setup_mfl:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_2:512:MBEDTLS_SSL_MAX_FRAG_LEN_NONE:0
Runtime content length: TLS 1.3-only client setup accepts a fragment length above the incoming length
depends_on:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_PROTO_TLS1_3
ssl_runtime_content_len_setup_mfl:MBEDTLS_SSL_IS_CLIENT:MBEDTLS_SSL_VERSION_TLS1_3:1023:MBEDTLS_SSL_MAX_FRAG_LEN_1024:0
Runtime content length: server setup accepts a fragment length above the incoming length
depends_on:MBEDTLS_SSL_SRV_C:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_setup_mfl:MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_2:1024:MBEDTLS_SSL_MAX_FRAG_LEN_4096:0
Runtime content length: ClientHello max_fragment_length at the incoming length
depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
ssl_runtime_content_len_client_hello_ext:MBEDTLS_SSL_VERSION_TLS1_2:1024:MBEDTLS_SSL_MAX_FRAG_LEN_1024:MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH:0:MBEDTLS_SSL_MAX_FRAG_LEN_1024
Runtime content length: ClientHello max_fragment_length below the incoming length
depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
ssl_runtime_content_len_client_hello_ext:MBEDTLS_SSL_VERSION_TLS1_2:1024:MBEDTLS_SSL_MAX_FRAG_LEN_512:MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH:0:MBEDTLS_SSL_MAX_FRAG_LEN_512
Runtime content length: ClientHello has no max_fragment_length unless configured
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_client_hello_ext:MBEDTLS_SSL_VERSION_TLS1_2:1024:MBEDTLS_SSL_MAX_FRAG_LEN_NONE:MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH:0:-1
Runtime content length: ClientHello record_size_limit, build-time incoming length
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_RECORD_SIZE_LIMIT
ssl_runtime_content_len_client_hello_ext:MBEDTLS_SSL_VERSION_TLS1_3:MBEDTLS_SSL_IN_CONTENT_LEN:MBEDTLS_SSL_MAX_FRAG_LEN_NONE:MBEDTLS_TLS_EXT_RECORD_SIZE_LIMIT:0:MBEDTLS_SSL_IN_CONTENT_LEN
Runtime content length: ClientHello record_size_limit carries the incoming length
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_RECORD_SIZE_LIMIT
ssl_runtime_content_len_client_hello_ext:MBEDTLS_SSL_VERSION_TLS1_3:1024:MBEDTLS_SSL_MAX_FRAG_LEN_NONE:MBEDTLS_TLS_EXT_RECORD_SIZE_LIMIT:0:1024
Runtime content length: ClientHello record_size_limit at the RFC 8449 minimum
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_RECORD_SIZE_LIMIT
ssl_runtime_content_len_client_hello_ext:MBEDTLS_SSL_VERSION_TLS1_3:64:MBEDTLS_SSL_MAX_FRAG_LEN_NONE:MBEDTLS_TLS_EXT_RECORD_SIZE_LIMIT:0:64
Runtime content length: ClientHello record_size_limit below the RFC 8449 minimum is refused
depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_RECORD_SIZE_LIMIT
ssl_runtime_content_len_client_hello_ext:MBEDTLS_SSL_VERSION_TLS1_3:63:MBEDTLS_SSL_MAX_FRAG_LEN_NONE:MBEDTLS_TLS_EXT_RECORD_SIZE_LIMIT:MBEDTLS_ERR_SSL_BAD_INPUT_DATA:-1
Runtime content length: max record payload reports the connection's lengths, TLS 1.2
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
ssl_runtime_content_len_max_payload:MBEDTLS_SSL_VERSION_TLS1_2:2048:1024:MBEDTLS_SSL_MAX_FRAG_LEN_NONE:1024:2048:1024
Runtime content length: max record payload with a fragment length below both lengths, TLS 1.2
depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
ssl_runtime_content_len_max_payload:MBEDTLS_SSL_VERSION_TLS1_2:2048:1024:MBEDTLS_SSL_MAX_FRAG_LEN_512:512:512:512
Runtime content length: max record payload with a fragment length at the incoming length, TLS 1.2
depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
ssl_runtime_content_len_max_payload:MBEDTLS_SSL_VERSION_TLS1_2:2048:4096:MBEDTLS_SSL_MAX_FRAG_LEN_2048:2048:2048:2048
Runtime content length: max record payload reports the connection's lengths, TLS 1.3
depends_on:MBEDTLS_SSL_PROTO_TLS1_3
ssl_runtime_content_len_max_payload:MBEDTLS_SSL_VERSION_TLS1_3:2048:1024:MBEDTLS_SSL_MAX_FRAG_LEN_NONE:1024:2048:1023

View File

@ -3825,6 +3825,567 @@ void resize_buffers_renegotiate_mfl(int mfl, int legacy_renegotiation,
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_RUNTIME_CONTENT_LEN:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256 */
void ssl_runtime_content_len_default_is_noop(int dtls)
{
/* MBEDTLS_SSL_RUNTIME_CONTENT_LEN promises that enabling it, without
* calling either setter, changes nothing. Prove it at the two places the
* option could leak: the lengths a fresh connection starts with, and the
* buffers that setting one up allocates. Then run a handshake and an
* application-data exchange over those buffers, and reset the connection,
* so that a length recorded wrongly shows up as a failure rather than as
* a number nobody reads. */
mbedtls_test_ssl_endpoint client;
memset(&client, 0, sizeof(client));
mbedtls_test_ssl_endpoint server;
memset(&server, 0, sizeof(server));
mbedtls_test_handshake_test_options options;
mbedtls_test_init_handshake_options(&options);
mbedtls_ssl_context fresh;
mbedtls_ssl_init(&fresh);
MD_OR_USE_PSA_INIT();
/* An initialised connection starts at the build-time maxima. */
TEST_EQUAL(fresh.in_content_len, MBEDTLS_SSL_IN_CONTENT_LEN);
TEST_EQUAL(fresh.out_content_len, MBEDTLS_SSL_OUT_CONTENT_LEN);
options.pk_alg = MBEDTLS_PK_ECDSA;
options.dtls = dtls;
if (dtls) {
options.expected_negotiated_version = MBEDTLS_SSL_VERSION_TLS1_2;
}
TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client, MBEDTLS_SSL_IS_CLIENT,
&options), 0);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&server, MBEDTLS_SSL_IS_SERVER,
&options), 0);
/* Setting up a connection that asked for nothing allocates exactly what
* it allocated before the option existed. */
TEST_EQUAL(client.ssl.in_buf_len, MBEDTLS_SSL_IN_BUFFER_LEN);
TEST_EQUAL(client.ssl.out_buf_len, MBEDTLS_SSL_OUT_BUFFER_LEN);
TEST_EQUAL(server.ssl.in_buf_len, MBEDTLS_SSL_IN_BUFFER_LEN);
TEST_EQUAL(server.ssl.out_buf_len, MBEDTLS_SSL_OUT_BUFFER_LEN);
if (dtls) {
TEST_EQUAL(mbedtls_test_ssl_dtls_join_endpoints(&client, &server), 0);
}
/* A full handshake plus an application-data exchange over those buffers.
* The handshake is where the automatic-resize path, when it is compiled
* in, would grow the buffers; either way they must land back on the same
* lengths as a connection that never asked for anything. */
TEST_ASSERT(mbedtls_test_ssl_perform_connection(&options, &client, &server));
TEST_EQUAL(client.ssl.in_buf_len, MBEDTLS_SSL_IN_BUFFER_LEN);
TEST_EQUAL(client.ssl.out_buf_len, MBEDTLS_SSL_OUT_BUFFER_LEN);
TEST_EQUAL(server.ssl.in_buf_len, MBEDTLS_SSL_IN_BUFFER_LEN);
TEST_EQUAL(server.ssl.out_buf_len, MBEDTLS_SSL_OUT_BUFFER_LEN);
/* Reset uses the recorded lengths to rebase the buffers; a disagreement
* between what was allocated and what reset believes was allocated shows
* up here. */
TEST_EQUAL(mbedtls_ssl_session_reset(&client.ssl), 0);
TEST_EQUAL(client.ssl.in_buf_len, MBEDTLS_SSL_IN_BUFFER_LEN);
TEST_EQUAL(client.ssl.out_buf_len, MBEDTLS_SSL_OUT_BUFFER_LEN);
TEST_EQUAL(client.ssl.in_content_len, MBEDTLS_SSL_IN_CONTENT_LEN);
TEST_EQUAL(client.ssl.out_content_len, MBEDTLS_SSL_OUT_CONTENT_LEN);
exit:
mbedtls_ssl_free(&fresh);
mbedtls_test_ssl_endpoint_free(&client);
mbedtls_test_ssl_endpoint_free(&server);
mbedtls_test_free_handshake_options(&options);
MD_OR_USE_PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_RUNTIME_CONTENT_LEN:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256 */
void ssl_runtime_content_len_set(int outgoing, int after_setup, int len,
int expected_ret)
{
/* Ask for a content length either in the window the setters allow,
* between configuring the connection and setting it up, or once the
* connection is set up (after_setup 1), or once it is set up and then
* recycled with mbedtls_ssl_session_reset() (after_setup 2), and check
* the verdict. A reset does not reopen the window. */
mbedtls_test_ssl_endpoint ep;
memset(&ep, 0, sizeof(ep));
mbedtls_test_handshake_test_options options;
mbedtls_test_init_handshake_options(&options);
MD_OR_USE_PSA_INIT();
options.pk_alg = MBEDTLS_PK_ECDSA;
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_conf(&ep, MBEDTLS_SSL_IS_CLIENT,
&options), 0);
if (after_setup) {
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_ssl(&ep, &options), 0);
}
if (after_setup == 2) {
TEST_EQUAL(mbedtls_ssl_session_reset(&ep.ssl), 0);
}
if (outgoing) {
TEST_EQUAL(mbedtls_ssl_set_out_content_len(&ep.ssl, len), expected_ret);
} else {
TEST_EQUAL(mbedtls_ssl_set_in_content_len(&ep.ssl, len), expected_ret);
}
exit:
mbedtls_test_ssl_endpoint_free(&ep);
mbedtls_test_free_handshake_options(&options);
MD_OR_USE_PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_RUNTIME_CONTENT_LEN:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256 */
void ssl_runtime_content_len_handshake(int version, int dtls,
int cli_in, int cli_out,
int srv_in, int srv_out,
int cli_msg_len, int expected_cli_fragments,
int srv_msg_len, int expected_srv_fragments,
int reset)
{
/* Give each peer its own content lengths (0 leaves one at the build-time
* maximum), run a full handshake, then exchange application data. The
* number of records each message is split into is what shows the lengths
* took effect: a sender splits at its own outgoing length, and a message
* that arrives in one record fit the receiver's incoming length.
*
* With reset set (stream transport only), recycle both connections with
* mbedtls_ssl_session_reset() over fresh sockets and do it all again: a
* recycled connection keeps the lengths it was set up with. */
mbedtls_test_ssl_endpoint client;
memset(&client, 0, sizeof(client));
mbedtls_test_ssl_endpoint server;
memset(&server, 0, sizeof(server));
mbedtls_test_handshake_test_options options;
mbedtls_test_init_handshake_options(&options);
MD_OR_USE_PSA_INIT();
options.pk_alg = MBEDTLS_PK_ECDSA;
options.dtls = dtls;
options.client_min_version = version;
options.client_max_version = version;
options.expected_negotiated_version = version;
options.cli_msg_len = cli_msg_len;
options.expected_cli_fragments = expected_cli_fragments;
options.srv_msg_len = srv_msg_len;
options.expected_srv_fragments = expected_srv_fragments;
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_conf(&client, MBEDTLS_SSL_IS_CLIENT,
&options), 0);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_conf(&server, MBEDTLS_SSL_IS_SERVER,
&options), 0);
if (cli_in != 0) {
TEST_EQUAL(mbedtls_ssl_set_in_content_len(&client.ssl, cli_in), 0);
}
if (cli_out != 0) {
TEST_EQUAL(mbedtls_ssl_set_out_content_len(&client.ssl, cli_out), 0);
}
if (srv_in != 0) {
TEST_EQUAL(mbedtls_ssl_set_in_content_len(&server.ssl, srv_in), 0);
}
if (srv_out != 0) {
TEST_EQUAL(mbedtls_ssl_set_out_content_len(&server.ssl, srv_out), 0);
}
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_ssl(&client, &options), 0);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_ssl(&server, &options), 0);
if (dtls) {
TEST_EQUAL(mbedtls_test_ssl_dtls_join_endpoints(&client, &server), 0);
}
TEST_ASSERT(mbedtls_test_ssl_perform_connection(&options, &client, &server));
if (reset) {
mbedtls_test_mock_socket_close(&client.socket);
mbedtls_test_mock_socket_close(&server.socket);
TEST_EQUAL(mbedtls_ssl_session_reset(&client.ssl), 0);
TEST_EQUAL(mbedtls_ssl_session_reset(&server.ssl), 0);
TEST_ASSERT(mbedtls_test_ssl_perform_connection(&options, &client, &server));
}
exit:
mbedtls_test_ssl_endpoint_free(&client);
mbedtls_test_ssl_endpoint_free(&server);
mbedtls_test_free_handshake_options(&options);
MD_OR_USE_PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_RUNTIME_CONTENT_LEN:MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:MBEDTLS_SSL_PROTO_TLS1_2:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256 */
void ssl_runtime_content_len_resize_buffers(int dtls, int mfl, int renegotiate,
int cli_in, int cli_out,
int srv_in, int srv_out)
{
/* With automatic buffer resizing as well, give each peer its own content
* lengths (0 leaves one at the build-time maximum) and run a handshake,
* optionally with a negotiated fragment length and a renegotiation, then
* recycle both connections with mbedtls_ssl_session_reset().
*
* Every handshake starts by growing the buffers back to full size, and
* full size is this connection's own length: growing to the build-time
* maximum would undo the saving. mbedtls_test_ssl_perform_connection()
* checks the buffers at each resize, including in the middle of the
* renegotiation; this test checks them after setup and after reset. */
mbedtls_test_ssl_endpoint client;
memset(&client, 0, sizeof(client));
mbedtls_test_ssl_endpoint server;
memset(&server, 0, sizeof(server));
mbedtls_test_handshake_test_options options;
mbedtls_test_init_handshake_options(&options);
/* A buffer is its content length plus a fixed overhead for the header,
* the crypto expansion and any connection ID. */
const size_t cli_in_buf_len = (cli_in ? cli_in : MBEDTLS_SSL_IN_CONTENT_LEN)
+ MBEDTLS_SSL_IN_BUFFER_LEN - MBEDTLS_SSL_IN_CONTENT_LEN;
const size_t cli_out_buf_len = (cli_out ? cli_out : MBEDTLS_SSL_OUT_CONTENT_LEN)
+ MBEDTLS_SSL_OUT_BUFFER_LEN - MBEDTLS_SSL_OUT_CONTENT_LEN;
const size_t srv_in_buf_len = (srv_in ? srv_in : MBEDTLS_SSL_IN_CONTENT_LEN)
+ MBEDTLS_SSL_IN_BUFFER_LEN - MBEDTLS_SSL_IN_CONTENT_LEN;
const size_t srv_out_buf_len = (srv_out ? srv_out : MBEDTLS_SSL_OUT_CONTENT_LEN)
+ MBEDTLS_SSL_OUT_BUFFER_LEN - MBEDTLS_SSL_OUT_CONTENT_LEN;
MD_OR_USE_PSA_INIT();
options.pk_alg = MBEDTLS_PK_ECDSA;
options.dtls = dtls;
options.client_min_version = MBEDTLS_SSL_VERSION_TLS1_2;
options.client_max_version = MBEDTLS_SSL_VERSION_TLS1_2;
options.expected_negotiated_version = MBEDTLS_SSL_VERSION_TLS1_2;
options.mfl = mfl;
options.renegotiate = renegotiate;
options.legacy_renegotiation = MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION;
options.resize_buffers = 1;
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_conf(&client, MBEDTLS_SSL_IS_CLIENT,
&options), 0);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_conf(&server, MBEDTLS_SSL_IS_SERVER,
&options), 0);
if (cli_in != 0) {
TEST_EQUAL(mbedtls_ssl_set_in_content_len(&client.ssl, cli_in), 0);
}
if (cli_out != 0) {
TEST_EQUAL(mbedtls_ssl_set_out_content_len(&client.ssl, cli_out), 0);
}
if (srv_in != 0) {
TEST_EQUAL(mbedtls_ssl_set_in_content_len(&server.ssl, srv_in), 0);
}
if (srv_out != 0) {
TEST_EQUAL(mbedtls_ssl_set_out_content_len(&server.ssl, srv_out), 0);
}
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_ssl(&client, &options), 0);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_ssl(&server, &options), 0);
/* Setup allocates from the connection's lengths, then runs the grow step
* of the first handshake, which must leave them alone. */
TEST_EQUAL(client.ssl.in_buf_len, cli_in_buf_len);
TEST_EQUAL(client.ssl.out_buf_len, cli_out_buf_len);
TEST_EQUAL(server.ssl.in_buf_len, srv_in_buf_len);
TEST_EQUAL(server.ssl.out_buf_len, srv_out_buf_len);
if (dtls) {
TEST_EQUAL(mbedtls_test_ssl_dtls_join_endpoints(&client, &server), 0);
}
TEST_ASSERT(mbedtls_test_ssl_perform_connection(&options, &client, &server));
/* Resizing after the handshake may have shrunk the buffers further, to a
* negotiated fragment length, but never grown them. */
TEST_LE_U(client.ssl.in_buf_len, cli_in_buf_len);
TEST_LE_U(client.ssl.out_buf_len, cli_out_buf_len);
TEST_LE_U(server.ssl.in_buf_len, srv_in_buf_len);
TEST_LE_U(server.ssl.out_buf_len, srv_out_buf_len);
/* A reset prepares the next handshake, growing the buffers back to the
* connection's lengths and no further. */
TEST_EQUAL(mbedtls_ssl_session_reset(&client.ssl), 0);
TEST_EQUAL(mbedtls_ssl_session_reset(&server.ssl), 0);
TEST_EQUAL(client.ssl.in_buf_len, cli_in_buf_len);
TEST_EQUAL(client.ssl.out_buf_len, cli_out_buf_len);
TEST_EQUAL(server.ssl.in_buf_len, srv_in_buf_len);
TEST_EQUAL(server.ssl.out_buf_len, srv_out_buf_len);
exit:
mbedtls_test_ssl_endpoint_free(&client);
mbedtls_test_ssl_endpoint_free(&server);
mbedtls_test_free_handshake_options(&options);
MD_OR_USE_PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_RUNTIME_CONTENT_LEN:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256 */
void ssl_runtime_content_len_oversized_record(int version, int srv_in,
int msg_len, int expected_ret)
{
/* Shrink only the server's incoming length, so that nothing on the
* wire tells the client (the TLS 1.3 cases therefore exclude
* MBEDTLS_SSL_RECORD_SIZE_LIMIT, which would), and have the full-size
* client send one record of msg_len bytes after the handshake. The
* server's verdict on that record is what shows its incoming length took
* effect. */
enum { BUFFSIZE = 17000 };
mbedtls_test_ssl_endpoint client;
memset(&client, 0, sizeof(client));
mbedtls_test_ssl_endpoint server;
memset(&server, 0, sizeof(server));
mbedtls_test_handshake_test_options options;
mbedtls_test_init_handshake_options(&options);
unsigned char *msg = NULL;
unsigned char *received = NULL;
MD_OR_USE_PSA_INIT();
TEST_CALLOC(msg, msg_len);
TEST_CALLOC(received, msg_len);
memset(msg, 'x', msg_len);
options.pk_alg = MBEDTLS_PK_ECDSA;
options.client_min_version = version;
options.client_max_version = version;
options.expected_negotiated_version = version;
TEST_EQUAL(mbedtls_test_ssl_endpoint_init(&client, MBEDTLS_SSL_IS_CLIENT,
&options), 0);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_conf(&server, MBEDTLS_SSL_IS_SERVER,
&options), 0);
TEST_EQUAL(mbedtls_ssl_set_in_content_len(&server.ssl, srv_in), 0);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_ssl(&server, &options), 0);
TEST_EQUAL(mbedtls_test_mock_socket_connect(&client.socket, &server.socket,
BUFFSIZE), 0);
TEST_EQUAL(mbedtls_test_move_handshake_to_state(&client.ssl, &server.ssl,
MBEDTLS_SSL_HANDSHAKE_OVER),
0);
TEST_EQUAL(mbedtls_test_move_handshake_to_state(&server.ssl, &client.ssl,
MBEDTLS_SSL_HANDSHAKE_OVER),
0);
TEST_EQUAL(mbedtls_ssl_write(&client.ssl, msg, msg_len), msg_len);
if (expected_ret == 0) {
TEST_EQUAL(mbedtls_ssl_read(&server.ssl, received, msg_len), msg_len);
TEST_MEMORY_COMPARE(received, msg_len, msg, msg_len);
} else {
TEST_EQUAL(mbedtls_ssl_read(&server.ssl, received, msg_len),
expected_ret);
}
exit:
mbedtls_free(msg);
mbedtls_free(received);
mbedtls_test_ssl_endpoint_free(&client);
mbedtls_test_ssl_endpoint_free(&server);
mbedtls_test_free_handshake_options(&options);
MD_OR_USE_PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_RUNTIME_CONTENT_LEN:MBEDTLS_SSL_MAX_FRAGMENT_LENGTH:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256 */
void ssl_runtime_content_len_setup_mfl(int endpoint, int min_version,
int in_len, int mfl, int expected_ret)
{
/* A client whose configuration negotiates a fragment length above the
* connection's incoming length would invite records it cannot hold, so
* mbedtls_ssl_setup() refuses it. A client that only offers TLS 1.3 never
* sends a fragment length, and a server's configured fragment length only
* caps what it sends, so neither is a contradiction. */
mbedtls_test_ssl_endpoint ep;
memset(&ep, 0, sizeof(ep));
mbedtls_test_handshake_test_options options;
mbedtls_test_init_handshake_options(&options);
MD_OR_USE_PSA_INIT();
options.pk_alg = MBEDTLS_PK_ECDSA;
options.client_min_version = min_version;
options.server_min_version = min_version;
options.mfl = mfl;
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_conf(&ep, endpoint, &options), 0);
TEST_EQUAL(mbedtls_ssl_set_in_content_len(&ep.ssl, in_len), 0);
TEST_EQUAL(mbedtls_ssl_setup(&ep.ssl, &ep.conf), expected_ret);
if (expected_ret != 0) {
/* A refused connection has no buffers, and cannot be recycled the way
* mbedtls_test_ssl_endpoint_free() recycles a set-up one. */
mbedtls_ssl_free(&ep.ssl);
mbedtls_ssl_init(&ep.ssl);
}
exit:
mbedtls_test_ssl_endpoint_free(&ep);
mbedtls_test_free_handshake_options(&options);
MD_OR_USE_PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_RUNTIME_CONTENT_LEN:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256 */
void ssl_runtime_content_len_client_hello_ext(int version, int cli_in, int mfl,
int ext_type, int expected_ret,
int expected_value)
{
/* Set the client's incoming length, have it send its ClientHello, and
* read the extension of type ext_type off the wire: its value (a
* max_fragment_length code or a record_size_limit) is what the client
* invites its peer to send. expected_value -1 means the extension must
* be absent. expected_ret is the handshake's verdict before anything is
* sent; 0 means the ClientHello went out and the client waits for the
* server. */
enum { BUFFSIZE = 17000 };
mbedtls_test_ssl_endpoint client;
memset(&client, 0, sizeof(client));
mbedtls_test_mock_socket peer;
mbedtls_test_mock_socket_init(&peer);
mbedtls_test_handshake_test_options options;
mbedtls_test_init_handshake_options(&options);
unsigned char buf[BUFFSIZE];
size_t len = 0;
size_t off = 0;
size_t end = 0;
int ext_value = -1;
int ret;
MD_OR_USE_PSA_INIT();
options.pk_alg = MBEDTLS_PK_ECDSA;
options.client_min_version = version;
options.client_max_version = version;
options.mfl = mfl;
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_conf(&client, MBEDTLS_SSL_IS_CLIENT,
&options), 0);
TEST_EQUAL(mbedtls_ssl_set_in_content_len(&client.ssl, cli_in), 0);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_ssl(&client, &options), 0);
TEST_EQUAL(mbedtls_test_mock_socket_connect(&client.socket, &peer,
BUFFSIZE), 0);
if (expected_ret != 0) {
TEST_EQUAL(mbedtls_ssl_handshake(&client.ssl), expected_ret);
TEST_EQUAL(mbedtls_test_mock_tcp_recv_nb(&peer, buf, sizeof(buf)),
MBEDTLS_ERR_SSL_WANT_READ);
goto exit;
}
TEST_EQUAL(mbedtls_ssl_handshake(&client.ssl), MBEDTLS_ERR_SSL_WANT_READ);
ret = mbedtls_test_mock_tcp_recv_nb(&peer, buf, sizeof(buf));
TEST_LE_S(1, ret);
len = (size_t) ret;
/* Record header (5), then handshake header (4): one ClientHello record. */
TEST_LE_U(9, len);
TEST_EQUAL(buf[0], MBEDTLS_SSL_MSG_HANDSHAKE);
TEST_EQUAL(MBEDTLS_GET_UINT16_BE(buf, 3), len - 5);
TEST_EQUAL(buf[5], MBEDTLS_SSL_HS_CLIENT_HELLO);
/* legacy_version (2) and random (32) */
off = 9 + 2 + 32;
/* legacy_session_id */
TEST_LE_U(off + 1, len);
off += 1 + buf[off];
/* cipher_suites */
TEST_LE_U(off + 2, len);
off += 2 + MBEDTLS_GET_UINT16_BE(buf, off);
/* legacy_compression_methods */
TEST_LE_U(off + 1, len);
off += 1 + buf[off];
/* extensions */
TEST_LE_U(off + 2, len);
end = off + 2 + MBEDTLS_GET_UINT16_BE(buf, off);
TEST_EQUAL(end, len);
off += 2;
while (off < end) {
size_t ext_len;
TEST_LE_U(off + 4, end);
ext_len = MBEDTLS_GET_UINT16_BE(buf, off + 2);
TEST_LE_U(off + 4 + ext_len, end);
if (MBEDTLS_GET_UINT16_BE(buf, off) == ext_type) {
TEST_EQUAL(ext_value, -1);
TEST_ASSERT(ext_len == 1 || ext_len == 2);
ext_value = ext_len == 1 ? buf[off + 4] : MBEDTLS_GET_UINT16_BE(buf, off + 4);
}
off += 4 + ext_len;
}
TEST_EQUAL(ext_value, expected_value);
exit:
mbedtls_test_ssl_endpoint_free(&client);
mbedtls_test_mock_socket_close(&peer);
mbedtls_test_free_handshake_options(&options);
MD_OR_USE_PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_RUNTIME_CONTENT_LEN:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256 */
void ssl_runtime_content_len_max_payload(int version, int cli_in, int cli_out,
int mfl, int pre_handshake_out,
int expected_in, int expected_out)
{
/* Give the client its own lengths (and optionally a fragment length to
* negotiate) and check what the public maximum-record-payload queries
* report on it, once set up and again once the handshake is over. The
* server sends no more than the client can take in, so that the
* handshake itself does not depend on negotiating anything. */
enum { BUFFSIZE = 17000 };
mbedtls_test_ssl_endpoint client;
memset(&client, 0, sizeof(client));
mbedtls_test_ssl_endpoint server;
memset(&server, 0, sizeof(server));
mbedtls_test_handshake_test_options options;
mbedtls_test_init_handshake_options(&options);
MD_OR_USE_PSA_INIT();
options.pk_alg = MBEDTLS_PK_ECDSA;
options.client_min_version = version;
options.client_max_version = version;
options.expected_negotiated_version = version;
options.mfl = mfl;
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_conf(&client, MBEDTLS_SSL_IS_CLIENT,
&options), 0);
TEST_EQUAL(mbedtls_ssl_set_in_content_len(&client.ssl, cli_in), 0);
TEST_EQUAL(mbedtls_ssl_set_out_content_len(&client.ssl, cli_out), 0);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_ssl(&client, &options), 0);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_conf(&server, MBEDTLS_SSL_IS_SERVER,
&options), 0);
TEST_EQUAL(mbedtls_ssl_set_out_content_len(&server.ssl, cli_in), 0);
TEST_EQUAL(mbedtls_test_ssl_endpoint_init_ssl(&server, &options), 0);
/* Before the handshake nothing is negotiated: the incoming length is the
* client's own, and the outgoing one is capped only by what the client
* itself configured. */
TEST_EQUAL(mbedtls_ssl_get_max_in_record_payload(&client.ssl), cli_in);
TEST_EQUAL(mbedtls_ssl_get_max_out_record_payload(&client.ssl),
pre_handshake_out);
TEST_EQUAL(mbedtls_test_mock_socket_connect(&client.socket, &server.socket,
BUFFSIZE), 0);
TEST_EQUAL(mbedtls_test_move_handshake_to_state(&client.ssl, &server.ssl,
MBEDTLS_SSL_HANDSHAKE_OVER),
0);
TEST_EQUAL(mbedtls_test_move_handshake_to_state(&server.ssl, &client.ssl,
MBEDTLS_SSL_HANDSHAKE_OVER),
0);
TEST_EQUAL(mbedtls_ssl_get_max_in_record_payload(&client.ssl), expected_in);
TEST_EQUAL(mbedtls_ssl_get_max_out_record_payload(&client.ssl), expected_out);
exit:
mbedtls_test_ssl_endpoint_free(&client);
mbedtls_test_ssl_endpoint_free(&server);
mbedtls_test_free_handshake_options(&options);
MD_OR_USE_PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */
void test_multiple_psks()
{